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