| Index: src/interpreter/bytecode-generator.cc
|
| diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
|
| index 7130d5204fd453af6f4b6c0598ddc71f7a67455b..2748007f97d3e2cb48a416073732b150a6a36c37 100644
|
| --- a/src/interpreter/bytecode-generator.cc
|
| +++ b/src/interpreter/bytecode-generator.cc
|
| @@ -2327,10 +2327,12 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
|
| }
|
| }
|
|
|
| -void BytecodeGenerator::VisitPropertyLoadForAccumulator(Register obj,
|
| - Property* expr) {
|
| +void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj,
|
| + Property* expr,
|
| + Register destination) {
|
| ValueResultScope result_scope(this);
|
| VisitPropertyLoad(obj, expr);
|
| + builder()->StoreAccumulatorInRegister(destination);
|
| }
|
|
|
| void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property,
|
| @@ -2379,11 +2381,10 @@ void BytecodeGenerator::VisitProperty(Property* expr) {
|
| }
|
|
|
| void BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args,
|
| - RegisterList arg_regs,
|
| - size_t first_argument_register) {
|
| + RegisterList* arg_regs) {
|
| // Visit arguments.
|
| for (int i = 0; i < static_cast<int>(args->length()); i++) {
|
| - VisitForRegisterValue(args->at(i), arg_regs[first_argument_register + i]);
|
| + VisitAndPushIntoRegisterList(args->at(i), arg_regs);
|
| }
|
| }
|
|
|
| @@ -2396,11 +2397,11 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
| }
|
|
|
| Register callee = register_allocator()->NewRegister();
|
| -
|
| - // Add an argument register for the receiver.
|
| - RegisterList args =
|
| - register_allocator()->NewRegisterList(expr->arguments()->length() + 1);
|
| - Register receiver = args[0];
|
| + // Grow the args list as we visit receiver / arguments to avoid allocating all
|
| + // the registers up-front. Otherwise these registers are unavailable during
|
| + // receiver / argument visiting and we can end up with memory leaks due to
|
| + // registers keeping objects alive.
|
| + RegisterList args = register_allocator()->NewGrowableRegisterList();
|
|
|
| // Prepare the callee and the receiver to the function call. This depends on
|
| // the semantics of the underlying call type.
|
| @@ -2408,15 +2409,13 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
| case Call::NAMED_PROPERTY_CALL:
|
| case Call::KEYED_PROPERTY_CALL: {
|
| Property* property = callee_expr->AsProperty();
|
| - VisitForAccumulatorValue(property->obj());
|
| - builder()->StoreAccumulatorInRegister(receiver);
|
| - VisitPropertyLoadForAccumulator(receiver, property);
|
| - builder()->StoreAccumulatorInRegister(callee);
|
| + VisitAndPushIntoRegisterList(property->obj(), &args);
|
| + VisitPropertyLoadForRegister(args[0], property, callee);
|
| break;
|
| }
|
| case Call::GLOBAL_CALL: {
|
| // Receiver is undefined for global calls.
|
| - builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
|
| + BuildPushUndefinedIntoRegisterList(&args);
|
| // Load callee as a global variable.
|
| VariableProxy* proxy = callee_expr->AsVariableProxy();
|
| BuildVariableLoadForAccumulatorValue(proxy->var(),
|
| @@ -2426,32 +2425,39 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
| break;
|
| }
|
| case Call::WITH_CALL: {
|
| + Register receiver = register_allocator()->GrowRegisterList(&args);
|
| DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot());
|
| - RegisterAllocationScope inner_register_scope(this);
|
| - Register name = register_allocator()->NewRegister();
|
| -
|
| - // Call %LoadLookupSlotForCall to get the callee and receiver.
|
| - DCHECK(Register::AreContiguous(callee, receiver));
|
| - RegisterList result_pair(callee.index(), 2);
|
| - Variable* variable = callee_expr->AsVariableProxy()->var();
|
| - builder()
|
| - ->LoadLiteral(variable->name())
|
| - .StoreAccumulatorInRegister(name)
|
| - .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name,
|
| - result_pair);
|
| + {
|
| + RegisterAllocationScope inner_register_scope(this);
|
| + Register name = register_allocator()->NewRegister();
|
| +
|
| + // Call %LoadLookupSlotForCall to get the callee and receiver.
|
| + DCHECK(Register::AreContiguous(callee, receiver));
|
| + RegisterList result_pair(callee.index(), 2);
|
| + USE(receiver);
|
| + Variable* variable = callee_expr->AsVariableProxy()->var();
|
| + builder()
|
| + ->LoadLiteral(variable->name())
|
| + .StoreAccumulatorInRegister(name)
|
| + .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name,
|
| + result_pair);
|
| + }
|
| break;
|
| }
|
| - case Call::OTHER_CALL:
|
| - builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
|
| + case Call::OTHER_CALL: {
|
| + BuildPushUndefinedIntoRegisterList(&args);
|
| VisitForRegisterValue(callee_expr, callee);
|
| break;
|
| + }
|
| case Call::NAMED_SUPER_PROPERTY_CALL: {
|
| + Register receiver = register_allocator()->GrowRegisterList(&args);
|
| Property* property = callee_expr->AsProperty();
|
| VisitNamedSuperPropertyLoad(property, receiver);
|
| builder()->StoreAccumulatorInRegister(callee);
|
| break;
|
| }
|
| case Call::KEYED_SUPER_PROPERTY_CALL: {
|
| + Register receiver = register_allocator()->GrowRegisterList(&args);
|
| Property* property = callee_expr->AsProperty();
|
| VisitKeyedSuperPropertyLoad(property, receiver);
|
| builder()->StoreAccumulatorInRegister(callee);
|
| @@ -2464,7 +2470,8 @@ void BytecodeGenerator::VisitCall(Call* expr) {
|
|
|
| // Evaluate all arguments to the function call and store in sequential args
|
| // registers.
|
| - VisitArguments(expr->arguments(), args, 1);
|
| + VisitArguments(expr->arguments(), &args);
|
| + CHECK_EQ(expr->arguments()->length() + 1, args.register_count());
|
|
|
| // Resolve callee for a potential direct eval call. This block will mutate the
|
| // callee value.
|
| @@ -2515,16 +2522,20 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
|
| // When a super call contains a spread, a CallSuper AST node is only created
|
| // if there is exactly one spread, and it is the last argument.
|
| if (!args->is_empty() && args->last()->IsSpread()) {
|
| - RegisterList args_regs =
|
| - register_allocator()->NewRegisterList(args->length() + 2);
|
| - builder()->MoveRegister(constructor, args_regs[0]);
|
| - VisitArguments(args, args_regs, 2);
|
| - VisitForRegisterValue(super->new_target_var(), args_regs[1]);
|
| + RegisterList args_regs = register_allocator()->NewGrowableRegisterList();
|
| + Register constructor_arg =
|
| + register_allocator()->GrowRegisterList(&args_regs);
|
| + builder()->MoveRegister(constructor, constructor_arg);
|
| + // Reserve argument reg for new.target in correct place for runtime call.
|
| + // TODO(petermarshall): Remove this when changing bytecode to use the new
|
| + // stub.
|
| + Register new_target = register_allocator()->GrowRegisterList(&args_regs);
|
| + VisitArguments(args, &args_regs);
|
| + VisitForRegisterValue(super->new_target_var(), new_target);
|
| builder()->NewWithSpread(args_regs);
|
| } else {
|
| - RegisterList args_regs =
|
| - register_allocator()->NewRegisterList(args->length());
|
| - VisitArguments(args, args_regs);
|
| + RegisterList args_regs = register_allocator()->NewGrowableRegisterList();
|
| + VisitArguments(args, &args_regs);
|
| // The new target is loaded into the accumulator from the
|
| // {new.target} variable.
|
| VisitForAccumulatorValue(super->new_target_var());
|
| @@ -2544,9 +2555,8 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
|
|
|
| void BytecodeGenerator::VisitCallNew(CallNew* expr) {
|
| Register constructor = VisitForRegisterValue(expr->expression());
|
| - RegisterList args =
|
| - register_allocator()->NewRegisterList(expr->arguments()->length());
|
| - VisitArguments(expr->arguments(), args);
|
| + RegisterList args = register_allocator()->NewGrowableRegisterList();
|
| + VisitArguments(expr->arguments(), &args);
|
|
|
| builder()->SetExpressionPosition(expr);
|
| // The accumulator holds new target which is the same as the
|
| @@ -2558,18 +2568,15 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) {
|
|
|
| void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
| if (expr->is_jsruntime()) {
|
| + RegisterList args = register_allocator()->NewGrowableRegisterList();
|
| // Allocate a register for the receiver and load it with undefined.
|
| - RegisterList args =
|
| - register_allocator()->NewRegisterList(expr->arguments()->length() + 1);
|
| - Register receiver = args[0];
|
| - builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
|
| - VisitArguments(expr->arguments(), args, 1);
|
| + BuildPushUndefinedIntoRegisterList(&args);
|
| + VisitArguments(expr->arguments(), &args);
|
| builder()->CallJSRuntime(expr->context_index(), args);
|
| } else {
|
| // Evaluate all arguments to the runtime call.
|
| - RegisterList args =
|
| - register_allocator()->NewRegisterList(expr->arguments()->length());
|
| - VisitArguments(expr->arguments(), args);
|
| + RegisterList args = register_allocator()->NewGrowableRegisterList();
|
| + VisitArguments(expr->arguments(), &args);
|
| Runtime::FunctionId function_id = expr->function()->function_id;
|
| builder()->CallRuntime(function_id, args);
|
| }
|
| @@ -3210,6 +3217,28 @@ void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
|
| builder()->StoreAccumulatorInRegister(destination);
|
| }
|
|
|
| +// Visits the expression |expr| and pushes the result into a new register
|
| +// added to the end of |reg_list|.
|
| +void BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr,
|
| + RegisterList* reg_list) {
|
| + {
|
| + ValueResultScope register_scope(this);
|
| + Visit(expr);
|
| + }
|
| + // Grow the register list after visiting the expression to avoid reserving
|
| + // the register across the expression evaluation, which could cause memory
|
| + // leaks for deep expressions due to dead objects being kept alive by pointers
|
| + // in registers.
|
| + Register destination = register_allocator()->GrowRegisterList(reg_list);
|
| + builder()->StoreAccumulatorInRegister(destination);
|
| +}
|
| +
|
| +void BytecodeGenerator::BuildPushUndefinedIntoRegisterList(
|
| + RegisterList* reg_list) {
|
| + Register reg = register_allocator()->GrowRegisterList(reg_list);
|
| + builder()->LoadUndefined().StoreAccumulatorInRegister(reg);
|
| +}
|
| +
|
| // Visits the expression |expr| for testing its boolean value and jumping to the
|
| // |then| or |other| label depending on value and short-circuit semantics
|
| void BytecodeGenerator::VisitForTest(Expression* expr,
|
|
|