 Chromium Code Reviews
 Chromium Code Reviews Issue 2629363002:
  [Ignition/turbo] Add a CallWithSpread bytecode.  (Closed)
    
  
    Issue 2629363002:
  [Ignition/turbo] Add a CallWithSpread bytecode.  (Closed) 
  | 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->arguments()->is_empty() && expr->arguments()->last()->IsSpread()) { | |
| 
rmcilroy
2017/01/16 10:29:40
Could you pull this out to a boolean and reuse it
 
petermarshall
2017/01/16 15:01:10
Yes I like it on the Call Expression (and CallNew)
 | |
| 2425 args = register_allocator()->NewGrowableRegisterList(); | |
| 2426 callee = register_allocator()->GrowRegisterList(&args); | |
| 2427 } else { | |
| 2428 callee = register_allocator()->NewRegister(); | |
| 2429 args = register_allocator()->NewGrowableRegisterList(); | |
| 2430 } | |
| 2424 | 2431 | 
| 2425 // Prepare the callee and the receiver to the function call. This depends on | 2432 // Prepare the callee and the receiver to the function call. This depends on | 
| 2426 // the semantics of the underlying call type. | 2433 // the semantics of the underlying call type. | 
| 2427 switch (call_type) { | 2434 switch (call_type) { | 
| 2428 case Call::NAMED_PROPERTY_CALL: | 2435 case Call::NAMED_PROPERTY_CALL: | 
| 2429 case Call::KEYED_PROPERTY_CALL: { | 2436 case Call::KEYED_PROPERTY_CALL: { | 
| 2430 Property* property = callee_expr->AsProperty(); | 2437 Property* property = callee_expr->AsProperty(); | 
| 2431 VisitAndPushIntoRegisterList(property->obj(), &args); | 2438 VisitAndPushIntoRegisterList(property->obj(), &args); | 
| 2432 VisitPropertyLoadForRegister(args[0], property, callee); | 2439 VisitPropertyLoadForRegister(args.last_register(), property, callee); | 
| 2433 break; | 2440 break; | 
| 2434 } | 2441 } | 
| 2435 case Call::GLOBAL_CALL: { | 2442 case Call::GLOBAL_CALL: { | 
| 2436 // Receiver is undefined for global calls. | 2443 // Receiver is undefined for global calls. | 
| 2437 BuildPushUndefinedIntoRegisterList(&args); | 2444 BuildPushUndefinedIntoRegisterList(&args); | 
| 2438 // Load callee as a global variable. | 2445 // Load callee as a global variable. | 
| 2439 VariableProxy* proxy = callee_expr->AsVariableProxy(); | 2446 VariableProxy* proxy = callee_expr->AsVariableProxy(); | 
| 2440 BuildVariableLoadForAccumulatorValue(proxy->var(), | 2447 BuildVariableLoadForAccumulatorValue(proxy->var(), | 
| 2441 proxy->VariableFeedbackSlot(), | 2448 proxy->VariableFeedbackSlot(), | 
| 2442 proxy->hole_check_mode()); | 2449 proxy->hole_check_mode()); | 
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2483 break; | 2490 break; | 
| 2484 } | 2491 } | 
| 2485 case Call::SUPER_CALL: | 2492 case Call::SUPER_CALL: | 
| 2486 UNREACHABLE(); | 2493 UNREACHABLE(); | 
| 2487 break; | 2494 break; | 
| 2488 } | 2495 } | 
| 2489 | 2496 | 
| 2490 // Evaluate all arguments to the function call and store in sequential args | 2497 // Evaluate all arguments to the function call and store in sequential args | 
| 2491 // registers. | 2498 // registers. | 
| 2492 VisitArguments(expr->arguments(), &args); | 2499 VisitArguments(expr->arguments(), &args); | 
| 2493 CHECK_EQ(expr->arguments()->length() + 1, args.register_count()); | |
| 
rmcilroy
2017/01/16 10:29:40
Please leave this DCHECK in for non spread calls (
 
petermarshall
2017/01/16 15:01:10
Yep, Done.
 | |
| 2494 | 2500 | 
| 2495 // Resolve callee for a potential direct eval call. This block will mutate the | 2501 // Resolve callee for a potential direct eval call. This block will mutate the | 
| 2496 // callee value. | 2502 // callee value. | 
| 2497 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { | 2503 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { | 
| 2498 RegisterAllocationScope inner_register_scope(this); | 2504 RegisterAllocationScope inner_register_scope(this); | 
| 2499 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source | 2505 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source | 
| 2500 // strings and function closure, and loading language and | 2506 // strings and function closure, and loading language and | 
| 2501 // position. | 2507 // position. | 
| 2502 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); | 2508 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); | 
| 2503 builder() | 2509 builder() | 
| 2504 ->MoveRegister(callee, runtime_call_args[0]) | 2510 ->MoveRegister(callee, runtime_call_args[0]) | 
| 2505 .MoveRegister(args[1], runtime_call_args[1]) | 2511 .MoveRegister(args[1], runtime_call_args[1]) | 
| 2506 .MoveRegister(Register::function_closure(), runtime_call_args[2]) | 2512 .MoveRegister(Register::function_closure(), runtime_call_args[2]) | 
| 2507 .LoadLiteral(Smi::FromInt(language_mode())) | 2513 .LoadLiteral(Smi::FromInt(language_mode())) | 
| 2508 .StoreAccumulatorInRegister(runtime_call_args[3]) | 2514 .StoreAccumulatorInRegister(runtime_call_args[3]) | 
| 2509 .LoadLiteral( | 2515 .LoadLiteral( | 
| 2510 Smi::FromInt(execution_context()->scope()->start_position())) | 2516 Smi::FromInt(execution_context()->scope()->start_position())) | 
| 2511 .StoreAccumulatorInRegister(runtime_call_args[4]) | 2517 .StoreAccumulatorInRegister(runtime_call_args[4]) | 
| 2512 .LoadLiteral(Smi::FromInt(expr->position())) | 2518 .LoadLiteral(Smi::FromInt(expr->position())) | 
| 2513 .StoreAccumulatorInRegister(runtime_call_args[5]); | 2519 .StoreAccumulatorInRegister(runtime_call_args[5]); | 
| 2514 | 2520 | 
| 2515 // Call ResolvePossiblyDirectEval and modify the callee. | 2521 // Call ResolvePossiblyDirectEval and modify the callee. | 
| 2516 builder() | 2522 builder() | 
| 2517 ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) | 2523 ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) | 
| 2518 .StoreAccumulatorInRegister(callee); | 2524 .StoreAccumulatorInRegister(callee); | 
| 2519 } | 2525 } | 
| 2520 | 2526 | 
| 2521 builder()->SetExpressionPosition(expr); | 2527 builder()->SetExpressionPosition(expr); | 
| 2522 | 2528 | 
| 2523 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); | 2529 // 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, | 2530 // exactly one spread, and it is the last argument. | 
| 2525 expr->tail_call_mode()); | 2531 if (!expr->arguments()->is_empty() && expr->arguments()->last()->IsSpread()) { | 
| 2532 CHECK_EQ(expr->arguments()->length() + 2, args.register_count()); | |
| 2533 DCHECK_EQ(expr->tail_call_mode(), TailCallMode::kDisallow); | |
| 
Benedikt Meurer
2017/01/14 18:37:14
Nit: DCHECK_EQ(TailCallMode::kDisallow, ...)
 
petermarshall
2017/01/16 15:01:10
Done.
 | |
| 2534 builder()->CallWithSpread(args); | |
| 
rmcilroy
2017/01/16 10:29:40
The issue with this is that we already have a Call
 
petermarshall
2017/01/16 15:01:10
Yeah I think that suggestion makes sense - added a
 | |
| 2535 } else { | |
| 2536 CHECK_EQ(expr->arguments()->length() + 1, args.register_count()); | |
| 2537 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); | |
| 2538 builder()->Call(callee, args, feedback_slot_index, call_type, | |
| 2539 expr->tail_call_mode()); | |
| 2540 } | |
| 2526 } | 2541 } | 
| 2527 | 2542 | 
| 2528 void BytecodeGenerator::VisitCallSuper(Call* expr) { | 2543 void BytecodeGenerator::VisitCallSuper(Call* expr) { | 
| 2529 RegisterAllocationScope register_scope(this); | 2544 RegisterAllocationScope register_scope(this); | 
| 2530 SuperCallReference* super = expr->expression()->AsSuperCallReference(); | 2545 SuperCallReference* super = expr->expression()->AsSuperCallReference(); | 
| 2531 | 2546 | 
| 2532 // Prepare the constructor to the super call. | 2547 // Prepare the constructor to the super call. | 
| 2533 VisitForAccumulatorValue(super->this_function_var()); | 2548 VisitForAccumulatorValue(super->this_function_var()); | 
| 2534 Register constructor = register_allocator()->NewRegister(); | 2549 Register constructor = register_allocator()->NewRegister(); | 
| 2535 builder()->GetSuperConstructor(constructor); | 2550 builder()->GetSuperConstructor(constructor); | 
| (...skipping 785 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3321 } | 3336 } | 
| 3322 | 3337 | 
| 3323 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 3338 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { | 
| 3324 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 3339 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict | 
| 3325 : Runtime::kStoreKeyedToSuper_Sloppy; | 3340 : Runtime::kStoreKeyedToSuper_Sloppy; | 
| 3326 } | 3341 } | 
| 3327 | 3342 | 
| 3328 } // namespace interpreter | 3343 } // namespace interpreter | 
| 3329 } // namespace internal | 3344 } // namespace internal | 
| 3330 } // namespace v8 | 3345 } // namespace v8 | 
| OLD | NEW |