Author: [EMAIL PROTECTED]
Date: Tue Dec  9 04:36:43 2008
New Revision: 951

Modified:
    branches/experimental/toiger/src/assembler-ia32.h
    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/virtual-frame-ia32.cc
    branches/experimental/toiger/src/virtual-frame-ia32.h

Log:
Experimental: more code generator changes.

1. Enable virtual frame/register allocator for for loops.

2. Spill all registers before the stack check code. We were always
    spilled before simply due to it being the function entry.  Now that
    we handle for loops, that is not necessarily the case.

3. Label blocks first reached via JumpTarget::Bind with a 'mergable'
    frame in case they are the later target of a backward CFG edge.  We
    didn't have non-spilled code at backward CFG edges before.

4. Avoid generating a branch to a jump for JumpTarget::Branch in the
    case that there is no code necessary to make the expected frame
    mergable.

5. Remove some overzealous spilling.
Review URL: http://codereview.chromium.org/13246

Modified: branches/experimental/toiger/src/assembler-ia32.h
==============================================================================
--- branches/experimental/toiger/src/assembler-ia32.h   (original)
+++ branches/experimental/toiger/src/assembler-ia32.h   Tue Dec  9 04:36:43  
2008
@@ -174,6 +174,15 @@
  };


+// The result of negating a hint is as if the corresponding condition
+// were negated by NegateCondition.  That is, no_hint is mapped to
+// itself and not_taken and taken are mapped to each other.
+inline Hint NegateHint(Hint hint) {
+  return (hint == no_hint)
+      ? no_hint
+      : ((hint == not_taken) ? taken : not_taken);
+}
+
  //  
-----------------------------------------------------------------------------
  // Machine instruction Immediates


Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Tue Dec  9 04:36:43  
2008
@@ -90,6 +90,26 @@
  }


+void CodeGenerator::SetFrame(VirtualFrame* new_frame) {
+  if (frame_ != NULL) {
+    frame_->DetachFromCodeGenerator();
+  }
+  if (new_frame != NULL) {
+    new_frame->AttachToCodeGenerator();
+  }
+  frame_ = new_frame;
+}
+
+
+void CodeGenerator::DeleteFrame() {
+  if (frame_ != NULL) {
+    frame_->DetachFromCodeGenerator();
+    delete frame_;
+    frame_ = NULL;
+  }
+}
+
+
  // Calling conventions:
  // ebp: frame pointer
  // esp: stack pointer
@@ -105,11 +125,11 @@
    // Initialize state.
    ASSERT(scope_ == NULL);
    scope_ = fun->scope();
-  ASSERT(frame_ == NULL);
-  set_frame(new VirtualFrame(this));
    ASSERT(allocator_ == NULL);
    RegisterAllocator register_allocator(this);
    allocator_ = &register_allocator;
+  ASSERT(frame_ == NULL);
+  SetFrame(new VirtualFrame(this));
    cc_reg_ = no_condition;
    function_return_.set_code_generator(this);
    function_return_is_shadowed_ = false;
@@ -288,8 +308,8 @@
    ASSERT(!has_cc());
    // There is no need to delete the register allocator, it is a
    // stack-allocated local.
+  DeleteFrame();
    allocator_ = NULL;
-  delete_frame();
    scope_ = NULL;
  }

@@ -497,6 +517,7 @@
      // The expression is a variable proxy that does not rewrite to a
      // property.  Global variables are treated as named property  
references.
      if (var->is_global()) {
+      frame_->SpillAll();
        LoadGlobal();
        ref->set_type(Reference::NAMED);
      } else {
@@ -1261,6 +1282,9 @@
          ExternalReference::address_of_stack_guard_limit();
      __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
      stack_is_ok.Branch(above_equal, taken);
+    // The stack check can trigger the debugger.  Before calling it, all
+    // values including constants must be spilled to the frame.
+    frame_->SpillAll();
      frame_->CallStub(&stub, 0);
      stack_is_ok.Bind();
    }
@@ -1275,7 +1299,6 @@


  void CodeGenerator::VisitBlock(Block* node) {
-  frame_->SpillAll();
    Comment cmnt(masm_, "[ Block");
    RecordStatementPosition(node);
    node->set_break_stack_height(break_stack_height_);
@@ -1370,10 +1393,6 @@
    Load(expression);
    // Remove the lingering expression result from the top of stack.
    frame_->Drop();
-  // Rather than using SpillAll after all recursive calls to Visit over
-  // statements, we spill here in the only statement type that uses the
-  // virtual frame.  This is temporary.
-  frame_->SpillAll();
  }


@@ -1416,6 +1435,7 @@
        // then statement, it escaped on all branches.  In that case, a jump
        // to the exit label would be dead code (and impossible, because we
        // don't have a current virtual frame to set at the exit label).
+      frame_->SpillAll();
        exit.Jump();
      }
      // else
@@ -1532,7 +1552,7 @@
      // receiver.
      frame_->Exit();
      __ ret((scope_->num_parameters() + 1) * kPointerSize);
-    delete_frame();
+    DeleteFrame();

      // Check that the size of the code used for returning matches what is
      // expected by the debugger.
@@ -1709,6 +1729,7 @@
      // If control flow can fall through from the body, jump to the next  
body
      // or the end of the statement.
      if (frame_ != NULL) {
+      frame_->SpillAll();
        if (i < length - 1 && cases->at(i + 1)->is_default()) {
          default_entry.Jump();
        } else {
@@ -1726,6 +1747,9 @@
      Comment cmnt(masm_, "[ Default clause");
      default_entry.Bind();
      VisitStatements(default_clause->statements());
+    if (frame_ != NULL) {
+      frame_->SpillAll();
+    }
      // If control flow can fall out of the default and there is a case  
after
      // it, jump to that case's body.
      if (frame_ != NULL && default_exit.is_bound()) {
@@ -1744,7 +1768,6 @@


  void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
-  frame_->SpillAll();
    Comment cmnt(masm_, "[ LoopStatement");
    RecordStatementPosition(node);
    node->set_break_stack_height(break_stack_height_);
@@ -1770,6 +1793,8 @@

    switch (node->type()) {
      case LoopStatement::DO_LOOP: {
+      // The new code generator does not yet compile do loops.
+      frame_->SpillAll();
        JumpTarget body(this);
        IncrementLoopNesting();
        // Label the body.
@@ -1783,6 +1808,9 @@
        }
        CheckStack();  // TODO(1222600): ignore if body contains calls.
        Visit(node->body());
+      if (frame_ != NULL) {
+        frame_->SpillAll();
+      }

        // Compile the "test".
        if (info == ALWAYS_TRUE) {
@@ -1816,6 +1844,8 @@
      }

      case LoopStatement::WHILE_LOOP: {
+      // The new code generator does not yet compile while loops.
+      frame_->SpillAll();
        JumpTarget body(this);
        IncrementLoopNesting();
        // Generate the loop header.
@@ -1847,6 +1877,7 @@

          // If control flow can fall out of the body, jump back to the top.
          if (frame_ != NULL) {
+          frame_->SpillAll();
            node->continue_target()->Jump();
          }
        }
@@ -1864,8 +1895,9 @@
        // There is no need to compile the test or body.
        if (info == ALWAYS_FALSE) break;

-      // If there is no update statement, label the top of the loop with  
the
-      // continue target, otherwise with the loop target.
+      // Label the top of the loop for the backward CFG edge.  If there is
+      // no update expression label it with the continue target, otherwise
+      // with the loop target.
        if (node->next() == NULL) {
          node->continue_target()->Bind();
        } else {
@@ -1890,7 +1922,7 @@

          if (node->next() == NULL) {
            // If there is no update statement and control flow can fall out
-          // of the loop, jump directly to the continue label.
+          // of the loop, jump to the continue label.
            if (frame_ != NULL) {
              node->continue_target()->Jump();
            }
@@ -2089,6 +2121,9 @@
    // Body.
    CheckStack();  // TODO(1222600): ignore if body contains calls.
    Visit(node->body());
+  if (frame_ != NULL) {
+    frame_->SpillAll();
+  }

    // Next.
    node->continue_target()->Bind();
@@ -2134,6 +2169,7 @@

    VisitStatements(node->catch_block()->statements());
    if (frame_ != NULL) {
+    frame_->SpillAll();
      exit.Jump();
    }

@@ -2164,6 +2200,9 @@
    bool was_inside_try = is_inside_try_;
    is_inside_try_ = true;
    VisitStatements(node->try_block()->statements());
+  if (frame_ != NULL) {
+    frame_->SpillAll();
+  }
    is_inside_try_ = was_inside_try;

    // Stop the introduced shadowing and count the number of required  
unlinks.
@@ -2272,6 +2311,9 @@
    bool was_inside_try = is_inside_try_;
    is_inside_try_ = true;
    VisitStatements(node->try_block()->statements());
+  if (frame_ != NULL) {
+    frame_->SpillAll();
+  }
    is_inside_try_ = was_inside_try;

    // Stop the introduced shadowing and count the number of required  
unlinks.
@@ -2348,6 +2390,7 @@

    break_stack_height_ -= kFinallyStackSize;
    if (frame_ != NULL) {
+    frame_->SpillAll();
      JumpTarget exit(this);
      // Restore state and return value or faked TOS.
      frame_->EmitPop(ecx);
@@ -2852,7 +2895,6 @@


  void CodeGenerator::VisitAssignment(Assignment* node) {
-  frame_->SpillAll();
    Comment cmnt(masm_, "[ Assignment");

    RecordStatementPosition(node);
@@ -2870,6 +2912,7 @@
        Load(node->value());

      } else {
+      frame_->SpillAll();
        target.GetValue(NOT_INSIDE_TYPEOF);
        Literal* literal = node->value()->AsLiteral();
        if (IsInlineSmi(literal)) {

Modified: branches/experimental/toiger/src/codegen-ia32.h
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.h     (original)
+++ branches/experimental/toiger/src/codegen-ia32.h     Tue Dec  9 04:36:43 2008
@@ -174,11 +174,10 @@
    MacroAssembler* masm() { return masm_; }

    VirtualFrame* frame() const { return frame_; }
-  void set_frame(VirtualFrame* frame) { frame_ = frame; }
-  void delete_frame() {
-    delete frame_;
-    frame_ = NULL;
-  }
+
+  void SetFrame(VirtualFrame* frame);
+
+  void DeleteFrame();

    RegisterAllocator* allocator() const { return allocator_; }


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 Dec  9  
04:36:43 2008
@@ -68,22 +68,22 @@
    ASSERT(current_frame != NULL);

    if (expected_frame_ == NULL) {
-    expected_frame_ = current_frame;
      // The frame at the actual function return will always have height  
zero.
      if (code_generator_->IsActualFunctionReturn(this)) {
-      expected_frame_->Forget(expected_frame_->height());
+      current_frame->Forget(current_frame->height());
      }
-    if (!expected_frame_->IsMergable()) {
-      expected_frame_->MakeMergable();
+    if (!current_frame->IsMergable()) {
+      current_frame->MakeMergable();
      }
-    code_generator_->set_frame(NULL);
+    expected_frame_ = current_frame;
+    code_generator_->SetFrame(NULL);
    } else {
      // No code needs to be emitted to merge to the expected frame at the
      // actual function return.
      if (!code_generator_->IsActualFunctionReturn(this)) {
        current_frame->MergeTo(expected_frame_);
      }
-    code_generator_->delete_frame();
+    code_generator_->DeleteFrame();
    }

    __ jmp(&label_);
@@ -107,8 +107,22 @@
      if (code_generator_->IsActualFunctionReturn(this)) {
        expected_frame_->Forget(expected_frame_->height());
      }
-    if (!expected_frame_->IsMergable()) {
+    // For a branch, the frame at the fall-through basic block (not  
labeled)
+    // does not need to be mergable, but only the other (labeled) one.   
That
+    // is achieved by reversing the condition and emitting the make  
mergable
+    // code as the actual fall-through block.  This is necessary only when
+    // MakeMergable will generate code.
+    if (expected_frame_->RequiresMergeCode()) {
+      Label original_fall_through;
+      __ j(NegateCondition(cc), &original_fall_through, NegateHint(hint));
        expected_frame_->MakeMergable();
+      __ jmp(&label_);
+      __ bind(&original_fall_through);
+    } else {
+      if (!expected_frame_->IsMergable()) {
+        expected_frame_->MakeMergable();
+      }
+      __ j(cc, &label_, hint);
      }
    } else {
      // No code needs to be emitted to merge to the expected frame at the
@@ -116,9 +130,8 @@
      if (!code_generator_->IsActualFunctionReturn(this)) {
        current_frame->MergeTo(expected_frame_);
      }
+      __ j(cc, &label_, hint);
    }
-
-  __ j(cc, &label_, hint);
    // Postcondition: there is both a current frame and an expected frame at
    // the label and they match.
  }
@@ -161,16 +174,18 @@
    ASSERT(!label_.is_bound());

    if (expected_frame_ == NULL) {
-    expected_frame_ = new VirtualFrame(current_frame);
+    // When a label is bound the current frame becomes the expected frame  
at
+    // the label.  This requires the current frame to be mergable.
      // The frame at the actual function return will always have height  
zero.
      if (code_generator_->IsActualFunctionReturn(this)) {
-      expected_frame_->Forget(expected_frame_->height());
+      current_frame->Forget(current_frame->height());
      }
-    if (!expected_frame_->IsMergable()) {
-      expected_frame_->MakeMergable();
+    if (!current_frame->IsMergable()) {
+      current_frame->MakeMergable();
      }
+    expected_frame_ = new VirtualFrame(current_frame);
    } else if (current_frame == NULL) {
-    code_generator_->set_frame(new VirtualFrame(expected_frame_));
+    code_generator_->SetFrame(new VirtualFrame(expected_frame_));
    } else {
      // No code needs to be emitted to merge to the expected frame at the
      // actual function return.

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 Dec  9  
04:36:43 2008
@@ -44,7 +44,7 @@
    : type_(REGISTER),
      cgen_(cgen) {
    data_.reg_ = reg;
-  ASSERT(!reg().is(no_reg));
+  ASSERT(!reg.is(no_reg));
    cgen_->allocator()->Use(reg);
  }

@@ -240,6 +240,7 @@
    }
  }

+
  // Make the type of all elements be MEMORY.
  void VirtualFrame::SpillAll() {
    for (int i = 0; i < elements_.length(); i++) {
@@ -296,6 +297,35 @@
  }


+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.
+  RegisterFile non_synced_regs;
+  for (int i = 0; i < elements_.length(); i++) {
+    FrameElement element = elements_[i];
+    if (!element.is_synced()) {
+      if (element.is_register()) {
+        non_synced_regs.Use(elements_[i].reg());
+      } else if (!element.is_memory()) {
+        // Not memory or register and not synced.
+        return true;
+      }
+    }
+  }
+
+  for (int i = 0; i < RegisterFile::kNumRegisters; i++) {
+    if (non_synced_regs.count(i) > 1) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
  void VirtualFrame::MakeMergable() {
    Comment cmnt(masm_, "[ Make frame mergable");
    // Remove constants from the frame and ensure that no registers are
@@ -318,10 +348,6 @@
        if (element.is_synced()) {
          new_elements[i] = memory_element;
        } else {
-        // This code path is currently not triggered.  UNIMPLEMENTED is
-        // temporarily used to trap when it becomes active so we can test
-        // it.
-        UNIMPLEMENTED();
          Register reg = cgen_->allocator()->AllocateWithoutSpilling();
          if (reg.is(no_reg)) {
            new_elements[i] = memory_element;
@@ -432,17 +458,60 @@
            stack_pointer_--;
            __ pop(target.reg());
          }
-        Use(target.reg());
-      } else if (source.is_constant()) {
-        // Not yet implemented.  When done, code in common with the
-        // memory-to-register just above case can be factored out.
-        UNIMPLEMENTED();
+      } else {
+        // Source is constant.
+        __ Set(target.reg(), Immediate(source.handle()));
        }
+      Use(target.reg());
        elements_[i] = target;
      }
    }

+  // At this point, the frames should be identical.
    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()) {
+      ASSERT(elements_[i].is_memory());
+      ASSERT(elements_[i].is_synced() && expect.is_synced());
+    } else if (expect.is_register()) {
+      ASSERT(elements_[i].is_register());
+      ASSERT(elements_[i].reg().is(expect.reg()));
+      ASSERT(elements_[i].is_synced() == expect.is_synced());
+    } else {
+      ASSERT(expect.is_constant());
+      ASSERT(elements_[i].is_constant());
+      ASSERT(elements_[i].handle().location() ==
+             expect.handle().location());
+      ASSERT(elements_[i].is_synced() == expect.is_synced());
+    }
+  }
+#endif
+}
+
+
+void VirtualFrame::DetachFromCodeGenerator() {
+  // Tell the global register allocator that it is free to reallocate all
+  // register references contained in this frame.  The frame elements  
remain
+  // register references, so the frame-internal reference count is not
+  // decremented.
+  for (int i = 0; i < elements_.length(); i++) {
+    if (elements_[i].is_register()) {
+      cgen_->allocator()->Unuse(elements_[i].reg());
+    }
+  }
+}
+
+
+void VirtualFrame::AttachToCodeGenerator() {
+  // Tell the global register allocator that the frame-internal register
+  // references are live again.
+  for (int i = 0; i < elements_.length(); i++) {
+    if (elements_[i].is_register()) {
+      cgen_->allocator()->Use(elements_[i].reg());
+    }
+  }
  }


@@ -454,11 +523,14 @@
    frame_pointer_ = stack_pointer_;
    __ mov(ebp, Operand(esp));

-  // Store the context and the function in the frame.
-  Push(esi);
-  // The frame owns the register reference now.
-  cgen_->allocator()->Unuse(esi);
+  // Store the context in the frame.  The context is kept in esi, so the
+  // register reference is not owned by the frame (ie, the frame is not  
free
+  // to spill it).  This is implemented by making the in-frame value be
+  // memory.
+  EmitPush(esi);

+  // Store the function in the frame.  The frame owns the register  
reference
+  // now (ie, it can keep it in edi or spill it later).
    Push(edi);
    cgen_->allocator()->Unuse(edi);
  }

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 Dec  9  
04:36:43 2008
@@ -51,7 +51,7 @@

    ~Result() {
      // We have called Unuse() before Result goes out of scope.
-    ASSERT(reg_.is(no_reg));
+    ASSERT(!is_register() || reg().is(no_reg));
    }

    void Unuse();
@@ -211,6 +211,13 @@
    // location.
    bool IsMergable();

+  // True if making the frame mergable via MakeMergable will generate code.
+  // This differs from !IsMergable() because there are some non-mergable
+  // frames that can be made mergable simply by changing internal state  
(eg,
+  // forgetting about constants that are synced to memory) without
+  // generating code.
+  bool RequiresMergeCode();
+
    // Ensure that this frame is in a state where an arbitrary frame of the
    // right size could be merged to it.  May emit code.
    void MakeMergable();
@@ -219,6 +226,18 @@
    // frame.  As a side effect, code may be emitted to make this frame match
    // the expected one.
    void MergeTo(VirtualFrame* expected);
+
+  // Detach a frame from its code generator, perhaps temporarily.  This
+  // tells the register allocator that it is free to use frame-internal
+  // registers.  Used when the code generator's frame is switched from this
+  // one to NULL by an unconditional jump.
+  void DetachFromCodeGenerator();
+
+  // (Re)attach a frame to its code generator.  This informs the register
+  // allocator that the frame-internal register references are active  
again.
+  // Used when a code generator's frame is switched from NULL to this one  
by
+  // binding a label.
+  void AttachToCodeGenerator();

    // Emit code for the physical JS entry and exit frame sequences.  After
    // calling Enter, the virtual frame is ready for use; and after calling

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

Reply via email to