Revision: 3455 Author: [email protected] Date: Fri Dec 11 08:09:16 2009 Log: Adding compound assignments to the top-level compiler.
Review URL: http://codereview.chromium.org/486008 http://code.google.com/p/v8/source/detail?r=3455 Modified: /branches/bleeding_edge/src/arm/fast-codegen-arm.cc /branches/bleeding_edge/src/ast.h /branches/bleeding_edge/src/compiler.cc /branches/bleeding_edge/src/fast-codegen.cc /branches/bleeding_edge/src/fast-codegen.h /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc /branches/bleeding_edge/src/token.h /branches/bleeding_edge/src/x64/fast-codegen-x64.cc ======================================= --- /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Thu Dec 10 06:06:08 2009 +++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Fri Dec 11 08:09:16 2009 @@ -541,18 +541,24 @@ 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 @@ 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 @@ __ 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); } } @@ -829,6 +835,34 @@ } } } + + +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) { ======================================= --- /branches/bleeding_edge/src/ast.h Thu Nov 26 16:28:06 2009 +++ /branches/bleeding_edge/src/ast.h Fri Dec 11 08:09:16 2009 @@ -1241,6 +1241,8 @@ 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 ======================================= --- /branches/bleeding_edge/src/compiler.cc Thu Dec 10 06:06:08 2009 +++ /branches/bleeding_edge/src/compiler.cc Fri Dec 11 08:09:16 2009 @@ -883,9 +883,6 @@ // 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(); ======================================= --- /branches/bleeding_edge/src/fast-codegen.cc Thu Dec 10 06:06:08 2009 +++ /branches/bleeding_edge/src/fast-codegen.cc Fri Dec 11 08:09:16 2009 @@ -512,7 +512,6 @@ 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 @@ : 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; } ======================================= --- /branches/bleeding_edge/src/fast-codegen.h Thu Dec 10 06:06:08 2009 +++ /branches/bleeding_edge/src/fast-codegen.h Fri Dec 11 08:09:16 2009 @@ -242,8 +242,23 @@ 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); ======================================= --- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Thu Dec 10 06:06:08 2009 +++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc Fri Dec 11 08:09:16 2009 @@ -535,14 +535,20 @@ 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 @@ // 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 @@ 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 @@ // 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); } } @@ -820,6 +824,32 @@ } } } + + +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) { ======================================= --- /branches/bleeding_edge/src/token.h Fri Dec 11 02:40:01 2009 +++ /branches/bleeding_edge/src/token.h Fri Dec 11 08:09:16 2009 @@ -66,8 +66,9 @@ 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) \ ======================================= --- /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Thu Dec 10 06:06:08 2009 +++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Fri Dec 11 08:09:16 2009 @@ -545,14 +545,20 @@ 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 @@ // 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 @@ 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 @@ // 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); } } @@ -827,6 +833,33 @@ } } } + + +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) { -- v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev
