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

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

Issue 1884183002: First version of the new generators implementation. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 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 547 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 : isolate_(isolate), 558 : isolate_(isolate),
559 zone_(zone), 559 zone_(zone),
560 builder_(nullptr), 560 builder_(nullptr),
561 info_(nullptr), 561 info_(nullptr),
562 scope_(nullptr), 562 scope_(nullptr),
563 globals_(0, zone), 563 globals_(0, zone),
564 execution_control_(nullptr), 564 execution_control_(nullptr),
565 execution_context_(nullptr), 565 execution_context_(nullptr),
566 execution_result_(nullptr), 566 execution_result_(nullptr),
567 register_allocator_(nullptr), 567 register_allocator_(nullptr),
568 resume_points_(0, zone),
568 try_catch_nesting_level_(0), 569 try_catch_nesting_level_(0),
569 try_finally_nesting_level_(0) { 570 try_finally_nesting_level_(0),
571 yield_count_(0) {
570 InitializeAstVisitor(isolate); 572 InitializeAstVisitor(isolate);
571 } 573 }
572 574
573 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { 575 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
574 set_info(info); 576 set_info(info);
575 set_scope(info->scope()); 577 set_scope(info->scope());
576 578
577 // Initialize bytecode array builder. 579 // Initialize bytecode array builder.
578 set_builder(new (zone()) BytecodeArrayBuilder( 580 set_builder(new (zone()) BytecodeArrayBuilder(
579 isolate(), zone(), info->num_parameters_including_this(), 581 isolate(), zone(), info->num_parameters_including_this(),
580 scope()->MaxNestedContextChainLength(), scope()->num_stack_slots(), 582 scope()->MaxNestedContextChainLength(), scope()->num_stack_slots(),
581 info->literal())); 583 info->literal()));
582 584
583 // Initialize the incoming context. 585 // Initialize the incoming context.
584 ContextScope incoming_context(this, scope(), false); 586 ContextScope incoming_context(this, scope(), false);
585 587
586 // Initialize control scope. 588 // Initialize control scope.
587 ControlScopeForTopLevel control(this); 589 ControlScopeForTopLevel control(this);
588 590
591 if (IsGeneratorFunction(info->literal()->kind())) {
592 BuildGeneratorPrologue();
593 }
594
589 // Build function context only if there are context allocated variables. 595 // Build function context only if there are context allocated variables.
590 if (scope()->NeedsContext()) { 596 if (scope()->NeedsContext()) {
591 // Push a new inner context scope for the function. 597 // Push a new inner context scope for the function.
592 VisitNewLocalFunctionContext(); 598 VisitNewLocalFunctionContext();
593 ContextScope local_function_context(this, scope(), false); 599 ContextScope local_function_context(this, scope(), false);
594 VisitBuildLocalActivationContext(); 600 VisitBuildLocalActivationContext();
595 MakeBytecodeBody(); 601 MakeBytecodeBody();
596 } else { 602 } else {
597 MakeBytecodeBody(); 603 MakeBytecodeBody();
598 } 604 }
(...skipping 28 matching lines...) Expand all
627 // Visit declarations within the function scope. 633 // Visit declarations within the function scope.
628 VisitDeclarations(scope()->declarations()); 634 VisitDeclarations(scope()->declarations());
629 635
630 // Perform a stack-check before the body. 636 // Perform a stack-check before the body.
631 builder()->StackCheck(); 637 builder()->StackCheck();
632 638
633 // Visit statements in the function body. 639 // Visit statements in the function body.
634 VisitStatements(info()->literal()->body()); 640 VisitStatements(info()->literal()->body());
635 } 641 }
636 642
643 void BytecodeGenerator::BuildGeneratorPrologue() {
644 resume_points_.clear();
rmcilroy 2016/04/15 13:17:46 Do we need the clear? it should be empty when we r
neis 2016/04/18 08:04:17 MakeBytecode could be called several times on the
rmcilroy 2016/04/18 10:01:57 No it's only ever used for a single compile info.
neis 2016/04/18 14:07:52 Ok. After your change I can probably initialize it
645 resume_points_.resize(info()->literal()->yield_count());
646
647 BytecodeLabel regular_call;
648 builder()
649 ->LoadAccumulatorWithRegister(Register::new_target())
650 .JumpIfUndefined(&regular_call);
651
652 // This is a resume call. Restore registers and perform state dispatch.
653 // (The current context has already been restored by the trampoline.)
654 {
655 RegisterAllocationScope register_scope(this);
656 Register state = register_allocator()->NewRegister();
657 builder()
658 ->CallRuntime(Runtime::kResumeIgnitionGenerator, Register::new_target(),
659 1)
660 .StoreAccumulatorInRegister(state);
661
662 // TODO(neis): Optimize this by using a proper jump table.
663 for (size_t i = 0; i < resume_points_.size(); ++i) {
664 builder()
665 ->LoadLiteral(Smi::FromInt(static_cast<int>(i)))
666 .CompareOperation(Token::Value::EQ_STRICT, state)
667 .JumpIfTrue(&(resume_points_[i]));
668 }
669 builder()->Illegal(); // Should never get here.
670 }
671
672 builder()->Bind(&regular_call);
673 // This is a regular call. Fall through to the ordinary function prologue,
674 // after which we will run into the generator object creation and the initial
675 // yield (both inserted by the parser).
676 }
637 677
638 void BytecodeGenerator::VisitBlock(Block* stmt) { 678 void BytecodeGenerator::VisitBlock(Block* stmt) {
639 // Visit declarations and statements. 679 // Visit declarations and statements.
640 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) { 680 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) {
641 VisitNewLocalBlockContext(stmt->scope()); 681 VisitNewLocalBlockContext(stmt->scope());
642 ContextScope scope(this, stmt->scope()); 682 ContextScope scope(this, stmt->scope());
643 VisitBlockDeclarationsAndStatements(stmt); 683 VisitBlockDeclarationsAndStatements(stmt);
644 } else { 684 } else {
645 VisitBlockDeclarationsAndStatements(stmt); 685 VisitBlockDeclarationsAndStatements(stmt);
646 } 686 }
(...skipping 1575 matching lines...) Expand 10 before | Expand all | Expand 10 after
2222 } 2262 }
2223 case KEYED_SUPER_PROPERTY: { 2263 case KEYED_SUPER_PROPERTY: {
2224 builder()->StoreAccumulatorInRegister(value); 2264 builder()->StoreAccumulatorInRegister(value);
2225 BuildKeyedSuperPropertyStore(object, home_object, key, value); 2265 BuildKeyedSuperPropertyStore(object, home_object, key, value);
2226 break; 2266 break;
2227 } 2267 }
2228 } 2268 }
2229 execution_result()->SetResultInAccumulator(); 2269 execution_result()->SetResultInAccumulator();
2230 } 2270 }
2231 2271
2272 void BytecodeGenerator::VisitYield(Yield* expr) {
2273 int id = yield_count_++;
rmcilroy 2016/04/15 13:17:46 Rather than doing this id naming implicitly, would
neis 2016/04/18 08:04:17 I don't think that would be safer and I don't see
rmcilroy 2016/04/18 10:01:57 OK. I'm fine with this for this CL, but maybe it's
neis 2016/04/18 14:07:52 OK. Also, I probably need to move them into array
2232 2274
2233 void BytecodeGenerator::VisitYield(Yield* expr) { UNIMPLEMENTED(); } 2275 builder()->SetExpressionPosition(expr);
2276 Register value = VisitForRegisterValue(expr->expression());
rmcilroy 2016/04/15 13:17:46 nit - maybe scope the pre-yield, and post-resume p
neis 2016/04/18 08:04:17 Thanks, I didn't think of that. I added a scope f
2234 2277
2278 register_allocator()->PrepareForConsecutiveAllocations(2);
2279 Register generator = register_allocator()->NextConsecutiveRegister();
2280 Register state = register_allocator()->NextConsecutiveRegister();
2281
2282 // Save context, registers, and state. Then return.
2283 VisitForRegisterValue(expr->generator_object(), generator);
2284 builder()
2285 ->LoadLiteral(Smi::FromInt(id))
2286 .StoreAccumulatorInRegister(state)
2287 .CallRuntime(Runtime::kSuspendIgnitionGenerator, generator, 2)
2288 .LoadAccumulatorWithRegister(value)
2289 .Return(); // Hard return (ignore any finally blocks).
2290
2291 builder()->Bind(&(resume_points_[id]));
2292 // Upon resume, we continue here.
2293
2294 Register input = register_allocator()->NewRegister();
2295 builder()
2296 ->CallRuntime(Runtime::kGeneratorGetInput, generator, 1)
2297 .StoreAccumulatorInRegister(input);
2298
2299 Register resume_mode = register_allocator()->NewRegister();
2300 builder()
2301 ->CallRuntime(Runtime::kGeneratorGetResumeMode, generator, 1)
rmcilroy 2016/04/15 13:17:46 Maybe you could have a runtime function which retu
neis 2016/04/18 08:04:17 Let's keep it as is for now. I think we want to g
rmcilroy 2016/04/18 10:01:57 Acknowledged.
2302 .StoreAccumulatorInRegister(resume_mode);
2303
2304 // Dispatch on resume mode.
2305 {
2306 BytecodeLabel resume_with_next;
2307 BytecodeLabel resume_with_return;
2308 BytecodeLabel resume_with_throw;
2309
2310 builder()
2311 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kReturn))
2312 .CompareOperation(Token::EQ_STRICT, resume_mode)
2313 .JumpIfTrue(&resume_with_return)
2314 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow))
2315 .CompareOperation(Token::EQ_STRICT, resume_mode)
2316 .JumpIfTrue(&resume_with_throw)
2317 .Jump(&resume_with_next);
rmcilroy 2016/04/15 13:17:46 (micro optimization) - presumably JSGeneratorObjec
neis 2016/04/18 08:04:17 Done.
2318
2319 builder()->Bind(&resume_with_return);
2320 {
2321 register_allocator()->PrepareForConsecutiveAllocations(2);
2322 Register value = register_allocator()->NextConsecutiveRegister();
2323 Register done = register_allocator()->NextConsecutiveRegister();
2324 builder()
2325 ->MoveRegister(input, value)
2326 .LoadTrue()
2327 .StoreAccumulatorInRegister(done)
2328 .CallRuntime(Runtime::kCreateIterResultObject, value, 2);
2329 execution_control()->ReturnAccumulator();
2330 }
2331
2332 builder()->Bind(&resume_with_throw);
2333 builder()
2334 ->LoadAccumulatorWithRegister(input)
2335 .Throw();
2336
2337 builder()->Bind(&resume_with_next);
2338 builder()->LoadAccumulatorWithRegister(input);
2339 execution_result()->SetResultInAccumulator();
2340 }
2341 }
2235 2342
2236 void BytecodeGenerator::VisitThrow(Throw* expr) { 2343 void BytecodeGenerator::VisitThrow(Throw* expr) {
2237 VisitForAccumulatorValue(expr->exception()); 2344 VisitForAccumulatorValue(expr->exception());
2238 builder()->SetExpressionPosition(expr); 2345 builder()->SetExpressionPosition(expr);
2239 builder()->Throw(); 2346 builder()->Throw();
2240 // Throw statments are modeled as expression instead of statments. These are 2347 // Throw statements are modeled as expressions instead of statements. These
2241 // converted from assignment statements in Rewriter::ReWrite pass. An 2348 // are converted from assignment statements in Rewriter::ReWrite pass. An
rmcilroy 2016/04/15 13:17:46 Thanks!
2242 // assignment statement expects a value in the accumulator. This is a hack to 2349 // assignment statement expects a value in the accumulator. This is a hack to
2243 // avoid DCHECK fails assert accumulator has been set. 2350 // avoid DCHECK fails assert accumulator has been set.
2244 execution_result()->SetResultInAccumulator(); 2351 execution_result()->SetResultInAccumulator();
2245 } 2352 }
2246 2353
2247 2354
2248 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { 2355 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
2249 LhsKind property_kind = Property::GetAssignType(expr); 2356 LhsKind property_kind = Property::GetAssignType(expr);
2250 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); 2357 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot();
2251 builder()->SetExpressionPosition(expr); 2358 builder()->SetExpressionPosition(expr);
(...skipping 907 matching lines...) Expand 10 before | Expand all | Expand 10 after
3159 } 3266 }
3160 3267
3161 3268
3162 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { 3269 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const {
3163 return info()->shared_info()->feedback_vector()->GetIndex(slot); 3270 return info()->shared_info()->feedback_vector()->GetIndex(slot);
3164 } 3271 }
3165 3272
3166 } // namespace interpreter 3273 } // namespace interpreter
3167 } // namespace internal 3274 } // namespace internal
3168 } // namespace v8 3275 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698