Author: [EMAIL PROTECTED]
Date: Tue Nov 11 03:40:34 2008
New Revision: 731

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

Log:
Add state to track the individual elements of the virtual frame.
Currently, all elements are eagerly pushed to and popped from the
actual frame, so they are always in memory.

The code still passes all the v8 and mozilla tests (in debug mode,
asserting that frames match at every CFG merge point).

This change has not yet been ported to ARM.
Review URL: http://codereview.chromium.org/9769

Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Tue Nov 11 03:40:34  
2008
@@ -32,7 +32,6 @@
  #include "debug.h"
  #include "scopes.h"
  #include "runtime.h"
-#include "virtual-frame-ia32-inl.h"

  namespace v8 { namespace internal {

@@ -156,7 +155,7 @@
      }

      // Allocate space for locals and initialize them.
-    frame_->AllocateLocals();
+    frame_->AllocateStackSlots(scope_->num_stack_slots());

      if (scope_->num_heap_slots() > 0) {
        Comment cmnt(masm_, "[ allocate local context");
@@ -247,7 +246,7 @@
          }
          shadow_ref.SetValue(NOT_CONST_INIT);
        }
-      frame_->Pop();  // Value is no longer needed.
+      frame_->Drop();  // Value is no longer needed.
      }

      // Generate code to 'execute' declarations and initialize functions
@@ -720,7 +719,7 @@
    if (op == Token::COMMA) {
      // Simply discard left value.
      frame_->Pop(eax);
-    frame_->Pop();
+    frame_->Drop();
      frame_->Push(eax);
      return;
    }
@@ -1364,7 +1363,7 @@
      // safe to pop the value lying on top of the reference before unloading
      // the reference itself (which preserves the top of stack) because we
      // know that it is a zero-sized reference.
-    frame_->Pop();
+    frame_->Drop();
    }
  }

@@ -1376,7 +1375,7 @@
    expression->MarkAsStatement();
    Load(expression);
    // Remove the lingering expression result from the top of stack.
-  frame_->Pop();
+  frame_->Drop();
  }


@@ -1465,7 +1464,7 @@
        } else {
          // No cc value set up, that means the boolean was pushed.
          // Pop it again, since it is not going to be used.
-        frame_->Pop();
+        frame_->Drop();
        }
      }
    }
@@ -1684,7 +1683,7 @@
        Branch(false, &next_test);

        // Before entering the body, remove the switch value from the stack.
-      frame_->Pop();
+      frame_->Drop();

        // Label the body so that fall through is enabled.
        if (i > 0 && cases->at(i - 1)->is_default()) {
@@ -1709,7 +1708,7 @@

    // The final test removes the switch value.
    next_test.Bind();
-  frame_->Pop();
+  frame_->Drop();

    // If there is a default clause, compile it.
    if (default_clause != NULL) {
@@ -2021,31 +2020,31 @@
    // Condition.
    entry.Bind();

-  __ mov(eax, frame_->Element(0));  // load the current count
-  __ cmp(eax, frame_->Element(1));  // compare to the array length
+  __ mov(eax, frame_->ElementAt(0));  // load the current count
+  __ cmp(eax, frame_->ElementAt(1));  // compare to the array length
    cleanup.Branch(above_equal);

    // Get the i'th entry of the array.
-  __ mov(edx, frame_->Element(2));
+  __ mov(edx, frame_->ElementAt(2));
    __ mov(ebx, Operand(edx, eax, times_2,
                        FixedArray::kHeaderSize - kHeapObjectTag));

    // Get the expected map from the stack or a zero map in the
    // permanent slow case eax: current iteration count ebx: i'th entry
    // of the enum cache
-  __ mov(edx, frame_->Element(3));
+  __ mov(edx, frame_->ElementAt(3));
    // Check if the expected map still matches that of the enumerable.
    // If not, we have to filter the key.
    // eax: current iteration count
    // ebx: i'th entry of the enum cache
    // edx: expected map value
-  __ mov(ecx, frame_->Element(4));
+  __ mov(ecx, frame_->ElementAt(4));
    __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
    __ cmp(ecx, Operand(edx));
    end_del_check.Branch(equal);

    // Convert the entry to a string (or null if it isn't a property  
anymore).
-  frame_->Push(frame_->Element(4));  // push enumerable
+  frame_->Push(frame_->ElementAt(4));  // push enumerable
    frame_->Push(ebx);  // push entry
    frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2);
    __ mov(ebx, Operand(eax));
@@ -2061,7 +2060,7 @@
    { Reference each(this, node->each());
      if (!each.is_illegal()) {
        if (each.size() > 0) {
-        frame_->Push(frame_->Element(each.size()));
+        frame_->Push(frame_->ElementAt(each.size()));
        }
        // If the reference was to a slot we rely on the convenient property
        // that it doesn't matter whether a value (eg, ebx pushed above) is
@@ -2073,13 +2072,13 @@
          // ie, now the topmost value of the non-zero sized reference),  
since
          // we will discard the top of stack after unloading the reference
          // anyway.
-        frame_->Pop();
+        frame_->Drop();
        }
      }
    }
    // Discard the i'th entry pushed above or else the remainder of the
    // reference, whichever is currently on top of the stack.
-  frame_->Pop();
+  frame_->Drop();

    // Body.
    CheckStack();  // TODO(1222600): ignore if body contains calls.
@@ -2124,7 +2123,7 @@
    }

    // Remove the exception from the stack.
-  frame_->Pop();
+  frame_->Drop();

    VisitStatements(node->catch_block()->statements());
    if (frame_ != NULL) {
@@ -2646,7 +2645,7 @@
            frame_->Pop(eax);
            __ Set(ecx, Immediate(key));
            frame_->CallCode(ic, RelocInfo::CODE_TARGET, 0);
-          frame_->Pop();
+          frame_->Drop();
            // Ignore result.
            break;
          }
@@ -2911,7 +2910,7 @@

        // Pass receiver to called function.
        // The reference's size is non-negative.
-      frame_->Push(frame_->Element(ref.size()));
+      frame_->Push(frame_->ElementAt(ref.size()));

        // Call the function.
        CallWithArguments(args, node->position());
@@ -2962,7 +2961,7 @@

    // Load the function into temporary function slot as per calling
    // convention.
-  __ mov(edi, frame_->Element(args->length() + 1));
+  __ mov(edi, frame_->ElementAt(args->length() + 1));

    // Call the construct call builtin that handles allocation and
    // constructor invocation.
@@ -3174,7 +3173,7 @@
    JumpTarget leave(this);
    Load(args->at(0));  // Load the object.
    Load(args->at(1));  // Load the value.
-  __ mov(eax, frame_->Element(1));
+  __ mov(eax, frame_->ElementAt(1));
    __ mov(ecx, frame_->Top());
    // if (object->IsSmi()) return object.
    __ test(eax, Immediate(kSmiTagMask));
@@ -3192,7 +3191,7 @@
    // Leave.
    leave.Bind();
    __ mov(ecx, frame_->Top());
-  frame_->Pop();
+  frame_->Drop();
    __ mov(frame_->Top(), ecx);
  }

@@ -3507,7 +3506,7 @@

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

      // Perform optimistic increment/decrement.
@@ -3532,7 +3531,7 @@

    // Postfix: Discard the new value and use the old.
    if (is_postfix) {
-    frame_->Pop();
+    frame_->Drop();
    }
  }

@@ -3589,7 +3588,7 @@

        // Pop the result of evaluating the first part.
        pop_and_continue.Bind();
-      frame_->Pop();
+      frame_->Drop();

        // Evaluate right side expression.
        is_true.Bind();
@@ -3632,7 +3631,7 @@

        // Pop the result of evaluating the first part.
        pop_and_continue.Bind();
-      frame_->Pop();
+      frame_->Drop();

        // Evaluate right side expression.
        is_false.Bind();

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        Tue Nov 11  
03:40:34 2008
@@ -75,7 +75,7 @@
      // The frame at the actual function return will always have height
      // zero.
      if (code_generator_->IsActualFunctionReturn(this)) {
-      expected_frame_->height_ = 0;
+      expected_frame_->Forget(expected_frame_->height());
      }
    } else {
      // No code needs to be emitted to merge to the expected frame at the
@@ -106,7 +106,7 @@
      // The frame at the actual function return will always have height
      // zero.
      if (code_generator_->IsActualFunctionReturn(this)) {
-      expected_frame_->height_ = 0;
+      expected_frame_->Forget(expected_frame_->height());
      }
    } else {
      // No code needs to be emitted to merge to the expected frame at the
@@ -136,7 +136,7 @@
    expected_frame_ = new VirtualFrame(current_frame);
    // Adjust the expected frame's height to account for the return address
    // pushed by the call instruction.
-  expected_frame_->height_++;
+  expected_frame_->Adjust(1);

    __ call(&label_);

@@ -162,7 +162,7 @@
      // The frame at the actual function return will always have height
      // zero.
      if (code_generator_->IsActualFunctionReturn(this)) {
-      expected_frame_->height_ = 0;
+      expected_frame_->Forget(expected_frame_->height());
      }
    } else if (current_frame == NULL) {
      code_generator_->set_frame(new VirtualFrame(expected_frame_));

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      Tue Nov 11  
03:40:34 2008
@@ -40,41 +40,71 @@

  VirtualFrame::VirtualFrame(CodeGenerator* cgen)
      : masm_(cgen->masm()),
+      elements_(cgen->scope()->num_parameters() + 5),
+      virtual_stack_pointer_(-1),
+      virtual_frame_pointer_(-1),
        parameter_count_(cgen->scope()->num_parameters()),
-      frame_local_count_(cgen->scope()->num_stack_slots()),
-      height_(0) {
+      local_count_(0) {
+  // The virtual frame contains a receiver, the parameters, and a return
+  // address (all in memory) when it is created.
+  Adjust(parameter_count_ + 2);
  }


  VirtualFrame::VirtualFrame(VirtualFrame* original)
      : masm_(original->masm_),
+      elements_(original->elements_.length()),
+      virtual_stack_pointer_(original->virtual_stack_pointer_),
+      virtual_frame_pointer_(original->virtual_frame_pointer_),
        parameter_count_(original->parameter_count_),
-      frame_local_count_(original->frame_local_count_),
-      height_(original->height_) {
+      local_count_(original->local_count_) {
+  // Copy all the elements.
+  for (int i = 0; i <= virtual_stack_pointer_; i++) {
+    elements_.Add(original->elements_[i]);
+  }
+}
+
+
+void VirtualFrame::Adjust(int count) {
+  ASSERT(count >= 0);
+  for (int i = 0; i < count; i++) {
+    AddElement(Element());
+  }
  }


  void VirtualFrame::Forget(int count) {
    ASSERT(count >= 0);
-  ASSERT(height_ >= count);
-  height_ -= count;
+  ASSERT(virtual_stack_pointer_ >= count);
+  for (int i = 0; i < count; i++) {
+    RemoveElement();
+  }
  }


  void VirtualFrame::MergeTo(VirtualFrame* expected) {
    ASSERT(masm_ == expected->masm_);
-  ASSERT(frame_local_count_ == expected->frame_local_count_);
+  ASSERT(elements_.length() == expected->elements_.length());
+  ASSERT(virtual_frame_pointer_ == expected->virtual_frame_pointer_);
+  ASSERT(virtual_stack_pointer_ == expected->virtual_stack_pointer_);
    ASSERT(parameter_count_ == expected->parameter_count_);
-  ASSERT(height_ == expected->height_);
+  ASSERT(local_count_ == expected->local_count_);
+  for (int i = 0; i <= virtual_stack_pointer_; i++) {
+    ASSERT(elements_[i].matches(expected->elements_[i]));
+  }
  }


  void VirtualFrame::Enter() {
    Comment cmnt(masm_, "[ Enter JS frame");
+  Adjust(1);
    __ push(ebp);
+
+  virtual_frame_pointer_ = virtual_stack_pointer_;
    __ mov(ebp, Operand(esp));

    // Store the context and the function in the frame.
+  Adjust(2);
    __ push(esi);
    __ push(edi);

@@ -100,14 +130,110 @@
  }


-void VirtualFrame::AllocateLocals() {
-  if (frame_local_count_ > 0) {
+void VirtualFrame::AllocateStackSlots(int count) {
+  ASSERT(height() == 0);
+  local_count_ = count;
+  Adjust(count);
+  if (count > 0) {
      Comment cmnt(masm_, "[ Allocate space for locals");
      __ Set(eax, Immediate(Factory::undefined_value()));
-    for (int i = 0; i < frame_local_count_; i++) {
+    for (int i = 0; i < count; i++) {
        __ push(eax);
      }
    }
+}
+
+
+void VirtualFrame::PushTryHandler(HandlerType type) {
+  // Grow the expression stack by handler size less two (the return address
+  // is already pushed by a call instruction, and PushTryHandler from the
+  // macro assembler will leave the top of stack in the eax register to be
+  // pushed separately).
+  Adjust(kHandlerSize - 2);
+  __ PushTryHandler(IN_JAVASCRIPT, type);
+  // TODO(1222589): remove the reliance of PushTryHandler on a cached TOS
+  Push(eax);
+}
+
+
+void VirtualFrame::CallStub(CodeStub* stub, int frame_arg_count) {
+  ASSERT(height() >= frame_arg_count);
+  Forget(frame_arg_count);
+  __ CallStub(stub);
+}
+
+
+void VirtualFrame::CallRuntime(Runtime::Function* f, int frame_arg_count) {
+  ASSERT(height() >= frame_arg_count);
+  Forget(frame_arg_count);
+  __ CallRuntime(f, frame_arg_count);
+}
+
+
+void VirtualFrame::CallRuntime(Runtime::FunctionId id, int  
frame_arg_count) {
+  ASSERT(height() >= frame_arg_count);
+  Forget(frame_arg_count);
+  __ CallRuntime(id, frame_arg_count);
+}
+
+
+void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
+                                 InvokeFlag flag,
+                                 int frame_arg_count) {
+  ASSERT(height() >= frame_arg_count);
+  Forget(frame_arg_count);
+  __ InvokeBuiltin(id, flag);
+}
+
+
+void VirtualFrame::CallCode(Handle<Code> code,
+                            RelocInfo::Mode rmode,
+                            int frame_arg_count) {
+  ASSERT(height() >= frame_arg_count);
+  Forget(frame_arg_count);
+  __ call(code, rmode);
+}
+
+
+void VirtualFrame::Drop(int count) {
+  ASSERT(height() >= count);
+  Forget(count);
+  if (count > 0) {
+    __ add(Operand(esp), Immediate(count * kPointerSize));
+  }
+}
+
+
+void VirtualFrame::Drop() { Drop(1); }
+
+
+void VirtualFrame::Pop(Register reg) {
+  Forget(1);
+  __ pop(reg);
+}
+
+
+void VirtualFrame::Pop(Operand operand) {
+  Forget(1);
+  __ pop(operand);
+}
+
+
+void VirtualFrame::Push(Register reg) {
+  Adjust(1);
+  __ push(reg);
+}
+
+
+void VirtualFrame::Push(Operand operand) {
+  Adjust(1);
+  __ push(operand);
+}
+
+
+void VirtualFrame::Push(Immediate immediate) {
+  Adjust(1);
+  __ push(immediate);
  }

  #undef __

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       Tue Nov 11  
03:40:34 2008
@@ -33,6 +33,21 @@
  namespace v8 { namespace internal {

  //  
-------------------------------------------------------------------------
+// Virtual frame elements
+//
+// The internal elements of the virtual frames.  Elements are (currently)  
of
+// only one kind, in-memory.  Their actual location is given by their
+// position in the virtual frame.
+
+class Element BASE_EMBEDDED {
+ public:
+  Element() {}
+
+  bool matches(const Element& other) { return true; }
+};
+
+
+//  
-------------------------------------------------------------------------
  // Virtual frames
  //
  // The virtual frame is an abstraction of the physical stack frame.  It
@@ -52,12 +67,15 @@
    explicit VirtualFrame(VirtualFrame* original);

    // The height of the virtual expression stack.  Always non-negative.
-  int height() const { return height_; }
+  int height() const {
+    return virtual_stack_pointer_ - expression_base_index() + 1;
+  }

-  // Forget elements from the top of the expression stack.  This is
-  // used when the stack pointer is manually lowered to pop values
-  // left by statements (eg, for...in, try...finally) that have been
-  // escaped from.
+  // Add extra in-memory elements to the top of the frame without  
generating
+  // code.
+  void Adjust(int count);
+
+  // Forget frame elements without generating code.
    void Forget(int count);

    // Make this virtual frame have a state identical to an expected virtual
@@ -75,19 +93,20 @@
    // Allocate and initialize the frame-allocated locals.  The number of
    // locals is known from the frame's code generator's state (specifically
    // its scope).  As a side effect, code may be emitted.
-  void AllocateLocals();
+  void AllocateStackSlots(int count);

    // The current top of the expression stack as an assembly operand.
    Operand Top() const { return Operand(esp, 0); }

    // An element of the expression stack as an assembly operand.
-  Operand Element(int index) const {
+  Operand ElementAt(int index) const {
      return Operand(esp, index * kPointerSize);
    }

    // A frame-allocated local as an assembly operand.
    Operand Local(int index) const {
-    ASSERT(0 <= index && index < frame_local_count_);
+    ASSERT(0 <= index);
+    ASSERT(index < local_count_);
      return Operand(ebp, kLocal0Offset - index * kPointerSize);
    }

@@ -99,7 +118,8 @@

    // A parameter as an assembly operand.
    Operand Parameter(int index) const {
-    ASSERT(-1 <= index && index < parameter_count_);
+    ASSERT(-1 <= index);
+    ASSERT(index < parameter_count_);
      return Operand(ebp, (1 + parameter_count_ - index) * kPointerSize);
    }

@@ -107,47 +127,44 @@
    Operand Receiver() const { return Parameter(-1); }

    // Push a try-catch or try-finally handler on top of the virtual frame.
-  inline void PushTryHandler(HandlerType type);
+  void PushTryHandler(HandlerType type);

    // Call a code stub, given the number of arguments it expects on (and
    // removes from) the top of the physical frame.
-  inline void CallStub(CodeStub* stub, int frame_arg_count);
+  void CallStub(CodeStub* stub, int frame_arg_count);

    // Call the runtime, given the number of arguments expected on (and
    // removed from) the top of the physical frame.
-  inline void CallRuntime(Runtime::Function* f, int frame_arg_count);
-  inline void CallRuntime(Runtime::FunctionId id, int frame_arg_count);
+  void CallRuntime(Runtime::Function* f, int frame_arg_count);
+  void CallRuntime(Runtime::FunctionId id, int frame_arg_count);

    // Invoke a builtin, given the number of arguments it expects on (and
    // removes from) the top of the physical frame.
-  inline void InvokeBuiltin(Builtins::JavaScript id,
-                            InvokeFlag flag,
-                            int frame_arg_count);
+  void InvokeBuiltin(Builtins::JavaScript id,
+                     InvokeFlag flag,
+                     int frame_arg_count);

    // Call into a JS code object, given the number of arguments it expects  
on
    // (and removes from) the top of the physical frame.
-  inline void CallCode(Handle<Code> ic,
-                       RelocInfo::Mode rmode,
-                       int frame_arg_count);
+  void CallCode(Handle<Code> ic, RelocInfo::Mode rmode, int  
frame_arg_count);

    // Drop a number of elements from the top of the expression stack.  May
-  // emit code to effect the physical frame.
-  inline void Drop(int count);
+  // emit code to affect the physical frame.  Does not clobber any  
registers
+  // excepting possibly the stack pointer.
+  void Drop(int count);

-  // Pop and discard an element from the top of the expression stack.
-  // Specifically does not clobber any registers excepting possibly the
-  // stack pointer.
-  inline void Pop();
+  // Drop one element.
+  void Drop();

    // Pop and save an element from the top of the expression stack.  May  
emit
    // code.
-  inline void Pop(Register reg);
-  inline void Pop(Operand operand);
+  void Pop(Register reg);
+  void Pop(Operand operand);

    // Push an element on top of the expression stack.  May emit code.
-  inline void Push(Register reg);
-  inline void Push(Operand operand);
-  inline void Push(Immediate immediate);
+  void Push(Register reg);
+  void Push(Operand operand);
+  void Push(Immediate immediate);

   private:
    static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
@@ -158,12 +175,37 @@

    MacroAssembler* masm_;

-  // The number of frame-allocated locals and parameters respectively.
+  List<Element> elements_;
+
+  // The virtual stack pointer is the index of the top element of the  
stack.
+  int virtual_stack_pointer_;
+
+  int virtual_frame_pointer_;
+
    int parameter_count_;
-  int frame_local_count_;
+  int local_count_;

-  // The height of the expression stack.
-  int height_;
+  // The index of the first parameter.  The receiver lies below the first
+  // parameter.
+  int param0_index() const { return 1; }
+
+  // The index of the first local.  Between the parameters and the locals
+  // lie the return address, the saved frame pointer, the context, and the
+  // function.
+  int local0_index() const { return param0_index() + parameter_count_ + 4;  
}
+
+  // The index of the base of the expression stack.
+  int expression_base_index() const { return local0_index() +  
local_count_; }
+
+  void AddElement(const Element& element) {
+    virtual_stack_pointer_++;
+    elements_.Add(element);
+  }
+
+  Element RemoveElement() {
+    virtual_stack_pointer_--;
+    return elements_.RemoveLast();
+  }

    // The JumpTarget class explicitly sets the height_ field of the expected
    // frame at the actual return target.

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

Reply via email to