Author: [email protected]
Date: Thu Jan 15 05:58:19 2009
New Revision: 1082

Modified:
    branches/experimental/toiger/src/codegen-ia32.cc
    branches/experimental/toiger/src/jump-target-ia32.cc
    branches/experimental/toiger/src/jump-target.h
    branches/experimental/toiger/src/list.h
    branches/experimental/toiger/src/register-allocator-ia32.h
    branches/experimental/toiger/src/virtual-frame-ia32.cc
    branches/experimental/toiger/test/mjsunit/this.js

Log:
Experimental: for forward CFG edges, generate the code to merge to an
expected frame just before the entry to the basic block, rather than
at each exit from a preceding block.

This will enable us to make better decisions about the frame layout
for the block (better than first-come-first-served), to eliminate
silly jumps caused by empty merge code, and to eliminate the
constraint that the frame has to be mergable in blocks (that are only
targeted by forward CFG edges).
Review URL: http://codereview.chromium.org/18089

Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Thu Jan 15 05:58:19  
2009
@@ -1868,7 +1868,7 @@
    __ Align(4);
    JumpTarget table_start(this);
    table_start.Bind();
-  __ WriteInternalReference(jump_table_ref, *table_start.label());
+  __ WriteInternalReference(jump_table_ref, *table_start.entry_label());

    for (int i = 0; i < range; i++) {
      // table entry, 0 is placeholder for case address
@@ -1877,10 +1877,10 @@

    GenerateFastCaseSwitchCases(node, case_labels, &table_start);

-  for (int i = 0, entry_pos = table_start.label()->pos();
+  for (int i = 0, entry_pos = table_start.entry_label()->pos();
         i < range;
         i++, entry_pos += sizeof(uint32_t)) {
-    __ WriteInternalReference(entry_pos, *case_targets[i]->label());
+    __ WriteInternalReference(entry_pos, *case_targets[i]->entry_label());
    }
  }

@@ -2417,7 +2417,7 @@
    shadows.Add(new ShadowTarget(&function_return_));
    bool function_return_was_shadowed = function_return_is_shadowed_;
    function_return_is_shadowed_ = true;
-  ASSERT(shadows[kReturnShadowIndex]->original_target() ==  
&function_return_);
+  ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_);

    // Add the remaining shadow targets.
    for (int i = 0; i < nof_escapes; i++) {
@@ -2486,7 +2486,7 @@
        if (!function_return_is_shadowed_ && i == kReturnShadowIndex) {
          frame_->PrepareForReturn();
        }
-      shadows[i]->original_target()->Jump();
+      shadows[i]->other_target()->Jump();
      }
    }

@@ -2538,7 +2538,7 @@
    shadows.Add(new ShadowTarget(&function_return_));
    bool function_return_was_shadowed = function_return_is_shadowed_;
    function_return_is_shadowed_ = true;
-  ASSERT(shadows[kReturnShadowIndex]->original_target() ==  
&function_return_);
+  ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_);

    // Add the remaining shadow targets.
    for (int i = 0; i < nof_escapes; i++) {
@@ -2635,7 +2635,7 @@
      // formerly shadowing targets.
      for (int i = 0; i <= nof_escapes; i++) {
        if (shadows[i]->is_bound()) {
-        JumpTarget* original = shadows[i]->original_target();
+        JumpTarget* original = shadows[i]->other_target();
          __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i)));
          if (!function_return_is_shadowed_ && i == kReturnShadowIndex) {
            JumpTarget skip(this);

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        Thu Jan 15  
05:58:19 2009
@@ -38,16 +38,21 @@
  #define __ masm_->

  JumpTarget::JumpTarget(CodeGenerator* cgen)
-    : expected_frame_(NULL),
-      cgen_(cgen),
-      masm_(cgen->masm()) {
+    : cgen_(cgen),
+      reaching_frames_(0),
+      merge_labels_(0),
+      expected_frame_(NULL) {
+  ASSERT(cgen_ != NULL);
+  masm_ = cgen_->masm();
  }


  JumpTarget::JumpTarget()
-    : expected_frame_(NULL),
-      cgen_(NULL),
-      masm_(NULL) {
+    : cgen_(NULL),
+      masm_(NULL),
+      reaching_frames_(0),
+      merge_labels_(0),
+      expected_frame_(NULL) {
  }


@@ -60,30 +65,28 @@


  void JumpTarget::Jump() {
-  // Precondition: there is a current frame.  There may or may not be an
-  // expected frame at the label.
    ASSERT(cgen_ != NULL);
+  ASSERT(cgen_->has_valid_frame());
    ASSERT(!cgen_->has_cc());
-
-  VirtualFrame* current_frame = cgen_->frame();
-  ASSERT(current_frame != NULL);
+  // Live non-frame registers are not allowed at unconditional jumps
+  // because we have no way of invalidating the corresponding results
+  // which are still live in the C++ code.
    ASSERT(cgen_->HasValidEntryRegisters());

-  if (expected_frame_ == NULL) {
-    current_frame->MakeMergable();
-    expected_frame_ = current_frame;
-    ASSERT(cgen_->HasValidEntryRegisters());
-    RegisterFile ignored;
-    cgen_->SetFrame(NULL, &ignored);
-  } else {
-    current_frame->MergeTo(expected_frame_);
-    ASSERT(cgen_->HasValidEntryRegisters());
+  if (is_bound()) {
+    // Backward jump.  There is an expected frame to merge to.
+    cgen_->frame()->MergeTo(expected_frame_);
      cgen_->DeleteFrame();
+    __ jmp(&entry_label_);
+  } else {
+    // Forward jump.  The current frame is added to the end of the list
+    // of frames reaching the target block and a jump to the merge code
+    // is emitted.
+    AddReachingFrame(cgen_->frame());
+    RegisterFile empty;
+    cgen_->SetFrame(NULL, &empty);
+    __ jmp(&merge_labels_.last());
    }
-
-  __ jmp(&label_);
-  // Postcondition: there is no current frame but there is an expected  
frame
-  // at the label.
  }


@@ -97,79 +100,75 @@


  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.
    ASSERT(cgen_ != NULL);
-  ASSERT(masm_ != NULL);
+  ASSERT(cgen_->has_valid_frame());
    ASSERT(!cgen_->has_cc());

-  VirtualFrame* current_frame = cgen_->frame();
-  ASSERT(current_frame != NULL);
-
-  if (expected_frame_ == NULL) {
-    expected_frame_ = new VirtualFrame(current_frame);
-    // 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.
+  if (is_bound()) {
+    // Backward branch.  We have an expected frame to merge to on the
+    // backward edge.  We negate the condition and emit the merge code
+    // here.
      //
-    // TODO(): This is necessary only when MakeMergable will generate code.
+    // TODO(): we should try to avoid negating the condition in the case
+    // where there is no merge code to emit.  Otherwise, we emit a
+    // branch around an unconditional jump.
      Label original_fall_through;
      __ j(NegateCondition(cc), &original_fall_through, NegateHint(hint));
-    expected_frame_->MakeMergable();
-    __ jmp(&label_);
-    __ bind(&original_fall_through);
-  } else {
-    // We negate the condition and emit the code to merge to the expected
-    // frame immediately.
-    //
-    // TODO(): This should be replaced with a solution that emits the
-    // merge code for forward CFG edges at the appropriate entry to the
-    // target block.
-    Label original_fall_through;
-    __ j(NegateCondition(cc), &original_fall_through, NegateHint(hint));
-    VirtualFrame* working_frame = new VirtualFrame(current_frame);
-
-    // Switch to the working frame for the merge code with only the  
reserved
-    // registers referenced outside the frame.  Explicitly setting
-    // references here is ugly, but temporary.
-    RegisterFile non_frame_registers;
-    non_frame_registers.Use(esi);
-    non_frame_registers.Use(ebp);
-    non_frame_registers.Use(esp);
+    // Swap the current frame for a copy of it, saving non-frame
+    // register reference counts and invalidating all non-frame register
+    // references except the reserved ones on the backward edge.
+    VirtualFrame* original_frame = cgen_->frame();
+    VirtualFrame* working_frame = new VirtualFrame(original_frame);
+    RegisterFile non_frame_registers = RegisterAllocator::Reserved();
      cgen_->SetFrame(working_frame, &non_frame_registers);

      working_frame->MergeTo(expected_frame_);
-    ASSERT(cgen_->HasValidEntryRegisters());
-    __ jmp(&label_);
+    cgen_->DeleteFrame();
+    __ jmp(&entry_label_);

-    // Restore the current frame and its associated non-frame registers.
-    cgen_->SetFrame(current_frame, &non_frame_registers);
-    delete working_frame;
+    // Restore the frame and its associated non-frame registers.
+    cgen_->SetFrame(original_frame, &non_frame_registers);
      __ bind(&original_fall_through);
+  } else {
+    // Forward branch.  A copy of the current frame is added to the end
+    // of the list of frames reaching the target block and a branch to
+    // the merge code is emitted.
+    AddReachingFrame(new VirtualFrame(cgen_->frame()));
+    __ j(cc, &merge_labels_.last(), hint);
    }
-  // Postcondition: there is both a current frame and an expected frame at
-  // the label and they match.
  }


+#ifdef DEBUG
+#define DECLARE_ARGCHECK_VARS(name)                                \
+  Result::Type name##_type = name->type();                         \
+  Register name##_reg = name->is_register() ? name->reg() : no_reg
+
+#define ASSERT_ARGCHECK(name)                                \
+  ASSERT(name->type() == name##_type);                       \
+  ASSERT(!name->is_register() || name->reg().is(name##_reg))
+
+#else
+#define DECLARE_ARGCHECK_VARS(name) do {} while (false)
+
+#define ASSERT_ARGCHECK(name) do {} while (false)
+#endif
+
+
+
  void JumpTarget::Branch(Condition cc, Result* arg, Hint hint) {
    ASSERT(cgen_ != NULL);
    ASSERT(cgen_->has_valid_frame());

-#ifdef DEBUG
-  // We want register results at the call site to stay in the same  
registers
-  // on the fall-through branch.
-  Result::Type arg_type = arg->type();
-  Register arg_reg = arg->is_register() ? arg->reg() : no_reg;
-#endif
+  // We want to check that non-frame registers at the call site stay in
+  // the same registers on the fall-through branch.
+  DECLARE_ARGCHECK_VARS(arg);

    cgen_->frame()->Push(arg);
    Branch(cc, hint);
    *arg = cgen_->frame()->Pop();

-  ASSERT(arg->type() == arg_type);
-  ASSERT(!arg->is_register() || arg->reg().is(arg_reg));
+  ASSERT_ARGCHECK(arg);
  }


@@ -177,14 +176,10 @@
    ASSERT(cgen_ != NULL);
    ASSERT(cgen_->frame() != NULL);

-#ifdef DEBUG
-  // We want register results at the call site to stay in the same  
registers
-  // on the fall-through branch.
-  Result::Type arg0_type = arg0->type();
-  Register arg0_reg = arg0->is_register() ? arg0->reg() : no_reg;
-  Result::Type arg1_type = arg1->type();
-  Register arg1_reg = arg1->is_register() ? arg1->reg() : no_reg;
-#endif
+  // We want to check that non-frame registers at the call site stay in
+  // the same registers on the fall-through branch.
+  DECLARE_ARGCHECK_VARS(arg0);
+  DECLARE_ARGCHECK_VARS(arg1);

    cgen_->frame()->Push(arg0);
    cgen_->frame()->Push(arg1);
@@ -192,76 +187,88 @@
    *arg1 = cgen_->frame()->Pop();
    *arg0 = cgen_->frame()->Pop();

-  ASSERT(arg0->type() == arg0_type);
-  ASSERT(!arg0->is_register() || arg0->reg().is(arg0_reg));
-  ASSERT(arg1->type() == arg1_type);
-  ASSERT(!arg1->is_register() || arg1->reg().is(arg1_reg));
+  ASSERT_ARGCHECK(arg0);
+  ASSERT_ARGCHECK(arg1);
  }

+#undef DECLARE_ARGCHECK_VARS
+#undef ASSERT_ARGCHECK
+

  void JumpTarget::Call() {
-  // Precondition: there is a current frame, and there is no expected frame
-  // at the label.
+  // Call is used to push the address of the catch block on the stack as
+  // a return address when compiling try/catch and try/finally.  We
+  // fully spill the frame before making the call.  The expected frame
+  // at the label (which should be the only one) is the spilled current
+  // frame plus an in-memory return address.  The "fall-through" frame
+  // at the return site is the spilled current frame.
    ASSERT(cgen_ != NULL);
-  ASSERT(masm_ != NULL);
+  ASSERT(cgen_->has_valid_frame());
    ASSERT(!cgen_->has_cc());
-
-  VirtualFrame* current_frame = cgen_->frame();
-  ASSERT(current_frame != NULL);
-  ASSERT(expected_frame_ == NULL);
+  // There are no non-frame references across the call.
    ASSERT(cgen_->HasValidEntryRegisters());
+  ASSERT(!is_linked());

-  expected_frame_ = new VirtualFrame(current_frame);
-  expected_frame_->MakeMergable();
-  // Adjust the expected frame's height to account for the return address
-  // pushed by the call instruction.
-  expected_frame_->Adjust(1);
-  ASSERT(cgen_->HasValidEntryRegisters());
-
-  __ call(&label_);
-  // Postcondition: there is both a current frame and an expected frame at
-  // the label.  The current frame is one shorter than the one at the label
-  // (which contains the return address in memory).
+  cgen_->frame()->SpillAll();
+  VirtualFrame* target_frame = new VirtualFrame(cgen_->frame());
+  target_frame->Adjust(1);
+  AddReachingFrame(target_frame);
+  __ call(&merge_labels_.last());
  }


  void JumpTarget::Bind() {
-  // Precondition: there is either a current frame or an expected frame at
-  // the label (and possibly both).  The label is unbound.
    ASSERT(cgen_ != NULL);
-  ASSERT(masm_ != NULL);
+  ASSERT(is_linked() || cgen_->has_valid_frame());
+  ASSERT(!cgen_->has_cc());
+  ASSERT(!is_bound());
    ASSERT(!cgen_->has_cc());

-  VirtualFrame* current_frame = cgen_->frame();
-  ASSERT(current_frame != NULL || expected_frame_ != NULL);
-  ASSERT(!label_.is_bound());
-
-  if (expected_frame_ == NULL) {
-    ASSERT(cgen_->HasValidEntryRegisters());
-    // When a label is bound the current frame becomes the expected frame  
at
-    // the label.  This requires the current frame to be mergable.
-    current_frame->MakeMergable();
-    ASSERT(cgen_->HasValidEntryRegisters());
-    expected_frame_ = new VirtualFrame(current_frame);
-  } else if (current_frame == NULL) {
-    // Pick up the frame from the label.  No merge code is necessary.
-    // Manually setting the reserved register reference counts is clumsy  
but
-    // temporary.
-    RegisterFile non_frame_registers;
-    non_frame_registers.Use(esi);
-    non_frame_registers.Use(ebp);
-    non_frame_registers.Use(esp);
-    cgen_->SetFrame(new VirtualFrame(expected_frame_),  
&non_frame_registers);
-    ASSERT(cgen_->HasValidEntryRegisters());
+  if (is_linked()) {
+    // There were forward jumps.  A mergable frame is created and all
+    // the frames reaching the block via forward jumps are merged to it.
+    ASSERT(reaching_frames_.length() == merge_labels_.length());
+
+    // Choose a frame as the basis of the expected frame, and make it
+    // mergable.  If there is a current frame use it, otherwise use the
+    // first in the list (there will be at least one).
+    int start_index = 0;
+    if (cgen_->has_valid_frame()) {
+      // Live non-frame registers are not allowed at the start of a labeled
+      // basic block.
+      ASSERT(cgen_->HasValidEntryRegisters());
+    } else {
+      RegisterFile reserved_registers = RegisterAllocator::Reserved();
+      cgen_->SetFrame(reaching_frames_[start_index], &reserved_registers);
+      __ bind(&merge_labels_[start_index++]);
+    }
+    cgen_->frame()->MakeMergable();
+    expected_frame_ = new VirtualFrame(cgen_->frame());
+
+    for (int i = start_index; i < reaching_frames_.length(); i++) {
+      cgen_->DeleteFrame();
+      __ jmp(&entry_label_);
+
+      RegisterFile reserved_registers = RegisterAllocator::Reserved();
+      cgen_->SetFrame(reaching_frames_[i], &reserved_registers);
+      __ bind(&merge_labels_[i]);
+
+      cgen_->frame()->MergeTo(expected_frame_);
+    }
+    __ bind(&entry_label_);
+
+    // All but the last reaching virtual frame have been deleted, and
+    // the last one is the current frame.
+    reaching_frames_.Clear();
+    merge_labels_.Clear();
    } else {
+    // There were no forward jumps.  There must be a current frame,
+    // which is made mergable and used as the expected frame.
      ASSERT(cgen_->HasValidEntryRegisters());
-    current_frame->MergeTo(expected_frame_);
-    ASSERT(cgen_->HasValidEntryRegisters());
+    cgen_->frame()->MakeMergable();
+    expected_frame_ = new VirtualFrame(cgen_->frame());
+    __ bind(&entry_label_);
    }
-
-  __ bind(&label_);
-  // Postcondition: there is both a current frame and an expected frame at
-  // the label and they match.  The label is bound.
  }


@@ -279,7 +286,7 @@
  void JumpTarget::Bind(Result* arg0, Result* arg1) {
    ASSERT(cgen_ != NULL);

-  if (cgen_->frame() != NULL) {
+  if (cgen_->has_valid_frame()) {
      cgen_->frame()->Push(arg0);
      cgen_->frame()->Push(arg1);
    }
@@ -289,36 +296,70 @@
  }


+void JumpTarget::CopyTo(JumpTarget* destination) {
+  ASSERT(destination != NULL);
+  destination->cgen_ = cgen_;
+  destination->masm_ = masm_;
+
+  destination->reaching_frames_.Clear();
+  destination->merge_labels_.Clear();
+  ASSERT(reaching_frames_.length() == merge_labels_.length());
+  for (int i = 0; i < reaching_frames_.length(); i++) {
+    destination->reaching_frames_.Add(reaching_frames_[i]);
+    destination->merge_labels_.Add(merge_labels_[i]);
+  }
+  destination->expected_frame_ = expected_frame_;
+  destination->entry_label_ = entry_label_;
+}
+
+
+void JumpTarget::AddReachingFrame(VirtualFrame* frame) {
+  ASSERT(reaching_frames_.length() == merge_labels_.length());
+  Label fresh;
+  merge_labels_.Add(fresh);
+  reaching_frames_.Add(frame);
+}
+
+
  //  
-------------------------------------------------------------------------
  // ShadowTarget implementation.

-ShadowTarget::ShadowTarget(JumpTarget* original) {
-  ASSERT(original != NULL);
-  original_target_ = original;
-  original_pos_ = original->label()->pos_;
-  original_expected_frame_ = original->expected_frame();
-
-  // We do not call Unuse() on the orginal jump target, because we do not
-  // want to delete the expected frame.
-  original->label()->pos_ = 0;
-  original->set_expected_frame(NULL);
+ShadowTarget::ShadowTarget(JumpTarget* shadowed) {
+  ASSERT(shadowed != NULL);
+  other_target_ = shadowed;
+
  #ifdef DEBUG
    is_shadowing_ = true;
  #endif
+  // While shadowing this shadow target saves the state of the original.
+  shadowed->CopyTo(this);
+
+  // Setting the code generator to null prevents the shadow target from
+  // being used until shadowing stops.
+  cgen_ = NULL;
+  masm_ = NULL;
+
+  // The original's state is reset.  We do not Unuse it because that
+  // would delete the expected frame and assert that the target is not
+  // linked.
+  shadowed->Reset();
  }


  void ShadowTarget::StopShadowing() {
    ASSERT(is_shadowing_);
-  ASSERT(is_unused());
-
-  set_code_generator(original_target_->code_generator());
-  label_.pos_ = original_target_->label()->pos_;
-  expected_frame_ = original_target_->expected_frame();

-  original_target_->label()->pos_ = original_pos_;
-  original_target_->set_expected_frame(original_expected_frame_);
+  // The states of this target, which was shadowed, and the original
+  // target, which was shadowing, are swapped.
+  JumpTarget temp;
+
+  other_target_->CopyTo(&temp);
+  CopyTo(other_target_);
+  temp.CopyTo(this);
+  temp.Reset();  // So the destructor does not deallocate virtual frames.

+  // The shadowing target does not have a valid code generator yet.
+  other_target_->set_code_generator(cgen_);
  #ifdef DEBUG
    is_shadowing_ = false;
  #endif

Modified: branches/experimental/toiger/src/jump-target.h
==============================================================================
--- branches/experimental/toiger/src/jump-target.h      (original)
+++ branches/experimental/toiger/src/jump-target.h      Thu Jan 15 05:58:19 2009
@@ -35,18 +35,20 @@
  //  
-------------------------------------------------------------------------
  // Jump targets
  //
-// A jump target is an abstraction of a control-flow target in generated
-// code.  It encapsulates an assembler label and an expected virtual frame
-// layout at that label.  The first time control flow reaches the target,
-// either via jumping or branching or by binding the target, the expected
-// frame is set.  If control flow subsequently reaches the target, code may
-// be emitted to ensure that the current frame matches the expected frame.
+// TODO(): Update this comment.
  //
-// A jump target must have been reached via control flow (either by  
jumping,
-// branching, or falling through) when it is bound.  In particular, this
-// means that at least one of the control-flow graph edges reaching the
-// target must be a forward edge and must be compiled before any backward
-// edges.
+// A jump target is an abstraction of a basic-block entry in generated
+// code.  It collects all the virtual frames reaching the block by
+// forward jumps and pairs them with labels for the merge code along
+// all forward-reaching paths.  When bound, an expected frame for the
+// block is determined and code is generated to merge to the expected
+// frame.  For backward jumps, the merge code is generated at the edge
+// leaving the predecessor block.
+//
+// A jump target must have been reached via control flow (either by
+// jumping, branching, or falling through) at the time it is bound.
+// In particular, this means that at least one of the control-flow
+// graph edges reaching the target must be a forward edge.

  class JumpTarget : public ZoneObject {  // Shadows are dynamically  
allocated.
   public:
@@ -59,7 +61,7 @@
    // useful, eg, when jump targets are embedded in AST nodes.
    JumpTarget();

-  virtual ~JumpTarget() { delete expected_frame_; }
+  virtual ~JumpTarget() { Unuse(); }

    // Supply a code generator.  This function expects to be given a non-null
    // code generator, and to be called only when the code generator is not
@@ -69,7 +71,7 @@
    // Accessors.
    CodeGenerator* code_generator() const { return cgen_; }

-  Label* label() { return &label_; }
+  Label* entry_label() { return &entry_label_; }

    VirtualFrame* expected_frame() const { return expected_frame_; }
    void set_expected_frame(VirtualFrame* frame) {
@@ -77,53 +79,88 @@
    }

    // Predicates testing the state of the encapsulated label.
-  bool is_bound() const { return label_.is_bound(); }
-  bool is_linked() const { return label_.is_linked(); }
-  bool is_unused() const { return label_.is_unused(); }
-
-  // Treat the jump target as a fresh one---the label is unused and the
-  // expected frame if any is reset.
+  bool is_bound() const { return expected_frame_ != NULL; }
+  bool is_linked() const { return reaching_frames_.length() > 0; }
+  bool is_unused() const { return !is_bound() && !is_linked(); }
+
+  // Treat the jump target as a fresh one.  The expected frame if any
+  // will be deallocated and there should be no dangling jumps to the
+  // target (thus no reaching frames).
    void Unuse() {
-    label_.Unuse();
+    ASSERT(!is_linked());
+    entry_label_.Unuse();
      delete expected_frame_;
      expected_frame_ = NULL;
    }

-  // Emit a jump to the target.  There must be a current frame before the
+  // Reset the internal state of this jump target.  Pointed-to virtual
+  // frames are not deallocated and dangling jumps to the target are
+  // left dangling.
+  void Reset() {
+    reaching_frames_.Clear();
+    merge_labels_.Clear();
+    expected_frame_ = NULL;
+    entry_label_.Unuse();
+  }
+
+  // Copy the state of this jump target to the destination.  The lists
+  // of forward-reaching frames and merge-point labels are copied.
+  // All virtual frame pointers are copied, not the pointed-to frames.
+  // The previous state of the destination is overwritten, without
+  // deallocating pointed-to virtual frames.
+  void CopyTo(JumpTarget* destination);
+
+  // Emit a jump to the target.  There must be a current frame at 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.
+  // Emit a conditional branch to the target.  There must be a current
+  // frame at the branch.  The current frame will fall through to the
+  // code after the branch.
    void Branch(Condition cc, Hint hint = no_hint);
    void Branch(Condition cc, Result* arg, Hint hint = no_hint);
    void Branch(Condition cc, Result* arg0, Result* arg1, Hint hint =  
no_hint);

-  // Bind a jump target.  There must be a current frame and no expected
-  // frame at the target (targets are only bound once).
+  // Bind a jump target.  If there is no current frame at the binding
+  // site, there must be at least one frame reaching via a forward
+  // jump.  This frame will be used to establish an expected frame for
+  // the block, which will be the current frame after the bind.
    void Bind();
    void Bind(Result* arg);
    void Bind(Result* arg0, Result* arg1);

-  // Emit a call to a jump target.  There must be a current frame.  The
-  // frame at the target is the same as the current frame except for an
-  // extra return address on top of it.
+  // Emit a call to a jump target.  There must be a current frame at
+  // the call.  The frame at the target is the same as the current
+  // frame except for an extra return address on top of it.  The frame
+  // after the call is the same as the frame before the call.
    void Call();

   protected:
-  // The encapsulated assembler label.
-  Label label_;
-
-  // The expected frame where the label is bound, or NULL.
-  VirtualFrame* expected_frame_;
-
- private:
-  // The code generator gives access to the current frame.
+  // The code generator gives access to its current frame.
    CodeGenerator* cgen_;

    // Used to emit code.
    MacroAssembler* masm_;
+
+ private:
+  // A list of frames reaching this block via forward jumps.
+  List<VirtualFrame*> reaching_frames_;
+
+  // A parallel list of labels for merge code.
+  List<Label> merge_labels_;
+
+  // The (mergable) frame expected at backward jumps to the block.
+  VirtualFrame* expected_frame_;
+
+  // The actual entry label of the block.
+  Label entry_label_;
+
+  // Add a virtual frame reaching this labeled block via a forward
+  // jump, and a fresh label for its merge code.
+  void AddReachingFrame(VirtualFrame* frame);
+
+  DISALLOW_COPY_AND_ASSIGN(JumpTarget);
  };


@@ -139,39 +176,35 @@

  class ShadowTarget : public JumpTarget {
   public:
-  // Construct a shadow a jump target.  After construction, the original
-  // jump target shadows the former target, which is hidden as the
-  // newly-constructed shadow target.
-  explicit ShadowTarget(JumpTarget* original);
+  // Construct a shadow jump target.  After construction the shadow
+  // target object holds the state of the original jump target, and
+  // the original target is actually a fresh one that intercepts jumps
+  // intended for the shadowed one.
+  explicit ShadowTarget(JumpTarget* shadowed);

    virtual ~ShadowTarget() {
      ASSERT(!is_shadowing_);
    }

-  // End shadowing.  After shadowing ends, the original jump target gives
-  // access to the formerly shadowed target and the shadow target object
-  // gives access to the formerly shadowing target.
+  // End shadowing.  After shadowing ends, the original jump target
+  // again gives access to the formerly shadowed target and the shadow
+  // target object gives access to the formerly shadowing target.
    void StopShadowing();

-  // During shadowing, the currently shadowing target.  After shadowing,  
the
-  // target that was shadowed.
-  JumpTarget* original_target() const { return original_target_; }
+  // During shadowing, the currently shadowing target.  After
+  // shadowing, the target that was shadowed.
+  JumpTarget* other_target() const { return other_target_; }

   private:
-  // During shadowing, the currently shadowing target.  After shadowing,  
the
-  // target that was shadowed.
-  JumpTarget* original_target_;
-
-  // During shadowing, the saved state of the shadowed target's label.
-  int original_pos_;
-
-  // During shadowing, the saved state of the shadowed target's expected
-  // frame.
-  VirtualFrame* original_expected_frame_;
+  // During shadowing, the currently shadowing target.  After
+  // shadowing, the target that was shadowed.
+  JumpTarget* other_target_;

  #ifdef DEBUG
    bool is_shadowing_;
  #endif
+
+  DISALLOW_COPY_AND_ASSIGN(ShadowTarget);
  };



Modified: branches/experimental/toiger/src/list.h
==============================================================================
--- branches/experimental/toiger/src/list.h     (original)
+++ branches/experimental/toiger/src/list.h     Thu Jan 15 05:58:19 2009
@@ -57,10 +57,10 @@
      ASSERT(0 <= i && i < length_);
      return data_[i];
    }
-  inline T& at(int i) const  { return this->operator[](i); }
-  INLINE(const T& last() const)  {
+  inline T& at(int i) const  { return operator[](i); }
+  inline T& last() const {
      ASSERT(!is_empty());
-    return this->at(length_ - 1);
+    return at(length_ - 1);
    }

    INLINE(bool is_empty() const) { return length_ == 0; }

Modified: branches/experimental/toiger/src/register-allocator-ia32.h
==============================================================================
--- branches/experimental/toiger/src/register-allocator-ia32.h  (original)
+++ branches/experimental/toiger/src/register-allocator-ia32.h  Thu Jan 15  
05:58:19 2009
@@ -174,6 +174,14 @@
   public:
    explicit RegisterAllocator(CodeGenerator* cgen) : cgen_(cgen) {}

+  static RegisterFile Reserved() {
+    RegisterFile reserved;
+    reserved.Use(esi);
+    reserved.Use(ebp);
+    reserved.Use(esp);
+    return reserved;
+  }
+
    int num_registers() const { return RegisterFile::kNumRegisters; }

    // Predicates and accessors for the registers' reference counts.

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      Thu Jan 15  
05:58:19 2009
@@ -309,16 +309,9 @@

  void VirtualFrame::MakeMergable() {
    Comment cmnt(masm_, "[ Make frame mergable");
-  // We can call MakeMergable on a frame that is not the code generator's
-  // current frame, which will leave the global register counts out of sync
-  // with the frame.  We simply save the current frame and restore it at  
the
-  // end of this function.  We should find a better way to deal with this.
-  VirtualFrame* original_frame = cgen_->frame();
-  RegisterFile non_frame_registers;
-  non_frame_registers.Use(esi);
-  non_frame_registers.Use(ebp);
-  non_frame_registers.Use(esp);
-  cgen_->SetFrame(this, &non_frame_registers);
+  // We should always be merging the code generator's current frame to an
+  // expected frame.
+  ASSERT(cgen_->frame() == this);
    ASSERT(cgen_->HasValidEntryRegisters());

    // Remove constants from the frame and ensure that no registers are
@@ -392,7 +385,6 @@

    delete[] new_elements;
    ASSERT(cgen_->HasValidEntryRegisters());
-  cgen_->SetFrame(original_frame, &non_frame_registers);
  }


@@ -426,6 +418,7 @@
        ASSERT(!elements_[i].is_synced());
      }
  #endif
+    ASSERT(!cgen_->has_cc());
      __ add(Operand(esp), Immediate(height_difference * kPointerSize));
      stack_pointer_ = expected->stack_pointer_;
    } else if (stack_pointer_ < expected->stack_pointer_) {
@@ -563,10 +556,11 @@
                ASSERT(!elements_[j].is_memory());
              }
  #endif
-            __ add(Operand(esp),
-                   Immediate((stack_pointer_ - i) * kPointerSize));
+            int difference = stack_pointer_ - i;
+            ASSERT(!cgen_->has_cc());
+            __ add(Operand(esp), Immediate(difference * kPointerSize));
              stack_pointer_ = i;
-            }
+          }
            stack_pointer_--;
            __ pop(target.reg());
          }
@@ -938,6 +932,7 @@
    if (num_virtual_elements < count) {
      int num_dropped = count - num_virtual_elements;
      stack_pointer_ -= num_dropped;
+    ASSERT(!cgen_->has_cc());
      __ add(Operand(esp), Immediate(num_dropped * kPointerSize));
    }

@@ -958,6 +953,7 @@
    if (popped.is_constant()) {
      if (pop_needed) {
        stack_pointer_--;
+      ASSERT(!cgen_->has_cc());
        __ add(Operand(esp), Immediate(kPointerSize));
      }
      return Result(popped.handle(), cgen_);
@@ -965,6 +961,7 @@
      Unuse(popped.reg());
      if (pop_needed) {
        stack_pointer_--;
+      ASSERT(!cgen_->has_cc());
        __ add(Operand(esp), Immediate(kPointerSize));
      }
      return Result(popped.reg(), cgen_);

Modified: branches/experimental/toiger/test/mjsunit/this.js
==============================================================================
--- branches/experimental/toiger/test/mjsunit/this.js   (original)
+++ branches/experimental/toiger/test/mjsunit/this.js   Thu Jan 15 05:58:19  
2009
@@ -35,7 +35,7 @@
  assertTrue(this === f());

  var x = {}, y = {};
-x.f = y.f = f;
+x.f = y.f = f;
  assertFalse(x === f());
  assertFalse(y === f());
  assertTrue(x === x.f());

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

Reply via email to