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, | |
640 ZoneVector<BytecodeLabel>& targets) { | |
641 // TODO(neis): Optimize this by using a proper jump table. | |
642 for (size_t i = min; i < min + size; i++) { | |
643 DCHECK(0 <= i && i < targets.size()); | |
644 builder() | |
645 ->LoadLiteral(Smi::FromInt(static_cast<int>(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. | |
Jarin
2016/04/26 12:59:51
I am wondering whether you should not say somethin
neis
2016/04/26 14:59:10
Acknowledged. Regarding your question: yes
neis
2016/04/27 12:01:25
Done.
| |
657 ZoneVector<BytecodeLabel> resume_points_in_loop(zone()); | |
658 for (int id = generator_yields_seen_; | |
659 id < generator_yields_seen_ + stmt->yield_count(); id++) { | |
660 DCHECK(0 <= id && id < generator_resume_points_.size()); | |
661 auto& label = generator_resume_points_[id]; | |
662 resume_points_in_loop.push_back(label); | |
663 generator_resume_points_[id] = BytecodeLabel(); | |
664 } | |
665 | |
666 loop_builder->LoopHeader(&resume_points_in_loop); | |
667 | |
668 if (stmt->yield_count() > 0) { | |
669 // If we are not resuming, fall through to loop body. | |
670 // If we are resuming, perform state dispatch. | |
671 BytecodeLabel not_resuming; | |
672 builder() | |
673 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | |
674 .CompareOperation(Token::Value::EQ, generator_state_) | |
675 .JumpIfTrue(¬_resuming); | |
676 BuildIndexedJump(generator_state_, generator_yields_seen_, | |
677 stmt->yield_count(), generator_resume_points_); | |
678 builder()->Bind(¬_resuming); | |
679 } | |
680 } | |
681 | |
635 void BytecodeGenerator::VisitGeneratorPrologue() { | 682 void BytecodeGenerator::VisitGeneratorPrologue() { |
683 Register generator_object = Register::new_target(); | |
684 | |
636 BytecodeLabel regular_call; | 685 BytecodeLabel regular_call; |
637 builder() | 686 builder() |
638 ->LoadAccumulatorWithRegister(Register::new_target()) | 687 ->LoadAccumulatorWithRegister(generator_object) |
639 .JumpIfUndefined(®ular_call); | 688 .JumpIfUndefined(®ular_call); |
640 | 689 |
641 // This is a resume call. Restore registers and perform state dispatch. | 690 // This is a resume call. Restore registers and perform state dispatch. |
642 // (The current context has already been restored by the trampoline.) | 691 // (The current context has already been restored by the trampoline.) |
643 { | 692 builder() |
644 RegisterAllocationScope register_scope(this); | 693 ->ResumeGenerator(generator_object) |
645 Register state = register_allocator()->NewRegister(); | 694 .StoreAccumulatorInRegister(generator_state_); |
646 builder() | 695 BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(), |
647 ->ResumeGenerator(Register::new_target()) | 696 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 | 697 |
660 builder()->Bind(®ular_call); | 698 builder()->Bind(®ular_call); |
661 // This is a regular call. Fall through to the ordinary function prologue, | 699 // 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 | 700 // after which we will run into the generator object creation and the initial |
663 // yield (both inserted by the parser). | 701 // yield (both inserted by the parser). |
664 } | 702 } |
665 | 703 |
666 void BytecodeGenerator::VisitBlock(Block* stmt) { | 704 void BytecodeGenerator::VisitBlock(Block* stmt) { |
667 // Visit declarations and statements. | 705 // Visit declarations and statements. |
668 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { | 706 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
982 | 1020 |
983 void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt, | 1021 void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt, |
984 LoopBuilder* loop_builder) { | 1022 LoopBuilder* loop_builder) { |
985 ControlScopeForIteration execution_control(this, stmt, loop_builder); | 1023 ControlScopeForIteration execution_control(this, stmt, loop_builder); |
986 builder()->StackCheck(); | 1024 builder()->StackCheck(); |
987 Visit(stmt->body()); | 1025 Visit(stmt->body()); |
988 } | 1026 } |
989 | 1027 |
990 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | 1028 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
991 LoopBuilder loop_builder(builder()); | 1029 LoopBuilder loop_builder(builder()); |
992 loop_builder.LoopHeader(); | 1030 VisitIterationHeader(stmt, &loop_builder); |
993 if (stmt->cond()->ToBooleanIsFalse()) { | 1031 if (stmt->cond()->ToBooleanIsFalse()) { |
994 VisitIterationBody(stmt, &loop_builder); | 1032 VisitIterationBody(stmt, &loop_builder); |
995 loop_builder.Condition(); | 1033 loop_builder.Condition(); |
996 } else if (stmt->cond()->ToBooleanIsTrue()) { | 1034 } else if (stmt->cond()->ToBooleanIsTrue()) { |
997 loop_builder.Condition(); | 1035 loop_builder.Condition(); |
998 VisitIterationBody(stmt, &loop_builder); | 1036 VisitIterationBody(stmt, &loop_builder); |
999 loop_builder.JumpToHeader(); | 1037 loop_builder.JumpToHeader(); |
1000 } else { | 1038 } else { |
1001 VisitIterationBody(stmt, &loop_builder); | 1039 VisitIterationBody(stmt, &loop_builder); |
1002 loop_builder.Condition(); | 1040 loop_builder.Condition(); |
1003 builder()->SetExpressionAsStatementPosition(stmt->cond()); | 1041 builder()->SetExpressionAsStatementPosition(stmt->cond()); |
1004 VisitForAccumulatorValue(stmt->cond()); | 1042 VisitForAccumulatorValue(stmt->cond()); |
1005 loop_builder.JumpToHeaderIfTrue(); | 1043 loop_builder.JumpToHeaderIfTrue(); |
1006 } | 1044 } |
1007 loop_builder.EndLoop(); | 1045 loop_builder.EndLoop(); |
1008 } | 1046 } |
1009 | 1047 |
1010 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { | 1048 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
1011 if (stmt->cond()->ToBooleanIsFalse()) { | 1049 if (stmt->cond()->ToBooleanIsFalse()) { |
1012 // If the condition is false there is no need to generate the loop. | 1050 // If the condition is false there is no need to generate the loop. |
1013 return; | 1051 return; |
1014 } | 1052 } |
1015 | 1053 |
1016 LoopBuilder loop_builder(builder()); | 1054 LoopBuilder loop_builder(builder()); |
1017 loop_builder.LoopHeader(); | 1055 VisitIterationHeader(stmt, &loop_builder); |
1018 loop_builder.Condition(); | 1056 loop_builder.Condition(); |
1019 if (!stmt->cond()->ToBooleanIsTrue()) { | 1057 if (!stmt->cond()->ToBooleanIsTrue()) { |
1020 builder()->SetExpressionAsStatementPosition(stmt->cond()); | 1058 builder()->SetExpressionAsStatementPosition(stmt->cond()); |
1021 VisitForAccumulatorValue(stmt->cond()); | 1059 VisitForAccumulatorValue(stmt->cond()); |
1022 loop_builder.BreakIfFalse(); | 1060 loop_builder.BreakIfFalse(); |
1023 } | 1061 } |
1024 VisitIterationBody(stmt, &loop_builder); | 1062 VisitIterationBody(stmt, &loop_builder); |
1025 loop_builder.JumpToHeader(); | 1063 loop_builder.JumpToHeader(); |
1026 loop_builder.EndLoop(); | 1064 loop_builder.EndLoop(); |
1027 } | 1065 } |
1028 | 1066 |
1029 | 1067 |
1030 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { | 1068 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { |
1031 if (stmt->init() != nullptr) { | 1069 if (stmt->init() != nullptr) { |
1032 Visit(stmt->init()); | 1070 Visit(stmt->init()); |
1033 } | 1071 } |
1034 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { | 1072 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { |
1035 // If the condition is known to be false there is no need to generate | 1073 // 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. | 1074 // body, next or condition blocks. Init block should be generated. |
1037 return; | 1075 return; |
1038 } | 1076 } |
1039 | 1077 |
1040 LoopBuilder loop_builder(builder()); | 1078 LoopBuilder loop_builder(builder()); |
1041 loop_builder.LoopHeader(); | 1079 VisitIterationHeader(stmt, &loop_builder); |
1042 loop_builder.Condition(); | 1080 loop_builder.Condition(); |
1043 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { | 1081 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { |
1044 builder()->SetExpressionAsStatementPosition(stmt->cond()); | 1082 builder()->SetExpressionAsStatementPosition(stmt->cond()); |
1045 VisitForAccumulatorValue(stmt->cond()); | 1083 VisitForAccumulatorValue(stmt->cond()); |
1046 loop_builder.BreakIfFalse(); | 1084 loop_builder.BreakIfFalse(); |
1047 } | 1085 } |
1048 VisitIterationBody(stmt, &loop_builder); | 1086 VisitIterationBody(stmt, &loop_builder); |
1049 if (stmt->next() != nullptr) { | 1087 if (stmt->next() != nullptr) { |
1050 loop_builder.Next(); | 1088 loop_builder.Next(); |
1051 builder()->SetStatementPosition(stmt->next()); | 1089 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. | 1194 // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext. |
1157 USE(cache_array); | 1195 USE(cache_array); |
1158 builder()->ForInPrepare(cache_type); | 1196 builder()->ForInPrepare(cache_type); |
1159 | 1197 |
1160 // Set up loop counter | 1198 // Set up loop counter |
1161 Register index = register_allocator()->NewRegister(); | 1199 Register index = register_allocator()->NewRegister(); |
1162 builder()->LoadLiteral(Smi::FromInt(0)); | 1200 builder()->LoadLiteral(Smi::FromInt(0)); |
1163 builder()->StoreAccumulatorInRegister(index); | 1201 builder()->StoreAccumulatorInRegister(index); |
1164 | 1202 |
1165 // The loop | 1203 // The loop |
1166 loop_builder.LoopHeader(); | 1204 VisitIterationHeader(stmt, &loop_builder); |
1167 builder()->SetExpressionAsStatementPosition(stmt->each()); | 1205 builder()->SetExpressionAsStatementPosition(stmt->each()); |
1168 loop_builder.Condition(); | 1206 loop_builder.Condition(); |
1169 builder()->ForInDone(index, cache_length); | 1207 builder()->ForInDone(index, cache_length); |
1170 loop_builder.BreakIfTrue(); | 1208 loop_builder.BreakIfTrue(); |
1171 DCHECK(Register::AreContiguous(cache_type, cache_array)); | 1209 DCHECK(Register::AreContiguous(cache_type, cache_array)); |
1172 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); | 1210 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); |
1173 builder()->ForInNext(receiver, index, cache_type, feedback_index(slot)); | 1211 builder()->ForInNext(receiver, index, cache_type, feedback_index(slot)); |
1174 loop_builder.ContinueIfUndefined(); | 1212 loop_builder.ContinueIfUndefined(); |
1175 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); | 1213 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); |
1176 VisitIterationBody(stmt, &loop_builder); | 1214 VisitIterationBody(stmt, &loop_builder); |
1177 loop_builder.Next(); | 1215 loop_builder.Next(); |
1178 builder()->ForInStep(index); | 1216 builder()->ForInStep(index); |
1179 builder()->StoreAccumulatorInRegister(index); | 1217 builder()->StoreAccumulatorInRegister(index); |
1180 loop_builder.JumpToHeader(); | 1218 loop_builder.JumpToHeader(); |
1181 loop_builder.EndLoop(); | 1219 loop_builder.EndLoop(); |
1182 builder()->Bind(&subject_null_label); | 1220 builder()->Bind(&subject_null_label); |
1183 builder()->Bind(&subject_undefined_label); | 1221 builder()->Bind(&subject_undefined_label); |
1184 } | 1222 } |
1185 | 1223 |
1186 | 1224 |
1187 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { | 1225 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { |
1188 LoopBuilder loop_builder(builder()); | 1226 LoopBuilder loop_builder(builder()); |
1189 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 1227 ControlScopeForIteration control_scope(this, stmt, &loop_builder); |
1190 | 1228 |
1191 builder()->SetExpressionAsStatementPosition(stmt->assign_iterator()); | 1229 builder()->SetExpressionAsStatementPosition(stmt->assign_iterator()); |
1192 VisitForEffect(stmt->assign_iterator()); | 1230 VisitForEffect(stmt->assign_iterator()); |
1193 | 1231 |
1194 loop_builder.LoopHeader(); | 1232 VisitIterationHeader(stmt, &loop_builder); |
1195 loop_builder.Next(); | 1233 loop_builder.Next(); |
1196 builder()->SetExpressionAsStatementPosition(stmt->next_result()); | 1234 builder()->SetExpressionAsStatementPosition(stmt->next_result()); |
1197 VisitForEffect(stmt->next_result()); | 1235 VisitForEffect(stmt->next_result()); |
1198 VisitForAccumulatorValue(stmt->result_done()); | 1236 VisitForAccumulatorValue(stmt->result_done()); |
1199 loop_builder.BreakIfTrue(); | 1237 loop_builder.BreakIfTrue(); |
1200 | 1238 |
1201 VisitForEffect(stmt->assign_each()); | 1239 VisitForEffect(stmt->assign_each()); |
1202 VisitIterationBody(stmt, &loop_builder); | 1240 VisitIterationBody(stmt, &loop_builder); |
1203 loop_builder.JumpToHeader(); | 1241 loop_builder.JumpToHeader(); |
1204 loop_builder.EndLoop(); | 1242 loop_builder.EndLoop(); |
(...skipping 1021 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2226 .SuspendGenerator(generator) | 2264 .SuspendGenerator(generator) |
2227 .LoadAccumulatorWithRegister(value) | 2265 .LoadAccumulatorWithRegister(value) |
2228 .Return(); // Hard return (ignore any finally blocks). | 2266 .Return(); // Hard return (ignore any finally blocks). |
2229 | 2267 |
2230 builder()->Bind(&(generator_resume_points_[id])); | 2268 builder()->Bind(&(generator_resume_points_[id])); |
2231 // Upon resume, we continue here. | 2269 // Upon resume, we continue here. |
2232 | 2270 |
2233 { | 2271 { |
2234 RegisterAllocationScope register_scope(this); | 2272 RegisterAllocationScope register_scope(this); |
2235 | 2273 |
2274 // Update state to indicate that we have finished resuming. Loop headers | |
2275 // rely on this. | |
2276 builder() | |
2277 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) | |
2278 .StoreAccumulatorInRegister(generator_state_); | |
2279 | |
2236 Register input = register_allocator()->NewRegister(); | 2280 Register input = register_allocator()->NewRegister(); |
2237 builder() | 2281 builder() |
2238 ->CallRuntime(Runtime::kGeneratorGetInput, generator, 1) | 2282 ->CallRuntime(Runtime::kGeneratorGetInput, generator, 1) |
2239 .StoreAccumulatorInRegister(input); | 2283 .StoreAccumulatorInRegister(input); |
2240 | 2284 |
2241 Register resume_mode = register_allocator()->NewRegister(); | 2285 Register resume_mode = register_allocator()->NewRegister(); |
2242 builder() | 2286 builder() |
2243 ->CallRuntime(Runtime::kGeneratorGetResumeMode, generator, 1) | 2287 ->CallRuntime(Runtime::kGeneratorGetResumeMode, generator, 1) |
2244 .StoreAccumulatorInRegister(resume_mode); | 2288 .StoreAccumulatorInRegister(resume_mode); |
2245 | 2289 |
(...skipping 966 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3212 } | 3256 } |
3213 | 3257 |
3214 | 3258 |
3215 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 3259 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
3216 return info()->shared_info()->feedback_vector()->GetIndex(slot); | 3260 return info()->shared_info()->feedback_vector()->GetIndex(slot); |
3217 } | 3261 } |
3218 | 3262 |
3219 } // namespace interpreter | 3263 } // namespace interpreter |
3220 } // namespace internal | 3264 } // namespace internal |
3221 } // namespace v8 | 3265 } // namespace v8 |
OLD | NEW |