Sets a register aside on x64 for use as a pool-pointer. It is loaded and restored from the code object on Frame entry and exit. All LoadObject calls that can, and many calls and jumps through ExternalLabels now use the pool-pointer. The --compiler-stats flag when running dart2js indicates that code size is reduced ~13%, and more is probably possible.

R=fschneider@google.com, srdjan@google.com

Review URL: https://codereview.chromium.org//22825023

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@27295 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
zra@google.com
2013-09-09 15:39:26 +00:00
parent 99b8252f45
commit df2054dae7
34 changed files with 1032 additions and 560 deletions
+3
View File
@@ -48,6 +48,9 @@ dart/inline_stack_frame_test: Fail
# Skip until we stabilize language tests.
*: Skip
[ $arch == x64 && $mode == debug ]
cc/FindCodeObject: Timeout # Issue 13144
[ $arch == simarm ]
dart/isolate_mirror_local_test: Skip
+271 -62
View File
@@ -65,6 +65,47 @@ void CPUFeatures::InitOnce() {
#undef __
Assembler::Assembler(bool use_far_branches)
: buffer_(),
object_pool_(GrowableObjectArray::Handle()),
patchable_pool_entries_(),
prologue_offset_(-1),
comments_() {
// Far branching mode is only needed and implemented for MIPS and ARM.
ASSERT(!use_far_branches);
if (Isolate::Current() != Dart::vm_isolate()) {
object_pool_ = GrowableObjectArray::New(Heap::kOld);
// These objects and labels need to be accessible through every pool-pointer
// at the same index.
object_pool_.Add(Object::Handle(), Heap::kOld);
patchable_pool_entries_.Add(kNotPatchable);
object_pool_.Add(Bool::True(), Heap::kOld);
patchable_pool_entries_.Add(kNotPatchable);
object_pool_.Add(Bool::False(), Heap::kOld);
patchable_pool_entries_.Add(kNotPatchable);
if (StubCode::UpdateStoreBuffer_entry() != NULL) {
FindExternalLabel(&StubCode::UpdateStoreBufferLabel(), kNotPatchable);
patchable_pool_entries_.Add(kNotPatchable);
} else {
object_pool_.Add(Object::Handle(), Heap::kOld);
patchable_pool_entries_.Add(kNotPatchable);
}
if (StubCode::CallToRuntime_entry() != NULL) {
FindExternalLabel(&StubCode::CallToRuntimeLabel(), kNotPatchable);
patchable_pool_entries_.Add(kNotPatchable);
} else {
object_pool_.Add(Object::Handle(), Heap::kOld);
patchable_pool_entries_.Add(kNotPatchable);
}
}
}
void Assembler::InitializeMemoryWithBreakpoints(uword data, int length) {
memset(reinterpret_cast<void*>(data), Instr::kBreakPointInstruction, length);
}
@@ -95,25 +136,45 @@ void Assembler::call(Label* label) {
}
void Assembler::LoadExternalLabel(Register dst,
const ExternalLabel* label,
Patchability patchable,
Register pp) {
const int32_t offset =
Array::element_offset(FindExternalLabel(label, patchable));
LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag);
}
void Assembler::call(const ExternalLabel* label) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
{ // Encode movq(TMP, Immediate(label->address())), but always as imm64.
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(TMP, REX_W);
EmitUint8(0xB8 | (TMP & 7));
EmitInt64(label->address());
}
call(TMP);
}
void Assembler::CallPatchable(const ExternalLabel* label) {
intptr_t call_start = buffer_.GetPosition();
// Encode movq(TMP, Immediate(label->address())), but always as imm64.
EmitRegisterREX(TMP, REX_W);
EmitUint8(0xB8 | (TMP & 7));
EmitInt64(label->address());
// Encode call(TMP).
Operand operand(TMP);
EmitOperandREX(2, operand, REX_NONE);
EmitUint8(0xFF);
EmitOperand(2, operand);
LoadExternalLabel(TMP, label, kPatchable, PP);
call(TMP);
ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize);
}
void Assembler::Call(const ExternalLabel* label, Register pp) {
if (Isolate::Current() == Dart::vm_isolate()) {
call(label);
} else {
LoadExternalLabel(TMP, label, kNotPatchable, pp);
call(TMP);
}
}
void Assembler::pushq(Register reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(reg, REX_NONE);
@@ -1960,6 +2021,15 @@ void Assembler::j(Condition condition, const ExternalLabel* label) {
}
void Assembler::J(Condition condition, const ExternalLabel* label,
Register pp) {
Label no_jump;
j(static_cast<Condition>(condition ^ 1), &no_jump); // Negate condition.
Jmp(label, pp);
Bind(&no_jump);
}
void Assembler::jmp(Register reg) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
Operand operand(reg);
@@ -1994,24 +2064,30 @@ void Assembler::jmp(Label* label, bool near) {
void Assembler::jmp(const ExternalLabel* label) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
{ // Encode movq(TMP, Immediate(label->address())), but always as imm64.
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(TMP, REX_W);
EmitUint8(0xB8 | (TMP & 7));
EmitInt64(label->address());
}
jmp(TMP);
}
void Assembler::JmpPatchable(const ExternalLabel* label, Register pp) {
intptr_t call_start = buffer_.GetPosition();
// Encode movq(TMP, Immediate(label->address())), but always as imm64.
EmitRegisterREX(TMP, REX_W);
EmitUint8(0xB8 | (TMP & 7));
EmitInt64(label->address());
// Encode jmp(TMP).
Operand operand(TMP);
EmitOperandREX(4, operand, REX_NONE);
EmitUint8(0xFF);
EmitOperand(4, operand);
LoadExternalLabel(TMP, label, kPatchable, pp);
jmp(TMP);
ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize);
}
void Assembler::Jmp(const ExternalLabel* label, Register pp) {
LoadExternalLabel(TMP, label, kNotPatchable, pp);
jmp(TMP);
}
void Assembler::lock() {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF0);
@@ -2091,49 +2167,103 @@ void Assembler::Drop(intptr_t stack_elements) {
}
void Assembler::LoadObject(Register dst, const Object& object) {
if (object.IsSmi() || object.InVMHeap()) {
movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
intptr_t Assembler::FindObject(const Object& obj, Patchability patchable) {
// The object pool cannot be used in the vm isolate.
ASSERT(Isolate::Current() != Dart::vm_isolate());
ASSERT(!object_pool_.IsNull());
// TODO(zra): This can be slow. Add a hash map from obj.raw() to
// object pool indexes to speed lookup.
for (int i = 0; i < object_pool_.Length(); i++) {
if ((object_pool_.At(i) == obj.raw()) &&
(patchable_pool_entries_[i] != kPatchable)) {
return i;
}
}
object_pool_.Add(obj, Heap::kOld);
patchable_pool_entries_.Add(patchable);
return object_pool_.Length() - 1;
}
intptr_t Assembler::FindExternalLabel(const ExternalLabel* label,
Patchability patchable) {
// The object pool cannot be used in the vm isolate.
ASSERT(Isolate::Current() != Dart::vm_isolate());
ASSERT(!object_pool_.IsNull());
const uword address = label->address();
ASSERT(Utils::IsAligned(address, 4));
// The address is stored in the object array as a RawSmi.
const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(address));
if (patchable == kNotPatchable) {
return FindObject(smi, kNotPatchable);
}
// If the call is patchable, do not reuse an existing entry since each
// reference may be patched independently.
object_pool_.Add(smi, Heap::kOld);
patchable_pool_entries_.Add(patchable);
return object_pool_.Length() - 1;
}
bool Assembler::CanLoadFromObjectPool(const Object& object) {
return !object.IsSmi() && // Not a Smi
// Not in the VMHeap, OR is one of the VMHeap objects we put in every
// object pool.
(!object.InVMHeap() || (object.raw() == Object::null()) ||
(object.raw() == Bool::True().raw()) ||
(object.raw() == Bool::False().raw())) &&
object.IsNotTemporaryScopedHandle() &&
object.IsOld();
}
void Assembler::LoadWordFromPoolOffset(Register dst, Register pp,
int32_t offset) {
// This sequence must be of fixed size. AddressBaseImm32
// forces the address operand to use a fixed-size imm32 encoding.
movq(dst, Address::AddressBaseImm32(pp, offset));
}
void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
if (CanLoadFromObjectPool(object)) {
const int32_t offset =
Array::element_offset(FindObject(object, kNotPatchable));
LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag);
} else {
ASSERT(object.IsNotTemporaryScopedHandle());
ASSERT(object.IsOld());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitRegisterREX(dst, REX_W);
EmitUint8(0xB8 | (dst & 7));
buffer_.EmitObject(object);
movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
void Assembler::StoreObject(const Address& dst, const Object& object) {
if (object.IsSmi() || object.InVMHeap()) {
movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
} else {
ASSERT(object.IsNotTemporaryScopedHandle());
ASSERT(object.IsOld());
LoadObject(TMP, object);
if (CanLoadFromObjectPool(object)) {
LoadObject(TMP, object, PP);
movq(dst, TMP);
} else {
movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
void Assembler::PushObject(const Object& object) {
if (object.IsSmi() || object.InVMHeap()) {
pushq(Immediate(reinterpret_cast<int64_t>(object.raw())));
} else {
LoadObject(TMP, object);
if (CanLoadFromObjectPool(object)) {
LoadObject(TMP, object, PP);
pushq(TMP);
} else {
pushq(Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
void Assembler::CompareObject(Register reg, const Object& object) {
if (object.IsSmi() || object.InVMHeap()) {
cmpq(reg, Immediate(reinterpret_cast<int64_t>(object.raw())));
} else {
if (CanLoadFromObjectPool(object)) {
ASSERT(reg != TMP);
LoadObject(TMP, object);
LoadObject(TMP, object, PP);
cmpq(reg, TMP);
} else {
cmpq(reg, Immediate(reinterpret_cast<int64_t>(object.raw())));
}
}
@@ -2196,7 +2326,7 @@ void Assembler::StoreIntoObject(Register object,
if (object != RAX) {
movq(RAX, object);
}
call(&StubCode::UpdateStoreBufferLabel());
Call(&StubCode::UpdateStoreBufferLabel(), PP);
if (value != RAX) popq(RAX);
Bind(&done);
}
@@ -2298,6 +2428,23 @@ void Assembler::LeaveFrame() {
}
void Assembler::LeaveFrameWithPP() {
movq(PP, Address(RBP, -2 * kWordSize));
LeaveFrame();
}
void Assembler::ReturnPatchable() {
// This sequence must have a fixed size so that it can be patched by the
// debugger.
intptr_t start = buffer_.GetPosition();
LeaveFrameWithPP();
ret();
nop(4);
ASSERT((buffer_.GetPosition() - start) == 13);
}
void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) {
// Reserve space for arguments and align frame before entering
// the C++ world.
@@ -2378,18 +2525,59 @@ void Assembler::CallRuntime(const RuntimeEntry& entry,
}
void Assembler::LoadPoolPointer(Register pp) {
Label next;
call(&next);
Bind(&next);
// Load new pool pointer.
const intptr_t object_pool_pc_dist =
Instructions::HeaderSize() - Instructions::object_pool_offset() +
CodeSize();
popq(pp);
movq(pp, Address(pp, -object_pool_pc_dist));
}
void Assembler::EnterDartFrame(intptr_t frame_size) {
EnterFrame(0);
Label dart_entry;
call(&dart_entry);
Bind(&dart_entry);
// The runtime system assumes that the code marker address is
// kEntryPointToPcMarkerOffset bytes from the entry. If there is any code
// generated before entering the frame, the address needs to be adjusted.
const intptr_t object_pool_pc_dist =
Instructions::HeaderSize() - Instructions::object_pool_offset() +
CodeSize();
const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
if (offset != 0) {
addq(Address(RSP, 0), Immediate(offset));
}
// Save caller's pool pointer
pushq(PP);
// Load callee's pool pointer.
movq(PP, Address(RSP, 1 * kWordSize));
movq(PP, Address(PP, -object_pool_pc_dist - offset));
if (frame_size != 0) {
subq(RSP, Immediate(frame_size));
}
}
void Assembler::EnterDartFrameWithInfo(intptr_t frame_size,
Register new_pp, Register new_pc) {
if (new_pc == kNoRegister) {
EnterDartFrame(0);
} else {
EnterFrame(0);
pushq(new_pc);
pushq(PP);
movq(PP, new_pp);
}
if (frame_size != 0) {
subq(RSP, Immediate(frame_size));
}
@@ -2401,18 +2589,32 @@ void Assembler::EnterDartFrame(intptr_t frame_size) {
// pointer is already set up. The PC marker is not correct for the
// optimized function and there may be extra space for spill slots to
// allocate.
void Assembler::EnterOsrFrame(intptr_t extra_size) {
Label dart_entry;
call(&dart_entry);
Bind(&dart_entry);
// The runtime system assumes that the code marker address is
// kEntryPointToPcMarkerOffset bytes from the entry. Since there is no
// code to set up the frame pointer, the address needs to be adjusted.
const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
if (offset != 0) {
addq(Address(RSP, 0), Immediate(offset));
void Assembler::EnterOsrFrame(intptr_t extra_size,
Register new_pp, Register new_pc) {
if (new_pc == kNoRegister) {
Label dart_entry;
call(&dart_entry);
Bind(&dart_entry);
// The runtime system assumes that the code marker address is
// kEntryPointToPcMarkerOffset bytes from the entry. Since there is no
// code to set up the frame pointer, the address needs to be adjusted.
const intptr_t object_pool_pc_dist =
Instructions::HeaderSize() - Instructions::object_pool_offset() +
CodeSize();
const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
if (offset != 0) {
addq(Address(RSP, 0), Immediate(offset));
}
// Load callee's pool pointer.
movq(PP, Address(RSP, 0));
movq(PP, Address(PP, -object_pool_pc_dist - offset));
popq(Address(RBP, kPcMarkerSlotFromFp * kWordSize));
} else {
movq(Address(RBP, kPcMarkerSlotFromFp * kWordSize), new_pc);
movq(PP, new_pp);
}
popq(Address(RBP, kPcMarkerSlotFromFp * kWordSize));
if (extra_size != 0) {
subq(RSP, Immediate(extra_size));
}
@@ -2425,6 +2627,14 @@ void Assembler::EnterStubFrame() {
}
void Assembler::EnterStubFrameWithPP() {
EnterFrame(0);
pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames.
pushq(PP); // Save caller's pool pointer
LoadPoolPointer(PP);
}
void Assembler::TryAllocate(const Class& cls,
Label* failure,
bool near_jump,
@@ -2647,7 +2857,6 @@ const char* Assembler::FpuRegisterName(FpuRegister reg) {
return xmm_reg_names[reg];
}
} // namespace dart
#endif // defined TARGET_ARCH_X64
+57 -13
View File
@@ -212,6 +212,20 @@ class Address : public Operand {
Operand::operator=(other);
return *this;
}
static Address AddressBaseImm32(Register base, int32_t disp) {
return Address(base, disp, true);
}
private:
Address(Register base, int32_t disp, bool fixed) {
ASSERT(fixed);
SetModRM(2, base);
if ((base & 7) == RSP) {
SetSIB(TIMES_1, RSP, base);
}
SetDisp32(disp);
}
};
@@ -321,14 +335,8 @@ class CPUFeatures : public AllStatic {
class Assembler : public ValueObject {
public:
explicit Assembler(bool use_far_branches = false)
: buffer_(),
object_pool_(GrowableObjectArray::Handle()),
prologue_offset_(-1),
comments_() {
// This mode is only needed and implemented for MIPS and ARM.
ASSERT(!use_far_branches);
}
explicit Assembler(bool use_far_branches = false);
~Assembler() { }
static const bool kNearJump = true;
@@ -342,7 +350,7 @@ class Assembler : public ValueObject {
void call(Label* label);
void call(const ExternalLabel* label);
static const intptr_t kCallExternalLabelSize = 13;
static const intptr_t kCallExternalLabelSize = 10;
void pushq(Register reg);
void pushq(const Address& address);
@@ -652,7 +660,17 @@ class Assembler : public ValueObject {
void Drop(intptr_t stack_elements);
void LoadObject(Register dst, const Object& object);
enum Patchability {
kPatchable,
kNotPatchable,
};
void LoadObject(Register dst, const Object& obj, Register pp);
void JmpPatchable(const ExternalLabel* label, Register pp);
void Jmp(const ExternalLabel* label, Register pp);
void J(Condition condition, const ExternalLabel* label, Register pp);
void CallPatchable(const ExternalLabel* label);
void Call(const ExternalLabel* label, Register pp);
void StoreObject(const Address& dst, const Object& obj);
void PushObject(const Object& object);
void CompareObject(Register reg, const Object& object);
@@ -680,6 +698,8 @@ class Assembler : public ValueObject {
void EnterFrame(intptr_t frame_space);
void LeaveFrame();
void LeaveFrameWithPP();
void ReturnPatchable();
void ReserveAlignedFrameSpace(intptr_t frame_space);
// Create a frame for calling into runtime that preserves all volatile
@@ -731,6 +751,8 @@ class Assembler : public ValueObject {
buffer_.FinalizeInstructions(region);
}
void LoadPoolPointer(Register pp);
// Set up a Dart frame on entry with a frame pointer and PC information to
// enable easy access to the RawInstruction object of code corresponding
// to this frame.
@@ -739,6 +761,7 @@ class Assembler : public ValueObject {
// ret PC
// saved RBP <=== RBP
// pc (used to derive the RawInstruction Object of the dart code)
// saved PP
// locals space <=== RSP
// .....
// This code sets this up with the sequence:
@@ -746,13 +769,17 @@ class Assembler : public ValueObject {
// movq rbp, rsp
// call L
// L: <code to adjust saved pc if there is any intrinsification code>
// ...
// pushq r15
// .....
void EnterDartFrame(intptr_t frame_size);
void EnterDartFrameWithInfo(intptr_t frame_size,
Register new_pp, Register new_pc);
// Set up a Dart frame for a function compiled for on-stack replacement.
// The frame layout is a normal Dart frame, but the frame is partially set
// up on entry (it is the frame of the unoptimized code).
void EnterOsrFrame(intptr_t extra_size);
void EnterOsrFrame(intptr_t extra_size, Register new_pp, Register new_pc);
// Set up a stub frame so that the stack traversal code can easily identify
// a stub frame.
@@ -768,8 +795,9 @@ class Assembler : public ValueObject {
// pushq immediate(0)
// .....
void EnterStubFrame();
void EnterStubFrameWithPP();
// Instruction pattern from entrypoint is used in dart frame prologs
// Instruction pattern from entrypoint is used in dart frame prologues
// to set up the frame and save a PC which can be used to figure out the
// RawInstruction object corresponding to the code running in the frame.
// entrypoint:
@@ -802,7 +830,13 @@ class Assembler : public ValueObject {
private:
AssemblerBuffer buffer_;
GrowableObjectArray& object_pool_; // Object pool is not used on x64.
// Objects and jump targets.
GrowableObjectArray& object_pool_;
// Patchability of pool entries.
GrowableArray<Patchability> patchable_pool_entries_;
int prologue_offset_;
class CodeComment : public ZoneAllocated {
@@ -822,6 +856,16 @@ class Assembler : public ValueObject {
GrowableArray<CodeComment*> comments_;
intptr_t FindObject(const Object& obj, Patchability patchable);
intptr_t FindExternalLabel(const ExternalLabel* label,
Patchability patchable);
void LoadExternalLabel(Register dst,
const ExternalLabel* label,
Patchability patchable,
Register pp);
bool CanLoadFromObjectPool(const Object& object);
void LoadWordFromPoolOffset(Register dst, Register pp, int32_t offset);
inline void EmitUint8(uint8_t value);
inline void EmitInt32(int32_t value);
inline void EmitInt64(int64_t value);
+30 -3
View File
@@ -200,6 +200,28 @@ ASSEMBLER_TEST_GENERATE(AddressingModes, assembler) {
__ 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));
__ movq(RAX, Address::AddressBaseImm32(RSP, 0));
__ movq(RAX, Address::AddressBaseImm32(RBP, 0));
__ movq(RAX, Address::AddressBaseImm32(RAX, 0));
__ movq(RAX, Address::AddressBaseImm32(R10, 0));
__ movq(RAX, Address::AddressBaseImm32(R12, 0));
__ movq(RAX, Address::AddressBaseImm32(R13, 0));
__ movq(R10, Address::AddressBaseImm32(RAX, 0));
__ movq(RAX, Address::AddressBaseImm32(RSP, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RBP, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RAX, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R10, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R12, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R13, kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RSP, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RBP, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(RAX, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R10, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R12, -kWordSize));
__ movq(RAX, Address::AddressBaseImm32(R13, -kWordSize));
}
@@ -2159,14 +2181,15 @@ ASSEMBLER_TEST_GENERATE(TestObjectCompare, assembler) {
ObjectStore* object_store = Isolate::Current()->object_store();
const Object& obj = Object::ZoneHandle(object_store->smi_class());
Label fail;
__ LoadObject(RAX, obj);
__ EnterDartFrame(0);
__ LoadObject(RAX, obj, PP);
__ CompareObject(RAX, obj);
__ j(NOT_EQUAL, &fail);
__ LoadObject(RCX, obj);
__ LoadObject(RCX, obj, PP);
__ CompareObject(RCX, obj);
__ j(NOT_EQUAL, &fail);
const Smi& smi = Smi::ZoneHandle(Smi::New(15));
__ LoadObject(RCX, smi);
__ LoadObject(RCX, smi, PP);
__ CompareObject(RCX, smi);
__ j(NOT_EQUAL, &fail);
__ pushq(RAX);
@@ -2180,9 +2203,11 @@ ASSEMBLER_TEST_GENERATE(TestObjectCompare, assembler) {
__ CompareObject(RCX, smi);
__ j(NOT_EQUAL, &fail);
__ movl(RAX, Immediate(1)); // OK
__ LeaveFrameWithPP();
__ ret();
__ Bind(&fail);
__ movl(RAX, Immediate(0)); // Fail.
__ LeaveFrameWithPP();
__ ret();
}
@@ -2393,12 +2418,14 @@ ASSEMBLER_TEST_RUN(SquareRootDouble, test) {
// Called from assembler_test.cc.
ASSEMBLER_TEST_GENERATE(StoreIntoObject, assembler) {
__ EnterDartFrame(0);
__ pushq(CTX);
__ movq(CTX, RDI);
__ StoreIntoObject(RDX,
FieldAddress(RDX, GrowableObjectArray::data_offset()),
RSI);
__ popq(CTX);
__ LeaveFrameWithPP();
__ ret();
}
+5 -5
View File
@@ -29,11 +29,11 @@ void CodePatcher::PatchEntry(const Code& code) {
const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
PcDescriptors::kEntryPatch);
ASSERT(patch_addr != 0);
JumpPattern jmp_entry(patch_addr);
JumpPattern jmp_entry(patch_addr, code);
ASSERT(!jmp_entry.IsValid());
const uword patch_buffer = code.GetPatchCodePc();
ASSERT(patch_buffer != 0);
JumpPattern jmp_patch(patch_buffer);
JumpPattern jmp_patch(patch_buffer, code);
ASSERT(jmp_patch.IsValid());
const uword jump_target = jmp_patch.TargetAddress();
SwapCode(jmp_patch.pattern_length_in_bytes(),
@@ -49,13 +49,13 @@ void CodePatcher::RestoreEntry(const Code& code) {
const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
PcDescriptors::kEntryPatch);
ASSERT(patch_addr != 0);
JumpPattern jmp_entry(patch_addr);
JumpPattern jmp_entry(patch_addr, code);
ASSERT(jmp_entry.IsValid());
const uword jump_target = jmp_entry.TargetAddress();
const uword patch_buffer = code.GetPatchCodePc();
ASSERT(patch_buffer != 0);
// 'patch_buffer' contains original entry code.
JumpPattern jmp_patch(patch_buffer);
JumpPattern jmp_patch(patch_buffer, code);
ASSERT(!jmp_patch.IsValid());
SwapCode(jmp_patch.pattern_length_in_bytes(),
reinterpret_cast<char*>(patch_addr),
@@ -72,7 +72,7 @@ bool CodePatcher::CodeIsPatchable(const Code& code) {
if (patch_addr == 0) {
return true;
}
JumpPattern jmp_entry(patch_addr);
JumpPattern jmp_entry(patch_addr, code);
if (code.Size() < (jmp_entry.pattern_length_in_bytes() * 2)) {
return false;
}
+60 -48
View File
@@ -16,53 +16,60 @@
namespace dart {
// The expected pattern of a Dart unoptimized call (static and instance):
// 00: 48 bb imm64 mov RBX, ic-data
// 10: 49 bb imm64 mov R11, target_address
// 20: 41 ff d3 call R11
// 23 <- return address
// 00: 49 8b 9f imm32 mov RBX, [PP + off]
// 07: 4d 8b 9f imm32 mov R11, [PP + off]
// 14: 41 ff d3 call R11
// 17 <- return address
class UnoptimizedCall : public ValueObject {
public:
explicit UnoptimizedCall(uword return_address)
: start_(return_address - kCallPatternSize) {
UnoptimizedCall(uword return_address, const Code& code)
: start_(return_address - kCallPatternSize),
object_pool_(Array::Handle(code.ObjectPool())) {
ASSERT(IsValid(return_address));
ASSERT((kCallPatternSize - 10) == Assembler::kCallExternalLabelSize);
ASSERT((kCallPatternSize - 7) == Assembler::kCallExternalLabelSize);
}
static const int kCallPatternSize = 23;
static const int kCallPatternSize = 17;
static bool IsValid(uword return_address) {
uint8_t* code_bytes =
reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
return (code_bytes[00] == 0x48) && (code_bytes[01] == 0xBB) &&
(code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) &&
(code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) &&
(code_bytes[22] == 0xD3);
return (code_bytes[0] == 0x49) && (code_bytes[1] == 0x8B) &&
(code_bytes[2] == 0x9F) &&
(code_bytes[7] == 0x4D) && (code_bytes[8] == 0x8B) &&
(code_bytes[9] == 0x9F) &&
(code_bytes[14] == 0x41) && (code_bytes[15] == 0xFF) &&
(code_bytes[16] == 0xD3);
}
RawObject* ic_data() const {
return *reinterpret_cast<RawObject**>(start_ + 0 + 2);
int index = InstructionPattern::IndexFromPPLoad(start_ + 3);
return object_pool_.At(index);
}
uword target() const {
return *reinterpret_cast<uword*>(start_ + 10 + 2);
int index = InstructionPattern::IndexFromPPLoad(start_ + 10);
return reinterpret_cast<uword>(object_pool_.At(index));
}
void set_target(uword target) const {
uword* target_addr = reinterpret_cast<uword*>(start_ + 10 + 2);
*target_addr = target;
CPU::FlushICache(start_ + 10, 2 + 8);
int index = InstructionPattern::IndexFromPPLoad(start_ + 10);
const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target));
object_pool_.SetAt(index, smi);
// No need to flush the instruction cache, since the code is not modified.
}
private:
uword start_;
const Array& object_pool_;
DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall);
};
class InstanceCall : public UnoptimizedCall {
public:
explicit InstanceCall(uword return_address)
: UnoptimizedCall(return_address) {
InstanceCall(uword return_address, const Code& code)
: UnoptimizedCall(return_address, code) {
#if defined(DEBUG)
ICData& test_ic_data = ICData::Handle();
test_ic_data ^= ic_data();
@@ -77,8 +84,8 @@ class InstanceCall : public UnoptimizedCall {
class UnoptimizedStaticCall : public UnoptimizedCall {
public:
explicit UnoptimizedStaticCall(uword return_address)
: UnoptimizedCall(return_address) {
UnoptimizedStaticCall(uword return_address, const Code& code)
: UnoptimizedCall(return_address, code) {
#if defined(DEBUG)
ICData& test_ic_data = ICData::Handle();
test_ic_data ^= ic_data();
@@ -92,50 +99,54 @@ class UnoptimizedStaticCall : public UnoptimizedCall {
// The expected pattern of a dart static call:
// mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls)
// mov R11, target_address (10 bytes)
// call R11 (3 bytes)
// 00 mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls)
// 11: 4d 8b 9f imm32 mov R11, [PP + off]
// 16: call R11 (3 bytes)
// <- return address
class StaticCall : public ValueObject {
public:
explicit StaticCall(uword return_address)
: start_(return_address - kCallPatternSize) {
explicit StaticCall(uword return_address, const Code& code)
: start_(return_address - kCallPatternSize),
object_pool_(Array::Handle(code.ObjectPool())) {
ASSERT(IsValid(return_address));
ASSERT(kCallPatternSize == Assembler::kCallExternalLabelSize);
}
static const int kCallPatternSize = 13;
static const int kCallPatternSize = 10;
static bool IsValid(uword return_address) {
uint8_t* code_bytes =
reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBB) &&
(code_bytes[10] == 0x41) && (code_bytes[11] == 0xFF) &&
(code_bytes[12] == 0xD3);
return (code_bytes[0] == 0x4D) && (code_bytes[1] == 0x8B) &&
(code_bytes[2] == 0x9F) &&
(code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) &&
(code_bytes[9] == 0xD3);
}
uword target() const {
return *reinterpret_cast<uword*>(start_ + 2);
int index = InstructionPattern::IndexFromPPLoad(start_ + 3);
return reinterpret_cast<uword>(object_pool_.At(index));
}
void set_target(uword target) const {
uword* target_addr = reinterpret_cast<uword*>(start_ + 2);
*target_addr = target;
CPU::FlushICache(start_, 2 + 8);
int index = InstructionPattern::IndexFromPPLoad(start_ + 3);
const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target));
object_pool_.SetAt(index, smi);
// No need to flush the instruction cache, since the code is not modified.
}
private:
uword start_;
const Array& object_pool_;
DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall);
};
// The expected code pattern of a dart closure call:
// 00: 49 ba imm64 mov R10, immediate 2 ; 10 bytes
// 10: 49 bb imm64 mov R11, target_address ; 10 bytes
// 20: 41 ff d3 call R11 ; 3 bytes
// 23: <- return_address
// 00: 49 ba imm64 mov R10, immediate 2 ; 10 bytes
// 10: 4d 8b 9f imm32 mov R11, [PP + off]
// 17: 41 ff d3 call R11 ; 3 bytes
// 20: <- return_address
class ClosureCall : public ValueObject {
public:
explicit ClosureCall(uword return_address)
@@ -147,9 +158,10 @@ class ClosureCall : public ValueObject {
uint8_t* code_bytes =
reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBA) &&
(code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) &&
(code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) &&
(code_bytes[22] == 0xD3);
(code_bytes[10] == 0x4D) && (code_bytes[11] == 0x8B) &&
(code_bytes[12] == 0x9F) &&
(code_bytes[17] == 0x41) && (code_bytes[18] == 0xFF) &&
(code_bytes[19] == 0xD3);
}
RawArray* arguments_descriptor() const {
@@ -157,7 +169,7 @@ class ClosureCall : public ValueObject {
}
private:
static const int kCallPatternSize = 10 + 10 + 3;
static const int kCallPatternSize = 10 + 7 + 3;
uword start_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ClosureCall);
};
@@ -174,7 +186,7 @@ RawArray* CodePatcher::GetClosureArgDescAt(uword return_address,
uword CodePatcher::GetStaticCallTargetAt(uword return_address,
const Code& code) {
ASSERT(code.ContainsInstructionAt(return_address));
StaticCall call(return_address);
StaticCall call(return_address, code);
return call.target();
}
@@ -183,7 +195,7 @@ void CodePatcher::PatchStaticCallAt(uword return_address,
const Code& code,
uword new_target) {
ASSERT(code.ContainsInstructionAt(return_address));
StaticCall call(return_address);
StaticCall call(return_address, code);
call.set_target(new_target);
}
@@ -192,7 +204,7 @@ void CodePatcher::PatchInstanceCallAt(uword return_address,
const Code& code,
uword new_target) {
ASSERT(code.ContainsInstructionAt(return_address));
InstanceCall call(return_address);
InstanceCall call(return_address, code);
call.set_target(new_target);
}
@@ -201,7 +213,7 @@ uword CodePatcher::GetInstanceCallAt(uword return_address,
const Code& code,
ICData* ic_data) {
ASSERT(code.ContainsInstructionAt(return_address));
InstanceCall call(return_address);
InstanceCall call(return_address, code);
if (ic_data != NULL) {
*ic_data ^= call.ic_data();
}
@@ -227,7 +239,7 @@ void CodePatcher::InsertCallAt(uword start, uword target) {
RawFunction* CodePatcher::GetUnoptimizedStaticCallAt(
uword return_address, const Code& code, ICData* ic_data_result) {
ASSERT(code.ContainsInstructionAt(return_address));
UnoptimizedStaticCall static_call(return_address);
UnoptimizedStaticCall static_call(return_address, code);
ICData& ic_data = ICData::Handle();
ic_data ^= static_call.ic_data();
if (ic_data_result != NULL) {
+2 -2
View File
@@ -39,10 +39,10 @@ ASSEMBLER_TEST_GENERATE(IcDataAccess, assembler) {
15,
1));
__ LoadObject(RBX, ic_data);
__ LoadObject(RBX, ic_data, PP);
ExternalLabel target_label(
"InlineCache", StubCode::OneArgCheckInlineCacheEntryPoint());
__ call(&target_label);
__ CallPatchable(&target_label);
__ ret();
}
+3 -2
View File
@@ -85,8 +85,9 @@ enum RexBits {
// Register aliases.
const Register TMP = R11; // Used as scratch register by the assembler.
const Register CTX = R15; // Caches current context in generated code.
const Register PP = kNoRegister; // No object pool pointer.
const Register CTX = R14; // Caches current context in generated code.
// Caches object pool pointer in generated code.
const Register PP = R15;
const Register SPREG = RSP; // Stack pointer register.
const Register FPREG = RBP; // Frame pointer register.
const Register ICREG = RBX; // IC data register.
+17 -23
View File
@@ -7,6 +7,7 @@
#include "vm/debugger.h"
#include "vm/assembler.h"
#include "vm/cpu.h"
#include "vm/stub_code.h"
@@ -42,16 +43,15 @@ RawObject* ActivationFrame::GetClosureObject(intptr_t num_actual_args) {
void CodeBreakpoint::PatchFunctionReturn() {
uint8_t* code = reinterpret_cast<uint8_t*>(pc_ - 13);
// movq %rbp,%rsp
ASSERT((code[0] == 0x48) && (code[1] == 0x89) && (code[2] == 0xec));
ASSERT(code[3] == 0x5d); // popq %rbp
ASSERT(code[4] == 0xc3); // ret
// Next 8 bytes are nop instructions
ASSERT((code[5] == 0x90) && (code[6] == 0x90) &&
(code[7] == 0x90) && (code[8] == 0x90) &&
(code[9] == 0x90) && (code[10] == 0x90) &&
(code[11] == 0x90) && (code[12] == 0x90));
// Smash code with call instruction and relative target address.
ASSERT((code[0] == 0x4c) && (code[1] == 0x8b) && (code[2] == 0x7d) &&
(code[3] == 0xf0)); // movq r15,[rbp-0x10]
ASSERT((code[4] == 0x48) && (code[5] == 0x89) &&
(code[6] == 0xec)); // mov rsp, rbp
ASSERT(code[7] == 0x5d); // pop rbp
ASSERT(code[8] == 0xc3); // ret
ASSERT((code[9] == 0x0F) && (code[10] == 0x1F) && (code[11] == 0x40) &&
(code[12] == 0x00)); // nops
// Smash code with call instruction and relative target address.
uword stub_addr = StubCode::BreakpointReturnEntryPoint();
code[0] = 0x49;
code[1] = 0xbb;
@@ -66,19 +66,13 @@ void CodeBreakpoint::PatchFunctionReturn() {
void CodeBreakpoint::RestoreFunctionReturn() {
uint8_t* code = reinterpret_cast<uint8_t*>(pc_ - 13);
ASSERT((code[0] == 0x49) && (code[1] == 0xbb));
code[0] = 0x48; // movq %rbp,%rsp
code[1] = 0x89;
code[2] = 0xec;
code[3] = 0x5d; // popq %rbp
code[4] = 0xc3; // ret
code[5] = 0x90; // nop
code[6] = 0x90; // nop
code[7] = 0x90; // nop
code[8] = 0x90; // nop
code[9] = 0x90; // nop
code[10] = 0x90; // nop
code[11] = 0x90; // nop
code[12] = 0x90; // nop
MemoryRegion code_region(reinterpret_cast<void*>(pc_ - 13), 13);
Assembler assembler;
assembler.ReturnPatchable();
assembler.FinalizeInstructions(code_region);
CPU::FlushICache(pc_ - 13, 13);
}
+1 -1
View File
@@ -14,7 +14,7 @@
namespace dart {
TEST_CASE(FindCodeObject) {
#if defined(TARGET_ARCH_IA32)
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
const int kLoopCount = 50000;
#else
const int kLoopCount = 25000;
-42
View File
@@ -633,48 +633,6 @@ void FlowGraphCompiler::GenerateStaticCall(intptr_t deopt_id,
}
void FlowGraphCompiler::EmitUnoptimizedStaticCall(
const Function& target_function,
const Array& arguments_descriptor,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
// TODO(srdjan): Improve performance of function recognition.
MethodRecognizer::Kind recognized_kind =
MethodRecognizer::RecognizeKind(target_function);
int num_args_checked = 0;
if ((recognized_kind == MethodRecognizer::kMathMin) ||
(recognized_kind == MethodRecognizer::kMathMax)) {
num_args_checked = 2;
}
const ICData& ic_data = ICData::ZoneHandle(
ICData::New(parsed_function().function(), // Caller function.
String::Handle(target_function.name()),
arguments_descriptor,
deopt_id,
num_args_checked)); // No arguments checked.
ic_data.AddTarget(target_function);
uword label_address = 0;
if (ic_data.num_args_tested() == 0) {
label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.num_args_tested() == 2) {
label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
ExternalLabel target_label("StaticCallICStub", label_address);
assembler()->LoadObject(ICREG, ic_data);
GenerateDartCall(deopt_id,
token_pos,
&target_label,
PcDescriptors::kUnoptStaticCall,
locs);
assembler()->Drop(argument_count);
}
void FlowGraphCompiler::GenerateNumberTypeCheck(Register kClassIdReg,
const AbstractType& type,
Label* is_instance_lbl,
+41
View File
@@ -1385,6 +1385,47 @@ void FlowGraphCompiler::EmitMegamorphicInstanceCall(
}
void FlowGraphCompiler::EmitUnoptimizedStaticCall(
const Function& target_function,
const Array& arguments_descriptor,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
// TODO(srdjan): Improve performance of function recognition.
MethodRecognizer::Kind recognized_kind =
MethodRecognizer::RecognizeKind(target_function);
int num_args_checked = 0;
if ((recognized_kind == MethodRecognizer::kMathMin) ||
(recognized_kind == MethodRecognizer::kMathMax)) {
num_args_checked = 2;
}
const ICData& ic_data = ICData::ZoneHandle(
ICData::New(parsed_function().function(), // Caller function.
String::Handle(target_function.name()),
arguments_descriptor,
deopt_id,
num_args_checked)); // No arguments checked.
ic_data.AddTarget(target_function);
uword label_address = 0;
if (ic_data.num_args_tested() == 0) {
label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.num_args_tested() == 2) {
label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
ExternalLabel target_label("StaticCallICStub", label_address);
__ LoadObject(R5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
&target_label,
PcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
}
void FlowGraphCompiler::EmitOptimizedStaticCall(
const Function& function,
const Array& arguments_descriptor,
+41
View File
@@ -1280,6 +1280,47 @@ void FlowGraphCompiler::GenerateCallRuntime(intptr_t token_pos,
}
void FlowGraphCompiler::EmitUnoptimizedStaticCall(
const Function& target_function,
const Array& arguments_descriptor,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
// TODO(srdjan): Improve performance of function recognition.
MethodRecognizer::Kind recognized_kind =
MethodRecognizer::RecognizeKind(target_function);
int num_args_checked = 0;
if ((recognized_kind == MethodRecognizer::kMathMin) ||
(recognized_kind == MethodRecognizer::kMathMax)) {
num_args_checked = 2;
}
const ICData& ic_data = ICData::ZoneHandle(
ICData::New(parsed_function().function(), // Caller function.
String::Handle(target_function.name()),
arguments_descriptor,
deopt_id,
num_args_checked)); // No arguments checked.
ic_data.AddTarget(target_function);
uword label_address = 0;
if (ic_data.num_args_tested() == 0) {
label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.num_args_tested() == 2) {
label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
ExternalLabel target_label("StaticCallICStub", label_address);
__ LoadObject(ECX, ic_data);
GenerateDartCall(deopt_id,
token_pos,
&target_label,
PcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
}
void FlowGraphCompiler::EmitOptimizedInstanceCall(
ExternalLabel* target_label,
const ICData& ic_data,
+41
View File
@@ -1432,6 +1432,47 @@ void FlowGraphCompiler::EmitMegamorphicInstanceCall(
}
void FlowGraphCompiler::EmitUnoptimizedStaticCall(
const Function& target_function,
const Array& arguments_descriptor,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
// TODO(srdjan): Improve performance of function recognition.
MethodRecognizer::Kind recognized_kind =
MethodRecognizer::RecognizeKind(target_function);
int num_args_checked = 0;
if ((recognized_kind == MethodRecognizer::kMathMin) ||
(recognized_kind == MethodRecognizer::kMathMax)) {
num_args_checked = 2;
}
const ICData& ic_data = ICData::ZoneHandle(
ICData::New(parsed_function().function(), // Caller function.
String::Handle(target_function.name()),
arguments_descriptor,
deopt_id,
num_args_checked)); // No arguments checked.
ic_data.AddTarget(target_function);
uword label_address = 0;
if (ic_data.num_args_tested() == 0) {
label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.num_args_tested() == 2) {
label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
ExternalLabel target_label("StaticCallICStub", label_address);
__ LoadObject(S5, ic_data);
GenerateDartCall(deopt_id,
token_pos,
&target_label,
PcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
}
void FlowGraphCompiler::EmitOptimizedStaticCall(
const Function& function,
const Array& arguments_descriptor,
+159 -84
View File
@@ -61,10 +61,9 @@ RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
// The real frame starts here.
builder->MarkFrameStart();
// Callee's PC marker is not used anymore. Pass Function::null() to set to 0.
// Current PP, FP, and PC.
builder->AddPp(current->function(), slot_ix++);
builder->AddPcMarker(Function::Handle(), slot_ix++);
// Current FP and PC.
builder->AddCallerFp(slot_ix++);
builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++);
@@ -80,13 +79,14 @@ RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++);
}
// Current PC marker and caller FP.
builder->AddPcMarker(current->function(), slot_ix++);
builder->AddCallerFp(slot_ix++);
Environment* previous = current;
current = current->outer();
while (current != NULL) {
// PP, FP, and PC.
builder->AddPp(current->function(), slot_ix++);
builder->AddPcMarker(previous->function(), slot_ix++);
builder->AddCallerFp(slot_ix++);
// For any outer environment the deopt id is that of the call instruction
// which is recorded in the outer environment.
builder->AddReturnAddress(current->function(),
@@ -110,10 +110,6 @@ RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
slot_ix++);
}
// PC marker and caller FP.
builder->AddPcMarker(current->function(), slot_ix++);
builder->AddCallerFp(slot_ix++);
// Iterate on the outer environment.
previous = current;
current = current->outer();
@@ -121,7 +117,11 @@ RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
// The previous pointer is now the outermost environment.
ASSERT(previous != NULL);
// For the outermost environment, set caller PC.
// For the outermost environment, set caller PC, caller PP, and caller FP.
builder->AddCallerPp(slot_ix++);
// PC marker.
builder->AddPcMarker(previous->function(), slot_ix++);
builder->AddCallerFp(slot_ix++);
builder->AddCallerPc(slot_ix++);
// For the outermost environment, set the incoming arguments.
@@ -146,7 +146,7 @@ void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler,
ASSERT(deopt_env() != NULL);
__ call(&StubCode::DeoptimizeLabel());
__ Call(&StubCode::DeoptimizeLabel(), PP);
set_pc_offset(assem->CodeSize());
__ int3();
#undef __
@@ -160,10 +160,8 @@ void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler,
void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
Label* is_true,
Label* is_false) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label fall_through;
__ cmpq(bool_register, raw_null);
__ CompareObject(bool_register, Object::Handle());
__ j(EQUAL, &fall_through, Assembler::kNearJump);
__ CompareObject(bool_register, Bool::True());
__ j(EQUAL, is_true);
@@ -182,22 +180,20 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
Label* is_not_instance_lbl) {
const SubtypeTestCache& type_test_cache =
SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ LoadObject(temp_reg, type_test_cache);
__ LoadObject(temp_reg, type_test_cache, PP);
__ pushq(temp_reg); // Subtype test cache.
__ pushq(instance_reg); // Instance.
if (test_kind == kTestTypeOneArg) {
ASSERT(type_arguments_reg == kNoRegister);
__ pushq(raw_null);
__ call(&StubCode::Subtype1TestCacheLabel());
__ PushObject(Object::Handle());
__ Call(&StubCode::Subtype1TestCacheLabel(), PP);
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(type_arguments_reg == kNoRegister);
__ pushq(raw_null);
__ call(&StubCode::Subtype2TestCacheLabel());
__ PushObject(Object::Handle());
__ Call(&StubCode::Subtype2TestCacheLabel(), PP);
} else if (test_kind == kTestTypeThreeArgs) {
__ pushq(type_arguments_reg);
__ call(&StubCode::Subtype3TestCacheLabel());
__ Call(&StubCode::Subtype3TestCacheLabel(), PP);
} else {
UNREACHABLE();
}
@@ -342,11 +338,9 @@ bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
}
if (type.IsFunctionType()) {
// Check if instance is a closure.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ LoadClassById(R13, kClassIdReg);
__ movq(R13, FieldAddress(R13, Class::signature_function_offset()));
__ cmpq(R13, raw_null);
__ CompareObject(R13, Object::Handle());
__ j(NOT_EQUAL, is_instance_lbl);
}
// Custom checking for numbers (Smi, Mint, Bigint and Double).
@@ -409,15 +403,13 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
__ Comment("UninstantiatedTypeTest");
ASSERT(!type.IsInstantiated());
// Skip check if destination is a dynamic type.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
if (type.IsTypeParameter()) {
const TypeParameter& type_param = TypeParameter::Cast(type);
// Load instantiator (or null) and instantiator type arguments on stack.
__ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
// RDX: instantiator type arguments.
// Check if type argument is dynamic.
__ cmpq(RDX, raw_null);
__ CompareObject(RDX, Object::Handle());
__ j(EQUAL, is_instance_lbl);
// Can handle only type arguments that are instances of TypeArguments.
// (runtime checks canonicalize type arguments).
@@ -430,7 +422,7 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
// Check if type argument is dynamic.
__ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()));
__ j(EQUAL, is_instance_lbl);
__ cmpq(RDI, raw_null);
__ CompareObject(RDI, Object::Handle());
__ j(EQUAL, is_instance_lbl);
const Type& object_type = Type::ZoneHandle(Type::ObjectType());
__ CompareObject(RDI, object_type);
@@ -570,8 +562,6 @@ void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
LocationSummary* locs) {
ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded());
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label is_instance, is_not_instance;
__ pushq(RCX); // Store instantiator on stack.
__ pushq(RDX); // Store instantiator type arguments.
@@ -585,7 +575,7 @@ void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
// We can only inline this null check if the type is instantiated at compile
// time, since an uninstantiated type at compile time could be Object or
// dynamic at run time.
__ cmpq(RAX, raw_null);
__ CompareObject(RAX, Object::Handle());
__ j(EQUAL, &is_not_instance);
}
@@ -605,7 +595,7 @@ void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
__ PushObject(type); // Push the type.
__ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null.
__ pushq(RDX); // Instantiator type arguments.
__ LoadObject(RAX, test_cache);
__ LoadObject(RAX, test_cache, PP);
__ pushq(RAX);
GenerateCallRuntime(token_pos,
deopt_id,
@@ -617,21 +607,21 @@ void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
__ Drop(5);
if (negate_result) {
__ popq(RDX);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ cmpq(RDX, RAX);
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
} else {
__ popq(RAX);
}
__ jmp(&done, Assembler::kNearJump);
}
__ Bind(&is_not_instance);
__ LoadObject(RAX, Bool::Get(negate_result));
__ LoadObject(RAX, Bool::Get(negate_result), PP);
__ jmp(&done, Assembler::kNearJump);
__ Bind(&is_instance);
__ LoadObject(RAX, Bool::Get(!negate_result));
__ LoadObject(RAX, Bool::Get(!negate_result), PP);
__ Bind(&done);
__ popq(RDX); // Remove pushed instantiator type arguments.
__ popq(RCX); // Remove pushed instantiator.
@@ -664,10 +654,8 @@ void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
__ pushq(RCX); // Store instantiator.
__ pushq(RDX); // Store instantiator type arguments.
// A null object is always assignable and is returned as result.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label is_assignable, runtime_call;
__ cmpq(RAX, raw_null);
__ CompareObject(RAX, Object::Handle());
__ j(EQUAL, &is_assignable);
if (!FLAG_eliminate_type_checks || dst_type.IsMalformed()) {
@@ -720,7 +708,7 @@ void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
__ pushq(RCX); // Instantiator.
__ pushq(RDX); // Instantiator type arguments.
__ PushObject(dst_name); // Push the name of the destination.
__ LoadObject(RAX, test_cache);
__ LoadObject(RAX, test_cache, PP);
__ pushq(RAX);
GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
// Pop the parameters supplied to the runtime entry. The result of the
@@ -765,7 +753,7 @@ void FlowGraphCompiler::EmitTrySyncMove(intptr_t dest_offset,
__ pushq(RAX);
*push_emitted = true;
}
__ LoadObject(RAX, loc.constant());
__ LoadObject(RAX, loc.constant(), PP);
__ movq(dest, RAX);
} else if (loc.IsRegister()) {
if (*push_emitted && loc.reg() == RAX) {
@@ -895,8 +883,6 @@ void FlowGraphCompiler::CopyParameters() {
__ j(POSITIVE, &loop, Assembler::kNearJump);
// Copy or initialize optional named arguments.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label all_arguments_processed;
#ifdef DEBUG
const bool check_correct_named_args = true;
@@ -958,7 +944,7 @@ void FlowGraphCompiler::CopyParameters() {
const Object& value = Object::ZoneHandle(
parsed_function().default_parameter_values().At(
param_pos - num_fixed_params));
__ LoadObject(RAX, value);
__ LoadObject(RAX, value, PP);
__ Bind(&assign_optional_parameter);
// Assign RAX to fp[kFirstLocalSlotFromFp - param_pos].
// We do not use the final allocation index of the variable here, i.e.
@@ -973,7 +959,8 @@ void FlowGraphCompiler::CopyParameters() {
if (check_correct_named_args) {
// Check that RDI now points to the null terminator in the arguments
// descriptor.
__ cmpq(Address(RDI, 0), raw_null);
__ LoadObject(TMP, Object::Handle(), PP);
__ cmpq(Address(RDI, 0), TMP);
__ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
}
} else {
@@ -992,7 +979,7 @@ void FlowGraphCompiler::CopyParameters() {
// Load RAX with default argument.
const Object& value = Object::ZoneHandle(
parsed_function().default_parameter_values().At(i));
__ LoadObject(RAX, value);
__ LoadObject(RAX, value, PP);
// Assign RAX to fp[kFirstLocalSlotFromFp - param_pos].
// We do not use the final allocation index of the variable here, i.e.
// scope->VariableAt(i)->index(), because captured variables still need
@@ -1018,8 +1005,8 @@ void FlowGraphCompiler::CopyParameters() {
const ICData& ic_data = ICData::ZoneHandle(
ICData::New(function, Symbols::Call(), Object::empty_array(),
Isolate::kNoDeoptId, kNumArgsChecked));
__ LoadObject(RBX, ic_data);
__ LeaveFrame(); // The arguments are still on the stack.
__ LoadObject(RBX, ic_data, PP);
__ LeaveFrameWithPP(); // The arguments are still on the stack.
__ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
// The noSuchMethod call may return to the caller, but not here.
__ int3();
@@ -1037,12 +1024,13 @@ void FlowGraphCompiler::CopyParameters() {
// R10 : arguments descriptor array.
__ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
__ SmiUntag(RCX);
__ LoadObject(R12, Object::Handle(), PP);
Label null_args_loop, null_args_loop_condition;
__ jmp(&null_args_loop_condition, Assembler::kNearJump);
const Address original_argument_addr(
RBP, RCX, TIMES_8, (kParamEndSlotFromFp + 1) * kWordSize);
__ Bind(&null_args_loop);
__ movq(original_argument_addr, raw_null);
__ movq(original_argument_addr, R12);
__ Bind(&null_args_loop_condition);
__ decq(RCX);
__ j(POSITIVE, &null_args_loop, Assembler::kNearJump);
@@ -1067,20 +1055,43 @@ void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) {
__ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver.
__ movq(RBX, Address(RSP, 1 * kWordSize)); // Value.
__ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX);
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ movq(RAX, raw_null);
__ LoadObject(RAX, Object::Handle(), PP);
__ ret();
}
void FlowGraphCompiler::EmitFrameEntry() {
const Function& function = parsed_function().function();
Register new_pp = kNoRegister;
Register new_pc = kNoRegister;
if (CanOptimizeFunction() &&
function.is_optimizable() &&
(!is_optimizing() || may_reoptimize())) {
const Register function_reg = RDI;
__ LoadObject(function_reg, function);
new_pp = R13;
new_pc = R12;
Label next;
__ nop(4); // Need a fixed size sequence on frame entry.
__ call(&next);
__ Bind(&next);
const intptr_t object_pool_pc_dist =
Instructions::HeaderSize() - Instructions::object_pool_offset() +
__ CodeSize();
const intptr_t offset =
Assembler::kEntryPointToPcMarkerOffset - __ CodeSize();
__ popq(new_pc);
if (offset != 0) {
__ addq(new_pc, Immediate(offset));
}
// Load callee's pool pointer.
__ movq(new_pp, Address(new_pc, -object_pool_pc_dist - offset));
// Load function object using the callee's pool pointer.
__ LoadObject(function_reg, function, new_pp);
// Patch point is after the eventually inlined function object.
AddCurrentDescriptor(PcDescriptors::kEntryPatch,
Isolate::kNoDeoptId,
@@ -1096,8 +1107,30 @@ void FlowGraphCompiler::EmitFrameEntry() {
Immediate(FLAG_optimization_counter_threshold));
}
ASSERT(function_reg == RDI);
__ j(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel());
__ J(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel(), R13);
} else if (!flow_graph().IsCompiledForOsr()) {
// We have to load the PP here too because a load of an external label
// may be patched at the AddCurrentDescriptor below.
new_pp = R13;
new_pc = R12;
Label next;
__ nop(4); // Need a fixed size sequence on frame entry.
__ call(&next);
__ Bind(&next);
const intptr_t object_pool_pc_dist =
Instructions::HeaderSize() - Instructions::object_pool_offset() +
__ CodeSize();
const intptr_t offset =
Assembler::kEntryPointToPcMarkerOffset - __ CodeSize();
__ popq(new_pc);
if (offset != 0) {
__ addq(new_pc, Immediate(offset));
}
// Load callee's pool pointer.
__ movq(new_pp, Address(new_pc, -object_pool_pc_dist - offset));
AddCurrentDescriptor(PcDescriptors::kEntryPatch,
Isolate::kNoDeoptId,
0); // No token position.
@@ -1108,10 +1141,10 @@ void FlowGraphCompiler::EmitFrameEntry() {
- flow_graph().num_stack_locals()
- flow_graph().num_copied_params();
ASSERT(extra_slots >= 0);
__ EnterOsrFrame(extra_slots * kWordSize);
__ EnterOsrFrame(extra_slots * kWordSize, new_pp, new_pc);
} else {
ASSERT(StackSize() >= 0);
__ EnterDartFrame(StackSize() * kWordSize);
__ EnterDartFrameWithInfo(StackSize() * kWordSize, new_pp, new_pc);
}
}
@@ -1165,8 +1198,8 @@ void FlowGraphCompiler::CompileGraph() {
const ICData& ic_data = ICData::ZoneHandle(
ICData::New(function, name, Object::empty_array(),
Isolate::kNoDeoptId, kNumArgsChecked));
__ LoadObject(RBX, ic_data);
__ LeaveFrame(); // The arguments are still on the stack.
__ LoadObject(RBX, ic_data, PP);
__ LeaveFrameWithPP(); // The arguments are still on the stack.
__ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
// The noSuchMethod call may return to the caller, but not here.
__ int3();
@@ -1184,9 +1217,7 @@ void FlowGraphCompiler::CompileGraph() {
if (!is_optimizing() && (num_locals > 0)) {
__ Comment("Initialize spill slots");
const intptr_t slot_base = parsed_function().first_stack_local_index();
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ movq(RAX, raw_null);
__ LoadObject(RAX, Object::Handle(), PP);
for (intptr_t i = 0; i < num_locals; ++i) {
// Subtract index i (locals lie at lower addresses than RBP).
__ movq(Address(RBP, (slot_base - i) * kWordSize), RAX);
@@ -1213,11 +1244,15 @@ void FlowGraphCompiler::CompileGraph() {
AddCurrentDescriptor(PcDescriptors::kPatchCode,
Isolate::kNoDeoptId,
0); // No token position.
__ jmp(&StubCode::FixCallersTargetLabel());
// This is patched up to a point in FrameEntry where the PP for the
// current function is in R13 instead of PP.
__ JmpPatchable(&StubCode::FixCallersTargetLabel(), R13);
// TOOD(zra): Is this descriptor used?
AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump,
Isolate::kNoDeoptId,
0); // No token position.
__ jmp(&StubCode::DeoptimizeLazyLabel());
__ Jmp(&StubCode::DeoptimizeLazyLabel(), PP);
}
@@ -1225,7 +1260,7 @@ void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
const ExternalLabel* label,
PcDescriptors::Kind kind,
LocationSummary* locs) {
__ call(label);
__ Call(label, PP);
AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
RecordSafepoint(locs);
}
@@ -1236,7 +1271,7 @@ void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
const ExternalLabel* label,
PcDescriptors::Kind kind,
LocationSummary* locs) {
__ call(label);
__ CallPatchable(label);
AddCurrentDescriptor(kind, deopt_id, token_pos);
RecordSafepoint(locs);
// Marks either the continuation point in unoptimized code or the
@@ -1275,6 +1310,47 @@ void FlowGraphCompiler::GenerateCallRuntime(intptr_t token_pos,
}
void FlowGraphCompiler::EmitUnoptimizedStaticCall(
const Function& target_function,
const Array& arguments_descriptor,
intptr_t argument_count,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
// TODO(srdjan): Improve performance of function recognition.
MethodRecognizer::Kind recognized_kind =
MethodRecognizer::RecognizeKind(target_function);
int num_args_checked = 0;
if ((recognized_kind == MethodRecognizer::kMathMin) ||
(recognized_kind == MethodRecognizer::kMathMax)) {
num_args_checked = 2;
}
const ICData& ic_data = ICData::ZoneHandle(
ICData::New(parsed_function().function(), // Caller function.
String::Handle(target_function.name()),
arguments_descriptor,
deopt_id,
num_args_checked)); // No arguments checked.
ic_data.AddTarget(target_function);
uword label_address = 0;
if (ic_data.num_args_tested() == 0) {
label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
} else if (ic_data.num_args_tested() == 2) {
label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
} else {
UNIMPLEMENTED();
}
ExternalLabel target_label("StaticCallICStub", label_address);
__ LoadObject(RBX, ic_data, PP);
GenerateDartCall(deopt_id,
token_pos,
&target_label,
PcDescriptors::kUnoptStaticCall,
locs);
__ Drop(argument_count);
}
void FlowGraphCompiler::EmitOptimizedInstanceCall(
ExternalLabel* target_label,
const ICData& ic_data,
@@ -1288,8 +1364,8 @@ void FlowGraphCompiler::EmitOptimizedInstanceCall(
// top-level function (parsed_function().function()) which could be
// reoptimized and which counter needs to be incremented.
// Pass the function explicitly, it is used in IC stub.
__ LoadObject(RDI, parsed_function().function());
__ LoadObject(RBX, ic_data);
__ LoadObject(RDI, parsed_function().function(), PP);
__ LoadObject(RBX, ic_data, PP);
GenerateDartCall(deopt_id,
token_pos,
target_label,
@@ -1305,7 +1381,7 @@ void FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
__ LoadObject(RBX, ic_data);
__ LoadObject(RBX, ic_data, PP);
GenerateDartCall(deopt_id,
token_pos,
target_label,
@@ -1341,7 +1417,7 @@ void FlowGraphCompiler::EmitMegamorphicInstanceCall(
// RAX: class ID of the receiver (smi).
__ Bind(&load_cache);
__ LoadObject(RBX, cache);
__ LoadObject(RBX, cache, PP);
__ movq(RDI, FieldAddress(RBX, MegamorphicCache::buckets_offset()));
__ movq(RBX, FieldAddress(RBX, MegamorphicCache::mask_offset()));
// RDI: cache buckets array.
@@ -1373,8 +1449,8 @@ void FlowGraphCompiler::EmitMegamorphicInstanceCall(
__ movq(RAX, FieldAddress(RDI, RCX, TIMES_8, base + kWordSize));
__ movq(RAX, FieldAddress(RAX, Function::code_offset()));
__ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
__ LoadObject(RBX, ic_data);
__ LoadObject(R10, arguments_descriptor);
__ LoadObject(RBX, ic_data, PP);
__ LoadObject(R10, arguments_descriptor, PP);
__ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
__ call(RAX);
AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos);
@@ -1391,7 +1467,7 @@ void FlowGraphCompiler::EmitOptimizedStaticCall(
intptr_t deopt_id,
intptr_t token_pos,
LocationSummary* locs) {
__ LoadObject(R10, arguments_descriptor);
__ LoadObject(R10, arguments_descriptor, PP);
// Do not use the code from the function, but let the code be patched so that
// we can record the outgoing edges to other code.
GenerateDartCall(deopt_id,
@@ -1424,9 +1500,9 @@ void FlowGraphCompiler::EmitEqualityRegConstCompare(Register reg,
__ pushq(reg);
__ PushObject(obj);
if (is_optimizing()) {
__ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
__ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
} else {
__ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
__ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
}
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
@@ -1448,9 +1524,9 @@ void FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
__ pushq(left);
__ pushq(right);
if (is_optimizing()) {
__ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
__ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
} else {
__ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
__ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
}
AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
Isolate::kNoDeoptId,
@@ -1540,7 +1616,7 @@ void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data,
const Array& arguments_descriptor =
Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
argument_names));
__ LoadObject(R10, arguments_descriptor);
__ LoadObject(R10, arguments_descriptor, PP);
for (intptr_t i = 0; i < len; i++) {
const bool is_last_check = (i == (len - 1));
Label next_test;
@@ -1582,7 +1658,6 @@ void FlowGraphCompiler::EmitDoubleCompareBranch(Condition true_condition,
}
void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition,
FpuRegister left,
FpuRegister right,
@@ -1592,10 +1667,10 @@ void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition,
assembler()->j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN false;
assembler()->j(true_condition, &is_true, Assembler::kNearJump);
assembler()->Bind(&is_false);
assembler()->LoadObject(result, Bool::False());
assembler()->LoadObject(result, Bool::False(), PP);
assembler()->jmp(&done);
assembler()->Bind(&is_true);
assembler()->LoadObject(result, Bool::True());
assembler()->LoadObject(result, Bool::True(), PP);
assembler()->Bind(&done);
}
@@ -1716,7 +1791,7 @@ void ParallelMoveResolver::EmitMove(int index) {
if (constant.IsSmi() && (Smi::Cast(constant).Value() == 0)) {
__ xorq(destination.reg(), destination.reg());
} else {
__ LoadObject(destination.reg(), constant);
__ LoadObject(destination.reg(), constant, PP);
}
} else {
ASSERT(destination.IsStackSlot());
+1 -1
View File
@@ -163,7 +163,7 @@ void CallPattern::InsertAt(uword pc, uword target_address) {
}
JumpPattern::JumpPattern(uword pc) : pc_(pc) { }
JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { }
bool JumpPattern::IsValid() const {
+1 -1
View File
@@ -50,7 +50,7 @@ class CallPattern : public ValueObject {
class JumpPattern : public ValueObject {
public:
explicit JumpPattern(uword pc);
JumpPattern(uword pc, const Code& code);
static const int kLengthInBytes = 3 * Instr::kInstrSize;
+3 -2
View File
@@ -38,10 +38,11 @@ ASSEMBLER_TEST_GENERATE(Jump, assembler) {
ASSEMBLER_TEST_RUN(Jump, test) {
JumpPattern jump1(test->entry());
JumpPattern jump1(test->entry(), test->code());
EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
jump1.TargetAddress());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
test->code());
EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
+2 -1
View File
@@ -11,6 +11,7 @@
#endif
#include "vm/allocation.h"
#include "vm/object.h"
namespace dart {
@@ -85,7 +86,7 @@ class CallPattern : public CallOrJumpPattern {
class JumpPattern : public CallOrJumpPattern {
public:
explicit JumpPattern(uword pc) : CallOrJumpPattern(pc) {}
JumpPattern(uword pc, const Code& code) : CallOrJumpPattern(pc) {}
private:
virtual const int* pattern() const;
+3 -2
View File
@@ -35,10 +35,11 @@ ASSEMBLER_TEST_GENERATE(Jump, assembler) {
ASSEMBLER_TEST_RUN(Jump, test) {
JumpPattern jump1(test->entry());
JumpPattern jump1(test->entry(), test->code());
EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
jump1.TargetAddress());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
test->code());
EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
+1 -1
View File
@@ -177,7 +177,7 @@ void CallPattern::InsertAt(uword pc, uword target_address) {
}
JumpPattern::JumpPattern(uword pc) : pc_(pc) { }
JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { }
bool JumpPattern::IsValid() const {
+1 -1
View File
@@ -50,7 +50,7 @@ class CallPattern : public ValueObject {
class JumpPattern : public ValueObject {
public:
explicit JumpPattern(uword pc);
JumpPattern(uword pc, const Code& code);
// lui; ori; jr; nop (in delay slot) = 4.
static const int kLengthInBytes = 4*Instr::kInstrSize;
+3 -2
View File
@@ -39,10 +39,11 @@ ASSEMBLER_TEST_GENERATE(Jump, assembler) {
ASSEMBLER_TEST_RUN(Jump, test) {
JumpPattern jump1(test->entry());
JumpPattern jump1(test->entry(), test->code());
EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
jump1.TargetAddress());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
test->code());
EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
+28 -5
View File
@@ -11,6 +11,13 @@
namespace dart {
intptr_t InstructionPattern::IndexFromPPLoad(uword start) {
int32_t offset = *reinterpret_cast<int32_t*>(start);
offset += kHeapObjectTag;
return (offset - Array::data_offset()) / kWordSize;
}
bool InstructionPattern::TestBytesWith(const int* data, int num_bytes) const {
ASSERT(data != NULL);
const uint8_t* byte_array = reinterpret_cast<const uint8_t*>(start_);
@@ -24,13 +31,13 @@ bool InstructionPattern::TestBytesWith(const int* data, int num_bytes) const {
}
uword CallOrJumpPattern::TargetAddress() const {
uword CallPattern::TargetAddress() const {
ASSERT(IsValid());
return *reinterpret_cast<uword*>(start() + 2);
}
void CallOrJumpPattern::SetTargetAddress(uword target) const {
void CallPattern::SetTargetAddress(uword target) const {
ASSERT(IsValid());
*reinterpret_cast<uword*>(start() + 2) = target;
CPU::FlushICache(start() + 2, kWordSize);
@@ -46,11 +53,27 @@ const int* CallPattern::pattern() const {
}
uword JumpPattern::TargetAddress() const {
ASSERT(IsValid());
int index = InstructionPattern::IndexFromPPLoad(start() + 3);
return reinterpret_cast<uword>(object_pool_.At(index));
}
void JumpPattern::SetTargetAddress(uword target) const {
ASSERT(IsValid());
int index = InstructionPattern::IndexFromPPLoad(start() + 3);
const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target));
object_pool_.SetAt(index, smi);
// No need to flush the instruction cache, since the code is not modified.
}
const int* JumpPattern::pattern() const {
// movq $target, TMP
// jmpq TMP
// 00: 4d 8b 9d imm32 mov R11, [R13 + off]
// 07: 41 ff e3 jmpq R11
static const int kJumpPattern[kLengthInBytes] =
{0x49, 0xBB, -1, -1, -1, -1, -1, -1, -1, -1, 0x41, 0xFF, 0xE3};
{0x4D, 0x8B, -1, -1, -1, -1, -1, 0x41, 0xFF, 0xE3};
return kJumpPattern;
}
+22 -18
View File
@@ -11,6 +11,7 @@
#endif
#include "vm/allocation.h"
#include "vm/object.h"
namespace dart {
@@ -37,6 +38,8 @@ class InstructionPattern : public ValueObject {
virtual const int* pattern() const = 0;
virtual int pattern_length_in_bytes() const = 0;
static intptr_t IndexFromPPLoad(uword start);
protected:
uword start() const { return start_; }
@@ -52,46 +55,47 @@ class InstructionPattern : public ValueObject {
};
class CallOrJumpPattern : public InstructionPattern {
class CallPattern : public InstructionPattern {
public:
virtual int pattern_length_in_bytes() const {
CallPattern(uword pc, const Code& code)
: InstructionPattern(pc),
code_(code) {}
static int InstructionLength() {
return kLengthInBytes;
}
uword TargetAddress() const;
void SetTargetAddress(uword new_target) const;
protected:
explicit CallOrJumpPattern(uword pc) : InstructionPattern(pc) {}
static const int kLengthInBytes = 13;
private:
DISALLOW_COPY_AND_ASSIGN(CallOrJumpPattern);
};
class CallPattern : public CallOrJumpPattern {
public:
explicit CallPattern(uword pc) : CallOrJumpPattern(pc) {}
static int InstructionLength() {
virtual int pattern_length_in_bytes() const {
return kLengthInBytes;
}
private:
static const int kLengthInBytes = 13;
virtual const int* pattern() const;
const Code& code_;
DISALLOW_COPY_AND_ASSIGN(CallPattern);
};
class JumpPattern : public CallOrJumpPattern {
class JumpPattern : public InstructionPattern {
public:
explicit JumpPattern(uword pc) : CallOrJumpPattern(pc) {}
JumpPattern(uword pc, const Code& code)
: InstructionPattern(pc),
object_pool_(Array::Handle(code.ObjectPool())) {}
static int InstructionLength() {
return kLengthInBytes;
}
uword TargetAddress() const;
void SetTargetAddress(uword new_target) const;
virtual int pattern_length_in_bytes() const {
return kLengthInBytes;
}
private:
static const int kLengthInBytes = 10;
virtual const int* pattern() const;
const Array& object_pool_;
DISALLOW_COPY_AND_ASSIGN(JumpPattern);
};
+8 -5
View File
@@ -21,25 +21,28 @@ ASSEMBLER_TEST_GENERATE(Call, assembler) {
ASSEMBLER_TEST_RUN(Call, test) {
CallPattern call(test->entry());
CallPattern call(test->entry(), test->code());
EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
call.TargetAddress());
}
ASSEMBLER_TEST_GENERATE(Jump, assembler) {
__ jmp(&StubCode::InstanceFunctionLookupLabel());
__ jmp(&StubCode::AllocateArrayLabel());
__ EnterDartFrame(0); // 20 bytes
__ JmpPatchable(&StubCode::InstanceFunctionLookupLabel(), PP);
__ JmpPatchable(&StubCode::AllocateArrayLabel(), PP);
__ LeaveFrameWithPP();
__ ret();
}
ASSEMBLER_TEST_RUN(Jump, test) {
JumpPattern jump1(test->entry());
JumpPattern jump1(test->entry() + 20, test->code());
jump1.IsValid();
EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
jump1.TargetAddress());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes() + 20,
test->code());
EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
jump2.TargetAddress());
uword target1 = jump1.TargetAddress();
+55 -73
View File
@@ -96,20 +96,8 @@ void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ Bind(&done);
}
#endif
__ LeaveFrame();
__ ret();
// Generate 8 bytes of NOPs so that the debugger can patch the
// return pattern with a call to the debug stub.
// Note that the nop(8) byte pattern is not recognized by the debugger.
__ nop(1);
__ nop(1);
__ nop(1);
__ nop(1);
__ nop(1);
__ nop(1);
__ nop(1);
__ nop(1);
__ ReturnPatchable();
compiler->AddCurrentDescriptor(PcDescriptors::kReturn,
Isolate::kNoDeoptId,
token_pos());
@@ -315,7 +303,7 @@ void ConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// The register allocator drops constant definitions that have no uses.
if (!locs()->out().IsInvalid()) {
Register result = locs()->out().reg();
__ LoadObject(result, value());
__ LoadObject(result, value(), PP);
}
}
@@ -465,12 +453,11 @@ static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
const Array& kNoArgumentNames = Object::null_array();
const int kNumArgumentsChecked = 2;
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label check_identity;
__ cmpq(Address(RSP, 0 * kWordSize), raw_null);
__ LoadObject(TMP, Object::Handle(), PP);
__ cmpq(Address(RSP, 0 * kWordSize), TMP);
__ j(EQUAL, &check_identity);
__ cmpq(Address(RSP, 1 * kWordSize), raw_null);
__ cmpq(Address(RSP, 1 * kWordSize), TMP);
__ j(EQUAL, &check_identity);
ICData& equality_ic_data = ICData::ZoneHandle(original_ic_data.raw());
@@ -511,10 +498,10 @@ static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
__ popq(RDX);
__ cmpq(RAX, RDX);
__ j(EQUAL, &is_true);
__ LoadObject(RAX, Bool::Get(kind != Token::kEQ));
__ LoadObject(RAX, Bool::Get(kind != Token::kEQ), PP);
__ jmp(&equality_done);
__ Bind(&is_true);
__ LoadObject(RAX, Bool::Get(kind == Token::kEQ));
__ LoadObject(RAX, Bool::Get(kind == Token::kEQ), PP);
if (kind == Token::kNE) {
// Skip not-equal result conversion.
__ jmp(&equality_done);
@@ -524,7 +511,7 @@ static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
// necessary.
Register ic_data_reg = locs->temp(0).reg();
ASSERT(ic_data_reg == RBX); // Stub depends on it.
__ LoadObject(ic_data_reg, equality_ic_data);
__ LoadObject(ic_data_reg, equality_ic_data, PP);
compiler->GenerateCall(token_pos,
&StubCode::EqualityWithNullArgLabel(),
PcDescriptors::kRuntimeCall,
@@ -537,10 +524,10 @@ static void EmitEqualityAsInstanceCall(FlowGraphCompiler* compiler,
// Negate the condition: true label returns false and vice versa.
__ CompareObject(RAX, Bool::True());
__ j(EQUAL, &true_label, Assembler::kNearJump);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ jmp(&done, Assembler::kNearJump);
__ Bind(&true_label);
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
__ Bind(&done);
}
__ Bind(&equality_done);
@@ -610,10 +597,10 @@ static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
Register result = locs->out().reg();
Label load_true;
__ j(cond, &load_true, Assembler::kNearJump);
__ LoadObject(result, Bool::False());
__ LoadObject(result, Bool::False(), PP);
__ jmp(&done);
__ Bind(&load_true);
__ LoadObject(result, Bool::True());
__ LoadObject(result, Bool::True(), PP);
}
} else {
const int kNumberOfArguments = 2;
@@ -629,10 +616,10 @@ static void EmitEqualityAsPolymorphicCall(FlowGraphCompiler* compiler,
Label false_label;
__ CompareObject(RAX, Bool::True());
__ j(EQUAL, &false_label, Assembler::kNearJump);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ jmp(&done);
__ Bind(&false_label);
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
}
} else {
if (branch->is_checked()) {
@@ -666,12 +653,11 @@ static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
__ testq(left, Immediate(kSmiTagMask));
__ j(ZERO, deopt);
// 'left' is not Smi.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label identity_compare;
__ cmpq(right, raw_null);
__ CompareObject(right, Object::Handle());
__ j(EQUAL, &identity_compare);
__ cmpq(left, raw_null);
__ CompareObject(left, Object::Handle());
__ j(EQUAL, &identity_compare);
__ LoadClassId(temp, left);
@@ -692,10 +678,10 @@ static void EmitCheckedStrictEqual(FlowGraphCompiler* compiler,
Register result = locs.out().reg();
__ j(EQUAL, &is_equal, Assembler::kNearJump);
// Not equal.
__ LoadObject(result, Bool::Get(kind != Token::kEQ));
__ LoadObject(result, Bool::Get(kind != Token::kEQ), PP);
__ jmp(&done, Assembler::kNearJump);
__ Bind(&is_equal);
__ LoadObject(result, Bool::Get(kind == Token::kEQ));
__ LoadObject(result, Bool::Get(kind == Token::kEQ), PP);
__ Bind(&done);
} else {
Condition cond = TokenKindToSmiCondition(kind);
@@ -718,12 +704,11 @@ static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0));
Register left = locs->in(0).reg();
Register right = locs->in(1).reg();
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label done, identity_compare, non_null_compare;
__ cmpq(right, raw_null);
__ CompareObject(right, Object::Handle());
__ j(EQUAL, &identity_compare, Assembler::kNearJump);
__ cmpq(left, raw_null);
__ CompareObject(left, Object::Handle());
__ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump);
// Comparison with NULL is "===".
__ Bind(&identity_compare);
@@ -735,10 +720,10 @@ static void EmitGenericEqualityCompare(FlowGraphCompiler* compiler,
Register result = locs->out().reg();
Label load_true;
__ j(cond, &load_true, Assembler::kNearJump);
__ LoadObject(result, Bool::False());
__ LoadObject(result, Bool::False(), PP);
__ jmp(&done);
__ Bind(&load_true);
__ LoadObject(result, Bool::True());
__ LoadObject(result, Bool::True(), PP);
}
__ jmp(&done);
__ Bind(&non_null_compare); // Receiver is not null.
@@ -796,10 +781,10 @@ static void EmitSmiComparisonOp(FlowGraphCompiler* compiler,
Register result = locs.out().reg();
Label done, is_true;
__ j(true_condition, &is_true);
__ LoadObject(result, Bool::False());
__ LoadObject(result, Bool::False(), PP);
__ jmp(&done);
__ Bind(&is_true);
__ LoadObject(result, Bool::True());
__ LoadObject(result, Bool::True(), PP);
__ Bind(&done);
}
}
@@ -1527,7 +1512,7 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg));
}
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
FieldAddress field_nullability_operand(
@@ -1711,7 +1696,7 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
}
} else {
if (field_reg != kNoRegister) {
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
__ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
}
if (value_cid == kDynamicCid) {
@@ -1747,9 +1732,7 @@ void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (field().is_nullable() && (field_cid != kNullCid)) {
__ j(EQUAL, &ok);
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ cmpq(value_reg, raw_null);
__ CompareObject(value_reg, Object::Handle());
}
if (ok_is_fall_through) {
@@ -1874,7 +1857,7 @@ void StoreStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
__ LoadObject(temp, field());
__ LoadObject(temp, field(), PP);
if (this->value()->NeedsStoreBuffer()) {
__ StoreIntoObject(temp,
FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi());
@@ -2028,9 +2011,7 @@ void InstantiateTypeArgumentsInstr::EmitNativeCode(
Label type_arguments_instantiated;
const intptr_t len = type_arguments().Length();
if (type_arguments().IsRawInstantiatedRaw(len)) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ cmpq(instantiator_reg, raw_null);
__ CompareObject(instantiator_reg, Object::Handle());
__ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
}
// Instantiate non-null type arguments.
@@ -2078,14 +2059,13 @@ void ExtractConstructorTypeArgumentsInstr::EmitNativeCode(
// the type arguments.
Label type_arguments_instantiated;
ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ cmpq(instantiator_reg, raw_null);
__ CompareObject(instantiator_reg, Object::Handle());
__ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
// Instantiate non-null type arguments.
// In the non-factory case, we rely on the allocation stub to
// instantiate the type arguments.
__ LoadObject(result_reg, type_arguments());
__ LoadObject(result_reg, type_arguments(), PP);
// result_reg: uninstantiated type arguments.
__ Bind(&type_arguments_instantiated);
@@ -2120,10 +2100,9 @@ void ExtractConstructorInstantiatorInstr::EmitNativeCode(
// instantiated from null becomes a vector of dynamic, then use null as
// the type arguments and do not pass the instantiator.
ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label instantiator_not_null;
__ cmpq(instantiator_reg, raw_null);
__ CompareObject(instantiator_reg, Object::Handle());
__ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump);
// Null was used in VisitExtractConstructorTypeArguments as the
// instantiated type arguments, no proper instantiator needed.
@@ -2199,6 +2178,10 @@ void CatchBlockEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
compiler->assembler()->CodeSize(),
catch_handler_types_,
needs_stacktrace());
// Restore the pool pointer.
__ LoadPoolPointer(PP);
if (HasParallelMove()) {
compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
}
@@ -2279,7 +2262,7 @@ void CheckStackOverflowInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// In unoptimized code check the usage counter to trigger OSR at loop
// stack checks. Use progressively higher thresholds for more deeply
// nested loops to attempt to hit outer loops with OSR when possible.
__ LoadObject(temp, compiler->parsed_function().function());
__ LoadObject(temp, compiler->parsed_function().function(), PP);
intptr_t threshold =
FLAG_optimization_counter_threshold * (loop_depth() + 1);
__ cmpq(FieldAddress(temp, Function::usage_counter_offset()),
@@ -3726,10 +3709,10 @@ void Uint32x4GetFlagInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ addq(RSP, Immediate(16));
__ testl(result, result);
__ j(NOT_ZERO, &non_zero, Assembler::kNearJump);
__ LoadObject(result, Bool::False());
__ LoadObject(result, Bool::False(), PP);
__ jmp(&done);
__ Bind(&non_zero);
__ LoadObject(result, Bool::True());
__ LoadObject(result, Bool::True(), PP);
__ Bind(&done);
}
@@ -4247,9 +4230,9 @@ void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Label check_base_is_one;
// Check if exponent is 0.0 -> return 1.0;
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0)));
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0)), PP);
__ movsd(zero_temp, FieldAddress(temp, Double::value_offset()));
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(1)));
__ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(1)), PP);
__ movsd(result, FieldAddress(temp, Double::value_offset()));
// 'result' contains 1.0.
__ comisd(exp, zero_temp);
@@ -4347,9 +4330,8 @@ void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
if (IsNullCheck()) {
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ cmpq(locs()->in(0).reg(), raw_null);
__ CompareObject(locs()->in(0).reg(),
Object::Handle());
__ j(EQUAL, deopt);
return;
}
@@ -4559,7 +4541,7 @@ void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
counter.SetAt(0, Smi::Handle(Smi::New(0)));
Label done;
__ Comment("Edge counter");
__ LoadObject(RAX, counter);
__ LoadObject(RAX, counter, PP);
__ addq(FieldAddress(RAX, Array::element_offset(0)),
Immediate(Smi::RawValue(1)));
__ j(NO_OVERFLOW, &done);
@@ -4590,7 +4572,7 @@ void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
counter.SetAt(0, Smi::Handle(Smi::New(0)));
Label done;
__ Comment("Edge counter");
__ LoadObject(RAX, counter);
__ LoadObject(RAX, counter, PP);
__ addq(FieldAddress(RAX, Array::element_offset(0)),
Immediate(Smi::RawValue(1)));
__ j(NO_OVERFLOW, &done);
@@ -4673,7 +4655,7 @@ void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const bool result = (kind() == Token::kEQ_STRICT) ?
left.constant().raw() == right.constant().raw() :
left.constant().raw() != right.constant().raw();
__ LoadObject(locs()->out().reg(), Bool::Get(result));
__ LoadObject(locs()->out().reg(), Bool::Get(result), PP);
return;
}
if (left.IsConstant()) {
@@ -4697,10 +4679,10 @@ void StrictCompareInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Label load_true, done;
Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
__ j(true_condition, &load_true, Assembler::kNearJump);
__ LoadObject(result, Bool::False());
__ LoadObject(result, Bool::False(), PP);
__ jmp(&done, Assembler::kNearJump);
__ Bind(&load_true);
__ LoadObject(result, Bool::True());
__ LoadObject(result, Bool::True(), PP);
__ Bind(&done);
}
@@ -4759,7 +4741,7 @@ void ClosureCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const Array& arguments_descriptor =
Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
argument_names()));
__ LoadObject(temp_reg, arguments_descriptor);
__ LoadObject(temp_reg, arguments_descriptor, PP);
ASSERT(temp_reg == R10);
compiler->GenerateDartCall(deopt_id(),
token_pos(),
@@ -4782,10 +4764,10 @@ void BooleanNegateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result = locs()->out().reg();
Label done;
__ LoadObject(result, Bool::True());
__ LoadObject(result, Bool::True(), PP);
__ CompareRegisters(result, value);
__ j(NOT_EQUAL, &done, Assembler::kNearJump);
__ LoadObject(result, Bool::False());
__ LoadObject(result, Bool::False(), PP);
__ Bind(&done);
}
+41 -30
View File
@@ -117,15 +117,14 @@ void Intrinsifier::ObjectArray_Allocate(Assembler* assembler) {
// RCX: new object end address.
// RDI: iterator which initially points to the start of the variable
// data area to be initialized.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ LoadObject(R12, Object::Handle(), PP);
__ leaq(RDI, FieldAddress(RAX, sizeof(RawArray)));
Label done;
Label init_loop;
__ Bind(&init_loop);
__ cmpq(RDI, RCX);
__ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
__ movq(Address(RDI, 0), raw_null);
__ movq(Address(RDI, 0), R12);
__ addq(RDI, Immediate(kWordSize));
__ jmp(&init_loop, Assembler::kNearJump);
__ Bind(&done);
@@ -392,9 +391,7 @@ void Intrinsifier::GrowableArray_add(Assembler* assembler) {
__ StoreIntoObject(RDX,
FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()),
RAX);
const Immediate& raw_null =
Immediate(reinterpret_cast<int64_t>(Object::null()));
__ movq(RAX, raw_null);
__ LoadObject(RAX, Object::Handle(), PP);
__ ret();
__ Bind(&fall_through);
}
@@ -879,10 +876,10 @@ static void CompareIntegers(Assembler* assembler, Condition true_condition) {
// RAX contains the right argument.
__ cmpq(Address(RSP, + 2 * kWordSize), RAX);
__ j(true_condition, &true_label, Assembler::kNearJump);
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
__ ret();
__ Bind(&true_label);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ ret();
__ Bind(&fall_through);
}
@@ -919,34 +916,39 @@ void Intrinsifier::Integer_greaterEqualThan(Assembler* assembler) {
void Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
Label fall_through, true_label, check_for_mint;
// For integer receiver '===' check first.
__ movq(RAX, Address(RSP, + 1 * kWordSize));
__ movq(RCX, Address(RSP, + 2 * kWordSize));
// Entering a dart frame so we can use the PP for loading True and False.
__ EnterDartFrame(0);
__ movq(RAX, Address(RSP, + 4 * kWordSize));
__ movq(RCX, Address(RSP, + 5 * kWordSize));
__ cmpq(RAX, RCX);
__ j(EQUAL, &true_label, Assembler::kNearJump);
__ orq(RAX, RCX);
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump);
// Both arguments are smi, '===' is good enough.
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
__ LeaveFrameWithPP();
__ ret();
__ Bind(&true_label);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ LeaveFrameWithPP();
__ ret();
// At least one of the arguments was not Smi.
Label receiver_not_smi;
__ Bind(&check_for_mint);
__ movq(RAX, Address(RSP, + 2 * kWordSize)); // Receiver.
__ movq(RAX, Address(RSP, + 5 * kWordSize)); // Receiver.
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &receiver_not_smi);
// Left (receiver) is Smi, return false if right is not Double.
// Note that an instance of Mint or Bigint never contains a value that can be
// represented by Smi.
__ movq(RAX, Address(RSP, + 1 * kWordSize));
__ movq(RAX, Address(RSP, + 4 * kWordSize));
__ CompareClassId(RAX, kDoubleCid);
__ j(EQUAL, &fall_through);
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
__ LeaveFrameWithPP();
__ ret();
__ Bind(&receiver_not_smi);
@@ -954,14 +956,17 @@ void Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
__ CompareClassId(RAX, kMintCid);
__ j(NOT_EQUAL, &fall_through);
// Receiver is Mint, return false if right is Smi.
__ movq(RAX, Address(RSP, + 1 * kWordSize)); // Right argument.
__ movq(RAX, Address(RSP, + 4 * kWordSize)); // Right argument.
__ testq(RAX, Immediate(kSmiTagMask));
__ j(NOT_ZERO, &fall_through);
__ LoadObject(RAX, Bool::False()); // Smi == Mint -> false.
// Smi == Mint -> false.
__ LoadObject(RAX, Bool::False(), PP);
__ LeaveFrameWithPP();
__ ret();
// TODO(srdjan): Implement Mint == Mint comparison.
__ Bind(&fall_through);
__ LeaveFrameWithPP();
}
@@ -1041,10 +1046,10 @@ static void CompareDoubles(Assembler* assembler, Condition true_condition) {
__ j(true_condition, &is_true, Assembler::kNearJump);
// Fall through false.
__ Bind(&is_false);
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
__ ret();
__ Bind(&is_true);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ ret();
__ Bind(&is_smi);
__ SmiUntag(RAX);
@@ -1178,10 +1183,10 @@ void Intrinsifier::Double_getIsNaN(Assembler* assembler) {
__ movsd(XMM0, FieldAddress(RAX, Double::value_offset()));
__ comisd(XMM0, XMM0);
__ j(PARITY_EVEN, &is_true, Assembler::kNearJump); // NaN -> true;
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
__ ret();
__ Bind(&is_true);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ ret();
}
@@ -1196,10 +1201,10 @@ void Intrinsifier::Double_getIsNegative(Assembler* assembler) {
__ j(EQUAL, &is_zero, Assembler::kNearJump); // Check for negative zero.
__ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump); // >= 0 -> false.
__ Bind(&is_true);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ ret();
__ Bind(&is_false);
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
__ ret();
__ Bind(&is_zero);
// Check for negative zero (get the sign bit).
@@ -1347,17 +1352,23 @@ void Intrinsifier::Random_nextState(Assembler* assembler) {
}
// Identity comparison.
void Intrinsifier::Object_equal(Assembler* assembler) {
Label is_true;
__ movq(RAX, Address(RSP, + 1 * kWordSize));
__ cmpq(RAX, Address(RSP, + 2 * kWordSize));
// This intrinsic is used from the API even when we have not entered any
// Dart frame, yet, so the PP would otherwise be null in this case unless
// we enter a Dart frame here.
__ EnterDartFrame(0);
__ movq(RAX, Address(RSP, + 4 * kWordSize));
__ cmpq(RAX, Address(RSP, + 5 * kWordSize));
__ j(EQUAL, &is_true, Assembler::kNearJump);
__ LoadObject(RAX, Bool::False());
__ movq(RAX, Immediate(reinterpret_cast<int64_t>(Bool::False().raw())));
__ LoadObject(RAX, Bool::False(), PP);
__ LeaveFrameWithPP();
__ ret();
__ Bind(&is_true);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ LeaveFrameWithPP();
__ ret();
}
@@ -1417,10 +1428,10 @@ void Intrinsifier::String_getIsEmpty(Assembler* assembler) {
__ movq(RAX, FieldAddress(RAX, String::length_offset()));
__ cmpq(RAX, Immediate(Smi::RawValue(0)));
__ j(EQUAL, &is_true, Assembler::kNearJump);
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
__ ret();
__ Bind(&is_true);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ ret();
}
+4 -2
View File
@@ -34,7 +34,9 @@ void GenerateIncrement(Assembler* assembler) {
void GenerateEmbedStringInCode(Assembler* assembler, const char* str) {
const String& string_object =
String::ZoneHandle(String::New(str, Heap::kOld));
__ LoadObject(RAX, string_object);
__ EnterDartFrame(0);
__ LoadObject(RAX, string_object, PP);
__ LeaveFrameWithPP();
__ ret();
}
@@ -43,7 +45,7 @@ void GenerateEmbedStringInCode(Assembler* assembler, const char* str) {
// This is used to test Embedded Smi objects in the instructions.
void GenerateEmbedSmiInCode(Assembler* assembler, intptr_t value) {
const Smi& smi_object = Smi::ZoneHandle(Smi::New(value));
__ LoadObject(RAX, smi_object);
__ LoadObject(RAX, smi_object, PP);
__ ret();
}
+1 -1
View File
@@ -30,7 +30,7 @@ void RuntimeEntry::Call(Assembler* assembler, intptr_t argument_count) const {
// informative error message.
__ movq(RBX, Immediate(GetEntryPoint()));
__ movq(R10, Immediate(argument_count));
__ call(&StubCode::CallToRuntimeLabel());
__ Call(&StubCode::CallToRuntimeLabel(), PP);
}
}
+11 -7
View File
@@ -11,11 +11,14 @@ namespace dart {
| | <- TOS
Callee frame | ... |
| saved PP |
| callee's PC marker |
| saved RBP | (RBP of current frame)
| saved PC | (PC of current frame)
+--------------------+
Current frame | ... | <- RSP of current frame
| first local |
| caller's PP |
| PC marker | (current frame's code entry + offset)
| caller's RBP | <- RBP of current frame
| caller's ret addr | (PC of caller frame)
@@ -24,21 +27,22 @@ Caller frame | last parameter | <- RSP of caller frame
| ... |
*/
static const int kDartFrameFixedSize = 3; // PC marker, RBP, PC.
static const int kDartFrameFixedSize = 4; // PC marker, RBP, PP, PC.
static const int kSavedPcSlotFromSp = -1;
static const int kFirstLocalSlotFromFp = -2;
static const int kFirstLocalSlotFromFp = -3;
static const int kSavedCallerPpSlotFromFp = -2;
static const int kPcMarkerSlotFromFp = -1;
static const int kSavedCallerFpSlotFromFp = 0;
static const int kSavedCallerPcSlotFromFp = 1;
static const int kParamEndSlotFromFp = 1; // One slot past last parameter.
static const int kCallerSpSlotFromFp = 2;
// No pool pointer on X64 (indicated by aliasing saved fp).
static const int kSavedCallerPpSlotFromFp = kSavedCallerFpSlotFromFp;
static const int kSavedAboveReturnAddress = 3; // Saved above return address.
// Entry and exit frame layout.
static const int kSavedContextSlotFromEntryFp = -9;
static const int kExitLinkSlotFromEntryFp = -8;
static const int kSavedContextSlotFromEntryFp = -10;
static const int kExitLinkSlotFromEntryFp = -9;
} // namespace dart
+2 -1
View File
@@ -182,7 +182,8 @@ class StubCode {
StubEntry* name##_entry_;
STUB_CODE_LIST(STUB_CODE_ENTRY);
#undef STUB_CODE_ENTRY
// This dummy field is needed so that we can intialize the stubs from a macro.
// This dummy field is needed so that we can initialize
// the stubs from a macro.
void* dummy_;
// Generate the stub and finalize the generated code into the stub
+109 -117
View File
@@ -83,9 +83,8 @@ void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) {
__ 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);
__ LoadObject(R12, Object::Handle(), PP);
__ movq(Address(CTX, Isolate::top_context_offset()), R12);
// Cache Context pointer into CTX while executing Dart code.
__ movq(CTX, RBX);
@@ -172,9 +171,8 @@ void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) {
__ 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);
__ LoadObject(R12, Object::Handle(), PP);
__ movq(Address(CTX, Isolate::top_context_offset()), R12);
// Cache Context pointer into CTX while executing Dart code.
__ movq(CTX, R8);
@@ -240,9 +238,8 @@ void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) {
__ 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);
__ LoadObject(R12, Object::Handle(), PP);
__ movq(Address(CTX, Isolate::top_context_offset()), R12);
// Cache Context pointer into CTX while executing Dart code.
__ movq(CTX, R8);
@@ -255,11 +252,10 @@ void StubCode::GenerateCallBootstrapCFunctionStub(Assembler* assembler) {
// Input parameters:
// R10: arguments descriptor array.
void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ EnterStubFrame();
__ pushq(R10); // Preserve arguments descriptor array.
__ pushq(raw_null); // Setup space on stack for return value.
// Setup space on stack for return value.
__ PushObject(Object::Handle());
__ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
__ popq(RAX); // Get Code object result.
__ popq(R10); // Restore arguments descriptor array.
@@ -276,11 +272,10 @@ void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
// (invalid because its function was optimized or deoptimized).
// R10: arguments descriptor array.
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ EnterStubFrame();
__ pushq(R10); // Preserve arguments descriptor array.
__ pushq(raw_null); // Setup space on stack for return value.
// Setup space on stack for return value.
__ PushObject(Object::Handle());
__ CallRuntime(kFixCallersTargetRuntimeEntry, 0);
__ popq(RAX); // Get Code object.
__ popq(R10); // Restore arguments descriptor array.
@@ -296,11 +291,9 @@ void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
// R10: smi-tagged argument count, may be zero.
// RBP[kParamEndSlotFromFp + 1]: last argument.
static void PushArgumentsArray(Assembler* assembler) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ LoadObject(R12, Object::Handle(), PP);
// Allocate array to store arguments of caller.
__ movq(RBX, raw_null); // Null element type for raw Array.
__ movq(RBX, R12); // Null element type for raw Array.
__ call(&StubCode::AllocateArrayLabel());
__ SmiUntag(R10);
// RAX: newly allocated array.
@@ -330,18 +323,15 @@ static void PushArgumentsArray(Assembler* assembler) {
// called, the stub accesses the receiver from this location directly
// when trying to resolve the call.
void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) {
__ EnterStubFrame();
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ pushq(raw_null); // Space for the return value.
__ EnterStubFrameWithPP();
__ PushObject(Object::Handle()); // Space for the return value.
// Push the receiver as an argument. Load the smi-tagged argument
// count into R13 to index the receiver in the stack. There are
// three words (null, stub's pc marker, saved fp) above the return
// four words (null, stub's pc marker, saved pp, saved fp) above the return
// address.
__ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
__ pushq(Address(RSP, R13, TIMES_4, (3 * kWordSize)));
__ pushq(Address(RSP, R13, TIMES_4, (4 * kWordSize)));
__ pushq(RBX); // Pass IC data object.
__ pushq(R10); // Pass arguments descriptor array.
@@ -355,7 +345,7 @@ void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) {
// Remove arguments.
__ Drop(4);
__ popq(RAX); // Get result into RAX.
__ LeaveFrame();
__ LeaveFrameWithPP();
__ ret();
}
@@ -378,7 +368,9 @@ DECLARE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp);
// - Fill the unoptimized frame.
// - Materialize objects that require allocation (e.g. Double instances).
// GC can occur only after frame is fully rewritten.
// Stack after EnterDartFrame(0) below:
// Stack after EnterDartFrame(0, PP, kNoRegister) below:
// +------------------+
// | Saved PP | <- PP
// +------------------+
// | PC marker | <- TOS
// +------------------+
@@ -391,8 +383,12 @@ DECLARE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp);
// Parts of the code cannot GC, part of the code can GC.
static void GenerateDeoptimizationSequence(Assembler* assembler,
bool preserve_result) {
// Leaf runtime function DeoptimizeCopyFrame expects a Dart frame.
__ EnterDartFrame(0);
// DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there
// is no need to set the correct PC marker or load PP, since they get patched.
__ EnterFrame(0);
__ pushq(Immediate(0));
__ pushq(PP);
// The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry
// and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls.
const intptr_t saved_result_slot_from_fp =
@@ -422,14 +418,21 @@ static void GenerateDeoptimizationSequence(Assembler* assembler,
__ movq(RBX, Address(RBP, saved_result_slot_from_fp * kWordSize));
}
// There is a Dart Frame on the stack. We just need the PP.
__ movq(PP, Address(RBP, -2 * kWordSize));
__ LeaveFrame();
__ popq(RCX); // Preserve return address.
__ movq(RSP, RBP); // Discard optimized frame.
__ subq(RSP, RAX); // Reserve space for deoptimized frame.
__ pushq(RCX); // Restore return address.
// Leaf runtime function DeoptimizeFillFrame expects a Dart frame.
__ EnterDartFrame(0);
// DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there
// is no need to set the correct PC marker or load PP, since they get patched.
__ EnterFrame(0);
__ pushq(Immediate(0));
__ pushq(PP);
if (preserve_result) {
__ pushq(RBX); // Preserve result as first local.
}
@@ -441,6 +444,8 @@ static void GenerateDeoptimizationSequence(Assembler* assembler,
__ movq(RBX, Address(RBP, kFirstLocalSlotFromFp * kWordSize));
}
// Code above cannot cause GC.
// There is a Dart Frame on the stack. We just need the PP.
__ movq(PP, Address(RBP, -2 * kWordSize));
__ LeaveFrame();
// Frame is fully rewritten at this point and it is safe to perform a GC.
@@ -486,20 +491,20 @@ void StubCode::GenerateDeoptimizeStub(Assembler* assembler) {
void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
__ EnterStubFrame();
__ EnterStubFrameWithPP();
// Load the receiver into RAX. The argument count in the arguments
// descriptor in R10 is a smi.
__ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
// Two words (saved fp, stub's pc marker) in the stack above the return
// address.
__ movq(RAX, Address(RSP, RAX, TIMES_4, 2 * kWordSize));
// Three words (saved pp, saved fp, stub's pc marker)
// in the stack above the return address.
__ movq(RAX, Address(RSP, RAX, TIMES_4,
kSavedAboveReturnAddress * kWordSize));
// Preserve IC data and arguments descriptor.
__ pushq(RBX);
__ pushq(R10);
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Instructions::null()));
__ pushq(raw_null); // Space for the result of the runtime call.
// Space for the result of the runtime call.
__ PushObject(Object::Handle());
__ pushq(RAX); // Receiver.
__ pushq(RBX); // IC data.
__ pushq(R10); // Arguments descriptor.
@@ -511,10 +516,10 @@ void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
__ popq(RAX); // Return value from the runtime call (instructions).
__ popq(R10); // Restore arguments descriptor.
__ popq(RBX); // Restore IC data.
__ LeaveFrame();
__ LeaveFrameWithPP();
Label lookup;
__ cmpq(RAX, raw_null);
__ CompareObject(RAX, Object::Handle());
__ j(EQUAL, &lookup, Assembler::kNearJump);
__ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
__ jmp(RAX);
@@ -532,8 +537,6 @@ void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
// The newly allocated object is returned in RAX.
void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
Label slow_case;
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
if (FLAG_inline_alloc) {
// Compute the size to be allocated, it is based on the array length
@@ -622,13 +625,14 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
__ leaq(RBX, FieldAddress(RAX, Array::data_offset()));
// RBX: iterator which initially points to the start of the variable
// data area to be initialized.
__ LoadObject(R13, Object::Handle(), PP);
Label done;
Label init_loop;
__ Bind(&init_loop);
__ cmpq(RBX, R12);
__ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
// TODO(cshapiro): StoreIntoObjectNoBarrier
__ movq(Address(RBX, 0), raw_null);
__ movq(Address(RBX, 0), R13);
__ addq(RBX, Immediate(kWordSize));
__ jmp(&init_loop, Assembler::kNearJump);
__ Bind(&done);
@@ -645,7 +649,8 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame();
__ pushq(raw_null); // Setup space on stack for return value.
// Setup space on stack for return value.
__ PushObject(Object::Handle());
__ pushq(R10); // Array length as Smi.
__ pushq(RBX); // Element type.
__ CallRuntime(kAllocateArrayRuntimeEntry, 2);
@@ -663,17 +668,16 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
// called, the stub accesses the closure from this location directly
// when trying to resolve the call.
void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
// Load num_args.
__ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
// Load closure object in R13.
__ movq(R13, Address(RSP, RAX, TIMES_4, 0)); // RAX is a Smi.
__ LoadObject(R12, Object::Handle(), PP);
// Verify that R13 is a closure by checking its class.
Label not_closure;
__ cmpq(R13, raw_null);
__ cmpq(R13, R12);
// Not a closure, but null object.
__ j(EQUAL, &not_closure);
__ testq(R13, Immediate(kSmiTagMask));
@@ -682,7 +686,7 @@ void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
// class.signature_function() is not null.
__ LoadClass(RAX, R13);
__ movq(RAX, FieldAddress(RAX, Class::signature_function_offset()));
__ cmpq(RAX, raw_null);
__ cmpq(RAX, R12);
// Actual class is not a closure class.
__ j(EQUAL, &not_closure, Assembler::kNearJump);
@@ -694,7 +698,7 @@ void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
// Load closure function code in RAX.
__ movq(RAX, FieldAddress(RBX, Function::code_offset()));
__ cmpq(RAX, raw_null);
__ cmpq(RAX, R12);
Label function_compiled;
__ j(NOT_EQUAL, &function_compiled, Assembler::kNearJump);
@@ -733,8 +737,8 @@ void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame();
__ pushq(raw_null); // Setup space on stack for result from call.
// Setup space on stack for result from call.
__ pushq(R12);
__ pushq(R10); // Arguments descriptor.
// Load smi-tagged arguments array length, including the non-closure.
__ movq(R10, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
@@ -761,12 +765,12 @@ void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
// RCX : new context containing the current isolate pointer.
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
// Save frame pointer coming in.
__ EnterFrame(0);
__ EnterStubFrame();
// Save arguments descriptor array and new context.
const intptr_t kArgumentsDescOffset = -1 * kWordSize;
const intptr_t kArgumentsDescOffset = -2 * kWordSize;
__ pushq(RSI);
const intptr_t kNewContextOffset = -2 * kWordSize;
const intptr_t kNewContextOffset = -3 * kWordSize;
__ pushq(RCX);
// Save C++ ABI callee-saved registers.
@@ -792,7 +796,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
// StackFrameIterator reads the top exit frame info saved in this frame.
// The constant kExitLinkSlotFromEntryFp must be kept in sync with the
// code below.
ASSERT(kExitLinkSlotFromEntryFp == -8);
ASSERT(kExitLinkSlotFromEntryFp == -9);
__ movq(RAX, Address(R8, Isolate::top_exit_frame_info_offset()));
__ pushq(RAX);
__ movq(Address(R8, Isolate::top_exit_frame_info_offset()), Immediate(0));
@@ -804,7 +808,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
// EntryFrame::SavedContext reads the context saved in this frame.
// The constant kSavedContextSlotFromEntryFp must be kept in sync with
// the code below.
ASSERT(kSavedContextSlotFromEntryFp == -9);
ASSERT(kSavedContextSlotFromEntryFp == -10);
__ movq(RAX, Address(R8, Isolate::top_context_offset()));
__ pushq(RAX);
@@ -881,8 +885,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
// Output:
// RAX: new allocated RawContext object.
void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ LoadObject(R12, Object::Handle(), PP);
if (FLAG_inline_alloc) {
const Class& context_class = Class::ZoneHandle(Object::context_class());
Label slow_case;
@@ -957,12 +960,10 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
// R13: Isolate, not an object.
__ movq(FieldAddress(RAX, Context::isolate_offset()), R13);
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
// Setup the parent field.
// RAX: new object.
// R10: number of context variables.
__ movq(FieldAddress(RAX, Context::parent_offset()), raw_null);
__ movq(FieldAddress(RAX, Context::parent_offset()), R12);
// Initialize the context variables.
// RAX: new object.
@@ -974,7 +975,7 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
__ jmp(&entry, Assembler::kNearJump);
__ Bind(&loop);
__ decq(R10);
__ movq(Address(R13, R10, TIMES_8, 0), raw_null);
__ movq(Address(R13, R10, TIMES_8, 0), R12);
__ Bind(&entry);
__ cmpq(R10, Immediate(0));
__ j(NOT_EQUAL, &loop, Assembler::kNearJump);
@@ -988,7 +989,7 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
}
// Create a stub frame.
__ EnterStubFrame();
__ pushq(raw_null); // Setup space on stack for the return value.
__ pushq(R12); // Setup space on stack for the return value.
__ SmiTag(R10);
__ pushq(R10); // Push number of context variables.
__ CallRuntime(kAllocateContextRuntimeEntry, 1); // Allocate context.
@@ -1072,8 +1073,6 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
const Class& cls) {
const intptr_t kObjectTypeArgumentsOffset = 2 * kWordSize;
const intptr_t kInstantiatorTypeArgumentsOffset = 1 * kWordSize;
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
// The generated code is different if the class is parameterized.
const bool is_cls_parameterized = cls.HasTypeArguments();
ASSERT(!cls.HasTypeArguments() ||
@@ -1085,6 +1084,7 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
const intptr_t instance_size = cls.instance_size();
ASSERT(instance_size > 0);
const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize();
__ LoadObject(R12, Object::Handle(), PP);
if (FLAG_inline_alloc &&
Heap::IsAllocatableInNewSpace(instance_size + type_args_size)) {
Label slow_case;
@@ -1168,9 +1168,6 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
__ movq(Address(RAX, Instance::tags_offset()), Immediate(tags));
// Initialize the remaining words of the object.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
// RAX: new object start.
// RBX: next object start.
// RDI: new object type arguments (if is_cls_parameterized).
@@ -1181,7 +1178,7 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
for (intptr_t current_offset = sizeof(RawObject);
current_offset < instance_size;
current_offset += kWordSize) {
__ movq(Address(RAX, current_offset), raw_null);
__ movq(Address(RAX, current_offset), R12);
}
} else {
__ leaq(RCX, Address(RAX, sizeof(RawObject)));
@@ -1195,7 +1192,7 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
__ Bind(&init_loop);
__ cmpq(RCX, RBX);
__ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
__ movq(Address(RCX, 0), raw_null);
__ movq(Address(RCX, 0), R12);
__ addq(RCX, Immediate(kWordSize));
__ jmp(&init_loop, Assembler::kNearJump);
__ Bind(&done);
@@ -1217,14 +1214,14 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
__ movq(RDX, Address(RSP, kInstantiatorTypeArgumentsOffset));
}
// Create a stub frame.
__ EnterStubFrame();
__ pushq(raw_null); // Setup space on stack for return value.
__ EnterStubFrameWithPP();
__ pushq(R12); // Setup space on stack for return value.
__ PushObject(cls); // Push class of object to be allocated.
if (is_cls_parameterized) {
__ pushq(RAX); // Push type arguments of object to be allocated.
__ pushq(RDX); // Push type arguments of instantiator.
} else {
__ pushq(raw_null); // Push null type arguments.
__ pushq(R12); // Push null type arguments.
__ pushq(Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
}
__ CallRuntime(kAllocateObjectRuntimeEntry, 3); // Allocate object.
@@ -1234,7 +1231,7 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
__ popq(RAX); // Pop result (newly allocated object).
// RAX: new object
// Restore the frame pointer.
__ LeaveFrame();
__ LeaveFrameWithPP();
__ ret();
}
@@ -1246,16 +1243,17 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
// RSP : points to return address.
void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
const Function& func) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
ASSERT(func.IsClosureFunction());
ASSERT(!func.IsImplicitStaticClosureFunction());
const bool is_implicit_instance_closure =
func.IsImplicitInstanceClosureFunction();
const Class& cls = Class::ZoneHandle(func.signature_class());
const bool has_type_arguments = cls.HasTypeArguments();
const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
const intptr_t kReceiverOffset = 2 * kWordSize;
__ EnterStubFrameWithPP(); // Uses pool pointer to refer to function.
__ LoadObject(R12, Object::Handle(), PP);
const intptr_t kTypeArgumentsOffset = 4 * kWordSize;
const intptr_t kReceiverOffset = 5 * kWordSize;
const intptr_t closure_size = Closure::InstanceSize();
const intptr_t context_size = Context::InstanceSize(1); // Captured receiver.
if (FLAG_inline_alloc &&
@@ -1298,7 +1296,8 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
// RAX: new closure object.
// RBX: new context object (only if is_implicit_closure).
// R13: next object start.
__ LoadObject(R10, func); // Load function of closure to be allocated.
// Load function of closure to be allocated.
__ LoadObject(R10, func, PP);
__ movq(Address(RAX, Closure::function_offset()), R10);
// Setup the context for this closure.
@@ -1320,7 +1319,7 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
__ movq(Address(RBX, Context::isolate_offset()), R10);
// Set the parent to null.
__ movq(Address(RBX, Context::parent_offset()), raw_null);
__ movq(Address(RBX, Context::parent_offset()), R12);
// Initialize the context variable to the receiver.
__ movq(R10, Address(RSP, kReceiverOffset));
@@ -1340,6 +1339,7 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
// Done allocating and initializing the instance.
// RAX: new object.
__ addq(RAX, Immediate(kHeapObjectTag));
__ LeaveFrameWithPP();
__ ret();
__ Bind(&slow_case);
@@ -1350,9 +1350,8 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
if (is_implicit_instance_closure) {
__ movq(RAX, Address(RSP, kReceiverOffset));
}
// Create the stub frame.
__ EnterStubFrame();
__ pushq(raw_null); // Setup space on stack for the return value.
__ pushq(R12); // Setup space on stack for the return value.
__ PushObject(func);
if (is_implicit_instance_closure) {
__ pushq(RAX); // Receiver.
@@ -1360,7 +1359,7 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
if (has_type_arguments) {
__ pushq(RCX); // Push type arguments of closure to be allocated.
} else {
__ pushq(raw_null); // Push null type arguments.
__ pushq(R12); // Push null type arguments.
}
if (is_implicit_instance_closure) {
__ CallRuntime(kAllocateImplicitInstanceClosureRuntimeEntry, 3);
@@ -1375,7 +1374,7 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
__ popq(RAX); // Pop the result.
// RAX: New closure object.
// Restore the calling frame.
__ LeaveFrame();
__ LeaveFrameWithPP();
__ ret();
}
@@ -1395,9 +1394,8 @@ void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
__ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
__ movq(RAX, Address(RBP, R13, TIMES_4, kParamEndSlotFromFp * kWordSize));
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ pushq(raw_null); // Setup space on stack for result from noSuchMethod.
__ LoadObject(R12, Object::Handle(), PP);
__ pushq(R12); // Setup space on stack for result from noSuchMethod.
__ pushq(RAX); // Receiver.
__ pushq(RBX); // IC data array.
__ pushq(R10); // Arguments descriptor array.
@@ -1545,8 +1543,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
__ j(NOT_EQUAL, &loop, Assembler::kNearJump);
// IC miss.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ LoadObject(R12, Object::Handle(), PP);
// Compute address of arguments (first read number of arguments from
// arguments descriptor array and then compute address on the stack).
__ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
@@ -1554,7 +1551,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
__ EnterStubFrame();
__ pushq(R10); // Preserve arguments descriptor array.
__ pushq(RBX); // Preserve IC data object.
__ pushq(raw_null); // Setup space on stack for result (target code object).
__ pushq(R12); // Setup space on stack for result (target code object).
// Push call arguments.
for (intptr_t i = 0; i < num_args; i++) {
__ movq(RCX, Address(RAX, -kWordSize * i));
@@ -1571,7 +1568,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
__ popq(R10); // Restore arguments descriptor array.
__ LeaveFrame();
Label call_target_function;
__ cmpq(RAX, raw_null);
__ cmpq(RAX, R12);
__ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump);
// NoSuchMethod or closure.
// Mark IC call that it may be a closure call that does not collect
@@ -1737,13 +1734,12 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
Immediate(Smi::RawValue(Smi::kMaxValue)));
__ Bind(&increment_done);
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
Label target_is_compiled;
// Get function and call it, if possible.
__ movq(R13, Address(R12, target_offset));
__ movq(RAX, FieldAddress(R13, Function::code_offset()));
__ cmpq(RAX, raw_null);
__ LoadObject(R12, Object::Handle(), PP);
__ cmpq(RAX, R12);
__ j(NOT_EQUAL, &target_is_compiled, Assembler::kNearJump);
__ EnterStubFrame();
@@ -1783,9 +1779,8 @@ void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) {
__ pushq(R10);
// Room for result. Debugger stub returns address of the
// unpatched runtime stub.
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ pushq(raw_null); // Room for result.
__ LoadObject(R12, Object::Handle(), PP);
__ pushq(R12); // Room for result.
__ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
__ popq(RAX); // Address of original.
__ popq(R10); // Restore arguments.
@@ -1798,11 +1793,10 @@ void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) {
// RBX: ICData (unoptimized static call)
// TOS(0): return address (Dart code).
void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ EnterStubFrame();
__ LoadObject(R12, Object::Handle(), PP);
__ pushq(RBX); // Preserve IC data for unoptimized call.
__ pushq(raw_null); // Room for result.
__ pushq(R12); // Room for result.
__ CallRuntime(kBreakpointStaticHandlerRuntimeEntry, 0);
__ popq(RAX); // Code object.
__ popq(RBX); // Restore IC data.
@@ -1827,7 +1821,7 @@ void StubCode::GenerateBreakpointReturnStub(Assembler* assembler) {
__ LeaveFrame();
__ popq(R11); // discard return address of call to this stub.
__ LeaveFrame();
__ LeaveFrameWithPP();
__ ret();
}
@@ -1868,17 +1862,16 @@ void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) {
// Result in RCX: null -> not found, otherwise result (true or false).
static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
ASSERT((1 <= n) && (n <= 3));
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
const intptr_t kInstantiatorTypeArgumentsInBytes = 1 * kWordSize;
const intptr_t kInstanceOffsetInBytes = 2 * kWordSize;
const intptr_t kCacheOffsetInBytes = 3 * kWordSize;
__ movq(RAX, Address(RSP, kInstanceOffsetInBytes));
__ LoadObject(R12, Object::Handle(), PP);
if (n > 1) {
__ LoadClass(R10, RAX);
// Compute instance type arguments into R13.
Label has_no_type_arguments;
__ movq(R13, raw_null);
__ movq(R13, R12);
__ movq(RDI, FieldAddress(R10,
Class::type_arguments_field_offset_in_words_offset()));
__ cmpq(RDI, Immediate(Class::kNoTypeArguments));
@@ -1900,7 +1893,7 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
__ SmiTag(R10);
__ Bind(&loop);
__ movq(RDI, Address(RDX, kWordSize * SubtypeTestCache::kInstanceClassId));
__ cmpq(RDI, raw_null);
__ cmpq(RDI, R12);
__ j(EQUAL, &not_found, Assembler::kNearJump);
__ cmpq(RDI, R10);
if (n == 1) {
@@ -1927,7 +1920,7 @@ static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
__ jmp(&loop, Assembler::kNearJump);
// Fall through to not found.
__ Bind(&not_found);
__ movq(RCX, raw_null);
__ movq(RCX, R12);
__ ret();
__ Bind(&found);
@@ -2060,10 +2053,10 @@ void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) {
__ movq(RAX, Address(RSP, 1 * kWordSize));
__ cmpq(RAX, Address(RSP, 2 * kWordSize));
__ j(EQUAL, &true_label, Assembler::kNearJump);
__ LoadObject(RAX, Bool::False());
__ LoadObject(RAX, Bool::False(), PP);
__ ret();
__ Bind(&true_label);
__ LoadObject(RAX, Bool::True());
__ LoadObject(RAX, Bool::True(), PP);
__ ret();
__ Bind(&get_class_id_as_smi);
@@ -2081,7 +2074,7 @@ void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) {
__ Bind(&update_ic_data);
// RCX: ICData
// RBX: ICData
__ movq(RAX, Address(RSP, 1 * kWordSize));
__ movq(R13, Address(RSP, 2 * kWordSize));
__ EnterStubFrame();
@@ -2100,11 +2093,10 @@ void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) {
// RDI: function to be reoptimized.
// R10: argument descriptor (preserved).
void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ EnterStubFrame();
__ EnterStubFrameWithPP();
__ LoadObject(R12, Object::Handle(), PP);
__ pushq(R10);
__ pushq(raw_null); // Setup space on stack for return value.
__ pushq(R12); // Setup space on stack for return value.
__ pushq(RDI);
__ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1);
__ popq(RAX); // Disard argument.
@@ -2112,7 +2104,7 @@ void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
__ popq(R10); // Restore argument descriptor.
__ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
__ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
__ LeaveFrame();
__ LeaveFrameWithPP();
__ jmp(RAX);
__ int3();
}
+5 -5
View File
@@ -45,8 +45,8 @@ static void GenerateCallToCallRuntimeStub(Assembler* assembler,
const Object& result = Object::ZoneHandle();
const Context& context = Context::ZoneHandle(Context::New(0, Heap::kOld));
ASSERT(context.isolate() == Isolate::Current());
__ enter(Immediate(0));
__ LoadObject(CTX, context);
__ EnterStubFrameWithPP();
__ LoadObject(CTX, context, PP);
__ PushObject(result); // Push Null object for return value.
__ PushObject(smi1); // Push argument 1 smi1.
__ PushObject(smi2); // Push argument 2 smi2.
@@ -54,7 +54,7 @@ static void GenerateCallToCallRuntimeStub(Assembler* assembler,
__ CallRuntime(kTestSmiSubRuntimeEntry, argc); // Call SmiSub runtime func.
__ AddImmediate(RSP, Immediate(argc * kWordSize));
__ popq(RAX); // Pop return value from return slot.
__ leave();
__ LeaveFrameWithPP();
__ ret();
}
@@ -84,8 +84,8 @@ static void GenerateCallToCallLeafRuntimeStub(Assembler* assembler,
const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
__ enter(Immediate(0));
__ ReserveAlignedFrameSpace(0);
__ LoadObject(RDI, smi1); // Set up argument 1 smi1.
__ LoadObject(RSI, smi2); // Set up argument 2 smi2.
__ LoadObject(RDI, smi1, PP); // Set up argument 1 smi1.
__ LoadObject(RSI, smi2, PP); // Set up argument 2 smi2.
__ CallRuntime(kTestLeafSmiAddRuntimeEntry, 2); // Call SmiAdd runtime func.
__ leave();
__ ret(); // Return value is in RAX.