Index: runtime/vm/assembler_arm.cc |
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc |
index d5fecd6d117dca82bb07c45a00d2d4e0fe7d532b..afb5744960a19789ed8a5b8d27763062f13fd6f7 100644 |
--- a/runtime/vm/assembler_arm.cc |
+++ b/runtime/vm/assembler_arm.cc |
@@ -1534,64 +1534,34 @@ intptr_t Assembler::FindImmediate(int32_t imm) { |
// Uses a code sequence that can easily be decoded. |
void Assembler::LoadWordFromPoolOffset(Register rd, |
int32_t offset, |
- Register pp, |
Condition cond) { |
- ASSERT((pp != PP) || constant_pool_allowed()); |
- ASSERT(rd != pp); |
+ ASSERT(constant_pool_allowed()); |
+ ASSERT(rd != PP); |
int32_t offset_mask = 0; |
if (Address::CanHoldLoadOffset(kWord, offset, &offset_mask)) { |
- ldr(rd, Address(pp, offset), cond); |
+ ldr(rd, Address(PP, offset), cond); |
} else { |
int32_t offset_hi = offset & ~offset_mask; // signed |
uint32_t offset_lo = offset & offset_mask; // unsigned |
- // Inline a simplified version of AddImmediate(rd, pp, offset_hi). |
+ // Inline a simplified version of AddImmediate(rd, PP, offset_hi). |
Operand o; |
if (Operand::CanHold(offset_hi, &o)) { |
- add(rd, pp, o, cond); |
+ add(rd, PP, o, cond); |
} else { |
LoadImmediate(rd, offset_hi, cond); |
- add(rd, pp, Operand(rd), cond); |
+ add(rd, PP, Operand(rd), cond); |
} |
ldr(rd, Address(rd, offset_lo), cond); |
} |
} |
-void Assembler::CheckCodePointer() { |
-#ifdef DEBUG |
- Label cid_ok, instructions_ok; |
- Push(R0); |
- Push(IP); |
- CompareClassId(CODE_REG, kCodeCid, R0); |
- b(&cid_ok, EQ); |
- bkpt(0); |
- Bind(&cid_ok); |
- |
- const intptr_t offset = CodeSize() + Instr::kPCReadOffset + |
- Instructions::HeaderSize() - kHeapObjectTag; |
- mov(R0, Operand(PC)); |
- AddImmediate(R0, R0, -offset); |
- ldr(IP, FieldAddress(CODE_REG, Code::saved_instructions_offset())); |
- cmp(R0, Operand(IP)); |
- b(&instructions_ok, EQ); |
- bkpt(1); |
- Bind(&instructions_ok); |
- Pop(IP); |
- Pop(R0); |
-#endif |
-} |
- |
- |
-void Assembler::RestoreCodePointer() { |
- ldr(CODE_REG, Address(FP, kPcMarkerSlotFromFp * kWordSize)); |
- CheckCodePointer(); |
-} |
- |
-void Assembler::LoadPoolPointer(Register reg) { |
- // Load new pool pointer. |
- CheckCodePointer(); |
- ldr(reg, FieldAddress(CODE_REG, Code::object_pool_offset())); |
- set_constant_pool_allowed(reg == PP); |
+void Assembler::LoadPoolPointer() { |
+ const intptr_t object_pool_pc_dist = |
+ Instructions::HeaderSize() - Instructions::object_pool_offset() + |
+ CodeSize() + Instr::kPCReadOffset; |
+ LoadFromOffset(kWord, PP, PC, -object_pool_pc_dist); |
+ set_constant_pool_allowed(true); |
} |
@@ -1603,8 +1573,7 @@ void Assembler::LoadIsolate(Register rd) { |
void Assembler::LoadObjectHelper(Register rd, |
const Object& object, |
Condition cond, |
- bool is_unique, |
- Register pp) { |
+ bool is_unique) { |
// Load common VM constants from the thread. This works also in places where |
// no constant pool is set up (e.g. intrinsic code). |
if (Thread::CanLoadFromThread(object)) { |
@@ -1625,20 +1594,20 @@ void Assembler::LoadObjectHelper(Register rd, |
const int32_t offset = ObjectPool::element_offset( |
is_unique ? object_pool_wrapper_.AddObject(object) |
: object_pool_wrapper_.FindObject(object)); |
- LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond); |
+ LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond); |
} |
} |
void Assembler::LoadObject(Register rd, const Object& object, Condition cond) { |
- LoadObjectHelper(rd, object, cond, /* is_unique = */ false, PP); |
+ LoadObjectHelper(rd, object, cond, false); |
} |
void Assembler::LoadUniqueObject(Register rd, |
const Object& object, |
Condition cond) { |
- LoadObjectHelper(rd, object, cond, /* is_unique = */ true, PP); |
+ LoadObjectHelper(rd, object, cond, true); |
} |
@@ -1648,16 +1617,7 @@ void Assembler::LoadExternalLabel(Register rd, |
Condition cond) { |
const int32_t offset = ObjectPool::element_offset( |
object_pool_wrapper_.FindExternalLabel(label, patchable)); |
- LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond); |
-} |
- |
- |
-void Assembler::LoadFunctionFromCalleePool(Register dst, |
- const Function& function, |
- Register new_pp) { |
- const int32_t offset = |
- ObjectPool::element_offset(object_pool_wrapper_.FindObject(function)); |
- LoadWordFromPoolOffset(dst, offset - kHeapObjectTag, new_pp, AL); |
+ LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond); |
} |
@@ -1667,7 +1627,7 @@ void Assembler::LoadNativeEntry(Register rd, |
Condition cond) { |
const int32_t offset = ObjectPool::element_offset( |
object_pool_wrapper_.FindNativeEntry(label, patchable)); |
- LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond); |
+ LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond); |
} |
@@ -1864,7 +1824,7 @@ void Assembler::StoreIntoObject(Register object, |
StoreIntoObjectFilterNoSmi(object, value, &done); |
} |
// A store buffer update is required. |
- RegList regs = (1 << CODE_REG) | (1 << LR); |
+ RegList regs = (1 << LR); |
if (value != R0) { |
regs |= (1 << R0); // Preserve R0. |
} |
@@ -1872,7 +1832,6 @@ void Assembler::StoreIntoObject(Register object, |
if (object != R0) { |
mov(R0, Operand(object)); |
} |
- ldr(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset())); |
ldr(LR, Address(THR, Thread::update_store_buffer_entry_point_offset())); |
blx(LR); |
PopList(regs); |
@@ -2728,52 +2687,49 @@ void Assembler::Vdivqs(QRegister qd, QRegister qn, QRegister qm) { |
} |
-void Assembler::Branch(const StubEntry& stub_entry, |
- Patchability patchable, |
- Register pp, |
- Condition cond) { |
- const Code& target_code = Code::Handle(stub_entry.code()); |
- const int32_t offset = ObjectPool::element_offset( |
- object_pool_wrapper_.FindObject(target_code, patchable)); |
- LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, pp, cond); |
- ldr(IP, FieldAddress(CODE_REG, Code::entry_point_offset()), cond); |
+void Assembler::Branch(const StubEntry& stub_entry, Condition cond) { |
+ // Address is never patched. |
+ LoadImmediate(IP, stub_entry.label().address(), cond); |
bx(IP, cond); |
} |
-void Assembler::BranchLink(const Code& target, Patchability patchable) { |
+void Assembler::BranchPatchable(const StubEntry& stub_entry) { |
+ // Use a fixed size code sequence, since a function prologue may be patched |
+ // with this branch sequence. |
+ // Contrarily to BranchLinkPatchable, BranchPatchable requires an instruction |
+ // cache flush upon patching. |
+ LoadPatchableImmediate(IP, stub_entry.label().address()); |
+ bx(IP); |
+} |
+ |
+ |
+void Assembler::BranchLink(const ExternalLabel* label) { |
+ LoadImmediate(LR, label->address()); // Target address is never patched. |
+ blx(LR); // Use blx instruction so that the return branch prediction works. |
+} |
+ |
+ |
+void Assembler::BranchLink(const ExternalLabel* label, Patchability patchable) { |
// Make sure that class CallPattern is able to patch the label referred |
// to by this code sequence. |
// For added code robustness, use 'blx lr' in a patchable sequence and |
// use 'blx ip' in a non-patchable sequence (see other BranchLink flavors). |
const int32_t offset = ObjectPool::element_offset( |
- object_pool_wrapper_.FindObject(target, patchable)); |
- LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, PP, AL); |
- ldr(LR, FieldAddress(CODE_REG, Code::entry_point_offset())); |
+ object_pool_wrapper_.FindExternalLabel(label, patchable)); |
+ LoadWordFromPoolOffset(LR, offset - kHeapObjectTag, AL); |
blx(LR); // Use blx instruction so that the return branch prediction works. |
} |
void Assembler::BranchLink(const StubEntry& stub_entry, |
Patchability patchable) { |
- const Code& code = Code::Handle(stub_entry.code()); |
- BranchLink(code, patchable); |
-} |
- |
- |
-void Assembler::BranchLinkPatchable(const Code& target) { |
- BranchLink(target, kPatchable); |
-} |
- |
- |
-void Assembler::BranchLink(const ExternalLabel* label) { |
- LoadImmediate(LR, label->address()); // Target address is never patched. |
- blx(LR); // Use blx instruction so that the return branch prediction works. |
+ BranchLink(&stub_entry.label(), patchable); |
} |
void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) { |
- BranchLinkPatchable(Code::Handle(stub_entry.code())); |
+ BranchLink(&stub_entry.label(), kPatchable); |
} |
@@ -2814,7 +2770,7 @@ void Assembler::LoadDecodableImmediate( |
if ((version == ARMv5TE) || (version == ARMv6)) { |
if (constant_pool_allowed()) { |
const int32_t offset = Array::element_offset(FindImmediate(value)); |
- LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond); |
+ LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond); |
} else { |
LoadPatchableImmediate(rd, value, cond); |
} |
@@ -3349,11 +3305,20 @@ void Assembler::CallRuntime(const RuntimeEntry& entry, |
void Assembler::EnterDartFrame(intptr_t frame_size) { |
- CheckCodePointer(); |
ASSERT(!constant_pool_allowed()); |
+ const intptr_t offset = CodeSize(); |
- // Registers are pushed in descending order: R9 | R10 | R11 | R14. |
- EnterFrame((1 << PP) | (1 << CODE_REG) | (1 << FP) | (1 << LR), 0); |
+ // Save PC in frame for fast identification of corresponding code. |
+ // Note that callee-saved registers can be added to the register list. |
+ EnterFrame((1 << PP) | (1 << FP) | (1 << LR) | (1 << PC), 0); |
+ |
+ if (offset != 0) { |
+ // Adjust saved PC for any intrinsic code that could have been generated |
+ // before a frame is created. Use PP as temp register. |
+ ldr(PP, Address(FP, 2 * kWordSize)); |
+ AddImmediate(PP, PP, -offset); |
+ str(PP, Address(FP, 2 * kWordSize)); |
+ } |
// Setup pool pointer for this dart function. |
LoadPoolPointer(); |
@@ -3370,26 +3335,41 @@ void Assembler::EnterDartFrame(intptr_t frame_size) { |
// allocate. We must also set up the pool pointer for the function. |
void Assembler::EnterOsrFrame(intptr_t extra_size) { |
ASSERT(!constant_pool_allowed()); |
+ // mov(IP, Operand(PC)) loads PC + Instr::kPCReadOffset (8). This may be |
+ // different from EntryPointToPcMarkerOffset(). |
+ const intptr_t offset = |
+ CodeSize() + Instr::kPCReadOffset - EntryPointToPcMarkerOffset(); |
+ |
Comment("EnterOsrFrame"); |
- RestoreCodePointer(); |
+ mov(IP, Operand(PC)); |
+ |
+ AddImmediate(IP, -offset); |
+ str(IP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); |
+ |
+ // Setup pool pointer for this dart function. |
LoadPoolPointer(); |
AddImmediate(SP, -extra_size); |
} |
-void Assembler::LeaveDartFrame(RestorePP restore_pp) { |
- if (restore_pp == kRestoreCallerPP) { |
- ldr(PP, Address(FP, kSavedCallerPpSlotFromFp * kWordSize)); |
- set_constant_pool_allowed(false); |
- } |
- Drop(2); // Drop saved PP, PC marker. |
- LeaveFrame((1 << FP) | (1 << LR)); |
+void Assembler::LeaveDartFrame() { |
+ set_constant_pool_allowed(false); |
+ LeaveFrame((1 << PP) | (1 << FP) | (1 << LR)); |
+ // Adjust SP for PC pushed in EnterDartFrame. |
+ AddImmediate(SP, kWordSize); |
} |
void Assembler::EnterStubFrame() { |
- EnterDartFrame(0); |
+ set_constant_pool_allowed(false); |
+ // Push 0 as saved PC for stub frames. |
+ mov(IP, Operand(LR)); |
+ mov(LR, Operand(0)); |
+ RegList regs = (1 << PP) | (1 << FP) | (1 << IP) | (1 << LR); |
+ EnterFrame(regs, 0); |
+ // Setup pool pointer for this stub. |
+ LoadPoolPointer(); |
} |