Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 5106) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -4965,103 +4965,158 @@ |
} |
+void CodeGenerator::EmitSlotAssignment(Assignment* node) { |
+#ifdef DEBUG |
+ int original_height = frame()->height(); |
+#endif |
+ Comment cmnt(masm(), "[ Variable Assignment"); |
+ Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
+ ASSERT(var != NULL); |
+ Slot* slot = var->slot(); |
+ ASSERT(slot != NULL); |
+ |
+ // 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); |
+ Load(node->value()); |
+ |
+ // Perform the binary operation. |
+ 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()); |
+ } |
+ |
+ // 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(frame()->height() == original_height + 1); |
+} |
+ |
+ |
void CodeGenerator::VisitAssignment(Assignment* node) { |
- Comment cmnt(masm_, "[ Assignment"); |
+#ifdef DEBUG |
+ int original_height = frame()->height(); |
+#endif |
+ Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
+ // Property* prop = node->target()->AsProperty(); |
- { 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. |
- frame_->Push(Smi::FromInt(0)); |
- return; |
- } |
- Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
+ if (var != NULL && !var->is_global()) { |
+ EmitSlotAssignment(node); |
- if (node->starts_initialization_block()) { |
- ASSERT(target.type() == Reference::NAMED || |
- target.type() == Reference::KEYED); |
- // Change to slow case in the beginning of an initialization |
- // block to avoid the quadratic behavior of repeatedly adding |
- // fast properties. |
+ } else { |
+ Comment cmnt(masm_, "[ Assignment"); |
- // The receiver is the argument to the runtime call. It is the |
- // first value pushed when the reference was loaded to the |
- // frame. |
- frame_->PushElementAt(target.size() - 1); |
- Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); |
- } |
- 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. |
- ASSERT(target.type() == Reference::NAMED || |
- target.type() == Reference::KEYED); |
- if (target.type() == Reference::NAMED) { |
- frame_->Dup(); |
- // Dup target receiver on stack. |
- } else { |
- ASSERT(target.type() == Reference::KEYED); |
- Result temp = frame_->Pop(); |
- frame_->Dup(); |
- frame_->Push(&temp); |
+ { 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. |
+ frame_->Push(Smi::FromInt(0)); |
+ return; |
} |
- } |
- if (node->op() == Token::ASSIGN || |
- node->op() == Token::INIT_VAR || |
- node->op() == Token::INIT_CONST) { |
- Load(node->value()); |
- } else { // Assignment is a compound assignment. |
- Literal* literal = node->value()->AsLiteral(); |
- bool overwrite_value = |
- (node->value()->AsBinaryOperation() != NULL && |
- node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
- Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); |
- // There are two cases where the target is not read in the right hand |
- // side, that are easy to test for: the right hand side is a literal, |
- // or the right hand side is a different variable. TakeValue invalidates |
- // the target, with an implicit promise that it will be written to again |
- // before it is read. |
- if (literal != NULL || (right_var != NULL && right_var != var)) { |
- target.TakeValue(); |
- } else { |
- target.GetValue(); |
+ if (node->starts_initialization_block()) { |
+ ASSERT(target.type() == Reference::NAMED || |
+ target.type() == Reference::KEYED); |
+ // Change to slow case in the beginning of an initialization |
+ // block to avoid the quadratic behavior of repeatedly adding |
+ // fast properties. |
+ |
+ // The receiver is the argument to the runtime call. It is the |
+ // first value pushed when the reference was loaded to the |
+ // frame. |
+ frame_->PushElementAt(target.size() - 1); |
+ Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); |
} |
- Load(node->value()); |
- BinaryOperation expr(node, node->binary_op(), node->target(), |
- node->value()); |
- GenericBinaryOperation(&expr, |
- overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
- } |
+ 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. |
+ ASSERT(target.type() == Reference::NAMED || |
+ target.type() == Reference::KEYED); |
+ if (target.type() == Reference::NAMED) { |
+ frame_->Dup(); |
+ // Dup target receiver on stack. |
+ } else { |
+ ASSERT(target.type() == Reference::KEYED); |
+ Result temp = frame_->Pop(); |
+ frame_->Dup(); |
+ frame_->Push(&temp); |
+ } |
+ } |
+ if (node->op() == Token::ASSIGN || |
+ node->op() == Token::INIT_VAR || |
+ node->op() == Token::INIT_CONST) { |
+ Load(node->value()); |
- 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); |
- } 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 { // Assignment is a compound assignment. |
+ Literal* literal = node->value()->AsLiteral(); |
+ bool overwrite_value = |
+ (node->value()->AsBinaryOperation() != NULL && |
+ node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
+ Variable* right_var = node->value()->AsVariableProxy()->AsVariable(); |
+ // There are two cases where the target is not read in the right hand |
+ // side, that are easy to test for: the right hand side is a literal, |
+ // or the right hand side is a different variable. TakeValue |
+ // invalidates the target, with an implicit promise that it will be |
+ // written to again |
+ // before it is read. |
+ if (literal != NULL || (right_var != NULL && right_var != var)) { |
+ target.TakeValue(); |
+ } else { |
+ target.GetValue(); |
+ } |
+ Load(node->value()); |
+ BinaryOperation expr(node, node->binary_op(), node->target(), |
+ node->value()); |
+ GenericBinaryOperation( |
+ &expr, overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
+ } |
+ 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); |
} else { |
- target.SetValue(NOT_CONST_INIT); |
+ 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); |
+ } |
+ if (node->ends_initialization_block()) { |
+ ASSERT(target.type() == Reference::UNLOADED); |
+ // End of initialization block. Revert to fast case. 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. |
+ Result lhs = frame_->Pop(); |
+ Result receiver = frame_->Pop(); |
+ frame_->Push(&lhs); |
+ frame_->Push(&receiver); |
+ Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
+ } |
} |
- if (node->ends_initialization_block()) { |
- ASSERT(target.type() == Reference::UNLOADED); |
- // End of initialization block. Revert to fast case. 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. |
- Result lhs = frame_->Pop(); |
- Result receiver = frame_->Pop(); |
- frame_->Push(&lhs); |
- frame_->Push(&receiver); |
- Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); |
- } |
} |
} |
+ // Stack layout: |
+ // [tos] : result |
+ |
+ ASSERT(frame()->height() == original_height + 1); |
} |