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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/bytecode-register.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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,
« 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