OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.h" |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/compiler.h" | 8 #include "src/compiler.h" |
9 #include "src/interpreter/bytecode-register-allocator.h" | 9 #include "src/interpreter/bytecode-register-allocator.h" |
10 #include "src/interpreter/control-flow-builders.h" | 10 #include "src/interpreter/control-flow-builders.h" |
(...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
562 info->scope()->MaxNestedContextChainLength(), | 562 info->scope()->MaxNestedContextChainLength(), |
563 info->scope()->num_stack_slots(), info->literal())), | 563 info->scope()->num_stack_slots(), info->literal())), |
564 info_(info), | 564 info_(info), |
565 scope_(info->scope()), | 565 scope_(info->scope()), |
566 globals_(0, info->zone()), | 566 globals_(0, info->zone()), |
567 execution_control_(nullptr), | 567 execution_control_(nullptr), |
568 execution_context_(nullptr), | 568 execution_context_(nullptr), |
569 execution_result_(nullptr), | 569 execution_result_(nullptr), |
570 register_allocator_(nullptr), | 570 register_allocator_(nullptr), |
571 generator_resume_points_(info->literal()->yield_count(), info->zone()), | 571 generator_resume_points_(info->literal()->yield_count(), info->zone()), |
572 generator_state_(), | |
573 generator_yields_seen_(0), | |
572 try_catch_nesting_level_(0), | 574 try_catch_nesting_level_(0), |
573 try_finally_nesting_level_(0), | 575 try_finally_nesting_level_(0) { |
574 generator_yields_seen_(0) { | |
575 InitializeAstVisitor(isolate()); | 576 InitializeAstVisitor(isolate()); |
576 } | 577 } |
577 | 578 |
578 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode() { | 579 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode() { |
579 // Initialize the incoming context. | 580 // Initialize the incoming context. |
580 ContextScope incoming_context(this, scope(), false); | 581 ContextScope incoming_context(this, scope(), false); |
581 | 582 |
582 // Initialize control scope. | 583 // Initialize control scope. |
583 ControlScopeForTopLevel control(this); | 584 ControlScopeForTopLevel control(this); |
584 | 585 |
586 RegisterAllocationScope register_scope(this); | |
587 | |
585 if (IsGeneratorFunction(info()->literal()->kind())) { | 588 if (IsGeneratorFunction(info()->literal()->kind())) { |
589 generator_state_ = register_allocator()->NewRegister(); | |
586 VisitGeneratorPrologue(); | 590 VisitGeneratorPrologue(); |
587 } | 591 } |
588 | 592 |
589 // Build function context only if there are context allocated variables. | 593 // Build function context only if there are context allocated variables. |
590 if (scope()->NeedsContext()) { | 594 if (scope()->NeedsContext()) { |
591 // Push a new inner context scope for the function. | 595 // Push a new inner context scope for the function. |
592 VisitNewLocalFunctionContext(); | 596 VisitNewLocalFunctionContext(); |
593 ContextScope local_function_context(this, scope(), false); | 597 ContextScope local_function_context(this, scope(), false); |
594 VisitBuildLocalActivationContext(); | 598 VisitBuildLocalActivationContext(); |
595 MakeBytecodeBody(); | 599 MakeBytecodeBody(); |
(...skipping 29 matching lines...) Expand all Loading... | |
625 // Visit declarations within the function scope. | 629 // Visit declarations within the function scope. |
626 VisitDeclarations(scope()->declarations()); | 630 VisitDeclarations(scope()->declarations()); |
627 | 631 |
628 // Perform a stack-check before the body. | 632 // Perform a stack-check before the body. |
629 builder()->StackCheck(); | 633 builder()->StackCheck(); |
630 | 634 |
631 // Visit statements in the function body. | 635 // Visit statements in the function body. |
632 VisitStatements(info()->literal()->body()); | 636 VisitStatements(info()->literal()->body()); |
633 } | 637 } |
634 | 638 |
639 void BytecodeGenerator::BuildIndexedJump(Register index, int min, size_t size, | |
rmcilroy
2016/04/27 11:02:26
nit /s/min/start_index/
neis
2016/04/27 12:01:25
Done.
| |
640 ZoneVector<BytecodeLabel>& targets) { | |
641 // TODO(neis): Optimize this by using a proper jump table. | |
642 for (int i = min; i < min + static_cast<int>(size); i++) { | |
643 DCHECK(0 <= i && i < static_cast<int>(targets.size())); | |
644 builder() | |
645 ->LoadLiteral(Smi::FromInt(i)) | |
646 .CompareOperation(Token::Value::EQ_STRICT, index) | |
647 .JumpIfTrue(&(targets[i])); | |
648 } | |
649 builder()->Illegal(); // Should never get here. | |
650 } | |
651 | |
652 void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt, | |
653 LoopBuilder* loop_builder) { | |
654 // Collect all labels for generator resume points within the loop (if any) so | |
655 // that they can be bound to the loop header below. Also create fresh labels | |
656 // for these resume points, to be used inside the loop. | |
657 ZoneVector<BytecodeLabel> resume_points_in_loop(zone()); | |
658 for (int id = generator_yields_seen_; | |
659 id < generator_yields_seen_ + static_cast<int>(stmt->yield_count()); | |
rmcilroy
2016/04/27 11:02:26
How about making generator_yields_seen_ and id siz
neis
2016/04/27 12:01:25
Done. Had to cast elsewhere though.
| |
660 id++) { | |
661 DCHECK(0 <= id && id < static_cast<int>(generator_resume_points_.size())); | |
662 auto& label = generator_resume_points_[id]; | |
663 resume_points_in_loop.push_back(label); | |
664 generator_resume_points_[id] = BytecodeLabel(); | |
665 } | |
666 | |
667 loop_builder->LoopHeader(&resume_points_in_loop); | |
668 | |
669 if (stmt->yield_count() > 0) { | |
670 // If we are not resuming, fall through to loop body. | |
671 // If we are resuming, perform state dispatch. | |
672 BytecodeLabel not_resuming; | |
673 builder() | |
674 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | |
675 .CompareOperation(Token::Value::EQ, generator_state_) | |
676 .JumpIfTrue(¬_resuming); | |
677 BuildIndexedJump(generator_state_, generator_yields_seen_, | |
678 stmt->yield_count(), generator_resume_points_); | |
679 builder()->Bind(¬_resuming); | |
680 } | |
681 } | |
682 | |
635 void BytecodeGenerator::VisitGeneratorPrologue() { | 683 void BytecodeGenerator::VisitGeneratorPrologue() { |
684 Register generator_object = Register::new_target(); | |
rmcilroy
2016/04/27 11:02:26
nit - could you add a comment here that generator
neis
2016/04/27 12:01:26
Done.
| |
685 | |
636 BytecodeLabel regular_call; | 686 BytecodeLabel regular_call; |
637 builder() | 687 builder() |
638 ->LoadAccumulatorWithRegister(Register::new_target()) | 688 ->LoadAccumulatorWithRegister(generator_object) |
639 .JumpIfUndefined(®ular_call); | 689 .JumpIfUndefined(®ular_call); |
640 | 690 |
641 // This is a resume call. Restore registers and perform state dispatch. | 691 // This is a resume call. Restore registers and perform state dispatch. |
642 // (The current context has already been restored by the trampoline.) | 692 // (The current context has already been restored by the trampoline.) |
643 { | 693 builder() |
644 RegisterAllocationScope register_scope(this); | 694 ->ResumeGenerator(generator_object) |
645 Register state = register_allocator()->NewRegister(); | 695 .StoreAccumulatorInRegister(generator_state_); |
646 builder() | 696 BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(), |
647 ->ResumeGenerator(Register::new_target()) | 697 generator_resume_points_); |
648 .StoreAccumulatorInRegister(state); | |
649 | |
650 // TODO(neis): Optimize this by using a proper jump table. | |
651 for (size_t i = 0; i < generator_resume_points_.size(); ++i) { | |
652 builder() | |
653 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) | |
654 .CompareOperation(Token::Value::EQ_STRICT, state) | |
655 .JumpIfTrue(&(generator_resume_points_[i])); | |
656 } | |
657 builder()->Illegal(); // Should never get here. | |
658 } | |
659 | 698 |
660 builder()->Bind(®ular_call); | 699 builder()->Bind(®ular_call); |
661 // This is a regular call. Fall through to the ordinary function prologue, | 700 // This is a regular call. Fall through to the ordinary function prologue, |
662 // after which we will run into the generator object creation and the initial | 701 // after which we will run into the generator object creation and the initial |
663 // yield (both inserted by the parser). | 702 // yield (both inserted by the parser). |
664 } | 703 } |
665 | 704 |
666 void BytecodeGenerator::VisitBlock(Block* stmt) { | 705 void BytecodeGenerator::VisitBlock(Block* stmt) { |
667 // Visit declarations and statements. | 706 // Visit declarations and statements. |
668 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { | 707 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
982 | 1021 |
983 void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt, | 1022 void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt, |
984 LoopBuilder* loop_builder) { | 1023 LoopBuilder* loop_builder) { |
985 ControlScopeForIteration execution_control(this, stmt, loop_builder); | 1024 ControlScopeForIteration execution_control(this, stmt, loop_builder); |
986 builder()->StackCheck(); | 1025 builder()->StackCheck(); |
987 Visit(stmt->body()); | 1026 Visit(stmt->body()); |
988 } | 1027 } |
989 | 1028 |
990 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | 1029 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
991 LoopBuilder loop_builder(builder()); | 1030 LoopBuilder loop_builder(builder()); |
992 loop_builder.LoopHeader(); | 1031 VisitIterationHeader(stmt, &loop_builder); |
993 if (stmt->cond()->ToBooleanIsFalse()) { | 1032 if (stmt->cond()->ToBooleanIsFalse()) { |
994 VisitIterationBody(stmt, &loop_builder); | 1033 VisitIterationBody(stmt, &loop_builder); |
995 loop_builder.Condition(); | 1034 loop_builder.Condition(); |
996 } else if (stmt->cond()->ToBooleanIsTrue()) { | 1035 } else if (stmt->cond()->ToBooleanIsTrue()) { |
997 loop_builder.Condition(); | 1036 loop_builder.Condition(); |
998 VisitIterationBody(stmt, &loop_builder); | 1037 VisitIterationBody(stmt, &loop_builder); |
999 loop_builder.JumpToHeader(); | 1038 loop_builder.JumpToHeader(); |
1000 } else { | 1039 } else { |
1001 VisitIterationBody(stmt, &loop_builder); | 1040 VisitIterationBody(stmt, &loop_builder); |
1002 loop_builder.Condition(); | 1041 loop_builder.Condition(); |
1003 builder()->SetExpressionAsStatementPosition(stmt->cond()); | 1042 builder()->SetExpressionAsStatementPosition(stmt->cond()); |
1004 VisitForAccumulatorValue(stmt->cond()); | 1043 VisitForAccumulatorValue(stmt->cond()); |
1005 loop_builder.JumpToHeaderIfTrue(); | 1044 loop_builder.JumpToHeaderIfTrue(); |
1006 } | 1045 } |
1007 loop_builder.EndLoop(); | 1046 loop_builder.EndLoop(); |
1008 } | 1047 } |
1009 | 1048 |
1010 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { | 1049 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
1011 if (stmt->cond()->ToBooleanIsFalse()) { | 1050 if (stmt->cond()->ToBooleanIsFalse()) { |
1012 // If the condition is false there is no need to generate the loop. | 1051 // If the condition is false there is no need to generate the loop. |
1013 return; | 1052 return; |
1014 } | 1053 } |
1015 | 1054 |
1016 LoopBuilder loop_builder(builder()); | 1055 LoopBuilder loop_builder(builder()); |
1017 loop_builder.LoopHeader(); | 1056 VisitIterationHeader(stmt, &loop_builder); |
1018 loop_builder.Condition(); | 1057 loop_builder.Condition(); |
1019 if (!stmt->cond()->ToBooleanIsTrue()) { | 1058 if (!stmt->cond()->ToBooleanIsTrue()) { |
1020 builder()->SetExpressionAsStatementPosition(stmt->cond()); | 1059 builder()->SetExpressionAsStatementPosition(stmt->cond()); |
1021 VisitForAccumulatorValue(stmt->cond()); | 1060 VisitForAccumulatorValue(stmt->cond()); |
1022 loop_builder.BreakIfFalse(); | 1061 loop_builder.BreakIfFalse(); |
1023 } | 1062 } |
1024 VisitIterationBody(stmt, &loop_builder); | 1063 VisitIterationBody(stmt, &loop_builder); |
1025 loop_builder.JumpToHeader(); | 1064 loop_builder.JumpToHeader(); |
1026 loop_builder.EndLoop(); | 1065 loop_builder.EndLoop(); |
1027 } | 1066 } |
1028 | 1067 |
1029 | 1068 |
1030 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { | 1069 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { |
1031 if (stmt->init() != nullptr) { | 1070 if (stmt->init() != nullptr) { |
1032 Visit(stmt->init()); | 1071 Visit(stmt->init()); |
1033 } | 1072 } |
1034 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { | 1073 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { |
1035 // If the condition is known to be false there is no need to generate | 1074 // If the condition is known to be false there is no need to generate |
1036 // body, next or condition blocks. Init block should be generated. | 1075 // body, next or condition blocks. Init block should be generated. |
1037 return; | 1076 return; |
1038 } | 1077 } |
1039 | 1078 |
1040 LoopBuilder loop_builder(builder()); | 1079 LoopBuilder loop_builder(builder()); |
1041 loop_builder.LoopHeader(); | 1080 VisitIterationHeader(stmt, &loop_builder); |
1042 loop_builder.Condition(); | 1081 loop_builder.Condition(); |
1043 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { | 1082 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { |
1044 builder()->SetExpressionAsStatementPosition(stmt->cond()); | 1083 builder()->SetExpressionAsStatementPosition(stmt->cond()); |
1045 VisitForAccumulatorValue(stmt->cond()); | 1084 VisitForAccumulatorValue(stmt->cond()); |
1046 loop_builder.BreakIfFalse(); | 1085 loop_builder.BreakIfFalse(); |
1047 } | 1086 } |
1048 VisitIterationBody(stmt, &loop_builder); | 1087 VisitIterationBody(stmt, &loop_builder); |
1049 if (stmt->next() != nullptr) { | 1088 if (stmt->next() != nullptr) { |
1050 loop_builder.Next(); | 1089 loop_builder.Next(); |
1051 builder()->SetStatementPosition(stmt->next()); | 1090 builder()->SetStatementPosition(stmt->next()); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1156 // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext. | 1195 // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext. |
1157 USE(cache_array); | 1196 USE(cache_array); |
1158 builder()->ForInPrepare(cache_type); | 1197 builder()->ForInPrepare(cache_type); |
1159 | 1198 |
1160 // Set up loop counter | 1199 // Set up loop counter |
1161 Register index = register_allocator()->NewRegister(); | 1200 Register index = register_allocator()->NewRegister(); |
1162 builder()->LoadLiteral(Smi::FromInt(0)); | 1201 builder()->LoadLiteral(Smi::FromInt(0)); |
1163 builder()->StoreAccumulatorInRegister(index); | 1202 builder()->StoreAccumulatorInRegister(index); |
1164 | 1203 |
1165 // The loop | 1204 // The loop |
1166 loop_builder.LoopHeader(); | 1205 VisitIterationHeader(stmt, &loop_builder); |
1167 builder()->SetExpressionAsStatementPosition(stmt->each()); | 1206 builder()->SetExpressionAsStatementPosition(stmt->each()); |
1168 loop_builder.Condition(); | 1207 loop_builder.Condition(); |
1169 builder()->ForInDone(index, cache_length); | 1208 builder()->ForInDone(index, cache_length); |
1170 loop_builder.BreakIfTrue(); | 1209 loop_builder.BreakIfTrue(); |
1171 DCHECK(Register::AreContiguous(cache_type, cache_array)); | 1210 DCHECK(Register::AreContiguous(cache_type, cache_array)); |
1172 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); | 1211 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); |
1173 builder()->ForInNext(receiver, index, cache_type, feedback_index(slot)); | 1212 builder()->ForInNext(receiver, index, cache_type, feedback_index(slot)); |
1174 loop_builder.ContinueIfUndefined(); | 1213 loop_builder.ContinueIfUndefined(); |
1175 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); | 1214 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); |
1176 VisitIterationBody(stmt, &loop_builder); | 1215 VisitIterationBody(stmt, &loop_builder); |
1177 loop_builder.Next(); | 1216 loop_builder.Next(); |
1178 builder()->ForInStep(index); | 1217 builder()->ForInStep(index); |
1179 builder()->StoreAccumulatorInRegister(index); | 1218 builder()->StoreAccumulatorInRegister(index); |
1180 loop_builder.JumpToHeader(); | 1219 loop_builder.JumpToHeader(); |
1181 loop_builder.EndLoop(); | 1220 loop_builder.EndLoop(); |
1182 builder()->Bind(&subject_null_label); | 1221 builder()->Bind(&subject_null_label); |
1183 builder()->Bind(&subject_undefined_label); | 1222 builder()->Bind(&subject_undefined_label); |
1184 } | 1223 } |
1185 | 1224 |
1186 | 1225 |
1187 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { | 1226 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { |
1188 LoopBuilder loop_builder(builder()); | 1227 LoopBuilder loop_builder(builder()); |
1189 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 1228 ControlScopeForIteration control_scope(this, stmt, &loop_builder); |
1190 | 1229 |
1191 builder()->SetExpressionAsStatementPosition(stmt->assign_iterator()); | 1230 builder()->SetExpressionAsStatementPosition(stmt->assign_iterator()); |
1192 VisitForEffect(stmt->assign_iterator()); | 1231 VisitForEffect(stmt->assign_iterator()); |
1193 | 1232 |
1194 loop_builder.LoopHeader(); | 1233 VisitIterationHeader(stmt, &loop_builder); |
1195 loop_builder.Next(); | 1234 loop_builder.Next(); |
1196 builder()->SetExpressionAsStatementPosition(stmt->next_result()); | 1235 builder()->SetExpressionAsStatementPosition(stmt->next_result()); |
1197 VisitForEffect(stmt->next_result()); | 1236 VisitForEffect(stmt->next_result()); |
1198 VisitForAccumulatorValue(stmt->result_done()); | 1237 VisitForAccumulatorValue(stmt->result_done()); |
1199 loop_builder.BreakIfTrue(); | 1238 loop_builder.BreakIfTrue(); |
1200 | 1239 |
1201 VisitForEffect(stmt->assign_each()); | 1240 VisitForEffect(stmt->assign_each()); |
1202 VisitIterationBody(stmt, &loop_builder); | 1241 VisitIterationBody(stmt, &loop_builder); |
1203 loop_builder.JumpToHeader(); | 1242 loop_builder.JumpToHeader(); |
1204 loop_builder.EndLoop(); | 1243 loop_builder.EndLoop(); |
(...skipping 1021 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2226 .SuspendGenerator(generator) | 2265 .SuspendGenerator(generator) |
2227 .LoadAccumulatorWithRegister(value) | 2266 .LoadAccumulatorWithRegister(value) |
2228 .Return(); // Hard return (ignore any finally blocks). | 2267 .Return(); // Hard return (ignore any finally blocks). |
2229 | 2268 |
2230 builder()->Bind(&(generator_resume_points_[id])); | 2269 builder()->Bind(&(generator_resume_points_[id])); |
2231 // Upon resume, we continue here. | 2270 // Upon resume, we continue here. |
2232 | 2271 |
2233 { | 2272 { |
2234 RegisterAllocationScope register_scope(this); | 2273 RegisterAllocationScope register_scope(this); |
2235 | 2274 |
2275 // Update state to indicate that we have finished resuming. Loop headers | |
2276 // rely on this. | |
2277 builder() | |
2278 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | |
2279 .StoreAccumulatorInRegister(generator_state_); | |
2280 | |
2236 Register input = register_allocator()->NewRegister(); | 2281 Register input = register_allocator()->NewRegister(); |
2237 builder() | 2282 builder() |
2238 ->CallRuntime(Runtime::kGeneratorGetInput, generator, 1) | 2283 ->CallRuntime(Runtime::kGeneratorGetInput, generator, 1) |
2239 .StoreAccumulatorInRegister(input); | 2284 .StoreAccumulatorInRegister(input); |
2240 | 2285 |
2241 Register resume_mode = register_allocator()->NewRegister(); | 2286 Register resume_mode = register_allocator()->NewRegister(); |
2242 builder() | 2287 builder() |
2243 ->CallRuntime(Runtime::kGeneratorGetResumeMode, generator, 1) | 2288 ->CallRuntime(Runtime::kGeneratorGetResumeMode, generator, 1) |
2244 .StoreAccumulatorInRegister(resume_mode); | 2289 .StoreAccumulatorInRegister(resume_mode); |
2245 | 2290 |
(...skipping 966 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3212 } | 3257 } |
3213 | 3258 |
3214 | 3259 |
3215 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 3260 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
3216 return info()->shared_info()->feedback_vector()->GetIndex(slot); | 3261 return info()->shared_info()->feedback_vector()->GetIndex(slot); |
3217 } | 3262 } |
3218 | 3263 |
3219 } // namespace interpreter | 3264 } // namespace interpreter |
3220 } // namespace internal | 3265 } // namespace internal |
3221 } // namespace v8 | 3266 } // namespace v8 |
OLD | NEW |