Commit 6612b98d authored by whesse@chromium.org's avatar whesse@chromium.org

Add EmitSlotAssignment to x64 platform.

Review URL: http://codereview.chromium.org/2878042

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5107 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 74f9789f
...@@ -4965,103 +4965,158 @@ void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { ...@@ -4965,103 +4965,158 @@ void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) {
} }
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) { 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 (var != NULL && !var->is_global()) {
if (target.is_illegal()) { EmitSlotAssignment(node);
// 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 (node->starts_initialization_block()) { } else {
ASSERT(target.type() == Reference::NAMED || Comment cmnt(masm_, "[ Assignment");
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 { Reference target(this, node->target(), node->is_compound());
// first value pushed when the reference was loaded to the if (target.is_illegal()) {
// frame. // Fool the virtual frame into thinking that we left the assignment's
frame_->PushElementAt(target.size() - 1); // value on the frame.
Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1); frame_->Push(Smi::FromInt(0));
} return;
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());
} 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(), if (node->starts_initialization_block()) {
node->value()); ASSERT(target.type() == Reference::NAMED ||
GenericBinaryOperation(&expr, target.type() == Reference::KEYED);
overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); // Change to slow case in the beginning of an initialization
} // block to avoid the quadratic behavior of repeatedly adding
// fast properties.
if (var != NULL &&
var->mode() == Variable::CONST && // The receiver is the argument to the runtime call. It is the
node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { // first value pushed when the reference was loaded to the
// Assignment ignored - leave the value on the stack. // frame.
UnloadReference(&target); frame_->PushElementAt(target.size() - 1);
} else { Result ignored = frame_->CallRuntime(Runtime::kToSlowProperties, 1);
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()) { if (node->ends_initialization_block()) {
ASSERT(target.type() == Reference::UNLOADED); // Add an extra copy of the receiver to the frame, so that it can be
// End of initialization block. Revert to fast case. The // converted back to fast case after the assignment.
// argument to the runtime call is the extra copy of the receiver, ASSERT(target.type() == Reference::NAMED ||
// which is below the value of the assignment. target.type() == Reference::KEYED);
// Swap the receiver and the value of the assignment expression. if (target.type() == Reference::NAMED) {
Result lhs = frame_->Pop(); frame_->Dup();
Result receiver = frame_->Pop(); // Dup target receiver on stack.
frame_->Push(&lhs); } else {
frame_->Push(&receiver); ASSERT(target.type() == Reference::KEYED);
Result ignored = frame_->CallRuntime(Runtime::kToFastProperties, 1); 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());
} 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 {
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);
}
} }
} }
} }
// Stack layout:
// [tos] : result
ASSERT(frame()->height() == original_height + 1);
} }
......
...@@ -454,6 +454,9 @@ class CodeGenerator: public AstVisitor { ...@@ -454,6 +454,9 @@ class CodeGenerator: public AstVisitor {
// value in place. // value in place.
void StoreToSlot(Slot* slot, InitState init_state); void StoreToSlot(Slot* slot, InitState init_state);
// Support for compiling assignment expressions.
void EmitSlotAssignment(Assignment* node);
// Receiver is passed on the frame and not consumed. // Receiver is passed on the frame and not consumed.
Result EmitNamedLoad(Handle<String> name, bool is_contextual); Result EmitNamedLoad(Handle<String> name, bool is_contextual);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment