Add basic assembler interface and an x86 backend.
Change-Id: Ia8136bad88f1194c8a247e2af80e486ab88c1e8c
diff --git a/Android.common.mk b/Android.common.mk
index 94a5ac8..69ea22c 100644
--- a/Android.common.mk
+++ b/Android.common.mk
@@ -20,4 +20,16 @@
src/main.cc
LIBART_LOCAL_SRC_FILES := \
- src/art.cc
+ src/art.cc \
+ src/assembler.cc \
+ src/memory_region.cc
+
+ifeq ($(LIBART_TARGET_ARCH),arm)
+LIBART_LOCAL_SRC_FILES += \
+ src/assembler_arm.cc
+endif
+
+ifeq ($(LIBART_TARGET_ARCH),x86)
+LIBART_LOCAL_SRC_FILES += \
+ src/assembler_x86.cc
+endif
diff --git a/Android.libart.host.mk b/Android.libart.host.mk
index a2b62ac..d0d3c8f 100644
--- a/Android.libart.host.mk
+++ b/Android.libart.host.mk
@@ -20,6 +20,7 @@
LOCAL_MODULE := libart
LOCAL_MODULE_TAGS := optional
+LIBART_TARGET_ARCH := $(HOST_ARCH)
include $(LOCAL_PATH)/Android.common.mk
LOCAL_SRC_FILES := $(LIBART_LOCAL_SRC_FILES)
diff --git a/Android.libart.mk b/Android.libart.mk
index 3992cf0..c54a6fe 100644
--- a/Android.libart.mk
+++ b/Android.libart.mk
@@ -20,6 +20,7 @@
LOCAL_MODULE := libart
LOCAL_MODULE_TAGS := optional
+LIBART_TARGET_ARCH := $(TARGET_ARCH)
include $(LOCAL_PATH)/Android.common.mk
LOCAL_SRC_FILES := $(LIBART_LOCAL_SRC_FILES)
diff --git a/src/assembler.cc b/src/assembler.cc
new file mode 100644
index 0000000..f6ca690
--- /dev/null
+++ b/src/assembler.cc
@@ -0,0 +1,137 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include <algorithm>
+#include <vector>
+#include "src/assembler.h"
+#include "src/globals.h"
+#include "src/memory_region.h"
+
+namespace android {
+namespace runtime {
+
+static byte* NewContents(size_t capacity) {
+ byte* result = new byte[capacity];
+#if defined(DEBUG)
+ // Initialize the buffer with kBreakPointInstruction to force a break
+ // point if we ever execute an uninitialized part of the code buffer.
+ Assembler::InitializeMemoryWithBreakpoints(result, capacity);
+#endif
+ return result;
+}
+
+
+#if defined(DEBUG)
+AssemblerBuffer::EnsureCapacity::EnsureCapacity(AssemblerBuffer* buffer) {
+ if (buffer->cursor() >= buffer->limit()) buffer->ExtendCapacity();
+ // In debug mode, we save the assembler buffer along with the gap
+ // size before we start emitting to the buffer. This allows us to
+ // check that any single generated instruction doesn't overflow the
+ // limit implied by the minimum gap size.
+ buffer_ = buffer;
+ gap_ = ComputeGap();
+ // Make sure that extending the capacity leaves a big enough gap
+ // for any kind of instruction.
+ CHECK(gap_ >= kMinimumGap);
+ // Mark the buffer as having ensured the capacity.
+ CHECK(!buffer->HasEnsuredCapacity()); // Cannot nest.
+ buffer->has_ensured_capacity_ = true;
+}
+
+
+AssemblerBuffer::EnsureCapacity::~EnsureCapacity() {
+ // Unmark the buffer, so we cannot emit after this.
+ buffer_->has_ensured_capacity_ = false;
+ // Make sure the generated instruction doesn't take up more
+ // space than the minimum gap.
+ int delta = gap_ - ComputeGap();
+ CHECK(delta <= kMinimumGap);
+}
+#endif
+
+
+AssemblerBuffer::AssemblerBuffer() {
+ static const size_t kInitialBufferCapacity = 4 * KB;
+ contents_ = NewContents(kInitialBufferCapacity);
+ cursor_ = contents_;
+ limit_ = ComputeLimit(contents_, kInitialBufferCapacity);
+ fixup_ = NULL;
+#if defined(DEBUG)
+ has_ensured_capacity_ = false;
+ fixups_processed_ = false;
+#endif
+
+ // Verify internal state.
+ CHECK_EQ(Capacity(), kInitialBufferCapacity);
+ CHECK_EQ(Size(), 0);
+}
+
+
+AssemblerBuffer::~AssemblerBuffer() {
+}
+
+
+void AssemblerBuffer::ProcessFixups(const MemoryRegion& region) {
+ AssemblerFixup* fixup = fixup_;
+ while (fixup != NULL) {
+ fixup->Process(region, fixup->position());
+ fixup = fixup->previous();
+ }
+}
+
+
+void AssemblerBuffer::FinalizeInstructions(const MemoryRegion& instructions) {
+ // Copy the instructions from the buffer.
+ MemoryRegion from(reinterpret_cast<void*>(contents()), Size());
+ instructions.CopyFrom(0, from);
+
+ // Process fixups in the instructions.
+ ProcessFixups(instructions);
+#if defined(DEBUG)
+ fixups_processed_ = true;
+#endif
+}
+
+
+void AssemblerBuffer::ExtendCapacity() {
+ size_t old_size = Size();
+ size_t old_capacity = Capacity();
+ size_t new_capacity = std::min(old_capacity * 2, old_capacity + 1 * MB);
+
+ // Allocate the new data area and copy contents of the old one to it.
+ byte* new_contents = NewContents(new_capacity);
+ memmove(reinterpret_cast<void*>(new_contents),
+ reinterpret_cast<void*>(contents_),
+ old_size);
+
+ // Compute the relocation delta and switch to the new contents area.
+ ptrdiff_t delta = new_contents - contents_;
+ contents_ = new_contents;
+
+ // Update the cursor and recompute the limit.
+ cursor_ += delta;
+ limit_ = ComputeLimit(new_contents, new_capacity);
+
+ // Verify internal state.
+ CHECK_EQ(Capacity(), new_capacity);
+ CHECK_EQ(Size(), old_size);
+}
+
+
+#if 0
+// Shared macros are implemented here.
+void Assembler::Unimplemented(const char* message) {
+ Stop("unimplemented");
+}
+
+
+void Assembler::Untested(const char* message) {
+ Stop("untested");
+}
+
+
+void Assembler::Unreachable(const char* message) {
+ Stop("unreachable");
+}
+#endif
+
+} } // namespace android::runtime
diff --git a/src/assembler.h b/src/assembler.h
new file mode 100644
index 0000000..d211b6f
--- /dev/null
+++ b/src/assembler.h
@@ -0,0 +1,238 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_ASSEMBLER_H_
+#define ART_SRC_ASSEMBLER_H_
+
+#include "src/logging.h"
+#include "src/macros.h"
+#include "src/memory_region.h"
+
+namespace android {
+namespace runtime {
+
+class Assembler;
+class AssemblerBuffer;
+class AssemblerFixup;
+
+
+class Label {
+ public:
+ Label() : position_(0) {}
+
+ ~Label() {
+ // Assert if label is being destroyed with unresolved branches pending.
+ CHECK(!IsLinked());
+ }
+
+ // Returns the position for bound and linked labels. Cannot be used
+ // for unused labels.
+ int Position() const {
+ CHECK(!IsUnused());
+ return IsBound() ? -position_ - kPointerSize : position_ - kPointerSize;
+ }
+
+ int LinkPosition() const {
+ CHECK(IsLinked());
+ return position_ - kWordSize;
+ }
+
+ bool IsBound() const { return position_ < 0; }
+ bool IsUnused() const { return position_ == 0; }
+ bool IsLinked() const { return position_ > 0; }
+
+ private:
+ int position_;
+
+ void Reinitialize() {
+ position_ = 0;
+ }
+
+ void BindTo(int position) {
+ CHECK(!IsBound());
+ position_ = -position - kPointerSize;
+ CHECK(IsBound());
+ }
+
+ void LinkTo(int position) {
+ CHECK(!IsBound());
+ position_ = position + kPointerSize;
+ CHECK(IsLinked());
+ }
+
+ friend class Assembler;
+ DISALLOW_COPY_AND_ASSIGN(Label);
+};
+
+
+// Assembler fixups are positions in generated code that require processing
+// after the code has been copied to executable memory. This includes building
+// relocation information.
+class AssemblerFixup {
+ public:
+ virtual void Process(const MemoryRegion& region, int position) = 0;
+ virtual ~AssemblerFixup() {}
+
+ private:
+ AssemblerFixup* previous_;
+ int position_;
+
+ AssemblerFixup* previous() const { return previous_; }
+ void set_previous(AssemblerFixup* previous) { previous_ = previous; }
+
+ int position() const { return position_; }
+ void set_position(int position) { position_ = position; }
+
+ friend class AssemblerBuffer;
+};
+
+
+class AssemblerBuffer {
+ public:
+ AssemblerBuffer();
+ ~AssemblerBuffer();
+
+ // Basic support for emitting, loading, and storing.
+ template<typename T> void Emit(T value) {
+ CHECK(HasEnsuredCapacity());
+ *reinterpret_cast<T*>(cursor_) = value;
+ cursor_ += sizeof(T);
+ }
+
+ template<typename T> T Load(size_t position) {
+ CHECK_LE(position, Size() - static_cast<int>(sizeof(T)));
+ return *reinterpret_cast<T*>(contents_ + position);
+ }
+
+ template<typename T> void Store(size_t position, T value) {
+ CHECK_LE(position, Size() - static_cast<int>(sizeof(T)));
+ *reinterpret_cast<T*>(contents_ + position) = value;
+ }
+
+ // Emit a fixup at the current location.
+ void EmitFixup(AssemblerFixup* fixup) {
+ fixup->set_previous(fixup_);
+ fixup->set_position(Size());
+ fixup_ = fixup;
+ }
+
+ // Get the size of the emitted code.
+ size_t Size() const {
+ CHECK_GE(cursor_, contents_);
+ return cursor_ - contents_;
+ }
+
+ byte* contents() const { return contents_; }
+
+ // Copy the assembled instructions into the specified memory block
+ // and apply all fixups.
+ void FinalizeInstructions(const MemoryRegion& region);
+
+ // To emit an instruction to the assembler buffer, the EnsureCapacity helper
+ // must be used to guarantee that the underlying data area is big enough to
+ // hold the emitted instruction. Usage:
+ //
+ // AssemblerBuffer buffer;
+ // AssemblerBuffer::EnsureCapacity ensured(&buffer);
+ // ... emit bytes for single instruction ...
+
+#ifdef DEBUG
+
+ class EnsureCapacity {
+ public:
+ explicit EnsureCapacity(AssemblerBuffer* buffer) {
+ if (buffer->cursor() >= buffer->limit()) buffer->ExtendCapacity();
+ // In debug mode, we save the assembler buffer along with the gap
+ // size before we start emitting to the buffer. This allows us to
+ // check that any single generated instruction doesn't overflow the
+ // limit implied by the minimum gap size.
+ buffer_ = buffer;
+ gap_ = ComputeGap();
+ // Make sure that extending the capacity leaves a big enough gap
+ // for any kind of instruction.
+ CHECK_GE(gap_, kMinimumGap);
+ // Mark the buffer as having ensured the capacity.
+ CHECK(!buffer->HasEnsuredCapacity()); // Cannot nest.
+ buffer->has_ensured_capacity_ = true;
+ }
+
+ ~EnsureCapacity() {
+ // Unmark the buffer, so we cannot emit after this.
+ buffer_->has_ensured_capacity_ = false;
+ // Make sure the generated instruction doesn't take up more
+ // space than the minimum gap.
+ int delta = gap_ - ComputeGap();
+ CHECK(delta <= kMinimumGap);
+ }
+
+ private:
+ AssemblerBuffer* buffer_;
+ int gap_;
+
+ int ComputeGap() { return buffer_->Capacity() - buffer_->Size(); }
+ };
+
+ bool has_ensured_capacity_;
+ bool HasEnsuredCapacity() const { return has_ensured_capacity_; }
+
+#else
+
+ class EnsureCapacity {
+ public:
+ explicit EnsureCapacity(AssemblerBuffer* buffer) {
+ if (buffer->cursor() >= buffer->limit()) buffer->ExtendCapacity();
+ }
+ };
+
+ // When building the C++ tests, assertion code is enabled. To allow
+ // asserting that the user of the assembler buffer has ensured the
+ // capacity needed for emitting, we add a dummy method in non-debug mode.
+ bool HasEnsuredCapacity() const { return true; }
+
+#endif
+
+ // Returns the position in the instruction stream.
+ int GetPosition() { return cursor_ - contents_; }
+
+ private:
+ // The limit is set to kMinimumGap bytes before the end of the data area.
+ // This leaves enough space for the longest possible instruction and allows
+ // for a single, fast space check per instruction.
+ static const int kMinimumGap = 32;
+
+ byte* contents_;
+ byte* cursor_;
+ byte* limit_;
+ AssemblerFixup* fixup_;
+ bool fixups_processed_;
+
+ byte* cursor() const { return cursor_; }
+ byte* limit() const { return limit_; }
+ size_t Capacity() const {
+ CHECK_GE(limit_, contents_);
+ return (limit_ - contents_) + kMinimumGap;
+ }
+
+ // Process the fixup chain starting at the given fixup. The offset is
+ // non-zero for fixups in the body if the preamble is non-empty.
+ void ProcessFixups(const MemoryRegion& region);
+
+ // Compute the limit based on the data area and the capacity. See
+ // description of kMinimumGap for the reasoning behind the value.
+ static byte* ComputeLimit(byte* data, size_t capacity) {
+ return data + capacity - kMinimumGap;
+ }
+
+ void ExtendCapacity();
+
+ friend class AssemblerFixup;
+};
+
+} } // namespace android::runtime
+
+#if defined(__i386__)
+#include "src/assembler_x86.h"
+#elif defined(__arm__)
+#include "src/assembler_arm.h"
+#endif
+
+#endif // ART_SRC_ASSEMBLER_H_
diff --git a/src/assembler_arm.cc b/src/assembler_arm.cc
new file mode 100644
index 0000000..79b89c3
--- /dev/null
+++ b/src/assembler_arm.cc
@@ -0,0 +1,8 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "src/assembler.h"
+
+namespace android {
+namespace runtime {
+
+} } // namespace android::runtime
diff --git a/src/assembler_arm.h b/src/assembler_arm.h
new file mode 100644
index 0000000..1ac5a82
--- /dev/null
+++ b/src/assembler_arm.h
@@ -0,0 +1,14 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_ASSEMBLER_ARM_H_
+#define ART_SRC_ASSEMBLER_ARM_H_
+
+namespace android {
+namespace runtime {
+
+class Assembler {
+};
+
+} } // namespace android::runtime
+
+#endif // ART_SRC_ASSEMBLER_ARM_H_
diff --git a/src/assembler_x86.cc b/src/assembler_x86.cc
new file mode 100644
index 0000000..de2219c
--- /dev/null
+++ b/src/assembler_x86.cc
@@ -0,0 +1,1350 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include <string.h>
+#include "src/assembler.h"
+#include "src/casts.h"
+#include "src/globals.h"
+#include "src/assembler.h"
+#include "src/memory_region.h"
+
+namespace android {
+namespace runtime {
+
+class DirectCallRelocation : public AssemblerFixup {
+ public:
+ void Process(const MemoryRegion& region, int position) {
+ // Direct calls are relative to the following instruction on x86.
+ int32_t pointer = region.Load<int32_t>(position);
+ int32_t start = reinterpret_cast<int32_t>(region.start());
+ int32_t delta = start + position + sizeof(int32_t);
+ region.Store<int32_t>(position, pointer - delta);
+ }
+};
+
+
+void Assembler::InitializeMemoryWithBreakpoints(byte* data, size_t length) {
+ memset(reinterpret_cast<void*>(data), Instr::kBreakPointInstruction, length);
+}
+
+
+void Assembler::call(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xFF);
+ EmitRegisterOperand(2, reg);
+}
+
+
+void Assembler::call(const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xFF);
+ EmitOperand(2, address);
+}
+
+
+void Assembler::call(Label* label) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xE8);
+ static const int kSize = 5;
+ EmitLabel(label, kSize);
+}
+
+
+void Assembler::pushl(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x50 + reg);
+}
+
+
+void Assembler::pushl(const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xFF);
+ EmitOperand(6, address);
+}
+
+
+void Assembler::pushl(const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x68);
+ EmitImmediate(imm);
+}
+
+
+void Assembler::popl(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x58 + reg);
+}
+
+
+void Assembler::popl(const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x8F);
+ EmitOperand(0, address);
+}
+
+
+void Assembler::movl(Register dst, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xB8 + dst);
+ EmitImmediate(imm);
+}
+
+
+void Assembler::movl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x89);
+ EmitRegisterOperand(src, dst);
+}
+
+
+void Assembler::movl(Register dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x8B);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::movl(const Address& dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x89);
+ EmitOperand(src, dst);
+}
+
+
+void Assembler::movl(const Address& dst, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xC7);
+ EmitOperand(0, dst);
+ EmitImmediate(imm);
+}
+
+
+void Assembler::movzxb(Register dst, ByteRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xB6);
+ EmitRegisterOperand(dst, src);
+}
+
+
+void Assembler::movzxb(Register dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xB6);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::movsxb(Register dst, ByteRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xBE);
+ EmitRegisterOperand(dst, src);
+}
+
+
+void Assembler::movsxb(Register dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xBE);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::movb(Register dst, const Address& src) {
+ LOG(FATAL) << "Use movzxb or movsxb instead.";
+}
+
+
+void Assembler::movb(const Address& dst, ByteRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x88);
+ EmitOperand(src, dst);
+}
+
+
+void Assembler::movb(const Address& dst, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xC6);
+ EmitOperand(EAX, dst);
+ CHECK(imm.is_int8());
+ EmitUint8(imm.value() & 0xFF);
+}
+
+
+void Assembler::movzxw(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xB7);
+ EmitRegisterOperand(dst, src);
+}
+
+
+void Assembler::movzxw(Register dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xB7);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::movsxw(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xBF);
+ EmitRegisterOperand(dst, src);
+}
+
+
+void Assembler::movsxw(Register dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xBF);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::movw(Register dst, const Address& src) {
+ LOG(FATAL) << "Use movzxw or movsxw instead.";
+}
+
+
+void Assembler::movw(const Address& dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitOperandSizeOverride();
+ EmitUint8(0x89);
+ EmitOperand(src, dst);
+}
+
+
+void Assembler::leal(Register dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x8D);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::cmovs(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x48);
+ EmitRegisterOperand(dst, src);
+}
+
+
+void Assembler::cmovns(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x49);
+ EmitRegisterOperand(dst, src);
+}
+
+
+void Assembler::movss(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x10);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::movss(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitOperand(src, dst);
+}
+
+
+void Assembler::movss(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitXmmRegisterOperand(src, dst);
+}
+
+
+void Assembler::movd(XmmRegister dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x6E);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::movd(Register dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x7E);
+ EmitOperand(src, Operand(dst));
+}
+
+
+void Assembler::addss(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::addss(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::subss(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::subss(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::mulss(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::mulss(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::divss(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::divss(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::flds(const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xD9);
+ EmitOperand(0, src);
+}
+
+
+void Assembler::fstps(const Address& dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xD9);
+ EmitOperand(3, dst);
+}
+
+
+void Assembler::movsd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x10);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::movsd(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitOperand(src, dst);
+}
+
+
+void Assembler::movsd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitXmmRegisterOperand(src, dst);
+}
+
+
+void Assembler::addsd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::addsd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::subsd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::subsd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::mulsd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::mulsd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::divsd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::divsd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::cvtsi2ss(XmmRegister dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x2A);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::cvtsi2sd(XmmRegister dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x2A);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::cvtss2si(Register dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x2D);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::cvtss2sd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x5A);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::cvtsd2si(Register dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x2D);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::cvttss2si(Register dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x2C);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::cvttsd2si(Register dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x2C);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::cvtsd2ss(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x5A);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::cvtdq2pd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0xE6);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::comiss(XmmRegister a, XmmRegister b) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x2F);
+ EmitXmmRegisterOperand(a, b);
+}
+
+
+void Assembler::comisd(XmmRegister a, XmmRegister b) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x2F);
+ EmitXmmRegisterOperand(a, b);
+}
+
+
+void Assembler::sqrtsd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF2);
+ EmitUint8(0x0F);
+ EmitUint8(0x51);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::sqrtss(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF3);
+ EmitUint8(0x0F);
+ EmitUint8(0x51);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::xorpd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x57);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::xorpd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x57);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::xorps(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x57);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::xorps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x57);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::andpd(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x54);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::fldl(const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xDD);
+ EmitOperand(0, src);
+}
+
+
+void Assembler::fstpl(const Address& dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xDD);
+ EmitOperand(3, dst);
+}
+
+
+void Assembler::fnstcw(const Address& dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xD9);
+ EmitOperand(7, dst);
+}
+
+
+void Assembler::fldcw(const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xD9);
+ EmitOperand(5, src);
+}
+
+
+void Assembler::fistpl(const Address& dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xDF);
+ EmitOperand(7, dst);
+}
+
+
+void Assembler::fistps(const Address& dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xDB);
+ EmitOperand(3, dst);
+}
+
+
+void Assembler::fildl(const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xDF);
+ EmitOperand(5, src);
+}
+
+
+void Assembler::fincstp() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xD9);
+ EmitUint8(0xF7);
+}
+
+
+void Assembler::ffree(const Immediate& index) {
+ CHECK_LT(index.value(), 7);
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xDD);
+ EmitUint8(0xC0 + index.value());
+}
+
+
+void Assembler::fsin() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xD9);
+ EmitUint8(0xFE);
+}
+
+
+void Assembler::fcos() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xD9);
+ EmitUint8(0xFF);
+}
+
+
+void Assembler::fptan() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xD9);
+ EmitUint8(0xF2);
+}
+
+
+void Assembler::xchgl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x87);
+ EmitRegisterOperand(dst, src);
+}
+
+
+void Assembler::cmpl(Register reg, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitComplex(7, Operand(reg), imm);
+}
+
+
+void Assembler::cmpl(Register reg0, Register reg1) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x3B);
+ EmitOperand(reg0, Operand(reg1));
+}
+
+
+void Assembler::cmpl(Register reg, const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x3B);
+ EmitOperand(reg, address);
+}
+
+
+void Assembler::addl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x03);
+ EmitRegisterOperand(dst, src);
+}
+
+
+void Assembler::addl(Register reg, const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x03);
+ EmitOperand(reg, address);
+}
+
+
+void Assembler::cmpl(const Address& address, Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x39);
+ EmitOperand(reg, address);
+}
+
+
+void Assembler::cmpl(const Address& address, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitComplex(7, address, imm);
+}
+
+
+void Assembler::testl(Register reg1, Register reg2) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x85);
+ EmitRegisterOperand(reg1, reg2);
+}
+
+
+void Assembler::testl(Register reg, const Immediate& immediate) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ // For registers that have a byte variant (EAX, EBX, ECX, and EDX)
+ // we only test the byte register to keep the encoding short.
+ if (immediate.is_uint8() && reg < 4) {
+ // Use zero-extended 8-bit immediate.
+ if (reg == EAX) {
+ EmitUint8(0xA8);
+ } else {
+ EmitUint8(0xF6);
+ EmitUint8(0xC0 + reg);
+ }
+ EmitUint8(immediate.value() & 0xFF);
+ } else if (reg == EAX) {
+ // Use short form if the destination is EAX.
+ EmitUint8(0xA9);
+ EmitImmediate(immediate);
+ } else {
+ EmitUint8(0xF7);
+ EmitOperand(0, Operand(reg));
+ EmitImmediate(immediate);
+ }
+}
+
+
+void Assembler::andl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x23);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::andl(Register dst, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitComplex(4, Operand(dst), imm);
+}
+
+
+void Assembler::orl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0B);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::orl(Register dst, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitComplex(1, Operand(dst), imm);
+}
+
+
+void Assembler::xorl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x33);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::addl(Register reg, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitComplex(0, Operand(reg), imm);
+}
+
+
+void Assembler::addl(const Address& address, Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x01);
+ EmitOperand(reg, address);
+}
+
+
+void Assembler::addl(const Address& address, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitComplex(0, address, imm);
+}
+
+
+void Assembler::adcl(Register reg, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitComplex(2, Operand(reg), imm);
+}
+
+
+void Assembler::adcl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x13);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::adcl(Register dst, const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x13);
+ EmitOperand(dst, address);
+}
+
+
+void Assembler::subl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x2B);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::subl(Register reg, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitComplex(5, Operand(reg), imm);
+}
+
+
+void Assembler::subl(Register reg, const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x2B);
+ EmitOperand(reg, address);
+}
+
+
+void Assembler::cdq() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x99);
+}
+
+
+void Assembler::idivl(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF7);
+ EmitUint8(0xF8 | reg);
+}
+
+
+void Assembler::imull(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xAF);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::imull(Register reg, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x69);
+ EmitOperand(reg, Operand(reg));
+ EmitImmediate(imm);
+}
+
+
+void Assembler::imull(Register reg, const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xAF);
+ EmitOperand(reg, address);
+}
+
+
+void Assembler::imull(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF7);
+ EmitOperand(5, Operand(reg));
+}
+
+
+void Assembler::imull(const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF7);
+ EmitOperand(5, address);
+}
+
+
+void Assembler::mull(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF7);
+ EmitOperand(4, Operand(reg));
+}
+
+
+void Assembler::mull(const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF7);
+ EmitOperand(4, address);
+}
+
+
+void Assembler::sbbl(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x1B);
+ EmitOperand(dst, Operand(src));
+}
+
+
+void Assembler::sbbl(Register reg, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitComplex(3, Operand(reg), imm);
+}
+
+
+void Assembler::sbbl(Register dst, const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x1B);
+ EmitOperand(dst, address);
+}
+
+
+void Assembler::incl(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x40 + reg);
+}
+
+
+void Assembler::incl(const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xFF);
+ EmitOperand(0, address);
+}
+
+
+void Assembler::decl(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x48 + reg);
+}
+
+
+void Assembler::decl(const Address& address) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xFF);
+ EmitOperand(1, address);
+}
+
+
+void Assembler::shll(Register reg, const Immediate& imm) {
+ EmitGenericShift(4, reg, imm);
+}
+
+
+void Assembler::shll(Register operand, Register shifter) {
+ EmitGenericShift(4, operand, shifter);
+}
+
+
+void Assembler::shrl(Register reg, const Immediate& imm) {
+ EmitGenericShift(5, reg, imm);
+}
+
+
+void Assembler::shrl(Register operand, Register shifter) {
+ EmitGenericShift(5, operand, shifter);
+}
+
+
+void Assembler::sarl(Register reg, const Immediate& imm) {
+ EmitGenericShift(7, reg, imm);
+}
+
+
+void Assembler::sarl(Register operand, Register shifter) {
+ EmitGenericShift(7, operand, shifter);
+}
+
+
+void Assembler::shld(Register dst, Register src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xA5);
+ EmitRegisterOperand(src, dst);
+}
+
+
+void Assembler::negl(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF7);
+ EmitOperand(3, Operand(reg));
+}
+
+
+void Assembler::notl(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF7);
+ EmitUint8(0xD0 | reg);
+}
+
+
+void Assembler::enter(const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xC8);
+ CHECK(imm.is_uint16());
+ EmitUint8(imm.value() & 0xFF);
+ EmitUint8((imm.value() >> 8) & 0xFF);
+ EmitUint8(0x00);
+}
+
+
+void Assembler::leave() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xC9);
+}
+
+
+void Assembler::ret() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xC3);
+}
+
+
+void Assembler::ret(const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xC2);
+ CHECK(imm.is_uint16());
+ EmitUint8(imm.value() & 0xFF);
+ EmitUint8((imm.value() >> 8) & 0xFF);
+}
+
+
+
+void Assembler::nop() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x90);
+}
+
+
+void Assembler::int3() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xCC);
+}
+
+
+void Assembler::hlt() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF4);
+}
+
+
+void Assembler::j(Condition condition, Label* label) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ if (label->IsBound()) {
+ static const int kShortSize = 2;
+ static const int kLongSize = 6;
+ int offset = label->Position() - buffer_.Size();
+ CHECK_LE(offset, 0);
+ if (IsInt(8, offset - kShortSize)) {
+ EmitUint8(0x70 + condition);
+ EmitUint8((offset - kShortSize) & 0xFF);
+ } else {
+ EmitUint8(0x0F);
+ EmitUint8(0x80 + condition);
+ EmitInt32(offset - kLongSize);
+ }
+ } else {
+ EmitUint8(0x0F);
+ EmitUint8(0x80 + condition);
+ EmitLabelLink(label);
+ }
+}
+
+
+void Assembler::jmp(Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xFF);
+ EmitRegisterOperand(4, reg);
+}
+
+
+void Assembler::jmp(Label* label) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ if (label->IsBound()) {
+ static const int kShortSize = 2;
+ static const int kLongSize = 5;
+ int offset = label->Position() - buffer_.Size();
+ CHECK_LE(offset, 0);
+ if (IsInt(8, offset - kShortSize)) {
+ EmitUint8(0xEB);
+ EmitUint8((offset - kShortSize) & 0xFF);
+ } else {
+ EmitUint8(0xE9);
+ EmitInt32(offset - kLongSize);
+ }
+ } else {
+ EmitUint8(0xE9);
+ EmitLabelLink(label);
+ }
+}
+
+
+void Assembler::lock() {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0xF0);
+}
+
+
+void Assembler::cmpxchgl(const Address& address, Register reg) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xB1);
+ EmitOperand(reg, address);
+}
+
+
+void Assembler::AddImmediate(Register reg, const Immediate& imm) {
+ int value = imm.value();
+ if (value > 0) {
+ if (value == 1) {
+ incl(reg);
+ } else if (value != 0) {
+ addl(reg, imm);
+ }
+ } else if (value < 0) {
+ value = -value;
+ if (value == 1) {
+ decl(reg);
+ } else if (value != 0) {
+ subl(reg, Immediate(value));
+ }
+ }
+}
+
+
+void Assembler::LoadDoubleConstant(XmmRegister dst, double value) {
+ // TODO: Need to have a code constants table.
+ int64_t constant = bit_cast<int64_t, double>(value);
+ pushl(Immediate(High32Bits(constant)));
+ pushl(Immediate(Low32Bits(constant)));
+ movsd(dst, Address(ESP, 0));
+ addl(ESP, Immediate(2 * kWordSize));
+}
+
+
+void Assembler::FloatNegate(XmmRegister f) {
+ static const struct {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } float_negate_constant __attribute__((aligned(16))) =
+ { 0x80000000, 0x00000000, 0x80000000, 0x00000000 };
+ xorps(f, Address::Absolute(reinterpret_cast<uword>(&float_negate_constant)));
+}
+
+
+void Assembler::DoubleNegate(XmmRegister d) {
+ static const struct {
+ uint64_t a;
+ uint64_t b;
+ } double_negate_constant __attribute__((aligned(16))) =
+ {0x8000000000000000LL, 0x8000000000000000LL};
+ xorpd(d, Address::Absolute(reinterpret_cast<uword>(&double_negate_constant)));
+}
+
+
+void Assembler::DoubleAbs(XmmRegister reg) {
+ static const struct {
+ uint64_t a;
+ uint64_t b;
+ } double_abs_constant __attribute__((aligned(16))) =
+ {0x7FFFFFFFFFFFFFFFLL, 0x7FFFFFFFFFFFFFFFLL};
+ andpd(reg, Address::Absolute(reinterpret_cast<uword>(&double_abs_constant)));
+}
+
+
+void Assembler::Align(int alignment, int offset) {
+ CHECK(IsPowerOfTwo(alignment));
+ // Emit nop instruction until the real position is aligned.
+ while (((offset + buffer_.GetPosition()) & (alignment-1)) != 0) {
+ nop();
+ }
+}
+
+
+void Assembler::Bind(Label* label) {
+ int bound = buffer_.Size();
+ CHECK(!label->IsBound()); // Labels can only be bound once.
+ while (label->IsLinked()) {
+ int position = label->LinkPosition();
+ int next = buffer_.Load<int32_t>(position);
+ buffer_.Store<int32_t>(position, bound - (position + 4));
+ label->position_ = next;
+ }
+ label->BindTo(bound);
+}
+
+
+void Assembler::Stop(const char* message) {
+ // Emit the message address as immediate operand in the test rax instruction,
+ // followed by the int3 instruction.
+ // Execution can be resumed with the 'cont' command in gdb.
+ testl(EAX, Immediate(reinterpret_cast<int32_t>(message)));
+ int3();
+}
+
+
+void Assembler::EmitOperand(int rm, const Operand& operand) {
+ CHECK_GE(rm, 0);
+ CHECK_LT(rm, 8);
+ const int length = operand.length_;
+ CHECK_GT(length, 0);
+ // Emit the ModRM byte updated with the given RM value.
+ CHECK_EQ(operand.encoding_[0] & 0x38, 0);
+ EmitUint8(operand.encoding_[0] + (rm << 3));
+ // Emit the rest of the encoded operand.
+ for (int i = 1; i < length; i++) {
+ EmitUint8(operand.encoding_[i]);
+ }
+}
+
+
+void Assembler::EmitImmediate(const Immediate& imm) {
+ EmitInt32(imm.value());
+}
+
+
+void Assembler::EmitComplex(int rm,
+ const Operand& operand,
+ const Immediate& immediate) {
+ CHECK_GE(rm, 0);
+ CHECK_LT(rm, 8);
+ if (immediate.is_int8()) {
+ // Use sign-extended 8-bit immediate.
+ EmitUint8(0x83);
+ EmitOperand(rm, operand);
+ EmitUint8(immediate.value() & 0xFF);
+ } else if (operand.IsRegister(EAX)) {
+ // Use short form if the destination is eax.
+ EmitUint8(0x05 + (rm << 3));
+ EmitImmediate(immediate);
+ } else {
+ EmitUint8(0x81);
+ EmitOperand(rm, operand);
+ EmitImmediate(immediate);
+ }
+}
+
+
+void Assembler::EmitLabel(Label* label, int instruction_size) {
+ if (label->IsBound()) {
+ int offset = label->Position() - buffer_.Size();
+ CHECK_LE(offset, 0);
+ EmitInt32(offset - instruction_size);
+ } else {
+ EmitLabelLink(label);
+ }
+}
+
+
+void Assembler::EmitLabelLink(Label* label) {
+ CHECK(!label->IsBound());
+ int position = buffer_.Size();
+ EmitInt32(label->position_);
+ label->LinkTo(position);
+}
+
+
+void Assembler::EmitGenericShift(int rm,
+ Register reg,
+ const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ CHECK(imm.is_int8());
+ if (imm.value() == 1) {
+ EmitUint8(0xD1);
+ EmitOperand(rm, Operand(reg));
+ } else {
+ EmitUint8(0xC1);
+ EmitOperand(rm, Operand(reg));
+ EmitUint8(imm.value() & 0xFF);
+ }
+}
+
+
+void Assembler::EmitGenericShift(int rm,
+ Register operand,
+ Register shifter) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ CHECK_EQ(shifter, ECX);
+ EmitUint8(0xD3);
+ EmitOperand(rm, Operand(operand));
+}
+
+} } // namespace android::runtime
diff --git a/src/assembler_x86.h b/src/assembler_x86.h
new file mode 100644
index 0000000..05dfe31
--- /dev/null
+++ b/src/assembler_x86.h
@@ -0,0 +1,479 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_ASSEMBLER_X86_H_
+#define ART_SRC_ASSEMBLER_X86_H_
+
+#include <stdint.h>
+#include <string.h>
+#include "src/constants_x86.h"
+#include "src/macros.h"
+#include "src/utils.h"
+
+namespace android {
+namespace runtime {
+
+class Immediate {
+ public:
+ explicit Immediate(int32_t value) : value_(value) {}
+
+ int32_t value() const { return value_; }
+
+ bool is_int8() const { return IsInt(8, value_); }
+ bool is_uint8() const { return IsUint(8, value_); }
+ bool is_uint16() const { return IsUint(16, value_); }
+
+ private:
+ const int32_t value_;
+
+ DISALLOW_COPY_AND_ASSIGN(Immediate);
+};
+
+
+class Operand {
+ public:
+ uint8_t mod() const {
+ return (encoding_at(0) >> 6) & 3;
+ }
+
+ Register rm() const {
+ return static_cast<Register>(encoding_at(0) & 7);
+ }
+
+ ScaleFactor scale() const {
+ return static_cast<ScaleFactor>((encoding_at(1) >> 6) & 3);
+ }
+
+ Register index() const {
+ return static_cast<Register>((encoding_at(1) >> 3) & 7);
+ }
+
+ Register base() const {
+ return static_cast<Register>(encoding_at(1) & 7);
+ }
+
+ int8_t disp8() const {
+ CHECK_GE(length_, 2);
+ return static_cast<int8_t>(encoding_[length_ - 1]);
+ }
+
+ int32_t disp32() const {
+ CHECK_GE(length_, 5);
+ int32_t value;
+ memcpy(&value, &encoding_[length_ - 4], sizeof(value));
+ return value;
+ }
+
+ bool IsRegister(Register reg) const {
+ return ((encoding_[0] & 0xF8) == 0xC0) // Addressing mode is register only.
+ && ((encoding_[0] & 0x07) == reg); // Register codes match.
+ }
+
+ protected:
+ // Operand can be sub classed (e.g: Address).
+ Operand() : length_(0) { }
+
+ void SetModRM(int mod, Register rm) {
+ CHECK_EQ(mod & ~3, 0);
+ encoding_[0] = (mod << 6) | rm;
+ length_ = 1;
+ }
+
+ void SetSIB(ScaleFactor scale, Register index, Register base) {
+ CHECK_EQ(length_, 1);
+ CHECK_EQ(scale & ~3, 0);
+ encoding_[1] = (scale << 6) | (index << 3) | base;
+ length_ = 2;
+ }
+
+ void SetDisp8(int8_t disp) {
+ CHECK(length_ == 1 || length_ == 2);
+ encoding_[length_++] = static_cast<uint8_t>(disp);
+ }
+
+ void SetDisp32(int32_t disp) {
+ CHECK(length_ == 1 || length_ == 2);
+ int disp_size = sizeof(disp);
+ memmove(&encoding_[length_], &disp, disp_size);
+ length_ += disp_size;
+ }
+
+ private:
+ byte length_;
+ byte encoding_[6];
+ byte padding_;
+
+ explicit Operand(Register reg) { SetModRM(3, reg); }
+
+ // Get the operand encoding byte at the given index.
+ uint8_t encoding_at(int index) const {
+ CHECK_GE(index, 0);
+ CHECK_LT(index, length_);
+ return encoding_[index];
+ }
+
+ friend class Assembler;
+
+ DISALLOW_COPY_AND_ASSIGN(Operand);
+};
+
+
+class Address : public Operand {
+ public:
+ Address(Register base, int32_t disp) {
+ if (disp == 0 && base != EBP) {
+ SetModRM(0, base);
+ if (base == ESP) SetSIB(TIMES_1, ESP, base);
+ } else if (disp >= -128 && disp <= 127) {
+ SetModRM(1, base);
+ if (base == ESP) SetSIB(TIMES_1, ESP, base);
+ SetDisp8(disp);
+ } else {
+ SetModRM(2, base);
+ if (base == ESP) SetSIB(TIMES_1, ESP, base);
+ SetDisp32(disp);
+ }
+ }
+
+ Address(Register index, ScaleFactor scale, int32_t disp) {
+ CHECK_NE(index, ESP); // Illegal addressing mode.
+ SetModRM(0, ESP);
+ SetSIB(scale, index, EBP);
+ SetDisp32(disp);
+ }
+
+ Address(Register base, Register index, ScaleFactor scale, int32_t disp) {
+ CHECK_NE(index, ESP); // Illegal addressing mode.
+ if (disp == 0 && base != EBP) {
+ SetModRM(0, ESP);
+ SetSIB(scale, index, base);
+ } else if (disp >= -128 && disp <= 127) {
+ SetModRM(1, ESP);
+ SetSIB(scale, index, base);
+ SetDisp8(disp);
+ } else {
+ SetModRM(2, ESP);
+ SetSIB(scale, index, base);
+ SetDisp32(disp);
+ }
+ }
+
+ static Address Absolute(const uword addr) {
+ Address result;
+ result.SetModRM(0, EBP);
+ result.SetDisp32(addr);
+ return result;
+ }
+
+ private:
+ Address() {}
+
+ DISALLOW_COPY_AND_ASSIGN(Address);
+};
+
+
+class Assembler {
+ public:
+ Assembler() : buffer_() {}
+ ~Assembler() {}
+
+ /*
+ * Emit Machine Instructions.
+ */
+ void call(Register reg);
+ void call(const Address& address);
+ void call(Label* label);
+
+ void pushl(Register reg);
+ void pushl(const Address& address);
+ void pushl(const Immediate& imm);
+
+ void popl(Register reg);
+ void popl(const Address& address);
+
+ void movl(Register dst, const Immediate& src);
+ void movl(Register dst, Register src);
+
+ void movl(Register dst, const Address& src);
+ void movl(const Address& dst, Register src);
+ void movl(const Address& dst, const Immediate& imm);
+
+ void movzxb(Register dst, ByteRegister src);
+ void movzxb(Register dst, const Address& src);
+ void movsxb(Register dst, ByteRegister src);
+ void movsxb(Register dst, const Address& src);
+ void movb(Register dst, const Address& src);
+ void movb(const Address& dst, ByteRegister src);
+ void movb(const Address& dst, const Immediate& imm);
+
+ void movzxw(Register dst, Register src);
+ void movzxw(Register dst, const Address& src);
+ void movsxw(Register dst, Register src);
+ void movsxw(Register dst, const Address& src);
+ void movw(Register dst, const Address& src);
+ void movw(const Address& dst, Register src);
+
+ void leal(Register dst, const Address& src);
+
+ void cmovs(Register dst, Register src);
+ void cmovns(Register dst, Register src);
+
+ void movss(XmmRegister dst, const Address& src);
+ void movss(const Address& dst, XmmRegister src);
+ void movss(XmmRegister dst, XmmRegister src);
+
+ void movd(XmmRegister dst, Register src);
+ void movd(Register dst, XmmRegister src);
+
+ void addss(XmmRegister dst, XmmRegister src);
+ void addss(XmmRegister dst, const Address& src);
+ void subss(XmmRegister dst, XmmRegister src);
+ void subss(XmmRegister dst, const Address& src);
+ void mulss(XmmRegister dst, XmmRegister src);
+ void mulss(XmmRegister dst, const Address& src);
+ void divss(XmmRegister dst, XmmRegister src);
+ void divss(XmmRegister dst, const Address& src);
+
+ void movsd(XmmRegister dst, const Address& src);
+ void movsd(const Address& dst, XmmRegister src);
+ void movsd(XmmRegister dst, XmmRegister src);
+
+ void addsd(XmmRegister dst, XmmRegister src);
+ void addsd(XmmRegister dst, const Address& src);
+ void subsd(XmmRegister dst, XmmRegister src);
+ void subsd(XmmRegister dst, const Address& src);
+ void mulsd(XmmRegister dst, XmmRegister src);
+ void mulsd(XmmRegister dst, const Address& src);
+ void divsd(XmmRegister dst, XmmRegister src);
+ void divsd(XmmRegister dst, const Address& src);
+
+ void cvtsi2ss(XmmRegister dst, Register src);
+ void cvtsi2sd(XmmRegister dst, Register src);
+
+ void cvtss2si(Register dst, XmmRegister src);
+ void cvtss2sd(XmmRegister dst, XmmRegister src);
+
+ void cvtsd2si(Register dst, XmmRegister src);
+ void cvtsd2ss(XmmRegister dst, XmmRegister src);
+
+ void cvttss2si(Register dst, XmmRegister src);
+ void cvttsd2si(Register dst, XmmRegister src);
+
+ void cvtdq2pd(XmmRegister dst, XmmRegister src);
+
+ void comiss(XmmRegister a, XmmRegister b);
+ void comisd(XmmRegister a, XmmRegister b);
+
+ void sqrtsd(XmmRegister dst, XmmRegister src);
+ void sqrtss(XmmRegister dst, XmmRegister src);
+
+ void xorpd(XmmRegister dst, const Address& src);
+ void xorpd(XmmRegister dst, XmmRegister src);
+ void xorps(XmmRegister dst, const Address& src);
+ void xorps(XmmRegister dst, XmmRegister src);
+
+ void andpd(XmmRegister dst, const Address& src);
+
+ void flds(const Address& src);
+ void fstps(const Address& dst);
+
+ void fldl(const Address& src);
+ void fstpl(const Address& dst);
+
+ void fnstcw(const Address& dst);
+ void fldcw(const Address& src);
+
+ void fistpl(const Address& dst);
+ void fistps(const Address& dst);
+ void fildl(const Address& src);
+
+ void fincstp();
+ void ffree(const Immediate& index);
+
+ void fsin();
+ void fcos();
+ void fptan();
+
+ void xchgl(Register dst, Register src);
+
+ void cmpl(Register reg, const Immediate& imm);
+ void cmpl(Register reg0, Register reg1);
+ void cmpl(Register reg, const Address& address);
+
+ void cmpl(const Address& address, Register reg);
+ void cmpl(const Address& address, const Immediate& imm);
+
+ void testl(Register reg1, Register reg2);
+ void testl(Register reg, const Immediate& imm);
+
+ void andl(Register dst, const Immediate& imm);
+ void andl(Register dst, Register src);
+
+ void orl(Register dst, const Immediate& imm);
+ void orl(Register dst, Register src);
+
+ void xorl(Register dst, Register src);
+
+ void addl(Register dst, Register src);
+ void addl(Register reg, const Immediate& imm);
+ void addl(Register reg, const Address& address);
+
+ void addl(const Address& address, Register reg);
+ void addl(const Address& address, const Immediate& imm);
+
+ void adcl(Register dst, Register src);
+ void adcl(Register reg, const Immediate& imm);
+ void adcl(Register dst, const Address& address);
+
+ void subl(Register dst, Register src);
+ void subl(Register reg, const Immediate& imm);
+ void subl(Register reg, const Address& address);
+
+ void cdq();
+
+ void idivl(Register reg);
+
+ void imull(Register dst, Register src);
+ void imull(Register reg, const Immediate& imm);
+ void imull(Register reg, const Address& address);
+
+ void imull(Register reg);
+ void imull(const Address& address);
+
+ void mull(Register reg);
+ void mull(const Address& address);
+
+ void sbbl(Register dst, Register src);
+ void sbbl(Register reg, const Immediate& imm);
+ void sbbl(Register reg, const Address& address);
+
+ void incl(Register reg);
+ void incl(const Address& address);
+
+ void decl(Register reg);
+ void decl(const Address& address);
+
+ void shll(Register reg, const Immediate& imm);
+ void shll(Register operand, Register shifter);
+ void shrl(Register reg, const Immediate& imm);
+ void shrl(Register operand, Register shifter);
+ void sarl(Register reg, const Immediate& imm);
+ void sarl(Register operand, Register shifter);
+ void shld(Register dst, Register src);
+
+ void negl(Register reg);
+ void notl(Register reg);
+
+ void enter(const Immediate& imm);
+ void leave();
+
+ void ret();
+ void ret(const Immediate& imm);
+
+ void nop();
+ void int3();
+ void hlt();
+
+ void j(Condition condition, Label* label);
+
+ void jmp(Register reg);
+ void jmp(Label* label);
+
+ void lock();
+ void cmpxchgl(const Address& address, Register reg);
+
+ /*
+ * Macros for High-level operations.
+ */
+ void AddImmediate(Register reg, const Immediate& imm);
+
+ void LoadDoubleConstant(XmmRegister dst, double value);
+
+ void DoubleNegate(XmmRegister d);
+ void FloatNegate(XmmRegister f);
+
+ void DoubleAbs(XmmRegister reg);
+
+ void LockCmpxchgl(const Address& address, Register reg) {
+ lock();
+ cmpxchgl(address, reg);
+ }
+
+ /*
+ * Misc. functionality
+ */
+ int PreferredLoopAlignment() { return 16; }
+ void Align(int alignment, int offset);
+ void Bind(Label* label);
+
+ int CodeSize() const { return buffer_.Size(); }
+
+ void FinalizeInstructions(const MemoryRegion& region) {
+ buffer_.FinalizeInstructions(region);
+ }
+
+ // Debugging and bringup support.
+ void Stop(const char* message);
+ void Unimplemented(const char* message);
+ void Untested(const char* message);
+ void Unreachable(const char* message);
+
+ static void InitializeMemoryWithBreakpoints(byte* data, size_t length);
+
+ private:
+ AssemblerBuffer buffer_;
+
+ inline void EmitUint8(uint8_t value);
+ inline void EmitInt32(int32_t value);
+ inline void EmitRegisterOperand(int rm, int reg);
+ inline void EmitXmmRegisterOperand(int rm, XmmRegister reg);
+ inline void EmitFixup(AssemblerFixup* fixup);
+ inline void EmitOperandSizeOverride();
+
+ void EmitOperand(int rm, const Operand& operand);
+ void EmitImmediate(const Immediate& imm);
+ void EmitComplex(int rm, const Operand& operand, const Immediate& immediate);
+ void EmitLabel(Label* label, int instruction_size);
+ void EmitLabelLink(Label* label);
+ void EmitNearLabelLink(Label* label);
+
+ void EmitGenericShift(int rm, Register reg, const Immediate& imm);
+ void EmitGenericShift(int rm, Register operand, Register shifter);
+
+ DISALLOW_COPY_AND_ASSIGN(Assembler);
+};
+
+
+inline void Assembler::EmitUint8(uint8_t value) {
+ buffer_.Emit<uint8_t>(value);
+}
+
+
+inline void Assembler::EmitInt32(int32_t value) {
+ buffer_.Emit<int32_t>(value);
+}
+
+
+inline void Assembler::EmitRegisterOperand(int rm, int reg) {
+ CHECK_GE(rm, 0);
+ CHECK_LT(rm, 8);
+ buffer_.Emit<uint8_t>(0xC0 + (rm << 3) + reg);
+}
+
+
+inline void Assembler::EmitXmmRegisterOperand(int rm, XmmRegister reg) {
+ EmitRegisterOperand(rm, static_cast<Register>(reg));
+}
+
+
+inline void Assembler::EmitFixup(AssemblerFixup* fixup) {
+ buffer_.EmitFixup(fixup);
+}
+
+
+inline void Assembler::EmitOperandSizeOverride() {
+ EmitUint8(0x66);
+}
+
+} } // namespace android::runtime
+
+#endif // ART_SRC_ASSEMBLER_X86_H_
diff --git a/src/casts.h b/src/casts.h
new file mode 100644
index 0000000..f9f3c6b
--- /dev/null
+++ b/src/casts.h
@@ -0,0 +1,24 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_CASTS_H_
+#define ART_SRC_CASTS_H_
+
+#include <string.h>
+#include "src/macros.h"
+
+namespace android {
+namespace runtime {
+
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+ // Compile time assertion: sizeof(Dest) == sizeof(Source)
+ // A compile error here means your Dest and Source have different sizes.
+ COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), verify_sizes_are_equal);
+ Dest dest;
+ memcpy(&dest, &source, sizeof(dest));
+ return dest;
+}
+
+} } // namespace android::runtime
+
+#endif // ART_SRC_CASTS_H_
diff --git a/src/constants_x86.h b/src/constants_x86.h
new file mode 100644
index 0000000..477bef8
--- /dev/null
+++ b/src/constants_x86.h
@@ -0,0 +1,112 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_CONSTANTS_X86_H_
+#define ART_SRC_CONSTANTS_X86_H_
+
+#include "src/globals.h"
+#include "src/logging.h"
+#include "src/macros.h"
+
+namespace android {
+namespace runtime {
+
+enum Register {
+ EAX = 0,
+ ECX = 1,
+ EDX = 2,
+ EBX = 3,
+ ESP = 4,
+ EBP = 5,
+ ESI = 6,
+ EDI = 7,
+ kNumberOfCpuRegisters = 8,
+ kFirstByteUnsafeRegister = 4,
+ kNoRegister = -1 // Signals an illegal register.
+};
+
+
+enum ByteRegister {
+ AL = 0,
+ CL = 1,
+ DL = 2,
+ BL = 3,
+ AH = 4,
+ CH = 5,
+ DH = 6,
+ BH = 7,
+ kNoByteRegister = -1 // Signals an illegal register.
+};
+
+
+enum XmmRegister {
+ XMM0 = 0,
+ XMM1 = 1,
+ XMM2 = 2,
+ XMM3 = 3,
+ XMM4 = 4,
+ XMM5 = 5,
+ XMM6 = 6,
+ XMM7 = 7,
+ kNumberOfXmmRegisters = 8,
+ kNoXmmRegister = -1 // Signals an illegal register.
+};
+
+
+enum ScaleFactor {
+ TIMES_1 = 0,
+ TIMES_2 = 1,
+ TIMES_4 = 2,
+ TIMES_8 = 3
+};
+
+
+enum Condition {
+ OVERFLOW = 0,
+ NO_OVERFLOW = 1,
+ BELOW = 2,
+ ABOVE_EQUAL = 3,
+ EQUAL = 4,
+ NOT_EQUAL = 5,
+ BELOW_EQUAL = 6,
+ ABOVE = 7,
+ SIGN = 8,
+ NOT_SIGN = 9,
+ PARITY_EVEN = 10,
+ PARITY_ODD = 11,
+ LESS = 12,
+ GREATER_EQUAL = 13,
+ LESS_EQUAL = 14,
+ GREATER = 15,
+
+ ZERO = EQUAL,
+ NOT_ZERO = NOT_EQUAL,
+ NEGATIVE = SIGN,
+ POSITIVE = NOT_SIGN
+};
+
+
+class Instr {
+ public:
+ static const uint8_t kHltInstruction = 0xF4;
+ // We prefer not to use the int3 instruction since it conflicts with gdb.
+ static const uint8_t kBreakPointInstruction = kHltInstruction;
+ static const int kBreakPointInstructionSize = 1;
+
+ bool IsBreakPoint() {
+ CHECK_EQ(kBreakPointInstructionSize, 1);
+ return (*reinterpret_cast<const uint8_t*>(this)) == kBreakPointInstruction;
+ }
+
+ // Instructions are read out of a code stream. The only way to get a
+ // reference to an instruction is to convert a pointer. There is no way
+ // to allocate or create instances of class Instr.
+ // Use the At(pc) function to create references to Instr.
+ static Instr* At(uintptr_t pc) { return reinterpret_cast<Instr*>(pc); }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
+};
+
+} } // namespace android::runtime
+
+#endif // ART_CONSTANTS_IA32_H_
diff --git a/src/globals.h b/src/globals.h
new file mode 100644
index 0000000..2f85270
--- /dev/null
+++ b/src/globals.h
@@ -0,0 +1,37 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_GLOBALS_H_
+#define ART_SRC_GLOBALS_H_
+
+#include <stdint.h>
+
+namespace android {
+namespace runtime {
+
+typedef uint8_t byte;
+typedef intptr_t word;
+typedef uintptr_t uword;
+
+const int KB = 1024;
+const int MB = KB * KB;
+const int GB = KB * KB * KB;
+const int kMaxInt = 0x7FFFFFFF;
+const int kMinInt = -kMaxInt - 1;
+
+const int kCharSize = sizeof(char);
+const int kShortSize = sizeof(short);
+const int kIntSize = sizeof(int);
+const int kDoubleSize = sizeof(double);
+const int kIntptrSize = sizeof(intptr_t);
+const int kWordSize = sizeof(word);
+const int kPointerSize = sizeof(void*);
+
+const int kBitsPerByte = 8;
+const int kBitsPerByteLog2 = 3;
+const int kBitsPerPointer = kPointerSize * kBitsPerByte;
+const int kBitsPerWord = kWordSize * kBitsPerWord;
+const int kBitsPerInt = kIntSize * kBitsPerByte;
+
+} } // namespace android::runtime
+
+#endif // ART_SRC_GLOBALS_H_
diff --git a/src/logging.h b/src/logging.h
index 2c05382..c1896e9 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -74,6 +74,7 @@
#endif
#define LOG_INFO LogMessage(__FILE__, __LINE__)
+#define LOG_FATAL LogMessageFatal(__FILE__, __LINE__)
#define LOG(severity) LOG_ ## severity.stream()
#define LG LOG(INFO)
diff --git a/src/macros.h b/src/macros.h
index 95c2590..c2a474e 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -14,6 +14,28 @@
#ifndef ART_MACROS_H_
#define ART_MACROS_H_
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+// COMPILE_ASSERT(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
+// content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+template <bool>
+struct CompileAssert {
+};
+
+#define COMPILE_ASSERT(expr, msg) \
+ typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions.
// It goes in the private: declarations in a class.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
diff --git a/src/memory_region.cc b/src/memory_region.cc
new file mode 100644
index 0000000..1fa5d1f
--- /dev/null
+++ b/src/memory_region.cc
@@ -0,0 +1,21 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include <stdint.h>
+#include <string.h>
+#include "src/globals.h"
+#include "src/logging.h"
+#include "src/memory_region.h"
+
+namespace android {
+namespace runtime {
+
+void MemoryRegion::CopyFrom(size_t offset, const MemoryRegion& from) const {
+ CHECK_NE(from.pointer(), NULL);
+ CHECK_GT(from.size(), 0);
+ CHECK_GE(this->size(), from.size());
+ CHECK_LE(offset, this->size() - from.size());
+ memmove(reinterpret_cast<void*>(start() + offset),
+ from.pointer(), from.size());
+}
+
+} } // namespace android::runtime
diff --git a/src/memory_region.h b/src/memory_region.h
new file mode 100644
index 0000000..da79fbd
--- /dev/null
+++ b/src/memory_region.h
@@ -0,0 +1,86 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_MEMORY_REGION_H_
+#define ART_SRC_MEMORY_REGION_H_
+
+#include <stdint.h>
+#include "src/globals.h"
+#include "src/logging.h"
+#include "src/macros.h"
+#include "src/memory_region.h"
+
+namespace android {
+namespace runtime {
+
+// Memory regions are useful for accessing memory with bounds check in
+// debug mode. They can be safely passed by value and do not assume ownership
+// of the region.
+class MemoryRegion {
+ public:
+ MemoryRegion() : pointer_(NULL), size_(0) {}
+ MemoryRegion(void* pointer, uword size) : pointer_(pointer), size_(size) {}
+
+ void* pointer() const { return pointer_; }
+ size_t size() const { return size_; }
+ size_t size_in_bits() const { return size_ * kBitsPerByte; }
+
+ static size_t pointer_offset() {
+ return OFFSETOF_MEMBER(MemoryRegion, pointer_);
+ }
+
+ byte* start() const { return reinterpret_cast<byte*>(pointer_); }
+ byte* end() const { return start() + size_; }
+
+ template<typename T> T Load(uintptr_t offset) const {
+ return *ComputeInternalPointer<T>(offset);
+ }
+
+ template<typename T> void Store(uintptr_t offset, T value) const {
+ *ComputeInternalPointer<T>(offset) = value;
+ }
+
+ template<typename T> T* PointerTo(uintptr_t offset) const {
+ return ComputeInternalPointer<T>(offset);
+ }
+
+ void CopyFrom(size_t offset, const MemoryRegion& from) const;
+
+ // Compute a sub memory region based on an existing one.
+ void Subregion(const MemoryRegion& from, uintptr_t offset, uintptr_t size) {
+ CHECK_GE(from.size(), size);
+ CHECK_LE(offset, from.size() - size);
+ pointer_ = reinterpret_cast<void*>(from.start() + offset);
+ size_ = size;
+ }
+
+ // Compute an extended memory region based on an existing one.
+ void Extend(const MemoryRegion& region, uintptr_t extra) {
+ pointer_ = region.pointer();
+ size_ = (region.size() + extra);
+ }
+
+ private:
+ template<typename T> T* ComputeInternalPointer(size_t offset) const {
+ CHECK_GE(size(), sizeof(T));
+ CHECK_LE(offset, size() - sizeof(T));
+ return reinterpret_cast<T*>(start() + offset);
+ }
+
+ // Locate the bit with the given offset. Returns a pointer to the byte
+ // containing the bit, and sets bit_mask to the bit within that byte.
+ byte* ComputeBitPointer(uintptr_t bit_offset, byte* bit_mask) const {
+ uintptr_t bit_remainder = (bit_offset & (kBitsPerByte - 1));
+ *bit_mask = (1U << bit_remainder);
+ uintptr_t byte_offset = (bit_offset >> kBitsPerByteLog2);
+ return ComputeInternalPointer<byte>(byte_offset);
+ }
+
+ void* pointer_;
+ size_t size_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryRegion);
+};
+
+} } // namespace android::runtime
+
+#endif // ART_MEMORY_REGION_H_
diff --git a/src/utils.h b/src/utils.h
new file mode 100644
index 0000000..6f38e7f
--- /dev/null
+++ b/src/utils.h
@@ -0,0 +1,45 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_UTILS_H_
+#define ART_SRC_UTILS_H_
+
+#include "src/globals.h"
+
+namespace android {
+namespace runtime {
+
+// Check whether an N-bit two's-complement representation can hold value.
+static inline bool IsInt(int N, word value) {
+ CHECK_LT(0, N);
+ CHECK_LT(N, kBitsPerWord);
+ word limit = static_cast<word>(1) << (N - 1);
+ return (-limit <= value) && (value < limit);
+}
+
+
+template<typename T>
+static inline bool IsPowerOfTwo(T x) {
+ return (x & (x - 1)) == 0;
+}
+
+
+static inline bool IsUint(int N, word value) {
+ CHECK_LT(0, N);
+ CHECK_LT(N, kBitsPerWord);
+ word limit = static_cast<word>(1) << N;
+ return (0 <= value) && (value < limit);
+}
+
+
+static inline int32_t Low32Bits(int64_t value) {
+ return static_cast<int32_t>(value);
+}
+
+
+static inline int32_t High32Bits(int64_t value) {
+ return static_cast<int32_t>(value >> 32);
+}
+
+} } // namespace android::runtime
+
+#endif // ART_SRC_UTILS_H_