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 547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 generator_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 generator_yields_seen_(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 VisitGeneratorPrologue(); | |
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 Loading... | |
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::VisitGeneratorPrologue() { | |
644 generator_resume_points_.clear(); | |
645 generator_resume_points_.resize(info()->literal()->yield_count()); | |
646 | |
647 BytecodeLabel regular_call; | |
648 builder() | |
649 ->LoadAccumulatorWithRegister(Register::new_target()) | |
650 .JumpIfUndefined(®ular_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 < generator_resume_points_.size(); ++i) { | |
664 builder() | |
665 ->LoadLiteral(Smi::FromInt(static_cast<int>(i))) | |
666 .CompareOperation(Token::Value::EQ_STRICT, state) | |
667 .JumpIfTrue(&(generator_resume_points_[i])); | |
668 } | |
669 builder()->Illegal(); // Should never get here. | |
670 } | |
671 | |
672 builder()->Bind(®ular_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 Loading... | |
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 = generator_yields_seen_++; | |
2232 | 2274 |
2233 void BytecodeGenerator::VisitYield(Yield* expr) { UNIMPLEMENTED(); } | 2275 builder()->SetExpressionPosition(expr); |
2276 Register value = VisitForRegisterValue(expr->expression()); | |
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(&(generator_resume_points_[id])); | |
2292 // Upon resume, we continue here. | |
2293 | |
2294 { | |
2295 RegisterAllocationScope register_scope(this); | |
2296 | |
2297 Register input = register_allocator()->NewRegister(); | |
2298 builder() | |
2299 ->CallRuntime(Runtime::kGeneratorGetInput, generator, 1) | |
2300 .StoreAccumulatorInRegister(input); | |
2301 | |
2302 Register resume_mode = register_allocator()->NewRegister(); | |
2303 builder() | |
2304 ->CallRuntime(Runtime::kGeneratorGetResumeMode, generator, 1) | |
2305 .StoreAccumulatorInRegister(resume_mode); | |
2306 | |
2307 // Now dispatch on resume mode. | |
2308 | |
2309 BytecodeLabel resume_with_next; | |
2310 BytecodeLabel resume_with_return; | |
2311 BytecodeLabel resume_with_throw; | |
2312 | |
2313 builder() | |
2314 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) | |
2315 .CompareOperation(Token::EQ_STRICT, resume_mode) | |
2316 .JumpIfTrue(&resume_with_next) | |
2317 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) | |
2318 .CompareOperation(Token::EQ_STRICT, resume_mode) | |
2319 .JumpIfTrue(&resume_with_throw) | |
2320 .Jump(&resume_with_return); | |
Jarin
2016/04/18 13:55:06
Out of curiosity, do you even need the Jump?
neis
2016/04/18 14:07:52
Shhh :)
| |
2321 | |
2322 builder()->Bind(&resume_with_return); | |
2323 { | |
2324 register_allocator()->PrepareForConsecutiveAllocations(2); | |
2325 Register value = register_allocator()->NextConsecutiveRegister(); | |
2326 Register done = register_allocator()->NextConsecutiveRegister(); | |
2327 builder() | |
2328 ->MoveRegister(input, value) | |
2329 .LoadTrue() | |
2330 .StoreAccumulatorInRegister(done) | |
2331 .CallRuntime(Runtime::kCreateIterResultObject, value, 2); | |
2332 execution_control()->ReturnAccumulator(); | |
2333 } | |
2334 | |
2335 builder()->Bind(&resume_with_throw); | |
2336 builder() | |
2337 ->LoadAccumulatorWithRegister(input) | |
2338 .Throw(); | |
2339 | |
2340 builder()->Bind(&resume_with_next); | |
2341 builder()->LoadAccumulatorWithRegister(input); | |
2342 } | |
2343 execution_result()->SetResultInAccumulator(); | |
2344 } | |
2235 | 2345 |
2236 void BytecodeGenerator::VisitThrow(Throw* expr) { | 2346 void BytecodeGenerator::VisitThrow(Throw* expr) { |
2237 VisitForAccumulatorValue(expr->exception()); | 2347 VisitForAccumulatorValue(expr->exception()); |
2238 builder()->SetExpressionPosition(expr); | 2348 builder()->SetExpressionPosition(expr); |
2239 builder()->Throw(); | 2349 builder()->Throw(); |
2240 // Throw statments are modeled as expression instead of statments. These are | 2350 // Throw statements are modeled as expressions instead of statements. These |
2241 // converted from assignment statements in Rewriter::ReWrite pass. An | 2351 // are converted from assignment statements in Rewriter::ReWrite pass. An |
2242 // assignment statement expects a value in the accumulator. This is a hack to | 2352 // assignment statement expects a value in the accumulator. This is a hack to |
2243 // avoid DCHECK fails assert accumulator has been set. | 2353 // avoid DCHECK fails assert accumulator has been set. |
2244 execution_result()->SetResultInAccumulator(); | 2354 execution_result()->SetResultInAccumulator(); |
2245 } | 2355 } |
2246 | 2356 |
2247 | 2357 |
2248 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { | 2358 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { |
2249 LhsKind property_kind = Property::GetAssignType(expr); | 2359 LhsKind property_kind = Property::GetAssignType(expr); |
2250 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); | 2360 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); |
2251 builder()->SetExpressionPosition(expr); | 2361 builder()->SetExpressionPosition(expr); |
(...skipping 908 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3160 } | 3270 } |
3161 | 3271 |
3162 | 3272 |
3163 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 3273 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
3164 return info()->shared_info()->feedback_vector()->GetIndex(slot); | 3274 return info()->shared_info()->feedback_vector()->GetIndex(slot); |
3165 } | 3275 } |
3166 | 3276 |
3167 } // namespace interpreter | 3277 } // namespace interpreter |
3168 } // namespace internal | 3278 } // namespace internal |
3169 } // namespace v8 | 3279 } // namespace v8 |
OLD | NEW |