Author: [email protected]
Date: Tue Jan  6 06:49:42 2009
New Revision: 1032

Modified:
    branches/experimental/toiger/src/codegen-ia32.cc

Log:
Experimental: a grab bag of support for register allocation.  Push the
register allocator through debugger statements, function literals,
conditional expressions, loading from and storing to any slot type,
and properties.
Review URL: http://codereview.chromium.org/16536

Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Tue Jan  6 06:49:42  
2009
@@ -503,10 +503,9 @@
    Variable* var = e->AsVariableProxy()->AsVariable();

    if (property != NULL) {
-    VirtualFrame::SpilledScope spilled_scope(this);
      // The expression is either a property or a variable proxy that  
rewrites
      // to a property.
-    LoadAndSpill(property->obj());
+    Load(property->obj());
      // We use a named reference if the key is a literal symbol, unless it  
is
      // a string that can be legally parsed as an integer.  This is because
      // otherwise we will not get into the slow case code that handles [] on
@@ -518,7 +517,7 @@
          !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
        ref->set_type(Reference::NAMED);
      } else {
-      LoadAndSpill(property->key());
+      Load(property->key());
        ref->set_type(Reference::KEYED);
      }
    } else if (var != NULL) {
@@ -533,9 +532,8 @@
        ref->set_type(Reference::SLOT);
      }
    } else {
-    VirtualFrame::SpilledScope spilled_scope(this);
      // Anything else is a runtime error.
-    LoadAndSpill(e);
+    Load(e);
      frame_->CallRuntime(Runtime::kThrowReferenceError, 1);
    }
  }
@@ -546,9 +544,11 @@
    Comment cmnt(masm_, "[ UnloadReference");
    int size = ref->size();
    if (size == 1) {
+    VirtualFrame::SpilledScope spilled_scope(this);
      frame_->EmitPop(eax);
      __ mov(frame_->Top(), eax);
    } else if (size > 1) {
+    VirtualFrame::SpilledScope spilled_scope(this);
      frame_->EmitPop(eax);
      frame_->Drop(size);
      frame_->EmitPush(eax);
@@ -2206,6 +2206,8 @@
    // loop.  edx: i'th entry of the enum cache (or string there of)
    frame_->EmitPush(ebx);
    { Reference each(this, node->each());
+    // Loading a reference may leave the frame in an unspilled state.
+    frame_->SpillAll();
      if (!each.is_illegal()) {
        if (each.size() > 0) {
          frame_->EmitPush(frame_->ElementAt(each.size()));
@@ -2224,6 +2226,9 @@
        }
      }
    }
+  // Unloading a reference may leave the frame in an unspilled state.
+  frame_->SpillAll();
+
    // Discard the i'th entry pushed above or else the remainder of the
    // reference, whichever is currently on top of the stack.
    frame_->Drop();
@@ -2529,9 +2534,10 @@

  void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
    ASSERT(!in_spilled_code());
-  VirtualFrame::SpilledScope spilled_scope(this);
    Comment cmnt(masm_, "[ DebuggerStatement");
    CodeForStatement(node);
+  // Spill everything, even constants, to the frame.
+  frame_->SpillAll();
    frame_->CallRuntime(Runtime::kDebugBreak, 0);
    // Ignore the return value.
  }
@@ -2541,17 +2547,16 @@
    ASSERT(boilerplate->IsBoilerplate());

    // Push the boilerplate on the stack.
-  frame_->EmitPush(Immediate(boilerplate));
+  frame_->Push(boilerplate);

    // Create a new closure.
-  frame_->EmitPush(esi);
-  frame_->CallRuntime(Runtime::kNewClosure, 2);
-  frame_->EmitPush(eax);
+  frame_->Push(esi);
+  Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
+  frame_->Push(&result);
  }


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

    // Build the function boilerplate and instantiate it.
@@ -2564,31 +2569,30 @@

  void CodeGenerator::VisitFunctionBoilerplateLiteral(
      FunctionBoilerplateLiteral* node) {
-  VirtualFrame::SpilledScope spilled_scope(this);
    Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
    InstantiateBoilerplate(node->boilerplate());
  }


  void CodeGenerator::VisitConditional(Conditional* node) {
-  VirtualFrame::SpilledScope spilled_scope(this);
    Comment cmnt(masm_, "[ Conditional");
    JumpTarget then(this);
    JumpTarget else_(this);
    JumpTarget exit(this);
-  LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF,
-                        &then, &else_, true);
+  LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
    if (has_valid_frame()) {
      Branch(false, &else_);
    }
-  if (has_valid_frame() || then.is_linked()) {
+  if (then.is_linked()) {
      then.Bind();
-    LoadAndSpill(node->then_expression(), typeof_state());
+  }
+  if (has_valid_frame()) {
+    Load(node->then_expression(), typeof_state());
      exit.Jump();
    }
    if (else_.is_linked()) {
      else_.Bind();
-    LoadAndSpill(node->else_expression(), typeof_state());
+    Load(node->else_expression(), typeof_state());
    }
    exit.Bind();
  }
@@ -2599,47 +2603,47 @@
      ASSERT(slot->var()->mode() == Variable::DYNAMIC);

      // For now, just do a runtime call.
-    VirtualFrame::SpilledScope spilled_scope(this);
-    frame_->EmitPush(esi);
-    frame_->EmitPush(Immediate(slot->var()->name()));
+    frame_->Push(esi);
+    frame_->Push(slot->var()->name());

+    Result value(this);
      if (typeof_state == INSIDE_TYPEOF) {
-      frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
+      value =
+          frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError,  
2);
      } else {
-      frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
+      value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
      }
-    frame_->EmitPush(eax);
+    frame_->Push(&value);
+
+  } else if (slot->var()->mode() == Variable::CONST) {
+    // Const slots may contain 'the hole' value (the constant hasn't been
+    // initialized yet) which needs to be converted into the 'undefined'
+    // value.
+    Comment cmnt(masm_, "[ Load const");
+    JumpTarget exit(this);
+    Result temp = allocator_->Allocate();
+    ASSERT(temp.is_valid());
+    __ mov(temp.reg(), SlotOperand(slot, temp.reg()));
+    __ cmp(temp.reg(), Factory::the_hole_value());
+    exit.Branch(not_equal, &temp);
+    __ mov(temp.reg(), Factory::undefined_value());
+    exit.Bind(&temp);
+    frame_->Push(&temp);
+
+  } else if (slot->type() == Slot::PARAMETER) {
+    frame_->LoadParameterAt(slot->index());
+
+  } else if (slot->type() == Slot::LOCAL) {
+    frame_->LoadLocalAt(slot->index());

    } else {
-    // Note: We would like to keep the assert below, but it fires because  
of
-    // some nasty code in LoadTypeofExpression() which should be removed...
-    // ASSERT(slot->var()->mode() != Variable::DYNAMIC);
-    if (slot->var()->mode() == Variable::CONST) {
-      // Const slots may contain 'the hole' value (the constant hasn't been
-      // initialized yet) which needs to be converted into the 'undefined'
-      // value.
-      VirtualFrame::SpilledScope spilled_scope(this);
-      Comment cmnt(masm_, "[ Load const");
-      JumpTarget exit(this);
-      __ mov(eax, SlotOperand(slot, ecx));
-      __ cmp(eax, Factory::the_hole_value());
-      exit.Branch(not_equal);
-      __ mov(eax, Factory::undefined_value());
-      exit.Bind();
-      frame_->EmitPush(eax);
-    } else {
-      if (slot->type() == Slot::PARAMETER) {
-        frame_->LoadParameterAt(slot->index());
-      } else if (slot->type() == Slot::LOCAL) {
-        frame_->LoadLocalAt(slot->index());
-      } else {
-        // The other remaining slot types (LOOKUP and GLOBAL) cannot reach
-        // here.
-        ASSERT(slot->type() == Slot::CONTEXT);
-        VirtualFrame::SpilledScope spilled_scope(this);
-        frame_->EmitPush(SlotOperand(slot, ecx));
-      }
-    }
+    // The other remaining slot types (LOOKUP and GLOBAL) cannot reach
+    // here.
+    ASSERT(slot->type() == Slot::CONTEXT);
+    Result temp = allocator_->Allocate();
+    ASSERT(temp.is_valid());
+    __ mov(temp.reg(), SlotOperand(slot, temp.reg()));
+    frame_->Push(&temp);
    }
  }

@@ -2649,10 +2653,10 @@
      ASSERT(slot->var()->mode() == Variable::DYNAMIC);

      // For now, just do a runtime call.
-    VirtualFrame::SpilledScope spilled_scope(this);
-    frame_->EmitPush(esi);
-    frame_->EmitPush(Immediate(slot->var()->name()));
+    frame_->Push(esi);
+    frame_->Push(slot->var()->name());

+    Result value(this);
      if (init_state == CONST_INIT) {
        // Same as the case for a normal store, but ignores attribute
        // (e.g. READ_ONLY) of context slot so that we can initialize const
@@ -2668,14 +2672,14 @@
        // the expression operands are defined and valid, and thus we need  
the
        // split into 2 operations: declaration of the context slot followed
        // by initialization.
-      frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+      value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
      } else {
-      frame_->CallRuntime(Runtime::kStoreContextSlot, 3);
+      value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3);
      }
      // Storing a variable must keep the (new) value on the expression
      // stack. This is necessary for compiling chained assignment
      // expressions.
-    frame_->EmitPush(eax);
+    frame_->Push(&value);

    } else {
      ASSERT(slot->var()->mode() != Variable::DYNAMIC);
@@ -2687,9 +2691,11 @@
        // still contains 'the hole' value). When the assignment is executed,
        // the code is identical to a normal store (see below).
        Comment cmnt(masm_, "[ Init const");
-      VirtualFrame::SpilledScope spilled_scope(this);
-      __ mov(eax, SlotOperand(slot, ecx));
-      __ cmp(eax, Factory::the_hole_value());
+      Result temp = allocator_->Allocate();
+      ASSERT(temp.is_valid());
+      __ mov(temp.reg(), SlotOperand(slot, temp.reg()));
+      __ cmp(temp.reg(), Factory::the_hole_value());
+      temp.Unuse();
        exit.Branch(not_equal);
      }

@@ -2707,18 +2713,29 @@
      } else {
        // The other slot types (LOOKUP and GLOBAL) cannot reach here.
        ASSERT(slot->type() == Slot::CONTEXT);
-      VirtualFrame::SpilledScope spilled_scope(this);
-      frame_->EmitPop(eax);
-      __ mov(SlotOperand(slot, ecx), eax);
-      frame_->EmitPush(eax);  // RecordWrite may destroy the value in eax.
+      frame_->Dup();
+      Result value = frame_->Pop();
+      value.ToRegister();
+      Result start = allocator_->Allocate();
+      ASSERT(start.is_valid());
+      __ mov(SlotOperand(slot, start.reg()), value.reg());
+      // RecordWrite may destroy the value registers.
+      //
+      // TODO(): Avoid actually spilling when the value is not needed
+      // (probably the common case).
+      frame_->Spill(value.reg());
        int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
-      __ RecordWrite(ecx, offset, eax, ebx);
+      Result temp = allocator_->Allocate();
+      ASSERT(temp.is_valid());
+      __ RecordWrite(start.reg(), offset, value.reg(), temp.reg());
+      // The results start, value, and temp are unused by going out of
+      // scope.
      }

      // If we definitely did not jump over the assignment, we do not need
      // to bind the exit label.  Doing so can defeat peephole
      // optimization.
-    if (init_state == CONST_INIT) {
+    if (exit.is_linked()) {
        exit.Bind();
      }
    }
@@ -3024,7 +3041,7 @@
      if (target.is_illegal()) {
        // Fool the virtual frame into thinking that we left the assignment's
        // value on the frame.
-      frame_->EmitPush(Immediate(Smi::FromInt(0)));
+      frame_->Push(Handle<Object>(Smi::FromInt(0)));
        return;
      }

@@ -3078,10 +3095,9 @@


  void CodeGenerator::VisitProperty(Property* node) {
-  VirtualFrame::SpilledScope spilled_scope(this);
    Comment cmnt(masm_, "[ Property");
    Reference property(this, node);
-  property.GetValueAndSpill(typeof_state());
+  property.GetValue(typeof_state());
  }


@@ -3193,6 +3209,7 @@

        // Load the function to call from the property through a reference.
        Reference ref(this, property);
+      frame_->SpillAll();
        ref.GetValueAndSpill(NOT_INSIDE_TYPEOF);

        // Pass receiver to called function.

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

Reply via email to