| 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 2444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2455 } | 2455 } |
| 2456 | 2456 |
| 2457 void BytecodeGenerator::VisitCall(Call* expr) { | 2457 void BytecodeGenerator::VisitCall(Call* expr) { |
| 2458 Expression* callee_expr = expr->expression(); | 2458 Expression* callee_expr = expr->expression(); |
| 2459 Call::CallType call_type = expr->GetCallType(); | 2459 Call::CallType call_type = expr->GetCallType(); |
| 2460 | 2460 |
| 2461 if (call_type == Call::SUPER_CALL) { | 2461 if (call_type == Call::SUPER_CALL) { |
| 2462 return VisitCallSuper(expr); | 2462 return VisitCallSuper(expr); |
| 2463 } | 2463 } |
| 2464 | 2464 |
| 2465 Register callee = register_allocator()->NewRegister(); |
| 2465 // Grow the args list as we visit receiver / arguments to avoid allocating all | 2466 // Grow the args list as we visit receiver / arguments to avoid allocating all |
| 2466 // the registers up-front. Otherwise these registers are unavailable during | 2467 // the registers up-front. Otherwise these registers are unavailable during |
| 2467 // receiver / argument visiting and we can end up with memory leaks due to | 2468 // receiver / argument visiting and we can end up with memory leaks due to |
| 2468 // registers keeping objects alive. | 2469 // registers keeping objects alive. |
| 2469 RegisterList args; | 2470 RegisterList args = register_allocator()->NewGrowableRegisterList(); |
| 2470 Register callee; | |
| 2471 // The CallWithSpread bytecode takes all arguments in a register list so that | |
| 2472 // it can easily call into a runtime function for its implementation. This | |
| 2473 // will change once CallWithSpread has an implementation in ASM. | |
| 2474 // TODO(petermarshall): Remove this special path when CallWithSpread is done. | |
| 2475 if (expr->only_last_arg_is_spread()) { | |
| 2476 args = register_allocator()->NewGrowableRegisterList(); | |
| 2477 callee = register_allocator()->GrowRegisterList(&args); | |
| 2478 } else { | |
| 2479 callee = register_allocator()->NewRegister(); | |
| 2480 args = register_allocator()->NewGrowableRegisterList(); | |
| 2481 } | |
| 2482 | |
| 2483 // TODO(petermarshall): We have a lot of call bytecodes that are very similar, | |
| 2484 // see if we can reduce the number by adding a separate argument which | |
| 2485 // specifies the call type (e.g., property, spread, tailcall, etc.). | |
| 2486 | 2471 |
| 2487 // Prepare the callee and the receiver to the function call. This depends on | 2472 // Prepare the callee and the receiver to the function call. This depends on |
| 2488 // the semantics of the underlying call type. | 2473 // the semantics of the underlying call type. |
| 2489 switch (call_type) { | 2474 switch (call_type) { |
| 2490 case Call::NAMED_PROPERTY_CALL: | 2475 case Call::NAMED_PROPERTY_CALL: |
| 2491 case Call::KEYED_PROPERTY_CALL: { | 2476 case Call::KEYED_PROPERTY_CALL: { |
| 2492 Property* property = callee_expr->AsProperty(); | 2477 Property* property = callee_expr->AsProperty(); |
| 2493 VisitAndPushIntoRegisterList(property->obj(), &args); | 2478 VisitAndPushIntoRegisterList(property->obj(), &args); |
| 2494 VisitPropertyLoadForRegister(args.last_register(), property, callee); | 2479 VisitPropertyLoadForRegister(args[0], property, callee); |
| 2495 break; | 2480 break; |
| 2496 } | 2481 } |
| 2497 case Call::GLOBAL_CALL: { | 2482 case Call::GLOBAL_CALL: { |
| 2498 // Receiver is undefined for global calls. | 2483 // Receiver is undefined for global calls. |
| 2499 BuildPushUndefinedIntoRegisterList(&args); | 2484 BuildPushUndefinedIntoRegisterList(&args); |
| 2500 // Load callee as a global variable. | 2485 // Load callee as a global variable. |
| 2501 VariableProxy* proxy = callee_expr->AsVariableProxy(); | 2486 VariableProxy* proxy = callee_expr->AsVariableProxy(); |
| 2502 BuildVariableLoadForAccumulatorValue(proxy->var(), | 2487 BuildVariableLoadForAccumulatorValue(proxy->var(), |
| 2503 proxy->VariableFeedbackSlot(), | 2488 proxy->VariableFeedbackSlot(), |
| 2504 proxy->hole_check_mode()); | 2489 proxy->hole_check_mode()); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2545 break; | 2530 break; |
| 2546 } | 2531 } |
| 2547 case Call::SUPER_CALL: | 2532 case Call::SUPER_CALL: |
| 2548 UNREACHABLE(); | 2533 UNREACHABLE(); |
| 2549 break; | 2534 break; |
| 2550 } | 2535 } |
| 2551 | 2536 |
| 2552 // Evaluate all arguments to the function call and store in sequential args | 2537 // Evaluate all arguments to the function call and store in sequential args |
| 2553 // registers. | 2538 // registers. |
| 2554 VisitArguments(expr->arguments(), &args); | 2539 VisitArguments(expr->arguments(), &args); |
| 2555 // TODO(petermarshall): Check this for spread calls as well when | 2540 CHECK_EQ(expr->arguments()->length() + 1, args.register_count()); |
| 2556 // CallWithSpread is done. | |
| 2557 if (!expr->only_last_arg_is_spread()) { | |
| 2558 CHECK_EQ(expr->arguments()->length() + 1, args.register_count()); | |
| 2559 } | |
| 2560 | 2541 |
| 2561 // Resolve callee for a potential direct eval call. This block will mutate the | 2542 // Resolve callee for a potential direct eval call. This block will mutate the |
| 2562 // callee value. | 2543 // callee value. |
| 2563 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { | 2544 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { |
| 2564 RegisterAllocationScope inner_register_scope(this); | 2545 RegisterAllocationScope inner_register_scope(this); |
| 2565 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source | 2546 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source |
| 2566 // strings and function closure, and loading language and | 2547 // strings and function closure, and loading language and |
| 2567 // position. | 2548 // position. |
| 2568 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); | 2549 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); |
| 2569 builder() | 2550 builder() |
| 2570 ->MoveRegister(callee, runtime_call_args[0]) | 2551 ->MoveRegister(callee, runtime_call_args[0]) |
| 2571 .MoveRegister(args[1], runtime_call_args[1]) | 2552 .MoveRegister(args[1], runtime_call_args[1]) |
| 2572 .MoveRegister(Register::function_closure(), runtime_call_args[2]) | 2553 .MoveRegister(Register::function_closure(), runtime_call_args[2]) |
| 2573 .LoadLiteral(Smi::FromInt(language_mode())) | 2554 .LoadLiteral(Smi::FromInt(language_mode())) |
| 2574 .StoreAccumulatorInRegister(runtime_call_args[3]) | 2555 .StoreAccumulatorInRegister(runtime_call_args[3]) |
| 2575 .LoadLiteral( | 2556 .LoadLiteral( |
| 2576 Smi::FromInt(execution_context()->scope()->start_position())) | 2557 Smi::FromInt(execution_context()->scope()->start_position())) |
| 2577 .StoreAccumulatorInRegister(runtime_call_args[4]) | 2558 .StoreAccumulatorInRegister(runtime_call_args[4]) |
| 2578 .LoadLiteral(Smi::FromInt(expr->position())) | 2559 .LoadLiteral(Smi::FromInt(expr->position())) |
| 2579 .StoreAccumulatorInRegister(runtime_call_args[5]); | 2560 .StoreAccumulatorInRegister(runtime_call_args[5]); |
| 2580 | 2561 |
| 2581 // Call ResolvePossiblyDirectEval and modify the callee. | 2562 // Call ResolvePossiblyDirectEval and modify the callee. |
| 2582 builder() | 2563 builder() |
| 2583 ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) | 2564 ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) |
| 2584 .StoreAccumulatorInRegister(callee); | 2565 .StoreAccumulatorInRegister(callee); |
| 2585 } | 2566 } |
| 2586 | 2567 |
| 2587 builder()->SetExpressionPosition(expr); | 2568 builder()->SetExpressionPosition(expr); |
| 2588 | 2569 |
| 2589 // When a call contains a spread, a Call AST node is only created if there is | 2570 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); |
| 2590 // exactly one spread, and it is the last argument. | 2571 builder()->Call(callee, args, feedback_slot_index, call_type, |
| 2591 if (expr->only_last_arg_is_spread()) { | 2572 expr->tail_call_mode()); |
| 2592 CHECK_EQ(expr->arguments()->length() + 2, args.register_count()); | |
| 2593 DCHECK_EQ(TailCallMode::kDisallow, expr->tail_call_mode()); | |
| 2594 builder()->CallWithSpread(args); | |
| 2595 } else { | |
| 2596 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); | |
| 2597 builder()->Call(callee, args, feedback_slot_index, call_type, | |
| 2598 expr->tail_call_mode()); | |
| 2599 } | |
| 2600 } | 2573 } |
| 2601 | 2574 |
| 2602 void BytecodeGenerator::VisitCallSuper(Call* expr) { | 2575 void BytecodeGenerator::VisitCallSuper(Call* expr) { |
| 2603 RegisterAllocationScope register_scope(this); | 2576 RegisterAllocationScope register_scope(this); |
| 2604 SuperCallReference* super = expr->expression()->AsSuperCallReference(); | 2577 SuperCallReference* super = expr->expression()->AsSuperCallReference(); |
| 2605 | 2578 |
| 2606 // Prepare the constructor to the super call. | 2579 // Prepare the constructor to the super call. |
| 2607 VisitForAccumulatorValue(super->this_function_var()); | 2580 VisitForAccumulatorValue(super->this_function_var()); |
| 2608 Register constructor = register_allocator()->NewRegister(); | 2581 Register constructor = register_allocator()->NewRegister(); |
| 2609 builder()->GetSuperConstructor(constructor); | 2582 builder()->GetSuperConstructor(constructor); |
| 2610 | 2583 |
| 2611 ZoneList<Expression*>* args = expr->arguments(); | 2584 ZoneList<Expression*>* args = expr->arguments(); |
| 2612 RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); | 2585 RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); |
| 2613 VisitArguments(args, &args_regs); | 2586 VisitArguments(args, &args_regs); |
| 2614 // The new target is loaded into the accumulator from the | 2587 // The new target is loaded into the accumulator from the |
| 2615 // {new.target} variable. | 2588 // {new.target} variable. |
| 2616 VisitForAccumulatorValue(super->new_target_var()); | 2589 VisitForAccumulatorValue(super->new_target_var()); |
| 2617 builder()->SetExpressionPosition(expr); | 2590 builder()->SetExpressionPosition(expr); |
| 2618 | 2591 |
| 2619 // When a super call contains a spread, a CallSuper AST node is only created | 2592 // When a super call contains a spread, a CallSuper AST node is only created |
| 2620 // if there is exactly one spread, and it is the last argument. | 2593 // if there is exactly one spread, and it is the last argument. |
| 2621 if (expr->only_last_arg_is_spread()) { | 2594 if (!args->is_empty() && args->last()->IsSpread()) { |
| 2622 // TODO(petermarshall): Collect type on the feedback slot. | 2595 // TODO(petermarshall): Collect type on the feedback slot. |
| 2623 builder()->NewWithSpread(constructor, args_regs); | 2596 builder()->NewWithSpread(constructor, args_regs); |
| 2624 } else { | 2597 } else { |
| 2625 // Call construct. | 2598 // Call construct. |
| 2626 // TODO(turbofan): For now we do gather feedback on super constructor | 2599 // TODO(turbofan): For now we do gather feedback on super constructor |
| 2627 // calls, utilizing the existing machinery to inline the actual call | 2600 // calls, utilizing the existing machinery to inline the actual call |
| 2628 // target and the JSCreate for the implicit receiver allocation. This | 2601 // target and the JSCreate for the implicit receiver allocation. This |
| 2629 // is not an ideal solution for super constructor calls, but it gets | 2602 // is not an ideal solution for super constructor calls, but it gets |
| 2630 // the job done for now. In the long run we might want to revisit this | 2603 // the job done for now. In the long run we might want to revisit this |
| 2631 // and come up with a better way. | 2604 // and come up with a better way. |
| 2632 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); | 2605 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); |
| 2633 builder()->New(constructor, args_regs, feedback_slot_index); | 2606 builder()->New(constructor, args_regs, feedback_slot_index); |
| 2634 } | 2607 } |
| 2635 } | 2608 } |
| 2636 | 2609 |
| 2637 void BytecodeGenerator::VisitCallNew(CallNew* expr) { | 2610 void BytecodeGenerator::VisitCallNew(CallNew* expr) { |
| 2638 Register constructor = VisitForRegisterValue(expr->expression()); | 2611 Register constructor = VisitForRegisterValue(expr->expression()); |
| 2639 RegisterList args = register_allocator()->NewGrowableRegisterList(); | 2612 RegisterList args = register_allocator()->NewGrowableRegisterList(); |
| 2640 VisitArguments(expr->arguments(), &args); | 2613 VisitArguments(expr->arguments(), &args); |
| 2641 | 2614 |
| 2615 builder()->SetExpressionPosition(expr); |
| 2642 // The accumulator holds new target which is the same as the | 2616 // The accumulator holds new target which is the same as the |
| 2643 // constructor for CallNew. | 2617 // constructor for CallNew. |
| 2644 builder()->SetExpressionPosition(expr); | 2618 builder() |
| 2645 builder()->LoadAccumulatorWithRegister(constructor); | 2619 ->LoadAccumulatorWithRegister(constructor) |
| 2646 | 2620 .New(constructor, args, feedback_index(expr->CallNewFeedbackSlot())); |
| 2647 if (expr->only_last_arg_is_spread()) { | |
| 2648 // TODO(petermarshall): Collect type on the feedback slot. | |
| 2649 builder()->NewWithSpread(constructor, args); | |
| 2650 } else { | |
| 2651 builder()->New(constructor, args, | |
| 2652 feedback_index(expr->CallNewFeedbackSlot())); | |
| 2653 } | |
| 2654 } | 2621 } |
| 2655 | 2622 |
| 2656 void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 2623 void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 2657 if (expr->is_jsruntime()) { | 2624 if (expr->is_jsruntime()) { |
| 2658 RegisterList args = register_allocator()->NewGrowableRegisterList(); | 2625 RegisterList args = register_allocator()->NewGrowableRegisterList(); |
| 2659 // Allocate a register for the receiver and load it with undefined. | 2626 // Allocate a register for the receiver and load it with undefined. |
| 2660 BuildPushUndefinedIntoRegisterList(&args); | 2627 BuildPushUndefinedIntoRegisterList(&args); |
| 2661 VisitArguments(expr->arguments(), &args); | 2628 VisitArguments(expr->arguments(), &args); |
| 2662 builder()->CallJSRuntime(expr->context_index(), args); | 2629 builder()->CallJSRuntime(expr->context_index(), args); |
| 2663 } else { | 2630 } else { |
| (...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3391 } | 3358 } |
| 3392 | 3359 |
| 3393 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 3360 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { |
| 3394 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 3361 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict |
| 3395 : Runtime::kStoreKeyedToSuper_Sloppy; | 3362 : Runtime::kStoreKeyedToSuper_Sloppy; |
| 3396 } | 3363 } |
| 3397 | 3364 |
| 3398 } // namespace interpreter | 3365 } // namespace interpreter |
| 3399 } // namespace internal | 3366 } // namespace internal |
| 3400 } // namespace v8 | 3367 } // namespace v8 |
| OLD | NEW |