Revision: 3530
Author: [email protected]
Date: Mon Jan  4 05:56:31 2010
Log: Added general pre- and postfix count operations to top-level compiler.

Until now we only supported postfix operations on global variables.
This change add generic count operations to the top-level compiler.

I tried to re-use code from the code generator used for assignment  
expressions
where possible.

Review URL: http://codereview.chromium.org/496009
http://code.google.com/p/v8/source/detail?r=3530

Added:
  /branches/bleeding_edge/test/mjsunit/compiler/countoperation.js
Modified:
  /branches/bleeding_edge/src/arm/fast-codegen-arm.cc
  /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/x64/fast-codegen-x64.cc

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/compiler/countoperation.js     Mon  
Jan  4 05:56:31 2010
@@ -0,0 +1,111 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test pre- and postfix count operations.
+
+// Test value context.
+var a = 42;
+var b = {x:42};
+var c = "x";
+assertEquals(43, ++a);
+assertEquals(43, a);
+assertEquals(43, a++);
+assertEquals(44, a);
+assertEquals(43, ++b.x);
+assertEquals(43, b.x);
+assertEquals(43, b.x++);
+assertEquals(44, b.x);
+assertEquals(45, ++b[c]);
+assertEquals(45, b[c]);
+assertEquals(45, b[c]++);
+assertEquals(46, b[c]);
+
+// Test effect context.
+a = 42;
+b = {x:42};
+c = "x";
+assertEquals(1, eval("++a; 1"));
+assertEquals(43, a);
+assertEquals(1, eval("a++; 1"));
+assertEquals(44, a);
+assertEquals(1, eval("++b.x; 1"));
+assertEquals(43, b.x);
+assertEquals(1, eval("b.x++; 1"));
+assertEquals(44, b.x);
+assertEquals(1, eval("++b[c]; 1"));
+assertEquals(45, b[c]);
+assertEquals(1, eval("b[c]++; 1"));
+assertEquals(46, b[c]);
+
+// Test test context.
+a = 42;
+b = {x:42};
+c = "x";
+assertEquals(1, (++a) ? 1 : 0);
+assertEquals(43, a);
+assertEquals(1, (a++) ? 1 : 0);
+assertEquals(44, a);
+assertEquals(1, (++b.x) ? 1 : 0);
+assertEquals(43, b.x);
+assertEquals(1, (b.x++) ? 1 : 0);
+assertEquals(44, b.x);
+assertEquals(1, (++b[c]) ? 1 : 0);
+assertEquals(45, b[c]);
+assertEquals(1, (b[c]++) ? 1 : 0);
+assertEquals(46, b[c]);
+
+// Test value/test and test/value contexts.
+a = 42;
+b = {x:42};
+c = "x";
+assertEquals(43, ++a || 1);
+assertEquals(43, a);
+assertEquals(43, a++ || 1);
+assertEquals(44, a);
+assertEquals(43, ++b.x || 1);
+assertEquals(43, b.x);
+assertEquals(43, (b.x++) || 1);
+assertEquals(44, b.x);
+assertEquals(45, ++b[c] || 1);
+assertEquals(45, b[c]);
+assertEquals(45, b[c]++ || 1);
+assertEquals(46, b[c]);
+a = 42;
+b = {x:42};
+c = "x";
+assertEquals(1, ++a && 1);
+assertEquals(43, a);
+assertEquals(1, a++ && 1);
+assertEquals(44, a);
+assertEquals(1, ++b.x && 1);
+assertEquals(43, b.x);
+assertEquals(1, (b.x++) && 1);
+assertEquals(44, b.x);
+assertEquals(1, ++b[c] && 1);
+assertEquals(45, b[c]);
+assertEquals(1, b[c]++ && 1);
+assertEquals(46, b[c]);
=======================================
--- /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Tue Dec 22 04:41:45  
2009
+++ /branches/bleeding_edge/src/arm/fast-codegen-arm.cc Mon Jan  4 05:56:31  
2010
@@ -245,6 +245,40 @@
      }
    }
  }
+
+
+void FastCodeGenerator::MoveTOS(Expression::Context context) {
+  switch (context) {
+    case Expression::kUninitialized:
+      UNREACHABLE();
+    case Expression::kEffect:
+      __ Drop(1);
+      break;
+    case Expression::kValue:
+      break;
+    case Expression::kTest:
+      __ pop(r0);
+      TestAndBranch(r0, true_label_, false_label_);
+      break;
+    case Expression::kValueTest: {
+      Label discard;
+      __ ldr(r0, MemOperand(sp, 0));
+      TestAndBranch(r0, true_label_, &discard);
+      __ bind(&discard);
+      __ Drop(1);
+      __ jmp(false_label_);
+      break;
+    }
+    case Expression::kTestValue: {
+      Label discard;
+      __ ldr(r0, MemOperand(sp, 0));
+      TestAndBranch(r0, &discard, false_label_);
+      __ bind(&discard);
+      __ Drop(1);
+      __ jmp(true_label_);
+    }
+  }
+}


  template <>
@@ -839,6 +873,7 @@

  void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
                                                Expression::Context context)  
{
+  SetSourcePosition(prop->position());
    Literal* key = prop->key()->AsLiteral();
    __ mov(r2, Operand(key->handle()));
    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
@@ -847,7 +882,9 @@
  }


-void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context)  
{
+void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
+                                              Expression::Context context)  
{
+  SetSourcePosition(prop->position());
    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
    __ Call(ic, RelocInfo::CODE_TARGET);
    Move(context, r0);
@@ -865,8 +902,8 @@
  }


-void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
-  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+void FastCodeGenerator::EmitVariableAssignment(Variable* var,
+                                               Expression::Context  
context) {
    ASSERT(var != NULL);
    ASSERT(var->is_global() || var->slot() != NULL);
    if (var->is_global()) {
@@ -880,7 +917,7 @@
      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 if (var->slot()) {
      Slot* slot = var->slot();
@@ -888,7 +925,7 @@
      switch (slot->type()) {
        case Slot::LOCAL:
        case Slot::PARAMETER: {
-        switch (expr->context()) {
+        switch (context) {
            case Expression::kUninitialized:
              UNREACHABLE();
            case Expression::kEffect:
@@ -953,9 +990,9 @@
          __ str(r1, CodeGenerator::ContextOperand(r0, slot->index()));

          // RecordWrite may destroy all its register arguments.
-        if (expr->context() == Expression::kValue) {
+        if (context == Expression::kValue) {
            __ push(r1);
-        } else if (expr->context() != Expression::kEffect) {
+        } else if (context != Expression::kEffect) {
            __ mov(r3, r1);
          }
          int offset = FixedArray::kHeaderSize + slot->index() *  
kPointerSize;
@@ -970,9 +1007,9 @@
          __ mov(r2, Operand(offset));
          __ RecordWrite(r0, r2, r1);
          __ bind(&exit);
-        if (expr->context() != Expression::kEffect &&
-            expr->context() != Expression::kValue) {
-        Move(expr->context(), r3);
+        if (context != Expression::kEffect &&
+            context != Expression::kValue) {
+          Move(context, r3);
          }
          break;
        }
@@ -1025,7 +1062,7 @@
    // change to slow case to avoid the quadratic behavior of repeatedly
    // adding fast properties.
    if (expr->starts_initialization_block()) {
-    // Reciever is under the key and value.
+    // Receiver is under the key and value.
      __ ldr(ip, MemOperand(sp, 2 * kPointerSize));
      __ push(ip);
      __ CallRuntime(Runtime::kToSlowProperties, 1);
@@ -1219,7 +1256,7 @@

    // Load function, arg_count into r1 and r0.
    __ mov(r0, Operand(arg_count));
-  // Function is in esp[arg_count + 1].
+  // Function is in sp[arg_count + 1].
    __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));

    Handle<Code>  
construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
@@ -1402,27 +1439,76 @@

  void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
    Comment cmnt(masm_, "[ CountOperation");
-  VariableProxy* proxy = expr->expression()->AsVariableProxy();
-  ASSERT(proxy->AsVariable() != NULL);
-  ASSERT(proxy->AsVariable()->is_global());
-
-  Visit(proxy);
+
+  // Expression can only be a property, a global or a (parameter or local)
+  // slot. Variables with rewrite to .arguments are treated as  
KEYED_PROPERTY.
+  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  LhsKind assign_type = VARIABLE;
+  Property* prop = expr->expression()->AsProperty();
+  // In case of a property we use the uninitialized expression context
+  // of the key to detect a named property.
+  if (prop != NULL) {
+    assign_type = (prop->key()->context() == Expression::kUninitialized)
+        ? NAMED_PROPERTY
+        : KEYED_PROPERTY;
+  }
+
+  // Evaluate expression and get value.
+  if (assign_type == VARIABLE) {
+    ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
+    EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
+                     Expression::kValue);
+  } else {
+    // Reserve space for result of postfix operation.
+    if (expr->is_postfix() && expr->context() != Expression::kEffect) {
+      ASSERT(expr->context() != Expression::kUninitialized);
+      __ mov(ip, Operand(Smi::FromInt(0)));
+      __ push(ip);
+    }
+    Visit(prop->obj());
+    ASSERT_EQ(Expression::kValue, prop->obj()->context());
+    if (assign_type == NAMED_PROPERTY) {
+      EmitNamedPropertyLoad(prop, Expression::kValue);
+    } else {
+      Visit(prop->key());
+      ASSERT_EQ(Expression::kValue, prop->key()->context());
+      EmitKeyedPropertyLoad(prop, Expression::kValue);
+    }
+  }
+
+  // Convert to number.
    __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);

-  switch (expr->context()) {
-    case Expression::kUninitialized:
-      UNREACHABLE();
-    case Expression::kValue:  // Fall through
-    case Expression::kTest:  // Fall through
-    case Expression::kTestValue:  // Fall through
-    case Expression::kValueTest:
-      // Duplicate the result on the stack.
-      __ push(r0);
-      break;
-    case Expression::kEffect:
-      // Do not save result.
-      break;
-  }
+  // Save result for postfix expressions.
+  if (expr->is_postfix()) {
+    switch (expr->context()) {
+      case Expression::kUninitialized:
+        UNREACHABLE();
+      case Expression::kEffect:
+        // Do not save result.
+        break;
+      case Expression::kValue:  // Fall through
+      case Expression::kTest:  // Fall through
+      case Expression::kTestValue:  // Fall through
+      case Expression::kValueTest:
+        // Save the result on the stack. If we have a named or keyed  
property
+        // we store the result under the receiver that is currently on top
+        // of the stack.
+        switch (assign_type) {
+          case VARIABLE:
+            __ push(r0);
+            break;
+          case NAMED_PROPERTY:
+            __ str(r0, MemOperand(sp, kPointerSize));
+            break;
+          case KEYED_PROPERTY:
+            __ str(r0, MemOperand(sp, 2 * kPointerSize));
+            break;
+        }
+        break;
+    }
+  }
+
    // Call runtime for +1/-1.
    __ push(r0);
    __ mov(ip, Operand(Smi::FromInt(1)));
@@ -1432,43 +1518,49 @@
    } else {
      __ CallRuntime(Runtime::kNumberSub, 2);
    }
-  // Call Store IC.
-  __ mov(r2, Operand(proxy->AsVariable()->name()));
-  __ ldr(ip, CodeGenerator::GlobalObject());
-  __ push(ip);
-  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
-  __ Call(ic, RelocInfo::CODE_TARGET);
-  // Restore up stack after store IC.
-  __ add(sp, sp, Operand(kPointerSize));
-
-  switch (expr->context()) {
-    case Expression::kUninitialized:
-      UNREACHABLE();
-    case Expression::kEffect:  // Fall through
-    case Expression::kValue:
-      // Do nothing. Result in either on the stack for value context
-      // or discarded for effect context.
+
+  // Store the value returned in r0.
+  switch (assign_type) {
+    case VARIABLE:
+      __ push(r0);
+      if (expr->is_postfix()) {
+         
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                               Expression::kEffect);
+        // For all contexts except kEffect: We have the result on
+        // top of the stack.
+        if (expr->context() != Expression::kEffect) {
+          MoveTOS(expr->context());
+        }
+      } else {
+         
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                               expr->context());
+      }
        break;
-    case Expression::kTest:
-      __ pop(r0);
-      TestAndBranch(r0, true_label_, false_label_);
+    case NAMED_PROPERTY: {
+      __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
+      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+      __ Call(ic, RelocInfo::CODE_TARGET);
+      if (expr->is_postfix()) {
+        __ Drop(1);  // Result is on the stack under the receiver.
+        if (expr->context() != Expression::kEffect) {
+          MoveTOS(expr->context());
+        }
+      } else {
+        DropAndMove(expr->context(), r0);
+      }
        break;
-    case Expression::kValueTest: {
-      Label discard;
-      __ ldr(r0, MemOperand(sp));
-      TestAndBranch(r0, true_label_, &discard);
-      __ bind(&discard);
-      __ add(sp, sp, Operand(kPointerSize));
-      __ b(false_label_);
-      break;
-    }
-    case Expression::kTestValue: {
-      Label discard;
-      __ ldr(r0, MemOperand(sp));
-      TestAndBranch(r0, &discard, false_label_);
-      __ bind(&discard);
-      __ add(sp, sp, Operand(kPointerSize));
-      __ b(true_label_);
+    }
+    case KEYED_PROPERTY: {
+      Handle<Code>  
ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+      __ Call(ic, RelocInfo::CODE_TARGET);
+      if (expr->is_postfix()) {
+        __ Drop(2);  // Result is on the stack under the key and the  
receiver.
+        if (expr->context() != Expression::kEffect) {
+          MoveTOS(expr->context());
+        }
+      } else {
+        DropAndMove(expr->context(), r0, 2);
+      }
        break;
      }
    }
=======================================
--- /branches/bleeding_edge/src/compiler.cc     Fri Dec 18 05:38:28 2009
+++ /branches/bleeding_edge/src/compiler.cc     Mon Jan  4 05:56:31 2010
@@ -649,12 +649,6 @@
  void CodeGenSelector::VisitDeclaration(Declaration* decl) {
    Property* prop = decl->proxy()->AsProperty();
    if (prop != NULL) {
-    // Property rewrites are shared, ensure we are not changing its
-    // expression context state.
-    ASSERT(prop->obj()->context() == Expression::kUninitialized ||
-           prop->obj()->context() == Expression::kValue);
-    ASSERT(prop->key()->context() == Expression::kUninitialized ||
-           prop->key()->context() == Expression::kValue);
      ProcessExpression(prop->obj(), Expression::kValue);
      ProcessExpression(prop->key(), Expression::kValue);
    }
@@ -903,8 +897,6 @@
        }
      }
    } else if (prop != NULL) {
-    ASSERT(prop->obj()->context() == Expression::kUninitialized ||
-           prop->obj()->context() == Expression::kValue);
      ProcessExpression(prop->obj(), Expression::kValue);
      CHECK_BAILOUT;
      // We will only visit the key during code generation for keyed property
@@ -915,8 +907,6 @@
      if (lit == NULL ||
          !lit->handle()->IsSymbol() ||
          String::cast(*(lit->handle()))->AsArrayIndex(&ignored)) {
-      ASSERT(prop->key()->context() == Expression::kUninitialized ||
-             prop->key()->context() == Expression::kValue);
        ProcessExpression(prop->key(), Expression::kValue);
        CHECK_BAILOUT;
      }
@@ -1022,11 +1012,36 @@


  void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
-  // We support postfix count operations on global variables.
-  if (expr->is_prefix()) BAILOUT("Prefix CountOperation");
    Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
-  if (var == NULL || !var->is_global()) BAILOUT("non-global  
postincrement");
-  ProcessExpression(expr->expression(), Expression::kValue);
+  Property* prop = expr->expression()->AsProperty();
+  ASSERT(var == NULL || prop == NULL);
+  if (var != NULL) {
+    // All global variables are supported.
+    if (!var->is_global()) {
+      ASSERT(var->slot() != NULL);
+      Slot::Type type = var->slot()->type();
+      if (type == Slot::LOOKUP) {
+        BAILOUT("CountOperation with lookup slot");
+      }
+    }
+  } 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("CountOperation non-variable/non-property expression");
+  }
  }


=======================================
--- /branches/bleeding_edge/src/fast-codegen.cc Fri Dec 18 05:38:28 2009
+++ /branches/bleeding_edge/src/fast-codegen.cc Mon Jan  4 05:56:31 2010
@@ -676,7 +676,7 @@
          EmitNamedPropertyLoad(prop, Expression::kValue);
          break;
        case KEYED_PROPERTY:
-        EmitKeyedPropertyLoad(Expression::kValue);
+        EmitKeyedPropertyLoad(prop, Expression::kValue);
          break;
      }
    }
@@ -694,7 +694,8 @@
    // Store the value.
    switch (assign_type) {
      case VARIABLE:
-      EmitVariableAssignment(expr);
+      EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
+                             expr->context());
        break;
      case NAMED_PROPERTY:
        EmitNamedPropertyAssignment(expr);
=======================================
--- /branches/bleeding_edge/src/fast-codegen.h  Fri Dec 18 05:38:28 2009
+++ /branches/bleeding_edge/src/fast-codegen.h  Mon Jan  4 05:56:31 2010
@@ -213,6 +213,7 @@

    int SlotOffset(Slot* slot);
    void Move(Expression::Context destination, Register source);
+  void MoveTOS(Expression::Context destination);
    void Move(Expression::Context destination, Slot* source, Register  
scratch);
    void Move(Expression::Context destination, Literal* source);
    void Move(Slot* dst, Register source, Register scratch1, Register  
scratch2);
@@ -247,13 +248,13 @@

    // Platform-specific support for compiling assignments.

-  // Load a value from a named property and push the result on the stack.
+  // Load a value from a named property.
    // 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.
+  // Load a value from a keyed property.
    // The receiver and the key is left on the stack by the IC.
-  void EmitKeyedPropertyLoad(Expression::Context context);
+  void EmitKeyedPropertyLoad(Property* expr, Expression::Context context);

    // Apply the compound assignment operator. Expects both operands on top
    // of the stack.
@@ -261,7 +262,7 @@

    // Complete a variable assignment.  The right-hand-side value is expected
    // on top of the stack.
-  void EmitVariableAssignment(Assignment* expr);
+  void EmitVariableAssignment(Variable* var, Expression::Context context);

    // Complete a named property assignment.  The receiver and  
right-hand-side
    // value are expected on top of the stack.
=======================================
--- /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc       Tue Dec 22  
04:41:45 2009
+++ /branches/bleeding_edge/src/ia32/fast-codegen-ia32.cc       Mon Jan  4  
05:56:31 2010
@@ -225,6 +225,40 @@
      }
    }
  }
+
+
+void FastCodeGenerator::MoveTOS(Expression::Context context) {
+  switch (context) {
+    case Expression::kUninitialized:
+      UNREACHABLE();
+    case Expression::kEffect:
+      __ Drop(1);
+      break;
+    case Expression::kValue:
+      break;
+    case Expression::kTest:
+      __ pop(eax);
+      TestAndBranch(eax, true_label_, false_label_);
+      break;
+    case Expression::kValueTest: {
+      Label discard;
+      __ mov(eax, Operand(esp, 0));
+      TestAndBranch(eax, true_label_, &discard);
+      __ bind(&discard);
+      __ Drop(1);
+      __ jmp(false_label_);
+      break;
+    }
+    case Expression::kTestValue: {
+      Label discard;
+      __ mov(eax, Operand(esp, 0));
+      TestAndBranch(eax, &discard, false_label_);
+      __ bind(&discard);
+      __ Drop(1);
+      __ jmp(true_label_);
+    }
+  }
+}


  template <>
@@ -828,6 +862,7 @@

  void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
                                                Expression::Context context)  
{
+  SetSourcePosition(prop->position());
    Literal* key = prop->key()->AsLiteral();
    __ mov(ecx, Immediate(key->handle()));
    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
@@ -836,7 +871,9 @@
  }


-void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context)  
{
+void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
+                                              Expression::Context context)  
{
+  SetSourcePosition(prop->position());
    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
    __ call(ic, RelocInfo::CODE_TARGET);
    Move(context, eax);
@@ -853,8 +890,8 @@
  }


-void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
-  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+void FastCodeGenerator::EmitVariableAssignment(Variable* var,
+                                               Expression::Context  
context) {
    ASSERT(var != NULL);
    ASSERT(var->is_global() || var->slot() != NULL);
    if (var->is_global()) {
@@ -867,7 +904,7 @@
      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
      __ call(ic, RelocInfo::CODE_TARGET);
      // Overwrite the receiver on the stack with the result if needed.
-    DropAndMove(expr->context(), eax);
+    DropAndMove(context, eax);

    } else if (var->slot() != NULL) {
      Slot* slot = var->slot();
@@ -875,7 +912,7 @@
        case Slot::LOCAL:
        case Slot::PARAMETER: {
          Operand target = Operand(ebp, SlotOffset(var->slot()));
-        switch (expr->context()) {
+        switch (context) {
            case Expression::kUninitialized:
              UNREACHABLE();
            case Expression::kEffect:
@@ -943,16 +980,16 @@
          __ mov(Operand(eax, Context::SlotOffset(slot->index())), ecx);

          // RecordWrite may destroy all its register arguments.
-        if (expr->context() == Expression::kValue) {
+        if (context == Expression::kValue) {
            __ push(ecx);
-        } else if (expr->context() != Expression::kEffect) {
+        } else if (context != Expression::kEffect) {
            __ mov(edx, ecx);
          }
          int offset = FixedArray::kHeaderSize + slot->index() *  
kPointerSize;
          __ RecordWrite(eax, offset, ecx, ebx);
-        if (expr->context() != Expression::kEffect &&
-            expr->context() != Expression::kValue) {
-          Move(expr->context(), edx);
+        if (context != Expression::kEffect &&
+            context != Expression::kValue) {
+          Move(context, edx);
          }
          break;
        }
@@ -1377,27 +1414,75 @@

  void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
    Comment cmnt(masm_, "[ CountOperation");
-  VariableProxy* proxy = expr->expression()->AsVariableProxy();
-  ASSERT(proxy->AsVariable() != NULL);
-  ASSERT(proxy->AsVariable()->is_global());
-
-  Visit(proxy);
+
+  // Expression can only be a property, a global or a (parameter or local)
+  // slot. Variables with rewrite to .arguments are treated as  
KEYED_PROPERTY.
+  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  LhsKind assign_type = VARIABLE;
+  Property* prop = expr->expression()->AsProperty();
+  // In case of a property we use the uninitialized expression context
+  // of the key to detect a named property.
+  if (prop != NULL) {
+    assign_type = (prop->key()->context() == Expression::kUninitialized)
+        ? NAMED_PROPERTY
+        : KEYED_PROPERTY;
+  }
+
+  // Evaluate expression and get value.
+  if (assign_type == VARIABLE) {
+    ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
+    EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
+                     Expression::kValue);
+  } else  {
+    // Reserve space for result of postfix operation.
+    if (expr->is_postfix() && expr->context() != Expression::kEffect) {
+      ASSERT(expr->context() != Expression::kUninitialized);
+      __ push(Immediate(Smi::FromInt(0)));
+    }
+    Visit(prop->obj());
+    ASSERT_EQ(Expression::kValue, prop->obj()->context());
+    if (assign_type == NAMED_PROPERTY) {
+      EmitNamedPropertyLoad(prop, Expression::kValue);
+    } else {
+      Visit(prop->key());
+      ASSERT_EQ(Expression::kValue, prop->key()->context());
+      EmitKeyedPropertyLoad(prop, Expression::kValue);
+    }
+  }
+
+  // Convert to number.
    __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);

-  switch (expr->context()) {
-    case Expression::kUninitialized:
-      UNREACHABLE();
-    case Expression::kValue:  // Fall through
-    case Expression::kTest:  // Fall through
-    case Expression::kTestValue:  // Fall through
-    case Expression::kValueTest:
-      // Duplicate the result on the stack.
-      __ push(eax);
-      break;
-    case Expression::kEffect:
-      // Do not save result.
-      break;
-  }
+  // Save result for postfix expressions.
+  if (expr->is_postfix()) {
+    switch (expr->context()) {
+      case Expression::kUninitialized:
+        UNREACHABLE();
+      case Expression::kEffect:
+        // Do not save result.
+        break;
+      case Expression::kValue:  // Fall through
+      case Expression::kTest:  // Fall through
+      case Expression::kTestValue:  // Fall through
+      case Expression::kValueTest:
+        // Save the result on the stack. If we have a named or keyed  
property
+        // we store the result under the receiver that is currently on top
+        // of the stack.
+        switch (assign_type) {
+          case VARIABLE:
+            __ push(eax);
+            break;
+          case NAMED_PROPERTY:
+            __ mov(Operand(esp, kPointerSize), eax);
+            break;
+          case KEYED_PROPERTY:
+            __ mov(Operand(esp, 2 * kPointerSize), eax);
+            break;
+        }
+        break;
+    }
+  }
+
    // Call runtime for +1/-1.
    __ push(eax);
    __ push(Immediate(Smi::FromInt(1)));
@@ -1406,42 +1491,55 @@
    } else {
      __ CallRuntime(Runtime::kNumberSub, 2);
    }
-  // Call Store IC.
-  __ mov(ecx, proxy->AsVariable()->name());
-  __ push(CodeGenerator::GlobalObject());
-  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
-  __ call(ic, RelocInfo::CODE_TARGET);
-  // Restore up stack after store IC.
-  __ add(Operand(esp), Immediate(kPointerSize));
-
-  switch (expr->context()) {
-    case Expression::kUninitialized:
-      UNREACHABLE();
-    case Expression::kEffect:  // Fall through
-    case Expression::kValue:
-      // Do nothing. Result in either on the stack for value context
-      // or discarded for effect context.
+
+  // Store the value returned in eax.
+  switch (assign_type) {
+    case VARIABLE:
+      __ push(eax);
+      if (expr->is_postfix()) {
+         
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                               Expression::kEffect);
+        // For all contexts except kEffect: We have the result on
+        // top of the stack.
+        if (expr->context() != Expression::kEffect) {
+          MoveTOS(expr->context());
+        }
+      } else {
+         
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                               expr->context());
+      }
        break;
-    case Expression::kTest:
-      __ pop(eax);
-      TestAndBranch(eax, true_label_, false_label_);
+    case NAMED_PROPERTY: {
+      __ mov(ecx, prop->key()->AsLiteral()->handle());
+      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_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();
+      if (expr->is_postfix()) {
+        __ Drop(1);  // Result is on the stack under the receiver.
+        if (expr->context() != Expression::kEffect) {
+          MoveTOS(expr->context());
+        }
+      } else {
+        DropAndMove(expr->context(), eax);
+      }
        break;
-    case Expression::kValueTest: {
-      Label discard;
-      __ mov(eax, Operand(esp, 0));
-      TestAndBranch(eax, true_label_, &discard);
-      __ bind(&discard);
-      __ add(Operand(esp), Immediate(kPointerSize));
-      __ jmp(false_label_);
-      break;
-    }
-    case Expression::kTestValue: {
-      Label discard;
-      __ mov(eax, Operand(esp, 0));
-      TestAndBranch(eax, &discard, false_label_);
-      __ bind(&discard);
-      __ add(Operand(esp), Immediate(kPointerSize));
-      __ jmp(true_label_);
+    }
+    case KEYED_PROPERTY: {
+      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();
+      if (expr->is_postfix()) {
+        __ Drop(2);  // Result is on the stack under the key and the  
receiver.
+        if (expr->context() != Expression::kEffect) {
+          MoveTOS(expr->context());
+        }
+      } else {
+        DropAndMove(expr->context(), eax, 2);
+      }
        break;
      }
    }
=======================================
--- /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Mon Dec 28 01:21:23  
2009
+++ /branches/bleeding_edge/src/x64/fast-codegen-x64.cc Mon Jan  4 05:56:31  
2010
@@ -234,6 +234,40 @@
      }
    }
  }
+
+
+void FastCodeGenerator::MoveTOS(Expression::Context context) {
+  switch (context) {
+    case Expression::kUninitialized:
+      UNREACHABLE();
+    case Expression::kEffect:
+      __ Drop(1);
+      break;
+    case Expression::kValue:
+      break;
+    case Expression::kTest:
+      __ pop(rax);
+      TestAndBranch(rax, true_label_, false_label_);
+      break;
+    case Expression::kValueTest: {
+      Label discard;
+      __ movq(rax, Operand(rsp, 0));
+      TestAndBranch(rax, true_label_, &discard);
+      __ bind(&discard);
+      __ Drop(1);
+      __ jmp(false_label_);
+      break;
+    }
+    case Expression::kTestValue: {
+      Label discard;
+      __ movq(rax, Operand(rsp, 0));
+      TestAndBranch(rax, &discard, false_label_);
+      __ bind(&discard);
+      __ Drop(1);
+      __ jmp(true_label_);
+    }
+  }
+}


  template <>
@@ -837,6 +871,7 @@

  void FastCodeGenerator::EmitNamedPropertyLoad(Property* prop,
                                                Expression::Context context)  
{
+  SetSourcePosition(prop->position());
    Literal* key = prop->key()->AsLiteral();
    __ Move(rcx, key->handle());
    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
@@ -845,7 +880,9 @@
  }


-void FastCodeGenerator::EmitKeyedPropertyLoad(Expression::Context context)  
{
+void FastCodeGenerator::EmitKeyedPropertyLoad(Property* prop,
+                                              Expression::Context context)  
{
+  SetSourcePosition(prop->position());
    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
    __ Call(ic, RelocInfo::CODE_TARGET);
    Move(context, rax);
@@ -862,8 +899,8 @@
  }


-void FastCodeGenerator::EmitVariableAssignment(Assignment* expr) {
-  Variable* var = expr->target()->AsVariableProxy()->AsVariable();
+void FastCodeGenerator::EmitVariableAssignment(Variable* var,
+                                               Expression::Context  
context) {
    ASSERT(var != NULL);
    ASSERT(var->is_global() || var->slot() != NULL);
    if (var->is_global()) {
@@ -876,7 +913,7 @@
      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 if (var->slot()) {
      Slot* slot = var->slot();
@@ -884,7 +921,7 @@
      switch (slot->type()) {
        case Slot::LOCAL:
        case Slot::PARAMETER: {
-        switch (expr->context()) {
+        switch (context) {
            case Expression::kUninitialized:
              UNREACHABLE();
            case Expression::kEffect:
@@ -952,16 +989,16 @@
          __ movq(Operand(rax, Context::SlotOffset(slot->index())), rcx);

          // RecordWrite may destroy all its register arguments.
-        if (expr->context() == Expression::kValue) {
+        if (context == Expression::kValue) {
            __ push(rcx);
-        } else if (expr->context() != Expression::kEffect) {
+        } else if (context != Expression::kEffect) {
            __ movq(rdx, rcx);
          }
          int offset = FixedArray::kHeaderSize + slot->index() *  
kPointerSize;
          __ RecordWrite(rax, offset, rcx, rbx);
-        if (expr->context() != Expression::kEffect &&
-            expr->context() != Expression::kValue) {
-          Move(expr->context(), rdx);
+        if (context != Expression::kEffect &&
+            context != Expression::kValue) {
+          Move(context, rdx);
          }
          break;
        }
@@ -1263,78 +1300,6 @@
    }
  }

-void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
-  Comment cmnt(masm_, "[ CountOperation");
-  VariableProxy* proxy = expr->expression()->AsVariableProxy();
-  ASSERT(proxy->AsVariable() != NULL);
-  ASSERT(proxy->AsVariable()->is_global());
-
-  Visit(proxy);
-  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
-
-  switch (expr->context()) {
-    case Expression::kUninitialized:
-      UNREACHABLE();
-    case Expression::kValue:  // Fall through
-    case Expression::kTest:  // Fall through
-    case Expression::kTestValue:  // Fall through
-    case Expression::kValueTest:
-      // Duplicate the result on the stack.
-      __ push(rax);
-      break;
-    case Expression::kEffect:
-      // Do not save result.
-      break;
-  }
-  // Call runtime for +1/-1.
-  __ push(rax);
-  __ Push(Smi::FromInt(1));
-  if (expr->op() == Token::INC) {
-    __ CallRuntime(Runtime::kNumberAdd, 2);
-  } else {
-    __ CallRuntime(Runtime::kNumberSub, 2);
-  }
-  // Call Store IC.
-  __ Move(rcx, proxy->AsVariable()->name());
-  __ push(CodeGenerator::GlobalObject());
-  Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
-  __ call(ic, RelocInfo::CODE_TARGET);
-  // Restore up stack after store IC
-  __ addq(rsp, Immediate(kPointerSize));
-
-  switch (expr->context()) {
-    case Expression::kUninitialized:
-      UNREACHABLE();
-    case Expression::kEffect:  // Fall through
-    case Expression::kValue:
-      // Do nothing. Result in either on the stack for value context
-      // or discarded for effect context.
-      break;
-    case Expression::kTest:
-      __ pop(rax);
-      TestAndBranch(rax, true_label_, false_label_);
-      break;
-    case Expression::kValueTest: {
-      Label discard;
-      __ movq(rax, Operand(rsp, 0));
-      TestAndBranch(rax, true_label_, &discard);
-      __ bind(&discard);
-      __ addq(rsp, Immediate(kPointerSize));
-      __ jmp(false_label_);
-      break;
-    }
-    case Expression::kTestValue: {
-      Label discard;
-      __ movq(rax, Operand(rsp, 0));
-      TestAndBranch(rax, &discard, false_label_);
-      __ bind(&discard);
-      __ addq(rsp, Immediate(kPointerSize));
-      __ jmp(true_label_);
-      break;
-    }
-  }
-}
-

  void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
    switch (expr->op()) {
@@ -1464,6 +1429,139 @@
  }


+void FastCodeGenerator::VisitCountOperation(CountOperation* expr) {
+  Comment cmnt(masm_, "[ CountOperation");
+
+  // Expression can only be a property, a global or a (parameter or local)
+  // slot. Variables with rewrite to .arguments are treated as  
KEYED_PROPERTY.
+  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  LhsKind assign_type = VARIABLE;
+  Property* prop = expr->expression()->AsProperty();
+  // In case of a property we use the uninitialized expression context
+  // of the key to detect a named property.
+  if (prop != NULL) {
+    assign_type = (prop->key()->context() == Expression::kUninitialized)
+        ? NAMED_PROPERTY
+        : KEYED_PROPERTY;
+  }
+
+  // Evaluate expression and get value.
+  if (assign_type == VARIABLE) {
+    ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
+    EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
+                     Expression::kValue);
+  } else  {
+    // Reserve space for result of postfix operation.
+    if (expr->is_postfix() && expr->context() != Expression::kEffect) {
+      ASSERT(expr->context() != Expression::kUninitialized);
+      __ Push(Smi::FromInt(0));
+    }
+    Visit(prop->obj());
+    ASSERT_EQ(Expression::kValue, prop->obj()->context());
+    if (assign_type == NAMED_PROPERTY) {
+      EmitNamedPropertyLoad(prop, Expression::kValue);
+    } else {
+      Visit(prop->key());
+      ASSERT_EQ(Expression::kValue, prop->key()->context());
+      EmitKeyedPropertyLoad(prop, Expression::kValue);
+    }
+  }
+
+  // Convert to number.
+  __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
+
+  // Save result for postfix expressions.
+  if (expr->is_postfix()) {
+    switch (expr->context()) {
+      case Expression::kUninitialized:
+        UNREACHABLE();
+      case Expression::kEffect:
+        // Do not save result.
+        break;
+      case Expression::kValue:  // Fall through
+      case Expression::kTest:  // Fall through
+      case Expression::kTestValue:  // Fall through
+      case Expression::kValueTest:
+        // Save the result on the stack. If we have a named or keyed  
property
+        // we store the result under the receiver that is currently on top
+        // of the stack.
+        switch (assign_type) {
+          case VARIABLE:
+            __ push(rax);
+            break;
+          case NAMED_PROPERTY:
+            __ movq(Operand(rsp, kPointerSize), rax);
+            break;
+          case KEYED_PROPERTY:
+            __ movq(Operand(rsp, 2 * kPointerSize), rax);
+            break;
+        }
+        break;
+    }
+  }
+
+  // Call runtime for +1/-1.
+  __ push(rax);
+  __ Push(Smi::FromInt(1));
+  if (expr->op() == Token::INC) {
+    __ CallRuntime(Runtime::kNumberAdd, 2);
+  } else {
+    __ CallRuntime(Runtime::kNumberSub, 2);
+  }
+
+  // Store the value returned in rax.
+  switch (assign_type) {
+    case VARIABLE:
+      __ push(rax);
+      if (expr->is_postfix()) {
+         
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                               Expression::kEffect);
+        // For all contexts except kEffect: We have the result on
+        // top of the stack.
+        if (expr->context() != Expression::kEffect) {
+          MoveTOS(expr->context());
+        }
+      } else {
+         
EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                               expr->context());
+      }
+      break;
+    case NAMED_PROPERTY: {
+      __ Move(rcx, prop->key()->AsLiteral()->handle());
+      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_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();
+      if (expr->is_postfix()) {
+        __ Drop(1);  // Result is on the stack under the receiver.
+        if (expr->context() != Expression::kEffect) {
+          MoveTOS(expr->context());
+        }
+      } else {
+        DropAndMove(expr->context(), rax);
+      }
+      break;
+    }
+    case KEYED_PROPERTY: {
+      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();
+      if (expr->is_postfix()) {
+        __ Drop(2);  // Result is on the stack under the key and the  
receiver.
+        if (expr->context() != Expression::kEffect) {
+          MoveTOS(expr->context());
+        }
+      } else {
+        DropAndMove(expr->context(), rax, 2);
+      }
+      break;
+    }
+  }
+}
+
  void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
    Comment cmnt(masm_, "[ BinaryOperation");
    switch (expr->op()) {

-- 
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to