blob: 8ca91265ba2338c0aa97ca6982607ae213b1e453 [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.
35// Copyright 2006-2008 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 "arm/assembler-arm.h"
41#include "cpu.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010042#include "debug.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000043
44
45namespace v8 {
46namespace internal {
47
48Condition NegateCondition(Condition cc) {
49 ASSERT(cc != al);
50 return static_cast<Condition>(cc ^ ne);
51}
52
53
54void RelocInfo::apply(intptr_t delta) {
55 if (RelocInfo::IsInternalReference(rmode_)) {
56 // absolute code pointer inside code object moves with the code object.
57 int32_t* p = reinterpret_cast<int32_t*>(pc_);
58 *p += delta; // relocate entry
59 }
60 // We do not use pc relative addressing on ARM, so there is
61 // nothing else to do.
62}
63
64
65Address RelocInfo::target_address() {
66 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
67 return Assembler::target_address_at(pc_);
68}
69
70
71Address RelocInfo::target_address_address() {
72 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
73 return reinterpret_cast<Address>(Assembler::target_address_address_at(pc_));
74}
75
76
Leon Clarkef7060e22010-06-03 12:02:55 +010077int RelocInfo::target_address_size() {
78 return Assembler::kExternalTargetSize;
79}
80
81
Steve Blocka7e24c12009-10-30 11:49:00 +000082void RelocInfo::set_target_address(Address target) {
83 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
84 Assembler::set_target_address_at(pc_, target);
85}
86
87
88Object* RelocInfo::target_object() {
89 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
Steve Block3ce2e202009-11-05 08:53:23 +000090 return Memory::Object_at(Assembler::target_address_address_at(pc_));
91}
92
93
Steve Blockd0582a62009-12-15 09:54:21 +000094Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
Steve Block3ce2e202009-11-05 08:53:23 +000095 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
96 return Memory::Object_Handle_at(Assembler::target_address_address_at(pc_));
Steve Blocka7e24c12009-10-30 11:49:00 +000097}
98
99
100Object** RelocInfo::target_object_address() {
101 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
102 return reinterpret_cast<Object**>(Assembler::target_address_address_at(pc_));
103}
104
105
106void RelocInfo::set_target_object(Object* target) {
107 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
108 Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target));
109}
110
111
112Address* RelocInfo::target_reference_address() {
113 ASSERT(rmode_ == EXTERNAL_REFERENCE);
114 return reinterpret_cast<Address*>(Assembler::target_address_address_at(pc_));
115}
116
117
118Address RelocInfo::call_address() {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100119 // The 2 instructions offset assumes patched debug break slot or return
120 // sequence.
121 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
122 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000123 return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize);
124}
125
126
127void RelocInfo::set_call_address(Address target) {
Steve Block3ce2e202009-11-05 08:53:23 +0000128 ASSERT(IsPatchedReturnSequence());
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 // The 2 instructions offset assumes patched return sequence.
130 ASSERT(IsJSReturn(rmode()));
131 Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target;
132}
133
134
135Object* RelocInfo::call_object() {
136 return *call_object_address();
137}
138
139
140Object** RelocInfo::call_object_address() {
Steve Block3ce2e202009-11-05 08:53:23 +0000141 ASSERT(IsPatchedReturnSequence());
Steve Blocka7e24c12009-10-30 11:49:00 +0000142 // The 2 instructions offset assumes patched return sequence.
143 ASSERT(IsJSReturn(rmode()));
144 return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
145}
146
147
148void RelocInfo::set_call_object(Object* target) {
149 *call_object_address() = target;
150}
151
152
Steve Block3ce2e202009-11-05 08:53:23 +0000153bool RelocInfo::IsPatchedReturnSequence() {
Steve Block6ded16b2010-05-10 14:33:55 +0100154 Instr current_instr = Assembler::instr_at(pc_);
155 Instr next_instr = Assembler::instr_at(pc_ + Assembler::kInstrSize);
156#ifdef USE_BLX
157 // A patched return sequence is:
158 // ldr ip, [pc, #0]
159 // blx ip
160 return ((current_instr & kLdrPCMask) == kLdrPCPattern)
161 && ((next_instr & kBlxRegMask) == kBlxRegPattern);
162#else
163 // A patched return sequence is:
164 // mov lr, pc
165 // ldr pc, [pc, #-4]
166 return (current_instr == kMovLrPc)
167 && ((next_instr & kLdrPCMask) == kLdrPCPattern);
168#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000169}
170
171
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100172bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
173 Instr current_instr = Assembler::instr_at(pc_);
174 return !Assembler::IsNop(current_instr, 2);
175}
176
177
Leon Clarkef7060e22010-06-03 12:02:55 +0100178void RelocInfo::Visit(ObjectVisitor* visitor) {
179 RelocInfo::Mode mode = rmode();
180 if (mode == RelocInfo::EMBEDDED_OBJECT) {
181 visitor->VisitPointer(target_object_address());
182 } else if (RelocInfo::IsCodeTarget(mode)) {
183 visitor->VisitCodeTarget(this);
184 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
185 visitor->VisitExternalReference(target_reference_address());
186#ifdef ENABLE_DEBUGGER_SUPPORT
187 } else if (Debug::has_break_points() &&
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100188 ((RelocInfo::IsJSReturn(mode) &&
189 IsPatchedReturnSequence()) ||
190 (RelocInfo::IsDebugBreakSlot(mode) &&
191 IsPatchedDebugBreakSlotSequence()))) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100192 visitor->VisitDebugTarget(this);
193#endif
194 } else if (mode == RelocInfo::RUNTIME_ENTRY) {
195 visitor->VisitRuntimeEntry(this);
196 }
197}
198
199
Steve Blocka7e24c12009-10-30 11:49:00 +0000200Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) {
201 rm_ = no_reg;
202 imm32_ = immediate;
203 rmode_ = rmode;
204}
205
206
Steve Blocka7e24c12009-10-30 11:49:00 +0000207Operand::Operand(const ExternalReference& f) {
208 rm_ = no_reg;
209 imm32_ = reinterpret_cast<int32_t>(f.address());
210 rmode_ = RelocInfo::EXTERNAL_REFERENCE;
211}
212
213
Steve Blocka7e24c12009-10-30 11:49:00 +0000214Operand::Operand(Smi* value) {
215 rm_ = no_reg;
216 imm32_ = reinterpret_cast<intptr_t>(value);
217 rmode_ = RelocInfo::NONE;
218}
219
220
221Operand::Operand(Register rm) {
222 rm_ = rm;
223 rs_ = no_reg;
224 shift_op_ = LSL;
225 shift_imm_ = 0;
226}
227
228
229bool Operand::is_reg() const {
230 return rm_.is_valid() &&
231 rs_.is(no_reg) &&
232 shift_op_ == LSL &&
233 shift_imm_ == 0;
234}
235
236
237void Assembler::CheckBuffer() {
238 if (buffer_space() <= kGap) {
239 GrowBuffer();
240 }
241 if (pc_offset() >= next_buffer_check_) {
242 CheckConstPool(false, true);
243 }
244}
245
246
247void Assembler::emit(Instr x) {
248 CheckBuffer();
249 *reinterpret_cast<Instr*>(pc_) = x;
250 pc_ += kInstrSize;
251}
252
253
254Address Assembler::target_address_address_at(Address pc) {
Leon Clarkee46be812010-01-19 14:06:41 +0000255 Address target_pc = pc;
256 Instr instr = Memory::int32_at(target_pc);
257 // If we have a bx instruction, the instruction before the bx is
258 // what we need to patch.
259 static const int32_t kBxInstMask = 0x0ffffff0;
260 static const int32_t kBxInstPattern = 0x012fff10;
261 if ((instr & kBxInstMask) == kBxInstPattern) {
262 target_pc -= kInstrSize;
263 instr = Memory::int32_at(target_pc);
264 }
Steve Block6ded16b2010-05-10 14:33:55 +0100265
266#ifdef USE_BLX
267 // If we have a blx instruction, the instruction before it is
268 // what needs to be patched.
269 if ((instr & kBlxRegMask) == kBlxRegPattern) {
270 target_pc -= kInstrSize;
271 instr = Memory::int32_at(target_pc);
272 }
273#endif
274
Leon Clarkee46be812010-01-19 14:06:41 +0000275 // Verify that the instruction to patch is a
276 // ldr<cond> <Rd>, [pc +/- offset_12].
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 ASSERT((instr & 0x0f7f0000) == 0x051f0000);
278 int offset = instr & 0xfff; // offset_12 is unsigned
279 if ((instr & (1 << 23)) == 0) offset = -offset; // U bit defines offset sign
280 // Verify that the constant pool comes after the instruction referencing it.
281 ASSERT(offset >= -4);
Leon Clarkee46be812010-01-19 14:06:41 +0000282 return target_pc + offset + 8;
Steve Blocka7e24c12009-10-30 11:49:00 +0000283}
284
285
286Address Assembler::target_address_at(Address pc) {
287 return Memory::Address_at(target_address_address_at(pc));
288}
289
290
Steve Blockd0582a62009-12-15 09:54:21 +0000291void Assembler::set_target_at(Address constant_pool_entry,
292 Address target) {
293 Memory::Address_at(constant_pool_entry) = target;
294}
295
296
Steve Blocka7e24c12009-10-30 11:49:00 +0000297void Assembler::set_target_address_at(Address pc, Address target) {
298 Memory::Address_at(target_address_address_at(pc)) = target;
299 // Intuitively, we would think it is necessary to flush the instruction cache
300 // after patching a target address in the code as follows:
301 // CPU::FlushICache(pc, sizeof(target));
302 // However, on ARM, no instruction was actually patched by the assignment
303 // above; the target address is not part of an instruction, it is patched in
304 // the constant pool and is read via a data access; the instruction accessing
305 // this address in the constant pool remains unchanged.
306}
307
308} } // namespace v8::internal
309
310#endif // V8_ARM_ASSEMBLER_ARM_INL_H_