Author: [EMAIL PROTECTED]
Date: Fri Nov 28 00:41:54 2008
New Revision: 861

Added:
    branches/experimental/toiger/src/register-allocator-ia32.cc
    branches/experimental/toiger/src/register-allocator-ia32.h
    branches/experimental/toiger/src/register-allocator.h
Modified:
    branches/experimental/toiger/src/SConscript
    branches/experimental/toiger/src/codegen-ia32.cc
    branches/experimental/toiger/src/codegen-ia32.h
    branches/experimental/toiger/src/virtual-frame-ia32.cc
    branches/experimental/toiger/src/virtual-frame-ia32.h

Log:
Begin counting references to registers, both in the frame and out.
Allocation/deallocation is explicit.  We still almost always spill
everything and then use registers directly (without allocating them).

None of this has been ported to the ARM.
Review URL: http://codereview.chromium.org/11396

Modified: branches/experimental/toiger/src/SConscript
==============================================================================
--- branches/experimental/toiger/src/SConscript (original)
+++ branches/experimental/toiger/src/SConscript Fri Nov 28 00:41:54 2008
@@ -54,10 +54,10 @@
      'macro-assembler-arm.cc', 'stub-cache-arm.cc', 'virtual-frame-arm.cc'
    ],
    'arch:ia32': [
-    'assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc',
-    'cpu-ia32.cc', 'disasm-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc',
-    'jump-target-ia32.cc', 'macro-assembler-ia32.cc', 'stub-cache-ia32.cc',
-    'virtual-frame-ia32.cc'
+    'assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc', 'cpu-ia32.cc',
+    'disasm-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc', 'jump-target-ia32.cc',
+    'macro-assembler-ia32.cc', 'register-allocator-ia32.cc',
+    'stub-cache-ia32.cc', 'virtual-frame-ia32.cc'
    ],
    'simulator:arm': ['simulator-arm.cc'],
    'os:linux':  ['platform-linux.cc'],

Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Fri Nov 28 00:41:54  
2008
@@ -80,6 +80,7 @@
        masm_(new MacroAssembler(NULL, buffer_size)),
        scope_(NULL),
        frame_(NULL),
+      allocator_(NULL),
        cc_reg_(no_condition),
        state_(NULL),
        is_inside_try_(false),
@@ -106,6 +107,9 @@
    scope_ = fun->scope();
    ASSERT(frame_ == NULL);
    set_frame(new VirtualFrame(this));
+  ASSERT(allocator_ == NULL);
+  RegisterAllocator register_allocator(this);
+  allocator_ = &register_allocator;
    cc_reg_ = no_condition;
    function_return_.set_code_generator(this);
    function_return_is_shadowed_ = false;
@@ -123,54 +127,39 @@
      // edi: caller's parameter pointer
      // esi: callee's context

+    allocator_->Initialize();
      frame_->Enter();
      // tos: code slot
  #ifdef DEBUG
      if (strlen(FLAG_stop_at) > 0 &&
          fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
+      frame_->SpillAll();
        __ int3();
      }
  #endif

-    // This section now only allocates and copies the formals into the
-    // arguments object. It saves the address in ecx, which is saved
-    // at any point before either garbage collection or ecx is
-    // overwritten.  The flag arguments_array_allocated communicates
-    // with the store into the arguments variable and guards the lazy
-    // pushes of ecx to TOS.  The flag arguments_array_saved notes
-    // when the push has happened.
-    bool arguments_object_allocated = false;
-    bool arguments_object_saved = false;
-
-    // Allocate arguments object.
-    // The arguments object pointer needs to be saved in ecx, since we need
-    // to store arguments into the context.
+    // Allocate space for locals and initialize them.
+    frame_->AllocateStackSlots(scope_->num_stack_slots());
+
+    // Allocate the arguments object and copy the parameters into it.
      if (scope_->arguments() != NULL) {
        ASSERT(scope_->arguments_shadow() != NULL);
-      Comment cmnt(masm_, "[ allocate arguments object");
+      Comment cmnt(masm_, "[ Allocate arguments object");
        ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
+      frame_->SpillAll();
        __ lea(eax, frame_->Receiver());
        frame_->EmitPush(frame_->Function());
        frame_->EmitPush(eax);
        frame_->EmitPush(Immediate(Smi::FromInt(scope_->num_parameters())));
        frame_->CallStub(&stub, 3);
-      __ mov(ecx, Operand(eax));
-      arguments_object_allocated = true;
+      frame_->Push(eax);
      }

-    // Allocate space for locals and initialize them.
-    frame_->AllocateStackSlots(scope_->num_stack_slots());
-
      if (scope_->num_heap_slots() > 0) {
-      frame_->SpillAll();
        Comment cmnt(masm_, "[ allocate local context");
-      // Save the arguments object pointer, if any.
-      if (arguments_object_allocated && !arguments_object_saved) {
-        frame_->EmitPush(ecx);
-        arguments_object_saved = true;
-      }
        // Allocate local context.
        // Get outer context and create a new context based on it.
+      frame_->SpillAll();
        frame_->EmitPush(frame_->Function());
        frame_->CallRuntime(Runtime::kNewContext, 1);  // eax holds the  
result

@@ -205,6 +194,7 @@
          Variable* par = scope_->parameter(i);
          Slot* slot = par->slot();
          if (slot != NULL && slot->type() == Slot::CONTEXT) {
+          frame_->SpillAll();
            ASSERT(!scope_->is_global_scope());  // no parameters in global  
scope
            __ mov(eax, frame_->ParameterAt(i));
            // Loads ecx with context; used below in RecordWrite.
@@ -222,27 +212,16 @@
      // Store the arguments object.  This must happen after context
      // initialization because the arguments object may be stored in the
      // context.
-    if (arguments_object_allocated) {
-      ASSERT(scope_->arguments() != NULL);
-      ASSERT(scope_->arguments_shadow() != NULL);
+    if (scope_->arguments() != NULL) {
+      frame_->SpillAll();
        Comment cmnt(masm_, "[ store arguments object");
        { Reference shadow_ref(this, scope_->arguments_shadow());
          ASSERT(shadow_ref.is_slot());
          { Reference arguments_ref(this, scope_->arguments());
            ASSERT(arguments_ref.is_slot());
-          // If the newly-allocated arguments object is already on the
-          // stack, we make use of the convenient property that references
-          // representing slots take up no space on the expression stack
-          // (ie, it doesn't matter that the stored value is actually below
-          // the reference).
-          //
-          // If the newly-allocated argument object is not already on
-          // the stack, we rely on the property that loading a
-          // zero-sized reference will not clobber the ecx register.
-          if (!arguments_object_saved) {
-            frame_->SpillAll();
-            frame_->EmitPush(ecx);
-          }
+          // Here we rely on the convenient property that references to  
slot
+          // take up zero space in the frame (ie, it doesn't matter that  
the
+          // stored value is actually below the reference on the frame).
            arguments_ref.SetValue(NOT_CONST_INIT);
          }
          shadow_ref.SetValue(NOT_CONST_INIT);
@@ -268,6 +247,7 @@
        frame_->CallRuntime(Runtime::kTraceEnter, 0);
        // Ignore the return value.
      }
+    frame_->SpillAll();
      CheckStack();

      // Compile the body of the function in a vanilla state. Don't
@@ -302,13 +282,16 @@
    loop_nesting_ -= fun->loop_nesting();

    // Code generation state must be reset.
+  ASSERT(state_ == NULL);
+  ASSERT(loop_nesting() == 0);
    ASSERT(!function_return_is_shadowed_);
    function_return_.Unuse();
-  scope_ = NULL;
-  delete_frame();
    ASSERT(!has_cc());
-  ASSERT(state_ == NULL);
-  ASSERT(loop_nesting() == 0);
+  // There is no need to delete the register allocator, it is a
+  // stack-allocated local.
+  allocator_ = NULL;
+  delete_frame();
+  scope_ = NULL;
  }


@@ -1195,8 +1178,8 @@


  void CodeGenerator::SmiComparison(Condition cc,
-                                      Handle<Object> value,
-                                      bool strict) {
+                                  Handle<Object> value,
+                                  bool strict) {
    // Strict only makes sense for equality comparisons.
    ASSERT(!strict || cc == equal);


Modified: branches/experimental/toiger/src/codegen-ia32.h
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.h     (original)
+++ branches/experimental/toiger/src/codegen-ia32.h     Fri Nov 28 00:41:54 2008
@@ -29,6 +29,7 @@
  #define V8_CODEGEN_IA32_H_

  #include "scopes.h"
+#include "register-allocator.h"

  namespace v8 { namespace internal {

@@ -173,14 +174,14 @@
    MacroAssembler* masm() { return masm_; }

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

+  RegisterAllocator* allocator() const { return allocator_; }
+
    CodeGenState* state() { return state_; }
    void set_state(CodeGenState* state) { state_ = state; }

@@ -389,6 +390,7 @@
    // Code generation state
    Scope* scope_;
    VirtualFrame* frame_;
+  RegisterAllocator* allocator_;
    Condition cc_reg_;
    CodeGenState* state_;
    bool is_inside_try_;

Added: branches/experimental/toiger/src/register-allocator-ia32.cc
==============================================================================
--- (empty file)
+++ branches/experimental/toiger/src/register-allocator-ia32.cc Fri Nov 28  
00:41:54 2008
@@ -0,0 +1,66 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "codegen.h"
+#include "register-allocator.h"
+
+namespace v8 { namespace internal {
+
+void RegisterAllocator::Initialize() {
+  registers_.Reset();
+  registers_.Use(esp);
+  registers_.Use(ebp);
+  registers_.Use(esi);
+  registers_.Use(edi);
+}
+
+
+Register RegisterAllocator::Allocate() {
+  // Return the first free register, if any.
+  for (int i = 0; i < num_registers(); i++) {
+    if (!registers_.is_used(i)) {
+      Register result = { i };
+      registers_.Use(result);
+      return result;
+    }
+  }
+
+  // Ask the current frame to spill a register.
+  ASSERT(code_generator_->frame() != NULL);
+  Register result = code_generator_->frame()->SpillAnyRegister();
+  if (!result.is(no_reg)) {
+    ASSERT(!registers_.is_used(result.code()));
+    registers_.Use(result);
+  }
+
+  return result;
+}
+
+
+} }  // namespace v8::internal

Added: branches/experimental/toiger/src/register-allocator-ia32.h
==============================================================================
--- (empty file)
+++ branches/experimental/toiger/src/register-allocator-ia32.h  Fri Nov 28  
00:41:54 2008
@@ -0,0 +1,111 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_REGISTER_ALLOCATOR_IA32_H_
+#define V8_REGISTER_ALLOCATOR_IA32_H_
+
+#include "macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+//  
-------------------------------------------------------------------------
+// Register file
+//
+// The register file tracks reference counts for the processor registers.
+// It is used by both the register allocator and the virtual frame.
+
+class RegisterFile BASE_EMBEDDED {
+ public:
+  RegisterFile() { Reset(); }
+
+  void Reset() {
+    for (int i = 0; i < kNumRegisters; i++) {
+      ref_counts_[i] = 0;
+    }
+  }
+
+  // Predicates and accessors for the reference counts.  They take a
+  // register code rather than a register because they are frequently used
+  // in a loop over the register codes.
+  bool is_used(int reg_code) const { return ref_counts_[reg_code] > 0; }
+  int count(int reg_code) const { return ref_counts_[reg_code]; }
+
+  // Record a use of a register by incrementing its reference count.
+  void Use(Register reg) {
+    ref_counts_[reg.code()]++;
+  }
+
+  // Record that a register will no longer be used by decrementing its
+  // reference count.
+  void Unuse(Register reg) {
+    ASSERT(is_used(reg.code()));
+    if (is_used(reg.code())) {
+      ref_counts_[reg.code()]--;
+    }
+  }
+
+  static const int kNumRegisters = 8;
+
+ private:
+  int ref_counts_[kNumRegisters];
+};
+
+
+//  
-------------------------------------------------------------------------
+// Register allocator
+//
+
+class RegisterAllocator BASE_EMBEDDED {
+ public:
+  RegisterAllocator(CodeGenerator* cgen) : code_generator_(cgen) {}
+
+  int num_registers() const { return RegisterFile::kNumRegisters; }
+
+  int count(int reg_code) { return registers_.count(reg_code); }
+
+  // Explicitly record a reference to a register.
+  void Use(Register reg) { registers_.Use(reg); }
+
+  // Explicitly record that a register will no lonber be used.
+  void Unuse(Register reg) { registers_.Unuse(reg); }
+
+  // Initialize the register allocator for entry to a JS function.  On
+  // entry, esp, ebp, esi, and edi are externally referenced (ie, outside
+  // the virtual frame); and the other registers are free.
+  void Initialize();
+
+  // Allocate a free register if possible or fail by returning no_reg.
+  Register Allocate();
+
+ private:
+  CodeGenerator* code_generator_;
+  RegisterFile registers_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_REGISTER_ALLOCATOR_IA32_H_

Added: branches/experimental/toiger/src/register-allocator.h
==============================================================================
--- (empty file)
+++ branches/experimental/toiger/src/register-allocator.h       Fri Nov 28  
00:41:54 2008
@@ -0,0 +1,36 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_REGISTER_ALLOCATOR_H_
+#define V8_REGISTER_ALLOCATOR_H_
+
+#if defined(ARM) || defined(__arm__) || defined(__thumb__)
+#else  // ia32
+#include "register-allocator-ia32.h"
+#endif
+
+#endif  // V8_REGISTER_ALLOCATOR_H_

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      Fri Nov 28  
00:41:54 2008
@@ -41,26 +41,30 @@
  // On entry to a function, the virtual frame already contains the receiver,
  // the parameters, and a return address.  All frame elements are in memory.
  VirtualFrame::VirtualFrame(CodeGenerator* cgen)
-    : masm_(cgen->masm()),
+    : cgen_(cgen),
+      masm_(cgen->masm()),
        elements_(0),
        parameter_count_(cgen->scope()->num_parameters()),
        local_count_(0),
        stack_pointer_(parameter_count_ + 1),  // 0-based index of TOS.
        frame_pointer_(kIllegalIndex) {
+  FrameElement memory_element;
    for (int i = 0; i < parameter_count_ + 2; i++) {
-    elements_.Add(FrameElement());
+    elements_.Add(memory_element);
    }
  }


  // When cloned, a frame is a deep copy of the original.
  VirtualFrame::VirtualFrame(VirtualFrame* original)
-    : masm_(original->masm_),
+    : cgen_(original->cgen_),
+      masm_(original->masm_),
        elements_(original->elements_.length()),
        parameter_count_(original->parameter_count_),
        local_count_(original->local_count_),
        stack_pointer_(original->stack_pointer_),
-      frame_pointer_(original->frame_pointer_) {
+      frame_pointer_(original->frame_pointer_),
+      frame_registers_(original->frame_registers_) {
    // Copy all the elements from the original.
    for (int i = 0; i < original->elements_.length(); i++) {
      elements_.Add(original->elements_[i]);
@@ -94,18 +98,33 @@

    stack_pointer_ -= count;
    for (int i = 0; i < count; i++) {
-    elements_.RemoveLast();
+    FrameElement last = elements_.RemoveLast();
+    if (last.is_register()) {
+      Unuse(last.reg());
+    }
    }
  }


+void VirtualFrame::Use(Register reg) {
+  frame_registers_.Use(reg);
+  cgen_->allocator()->Use(reg);
+}
+
+
+void VirtualFrame::Unuse(Register reg) {
+  frame_registers_.Unuse(reg);
+  cgen_->allocator()->Unuse(reg);
+}
+
+
  // Clear the dirty bit for the element at a given index.  We can only
  // allocate space in the actual frame for the virtual element immediately
  // above the stack pointer.
  void VirtualFrame::SyncElementAt(int index) {
    FrameElement element = elements_[index];

-  if (element.is_dirty()) {
+  if (!element.is_synced()) {
      if (index <= stack_pointer_) {
        // Write elements below the stack pointer to their (already  
allocated)
        // actual frame location.
@@ -128,7 +147,55 @@
          __ push(element.reg());
        }
      }
+
+    elements_[index].set_sync();
+  }
+}
+
+
+// Spill any register if possible, making its reference count zero.
+Register VirtualFrame::SpillAnyRegister() {
+  // Find the leftmost (ordered by register code), least
+  // internally-referenced register whose internal reference count matches
+  // its external reference count (so that spilling it from the frame frees
+  // it for use).
+  int min_count = kMaxInt;
+  int best_register_code = no_reg.code();
+
+  for (int i = 0; i < RegisterFile::kNumRegisters; i++) {
+    int count = frame_registers_.count(i);
+    if (count < min_count && count == cgen_->allocator()->count(i)) {
+      min_count = count;
+      best_register_code = i;
+    }
+  }
+
+  if (best_register_code != no_reg.code()) {
+    // Spill all occurrences of the register.  There are min_count
+    // occurrences, stop when we've spilled them all to avoid syncing
+    // elements unnecessarily.
+    int i = 0;
+    while (min_count > 0) {
+      ASSERT(i < elements_.length());
+      if (elements_[i].is_register() &&
+          elements_[i].reg().code() == best_register_code) {
+        // Found an instance of the best_register being used in the frame.
+        // Spill it.
+        SpillElementAt(i);
+        min_count--;
+      } else {
+        if (i > stack_pointer_) {
+          // Make sure to materialize elements on the virtual frame in
+          // memory.  We rely on this to spill occurrences of the register
+          // lying above the current virtual stack pointer.
+          SyncElementAt(i);
+        }
+      }
+    }
    }
+
+  Register result = { best_register_code };
+  return result;
  }


@@ -138,10 +205,21 @@
  void VirtualFrame::SpillElementAt(int index) {
    SyncElementAt(index);
    // The element is now in memory.
+  if (elements_[index].is_register()) {
+    Unuse(elements_[index].reg());
+  }
    elements_[index] = FrameElement();
  }


+// Clear the dirty bits for all elements.
+void VirtualFrame::SyncAll() {
+  for (int i = 0; i < elements_.length(); i++) {
+    SyncElementAt(i);
+  }
+}
+
+
  // Make the type of all elements be MEMORY.
  void VirtualFrame::SpillAll() {
    for (int i = 0; i < elements_.length(); i++) {
@@ -186,6 +264,7 @@


  void VirtualFrame::MergeTo(VirtualFrame* expected) {
+  ASSERT(cgen_ == expected->cgen_);
    ASSERT(masm_ == expected->masm_);
    ASSERT(elements_.length() == expected->elements_.length());
    ASSERT(parameter_count_ == expected->parameter_count_);
@@ -204,6 +283,7 @@


  void VirtualFrame::Enter() {
+  // Registers live on entry: esp, ebp, esi, edi.
    Comment cmnt(masm_, "[ Enter JS frame");
    EmitPush(ebp);

@@ -211,23 +291,12 @@
    __ mov(ebp, Operand(esp));

    // Store the context and the function in the frame.
-  FrameElement context(esi);
-  context.clear_dirty();
-  elements_.Add(context);
-  stack_pointer_++;
-  __ push(esi);
-
-  FrameElement function(edi);
-  function.clear_dirty();
-  elements_.Add(function);
-  stack_pointer_++;
-  __ push(edi);
+  Push(esi);
+  // The frame owns the register reference now.
+  cgen_->allocator()->Unuse(esi);

-  // Clear the function slot when generating debug code.
-  if (FLAG_debug_code) {
-    SpillElementAt(stack_pointer_);
-    __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue)));
-  }
+  Push(edi);
+  cgen_->allocator()->Unuse(edi);
  }


@@ -244,7 +313,10 @@
    __ mov(esp, Operand(ebp));
    stack_pointer_ = frame_pointer_;
    for (int i = elements_.length() - 1; i > stack_pointer_; i--) {
-    elements_.RemoveLast();
+    FrameElement last = elements_.RemoveLast();
+    if (last.is_register()) {
+      Unuse(last.reg());
+    }
    }

    frame_pointer_ = kIllegalIndex;
@@ -260,14 +332,17 @@
      Comment cmnt(masm_, "[ Allocate space for locals");
      // The locals are constants (the undefined value), but we sync them  
with
      // the actual frame to allocate space for spilling them.
-    FrameElement initial_value(Factory::undefined_value());
-    initial_value.clear_dirty();
-    __ Set(eax, Immediate(Factory::undefined_value()));
+    SyncAll();
+    Handle<Object> undefined = Factory::undefined_value();
+    FrameElement initial_value(undefined, FrameElement::SYNCED);
+    Register tmp = cgen_->allocator()->Allocate();
+    __ Set(tmp, Immediate(undefined));
      for (int i = 0; i < count; i++) {
        elements_.Add(initial_value);
        stack_pointer_++;
-      __ push(eax);
+      __ push(tmp);
      }
+    cgen_->allocator()->Unuse(tmp);
    }
  }

@@ -323,7 +398,10 @@

    // Discard elements above the stack pointer.
    while (count > 0 && stack_pointer_ < elements_.length() - 1) {
-    elements_.RemoveLast();
+    FrameElement last = elements_.RemoveLast();
+    if (last.is_register()) {
+      Unuse(last.reg());
+    }
    }

    // Discard the rest of the elements and lower the stack pointer.
@@ -371,9 +449,23 @@

  void VirtualFrame::EmitPush(Immediate immediate) {
    ASSERT(stack_pointer_ == elements_.length() - 1);
-  elements_.Add(FrameElement());
+  FrameElement memory_element;
+  elements_.Add(memory_element);
    stack_pointer_++;
    __ push(immediate);
+}
+
+
+void VirtualFrame::Push(Register reg) {
+  FrameElement register_element(reg, FrameElement::NOT_SYNCED);
+  Use(reg);
+  elements_.Add(register_element);
+}
+
+
+void VirtualFrame::Push(Handle<Object> value) {
+  FrameElement constant_element(value, FrameElement::NOT_SYNCED);
+  elements_.Add(constant_element);
  }



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       Fri Nov 28  
00:41:54 2008
@@ -29,44 +29,53 @@
  #define V8_VIRTUAL_FRAME_IA32_H_

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

  namespace v8 { namespace internal {

  //  
-------------------------------------------------------------------------
  // Virtual frame elements
  //
-// The internal elements of the virtual frames.  Elements are (currently)  
of
-// only one kind, in-memory.  Their actual location is given by their
-// position in the virtual frame.
+// The internal elements of the virtual frames.  There are several kinds of
+// elements:
+//   * Memory: an element that resides in the actual frame.  Its address is
+//     given by its position in the virtual frame.
+//   * Register: an element that resides in a register.
+//   * Constant: an element whose value is known at compile time.

  class FrameElement BASE_EMBEDDED {
   public:
+  enum SyncFlag { SYNCED, NOT_SYNCED };
+
+  // Construct an in-memory frame element.
    FrameElement() {
-    type_ = TypeField::encode(MEMORY) | DirtyField::encode(false);
-    // Memory elements have no useful data.
+    type_ = TypeField::encode(MEMORY) | SyncField::encode(SYNCED);
+    // In-memory elements have no useful data.
      data_.reg_ = no_reg;
    }

-  explicit FrameElement(Register reg) {
-    type_ = TypeField::encode(REGISTER) | DirtyField::encode(true);
+  // Construct an in-register frame element.
+  FrameElement(Register reg, SyncFlag is_synced) {
+    type_ = TypeField::encode(REGISTER) | SyncField::encode(is_synced);
      data_.reg_ = reg;
    }

-  explicit FrameElement(Handle<Object> value) {
-    type_ = TypeField::encode(CONSTANT) | DirtyField::encode(true);
+  // Construct a frame element whose value is known at compile time.
+  FrameElement(Handle<Object> value, SyncFlag is_synced) {
+    type_ = TypeField::encode(CONSTANT) | SyncField::encode(is_synced);
      data_.handle_ = value.location();
    }

-  bool is_dirty() const { return DirtyField::decode(type_); }
+  bool is_synced() const { return SyncField::decode(type_) == SYNCED; }

-  void set_dirty() {
+  void set_sync() {
      ASSERT(type() != MEMORY);
-    type_ = type_ | DirtyField::encode(true);
+    type_ = type_ | SyncField::encode(SYNCED);
    }

-  void clear_dirty() {
+  void clear_sync() {
      ASSERT(type() != MEMORY);
-    type_ = type_ & ~DirtyField::mask();
+    type_ = type_ & ~SyncField::mask();
    }

    bool is_register() const { return type() == REGISTER; }
@@ -86,7 +95,7 @@
    enum Type { MEMORY, REGISTER, CONSTANT };

    // BitField is <type, shift, size>.
-  class DirtyField : public BitField<bool, 0, 1> {};
+  class SyncField : public BitField<SyncFlag, 0, 1> {};
    class TypeField : public BitField<Type, 1, 32 - 1> {};

    Type type() const { return TypeField::decode(type_); }
@@ -137,6 +146,10 @@
    // Spill all values from the frame to memory.
    void SpillAll();

+  // Spill a register if possible.  Return the register spilled or no_reg  
if
+  // it was not possible to spill one.
+  Register SpillAnyRegister();
+
    // 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 EnsureMergable();
@@ -231,6 +244,10 @@
    void EmitPush(Operand operand);
    void EmitPush(Immediate immediate);

+  // Push an element on the virtual frame.
+  void Push(Register reg);
+  void Push(Handle<Object> value);
+
   private:
    // An illegal index into the virtual frame.
    static const int kIllegalIndex = -1;
@@ -241,6 +258,7 @@

    static const int kHandlerSize = StackHandlerConstants::kSize /  
kPointerSize;

+  CodeGenerator* cgen_;
    MacroAssembler* masm_;

    List<FrameElement> elements_;
@@ -256,14 +274,34 @@
    // (the ebp register).
    int frame_pointer_;

+  // The frame has an embedded register file that it uses to track  
registers
+  // used in the frame.
+  RegisterFile frame_registers_;
+
    // The index of the first parameter.  The receiver lies below the first
    // parameter.
    int param0_index() const { return 1; }

+  // The index of the context slot in the frame.
+  int context_index() const {
+    ASSERT(frame_pointer_ != kIllegalIndex);
+    return frame_pointer_ + 1;
+  }
+
+  // The index of the function slot in the frame.  It lies above the  
context
+  // slot.
+  int function_index() const {
+    ASSERT(frame_pointer_ != kIllegalIndex);
+    return frame_pointer_ + 2;
+  }
+
    // The index of the first local.  Between the parameters and the locals
    // lie the return address, the saved frame pointer, the context, and the
    // function.
-  int local0_index() const { return param0_index() + parameter_count_ + 4;  
}
+  int local0_index() const {
+    ASSERT(frame_pointer_ != kIllegalIndex);
+    return frame_pointer_ + 3;
+  }

    // The index of the base of the expression stack.
    int expression_base_index() const { return local0_index() +  
local_count_; }
@@ -274,6 +312,15 @@
      return (frame_pointer_ - index) * kPointerSize;
    }

+  // Record an occurrence of a register in the virtual frame.  This has the
+  // effect of incrementing both the register's frame-internal reference
+  // count and its external reference count.
+  void Use(Register reg);
+
+  // Record that a register reference has been dropped from the frame.   
This
+  // decrements both the register's internal and external reference counts.
+  void Unuse(Register reg);
+
    // Sync the element at a particular index---write it to memory if
    // necessary, but do not free any associated register or forget its value
    // if constant.  Space should have already been allocated in the actual
@@ -285,6 +332,9 @@
    // constant.  Space should have already been allocated in the actual  
frame
    // for all the elements below this one (at least).
    void SpillElementAt(int index);
+
+  // Sync all elements in the frame.
+  void SyncAll();

    // Spill the topmost elements of the frame to memory (eg, they are the
    // arguments to a call) and all registers.

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to