Change the register allocator so that it no longer tracks references

to the platform-specific reserved registers.  They are always in use
for their intended purpose, cannot appear in the virtual frame, and
can be freely used without allocation in the code generator.

Review URL: http://codereview.chromium.org/113837

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2061 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 94524539
......@@ -84,8 +84,6 @@ struct Register {
};
const int kNumRegisters = 16;
extern Register no_reg;
extern Register r0;
extern Register r1;
......
......@@ -80,7 +80,7 @@ void JumpTarget::DoBranch(Condition cc, Hint ignored) {
// branch.
VirtualFrame* fall_through_frame = cgen()->frame();
VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame);
RegisterFile non_frame_registers = RegisterAllocator::Reserved();
RegisterFile non_frame_registers;
cgen()->SetFrame(branch_frame, &non_frame_registers);
// Check if we can avoid merge code.
......@@ -163,8 +163,7 @@ void JumpTarget::DoBind(int mergable_elements) {
// virtual frame before the bind. Afterward, it should not.
ASSERT(cgen()->has_valid_frame());
VirtualFrame* frame = cgen()->frame();
int difference =
frame->stack_pointer_ - (frame->elements_.length() - 1);
int difference = frame->stack_pointer_ - (frame->element_count() - 1);
if (difference > 0) {
frame->stack_pointer_ -= difference;
__ add(sp, sp, Operand(difference * kPointerSize));
......@@ -179,15 +178,14 @@ void JumpTarget::DoBind(int mergable_elements) {
// Pick up the only reaching frame, take ownership of it, and
// use it for the block about to be emitted.
VirtualFrame* frame = reaching_frames_[0];
RegisterFile reserved = RegisterAllocator::Reserved();
cgen()->SetFrame(frame, &reserved);
RegisterFile empty;
cgen()->SetFrame(frame, &empty);
reaching_frames_[0] = NULL;
__ bind(&merge_labels_[0]);
// The stack pointer can be floating above the top of the
// virtual frame before the bind. Afterward, it should not.
int difference =
frame->stack_pointer_ - (frame->elements_.length() - 1);
int difference = frame->stack_pointer_ - (frame->element_count() - 1);
if (difference > 0) {
frame->stack_pointer_ -= difference;
__ add(sp, sp, Operand(difference * kPointerSize));
......@@ -247,11 +245,11 @@ void JumpTarget::DoBind(int mergable_elements) {
}
// Pick up the frame for this block. Assume ownership if
// there cannot be backward jumps.
RegisterFile reserved = RegisterAllocator::Reserved();
RegisterFile empty;
if (direction_ == BIDIRECTIONAL) {
cgen()->SetFrame(new VirtualFrame(frame), &reserved);
cgen()->SetFrame(new VirtualFrame(frame), &empty);
} else {
cgen()->SetFrame(frame, &reserved);
cgen()->SetFrame(frame, &empty);
reaching_frames_[i] = NULL;
}
__ bind(&merge_labels_[i]);
......@@ -274,8 +272,8 @@ void JumpTarget::DoBind(int mergable_elements) {
// If this is the fall through, and it didn't need merge
// code, we need to pick up the frame so we can jump around
// subsequent merge blocks if necessary.
RegisterFile reserved = RegisterAllocator::Reserved();
cgen()->SetFrame(frame, &reserved);
RegisterFile empty;
cgen()->SetFrame(frame, &empty);
reaching_frames_[i] = NULL;
}
}
......@@ -285,8 +283,8 @@ void JumpTarget::DoBind(int mergable_elements) {
// fall through and none of the reaching frames needed merging.
// In that case, clone the entry frame as the current frame.
if (!cgen()->has_valid_frame()) {
RegisterFile reserved_registers = RegisterAllocator::Reserved();
cgen()->SetFrame(new VirtualFrame(entry_frame_), &reserved_registers);
RegisterFile empty;
cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
}
// There may be unprocessed reaching frames that did not need
......@@ -311,8 +309,8 @@ void JumpTarget::DoBind(int mergable_elements) {
// Use a copy of the reaching frame so the original can be saved
// for possible reuse as a backward merge block.
RegisterFile reserved = RegisterAllocator::Reserved();
cgen()->SetFrame(new VirtualFrame(reaching_frames_[0]), &reserved);
RegisterFile empty;
cgen()->SetFrame(new VirtualFrame(reaching_frames_[0]), &empty);
__ bind(&merge_labels_[0]);
cgen()->frame()->MergeTo(entry_frame_);
}
......
// Copyright 2009 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_ARM_REGISTER_ALLOCATOR_ARM_INL_H_
#define V8_ARM_REGISTER_ALLOCATOR_ARM_INL_H_
#include "v8.h"
namespace v8 {
namespace internal {
// -------------------------------------------------------------------------
// RegisterAllocator implementation.
bool RegisterAllocator::IsReserved(Register reg) {
return reg.is(cp) || reg.is(fp) || reg.is(sp) || reg.is(pc);
}
// The register allocator uses small integers to represent the
// non-reserved assembler registers. The mapping is:
//
// r0 <-> 0
// r1 <-> 1
// r2 <-> 2
// r3 <-> 3
// r4 <-> 4
// r5 <-> 5
// r6 <-> 6
// r7 <-> 7
// r9 <-> 8
// r10 <-> 9
// ip <-> 10
// lr <-> 11
int RegisterAllocator::ToNumber(Register reg) {
ASSERT(reg.is_valid() && !IsReserved(reg));
static int numbers[] = {
0, // r0
1, // r1
2, // r2
3, // r3
4, // r4
5, // r5
6, // r6
7, // r7
-1, // cp
8, // r9
9, // r10
-1, // fp
10, // ip
-1, // sp
11, // lr
-1 // pc
};
return numbers[reg.code()];
}
Register RegisterAllocator::ToRegister(int num) {
ASSERT(num >= 0 && num < kNumRegisters);
static Register registers[] =
{ r0, r1, r2, r3, r4, r5, r6, r7, r9, r10, ip, lr };
return registers[num];
}
void RegisterAllocator::Initialize() {
Reset();
// The non-reserved r1 and lr registers are live on JS function entry.
Use(r1); // JS function.
Use(lr); // Return address.
}
} } // namespace v8::internal
#endif // V8_ARM_REGISTER_ALLOCATOR_ARM_INL_H_
......@@ -49,54 +49,9 @@ void Result::ToRegister(Register target) {
// -------------------------------------------------------------------------
// RegisterAllocator implementation.
RegisterFile RegisterAllocator::Reserved() {
RegisterFile reserved;
reserved.Use(sp);
reserved.Use(fp);
reserved.Use(cp);
reserved.Use(pc);
return reserved;
}
void RegisterAllocator::UnuseReserved(RegisterFile* register_file) {
register_file->ref_counts_[sp.code()] = 0;
register_file->ref_counts_[fp.code()] = 0;
register_file->ref_counts_[cp.code()] = 0;
register_file->ref_counts_[pc.code()] = 0;
}
bool RegisterAllocator::IsReserved(int reg_code) {
return (reg_code == sp.code())
|| (reg_code == fp.code())
|| (reg_code == cp.code())
|| (reg_code == pc.code());
}
void RegisterAllocator::Initialize() {
Reset();
// The following registers are live on function entry, saved in the
// frame, and available for allocation during execution.
Use(r1); // JS function.
Use(lr); // Return address.
}
void RegisterAllocator::Reset() {
registers_.Reset();
// The following registers are live on function entry and reserved
// during execution.
Use(sp); // Stack pointer.
Use(fp); // Frame pointer (caller's frame pointer on entry).
Use(cp); // Context context (callee's context on entry).
Use(pc); // Program counter.
}
Result RegisterAllocator::AllocateByteRegisterWithoutSpilling() {
UNIMPLEMENTED();
// No byte registers on ARM.
UNREACHABLE();
return Result();
}
......
// Copyright 2009 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_ARM_REGISTER_ALLOCATOR_ARM_H_
#define V8_ARM_REGISTER_ALLOCATOR_ARM_H_
namespace v8 {
namespace internal {
class RegisterAllocatorConstants : public AllStatic {
public:
static const int kNumRegisters = 12;
static const int kInvalidRegister = -1;
};
} } // namespace v8::internal
#endif // V8_ARM_REGISTER_ALLOCATOR_ARM_H_
......@@ -49,7 +49,7 @@ VirtualFrame::VirtualFrame()
for (int i = 0; i <= stack_pointer_; i++) {
elements_.Add(FrameElement::MemoryElement());
}
for (int i = 0; i < kNumRegisters; i++) {
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
register_locations_[i] = kIllegalIndex;
}
}
......@@ -96,7 +96,7 @@ void VirtualFrame::MergeTo(VirtualFrame* expected) {
// Fix any sync bit problems from the bottom-up, stopping when we
// hit the stack pointer or the top of the frame if the stack
// pointer is floating above the frame.
int limit = Min(static_cast<int>(stack_pointer_), elements_.length() - 1);
int limit = Min(static_cast<int>(stack_pointer_), element_count() - 1);
for (int i = 0; i <= limit; i++) {
FrameElement source = elements_[i];
FrameElement target = expected->elements_[i];
......@@ -128,7 +128,7 @@ void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) {
// On ARM, all elements are in memory.
#ifdef DEBUG
int start = Min(static_cast<int>(stack_pointer_), elements_.length() - 1);
int start = Min(static_cast<int>(stack_pointer_), element_count() - 1);
for (int i = start; i >= 0; i--) {
ASSERT(elements_[i].is_memory());
ASSERT(expected->elements_[i].is_memory());
......@@ -393,7 +393,7 @@ Result VirtualFrame::CallCodeObject(Handle<Code> code,
void VirtualFrame::Drop(int count) {
ASSERT(height() >= count);
int num_virtual_elements = (elements_.length() - 1) - stack_pointer_;
int num_virtual_elements = (element_count() - 1) - stack_pointer_;
// Emit code to lower the stack pointer if necessary.
if (num_virtual_elements < count) {
......@@ -419,7 +419,7 @@ Result VirtualFrame::Pop() {
void VirtualFrame::EmitPop(Register reg) {
ASSERT(stack_pointer_ == elements_.length() - 1);
ASSERT(stack_pointer_ == element_count() - 1);
stack_pointer_--;
elements_.RemoveLast();
__ pop(reg);
......@@ -427,7 +427,7 @@ void VirtualFrame::EmitPop(Register reg) {
void VirtualFrame::EmitPush(Register reg) {
ASSERT(stack_pointer_ == elements_.length() - 1);
ASSERT(stack_pointer_ == element_count() - 1);
elements_.Add(FrameElement::MemoryElement());
stack_pointer_++;
__ push(reg);
......
......@@ -83,21 +83,35 @@ class VirtualFrame : public ZoneObject {
// Create a duplicate of an existing valid frame element.
FrameElement CopyElementAt(int index);
// The number of elements on the virtual frame.
int element_count() { return elements_.length(); }
// The height of the virtual expression stack.
int height() {
return elements_.length() - expression_base_index();
return element_count() - expression_base_index();
}
int register_location(int num) {
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
return register_locations_[num];
}
int register_location(Register reg) {
return register_locations_[RegisterAllocator::ToNumber(reg)];
}
int register_index(Register reg) {
return register_locations_[reg.code()];
void set_register_location(Register reg, int index) {
register_locations_[RegisterAllocator::ToNumber(reg)] = index;
}
bool is_used(int reg_code) {
return register_locations_[reg_code] != kIllegalIndex;
bool is_used(int num) {
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
return register_locations_[num] != kIllegalIndex;
}
bool is_used(Register reg) {
return is_used(reg.code());
return register_locations_[RegisterAllocator::ToNumber(reg)]
!= kIllegalIndex;
}
// Add extra in-memory elements to the top of the frame to match an actual
......@@ -109,7 +123,7 @@ class VirtualFrame : public ZoneObject {
// the frame after a runtime call). No code is emitted.
void Forget(int count) {
ASSERT(count >= 0);
ASSERT(stack_pointer_ == elements_.length() - 1);
ASSERT(stack_pointer_ == element_count() - 1);
stack_pointer_ -= count;
ForgetElements(count);
}
......@@ -124,7 +138,7 @@ class VirtualFrame : public ZoneObject {
// Spill all occurrences of a specific register from the frame.
void Spill(Register reg) {
if (is_used(reg)) SpillElementAt(register_index(reg));
if (is_used(reg)) SpillElementAt(register_location(reg));
}
// Spill all occurrences of an arbitrary register if possible. Return the
......@@ -148,11 +162,8 @@ class VirtualFrame : public ZoneObject {
// one to NULL by an unconditional jump.
void DetachFromCodeGenerator() {
RegisterAllocator* cgen_allocator = cgen()->allocator();
for (int i = 0; i < kNumRegisters; i++) {
if (is_used(i)) {
Register temp = { i };
cgen_allocator->Unuse(temp);
}
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
if (is_used(i)) cgen_allocator->Unuse(i);
}
}
......@@ -162,11 +173,8 @@ class VirtualFrame : public ZoneObject {
// binding a label.
void AttachToCodeGenerator() {
RegisterAllocator* cgen_allocator = cgen()->allocator();
for (int i = 0; i < kNumRegisters; i++) {
if (is_used(i)) {
Register temp = { i };
cgen_allocator->Use(temp);
}
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
if (is_used(i)) cgen_allocator->Unuse(i);
}
}
......@@ -205,7 +213,7 @@ class VirtualFrame : public ZoneObject {
}
void PushElementAt(int index) {
PushFrameSlotAt(elements_.length() - index - 1);
PushFrameSlotAt(element_count() - index - 1);
}
// A frame-allocated local as an assembly operand.
......@@ -336,7 +344,7 @@ class VirtualFrame : public ZoneObject {
void Drop() { Drop(1); }
// Duplicate the top element of the frame.
void Dup() { PushFrameSlotAt(elements_.length() - 1); }
void Dup() { PushFrameSlotAt(element_count() - 1); }
// Pop an element from the top of the expression stack. Returns a
// Result, which may be a constant or a register.
......@@ -387,7 +395,7 @@ class VirtualFrame : public ZoneObject {
// The index of the register frame element using each register, or
// kIllegalIndex if a register is not on the frame.
int register_locations_[kNumRegisters];
int register_locations_[RegisterAllocator::kNumRegisters];
// The number of frame-allocated locals and parameters respectively.
int parameter_count() { return cgen()->scope()->num_parameters(); }
......@@ -420,8 +428,8 @@ class VirtualFrame : public ZoneObject {
// Convert a frame index into a frame pointer relative offset into the
// actual stack.
int fp_relative(int index) {
ASSERT(index < elements_.length());
ASSERT(frame_pointer() < elements_.length()); // FP is on the frame.
ASSERT(index < element_count());
ASSERT(frame_pointer() < element_count()); // FP is on the frame.
return (frame_pointer() - index) * kPointerSize;
}
......@@ -430,7 +438,7 @@ class VirtualFrame : public ZoneObject {
// of updating the index of the register's location in the frame.
void Use(Register reg, int index) {
ASSERT(!is_used(reg));
register_locations_[reg.code()] = index;
set_register_location(reg, index);
cgen()->allocator()->Use(reg);
}
......@@ -438,8 +446,8 @@ class VirtualFrame : public ZoneObject {
// decrements the register's external reference count and invalidates the
// index of the register's location in the frame.
void Unuse(Register reg) {
ASSERT(register_locations_[reg.code()] != kIllegalIndex);
register_locations_[reg.code()] = kIllegalIndex;
ASSERT(is_used(reg));
set_register_location(reg, kIllegalIndex);
cgen()->allocator()->Unuse(reg);
}
......@@ -453,7 +461,7 @@ class VirtualFrame : public ZoneObject {
// Keep the element type as register or constant, and clear the dirty bit.
void SyncElementAt(int index);
// Sync the range of elements in [begin, end).
// Sync the range of elements in [begin, end] with memory.
void SyncRange(int begin, int end);
// Sync a single unsynced element that lies beneath or at the stack pointer.
......
......@@ -515,8 +515,8 @@ void CodeGenerator::GenerateFastCaseSwitchCases(
// frame. Otherwise, we have to merge the existing one to the
// start frame as part of the previous case.
if (!has_valid_frame()) {
RegisterFile non_frame_registers = RegisterAllocator::Reserved();
SetFrame(new VirtualFrame(start_frame), &non_frame_registers);
RegisterFile empty;
SetFrame(new VirtualFrame(start_frame), &empty);
} else {
frame_->MergeTo(start_frame);
}
......
......@@ -79,8 +79,6 @@ struct Register {
int code_;
};
const int kNumRegisters = 8;
extern Register eax;
extern Register ecx;
extern Register edx;
......
This diff is collapsed.
......@@ -580,8 +580,8 @@ class CodeGenerator: public AstVisitor {
void CodeForSourcePosition(int pos);
#ifdef DEBUG
// True if the registers are valid for entry to a block. There should be
// no frame-external references to eax, ebx, ecx, edx, or edi.
// True if the registers are valid for entry to a block. There should
// be no frame-external references to (non-reserved) registers.
bool HasValidEntryRegisters();
#endif
......
......@@ -84,7 +84,7 @@ void JumpTarget::DoBranch(Condition cc, Hint hint) {
// branch.
VirtualFrame* fall_through_frame = cgen()->frame();
VirtualFrame* branch_frame = new VirtualFrame(fall_through_frame);
RegisterFile non_frame_registers = RegisterAllocator::Reserved();
RegisterFile non_frame_registers;
cgen()->SetFrame(branch_frame, &non_frame_registers);
// Check if we can avoid merge code.
......@@ -179,14 +179,14 @@ void JumpTarget::DoBind(int mergable_elements) {
ASSERT(reaching_frames_.is_empty());
ASSERT(!cgen()->has_valid_frame());
RegisterFile reserved = RegisterAllocator::Reserved();
RegisterFile empty;
if (direction_ == BIDIRECTIONAL) {
// Copy the entry frame so the original can be used for a
// possible backward jump.
cgen()->SetFrame(new VirtualFrame(entry_frame_), &reserved);
cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
} else {
// Take ownership of the entry frame.
cgen()->SetFrame(entry_frame_, &reserved);
cgen()->SetFrame(entry_frame_, &empty);
entry_frame_ = NULL;
}
__ bind(&entry_label_);
......@@ -200,8 +200,7 @@ void JumpTarget::DoBind(int mergable_elements) {
// The stack pointer can be floating above the top of the
// virtual frame before the bind. Afterward, it should not.
VirtualFrame* frame = cgen()->frame();
int difference =
frame->stack_pointer_ - (frame->elements_.length() - 1);
int difference = frame->stack_pointer_ - (frame->element_count() - 1);
if (difference > 0) {
frame->stack_pointer_ -= difference;
__ add(Operand(esp), Immediate(difference * kPointerSize));
......@@ -225,15 +224,14 @@ void JumpTarget::DoBind(int mergable_elements) {
// possible backward jumps. Pick up the only reaching frame, take
// ownership of it, and use it for the block about to be emitted.
VirtualFrame* frame = reaching_frames_[0];
RegisterFile reserved = RegisterAllocator::Reserved();
cgen()->SetFrame(frame, &reserved);
RegisterFile empty;
cgen()->SetFrame(frame, &empty);
reaching_frames_[0] = NULL;
__ bind(&merge_labels_[0]);
// The stack pointer can be floating above the top of the
// virtual frame before the bind. Afterward, it should not.
int difference =
frame->stack_pointer_ - (frame->elements_.length() - 1);
int difference = frame->stack_pointer_ - (frame->element_count() - 1);
if (difference > 0) {
frame->stack_pointer_ -= difference;
__ add(Operand(esp), Immediate(difference * kPointerSize));
......@@ -291,11 +289,11 @@ void JumpTarget::DoBind(int mergable_elements) {
}
// Pick up the frame for this block. Assume ownership if
// there cannot be backward jumps.
RegisterFile reserved = RegisterAllocator::Reserved();
RegisterFile empty;
if (direction_ == BIDIRECTIONAL) {
cgen()->SetFrame(new VirtualFrame(frame), &reserved);
cgen()->SetFrame(new VirtualFrame(frame), &empty);
} else {
cgen()->SetFrame(frame, &reserved);
cgen()->SetFrame(frame, &empty);
reaching_frames_[i] = NULL;
}
__ bind(&merge_labels_[i]);
......@@ -318,8 +316,8 @@ void JumpTarget::DoBind(int mergable_elements) {
// If this is the fall through frame, and it didn't need
// merge code, we need to pick up the frame so we can jump
// around subsequent merge blocks if necessary.
RegisterFile reserved = RegisterAllocator::Reserved();
cgen()->SetFrame(frame, &reserved);
RegisterFile empty;
cgen()->SetFrame(frame, &empty);
reaching_frames_[i] = NULL;
}
}
......@@ -329,8 +327,8 @@ void JumpTarget::DoBind(int mergable_elements) {
// fall through and none of the reaching frames needed merging.
// In that case, clone the entry frame as the current frame.
if (!cgen()->has_valid_frame()) {
RegisterFile reserved_registers = RegisterAllocator::Reserved();
cgen()->SetFrame(new VirtualFrame(entry_frame_), &reserved_registers);
RegisterFile empty;
cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
}
// There may be unprocessed reaching frames that did not need
......@@ -355,8 +353,8 @@ void JumpTarget::DoBind(int mergable_elements) {
// Use a copy of the reaching frame so the original can be saved
// for possible reuse as a backward merge block.
RegisterFile reserved = RegisterAllocator::Reserved();
cgen()->SetFrame(new VirtualFrame(reaching_frames_[0]), &reserved);
RegisterFile empty;
cgen()->SetFrame(new VirtualFrame(reaching_frames_[0]), &empty);
__ bind(&merge_labels_[0]);
cgen()->frame()->MergeTo(entry_frame_);
}
......
// Copyright 2009 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_IA32_REGISTER_ALLOCATOR_IA32_INL_H_
#define V8_IA32_REGISTER_ALLOCATOR_IA32_INL_H_
#include "v8.h"
namespace v8 {
namespace internal {
// -------------------------------------------------------------------------
// RegisterAllocator implementation.
bool RegisterAllocator::IsReserved(Register reg) {
// The code for this test relies on the order of register codes.
return reg.code() >= esp.code() && reg.code() <= esi.code();
}
// The register allocator uses small integers to represent the
// non-reserved assembler registers. The mapping is:
// eax <-> 0, ebx <-> 1, ecx <-> 2, edx <-> 3, edi <-> 4.
int RegisterAllocator::ToNumber(Register reg) {
ASSERT(reg.is_valid() && !IsReserved(reg));
static int numbers[] = {
0, // eax
2, // ecx
3, // edx
1, // ebx
-1, // esp
-1, // ebp
-1, // esi
4 // edi
};
return numbers[reg.code()];
}
Register RegisterAllocator::ToRegister(int num) {
ASSERT(num >= 0 && num < kNumRegisters);
static Register registers[] = { eax, ebx, ecx, edx, edi };
return registers[num];
}
void RegisterAllocator::Initialize() {
Reset();
// The non-reserved edi register is live on JS function entry.
Use(edi); // JS function.
}
} } // namespace v8::internal
#endif // V8_IA32_REGISTER_ALLOCATOR_IA32_INL_H_
......@@ -84,46 +84,6 @@ void Result::ToRegister(Register target) {
// -------------------------------------------------------------------------
// RegisterAllocator implementation.
RegisterFile RegisterAllocator::Reserved() {
RegisterFile reserved;
reserved.Use(esp);
reserved.Use(ebp);
reserved.Use(esi);
return reserved;
}
void RegisterAllocator::UnuseReserved(RegisterFile* register_file) {
register_file->ref_counts_[esp.code()] = 0;
register_file->ref_counts_[ebp.code()] = 0;
register_file->ref_counts_[esi.code()] = 0;
}
bool RegisterAllocator::IsReserved(int reg_code) {
// Test below relies on the order of register codes.
return reg_code >= esp.code() && reg_code <= esi.code();
}
void RegisterAllocator::Initialize() {
Reset();
// The following register is live on function entry, saved in the
// frame, and available for allocation during execution.
Use(edi); // JS function.
}
void RegisterAllocator::Reset() {
registers_.Reset();
// The following registers are live on function entry and reserved
// during execution.
Use(esp); // Stack pointer.
Use(ebp); // Frame pointer (caller's frame pointer on entry).
Use(esi); // Context (callee's context on entry).
}
Result RegisterAllocator::AllocateByteRegisterWithoutSpilling() {
Result result = AllocateWithoutSpilling();
// Check that the register is a byte register. If not, unuse the
......
// Copyright 2009 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_IA32_REGISTER_ALLOCATOR_IA32_H_
#define V8_IA32_REGISTER_ALLOCATOR_IA32_H_
namespace v8 {
namespace internal {
class RegisterAllocatorConstants : public AllStatic {
public:
static const int kNumRegisters = 5;
static const int kInvalidRegister = -1;
};
} } // namespace v8::internal
#endif // V8_IA32_REGISTER_ALLOCATOR_IA32_H_
This diff is collapsed.
......@@ -83,21 +83,35 @@ class VirtualFrame : public ZoneObject {
// Create a duplicate of an existing valid frame element.
FrameElement CopyElementAt(int index);
// The number of elements on the virtual frame.
int element_count() { return elements_.length(); }
// The height of the virtual expression stack.
int height() {
return elements_.length() - expression_base_index();
return element_count() - expression_base_index();
}
int register_location(int num) {
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
return register_locations_[num];
}
int register_location(Register reg) {
return register_locations_[RegisterAllocator::ToNumber(reg)];
}
int register_index(Register reg) {
return register_locations_[reg.code()];
void set_register_location(Register reg, int index) {
register_locations_[RegisterAllocator::ToNumber(reg)] = index;
}
bool is_used(int reg_code) {
return register_locations_[reg_code] != kIllegalIndex;
bool is_used(int num) {
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
return register_locations_[num] != kIllegalIndex;
}
bool is_used(Register reg) {
return is_used(reg.code());
return register_locations_[RegisterAllocator::ToNumber(reg)]
!= kIllegalIndex;
}
// Add extra in-memory elements to the top of the frame to match an actual
......@@ -112,7 +126,7 @@ class VirtualFrame : public ZoneObject {
// handler). No code will be emitted.
void Forget(int count) {
ASSERT(count >= 0);
ASSERT(stack_pointer_ == elements_.length() - 1);
ASSERT(stack_pointer_ == element_count() - 1);
stack_pointer_ -= count;
ForgetElements(count);
}
......@@ -127,7 +141,7 @@ class VirtualFrame : public ZoneObject {
// Spill all occurrences of a specific register from the frame.
void Spill(Register reg) {
if (is_used(reg)) SpillElementAt(register_index(reg));
if (is_used(reg)) SpillElementAt(register_location(reg));
}
// Spill all occurrences of an arbitrary register if possible. Return the
......@@ -135,6 +149,9 @@ class VirtualFrame : public ZoneObject {
// (ie, they all have frame-external references).
Register SpillAnyRegister();
// Sync the range of elements in [begin, end] with memory.
void SyncRange(int begin, int end);
// Make this frame so that an arbitrary frame of the same height can
// be merged to it. Copies and constants are removed from the
// topmost mergable_elements elements of the frame. A
......@@ -158,11 +175,8 @@ class VirtualFrame : public ZoneObject {
// one to NULL by an unconditional jump.
void DetachFromCodeGenerator() {
RegisterAllocator* cgen_allocator = cgen()->allocator();
for (int i = 0; i < kNumRegisters; i++) {
if (is_used(i)) {
Register temp = { i };
cgen_allocator->Unuse(temp);
}
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
if (is_used(i)) cgen_allocator->Unuse(i);
}
}
......@@ -172,11 +186,8 @@ class VirtualFrame : public ZoneObject {
// binding a label.
void AttachToCodeGenerator() {
RegisterAllocator* cgen_allocator = cgen()->allocator();
for (int i = 0; i < kNumRegisters; i++) {
if (is_used(i)) {
Register temp = { i };
cgen_allocator->Use(temp);
}
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
if (is_used(i)) cgen_allocator->Use(i);
}
}
......@@ -211,11 +222,11 @@ class VirtualFrame : public ZoneObject {
}
void PushElementAt(int index) {
PushFrameSlotAt(elements_.length() - index - 1);
PushFrameSlotAt(element_count() - index - 1);
}
void StoreToElementAt(int index) {
StoreToFrameSlotAt(elements_.length() - index - 1);
StoreToFrameSlotAt(element_count() - index - 1);
}
// A frame-allocated local as an assembly operand.
......@@ -259,7 +270,7 @@ class VirtualFrame : public ZoneObject {
// A parameter as an assembly operand.
Operand ParameterAt(int index) {
ASSERT(-1 <= index); // -1 is the receiver.
ASSERT(index <= parameter_count());
ASSERT(index < parameter_count());
return Operand(ebp, (1 + parameter_count() - index) * kPointerSize);
}
......@@ -352,7 +363,7 @@ class VirtualFrame : public ZoneObject {
void Drop() { Drop(1); }
// Duplicate the top element of the frame.
void Dup() { PushFrameSlotAt(elements_.length() - 1); }
void Dup() { PushFrameSlotAt(element_count() - 1); }
// Pop an element from the top of the expression stack. Returns a
// Result, which may be a constant or a register.
......@@ -407,7 +418,7 @@ class VirtualFrame : public ZoneObject {
// The index of the register frame element using each register, or
// kIllegalIndex if a register is not on the frame.
int register_locations_[kNumRegisters];
int register_locations_[RegisterAllocator::kNumRegisters];
// The number of frame-allocated locals and parameters respectively.
int parameter_count() { return cgen()->scope()->num_parameters(); }
......@@ -440,8 +451,8 @@ class VirtualFrame : public ZoneObject {
// Convert a frame index into a frame pointer relative offset into the
// actual stack.
int fp_relative(int index) {
ASSERT(index < elements_.length());
ASSERT(frame_pointer() < elements_.length()); // FP is on the frame.
ASSERT(index < element_count());
ASSERT(frame_pointer() < element_count()); // FP is on the frame.
return (frame_pointer() - index) * kPointerSize;
}
......@@ -450,7 +461,7 @@ class VirtualFrame : public ZoneObject {
// of updating the index of the register's location in the frame.
void Use(Register reg, int index) {
ASSERT(!is_used(reg));
register_locations_[reg.code()] = index;
set_register_location(reg, index);
cgen()->allocator()->Use(reg);
}
......@@ -458,8 +469,8 @@ class VirtualFrame : public ZoneObject {
// decrements the register's external reference count and invalidates the
// index of the register's location in the frame.
void Unuse(Register reg) {
ASSERT(register_locations_[reg.code()] != kIllegalIndex);
register_locations_[reg.code()] = kIllegalIndex;
ASSERT(is_used(reg));
set_register_location(reg, kIllegalIndex);
cgen()->allocator()->Unuse(reg);
}
......@@ -473,9 +484,6 @@ class VirtualFrame : public ZoneObject {
// Keep the element type as register or constant, and clear the dirty bit.
void SyncElementAt(int index);
// Sync the range of elements in [begin, end).
void SyncRange(int begin, int end);
// Sync a single unsynced element that lies beneath or at the stack pointer.
void SyncElementBelowStackPointer(int index);
......
......@@ -38,7 +38,7 @@ CodeGenerator* JumpTarget::cgen() {
void JumpTarget::InitializeEntryElement(int index, FrameElement* target) {
entry_frame_->elements_[index].clear_copied();
if (target->is_register()) {
entry_frame_->register_locations_[target->reg().code()] = index;
entry_frame_->set_register_location(target->reg(), index);
} else if (target->is_copy()) {
entry_frame_->elements_[target->index()].set_copied();
}
......
......@@ -74,7 +74,7 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) {
// A list of pointers to frame elements in the entry frame. NULL
// indicates that the element has not yet been determined.
int length = initial_frame->elements_.length();
int length = initial_frame->element_count();
ZoneList<FrameElement*> elements(length);
// Convert the number of mergable elements (counted from the top
......@@ -124,7 +124,7 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) {
// return address). Replace those first.
entry_frame_ = new VirtualFrame();
int index = 0;
for (; index < entry_frame_->elements_.length(); index++) {
for (; index < entry_frame_->element_count(); index++) {
FrameElement* target = elements[index];
// If the element is determined, set it now. Count registers. Mark
// elements as copied exactly when they have a copy. Undetermined
......@@ -155,7 +155,7 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) {
bool is_synced = true;
RegisterFile candidate_registers;
int best_count = kMinInt;
int best_reg_code = no_reg.code_;
int best_reg_num = RegisterAllocator::kInvalidRegister;
StaticType type; // Initially invalid.
if (direction_ != BIDIRECTIONAL || i < high_water_mark) {
......@@ -168,10 +168,11 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) {
if (element.is_register() && !entry_frame_->is_used(element.reg())) {
// Count the register occurrence and remember it if better
// than the previous best.
candidate_registers.Use(element.reg());
if (candidate_registers.count(element.reg()) > best_count) {
best_count = candidate_registers.count(element.reg());
best_reg_code = element.reg().code();
int num = RegisterAllocator::ToNumber(element.reg());
candidate_registers.Use(num);
if (candidate_registers.count(num) > best_count) {
best_count = candidate_registers.count(num);
best_reg_num = num;
}
}
type = type.merge(element.static_type());
......@@ -188,16 +189,16 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) {
// Try to put it in a register. If there was no best choice
// consider any free register.
if (best_reg_code == no_reg.code_) {
for (int j = 0; j < kNumRegisters; j++) {
if (!entry_frame_->is_used(j) && !RegisterAllocator::IsReserved(j)) {
best_reg_code = j;
if (best_reg_num == RegisterAllocator::kInvalidRegister) {
for (int j = 0; j < RegisterAllocator::kNumRegisters; j++) {
if (!entry_frame_->is_used(j)) {
best_reg_num = j;
break;
}
}
}
if (best_reg_code == no_reg.code_) {
if (best_reg_num == RegisterAllocator::kInvalidRegister) {
// If there was no register found, the element is already
// recorded as in memory.
entry_frame_->elements_[i].set_static_type(type);
......@@ -205,13 +206,13 @@ void JumpTarget::ComputeEntryFrame(int mergable_elements) {
// If there was a register choice, use it. Preserve the copied
// flag on the element. Set the static type as computed.
bool is_copied = entry_frame_->elements_[i].is_copied();
Register reg = { best_reg_code };
Register reg = RegisterAllocator::ToRegister(best_reg_num);
entry_frame_->elements_[i] =
FrameElement::RegisterElement(reg,
FrameElement::NOT_SYNCED);
if (is_copied) entry_frame_->elements_[i].set_copied();
entry_frame_->elements_[i].set_static_type(type);
entry_frame_->register_locations_[best_reg_code] = i;
entry_frame_->set_register_location(reg, i);
}
}
}
......
......@@ -32,6 +32,17 @@
#include "register-allocator.h"
#include "virtual-frame.h"
#if V8_TARGET_ARCH_IA32
#include "ia32/register-allocator-ia32-inl.h"
#elif V8_TARGET_ARCH_X64
#include "x64/register-allocator-x64-inl.h"
#elif V8_TARGET_ARCH_ARM
#include "arm/register-allocator-arm-inl.h"
#else
#error Unsupported target architecture.
#endif
namespace v8 {
namespace internal {
......
......@@ -38,7 +38,7 @@ namespace internal {
Result::Result(Register reg) {
ASSERT(reg.is_valid());
ASSERT(reg.is_valid() && !RegisterAllocator::IsReserved(reg));
CodeGeneratorScope::Current()->allocator()->Use(reg);
value_ = StaticTypeField::encode(StaticType::UNKNOWN_TYPE)
| TypeField::encode(REGISTER)
......@@ -47,7 +47,7 @@ Result::Result(Register reg) {
Result::Result(Register reg, StaticType type) {
ASSERT(reg.is_valid());
ASSERT(reg.is_valid() && !RegisterAllocator::IsReserved(reg));
CodeGeneratorScope::Current()->allocator()->Use(reg);
value_ = StaticTypeField::encode(type.static_type_)
| TypeField::encode(REGISTER)
......@@ -61,12 +61,11 @@ Result::Result(Register reg, StaticType type) {
Result RegisterAllocator::AllocateWithoutSpilling() {
// Return the first free register, if any.
int free_reg = registers_.ScanForFreeRegister();
if (free_reg < kNumRegisters) {
Register free_result = { free_reg };
return Result(free_result);
int num = registers_.ScanForFreeRegister();
if (num == RegisterAllocator::kInvalidRegister) {
return Result();
}
return Result();
return Result(RegisterAllocator::ToRegister(num));
}
......
......@@ -30,6 +30,16 @@
#include "macro-assembler.h"
#if V8_TARGET_ARCH_IA32
#include "ia32/register-allocator-ia32.h"
#elif V8_TARGET_ARCH_X64
#include "x64/register-allocator-x64.h"
#elif V8_TARGET_ARCH_ARM
#include "arm/register-allocator-arm.h"
#else
#error Unsupported target architecture.
#endif
namespace v8 {
namespace internal {
......@@ -241,25 +251,28 @@ class RegisterFile BASE_EMBEDDED {
}
}
// Predicates and accessors for the reference counts. The versions
// that take a register code rather than a register are for
// convenience in loops over the register codes.
bool is_used(int reg_code) const { return ref_counts_[reg_code] > 0; }
bool is_used(Register reg) const { return is_used(reg.code()); }
int count(int reg_code) const { return ref_counts_[reg_code]; }
int count(Register reg) const { return count(reg.code()); }
// Predicates and accessors for the reference counts.
bool is_used(int num) {
ASSERT(0 <= num && num < kNumRegisters);
return ref_counts_[num] > 0;
}
int count(int num) {
ASSERT(0 <= num && num < kNumRegisters);
return ref_counts_[num];
}
// Record a use of a register by incrementing its reference count.
void Use(Register reg) {
ref_counts_[reg.code()]++;
void Use(int num) {
ASSERT(0 <= num && num < kNumRegisters);
ref_counts_[num]++;
}
// Record that a register will no longer be used by decrementing its
// reference count.
void Unuse(Register reg) {
ASSERT(!reg.is(no_reg));
ASSERT(is_used(reg.code()));
ref_counts_[reg.code()]--;
void Unuse(int num) {
ASSERT(is_used(num));
ref_counts_[num]--;
}
// Copy the reference counts from this register file to the other.
......@@ -270,17 +283,18 @@ class RegisterFile BASE_EMBEDDED {
}
private:
static const int kNumRegisters = RegisterAllocatorConstants::kNumRegisters;
int ref_counts_[kNumRegisters];
// Very fast inlined loop to find a free register.
// Used in RegisterAllocator::AllocateWithoutSpilling.
// Returns kNumRegisters if no free register found.
inline int ScanForFreeRegister() {
int i = 0;
for (; i < kNumRegisters ; ++i) {
if (ref_counts_[i] == 0) break;
// Very fast inlined loop to find a free register. Used in
// RegisterAllocator::AllocateWithoutSpilling. Returns
// kInvalidRegister if no free register found.
int ScanForFreeRegister() {
for (int i = 0; i < RegisterAllocatorConstants::kNumRegisters; i++) {
if (!is_used(i)) return i;
}
return i;
return RegisterAllocatorConstants::kInvalidRegister;
}
friend class RegisterAllocator;
......@@ -293,55 +307,62 @@ class RegisterFile BASE_EMBEDDED {
class RegisterAllocator BASE_EMBEDDED {
public:
explicit RegisterAllocator(CodeGenerator* cgen) : cgen_(cgen) {}
static const int kNumRegisters =
RegisterAllocatorConstants::kNumRegisters;
static const int kInvalidRegister =
RegisterAllocatorConstants::kInvalidRegister;
// A register file with each of the reserved registers counted once.
static RegisterFile Reserved();
// Unuse all the reserved registers in a register file.
static void UnuseReserved(RegisterFile* register_file);
explicit RegisterAllocator(CodeGenerator* cgen) : cgen_(cgen) {}
// True if the register is reserved by the code generator, false if it
// can be freely used by the allocator.
static bool IsReserved(int reg_code);
static bool IsReserved(Register reg) { return IsReserved(reg); }
// can be freely used by the allocator Defined in the
// platform-specific XXX-inl.h files..
static inline bool IsReserved(Register reg);
// Convert between (unreserved) assembler registers and allocator
// numbers. Defined in the platform-specific XXX-inl.h files.
static inline int ToNumber(Register reg);
static inline Register ToRegister(int num);
// Predicates and accessors for the registers' reference counts.
bool is_used(int reg_code) const { return registers_.is_used(reg_code); }
bool is_used(Register reg) const { return registers_.is_used(reg.code()); }
int count(int reg_code) const { return registers_.count(reg_code); }
int count(Register reg) const { return registers_.count(reg.code()); }
bool is_used(int num) { return registers_.is_used(num); }
bool is_used(Register reg) { return registers_.is_used(ToNumber(reg)); }
int count(int num) { return registers_.count(num); }
int count(Register reg) { return registers_.count(ToNumber(reg)); }
// Explicitly record a reference to a register.
void Use(Register reg) { registers_.Use(reg); }
void Use(int num) { registers_.Use(num); }
void Use(Register reg) { registers_.Use(ToNumber(reg)); }
// Explicitly record that a register will no longer be used.
void Unuse(Register reg) { registers_.Unuse(reg); }
// Initialize the register allocator for entry to a JS function. On
// entry, the registers used by the JS calling convention are
// externally referenced (ie, outside the virtual frame); and the
// other registers are free.
void Initialize();
void Unuse(int num) { registers_.Unuse(num); }
void Unuse(Register reg) { registers_.Unuse(ToNumber(reg)); }
// Reset the register reference counts to free all non-reserved registers.
// A frame-external reference is kept to each of the reserved registers.
void Reset();
void Reset() { registers_.Reset(); }
// Initialize the register allocator for entry to a JS function. On
// entry, the (non-reserved) registers used by the JS calling
// convention are referenced and the other (non-reserved) registers
// are free.
inline void Initialize();
// Allocate a free register and return a register result if possible or
// fail and return an invalid result.
Result Allocate();
// Allocate a specific register if possible, spilling it from the frame if
// necessary, or else fail and return an invalid result.
// Allocate a specific register if possible, spilling it from the
// current frame if necessary, or else fail and return an invalid
// result.
Result Allocate(Register target);
// Allocate a free register without spilling any from the current frame or
// fail and return an invalid result.
// Allocate a free register without spilling any from the current
// frame or fail and return an invalid result.
Result AllocateWithoutSpilling();
// Allocate a free byte register without spilling any from the
// current frame or fail and return an invalid result.
// Allocate a free byte register without spilling any from the current
// frame or fail and return an invalid result.
Result AllocateByteRegisterWithoutSpilling();
// Copy the internal state to a register file, to be restored later by
......@@ -350,6 +371,7 @@ class RegisterAllocator BASE_EMBEDDED {
registers_.CopyTo(register_file);
}
// Restore the internal state.
void RestoreFrom(RegisterFile* register_file) {
register_file->CopyTo(&registers_);
}
......
......@@ -38,7 +38,7 @@ namespace internal {
// When cloned, a frame is a deep copy of the original.
VirtualFrame::VirtualFrame(VirtualFrame* original)
: elements_(original->elements_.length()),
: elements_(original->element_count()),
stack_pointer_(original->stack_pointer_) {
elements_.AddAll(original->elements_);
// Copy register locations from original.
......@@ -50,7 +50,7 @@ VirtualFrame::VirtualFrame(VirtualFrame* original)
FrameElement VirtualFrame::CopyElementAt(int index) {
ASSERT(index >= 0);
ASSERT(index < elements_.length());
ASSERT(index < element_count());
FrameElement target = elements_[index];
FrameElement result;
......@@ -96,7 +96,7 @@ FrameElement VirtualFrame::CopyElementAt(int index) {
// pushing an exception handler). No code is emitted.
void VirtualFrame::Adjust(int count) {
ASSERT(count >= 0);
ASSERT(stack_pointer_ == elements_.length() - 1);
ASSERT(stack_pointer_ == element_count() - 1);
for (int i = 0; i < count; i++) {
elements_.Add(FrameElement::MemoryElement());
......@@ -107,7 +107,7 @@ void VirtualFrame::Adjust(int count) {
void VirtualFrame::ForgetElements(int count) {
ASSERT(count >= 0);
ASSERT(elements_.length() >= count);
ASSERT(element_count() >= count);
for (int i = 0; i < count; i++) {
FrameElement last = elements_.RemoveLast();
......@@ -118,7 +118,7 @@ void VirtualFrame::ForgetElements(int count) {
if (cgen()->frame() == this) {
Unuse(last.reg());
} else {
register_locations_[last.reg().code()] = kIllegalIndex;
set_register_location(last.reg(), kIllegalIndex);
}
}
}
......@@ -127,14 +127,13 @@ void VirtualFrame::ForgetElements(int count) {
// If there are any registers referenced only by the frame, spill one.
Register VirtualFrame::SpillAnyRegister() {
// Find the leftmost (ordered by register code) register whose only
// Find the leftmost (ordered by register number) register whose only
// reference is in the frame.
for (int i = 0; i < kNumRegisters; i++) {
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
if (is_used(i) && cgen()->allocator()->count(i) == 1) {
Register result = { i };
Spill(result);
ASSERT(!cgen()->allocator()->is_used(result));
return result;
SpillElementAt(register_location(i));
ASSERT(!cgen()->allocator()->is_used(i));
return RegisterAllocator::ToRegister(i);
}
}
return no_reg;
......@@ -173,7 +172,7 @@ void VirtualFrame::SyncElementAt(int index) {
// Make the type of all elements be MEMORY.
void VirtualFrame::SpillAll() {
for (int i = 0; i < elements_.length(); i++) {
for (int i = 0; i < element_count(); i++) {
SpillElementAt(i);
}
}
......@@ -183,7 +182,7 @@ void VirtualFrame::PrepareMergeTo(VirtualFrame* expected) {
// Perform state changes on this frame that will make merge to the
// expected frame simpler or else increase the likelihood that his
// frame will match another.
for (int i = 0; i < elements_.length(); i++) {
for (int i = 0; i < element_count(); i++) {
FrameElement source = elements_[i];
FrameElement target = expected->elements_[i];
......@@ -200,7 +199,7 @@ void VirtualFrame::PrepareMergeTo(VirtualFrame* expected) {
if (cgen()->frame() == this) {
Unuse(source.reg());
} else {
register_locations_[source.reg().code()] = kIllegalIndex;
set_register_location(source.reg(), kIllegalIndex);
}
}
elements_[i] = target;
......@@ -224,16 +223,16 @@ void VirtualFrame::PrepareForCall(int spilled_args, int dropped_args) {
ASSERT(height() >= spilled_args);
ASSERT(dropped_args <= spilled_args);
SyncRange(0, elements_.length() - 1);
SyncRange(0, element_count() - 1);
// Spill registers.
for (int i = 0; i < kNumRegisters; i++) {
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
if (is_used(i)) {
SpillElementAt(register_locations_[i]);
SpillElementAt(register_location(i));
}
}
// Spill the arguments.
for (int i = elements_.length() - spilled_args; i < elements_.length(); i++) {
for (int i = element_count() - spilled_args; i < element_count(); i++) {
if (!elements_[i].is_memory()) {
SpillElementAt(i);
}
......@@ -257,9 +256,9 @@ void VirtualFrame::PrepareForReturn() {
void VirtualFrame::SetElementAt(int index, Result* value) {
int frame_index = elements_.length() - index - 1;
int frame_index = element_count() - index - 1;
ASSERT(frame_index >= 0);
ASSERT(frame_index < elements_.length());
ASSERT(frame_index < element_count());
ASSERT(value->is_valid());
FrameElement original = elements_[frame_index];
......@@ -283,7 +282,7 @@ void VirtualFrame::SetElementAt(int index, Result* value) {
// The register already appears on the frame. Either the existing
// register element, or the new element at frame_index, must be made
// a copy.
int i = register_index(value->reg());
int i = register_location(value->reg());
ASSERT(value->static_type() == elements_[i].static_type());
if (i < frame_index) {
......@@ -299,8 +298,8 @@ void VirtualFrame::SetElementAt(int index, Result* value) {
elements_[i].set_sync();
}
elements_[frame_index].clear_sync();
register_locations_[value->reg().code()] = frame_index;
for (int j = i + 1; j < elements_.length(); j++) {
set_register_location(value->reg(), frame_index);
for (int j = i + 1; j < element_count(); j++) {
if (elements_[j].is_copy() && elements_[j].index() == i) {
elements_[j].set_index(frame_index);
}
......@@ -331,12 +330,12 @@ void VirtualFrame::PushFrameSlotAt(int index) {
void VirtualFrame::Push(Register reg, StaticType static_type) {
if (is_used(reg)) {
int index = register_index(reg);
int index = register_location(reg);
FrameElement element = CopyElementAt(index);
ASSERT(static_type.merge(element.static_type()) == element.static_type());
elements_.Add(element);
} else {
Use(reg, elements_.length());
Use(reg, element_count());
FrameElement element =
FrameElement::RegisterElement(reg,
FrameElement::NOT_SYNCED,
......@@ -366,15 +365,15 @@ void VirtualFrame::Nip(int num_dropped) {
bool VirtualFrame::Equals(VirtualFrame* other) {
#ifdef DEBUG
for (int i = 0; i < kNumRegisters; i++) {
if (register_locations_[i] != other->register_locations_[i]) {
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
if (register_location(i) != other->register_location(i)) {
return false;
}
}
if (elements_.length() != other->elements_.length()) return false;
if (element_count() != other->element_count()) return false;
#endif
if (stack_pointer_ != other->stack_pointer_) return false;
for (int i = 0; i < elements_.length(); i++) {
for (int i = 0; i < element_count(); i++) {
if (!elements_[i].Equals(other->elements_[i])) return false;
}
......
......@@ -682,16 +682,6 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a,
return NULL;
}
bool RegisterAllocator::IsReserved(int a) {
UNIMPLEMENTED();
return false;
}
RegisterFile RegisterAllocator::Reserved() {
UNIMPLEMENTED();
return RegisterFile();
}
const int RelocInfo::kApplyMask = -1;
StackFrame::Type StackFrame::ComputeType(StackFrame::State* a) {
......
......@@ -61,10 +61,9 @@ namespace internal {
// mode. This way we get the compile-time error checking in debug mode
// and best performance in optimized code.
//
const int kNumRegisters = 16;
struct Register {
bool is_valid() const { return 0 <= code_ && code_ < kNumRegisters; }
bool is_valid() const { return 0 <= code_ && code_ < 16; }
bool is(Register reg) const { return code_ == reg.code_; }
// The byte-register distinction of ai32 has dissapeared.
bool is_byte_register() const { return false; }
......
......@@ -578,14 +578,14 @@ class CodeGenerator: public AstVisitor {
void CodeForSourcePosition(int pos);
#ifdef DEBUG
// True if the registers are valid for entry to a block. There should be
// no frame-external references to eax, ebx, ecx, edx, or edi.
// True if the registers are valid for entry to a block. There should
// be no frame-external references to (non-reserved) registers.
bool HasValidEntryRegisters();
#endif
bool is_eval_; // Tells whether code is generated for eval.
Handle<Script> script_;
List<DeferredCode*> deferred_;
ZoneList<DeferredCode*> deferred_;
// Assembler
MacroAssembler* masm_; // to generate code
......
// Copyright 2009 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_X64_REGISTER_ALLOCATOR_X64_INL_H_
#define V8_X64_REGISTER_ALLOCATOR_X64_INL_H_
#include "v8.h"
namespace v8 {
namespace internal {
// -------------------------------------------------------------------------
// RegisterAllocator implementation.
bool RegisterAllocator::IsReserved(Register reg) {
// All registers are reserved for now.
return true;
}
// The register allocator uses small integers to represent the
// non-reserved assembler registers.
int RegisterAllocator::ToNumber(Register reg) {
ASSERT(reg.is_valid() && !IsReserved(reg));
UNIMPLEMENTED();
return -1;
}
Register RegisterAllocator::ToRegister(int num) {
ASSERT(num >= 0 && num < kNumRegisters);
UNIMPLEMENTED();
return no_reg;
}
void RegisterAllocator::Initialize() {
UNIMPLEMENTED();
}
} } // namespace v8::internal
#endif // V8_X64_REGISTER_ALLOCATOR_X64_INL_H_
// Copyright 2009 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_X64_REGISTER_ALLOCATOR_X64_H_
#define V8_X64_REGISTER_ALLOCATOR_X64_H_
namespace v8 {
namespace internal {
class RegisterAllocatorConstants : public AllStatic {
public:
// Register allocation is not yet implemented on x64, but C++
// forbids 0-length arrays so we use 1 as the number of registers.
static const int kNumRegisters = 1;
static const int kInvalidRegister = -1;
};
} } // namespace v8::internal
#endif // V8_X64_REGISTER_ALLOCATOR_X64_H_
......@@ -83,21 +83,35 @@ class VirtualFrame : public ZoneObject {
// Create a duplicate of an existing valid frame element.
FrameElement CopyElementAt(int index);
// The number of elements on the virtual frame.
int element_count() { return elements_.length(); }
// The height of the virtual expression stack.
int height() {
return elements_.length() - expression_base_index();
return element_count() - expression_base_index();
}
int register_location(int num) {
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
return register_locations_[num];
}
int register_location(Register reg) {
return register_locations_[RegisterAllocator::ToNumber(reg)];
}
int register_index(Register reg) {
return register_locations_[reg.code()];
void set_register_location(Register reg, int index) {
register_locations_[RegisterAllocator::ToNumber(reg)] = index;
}
bool is_used(int reg_code) {
return register_locations_[reg_code] != kIllegalIndex;
bool is_used(int num) {
ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
return register_locations_[num] != kIllegalIndex;
}
bool is_used(Register reg) {
return is_used(reg.code());
return register_locations_[RegisterAllocator::ToNumber(reg)]
!= kIllegalIndex;
}
// Add extra in-memory elements to the top of the frame to match an actual
......@@ -112,7 +126,7 @@ class VirtualFrame : public ZoneObject {
// handler). No code will be emitted.
void Forget(int count) {
ASSERT(count >= 0);
ASSERT(stack_pointer_ == elements_.length() - 1);
ASSERT(stack_pointer_ == element_count() - 1);
stack_pointer_ -= count;
ForgetElements(count);
}
......@@ -127,7 +141,7 @@ class VirtualFrame : public ZoneObject {
// Spill all occurrences of a specific register from the frame.
void Spill(Register reg) {
if (is_used(reg)) SpillElementAt(register_index(reg));
if (is_used(reg)) SpillElementAt(register_location(reg));
}
// Spill all occurrences of an arbitrary register if possible. Return the
......@@ -135,6 +149,9 @@ class VirtualFrame : public ZoneObject {
// (ie, they all have frame-external references).
Register SpillAnyRegister();
// Sync the range of elements in [begin, end] with memory.
void SyncRange(int begin, int end);
// Make this frame so that an arbitrary frame of the same height can
// be merged to it. Copies and constants are removed from the
// topmost mergable_elements elements of the frame. A
......@@ -158,11 +175,8 @@ class VirtualFrame : public ZoneObject {
// one to NULL by an unconditional jump.
void DetachFromCodeGenerator() {
RegisterAllocator* cgen_allocator = cgen()->allocator();
for (int i = 0; i < kNumRegisters; i++) {
if (is_used(i)) {
Register temp = { i };
cgen_allocator->Unuse(temp);
}
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
if (is_used(i)) cgen_allocator->Unuse(i);
}
}
......@@ -172,11 +186,8 @@ class VirtualFrame : public ZoneObject {
// binding a label.
void AttachToCodeGenerator() {
RegisterAllocator* cgen_allocator = cgen()->allocator();
for (int i = 0; i < kNumRegisters; i++) {
if (is_used(i)) {
Register temp = { i };
cgen_allocator->Use(temp);
}
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
if (is_used(i)) cgen_allocator->Use(i);
}
}
......@@ -211,11 +222,11 @@ class VirtualFrame : public ZoneObject {
}
void PushElementAt(int index) {
PushFrameSlotAt(elements_.length() - index - 1);
PushFrameSlotAt(element_count() - index - 1);
}
void StoreToElementAt(int index) {
StoreToFrameSlotAt(elements_.length() - index - 1);
StoreToFrameSlotAt(element_count() - index - 1);
}
// A frame-allocated local as an assembly operand.
......@@ -352,7 +363,7 @@ class VirtualFrame : public ZoneObject {
void Drop() { Drop(1); }
// Duplicate the top element of the frame.
void Dup() { PushFrameSlotAt(elements_.length() - 1); }
void Dup() { PushFrameSlotAt(element_count() - 1); }
// Pop an element from the top of the expression stack. Returns a
// Result, which may be a constant or a register.
......@@ -407,7 +418,7 @@ class VirtualFrame : public ZoneObject {
// The index of the register frame element using each register, or
// kIllegalIndex if a register is not on the frame.
int register_locations_[kNumRegisters];
int register_locations_[RegisterAllocator::kNumRegisters];
// The number of frame-allocated locals and parameters respectively.
int parameter_count() { return cgen()->scope()->num_parameters(); }
......@@ -420,7 +431,7 @@ class VirtualFrame : public ZoneObject {
// The index of the first parameter. The receiver lies below the first
// parameter.
int param0_index() const { return 1; }
int param0_index() { return 1; }
// The index of the context slot in the frame. It is immediately
// above the frame pointer.
......@@ -440,8 +451,8 @@ class VirtualFrame : public ZoneObject {
// Convert a frame index into a frame pointer relative offset into the
// actual stack.
int fp_relative(int index) {
ASSERT(index < elements_.length());
ASSERT(frame_pointer() < elements_.length()); // FP is on the frame.
ASSERT(index < element_count());
ASSERT(frame_pointer() < element_count()); // FP is on the frame.
return (frame_pointer() - index) * kPointerSize;
}
......@@ -450,7 +461,7 @@ class VirtualFrame : public ZoneObject {
// of updating the index of the register's location in the frame.
void Use(Register reg, int index) {
ASSERT(!is_used(reg));
register_locations_[reg.code()] = index;
set_register_location(reg, index);
cgen()->allocator()->Use(reg);
}
......@@ -458,8 +469,8 @@ class VirtualFrame : public ZoneObject {
// decrements the register's external reference count and invalidates the
// index of the register's location in the frame.
void Unuse(Register reg) {
ASSERT(register_locations_[reg.code()] != kIllegalIndex);
register_locations_[reg.code()] = kIllegalIndex;
ASSERT(is_used(reg));
set_register_location(reg, kIllegalIndex);
cgen()->allocator()->Unuse(reg);
}
......@@ -473,9 +484,6 @@ class VirtualFrame : public ZoneObject {
// Keep the element type as register or constant, and clear the dirty bit.
void SyncElementAt(int index);
// Sync the range of elements in [begin, end).
void SyncRange(int begin, int end);
// Sync a single unsynced element that lies beneath or at the stack pointer.
void SyncElementBelowStackPointer(int index);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment