Fix for issue 14790 - Crash when using dartium devtools
The stack frame iteration during GC was missing one slot in stub frames that did not save the pool pointer. - This change makes all stub frames uniform, i.e they always save/restore the pool pointer. This ensures that we will traverse all slots on the stack. - A new constant called kFirstObjectSlotFromFp has been added which is used as the slot to start stack traversal. (The ARM and MIPs changes will be in a different CL) R=iposva@google.com, regis@google.com, zra@google.com Review URL: https://codereview.chromium.org//63093003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@30088 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
+19
-15
@@ -2667,17 +2667,11 @@ 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();
|
||||
LeaveDartFrame();
|
||||
ret();
|
||||
nop(4);
|
||||
ASSERT((buffer_.GetPosition() - start) == 13);
|
||||
@@ -2825,6 +2819,13 @@ void Assembler::EnterDartFrameWithInfo(intptr_t frame_size,
|
||||
}
|
||||
|
||||
|
||||
void Assembler::LeaveDartFrame() {
|
||||
// Restore caller's PP register that was pushed in EnterDartFrame.
|
||||
movq(PP, Address(RBP, (kSavedCallerPpSlotFromFp * kWordSize)));
|
||||
LeaveFrame();
|
||||
}
|
||||
|
||||
|
||||
// On entry to a function compiled for OSR, the caller's frame pointer, the
|
||||
// stack locals, and any copied parameters are already in place. The frame
|
||||
// pointer is already set up. The PC marker is not correct for the
|
||||
@@ -2862,17 +2863,20 @@ void Assembler::EnterOsrFrame(intptr_t extra_size,
|
||||
}
|
||||
|
||||
|
||||
void Assembler::EnterStubFrame() {
|
||||
EnterFrame(0);
|
||||
pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames.
|
||||
}
|
||||
|
||||
|
||||
void Assembler::EnterStubFrameWithPP() {
|
||||
void Assembler::EnterStubFrame(bool load_pp) {
|
||||
EnterFrame(0);
|
||||
pushq(Immediate(0)); // Push 0 in the saved PC area for stub frames.
|
||||
pushq(PP); // Save caller's pool pointer
|
||||
LoadPoolPointer(PP);
|
||||
if (load_pp) {
|
||||
LoadPoolPointer(PP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Assembler::LeaveStubFrame() {
|
||||
// Restore caller's PP register that was pushed in EnterStubFrame.
|
||||
movq(PP, Address(RBP, (kSavedCallerPpSlotFromFp * kWordSize)));
|
||||
LeaveFrame();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-10
@@ -716,7 +716,6 @@ class Assembler : public ValueObject {
|
||||
|
||||
void EnterFrame(intptr_t frame_space);
|
||||
void LeaveFrame();
|
||||
void LeaveFrameWithPP();
|
||||
void ReturnPatchable();
|
||||
void ReserveAlignedFrameSpace(intptr_t frame_space);
|
||||
|
||||
@@ -776,11 +775,11 @@ class Assembler : public ValueObject {
|
||||
// to this frame.
|
||||
// The dart frame layout is as follows:
|
||||
// ....
|
||||
// ret PC
|
||||
// saved RBP <=== RBP
|
||||
// pc (used to derive the RawInstruction Object of the dart code)
|
||||
// saved PP
|
||||
// locals space <=== RSP
|
||||
// saved PP
|
||||
// pc (used to derive the RawInstruction Object of the dart code)
|
||||
// saved RBP <=== RBP
|
||||
// ret PC
|
||||
// .....
|
||||
// This code sets this up with the sequence:
|
||||
// pushq rbp
|
||||
@@ -793,6 +792,7 @@ class Assembler : public ValueObject {
|
||||
void EnterDartFrame(intptr_t frame_size);
|
||||
void EnterDartFrameWithInfo(intptr_t frame_size,
|
||||
Register new_pp, Register new_pc);
|
||||
void LeaveDartFrame();
|
||||
|
||||
// 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
|
||||
@@ -802,18 +802,18 @@ class Assembler : public ValueObject {
|
||||
// Set up a stub frame so that the stack traversal code can easily identify
|
||||
// a stub frame.
|
||||
// The stub frame layout is as follows:
|
||||
// ....
|
||||
// ret PC
|
||||
// saved RBP
|
||||
// .... <=== RSP
|
||||
// pc (used to derive the RawInstruction Object of the stub)
|
||||
// saved RBP <=== RBP
|
||||
// ret PC
|
||||
// .....
|
||||
// This code sets this up with the sequence:
|
||||
// pushq rbp
|
||||
// movq rbp, rsp
|
||||
// pushq immediate(0)
|
||||
// .....
|
||||
void EnterStubFrame();
|
||||
void EnterStubFrameWithPP();
|
||||
void EnterStubFrame(bool load_pp = false);
|
||||
void LeaveStubFrame();
|
||||
|
||||
// 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
|
||||
|
||||
@@ -1625,13 +1625,11 @@ ASSEMBLER_TEST_RUN(PackedCompareNLE, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
|
||||
__ EnterDartFrame(0);
|
||||
__ movl(RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
|
||||
__ movd(XMM0, RAX);
|
||||
__ shufps(XMM0, XMM0, Immediate(0x0));
|
||||
__ negateps(XMM0);
|
||||
__ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
|
||||
__ LeaveFrameWithPP();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1644,13 +1642,11 @@ ASSEMBLER_TEST_RUN(PackedNegate, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
|
||||
__ EnterDartFrame(0);
|
||||
__ movl(RAX, Immediate(bit_cast<int32_t, float>(-15.3f)));
|
||||
__ movd(XMM0, RAX);
|
||||
__ shufps(XMM0, XMM0, Immediate(0x0));
|
||||
__ absps(XMM0);
|
||||
__ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
|
||||
__ LeaveFrameWithPP();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1663,11 +1659,9 @@ ASSEMBLER_TEST_RUN(PackedAbsolute, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
|
||||
__ EnterDartFrame(0);
|
||||
__ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
|
||||
__ zerowps(XMM0);
|
||||
__ shufps(XMM0, XMM0, Immediate(0xFF)); // Copy the W lane which is now 0.0.
|
||||
__ LeaveFrameWithPP();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1784,7 +1778,8 @@ ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) {
|
||||
uint32_t d;
|
||||
} constant1 =
|
||||
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
|
||||
__ EnterDartFrame(0);
|
||||
__ pushq(PP); // Save caller's pool pointer and load a new one here.
|
||||
__ LoadPoolPointer(PP);
|
||||
__ LoadImmediate(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)), PP);
|
||||
__ movups(XMM9, Address(RAX, 0));
|
||||
__ notps(XMM9);
|
||||
@@ -1792,7 +1787,7 @@ ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) {
|
||||
__ pushq(RAX);
|
||||
__ movss(Address(RSP, 0), XMM0);
|
||||
__ popq(RAX);
|
||||
__ LeaveFrameWithPP();
|
||||
__ popq(PP); // Restore caller's pool pointer.
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -2189,7 +2184,9 @@ ASSEMBLER_TEST_GENERATE(TestObjectCompare, assembler) {
|
||||
ObjectStore* object_store = Isolate::Current()->object_store();
|
||||
const Object& obj = Object::ZoneHandle(object_store->smi_class());
|
||||
Label fail;
|
||||
__ EnterDartFrame(0);
|
||||
__ EnterFrame(0);
|
||||
__ pushq(PP); // Save caller's pool pointer and load a new one here.
|
||||
__ LoadPoolPointer(PP);
|
||||
__ LoadObject(RAX, obj, PP);
|
||||
__ CompareObject(RAX, obj, PP);
|
||||
__ j(NOT_EQUAL, &fail);
|
||||
@@ -2211,11 +2208,12 @@ ASSEMBLER_TEST_GENERATE(TestObjectCompare, assembler) {
|
||||
__ CompareObject(RCX, smi, PP);
|
||||
__ j(NOT_EQUAL, &fail);
|
||||
__ movl(RAX, Immediate(1)); // OK
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveDartFrame();
|
||||
__ ret();
|
||||
__ Bind(&fail);
|
||||
__ movl(RAX, Immediate(0)); // Fail.
|
||||
__ LeaveFrameWithPP();
|
||||
__ popq(PP); // Restore caller's pool pointer.
|
||||
__ LeaveFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -2426,14 +2424,15 @@ ASSEMBLER_TEST_RUN(SquareRootDouble, test) {
|
||||
|
||||
// Called from assembler_test.cc.
|
||||
ASSEMBLER_TEST_GENERATE(StoreIntoObject, assembler) {
|
||||
__ EnterDartFrame(0);
|
||||
__ pushq(PP); // Save caller's pool pointer and load a new one here.
|
||||
__ LoadPoolPointer(PP);
|
||||
__ pushq(CTX);
|
||||
__ movq(CTX, RDI);
|
||||
__ StoreIntoObject(RDX,
|
||||
FieldAddress(RDX, GrowableObjectArray::data_offset()),
|
||||
RSI);
|
||||
__ popq(CTX);
|
||||
__ LeaveFrameWithPP();
|
||||
__ popq(PP); // Restore caller's pool pointer.
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -2547,9 +2546,7 @@ ASSEMBLER_TEST_RUN(DoubleToDoubleTrunc, test) {
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(DoubleAbs, assembler) {
|
||||
__ EnterDartFrame(0);
|
||||
__ DoubleAbs(XMM0);
|
||||
__ LeaveFrameWithPP();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
|
||||
@@ -977,7 +977,7 @@ void FlowGraphCompiler::CopyParameters() {
|
||||
ICData::New(function, Symbols::Call(), Object::empty_array(),
|
||||
Isolate::kNoDeoptId, kNumArgsChecked));
|
||||
__ LoadObject(RBX, ic_data, PP);
|
||||
__ LeaveFrameWithPP(); // The arguments are still on the stack.
|
||||
__ LeaveDartFrame(); // The arguments are still on the stack.
|
||||
__ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
|
||||
// The noSuchMethod call may return to the caller, but not here.
|
||||
__ int3();
|
||||
@@ -1176,7 +1176,7 @@ void FlowGraphCompiler::CompileGraph() {
|
||||
ICData::New(function, name, Object::empty_array(),
|
||||
Isolate::kNoDeoptId, kNumArgsChecked));
|
||||
__ LoadObject(RBX, ic_data, PP);
|
||||
__ LeaveFrameWithPP(); // The arguments are still on the stack.
|
||||
__ LeaveDartFrame(); // The arguments are still on the stack.
|
||||
__ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
|
||||
// The noSuchMethod call may return to the caller, but not here.
|
||||
__ int3();
|
||||
|
||||
@@ -27,21 +27,29 @@ ASSEMBLER_TEST_RUN(Call, test) {
|
||||
}
|
||||
|
||||
|
||||
static intptr_t prologue_code_size = -1;
|
||||
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Jump, assembler) {
|
||||
__ EnterDartFrame(0); // 20 bytes
|
||||
ASSERT(assembler->CodeSize() == 0);
|
||||
__ pushq(PP);
|
||||
__ LoadPoolPointer(PP);
|
||||
prologue_code_size = assembler->CodeSize();
|
||||
__ JmpPatchable(&StubCode::InstanceFunctionLookupLabel(), PP);
|
||||
__ JmpPatchable(&StubCode::AllocateArrayLabel(), PP);
|
||||
__ LeaveFrameWithPP();
|
||||
__ popq(PP);
|
||||
__ ret();
|
||||
}
|
||||
|
||||
|
||||
ASSEMBLER_TEST_RUN(Jump, test) {
|
||||
JumpPattern jump1(test->entry() + 20, test->code());
|
||||
ASSERT(prologue_code_size != -1);
|
||||
JumpPattern jump1(test->entry() + prologue_code_size, test->code());
|
||||
jump1.IsValid();
|
||||
EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
|
||||
jump1.TargetAddress());
|
||||
JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes() + 20,
|
||||
JumpPattern jump2((test->entry() +
|
||||
jump1.pattern_length_in_bytes() + prologue_code_size),
|
||||
test->code());
|
||||
EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
|
||||
jump2.TargetAddress());
|
||||
|
||||
@@ -34,9 +34,10 @@ void GenerateIncrement(Assembler* assembler) {
|
||||
void GenerateEmbedStringInCode(Assembler* assembler, const char* str) {
|
||||
const String& string_object =
|
||||
String::ZoneHandle(String::New(str, Heap::kOld));
|
||||
__ EnterDartFrame(0);
|
||||
__ pushq(PP); // Save caller's pool pointer and load a new one here.
|
||||
__ LoadPoolPointer(PP);
|
||||
__ LoadObject(RAX, string_object, PP);
|
||||
__ LeaveFrameWithPP();
|
||||
__ popq(PP); // Restore caller's pool pointer.
|
||||
__ ret();
|
||||
}
|
||||
|
||||
|
||||
@@ -61,21 +61,24 @@ void StackFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
||||
// helper functions to the raw object interface.
|
||||
ASSERT(visitor != NULL);
|
||||
NoGCScope no_gc;
|
||||
RawObject** first = reinterpret_cast<RawObject**>(sp());
|
||||
RawObject** last = reinterpret_cast<RawObject**>(
|
||||
fp() + (kFirstLocalSlotFromFp * kWordSize));
|
||||
Code code;
|
||||
code = LookupDartCode();
|
||||
if (!code.IsNull()) {
|
||||
// Visit the code object.
|
||||
RawObject* raw_code = code.raw();
|
||||
visitor->VisitPointer(&raw_code);
|
||||
// Visit stack based on stack maps.
|
||||
|
||||
// Optimized frames have a stack map. We need to visit the frame based
|
||||
// on the stack map.
|
||||
Array maps;
|
||||
maps = Array::null();
|
||||
Stackmap map;
|
||||
map = code.GetStackmap(pc(), &maps, &map);
|
||||
if (!map.IsNull()) {
|
||||
RawObject** first = reinterpret_cast<RawObject**>(sp());
|
||||
RawObject** last = reinterpret_cast<RawObject**>(
|
||||
fp() + (kFirstLocalSlotFromFp * kWordSize));
|
||||
|
||||
// A stack map is present in the code object, use the stack map to
|
||||
// visit frame slots which are marked as having objects.
|
||||
//
|
||||
@@ -108,9 +111,22 @@ void StackFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
|
||||
// The last slot can be one slot (but not more) past the last slot
|
||||
// in the case that all slots were covered by the stack map.
|
||||
ASSERT((last + 1) >= first);
|
||||
visitor->VisitPointers(first, last);
|
||||
|
||||
// Now visit other slots which might be part of the calling convention.
|
||||
first = reinterpret_cast<RawObject**>(
|
||||
fp() + ((kFirstLocalSlotFromFp + 1) * kWordSize));
|
||||
last = reinterpret_cast<RawObject**>(
|
||||
fp() + (kFirstObjectSlotFromFp * kWordSize));
|
||||
visitor->VisitPointers(first, last);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Each slot between the first and last included are tagged objects.
|
||||
// For normal unoptimized Dart frames and Stub frames each slot
|
||||
// between the first and last included are tagged objects.
|
||||
RawObject** first = reinterpret_cast<RawObject**>(sp());
|
||||
RawObject** last = reinterpret_cast<RawObject**>(
|
||||
fp() + (kFirstObjectSlotFromFp * kWordSize));
|
||||
visitor->VisitPointers(first, last);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,19 +16,24 @@ Callee frame | ... |
|
||||
| saved LR | (PC of current frame)
|
||||
| callee's PC marker |
|
||||
+--------------------+
|
||||
Current frame | ... | <- SP of current frame
|
||||
| first local |
|
||||
| caller's PP |
|
||||
Current frame | ... T| <- SP of current frame
|
||||
| first local T|
|
||||
| caller's PP T|
|
||||
| caller's FP | <- FP of current frame
|
||||
| caller's LR | (PC of caller frame)
|
||||
| PC marker | (current frame's code entry + offset)
|
||||
+--------------------+
|
||||
Caller frame | last parameter | <- SP of caller frame
|
||||
| ... |
|
||||
|
||||
T against a slot indicates it needs to be traversed during GC.
|
||||
*/
|
||||
|
||||
static const int kDartFrameFixedSize = 4; // PP, FP, LR, PC marker.
|
||||
static const int kSavedPcSlotFromSp = -2;
|
||||
|
||||
static const int kFirstObjectSlotFromFp = -2; // Used by GC to traverse stack.
|
||||
|
||||
static const int kFirstLocalSlotFromFp = -2;
|
||||
static const int kSavedCallerPpSlotFromFp = -1;
|
||||
static const int kSavedCallerFpSlotFromFp = 0;
|
||||
@@ -44,4 +49,3 @@ static const int kExitLinkSlotFromEntryFp = -25;
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_STACK_FRAME_ARM_H_
|
||||
|
||||
|
||||
@@ -14,18 +14,23 @@ Callee frame | ... |
|
||||
| saved EBP | (EBP of current frame)
|
||||
| saved PC | (PC of current frame)
|
||||
+--------------------+
|
||||
Current frame | ... | <- ESP of current frame
|
||||
| first local |
|
||||
Current frame | ... T| <- ESP of current frame
|
||||
| first local T|
|
||||
| PC marker | (current frame's code entry + offset)
|
||||
| caller's EBP | <- EBP of current frame
|
||||
| caller's ret addr | (PC of caller frame)
|
||||
+--------------------+
|
||||
Caller frame | last parameter | <- ESP of caller frame
|
||||
| ... |
|
||||
|
||||
T against a slot indicates it needs to be traversed during GC.
|
||||
*/
|
||||
|
||||
static const int kDartFrameFixedSize = 3; // PC marker, EBP, PC.
|
||||
static const int kSavedPcSlotFromSp = -1;
|
||||
|
||||
static const int kFirstObjectSlotFromFp = -2; // Used by GC to traverse stack.
|
||||
|
||||
static const int kFirstLocalSlotFromFp = -2;
|
||||
static const int kPcMarkerSlotFromFp = -1;
|
||||
static const int kSavedCallerFpSlotFromFp = 0;
|
||||
@@ -43,4 +48,3 @@ static const int kExitLinkSlotFromEntryFp = -4;
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_STACK_FRAME_IA32_H_
|
||||
|
||||
|
||||
@@ -14,19 +14,24 @@ Callee frame | ... |
|
||||
| current RA | (PC of current frame)
|
||||
| callee's PC marker |
|
||||
+--------------------+
|
||||
Current frame | ... | <- SP of current frame
|
||||
| first local |
|
||||
| caller's PP |
|
||||
Current frame | ... T| <- SP of current frame
|
||||
| first local T|
|
||||
| caller's PP T|
|
||||
| caller's FP | <- FP of current frame
|
||||
| caller's RA | (PC of caller frame)
|
||||
| PC marker | (current frame's code entry + offset)
|
||||
+--------------------+
|
||||
Caller frame | last parameter | <- SP of caller frame
|
||||
| ... |
|
||||
|
||||
T against a slot indicates it needs to be traversed during GC.
|
||||
*/
|
||||
|
||||
static const int kDartFrameFixedSize = 4; // PP, FP, RA, PC marker.
|
||||
static const int kSavedPcSlotFromSp = -2;
|
||||
|
||||
static const int kFirstObjectSlotFromFp = -2; // Used by GC to traverse stack.
|
||||
|
||||
static const int kFirstLocalSlotFromFp = -2;
|
||||
static const int kSavedCallerPpSlotFromFp = -1;
|
||||
static const int kSavedCallerFpSlotFromFp = 0;
|
||||
@@ -42,4 +47,3 @@ static const int kExitLinkSlotFromEntryFp = -22;
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_STACK_FRAME_MIPS_H_
|
||||
|
||||
|
||||
@@ -16,20 +16,24 @@ Callee frame | ... |
|
||||
| saved RBP | (RBP of current frame)
|
||||
| saved PC | (PC of current frame)
|
||||
+--------------------+
|
||||
Current frame | ... | <- RSP of current frame
|
||||
| first local |
|
||||
| caller's PP |
|
||||
Current frame | ... T| <- RSP of current frame
|
||||
| first local T|
|
||||
| caller's PP T|
|
||||
| PC marker | (current frame's code entry + offset)
|
||||
| caller's RBP | <- RBP of current frame
|
||||
| caller's ret addr | (PC of caller frame)
|
||||
+--------------------+
|
||||
Caller frame | last parameter | <- RSP of caller frame
|
||||
| ... |
|
||||
|
||||
T against a slot indicates it needs to be traversed during GC.
|
||||
*/
|
||||
|
||||
static const int kDartFrameFixedSize = 4; // PC marker, RBP, PP, PC.
|
||||
static const int kSavedPcSlotFromSp = -1;
|
||||
|
||||
static const int kFirstObjectSlotFromFp = -2; // Used by GC to traverse stack.
|
||||
|
||||
static const int kFirstLocalSlotFromFp = -3;
|
||||
static const int kSavedCallerPpSlotFromFp = -2;
|
||||
static const int kPcMarkerSlotFromFp = -1;
|
||||
@@ -41,10 +45,9 @@ static const int kCallerSpSlotFromFp = 2;
|
||||
static const int kSavedAboveReturnAddress = 3; // Saved above return address.
|
||||
|
||||
// Entry and exit frame layout.
|
||||
static const int kSavedContextSlotFromEntryFp = -10;
|
||||
static const int kExitLinkSlotFromEntryFp = -9;
|
||||
static const int kSavedContextSlotFromEntryFp = -9;
|
||||
static const int kExitLinkSlotFromEntryFp = -8;
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // VM_STACK_FRAME_X64_H_
|
||||
|
||||
|
||||
+50
-51
@@ -260,7 +260,7 @@ void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
|
||||
__ popq(RAX); // Get Code object result.
|
||||
__ popq(R10); // Restore arguments descriptor array.
|
||||
// Remove the stub frame as we are about to jump to the dart function.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
|
||||
__ movq(RBX, FieldAddress(RAX, Code::instructions_offset()));
|
||||
__ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
|
||||
@@ -281,7 +281,7 @@ void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
|
||||
__ popq(R10); // Restore arguments descriptor array.
|
||||
__ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
|
||||
__ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ jmp(RAX);
|
||||
__ int3();
|
||||
}
|
||||
@@ -323,7 +323,7 @@ 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) {
|
||||
__ EnterStubFrameWithPP();
|
||||
__ EnterStubFrame();
|
||||
__ PushObject(Object::null_object(), PP); // Space for the return value.
|
||||
|
||||
// Push the receiver as an argument. Load the smi-tagged argument
|
||||
@@ -345,7 +345,7 @@ void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) {
|
||||
// Remove arguments.
|
||||
__ Drop(4);
|
||||
__ popq(RAX); // Get result into RAX.
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -418,9 +418,8 @@ 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();
|
||||
// There is a Dart Frame on the stack. We must restore PP and leave frame.
|
||||
__ LeaveDartFrame();
|
||||
|
||||
__ popq(RCX); // Preserve return address.
|
||||
__ movq(RSP, RBP); // Discard optimized frame.
|
||||
@@ -444,9 +443,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();
|
||||
// There is a Dart Frame on the stack. We must restore PP and leave frame.
|
||||
__ LeaveDartFrame();
|
||||
|
||||
// Frame is fully rewritten at this point and it is safe to perform a GC.
|
||||
// Materialize any objects that were deferred by FillFrame because they
|
||||
@@ -466,7 +464,7 @@ static void GenerateDeoptimizationSequence(Assembler* assembler,
|
||||
__ popq(RAX); // Restore result.
|
||||
__ Drop(1); // Workaround for dropped stack slot during GC.
|
||||
}
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
|
||||
__ popq(RCX); // Pop return address.
|
||||
__ addq(RSP, RBX); // Remove materialization arguments.
|
||||
@@ -493,7 +491,7 @@ void StubCode::GenerateDeoptimizeStub(Assembler* assembler) {
|
||||
|
||||
|
||||
void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
|
||||
__ EnterStubFrameWithPP();
|
||||
__ EnterStubFrame();
|
||||
// Load the receiver into RAX. The argument count in the arguments
|
||||
// descriptor in R10 is a smi.
|
||||
__ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
|
||||
@@ -518,7 +516,7 @@ void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
|
||||
__ popq(RAX); // Return value from the runtime call (instructions).
|
||||
__ popq(R10); // Restore arguments descriptor.
|
||||
__ popq(RBX); // Restore IC data.
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveStubFrame();
|
||||
|
||||
Label lookup;
|
||||
__ CompareObject(RAX, Object::null_object(), PP);
|
||||
@@ -659,7 +657,7 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
|
||||
__ popq(RAX); // Pop element type argument.
|
||||
__ popq(R10); // Pop array length argument.
|
||||
__ popq(RAX); // Pop return value from return slot.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -717,7 +715,7 @@ void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
|
||||
__ movq(RAX, FieldAddress(RBX, Function::code_offset()));
|
||||
|
||||
// Remove the stub frame as we are about to jump to the closure function.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
|
||||
__ Bind(&function_compiled);
|
||||
// RAX: Code.
|
||||
@@ -753,7 +751,7 @@ void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
|
||||
__ popq(RAX); // Get result into RAX.
|
||||
|
||||
// Remove the stub frame as we are about to return.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -767,16 +765,13 @@ void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
|
||||
// RCX : new context containing the current isolate pointer.
|
||||
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
// Save frame pointer coming in.
|
||||
__ EnterStubFrameWithPP();
|
||||
__ EnterFrame(0);
|
||||
|
||||
// At this point, the stack looks like:
|
||||
// | saved RC15/PP | <-- RSP / TOS
|
||||
// | "saved PC area" = 0 |
|
||||
// | saved RBP | <-- RBP
|
||||
// | saved PC (return to DartEntry::InvokeFunction) |
|
||||
|
||||
// The old frame pointer, the return address, the old R15 (for PP).
|
||||
const intptr_t kInitialOffset = 3;
|
||||
const intptr_t kInitialOffset = 1;
|
||||
// Save arguments descriptor array and new context.
|
||||
const intptr_t kArgumentsDescOffset = -(kInitialOffset) * kWordSize;
|
||||
__ pushq(RSI);
|
||||
@@ -788,7 +783,12 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
__ pushq(R12);
|
||||
__ pushq(R13);
|
||||
__ pushq(R14);
|
||||
// R15 is already saved above by EnterStubFrameWithPP.
|
||||
__ pushq(R15);
|
||||
|
||||
// We now load the pool pointer(PP) as we are about to invoke dart code and we
|
||||
// could potentially invoke some intrinsic functions which need the PP to be
|
||||
// set up.
|
||||
__ LoadPoolPointer(PP);
|
||||
|
||||
// If any additional (or fewer) values are pushed, the offsets in
|
||||
// kExitLinkSlotFromEntryFp and kSavedContextSlotFromEntryFp will need to be
|
||||
@@ -810,7 +810,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 == -9);
|
||||
ASSERT(kExitLinkSlotFromEntryFp == -8);
|
||||
__ movq(RAX, Address(R8, Isolate::top_exit_frame_info_offset()));
|
||||
__ pushq(RAX);
|
||||
__ movq(Address(R8, Isolate::top_exit_frame_info_offset()), Immediate(0));
|
||||
@@ -822,7 +822,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 == -10);
|
||||
ASSERT(kSavedContextSlotFromEntryFp == -9);
|
||||
__ movq(RAX, Address(R8, Isolate::top_context_offset()));
|
||||
__ pushq(RAX);
|
||||
|
||||
@@ -880,14 +880,14 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
__ movq(Address(CTX, Isolate::top_exit_frame_info_offset()), RDX);
|
||||
|
||||
// Restore C++ ABI callee-saved registers.
|
||||
// R15 will be restored below by LeaveFrameWithPP.
|
||||
__ popq(R15);
|
||||
__ popq(R14);
|
||||
__ popq(R13);
|
||||
__ popq(R12);
|
||||
__ popq(RBX);
|
||||
|
||||
// Restore the frame pointer.
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveFrame();
|
||||
|
||||
__ ret();
|
||||
}
|
||||
@@ -1011,7 +1011,7 @@ void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
|
||||
__ popq(RAX); // Pop the new context object.
|
||||
// RAX: new object
|
||||
// Restore the frame pointer.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1228,7 +1228,7 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
|
||||
__ movq(RDX, Address(RSP, kInstantiatorTypeArgumentsOffset));
|
||||
}
|
||||
// Create a stub frame.
|
||||
__ EnterStubFrameWithPP();
|
||||
__ EnterStubFrame(true); // Uses PP to access class object.
|
||||
__ pushq(R12); // Setup space on stack for return value.
|
||||
__ PushObject(cls, PP); // Push class of object to be allocated.
|
||||
if (is_cls_parameterized) {
|
||||
@@ -1245,7 +1245,7 @@ void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
|
||||
__ popq(RAX); // Pop result (newly allocated object).
|
||||
// RAX: new object
|
||||
// Restore the frame pointer.
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1264,7 +1264,7 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
|
||||
const Class& cls = Class::ZoneHandle(func.signature_class());
|
||||
const bool has_type_arguments = cls.NumTypeArguments() > 0;
|
||||
|
||||
__ EnterStubFrameWithPP(); // Uses pool pointer to refer to function.
|
||||
__ EnterStubFrame(true); // Uses pool pointer to refer to function.
|
||||
__ LoadObject(R12, Object::null_object(), PP);
|
||||
const intptr_t kTypeArgumentsOffset = 4 * kWordSize;
|
||||
const intptr_t kReceiverOffset = 5 * kWordSize;
|
||||
@@ -1353,7 +1353,7 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
|
||||
// Done allocating and initializing the instance.
|
||||
// RAX: new object.
|
||||
__ addq(RAX, Immediate(kHeapObjectTag));
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
|
||||
__ Bind(&slow_case);
|
||||
@@ -1388,7 +1388,7 @@ void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
|
||||
__ popq(RAX); // Pop the result.
|
||||
// RAX: New closure object.
|
||||
// Restore the calling frame.
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1424,7 +1424,7 @@ void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
|
||||
__ popq(RAX); // Get result into RAX.
|
||||
|
||||
// Remove the stub frame as we are about to return.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1445,7 +1445,7 @@ void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) {
|
||||
__ popq(RAX); // Discard argument;
|
||||
__ popq(ic_reg); // Restore.
|
||||
__ popq(func_reg); // Restore.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
}
|
||||
__ incq(FieldAddress(func_reg, Function::usage_counter_offset()));
|
||||
}
|
||||
@@ -1499,7 +1499,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
|
||||
__ pushq(RBX);
|
||||
__ CallRuntime(kSingleStepHandlerRuntimeEntry, 0);
|
||||
__ popq(RBX);
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ Bind(¬_stepping);
|
||||
|
||||
// Load arguments descriptor into R10.
|
||||
@@ -1580,7 +1580,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
|
||||
__ popq(RAX); // Pop returned code object into RAX (null if not found).
|
||||
__ popq(RBX); // Restore IC data array.
|
||||
__ popq(R10); // Restore arguments descriptor array.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
Label call_target_function;
|
||||
__ cmpq(RAX, R12);
|
||||
__ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump);
|
||||
@@ -1616,7 +1616,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub(
|
||||
__ popq(RAX); // Restore function.
|
||||
__ popq(RBX); // Restore IC data array.
|
||||
__ popq(R10); // Restore arguments descriptor array.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ movq(RCX, FieldAddress(RAX, Function::code_offset()));
|
||||
__ Bind(&is_compiled);
|
||||
}
|
||||
@@ -1746,7 +1746,7 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
|
||||
__ pushq(RBX); // Preserve IC data object.
|
||||
__ CallRuntime(kSingleStepHandlerRuntimeEntry, 0);
|
||||
__ popq(RBX);
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ Bind(¬_stepping);
|
||||
|
||||
// RBX: IC data object (preserved).
|
||||
@@ -1781,7 +1781,7 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
|
||||
__ popq(RAX); // Discard argument.
|
||||
__ popq(RBX); // Restore IC data object.
|
||||
__ popq(R13); // Restore target function.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ movq(RAX, FieldAddress(R13, Function::code_offset()));
|
||||
|
||||
__ Bind(&target_is_compiled);
|
||||
@@ -1814,7 +1814,7 @@ void StubCode::GenerateCompileFunctionRuntimeCallStub(Assembler* assembler) {
|
||||
__ popq(RAX); // Restore function.
|
||||
__ popq(RCX); // Restore IC data array.
|
||||
__ popq(RDX); // Restore arguments descriptor array.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1822,7 +1822,7 @@ void StubCode::GenerateCompileFunctionRuntimeCallStub(Assembler* assembler) {
|
||||
// RBX, R10: May contain arguments to runtime stub.
|
||||
// TOS(0): return address (Dart code).
|
||||
void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) {
|
||||
__ EnterStubFrameWithPP();
|
||||
__ EnterStubFrame();
|
||||
// Preserve runtime args.
|
||||
__ pushq(RBX);
|
||||
__ pushq(R10);
|
||||
@@ -1834,7 +1834,7 @@ void StubCode::GenerateBreakpointRuntimeStub(Assembler* assembler) {
|
||||
__ popq(RAX); // Address of original.
|
||||
__ popq(R10); // Restore arguments.
|
||||
__ popq(RBX);
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveStubFrame();
|
||||
__ jmp(RAX); // Jump to original stub.
|
||||
}
|
||||
|
||||
@@ -1849,7 +1849,7 @@ void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
|
||||
__ CallRuntime(kBreakpointStaticHandlerRuntimeEntry, 0);
|
||||
__ popq(RAX); // Code object.
|
||||
__ popq(RBX); // Restore IC data.
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
|
||||
// Load arguments descriptor into R10.
|
||||
__ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset()));
|
||||
@@ -1863,14 +1863,13 @@ void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
|
||||
|
||||
// TOS(0): return address (Dart code).
|
||||
void StubCode::GenerateBreakpointReturnStub(Assembler* assembler) {
|
||||
__ EnterStubFrameWithPP();
|
||||
__ EnterStubFrame();
|
||||
__ pushq(RAX);
|
||||
__ CallRuntime(kBreakpointReturnHandlerRuntimeEntry, 0);
|
||||
__ popq(RAX);
|
||||
__ LeaveFrameWithPP();
|
||||
|
||||
__ LeaveStubFrame();
|
||||
__ popq(R11); // discard return address of call to this stub.
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveDartFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
@@ -1882,7 +1881,7 @@ void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) {
|
||||
__ pushq(RBX);
|
||||
__ CallRuntime(kBreakpointDynamicHandlerRuntimeEntry, 0);
|
||||
__ popq(RBX);
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
|
||||
// Find out which dispatch stub to call.
|
||||
Label test_two, test_three, test_four;
|
||||
@@ -2044,7 +2043,7 @@ void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
|
||||
// RDI: function to be reoptimized.
|
||||
// R10: argument descriptor (preserved).
|
||||
void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
|
||||
__ EnterStubFrameWithPP();
|
||||
__ EnterStubFrame();
|
||||
__ LoadObject(R12, Object::null_object(), PP);
|
||||
__ pushq(R10);
|
||||
__ pushq(R12); // Setup space on stack for return value.
|
||||
@@ -2055,7 +2054,7 @@ void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
|
||||
__ popq(R10); // Restore argument descriptor.
|
||||
__ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
|
||||
__ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveStubFrame();
|
||||
__ jmp(RAX);
|
||||
__ int3();
|
||||
}
|
||||
@@ -2141,7 +2140,7 @@ void StubCode::GenerateUnoptimizedIdenticalWithNumberCheckStub(
|
||||
__ j(EQUAL, ¬_stepping, Assembler::kNearJump);
|
||||
__ EnterStubFrame();
|
||||
__ CallRuntime(kSingleStepHandlerRuntimeEntry, 0);
|
||||
__ LeaveFrame();
|
||||
__ LeaveStubFrame();
|
||||
__ Bind(¬_stepping);
|
||||
|
||||
const Register left = RAX;
|
||||
|
||||
@@ -45,7 +45,7 @@ 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());
|
||||
__ EnterStubFrameWithPP();
|
||||
__ EnterStubFrame(true);
|
||||
__ LoadObject(CTX, context, PP);
|
||||
__ PushObject(result, PP); // Push Null object for return value.
|
||||
__ PushObject(smi1, PP); // Push argument 1 smi1.
|
||||
@@ -54,7 +54,7 @@ static void GenerateCallToCallRuntimeStub(Assembler* assembler,
|
||||
__ CallRuntime(kTestSmiSubRuntimeEntry, argc); // Call SmiSub runtime func.
|
||||
__ AddImmediate(RSP, Immediate(argc * kWordSize), PP);
|
||||
__ popq(RAX); // Pop return value from return slot.
|
||||
__ LeaveFrameWithPP();
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user