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_ = ®ister_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
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---