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/debug.h"
     44 #include "src/objects-inl.h"
     45 
     46 namespace v8 {
     47 namespace internal {
     48 
     49 bool CpuFeatures::SupportsCrankshaft() { return true; }
     50 
     51 bool CpuFeatures::SupportsSimd128() { return true; }
     52 
     53 int DoubleRegister::NumRegisters() {
     54   return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
     55 }
     56 
     57 
     58 void RelocInfo::apply(intptr_t delta) {
     59   if (RelocInfo::IsInternalReference(rmode_)) {
     60     // absolute code pointer inside code object moves with the code object.
     61     int32_t* p = reinterpret_cast<int32_t*>(pc_);
     62     *p += delta;  // relocate entry
     63   }
     64   // We do not use pc relative addressing on ARM, so there is
     65   // nothing else to do.
     66 }
     67 
     68 
     69 Address RelocInfo::target_address() {
     70   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
     71   return Assembler::target_address_at(pc_, host_);
     72 }
     73 
     74 Address RelocInfo::target_address_address() {
     75   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
     76                               || rmode_ == EMBEDDED_OBJECT
     77                               || rmode_ == EXTERNAL_REFERENCE);
     78   if (FLAG_enable_embedded_constant_pool ||
     79       Assembler::IsMovW(Memory::int32_at(pc_))) {
     80     // We return the PC for embedded constant pool since this function is used
     81     // by the serializer and expects the address to reside within the code
     82     // object.
     83     return reinterpret_cast<Address>(pc_);
     84   } else {
     85     DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
     86     return constant_pool_entry_address();
     87   }
     88 }
     89 
     90 
     91 Address RelocInfo::constant_pool_entry_address() {
     92   DCHECK(IsInConstantPool());
     93   return Assembler::constant_pool_entry_address(pc_, host_->constant_pool());
     94 }
     95 
     96 
     97 int RelocInfo::target_address_size() {
     98   return kPointerSize;
     99 }
    100 
    101 
    102 Object* RelocInfo::target_object() {
    103   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    104   return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
    105 }
    106 
    107 
    108 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
    109   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    110   return Handle<Object>(reinterpret_cast<Object**>(
    111       Assembler::target_address_at(pc_, host_)));
    112 }
    113 
    114 
    115 void RelocInfo::set_target_object(Object* target,
    116                                   WriteBarrierMode write_barrier_mode,
    117                                   ICacheFlushMode icache_flush_mode) {
    118   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    119   Assembler::set_target_address_at(isolate_, pc_, host_,
    120                                    reinterpret_cast<Address>(target),
    121                                    icache_flush_mode);
    122   if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
    123       host() != NULL &&
    124       target->IsHeapObject()) {
    125     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
    126         host(), this, HeapObject::cast(target));
    127     host()->GetHeap()->RecordWriteIntoCode(host(), this, target);
    128   }
    129 }
    130 
    131 
    132 Address RelocInfo::target_external_reference() {
    133   DCHECK(rmode_ == EXTERNAL_REFERENCE);
    134   return Assembler::target_address_at(pc_, host_);
    135 }
    136 
    137 
    138 Address RelocInfo::target_internal_reference() {
    139   DCHECK(rmode_ == INTERNAL_REFERENCE);
    140   return Memory::Address_at(pc_);
    141 }
    142 
    143 
    144 Address RelocInfo::target_internal_reference_address() {
    145   DCHECK(rmode_ == INTERNAL_REFERENCE);
    146   return reinterpret_cast<Address>(pc_);
    147 }
    148 
    149 
    150 Address RelocInfo::target_runtime_entry(Assembler* origin) {
    151   DCHECK(IsRuntimeEntry(rmode_));
    152   return target_address();
    153 }
    154 
    155 
    156 void RelocInfo::set_target_runtime_entry(Address target,
    157                                          WriteBarrierMode write_barrier_mode,
    158                                          ICacheFlushMode icache_flush_mode) {
    159   DCHECK(IsRuntimeEntry(rmode_));
    160   if (target_address() != target)
    161     set_target_address(target, write_barrier_mode, icache_flush_mode);
    162 }
    163 
    164 
    165 Handle<Cell> RelocInfo::target_cell_handle() {
    166   DCHECK(rmode_ == RelocInfo::CELL);
    167   Address address = Memory::Address_at(pc_);
    168   return Handle<Cell>(reinterpret_cast<Cell**>(address));
    169 }
    170 
    171 
    172 Cell* RelocInfo::target_cell() {
    173   DCHECK(rmode_ == RelocInfo::CELL);
    174   return Cell::FromValueAddress(Memory::Address_at(pc_));
    175 }
    176 
    177 
    178 void RelocInfo::set_target_cell(Cell* cell,
    179                                 WriteBarrierMode write_barrier_mode,
    180                                 ICacheFlushMode icache_flush_mode) {
    181   DCHECK(rmode_ == RelocInfo::CELL);
    182   Address address = cell->address() + Cell::kValueOffset;
    183   Memory::Address_at(pc_) = address;
    184   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
    185     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this,
    186                                                                   cell);
    187   }
    188 }
    189 
    190 
    191 static const int kNoCodeAgeSequenceLength = 3 * Assembler::kInstrSize;
    192 
    193 
    194 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
    195   UNREACHABLE();  // This should never be reached on Arm.
    196   return Handle<Object>();
    197 }
    198 
    199 
    200 Code* RelocInfo::code_age_stub() {
    201   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
    202   return Code::GetCodeFromTargetAddress(
    203       Memory::Address_at(pc_ +
    204                          (kNoCodeAgeSequenceLength - Assembler::kInstrSize)));
    205 }
    206 
    207 
    208 void RelocInfo::set_code_age_stub(Code* stub,
    209                                   ICacheFlushMode icache_flush_mode) {
    210   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
    211   Memory::Address_at(pc_ +
    212                      (kNoCodeAgeSequenceLength - Assembler::kInstrSize)) =
    213       stub->instruction_start();
    214 }
    215 
    216 
    217 Address RelocInfo::debug_call_address() {
    218   // The 2 instructions offset assumes patched debug break slot or return
    219   // sequence.
    220   DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
    221   return Memory::Address_at(pc_ + Assembler::kPatchDebugBreakSlotAddressOffset);
    222 }
    223 
    224 
    225 void RelocInfo::set_debug_call_address(Address target) {
    226   DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
    227   Memory::Address_at(pc_ + Assembler::kPatchDebugBreakSlotAddressOffset) =
    228       target;
    229   if (host() != NULL) {
    230     Object* target_code = Code::GetCodeFromTargetAddress(target);
    231     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
    232         host(), this, HeapObject::cast(target_code));
    233   }
    234 }
    235 
    236 
    237 void RelocInfo::WipeOut() {
    238   DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
    239          IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
    240          IsInternalReference(rmode_));
    241   if (IsInternalReference(rmode_)) {
    242     Memory::Address_at(pc_) = NULL;
    243   } else {
    244     Assembler::set_target_address_at(isolate_, pc_, host_, NULL);
    245   }
    246 }
    247 
    248 template <typename ObjectVisitor>
    249 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
    250   RelocInfo::Mode mode = rmode();
    251   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    252     visitor->VisitEmbeddedPointer(this);
    253   } else if (RelocInfo::IsCodeTarget(mode)) {
    254     visitor->VisitCodeTarget(this);
    255   } else if (mode == RelocInfo::CELL) {
    256     visitor->VisitCell(this);
    257   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    258     visitor->VisitExternalReference(this);
    259   } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
    260     visitor->VisitInternalReference(this);
    261   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    262     visitor->VisitCodeAgeSequence(this);
    263   } else if (RelocInfo::IsDebugBreakSlot(mode) &&
    264              IsPatchedDebugBreakSlotSequence()) {
    265     visitor->VisitDebugTarget(this);
    266   } else if (RelocInfo::IsRuntimeEntry(mode)) {
    267     visitor->VisitRuntimeEntry(this);
    268   }
    269 }
    270 
    271 
    272 template<typename StaticVisitor>
    273 void RelocInfo::Visit(Heap* heap) {
    274   RelocInfo::Mode mode = rmode();
    275   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    276     StaticVisitor::VisitEmbeddedPointer(heap, this);
    277   } else if (RelocInfo::IsCodeTarget(mode)) {
    278     StaticVisitor::VisitCodeTarget(heap, this);
    279   } else if (mode == RelocInfo::CELL) {
    280     StaticVisitor::VisitCell(heap, this);
    281   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    282     StaticVisitor::VisitExternalReference(this);
    283   } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
    284     StaticVisitor::VisitInternalReference(this);
    285   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    286     StaticVisitor::VisitCodeAgeSequence(heap, this);
    287   } else if (RelocInfo::IsDebugBreakSlot(mode) &&
    288              IsPatchedDebugBreakSlotSequence()) {
    289     StaticVisitor::VisitDebugTarget(heap, this);
    290   } else if (RelocInfo::IsRuntimeEntry(mode)) {
    291     StaticVisitor::VisitRuntimeEntry(this);
    292   }
    293 }
    294 
    295 
    296 Operand::Operand(int32_t immediate, RelocInfo::Mode rmode)  {
    297   rm_ = no_reg;
    298   imm32_ = immediate;
    299   rmode_ = rmode;
    300 }
    301 
    302 
    303 Operand::Operand(const ExternalReference& f)  {
    304   rm_ = no_reg;
    305   imm32_ = reinterpret_cast<int32_t>(f.address());
    306   rmode_ = RelocInfo::EXTERNAL_REFERENCE;
    307 }
    308 
    309 
    310 Operand::Operand(Smi* value) {
    311   rm_ = no_reg;
    312   imm32_ =  reinterpret_cast<intptr_t>(value);
    313   rmode_ = RelocInfo::NONE32;
    314 }
    315 
    316 
    317 Operand::Operand(Register rm) {
    318   rm_ = rm;
    319   rs_ = no_reg;
    320   shift_op_ = LSL;
    321   shift_imm_ = 0;
    322 }
    323 
    324 
    325 bool Operand::is_reg() const {
    326   return rm_.is_valid() &&
    327          rs_.is(no_reg) &&
    328          shift_op_ == LSL &&
    329          shift_imm_ == 0;
    330 }
    331 
    332 
    333 void Assembler::CheckBuffer() {
    334   if (buffer_space() <= kGap) {
    335     GrowBuffer();
    336   }
    337   MaybeCheckConstPool();
    338 }
    339 
    340 
    341 void Assembler::emit(Instr x) {
    342   CheckBuffer();
    343   *reinterpret_cast<Instr*>(pc_) = x;
    344   pc_ += kInstrSize;
    345 }
    346 
    347 
    348 Address Assembler::target_address_from_return_address(Address pc) {
    349   // Returns the address of the call target from the return address that will
    350   // be returned to after a call.
    351   // Call sequence on V7 or later is:
    352   //  movw  ip, #... @ call address low 16
    353   //  movt  ip, #... @ call address high 16
    354   //  blx   ip
    355   //                      @ return address
    356   // For V6 when the constant pool is unavailable, it is:
    357   //  mov  ip, #...     @ call address low 8
    358   //  orr  ip, ip, #... @ call address 2nd 8
    359   //  orr  ip, ip, #... @ call address 3rd 8
    360   //  orr  ip, ip, #... @ call address high 8
    361   //  blx   ip
    362   //                      @ return address
    363   // In cases that need frequent patching, the address is in the
    364   // constant pool.  It could be a small constant pool load:
    365   //  ldr   ip, [pc / pp, #...] @ call address
    366   //  blx   ip
    367   //                      @ return address
    368   // Or an extended constant pool load (ARMv7):
    369   //  movw  ip, #...
    370   //  movt  ip, #...
    371   //  ldr   ip, [pc, ip]  @ call address
    372   //  blx   ip
    373   //                      @ return address
    374   // Or an extended constant pool load (ARMv6):
    375   //  mov  ip, #...
    376   //  orr  ip, ip, #...
    377   //  orr  ip, ip, #...
    378   //  orr  ip, ip, #...
    379   //  ldr   ip, [pc, ip]  @ call address
    380   //  blx   ip
    381   //                      @ return address
    382   Address candidate = pc - 2 * Assembler::kInstrSize;
    383   Instr candidate_instr(Memory::int32_at(candidate));
    384   if (IsLdrPcImmediateOffset(candidate_instr) |
    385       IsLdrPpImmediateOffset(candidate_instr)) {
    386     return candidate;
    387   } else {
    388     if (IsLdrPpRegOffset(candidate_instr)) {
    389       candidate -= Assembler::kInstrSize;
    390     }
    391     if (CpuFeatures::IsSupported(ARMv7)) {
    392       candidate -= 1 * Assembler::kInstrSize;
    393       DCHECK(IsMovW(Memory::int32_at(candidate)) &&
    394              IsMovT(Memory::int32_at(candidate + Assembler::kInstrSize)));
    395     } else {
    396       candidate -= 3 * Assembler::kInstrSize;
    397       DCHECK(
    398           IsMovImmed(Memory::int32_at(candidate)) &&
    399           IsOrrImmed(Memory::int32_at(candidate + Assembler::kInstrSize)) &&
    400           IsOrrImmed(Memory::int32_at(candidate + 2 * Assembler::kInstrSize)) &&
    401           IsOrrImmed(Memory::int32_at(candidate + 3 * Assembler::kInstrSize)));
    402     }
    403     return candidate;
    404   }
    405 }
    406 
    407 
    408 Address Assembler::return_address_from_call_start(Address pc) {
    409   if (IsLdrPcImmediateOffset(Memory::int32_at(pc)) |
    410       IsLdrPpImmediateOffset(Memory::int32_at(pc))) {
    411     // Load from constant pool, small section.
    412     return pc + kInstrSize * 2;
    413   } else {
    414     if (CpuFeatures::IsSupported(ARMv7)) {
    415       DCHECK(IsMovW(Memory::int32_at(pc)));
    416       DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
    417       if (IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize))) {
    418         // Load from constant pool, extended section.
    419         return pc + kInstrSize * 4;
    420       } else {
    421         // A movw / movt load immediate.
    422         return pc + kInstrSize * 3;
    423       }
    424     } else {
    425       DCHECK(IsMovImmed(Memory::int32_at(pc)));
    426       DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize)));
    427       DCHECK(IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)));
    428       DCHECK(IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
    429       if (IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize))) {
    430         // Load from constant pool, extended section.
    431         return pc + kInstrSize * 6;
    432       } else {
    433         // A mov / orr load immediate.
    434         return pc + kInstrSize * 5;
    435       }
    436     }
    437   }
    438 }
    439 
    440 
    441 void Assembler::deserialization_set_special_target_at(
    442     Isolate* isolate, Address constant_pool_entry, Code* code, Address target) {
    443   if (FLAG_enable_embedded_constant_pool) {
    444     set_target_address_at(isolate, constant_pool_entry, code, target);
    445   } else {
    446     Memory::Address_at(constant_pool_entry) = target;
    447   }
    448 }
    449 
    450 
    451 void Assembler::deserialization_set_target_internal_reference_at(
    452     Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) {
    453   Memory::Address_at(pc) = target;
    454 }
    455 
    456 
    457 bool Assembler::is_constant_pool_load(Address pc) {
    458   if (CpuFeatures::IsSupported(ARMv7)) {
    459     return !Assembler::IsMovW(Memory::int32_at(pc)) ||
    460            (FLAG_enable_embedded_constant_pool &&
    461             Assembler::IsLdrPpRegOffset(
    462                 Memory::int32_at(pc + 2 * Assembler::kInstrSize)));
    463   } else {
    464     return !Assembler::IsMovImmed(Memory::int32_at(pc)) ||
    465            (FLAG_enable_embedded_constant_pool &&
    466             Assembler::IsLdrPpRegOffset(
    467                 Memory::int32_at(pc + 4 * Assembler::kInstrSize)));
    468   }
    469 }
    470 
    471 
    472 Address Assembler::constant_pool_entry_address(Address pc,
    473                                                Address constant_pool) {
    474   if (FLAG_enable_embedded_constant_pool) {
    475     DCHECK(constant_pool != NULL);
    476     int cp_offset;
    477     if (!CpuFeatures::IsSupported(ARMv7) && IsMovImmed(Memory::int32_at(pc))) {
    478       DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
    479              IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
    480              IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)) &&
    481              IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize)));
    482       // This is an extended constant pool lookup (ARMv6).
    483       Instr mov_instr = instr_at(pc);
    484       Instr orr_instr_1 = instr_at(pc + kInstrSize);
    485       Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize);
    486       Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize);
    487       cp_offset = DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) |
    488                   DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3);
    489     } else if (IsMovW(Memory::int32_at(pc))) {
    490       DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)) &&
    491              IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize)));
    492       // This is an extended constant pool lookup (ARMv7).
    493       Instruction* movw_instr = Instruction::At(pc);
    494       Instruction* movt_instr = Instruction::At(pc + kInstrSize);
    495       cp_offset = (movt_instr->ImmedMovwMovtValue() << 16) |
    496                   movw_instr->ImmedMovwMovtValue();
    497     } else {
    498       // This is a small constant pool lookup.
    499       DCHECK(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc)));
    500       cp_offset = GetLdrRegisterImmediateOffset(Memory::int32_at(pc));
    501     }
    502     return constant_pool + cp_offset;
    503   } else {
    504     DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc)));
    505     Instr instr = Memory::int32_at(pc);
    506     return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta;
    507   }
    508 }
    509 
    510 
    511 Address Assembler::target_address_at(Address pc, Address constant_pool) {
    512   if (is_constant_pool_load(pc)) {
    513     // This is a constant pool lookup. Return the value in the constant pool.
    514     return Memory::Address_at(constant_pool_entry_address(pc, constant_pool));
    515   } else if (CpuFeatures::IsSupported(ARMv7)) {
    516     // This is an movw / movt immediate load. Return the immediate.
    517     DCHECK(IsMovW(Memory::int32_at(pc)) &&
    518            IsMovT(Memory::int32_at(pc + kInstrSize)));
    519     Instruction* movw_instr = Instruction::At(pc);
    520     Instruction* movt_instr = Instruction::At(pc + kInstrSize);
    521     return reinterpret_cast<Address>(
    522         (movt_instr->ImmedMovwMovtValue() << 16) |
    523          movw_instr->ImmedMovwMovtValue());
    524   } else {
    525     // This is an mov / orr immediate load. Return the immediate.
    526     DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
    527            IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
    528            IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
    529            IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
    530     Instr mov_instr = instr_at(pc);
    531     Instr orr_instr_1 = instr_at(pc + kInstrSize);
    532     Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize);
    533     Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize);
    534     Address ret = reinterpret_cast<Address>(
    535         DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) |
    536         DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3));
    537     return ret;
    538   }
    539 }
    540 
    541 
    542 void Assembler::set_target_address_at(Isolate* isolate, Address pc,
    543                                       Address constant_pool, Address target,
    544                                       ICacheFlushMode icache_flush_mode) {
    545   if (is_constant_pool_load(pc)) {
    546     // This is a constant pool lookup. Update the entry in the constant pool.
    547     Memory::Address_at(constant_pool_entry_address(pc, constant_pool)) = target;
    548     // Intuitively, we would think it is necessary to always flush the
    549     // instruction cache after patching a target address in the code as follows:
    550     //   Assembler::FlushICache(isolate, pc, sizeof(target));
    551     // However, on ARM, no instruction is actually patched in the case
    552     // of embedded constants of the form:
    553     // ldr   ip, [pp, #...]
    554     // since the instruction accessing this address in the constant pool remains
    555     // unchanged.
    556   } else if (CpuFeatures::IsSupported(ARMv7)) {
    557     // This is an movw / movt immediate load. Patch the immediate embedded in
    558     // the instructions.
    559     DCHECK(IsMovW(Memory::int32_at(pc)));
    560     DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
    561     uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
    562     uint32_t immediate = reinterpret_cast<uint32_t>(target);
    563     instr_ptr[0] = PatchMovwImmediate(instr_ptr[0], immediate & 0xFFFF);
    564     instr_ptr[1] = PatchMovwImmediate(instr_ptr[1], immediate >> 16);
    565     DCHECK(IsMovW(Memory::int32_at(pc)));
    566     DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
    567     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
    568       Assembler::FlushICache(isolate, pc, 2 * kInstrSize);
    569     }
    570   } else {
    571     // This is an mov / orr immediate load. Patch the immediate embedded in
    572     // the instructions.
    573     DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
    574            IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
    575            IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
    576            IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
    577     uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
    578     uint32_t immediate = reinterpret_cast<uint32_t>(target);
    579     instr_ptr[0] = PatchShiftImm(instr_ptr[0], immediate & kImm8Mask);
    580     instr_ptr[1] = PatchShiftImm(instr_ptr[1], immediate & (kImm8Mask << 8));
    581     instr_ptr[2] = PatchShiftImm(instr_ptr[2], immediate & (kImm8Mask << 16));
    582     instr_ptr[3] = PatchShiftImm(instr_ptr[3], immediate & (kImm8Mask << 24));
    583     DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
    584            IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
    585            IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
    586            IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
    587     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
    588       Assembler::FlushICache(isolate, pc, 4 * kInstrSize);
    589     }
    590   }
    591 }
    592 
    593 Address Assembler::target_address_at(Address pc, Code* code) {
    594   Address constant_pool = code ? code->constant_pool() : NULL;
    595   return target_address_at(pc, constant_pool);
    596 }
    597 
    598 void Assembler::set_target_address_at(Isolate* isolate, Address pc, Code* code,
    599                                       Address target,
    600                                       ICacheFlushMode icache_flush_mode) {
    601   Address constant_pool = code ? code->constant_pool() : NULL;
    602   set_target_address_at(isolate, pc, constant_pool, target, icache_flush_mode);
    603 }
    604 
    605 }  // namespace internal
    606 }  // namespace v8
    607 
    608 #endif  // V8_ARM_ASSEMBLER_ARM_INL_H_
    609