Revision: 2653
Author: [email protected]
Date: Fri Aug  7 06:32:39 2009
Log: Added support for property loads to the CFG builder and fast-mode
compiler.

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

Modified:
  /branches/bleeding_edge/src/arm/cfg-arm.cc
  /branches/bleeding_edge/src/cfg.cc
  /branches/bleeding_edge/src/cfg.h
  /branches/bleeding_edge/src/ia32/cfg-ia32.cc
  /branches/bleeding_edge/src/x64/cfg-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/cfg-arm.cc  Fri Aug  7 03:55:19 2009
+++ /branches/bleeding_edge/src/arm/cfg-arm.cc  Fri Aug  7 06:32:39 2009
@@ -98,25 +98,62 @@
    __ add(sp, sp, Operand((count + 1) * kPointerSize));
    __ Jump(lr);
  }
+
+
+void PropLoadInstr::Compile(MacroAssembler* masm) {
+  // The key should not be on the stack---if it is a compiler-generated
+  // temporary it is in the accumulator.
+  ASSERT(!key()->is_on_stack());
+
+  Comment cmnt(masm, "[ Load from Property");
+  // If the key is known at compile-time we may be able to use a load IC.
+  bool is_keyed_load = true;
+  if (key()->is_constant()) {
+    // Still use the keyed load IC if the key can be parsed as an integer  
so
+    // we will get into the case that handles [] on string objects.
+    Handle<Object> key_val = Constant::cast(key())->handle();
+    uint32_t ignored;
+    if (key_val->IsSymbol() &&
+        !String::cast(*key_val)->AsArrayIndex(&ignored)) {
+      is_keyed_load = false;
+    }
+  }
+
+  if (!object()->is_on_stack()) object()->Push(masm);
+
+  if (is_keyed_load) {
+    key()->Push(masm);
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+    __ Call(ic, RelocInfo::CODE_TARGET);
+    // Discard key and receiver.
+    __ add(sp, sp, Operand(2 * kPointerSize));
+  } else {
+    key()->Get(masm, r2);
+    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+    __ Call(ic, RelocInfo::CODE_TARGET);
+    __ pop();  // Discard receiver.
+  }
+  location()->Set(masm, r0);
+}


  void BinaryOpInstr::Compile(MacroAssembler* masm) {
    // The right-hand value should not be on the stack---if it is a
    // compiler-generated temporary it is in the accumulator.
-  ASSERT(!value1()->is_on_stack());
+  ASSERT(!right()->is_on_stack());

    Comment cmnt(masm, "[ BinaryOpInstr");
    // We can overwrite one of the operands if it is a temporary.
    OverwriteMode mode = NO_OVERWRITE;
-  if (value0()->is_temporary()) {
+  if (left()->is_temporary()) {
      mode = OVERWRITE_LEFT;
-  } else if (value1()->is_temporary()) {
+  } else if (right()->is_temporary()) {
      mode = OVERWRITE_RIGHT;
    }

    // Move left to r1 and right to r0.
-  value0()->Get(masm, r1);
-  value1()->Get(masm, r0);
+  left()->Get(masm, r1);
+  right()->Get(masm, r0);
    GenericBinaryOpStub stub(op(), mode);
    __ CallStub(&stub);
    location()->Set(masm, r0);
@@ -127,7 +164,7 @@
    // The location should be 'Effect'.  As a side effect, move the value to
    // the accumulator.
    Comment cmnt(masm, "[ ReturnInstr");
-  value_->Get(masm, r0);
+  value()->Get(masm, r0);
  }


=======================================
--- /branches/bleeding_edge/src/cfg.cc  Fri Aug  7 03:55:19 2009
+++ /branches/bleeding_edge/src/cfg.cc  Fri Aug  7 06:32:39 2009
@@ -208,11 +208,21 @@
      temp->set_where(TempLocation::STACK);
    }
  }
+
+
+void PropLoadInstr::FastAllocate(TempLocation* temp) {
+  ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
+  if (temp == object() || temp == key()) {
+    temp->set_where(TempLocation::ACCUMULATOR);
+  } else {
+    temp->set_where(TempLocation::STACK);
+  }
+}


  void BinaryOpInstr::FastAllocate(TempLocation* temp) {
    ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
-  if (temp == value0() || temp == value1()) {
+  if (temp == left() || temp == right()) {
      temp->set_where(TempLocation::ACCUMULATOR);
    } else {
      temp->set_where(TempLocation::STACK);
@@ -222,7 +232,7 @@

  void ReturnInstr::FastAllocate(TempLocation* temp) {
    ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
-  if (temp == value_) {
+  if (temp == value()) {
      temp->set_where(TempLocation::ACCUMULATOR);
    } else {
      temp->set_where(TempLocation::STACK);
@@ -369,7 +379,36 @@


  void ExpressionCfgBuilder::VisitProperty(Property* expr) {
-  BAILOUT("Property");
+  ExpressionCfgBuilder object, key;
+  object.Build(expr->obj(), NULL);
+  if (object.graph() == NULL) {
+    BAILOUT("unsupported object subexpression in propref");
+  }
+  key.Build(expr->key(), NULL);
+  if (key.graph() == NULL) {
+    BAILOUT("unsupported key subexpression in propref");
+  }
+
+  if (destination_ == NULL) destination_ = new TempLocation();
+
+  graph_ = object.graph();
+  // Insert a move to a fresh temporary if the object value is in a slot
+  // that's assigned in the key.
+  Location* temp = NULL;
+  if (object.value()->is_slot() &&
+      key.assigned_vars()->Contains(SlotLocation::cast(object.value()))) {
+    temp = new TempLocation();
+    graph()->Append(new MoveInstr(temp, object.value()));
+  }
+  graph()->Concatenate(key.graph());
+  graph()->Append(new PropLoadInstr(destination_,
+                                    temp == NULL ? object.value() : temp,
+                                    key.value()));
+
+  assigned_vars_ = *object.assigned_vars();
+  assigned_vars()->Union(key.assigned_vars());
+
+  value_ = destination_;
  }


@@ -638,15 +677,26 @@
    value_->Print();
    PrintF(")\n");
  }
+
+
+void PropLoadInstr::Print() {
+  PrintF("PropLoad(");
+  location()->Print();
+  PrintF(", ");
+  object()->Print();
+  PrintF(", ");
+  key()->Print();
+  PrintF(")\n");
+}


  void BinaryOpInstr::Print() {
    PrintF("BinaryOp(");
    location()->Print();
    PrintF(", %s, ", Token::Name(op()));
-  value0()->Print();
+  left()->Print();
    PrintF(", ");
-  value1()->Print();
+  right()->Print();
    PrintF(")\n");
  }

=======================================
--- /branches/bleeding_edge/src/cfg.h   Fri Aug  7 03:35:48 2009
+++ /branches/bleeding_edge/src/cfg.h   Fri Aug  7 06:32:39 2009
@@ -43,10 +43,11 @@
  // Instructions are described by the following grammar.
  //
  // <Instruction> ::=
-//     MoveInstr <Location> <Value>
-//   | BinaryOpInstr <Location> Token::Value <Value> <Value>
-//   | ReturnInstr Nowhere <Value>
-//   | PositionInstr <Int>
+//     Move <Location> <Value>
+//   | PropLoad <Location> <Value> <Value>
+//   | BinaryOp <Location> Token::Value <Value> <Value>
+//   | Return Nowhere <Value>
+//   | Position <Int>
  //
  // Values are trivial expressions:
  //
@@ -130,16 +131,14 @@
    virtual ~Value() {}

    // Predicates:
+
+  virtual bool is_temporary() { return false; }
+  virtual bool is_slot() { return false; }
+  virtual bool is_constant() { return false; }

    // True if the value is a temporary allocated to the stack in
    // fast-compilation mode.
    virtual bool is_on_stack() { return false; }
-
-  // True if the value is a compiler-generated temporary location.
-  virtual bool is_temporary() { return false; }
-
-  // True if the value is a slot location.
-  virtual bool is_slot() { return false; }

    // Support for fast-compilation mode:

@@ -163,7 +162,17 @@
   public:
    explicit Constant(Handle<Object> handle) : handle_(handle) {}

-  virtual ~Constant() {}
+  // Cast accessor.
+  static Constant* cast(Value* value) {
+    ASSERT(value->is_constant());
+    return reinterpret_cast<Constant*>(value);
+  }
+
+  // Accessors.
+  Handle<Object> handle() { return handle_; }
+
+  // Predicates.
+  bool is_constant() { return true; }

    // Support for fast-compilation mode.
    void Get(MacroAssembler* masm, Register reg);
@@ -410,18 +419,43 @@
  };


+// Load a property from a receiver, leaving the result in a location.
+class PropLoadInstr : public Instruction {
+ public:
+  PropLoadInstr(Location* loc, Value* object, Value* key)
+      : Instruction(loc), object_(object), key_(key) {
+  }
+
+  // Accessors.
+  Value* object() { return object_; }
+  Value* key() { return key_; }
+
+  // Support for fast-compilation mode.
+  void Compile(MacroAssembler* masm);
+  void FastAllocate(TempLocation* temp);
+
+#ifdef DEBUG
+  void Print();
+#endif
+
+ private:
+  Value* object_;
+  Value* key_;
+};
+
+
  // Perform a (non-short-circuited) binary operation on a pair of values,
  // leaving the result in a location.
  class BinaryOpInstr : public Instruction {
   public:
-  BinaryOpInstr(Location* loc, Token::Value op, Value* value0, Value*  
value1)
-      : Instruction(loc), op_(op), value0_(value0), value1_(value1) {
+  BinaryOpInstr(Location* loc, Token::Value op, Value* left, Value* right)
+      : Instruction(loc), op_(op), left_(left), right_(right) {
    }

    // Accessors.
    Token::Value op() { return op_; }
-  Value* value0() { return value0_; }
-  Value* value1() { return value1_; }
+  Value* left() { return left_; }
+  Value* right() { return right_; }

    // Support for fast-compilation mode.
    void Compile(MacroAssembler* masm);
@@ -433,8 +467,8 @@

   private:
    Token::Value op_;
-  Value* value0_;
-  Value* value1_;
+  Value* left_;
+  Value* right_;
  };


@@ -448,6 +482,9 @@
    explicit ReturnInstr(Value* value) : value_(value) {}

    virtual ~ReturnInstr() {}
+
+  // Accessors.
+  Value* value() { return value_; }

    // Support for fast-compilation mode.
    void Compile(MacroAssembler* masm);
=======================================
--- /branches/bleeding_edge/src/ia32/cfg-ia32.cc        Fri Aug  7 03:55:19 2009
+++ /branches/bleeding_edge/src/ia32/cfg-ia32.cc        Fri Aug  7 06:32:39 2009
@@ -111,27 +111,62 @@
    int count = CfgGlobals::current()->fun()->scope()->num_parameters();
    __ ret((count + 1) * kPointerSize);
  }
+
+
+void PropLoadInstr::Compile(MacroAssembler* masm) {
+  // The key should not be on the stack---if it is a compiler-generated
+  // temporary it is in the accumulator.
+  ASSERT(!key()->is_on_stack());
+
+  Comment cmnt(masm, "[ Load from Property");
+  // If the key is known at compile-time we may be able to use a load IC.
+  bool is_keyed_load = true;
+  if (key()->is_constant()) {
+    // Still use the keyed load IC if the key can be parsed as an integer  
so
+    // we will get into the case that handles [] on string objects.
+    Handle<Object> key_val = Constant::cast(key())->handle();
+    uint32_t ignored;
+    if (key_val->IsSymbol() &&
+        !String::cast(*key_val)->AsArrayIndex(&ignored)) {
+      is_keyed_load = false;
+    }
+  }
+
+  if (!object()->is_on_stack()) object()->Push(masm);
+  // A test eax instruction after the call indicates to the IC code that it
+  // was inlined.  Ensure there is not one here.
+  if (is_keyed_load) {
+    key()->Push(masm);
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+    __ call(ic, RelocInfo::CODE_TARGET);
+    __ pop(ebx);  // Discard key.
+  } else {
+    key()->Get(masm, ecx);
+    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+    __ call(ic, RelocInfo::CODE_TARGET);
+  }
+  __ pop(ebx);  // Discard receiver.
+  location()->Set(masm, eax);
+}


  void BinaryOpInstr::Compile(MacroAssembler* masm) {
    // The right-hand value should not be on the stack---if it is a
    // compiler-generated temporary it is in the accumulator.
-  ASSERT(!value1()->is_on_stack());
+  ASSERT(!right()->is_on_stack());

    Comment cmnt(masm, "[ BinaryOpInstr");
    // We can overwrite one of the operands if it is a temporary.
    OverwriteMode mode = NO_OVERWRITE;
-  if (value0()->is_temporary()) {
+  if (left()->is_temporary()) {
      mode = OVERWRITE_LEFT;
-  } else if (value1()->is_temporary()) {
+  } else if (right()->is_temporary()) {
      mode = OVERWRITE_RIGHT;
    }

    // Push both operands and call the specialized stub.
-  if (!value0()->is_on_stack()) {
-    value0()->Push(masm);
-  }
-  value1()->Push(masm);
+  if (!left()->is_on_stack()) left()->Push(masm);
+  right()->Push(masm);
    GenericBinaryOpStub stub(op(), mode, SMI_CODE_IN_STUB);
    __ CallStub(&stub);
    location()->Set(masm, eax);
=======================================
--- /branches/bleeding_edge/src/x64/cfg-x64.cc  Fri Aug  7 03:55:19 2009
+++ /branches/bleeding_edge/src/x64/cfg-x64.cc  Fri Aug  7 06:32:39 2009
@@ -120,27 +120,62 @@
      __ int3();
    }
  }
+
+
+void PropLoadInstr::Compile(MacroAssembler* masm) {
+  // The key should not be on the stack---if it is a compiler-generated
+  // temporary it is in the accumulator.
+  ASSERT(!key()->is_on_stack());
+
+  Comment cmnt(masm, "[ Load from Property");
+  // If the key is known at compile-time we may be able to use a load IC.
+  bool is_keyed_load = true;
+  if (key()->is_constant()) {
+    // Still use the keyed load IC if the key can be parsed as an integer  
so
+    // we will get into the case that handles [] on string objects.
+    Handle<Object> key_val = Constant::cast(key())->handle();
+    uint32_t ignored;
+    if (key_val->IsSymbol() &&
+        !String::cast(*key_val)->AsArrayIndex(&ignored)) {
+      is_keyed_load = false;
+    }
+  }
+
+  if (!object()->is_on_stack()) object()->Push(masm);
+  // A test rax instruction after the call indicates to the IC code that it
+  // was inlined.  Ensure there is not one after the call below.
+  if (is_keyed_load) {
+    key()->Push(masm);
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+    __ Call(ic, RelocInfo::CODE_TARGET);
+    __ pop(rbx);  // Discard key.
+  } else {
+    key()->Get(masm, rcx);
+    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+    __ Call(ic, RelocInfo::CODE_TARGET);
+  }
+  __ pop(rbx);  // Discard receiver.
+  location()->Set(masm, rax);
+}


  void BinaryOpInstr::Compile(MacroAssembler* masm) {
    // The right-hand value should not be on the stack---if it is a
    // compiler-generated temporary it is in the accumulator.
-  ASSERT(!value1()->is_on_stack());
+  ASSERT(!right()->is_on_stack());

    Comment cmnt(masm, "[ BinaryOpInstr");
    // We can overwrite one of the operands if it is a temporary.
    OverwriteMode mode = NO_OVERWRITE;
-  if (value0()->is_temporary()) {
+  if (left()->is_temporary()) {
      mode = OVERWRITE_LEFT;
-  } else if (value1()->is_temporary()) {
+  } else if (right()->is_temporary()) {
      mode = OVERWRITE_RIGHT;
    }

    // Push both operands and call the specialized stub.
-  if (!value0()->is_on_stack()) {
-    value0()->Push(masm);
-  }
-  value1()->Push(masm);
+  if (!left()->is_on_stack()) left()->Push(masm);
+  right()->Push(masm);
    GenericBinaryOpStub stub(op(), mode, SMI_CODE_IN_STUB);
    __ CallStub(&stub);
    location()->Set(masm, rax);
@@ -151,7 +186,7 @@
    // The location should be 'Effect'.  As a side effect, move the value to
    // the accumulator.
    Comment cmnt(masm, "[ ReturnInstr");
-  value_->Get(masm, rax);
+  value()->Get(masm, rax);
  }



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

Reply via email to