blob: 876cd3d1bd04ce0aa99308603c1d81eb999a9a99 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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.
Ben Murdoch692be652012-01-10 18:47:50 +000035// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +000036
37#ifndef V8_ARM_ASSEMBLER_ARM_INL_H_
38#define V8_ARM_ASSEMBLER_ARM_INL_H_
39
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040#include "src/arm/assembler-arm.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +010041
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042#include "src/assembler.h"
43#include "src/debug.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000044
45
46namespace v8 {
47namespace internal {
48
Steve Blocka7e24c12009-10-30 11:49:00 +000049
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050bool CpuFeatures::SupportsCrankshaft() { return IsSupported(VFP3); }
51
52
53int Register::NumAllocatableRegisters() {
54 return kMaxNumAllocatableRegisters;
55}
56
57
58int DwVfpRegister::NumRegisters() {
59 return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
60}
61
62
63int DwVfpRegister::NumReservedRegisters() {
64 return kNumReservedRegisters;
65}
66
67
68int DwVfpRegister::NumAllocatableRegisters() {
69 return NumRegisters() - kNumReservedRegisters;
70}
71
72
Emily Bernier958fae72015-03-24 16:35:39 -040073// static
74int DwVfpRegister::NumAllocatableAliasedRegisters() {
75 return LowDwVfpRegister::kMaxNumLowRegisters - kNumReservedRegisters;
76}
77
78
Ben Murdoch692be652012-01-10 18:47:50 +000079int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000080 DCHECK(!reg.is(kDoubleRegZero));
81 DCHECK(!reg.is(kScratchDoubleReg));
82 if (reg.code() > kDoubleRegZero.code()) {
83 return reg.code() - kNumReservedRegisters;
84 }
Ben Murdoch692be652012-01-10 18:47:50 +000085 return reg.code();
86}
87
88
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089DwVfpRegister DwVfpRegister::FromAllocationIndex(int index) {
90 DCHECK(index >= 0 && index < NumAllocatableRegisters());
91 DCHECK(kScratchDoubleReg.code() - kDoubleRegZero.code() ==
92 kNumReservedRegisters - 1);
93 if (index >= kDoubleRegZero.code()) {
94 return from_code(index + kNumReservedRegisters);
95 }
96 return from_code(index);
97}
98
99
100void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000101 if (RelocInfo::IsInternalReference(rmode_)) {
102 // absolute code pointer inside code object moves with the code object.
103 int32_t* p = reinterpret_cast<int32_t*>(pc_);
104 *p += delta; // relocate entry
105 }
106 // We do not use pc relative addressing on ARM, so there is
107 // nothing else to do.
108}
109
110
111Address RelocInfo::target_address() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
113 return Assembler::target_address_at(pc_, host_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000114}
115
116
117Address RelocInfo::target_address_address() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000118 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100119 || rmode_ == EMBEDDED_OBJECT
120 || rmode_ == EXTERNAL_REFERENCE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000121 if (FLAG_enable_ool_constant_pool ||
122 Assembler::IsMovW(Memory::int32_at(pc_))) {
123 // We return the PC for ool constant pool since this function is used by the
124 // serializerer and expects the address to reside within the code object.
125 return reinterpret_cast<Address>(pc_);
126 } else {
127 DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
128 return constant_pool_entry_address();
129 }
130}
131
132
133Address RelocInfo::constant_pool_entry_address() {
134 DCHECK(IsInConstantPool());
135 return Assembler::constant_pool_entry_address(pc_, host_->constant_pool());
Steve Blocka7e24c12009-10-30 11:49:00 +0000136}
137
138
Leon Clarkef7060e22010-06-03 12:02:55 +0100139int RelocInfo::target_address_size() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100140 return kPointerSize;
Leon Clarkef7060e22010-06-03 12:02:55 +0100141}
142
143
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144void RelocInfo::set_target_address(Address target,
145 WriteBarrierMode write_barrier_mode,
146 ICacheFlushMode icache_flush_mode) {
147 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
148 Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
149 if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
150 host() != NULL && IsCodeTarget(rmode_)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100151 Object* target_code = Code::GetCodeFromTargetAddress(target);
152 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
153 host(), this, HeapObject::cast(target_code));
154 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000155}
156
157
158Object* RelocInfo::target_object() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000159 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
160 return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
Steve Block3ce2e202009-11-05 08:53:23 +0000161}
162
163
Steve Blockd0582a62009-12-15 09:54:21 +0000164Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
166 return Handle<Object>(reinterpret_cast<Object**>(
167 Assembler::target_address_at(pc_, host_)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000168}
169
170
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171void RelocInfo::set_target_object(Object* target,
172 WriteBarrierMode write_barrier_mode,
173 ICacheFlushMode icache_flush_mode) {
174 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
175 Assembler::set_target_address_at(pc_, host_,
176 reinterpret_cast<Address>(target),
177 icache_flush_mode);
178 if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100179 host() != NULL &&
180 target->IsHeapObject()) {
181 host()->GetHeap()->incremental_marking()->RecordWrite(
182 host(), &Memory::Object_at(pc_), HeapObject::cast(target));
183 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000184}
185
186
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187Address RelocInfo::target_reference() {
188 DCHECK(rmode_ == EXTERNAL_REFERENCE);
189 return Assembler::target_address_at(pc_, host_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000190}
191
192
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193Address RelocInfo::target_runtime_entry(Assembler* origin) {
194 DCHECK(IsRuntimeEntry(rmode_));
195 return target_address();
196}
197
198
199void RelocInfo::set_target_runtime_entry(Address target,
200 WriteBarrierMode write_barrier_mode,
201 ICacheFlushMode icache_flush_mode) {
202 DCHECK(IsRuntimeEntry(rmode_));
203 if (target_address() != target)
204 set_target_address(target, write_barrier_mode, icache_flush_mode);
205}
206
207
208Handle<Cell> RelocInfo::target_cell_handle() {
209 DCHECK(rmode_ == RelocInfo::CELL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100210 Address address = Memory::Address_at(pc_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000211 return Handle<Cell>(reinterpret_cast<Cell**>(address));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100212}
213
214
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215Cell* RelocInfo::target_cell() {
216 DCHECK(rmode_ == RelocInfo::CELL);
217 return Cell::FromValueAddress(Memory::Address_at(pc_));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100218}
219
220
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221void RelocInfo::set_target_cell(Cell* cell,
222 WriteBarrierMode write_barrier_mode,
223 ICacheFlushMode icache_flush_mode) {
224 DCHECK(rmode_ == RelocInfo::CELL);
225 Address address = cell->address() + Cell::kValueOffset;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100226 Memory::Address_at(pc_) = address;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000227 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100228 // TODO(1550) We are passing NULL as a slot because cell can never be on
229 // evacuation candidate.
230 host()->GetHeap()->incremental_marking()->RecordWrite(
231 host(), NULL, cell);
232 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100233}
234
235
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000236static const int kNoCodeAgeSequenceLength = 3 * Assembler::kInstrSize;
237
238
239Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
240 UNREACHABLE(); // This should never be reached on Arm.
241 return Handle<Object>();
242}
243
244
245Code* RelocInfo::code_age_stub() {
246 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
247 return Code::GetCodeFromTargetAddress(
248 Memory::Address_at(pc_ +
249 (kNoCodeAgeSequenceLength - Assembler::kInstrSize)));
250}
251
252
253void RelocInfo::set_code_age_stub(Code* stub,
254 ICacheFlushMode icache_flush_mode) {
255 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
256 Memory::Address_at(pc_ +
257 (kNoCodeAgeSequenceLength - Assembler::kInstrSize)) =
258 stub->instruction_start();
259}
260
261
Steve Blocka7e24c12009-10-30 11:49:00 +0000262Address RelocInfo::call_address() {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100263 // The 2 instructions offset assumes patched debug break slot or return
264 // sequence.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000265 DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100266 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize);
268}
269
270
271void RelocInfo::set_call_address(Address target) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000272 DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
Ben Murdochbb769b22010-08-11 14:56:33 +0100273 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000274 Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100275 if (host() != NULL) {
276 Object* target_code = Code::GetCodeFromTargetAddress(target);
277 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
278 host(), this, HeapObject::cast(target_code));
279 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000280}
281
282
283Object* RelocInfo::call_object() {
284 return *call_object_address();
285}
286
287
Ben Murdochbb769b22010-08-11 14:56:33 +0100288void RelocInfo::set_call_object(Object* target) {
289 *call_object_address() = target;
Steve Blocka7e24c12009-10-30 11:49:00 +0000290}
291
292
Ben Murdochbb769b22010-08-11 14:56:33 +0100293Object** RelocInfo::call_object_address() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000294 DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
Ben Murdochbb769b22010-08-11 14:56:33 +0100295 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
296 return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
Steve Blocka7e24c12009-10-30 11:49:00 +0000297}
298
299
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000300void RelocInfo::WipeOut() {
301 DCHECK(IsEmbeddedObject(rmode_) ||
302 IsCodeTarget(rmode_) ||
303 IsRuntimeEntry(rmode_) ||
304 IsExternalReference(rmode_));
305 Assembler::set_target_address_at(pc_, host_, NULL);
306}
307
308
Steve Block3ce2e202009-11-05 08:53:23 +0000309bool RelocInfo::IsPatchedReturnSequence() {
Steve Block6ded16b2010-05-10 14:33:55 +0100310 Instr current_instr = Assembler::instr_at(pc_);
311 Instr next_instr = Assembler::instr_at(pc_ + Assembler::kInstrSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100312 // A patched return sequence is:
313 // ldr ip, [pc, #0]
314 // blx ip
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000315 return Assembler::IsLdrPcImmediateOffset(current_instr) &&
316 Assembler::IsBlxReg(next_instr);
Steve Blocka7e24c12009-10-30 11:49:00 +0000317}
318
319
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100320bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
321 Instr current_instr = Assembler::instr_at(pc_);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800322 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100323}
324
325
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100327 RelocInfo::Mode mode = rmode();
328 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100329 visitor->VisitEmbeddedPointer(this);
Leon Clarkef7060e22010-06-03 12:02:55 +0100330 } else if (RelocInfo::IsCodeTarget(mode)) {
331 visitor->VisitCodeTarget(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332 } else if (mode == RelocInfo::CELL) {
333 visitor->VisitCell(this);
Leon Clarkef7060e22010-06-03 12:02:55 +0100334 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100335 visitor->VisitExternalReference(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000336 } else if (RelocInfo::IsCodeAgeSequence(mode)) {
337 visitor->VisitCodeAgeSequence(this);
Steve Block44f0eee2011-05-26 01:26:41 +0100338 } else if (((RelocInfo::IsJSReturn(mode) &&
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100339 IsPatchedReturnSequence()) ||
340 (RelocInfo::IsDebugBreakSlot(mode) &&
Steve Block44f0eee2011-05-26 01:26:41 +0100341 IsPatchedDebugBreakSlotSequence())) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000342 isolate->debug()->has_break_points()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100343 visitor->VisitDebugTarget(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344 } else if (RelocInfo::IsRuntimeEntry(mode)) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100345 visitor->VisitRuntimeEntry(this);
346 }
347}
348
349
Iain Merrick75681382010-08-19 15:07:18 +0100350template<typename StaticVisitor>
Steve Block44f0eee2011-05-26 01:26:41 +0100351void RelocInfo::Visit(Heap* heap) {
Iain Merrick75681382010-08-19 15:07:18 +0100352 RelocInfo::Mode mode = rmode();
353 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100354 StaticVisitor::VisitEmbeddedPointer(heap, this);
Iain Merrick75681382010-08-19 15:07:18 +0100355 } else if (RelocInfo::IsCodeTarget(mode)) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100356 StaticVisitor::VisitCodeTarget(heap, this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000357 } else if (mode == RelocInfo::CELL) {
358 StaticVisitor::VisitCell(heap, this);
Iain Merrick75681382010-08-19 15:07:18 +0100359 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100360 StaticVisitor::VisitExternalReference(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000361 } else if (RelocInfo::IsCodeAgeSequence(mode)) {
362 StaticVisitor::VisitCodeAgeSequence(heap, this);
Steve Block44f0eee2011-05-26 01:26:41 +0100363 } else if (heap->isolate()->debug()->has_break_points() &&
Iain Merrick75681382010-08-19 15:07:18 +0100364 ((RelocInfo::IsJSReturn(mode) &&
365 IsPatchedReturnSequence()) ||
366 (RelocInfo::IsDebugBreakSlot(mode) &&
367 IsPatchedDebugBreakSlotSequence()))) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100368 StaticVisitor::VisitDebugTarget(heap, this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369 } else if (RelocInfo::IsRuntimeEntry(mode)) {
Iain Merrick75681382010-08-19 15:07:18 +0100370 StaticVisitor::VisitRuntimeEntry(this);
371 }
372}
373
374
Steve Blocka7e24c12009-10-30 11:49:00 +0000375Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) {
376 rm_ = no_reg;
377 imm32_ = immediate;
378 rmode_ = rmode;
379}
380
381
Steve Blocka7e24c12009-10-30 11:49:00 +0000382Operand::Operand(const ExternalReference& f) {
383 rm_ = no_reg;
384 imm32_ = reinterpret_cast<int32_t>(f.address());
385 rmode_ = RelocInfo::EXTERNAL_REFERENCE;
386}
387
388
Steve Blocka7e24c12009-10-30 11:49:00 +0000389Operand::Operand(Smi* value) {
390 rm_ = no_reg;
391 imm32_ = reinterpret_cast<intptr_t>(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000392 rmode_ = RelocInfo::NONE32;
Steve Blocka7e24c12009-10-30 11:49:00 +0000393}
394
395
396Operand::Operand(Register rm) {
397 rm_ = rm;
398 rs_ = no_reg;
399 shift_op_ = LSL;
400 shift_imm_ = 0;
401}
402
403
404bool Operand::is_reg() const {
405 return rm_.is_valid() &&
406 rs_.is(no_reg) &&
407 shift_op_ == LSL &&
408 shift_imm_ == 0;
409}
410
411
412void Assembler::CheckBuffer() {
413 if (buffer_space() <= kGap) {
414 GrowBuffer();
415 }
416 if (pc_offset() >= next_buffer_check_) {
417 CheckConstPool(false, true);
418 }
419}
420
421
422void Assembler::emit(Instr x) {
423 CheckBuffer();
424 *reinterpret_cast<Instr*>(pc_) = x;
425 pc_ += kInstrSize;
426}
427
428
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429Address Assembler::target_address_from_return_address(Address pc) {
430 // Returns the address of the call target from the return address that will
431 // be returned to after a call.
432 // Call sequence on V7 or later is:
433 // movw ip, #... @ call address low 16
434 // movt ip, #... @ call address high 16
435 // blx ip
436 // @ return address
437 // For V6 when the constant pool is unavailable, it is:
438 // mov ip, #... @ call address low 8
439 // orr ip, ip, #... @ call address 2nd 8
440 // orr ip, ip, #... @ call address 3rd 8
441 // orr ip, ip, #... @ call address high 8
442 // blx ip
443 // @ return address
444 // In cases that need frequent patching, the address is in the
445 // constant pool. It could be a small constant pool load:
446 // ldr ip, [pc / pp, #...] @ call address
447 // blx ip
448 // @ return address
449 // Or an extended constant pool load (ARMv7):
450 // movw ip, #...
451 // movt ip, #...
452 // ldr ip, [pc, ip] @ call address
453 // blx ip
454 // @ return address
455 // Or an extended constant pool load (ARMv6):
456 // mov ip, #...
457 // orr ip, ip, #...
458 // orr ip, ip, #...
459 // orr ip, ip, #...
460 // ldr ip, [pc, ip] @ call address
461 // blx ip
462 // @ return address
463 Address candidate = pc - 2 * Assembler::kInstrSize;
464 Instr candidate_instr(Memory::int32_at(candidate));
465 if (IsLdrPcImmediateOffset(candidate_instr) |
466 IsLdrPpImmediateOffset(candidate_instr)) {
467 return candidate;
468 } else {
469 if (IsLdrPpRegOffset(candidate_instr)) {
470 candidate -= Assembler::kInstrSize;
471 }
472 if (CpuFeatures::IsSupported(ARMv7)) {
473 candidate -= 1 * Assembler::kInstrSize;
474 DCHECK(IsMovW(Memory::int32_at(candidate)) &&
475 IsMovT(Memory::int32_at(candidate + Assembler::kInstrSize)));
476 } else {
477 candidate -= 3 * Assembler::kInstrSize;
478 DCHECK(
479 IsMovImmed(Memory::int32_at(candidate)) &&
480 IsOrrImmed(Memory::int32_at(candidate + Assembler::kInstrSize)) &&
481 IsOrrImmed(Memory::int32_at(candidate + 2 * Assembler::kInstrSize)) &&
482 IsOrrImmed(Memory::int32_at(candidate + 3 * Assembler::kInstrSize)));
483 }
484 return candidate;
Leon Clarkee46be812010-01-19 14:06:41 +0000485 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000486}
487
488
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000489Address Assembler::break_address_from_return_address(Address pc) {
490 return pc - Assembler::kPatchDebugBreakSlotReturnOffset;
491}
492
493
494Address Assembler::return_address_from_call_start(Address pc) {
495 if (IsLdrPcImmediateOffset(Memory::int32_at(pc)) |
496 IsLdrPpImmediateOffset(Memory::int32_at(pc))) {
497 // Load from constant pool, small section.
498 return pc + kInstrSize * 2;
499 } else {
500 if (CpuFeatures::IsSupported(ARMv7)) {
501 DCHECK(IsMovW(Memory::int32_at(pc)));
502 DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
503 if (IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize))) {
504 // Load from constant pool, extended section.
505 return pc + kInstrSize * 4;
506 } else {
507 // A movw / movt load immediate.
508 return pc + kInstrSize * 3;
509 }
510 } else {
511 DCHECK(IsMovImmed(Memory::int32_at(pc)));
512 DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize)));
513 DCHECK(IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)));
514 DCHECK(IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
515 if (IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize))) {
516 // Load from constant pool, extended section.
517 return pc + kInstrSize * 6;
518 } else {
519 // A mov / orr load immediate.
520 return pc + kInstrSize * 5;
521 }
522 }
523 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000524}
525
526
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100527void Assembler::deserialization_set_special_target_at(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000528 Address constant_pool_entry, Code* code, Address target) {
529 if (FLAG_enable_ool_constant_pool) {
530 set_target_address_at(constant_pool_entry, code, target);
531 } else {
532 Memory::Address_at(constant_pool_entry) = target;
533 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100534}
535
536
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000537bool Assembler::is_constant_pool_load(Address pc) {
538 if (CpuFeatures::IsSupported(ARMv7)) {
539 return !Assembler::IsMovW(Memory::int32_at(pc)) ||
540 (FLAG_enable_ool_constant_pool &&
541 Assembler::IsLdrPpRegOffset(
542 Memory::int32_at(pc + 2 * Assembler::kInstrSize)));
543 } else {
544 return !Assembler::IsMovImmed(Memory::int32_at(pc)) ||
545 (FLAG_enable_ool_constant_pool &&
546 Assembler::IsLdrPpRegOffset(
547 Memory::int32_at(pc + 4 * Assembler::kInstrSize)));
548 }
Steve Blockd0582a62009-12-15 09:54:21 +0000549}
550
551
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552Address Assembler::constant_pool_entry_address(
553 Address pc, ConstantPoolArray* constant_pool) {
554 if (FLAG_enable_ool_constant_pool) {
555 DCHECK(constant_pool != NULL);
556 int cp_offset;
557 if (!CpuFeatures::IsSupported(ARMv7) && IsMovImmed(Memory::int32_at(pc))) {
558 DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
559 IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
560 IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)) &&
561 IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize)));
562 // This is an extended constant pool lookup (ARMv6).
563 Instr mov_instr = instr_at(pc);
564 Instr orr_instr_1 = instr_at(pc + kInstrSize);
565 Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize);
566 Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize);
567 cp_offset = DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) |
568 DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3);
569 } else if (IsMovW(Memory::int32_at(pc))) {
570 DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)) &&
571 IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize)));
572 // This is an extended constant pool lookup (ARMv7).
573 Instruction* movw_instr = Instruction::At(pc);
574 Instruction* movt_instr = Instruction::At(pc + kInstrSize);
575 cp_offset = (movt_instr->ImmedMovwMovtValue() << 16) |
576 movw_instr->ImmedMovwMovtValue();
577 } else {
578 // This is a small constant pool lookup.
579 DCHECK(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc)));
580 cp_offset = GetLdrRegisterImmediateOffset(Memory::int32_at(pc));
581 }
582 return reinterpret_cast<Address>(constant_pool) + cp_offset;
583 } else {
584 DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc)));
585 Instr instr = Memory::int32_at(pc);
586 return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta;
587 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000588}
589
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000590
591Address Assembler::target_address_at(Address pc,
592 ConstantPoolArray* constant_pool) {
593 if (is_constant_pool_load(pc)) {
594 // This is a constant pool lookup. Return the value in the constant pool.
595 return Memory::Address_at(constant_pool_entry_address(pc, constant_pool));
596 } else if (CpuFeatures::IsSupported(ARMv7)) {
597 // This is an movw / movt immediate load. Return the immediate.
598 DCHECK(IsMovW(Memory::int32_at(pc)) &&
599 IsMovT(Memory::int32_at(pc + kInstrSize)));
600 Instruction* movw_instr = Instruction::At(pc);
601 Instruction* movt_instr = Instruction::At(pc + kInstrSize);
602 return reinterpret_cast<Address>(
603 (movt_instr->ImmedMovwMovtValue() << 16) |
604 movw_instr->ImmedMovwMovtValue());
605 } else {
606 // This is an mov / orr immediate load. Return the immediate.
607 DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
608 IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
609 IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
610 IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
611 Instr mov_instr = instr_at(pc);
612 Instr orr_instr_1 = instr_at(pc + kInstrSize);
613 Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize);
614 Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize);
615 Address ret = reinterpret_cast<Address>(
616 DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) |
617 DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3));
618 return ret;
619 }
620}
621
622
623void Assembler::set_target_address_at(Address pc,
624 ConstantPoolArray* constant_pool,
625 Address target,
626 ICacheFlushMode icache_flush_mode) {
627 if (is_constant_pool_load(pc)) {
628 // This is a constant pool lookup. Update the entry in the constant pool.
629 Memory::Address_at(constant_pool_entry_address(pc, constant_pool)) = target;
630 // Intuitively, we would think it is necessary to always flush the
631 // instruction cache after patching a target address in the code as follows:
632 // CpuFeatures::FlushICache(pc, sizeof(target));
633 // However, on ARM, no instruction is actually patched in the case
634 // of embedded constants of the form:
635 // ldr ip, [pp, #...]
636 // since the instruction accessing this address in the constant pool remains
637 // unchanged.
638 } else if (CpuFeatures::IsSupported(ARMv7)) {
639 // This is an movw / movt immediate load. Patch the immediate embedded in
640 // the instructions.
641 DCHECK(IsMovW(Memory::int32_at(pc)));
642 DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
643 uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
644 uint32_t immediate = reinterpret_cast<uint32_t>(target);
645 instr_ptr[0] = PatchMovwImmediate(instr_ptr[0], immediate & 0xFFFF);
646 instr_ptr[1] = PatchMovwImmediate(instr_ptr[1], immediate >> 16);
647 DCHECK(IsMovW(Memory::int32_at(pc)));
648 DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
649 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
650 CpuFeatures::FlushICache(pc, 2 * kInstrSize);
651 }
652 } else {
653 // This is an mov / orr immediate load. Patch the immediate embedded in
654 // the instructions.
655 DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
656 IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
657 IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
658 IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
659 uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
660 uint32_t immediate = reinterpret_cast<uint32_t>(target);
661 instr_ptr[0] = PatchShiftImm(instr_ptr[0], immediate & kImm8Mask);
662 instr_ptr[1] = PatchShiftImm(instr_ptr[1], immediate & (kImm8Mask << 8));
663 instr_ptr[2] = PatchShiftImm(instr_ptr[2], immediate & (kImm8Mask << 16));
664 instr_ptr[3] = PatchShiftImm(instr_ptr[3], immediate & (kImm8Mask << 24));
665 DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
666 IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
667 IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
668 IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
669 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
670 CpuFeatures::FlushICache(pc, 4 * kInstrSize);
671 }
672 }
673}
674
675
Steve Blocka7e24c12009-10-30 11:49:00 +0000676} } // namespace v8::internal
677
678#endif // V8_ARM_ASSEMBLER_ARM_INL_H_