x86 JNI compiler and unit tests.
Change-Id: I4c2e10328961a2e8e27c90777fe2a93737b21143
diff --git a/src/assembler_x86.cc b/src/assembler_x86.cc
index 0c44c08..6f833ad 100644
--- a/src/assembler_x86.cc
+++ b/src/assembler_x86.cc
@@ -4,7 +4,6 @@
#include "src/assembler.h"
#include "src/casts.h"
#include "src/globals.h"
-#include "src/assembler.h"
#include "src/memory_region.h"
namespace art {
@@ -27,11 +26,18 @@
if (rhs >= EAX && rhs <= EDI) {
os << kRegisterNames[rhs];
} else {
- os << "Register[" << int(rhs) << "]";
+ os << "Register[" << static_cast<int>(rhs) << "]";
}
return os;
}
+std::ostream& operator<<(std::ostream& os, const XmmRegister& reg) {
+ return os << "XMM" << static_cast<int>(reg);
+}
+
+std::ostream& operator<<(std::ostream& os, const X87Register& reg) {
+ return os << "ST" << static_cast<int>(reg);
+}
void Assembler::InitializeMemoryWithBreakpoints(byte* data, size_t length) {
memset(reinterpret_cast<void*>(data), Instr::kBreakPointInstruction, length);
@@ -234,19 +240,19 @@
}
-void Assembler::cmovs(Register dst, Register src) {
+void Assembler::cmovl(Condition condition, Register dst, Register src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x0F);
- EmitUint8(0x48);
+ EmitUint8(0x40 + condition);
EmitRegisterOperand(dst, src);
}
-void Assembler::cmovns(Register dst, Register src) {
+void Assembler::setb(Condition condition, Register dst) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x0F);
- EmitUint8(0x49);
- EmitRegisterOperand(dst, src);
+ EmitUint8(0x90 + condition);
+ EmitOperand(0, Operand(dst));
}
@@ -1179,6 +1185,11 @@
EmitOperand(reg, address);
}
+void Assembler::fs() {
+ // TODO: fs is a prefix and not an instruction
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x64);
+}
void Assembler::AddImmediate(Register reg, const Immediate& imm) {
int value = imm.value();
@@ -1358,4 +1369,220 @@
EmitOperand(rm, Operand(operand));
}
-} // namespace art
+// Emit code that will create an activation on the stack
+void Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg) {
+ CHECK(IsAligned(frame_size, 16));
+ // return address then method on stack
+ addl(ESP, Immediate(-frame_size + 4 /*method*/ + 4 /*return address*/));
+ pushl(method_reg.AsCpuRegister());
+}
+
+// Emit code that will remove an activation from the stack
+void Assembler::RemoveFrame(size_t frame_size) {
+ CHECK(IsAligned(frame_size, 16));
+ addl(ESP, Immediate(frame_size - 4));
+ ret();
+}
+
+void Assembler::IncreaseFrameSize(size_t adjust) {
+ CHECK(IsAligned(adjust, 16));
+ addl(ESP, Immediate(-adjust));
+}
+
+void Assembler::DecreaseFrameSize(size_t adjust) {
+ CHECK(IsAligned(adjust, 16));
+ addl(ESP, Immediate(adjust));
+}
+
+// Store bytes from the given register onto the stack
+void Assembler::Store(FrameOffset offs, ManagedRegister src, size_t size) {
+ if (src.IsCpuRegister()) {
+ CHECK_EQ(4u, size);
+ movl(Address(ESP, offs), src.AsCpuRegister());
+ } else if (src.IsXmmRegister()) {
+ if (size == 4) {
+ movss(Address(ESP, offs), src.AsXmmRegister());
+ } else {
+ movsd(Address(ESP, offs), src.AsXmmRegister());
+ }
+ }
+}
+
+void Assembler::StoreRef(FrameOffset dest, ManagedRegister src) {
+ CHECK(src.IsCpuRegister());
+ movl(Address(ESP, dest), src.AsCpuRegister());
+}
+
+void Assembler::CopyRef(FrameOffset dest, FrameOffset src,
+ ManagedRegister scratch) {
+ CHECK(scratch.IsCpuRegister());
+ movl(scratch.AsCpuRegister(), Address(ESP, src));
+ movl(Address(ESP, dest), scratch.AsCpuRegister());
+}
+
+void Assembler::StoreImmediateToFrame(FrameOffset dest, uint32_t imm,
+ ManagedRegister) {
+ movl(Address(ESP, dest), Immediate(imm));
+}
+
+void Assembler::StoreImmediateToThread(ThreadOffset dest, uint32_t imm,
+ ManagedRegister) {
+ fs();
+ movl(Address::Absolute(dest), Immediate(imm));
+}
+
+void Assembler::Load(ManagedRegister dest, FrameOffset src, size_t size) {
+ if (dest.IsCpuRegister()) {
+ CHECK_EQ(4u, size);
+ movl(dest.AsCpuRegister(), Address(ESP, src));
+ } else {
+ // TODO: x87, SSE
+ LOG(FATAL) << "Unimplemented";
+ }
+}
+
+void Assembler::LoadRef(ManagedRegister dest, FrameOffset src) {
+ CHECK(dest.IsCpuRegister());
+ movl(dest.AsCpuRegister(), Address(ESP, src));
+}
+
+void Assembler::LoadRef(ManagedRegister dest, ManagedRegister base,
+ MemberOffset offs) {
+ CHECK(dest.IsCpuRegister() && dest.IsCpuRegister());
+ movl(dest.AsCpuRegister(), Address(base.AsCpuRegister(), offs));
+}
+
+void Assembler::LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset offs) {
+ CHECK(dest.IsCpuRegister());
+ fs();
+ movl(dest.AsCpuRegister(), Address::Absolute(offs));
+}
+
+void Assembler::CopyRawPtrFromThread(FrameOffset fr_offs, ThreadOffset thr_offs,
+ ManagedRegister scratch) {
+ CHECK(scratch.IsCpuRegister());
+ fs();
+ movl(scratch.AsCpuRegister(), Address::Absolute(thr_offs));
+ Store(fr_offs, scratch, 4);
+}
+
+void Assembler::CopyRawPtrToThread(ThreadOffset thr_offs, FrameOffset fr_offs,
+ ManagedRegister scratch) {
+ CHECK(scratch.IsCpuRegister());
+ Load(scratch, fr_offs, 4);
+ fs();
+ movl(Address::Absolute(thr_offs), scratch.AsCpuRegister());
+}
+
+void Assembler::StoreStackOffsetToThread(ThreadOffset thr_offs,
+ FrameOffset fr_offs,
+ ManagedRegister scratch) {
+ CHECK(scratch.IsCpuRegister());
+ leal(scratch.AsCpuRegister(), Address(ESP, fr_offs));
+ fs();
+ movl(Address::Absolute(thr_offs), scratch.AsCpuRegister());
+}
+
+void Assembler::Move(ManagedRegister dest, ManagedRegister src) {
+ if (!dest.Equals(src)) {
+ if (dest.IsCpuRegister() && src.IsCpuRegister()) {
+ movl(dest.AsCpuRegister(), src.AsCpuRegister());
+ } else {
+ // TODO: x87, SSE
+ LOG(FATAL) << "Unimplemented";
+ }
+ }
+}
+
+void Assembler::Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch,
+ size_t size) {
+ if (scratch.IsCpuRegister() && size == 8) {
+ Load(scratch, src, 4);
+ Store(dest, scratch, 4);
+ Load(scratch, FrameOffset(src.Int32Value() + 4), 4);
+ Store(FrameOffset(dest.Int32Value() + 4), scratch, 4);
+ } else {
+ Load(scratch, src, size);
+ Store(dest, scratch, size);
+ }
+}
+
+void Assembler::CreateStackHandle(ManagedRegister out_reg,
+ FrameOffset handle_offset,
+ ManagedRegister in_reg, bool null_allowed) {
+ CHECK(in_reg.IsCpuRegister());
+ CHECK(out_reg.IsCpuRegister());
+ ValidateRef(in_reg, null_allowed);
+ if (null_allowed) {
+ Label null_arg;
+ if (!out_reg.Equals(in_reg)) {
+ xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister());
+ }
+ testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister());
+ j(ZERO, &null_arg);
+ leal(out_reg.AsCpuRegister(), Address(ESP, handle_offset));
+ Bind(&null_arg);
+ } else {
+ leal(out_reg.AsCpuRegister(), Address(ESP, handle_offset));
+ }
+}
+
+void Assembler::CreateStackHandle(FrameOffset out_off,
+ FrameOffset handle_offset,
+ ManagedRegister scratch, bool null_allowed) {
+ CHECK(scratch.IsCpuRegister());
+ if (null_allowed) {
+ Label null_arg;
+ movl(scratch.AsCpuRegister(), Address(ESP, handle_offset));
+ testl(scratch.AsCpuRegister(), scratch.AsCpuRegister());
+ j(ZERO, &null_arg);
+ leal(scratch.AsCpuRegister(), Address(ESP, handle_offset));
+ Bind(&null_arg);
+ } else {
+ leal(scratch.AsCpuRegister(), Address(ESP, handle_offset));
+ }
+ Store(out_off, scratch, 4);
+}
+
+// Given a stack handle, load the associated reference.
+void Assembler::LoadReferenceFromStackHandle(ManagedRegister out_reg,
+ ManagedRegister in_reg,
+ FrameOffset shb_offset) {
+ CHECK(out_reg.IsCpuRegister());
+ CHECK(in_reg.IsCpuRegister());
+ Label null_arg;
+ if (!out_reg.Equals(in_reg)) {
+ xorl(out_reg.AsCpuRegister(), out_reg.AsCpuRegister());
+ }
+ testl(in_reg.AsCpuRegister(), in_reg.AsCpuRegister());
+ j(ZERO, &null_arg);
+ movl(out_reg.AsCpuRegister(), Address(in_reg.AsCpuRegister(), 0));
+ Bind(&null_arg);
+}
+
+void Assembler::ValidateRef(ManagedRegister src, bool could_be_null) {
+ // TODO: not validating references
+}
+
+void Assembler::ValidateRef(FrameOffset src, bool could_be_null) {
+ // TODO: not validating references
+}
+
+void Assembler::Call(ManagedRegister base, MemberOffset offset,
+ ManagedRegister) {
+ CHECK(base.IsCpuRegister());
+ call(Address(base.AsCpuRegister(), offset));
+ // TODO: place reference map on call
+}
+
+// Emit code that will lock the reference in the given register
+void Assembler::LockReferenceOnStack(FrameOffset fr_offs) {
+ LOG(FATAL) << "TODO";
+}
+// Emit code that will unlock the reference in the given register
+void Assembler::UnLockReferenceOnStack(FrameOffset fr_offs) {
+ LOG(FATAL) << "TODO";
+}
+
+
+} // namespace art