Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/interpreter/bytecode-generator.cc

Issue 1901713003: [generators] Perform state dispatch in loop header. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Make Windows happy Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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(&not_resuming);
676 BuildIndexedJump(generator_state_, generator_yields_seen_,
677 stmt->yield_count(), generator_resume_points_);
678 builder()->Bind(&not_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(&regular_call); 688 .JumpIfUndefined(&regular_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(&regular_call); 698 builder()->Bind(&regular_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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698