Author: [email protected]
Date: Mon Dec 22 07:43:47 2008
New Revision: 1017

Modified:
    branches/experimental/toiger/src/codegen-ia32.cc
    branches/experimental/toiger/src/codegen-ia32.h
    branches/experimental/toiger/src/jump-target-ia32.cc
    branches/experimental/toiger/src/jump-target.h
    branches/experimental/toiger/src/virtual-frame-ia32.cc
    branches/experimental/toiger/src/virtual-frame-ia32.h

Log:
Experimental: push the new code generator infrastructure into the
count operations (pre- and post- increment and decrement).

For frame-allocated slots in registers, we can overwrite them.  This
is a simple way to reduce register pressure by not consuming a
register to back the frame element that will be written before being
read again.  It also ensures that frame-allocated slots that are the
target of count operations do not migrate to a different register,
which would make merging generate silly moves.

This change allows INVALID frame elements to appear in expected
frames.  It is always safe to merge to invalid elements.  Currently we
require both source and target elements to be invalid, but that could
be relaxed.
Review URL: http://codereview.chromium.org/16412

Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Mon Dec 22 07:43:47  
2008
@@ -3761,22 +3761,24 @@


  void DeferredCountOperation::Generate() {
-  // The argument is actually passed in eax.
-  enter()->Bind();
-  VirtualFrame::SpilledScope spilled_scope(generator());
+  CodeGenerator* cgen = generator();
+
+  Result value(cgen);
+  enter()->Bind(&value);
+  value.ToRegister(eax);  // The stubs below expect their argument in eax.
+
    if (is_postfix_) {
      RevertToNumberStub to_number_stub(is_increment_);
-    generator()->frame()->CallStub(&to_number_stub, 0);
+    value = generator()->frame()->CallStub(&to_number_stub, &value, 0);
    }
+
    CounterOpStub stub(result_offset_, is_postfix_, is_increment_);
-  generator()->frame()->CallStub(&stub, 0);
-  // The result is actually returned in eax.
-  exit()->Jump();
+  value = generator()->frame()->CallStub(&stub, &value, 0);
+  exit()->Jump(&value);
  }


  void CodeGenerator::VisitCountOperation(CountOperation* node) {
-  VirtualFrame::SpilledScope spilled_scope(this);
    Comment cmnt(masm_, "[ CountOperation");

    bool is_postfix = node->is_postfix();
@@ -3787,7 +3789,7 @@

    // Postfix: Make room for the result.
    if (is_postfix) {
-    frame_->EmitPush(Immediate(0));
+    frame_->Push(Handle<Object>(Smi::FromInt(0)));
    }

    { Reference target(this, node->expression());
@@ -3795,41 +3797,49 @@
        // Spoof the virtual frame to have the expected height (one higher
        // than on entry).
        if (!is_postfix) {
-        frame_->EmitPush(Immediate(Smi::FromInt(0)));
+        frame_->Push(Handle<Object>(Smi::FromInt(0)));
        }
        return;
      }
-    target.GetValueAndSpill(NOT_INSIDE_TYPEOF);
+    target.TakeValue(NOT_INSIDE_TYPEOF);

      DeferredCountOperation* deferred =
          new DeferredCountOperation(this, is_postfix, is_increment,
                                     target.size() * kPointerSize);

-    frame_->EmitPop(eax);  // Load TOS into eax for calculations below
+    Result value = frame_->Pop();
+    value.ToRegister();
+    ASSERT(value.is_valid());

      // Postfix: Store the old value as the result.
      if (is_postfix) {
-      __ mov(frame_->ElementAt(target.size()), eax);
+      Result old_value = value;
+      frame_->SetElementAt(target.size(), &old_value);
      }

-    // Perform optimistic increment/decrement.
+    // Perform optimistic increment/decrement.  Ensure the value is
+    // writable.
+    frame_->Spill(value.reg());
+    ASSERT(allocator_->count(value.reg()) == 1);
      if (is_increment) {
-      __ add(Operand(eax), Immediate(Smi::FromInt(1)));
+      __ add(Operand(value.reg()), Immediate(Smi::FromInt(1)));
      } else {
-      __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
+      __ sub(Operand(value.reg()), Immediate(Smi::FromInt(1)));
      }

      // If the count operation didn't overflow and the result is a
      // valid smi, we're done. Otherwise, we jump to the deferred
      // slow-case code.
-    deferred->enter()->Branch(overflow, not_taken);
-    __ test(eax, Immediate(kSmiTagMask));
-    deferred->enter()->Branch(not_zero, not_taken);
+    deferred->enter()->Branch(overflow, &value, not_taken);
+    __ test(value.reg(), Immediate(kSmiTagMask));
+    deferred->enter()->Branch(not_zero, &value, not_taken);

      // Store the new value in the target if not const.
-    deferred->exit()->Bind();
-    frame_->EmitPush(eax);  // Push the new value to TOS
-    if (!is_const) target.SetValue(NOT_CONST_INIT);
+    deferred->exit()->Bind(&value);
+    frame_->Push(&value);
+    if (!is_const) {
+      target.SetValue(NOT_CONST_INIT);
+    }
    }

    // Postfix: Discard the new value and use the old.
@@ -4299,6 +4309,37 @@

      default:
        UNREACHABLE();
+  }
+}
+
+
+void Reference::TakeValue(TypeofState typeof_state) {
+  // For non-constant frame-allocated slots, we invalidate the value in the
+  // slot.  For all others, we fall back on GetValue.
+  ASSERT(!cgen_->in_spilled_code());
+  ASSERT(!is_illegal());
+  ASSERT(!cgen_->has_cc());
+  if (type_ != SLOT) {
+    GetValue(typeof_state);
+    return;
+  }
+
+  Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
+  ASSERT(slot != NULL);
+  if (slot->type() == Slot::LOOKUP ||
+      slot->type() == Slot::CONTEXT ||
+      slot->var()->mode() == Variable::CONST) {
+    GetValue(typeof_state);
+    return;
+  }
+
+  // Only non-constant, frame-allocated parameters and locals can reach
+  // here.
+  if (slot->type() == Slot::PARAMETER) {
+    cgen_->frame()->TakeParameterAt(slot->index());
+  } else {
+    ASSERT(slot->type() == Slot::LOCAL);
+    cgen_->frame()->TakeLocalAt(slot->index());
    }
  }


Modified: branches/experimental/toiger/src/codegen-ia32.h
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.h     (original)
+++ branches/experimental/toiger/src/codegen-ia32.h     Mon Dec 22 07:43:47 2008
@@ -87,6 +87,11 @@
    // while the code generator is being transformed.
    inline void GetValueAndSpill(TypeofState typeof_state);

+  // Like GetValue except that the slot is expected to be written to before
+  // being read from again.  Thae value of the reference may be  
invalidated,
+  // causign subsequent attempts to read it to fail.
+  void TakeValue(TypeofState typeof_state);
+
    // Generate code to store the value on top of the expression stack in the
    // reference.  The reference is expected to be immediately below the  
value
    // on the expression stack.  The stored value is left in place (with the

Modified: branches/experimental/toiger/src/jump-target-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/jump-target-ia32.cc        (original)
+++ branches/experimental/toiger/src/jump-target-ia32.cc        Mon Dec 22  
07:43:47 2008
@@ -93,6 +93,15 @@
  }


+void JumpTarget::Jump(Result* arg) {
+  ASSERT(cgen_ != NULL);
+  ASSERT(cgen_->frame() != NULL);
+
+  cgen_->frame()->Push(arg);
+  Jump();
+}
+
+
  void JumpTarget::Branch(Condition cc, Hint hint) {
    // Precondition: there is a current frame.  There may or may not be an
    // expected frame at the label.

Modified: branches/experimental/toiger/src/jump-target.h
==============================================================================
--- branches/experimental/toiger/src/jump-target.h      (original)
+++ branches/experimental/toiger/src/jump-target.h      Mon Dec 22 07:43:47 2008
@@ -92,6 +92,7 @@
    // Emit a jump to the target.  There must be a current frame before the
    // jump and there will be no current frame after the jump.
    void Jump();
+  void Jump(Result* arg);

    // Emit a conditional branch to the target.  If there is no current  
frame,
    // there must be one expected at the target.

Modified: branches/experimental/toiger/src/virtual-frame-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-ia32.cc      (original)
+++ branches/experimental/toiger/src/virtual-frame-ia32.cc      Mon Dec 22  
07:43:47 2008
@@ -272,15 +272,15 @@


  bool VirtualFrame::RequiresMergeCode() {
-  // A frame requires merge code to be generated in the event that
-  // there are duplicated non-synched registers or else elements not
-  // in a (memory or register) location in the frame.  We look for
-  // non-synced non-location elements and count occurrences of
-  // non-synced registers.
+  // A frame requires code to be generated to make the frame mergable if
+  // there are duplicated non-synched registers or else valid elements not
+  // in a (memory or register) location in the frame.  We look for valid
+  // non-synced non-location elements and count occurrences of non-synced
+  // registers.
    RegisterFile non_synced_regs;
    for (int i = 0; i < elements_.length(); i++) {
      FrameElement element = elements_[i];
-    if (!element.is_synced()) {
+    if (element.is_valid() && !element.is_synced()) {
        if (element.is_register()) {
          non_synced_regs.Use(elements_[i].reg());
        } else if (!element.is_memory()) {
@@ -361,7 +361,7 @@
    for (int i = 0; i < elements_.length(); i++) {
      FrameElement source = elements_[i];
      FrameElement target = new_elements[i];
-    ASSERT(target.is_register() || target.is_memory());
+    ASSERT(!target.is_valid() || target.is_register() ||  
target.is_memory());
      if (target.is_register()) {
        if (source.is_constant()) {
          __ Set(target.reg(), Immediate(source.handle()));
@@ -369,8 +369,7 @@
          __ mov(target.reg(), source.reg());
        }
        elements_[i] = target;
-    } else {
-      // The target is memory.
+    } else if (target.is_memory()) {
        if (!source.is_memory()) {
          // Spilling a source register would decrement its reference count,
          // but we have already done that when computing new target  
elements,
@@ -378,6 +377,7 @@
          RawSpillElementAt(i);
        }
      }
+    // Invalid elements do not need to be moved.
    }

    delete[] new_elements;
@@ -410,11 +410,14 @@
    MergeMoveMemoryToRegisters(expected);

    // At this point, the frames should be identical.
+  // TODO(): Consider an "equals" method for frames.
    ASSERT(stack_pointer_ == expected->stack_pointer_);
  #ifdef DEBUG
    for (int i = 0; i < elements_.length(); i++) {
      FrameElement expect = expected->elements_[i];
-    if (expect.is_memory()) {
+    if (!expect.is_valid()) {
+      ASSERT(!elements_[i].is_valid());
+    } else if (expect.is_memory()) {
        ASSERT(elements_[i].is_memory());
        ASSERT(elements_[i].is_synced() && expect.is_synced());
      } else if (expect.is_register()) {
@@ -649,6 +652,34 @@
  }


+void VirtualFrame::SetElementAt(int index, Result* value) {
+  int frame_index = elements_.length() - index - 1;
+  ASSERT(frame_index >= 0);
+  ASSERT(frame_index < elements_.length());
+  ASSERT(value->is_valid());
+
+  // TODO(): if the element is backed by the same register or the same
+  // constant, consider preserving the sync bit.
+  if (elements_[frame_index].is_register()) {
+    Unuse(elements_[frame_index].reg());
+  }
+
+  if (value->is_register()) {
+    Use(value->reg());
+    elements_[frame_index] =
+        FrameElement::RegisterElement(value->reg(),
+                                      FrameElement::NOT_SYNCED);
+  } else {
+    ASSERT(value->is_constant());
+    elements_[frame_index] =
+        FrameElement::ConstantElement(value->handle(),
+                                      FrameElement::NOT_SYNCED);
+  }
+
+  value->Unuse();
+}
+
+
  void VirtualFrame::LoadFrameSlotAt(int index) {
    ASSERT(index >= 0);
    ASSERT(index < elements_.length());
@@ -686,6 +717,16 @@
  }


+void VirtualFrame::TakeFrameSlotAt(int index) {
+  LoadFrameSlotAt(index);
+
+  if (elements_[index].is_register()) {
+    Unuse(elements_[index].reg());
+  }
+  elements_[index] = FrameElement::InvalidElement();
+}
+
+
  void VirtualFrame::StoreToFrameSlotAt(int index) {
    // Store the value on top of the frame to the virtual frame slot at a
    // given index.  The value on top of the frame is left in place.
@@ -701,6 +742,8 @@
    elements_[index] = top;

    if (top.is_memory()) {
+    // TODO(): consider allocating the slot to a register.
+    //
      // Emit code to store memory values into the required frame slot.
      Result temp = cgen_->allocator()->Allocate();
      ASSERT(temp.is_valid());
@@ -735,6 +778,17 @@
    ASSERT(cgen_->HasValidEntryRegisters());
    PrepareForCall(frame_arg_count);
    __ CallStub(stub);
+}
+
+
+Result VirtualFrame::CallStub(CodeStub* stub,
+                              Result* arg,
+                              int frame_arg_count) {
+  arg->Unuse();
+  CallStub(stub, frame_arg_count);
+  Result result = cgen_->allocator()->Allocate(eax);
+  ASSERT(result.is_valid());
+  return result;
  }



Modified: branches/experimental/toiger/src/virtual-frame-ia32.h
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-ia32.h       (original)
+++ branches/experimental/toiger/src/virtual-frame-ia32.h       Mon Dec 22  
07:43:47 2008
@@ -58,6 +58,12 @@
      data_.reg_ = no_reg;
    }

+  // Factory function to construct an invalid frame element.
+  static FrameElement InvalidElement() {
+    FrameElement result;
+    return result;
+  }
+
    // Factory function to construct an in-memory frame element.
    static FrameElement MemoryElement() {
      FrameElement result;
@@ -97,6 +103,7 @@
      type_ = (type_ & ~SyncField::mask()) | SyncField::encode(NOT_SYNCED);
    }

+  bool is_valid() const { return type() != INVALID; }
    bool is_memory() const { return type() == MEMORY; }
    bool is_register() const { return type() == REGISTER; }
    bool is_constant() const { return type() == CONSTANT; }
@@ -242,6 +249,10 @@
      return Operand(esp, index * kPointerSize);
    }

+  // Random-access store to a frame-top relative frame element.  The result
+  // becomes owned by the frame and is invalidated.
+  void SetElementAt(int index, Result* value);
+
    // A frame-allocated local as an assembly operand.
    Operand LocalAt(int index) const {
      ASSERT(0 <= index);
@@ -254,6 +265,13 @@
      LoadFrameSlotAt(local0_index() + index);
    }

+  // Push the value of a local frame slot on top of the frame and  
invalidate
+  // the local slot.  The slot should be written to before trying to read
+  // from it again.
+  void TakeLocalAt(int index) {
+    TakeFrameSlotAt(local0_index() + index);
+  }
+
    // Store the top value on the virtual frame into a local frame slot.  The
    // value is left in place on top of the frame.
    void StoreToLocalAt(int index) {
@@ -278,6 +296,13 @@
      LoadFrameSlotAt(param0_index() + index);
    }

+  // Push the value of a paramter frame slot on top of the frame and
+  // invalidate the parameter slot.  The slot should be written to before
+  // trying to read from it again.
+  void TakeParameterAt(int index) {
+    TakeFrameSlotAt(param0_index() + index);
+  }
+
    // Store the top value on the virtual frame into a parameter frame slot.
    // The value is left in place on top of the frame.
    void StoreToParameterAt(int index) {
@@ -293,6 +318,7 @@
    // Call a code stub, given the number of arguments it expects on (and
    // removes from) the top of the physical frame.
    void CallStub(CodeStub* stub, int frame_arg_count);
+  Result CallStub(CodeStub* stub, Result* arg, int frame_arg_count);
    Result CallStub(CodeStub* stub,
                    Result* arg0,
                    Result* arg1,
@@ -447,6 +473,10 @@
    // Push a copy of a frame slot (typically a local or parameter) on top of
    // the frame.
    void LoadFrameSlotAt(int index);
+
+  // Push a the value of a frame slot (typically a local or parameter) on
+  // top of the frame and invalidate the slot.
+  void TakeFrameSlotAt(int index);

    // Store the value on top of the frame to a frame slot (typically a local
    // or parameter).

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

Reply via email to