| Index: src/x64/codegen-x64.cc
|
| ===================================================================
|
| --- src/x64/codegen-x64.cc (revision 5107)
|
| +++ src/x64/codegen-x64.cc (working copy)
|
| @@ -5006,16 +5006,150 @@
|
| }
|
|
|
|
|
| +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 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);
|
| + if (is_trivial_receiver) {
|
| + frame()->Push(prop->obj());
|
| + } else {
|
| + 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() && !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) {
|
| + frame()->Push(prop->obj());
|
| + } else if (var != NULL) {
|
| + // The LoadIC stub expects the object in rax.
|
| + // Freeing rax causes the code generator to load the global into it.
|
| + frame_->Spill(rax);
|
| + LoadGlobal();
|
| + } else {
|
| + frame()->Dup();
|
| + }
|
| + Result value = EmitNamedLoad(name, var != NULL);
|
| + frame()->Push(&value);
|
| + Load(node->value());
|
| +
|
| + bool overwrite_value =
|
| + (node->value()->AsBinaryOperation() != NULL &&
|
| + node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
|
| + // Construct the implicit binary operation.
|
| + BinaryOperation expr(node, node->binary_op(), node->target(),
|
| + node->value());
|
| + 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());
|
| + if (is_trivial_receiver) {
|
| + Result value = frame()->Pop();
|
| + frame()->Push(prop->obj());
|
| + frame()->Push(&value);
|
| + }
|
| + CodeForSourcePosition(node->position());
|
| + bool is_contextual = (var != NULL);
|
| + 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.
|
| + if (is_trivial_receiver) {
|
| + frame()->Push(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.
|
| + Result result = frame()->Pop();
|
| + Result receiver = frame()->Pop();
|
| + frame()->Push(&result);
|
| + frame()->Push(&receiver);
|
| + }
|
| + Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1);
|
| + }
|
| +
|
| + // Stack layout:
|
| + // [tos] : result
|
| +
|
| + ASSERT_EQ(frame()->height(), original_height + 1);
|
| +}
|
| +
|
| +
|
| void CodeGenerator::VisitAssignment(Assignment* node) {
|
| #ifdef DEBUG
|
| int original_height = frame()->height();
|
| #endif
|
| Variable* var = node->target()->AsVariableProxy()->AsVariable();
|
| - // Property* prop = node->target()->AsProperty();
|
| + 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 {
|
| Comment cmnt(masm_, "[ Assignment");
|
|
|
| @@ -7847,6 +7981,22 @@
|
| }
|
|
|
|
|
| +Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) {
|
| +#ifdef DEBUG
|
| + int expected_height = frame()->height() - (is_contextual ? 1 : 2);
|
| +#endif
|
| +
|
| + Result result = frame()->CallStoreIC(name, is_contextual);
|
| + // A test eax instruction following the call signals that the inobject
|
| + // property case was inlined. Ensure that there is not a test eax
|
| + // instruction here.
|
| + __ nop();
|
| +
|
| + ASSERT_EQ(expected_height, frame()->height());
|
| + return result;
|
| +}
|
| +
|
| +
|
| Result CodeGenerator::EmitKeyedLoad() {
|
| #ifdef DEBUG
|
| int original_height = frame()->height();
|
|
|