Commit f1fcab31 authored by whesse@chromium.org's avatar whesse@chromium.org

X64 implementation starts using virtual frame and register allocators.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2146 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d39df380
......@@ -77,7 +77,7 @@ SOURCES = {
'x64/debug-x64.cc', 'x64/frames-x64.cc', 'x64/ic-x64.cc',
'x64/jump-target-x64.cc', 'x64/macro-assembler-x64.cc',
# 'x64/regexp-macro-assembler-x64.cc',
'x64/stub-cache-x64.cc'
'x64/stub-cache-x64.cc', 'x64/virtual-frame-x64.cc'
],
'simulator:arm': ['arm/simulator-arm.cc'],
'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
......
......@@ -441,11 +441,11 @@ void Assembler::immediate_arithmetic_op(byte subcode,
emit_rex_64(dst);
if (is_int8(src.value_)) {
emit(0x83);
emit_operand(Register::toRegister(subcode), dst);
emit_operand(subcode, dst);
emit(src.value_);
} else {
emit(0x81);
emit_operand(Register::toRegister(subcode), dst);
emit_operand(subcode, dst);
emitl(src.value_);
}
}
......@@ -459,16 +459,29 @@ void Assembler::immediate_arithmetic_op_32(byte subcode,
emit_optional_rex_32(dst);
if (is_int8(src.value_)) {
emit(0x83);
emit_operand(Register::toRegister(subcode), dst);
emit_operand(subcode, dst);
emit(src.value_);
} else {
emit(0x81);
emit_operand(Register::toRegister(subcode), dst);
emit_operand(subcode, dst);
emitl(src.value_);
}
}
void Assembler::immediate_arithmetic_op_8(byte subcode,
const Operand& dst,
Immediate src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit_optional_rex_32(dst);
ASSERT(is_int8(src.value_));
emit(0x80);
emit_operand(subcode, dst);
emit(src.value_);
}
void Assembler::shift(Register dst, Immediate shift_amount, int subcode) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
......@@ -1513,18 +1526,6 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* a,
return NULL;
}
StackFrame::Type ExitFrame::GetStateForFramePointer(unsigned char* a,
StackFrame::State* b) {
// TODO(X64): UNIMPLEMENTED
return NONE;
}
int JavaScriptFrame::GetProvidedParametersCount() const {
UNIMPLEMENTED();
return 0;
}
void JumpTarget::DoBind(int a) {
UNIMPLEMENTED();
}
......@@ -1537,7 +1538,6 @@ void JumpTarget::DoJump() {
UNIMPLEMENTED();
}
Object* LoadStubCompiler::CompileLoadCallback(JSObject* a,
JSObject* b,
AccessorInfo* c,
......@@ -1569,11 +1569,6 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* a,
return NULL;
}
StackFrame::Type StackFrame::ComputeType(StackFrame::State* a) {
UNIMPLEMENTED();
return NONE;
}
Object* StoreStubCompiler::CompileStoreCallback(JSObject* a,
AccessorInfo* b,
String* c) {
......@@ -1599,102 +1594,4 @@ Object* StubCompiler::CompileLazyCompile(Code::Flags a) {
return NULL;
}
void VirtualFrame::Drop(int a) {
UNIMPLEMENTED();
}
int VirtualFrame::InvalidateFrameSlotAt(int a) {
UNIMPLEMENTED();
return -1;
}
void VirtualFrame::MergeTo(VirtualFrame* a) {
UNIMPLEMENTED();
}
Result VirtualFrame::Pop() {
UNIMPLEMENTED();
return Result(NULL);
}
Result VirtualFrame::RawCallStub(CodeStub* a) {
UNIMPLEMENTED();
return Result(NULL);
}
void VirtualFrame::SyncElementBelowStackPointer(int a) {
UNIMPLEMENTED();
}
void VirtualFrame::SyncElementByPushing(int a) {
UNIMPLEMENTED();
}
void VirtualFrame::SyncRange(int a, int b) {
UNIMPLEMENTED();
}
VirtualFrame::VirtualFrame() : elements_(0) {
UNIMPLEMENTED();
}
byte* ArgumentsAdaptorFrame::GetCallerStackPointer() const {
UNIMPLEMENTED();
return NULL;
}
void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateLog(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void ExitFrame::Iterate(ObjectVisitor* a) const {
UNIMPLEMENTED();
}
byte* InternalFrame::GetCallerStackPointer() const {
UNIMPLEMENTED();
return NULL;
}
byte* JavaScriptFrame::GetCallerStackPointer() const {
UNIMPLEMENTED();
return NULL;
}
} } // namespace v8::internal
......@@ -482,6 +482,10 @@ class Assembler : public Malloced {
immediate_arithmetic_op_32(0x0, dst, src);
}
void cmpb(const Operand& dst, Immediate src) {
immediate_arithmetic_op_8(0x7, dst, src);
}
void cmpq(Register dst, Register src) {
arithmetic_op(0x3B, dst, src);
}
......@@ -958,9 +962,14 @@ class Assembler : public Malloced {
void arithmetic_op(byte opcode, Register reg, const Operand& op);
void immediate_arithmetic_op(byte subcode, Register dst, Immediate src);
void immediate_arithmetic_op(byte subcode, const Operand& dst, Immediate src);
// Operate on a 32-bit word in memory.
void immediate_arithmetic_op_32(byte subcode,
const Operand& dst,
Immediate src);
// Operate on a byte in memory.
void immediate_arithmetic_op_8(byte subcode,
const Operand& dst,
Immediate src);
// Emit machine code for a shift operation.
void shift(Register dst, Immediate shift_amount, int subcode);
// Shift dst by cl % 64 bits.
......
......@@ -41,6 +41,37 @@ void DeferredCode::SaveRegisters() { UNIMPLEMENTED(); }
void DeferredCode::RestoreRegisters() { UNIMPLEMENTED(); }
// -------------------------------------------------------------------------
// CodeGenState implementation.
CodeGenState::CodeGenState(CodeGenerator* owner)
: owner_(owner),
typeof_state_(NOT_INSIDE_TYPEOF),
destination_(NULL),
previous_(NULL) {
owner_->set_state(this);
}
CodeGenState::CodeGenState(CodeGenerator* owner,
TypeofState typeof_state,
ControlDestination* destination)
: owner_(owner),
typeof_state_(typeof_state),
destination_(destination),
previous_(owner->state()) {
owner_->set_state(this);
}
CodeGenState::~CodeGenState() {
ASSERT(owner_->state() == this);
owner_->set_state(previous_);
}
// -----------------------------------------------------------------------------
// CodeGenerator implementation.
CodeGenerator::CodeGenerator(int buffer_size,
Handle<Script> script,
......@@ -71,6 +102,8 @@ void CodeGenerator::TestCodeGenerator() {
const int initial_buffer_size = 4 * KB;
CodeGenerator cgen(initial_buffer_size, NULL, false);
CodeGeneratorScope scope(&cgen);
Scope dummy_scope;
cgen.scope_ = &dummy_scope;
cgen.GenCode(NULL);
CodeDesc desc;
......@@ -78,14 +111,67 @@ void CodeGenerator::TestCodeGenerator() {
}
void CodeGenerator::GenCode(FunctionLiteral* a) {
if (a != NULL) {
void CodeGenerator::GenCode(FunctionLiteral* function) {
if (function != NULL) {
CodeForFunctionPosition(function);
// ASSERT(scope_ == NULL);
// scope_ = function->scope();
__ int3(); // UNIMPLEMENTED
} else {
// GenCode Implementation under construction. Run by TestCodeGenerator
// with a == NULL.
__ movq(rax, Immediate(0x2a));
__ Ret();
// Everything guarded by if (function) should be run, unguarded,
// once testing is over.
// Record the position for debugging purposes.
if (function) {
CodeForFunctionPosition(function);
}
// ZoneList<Statement*>* body = fun->body();
// Initialize state.
// While testing, scope is set in cgen before calling GenCode().
if (function) {
ASSERT(scope_ == NULL);
scope_ = function->scope();
}
ASSERT(allocator_ == NULL);
RegisterAllocator register_allocator(this);
allocator_ = &register_allocator;
ASSERT(frame_ == NULL);
frame_ = new VirtualFrame();
set_in_spilled_code(false);
// Adjust for function-level loop nesting.
// loop_nesting_ += fun->loop_nesting();
JumpTarget::set_compiling_deferred_code(false);
#ifdef DEBUG
if (strlen(FLAG_stop_at) > 0 &&
// fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
false) {
frame_->SpillAll();
__ int3();
}
#endif
// New scope to get automatic timing calculation.
{ // NOLINT
HistogramTimerScope codegen_timer(&Counters::code_generation);
CodeGenState state(this);
// Entry:
// Stack: receiver, arguments, return address.
// ebp: caller's frame pointer
// esp: stack pointer
// edi: called JS function
// esi: callee's context
allocator_->Initialize();
frame_->Enter();
__ movq(rax, Immediate(0x2a));
__ Ret();
}
}
}
......@@ -255,6 +341,46 @@ void CodeGenerator::VisitThisFunction(ThisFunction* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateLog(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* a) {
UNIMPLEMENTED();
}
#undef __
// End of CodeGenerator implementation.
......
......@@ -25,3 +25,48 @@
// (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 "frames-inl.h"
namespace v8 {
namespace internal {
StackFrame::Type ExitFrame::GetStateForFramePointer(unsigned char* a,
StackFrame::State* b) {
// TODO(X64): UNIMPLEMENTED
return NONE;
}
int JavaScriptFrame::GetProvidedParametersCount() const {
UNIMPLEMENTED();
return 0;
}
StackFrame::Type StackFrame::ComputeType(StackFrame::State* a) {
UNIMPLEMENTED();
return NONE;
}
byte* ArgumentsAdaptorFrame::GetCallerStackPointer() const {
UNIMPLEMENTED();
return NULL;
}
void ExitFrame::Iterate(ObjectVisitor* a) const {
UNIMPLEMENTED();
}
byte* InternalFrame::GetCallerStackPointer() const {
UNIMPLEMENTED();
return NULL;
}
byte* JavaScriptFrame::GetCallerStackPointer() const {
UNIMPLEMENTED();
return NULL;
}
} } // namespace v8::internal
......@@ -278,6 +278,21 @@ void MacroAssembler::Ret() {
}
void MacroAssembler::CmpObjectType(Register heap_object,
InstanceType type,
Register map) {
movq(map, FieldOperand(heap_object, HeapObject::kMapOffset));
CmpInstanceType(map, type);
}
void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
cmpb(FieldOperand(map, Map::kInstanceTypeOffset),
Immediate(static_cast<int8_t>(type)));
}
void MacroAssembler::SetCounter(StatsCounter* counter, int value) {
if (FLAG_native_code_counters && counter->Enabled()) {
movq(kScratchRegister, ExternalReference(counter));
......
......@@ -37,8 +37,7 @@ namespace internal {
// RegisterAllocator implementation.
bool RegisterAllocator::IsReserved(Register reg) {
// All registers are reserved for now.
return true;
return reg.is(rsp) || reg.is(rbp) || reg.is(rsi) || reg.is(r10);
}
......@@ -47,20 +46,19 @@ bool RegisterAllocator::IsReserved(Register reg) {
int RegisterAllocator::ToNumber(Register reg) {
ASSERT(reg.is_valid() && !IsReserved(reg));
UNIMPLEMENTED();
return -1;
return reg.code();
}
Register RegisterAllocator::ToRegister(int num) {
ASSERT(num >= 0 && num < kNumRegisters);
UNIMPLEMENTED();
return no_reg;
Register result = {num};
return result;
}
void RegisterAllocator::Initialize() {
UNIMPLEMENTED();
// TODO(X64): Implement.
}
......
......@@ -35,7 +35,7 @@ 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 kNumRegisters = 16;
static const int kInvalidRegister = -1;
};
......
......@@ -25,3 +25,170 @@
// (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-inl.h"
#include "register-allocator-inl.h"
#include "scopes.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm())
// -------------------------------------------------------------------------
// VirtualFrame implementation.
// 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()
: elements_(parameter_count() + local_count() + kPreallocatedElements),
stack_pointer_(parameter_count() + 1) { // 0-based index of TOS.
for (int i = 0; i <= stack_pointer_; i++) {
elements_.Add(FrameElement::MemoryElement());
}
for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
register_locations_[i] = kIllegalIndex;
}
}
void VirtualFrame::Enter() {
// Registers live on entry to a JS frame:
// rsp: stack pointer, points to return address from this function.
// rbp: base pointer, points to previous JS, ArgumentsAdaptor, or
// Trampoline frame.
// rsi: context of this function call.
// rdi: pointer to this function object.
Comment cmnt(masm(), "[ Enter JS frame");
#ifdef DEBUG
// Verify that rdi contains a JS function. The following code
// relies on rax being available for use.
__ testq(rdi, Immediate(kSmiTagMask));
__ Check(not_zero,
"VirtualFrame::Enter - rdi is not a function (smi check).");
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
__ Check(equal,
"VirtualFrame::Enter - rdi is not a function (map check).");
#endif
EmitPush(rbp);
__ movq(rbp, rsp);
// Store the context in the frame. The context is kept in rsi and a
// copy is stored in the frame. The external reference to rsi
// remains.
EmitPush(rsi);
// Store the function in the frame. The frame owns the register
// reference now (ie, it can keep it in rdi or spill it later).
Push(rdi);
// SyncElementAt(element_count() - 1);
cgen()->allocator()->Unuse(rdi);
}
void VirtualFrame::Exit() {
Comment cmnt(masm(), "[ Exit JS frame");
// Record the location of the JS exit code for patching when setting
// break point.
__ RecordJSReturn();
// Avoid using the leave instruction here, because it is too
// short. We need the return sequence to be a least the size of a
// call instruction to support patching the exit code in the
// debugger. See VisitReturnStatement for the full return sequence.
__ movq(rsp, rbp);
stack_pointer_ = frame_pointer();
for (int i = element_count() - 1; i > stack_pointer_; i--) {
FrameElement last = elements_.RemoveLast();
if (last.is_register()) {
Unuse(last.reg());
}
}
EmitPop(rbp);
}
void VirtualFrame::EmitPop(Register reg) {
ASSERT(stack_pointer_ == element_count() - 1);
stack_pointer_--;
elements_.RemoveLast();
__ pop(reg);
}
void VirtualFrame::EmitPop(const Operand& operand) {
ASSERT(stack_pointer_ == element_count() - 1);
stack_pointer_--;
elements_.RemoveLast();
__ pop(operand);
}
void VirtualFrame::EmitPush(Register reg) {
ASSERT(stack_pointer_ == element_count() - 1);
elements_.Add(FrameElement::MemoryElement());
stack_pointer_++;
__ push(reg);
}
void VirtualFrame::EmitPush(const Operand& operand) {
ASSERT(stack_pointer_ == element_count() - 1);
elements_.Add(FrameElement::MemoryElement());
stack_pointer_++;
__ push(operand);
}
void VirtualFrame::EmitPush(Immediate immediate) {
ASSERT(stack_pointer_ == element_count() - 1);
elements_.Add(FrameElement::MemoryElement());
stack_pointer_++;
__ push(immediate);
}
void VirtualFrame::Drop(int a) {
UNIMPLEMENTED();
}
int VirtualFrame::InvalidateFrameSlotAt(int a) {
UNIMPLEMENTED();
return -1;
}
void VirtualFrame::MergeTo(VirtualFrame* a) {
UNIMPLEMENTED();
}
Result VirtualFrame::Pop() {
UNIMPLEMENTED();
return Result(NULL);
}
Result VirtualFrame::RawCallStub(CodeStub* a) {
UNIMPLEMENTED();
return Result(NULL);
}
void VirtualFrame::SyncElementBelowStackPointer(int a) {
UNIMPLEMENTED();
}
void VirtualFrame::SyncElementByPushing(int a) {
UNIMPLEMENTED();
}
void VirtualFrame::SyncRange(int a, int b) {
UNIMPLEMENTED();
}
#undef __
} } // namespace v8::internal
......@@ -372,12 +372,12 @@ class VirtualFrame : public ZoneObject {
// Pop and save an element from the top of the expression stack and
// emit a corresponding pop instruction.
void EmitPop(Register reg);
void EmitPop(Operand operand);
void EmitPop(const Operand& operand);
// Push an element on top of the expression stack and emit a
// corresponding push instruction.
void EmitPush(Register reg);
void EmitPush(Operand operand);
void EmitPush(const Operand& operand);
void EmitPush(Immediate immediate);
// Push an element on the virtual frame.
......
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