Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Side by Side Diff: src/interpreter/bytecode-generator.cc

Issue 2557173004: [Interpreter] Allocate registers used as call arguments on-demand. (Closed)
Patch Set: Fix release build unused variable Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/bytecode-register.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/code-stubs.h" 9 #include "src/code-stubs.h"
10 #include "src/compilation-info.h" 10 #include "src/compilation-info.h"
(...skipping 2309 matching lines...) Expand 10 before | Expand all | Expand 10 after
2320 } 2320 }
2321 case NAMED_SUPER_PROPERTY: 2321 case NAMED_SUPER_PROPERTY:
2322 VisitNamedSuperPropertyLoad(expr, Register::invalid_value()); 2322 VisitNamedSuperPropertyLoad(expr, Register::invalid_value());
2323 break; 2323 break;
2324 case KEYED_SUPER_PROPERTY: 2324 case KEYED_SUPER_PROPERTY:
2325 VisitKeyedSuperPropertyLoad(expr, Register::invalid_value()); 2325 VisitKeyedSuperPropertyLoad(expr, Register::invalid_value());
2326 break; 2326 break;
2327 } 2327 }
2328 } 2328 }
2329 2329
2330 void BytecodeGenerator::VisitPropertyLoadForAccumulator(Register obj, 2330 void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj,
2331 Property* expr) { 2331 Property* expr,
2332 Register destination) {
2332 ValueResultScope result_scope(this); 2333 ValueResultScope result_scope(this);
2333 VisitPropertyLoad(obj, expr); 2334 VisitPropertyLoad(obj, expr);
2335 builder()->StoreAccumulatorInRegister(destination);
2334 } 2336 }
2335 2337
2336 void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property, 2338 void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property,
2337 Register opt_receiver_out) { 2339 Register opt_receiver_out) {
2338 RegisterAllocationScope register_scope(this); 2340 RegisterAllocationScope register_scope(this);
2339 SuperPropertyReference* super_property = 2341 SuperPropertyReference* super_property =
2340 property->obj()->AsSuperPropertyReference(); 2342 property->obj()->AsSuperPropertyReference();
2341 RegisterList args = register_allocator()->NewRegisterList(3); 2343 RegisterList args = register_allocator()->NewRegisterList(3);
2342 VisitForRegisterValue(super_property->this_var(), args[0]); 2344 VisitForRegisterValue(super_property->this_var(), args[0]);
2343 VisitForRegisterValue(super_property->home_object(), args[1]); 2345 VisitForRegisterValue(super_property->home_object(), args[1]);
(...skipping 28 matching lines...) Expand all
2372 if (property_kind != NAMED_SUPER_PROPERTY && 2374 if (property_kind != NAMED_SUPER_PROPERTY &&
2373 property_kind != KEYED_SUPER_PROPERTY) { 2375 property_kind != KEYED_SUPER_PROPERTY) {
2374 Register obj = VisitForRegisterValue(expr->obj()); 2376 Register obj = VisitForRegisterValue(expr->obj());
2375 VisitPropertyLoad(obj, expr); 2377 VisitPropertyLoad(obj, expr);
2376 } else { 2378 } else {
2377 VisitPropertyLoad(Register::invalid_value(), expr); 2379 VisitPropertyLoad(Register::invalid_value(), expr);
2378 } 2380 }
2379 } 2381 }
2380 2382
2381 void BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args, 2383 void BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args,
2382 RegisterList arg_regs, 2384 RegisterList* arg_regs) {
2383 size_t first_argument_register) {
2384 // Visit arguments. 2385 // Visit arguments.
2385 for (int i = 0; i < static_cast<int>(args->length()); i++) { 2386 for (int i = 0; i < static_cast<int>(args->length()); i++) {
2386 VisitForRegisterValue(args->at(i), arg_regs[first_argument_register + i]); 2387 VisitAndPushIntoRegisterList(args->at(i), arg_regs);
2387 } 2388 }
2388 } 2389 }
2389 2390
2390 void BytecodeGenerator::VisitCall(Call* expr) { 2391 void BytecodeGenerator::VisitCall(Call* expr) {
2391 Expression* callee_expr = expr->expression(); 2392 Expression* callee_expr = expr->expression();
2392 Call::CallType call_type = expr->GetCallType(); 2393 Call::CallType call_type = expr->GetCallType();
2393 2394
2394 if (call_type == Call::SUPER_CALL) { 2395 if (call_type == Call::SUPER_CALL) {
2395 return VisitCallSuper(expr); 2396 return VisitCallSuper(expr);
2396 } 2397 }
2397 2398
2398 Register callee = register_allocator()->NewRegister(); 2399 Register callee = register_allocator()->NewRegister();
2399 2400 // Grow the args list as we visit receiver / arguments to avoid allocating all
2400 // Add an argument register for the receiver. 2401 // the registers up-front. Otherwise these registers are unavailable during
2401 RegisterList args = 2402 // receiver / argument visiting and we can end up with memory leaks due to
2402 register_allocator()->NewRegisterList(expr->arguments()->length() + 1); 2403 // registers keeping objects alive.
2403 Register receiver = args[0]; 2404 RegisterList args = register_allocator()->NewGrowableRegisterList();
2404 2405
2405 // Prepare the callee and the receiver to the function call. This depends on 2406 // Prepare the callee and the receiver to the function call. This depends on
2406 // the semantics of the underlying call type. 2407 // the semantics of the underlying call type.
2407 switch (call_type) { 2408 switch (call_type) {
2408 case Call::NAMED_PROPERTY_CALL: 2409 case Call::NAMED_PROPERTY_CALL:
2409 case Call::KEYED_PROPERTY_CALL: { 2410 case Call::KEYED_PROPERTY_CALL: {
2410 Property* property = callee_expr->AsProperty(); 2411 Property* property = callee_expr->AsProperty();
2411 VisitForAccumulatorValue(property->obj()); 2412 VisitAndPushIntoRegisterList(property->obj(), &args);
2412 builder()->StoreAccumulatorInRegister(receiver); 2413 VisitPropertyLoadForRegister(args[0], property, callee);
2413 VisitPropertyLoadForAccumulator(receiver, property);
2414 builder()->StoreAccumulatorInRegister(callee);
2415 break; 2414 break;
2416 } 2415 }
2417 case Call::GLOBAL_CALL: { 2416 case Call::GLOBAL_CALL: {
2418 // Receiver is undefined for global calls. 2417 // Receiver is undefined for global calls.
2419 builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); 2418 BuildPushUndefinedIntoRegisterList(&args);
2420 // Load callee as a global variable. 2419 // Load callee as a global variable.
2421 VariableProxy* proxy = callee_expr->AsVariableProxy(); 2420 VariableProxy* proxy = callee_expr->AsVariableProxy();
2422 BuildVariableLoadForAccumulatorValue(proxy->var(), 2421 BuildVariableLoadForAccumulatorValue(proxy->var(),
2423 proxy->VariableFeedbackSlot(), 2422 proxy->VariableFeedbackSlot(),
2424 proxy->hole_check_mode()); 2423 proxy->hole_check_mode());
2425 builder()->StoreAccumulatorInRegister(callee); 2424 builder()->StoreAccumulatorInRegister(callee);
2426 break; 2425 break;
2427 } 2426 }
2428 case Call::WITH_CALL: { 2427 case Call::WITH_CALL: {
2428 Register receiver = register_allocator()->GrowRegisterList(&args);
2429 DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot()); 2429 DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot());
2430 RegisterAllocationScope inner_register_scope(this); 2430 {
2431 Register name = register_allocator()->NewRegister(); 2431 RegisterAllocationScope inner_register_scope(this);
2432 Register name = register_allocator()->NewRegister();
2432 2433
2433 // Call %LoadLookupSlotForCall to get the callee and receiver. 2434 // Call %LoadLookupSlotForCall to get the callee and receiver.
2434 DCHECK(Register::AreContiguous(callee, receiver)); 2435 DCHECK(Register::AreContiguous(callee, receiver));
2435 RegisterList result_pair(callee.index(), 2); 2436 RegisterList result_pair(callee.index(), 2);
2436 Variable* variable = callee_expr->AsVariableProxy()->var(); 2437 USE(receiver);
2437 builder() 2438 Variable* variable = callee_expr->AsVariableProxy()->var();
2438 ->LoadLiteral(variable->name()) 2439 builder()
2439 .StoreAccumulatorInRegister(name) 2440 ->LoadLiteral(variable->name())
2440 .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name, 2441 .StoreAccumulatorInRegister(name)
2441 result_pair); 2442 .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name,
2443 result_pair);
2444 }
2442 break; 2445 break;
2443 } 2446 }
2444 case Call::OTHER_CALL: 2447 case Call::OTHER_CALL: {
2445 builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); 2448 BuildPushUndefinedIntoRegisterList(&args);
2446 VisitForRegisterValue(callee_expr, callee); 2449 VisitForRegisterValue(callee_expr, callee);
2447 break; 2450 break;
2451 }
2448 case Call::NAMED_SUPER_PROPERTY_CALL: { 2452 case Call::NAMED_SUPER_PROPERTY_CALL: {
2453 Register receiver = register_allocator()->GrowRegisterList(&args);
2449 Property* property = callee_expr->AsProperty(); 2454 Property* property = callee_expr->AsProperty();
2450 VisitNamedSuperPropertyLoad(property, receiver); 2455 VisitNamedSuperPropertyLoad(property, receiver);
2451 builder()->StoreAccumulatorInRegister(callee); 2456 builder()->StoreAccumulatorInRegister(callee);
2452 break; 2457 break;
2453 } 2458 }
2454 case Call::KEYED_SUPER_PROPERTY_CALL: { 2459 case Call::KEYED_SUPER_PROPERTY_CALL: {
2460 Register receiver = register_allocator()->GrowRegisterList(&args);
2455 Property* property = callee_expr->AsProperty(); 2461 Property* property = callee_expr->AsProperty();
2456 VisitKeyedSuperPropertyLoad(property, receiver); 2462 VisitKeyedSuperPropertyLoad(property, receiver);
2457 builder()->StoreAccumulatorInRegister(callee); 2463 builder()->StoreAccumulatorInRegister(callee);
2458 break; 2464 break;
2459 } 2465 }
2460 case Call::SUPER_CALL: 2466 case Call::SUPER_CALL:
2461 UNREACHABLE(); 2467 UNREACHABLE();
2462 break; 2468 break;
2463 } 2469 }
2464 2470
2465 // Evaluate all arguments to the function call and store in sequential args 2471 // Evaluate all arguments to the function call and store in sequential args
2466 // registers. 2472 // registers.
2467 VisitArguments(expr->arguments(), args, 1); 2473 VisitArguments(expr->arguments(), &args);
2474 CHECK_EQ(expr->arguments()->length() + 1, args.register_count());
2468 2475
2469 // Resolve callee for a potential direct eval call. This block will mutate the 2476 // Resolve callee for a potential direct eval call. This block will mutate the
2470 // callee value. 2477 // callee value.
2471 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) { 2478 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) {
2472 RegisterAllocationScope inner_register_scope(this); 2479 RegisterAllocationScope inner_register_scope(this);
2473 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source 2480 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source
2474 // strings and function closure, and loading language and 2481 // strings and function closure, and loading language and
2475 // position. 2482 // position.
2476 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); 2483 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6);
2477 builder() 2484 builder()
(...skipping 30 matching lines...) Expand all
2508 builder()->CallRuntime(Runtime::kInlineGetSuperConstructor, this_function); 2515 builder()->CallRuntime(Runtime::kInlineGetSuperConstructor, this_function);
2509 2516
2510 Register constructor = this_function; // Re-use dead this_function register. 2517 Register constructor = this_function; // Re-use dead this_function register.
2511 builder()->StoreAccumulatorInRegister(constructor); 2518 builder()->StoreAccumulatorInRegister(constructor);
2512 2519
2513 ZoneList<Expression*>* args = expr->arguments(); 2520 ZoneList<Expression*>* args = expr->arguments();
2514 2521
2515 // When a super call contains a spread, a CallSuper AST node is only created 2522 // When a super call contains a spread, a CallSuper AST node is only created
2516 // if there is exactly one spread, and it is the last argument. 2523 // if there is exactly one spread, and it is the last argument.
2517 if (!args->is_empty() && args->last()->IsSpread()) { 2524 if (!args->is_empty() && args->last()->IsSpread()) {
2518 RegisterList args_regs = 2525 RegisterList args_regs = register_allocator()->NewGrowableRegisterList();
2519 register_allocator()->NewRegisterList(args->length() + 2); 2526 Register constructor_arg =
2520 builder()->MoveRegister(constructor, args_regs[0]); 2527 register_allocator()->GrowRegisterList(&args_regs);
2521 VisitArguments(args, args_regs, 2); 2528 builder()->MoveRegister(constructor, constructor_arg);
2522 VisitForRegisterValue(super->new_target_var(), args_regs[1]); 2529 // Reserve argument reg for new.target in correct place for runtime call.
2530 // TODO(petermarshall): Remove this when changing bytecode to use the new
2531 // stub.
2532 Register new_target = register_allocator()->GrowRegisterList(&args_regs);
2533 VisitArguments(args, &args_regs);
2534 VisitForRegisterValue(super->new_target_var(), new_target);
2523 builder()->NewWithSpread(args_regs); 2535 builder()->NewWithSpread(args_regs);
2524 } else { 2536 } else {
2525 RegisterList args_regs = 2537 RegisterList args_regs = register_allocator()->NewGrowableRegisterList();
2526 register_allocator()->NewRegisterList(args->length()); 2538 VisitArguments(args, &args_regs);
2527 VisitArguments(args, args_regs);
2528 // The new target is loaded into the accumulator from the 2539 // The new target is loaded into the accumulator from the
2529 // {new.target} variable. 2540 // {new.target} variable.
2530 VisitForAccumulatorValue(super->new_target_var()); 2541 VisitForAccumulatorValue(super->new_target_var());
2531 2542
2532 // Call construct. 2543 // Call construct.
2533 builder()->SetExpressionPosition(expr); 2544 builder()->SetExpressionPosition(expr);
2534 // TODO(turbofan): For now we do gather feedback on super constructor 2545 // TODO(turbofan): For now we do gather feedback on super constructor
2535 // calls, utilizing the existing machinery to inline the actual call 2546 // calls, utilizing the existing machinery to inline the actual call
2536 // target and the JSCreate for the implicit receiver allocation. This 2547 // target and the JSCreate for the implicit receiver allocation. This
2537 // is not an ideal solution for super constructor calls, but it gets 2548 // is not an ideal solution for super constructor calls, but it gets
2538 // the job done for now. In the long run we might want to revisit this 2549 // the job done for now. In the long run we might want to revisit this
2539 // and come up with a better way. 2550 // and come up with a better way.
2540 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); 2551 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
2541 builder()->New(constructor, args_regs, feedback_slot_index); 2552 builder()->New(constructor, args_regs, feedback_slot_index);
2542 } 2553 }
2543 } 2554 }
2544 2555
2545 void BytecodeGenerator::VisitCallNew(CallNew* expr) { 2556 void BytecodeGenerator::VisitCallNew(CallNew* expr) {
2546 Register constructor = VisitForRegisterValue(expr->expression()); 2557 Register constructor = VisitForRegisterValue(expr->expression());
2547 RegisterList args = 2558 RegisterList args = register_allocator()->NewGrowableRegisterList();
2548 register_allocator()->NewRegisterList(expr->arguments()->length()); 2559 VisitArguments(expr->arguments(), &args);
2549 VisitArguments(expr->arguments(), args);
2550 2560
2551 builder()->SetExpressionPosition(expr); 2561 builder()->SetExpressionPosition(expr);
2552 // The accumulator holds new target which is the same as the 2562 // The accumulator holds new target which is the same as the
2553 // constructor for CallNew. 2563 // constructor for CallNew.
2554 builder() 2564 builder()
2555 ->LoadAccumulatorWithRegister(constructor) 2565 ->LoadAccumulatorWithRegister(constructor)
2556 .New(constructor, args, feedback_index(expr->CallNewFeedbackSlot())); 2566 .New(constructor, args, feedback_index(expr->CallNewFeedbackSlot()));
2557 } 2567 }
2558 2568
2559 void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { 2569 void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
2560 if (expr->is_jsruntime()) { 2570 if (expr->is_jsruntime()) {
2571 RegisterList args = register_allocator()->NewGrowableRegisterList();
2561 // Allocate a register for the receiver and load it with undefined. 2572 // Allocate a register for the receiver and load it with undefined.
2562 RegisterList args = 2573 BuildPushUndefinedIntoRegisterList(&args);
2563 register_allocator()->NewRegisterList(expr->arguments()->length() + 1); 2574 VisitArguments(expr->arguments(), &args);
2564 Register receiver = args[0];
2565 builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
2566 VisitArguments(expr->arguments(), args, 1);
2567 builder()->CallJSRuntime(expr->context_index(), args); 2575 builder()->CallJSRuntime(expr->context_index(), args);
2568 } else { 2576 } else {
2569 // Evaluate all arguments to the runtime call. 2577 // Evaluate all arguments to the runtime call.
2570 RegisterList args = 2578 RegisterList args = register_allocator()->NewGrowableRegisterList();
2571 register_allocator()->NewRegisterList(expr->arguments()->length()); 2579 VisitArguments(expr->arguments(), &args);
2572 VisitArguments(expr->arguments(), args);
2573 Runtime::FunctionId function_id = expr->function()->function_id; 2580 Runtime::FunctionId function_id = expr->function()->function_id;
2574 builder()->CallRuntime(function_id, args); 2581 builder()->CallRuntime(function_id, args);
2575 } 2582 }
2576 } 2583 }
2577 2584
2578 void BytecodeGenerator::VisitVoid(UnaryOperation* expr) { 2585 void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
2579 VisitForEffect(expr->expression()); 2586 VisitForEffect(expr->expression());
2580 builder()->LoadUndefined(); 2587 builder()->LoadUndefined();
2581 } 2588 }
2582 2589
(...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after
3203 3210
3204 // Visits the expression |expr| and stores the expression result in 3211 // Visits the expression |expr| and stores the expression result in
3205 // |destination|. 3212 // |destination|.
3206 void BytecodeGenerator::VisitForRegisterValue(Expression* expr, 3213 void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
3207 Register destination) { 3214 Register destination) {
3208 ValueResultScope register_scope(this); 3215 ValueResultScope register_scope(this);
3209 Visit(expr); 3216 Visit(expr);
3210 builder()->StoreAccumulatorInRegister(destination); 3217 builder()->StoreAccumulatorInRegister(destination);
3211 } 3218 }
3212 3219
3220 // Visits the expression |expr| and pushes the result into a new register
3221 // added to the end of |reg_list|.
3222 void BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr,
3223 RegisterList* reg_list) {
3224 {
3225 ValueResultScope register_scope(this);
3226 Visit(expr);
3227 }
3228 // Grow the register list after visiting the expression to avoid reserving
3229 // the register across the expression evaluation, which could cause memory
3230 // leaks for deep expressions due to dead objects being kept alive by pointers
3231 // in registers.
3232 Register destination = register_allocator()->GrowRegisterList(reg_list);
3233 builder()->StoreAccumulatorInRegister(destination);
3234 }
3235
3236 void BytecodeGenerator::BuildPushUndefinedIntoRegisterList(
3237 RegisterList* reg_list) {
3238 Register reg = register_allocator()->GrowRegisterList(reg_list);
3239 builder()->LoadUndefined().StoreAccumulatorInRegister(reg);
3240 }
3241
3213 // Visits the expression |expr| for testing its boolean value and jumping to the 3242 // Visits the expression |expr| for testing its boolean value and jumping to the
3214 // |then| or |other| label depending on value and short-circuit semantics 3243 // |then| or |other| label depending on value and short-circuit semantics
3215 void BytecodeGenerator::VisitForTest(Expression* expr, 3244 void BytecodeGenerator::VisitForTest(Expression* expr,
3216 BytecodeLabels* then_labels, 3245 BytecodeLabels* then_labels,
3217 BytecodeLabels* else_labels, 3246 BytecodeLabels* else_labels,
3218 TestFallthrough fallthrough) { 3247 TestFallthrough fallthrough) {
3219 bool result_consumed; 3248 bool result_consumed;
3220 { 3249 {
3221 // To make sure that all temporary registers are returned before generating 3250 // To make sure that all temporary registers are returned before generating
3222 // jumps below, we ensure that the result scope is deleted before doing so. 3251 // jumps below, we ensure that the result scope is deleted before doing so.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
3260 } 3289 }
3261 3290
3262 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { 3291 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() {
3263 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict 3292 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict
3264 : Runtime::kStoreKeyedToSuper_Sloppy; 3293 : Runtime::kStoreKeyedToSuper_Sloppy;
3265 } 3294 }
3266 3295
3267 } // namespace interpreter 3296 } // namespace interpreter
3268 } // namespace internal 3297 } // namespace internal
3269 } // namespace v8 3298 } // namespace v8
OLDNEW
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/bytecode-register.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698