mirror of
https://github.com/dart-lang/sdk
synced 2024-09-19 20:51:50 +00:00
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:
parent
f7419664c4
commit
ec7f6331d1
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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; \
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
115
runtime/vm/stub_code_x64_test.cc
Normal file
115
runtime/vm/stub_code_x64_test.cc
Normal 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
|
|
@ -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',
|
||||
|
|
Loading…
Reference in a new issue