Add 64-bit stubs to call into the runtime and to call native functions.

Fix 64-bit assembler bugs.
Review URL: http://codereview.chromium.org//8818001

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@2206 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
regis@google.com 2011-12-08 00:03:08 +00:00
parent f7419664c4
commit ec7f6331d1
18 changed files with 832 additions and 151 deletions

View file

@ -153,17 +153,29 @@ void AssemblerBuffer::EmitObject(const Object& object) {
// Shared macros are implemented here.
void Assembler::Unimplemented(const char* message) {
Stop("unimplemented");
const char* format = "Unimplemented: %s";
const intptr_t len = snprintf(NULL, 0, format, message);
char* buffer = reinterpret_cast<char*>(malloc(len + 1));
snprintf(buffer, len + 1, format, message);
Stop(buffer);
}
void Assembler::Untested(const char* message) {
Stop("untested");
const char* format = "Untested: %s";
const intptr_t len = snprintf(NULL, 0, format, message);
char* buffer = reinterpret_cast<char*>(malloc(len + 1));
snprintf(buffer, len + 1, format, message);
Stop(buffer);
}
void Assembler::Unreachable(const char* message) {
Stop("unreachable");
const char* format = "Unreachable: %s";
const intptr_t len = snprintf(NULL, 0, format, message);
char* buffer = reinterpret_cast<char*>(malloc(len + 1));
snprintf(buffer, len + 1, format, message);
Stop(buffer);
}
} // namespace dart

View file

@ -1223,31 +1223,43 @@ void Assembler::AddImmediate(Register reg, const Immediate& imm) {
void Assembler::LoadObject(Register dst, const Object& object) {
ASSERT(object.IsZoneHandle());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xB8 + dst);
buffer_.EmitObject(object);
if (object.IsSmi()) {
movl(dst, Immediate(reinterpret_cast<int32_t>(object.raw())));
} else {
ASSERT(object.IsZoneHandle());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xB8 + dst);
buffer_.EmitObject(object);
}
}
void Assembler::PushObject(const Object& object) {
ASSERT(object.IsZoneHandle());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x68);
buffer_.EmitObject(object);
if (object.IsSmi()) {
pushl(Immediate(reinterpret_cast<int32_t>(object.raw())));
} else {
ASSERT(object.IsZoneHandle());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x68);
buffer_.EmitObject(object);
}
}
void Assembler::CompareObject(Register reg, const Object& object) {
ASSERT(object.IsZoneHandle());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
if (reg == EAX) {
EmitUint8(0x05 + (7 << 3));
buffer_.EmitObject(object);
if (object.IsSmi()) {
cmpl(reg, Immediate(reinterpret_cast<int32_t>(object.raw())));
} else {
EmitUint8(0x81);
EmitOperand(7, Operand(reg));
buffer_.EmitObject(object);
ASSERT(object.IsZoneHandle());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
if (reg == EAX) {
EmitUint8(0x05 + (7 << 3));
buffer_.EmitObject(object);
} else {
EmitUint8(0x81);
EmitOperand(7, Operand(reg));
buffer_.EmitObject(object);
}
}
}

View file

@ -22,12 +22,8 @@ class RuntimeEntry;
#if defined(TESTING) || defined(DEBUG)
#if defined(TARGET_OS_WINDOWS)
#define CHECK_STACK_ALIGNMENT { \
uword current_sp; \
__asm { mov current_sp, esp } \
ASSERT((OS::ActivationFrameAlignment() == 0) || \
(Utils::IsAligned(current_sp, OS::ActivationFrameAlignment()))); \
}
// The compiler may dynamically align the stack on Windows, so do not check.
#define CHECK_STACK_ALIGNMENT { }
#else
#define CHECK_STACK_ALIGNMENT { \
uword current_sp; \

View file

@ -63,6 +63,18 @@ void Assembler::pushq(const Address& address) {
}
void Assembler::pushq(const Immediate& imm) {
if (imm.is_int32()) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0x68);
EmitImmediate(imm);
} else {
movq(TMP, imm);
pushq(TMP);
}
}
void Assembler::popq(Register reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(reg, REX_NONE);
@ -275,13 +287,17 @@ void Assembler::movq(const Address& dst, Register src) {
void Assembler::movq(const Address& dst, const Immediate& imm) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
ASSERT(imm.is_int32());
Operand operand(dst);
EmitOperandREX(0, operand, REX_W);
EmitUint8(0xC7);
EmitOperand(0, operand);
EmitImmediate(imm);
if (imm.is_int32()) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
Operand operand(dst);
EmitOperandREX(0, operand, REX_W);
EmitUint8(0xC7);
EmitOperand(0, operand);
EmitImmediate(imm);
} else {
movq(TMP, imm);
movq(dst, TMP);
}
}
@ -340,7 +356,7 @@ void Assembler::movd(XmmRegister dst, Register src) {
EmitUint8(0x66);
EmitUint8(0x0F);
EmitUint8(0x6E);
EmitOperand(dst, Operand(src));
EmitOperand(dst & 7, Operand(src));
}
@ -350,7 +366,7 @@ void Assembler::movd(Register dst, XmmRegister src) {
EmitUint8(0x66);
EmitUint8(0x0F);
EmitUint8(0x7E);
EmitOperand(src, Operand(dst));
EmitOperand(src & 7, Operand(dst));
}
@ -536,18 +552,36 @@ void Assembler::cmpl(const Address& address, const Immediate& imm) {
}
void Assembler::cmpq(const Address& address, const Immediate& imm) {
void Assembler::cmpq(const Address& address, Register reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
Operand operand(address);
EmitOperandREX(7, operand, REX_W);
EmitComplex(7, operand, imm);
EmitOperandREX(reg, address, REX_W);
EmitUint8(0x39);
EmitOperand(reg & 7, address);
}
void Assembler::cmpq(const Address& address, const Immediate& imm) {
if (imm.is_int32()) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
Operand operand(address);
EmitOperandREX(7, operand, REX_W);
EmitComplex(7, operand, imm);
} else {
movq(TMP, imm);
cmpq(address, TMP);
}
}
void Assembler::cmpq(Register reg, const Immediate& imm) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(reg, REX_W);
EmitComplex(7, Operand(reg), imm);
if (imm.is_int32()) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(reg, REX_W);
EmitComplex(7, Operand(reg), imm);
} else {
movq(TMP, imm);
cmpq(reg, TMP);
}
}
@ -805,16 +839,19 @@ void Assembler::idivq(Register reg) {
void Assembler::imull(Register dst, Register src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
Operand operand(src);
EmitOperandREX(dst, operand, REX_NONE);
EmitUint8(0x0F);
EmitUint8(0xAF);
EmitOperand(dst, Operand(src));
EmitOperand(dst & 7, Operand(src));
}
void Assembler::imull(Register reg, const Immediate& imm) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(reg, REX_NONE);
EmitUint8(0x69);
EmitOperand(reg, Operand(reg));
EmitOperand(reg & 7, Operand(reg));
EmitImmediate(imm);
}
@ -1124,24 +1161,36 @@ void Assembler::AddImmediate(Register reg, const Immediate& imm) {
void Assembler::LoadObject(Register dst, const Object& object) {
ASSERT(object.IsZoneHandle());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(dst, REX_W);
EmitUint8(0xB8 | (dst & 7));
buffer_.EmitObject(object);
if (object.IsSmi()) {
movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
} else {
ASSERT(object.IsZoneHandle());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(dst, REX_W);
EmitUint8(0xB8 | (dst & 7));
buffer_.EmitObject(object);
}
}
void Assembler::PushObject(const Object& object) {
LoadObject(TMP, object);
pushq(TMP);
if (object.IsSmi()) {
pushq(Immediate(reinterpret_cast<int64_t>(object.raw())));
} else {
LoadObject(TMP, object);
pushq(TMP);
}
}
void Assembler::CompareObject(Register reg, const Object& object) {
ASSERT(reg != TMP);
LoadObject(TMP, object);
cmpq(reg, TMP);
if (object.IsSmi()) {
cmpq(reg, Immediate(reinterpret_cast<int64_t>(object.raw())));
} else {
ASSERT(reg != TMP);
LoadObject(TMP, object);
cmpq(reg, TMP);
}
}
@ -1175,6 +1224,35 @@ void Assembler::Bind(Label* label) {
}
void Assembler::EnterFrame(intptr_t frame_size) {
if (prolog_offset_ == -1) {
prolog_offset_ = CodeSize();
}
pushq(RBP);
movq(RBP, RSP);
if (frame_size != 0) {
Immediate frame_space(frame_size);
subq(RSP, frame_space);
}
}
void Assembler::LeaveFrame() {
movq(RSP, RBP);
popq(RBP);
}
void Assembler::CallRuntimeFromDart(const RuntimeEntry& entry) {
entry.CallFromDart(this);
}
void Assembler::CallRuntimeFromStub(const RuntimeEntry& entry) {
entry.CallFromStub(this);
}
void Assembler::Align(int alignment, int offset) {
UNIMPLEMENTED();
}
@ -1211,8 +1289,8 @@ void Assembler::EmitImmediate(const Immediate& imm) {
void Assembler::EmitComplex(int rm,
const Operand& operand,
const Immediate& immediate) {
const Operand& operand,
const Immediate& immediate) {
ASSERT(rm >= 0 && rm < 8);
ASSERT(immediate.is_int32());
if (immediate.is_int8()) {

View file

@ -21,9 +21,17 @@ class RuntimeEntry;
#if defined(TESTING) || defined(DEBUG)
#if defined(TARGET_OS_WINDOWS)
// The compiler may dynamically align the stack on Windows, so do not check.
#define CHECK_STACK_ALIGNMENT { }
#else
#define CHECK_STACK_ALIGNMENT { \
UNIMPLEMENTED(); \
uword current_sp; \
asm volatile("mov %%rsp, %[current_sp]" : [current_sp] "=r" (current_sp)); \
ASSERT((OS::ActivationFrameAlignment() == 0) || \
(Utils::IsAligned(current_sp, OS::ActivationFrameAlignment()))); \
}
#endif
#else
@ -62,7 +70,7 @@ class Operand : public ValueObject {
}
Register rm() const {
int rm_rex = (rex_ & 1) << 3;
int rm_rex = (rex_ & REX_B) << 3;
return static_cast<Register>(rm_rex + (encoding_at(0) & 7));
}
@ -71,12 +79,12 @@ class Operand : public ValueObject {
}
Register index() const {
int index_rex = (rex_ & 2) << 2;
int index_rex = (rex_ & REX_X) << 2;
return static_cast<Register>(index_rex + ((encoding_at(1) >> 3) & 7));
}
Register base() const {
int base_rex = (rex_ & 1) << 3;
int base_rex = (rex_ & REX_B) << 3;
return static_cast<Register>(base_rex + (encoding_at(1) & 7));
}
@ -91,11 +99,13 @@ class Operand : public ValueObject {
}
protected:
Operand() : length_(0), rex_(0) { }
Operand() : length_(0), rex_(REX_NONE) { }
void SetModRM(int mod, Register rm) {
ASSERT((mod & ~3) == 0);
if (rm > 7) rex_ |= 1;
if ((rm > 7) && !((rm == R12) && (mod != 3))) {
rex_ |= REX_B;
}
encoding_[0] = (mod << 6) | (rm & 7);
length_ = 1;
}
@ -104,10 +114,10 @@ class Operand : public ValueObject {
ASSERT(length_ == 1);
ASSERT((scale & ~3) == 0);
if (base > 7) {
ASSERT((rex_ & 1) == 0); // Must not have REX.B already set.
rex_ |= 1;
ASSERT((rex_ & REX_B) == 0); // Must not have REX.B already set.
rex_ |= REX_B;
}
if (index > 7) rex_ |= 2;
if (index > 7) rex_ |= REX_X;
encoding_[1] = (scale << 6) | ((index & 7) << 3) | (base & 7);
length_ = 2;
}
@ -128,7 +138,7 @@ class Operand : public ValueObject {
uint8_t rex_;
uint8_t encoding_[6];
explicit Operand(Register reg) : rex_(0) { SetModRM(3, reg); }
explicit Operand(Register reg) : rex_(REX_NONE) { SetModRM(3, reg); }
// Get the operand encoding byte at the given index.
uint8_t encoding_at(int index) const {
@ -139,7 +149,7 @@ class Operand : public ValueObject {
// Returns whether or not this operand is really the given register in
// disguise. Used from the assembler to generate better encodings.
bool IsRegister(Register reg) const {
return ((reg > 7 ? 1 : 0) == (rex_ & 1)) // REX.B match.
return ((reg > 7 ? 1 : 0) == (rex_ & REX_B)) // REX.B match.
&& ((encoding_at(0) & 0xF8) == 0xC0) // Addressing mode is register.
&& ((encoding_at(0) & 0x07) == reg); // Register codes match.
}
@ -155,16 +165,22 @@ class Operand : public ValueObject {
class Address : public Operand {
public:
Address(Register base, int32_t disp) {
if (disp == 0 && base != RBP) {
if ((disp == 0) && ((base & 7) != RBP)) {
SetModRM(0, base);
if (base == RSP) SetSIB(TIMES_1, RSP, base);
if ((base & 7) == RSP) {
SetSIB(TIMES_1, RSP, base);
}
} else if (Utils::IsInt(8, disp)) {
SetModRM(1, base);
if (base == RSP) SetSIB(TIMES_1, RSP, base);
if ((base & 7) == RSP) {
SetSIB(TIMES_1, RSP, base);
}
SetDisp8(disp);
} else {
SetModRM(2, base);
if (base == RSP) SetSIB(TIMES_1, RSP, base);
if ((base & 7) == RSP) {
SetSIB(TIMES_1, RSP, base);
}
SetDisp32(disp);
}
}
@ -178,7 +194,7 @@ class Address : public Operand {
Address(Register base, Register index, ScaleFactor scale, int32_t disp) {
ASSERT(index != RSP); // Illegal addressing mode.
if (disp == 0 && base != RBP) {
if ((disp == 0) && ((base & 7) != RBP)) {
SetModRM(0, RSP);
SetSIB(scale, index, base);
} else if (Utils::IsInt(8, disp)) {
@ -306,6 +322,7 @@ class Assembler : public ValueObject {
void pushq(Register reg);
void pushq(const Address& address);
void pushq(const Immediate& imm);
void popq(Register reg);
void popq(const Address& address);
@ -370,6 +387,7 @@ class Assembler : public ValueObject {
void cmpl(const Address& address, const Immediate& imm);
void cmpq(Register reg, const Immediate& imm);
void cmpq(const Address& address, Register reg);
void cmpq(const Address& address, const Immediate& imm);
void cmpq(Register reg0, Register reg1);
void cmpq(Register reg, const Address& address);
@ -505,11 +523,11 @@ class Assembler : public ValueObject {
* Misc. functionality.
*/
void SmiTag(Register reg) {
addl(reg, reg);
addq(reg, reg);
}
void SmiUntag(Register reg) {
sarl(reg, Immediate(kSmiTagSize));
sarq(reg, Immediate(kSmiTagSize));
}
int PreferredLoopAlignment() { return 16; }
@ -564,15 +582,6 @@ class Assembler : public ValueObject {
};
enum {
REX_NONE = 0,
REX_B = 1 << 0,
REX_X = 1 << 1,
REX_R = 1 << 2,
REX_W = 1 << 3
};
inline void Assembler::EmitUint8(uint8_t value) {
buffer_.Emit<uint8_t>(value);
}
@ -591,7 +600,7 @@ inline void Assembler::EmitInt64(int64_t value) {
inline void Assembler::EmitRegisterREX(Register reg, uint8_t rex) {
ASSERT(reg != kNoRegister);
rex |= (reg > 7 ? REX_B : REX_NONE);
if (rex != 0) EmitUint8(0x40 | rex);
if (rex != REX_NONE) EmitUint8(REX_PREFIX | rex);
}
@ -599,7 +608,7 @@ inline void Assembler::EmitOperandREX(int rm,
const Operand& operand,
uint8_t rex) {
rex |= (rm > 7 ? REX_R : REX_NONE) | operand.rex();
if (rex != 0) EmitUint8(0x40 | rex);
if (rex != REX_NONE) EmitUint8(REX_PREFIX | rex);
}

View file

@ -38,92 +38,168 @@ ASSEMBLER_TEST_GENERATE(AddressingModes, assembler) {
__ movq(RAX, Address(RBP, 0));
__ movq(RAX, Address(RAX, 0));
__ movq(RAX, Address(R10, 0));
__ movq(RAX, Address(R12, 0));
__ movq(RAX, Address(R13, 0));
__ movq(R10, Address(RAX, 0));
__ movq(RAX, Address(RSP, kWordSize));
__ movq(RAX, Address(RBP, kWordSize));
__ movq(RAX, Address(RAX, kWordSize));
__ movq(RAX, Address(R10, kWordSize));
__ movq(RAX, Address(R12, kWordSize));
__ movq(RAX, Address(R13, kWordSize));
__ movq(RAX, Address(RSP, -kWordSize));
__ movq(RAX, Address(RBP, -kWordSize));
__ movq(RAX, Address(RAX, -kWordSize));
__ movq(RAX, Address(R10, -kWordSize));
__ movq(RAX, Address(R12, -kWordSize));
__ movq(RAX, Address(R13, -kWordSize));
__ movq(RAX, Address(RSP, 256 * kWordSize));
__ movq(RAX, Address(RBP, 256 * kWordSize));
__ movq(RAX, Address(RAX, 256 * kWordSize));
__ movq(RAX, Address(R10, 256 * kWordSize));
__ movq(RAX, Address(R12, 256 * kWordSize));
__ movq(RAX, Address(R13, 256 * kWordSize));
__ movq(RAX, Address(RSP, -256 * kWordSize));
__ movq(RAX, Address(RBP, -256 * kWordSize));
__ movq(RAX, Address(RAX, -256 * kWordSize));
__ movq(RAX, Address(R10, -256 * kWordSize));
__ movq(RAX, Address(R12, -256 * kWordSize));
__ movq(RAX, Address(R13, -256 * kWordSize));
__ movq(RAX, Address(RAX, TIMES_1));
__ movq(RAX, Address(RAX, TIMES_2));
__ movq(RAX, Address(RAX, TIMES_4));
__ movq(RAX, Address(RAX, TIMES_8));
__ movq(RAX, Address(RAX, TIMES_1, 0));
__ movq(RAX, Address(RAX, TIMES_2, 0));
__ movq(RAX, Address(RAX, TIMES_4, 0));
__ movq(RAX, Address(RAX, TIMES_8, 0));
__ movq(RAX, Address(RBP, TIMES_2));
__ movq(RAX, Address(RAX, TIMES_2));
__ movq(RAX, Address(R10, TIMES_2));
__ movq(RAX, Address(RBP, TIMES_2, 0));
__ movq(RAX, Address(RAX, TIMES_2, 0));
__ movq(RAX, Address(R10, TIMES_2, 0));
__ movq(RAX, Address(R12, TIMES_2, 0));
__ movq(RAX, Address(R13, TIMES_2, 0));
__ movq(RAX, Address(RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, RBP, TIMES_2, 0));
__ movq(RAX, Address(RAX, RAX, TIMES_2, 0));
__ movq(RAX, Address(RAX, R10, TIMES_2, 0));
__ movq(RAX, Address(RAX, R12, TIMES_2, 0));
__ movq(RAX, Address(RAX, R13, TIMES_2, 0));
__ movq(RAX, Address(RBP, RBP, TIMES_2, 0));
__ movq(RAX, Address(RBP, RAX, TIMES_2, 0));
__ movq(RAX, Address(RBP, R10, TIMES_2, 0));
__ movq(RAX, Address(RBP, R12, TIMES_2, 0));
__ movq(RAX, Address(RBP, R13, TIMES_2, 0));
__ movq(RAX, Address(RSP, RBP, TIMES_2, 0));
__ movq(RAX, Address(RSP, RAX, TIMES_2, 0));
__ movq(RAX, Address(RSP, R10, TIMES_2, 0));
__ movq(RAX, Address(RSP, R12, TIMES_2, 0));
__ movq(RAX, Address(RSP, R13, TIMES_2, 0));
__ movq(RAX, Address(R10, RBP, TIMES_2, 0));
__ movq(RAX, Address(R10, RAX, TIMES_2, 0));
__ movq(RAX, Address(R10, R10, TIMES_2, 0));
__ movq(RAX, Address(R10, R12, TIMES_2, 0));
__ movq(RAX, Address(R10, R13, TIMES_2, 0));
__ movq(RAX, Address(R12, RBP, TIMES_2, 0));
__ movq(RAX, Address(R12, RAX, TIMES_2, 0));
__ movq(RAX, Address(R12, R10, TIMES_2, 0));
__ movq(RAX, Address(R12, R12, TIMES_2, 0));
__ movq(RAX, Address(R12, R13, TIMES_2, 0));
__ movq(RAX, Address(R13, RBP, TIMES_2, 0));
__ movq(RAX, Address(R13, RAX, TIMES_2, 0));
__ movq(RAX, Address(R13, R10, TIMES_2, 0));
__ movq(RAX, Address(R13, R12, TIMES_2, 0));
__ movq(RAX, Address(R13, R13, TIMES_2, 0));
__ movq(RAX, Address(RAX, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(RBP, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(RSP, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(R10, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(R12, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, RBP, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, RAX, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, R10, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, R12, TIMES_2, kWordSize));
__ movq(RAX, Address(R13, R13, TIMES_2, kWordSize));
__ movq(RAX, Address(RAX, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RAX, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RBP, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(RSP, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R10, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R12, R13, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, RBP, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, RAX, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, R10, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, R12, TIMES_2, 256 * kWordSize));
__ movq(RAX, Address(R13, R13, TIMES_2, 256 * kWordSize));
}
@ -269,6 +345,24 @@ ASSEMBLER_TEST_RUN(SignedMultiply, entry) {
}
ASSEMBLER_TEST_GENERATE(SignedMultiply64, assembler) {
__ movq(RAX, Immediate(2));
__ movq(RCX, Immediate(4));
__ imulq(RAX, RCX);
__ movq(R8, Immediate(2));
__ movq(R9, Immediate(4));
__ imulq(R8, R9);
__ addq(RAX, R8);
__ ret();
}
ASSEMBLER_TEST_RUN(SignedMultiply64, entry) {
typedef int64_t (*SignedMultiply64)();
EXPECT_EQ(16, reinterpret_cast<SignedMultiply64>(entry)());
}
static const int64_t kLargeConstant = 0x1234567887654321;
static const int64_t kAnotherLargeConstant = 987654321987654321LL;
static const int64_t kProductLargeConstants = 0x5bbb29a7f52fbbd1;

View file

@ -287,7 +287,6 @@ DEFINE_RUNTIME_ENTRY(AllocateImplicitInstanceClosure, 3) {
// Arg0: number of variables.
// Return value: newly allocated context.
DEFINE_RUNTIME_ENTRY(AllocateContext, 1) {
CHECK_STACK_ALIGNMENT;
ASSERT(arguments.Count() == kAllocateContextRuntimeEntry.argument_count());
const Smi& num_variables = Smi::CheckedHandle(arguments.At(0));
arguments.SetReturn(Context::Handle(Context::New(num_variables.Value())));
@ -299,7 +298,6 @@ DEFINE_RUNTIME_ENTRY(AllocateContext, 1) {
// Arg0: the context to be cloned.
// Return value: newly allocated context.
DEFINE_RUNTIME_ENTRY(CloneContext, 1) {
CHECK_STACK_ALIGNMENT;
ASSERT(arguments.Count() == kCloneContextRuntimeEntry.argument_count());
const Context& ctx = Context::CheckedHandle(arguments.At(0));
Context& cloned_ctx = Context::Handle(Context::New(ctx.num_variables()));

View file

@ -803,12 +803,7 @@ void CodeGenerator::VisitReturnNode(ReturnNode* node) {
void CodeGenerator::VisitLiteralNode(LiteralNode* node) {
if (!IsResultNeeded(node)) return;
const Object& literal = node->literal();
if (literal.IsSmi()) {
__ pushl(Immediate(reinterpret_cast<int32_t>(literal.raw())));
} else {
__ PushObject(literal);
}
__ PushObject(node->literal());
}

View file

@ -56,9 +56,19 @@ enum XmmRegister {
};
enum RexBits {
REX_NONE = 0,
REX_B = 1 << 0,
REX_X = 1 << 1,
REX_R = 1 << 2,
REX_W = 1 << 3,
REX_PREFIX = 1 << 6
};
// Register aliases.
const Register TMP = R11; // Used as scratch register by the assembler.
const Register CTX = R12; // Caches current context in generated code.
const Register CTX = R15; // Caches current context in generated code.
// Exception object is passed in this register to the catch handlers when an
// exception is thrown.

View file

@ -4,11 +4,34 @@
#include "vm/runtime_entry.h"
#include "vm/code_index_table.h"
#include "vm/object.h"
#include "vm/verifier.h"
namespace dart {
// Add function to a class and that class to the class dictionary so that
// frame walking can be used.
const Function& RegisterFakeFunction(const char* name, const Code& code) {
const String& function_name = String::ZoneHandle(String::NewSymbol(name));
const Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kFunction, true, false, 0));
Class& cls = Class::ZoneHandle();
const Script& script = Script::Handle();
cls = Class::New(function_name, script);
const Array& functions = Array::Handle(Array::New(1));
functions.SetAt(0, function);
cls.SetFunctions(functions);
Library& lib = Library::Handle(Library::CoreLibrary());
lib.AddClass(cls);
function.SetCode(code);
CodeIndexTable* code_index_table = Isolate::Current()->code_index_table();
ASSERT(code_index_table != NULL);
code_index_table->AddFunction(function);
return function;
}
// A runtime call for test purposes.
// Arg0: a smi.
// Arg1: a smi.

View file

@ -7,14 +7,35 @@
#include "vm/runtime_entry.h"
#include "vm/assembler.h"
#include "vm/stub_code.h"
namespace dart {
#define __ assembler->
// Generate code to call into the stub which will call the runtime
// function. Input for the stub is as follows:
// RSP : points to the arguments and return value array.
// RBX : address of the runtime function to call.
// R10 : number of arguments to the call.
void RuntimeEntry::CallFromDart(Assembler* assembler) const {
UNIMPLEMENTED();
__ movq(RBX, Immediate(GetEntryPoint()));
__ movq(R10, Immediate(argument_count()));
__ call(&StubCode::DartCallToRuntimeLabel());
}
// Generate code to call into the stub which will call the runtime
// function. Input for the stub is as follows:
// RSP : points to the arguments and return value array.
// RBX : address of the runtime function to call.
// R10 : number of arguments to the call.
void RuntimeEntry::CallFromStub(Assembler* assembler) const {
UNIMPLEMENTED();
__ movq(RBX, Immediate(GetEntryPoint()));
__ movq(R10, Immediate(argument_count()));
__ call(&StubCode::StubCallToRuntimeLabel());
}
} // namespace dart

View file

@ -9,6 +9,11 @@
namespace dart {
// The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
// code in the InvokeDartCode stub.
static const int kExitLinkOffsetInEntryFrame = -8 * kWordSize;
intptr_t StackFrame::PcAddressOffsetFromSp() {
UNIMPLEMENTED();
return 0;

View file

@ -50,8 +50,8 @@ StubCode::~StubCode() {
void StubCode::InitOnce() {
// TODO(regis): Re-enable this after we are able to generate x64 and arm code.
#if defined(TARGET_ARCH_IA32)
// TODO(regis): Re-enable this after we are able to generate arm code.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
// Generate all the stubs.
Code& code = Code::Handle();
VM_STUB_CODE_LIST(STUB_CODE_GENERATE);
@ -60,8 +60,8 @@ void StubCode::InitOnce() {
void StubCode::GenerateFor(Isolate* init) {
// TODO(regis): Re-enable this after we are able to generate x64 and arm code.
#if defined(TARGET_ARCH_IA32)
// TODO(regis): Re-enable this after we are able to generate arm code.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
// Generate all the stubs.
Code& code = Code::Handle();
STUB_CODE_LIST(STUB_CODE_GENERATE);

View file

@ -26,31 +26,51 @@ void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) {
}
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
__ Unimplemented("CallNoSuchMethodFunction stub");
}
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
__ Unimplemented("InvokeDartCode stub");
}
void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
__ Unimplemented("CallStaticFunction stub");
}
void StubCode::GenerateStackOverflowStub(Assembler* assembler) {
__ Unimplemented("StackOverflow stub");
}
void StubCode::GenerateOptimizeInvokedFunctionStub(Assembler* assembler) {
__ Unimplemented("OptimizeInvokedFunction stub");
}
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
__ Unimplemented("FixCallersTarget stub");
}
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
__ Unimplemented("MegamorphicLookup stub");
}
void StubCode::GenerateDeoptimizeStub(Assembler* assembler) {
__ Unimplemented("Deoptimize stub");
}
void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
__ Unimplemented("AllocateArray stub");
}
void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
__ Unimplemented("CallClosureFunction stub");
}
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
__ Unimplemented("InvokeDartCode stub");
}
void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
__ Unimplemented("AllocateContext stub");
}
@ -67,6 +87,26 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
__ Unimplemented("AllocateClosure stub");
}
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
__ Unimplemented("CallNoSuchMethodFunction stub");
}
void StubCode::GenerateInlineCacheStub(Assembler* assembler) {
__ Unimplemented("InlineCache stub");
}
void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
__ Unimplemented("BreakpointStatic stub");
}
void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) {
__ Unimplemented("BreakpointDynamic stub");
}
} // namespace dart
#endif // defined TARGET_ARCH_ARM

View file

@ -5,7 +5,6 @@
#include "vm/globals.h"
#if defined(TARGET_ARCH_IA32)
#include "vm/code_index_table.h"
#include "vm/isolate.h"
#include "vm/dart_entry.h"
#include "vm/native_entry.h"
@ -22,29 +21,6 @@ namespace dart {
DECLARE_RUNTIME_ENTRY(TestSmiSub);
// Add function to a class and that class to the class dictionary so that
// frame walking can be used.
static const Function& RegisterFakeFunction(const char* name,
const Code& code) {
const String& function_name = String::ZoneHandle(String::NewSymbol(name));
const Function& function = Function::ZoneHandle(
Function::New(function_name, RawFunction::kFunction, true, false, 0));
Class& cls = Class::ZoneHandle();
const Script& script = Script::Handle();
cls = Class::New(function_name, script);
const Array& functions = Array::Handle(Array::New(1));
functions.SetAt(0, function);
cls.SetFunctions(functions);
Library& lib = Library::Handle(Library::CoreLibrary());
lib.AddClass(cls);
function.SetCode(code);
CodeIndexTable* code_index_table = Isolate::Current()->code_index_table();
ASSERT(code_index_table != NULL);
code_index_table->AddFunction(function);
return function;
}
// Test calls to stub code which calls into the runtime.
static void GenerateCallToCallRuntimeStub(Assembler* assembler,
int value1, int value2) {
@ -69,6 +45,8 @@ static void GenerateCallToCallRuntimeStub(Assembler* assembler,
TEST_CASE(CallRuntimeStubCode) {
extern const Function& RegisterFakeFunction(const char* name,
const Code& code);
const int value1 = 10;
const int value2 = 20;
const char* kName = "Test_CallRuntimeStubCode";
@ -115,6 +93,8 @@ static void GenerateCallToCallNativeCFunctionStub(Assembler* assembler,
TEST_CASE(CallNativeCFunctionStubCode) {
extern const Function& RegisterFakeFunction(const char* name,
const Code& code);
const int value1 = 15;
const int value2 = 20;
const char* kName = "Test_CallNativeCFunctionStubCode";

View file

@ -5,34 +5,165 @@
#include "vm/globals.h"
#if defined(TARGET_ARCH_X64)
#include "vm/native_entry.h"
#include "vm/stub_code.h"
#define __ assembler->
namespace dart {
// Input parameters:
// RSP : points to return address.
// RSP + 8 : address of last argument in argument array.
// RSP + 8*R10 : address of first argument in argument array.
// RSP + 8*R10 + 8 : address of return value.
// RBX : address of the runtime function to call.
// R10 : number of arguments to the call.
static void GenerateCallRuntimeStub(Assembler* assembler) {
const intptr_t isolate_offset = NativeArguments::isolate_offset();
const intptr_t argc_offset = NativeArguments::argc_offset();
const intptr_t argv_offset = NativeArguments::argv_offset();
const intptr_t retval_offset = NativeArguments::retval_offset();
__ EnterFrame(0);
// Load current Isolate pointer from Context structure into RAX.
__ movq(RAX, FieldAddress(CTX, Context::isolate_offset()));
// Save exit frame information to enable stack walking as we are about
// to transition to Dart VM C++ code.
__ movq(Address(RAX, Isolate::top_exit_frame_info_offset()), RSP);
// Save current Context pointer into Isolate structure.
__ movq(Address(RAX, Isolate::top_context_offset()), CTX);
// Cache Isolate pointer into CTX while executing runtime code.
__ movq(CTX, RAX);
// Reserve space for arguments and align frame before entering C++ world.
__ AddImmediate(RSP, Immediate(-sizeof(NativeArguments)));
if (OS::ActivationFrameAlignment() > 0) {
__ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1)));
}
// Pass NativeArguments structure by value and call runtime.
__ movq(Address(RSP, isolate_offset), CTX); // Set isolate in NativeArgs.
__ movq(Address(RSP, argc_offset), R10); // Set argc in NativeArguments.
__ leaq(RAX, Address(RBP, R10, TIMES_8, 1 * kWordSize)); // Compute argv.
__ movq(Address(RSP, argv_offset), RAX); // Set argv in NativeArguments.
__ addq(RAX, Immediate(1 * kWordSize)); // Retval is next to 1st argument.
__ movq(Address(RSP, retval_offset), RAX); // Set retval in NativeArguments.
__ call(RBX);
// Reset exit frame information in Isolate structure.
__ movq(Address(CTX, Isolate::top_exit_frame_info_offset()), Immediate(0));
// Load Context pointer from Isolate structure into RBX.
__ movq(RBX, Address(CTX, Isolate::top_context_offset()));
// Reset Context pointer in Isolate structure.
const Immediate raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ movq(Address(CTX, Isolate::top_context_offset()), raw_null);
// Cache Context pointer into CTX while executing Dart code.
__ movq(CTX, RBX);
__ LeaveFrame();
__ ret();
}
// Input parameters:
// RSP : points to return address.
// RSP + 8 : address of last argument in argument array.
// RSP + 8*R10 : address of first argument in argument array.
// RSP + 8*R10 + 8 : address of return value.
// RBX : address of the runtime function to call.
// R10 : number of arguments to the call.
void StubCode::GenerateDartCallToRuntimeStub(Assembler* assembler) {
__ Unimplemented("DartCallToRuntime stub");
GenerateCallRuntimeStub(assembler);
}
// Input parameters:
// RSP : points to return address.
// RSP + 8 : address of last argument in argument array.
// RSP + 8*R10 : address of first argument in argument array.
// RSP + 8*R10 + 8 : address of return value.
// RBX : address of the runtime function to call.
// R10 : number of arguments to the call.
void StubCode::GenerateStubCallToRuntimeStub(Assembler* assembler) {
__ Unimplemented("StubCallToRuntime stub");
GenerateCallRuntimeStub(assembler);
}
// Input parameters:
// RSP : points to return address.
// RSP + 8 : address of return value.
// RAX : address of first argument in argument array.
// RAX - 8*R10 + 8 : address of last argument in argument array.
// RBX : address of the native function to call.
// R10 : number of arguments to the call.
void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) {
__ Unimplemented("CallNativeCFunction stub");
}
const intptr_t native_args_struct_offset = 0;
const intptr_t isolate_offset =
NativeArguments::isolate_offset() + native_args_struct_offset;
const intptr_t argc_offset =
NativeArguments::argc_offset() + native_args_struct_offset;
const intptr_t argv_offset =
NativeArguments::argv_offset() + native_args_struct_offset;
const intptr_t retval_offset =
NativeArguments::retval_offset() + native_args_struct_offset;
__ EnterFrame(0);
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
__ Unimplemented("CallNoSuchMethodFunction stub");
}
// Load current Isolate pointer from Context structure into R8.
__ movq(R8, FieldAddress(CTX, Context::isolate_offset()));
// Save exit frame information to enable stack walking as we are about
// to transition to native code.
__ movq(Address(R8, Isolate::top_exit_frame_info_offset()), RSP);
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
__ Unimplemented("InvokeDartCode stub");
// Save current Context pointer into Isolate structure.
__ movq(Address(R8, Isolate::top_context_offset()), CTX);
// Cache Isolate pointer into CTX while executing native code.
__ movq(CTX, R8);
// Reserve space for the native arguments structure passed on the stack (the
// outgoing pointer parameter to the native arguments structure is passed in
// RDI) and align frame before entering the C++ world.
__ AddImmediate(RSP, Immediate(-sizeof(NativeArguments)));
if (OS::ActivationFrameAlignment() > 0) {
__ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1)));
}
// Pass NativeArguments structure by value and call native function.
__ movq(Address(RSP, isolate_offset), CTX); // Set isolate in NativeArgs.
__ movq(Address(RSP, argc_offset), R10); // Set argc in NativeArguments.
__ movq(Address(RSP, argv_offset), RAX); // Set argv in NativeArguments.
__ leaq(RAX, Address(RBP, 2 * kWordSize)); // Compute return value addr.
__ movq(Address(RSP, retval_offset), RAX); // Set retval in NativeArguments.
__ movq(RDI, RSP); // Pass the pointer to the NativeArguments.
__ call(RBX);
// Reset exit frame information in Isolate structure.
__ movq(Address(CTX, Isolate::top_exit_frame_info_offset()), Immediate(0));
// Load Context pointer from Isolate structure into R8.
__ movq(R8, Address(CTX, Isolate::top_context_offset()));
// Reset Context pointer in Isolate structure.
const Immediate raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ movq(Address(CTX, Isolate::top_context_offset()), raw_null);
// Cache Context pointer into CTX while executing Dart code.
__ movq(CTX, R8);
__ LeaveFrame();
__ ret();
}
@ -41,16 +172,157 @@ void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
}
void StubCode::GenerateStackOverflowStub(Assembler* assembler) {
__ Unimplemented("StackOverflow stub");
}
void StubCode::GenerateOptimizeInvokedFunctionStub(Assembler* assembler) {
__ Unimplemented("OptimizeInvokedFunction stub");
}
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
__ Unimplemented("FixCallersTarget stub");
}
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
__ Unimplemented("MegamorphicLookup stub");
}
void StubCode::GenerateDeoptimizeStub(Assembler* assembler) {
__ Unimplemented("Deoptimize stub");
}
void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
__ Unimplemented("AllocateArray stub");
}
void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
__ Unimplemented("CallClosureFunction stub");
}
// Called when invoking Dart code from C++ (VM code).
// Input parameters:
// RSP : points to return address.
// RDI : entrypoint of the Dart function to call.
// RSI : arguments descriptor array.
// RDX : pointer to the argument array.
// RCX : new context containing the current isolate pointer.
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
// Save frame pointer coming in.
__ EnterFrame(0);
// Save arguments descriptor array and new context.
const intptr_t kArgumentsDescOffset = -1 * kWordSize;
__ pushq(RSI);
const intptr_t kNewContextOffset = -2 * kWordSize;
__ pushq(RCX);
// Save C++ ABI callee-saved registers.
__ pushq(RBX);
__ pushq(R12);
__ pushq(R13);
__ pushq(R14);
__ pushq(R15);
// The new Context structure contains a pointer to the current Isolate
// structure. Cache the Context pointer in the CTX register so that it is
// available in generated code and calls to Isolate::Current() need not be
// done. The assumption is that this register will never be clobbered by
// compiled or runtime stub code.
// Cache the new Context pointer into CTX while executing Dart code.
__ movq(CTX, Address(RCX, VMHandles::kOffsetOfRawPtrInHandle));
// Load Isolate pointer from Context structure into R8.
__ movq(R8, FieldAddress(CTX, Context::isolate_offset()));
// Save the top exit frame info. Use RAX as a temporary register.
__ movq(RAX, Address(R8, Isolate::top_exit_frame_info_offset()));
__ pushq(RAX);
__ movq(Address(R8, Isolate::top_exit_frame_info_offset()), Immediate(0));
// StackFrameIterator reads the top exit frame info saved in this frame.
// The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
// code above: kExitLinkOffsetInEntryFrame = -8 * kWordSize.
// Save the old Context pointer. Use RAX as a temporary register.
// Note that VisitObjectPointers will find this saved Context pointer during
// GC marking, since it traverses any information between SP and
// FP - kExitLinkOffsetInEntryFrame.
__ movq(RAX, Address(R8, Isolate::top_context_offset()));
__ pushq(RAX);
// Load arguments descriptor array into R10, which is passed to Dart code.
__ movq(R10, Address(RSI, VMHandles::kOffsetOfRawPtrInHandle));
// Load number of arguments into RBX.
__ movq(RBX, FieldAddress(R10, Array::data_offset()));
__ SmiUntag(RBX);
// Set up arguments for the Dart call.
Label push_arguments;
Label done_push_arguments;
__ testq(RBX, RBX); // check if there are arguments.
__ j(ZERO, &done_push_arguments, Assembler::kNearJump);
__ movq(RAX, Immediate(0));
__ Bind(&push_arguments);
__ movq(RCX, Address(RDX, RAX, TIMES_8, 0)); // RDX is start of arguments.
__ movq(RCX, Address(RCX, VMHandles::kOffsetOfRawPtrInHandle));
__ pushq(RCX);
__ incq(RAX);
__ cmpq(RAX, RBX);
__ j(LESS, &push_arguments, Assembler::kNearJump);
__ Bind(&done_push_arguments);
// Call the Dart code entrypoint.
__ call(RDI); // R10 is the arguments descriptor array.
// Read the saved new Context pointer.
__ movq(CTX, Address(RBP, kNewContextOffset));
__ movq(CTX, Address(CTX, VMHandles::kOffsetOfRawPtrInHandle));
// Read the saved arguments descriptor array to obtain the number of passed
// arguments, which is the first element of the array, a Smi.
__ movq(RSI, Address(RBP, kArgumentsDescOffset));
__ movq(R10, Address(RSI, VMHandles::kOffsetOfRawPtrInHandle));
__ movq(RDX, FieldAddress(R10, Array::data_offset()));
// Get rid of arguments pushed on the stack.
__ leaq(RSP, Address(RSP, RDX, TIMES_4, 0)); // RDX is a Smi.
// Load Isolate pointer from Context structure into CTX. Drop Context.
__ movq(CTX, FieldAddress(CTX, Context::isolate_offset()));
// Restore the saved Context pointer into the Isolate structure.
// Uses RCX as a temporary register for this.
__ popq(RCX);
__ movq(Address(CTX, Isolate::top_context_offset()), RCX);
// Restore the saved top exit frame info back into the Isolate structure.
// Uses RDX as a temporary register for this.
__ popq(RDX);
__ movq(Address(CTX, Isolate::top_exit_frame_info_offset()), RDX);
// Restore C++ ABI callee-saved registers.
__ popq(R15);
__ popq(R14);
__ popq(R13);
__ popq(R12);
__ popq(RBX);
// Restore the frame pointer.
__ LeaveFrame();
__ ret();
}
void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
__ Unimplemented("AllocateContext stub");
}
@ -67,6 +339,26 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
__ Unimplemented("AllocateClosure stub");
}
void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
__ Unimplemented("CallNoSuchMethodFunction stub");
}
void StubCode::GenerateInlineCacheStub(Assembler* assembler) {
__ Unimplemented("InlineCache stub");
}
void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
__ Unimplemented("BreakpointStatic stub");
}
void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) {
__ Unimplemented("BreakpointDynamic stub");
}
} // namespace dart
#endif // defined TARGET_ARCH_X64

View file

@ -0,0 +1,115 @@
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
#if defined(TARGET_ARCH_X64)
#include "vm/isolate.h"
#include "vm/dart_entry.h"
#include "vm/native_entry.h"
#include "vm/native_entry_test.h"
#include "vm/object.h"
#include "vm/runtime_entry.h"
#include "vm/stub_code.h"
#include "vm/unit_test.h"
#define __ assembler->
namespace dart {
DECLARE_RUNTIME_ENTRY(TestSmiSub);
// Test calls to stub code which calls into the runtime.
static void GenerateCallToCallRuntimeStub(Assembler* assembler,
int value1, int value2) {
const int argc = 2;
const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
const Object& result = Object::ZoneHandle();
const Context& context = Context::ZoneHandle(Context::New(0));
ASSERT(context.isolate() == Isolate::Current());
__ enter(Immediate(0));
__ LoadObject(CTX, context);
__ PushObject(result); // Push Null object for return value.
__ PushObject(smi1); // Push argument 1 smi1.
__ PushObject(smi2); // Push argument 2 smi2.
ASSERT(kTestSmiSubRuntimeEntry.argument_count() == argc);
__ CallRuntimeFromStub(kTestSmiSubRuntimeEntry); // Call SmiSub runtime func.
__ AddImmediate(RSP, Immediate(argc * kWordSize));
__ popq(RAX); // Pop return value from return slot.
__ leave();
__ ret();
}
TEST_CASE(CallRuntimeStubCode) {
extern const Function& RegisterFakeFunction(const char* name,
const Code& code);
const int value1 = 10;
const int value2 = 20;
const char* kName = "Test_CallRuntimeStubCode";
Assembler _assembler_;
GenerateCallToCallRuntimeStub(&_assembler_, value1, value2);
const Code& code = Code::Handle(
Code::FinalizeCode("Test_CallRuntimeStubCode", &_assembler_));
const Function& function = RegisterFakeFunction(kName, code);
GrowableArray<const Object*> arguments;
const Array& kNoArgumentNames = Array::Handle();
Smi& result = Smi::Handle();
result ^= DartEntry::InvokeStatic(function, arguments, kNoArgumentNames);
EXPECT_EQ((value1 - value2), result.Value());
}
// Test calls to stub code which calls a native C function.
static void GenerateCallToCallNativeCFunctionStub(Assembler* assembler,
int value1, int value2) {
const int argc = 2;
const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
const Object& result = Object::ZoneHandle();
const String& native_name = String::ZoneHandle(String::New("TestSmiSub"));
Dart_NativeFunction native_function =
NativeTestEntry_Lookup(native_name, argc);
const Context& context = Context::ZoneHandle(Context::New(0));
ASSERT(context.isolate() == Isolate::Current());
__ enter(Immediate(0));
__ LoadObject(CTX, context);
__ PushObject(smi1); // Push argument 1 smi1.
__ PushObject(smi2); // Push argument 2 smi2.
__ PushObject(result); // Push Null object for return value.
// Pass a pointer to the first argument in RAX.
__ leaq(RAX, Address(RSP, 2 * kWordSize));
__ movq(RBX, Immediate(reinterpret_cast<uword>(native_function)));
__ movq(R10, Immediate(argc));
__ call(&StubCode::CallNativeCFunctionLabel());
__ popq(RAX); // Pop return value from return slot.
__ AddImmediate(RSP, Immediate(argc * kWordSize));
__ leave();
__ ret();
}
TEST_CASE(CallNativeCFunctionStubCode) {
extern const Function& RegisterFakeFunction(const char* name,
const Code& code);
const int value1 = 15;
const int value2 = 20;
const char* kName = "Test_CallNativeCFunctionStubCode";
Assembler _assembler_;
GenerateCallToCallNativeCFunctionStub(&_assembler_, value1, value2);
const Code& code = Code::Handle(
Code::FinalizeCode(kName, &_assembler_));
const Function& function = RegisterFakeFunction(kName, code);
GrowableArray<const Object*> arguments;
const Array& kNoArgumentNames = Array::Handle();
Smi& result = Smi::Handle();
result ^= DartEntry::InvokeStatic(function, arguments, kNoArgumentNames);
EXPECT_EQ((value1 - value2), result.Value());
}
} // namespace dart
#endif // defined TARGET_ARCH_X64

View file

@ -219,10 +219,11 @@
'store_buffer.h',
'stub_code.cc',
'stub_code.h',
'stub_code_ia32.cc',
'stub_code_arm.cc',
'stub_code_x64.cc',
'stub_code_ia32.cc',
'stub_code_ia32_test.cc',
'stub_code_x64.cc',
'stub_code_x64_test.cc',
'thread.h',
'thread_linux.cc',
'thread_linux.h',