| Index: src/ia32/codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/codegen-ia32.cc (revision 4583)
|
| +++ src/ia32/codegen-ia32.cc (working copy)
|
| @@ -5369,10 +5369,13 @@
|
|
|
| // 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.
|
| Result result = LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
|
| frame()->Push(&result);
|
| Load(node->value());
|
|
|
| + // Perform the binary operation.
|
| bool overwrite_value =
|
| (node->value()->AsBinaryOperation() != NULL &&
|
| node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
|
| @@ -5382,6 +5385,7 @@
|
| GenericBinaryOperation(&expr,
|
| overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
|
| } else {
|
| + // For non-compound assignment just load the right-hand side.
|
| Load(node->value());
|
| }
|
|
|
| @@ -5404,7 +5408,9 @@
|
| Property* prop = node->target()->AsProperty();
|
| ASSERT(var == NULL || (prop == NULL && var->is_global()));
|
|
|
| - // Initialize name and evaluate the receiver subexpression if necessary.
|
| + // 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) {
|
| @@ -5418,10 +5424,13 @@
|
| 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 of 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);
|
| - // Change to slow case in the beginning of an initialization block to
|
| - // avoid the quadratic behavior of repeatedly adding fast properties.
|
| if (is_trivial_receiver) {
|
| frame()->Push(prop->obj());
|
| } else {
|
| @@ -5430,14 +5439,21 @@
|
| Result ignored = 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) {
|
| - // Add an extra copy of the receiver to the frame, so that it can be
|
| - // converted back to fast case after the assignment.
|
| 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) {
|
| frame()->Push(prop->obj());
|
| } else if (var != NULL) {
|
| @@ -5461,9 +5477,15 @@
|
| GenericBinaryOperation(&expr,
|
| overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
|
| } else {
|
| + // For non-compound assignment just load the right-hand side.
|
| Load(node->value());
|
| }
|
|
|
| + // 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());
|
| @@ -5477,6 +5499,10 @@
|
| Result answer = EmitNamedStore(name, is_contextual);
|
| frame()->Push(&answer);
|
|
|
| + // Stack layout:
|
| + // [tos] : result
|
| + // [tos+1] : receiver if 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.
|
| @@ -5493,6 +5519,9 @@
|
| Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
|
| }
|
|
|
| + // Stack layout:
|
| + // [tos] : result
|
| +
|
| ASSERT_EQ(frame()->height(), original_height + 1);
|
| }
|
|
|
| @@ -5501,38 +5530,47 @@
|
| #ifdef DEBUG
|
| int original_height = frame()->height();
|
| #endif
|
| - Comment cmnt(masm_, "[ Named Property Assignment");
|
| + 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()) {
|
| - // Change to slow case in the beginning of an initialization block to
|
| - // avoid the quadratic behavior of repeatedly adding fast properties.
|
| frame_->Dup();
|
| Result ignored = 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()) {
|
| - // Add an extra copy of the receiver to the frame, so that it can be
|
| - // converted back to fast case after the assignment.
|
| 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()) {
|
| - // Duplicate receiver and key.
|
| + // For a compound assignment the right-hand side is a binary operation
|
| + // between the current property value and the actual right-hand side.
|
| + // Duplicate receiver and key for loading the current property value.
|
| frame()->PushElementAt(1);
|
| frame()->PushElementAt(1);
|
| Result value = EmitKeyedLoad();
|
| frame()->Push(&value);
|
| Load(node->value());
|
|
|
| + // Perform the binary operation.
|
| bool overwrite_value =
|
| (node->value()->AsBinaryOperation() != NULL &&
|
| node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
|
| @@ -5541,15 +5579,27 @@
|
| GenericBinaryOperation(&expr,
|
| overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
|
| } else {
|
| + // For non-compound assignment just load the right-hand side.
|
| Load(node->value());
|
| }
|
|
|
| + // 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());
|
| Result answer = EmitKeyedStore(prop->key()->type());
|
| frame()->Push(&answer);
|
|
|
| + // 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
|
| @@ -5561,6 +5611,9 @@
|
| Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
|
| }
|
|
|
| + // Stack layout:
|
| + // [tos] : result
|
| +
|
| ASSERT(frame()->height() == original_height + 1);
|
| }
|
|
|
|
|