Refactor the somewhat complicated code generation for assignments into
a platform-independent structure and a few platform-specific helpers to do the heavy lifting. Review URL: http://codereview.chromium.org/342073 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3195 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a07146c0cb
commit
b710d66f39
@ -572,129 +572,87 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
Comment cmnt(masm_, "[ Assignment");
|
||||
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
|
||||
|
||||
// Record the source position for the assignment.
|
||||
SetSourcePosition(expr->position());
|
||||
|
||||
// Left-hand side can only be a property, a global or
|
||||
// a (parameter or local) slot.
|
||||
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
||||
Expression* rhs = expr->value();
|
||||
if (var == NULL) {
|
||||
// Assignment to a property.
|
||||
ASSERT(expr->target()->AsProperty() != NULL);
|
||||
Property* prop = expr->target()->AsProperty();
|
||||
Visit(prop->obj());
|
||||
Literal* literal_key = prop->key()->AsLiteral();
|
||||
uint32_t dummy;
|
||||
if (literal_key != NULL &&
|
||||
literal_key->handle()->IsSymbol() &&
|
||||
!String::cast(*(literal_key->handle()))->AsArrayIndex(&dummy)) {
|
||||
// NAMED property assignment
|
||||
Visit(rhs);
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
__ pop(r0);
|
||||
__ mov(r2, Operand(literal_key->handle()));
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
} else {
|
||||
// KEYED property assignment
|
||||
Visit(prop->key());
|
||||
Visit(rhs);
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
__ pop(r0);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
// Drop key from the stack
|
||||
__ pop();
|
||||
}
|
||||
// Overwrite the receiver on the stack with the result if needed.
|
||||
DropAndMove(expr->context(), r0);
|
||||
} else if (var->is_global()) {
|
||||
void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
||||
Variable* var) {
|
||||
if (var->is_global()) {
|
||||
// Assignment to a global variable, use inline caching. Right-hand-side
|
||||
// value is passed in r0, variable name in r2, and the global object on
|
||||
// the stack.
|
||||
|
||||
// Code for the right-hand-side expression depends on its type.
|
||||
if (rhs->AsLiteral() != NULL) {
|
||||
__ mov(r0, Operand(rhs->AsLiteral()->handle()));
|
||||
} else {
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
Visit(rhs);
|
||||
__ pop(r0);
|
||||
}
|
||||
// value is passed in r0, variable name in r2, and the global object
|
||||
// on the stack.
|
||||
__ pop(r0);
|
||||
__ mov(r2, Operand(var->name()));
|
||||
__ ldr(ip, CodeGenerator::GlobalObject());
|
||||
__ push(ip);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
// Overwrite the global object on the stack with the result if needed.
|
||||
DropAndMove(expr->context(), r0);
|
||||
DropAndMove(context, r0);
|
||||
} else {
|
||||
// Local or parameter assignment.
|
||||
|
||||
// Code for the right-hand side expression depends on its type.
|
||||
if (rhs->AsLiteral() != NULL) {
|
||||
// Two cases: 'temp <- (var = constant)', or 'var = constant' with a
|
||||
// discarded result. Always perform the assignment.
|
||||
__ mov(ip, Operand(rhs->AsLiteral()->handle()));
|
||||
__ str(ip, MemOperand(fp, SlotOffset(var->slot())));
|
||||
Move(expr->context(), ip);
|
||||
} else {
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
Visit(rhs);
|
||||
// Load right-hand side into ip.
|
||||
switch (expr->context()) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
// Case 'var = temp'. Discard right-hand-side temporary.
|
||||
__ pop(r0);
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// Case 'temp1 <- (var = temp0)'. Preserve right-hand-side
|
||||
// temporary on the stack.
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kTest:
|
||||
// Case 'if (var = temp) ...'.
|
||||
__ pop(r0);
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
TestAndBranch(r0, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
// Case '(var = temp) || ...' in value context.
|
||||
Label discard;
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
TestAndBranch(r0, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
// Case '(var = temp) && ...' in value context.
|
||||
Label discard;
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
TestAndBranch(r0, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
// Perform assignment and discard value.
|
||||
__ pop(r0);
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// Perform assignment and preserve value.
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kTest:
|
||||
// Perform assignment and test (and discard) value.
|
||||
__ pop(r0);
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
TestAndBranch(r0, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
TestAndBranch(r0, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
TestAndBranch(r0, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitNamedPropertyAssignment(
|
||||
Expression::Context context,
|
||||
Handle<Object> name) {
|
||||
__ pop(r0);
|
||||
__ mov(r2, Operand(name));
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
DropAndMove(context, r0);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitKeyedPropertyAssignment(
|
||||
Expression::Context context) {
|
||||
__ pop(r0);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
// Receiver and key are still on stack.
|
||||
__ add(sp, sp, Operand(2 * kPointerSize));
|
||||
Move(context, r0);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitProperty(Property* expr) {
|
||||
Comment cmnt(masm_, "[ Property");
|
||||
Expression* key = expr->key();
|
||||
|
@ -736,18 +736,36 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
|
||||
}
|
||||
|
||||
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
||||
if (var == NULL) {
|
||||
Property* prop = expr->target()->AsProperty();
|
||||
if (prop == NULL) BAILOUT("non-variable, non-property assignment");
|
||||
Property* prop = expr->target()->AsProperty();
|
||||
if (var != NULL) {
|
||||
// All global variables are supported.
|
||||
if (!var->is_global()) {
|
||||
if (var->slot() == NULL) {
|
||||
// This is a parameter that has rewritten to an arguments access.
|
||||
BAILOUT("non-global/non-slot assignment");
|
||||
}
|
||||
Slot::Type type = var->slot()->type();
|
||||
if (type != Slot::PARAMETER && type != Slot::LOCAL) {
|
||||
BAILOUT("non-parameter/non-local slot assignment");
|
||||
}
|
||||
}
|
||||
} else if (prop != NULL) {
|
||||
ProcessExpression(prop->obj(), Expression::kValue);
|
||||
CHECK_BAILOUT;
|
||||
ProcessExpression(prop->key(), Expression::kValue);
|
||||
} else if (!var->is_global()) {
|
||||
if (var->slot() == NULL) BAILOUT("Assigment with an unsupported LHS.");
|
||||
Slot::Type type = var->slot()->type();
|
||||
if (type != Slot::PARAMETER && type != Slot::LOCAL) {
|
||||
BAILOUT("non-parameter/non-local slot assignment");
|
||||
// We will only visit the key during code generation for keyed property
|
||||
// stores. Leave its expression context uninitialized for named
|
||||
// property stores.
|
||||
Literal* lit = prop->key()->AsLiteral();
|
||||
uint32_t ignored;
|
||||
if (lit == NULL ||
|
||||
!lit->handle()->IsSymbol() ||
|
||||
String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
|
||||
ProcessExpression(prop->key(), Expression::kValue);
|
||||
CHECK_BAILOUT;
|
||||
}
|
||||
} else {
|
||||
// This is a throw reference error.
|
||||
BAILOUT("non-variable/non-property assignment");
|
||||
}
|
||||
|
||||
ProcessExpression(expr->value(), Expression::kValue);
|
||||
|
@ -424,6 +424,47 @@ void FastCodeGenerator::VisitLiteral(Literal* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
Comment cmnt(masm_, "[ Assignment");
|
||||
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
|
||||
|
||||
// Record source code position of the (possible) IC call.
|
||||
SetSourcePosition(expr->position());
|
||||
|
||||
Expression* rhs = expr->value();
|
||||
// Left-hand side can only be a property, a global or a (parameter or
|
||||
// local) slot.
|
||||
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
||||
Property* prop = expr->target()->AsProperty();
|
||||
if (var != NULL) {
|
||||
Visit(rhs);
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
EmitVariableAssignment(expr->context(), var);
|
||||
} else if (prop != NULL) {
|
||||
// Assignment to a property.
|
||||
Visit(prop->obj());
|
||||
ASSERT_EQ(Expression::kValue, prop->obj()->context());
|
||||
// Use the expression context of the key subexpression to detect whether
|
||||
// we have decided to us a named or keyed IC.
|
||||
if (prop->key()->context() == Expression::kUninitialized) {
|
||||
ASSERT(prop->key()->AsLiteral() != NULL);
|
||||
Visit(rhs);
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
EmitNamedPropertyAssignment(expr->context(),
|
||||
prop->key()->AsLiteral()->handle());
|
||||
} else {
|
||||
Visit(prop->key());
|
||||
ASSERT_EQ(Expression::kValue, prop->key()->context());
|
||||
Visit(rhs);
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
EmitKeyedPropertyAssignment(expr->context());
|
||||
}
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -75,6 +75,21 @@ class FastCodeGenerator: public AstVisitor {
|
||||
void EmitCallWithStub(Call* expr);
|
||||
void EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info);
|
||||
|
||||
// Platform-specific support for compiling assignments.
|
||||
|
||||
// Complete a variable assignment. The right-hand-side value are expected
|
||||
// on top of the stack.
|
||||
void EmitVariableAssignment(Expression::Context context, Variable* var);
|
||||
|
||||
// Complete a named property assignment. The receiver and right-hand-side
|
||||
// value are expected on top of the stack.
|
||||
void EmitNamedPropertyAssignment(Expression::Context context,
|
||||
Handle<Object> name);
|
||||
|
||||
// Complete a keyed property assignment. The reciever, key, and
|
||||
// right-hand-side value are expected on top of the stack.
|
||||
void EmitKeyedPropertyAssignment(Expression::Context context);
|
||||
|
||||
void SetFunctionPosition(FunctionLiteral* fun);
|
||||
void SetReturnPosition(FunctionLiteral* fun);
|
||||
void SetStatementPosition(Statement* stmt);
|
||||
|
@ -586,131 +586,88 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
Comment cmnt(masm_, "[ Assignment");
|
||||
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
|
||||
|
||||
// Record the source position for the assignment.
|
||||
SetSourcePosition(expr->position());
|
||||
|
||||
// Left-hand side can only be a property, a global or
|
||||
// a (parameter or local) slot.
|
||||
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
||||
Expression* rhs = expr->value();
|
||||
if (var == NULL) {
|
||||
// Assignment to a property.
|
||||
ASSERT(expr->target()->AsProperty() != NULL);
|
||||
Property* prop = expr->target()->AsProperty();
|
||||
Visit(prop->obj());
|
||||
Literal* literal_key = prop->key()->AsLiteral();
|
||||
uint32_t dummy;
|
||||
if (literal_key != NULL &&
|
||||
literal_key->handle()->IsSymbol() &&
|
||||
!String::cast(*(literal_key->handle()))->AsArrayIndex(&dummy)) {
|
||||
// NAMED property assignment
|
||||
Visit(rhs);
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
__ pop(eax);
|
||||
__ mov(ecx, Immediate(literal_key->handle()));
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
__ call(ic, RelocInfo::CODE_TARGET);
|
||||
__ nop();
|
||||
} else {
|
||||
// KEYED property assignment
|
||||
Visit(prop->key());
|
||||
Visit(rhs);
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
__ pop(eax);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
||||
__ call(ic, RelocInfo::CODE_TARGET);
|
||||
__ nop();
|
||||
// Drop key from the stack
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
}
|
||||
// Overwrite the receiver on the stack with the result if needed.
|
||||
DropAndMove(expr->context(), eax);
|
||||
} else if (var->is_global()) {
|
||||
void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
||||
Variable* var) {
|
||||
if (var->is_global()) {
|
||||
// Assignment to a global variable, use inline caching. Right-hand-side
|
||||
// value is passed in eax, variable name in ecx, and the global object
|
||||
// on the stack.
|
||||
|
||||
// Code for the right-hand-side expression depends on its type.
|
||||
if (rhs->AsLiteral() != NULL) {
|
||||
__ mov(eax, rhs->AsLiteral()->handle());
|
||||
} else {
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
Visit(rhs);
|
||||
__ pop(eax);
|
||||
}
|
||||
// Record position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
__ pop(eax);
|
||||
__ mov(ecx, var->name());
|
||||
__ push(CodeGenerator::GlobalObject());
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
__ call(ic, RelocInfo::CODE_TARGET);
|
||||
// Overwrite the global object on the stack with the result if needed.
|
||||
DropAndMove(expr->context(), eax);
|
||||
DropAndMove(context, eax);
|
||||
} else {
|
||||
// Local or parameter assignment.
|
||||
ASSERT(var->slot() != NULL);
|
||||
|
||||
// Code for the right-hand side expression depends on its type.
|
||||
if (rhs->AsLiteral() != NULL) {
|
||||
// Two cases: 'temp <- (var = constant)', or 'var = constant' with a
|
||||
// discarded result. Always perform the assignment.
|
||||
__ mov(eax, rhs->AsLiteral()->handle());
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
Move(expr->context(), eax);
|
||||
} else {
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
Visit(rhs);
|
||||
switch (expr->context()) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
// Case 'var = temp'. Discard right-hand-side temporary.
|
||||
__ pop(Operand(ebp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// Case 'temp1 <- (var = temp0)'. Preserve right-hand-side
|
||||
// temporary on the stack.
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
// Case 'if (var = temp) ...'.
|
||||
__ pop(eax);
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
TestAndBranch(eax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
// Case '(var = temp) || ...' in value context.
|
||||
Label discard;
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
TestAndBranch(eax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
// Case '(var = temp) && ...' in value context.
|
||||
Label discard;
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
TestAndBranch(eax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
// Perform assignment and discard value.
|
||||
__ pop(Operand(ebp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// Perform assignment and preserve value.
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
// Perform assignment and test (and discard) value.
|
||||
__ pop(eax);
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
TestAndBranch(eax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
TestAndBranch(eax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
TestAndBranch(eax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitNamedPropertyAssignment(
|
||||
Expression::Context context,
|
||||
Handle<Object> name) {
|
||||
__ pop(eax);
|
||||
__ mov(ecx, name);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
__ call(ic, RelocInfo::CODE_TARGET);
|
||||
DropAndMove(context, eax);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitKeyedPropertyAssignment(
|
||||
Expression::Context context) {
|
||||
__ pop(eax);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
||||
__ call(ic, RelocInfo::CODE_TARGET);
|
||||
// This nop signals to the IC that there is no inlined code at the call
|
||||
// site for it to patch.
|
||||
__ nop();
|
||||
// Receiver and key are still on stack.
|
||||
__ add(Operand(esp), Immediate(2 * kPointerSize));
|
||||
Move(context, eax);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitProperty(Property* expr) {
|
||||
Comment cmnt(masm_, "[ Property");
|
||||
Expression* key = expr->key();
|
||||
|
@ -600,130 +600,88 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
Comment cmnt(masm_, "[ Assignment");
|
||||
ASSERT(expr->op() == Token::ASSIGN || expr->op() == Token::INIT_VAR);
|
||||
|
||||
// Record the source position for the assignment.
|
||||
SetSourcePosition(expr->position());
|
||||
|
||||
// Left-hand side can only be a property, a global or
|
||||
// a (parameter or local) slot.
|
||||
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
|
||||
Expression* rhs = expr->value();
|
||||
if (var == NULL) {
|
||||
// Assignment to a property.
|
||||
ASSERT(expr->target()->AsProperty() != NULL);
|
||||
Property* prop = expr->target()->AsProperty();
|
||||
Visit(prop->obj());
|
||||
Literal* literal_key = prop->key()->AsLiteral();
|
||||
uint32_t dummy;
|
||||
if (literal_key != NULL &&
|
||||
literal_key->handle()->IsSymbol() &&
|
||||
!String::cast(*(literal_key->handle()))->AsArrayIndex(&dummy)) {
|
||||
// NAMED property assignment
|
||||
Visit(rhs);
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
__ pop(rax);
|
||||
__ Move(rcx, literal_key->handle());
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
__ call(ic, RelocInfo::CODE_TARGET);
|
||||
__ nop();
|
||||
} else {
|
||||
// KEYED property assignment
|
||||
Visit(prop->key());
|
||||
Visit(rhs);
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
__ pop(rax);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
||||
__ call(ic, RelocInfo::CODE_TARGET);
|
||||
__ nop();
|
||||
// Drop key from the stack
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
}
|
||||
// Overwrite the receiver on the stack with the result if needed.
|
||||
DropAndMove(expr->context(), rax);
|
||||
} else if (var->is_global()) {
|
||||
void FastCodeGenerator::EmitVariableAssignment(Expression::Context context,
|
||||
Variable* var) {
|
||||
if (var->is_global()) {
|
||||
// Assignment to a global variable, use inline caching. Right-hand-side
|
||||
// value is passed in rax, variable name in rcx, and the global object
|
||||
// on the stack.
|
||||
|
||||
// Code for the right-hand-side expression depends on its type.
|
||||
if (rhs->AsLiteral() != NULL) {
|
||||
__ Move(rax, rhs->AsLiteral()->handle());
|
||||
} else {
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
Visit(rhs);
|
||||
__ pop(rax);
|
||||
}
|
||||
// Record position for debugger.
|
||||
SetSourcePosition(expr->position());
|
||||
__ pop(rax);
|
||||
__ Move(rcx, var->name());
|
||||
__ push(CodeGenerator::GlobalObject());
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
// Overwrite the global object on the stack with the result if needed.
|
||||
DropAndMove(expr->context(), rax);
|
||||
DropAndMove(context, rax);
|
||||
} else {
|
||||
// Local or parameter assignment.
|
||||
|
||||
// Code for the right-hand-side expression depends on its type.
|
||||
if (rhs->AsLiteral() != NULL) {
|
||||
// Two cases: 'temp <- (var = constant)', or 'var = constant' with a
|
||||
// discarded result. Always perform the assignment.
|
||||
__ Move(kScratchRegister, rhs->AsLiteral()->handle());
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
|
||||
Move(expr->context(), kScratchRegister);
|
||||
} else {
|
||||
ASSERT_EQ(Expression::kValue, rhs->context());
|
||||
Visit(rhs);
|
||||
switch (expr->context()) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
// Case 'var = temp'. Discard right-hand-side temporary.
|
||||
__ pop(Operand(rbp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// Case 'temp1 <- (var = temp0)'. Preserve right-hand-side
|
||||
// temporary on the stack.
|
||||
__ movq(kScratchRegister, Operand(rsp, 0));
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
// Case 'if (var = temp) ...'.
|
||||
__ pop(rax);
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
TestAndBranch(rax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
// Case '(var = temp) || ...' in value context.
|
||||
Label discard;
|
||||
__ movq(rax, Operand(rsp, 0));
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
TestAndBranch(rax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
// Case '(var = temp) && ...' in value context.
|
||||
Label discard;
|
||||
__ movq(rax, Operand(rsp, 0));
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
TestAndBranch(rax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
// Perform assignment and discard value.
|
||||
__ pop(Operand(rbp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// Perform assignment and preserve value.
|
||||
__ movq(rax, Operand(rsp, 0));
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
// Perform assignment and test (and discard) value.
|
||||
__ pop(rax);
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
TestAndBranch(rax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
__ movq(rax, Operand(rsp, 0));
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
TestAndBranch(rax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
__ movq(rax, Operand(rsp, 0));
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
TestAndBranch(rax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitNamedPropertyAssignment(
|
||||
Expression::Context context,
|
||||
Handle<Object> name) {
|
||||
__ pop(rax);
|
||||
__ Move(rcx, name);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
DropAndMove(context, rax);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitKeyedPropertyAssignment(
|
||||
Expression::Context context) {
|
||||
__ pop(rax);
|
||||
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||
// This nop signals to the IC that there is no inlined code at the call
|
||||
// site for it to patch.
|
||||
__ nop();
|
||||
// Receiver and key are still on stack.
|
||||
__ addq(rsp, Immediate(2 * kPointerSize));
|
||||
Move(context, rax);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitProperty(Property* expr) {
|
||||
Comment cmnt(masm_, "[ Property");
|
||||
Expression* key = expr->key();
|
||||
|
Loading…
Reference in New Issue
Block a user