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:
kmillikin@chromium.org 2009-11-02 11:01:47 +00:00
parent a07146c0cb
commit b710d66f39
6 changed files with 284 additions and 337 deletions

View File

@ -572,103 +572,41 @@ 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);
// 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()) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
// Case 'var = temp'. Discard right-hand-side temporary.
// Perform assignment and discard value.
__ 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.
// Perform assignment and preserve value.
__ ldr(r0, MemOperand(sp));
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
break;
case Expression::kTest:
// Case 'if (var = temp) ...'.
// 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: {
// Case '(var = temp) || ...' in value context.
Label discard;
__ ldr(r0, MemOperand(sp));
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
@ -679,7 +617,6 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
break;
}
case Expression::kTestValue: {
// Case '(var = temp) && ...' in value context.
Label discard;
__ ldr(r0, MemOperand(sp));
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
@ -691,7 +628,28 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
}
}
}
}
}
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);
}

View File

@ -736,19 +736,37 @@ 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");
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.");
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;
// 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);
}

View File

@ -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();
}

View File

@ -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);

View File

@ -586,105 +586,39 @@ 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());
__ 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()) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
// Case 'var = temp'. Discard right-hand-side temporary.
// Perform assignment and discard value.
__ pop(Operand(ebp, SlotOffset(var->slot())));
break;
case Expression::kValue:
// Case 'temp1 <- (var = temp0)'. Preserve right-hand-side
// temporary on the stack.
// Perform assignment and preserve value.
__ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
break;
case Expression::kTest:
// Case 'if (var = temp) ...'.
// 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: {
// Case '(var = temp) || ...' in value context.
Label discard;
__ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
@ -695,7 +629,6 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
break;
}
case Expression::kTestValue: {
// Case '(var = temp) && ...' in value context.
Label discard;
__ mov(eax, Operand(esp, 0));
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
@ -707,7 +640,31 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
}
}
}
}
}
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);
}

View File

@ -600,104 +600,39 @@ 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());
__ 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()) {
switch (context) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
// Case 'var = temp'. Discard right-hand-side temporary.
// Perform assignment and discard value.
__ 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);
// Perform assignment and preserve value.
__ movq(rax, Operand(rsp, 0));
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
break;
case Expression::kTest:
// Case 'if (var = temp) ...'.
// 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: {
// Case '(var = temp) || ...' in value context.
Label discard;
__ movq(rax, Operand(rsp, 0));
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
@ -708,7 +643,6 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
break;
}
case Expression::kTestValue: {
// Case '(var = temp) && ...' in value context.
Label discard;
__ movq(rax, Operand(rsp, 0));
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
@ -720,7 +654,31 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
}
}
}
}
}
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);
}