• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/cpu.h"
43 #include "src/debug.h"
44 
45 
46 namespace v8 {
47 namespace internal {
48 
49 
SupportsCrankshaft()50 bool CpuFeatures::SupportsCrankshaft() { return IsSupported(VFP3); }
51 
52 
NumAllocatableRegisters()53 int Register::NumAllocatableRegisters() {
54   return kMaxNumAllocatableRegisters;
55 }
56 
57 
NumRegisters()58 int DwVfpRegister::NumRegisters() {
59   return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
60 }
61 
62 
NumReservedRegisters()63 int DwVfpRegister::NumReservedRegisters() {
64   return kNumReservedRegisters;
65 }
66 
67 
NumAllocatableRegisters()68 int DwVfpRegister::NumAllocatableRegisters() {
69   return NumRegisters() - kNumReservedRegisters;
70 }
71 
72 
ToAllocationIndex(DwVfpRegister reg)73 int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) {
74   ASSERT(!reg.is(kDoubleRegZero));
75   ASSERT(!reg.is(kScratchDoubleReg));
76   if (reg.code() > kDoubleRegZero.code()) {
77     return reg.code() - kNumReservedRegisters;
78   }
79   return reg.code();
80 }
81 
82 
FromAllocationIndex(int index)83 DwVfpRegister DwVfpRegister::FromAllocationIndex(int index) {
84   ASSERT(index >= 0 && index < NumAllocatableRegisters());
85   ASSERT(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 
apply(intptr_t delta,ICacheFlushMode icache_flush_mode)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 
target_address()105 Address RelocInfo::target_address() {
106   ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
107   return Assembler::target_address_at(pc_, host_);
108 }
109 
110 
target_address_address()111 Address RelocInfo::target_address_address() {
112   ASSERT(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     ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
122     return Assembler::target_pointer_address_at(pc_);
123   }
124 }
125 
126 
constant_pool_entry_address()127 Address RelocInfo::constant_pool_entry_address() {
128   ASSERT(IsInConstantPool());
129   if (FLAG_enable_ool_constant_pool) {
130     ASSERT(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc_)));
131     return Assembler::target_constant_pool_address_at(pc_,
132                                                       host_->constant_pool());
133   } else {
134     ASSERT(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
135     return Assembler::target_pointer_address_at(pc_);
136   }
137 }
138 
139 
target_address_size()140 int RelocInfo::target_address_size() {
141   return kPointerSize;
142 }
143 
144 
set_target_address(Address target,WriteBarrierMode write_barrier_mode,ICacheFlushMode icache_flush_mode)145 void RelocInfo::set_target_address(Address target,
146                                    WriteBarrierMode write_barrier_mode,
147                                    ICacheFlushMode icache_flush_mode) {
148   ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
149   Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
150   if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
151       host() != NULL && IsCodeTarget(rmode_)) {
152     Object* target_code = Code::GetCodeFromTargetAddress(target);
153     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
154         host(), this, HeapObject::cast(target_code));
155   }
156 }
157 
158 
target_object()159 Object* RelocInfo::target_object() {
160   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
161   return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
162 }
163 
164 
target_object_handle(Assembler * origin)165 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
166   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
167   return Handle<Object>(reinterpret_cast<Object**>(
168       Assembler::target_address_at(pc_, host_)));
169 }
170 
171 
set_target_object(Object * target,WriteBarrierMode write_barrier_mode,ICacheFlushMode icache_flush_mode)172 void RelocInfo::set_target_object(Object* target,
173                                   WriteBarrierMode write_barrier_mode,
174                                   ICacheFlushMode icache_flush_mode) {
175   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
176   ASSERT(!target->IsConsString());
177   Assembler::set_target_address_at(pc_, host_,
178                                    reinterpret_cast<Address>(target),
179                                    icache_flush_mode);
180   if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
181       host() != NULL &&
182       target->IsHeapObject()) {
183     host()->GetHeap()->incremental_marking()->RecordWrite(
184         host(), &Memory::Object_at(pc_), HeapObject::cast(target));
185   }
186 }
187 
188 
target_reference()189 Address RelocInfo::target_reference() {
190   ASSERT(rmode_ == EXTERNAL_REFERENCE);
191   return Assembler::target_address_at(pc_, host_);
192 }
193 
194 
target_runtime_entry(Assembler * origin)195 Address RelocInfo::target_runtime_entry(Assembler* origin) {
196   ASSERT(IsRuntimeEntry(rmode_));
197   return target_address();
198 }
199 
200 
set_target_runtime_entry(Address target,WriteBarrierMode write_barrier_mode,ICacheFlushMode icache_flush_mode)201 void RelocInfo::set_target_runtime_entry(Address target,
202                                          WriteBarrierMode write_barrier_mode,
203                                          ICacheFlushMode icache_flush_mode) {
204   ASSERT(IsRuntimeEntry(rmode_));
205   if (target_address() != target)
206     set_target_address(target, write_barrier_mode, icache_flush_mode);
207 }
208 
209 
target_cell_handle()210 Handle<Cell> RelocInfo::target_cell_handle() {
211   ASSERT(rmode_ == RelocInfo::CELL);
212   Address address = Memory::Address_at(pc_);
213   return Handle<Cell>(reinterpret_cast<Cell**>(address));
214 }
215 
216 
target_cell()217 Cell* RelocInfo::target_cell() {
218   ASSERT(rmode_ == RelocInfo::CELL);
219   return Cell::FromValueAddress(Memory::Address_at(pc_));
220 }
221 
222 
set_target_cell(Cell * cell,WriteBarrierMode write_barrier_mode,ICacheFlushMode icache_flush_mode)223 void RelocInfo::set_target_cell(Cell* cell,
224                                 WriteBarrierMode write_barrier_mode,
225                                 ICacheFlushMode icache_flush_mode) {
226   ASSERT(rmode_ == RelocInfo::CELL);
227   Address address = cell->address() + Cell::kValueOffset;
228   Memory::Address_at(pc_) = address;
229   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
230     // TODO(1550) We are passing NULL as a slot because cell can never be on
231     // evacuation candidate.
232     host()->GetHeap()->incremental_marking()->RecordWrite(
233         host(), NULL, cell);
234   }
235 }
236 
237 
238 static const int kNoCodeAgeSequenceLength = 3 * Assembler::kInstrSize;
239 
240 
code_age_stub_handle(Assembler * origin)241 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
242   UNREACHABLE();  // This should never be reached on Arm.
243   return Handle<Object>();
244 }
245 
246 
code_age_stub()247 Code* RelocInfo::code_age_stub() {
248   ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
249   return Code::GetCodeFromTargetAddress(
250       Memory::Address_at(pc_ +
251                          (kNoCodeAgeSequenceLength - Assembler::kInstrSize)));
252 }
253 
254 
set_code_age_stub(Code * stub,ICacheFlushMode icache_flush_mode)255 void RelocInfo::set_code_age_stub(Code* stub,
256                                   ICacheFlushMode icache_flush_mode) {
257   ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
258   Memory::Address_at(pc_ +
259                      (kNoCodeAgeSequenceLength - Assembler::kInstrSize)) =
260       stub->instruction_start();
261 }
262 
263 
call_address()264 Address RelocInfo::call_address() {
265   // The 2 instructions offset assumes patched debug break slot or return
266   // sequence.
267   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
268          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
269   return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize);
270 }
271 
272 
set_call_address(Address target)273 void RelocInfo::set_call_address(Address target) {
274   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
275          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
276   Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target;
277   if (host() != NULL) {
278     Object* target_code = Code::GetCodeFromTargetAddress(target);
279     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
280         host(), this, HeapObject::cast(target_code));
281   }
282 }
283 
284 
call_object()285 Object* RelocInfo::call_object() {
286   return *call_object_address();
287 }
288 
289 
set_call_object(Object * target)290 void RelocInfo::set_call_object(Object* target) {
291   *call_object_address() = target;
292 }
293 
294 
call_object_address()295 Object** RelocInfo::call_object_address() {
296   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
297          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
298   return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
299 }
300 
301 
WipeOut()302 void RelocInfo::WipeOut() {
303   ASSERT(IsEmbeddedObject(rmode_) ||
304          IsCodeTarget(rmode_) ||
305          IsRuntimeEntry(rmode_) ||
306          IsExternalReference(rmode_));
307   Assembler::set_target_address_at(pc_, host_, NULL);
308 }
309 
310 
IsPatchedReturnSequence()311 bool RelocInfo::IsPatchedReturnSequence() {
312   Instr current_instr = Assembler::instr_at(pc_);
313   Instr next_instr = Assembler::instr_at(pc_ + Assembler::kInstrSize);
314   // A patched return sequence is:
315   //  ldr ip, [pc, #0]
316   //  blx ip
317   return ((current_instr & kLdrPCMask) == kLdrPCPattern)
318           && ((next_instr & kBlxRegMask) == kBlxRegPattern);
319 }
320 
321 
IsPatchedDebugBreakSlotSequence()322 bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
323   Instr current_instr = Assembler::instr_at(pc_);
324   return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
325 }
326 
327 
Visit(Isolate * isolate,ObjectVisitor * visitor)328 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
329   RelocInfo::Mode mode = rmode();
330   if (mode == RelocInfo::EMBEDDED_OBJECT) {
331     visitor->VisitEmbeddedPointer(this);
332   } else if (RelocInfo::IsCodeTarget(mode)) {
333     visitor->VisitCodeTarget(this);
334   } else if (mode == RelocInfo::CELL) {
335     visitor->VisitCell(this);
336   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
337     visitor->VisitExternalReference(this);
338   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
339     visitor->VisitCodeAgeSequence(this);
340   } else if (((RelocInfo::IsJSReturn(mode) &&
341               IsPatchedReturnSequence()) ||
342              (RelocInfo::IsDebugBreakSlot(mode) &&
343               IsPatchedDebugBreakSlotSequence())) &&
344              isolate->debug()->has_break_points()) {
345     visitor->VisitDebugTarget(this);
346   } else if (RelocInfo::IsRuntimeEntry(mode)) {
347     visitor->VisitRuntimeEntry(this);
348   }
349 }
350 
351 
352 template<typename StaticVisitor>
Visit(Heap * heap)353 void RelocInfo::Visit(Heap* heap) {
354   RelocInfo::Mode mode = rmode();
355   if (mode == RelocInfo::EMBEDDED_OBJECT) {
356     StaticVisitor::VisitEmbeddedPointer(heap, this);
357   } else if (RelocInfo::IsCodeTarget(mode)) {
358     StaticVisitor::VisitCodeTarget(heap, this);
359   } else if (mode == RelocInfo::CELL) {
360     StaticVisitor::VisitCell(heap, this);
361   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
362     StaticVisitor::VisitExternalReference(this);
363   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
364     StaticVisitor::VisitCodeAgeSequence(heap, this);
365   } else if (heap->isolate()->debug()->has_break_points() &&
366              ((RelocInfo::IsJSReturn(mode) &&
367               IsPatchedReturnSequence()) ||
368              (RelocInfo::IsDebugBreakSlot(mode) &&
369               IsPatchedDebugBreakSlotSequence()))) {
370     StaticVisitor::VisitDebugTarget(heap, this);
371   } else if (RelocInfo::IsRuntimeEntry(mode)) {
372     StaticVisitor::VisitRuntimeEntry(this);
373   }
374 }
375 
376 
Operand(int32_t immediate,RelocInfo::Mode rmode)377 Operand::Operand(int32_t immediate, RelocInfo::Mode rmode)  {
378   rm_ = no_reg;
379   imm32_ = immediate;
380   rmode_ = rmode;
381 }
382 
383 
Operand(const ExternalReference & f)384 Operand::Operand(const ExternalReference& f)  {
385   rm_ = no_reg;
386   imm32_ = reinterpret_cast<int32_t>(f.address());
387   rmode_ = RelocInfo::EXTERNAL_REFERENCE;
388 }
389 
390 
Operand(Smi * value)391 Operand::Operand(Smi* value) {
392   rm_ = no_reg;
393   imm32_ =  reinterpret_cast<intptr_t>(value);
394   rmode_ = RelocInfo::NONE32;
395 }
396 
397 
Operand(Register rm)398 Operand::Operand(Register rm) {
399   rm_ = rm;
400   rs_ = no_reg;
401   shift_op_ = LSL;
402   shift_imm_ = 0;
403 }
404 
405 
is_reg()406 bool Operand::is_reg() const {
407   return rm_.is_valid() &&
408          rs_.is(no_reg) &&
409          shift_op_ == LSL &&
410          shift_imm_ == 0;
411 }
412 
413 
CheckBuffer()414 void Assembler::CheckBuffer() {
415   if (buffer_space() <= kGap) {
416     GrowBuffer();
417   }
418   if (pc_offset() >= next_buffer_check_) {
419     CheckConstPool(false, true);
420   }
421 }
422 
423 
emit(Instr x)424 void Assembler::emit(Instr x) {
425   CheckBuffer();
426   *reinterpret_cast<Instr*>(pc_) = x;
427   pc_ += kInstrSize;
428 }
429 
430 
target_pointer_address_at(Address pc)431 Address Assembler::target_pointer_address_at(Address pc) {
432   Instr instr = Memory::int32_at(pc);
433   return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta;
434 }
435 
436 
target_constant_pool_address_at(Address pc,ConstantPoolArray * constant_pool)437 Address Assembler::target_constant_pool_address_at(
438     Address pc, ConstantPoolArray* constant_pool) {
439   ASSERT(constant_pool != NULL);
440   ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
441   Instr instr = Memory::int32_at(pc);
442   return reinterpret_cast<Address>(constant_pool) +
443       GetLdrRegisterImmediateOffset(instr);
444 }
445 
446 
target_address_at(Address pc,ConstantPoolArray * constant_pool)447 Address Assembler::target_address_at(Address pc,
448                                      ConstantPoolArray* constant_pool) {
449   if (IsMovW(Memory::int32_at(pc))) {
450     ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
451     Instruction* instr = Instruction::At(pc);
452     Instruction* next_instr = Instruction::At(pc + kInstrSize);
453     return reinterpret_cast<Address>(
454         (next_instr->ImmedMovwMovtValue() << 16) |
455         instr->ImmedMovwMovtValue());
456   } else if (FLAG_enable_ool_constant_pool) {
457     ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
458     return Memory::Address_at(
459         target_constant_pool_address_at(pc, constant_pool));
460   } else {
461     ASSERT(IsLdrPcImmediateOffset(Memory::int32_at(pc)));
462     return Memory::Address_at(target_pointer_address_at(pc));
463   }
464 }
465 
466 
target_address_from_return_address(Address pc)467 Address Assembler::target_address_from_return_address(Address pc) {
468   // Returns the address of the call target from the return address that will
469   // be returned to after a call.
470   // Call sequence on V7 or later is :
471   //  movw  ip, #... @ call address low 16
472   //  movt  ip, #... @ call address high 16
473   //  blx   ip
474   //                      @ return address
475   // Or pre-V7 or cases that need frequent patching:
476   //  ldr   ip, [pc, #...] @ call address
477   //  blx   ip
478   //                      @ return address
479   Address candidate = pc - 2 * Assembler::kInstrSize;
480   Instr candidate_instr(Memory::int32_at(candidate));
481   if (IsLdrPcImmediateOffset(candidate_instr) |
482       IsLdrPpImmediateOffset(candidate_instr)) {
483     return candidate;
484   }
485   candidate = pc - 3 * Assembler::kInstrSize;
486   ASSERT(IsMovW(Memory::int32_at(candidate)) &&
487          IsMovT(Memory::int32_at(candidate + kInstrSize)));
488   return candidate;
489 }
490 
491 
return_address_from_call_start(Address pc)492 Address Assembler::return_address_from_call_start(Address pc) {
493   if (IsLdrPcImmediateOffset(Memory::int32_at(pc)) |
494       IsLdrPpImmediateOffset(Memory::int32_at(pc))) {
495     return pc + kInstrSize * 2;
496   } else {
497     ASSERT(IsMovW(Memory::int32_at(pc)));
498     ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
499     return pc + kInstrSize * 3;
500   }
501 }
502 
503 
deserialization_set_special_target_at(Address constant_pool_entry,Code * code,Address target)504 void Assembler::deserialization_set_special_target_at(
505     Address constant_pool_entry, Code* code, Address target) {
506   if (FLAG_enable_ool_constant_pool) {
507     set_target_address_at(constant_pool_entry, code, target);
508   } else {
509     Memory::Address_at(constant_pool_entry) = target;
510   }
511 }
512 
513 
EncodeMovwImmediate(uint32_t immediate)514 static Instr EncodeMovwImmediate(uint32_t immediate) {
515   ASSERT(immediate < 0x10000);
516   return ((immediate & 0xf000) << 4) | (immediate & 0xfff);
517 }
518 
519 
PatchMovwImmediate(Instr instruction,uint32_t immediate)520 static Instr PatchMovwImmediate(Instr instruction, uint32_t immediate) {
521   instruction &= ~EncodeMovwImmediate(0xffff);
522   return instruction | EncodeMovwImmediate(immediate);
523 }
524 
525 
set_target_address_at(Address pc,ConstantPoolArray * constant_pool,Address target,ICacheFlushMode icache_flush_mode)526 void Assembler::set_target_address_at(Address pc,
527                                       ConstantPoolArray* constant_pool,
528                                       Address target,
529                                       ICacheFlushMode icache_flush_mode) {
530   if (IsMovW(Memory::int32_at(pc))) {
531     ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
532     uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
533     uint32_t immediate = reinterpret_cast<uint32_t>(target);
534     instr_ptr[0] = PatchMovwImmediate(instr_ptr[0], immediate & 0xFFFF);
535     instr_ptr[1] = PatchMovwImmediate(instr_ptr[1], immediate >> 16);
536     ASSERT(IsMovW(Memory::int32_at(pc)));
537     ASSERT(IsMovT(Memory::int32_at(pc + kInstrSize)));
538     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
539       CPU::FlushICache(pc, 2 * kInstrSize);
540     }
541   } else if (FLAG_enable_ool_constant_pool) {
542     ASSERT(IsLdrPpImmediateOffset(Memory::int32_at(pc)));
543     Memory::Address_at(
544       target_constant_pool_address_at(pc, constant_pool)) = target;
545   } else {
546     ASSERT(IsLdrPcImmediateOffset(Memory::int32_at(pc)));
547     Memory::Address_at(target_pointer_address_at(pc)) = 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     //   CPU::FlushICache(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, [pc, #...]
554     // since the instruction accessing this address in the constant pool remains
555     // unchanged.
556   }
557 }
558 
559 
560 } }  // namespace v8::internal
561 
562 #endif  // V8_ARM_ASSEMBLER_ARM_INL_H_
563