Chromium Code Reviews| 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 |