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

Unified Diff: src/arm/codegen-arm.cc

Issue 1846002: Refactor assignment in the ARM code generator... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 8 months 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/arm/codegen-arm.h ('k') | src/arm/virtual-frame-arm.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/arm/codegen-arm.cc
===================================================================
--- src/arm/codegen-arm.cc (revision 4568)
+++ src/arm/codegen-arm.cc (working copy)
@@ -565,7 +565,7 @@
}
ASSERT(has_valid_frame());
ASSERT(!has_cc());
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -2717,7 +2717,7 @@
return;
}
InstantiateFunction(function_info);
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -2729,7 +2729,7 @@
VirtualFrame::SpilledScope spilled_scope(frame_);
Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
InstantiateFunction(node->shared_function_info());
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -2756,7 +2756,7 @@
LoadAndSpill(node->else_expression());
if (exit.is_linked()) exit.Bind();
}
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3028,7 +3028,7 @@
#endif
Comment cmnt(masm_, "[ Slot");
LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF);
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3047,7 +3047,7 @@
Reference ref(this, node);
ref.GetValue();
}
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3059,7 +3059,7 @@
Register reg = frame_->GetTOSRegister();
__ mov(reg, Operand(node->handle()));
frame_->EmitPush(reg);
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3103,7 +3103,7 @@
done.Bind();
// Push the literal.
frame_->EmitPush(r2);
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3184,7 +3184,7 @@
}
}
}
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3243,7 +3243,7 @@
__ mov(r3, Operand(offset));
__ RecordWrite(r1, r3, r2);
}
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3259,73 +3259,321 @@
LoadAndSpill(node->value());
frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
frame_->EmitPush(r0);
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
-void CodeGenerator::VisitAssignment(Assignment* node) {
- VirtualFrame::RegisterAllocationScope scope(this);
+void CodeGenerator::EmitSlotAssignment(Assignment* node) {
#ifdef DEBUG
int original_height = frame_->height();
#endif
- Comment cmnt(masm_, "[ Assignment");
+ Comment cmnt(masm(), "[ Variable Assignment");
+ Variable* var = node->target()->AsVariableProxy()->AsVariable();
+ ASSERT(var != NULL);
+ Slot* slot = var->slot();
+ ASSERT(slot != NULL);
- { Reference target(this, node->target(), node->is_compound());
- if (target.is_illegal()) {
- // Fool the virtual frame into thinking that we left the assignment's
- // value on the frame.
- Register tos = frame_->GetTOSRegister();
- __ mov(tos, Operand(Smi::FromInt(0)));
- frame_->EmitPush(tos);
- ASSERT(frame_->height() == original_height + 1);
- return;
+ // Evaluate the right-hand side.
+ if (node->is_compound()) {
+ // For a compound assignment the right-hand side is a binary operation
+ // between the current property value and the actual right-hand side.
+ LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
+
+ // Perform the binary operation.
+ Literal* literal = node->value()->AsLiteral();
+ bool overwrite_value =
+ (node->value()->AsBinaryOperation() != NULL &&
+ node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
+ if (literal != NULL && literal->handle()->IsSmi()) {
+ SmiOperation(node->binary_op(),
+ literal->handle(),
+ false,
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
+ } else {
+ Load(node->value());
+ VirtualFrameBinaryOperation(
+ node->binary_op(), overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
}
+ } else {
+ Load(node->value());
+ }
- if (node->op() == Token::ASSIGN ||
- node->op() == Token::INIT_VAR ||
- node->op() == Token::INIT_CONST) {
+ // Perform the assignment.
+ if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) {
+ CodeForSourcePosition(node->position());
+ StoreToSlot(slot,
+ node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT);
+ }
+ ASSERT_EQ(original_height + 1, frame_->height());
+}
+
+
+void CodeGenerator::EmitNamedPropertyAssignment(Assignment* node) {
+#ifdef DEBUG
+ int original_height = frame_->height();
+#endif
+ Comment cmnt(masm(), "[ Named Property Assignment");
+ Variable* var = node->target()->AsVariableProxy()->AsVariable();
+ Property* prop = node->target()->AsProperty();
+ ASSERT(var == NULL || (prop == NULL && var->is_global()));
+
+ // Initialize name and evaluate the receiver sub-expression if necessary. If
+ // the receiver is trivial it is not placed on the stack at this point, but
+ // loaded whenever actually needed.
+ Handle<String> name;
+ bool is_trivial_receiver = false;
+ if (var != NULL) {
+ name = var->name();
+ } else {
+ Literal* lit = prop->key()->AsLiteral();
+ ASSERT_NOT_NULL(lit);
+ name = Handle<String>::cast(lit->handle());
+ // Do not materialize the receiver on the frame if it is trivial.
+ is_trivial_receiver = prop->obj()->IsTrivial();
+ if (!is_trivial_receiver) Load(prop->obj());
+ }
+
+ // Change to slow case in the beginning of an initialization block to
+ // avoid the quadratic behavior of repeatedly adding fast properties.
+ if (node->starts_initialization_block()) {
+ // Initialization block consists of assignments on the form expr.x = ..., so
+ // this will never be an assignment to a variable, so there must be a
+ // receiver object.
+ ASSERT_EQ(NULL, var);
+ if (is_trivial_receiver) {
+ Load(prop->obj());
+ } else {
+ frame_->Dup();
+ }
+ frame_->CallRuntime(Runtime::kToSlowProperties, 1);
+ }
+
+ // Change to fast case at the end of an initialization block. To prepare for
+ // that add an extra copy of the receiver to the frame, so that it can be
+ // converted back to fast case after the assignment.
+ if (node->ends_initialization_block() && !is_trivial_receiver) {
+ frame_->Dup();
+ }
+
+ // Stack layout:
+ // [tos] : receiver (only materialized if non-trivial)
+ // [tos+1] : receiver if at the end of an initialization block
+
+ // Evaluate the right-hand side.
+ if (node->is_compound()) {
+ // For a compound assignment the right-hand side is a binary operation
+ // between the current property value and the actual right-hand side.
+ if (is_trivial_receiver) {
+ Load(prop->obj());
+ } else if (var != NULL) {
+ LoadGlobal();
+ } else {
+ frame_->Dup();
+ }
+ EmitNamedLoad(name, var != NULL);
+ frame_->Drop(); // Receiver is left on the stack.
+ frame_->EmitPush(r0);
+
+ // Perform the binary operation.
+ Literal* literal = node->value()->AsLiteral();
+ bool overwrite_value =
+ (node->value()->AsBinaryOperation() != NULL &&
+ node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
+ if (literal != NULL && literal->handle()->IsSmi()) {
+ SmiOperation(node->binary_op(),
+ literal->handle(),
+ false,
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
+ } else {
Load(node->value());
+ VirtualFrameBinaryOperation(
+ node->binary_op(), overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
+ }
+ } else {
+ // For non-compound assignment just load the right-hand side.
+ Load(node->value());
+ }
- } else { // Assignment is a compound assignment.
- // Get the old value of the lhs.
- target.GetValue();
- Literal* literal = node->value()->AsLiteral();
- bool overwrite =
- (node->value()->AsBinaryOperation() != NULL &&
- node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
- if (literal != NULL && literal->handle()->IsSmi()) {
- SmiOperation(node->binary_op(),
- literal->handle(),
- false,
- overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE);
- } else {
- Load(node->value());
- VirtualFrameBinaryOperation(node->binary_op(),
- overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE);
- }
+ // Stack layout:
+ // [tos] : value
+ // [tos+1] : receiver (only materialized if non-trivial)
+ // [tos+2] : receiver if at the end of an initialization block
+
+ // Perform the assignment. It is safe to ignore constants here.
+ ASSERT(var == NULL || var->mode() != Variable::CONST);
+ ASSERT_NE(Token::INIT_CONST, node->op());
+ if (is_trivial_receiver) {
+ // Load the receiver and swap with the value.
+ Load(prop->obj());
+ Register t0 = frame_->PopToRegister();
+ Register t1 = frame_->PopToRegister(t0);
+ frame_->EmitPush(t0);
+ frame_->EmitPush(t1);
+ }
+ CodeForSourcePosition(node->position());
+ bool is_contextual = (var != NULL);
+ EmitNamedStore(name, is_contextual);
+ frame_->EmitPush(r0);
+
+ // Change to fast case at the end of an initialization block.
+ if (node->ends_initialization_block()) {
+ ASSERT_EQ(NULL, var);
+ // The argument to the runtime call is the receiver.
+ if (is_trivial_receiver) {
+ Load(prop->obj());
+ } else {
+ // A copy of the receiver is below the value of the assignment. Swap
+ // the receiver and the value of the assignment expression.
+ Register t0 = frame_->PopToRegister();
+ Register t1 = frame_->PopToRegister(t0);
+ frame_->EmitPush(t0);
+ frame_->EmitPush(t1);
}
- Variable* var = node->target()->AsVariableProxy()->AsVariable();
- if (var != NULL &&
- (var->mode() == Variable::CONST) &&
- node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
- // Assignment ignored - leave the value on the stack.
- UnloadReference(&target);
+ frame_->CallRuntime(Runtime::kToFastProperties, 1);
+ }
+
+ // Stack layout:
+ // [tos] : result
+
+ ASSERT_EQ(original_height + 1, frame_->height());
+}
+
+
+void CodeGenerator::EmitKeyedPropertyAssignment(Assignment* node) {
+#ifdef DEBUG
+ int original_height = frame_->height();
+#endif
+ Comment cmnt(masm_, "[ Keyed Property Assignment");
+ Property* prop = node->target()->AsProperty();
+ ASSERT_NOT_NULL(prop);
+
+ // Evaluate the receiver subexpression.
+ Load(prop->obj());
+
+ // Change to slow case in the beginning of an initialization block to
+ // avoid the quadratic behavior of repeatedly adding fast properties.
+ if (node->starts_initialization_block()) {
+ frame_->Dup();
+ frame_->CallRuntime(Runtime::kToSlowProperties, 1);
+ }
+
+ // Change to fast case at the end of an initialization block. To prepare for
+ // that add an extra copy of the receiver to the frame, so that it can be
+ // converted back to fast case after the assignment.
+ if (node->ends_initialization_block()) {
+ frame_->Dup();
+ }
+
+ // Evaluate the key subexpression.
+ Load(prop->key());
+
+ // Stack layout:
+ // [tos] : key
+ // [tos+1] : receiver
+ // [tos+2] : receiver if at the end of an initialization block
+
+ // Evaluate the right-hand side.
+ if (node->is_compound()) {
+ // For a compound assignment the right-hand side is a binary operation
+ // between the current property value and the actual right-hand side.
+ // Load of the current value leaves receiver and key on the stack.
+ EmitKeyedLoad();
+ frame_->EmitPush(r0);
+
+ // Perform the binary operation.
+ Literal* literal = node->value()->AsLiteral();
+ bool overwrite_value =
+ (node->value()->AsBinaryOperation() != NULL &&
+ node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
+ if (literal != NULL && literal->handle()->IsSmi()) {
+ SmiOperation(node->binary_op(),
+ literal->handle(),
+ false,
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
} else {
- CodeForSourcePosition(node->position());
- if (node->op() == Token::INIT_CONST) {
- // Dynamic constant initializations must use the function context
- // and initialize the actual constant declared. Dynamic variable
- // initializations are simply assignments and use SetValue.
- target.SetValue(CONST_INIT);
- } else {
- target.SetValue(NOT_CONST_INIT);
- }
+ Load(node->value());
+ VirtualFrameBinaryOperation(
+ node->binary_op(), overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
}
+ } else {
+ // For non-compound assignment just load the right-hand side.
+ Load(node->value());
}
- ASSERT(frame_->height() == original_height + 1);
+
+ // Stack layout:
+ // [tos] : value
+ // [tos+1] : key
+ // [tos+2] : receiver
+ // [tos+3] : receiver if at the end of an initialization block
+
+ // Perform the assignment. It is safe to ignore constants here.
+ ASSERT(node->op() != Token::INIT_CONST);
+ CodeForSourcePosition(node->position());
+ frame_->PopToR0();
+ EmitKeyedStore(prop->key()->type());
+ frame_->Drop(2); // Key and receiver are left on the stack.
+ frame_->EmitPush(r0);
+
+ // Stack layout:
+ // [tos] : result
+ // [tos+1] : receiver if at the end of an initialization block
+
+ // Change to fast case at the end of an initialization block.
+ if (node->ends_initialization_block()) {
+ // The argument to the runtime call is the extra copy of the receiver,
+ // which is below the value of the assignment. Swap the receiver and
+ // the value of the assignment expression.
+ Register t0 = frame_->PopToRegister();
+ Register t1 = frame_->PopToRegister(t0);
+ frame_->EmitPush(t1);
+ frame_->EmitPush(t0);
+ frame_->CallRuntime(Runtime::kToFastProperties, 1);
+ }
+
+ // Stack layout:
+ // [tos] : result
+
+ ASSERT_EQ(original_height + 1, frame_->height());
}
+void CodeGenerator::VisitAssignment(Assignment* node) {
+ VirtualFrame::RegisterAllocationScope scope(this);
+#ifdef DEBUG
+ int original_height = frame_->height();
+#endif
+ Comment cmnt(masm_, "[ Assignment");
+
+ Variable* var = node->target()->AsVariableProxy()->AsVariable();
+ Property* prop = node->target()->AsProperty();
+
+ if (var != NULL && !var->is_global()) {
+ EmitSlotAssignment(node);
+
+ } else if ((prop != NULL && prop->key()->IsPropertyName()) ||
+ (var != NULL && var->is_global())) {
+ // Properties whose keys are property names and global variables are
+ // treated as named property references. We do not need to consider
+ // global 'this' because it is not a valid left-hand side.
+ EmitNamedPropertyAssignment(node);
+
+ } else if (prop != NULL) {
+ // Other properties (including rewritten parameters for a function that
+ // uses arguments) are keyed property assignments.
+ EmitKeyedPropertyAssignment(node);
+
+ } else {
+ // Invalid left-hand side.
+ Load(node->target());
+ frame_->CallRuntime(Runtime::kThrowReferenceError, 1);
+ // The runtime call doesn't actually return but the code generator will
+ // still generate code and expects a certain frame height.
+ frame_->EmitPush(r0);
+ }
+ ASSERT_EQ(original_height + 1, frame_->height());
+}
+
+
void CodeGenerator::VisitThrow(Throw* node) {
#ifdef DEBUG
int original_height = frame_->height();
@@ -3337,7 +3585,7 @@
CodeForSourcePosition(node->position());
frame_->CallRuntime(Runtime::kThrow, 1);
frame_->EmitPush(r0);
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3350,7 +3598,7 @@
{ Reference property(this, node);
property.GetValue();
}
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3557,7 +3805,7 @@
CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position());
frame_->EmitPush(r0);
}
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -3600,7 +3848,7 @@
// Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
__ str(r0, frame_->Top());
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -4425,7 +4673,7 @@
frame_->CallRuntime(function, arg_count);
frame_->EmitPush(r0);
}
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -4589,7 +4837,7 @@
__ mov(r0, Operand(Smi::FromInt(0)));
frame_->EmitPush(r0);
}
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
return;
}
target.GetValue();
@@ -4657,7 +4905,7 @@
// Postfix: Discard the new value and use the old.
if (is_postfix) frame_->EmitPop(r0);
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -4832,7 +5080,7 @@
VirtualFrame::SpilledScope spilled_scope(frame_);
__ ldr(r0, frame_->Function());
frame_->EmitPush(r0);
- ASSERT(frame_->height() == original_height + 1);
+ ASSERT_EQ(original_height + 1, frame_->height());
}
@@ -5226,6 +5474,16 @@
}
+void CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
+#ifdef DEBUG
+ int expected_height = frame_->height() - (is_contextual ? 1 : 2);
+#endif
+ frame_->CallStoreIC(name, is_contextual);
+
+ ASSERT_EQ(expected_height, frame_->height());
+}
+
+
void CodeGenerator::EmitKeyedLoad() {
if (loop_nesting() == 0) {
VirtualFrame::SpilledScope spilled(frame_);
@@ -5240,7 +5498,7 @@
__ IncrementCounter(&Counters::keyed_load_inline, 1,
frame_->scratch0(), frame_->scratch1());
- // Load the receiver and key from the stack.
+ // Load the receiver and key from the stack.
frame_->SpillAllButCopyTOSToR1R0();
Register receiver = r0;
Register key = r1;
@@ -5315,7 +5573,7 @@
void CodeGenerator::EmitKeyedStore(StaticType* key_type) {
- frame_->AssertIsSpilled();
+ VirtualFrame::SpilledScope scope(frame_);
// Generate inlined version of the keyed store if the code is in a loop
// and the key is likely to be a smi.
if (loop_nesting() > 0 && key_type->IsLikelySmi()) {
@@ -5483,21 +5741,13 @@
Comment cmnt(masm, "[ Store to Slot");
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
cgen_->StoreToSlot(slot, init_state);
- cgen_->UnloadReference(this);
+ set_unloaded();
break;
}
case NAMED: {
- VirtualFrame::SpilledScope scope(frame);
Comment cmnt(masm, "[ Store to named Property");
- // Call the appropriate IC code.
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
- Handle<String> name(GetName());
-
- frame->EmitPop(r0);
- frame->EmitPop(r1);
- __ mov(r2, Operand(name));
- frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
+ cgen_->EmitNamedStore(GetName(), false);
frame->EmitPush(r0);
set_unloaded();
break;
« no previous file with comments | « src/arm/codegen-arm.h ('k') | src/arm/virtual-frame-arm.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698