Author: [email protected]
Date: Tue Feb 10 02:34:41 2009
New Revision: 1246

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

Log:
A bunch of changes to get the ARM port compiling again.
Review URL: http://codereview.chromium.org/20218

Modified: branches/experimental/toiger/src/codegen-arm.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-arm.cc     (original)
+++ branches/experimental/toiger/src/codegen-arm.cc     Tue Feb 10 02:34:41 2009
@@ -87,6 +87,17 @@
  }


+void CodeGenerator::SetFrame(VirtualFrame* new_frame) {
+  frame_ = new_frame;
+}
+
+
+void CodeGenerator::DeleteFrame() {
+  delete frame_;
+  frame_ = NULL;
+}
+
+
  // Calling conventions:
  // r0: the number of arguments
  // fp: frame pointer
@@ -101,9 +112,9 @@
    ASSERT(scope_ == NULL);
    scope_ = fun->scope();
    ASSERT(frame_ == NULL);
-  set_frame(new VirtualFrame(this));
+  frame_ = new VirtualFrame(this);
    cc_reg_ = al;
-  function_return_.set_code_generator(this);
+  function_return_.Initialize(this, JumpTarget::BIDIRECTIONAL);
    function_return_is_shadowed_ = false;
    {
      CodeGenState state(this);
@@ -771,10 +782,10 @@
          new DeferredInlinedSmiOperation(this, op, int_value, reversed);

        __ add(r0, r0, Operand(value), SetCC);
-      __ b(vs, deferred->enter());
+      deferred->enter()->Branch(vs);
        __ tst(r0, Operand(kSmiTagMask));
-      __ b(ne, deferred->enter());
-      __ bind(deferred->exit());
+      deferred->enter()->Branch(ne);
+      deferred->exit()->Bind();
        break;
      }

@@ -787,10 +798,10 @@
        } else {
          __ rsb(r0, r0, Operand(value), SetCC);
        }
-      __ b(vs, deferred->enter());
+      deferred->enter()->Branch(vs);
        __ tst(r0, Operand(kSmiTagMask));
-      __ b(ne, deferred->enter());
-      __ bind(deferred->exit());
+      deferred->enter()->Branch(ne);
+      deferred->exit()->Bind();
        break;
      }

@@ -800,14 +811,14 @@
        DeferredCode* deferred =
          new DeferredInlinedSmiOperation(this, op, int_value, reversed);
        __ tst(r0, Operand(kSmiTagMask));
-      __ b(ne, deferred->enter());
+      deferred->enter()->Branch(ne);
        switch (op) {
          case Token::BIT_OR:  __ orr(r0, r0, Operand(value)); break;
          case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break;
          case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break;
          default: UNREACHABLE();
        }
-      __ bind(deferred->exit());
+      deferred->exit()->Bind();
        break;
      }

@@ -825,14 +836,14 @@
          DeferredCode* deferred =
            new DeferredInlinedSmiOperation(this, op, shift_value, false);
          __ tst(r0, Operand(kSmiTagMask));
-        __ b(ne, deferred->enter());
+        deferred->enter()->Branch(ne);
          __ mov(r2, Operand(r0, ASR, kSmiTagSize));  // remove tags
          switch (op) {
            case Token::SHL: {
              __ mov(r2, Operand(r2, LSL, shift_value));
              // check that the *unsigned* result fits in a smi
              __ add(r3, r2, Operand(0x40000000), SetCC);
-            __ b(mi, deferred->enter());
+            deferred->enter()->Branch(mi);
              break;
            }
            case Token::SHR: {
@@ -847,7 +858,7 @@
              // smi tagging these two cases can only happen with shifts
              // by 0 or 1 when handed a valid smi
              __ and_(r3, r2, Operand(0xc0000000), SetCC);
-            __ b(ne, deferred->enter());
+            deferred->enter()->Branch(ne);
              break;
            }
            case Token::SAR: {
@@ -860,7 +871,7 @@
            default: UNREACHABLE();
          }
          __ mov(r0, Operand(r2, LSL, kSmiTagSize));
-        __ bind(deferred->exit());
+        deferred->exit()->Bind();
        }
        break;
      }
@@ -1011,13 +1022,11 @@

  void CodeGenerator::VisitBlock(Block* node) {
    Comment cmnt(masm_, "[ Block");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    node->set_break_stack_height(break_stack_height_);
-  node->break_target()->set_code_generator(this);
+  node->break_target()->Initialize(this);
    VisitStatements(node->statements());
-  if (node->break_target()->is_linked()) {
-    node->break_target()->Bind();
-  }
+  node->break_target()->Bind();
  }


@@ -1034,7 +1043,7 @@

  void CodeGenerator::VisitDeclaration(Declaration* node) {
    Comment cmnt(masm_, "[ Declaration");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    Variable* var = node->proxy()->var();
    ASSERT(var != NULL);  // must have been resolved
    Slot* slot = var->slot();
@@ -1100,7 +1109,7 @@

  void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
    Comment cmnt(masm_, "[ ExpressionStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    Expression* expression = node->expression();
    expression->MarkAsStatement();
    Load(expression);
@@ -1110,7 +1119,7 @@

  void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
    Comment cmnt(masm_, "// EmptyStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    // nothing to do
  }

@@ -1122,7 +1131,7 @@
    bool has_then_stm = node->HasThenStatement();
    bool has_else_stm = node->HasElseStatement();

-  CodeForStatement(node);
+  CodeForStatementPosition(node);

    JumpTarget exit(this);
    if (has_then_stm && has_else_stm) {
@@ -1207,7 +1216,7 @@

  void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
    Comment cmnt(masm_, "[ ContinueStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    CleanStack(break_stack_height_ - node->target()->break_stack_height());
    node->target()->continue_target()->Jump();
  }
@@ -1215,7 +1224,7 @@

  void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
    Comment cmnt(masm_, "[ BreakStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    CleanStack(break_stack_height_ - node->target()->break_stack_height());
    node->target()->break_target()->Jump();
  }
@@ -1223,7 +1232,7 @@

  void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
    Comment cmnt(masm_, "[ ReturnStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    Load(node->expression());
    // Move the function result into r0.
    frame_->Pop(r0);
@@ -1234,7 +1243,7 @@

  void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
    Comment cmnt(masm_, "[ WithEnterStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    Load(node->expression());
    if (node->is_catch_block()) {
      frame_->CallRuntime(Runtime::kPushCatchContext, 1);
@@ -1255,7 +1264,7 @@

  void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
    Comment cmnt(masm_, "[ WithExitStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    // Pop context.
    __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
    // Update context local.
@@ -1276,9 +1285,9 @@
      SwitchStatement* node,
      int min_index,
      int range,
-    JumpTarget* fail_label,
-    Vector<JumpTarget*> case_targets,
-    Vector<JumpTarget> case_labels) {
+    Label* default_label,
+    Vector<Label*> case_targets,
+    Vector<Label> case_labels) {

    ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);

@@ -1291,7 +1300,7 @@
    __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag));
    __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag));
    __ cmp(r1, Operand(HEAP_NUMBER_TYPE));
-  fail_label->Branch(ne);
+  __ b(ne, default_label);
    frame_->EmitPush(r0);
    frame_->CallRuntime(Runtime::kNumberToSmi, 1);
    is_smi.Bind();
@@ -1311,32 +1320,31 @@
      }
    }
    __ tst(r0, Operand(0x80000000 | kSmiTagMask));
-  fail_label->Branch(ne);
+  __ b(ne, default_label);
    __ cmp(r0, Operand(Smi::FromInt(range)));
-  fail_label->Branch(ge);
+  __ b(ge, default_label);
    __ SmiJumpTable(r0, case_targets);

-  JumpTarget table_start(this);
-  table_start.Bind();
+  frame_->MakeMergable();
+  VirtualFrame* start_frame = new VirtualFrame(frame_);
    // Table containing branch operations.
    for (int i = 0; i < range; i++) {
-    case_targets[i]->Jump();
-    frame_ = new VirtualFrame(table_start.expected_frame());
+    __ jmp(case_targets[i]);
    }
-  GenerateFastCaseSwitchCases(node, case_labels, &table_start);
+  GenerateFastCaseSwitchCases(node, case_labels, start_frame);
+  delete start_frame;
  }


  void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
    Comment cmnt(masm_, "[ SwitchStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    node->set_break_stack_height(break_stack_height_);
-  node->break_target()->set_code_generator(this);
+  node->break_target()->Initialize(this);

    Load(node->tag());
-
    if (TryGenerateFastCaseSwitchStatement(node)) {
-      return;
+    return;
    }

    JumpTarget next_test(this);
@@ -1418,10 +1426,10 @@

  void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
    Comment cmnt(masm_, "[ LoopStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    node->set_break_stack_height(break_stack_height_);
-  node->break_target()->set_code_generator(this);
-  node->continue_target()->set_code_generator(this);
+  node->break_target()->Initialize(this);
+  node->continue_target()->Initialize(this);

    // Simple condition analysis.  ALWAYS_TRUE and ALWAYS_FALSE represent a
    // known result for the test expression, with no side effects.
@@ -1572,10 +1580,8 @@
              // Record source position of the statement as this code which  
is
              // after the code for the body actually belongs to the loop
              // statement and not the body.
-            CodeForStatement(node);
-
+            CodeForStatementPosition(node);

-            ASSERT(node->type() == LoopStatement::FOR_LOOP);
              Visit(node->next());
              loop.Jump();
            }
@@ -1593,7 +1599,7 @@

  void CodeGenerator::VisitForInStatement(ForInStatement* node) {
    Comment cmnt(masm_, "[ ForInStatement");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);

    // We keep stuff on the stack while the body is executing.
    // Record it, so that a break/continue crossing this statement
@@ -1601,8 +1607,8 @@
    const int kForInStackSize = 5 * kPointerSize;
    break_stack_height_ += kForInStackSize;
    node->set_break_stack_height(break_stack_height_);
-  node->break_target()->set_code_generator(this);
-  node->continue_target()->set_code_generator(this);
+  node->break_target()->Initialize(this);
+  node->continue_target()->Initialize(this);

    JumpTarget primitive(this);
    JumpTarget jsobject(this);
@@ -1782,7 +1788,7 @@

  void CodeGenerator::VisitTryCatch(TryCatch* node) {
    Comment cmnt(masm_, "[ TryCatch");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);

    JumpTarget try_block(this);
    JumpTarget exit(this);
@@ -1882,7 +1888,7 @@
        frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
        // Code slot popped.
        frame_->Forget(1);
-      shadows[i]->original_target()->Jump();
+      shadows[i]->other_target()->Jump();
      }
    }

@@ -1892,7 +1898,7 @@

  void CodeGenerator::VisitTryFinally(TryFinally* node) {
    Comment cmnt(masm_, "[ TryFinally");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);

    // State: Used to keep track of reason for entering the finally
    // block. Should probably be extended to hold information for
@@ -1961,7 +1967,7 @@
    for (int i = 0; i <= nof_escapes; i++) {
      if (shadows[i]->is_linked()) {
        shadows[i]->Bind();
-      if (shadows[i]->original_target() == &function_return_) {
+      if (shadows[i]->other_target() == &function_return_) {
          // If this label shadowed the function return, materialize the
          // return value on the stack.
          frame_->EmitPush(r0);
@@ -2023,13 +2029,13 @@
      for (int i = 0; i <= nof_escapes; i++) {
        if (shadows[i]->is_bound()) {
          __ cmp(r2, Operand(Smi::FromInt(JUMPING + i)));
-        if (shadows[i]->original_target() != &function_return_) {
+        if (shadows[i]->other_target() != &function_return_) {
            JumpTarget next(this);
            next.Branch(ne);
-          shadows[i]->original_target()->Jump();
+          shadows[i]->other_target()->Jump();
            next.Bind();
          } else {
-          shadows[i]->original_target()->Branch(eq);
+          shadows[i]->other_target()->Branch(eq);
          }
        }
      }
@@ -2050,7 +2056,7 @@

  void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
    Comment cmnt(masm_, "[ DebuggerStatament");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    frame_->CallRuntime(Runtime::kDebugBreak, 0);
    // Ignore the return value.
  }
@@ -2262,8 +2268,8 @@
    // Check whether we need to materialize the object literal boilerplate.
    // If so, jump to the deferred code.
    __ cmp(r2, Operand(Factory::undefined_value()));
-  __ b(eq, deferred->enter());
-  __ bind(deferred->exit());
+  deferred->enter()->Branch(eq);
+  deferred->exit()->Bind();

    // Push the object literal boilerplate.
    frame_->EmitPush(r2);
@@ -2365,13 +2371,13 @@
    Load(node->key());
    Load(node->value());
    __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
-  frame_->Push(r0);
+  frame_->EmitPush(r0);
  }


  void CodeGenerator::VisitAssignment(Assignment* node) {
    Comment cmnt(masm_, "[ Assignment");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);

    Reference target(this, node->target());
    if (target.is_illegal()) {
@@ -2444,7 +2450,7 @@

    ZoneList<Expression*>* args = node->arguments();

-  CodeForStatement(node);
+  CodeForStatementPosition(node);
    // Standard function call.

    // Check if the function is a variable or a property.
@@ -2588,7 +2594,7 @@
    ZoneList<Expression*>* args = node->arguments();
    Expression* function = node->expression();

-  CodeForStatement(node);
+  CodeForStatementPosition(node);

    // Prepare stack for call to resolved function.
    Load(function);
@@ -2625,14 +2631,14 @@

    __ ldr(cp, frame_->Context());
    // Remove the function from the stack.
-  frame_->Pop();
-  frame_->Push(r0);
+  frame_->Drop();
+  frame_->EmitPush(r0);
  }


  void CodeGenerator::VisitCallNew(CallNew* node) {
    Comment cmnt(masm_, "[ CallNew");
-  CodeForStatement(node);
+  CodeForStatementPosition(node);

    // According to ECMA-262, section 11.2.2, page 44, the function
    // expression in new calls must be evaluated before the
@@ -2738,7 +2744,7 @@
    }
  #endif
    __ mov(r0, Operand(Factory::undefined_value()));
-  frame_->Push(r0);
+  frame_->EmitPush(r0);
  }


@@ -3399,6 +3405,11 @@
        UNREACHABLE();
    }
  }
+
+
+#ifdef DEBUG
+bool CodeGenerator::HasValidEntryRegisters() { return true; }
+#endif


  bool CodeGenerator::IsActualFunctionReturn(JumpTarget* target) {

Modified: branches/experimental/toiger/src/codegen-arm.h
==============================================================================
--- branches/experimental/toiger/src/codegen-arm.h      (original)
+++ branches/experimental/toiger/src/codegen-arm.h      Tue Feb 10 02:34:41 2009
@@ -162,12 +162,11 @@

    VirtualFrame* frame() const { return frame_; }

-  void set_frame(VirtualFrame* frame) { frame_ = frame; }
+  bool has_valid_frame() const { return frame_ != NULL; }

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

    CodeGenState* state() { return state_; }
    void set_state(CodeGenState* state) { state_ = state; }
@@ -319,15 +318,15 @@
    void GenerateFastCaseSwitchJumpTable(SwitchStatement* node,
                                         int min_index,
                                         int range,
-                                       JumpTarget* fail_label,
-                                       Vector<JumpTarget*> case_targets,
-                                       Vector<JumpTarget> case_labels);
+                                       Label* default_label,
+                                       Vector<Label*> case_targets,
+                                       Vector<Label> case_labels);

    // Generate the code for cases for the fast case switch.
    // Called by GenerateFastCaseSwitchJumpTable.
    void GenerateFastCaseSwitchCases(SwitchStatement* node,
-                                   Vector<JumpTarget> case_labels,
-                                   JumpTarget* table_start);
+                                   Vector<Label> case_labels,
+                                   VirtualFrame* start_frame);

    // Fast support for constant-Smi switches.
    void GenerateFastCaseSwitchStatement(SwitchStatement* node,
@@ -344,7 +343,8 @@
    // Methods used to indicate which source code is generated for. Source
    // positions are collected by the assembler and emitted with the  
relocation
    // information.
-  void CodeForStatement(Node* node);
+  void CodeForFunctionPosition(FunctionLiteral* fun);
+  void CodeForStatementPosition(Node* node);
    void CodeForSourcePosition(int pos);

    // Is the given jump target the actual (ie, non-shadowed) function return
@@ -352,6 +352,12 @@
    bool IsActualFunctionReturn(JumpTarget* target);

    bool is_eval_;  // Tells whether code is generated for eval.
+
+#ifdef DEBUG
+  // True if the registers are valid for entry to a block.
+  bool HasValidEntryRegisters();
+#endif
+
    Handle<Script> script_;
    List<DeferredCode*> deferred_;


Modified: branches/experimental/toiger/src/jump-target-arm.cc
==============================================================================
--- branches/experimental/toiger/src/jump-target-arm.cc (original)
+++ branches/experimental/toiger/src/jump-target-arm.cc Tue Feb 10 02:34:41  
2009
@@ -37,171 +37,358 @@

  #define __ masm_->

-JumpTarget::JumpTarget(CodeGenerator* cgen)
-    : expected_frame_(NULL),
-      code_generator_(cgen),
-      masm_(cgen->masm()) {
+JumpTarget::JumpTarget(CodeGenerator* cgen, Directionality direction)
+    : cgen_(cgen),
+      direction_(direction),
+      reaching_frames_(0),
+      merge_labels_(0),
+      expected_frame_(NULL),
+      is_bound_(false),
+      is_linked_(false) {
+  ASSERT(cgen_ != NULL);
+  masm_ = cgen_->masm();
  }


  JumpTarget::JumpTarget()
-    : expected_frame_(NULL),
-      code_generator_(NULL),
-      masm_(NULL) {
+    : cgen_(NULL),
+      masm_(NULL),
+      direction_(FORWARD_ONLY),
+      reaching_frames_(0),
+      merge_labels_(0),
+      expected_frame_(NULL),
+      is_bound_(false),
+      is_linked_(false) {
  }


-void JumpTarget::set_code_generator(CodeGenerator* cgen) {
+void JumpTarget::Initialize(CodeGenerator* cgen, Directionality direction)  
{
    ASSERT(cgen != NULL);
-  ASSERT(code_generator_ == NULL);
-  code_generator_ = cgen;
+  ASSERT(cgen_ == NULL);
+  cgen_ = cgen;
    masm_ = cgen->masm();
+  direction_ = direction;
+}
+
+
+void JumpTarget::Unuse() {
+  ASSERT(!is_linked());
+  entry_label_.Unuse();
+  delete expected_frame_;
+  expected_frame_ = NULL;
+  is_bound_ = false;
+  is_linked_ = false;
+}
+
+
+void JumpTarget::Reset() {
+  reaching_frames_.Clear();
+  merge_labels_.Clear();
+  expected_frame_ = NULL;
+  entry_label_.Unuse();
+  is_bound_ = false;
+  is_linked_ = false;
  }


  void JumpTarget::Jump() {
-  // Precondition: there is a current frame.  There may or may not be an
-  // expected frame at the label.
-  ASSERT(code_generator_ != NULL);
-
-  VirtualFrame* current_frame = code_generator_->frame();
-  ASSERT(current_frame != NULL);
-
-  if (expected_frame_ == NULL) {
-    expected_frame_ = current_frame;
-    code_generator_->set_frame(NULL);
-    // The frame at the actual function return will always have height  
zero.
-    if (code_generator_->IsActualFunctionReturn(this)) {
-      expected_frame_->Forget(expected_frame_->height());
-    }
+  ASSERT(cgen_ != NULL);
+  ASSERT(cgen_->has_valid_frame());
+  // 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 (is_bound()) {
+    // Backward jump.  There is an expected frame to merge to.
+    ASSERT(direction_ == BIDIRECTIONAL);
+    cgen_->frame()->MergeTo(expected_frame_);
+    cgen_->DeleteFrame();
+    __ jmp(&entry_label_);
    } 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();
+    // 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());
+    cgen_->SetFrame(NULL);
+    __ jmp(&merge_labels_.last());
    }

-  __ b(&label_);
-  // Postcondition: there is no current frame but there is an expected  
frame
-  // at the label.
+  is_linked_ = !is_bound_;
+}
+
+
+void JumpTarget::Jump(Result* arg) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Jump(Result* arg0, Result* arg1) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Jump(Result* arg0, Result* arg1, Result* arg2) {
+  UNIMPLEMENTED();
  }


  void JumpTarget::Branch(Condition cc, Hint ignored) {
-  // Precondition: there is a current frame.  There may or may not be an
-  // expected frame at the label.
-  ASSERT(code_generator_ != NULL);
-  ASSERT(masm_ != NULL);
-
-  VirtualFrame* current_frame = code_generator_->frame();
-  ASSERT(current_frame != NULL);
-
-  if (expected_frame_ == NULL) {
-    expected_frame_ = new VirtualFrame(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());
-    }
+  ASSERT(cgen_ != NULL);
+  ASSERT(cgen_->has_valid_frame());
+
+  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(210): 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.
+    ASSERT(direction_ == BIDIRECTIONAL);
+    Label original_fall_through;
+    __ b(NegateCondition(cc), &original_fall_through);
+    // 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);
+    cgen_->SetFrame(working_frame);
+
+    working_frame->MergeTo(expected_frame_);
+    cgen_->DeleteFrame();
+    __ jmp(&entry_label_);
+
+    // Restore the frame and its associated non-frame registers.
+    cgen_->SetFrame(original_frame);
+    __ bind(&original_fall_through);
    } 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_);
-    }
+    // 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()));
+    __ b(cc, &merge_labels_.last());
    }

-  __ b(cc, &label_);
-  // Postcondition: there is both a current frame and an expected frame at
-  // the label and they match.
+  is_linked_ = !is_bound_;
+}
+
+
+void JumpTarget::Branch(Condition cc, Result* arg, Hint ignored) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Branch(Condition cc,
+                        Result* arg0,
+                        Result* arg1,
+                        Hint ignored) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Branch(Condition cc,
+                        Result* arg0,
+                        Result* arg1,
+                        Result* arg2,
+                        Hint ignored) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Branch(Condition cc,
+                        Result* arg0,
+                        Result* arg1,
+                        Result* arg2,
+                        Result* arg3,
+                        Hint ignored) {
+  UNIMPLEMENTED();
  }


  void JumpTarget::Call() {
-  // Precondition: there is a current frame, and there is no expected frame
-  // at the label.
-  ASSERT(code_generator_ != NULL);
-  ASSERT(masm_ != NULL);
-  ASSERT(!code_generator_->IsActualFunctionReturn(this));
-
-  VirtualFrame* current_frame = code_generator_->frame();
-  ASSERT(current_frame != NULL);
-  ASSERT(expected_frame_ == NULL);
-
-  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_->Adjust(1);
-
-  __ bl(&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).
+  // 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(cgen_->has_valid_frame());
+  // There are no non-frame references across the call.
+  ASSERT(cgen_->HasValidEntryRegisters());
+  ASSERT(!is_linked());
+
+  VirtualFrame* target_frame = new VirtualFrame(cgen_->frame());
+  target_frame->Adjust(1);
+  AddReachingFrame(target_frame);
+  __ bl(&merge_labels_.last());
+
+  is_linked_ = !is_bound_;
  }


  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(code_generator_ != NULL);
-  ASSERT(masm_ != NULL);
-
-  VirtualFrame* current_frame = code_generator_->frame();
-  ASSERT(current_frame != NULL || expected_frame_ != NULL);
-  ASSERT(!label_.is_bound());
-
-  if (expected_frame_ == NULL) {
-    expected_frame_ = new VirtualFrame(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());
+  ASSERT(cgen_ != NULL);
+  ASSERT(!is_bound());
+
+  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());
+
+    // A special case is that there was only one jump to the block so
+    // far, no fall-through, and there cannot be another entry because
+    // the block is forward only.  In that case, simply use the single
+    // frame.
+    bool single_entry = (direction_ == FORWARD_ONLY) &&
+                        !cgen_->has_valid_frame() &&
+                        (reaching_frames_.length() == 1);
+    if (single_entry) {
+      // Pick up the only forward reaching frame and bind its merge
+      // label.  No merge code is emitted.
+      cgen_->SetFrame(reaching_frames_[0]);
+      __ bind(&merge_labels_[0]);
+    } else {
+      // Otherwise, 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 {
+        cgen_->SetFrame(reaching_frames_[start_index]);
+        __ 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_);
+
+        cgen_->SetFrame(reaching_frames_[i]);
+        __ bind(&merge_labels_[i]);
+
+        cgen_->frame()->MergeTo(expected_frame_);
+      }
+
+      __ bind(&entry_label_);
      }
-  } else if (current_frame == NULL) {
-    code_generator_->set_frame(new VirtualFrame(expected_frame_));
+
+    // 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 {
-    // 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_);
+    // There were no forward jumps.  If this jump target is not
+    // bidirectional, there is no need to do anything.  For
+    // bidirectional jump targets, the current frame is made mergable
+    // and used for the expected frame.
+    if (direction_ == BIDIRECTIONAL) {
+      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.
+  is_linked_ = false;
+  is_bound_ = true;
+}
+
+
+void JumpTarget::Bind(Result* arg) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Bind(Result* arg0, Result* arg1) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Bind(Result* arg0, Result* arg1, Result* arg2) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::Bind(Result* arg0, Result* arg1, Result* arg2, Result*  
arg3) {
+  UNIMPLEMENTED();
+}
+
+
+void JumpTarget::CopyTo(JumpTarget* destination) {
+  ASSERT(destination != NULL);
+  destination->cgen_ = cgen_;
+  destination->masm_ = masm_;
+  destination->direction_ = direction_;
+  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_;
+  destination->is_bound_ = is_bound_;
+  destination->is_linked_ = is_linked_;
+}
+
+
+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_);
+  // This target does not have a valid code generator yet.
+  cgen_ = other_target_->code_generator();
+  ASSERT(cgen_ != NULL);
+  masm_ = cgen_->masm();
+
+  // 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.

  #ifdef DEBUG
    is_shadowing_ = false;

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  Tue Feb 10  
02:34:41 2009
@@ -28,94 +28,7 @@
  #ifndef V8_REGISTER_ALLOCATOR_IA32_H_
  #define V8_REGISTER_ALLOCATOR_IA32_H_

-#include "macro-assembler.h"
-
  namespace v8 { namespace internal {
-
-
-//  
-------------------------------------------------------------------------
-// Results
-//
-// Results encapsulate the compile-time values manipulated by the code
-// generator.  They can represent registers or constants.
-
-class Result BASE_EMBEDDED {
- public:
-  enum Type {
-    INVALID,
-    REGISTER,
-    CONSTANT
-  };
-
-  // Construct an invalid result.
-  explicit Result(CodeGenerator* cgen) : type_(INVALID), cgen_(cgen) {}
-
-  // Construct a register Result.
-  Result(Register reg, CodeGenerator* cgen);
-
-  // Construct a Result whose value is a compile-time constant.
-  Result(Handle<Object> value, CodeGenerator * cgen)
-      : type_(CONSTANT),
-        cgen_(cgen) {
-    data_.handle_ = value.location();
-  }
-
-  // The copy constructor and assignment operators could each create a new
-  // register reference.
-  Result(const Result& other) {
-    other.CopyTo(this);
-  }
-
-  Result& operator=(const Result& other) {
-    if (this != &other) {
-      Unuse();
-      other.CopyTo(this);
-    }
-    return *this;
-  }
-
-  ~Result() { Unuse(); }
-
-  void Unuse();
-
-  Type type() const { return type_; }
-
-  bool is_valid() const { return type() != INVALID; }
-  bool is_register() const { return type() == REGISTER; }
-  bool is_constant() const { return type() == CONSTANT; }
-
-  Register reg() const {
-    ASSERT(type() == REGISTER);
-    return data_.reg_;
-  }
-
-  Handle<Object> handle() const {
-    ASSERT(type() == CONSTANT);
-    return Handle<Object>(data_.handle_);
-  }
-
-  // Move this result to an arbitrary register.  The register is not
-  // necessarily spilled from the frame or even singly-referenced outside
-  // it.
-  void ToRegister();
-
-  // Move this result to a specified register.  The register is spilled  
from
-  // the frame, and the register is singly-referenced (by this result)
-  // outside the frame.
-  void ToRegister(Register reg);
-
- private:
-  Type type_;
-
-  union {
-    Register reg_;
-    Object** handle_;
-  } data_;
-
-  CodeGenerator* cgen_;
-
-  void CopyTo(Result* destination) const;
-};


  //  
-------------------------------------------------------------------------

Modified: branches/experimental/toiger/src/register-allocator.h
==============================================================================
--- branches/experimental/toiger/src/register-allocator.h       (original)
+++ branches/experimental/toiger/src/register-allocator.h       Tue Feb 10  
02:34:41 2009
@@ -28,7 +28,98 @@
  #ifndef V8_REGISTER_ALLOCATOR_H_
  #define V8_REGISTER_ALLOCATOR_H_

-#if defined(ARM) || defined(__arm__) || defined(__thumb__)
+#include "macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+//  
-------------------------------------------------------------------------
+// Results
+//
+// Results encapsulate the compile-time values manipulated by the code
+// generator.  They can represent registers or constants.
+
+class Result BASE_EMBEDDED {
+ public:
+  enum Type {
+    INVALID,
+    REGISTER,
+    CONSTANT
+  };
+
+  // Construct an invalid result.
+  explicit Result(CodeGenerator* cgen) : type_(INVALID), cgen_(cgen) {}
+
+  // Construct a register Result.
+  Result(Register reg, CodeGenerator* cgen);
+
+  // Construct a Result whose value is a compile-time constant.
+  Result(Handle<Object> value, CodeGenerator * cgen)
+      : type_(CONSTANT),
+        cgen_(cgen) {
+    data_.handle_ = value.location();
+  }
+
+  // The copy constructor and assignment operators could each create a new
+  // register reference.
+  Result(const Result& other) {
+    other.CopyTo(this);
+  }
+
+  Result& operator=(const Result& other) {
+    if (this != &other) {
+      Unuse();
+      other.CopyTo(this);
+    }
+    return *this;
+  }
+
+  ~Result() { Unuse(); }
+
+  void Unuse();
+
+  Type type() const { return type_; }
+
+  bool is_valid() const { return type() != INVALID; }
+  bool is_register() const { return type() == REGISTER; }
+  bool is_constant() const { return type() == CONSTANT; }
+
+  Register reg() const {
+    ASSERT(type() == REGISTER);
+    return data_.reg_;
+  }
+
+  Handle<Object> handle() const {
+    ASSERT(type() == CONSTANT);
+    return Handle<Object>(data_.handle_);
+  }
+
+  // Move this result to an arbitrary register.  The register is not
+  // necessarily spilled from the frame or even singly-referenced outside
+  // it.
+  void ToRegister();
+
+  // Move this result to a specified register.  The register is spilled  
from
+  // the frame, and the register is singly-referenced (by this result)
+  // outside the frame.
+  void ToRegister(Register reg);
+
+ private:
+  Type type_;
+
+  union {
+    Register reg_;
+    Object** handle_;
+  } data_;
+
+  CodeGenerator* cgen_;
+
+  void CopyTo(Result* destination) const;
+};
+
+} }  // namespace v8::internal
+
+
+#ifdef ARM
  #else  // ia32
  #include "register-allocator-ia32.h"
  #endif

Modified: branches/experimental/toiger/src/virtual-frame-arm.h
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-arm.h        (original)
+++ branches/experimental/toiger/src/virtual-frame-arm.h        Tue Feb 10  
02:34:41 2009
@@ -29,6 +29,7 @@
  #define V8_VIRTUAL_FRAME_ARM_H_

  #include "macro-assembler.h"
+#include "register-allocator.h"

  namespace v8 { namespace internal {

@@ -76,6 +77,10 @@

    // Forget frame elements without generating code.
    void Forget(int count);
+
+  // 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() { }

    // Make this virtual frame have a state identical to an expected virtual
    // frame.  As a side effect, code may be emitted to make this frame match

Modified: branches/experimental/toiger/src/virtual-frame.h
==============================================================================
--- branches/experimental/toiger/src/virtual-frame.h    (original)
+++ branches/experimental/toiger/src/virtual-frame.h    Tue Feb 10 02:34:41  
2009
@@ -28,7 +28,7 @@
  #ifndef V8_VIRTUAL_FRAME_H_
  #define V8_VIRTUAL_FRAME_H_

-#if defined(ARM) || defined (__arm__) || defined(__thumb__)
+#ifdef ARM
  #include "virtual-frame-arm.h"
  #else  // ia32
  #include "virtual-frame-ia32.h"

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

Reply via email to