From: fschneider@chromium.org Date: Fri, 11 Dec 2009 16:09:16 +0000 (+0000) Subject: Adding compound assignments to the top-level compiler. X-Git-Tag: upstream/4.7.83~22819 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c25151faa6934df9ec9af32417f2af22b0f08520;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/arm/fast-codegen-arm.cc b/src/arm/fast-codegen-arm.cc index 04fff5ca1..303f0a042 100644 --- a/src/arm/fast-codegen-arm.cc +++ b/src/arm/fast-codegen-arm.cc @@ -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 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 ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + Move(context, r0); +} + + +void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { + Handle 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); diff --git a/src/ast.h b/src/ast.h index c27d558a2..00f36290a 100644 --- a/src/ast.h +++ b/src/ast.h @@ -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 diff --git a/src/compiler.cc b/src/compiler.cc index d8dd65036..46b5aa0e5 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -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(); diff --git a/src/fast-codegen.cc b/src/fast-codegen.cc index 5c4a70b08..e53f43af0 100644 --- a/src/fast-codegen.cc +++ b/src/fast-codegen.cc @@ -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; } diff --git a/src/fast-codegen.h b/src/fast-codegen.h index 9a8c990e4..53d3f244b 100644 --- a/src/fast-codegen.h +++ b/src/fast-codegen.h @@ -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); diff --git a/src/ia32/fast-codegen-ia32.cc b/src/ia32/fast-codegen-ia32.cc index b6e16f322..b7b9a1522 100644 --- a/src/ia32/fast-codegen-ia32.cc +++ b/src/ia32/fast-codegen-ia32.cc @@ -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 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 ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + __ call(ic, RelocInfo::CODE_TARGET); + Move(context, eax); +} + + +void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { + Handle 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); diff --git a/src/token.h b/src/token.h index 42f3ce3eb..2a228d67c 100644 --- a/src/token.h +++ b/src/token.h @@ -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) \ diff --git a/src/x64/fast-codegen-x64.cc b/src/x64/fast-codegen-x64.cc index 69a2ff3af..192c7b0ce 100644 --- a/src/x64/fast-codegen-x64.cc +++ b/src/x64/fast-codegen-x64.cc @@ -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 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 ic(Builtins::builtin(Builtins::LoadIC_Initialize)); + __ Call(ic, RelocInfo::CODE_TARGET); + Move(context, rax); +} + + +void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context) { + Handle 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);