Index: src/interpreter/bytecode-generator.cc |
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
index 7c7f23eb6d8eb5def098fd17493ab58cc358cdab..847eaa880c6b5cc268510078c06d521c38d9469a 100644 |
--- a/src/interpreter/bytecode-generator.cc |
+++ b/src/interpreter/bytecode-generator.cc |
@@ -4,8 +4,6 @@ |
#include "src/interpreter/bytecode-generator.h" |
-#include <stack> |
- |
#include "src/compiler.h" |
#include "src/interpreter/control-flow-builders.h" |
#include "src/objects.h" |
@@ -146,6 +144,123 @@ void BytecodeGenerator::ControlScope::PerformCommand(Command command, |
} |
+// Scoped base class for determining where the result of an expression |
+// is stored. |
+class BytecodeGenerator::ExpressionResultScope { |
+ public: |
+ ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind) |
+ : generator_(generator), |
+ kind_(kind), |
+ outer_(generator->execution_result()), |
+ allocator_(builder()), |
+ result_identified_(false) { |
+ generator_->set_execution_result(this); |
+ } |
+ |
+ virtual ~ExpressionResultScope() { |
+ generator_->set_execution_result(outer_); |
+ DCHECK(result_identified()); |
+ } |
+ |
+ bool IsEffect() const { return kind_ == Expression::kEffect; } |
+ bool IsValue() const { return kind_ == Expression::kValue; } |
+ |
+ virtual void SetResultInAccumulator() = 0; |
+ virtual void SetResultInRegister(Register reg) = 0; |
+ |
+ BytecodeGenerator* generator() const { return generator_; } |
+ BytecodeArrayBuilder* builder() const { return generator()->builder(); } |
+ ExpressionResultScope* outer() const { return outer_; } |
+ |
+ Register NewRegister() { return allocator_.NewRegister(); } |
+ |
+ void PrepareForConsecutiveAllocations(size_t count) { |
+ allocator_.PrepareForConsecutiveAllocations(count); |
+ } |
+ |
+ Register NextConsecutiveRegister() { |
+ return allocator_.NextConsecutiveRegister(); |
+ } |
+ |
+ protected: |
+ void set_result_identified() { |
+ DCHECK(!result_identified()); |
+ result_identified_ = true; |
+ } |
+ |
+ bool result_identified() const { return result_identified_; } |
+ |
+ private: |
+ BytecodeGenerator* generator_; |
+ Expression::Context kind_; |
+ ExpressionResultScope* outer_; |
+ TemporaryRegisterScope allocator_; |
+ bool result_identified_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); |
+}; |
+ |
+ |
+// Scoped class used when the result of the current expression is not |
+// expected to produce a result. |
+class BytecodeGenerator::EffectResultScope final |
+ : public ExpressionResultScope { |
+ public: |
+ explicit EffectResultScope(BytecodeGenerator* generator) |
+ : ExpressionResultScope(generator, Expression::kEffect) { |
+ set_result_identified(); |
+ } |
+ |
+ virtual void SetResultInAccumulator() {} |
+ virtual void SetResultInRegister(Register reg) {} |
+}; |
+ |
+ |
+// Scoped class used when the result of the current expression to be |
+// evaluated should go into the interpreter's accumulator register. |
+class BytecodeGenerator::AccumulatorResultScope final |
+ : public ExpressionResultScope { |
+ public: |
+ explicit AccumulatorResultScope(BytecodeGenerator* generator) |
+ : ExpressionResultScope(generator, Expression::kValue) {} |
+ |
+ virtual void SetResultInAccumulator() { set_result_identified(); } |
+ |
+ virtual void SetResultInRegister(Register reg) { |
+ builder()->LoadAccumulatorWithRegister(reg); |
+ set_result_identified(); |
+ } |
+}; |
+ |
+ |
+// Scoped class used when the result of the current expression to be |
+// evaluated should go into an interpreter register. |
+class BytecodeGenerator::RegisterResultScope final |
+ : public ExpressionResultScope { |
+ public: |
+ explicit RegisterResultScope(BytecodeGenerator* generator) |
+ : ExpressionResultScope(generator, Expression::kValue) {} |
+ |
+ virtual void SetResultInAccumulator() { |
+ result_register_ = outer()->NewRegister(); |
+ builder()->StoreAccumulatorInRegister(result_register_); |
+ set_result_identified(); |
+ } |
+ |
+ virtual void SetResultInRegister(Register reg) { |
+ DCHECK(builder()->RegisterIsParameterOrLocal(reg) || |
+ builder()->RegisterIsTemporary(reg)); |
+ result_register_ = reg; |
+ set_result_identified(); |
+ } |
+ |
+ Register ResultRegister() const { return result_register_; } |
+ |
+ private: |
+ Register result_register_; |
+}; |
+ |
+ |
BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
: isolate_(isolate), |
zone_(zone), |
@@ -154,7 +269,10 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
scope_(nullptr), |
globals_(0, zone), |
execution_control_(nullptr), |
- execution_context_(nullptr) { |
+ execution_context_(nullptr), |
+ execution_result_(nullptr), |
+ binary_expression_depth_(0), |
+ binary_expression_hazard_set_(zone) { |
InitializeAstVisitor(isolate); |
} |
@@ -324,12 +442,11 @@ void BytecodeGenerator::VisitDeclarations( |
void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) { |
- Visit(stmt->expression()); |
+ VisitForEffect(stmt->expression()); |
} |
void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { |
- // TODO(oth): For control-flow it could be useful to signal empty paths here. |
} |
@@ -340,7 +457,7 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { |
BytecodeLabel else_label, end_label; |
- Visit(stmt->condition()); |
+ VisitForAccumulatorValue(stmt->condition()); |
builder()->CastAccumulatorToBoolean(); |
builder()->JumpIfFalse(&else_label); |
Visit(stmt->then_statement()); |
@@ -372,7 +489,7 @@ void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
- Visit(stmt->expression()); |
+ VisitForAccumulatorValue(stmt->expression()); |
builder()->Return(); |
} |
@@ -398,7 +515,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
builder()->Bind(&body_label); |
Visit(stmt->body()); |
builder()->Bind(&condition_label); |
- Visit(stmt->cond()); |
+ VisitForAccumulatorValue(stmt->cond()); |
builder()->JumpIfTrue(&body_label); |
builder()->Bind(&done_label); |
@@ -416,7 +533,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
builder()->Bind(&body_label); |
Visit(stmt->body()); |
builder()->Bind(&condition_label); |
- Visit(stmt->cond()); |
+ VisitForAccumulatorValue(stmt->cond()); |
builder()->JumpIfTrue(&body_label); |
builder()->Bind(&done_label); |
@@ -445,7 +562,7 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { |
} |
if (stmt->cond()) { |
builder()->Bind(&condition_label); |
- Visit(stmt->cond()); |
+ VisitForAccumulatorValue(stmt->cond()); |
builder()->JumpIfTrue(&body_label); |
} else { |
builder()->Jump(&body_label); |
@@ -500,6 +617,7 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { |
builder() |
->LoadLiteral(shared_info) |
.CreateClosure(expr->pretenure() ? TENURED : NOT_TENURED); |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -518,21 +636,24 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) { UNIMPLEMENTED(); } |
void BytecodeGenerator::VisitLiteral(Literal* expr) { |
- Handle<Object> value = expr->value(); |
- if (value->IsSmi()) { |
- builder()->LoadLiteral(Smi::cast(*value)); |
- } else if (value->IsUndefined()) { |
- builder()->LoadUndefined(); |
- } else if (value->IsTrue()) { |
- builder()->LoadTrue(); |
- } else if (value->IsFalse()) { |
- builder()->LoadFalse(); |
- } else if (value->IsNull()) { |
- builder()->LoadNull(); |
- } else if (value->IsTheHole()) { |
- builder()->LoadTheHole(); |
- } else { |
- builder()->LoadLiteral(value); |
+ if (!execution_result()->IsEffect()) { |
+ Handle<Object> value = expr->value(); |
+ if (value->IsSmi()) { |
+ builder()->LoadLiteral(Smi::cast(*value)); |
+ } else if (value->IsUndefined()) { |
+ builder()->LoadUndefined(); |
+ } else if (value->IsTrue()) { |
+ builder()->LoadTrue(); |
+ } else if (value->IsFalse()) { |
+ builder()->LoadFalse(); |
+ } else if (value->IsNull()) { |
+ builder()->LoadNull(); |
+ } else if (value->IsTheHole()) { |
+ builder()->LoadTheHole(); |
+ } else { |
+ builder()->LoadLiteral(value); |
+ } |
+ execution_result()->SetResultInAccumulator(); |
} |
} |
@@ -546,6 +667,7 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
.StoreAccumulatorInRegister(flags) |
.LoadLiteral(expr->pattern()) |
.CreateRegExpLiteral(expr->literal_index(), flags); |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -590,21 +712,28 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
builder() |
->LoadLiteral(literal_key->AsPropertyName()) |
.StoreAccumulatorInRegister(name); |
- Visit(property->value()); |
+ VisitForAccumulatorValue(property->value()); |
builder()->StoreNamedProperty(literal, name, |
feedback_index(property->GetSlot(0)), |
language_mode()); |
} else { |
- Visit(property->value()); |
+ VisitForEffect(property->value()); |
} |
} else { |
- Register key = inner_temporary_register_scope.NewRegister(); |
- Register value = inner_temporary_register_scope.NewRegister(); |
- Register language = inner_temporary_register_scope.NewRegister(); |
+ inner_temporary_register_scope.PrepareForConsecutiveAllocations(3); |
+ Register key = |
+ inner_temporary_register_scope.NextConsecutiveRegister(); |
+ Register value = |
+ inner_temporary_register_scope.NextConsecutiveRegister(); |
+ Register language = |
+ inner_temporary_register_scope.NextConsecutiveRegister(); |
+ // TODO(oth): This is problematic - can't assume contiguous here. |
+ // literal is allocated in temporary_register_scope, whereas |
+ // key, value, language are in another. |
DCHECK(Register::AreContiguous(literal, key, value, language)); |
- Visit(property->key()); |
+ VisitForAccumulatorValue(property->key()); |
builder()->StoreAccumulatorInRegister(key); |
- Visit(property->value()); |
+ VisitForAccumulatorValue(property->value()); |
builder()->StoreAccumulatorInRegister(value); |
if (property->emit_store()) { |
builder() |
@@ -617,10 +746,12 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
break; |
} |
case ObjectLiteral::Property::PROTOTYPE: { |
+ inner_temporary_register_scope.PrepareForConsecutiveAllocations(1); |
DCHECK(property->emit_store()); |
- Register value = inner_temporary_register_scope.NewRegister(); |
+ Register value = |
+ inner_temporary_register_scope.NextConsecutiveRegister(); |
DCHECK(Register::AreContiguous(literal, value)); |
- Visit(property->value()); |
+ VisitForAccumulatorValue(property->value()); |
builder()->StoreAccumulatorInRegister(value).CallRuntime( |
Runtime::kInternalSetPrototype, literal, 2); |
break; |
@@ -643,12 +774,13 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
for (AccessorTable::Iterator it = accessor_table.begin(); |
it != accessor_table.end(); ++it) { |
TemporaryRegisterScope inner_temporary_register_scope(builder()); |
- Register name = inner_temporary_register_scope.NewRegister(); |
- Register getter = inner_temporary_register_scope.NewRegister(); |
- Register setter = inner_temporary_register_scope.NewRegister(); |
- Register attr = inner_temporary_register_scope.NewRegister(); |
+ inner_temporary_register_scope.PrepareForConsecutiveAllocations(4); |
+ Register name = inner_temporary_register_scope.NextConsecutiveRegister(); |
+ Register getter = inner_temporary_register_scope.NextConsecutiveRegister(); |
+ Register setter = inner_temporary_register_scope.NextConsecutiveRegister(); |
+ Register attr = inner_temporary_register_scope.NextConsecutiveRegister(); |
DCHECK(Register::AreContiguous(literal, name, getter, setter, attr)); |
- Visit(it->first); |
+ VisitForAccumulatorValue(it->first); |
builder()->StoreAccumulatorInRegister(name); |
VisitObjectLiteralAccessor(literal, it->second->getter, getter); |
VisitObjectLiteralAccessor(literal, it->second->setter, setter); |
@@ -671,7 +803,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
ObjectLiteral::Property* property = expr->properties()->at(property_index); |
if (literal_in_accumulator) { |
- literal = temporary_register_scope.NewRegister(); |
+ temporary_register_scope.PrepareForConsecutiveAllocations(4); |
+ literal = temporary_register_scope.NextConsecutiveRegister(); |
builder()->StoreAccumulatorInRegister(literal); |
literal_in_accumulator = false; |
} |
@@ -681,21 +814,22 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
TemporaryRegisterScope inner_temporary_register_scope(builder()); |
Register value = inner_temporary_register_scope.NewRegister(); |
DCHECK(Register::AreContiguous(literal, value)); |
- Visit(property->value()); |
+ VisitForAccumulatorValue(property->value()); |
builder()->StoreAccumulatorInRegister(value).CallRuntime( |
Runtime::kInternalSetPrototype, literal, 2); |
continue; |
} |
TemporaryRegisterScope inner_temporary_register_scope(builder()); |
- Register key = inner_temporary_register_scope.NewRegister(); |
- Register value = inner_temporary_register_scope.NewRegister(); |
- Register attr = inner_temporary_register_scope.NewRegister(); |
+ inner_temporary_register_scope.PrepareForConsecutiveAllocations(3); |
+ Register key = inner_temporary_register_scope.NextConsecutiveRegister(); |
+ Register value = inner_temporary_register_scope.NextConsecutiveRegister(); |
+ Register attr = inner_temporary_register_scope.NextConsecutiveRegister(); |
DCHECK(Register::AreContiguous(literal, key, value, attr)); |
- Visit(property->key()); |
+ VisitForAccumulatorValue(property->key()); |
builder()->CastAccumulatorToName().StoreAccumulatorInRegister(key); |
- Visit(property->value()); |
+ VisitForAccumulatorValue(property->value()); |
builder()->StoreAccumulatorInRegister(value); |
VisitSetHomeObject(value, literal, property); |
builder()->LoadLiteral(Smi::FromInt(NONE)).StoreAccumulatorInRegister(attr); |
@@ -729,6 +863,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { |
// Restore literal array into accumulator. |
builder()->LoadAccumulatorWithRegister(literal); |
} |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -760,11 +895,11 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
literal_in_accumulator = false; |
} |
+ FeedbackVectorSlot slot = expr->LiteralFeedbackSlot(); |
builder() |
->LoadLiteral(Smi::FromInt(array_index)) |
.StoreAccumulatorInRegister(index); |
- Visit(subexpr); |
- FeedbackVectorSlot slot = expr->LiteralFeedbackSlot(); |
+ VisitForAccumulatorValue(subexpr); |
builder()->StoreKeyedProperty(literal, index, feedback_index(slot), |
language_mode()); |
} |
@@ -773,6 +908,7 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
// Restore literal array into accumulator. |
builder()->LoadAccumulatorWithRegister(literal); |
} |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -785,17 +921,15 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
FeedbackVectorSlot slot) { |
switch (variable->location()) { |
case VariableLocation::LOCAL: { |
- Register source(variable->index()); |
- builder()->LoadAccumulatorWithRegister(source); |
- // TODO(rmcilroy): Perform check for uninitialized legacy const, const and |
- // let variables. |
+ Register source(Register(variable->index())); |
+ execution_result()->SetResultInRegister(source); |
break; |
} |
case VariableLocation::PARAMETER: { |
// The parameter indices are shifted by 1 (receiver is variable |
// index -1 but is parameter index 0 in BytecodeArrayBuilder). |
- Register source(builder()->Parameter(variable->index() + 1)); |
- builder()->LoadAccumulatorWithRegister(source); |
+ Register source = builder()->Parameter(variable->index() + 1); |
+ execution_result()->SetResultInRegister(source); |
break; |
} |
case VariableLocation::GLOBAL: { |
@@ -805,6 +939,7 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
// runtime. |
DCHECK(variable->IsStaticGlobalObjectProperty()); |
builder()->LoadGlobal(variable->index()); |
+ execution_result()->SetResultInAccumulator(); |
break; |
} |
case VariableLocation::UNALLOCATED: { |
@@ -815,12 +950,14 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
builder()->StoreAccumulatorInRegister(obj); |
builder()->LoadLiteral(variable->name()); |
builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode()); |
+ execution_result()->SetResultInAccumulator(); |
break; |
} |
case VariableLocation::CONTEXT: { |
ContextScope* context = execution_context()->Previous(variable->scope()); |
if (context) { |
builder()->LoadContextSlot(context->reg(), variable->index()); |
+ execution_result()->SetResultInAccumulator(); |
} else { |
UNIMPLEMENTED(); |
} |
@@ -841,6 +978,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
// TODO(rmcilroy): support const mode initialization. |
Register destination(variable->index()); |
builder()->StoreAccumulatorInRegister(destination); |
+ RecordStoreToRegister(destination); |
break; |
} |
case VariableLocation::PARAMETER: { |
@@ -848,6 +986,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
// index -1 but is parameter index 0 in BytecodeArrayBuilder). |
Register destination(builder()->Parameter(variable->index() + 1)); |
builder()->StoreAccumulatorInRegister(destination); |
+ RecordStoreToRegister(destination); |
break; |
} |
case VariableLocation::GLOBAL: { |
@@ -860,10 +999,10 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
break; |
} |
case VariableLocation::UNALLOCATED: { |
- TemporaryRegisterScope temporary_register_scope(builder()); |
- Register value = temporary_register_scope.NewRegister(); |
- Register obj = temporary_register_scope.NewRegister(); |
- Register name = temporary_register_scope.NewRegister(); |
+ Register value = execution_result()->NewRegister(); |
+ Register obj = execution_result()->NewRegister(); |
+ Register name = execution_result()->NewRegister(); |
+ |
// TODO(rmcilroy): Investigate whether we can avoid having to stash the |
// value in a register. |
builder()->StoreAccumulatorInRegister(value); |
@@ -895,7 +1034,6 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
DCHECK(expr->target()->IsValidReferenceExpression()); |
- TemporaryRegisterScope temporary_register_scope(builder()); |
Register object, key; |
// Left-hand side can only be a property, a global or a variable slot. |
@@ -907,22 +1045,18 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
case VARIABLE: |
// Nothing to do to evaluate variable assignment LHS. |
break; |
- case NAMED_PROPERTY: |
- object = temporary_register_scope.NewRegister(); |
- key = temporary_register_scope.NewRegister(); |
- Visit(property->obj()); |
- builder()->StoreAccumulatorInRegister(object); |
+ case NAMED_PROPERTY: { |
+ object = VisitForRegisterValue(property->obj()); |
+ key = execution_result()->NewRegister(); |
builder()->LoadLiteral(property->key()->AsLiteral()->AsPropertyName()); |
builder()->StoreAccumulatorInRegister(key); |
break; |
- case KEYED_PROPERTY: |
- object = temporary_register_scope.NewRegister(); |
- key = temporary_register_scope.NewRegister(); |
- Visit(property->obj()); |
- builder()->StoreAccumulatorInRegister(object); |
- Visit(property->key()); |
- builder()->StoreAccumulatorInRegister(key); |
+ } |
+ case KEYED_PROPERTY: { |
+ object = VisitForRegisterValue(property->obj()); |
+ key = VisitForRegisterValue(property->key()); |
break; |
+ } |
case NAMED_SUPER_PROPERTY: |
case KEYED_SUPER_PROPERTY: |
UNIMPLEMENTED(); |
@@ -933,13 +1067,15 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
if (expr->is_compound()) { |
UNIMPLEMENTED(); |
} else { |
- Visit(expr->value()); |
+ VisitForAccumulatorValue(expr->value()); |
} |
// Store the value. |
FeedbackVectorSlot slot = expr->AssignmentSlot(); |
switch (assign_type) { |
case VARIABLE: { |
+ // TODO(oth): The VisitVariableAssignment() call is hard to reason about. |
+ // Is the value in the accumulator safe? Yes, but scary. |
Variable* variable = expr->target()->AsVariableProxy()->var(); |
VisitVariableAssignment(variable, slot); |
break; |
@@ -956,6 +1092,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
case KEYED_SUPER_PROPERTY: |
UNIMPLEMENTED(); |
} |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -963,8 +1100,7 @@ void BytecodeGenerator::VisitYield(Yield* expr) { UNIMPLEMENTED(); } |
void BytecodeGenerator::VisitThrow(Throw* expr) { |
- TemporaryRegisterScope temporary_register_scope(builder()); |
- Visit(expr->exception()); |
+ VisitForAccumulatorValue(expr->exception()); |
builder()->Throw(); |
} |
@@ -981,7 +1117,7 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { |
break; |
} |
case KEYED_PROPERTY: { |
- Visit(expr->key()); |
+ VisitForAccumulatorValue(expr->key()); |
builder()->LoadKeyedProperty(obj, feedback_index(slot), language_mode()); |
break; |
} |
@@ -989,33 +1125,41 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { |
case KEYED_SUPER_PROPERTY: |
UNIMPLEMENTED(); |
} |
+ execution_result()->SetResultInAccumulator(); |
} |
void BytecodeGenerator::VisitProperty(Property* expr) { |
- TemporaryRegisterScope temporary_register_scope(builder()); |
- Register obj = temporary_register_scope.NewRegister(); |
- Visit(expr->obj()); |
- builder()->StoreAccumulatorInRegister(obj); |
+ Register obj = VisitForRegisterValue(expr->obj()); |
VisitPropertyLoad(obj, expr); |
} |
-Register BytecodeGenerator::VisitArguments( |
- ZoneList<Expression*>* args, TemporaryRegisterScope* register_scope) { |
- // Visit arguments and place in a contiguous block of temporary registers. |
- // Return the first temporary register corresponding to the first argument. |
- DCHECK_GT(args->length(), 0); |
- Register first_arg = register_scope->NewRegister(); |
- Visit(args->at(0)); |
+Register BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args) { |
+ // Visit arguments and place in a contiguous block of temporary |
+ // registers. Return the first temporary register corresponding to |
+ // the first argument. |
+ // |
+ // NB the caller may have already called |
+ // PrepareForConsecutiveAllocations() with args->length() + N. The |
+ // second call here will be a no-op provided there have been N or |
+ // less calls to NextConsecutiveRegister(). Otherwise, the arguments |
+ // here will be consecutive, but they will not be consecutive with |
+ // earlier consecutive allocations made by the caller. |
+ execution_result()->PrepareForConsecutiveAllocations(args->length()); |
+ |
+ // Visit for first argument that goes into returned register |
+ Register first_arg = execution_result()->NextConsecutiveRegister(); |
+ VisitForAccumulatorValue(args->at(0)); |
builder()->StoreAccumulatorInRegister(first_arg); |
+ |
+ // Visit remaining arguments |
for (int i = 1; i < static_cast<int>(args->length()); i++) { |
- Register ith_arg = register_scope->NewRegister(); |
- Visit(args->at(i)); |
+ Register ith_arg = execution_result()->NextConsecutiveRegister(); |
+ VisitForAccumulatorValue(args->at(i)); |
builder()->StoreAccumulatorInRegister(ith_arg); |
DCHECK(ith_arg.index() - i == first_arg.index()); |
} |
- |
return first_arg; |
} |
@@ -1026,9 +1170,14 @@ void BytecodeGenerator::VisitCall(Call* expr) { |
// Prepare the callee and the receiver to the function call. This depends on |
// the semantics of the underlying call type. |
- TemporaryRegisterScope temporary_register_scope(builder()); |
- Register callee = temporary_register_scope.NewRegister(); |
- Register receiver = temporary_register_scope.NewRegister(); |
+ Register callee = execution_result()->NewRegister(); |
+ |
+ // The receiver and arguments need to be allocated consecutively for |
+ // Call(). Future optimizations could avoid this there are no |
+ // arguments or the receiver and arguments are already consecutive. |
+ ZoneList<Expression*>* args = expr->arguments(); |
+ execution_result()->PrepareForConsecutiveAllocations(args->length() + 1); |
+ Register receiver = execution_result()->NextConsecutiveRegister(); |
switch (call_type) { |
case Call::PROPERTY_CALL: { |
@@ -1036,8 +1185,11 @@ void BytecodeGenerator::VisitCall(Call* expr) { |
if (property->IsSuperAccess()) { |
UNIMPLEMENTED(); |
} |
- Visit(property->obj()); |
+ VisitForAccumulatorValue(property->obj()); |
builder()->StoreAccumulatorInRegister(receiver); |
+ // Need a result scope here to keep our consecutive |
+ // temporaries. |
+ AccumulatorResultScope accumulator_execution_result(this); |
// Perform a property load of the callee. |
VisitPropertyLoad(receiver, property); |
builder()->StoreAccumulatorInRegister(callee); |
@@ -1048,13 +1200,16 @@ void BytecodeGenerator::VisitCall(Call* expr) { |
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); |
// Load callee as a global variable. |
VariableProxy* proxy = callee_expr->AsVariableProxy(); |
+ // Result scope for VisitVariableLoad to avoid using our temporaries |
+ // and double setting the result in our result_scope() and. |
+ AccumulatorResultScope accumulator_execution_result(this); |
VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
builder()->StoreAccumulatorInRegister(callee); |
break; |
} |
case Call::OTHER_CALL: { |
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); |
- Visit(callee_expr); |
+ VisitForAccumulatorValue(callee_expr); |
builder()->StoreAccumulatorInRegister(callee); |
break; |
} |
@@ -1066,26 +1221,26 @@ void BytecodeGenerator::VisitCall(Call* expr) { |
// Evaluate all arguments to the function call and store in sequential |
// registers. |
- ZoneList<Expression*>* args = expr->arguments(); |
if (args->length() > 0) { |
- Register first_arg = VisitArguments(args, &temporary_register_scope); |
- CHECK_EQ(first_arg.index(), receiver.index() + 1); |
+ Register arg = VisitArguments(args); |
+ CHECK(arg.index() == receiver.index() + 1); |
} |
// TODO(rmcilroy): Deal with possible direct eval here? |
// TODO(rmcilroy): Use CallIC to allow call type feedback. |
builder()->Call(callee, receiver, args->length()); |
+ execution_result()->SetResultInAccumulator(); |
} |
void BytecodeGenerator::VisitCallNew(CallNew* expr) { |
- TemporaryRegisterScope temporary_register_scope(builder()); |
- Register constructor = temporary_register_scope.NewRegister(); |
- Visit(expr->expression()); |
+ Register constructor = execution_result()->NewRegister(); |
+ VisitForAccumulatorValue(expr->expression()); |
builder()->StoreAccumulatorInRegister(constructor); |
+ |
ZoneList<Expression*>* args = expr->arguments(); |
if (args->length() > 0) { |
- Register first_arg = VisitArguments(args, &temporary_register_scope); |
+ Register first_arg = VisitArguments(args); |
builder()->New(constructor, first_arg, args->length()); |
} else { |
// The second argument here will be ignored as there are zero |
@@ -1093,6 +1248,7 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) { |
// allocating a temporary just to fill the operands. |
builder()->New(constructor, constructor, 0); |
} |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -1101,41 +1257,44 @@ void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
UNIMPLEMENTED(); |
} |
- // Evaluate all arguments to the runtime call. |
- TemporaryRegisterScope temporary_register_scope(&builder_); |
- |
// TODO(rmcilroy): support multiple return values. |
DCHECK_LE(expr->function()->result_size, 1); |
Runtime::FunctionId function_id = expr->function()->function_id; |
+ |
+ // Evaluate all arguments to the runtime call. |
ZoneList<Expression*>* args = expr->arguments(); |
Register first_arg; |
if (args->length() > 0) { |
- first_arg = VisitArguments(args, &temporary_register_scope); |
+ first_arg = VisitArguments(args); |
} else { |
// Allocation here is just to fullfil the requirement that there |
// is a register operand for the start of the arguments though |
// there are zero when this is generated. |
- first_arg = temporary_register_scope.NewRegister(); |
+ first_arg = execution_result()->NewRegister(); |
} |
builder()->CallRuntime(function_id, first_arg, args->length()); |
+ execution_result()->SetResultInAccumulator(); |
} |
void BytecodeGenerator::VisitVoid(UnaryOperation* expr) { |
- Visit(expr->expression()); |
+ VisitForEffect(expr->expression()); |
builder()->LoadUndefined(); |
+ execution_result()->SetResultInAccumulator(); |
} |
void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { |
- Visit(expr->expression()); |
+ VisitForAccumulatorValue(expr->expression()); |
builder()->TypeOf(); |
+ execution_result()->SetResultInAccumulator(); |
} |
void BytecodeGenerator::VisitNot(UnaryOperation* expr) { |
- Visit(expr->expression()); |
+ VisitForAccumulatorValue(expr->expression()); |
builder()->LogicalNot(); |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -1183,17 +1342,38 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { |
void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
- Token::Value op = expr->op(); |
- Expression* left = expr->left(); |
- Expression* right = expr->right(); |
- |
- TemporaryRegisterScope temporary_register_scope(builder()); |
- Register temporary = temporary_register_scope.NewRegister(); |
- |
- Visit(left); |
- builder()->StoreAccumulatorInRegister(temporary); |
- Visit(right); |
- builder()->CompareOperation(op, temporary, language_mode_strength()); |
+ // TODO(oth): Remove PrepareForBinaryExpression/CompleteBinaryExpression |
+ // once we have StatementScope that tracks hazardous loads/stores. |
+ PrepareForBinaryExpression(); |
+ Register lhs = VisitForRegisterValue(expr->left()); |
+ if (builder()->RegisterIsParameterOrLocal(lhs)) { |
+ // Result was returned in an existing local or parameter. See if |
+ // it needs to be moved to a temporary. |
+ // TODO(oth) LoadFromAliasedRegister call into VisitVariableLoad(). |
+ lhs = LoadFromAliasedRegister(lhs); |
+ } |
+ VisitForAccumulatorValue(expr->right()); |
+ builder()->CompareOperation(expr->op(), lhs, language_mode_strength()); |
+ CompleteBinaryExpression(); |
+ execution_result()->SetResultInAccumulator(); |
+} |
+ |
+ |
+void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { |
+ // TODO(oth): Remove PrepareForBinaryExpression/CompleteBinaryExpression |
+ // once we have StatementScope that tracks hazardous loads/stores. |
+ PrepareForBinaryExpression(); |
+ Register lhs = VisitForRegisterValue(expr->left()); |
+ if (builder()->RegisterIsParameterOrLocal(lhs)) { |
+ // Result was returned in an existing local or parameter. See if |
+ // it needs to be moved to a temporary. |
+ // TODO(oth) LoadFromAliasedRegister call into VisitVariableLoad(). |
+ lhs = LoadFromAliasedRegister(lhs); |
+ } |
+ VisitForAccumulatorValue(expr->right()); |
+ builder()->BinaryOperation(expr->op(), lhs, language_mode_strength()); |
+ CompleteBinaryExpression(); |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -1285,27 +1465,9 @@ void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) { |
} |
-void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { |
- Token::Value op = binop->op(); |
- Expression* left = binop->left(); |
- Expression* right = binop->right(); |
- |
- TemporaryRegisterScope temporary_register_scope(builder()); |
- Register temporary = temporary_register_scope.NewRegister(); |
- |
- Visit(left); |
- builder()->StoreAccumulatorInRegister(temporary); |
- Visit(right); |
- builder()->BinaryOperation(op, temporary, language_mode_strength()); |
-} |
- |
- |
void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { |
- Expression* left = binop->left(); |
- Expression* right = binop->right(); |
- |
- Visit(left); |
- Visit(right); |
+ VisitForEffect(binop->left()); |
+ Visit(binop->right()); |
} |
@@ -1316,15 +1478,15 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { |
// Short-circuit evaluation- If it is known that left is always true, |
// no need to visit right |
if (left->ToBooleanIsTrue()) { |
- Visit(left); |
+ VisitForAccumulatorValue(left); |
} else { |
BytecodeLabel end_label; |
- |
- Visit(left); |
+ VisitForAccumulatorValue(left); |
builder()->JumpIfToBooleanTrue(&end_label); |
- Visit(right); |
+ VisitForAccumulatorValue(right); |
builder()->Bind(&end_label); |
} |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -1335,15 +1497,15 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { |
// Short-circuit evaluation- If it is known that left is always false, |
// no need to visit right |
if (left->ToBooleanIsFalse()) { |
- Visit(left); |
+ VisitForAccumulatorValue(left); |
} else { |
BytecodeLabel end_label; |
- |
- Visit(left); |
+ VisitForAccumulatorValue(left); |
builder()->JumpIfToBooleanFalse(&end_label); |
- Visit(right); |
+ VisitForAccumulatorValue(right); |
builder()->Bind(&end_label); |
} |
+ execution_result()->SetResultInAccumulator(); |
} |
@@ -1353,7 +1515,7 @@ void BytecodeGenerator::VisitObjectLiteralAccessor( |
if (property == nullptr) { |
builder()->LoadNull().StoreAccumulatorInRegister(value_out); |
} else { |
- Visit(property->value()); |
+ VisitForAccumulatorValue(property->value()); |
builder()->StoreAccumulatorInRegister(value_out); |
VisitSetHomeObject(value_out, home_object, property); |
} |
@@ -1397,6 +1559,65 @@ void BytecodeGenerator::VisitFunctionClosureForContext() { |
} |
+void BytecodeGenerator::PrepareForBinaryExpression() { |
+ if (binary_expression_depth_++ == 0) { |
+ binary_expression_hazard_set_.clear(); |
+ } |
+} |
+ |
+ |
+// Visits the expression |expr| and places the result in the accumulator. |
+void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { |
+ AccumulatorResultScope accumulator_scope(this); |
+ Visit(expr); |
+} |
+ |
+ |
+// Visits the expression |expr| and discards the result. |
+void BytecodeGenerator::VisitForEffect(Expression* expr) { |
+ EffectResultScope effect_scope(this); |
+ Visit(expr); |
+} |
+ |
+ |
+// Visits the expression |expr| and returns the register containing |
+// the expression result. |
+Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { |
+ RegisterResultScope register_scope(this); |
+ Visit(expr); |
+ return register_scope.ResultRegister(); |
+} |
+ |
+ |
+Register BytecodeGenerator::LoadFromAliasedRegister(Register reg) { |
+ // TODO(oth): Follow on CL to load from re-map here. |
+ DCHECK(builder()->RegisterIsParameterOrLocal(reg)); |
+ if (binary_expression_depth_ > 0) { |
+ binary_expression_hazard_set_.insert(reg.index()); |
+ } |
+ return reg; |
+} |
+ |
+ |
+void BytecodeGenerator::RecordStoreToRegister(Register reg) { |
+ DCHECK(builder()->RegisterIsParameterOrLocal(reg)); |
+ if (binary_expression_depth_ > 0) { |
+ // TODO(oth): a store to a register that's be loaded needs to be |
+ // remapped. |
+ DCHECK(binary_expression_hazard_set_.find(reg.index()) == |
+ binary_expression_hazard_set_.end()); |
+ } |
+} |
+ |
+ |
+void BytecodeGenerator::CompleteBinaryExpression() { |
+ DCHECK(binary_expression_depth_ > 0); |
+ binary_expression_depth_ -= 1; |
+ // TODO(oth): spill remapped registers into origins. |
+ // TODO(oth): make statement/top-level. |
+} |
+ |
+ |
Register BytecodeGenerator::NextContextRegister() const { |
if (execution_context() == nullptr) { |
// Return the incoming function context for the outermost execution context. |