Add EmitNamedStore and CallStoreIC(name, is_contextual) to x64 platform.
Review URL: http://codereview.chromium.org/3050008 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5108 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
6612b98dcf
commit
fe02d5e25f
@ -5006,16 +5006,150 @@ void CodeGenerator::EmitSlotAssignment(Assignment* node) {
|
||||
}
|
||||
|
||||
|
||||
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::EmitNamedLoad(Handle<String> name, bool is_contextual) {
|
||||
}
|
||||
|
||||
|
||||
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 rax instruction following the call signals that the inobject
|
||||
// property case was inlined. Ensure that there is not a test rax
|
||||
// instruction here.
|
||||
__ nop();
|
||||
|
||||
ASSERT_EQ(expected_height, frame()->height());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Result CodeGenerator::EmitKeyedLoad() {
|
||||
#ifdef DEBUG
|
||||
int original_height = frame()->height();
|
||||
|
@ -456,10 +456,15 @@ class CodeGenerator: public AstVisitor {
|
||||
|
||||
// Support for compiling assignment expressions.
|
||||
void EmitSlotAssignment(Assignment* node);
|
||||
void EmitNamedPropertyAssignment(Assignment* node);
|
||||
|
||||
// Receiver is passed on the frame and not consumed.
|
||||
Result EmitNamedLoad(Handle<String> name, bool is_contextual);
|
||||
|
||||
// If the store is contextual, value is passed on the frame and consumed.
|
||||
// Otherwise, receiver and value are passed on the frame and consumed.
|
||||
Result EmitNamedStore(Handle<String> name, bool is_contextual);
|
||||
|
||||
// Load a property of an object, returning it in a Result.
|
||||
// The object and the property name are passed on the stack, and
|
||||
// not changed.
|
||||
|
@ -1168,6 +1168,26 @@ Result VirtualFrame::CallCommonStoreIC(Handle<Code> ic,
|
||||
}
|
||||
|
||||
|
||||
Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
|
||||
// Value and (if not contextual) receiver are on top of the frame.
|
||||
// The IC expects name in rcx, value in rax, and receiver in rdx.
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
Result value = Pop();
|
||||
if (is_contextual) {
|
||||
PrepareForCall(0, 0);
|
||||
value.ToRegister(rax);
|
||||
__ movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||
value.Unuse();
|
||||
} else {
|
||||
Result receiver = Pop();
|
||||
PrepareForCall(0, 0);
|
||||
MoveResultsToRegisters(&value, &receiver, rax, rdx);
|
||||
}
|
||||
__ Move(rcx, name);
|
||||
return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
|
||||
}
|
||||
|
||||
|
||||
Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
|
||||
int arg_count,
|
||||
int loop_nesting) {
|
||||
|
@ -341,7 +341,7 @@ class VirtualFrame : public ZoneObject {
|
||||
// and by the order of the three arguments on the frame.
|
||||
Result CallCommonStoreIC(Handle<Code> ic,
|
||||
Result* value,
|
||||
Result *key,
|
||||
Result* key,
|
||||
Result* receiver);
|
||||
|
||||
// Call store IC. Name, value, and receiver are found on top
|
||||
@ -354,6 +354,10 @@ class VirtualFrame : public ZoneObject {
|
||||
return CallCommonStoreIC(ic, &value, &name, &receiver);
|
||||
}
|
||||
|
||||
// Call store IC. If the load is contextual, value is found on top of the
|
||||
// frame. If not, value and receiver are on the frame. Both are dropped.
|
||||
Result CallStoreIC(Handle<String> name, bool is_contextual);
|
||||
|
||||
// Call keyed store IC. Value, key, and receiver are found on top
|
||||
// of the frame. All are dropped.
|
||||
Result CallKeyedStoreIC() {
|
||||
|
Loading…
Reference in New Issue
Block a user