Adding compound assignments to the top-level compiler.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3455 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
fschneider@chromium.org 2009-12-11 16:09:16 +00:00
parent a4ad7b8bf3
commit c25151faa6
8 changed files with 180 additions and 35 deletions

View File

@ -541,18 +541,24 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Comment cmnt(masm_, "[ VariableProxy");
Expression* rewrite = expr->var()->rewrite();
EmitVariableLoad(expr->var(), expr->context());
}
void FastCodeGenerator::EmitVariableLoad(Variable* var,
Expression::Context context) {
Expression* rewrite = var->rewrite();
if (rewrite == NULL) {
ASSERT(expr->var()->is_global());
ASSERT(var->is_global());
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in r2 and the global
// object on the stack.
__ ldr(ip, CodeGenerator::GlobalObject());
__ push(ip);
__ mov(r2, Operand(expr->name()));
__ mov(r2, Operand(var->name()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
DropAndMove(expr->context(), r0);
DropAndMove(context, r0);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
@ -573,7 +579,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
UNREACHABLE();
}
}
Move(expr->context(), slot, r0);
Move(context, slot, r0);
} else {
// A variable has been rewritten into an explicit access to
// an object property.
@ -608,7 +614,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
__ Call(ic, RelocInfo::CODE_TARGET);
// Drop key and object left on the stack by IC, and push the result.
DropAndMove(expr->context(), r0, 2);
DropAndMove(context, r0, 2);
}
}
@ -831,6 +837,34 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
}
void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
Expression::Context context) {
Literal* key = prop->key()->AsLiteral();
__ mov(r2, Operand(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
Move(context, r0);
}
void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) {
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
Move(context, r0);
}
void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
Expression::Context context) {
__ pop(r0);
__ pop(r1);
GenericBinaryOpStub stub(op,
NO_OVERWRITE);
__ CallStub(&stub);
Move(context, r0);
}
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);

View File

@ -1241,6 +1241,8 @@ class Assignment: public Expression {
Expression* target() const { return target_; }
Expression* value() const { return value_; }
int position() { return pos_; }
// This check relies on the definition order of token in token.h.
bool is_compound() const { return op() > Token::ASSIGN; }
// An initialization block is a series of statments of the form
// x.y.z.a = ...; x.y.z.b = ...; etc. The parser marks the beginning and

View File

@ -883,9 +883,6 @@ void CodeGenSelector::VisitAssignment(Assignment* expr) {
// non-context (stack-allocated) locals, and global variables.
Token::Value op = expr->op();
if (op == Token::INIT_CONST) BAILOUT("initialize constant");
if (op != Token::ASSIGN && op != Token::INIT_VAR) {
BAILOUT("compound assignment");
}
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
Property* prop = expr->target()->AsProperty();

View File

@ -512,7 +512,6 @@ 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());
@ -530,26 +529,60 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
: KEYED_PROPERTY;
}
Expression* rhs = expr->value();
ASSERT_EQ(Expression::kValue, rhs->context());
// Evaluate LHS expression.
switch (assign_type) {
case VARIABLE:
Visit(rhs);
EmitVariableAssignment(expr);
// Nothing to do here.
break;
case NAMED_PROPERTY:
Visit(prop->obj());
ASSERT_EQ(Expression::kValue, prop->obj()->context());
Visit(rhs);
EmitNamedPropertyAssignment(expr);
break;
case KEYED_PROPERTY:
Visit(prop->obj());
ASSERT_EQ(Expression::kValue, prop->obj()->context());
Visit(prop->key());
ASSERT_EQ(Expression::kValue, prop->key()->context());
Visit(rhs);
break;
}
// If we have a compound assignment: Get value of LHS expression and
// store in on top of the stack.
// Note: Relies on kValue context being 'stack'.
if (expr->is_compound()) {
switch (assign_type) {
case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
Expression::kValue);
break;
case NAMED_PROPERTY:
EmitNamedPropertyLoad(prop, Expression::kValue);
break;
case KEYED_PROPERTY:
EmitKeyedPropertyLoad(Expression::kValue);
break;
}
}
// Evaluate RHS expression.
Expression* rhs = expr->value();
ASSERT_EQ(Expression::kValue, rhs->context());
Visit(rhs);
// If we have a compount assignment: Apply operator.
if (expr->is_compound()) {
EmitCompoundAssignmentOp(expr->binary_op(), Expression::kValue);
}
// Store the value.
switch (assign_type) {
case VARIABLE:
EmitVariableAssignment(expr);
break;
case NAMED_PROPERTY:
EmitNamedPropertyAssignment(expr);
break;
case KEYED_PROPERTY:
EmitKeyedPropertyAssignment(expr);
break;
}

View File

@ -242,8 +242,23 @@ class FastCodeGenerator: public AstVisitor {
void EmitCallWithStub(Call* expr);
void EmitCallWithIC(Call* expr, RelocInfo::Mode reloc_info);
// Platform-specific code for loading variables.
void EmitVariableLoad(Variable* expr, Expression::Context context);
// Platform-specific support for compiling assignments.
// Load a value from a named property and push the result on the stack.
// The receiver is left on the stack by the IC.
void EmitNamedPropertyLoad(Property* expr, Expression::Context context);
// Load a value from a named property and push the result on the stack.
// The receiver and the key is left on the stack by the IC.
void EmitKeyedPropertyLoad(Expression::Context context);
// Apply the compound assignment operator. Expects both operands on top
// of the stack.
void EmitCompoundAssignmentOp(Token::Value op, Expression::Context context);
// Complete a variable assignment. The right-hand-side value is expected
// on top of the stack.
void EmitVariableAssignment(Assignment* expr);

View File

@ -535,14 +535,20 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Comment cmnt(masm_, "[ VariableProxy");
Expression* rewrite = expr->var()->rewrite();
EmitVariableLoad(expr->var(), expr->context());
}
void FastCodeGenerator::EmitVariableLoad(Variable* var,
Expression::Context context) {
Expression* rewrite = var->rewrite();
if (rewrite == NULL) {
ASSERT(expr->var()->is_global());
ASSERT(var->is_global());
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in ecx and the global
// object on the stack.
__ push(CodeGenerator::GlobalObject());
__ mov(ecx, expr->name());
__ mov(ecx, var->name());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
// By emitting a nop we make sure that we do not have a test eax
@ -550,8 +556,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
// Remember that the assembler may choose to do peephole optimization
// (eg, push/pop elimination).
__ nop();
DropAndMove(expr->context(), eax);
DropAndMove(context, eax);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
@ -572,7 +577,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
UNREACHABLE();
}
}
Move(expr->context(), slot, eax);
Move(context, slot, eax);
} else {
Comment cmnt(masm_, "Variable rewritten to Property");
// A variable has been rewritten into an explicit access to
@ -606,9 +611,8 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
// Notice: We must not have a "test eax, ..." instruction after
// the call. It is treated specially by the LoadIC code.
__ nop();
// Drop key and object left on the stack by IC, and push the result.
DropAndMove(expr->context(), eax, 2);
// Drop key and object left on the stack by IC.
DropAndMove(context, eax, 2);
}
}
@ -822,6 +826,32 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
}
void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop, Expression::Context context) {
Literal* key = prop->key()->AsLiteral();
__ mov(ecx, Immediate(key->handle()));
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
Move(context, eax);
}
void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) {
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ call(ic, RelocInfo::CODE_TARGET);
Move(context, eax);
}
void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
Expression::Context context) {
GenericBinaryOpStub stub(op,
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
Move(context, eax);
}
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);

View File

@ -66,8 +66,9 @@ namespace internal {
T(DEC, "--", 0) \
\
/* Assignment operators. */ \
/* IsAssignmentOp() relies on this block of enum values */ \
/* being contiguous and sorted in the same order! */ \
/* IsAssignmentOp() and Assignment::is_compound() relies on */ \
/* this block of enum values being contiguous and sorted in the */ \
/* same order! */ \
T(INIT_VAR, "=init_var", 2) /* AST-use only. */ \
T(INIT_CONST, "=init_const", 2) /* AST-use only. */ \
T(ASSIGN, "=", 2) \

View File

@ -545,14 +545,20 @@ void FastCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
Comment cmnt(masm_, "[ VariableProxy");
Expression* rewrite = expr->var()->rewrite();
EmitVariableLoad(expr->var(), expr->context());
}
void FastCodeGenerator::EmitVariableLoad(Variable* var,
Expression::Context context) {
Expression* rewrite = var->rewrite();
if (rewrite == NULL) {
ASSERT(expr->var()->is_global());
ASSERT(var->is_global());
Comment cmnt(masm_, "Global variable");
// Use inline caching. Variable name is passed in rcx and the global
// object on the stack.
__ push(CodeGenerator::GlobalObject());
__ Move(rcx, expr->name());
__ Move(rcx, var->name());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
// A test rax instruction following the call is used by the IC to
@ -560,7 +566,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
// is no test rax instruction here.
__ nop();
DropAndMove(expr->context(), rax);
DropAndMove(context, rax);
} else if (rewrite->AsSlot() != NULL) {
Slot* slot = rewrite->AsSlot();
if (FLAG_debug_code) {
@ -581,7 +587,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
UNREACHABLE();
}
}
Move(expr->context(), slot, rax);
Move(context, slot, rax);
} else {
// A variable has been rewritten into an explicit access to
// an object property.
@ -615,7 +621,7 @@ void FastCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
// the call. It is treated specially by the LoadIC code.
// Drop key and object left on the stack by IC, and push the result.
DropAndMove(expr->context(), rax, 2);
DropAndMove(context, rax, 2);
}
}
@ -829,6 +835,33 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
}
void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
Expression::Context context) {
Literal* key = prop->key()->AsLiteral();
__ Move(rcx, key->handle());
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
Move(context, rax);
}
void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) {
Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
__ Call(ic, RelocInfo::CODE_TARGET);
Move(context, rax);
}
void FastCodeGenerator::EmitCompoundAssignmentOp(Token::Value op,
Expression::Context context) {
GenericBinaryOpStub stub(op,
NO_OVERWRITE,
NO_GENERIC_BINARY_FLAGS);
__ CallStub(&stub);
Move(context, rax);
}
void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
Variable* var = expr->target()->AsVariableProxy()->AsVariable();
ASSERT(var != NULL);