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