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/compile-time-value.h" | 7 #include "src/ast/compile-time-value.h" |
| 8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
| 9 #include "src/builtins/builtins-constructor.h" | 9 #include "src/builtins/builtins-constructor.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 2397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2408 } | 2408 } |
| 2409 | 2409 |
| 2410 void BytecodeGenerator::VisitCall(Call* expr) { | 2410 void BytecodeGenerator::VisitCall(Call* expr) { |
| 2411 Expression* callee_expr = expr->expression(); | 2411 Expression* callee_expr = expr->expression(); |
| 2412 Call::CallType call_type = expr->GetCallType(); | 2412 Call::CallType call_type = expr->GetCallType(); |
| 2413 | 2413 |
| 2414 if (call_type == Call::SUPER_CALL) { | 2414 if (call_type == Call::SUPER_CALL) { |
| 2415 return VisitCallSuper(expr); | 2415 return VisitCallSuper(expr); |
| 2416 } | 2416 } |
| 2417 | 2417 |
| 2418 Register callee = register_allocator()->NewRegister(); | |
| 2419 // Grow the args list as we visit receiver / arguments to avoid allocating all | 2418 // Grow the args list as we visit receiver / arguments to avoid allocating all |
| 2420 // the registers up-front. Otherwise these registers are unavailable during | 2419 // the registers up-front. Otherwise these registers are unavailable during |
| 2421 // receiver / argument visiting and we can end up with memory leaks due to | 2420 // receiver / argument visiting and we can end up with memory leaks due to |
| 2422 // registers keeping objects alive. | 2421 // registers keeping objects alive. |
| 2423 RegisterList args = register_allocator()->NewGrowableRegisterList(); | 2422 RegisterList args; |
| 2423 Register callee; | |
| 2424 if (expr->only_last_arg_is_spread()) { | |
| 2425 args = register_allocator()->NewGrowableRegisterList(); | |
|
rmcilroy
2017/01/16 16:04:35
nit - could you add a comment on why this is diffe
petermarshall
2017/01/17 08:39:38
Done
| |
| 2426 callee = register_allocator()->GrowRegisterList(&args); | |
| 2427 } else { | |
| 2428 callee = register_allocator()->NewRegister(); | |
| 2429 args = register_allocator()->NewGrowableRegisterList(); | |
| 2430 } | |
| 2431 | |
| 2432 // TODO(petermarshall): We have a lot of call bytecodes that are very similar, | |
| 2433 // see if we can reduce the number by adding a separate argument which | |
| 2434 // specifies the call type (e.g., property, spread, tailcall, etc.). | |
| 2424 | 2435 |
| 2425 // Prepare the callee and the receiver to the function call. This depends on | 2436 // Prepare the callee and the receiver to the function call. This depends on |
| 2426 // the semantics of the underlying call type. | 2437 // the semantics of the underlying call type. |
| 2427 switch (call_type) { | 2438 switch (call_type) { |
| 2428 case Call::NAMED_PROPERTY_CALL: | 2439 case Call::NAMED_PROPERTY_CALL: |
| 2429 case Call::KEYED_PROPERTY_CALL: { | 2440 case Call::KEYED_PROPERTY_CALL: { |
| 2430 Property* property = callee_expr->AsProperty(); | 2441 Property* property = callee_expr->AsProperty(); |
| 2431 VisitAndPushIntoRegisterList(property->obj(), &args); | 2442 VisitAndPushIntoRegisterList(property->obj(), &args); |
| 2432 VisitPropertyLoadForRegister(args[0], property, callee); | 2443 VisitPropertyLoadForRegister(args.last_register(), property, callee); |
| 2433 break; | 2444 break; |
| 2434 } | 2445 } |
| 2435 case Call::GLOBAL_CALL: { | 2446 case Call::GLOBAL_CALL: { |
| 2436 // Receiver is undefined for global calls. | 2447 // Receiver is undefined for global calls. |
| 2437 BuildPushUndefinedIntoRegisterList(&args); | 2448 BuildPushUndefinedIntoRegisterList(&args); |
| 2438 // Load callee as a global variable. | 2449 // Load callee as a global variable. |
| 2439 VariableProxy* proxy = callee_expr->AsVariableProxy(); | 2450 VariableProxy* proxy = callee_expr->AsVariableProxy(); |
| 2440 BuildVariableLoadForAccumulatorValue(proxy->var(), | 2451 BuildVariableLoadForAccumulatorValue(proxy->var(), |
| 2441 proxy->VariableFeedbackSlot(), | 2452 proxy->VariableFeedbackSlot(), |
| 2442 proxy->hole_check_mode()); | 2453 proxy->hole_check_mode()); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2483 break; | 2494 break; |
| 2484 } | 2495 } |
| 2485 case Call::SUPER_CALL: | 2496 case Call::SUPER_CALL: |
| 2486 UNREACHABLE(); | 2497 UNREACHABLE(); |
| 2487 break; | 2498 break; |
| 2488 } | 2499 } |
| 2489 | 2500 |
| 2490 // Evaluate all arguments to the function call and store in sequential args | 2501 // Evaluate all arguments to the function call and store in sequential args |
| 2491 // registers. | 2502 // registers. |
| 2492 VisitArguments(expr->arguments(), &args); | 2503 VisitArguments(expr->arguments(), &args); |
| 2493 CHECK_EQ(expr->arguments()->length() + 1, args.register_count()); | 2504 if (!expr->only_last_arg_is_spread()) { |
| 2505 CHECK_EQ(expr->arguments()->length() + 1, args.register_count()); | |
|
rmcilroy
2017/01/16 16:04:35
nit - please add a TODO to check this for spread c
petermarshall
2017/01/17 08:39:39
Done
| |
| 2506 } | |
| 2494 | 2507 |
| 2495 // Resolve callee for a potential direct eval call. This block will mutate the | 2508 // Resolve callee for a potential direct eval call. This block will mutate the |
| 2496 // callee value. | 2509 // callee value. |
| 2497 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { | 2510 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { |
| 2498 RegisterAllocationScope inner_register_scope(this); | 2511 RegisterAllocationScope inner_register_scope(this); |
| 2499 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source | 2512 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source |
| 2500 // strings and function closure, and loading language and | 2513 // strings and function closure, and loading language and |
| 2501 // position. | 2514 // position. |
| 2502 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); | 2515 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); |
| 2503 builder() | 2516 builder() |
| 2504 ->MoveRegister(callee, runtime_call_args[0]) | 2517 ->MoveRegister(callee, runtime_call_args[0]) |
| 2505 .MoveRegister(args[1], runtime_call_args[1]) | 2518 .MoveRegister(args[1], runtime_call_args[1]) |
| 2506 .MoveRegister(Register::function_closure(), runtime_call_args[2]) | 2519 .MoveRegister(Register::function_closure(), runtime_call_args[2]) |
| 2507 .LoadLiteral(Smi::FromInt(language_mode())) | 2520 .LoadLiteral(Smi::FromInt(language_mode())) |
| 2508 .StoreAccumulatorInRegister(runtime_call_args[3]) | 2521 .StoreAccumulatorInRegister(runtime_call_args[3]) |
| 2509 .LoadLiteral( | 2522 .LoadLiteral( |
| 2510 Smi::FromInt(execution_context()->scope()->start_position())) | 2523 Smi::FromInt(execution_context()->scope()->start_position())) |
| 2511 .StoreAccumulatorInRegister(runtime_call_args[4]) | 2524 .StoreAccumulatorInRegister(runtime_call_args[4]) |
| 2512 .LoadLiteral(Smi::FromInt(expr->position())) | 2525 .LoadLiteral(Smi::FromInt(expr->position())) |
| 2513 .StoreAccumulatorInRegister(runtime_call_args[5]); | 2526 .StoreAccumulatorInRegister(runtime_call_args[5]); |
| 2514 | 2527 |
| 2515 // Call ResolvePossiblyDirectEval and modify the callee. | 2528 // Call ResolvePossiblyDirectEval and modify the callee. |
| 2516 builder() | 2529 builder() |
| 2517 ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) | 2530 ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) |
| 2518 .StoreAccumulatorInRegister(callee); | 2531 .StoreAccumulatorInRegister(callee); |
| 2519 } | 2532 } |
| 2520 | 2533 |
| 2521 builder()->SetExpressionPosition(expr); | 2534 builder()->SetExpressionPosition(expr); |
| 2522 | 2535 |
| 2523 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); | 2536 // When a call contains a spread, a Call AST node is only created if there is |
| 2524 builder()->Call(callee, args, feedback_slot_index, call_type, | 2537 // exactly one spread, and it is the last argument. |
| 2525 expr->tail_call_mode()); | 2538 if (expr->only_last_arg_is_spread()) { |
| 2539 CHECK_EQ(expr->arguments()->length() + 2, args.register_count()); | |
| 2540 DCHECK_EQ(TailCallMode::kDisallow, expr->tail_call_mode()); | |
| 2541 builder()->CallWithSpread(args); | |
|
rmcilroy
2017/01/16 16:04:35
Please add a test to test-bytecode-generator which
petermarshall
2017/01/17 08:39:39
Done
| |
| 2542 } else { | |
| 2543 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); | |
| 2544 builder()->Call(callee, args, feedback_slot_index, call_type, | |
| 2545 expr->tail_call_mode()); | |
| 2546 } | |
| 2526 } | 2547 } |
| 2527 | 2548 |
| 2528 void BytecodeGenerator::VisitCallSuper(Call* expr) { | 2549 void BytecodeGenerator::VisitCallSuper(Call* expr) { |
| 2529 RegisterAllocationScope register_scope(this); | 2550 RegisterAllocationScope register_scope(this); |
| 2530 SuperCallReference* super = expr->expression()->AsSuperCallReference(); | 2551 SuperCallReference* super = expr->expression()->AsSuperCallReference(); |
| 2531 | 2552 |
| 2532 // Prepare the constructor to the super call. | 2553 // Prepare the constructor to the super call. |
| 2533 VisitForAccumulatorValue(super->this_function_var()); | 2554 VisitForAccumulatorValue(super->this_function_var()); |
| 2534 Register constructor = register_allocator()->NewRegister(); | 2555 Register constructor = register_allocator()->NewRegister(); |
| 2535 builder()->GetSuperConstructor(constructor); | 2556 builder()->GetSuperConstructor(constructor); |
| 2536 | 2557 |
| 2537 ZoneList<Expression*>* args = expr->arguments(); | |
| 2538 | |
| 2539 // When a super call contains a spread, a CallSuper AST node is only created | 2558 // When a super call contains a spread, a CallSuper AST node is only created |
| 2540 // if there is exactly one spread, and it is the last argument. | 2559 // if there is exactly one spread, and it is the last argument. |
| 2541 if (!args->is_empty() && args->last()->IsSpread()) { | 2560 if (expr->only_last_arg_is_spread()) { |
| 2542 RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); | 2561 RegisterList args = register_allocator()->NewGrowableRegisterList(); |
| 2543 Register constructor_arg = | 2562 Register constructor_arg = register_allocator()->GrowRegisterList(&args); |
| 2544 register_allocator()->GrowRegisterList(&args_regs); | |
| 2545 builder()->MoveRegister(constructor, constructor_arg); | 2563 builder()->MoveRegister(constructor, constructor_arg); |
| 2546 // Reserve argument reg for new.target in correct place for runtime call. | 2564 // Reserve argument reg for new.target in correct place for runtime call. |
| 2547 // TODO(petermarshall): Remove this when changing bytecode to use the new | 2565 // TODO(petermarshall): Remove this when changing bytecode to use the new |
| 2548 // stub. | 2566 // stub. |
| 2549 Register new_target = register_allocator()->GrowRegisterList(&args_regs); | 2567 Register new_target = register_allocator()->GrowRegisterList(&args); |
| 2550 VisitArguments(args, &args_regs); | 2568 VisitArguments(expr->arguments(), &args); |
| 2551 VisitForRegisterValue(super->new_target_var(), new_target); | 2569 VisitForRegisterValue(super->new_target_var(), new_target); |
| 2552 builder()->NewWithSpread(args_regs); | 2570 builder()->NewWithSpread(args); |
| 2553 } else { | 2571 } else { |
| 2554 RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); | 2572 RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); |
| 2555 VisitArguments(args, &args_regs); | 2573 VisitArguments(expr->arguments(), &args_regs); |
| 2556 // The new target is loaded into the accumulator from the | 2574 // The new target is loaded into the accumulator from the |
| 2557 // {new.target} variable. | 2575 // {new.target} variable. |
| 2558 VisitForAccumulatorValue(super->new_target_var()); | 2576 VisitForAccumulatorValue(super->new_target_var()); |
| 2559 | 2577 |
| 2560 // Call construct. | 2578 // Call construct. |
| 2561 builder()->SetExpressionPosition(expr); | 2579 builder()->SetExpressionPosition(expr); |
| 2562 // TODO(turbofan): For now we do gather feedback on super constructor | 2580 // TODO(turbofan): For now we do gather feedback on super constructor |
| 2563 // calls, utilizing the existing machinery to inline the actual call | 2581 // calls, utilizing the existing machinery to inline the actual call |
| 2564 // target and the JSCreate for the implicit receiver allocation. This | 2582 // target and the JSCreate for the implicit receiver allocation. This |
| 2565 // is not an ideal solution for super constructor calls, but it gets | 2583 // is not an ideal solution for super constructor calls, but it gets |
| 2566 // the job done for now. In the long run we might want to revisit this | 2584 // the job done for now. In the long run we might want to revisit this |
| 2567 // and come up with a better way. | 2585 // and come up with a better way. |
| 2568 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); | 2586 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); |
| 2569 builder()->New(constructor, args_regs, feedback_slot_index); | 2587 builder()->New(constructor, args_regs, feedback_slot_index); |
| 2570 } | 2588 } |
| 2571 } | 2589 } |
| 2572 | 2590 |
| 2573 void BytecodeGenerator::VisitCallNew(CallNew* expr) { | 2591 void BytecodeGenerator::VisitCallNew(CallNew* expr) { |
| 2574 Register constructor = VisitForRegisterValue(expr->expression()); | 2592 Register constructor = VisitForRegisterValue(expr->expression()); |
| 2575 RegisterList args = register_allocator()->NewGrowableRegisterList(); | 2593 RegisterList args = register_allocator()->NewGrowableRegisterList(); |
| 2576 VisitArguments(expr->arguments(), &args); | |
| 2577 | 2594 |
| 2578 builder()->SetExpressionPosition(expr); | 2595 if (expr->only_last_arg_is_spread()) { |
| 2579 // The accumulator holds new target which is the same as the | 2596 Register constructor_arg = register_allocator()->GrowRegisterList(&args); |
| 2580 // constructor for CallNew. | 2597 Register new_target = register_allocator()->GrowRegisterList(&args); |
| 2581 builder() | 2598 |
| 2582 ->LoadAccumulatorWithRegister(constructor) | 2599 builder() |
| 2583 .New(constructor, args, feedback_index(expr->CallNewFeedbackSlot())); | 2600 ->MoveRegister(constructor, constructor_arg) |
| 2601 .MoveRegister(constructor, new_target); | |
| 2602 VisitArguments(expr->arguments(), &args); | |
| 2603 | |
| 2604 builder()->SetExpressionPosition(expr); | |
| 2605 builder()->NewWithSpread(args); | |
| 2606 } else { | |
| 2607 VisitArguments(expr->arguments(), &args); | |
| 2608 | |
| 2609 builder()->SetExpressionPosition(expr); | |
| 2610 // The accumulator holds new target which is the same as the | |
| 2611 // constructor for CallNew. | |
| 2612 builder() | |
| 2613 ->LoadAccumulatorWithRegister(constructor) | |
| 2614 .New(constructor, args, feedback_index(expr->CallNewFeedbackSlot())); | |
| 2615 } | |
|
rmcilroy
2017/01/16 16:04:35
This seems like an unrelated change, could you do
petermarshall
2017/01/17 08:39:39
I thought about that but it is actually quite diff
rmcilroy
2017/01/17 10:11:31
I see, in that case I'm fine with it being here, b
| |
| 2584 } | 2616 } |
| 2585 | 2617 |
| 2586 void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 2618 void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 2587 if (expr->is_jsruntime()) { | 2619 if (expr->is_jsruntime()) { |
| 2588 RegisterList args = register_allocator()->NewGrowableRegisterList(); | 2620 RegisterList args = register_allocator()->NewGrowableRegisterList(); |
| 2589 // Allocate a register for the receiver and load it with undefined. | 2621 // Allocate a register for the receiver and load it with undefined. |
| 2590 BuildPushUndefinedIntoRegisterList(&args); | 2622 BuildPushUndefinedIntoRegisterList(&args); |
| 2591 VisitArguments(expr->arguments(), &args); | 2623 VisitArguments(expr->arguments(), &args); |
| 2592 builder()->CallJSRuntime(expr->context_index(), args); | 2624 builder()->CallJSRuntime(expr->context_index(), args); |
| 2593 } else { | 2625 } else { |
| (...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3321 } | 3353 } |
| 3322 | 3354 |
| 3323 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 3355 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { |
| 3324 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 3356 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict |
| 3325 : Runtime::kStoreKeyedToSuper_Sloppy; | 3357 : Runtime::kStoreKeyedToSuper_Sloppy; |
| 3326 } | 3358 } |
| 3327 | 3359 |
| 3328 } // namespace interpreter | 3360 } // namespace interpreter |
| 3329 } // namespace internal | 3361 } // namespace internal |
| 3330 } // namespace v8 | 3362 } // namespace v8 |
| OLD | NEW |