Home | History | Annotate | Download | only in arm
      1 // Copyright (c) 1994-2006 Sun Microsystems Inc.
      2 // All Rights Reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions
      6 // are met:
      7 //
      8 // - Redistributions of source code must retain the above copyright notice,
      9 // this list of conditions and the following disclaimer.
     10 //
     11 // - Redistribution in binary form must reproduce the above copyright
     12 // notice, this list of conditions and the following disclaimer in the
     13 // documentation and/or other materials provided with the
     14 // distribution.
     15 //
     16 // - Neither the name of Sun Microsystems or the names of contributors may
     17 // be used to endorse or promote products derived from this software without
     18 // specific prior written permission.
     19 //
     20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     23 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     24 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     25 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     26 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     29 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     31 // OF THE POSSIBILITY OF SUCH DAMAGE.
     32 
     33 // The original source code covered by the above license above has been modified
     34 // significantly by Google Inc.
     35 // Copyright 2012 the V8 project authors. All rights reserved.
     36 
     37 #ifndef V8_ARM_ASSEMBLER_ARM_INL_H_
     38 #define V8_ARM_ASSEMBLER_ARM_INL_H_
     39 
     40 #include "src/arm/assembler-arm.h"
     41 
     42 #include "src/assembler.h"
     43 #include "src/debug.h"
     44 
     45 
     46 namespace v8 {
     47 namespace internal {
     48 
     49 
     50 bool CpuFeatures::SupportsCrankshaft() { return IsSupported(VFP3); }
     51 
     52 
     53 int Register::NumAllocatableRegisters() {
     54   return kMaxNumAllocatableRegisters;
     55 }
     56 
     57 
     58 int DwVfpRegister::NumRegisters() {
     59   return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
     60 }
     61 
     62 
     63 int DwVfpRegister::NumReservedRegisters() {
     64   return kNumReservedRegisters;
     65 }
     66 
     67 
     68 int DwVfpRegister::NumAllocatableRegisters() {
     69   return NumRegisters() - kNumReservedRegisters;
     70 }
     71 
     72 
     73 int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) {
     74   DCHECK(!reg.is(kDoubleRegZero));
     75   DCHECK(!reg.is(kScratchDoubleReg));
     76   if (reg.code() > kDoubleRegZero.code()) {
     77     return reg.code() - kNumReservedRegisters;
     78   }
     79   return reg.code();
     80 }
     81 
     82 
     83 DwVfpRegister DwVfpRegister::FromAllocationIndex(int index) {
     84   DCHECK(index >= 0 && index < NumAllocatableRegisters());
     85   DCHECK(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
     86          kNumReservedRegisters - 1);
     87   if (index >= kDoubleRegZero.code()) {
     88     return from_code(index + kNumReservedRegisters);
     89   }
     90   return from_code(index);
     91 }
     92 
     93 
     94 void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
     95   if (RelocInfo::IsInternalReference(rmode_)) {
     96     // absolute code pointer inside code object moves with the code object.
     97     int32_t* p = reinterpret_cast<int32_t*>(pc_);
     98     *p += delta;  // relocate entry
     99   }
    100   // We do not use pc relative addressing on ARM, so there is
    101   // nothing else to do.
    102 }
    103 
    104 
    105 Address RelocInfo::target_address() {
    106   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
    107   return Assembler::target_address_at(pc_, host_);
    108 }
    109 
    110 
    111 Address RelocInfo::target_address_address() {
    112   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
    113                               || rmode_ == EMBEDDED_OBJECT
    114                               || rmode_ == EXTERNAL_REFERENCE);
    115   if (FLAG_enable_ool_constant_pool ||
    116       Assembler::IsMovW(Memory::int32_at(pc_))) {
    117     // We return the PC for ool constant pool since this function is used by the
    118     // serializerer and expects the address to reside within the code object.
    119     return reinterpret_cast<Address>(pc_);
    120   } else {
    121     DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
    122     return constant_pool_entry_address();
    123   }
    124 }
    125 
    126 
    127 Address RelocInfo::constant_pool_entry_address() {
    128   DCHECK(IsInConstantPool());
    129   return Assembler::constant_pool_entry_address(pc_, host_->constant_pool());
    130 }
    131 
    132 
    133 int RelocInfo::target_address_size() {
    134   return kPointerSize;
    135 }
    136 
    137 
    138 void RelocInfo::set_target_address(Address target,
    139                                    WriteBarrierMode write_barrier_mode,
    140                                    ICacheFlushMode icache_flush_mode) {
    141   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
    142   Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
    143   if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
    144       host() != NULL && IsCodeTarget(rmode_)) {
    145     Object* target_code = Code::GetCodeFromTargetAddress(target);
    146     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
    147         host(), this, HeapObject::cast(target_code));
    148   }
    149 }
    150 
    151 
    152 Object* RelocInfo::target_object() {
    153   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    154   return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
    155 }
    156 
    157 
    158 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
    159   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    160   return Handle<Object>(reinterpret_cast<Object**>(
    161       Assembler::target_address_at(pc_, host_)));
    162 }
    163 
    164 
    165 void RelocInfo::set_target_object(Object* target,
    166                                   WriteBarrierMode write_barrier_mode,
    167                                   ICacheFlushMode icache_flush_mode) {
    168   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    169   Assembler::set_target_address_at(pc_, host_,
    170                                    reinterpret_cast<Address>(target),
    171                                    icache_flush_mode);
    172   if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
    173       host() != NULL &&
    174       target->IsHeapObject()) {
    175     host()->GetHeap()->incremental_marking()->RecordWrite(
    176         host(), &Memory::Object_at(pc_), HeapObject::cast(target));
    177   }
    178 }
    179 
    180 
    181 Address RelocInfo::target_reference() {
    182   DCHECK(rmode_ == EXTERNAL_REFERENCE);
    183   return Assembler::target_address_at(pc_, host_);
    184 }
    185 
    186 
    187 Address RelocInfo::target_runtime_entry(Assembler* origin) {
    188   DCHECK(IsRuntimeEntry(rmode_));
    189   return target_address();
    190 }
    191 
    192 
    193 void RelocInfo::set_target_runtime_entry(Address target,
    194                                          WriteBarrierMode write_barrier_mode,
    195                                          ICacheFlushMode icache_flush_mode) {
    196   DCHECK(IsRuntimeEntry(rmode_));
    197   if (target_address() != target)
    198     set_target_address(target, write_barrier_mode, icache_flush_mode);
    199 }
    200 
    201 
    202 Handle<Cell> RelocInfo::target_cell_handle() {
    203   DCHECK(rmode_ == RelocInfo::CELL);
    204   Address address = Memory::Address_at(pc_);
    205   return Handle<Cell>(reinterpret_cast<Cell**>(address));
    206 }
    207 
    208 
    209 Cell* RelocInfo::target_cell() {
    210   DCHECK(rmode_ == RelocInfo::CELL);
    211   return Cell::FromValueAddress(Memory::Address_at(pc_));
    212 }
    213 
    214 
    215 void RelocInfo::set_target_cell(Cell* cell,
    216                                 WriteBarrierMode write_barrier_mode,
    217                                 ICacheFlushMode icache_flush_mode) {
    218   DCHECK(rmode_ == RelocInfo::CELL);
    219   Address address = cell->address() + Cell::kValueOffset;
    220   Memory::Address_at(pc_) = address;
    221   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
    222     // TODO(1550) We are passing NULL as a slot because cell can never be on
    223     // evacuation candidate.
    224     host()->GetHeap()->incremental_marking()->RecordWrite(
    225         host(), NULL, cell);
    226   }
    227 }
    228 
    229 
    230 static const int kNoCodeAgeSequenceLength = 3 * Assembler::kInstrSize;
    231 
    232 
    233 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
    234   UNREACHABLE();  // This should never be reached on Arm.
    235   return Handle<Object>();
    236 }
    237 
    238 
    239 Code* RelocInfo::code_age_stub() {
    240   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
    241   return Code::GetCodeFromTargetAddress(
    242       Memory::Address_at(pc_ +
    243                          (kNoCodeAgeSequenceLength - Assembler::kInstrSize)));
    244 }
    245 
    246 
    247 void RelocInfo::set_code_age_stub(Code* stub,
    248                                   ICacheFlushMode icache_flush_mode) {
    249   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
    250   Memory::Address_at(pc_ +
    251                      (kNoCodeAgeSequenceLength - Assembler::kInstrSize)) =
    252       stub->instruction_start();
    253 }
    254 
    255 
    256 Address RelocInfo::call_address() {
    257   // The 2 instructions offset assumes patched debug break slot or return
    258   // sequence.
    259   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
    260          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
    261   return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize);
    262 }
    263 
    264 
    265 void RelocInfo::set_call_address(Address target) {
    266   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
    267          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
    268   Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target;
    269   if (host() != NULL) {
    270     Object* target_code = Code::GetCodeFromTargetAddress(target);
    271     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
    272         host(), this, HeapObject::cast(target_code));
    273   }
    274 }
    275 
    276 
    277 Object* RelocInfo::call_object() {
    278   return *call_object_address();
    279 }
    280 
    281 
    282 void RelocInfo::set_call_object(Object* target) {
    283   *call_object_address() = target;
    284 }
    285 
    286 
    287 Object** RelocInfo::call_object_address() {
    288   DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
    289          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
    290   return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
    291 }
    292 
    293 
    294 void RelocInfo::WipeOut() {
    295   DCHECK(IsEmbeddedObject(rmode_) ||
    296          IsCodeTarget(rmode_) ||
    297          IsRuntimeEntry(rmode_) ||
    298          IsExternalReference(rmode_));
    299   Assembler::set_target_address_at(pc_, host_, NULL);
    300 }
    301 
    302 
    303 bool RelocInfo::IsPatchedReturnSequence() {
    304   Instr current_instr = Assembler::instr_at(pc_);
    305   Instr next_instr = Assembler::instr_at(pc_ + Assembler::kInstrSize);
    306   // A patched return sequence is:
    307   //  ldr ip, [pc, #0]
    308   //  blx ip
    309   return Assembler::IsLdrPcImmediateOffset(current_instr) &&
    310          Assembler::IsBlxReg(next_instr);
    311 }
    312 
    313 
    314 bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
    315   Instr current_instr = Assembler::instr_at(pc_);
    316   return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
    317 }
    318 
    319 
    320 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
    321   RelocInfo::Mode mode = rmode();
    322   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    323     visitor->VisitEmbeddedPointer(this);
    324   } else if (RelocInfo::IsCodeTarget(mode)) {
    325     visitor->VisitCodeTarget(this);
    326   } else if (mode == RelocInfo::CELL) {
    327     visitor->VisitCell(this);
    328   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    329     visitor->VisitExternalReference(this);
    330   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    331     visitor->VisitCodeAgeSequence(this);
    332   } else if (((RelocInfo::IsJSReturn(mode) &&
    333               IsPatchedReturnSequence()) ||
    334              (RelocInfo::IsDebugBreakSlot(mode) &&
    335               IsPatchedDebugBreakSlotSequence())) &&
    336              isolate->debug()->has_break_points()) {
    337     visitor->VisitDebugTarget(this);
    338   } else if (RelocInfo::IsRuntimeEntry(mode)) {
    339     visitor->VisitRuntimeEntry(this);
    340   }
    341 }
    342 
    343 
    344 template<typename StaticVisitor>
    345 void RelocInfo::Visit(Heap* heap) {
    346   RelocInfo::Mode mode = rmode();
    347   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    348     StaticVisitor::VisitEmbeddedPointer(heap, this);
    349   } else if (RelocInfo::IsCodeTarget(mode)) {
    350     StaticVisitor::VisitCodeTarget(heap, this);
    351   } else if (mode == RelocInfo::CELL) {
    352     StaticVisitor::VisitCell(heap, this);
    353   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    354     StaticVisitor::VisitExternalReference(this);
    355   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    356     StaticVisitor::VisitCodeAgeSequence(heap, this);
    357   } else if (heap->isolate()->debug()->has_break_points() &&
    358              ((RelocInfo::IsJSReturn(mode) &&
    359               IsPatchedReturnSequence()) ||
    360              (RelocInfo::IsDebugBreakSlot(mode) &&
    361               IsPatchedDebugBreakSlotSequence()))) {
    362     StaticVisitor::VisitDebugTarget(heap, this);
    363   } else if (RelocInfo::IsRuntimeEntry(mode)) {
    364     StaticVisitor::VisitRuntimeEntry(this);
    365   }
    366 }
    367 
    368 
    369 Operand::Operand(int32_t immediate, RelocInfo::Mode rmode)  {
    370   rm_ = no_reg;
    371   imm32_ = immediate;
    372   rmode_ = rmode;
    373 }
    374 
    375 
    376 Operand::Operand(const ExternalReference& f)  {
    377   rm_ = no_reg;
    378   imm32_ = reinterpret_cast<int32_t>(f.address());
    379   rmode_ = RelocInfo::EXTERNAL_REFERENCE;
    380 }
    381 
    382 
    383 Operand::Operand(Smi* value) {
    384   rm_ = no_reg;
    385   imm32_ =  reinterpret_cast<intptr_t>(value);
    386   rmode_ = RelocInfo::NONE32;
    387 }
    388 
    389 
    390 Operand::Operand(Register rm) {
    391   rm_ = rm;
    392   rs_ = no_reg;
    393   shift_op_ = LSL;
    394   shift_imm_ = 0;
    395 }
    396 
    397 
    398 bool Operand::is_reg() const {
    399   return rm_.is_valid() &&
    400          rs_.is(no_reg) &&
    401          shift_op_ == LSL &&
    402          shift_imm_ == 0;
    403 }
    404 
    405 
    406 void Assembler::CheckBuffer() {
    407   if (buffer_space() <= kGap) {
    408     GrowBuffer();
    409   }
    410   if (pc_offset() >= next_buffer_check_) {
    411     CheckConstPool(false, true);
    412   }
    413 }
    414 
    415 
    416 void Assembler::emit(Instr x) {
    417   CheckBuffer();
    418   *reinterpret_cast<Instr*>(pc_) = x;
    419   pc_ += kInstrSize;
    420 }
    421 
    422 
    423 Address Assembler::target_address_from_return_address(Address pc) {
    424   // Returns the address of the call target from the return address that will
    425   // be returned to after a call.
    426   // Call sequence on V7 or later is:
    427   //  movw  ip, #... @ call address low 16
    428   //  movt  ip, #... @ call address high 16
    429   //  blx   ip
    430   //                      @ return address
    431   // For V6 when the constant pool is unavailable, it is:
    432   //  mov  ip, #...     @ call address low 8
    433   //  orr  ip, ip, #... @ call address 2nd 8
    434   //  orr  ip, ip, #... @ call address 3rd 8
    435   //  orr  ip, ip, #... @ call address high 8
    436   //  blx   ip
    437   //                      @ return address
    438   // In cases that need frequent patching, the address is in the
    439   // constant pool.  It could be a small constant pool load:
    440   //  ldr   ip, [pc / pp, #...] @ call address
    441   //  blx   ip
    442   //                      @ return address
    443   // Or an extended constant pool load (ARMv7):
    444   //  movw  ip, #...
    445   //  movt  ip, #...
    446   //  ldr   ip, [pc, ip]  @ call address
    447   //  blx   ip
    448   //                      @ return address
    449   // Or an extended constant pool load (ARMv6):
    450   //  mov  ip, #...
    451   //  orr  ip, ip, #...
    452   //  orr  ip, ip, #...
    453   //  orr  ip, ip, #...
    454   //  ldr   ip, [pc, ip]  @ call address
    455   //  blx   ip
    456   //                      @ return address
    457   Address candidate = pc - 2 * Assembler::kInstrSize;
    458   Instr candidate_instr(Memory::int32_at(candidate));
    459   if (IsLdrPcImmediateOffset(candidate_instr) |
    460       IsLdrPpImmediateOffset(candidate_instr)) {
    461     return candidate;
    462   } else {
    463     if (IsLdrPpRegOffset(candidate_instr)) {
    464       candidate -= Assembler::kInstrSize;
    465     }
    466     if (CpuFeatures::IsSupported(ARMv7)) {
    467       candidate -= 1 * Assembler::kInstrSize;
    468       DCHECK(IsMovW(Memory::int32_at(candidate)) &&
    469              IsMovT(Memory::int32_at(candidate + Assembler::kInstrSize)));
    470     } else {
    471       candidate -= 3 * Assembler::kInstrSize;
    472       DCHECK(
    473           IsMovImmed(Memory::int32_at(candidate)) &&
    474           IsOrrImmed(Memory::int32_at(candidate + Assembler::kInstrSize)) &&
    475           IsOrrImmed(Memory::int32_at(candidate + 2 * Assembler::kInstrSize)) &&
    476           IsOrrImmed(Memory::int32_at(candidate + 3 * Assembler::kInstrSize)));
    477     }
    478     return candidate;
    479   }
    480 }
    481 
    482 
    483 Address Assembler::break_address_from_return_address(Address pc) {
    484   return pc - Assembler::kPatchDebugBreakSlotReturnOffset;
    485 }
    486 
    487 
    488 Address Assembler::return_address_from_call_start(Address pc) {
    489   if (IsLdrPcImmediateOffset(Memory::int32_at(pc)) |
    490       IsLdrPpImmediateOffset(Memory::int32_at(pc))) {
    491     // Load from constant pool, small section.
    492     return pc + kInstrSize * 2;
    493   } else {
    494     if (CpuFeatures::IsSupported(ARMv7)) {
    495       DCHECK(IsMovW(Memory::int32_at(pc)));
    496       DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
    497       if (IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize))) {
    498         // Load from constant pool, extended section.
    499         return pc + kInstrSize * 4;
    500       } else {
    501         // A movw / movt load immediate.
    502         return pc + kInstrSize * 3;
    503       }
    504     } else {
    505       DCHECK(IsMovImmed(Memory::int32_at(pc)));
    506       DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize)));
    507       DCHECK(IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)));
    508       DCHECK(IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
    509       if (IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize))) {
    510         // Load from constant pool, extended section.
    511         return pc + kInstrSize * 6;
    512       } else {
    513         // A mov / orr load immediate.
    514         return pc + kInstrSize * 5;
    515       }
    516     }
    517   }
    518 }
    519 
    520 
    521 void Assembler::deserialization_set_special_target_at(
    522     Address constant_pool_entry, Code* code, Address target) {
    523   if (FLAG_enable_ool_constant_pool) {
    524     set_target_address_at(constant_pool_entry, code, target);
    525   } else {
    526     Memory::Address_at(constant_pool_entry) = target;
    527   }
    528 }
    529 
    530 
    531 bool Assembler::is_constant_pool_load(Address pc) {
    532   if (CpuFeatures::IsSupported(ARMv7)) {
    533     return !Assembler::IsMovW(Memory::int32_at(pc)) ||
    534            (FLAG_enable_ool_constant_pool &&
    535             Assembler::IsLdrPpRegOffset(
    536                 Memory::int32_at(pc + 2 * Assembler::kInstrSize)));
    537   } else {
    538     return !Assembler::IsMovImmed(Memory::int32_at(pc)) ||
    539            (FLAG_enable_ool_constant_pool &&
    540             Assembler::IsLdrPpRegOffset(
    541                 Memory::int32_at(pc + 4 * Assembler::kInstrSize)));
    542   }
    543 }
    544 
    545 
    546 Address Assembler::constant_pool_entry_address(
    547     Address pc, ConstantPoolArray* constant_pool) {
    548   if (FLAG_enable_ool_constant_pool) {
    549     DCHECK(constant_pool != NULL);
    550     int cp_offset;
    551     if (!CpuFeatures::IsSupported(ARMv7) && IsMovImmed(Memory::int32_at(pc))) {
    552       DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
    553              IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
    554              IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)) &&
    555              IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize)));
    556       // This is an extended constant pool lookup (ARMv6).
    557       Instr mov_instr = instr_at(pc);
    558       Instr orr_instr_1 = instr_at(pc + kInstrSize);
    559       Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize);
    560       Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize);
    561       cp_offset = DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) |
    562                   DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3);
    563     } else if (IsMovW(Memory::int32_at(pc))) {
    564       DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)) &&
    565              IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize)));
    566       // This is an extended constant pool lookup (ARMv7).
    567       Instruction* movw_instr = Instruction::At(pc);
    568       Instruction* movt_instr = Instruction::At(pc + kInstrSize);
    569       cp_offset = (movt_instr->ImmedMovwMovtValue() << 16) |
    570                   movw_instr->ImmedMovwMovtValue();
    571     } else {
    572       // This is a small constant pool lookup.
    573       DCHECK(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc)));
    574       cp_offset = GetLdrRegisterImmediateOffset(Memory::int32_at(pc));
    575     }
    576     return reinterpret_cast<Address>(constant_pool) + cp_offset;
    577   } else {
    578     DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc)));
    579     Instr instr = Memory::int32_at(pc);
    580     return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta;
    581   }
    582 }
    583 
    584 
    585 Address Assembler::target_address_at(Address pc,
    586                                      ConstantPoolArray* constant_pool) {
    587   if (is_constant_pool_load(pc)) {
    588     // This is a constant pool lookup. Return the value in the constant pool.
    589     return Memory::Address_at(constant_pool_entry_address(pc, constant_pool));
    590   } else if (CpuFeatures::IsSupported(ARMv7)) {
    591     // This is an movw / movt immediate load. Return the immediate.
    592     DCHECK(IsMovW(Memory::int32_at(pc)) &&
    593            IsMovT(Memory::int32_at(pc + kInstrSize)));
    594     Instruction* movw_instr = Instruction::At(pc);
    595     Instruction* movt_instr = Instruction::At(pc + kInstrSize);
    596     return reinterpret_cast<Address>(
    597         (movt_instr->ImmedMovwMovtValue() << 16) |
    598          movw_instr->ImmedMovwMovtValue());
    599   } else {
    600     // This is an mov / orr immediate load. Return the immediate.
    601     DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
    602            IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
    603            IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
    604            IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
    605     Instr mov_instr = instr_at(pc);
    606     Instr orr_instr_1 = instr_at(pc + kInstrSize);
    607     Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize);
    608     Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize);
    609     Address ret = reinterpret_cast<Address>(
    610         DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) |
    611         DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3));
    612     return ret;
    613   }
    614 }
    615 
    616 
    617 void Assembler::set_target_address_at(Address pc,
    618                                       ConstantPoolArray* constant_pool,
    619                                       Address target,
    620                                       ICacheFlushMode icache_flush_mode) {
    621   if (is_constant_pool_load(pc)) {
    622     // This is a constant pool lookup. Update the entry in the constant pool.
    623     Memory::Address_at(constant_pool_entry_address(pc, constant_pool)) = target;
    624     // Intuitively, we would think it is necessary to always flush the
    625     // instruction cache after patching a target address in the code as follows:
    626     //   CpuFeatures::FlushICache(pc, sizeof(target));
    627     // However, on ARM, no instruction is actually patched in the case
    628     // of embedded constants of the form:
    629     // ldr   ip, [pp, #...]
    630     // since the instruction accessing this address in the constant pool remains
    631     // unchanged.
    632   } else if (CpuFeatures::IsSupported(ARMv7)) {
    633     // This is an movw / movt immediate load. Patch the immediate embedded in
    634     // the instructions.
    635     DCHECK(IsMovW(Memory::int32_at(pc)));
    636     DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
    637     uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
    638     uint32_t immediate = reinterpret_cast<uint32_t>(target);
    639     instr_ptr[0] = PatchMovwImmediate(instr_ptr[0], immediate & 0xFFFF);
    640     instr_ptr[1] = PatchMovwImmediate(instr_ptr[1], immediate >> 16);
    641     DCHECK(IsMovW(Memory::int32_at(pc)));
    642     DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
    643     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
    644       CpuFeatures::FlushICache(pc, 2 * kInstrSize);
    645     }
    646   } else {
    647     // This is an mov / orr immediate load. Patch the immediate embedded in
    648     // the instructions.
    649     DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
    650            IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
    651            IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
    652            IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
    653     uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
    654     uint32_t immediate = reinterpret_cast<uint32_t>(target);
    655     instr_ptr[0] = PatchShiftImm(instr_ptr[0], immediate & kImm8Mask);
    656     instr_ptr[1] = PatchShiftImm(instr_ptr[1], immediate & (kImm8Mask << 8));
    657     instr_ptr[2] = PatchShiftImm(instr_ptr[2], immediate & (kImm8Mask << 16));
    658     instr_ptr[3] = PatchShiftImm(instr_ptr[3], immediate & (kImm8Mask << 24));
    659     DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
    660            IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
    661            IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
    662            IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
    663     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
    664       CpuFeatures::FlushICache(pc, 4 * kInstrSize);
    665     }
    666   }
    667 }
    668 
    669 
    670 } }  // namespace v8::internal
    671 
    672 #endif  // V8_ARM_ASSEMBLER_ARM_INL_H_
    673