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