blob: b0b22b63c20c210dcb4bf327533ea38a8abad8b9 [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"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043#include "src/debug/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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000053int DoubleRegister::NumRegisters() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 return CpuFeatures::IsSupported(VFP32DREGS) ? 32 : 16;
55}
56
57
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000058void RelocInfo::apply(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +000059 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
69Address RelocInfo::target_address() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000070 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
71 return Assembler::target_address_at(pc_, host_);
Steve Blocka7e24c12009-10-30 11:49:00 +000072}
73
Ben Murdochda12d292016-06-02 14:46:10 +010074Address RelocInfo::wasm_memory_reference() {
75 DCHECK(IsWasmMemoryReference(rmode_));
76 return Assembler::target_address_at(pc_, host_);
77}
Steve Blocka7e24c12009-10-30 11:49:00 +000078
79Address RelocInfo::target_address_address() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000080 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
Ben Murdoch3ef787d2012-04-12 10:51:47 +010081 || rmode_ == EMBEDDED_OBJECT
82 || rmode_ == EXTERNAL_REFERENCE);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 if (FLAG_enable_embedded_constant_pool ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +000084 Assembler::IsMovW(Memory::int32_at(pc_))) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000085 // We return the PC for embedded constant pool since this function is used
86 // by the serializer and expects the address to reside within the code
87 // object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000088 return reinterpret_cast<Address>(pc_);
89 } else {
90 DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc_)));
91 return constant_pool_entry_address();
92 }
93}
94
95
96Address RelocInfo::constant_pool_entry_address() {
97 DCHECK(IsInConstantPool());
98 return Assembler::constant_pool_entry_address(pc_, host_->constant_pool());
Steve Blocka7e24c12009-10-30 11:49:00 +000099}
100
101
Leon Clarkef7060e22010-06-03 12:02:55 +0100102int RelocInfo::target_address_size() {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100103 return kPointerSize;
Leon Clarkef7060e22010-06-03 12:02:55 +0100104}
105
106
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107void RelocInfo::set_target_address(Address target,
108 WriteBarrierMode write_barrier_mode,
109 ICacheFlushMode icache_flush_mode) {
110 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 Assembler::set_target_address_at(isolate_, pc_, host_, target,
112 icache_flush_mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000113 if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
114 host() != NULL && IsCodeTarget(rmode_)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100115 Object* target_code = Code::GetCodeFromTargetAddress(target);
116 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
117 host(), this, HeapObject::cast(target_code));
118 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000119}
120
Ben Murdochda12d292016-06-02 14:46:10 +0100121void RelocInfo::update_wasm_memory_reference(
122 Address old_base, Address new_base, size_t old_size, size_t new_size,
123 ICacheFlushMode icache_flush_mode) {
124 DCHECK(IsWasmMemoryReference(rmode_));
125 DCHECK(old_base <= wasm_memory_reference() &&
126 wasm_memory_reference() < old_base + old_size);
127 Address updated_reference = new_base + (wasm_memory_reference() - old_base);
128 DCHECK(new_base <= updated_reference &&
129 updated_reference < new_base + new_size);
130 Assembler::set_target_address_at(isolate_, pc_, host_, updated_reference,
131 icache_flush_mode);
132}
Steve Blocka7e24c12009-10-30 11:49:00 +0000133
134Object* RelocInfo::target_object() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
136 return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
Steve Block3ce2e202009-11-05 08:53:23 +0000137}
138
139
Steve Blockd0582a62009-12-15 09:54:21 +0000140Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
142 return Handle<Object>(reinterpret_cast<Object**>(
143 Assembler::target_address_at(pc_, host_)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000144}
145
146
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000147void RelocInfo::set_target_object(Object* target,
148 WriteBarrierMode write_barrier_mode,
149 ICacheFlushMode icache_flush_mode) {
150 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 Assembler::set_target_address_at(isolate_, pc_, host_,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000152 reinterpret_cast<Address>(target),
153 icache_flush_mode);
154 if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100155 host() != NULL &&
156 target->IsHeapObject()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100157 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
158 host(), this, HeapObject::cast(target));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100159 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000160}
161
162
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163Address RelocInfo::target_external_reference() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000164 DCHECK(rmode_ == EXTERNAL_REFERENCE);
165 return Assembler::target_address_at(pc_, host_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000166}
167
168
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000169Address RelocInfo::target_internal_reference() {
170 DCHECK(rmode_ == INTERNAL_REFERENCE);
171 return Memory::Address_at(pc_);
172}
173
174
175Address RelocInfo::target_internal_reference_address() {
176 DCHECK(rmode_ == INTERNAL_REFERENCE);
177 return reinterpret_cast<Address>(pc_);
178}
179
180
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000181Address RelocInfo::target_runtime_entry(Assembler* origin) {
182 DCHECK(IsRuntimeEntry(rmode_));
183 return target_address();
184}
185
186
187void RelocInfo::set_target_runtime_entry(Address target,
188 WriteBarrierMode write_barrier_mode,
189 ICacheFlushMode icache_flush_mode) {
190 DCHECK(IsRuntimeEntry(rmode_));
191 if (target_address() != target)
192 set_target_address(target, write_barrier_mode, icache_flush_mode);
193}
194
195
196Handle<Cell> RelocInfo::target_cell_handle() {
197 DCHECK(rmode_ == RelocInfo::CELL);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100198 Address address = Memory::Address_at(pc_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000199 return Handle<Cell>(reinterpret_cast<Cell**>(address));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100200}
201
202
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203Cell* RelocInfo::target_cell() {
204 DCHECK(rmode_ == RelocInfo::CELL);
205 return Cell::FromValueAddress(Memory::Address_at(pc_));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100206}
207
208
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209void RelocInfo::set_target_cell(Cell* cell,
210 WriteBarrierMode write_barrier_mode,
211 ICacheFlushMode icache_flush_mode) {
212 DCHECK(rmode_ == RelocInfo::CELL);
213 Address address = cell->address() + Cell::kValueOffset;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100214 Memory::Address_at(pc_) = address;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100216 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this,
217 cell);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100218 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100219}
220
221
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222static const int kNoCodeAgeSequenceLength = 3 * Assembler::kInstrSize;
223
224
225Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
226 UNREACHABLE(); // This should never be reached on Arm.
227 return Handle<Object>();
228}
229
230
231Code* RelocInfo::code_age_stub() {
232 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
233 return Code::GetCodeFromTargetAddress(
234 Memory::Address_at(pc_ +
235 (kNoCodeAgeSequenceLength - Assembler::kInstrSize)));
236}
237
238
239void RelocInfo::set_code_age_stub(Code* stub,
240 ICacheFlushMode icache_flush_mode) {
241 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
242 Memory::Address_at(pc_ +
243 (kNoCodeAgeSequenceLength - Assembler::kInstrSize)) =
244 stub->instruction_start();
245}
246
247
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000248Address RelocInfo::debug_call_address() {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100249 // The 2 instructions offset assumes patched debug break slot or return
250 // sequence.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
252 return Memory::Address_at(pc_ + Assembler::kPatchDebugBreakSlotAddressOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +0000253}
254
255
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256void RelocInfo::set_debug_call_address(Address target) {
257 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
258 Memory::Address_at(pc_ + Assembler::kPatchDebugBreakSlotAddressOffset) =
259 target;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100260 if (host() != NULL) {
261 Object* target_code = Code::GetCodeFromTargetAddress(target);
262 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
263 host(), this, HeapObject::cast(target_code));
264 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000265}
266
267
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000268void RelocInfo::WipeOut() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000269 DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
270 IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
271 IsInternalReference(rmode_));
272 if (IsInternalReference(rmode_)) {
273 Memory::Address_at(pc_) = NULL;
274 } else {
275 Assembler::set_target_address_at(isolate_, pc_, host_, NULL);
276 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000277}
278
279
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000280void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100281 RelocInfo::Mode mode = rmode();
282 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100283 visitor->VisitEmbeddedPointer(this);
Leon Clarkef7060e22010-06-03 12:02:55 +0100284 } else if (RelocInfo::IsCodeTarget(mode)) {
285 visitor->VisitCodeTarget(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000286 } else if (mode == RelocInfo::CELL) {
287 visitor->VisitCell(this);
Leon Clarkef7060e22010-06-03 12:02:55 +0100288 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100289 visitor->VisitExternalReference(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290 } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
291 visitor->VisitInternalReference(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000292 } else if (RelocInfo::IsCodeAgeSequence(mode)) {
293 visitor->VisitCodeAgeSequence(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294 } else if (RelocInfo::IsDebugBreakSlot(mode) &&
295 IsPatchedDebugBreakSlotSequence()) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100296 visitor->VisitDebugTarget(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000297 } else if (RelocInfo::IsRuntimeEntry(mode)) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100298 visitor->VisitRuntimeEntry(this);
299 }
300}
301
302
Iain Merrick75681382010-08-19 15:07:18 +0100303template<typename StaticVisitor>
Steve Block44f0eee2011-05-26 01:26:41 +0100304void RelocInfo::Visit(Heap* heap) {
Iain Merrick75681382010-08-19 15:07:18 +0100305 RelocInfo::Mode mode = rmode();
306 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100307 StaticVisitor::VisitEmbeddedPointer(heap, this);
Iain Merrick75681382010-08-19 15:07:18 +0100308 } else if (RelocInfo::IsCodeTarget(mode)) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100309 StaticVisitor::VisitCodeTarget(heap, this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000310 } else if (mode == RelocInfo::CELL) {
311 StaticVisitor::VisitCell(heap, this);
Iain Merrick75681382010-08-19 15:07:18 +0100312 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100313 StaticVisitor::VisitExternalReference(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314 } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
315 StaticVisitor::VisitInternalReference(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316 } else if (RelocInfo::IsCodeAgeSequence(mode)) {
317 StaticVisitor::VisitCodeAgeSequence(heap, this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 } else if (RelocInfo::IsDebugBreakSlot(mode) &&
319 IsPatchedDebugBreakSlotSequence()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100320 StaticVisitor::VisitDebugTarget(heap, this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000321 } else if (RelocInfo::IsRuntimeEntry(mode)) {
Iain Merrick75681382010-08-19 15:07:18 +0100322 StaticVisitor::VisitRuntimeEntry(this);
323 }
324}
325
326
Steve Blocka7e24c12009-10-30 11:49:00 +0000327Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) {
328 rm_ = no_reg;
329 imm32_ = immediate;
330 rmode_ = rmode;
331}
332
333
Steve Blocka7e24c12009-10-30 11:49:00 +0000334Operand::Operand(const ExternalReference& f) {
335 rm_ = no_reg;
336 imm32_ = reinterpret_cast<int32_t>(f.address());
337 rmode_ = RelocInfo::EXTERNAL_REFERENCE;
338}
339
340
Steve Blocka7e24c12009-10-30 11:49:00 +0000341Operand::Operand(Smi* value) {
342 rm_ = no_reg;
343 imm32_ = reinterpret_cast<intptr_t>(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344 rmode_ = RelocInfo::NONE32;
Steve Blocka7e24c12009-10-30 11:49:00 +0000345}
346
347
348Operand::Operand(Register rm) {
349 rm_ = rm;
350 rs_ = no_reg;
351 shift_op_ = LSL;
352 shift_imm_ = 0;
353}
354
355
356bool Operand::is_reg() const {
357 return rm_.is_valid() &&
358 rs_.is(no_reg) &&
359 shift_op_ == LSL &&
360 shift_imm_ == 0;
361}
362
363
364void Assembler::CheckBuffer() {
365 if (buffer_space() <= kGap) {
366 GrowBuffer();
367 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000368 MaybeCheckConstPool();
Steve Blocka7e24c12009-10-30 11:49:00 +0000369}
370
371
372void Assembler::emit(Instr x) {
373 CheckBuffer();
374 *reinterpret_cast<Instr*>(pc_) = x;
375 pc_ += kInstrSize;
376}
377
378
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000379Address Assembler::target_address_from_return_address(Address pc) {
380 // Returns the address of the call target from the return address that will
381 // be returned to after a call.
382 // Call sequence on V7 or later is:
383 // movw ip, #... @ call address low 16
384 // movt ip, #... @ call address high 16
385 // blx ip
386 // @ return address
387 // For V6 when the constant pool is unavailable, it is:
388 // mov ip, #... @ call address low 8
389 // orr ip, ip, #... @ call address 2nd 8
390 // orr ip, ip, #... @ call address 3rd 8
391 // orr ip, ip, #... @ call address high 8
392 // blx ip
393 // @ return address
394 // In cases that need frequent patching, the address is in the
395 // constant pool. It could be a small constant pool load:
396 // ldr ip, [pc / pp, #...] @ call address
397 // blx ip
398 // @ return address
399 // Or an extended constant pool load (ARMv7):
400 // movw ip, #...
401 // movt ip, #...
402 // ldr ip, [pc, ip] @ call address
403 // blx ip
404 // @ return address
405 // Or an extended constant pool load (ARMv6):
406 // mov ip, #...
407 // orr ip, ip, #...
408 // orr ip, ip, #...
409 // orr ip, ip, #...
410 // ldr ip, [pc, ip] @ call address
411 // blx ip
412 // @ return address
413 Address candidate = pc - 2 * Assembler::kInstrSize;
414 Instr candidate_instr(Memory::int32_at(candidate));
415 if (IsLdrPcImmediateOffset(candidate_instr) |
416 IsLdrPpImmediateOffset(candidate_instr)) {
417 return candidate;
418 } else {
419 if (IsLdrPpRegOffset(candidate_instr)) {
420 candidate -= Assembler::kInstrSize;
421 }
422 if (CpuFeatures::IsSupported(ARMv7)) {
423 candidate -= 1 * Assembler::kInstrSize;
424 DCHECK(IsMovW(Memory::int32_at(candidate)) &&
425 IsMovT(Memory::int32_at(candidate + Assembler::kInstrSize)));
426 } else {
427 candidate -= 3 * Assembler::kInstrSize;
428 DCHECK(
429 IsMovImmed(Memory::int32_at(candidate)) &&
430 IsOrrImmed(Memory::int32_at(candidate + Assembler::kInstrSize)) &&
431 IsOrrImmed(Memory::int32_at(candidate + 2 * Assembler::kInstrSize)) &&
432 IsOrrImmed(Memory::int32_at(candidate + 3 * Assembler::kInstrSize)));
433 }
434 return candidate;
Leon Clarkee46be812010-01-19 14:06:41 +0000435 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000436}
437
438
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439Address Assembler::return_address_from_call_start(Address pc) {
440 if (IsLdrPcImmediateOffset(Memory::int32_at(pc)) |
441 IsLdrPpImmediateOffset(Memory::int32_at(pc))) {
442 // Load from constant pool, small section.
443 return pc + kInstrSize * 2;
444 } else {
445 if (CpuFeatures::IsSupported(ARMv7)) {
446 DCHECK(IsMovW(Memory::int32_at(pc)));
447 DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
448 if (IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize))) {
449 // Load from constant pool, extended section.
450 return pc + kInstrSize * 4;
451 } else {
452 // A movw / movt load immediate.
453 return pc + kInstrSize * 3;
454 }
455 } else {
456 DCHECK(IsMovImmed(Memory::int32_at(pc)));
457 DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize)));
458 DCHECK(IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)));
459 DCHECK(IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
460 if (IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize))) {
461 // Load from constant pool, extended section.
462 return pc + kInstrSize * 6;
463 } else {
464 // A mov / orr load immediate.
465 return pc + kInstrSize * 5;
466 }
467 }
468 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000469}
470
471
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100472void Assembler::deserialization_set_special_target_at(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473 Isolate* isolate, Address constant_pool_entry, Code* code, Address target) {
474 if (FLAG_enable_embedded_constant_pool) {
475 set_target_address_at(isolate, constant_pool_entry, code, target);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 } else {
477 Memory::Address_at(constant_pool_entry) = target;
478 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100479}
480
481
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482void Assembler::deserialization_set_target_internal_reference_at(
483 Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) {
484 Memory::Address_at(pc) = target;
485}
486
487
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000488bool Assembler::is_constant_pool_load(Address pc) {
489 if (CpuFeatures::IsSupported(ARMv7)) {
490 return !Assembler::IsMovW(Memory::int32_at(pc)) ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000491 (FLAG_enable_embedded_constant_pool &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000492 Assembler::IsLdrPpRegOffset(
493 Memory::int32_at(pc + 2 * Assembler::kInstrSize)));
494 } else {
495 return !Assembler::IsMovImmed(Memory::int32_at(pc)) ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496 (FLAG_enable_embedded_constant_pool &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497 Assembler::IsLdrPpRegOffset(
498 Memory::int32_at(pc + 4 * Assembler::kInstrSize)));
499 }
Steve Blockd0582a62009-12-15 09:54:21 +0000500}
501
502
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000503Address Assembler::constant_pool_entry_address(Address pc,
504 Address constant_pool) {
505 if (FLAG_enable_embedded_constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000506 DCHECK(constant_pool != NULL);
507 int cp_offset;
508 if (!CpuFeatures::IsSupported(ARMv7) && IsMovImmed(Memory::int32_at(pc))) {
509 DCHECK(IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
510 IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
511 IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)) &&
512 IsLdrPpRegOffset(Memory::int32_at(pc + 4 * kInstrSize)));
513 // This is an extended constant pool lookup (ARMv6).
514 Instr mov_instr = instr_at(pc);
515 Instr orr_instr_1 = instr_at(pc + kInstrSize);
516 Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize);
517 Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize);
518 cp_offset = DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) |
519 DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3);
520 } else if (IsMovW(Memory::int32_at(pc))) {
521 DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)) &&
522 IsLdrPpRegOffset(Memory::int32_at(pc + 2 * kInstrSize)));
523 // This is an extended constant pool lookup (ARMv7).
524 Instruction* movw_instr = Instruction::At(pc);
525 Instruction* movt_instr = Instruction::At(pc + kInstrSize);
526 cp_offset = (movt_instr->ImmedMovwMovtValue() << 16) |
527 movw_instr->ImmedMovwMovtValue();
528 } else {
529 // This is a small constant pool lookup.
530 DCHECK(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(pc)));
531 cp_offset = GetLdrRegisterImmediateOffset(Memory::int32_at(pc));
532 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533 return constant_pool + cp_offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 } else {
535 DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(pc)));
536 Instr instr = Memory::int32_at(pc);
537 return pc + GetLdrRegisterImmediateOffset(instr) + kPcLoadDelta;
538 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000539}
540
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000541
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542Address Assembler::target_address_at(Address pc, Address constant_pool) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000543 if (is_constant_pool_load(pc)) {
544 // This is a constant pool lookup. Return the value in the constant pool.
545 return Memory::Address_at(constant_pool_entry_address(pc, constant_pool));
546 } else if (CpuFeatures::IsSupported(ARMv7)) {
547 // This is an movw / movt immediate load. Return the immediate.
548 DCHECK(IsMovW(Memory::int32_at(pc)) &&
549 IsMovT(Memory::int32_at(pc + kInstrSize)));
550 Instruction* movw_instr = Instruction::At(pc);
551 Instruction* movt_instr = Instruction::At(pc + kInstrSize);
552 return reinterpret_cast<Address>(
553 (movt_instr->ImmedMovwMovtValue() << 16) |
554 movw_instr->ImmedMovwMovtValue());
555 } else {
556 // This is an mov / orr immediate load. Return the immediate.
557 DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
558 IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
559 IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
560 IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
561 Instr mov_instr = instr_at(pc);
562 Instr orr_instr_1 = instr_at(pc + kInstrSize);
563 Instr orr_instr_2 = instr_at(pc + 2 * kInstrSize);
564 Instr orr_instr_3 = instr_at(pc + 3 * kInstrSize);
565 Address ret = reinterpret_cast<Address>(
566 DecodeShiftImm(mov_instr) | DecodeShiftImm(orr_instr_1) |
567 DecodeShiftImm(orr_instr_2) | DecodeShiftImm(orr_instr_3));
568 return ret;
569 }
570}
571
572
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573void Assembler::set_target_address_at(Isolate* isolate, Address pc,
574 Address constant_pool, Address target,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000575 ICacheFlushMode icache_flush_mode) {
576 if (is_constant_pool_load(pc)) {
577 // This is a constant pool lookup. Update the entry in the constant pool.
578 Memory::Address_at(constant_pool_entry_address(pc, constant_pool)) = target;
579 // Intuitively, we would think it is necessary to always flush the
580 // instruction cache after patching a target address in the code as follows:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000581 // Assembler::FlushICache(isolate, pc, sizeof(target));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582 // However, on ARM, no instruction is actually patched in the case
583 // of embedded constants of the form:
584 // ldr ip, [pp, #...]
585 // since the instruction accessing this address in the constant pool remains
586 // unchanged.
587 } else if (CpuFeatures::IsSupported(ARMv7)) {
588 // This is an movw / movt immediate load. Patch the immediate embedded in
589 // the instructions.
590 DCHECK(IsMovW(Memory::int32_at(pc)));
591 DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
592 uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
593 uint32_t immediate = reinterpret_cast<uint32_t>(target);
594 instr_ptr[0] = PatchMovwImmediate(instr_ptr[0], immediate & 0xFFFF);
595 instr_ptr[1] = PatchMovwImmediate(instr_ptr[1], immediate >> 16);
596 DCHECK(IsMovW(Memory::int32_at(pc)));
597 DCHECK(IsMovT(Memory::int32_at(pc + kInstrSize)));
598 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000599 Assembler::FlushICache(isolate, pc, 2 * kInstrSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000600 }
601 } else {
602 // This is an mov / orr immediate load. Patch the immediate embedded in
603 // the instructions.
604 DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
605 IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
606 IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
607 IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
608 uint32_t* instr_ptr = reinterpret_cast<uint32_t*>(pc);
609 uint32_t immediate = reinterpret_cast<uint32_t>(target);
610 instr_ptr[0] = PatchShiftImm(instr_ptr[0], immediate & kImm8Mask);
611 instr_ptr[1] = PatchShiftImm(instr_ptr[1], immediate & (kImm8Mask << 8));
612 instr_ptr[2] = PatchShiftImm(instr_ptr[2], immediate & (kImm8Mask << 16));
613 instr_ptr[3] = PatchShiftImm(instr_ptr[3], immediate & (kImm8Mask << 24));
614 DCHECK(IsMovImmed(Memory::int32_at(pc)) &&
615 IsOrrImmed(Memory::int32_at(pc + kInstrSize)) &&
616 IsOrrImmed(Memory::int32_at(pc + 2 * kInstrSize)) &&
617 IsOrrImmed(Memory::int32_at(pc + 3 * kInstrSize)));
618 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619 Assembler::FlushICache(isolate, pc, 4 * kInstrSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000620 }
621 }
622}
623
624
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000625} // namespace internal
626} // namespace v8
Steve Blocka7e24c12009-10-30 11:49:00 +0000627
628#endif // V8_ARM_ASSEMBLER_ARM_INL_H_