Commit 960a1d36 authored by whesse@chromium.org's avatar whesse@chromium.org

Add implementation of control flow and label binding to x64 assembler.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2057 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d1915ea4
......@@ -44,6 +44,10 @@ Condition NegateCondition(Condition cc) {
#define EMIT(x) \
*pc_++ = (x)
void Assembler::emit(uint32_t x) {
*reinterpret_cast<uint32_t*>(pc_) = x;
pc_ += sizeof(uint32_t);
}
void Assembler::emit_rex_64(Register reg, Register rm_reg) {
EMIT(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
......
......@@ -189,10 +189,34 @@ void Assembler::RecordStatementPosition(int a) {
UNIMPLEMENTED();
}
void Assembler::bind(Label* a) {
UNIMPLEMENTED();
void Assembler::bind_to(Label* L, int pos) {
ASSERT(!L->is_bound()); // Label may only be bound once.
last_pc_ = NULL;
ASSERT(0 <= pos && pos <= pc_offset()); // Position must be valid.
if (L->is_linked()) {
int current = L->pos();
int next = long_at(current);
while (next != current) {
// relative address, relative to point after address
int imm32 = pos - (current + sizeof(int32_t));
long_at_put(current, imm32);
current = next;
next = long_at(next);
}
// Fix up last fixup on linked list.
int last_imm32 = pos - (current + sizeof(int32_t));
long_at_put(current, last_imm32);
}
L->bind_to(pos);
}
void Assembler::bind(Label* L) {
bind_to(L, pc_offset());
}
void Assembler::GrowBuffer() {
ASSERT(overflow()); // should not call this otherwise
if (!own_buffer_) FATAL("external code buffer is too small");
......@@ -275,6 +299,8 @@ void Assembler::emit_operand(Register reg, const Operand& adr) {
}
// Assembler Instruction implementations
void Assembler::add(Register dst, const Operand& src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
......@@ -289,7 +315,28 @@ void Assembler::add(Register dst, Register src) {
last_pc_ = pc_;
emit_rex_64(dst, src);
EMIT(0x03);
EMIT(0xC0 | (src.code() & 0x7) << 3 | (dst.code() & 0x7));
EMIT(0xC0 | (dst.code() & 0x7) << 3 | (src.code() & 0x7));
}
void Assembler::call(Label* L) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
// 1110 1000 #32-bit disp
EMIT(0xE8);
if (L->is_bound()) {
int offset = L->pos() - pc_offset() - sizeof(int32_t);
ASSERT(offset <= 0);
emit(offset);
} else if (L->is_linked()) {
emit(L->pos());
L->link_to(pc_offset() - sizeof(int32_t));
} else {
ASSERT(L->is_unused());
int32_t current = pc_offset();
emit(current);
L->link_to(current);
}
}
......@@ -343,6 +390,73 @@ void Assembler::int3() {
}
void Assembler::j(Condition cc, Label* L) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
ASSERT(0 <= cc && cc < 16);
if (L->is_bound()) {
const int short_size = 2;
const int long_size = 6;
int offs = L->pos() - pc_offset();
ASSERT(offs <= 0);
if (is_int8(offs - short_size)) {
// 0111 tttn #8-bit disp
EMIT(0x70 | cc);
EMIT((offs - short_size) & 0xFF);
} else {
// 0000 1111 1000 tttn #32-bit disp
EMIT(0x0F);
EMIT(0x80 | cc);
emit(offs - long_size);
}
} else if (L->is_linked()) {
// 0000 1111 1000 tttn #32-bit disp
EMIT(0x0F);
EMIT(0x80 | cc);
emit(L->pos());
L->link_to(pc_offset() - sizeof(int32_t));
} else {
ASSERT(L->is_unused());
EMIT(0x0F);
EMIT(0x80 | cc);
int32_t current = pc_offset();
emit(current);
L->link_to(current);
}
}
void Assembler::jmp(Label* L) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
if (L->is_bound()) {
int offs = L->pos() - pc_offset() - 1;
ASSERT(offs <= 0);
if (is_int8(offs - sizeof(int8_t))) {
// 1110 1011 #8-bit disp
EMIT(0xEB);
EMIT((offs - sizeof(int8_t)) & 0xFF);
} else {
// 1110 1001 #32-bit disp
EMIT(0xE9);
emit(offs - sizeof(int32_t));
}
} else if (L->is_linked()) {
// 1110 1001 #32-bit disp
EMIT(0xE9);
emit(L->pos());
L->link_to(pc_offset() - sizeof(int32_t));
} else {
// 1110 1001 #32-bit disp
ASSERT(L->is_unused());
EMIT(0xE9);
int32_t current = pc_offset();
emit(current);
L->link_to(current);
}
}
void Assembler::mov(Register dst, const Operand& src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
......@@ -356,8 +470,8 @@ void Assembler::mov(Register dst, Register src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit_rex_64(dst, src);
EMIT(0x89);
EMIT(0xC0 | (src.code() & 0x7) << 3 | (dst.code() & 0x7));
EMIT(0x8B);
EMIT(0xC0 | (dst.code() & 0x7) << 3 | (src.code() & 0x7));
}
......
......@@ -676,9 +676,9 @@ class Assembler : public Malloced {
void jmp(Handle<Code> code, RelocInfo::Mode rmode);
// Conditional jumps
void j(Condition cc, Label* L, Hint hint = no_hint);
void j(Condition cc, byte* entry, RelocInfo::Mode rmode, Hint hint = no_hint);
void j(Condition cc, Handle<Code> code, Hint hint = no_hint);
void j(Condition cc, Label* L);
void j(Condition cc, byte* entry, RelocInfo::Mode rmode);
void j(Condition cc, Handle<Code> code);
// Floating-point operations
void fld(int i);
......
......@@ -38,8 +38,13 @@
using v8::internal::byte;
using v8::internal::OS;
using v8::internal::Assembler;
using v8::internal::Operand;
using v8::internal::Label;
using v8::internal::rax;
using v8::internal::rsi;
using v8::internal::rdi;
using v8::internal::rbp;
using v8::internal::rsp;
using v8::internal::FUNCTION_CAST;
using v8::internal::CodeDesc;
......@@ -60,7 +65,7 @@ typedef int (*F2)(int x, int y);
#define __ assm.
TEST(AssemblerX640) {
TEST(AssemblerX64ReturnOperation) {
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
......@@ -81,4 +86,114 @@ TEST(AssemblerX640) {
CHECK_EQ(2, result);
}
TEST(AssemblerX64StackOperations) {
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
&actual_size,
true));
CHECK(buffer);
Assembler assm(buffer, actual_size);
// Assemble a simple function that copies argument 2 and returns it.
// We compile without stack frame pointers, so the gdb debugger shows
// incorrect stack frames when debugging this function (which has them).
__ push(rbp);
__ mov(rbp, rsp);
__ push(rsi); // Value at (rbp - 8)
__ push(rsi); // Value at (rbp - 16)
__ push(rdi); // Value at (rbp - 24)
__ pop(rax);
__ pop(rax);
__ pop(rax);
__ pop(rbp);
__ nop();
__ ret(0);
CodeDesc desc;
assm.GetCode(&desc);
// Call the function from C++.
int result = FUNCTION_CAST<F2>(buffer)(3, 2);
CHECK_EQ(2, result);
}
TEST(AssemblerX64ArithmeticOperations) {
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
&actual_size,
true));
CHECK(buffer);
Assembler assm(buffer, actual_size);
// Assemble a simple function that copies argument 2 and returns it.
__ mov(rax, rsi);
__ add(rax, rdi);
__ ret(0);
CodeDesc desc;
assm.GetCode(&desc);
// Call the function from C++.
int result = FUNCTION_CAST<F2>(buffer)(3, 2);
CHECK_EQ(5, result);
}
TEST(AssemblerX64MemoryOperands) {
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
&actual_size,
true));
CHECK(buffer);
Assembler assm(buffer, actual_size);
// Assemble a simple function that copies argument 2 and returns it.
__ push(rbp);
__ mov(rbp, rsp);
__ push(rsi); // Value at (rbp - 8)
__ push(rsi); // Value at (rbp - 16)
__ push(rdi); // Value at (rbp - 24)
// const int kStackElementSize = 8;
// __ mov(rax, Operand(rbp,-3 * kStackElementSize));
__ pop(rax);
__ pop(rax);
__ pop(rax);
__ pop(rbp);
__ nop();
__ ret(0);
CodeDesc desc;
assm.GetCode(&desc);
// Call the function from C++.
int result = FUNCTION_CAST<F2>(buffer)(3, 2);
CHECK_EQ(2, result);
}
TEST(AssemblerX64ControlFlow) {
// Allocate an executable page of memory.
size_t actual_size;
byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
&actual_size,
true));
CHECK(buffer);
Assembler assm(buffer, actual_size);
// Assemble a simple function that copies argument 2 and returns it.
__ push(rbp);
__ mov(rbp, rsp);
__ mov(rax, rdi);
Label target;
__ jmp(&target);
__ mov(rax, rsi);
__ bind(&target);
__ pop(rbp);
__ ret(0);
CodeDesc desc;
assm.GetCode(&desc);
// Call the function from C++.
int result = FUNCTION_CAST<F2>(buffer)(3, 2);
CHECK_EQ(3, result);
}
#undef __
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