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, |