| 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();
|
| }
|
|
|
|
|
|
|