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 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 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::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(®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 < 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(®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 = 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 Loading... | |
| 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 |
| OLD | NEW |