Adding compound assignments to the top-level compiler.
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 11 Dec 2009 16:09:16 +0000 (16:09 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 11 Dec 2009 16:09:16 +0000 (16:09 +0000)
Review URL: http://codereview.chromium.org/486008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3455 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/fast-codegen-arm.cc
src/ast.h
src/compiler.cc
src/fast-codegen.cc
src/fast-codegen.h
src/ia32/fast-codegen-ia32.cc
src/token.h
src/x64/fast-codegen-x64.cc

index 04fff5c..303f0a0 100644 (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);
index c27d558..00f3629 100644 (file)
--- 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
index d8dd650..46b5aa0 100644 (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();
index 5c4a70b..e53f43a 100644 (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;
   }
index 9a8c990..53d3f24 100644 (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);
index b6e16f3..b7b9a15 100644 (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);
index 42f3ce3..2a228d6 100644 (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)                                                     \
index 69a2ff3..192c7b0 100644 (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);