assembler-arm-inl.h revision 5d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0b
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 "arm/assembler-arm.h"
41
42#include "cpu.h"
43#include "debug.h"
44
45
46namespace v8 {
47namespace internal {
48
49
50int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) {
51  ASSERT(!reg.is(kDoubleRegZero));
52  ASSERT(!reg.is(kScratchDoubleReg));
53  return reg.code();
54}
55
56
57void RelocInfo::apply(intptr_t delta) {
58  if (RelocInfo::IsInternalReference(rmode_)) {
59    // absolute code pointer inside code object moves with the code object.
60    int32_t* p = reinterpret_cast<int32_t*>(pc_);
61    *p += delta;  // relocate entry
62  }
63  // We do not use pc relative addressing on ARM, so there is
64  // nothing else to do.
65}
66
67
68Address RelocInfo::target_address() {
69  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
70  return Assembler::target_address_at(pc_);
71}
72
73
74Address RelocInfo::target_address_address() {
75  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY
76                              || rmode_ == EMBEDDED_OBJECT
77                              || rmode_ == EXTERNAL_REFERENCE);
78  return reinterpret_cast<Address>(Assembler::target_address_address_at(pc_));
79}
80
81
82int RelocInfo::target_address_size() {
83  return kPointerSize;
84}
85
86
87void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) {
88  ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
89  Assembler::set_target_address_at(pc_, target);
90  if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) {
91    Object* target_code = Code::GetCodeFromTargetAddress(target);
92    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
93        host(), this, HeapObject::cast(target_code));
94  }
95}
96
97
98Object* RelocInfo::target_object() {
99  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
100  return Memory::Object_at(Assembler::target_address_address_at(pc_));
101}
102
103
104Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
105  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
106  return Memory::Object_Handle_at(Assembler::target_address_address_at(pc_));
107}
108
109
110Object** RelocInfo::target_object_address() {
111  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
112  return reinterpret_cast<Object**>(Assembler::target_address_address_at(pc_));
113}
114
115
116void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
117  ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
118  Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target));
119  if (mode == UPDATE_WRITE_BARRIER &&
120      host() != NULL &&
121      target->IsHeapObject()) {
122    host()->GetHeap()->incremental_marking()->RecordWrite(
123        host(), &Memory::Object_at(pc_), HeapObject::cast(target));
124  }
125}
126
127
128Address* RelocInfo::target_reference_address() {
129  ASSERT(rmode_ == EXTERNAL_REFERENCE);
130  return reinterpret_cast<Address*>(Assembler::target_address_address_at(pc_));
131}
132
133
134Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() {
135  ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
136  Address address = Memory::Address_at(pc_);
137  return Handle<JSGlobalPropertyCell>(
138      reinterpret_cast<JSGlobalPropertyCell**>(address));
139}
140
141
142JSGlobalPropertyCell* RelocInfo::target_cell() {
143  ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
144  Address address = Memory::Address_at(pc_);
145  Object* object = HeapObject::FromAddress(
146      address - JSGlobalPropertyCell::kValueOffset);
147  return reinterpret_cast<JSGlobalPropertyCell*>(object);
148}
149
150
151void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell,
152                                WriteBarrierMode mode) {
153  ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
154  Address address = cell->address() + JSGlobalPropertyCell::kValueOffset;
155  Memory::Address_at(pc_) = address;
156  if (mode == UPDATE_WRITE_BARRIER && host() != NULL) {
157    // TODO(1550) We are passing NULL as a slot because cell can never be on
158    // evacuation candidate.
159    host()->GetHeap()->incremental_marking()->RecordWrite(
160        host(), NULL, cell);
161  }
162}
163
164
165Address RelocInfo::call_address() {
166  // The 2 instructions offset assumes patched debug break slot or return
167  // sequence.
168  ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
169         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
170  return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize);
171}
172
173
174void RelocInfo::set_call_address(Address target) {
175  ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
176         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
177  Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target;
178  if (host() != NULL) {
179    Object* target_code = Code::GetCodeFromTargetAddress(target);
180    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
181        host(), this, HeapObject::cast(target_code));
182  }
183}
184
185
186Object* RelocInfo::call_object() {
187  return *call_object_address();
188}
189
190
191void RelocInfo::set_call_object(Object* target) {
192  *call_object_address() = target;
193}
194
195
196Object** RelocInfo::call_object_address() {
197  ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
198         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
199  return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
200}
201
202
203bool RelocInfo::IsPatchedReturnSequence() {
204  Instr current_instr = Assembler::instr_at(pc_);
205  Instr next_instr = Assembler::instr_at(pc_ + Assembler::kInstrSize);
206#ifdef USE_BLX
207  // A patched return sequence is:
208  //  ldr ip, [pc, #0]
209  //  blx ip
210  return ((current_instr & kLdrPCMask) == kLdrPCPattern)
211          && ((next_instr & kBlxRegMask) == kBlxRegPattern);
212#else
213  // A patched return sequence is:
214  //  mov lr, pc
215  //  ldr pc, [pc, #-4]
216  return (current_instr == kMovLrPc)
217          && ((next_instr & kLdrPCMask) == kLdrPCPattern);
218#endif
219}
220
221
222bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
223  Instr current_instr = Assembler::instr_at(pc_);
224  return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
225}
226
227
228void RelocInfo::Visit(ObjectVisitor* visitor) {
229  RelocInfo::Mode mode = rmode();
230  if (mode == RelocInfo::EMBEDDED_OBJECT) {
231    visitor->VisitEmbeddedPointer(this);
232  } else if (RelocInfo::IsCodeTarget(mode)) {
233    visitor->VisitCodeTarget(this);
234  } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
235    visitor->VisitGlobalPropertyCell(this);
236  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
237    visitor->VisitExternalReference(this);
238#ifdef ENABLE_DEBUGGER_SUPPORT
239  // TODO(isolates): Get a cached isolate below.
240  } else if (((RelocInfo::IsJSReturn(mode) &&
241              IsPatchedReturnSequence()) ||
242             (RelocInfo::IsDebugBreakSlot(mode) &&
243              IsPatchedDebugBreakSlotSequence())) &&
244             Isolate::Current()->debug()->has_break_points()) {
245    visitor->VisitDebugTarget(this);
246#endif
247  } else if (mode == RelocInfo::RUNTIME_ENTRY) {
248    visitor->VisitRuntimeEntry(this);
249  }
250}
251
252
253template<typename StaticVisitor>
254void RelocInfo::Visit(Heap* heap) {
255  RelocInfo::Mode mode = rmode();
256  if (mode == RelocInfo::EMBEDDED_OBJECT) {
257    StaticVisitor::VisitEmbeddedPointer(heap, this);
258  } else if (RelocInfo::IsCodeTarget(mode)) {
259    StaticVisitor::VisitCodeTarget(heap, this);
260  } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
261    StaticVisitor::VisitGlobalPropertyCell(heap, this);
262  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
263    StaticVisitor::VisitExternalReference(this);
264#ifdef ENABLE_DEBUGGER_SUPPORT
265  } else if (heap->isolate()->debug()->has_break_points() &&
266             ((RelocInfo::IsJSReturn(mode) &&
267              IsPatchedReturnSequence()) ||
268             (RelocInfo::IsDebugBreakSlot(mode) &&
269              IsPatchedDebugBreakSlotSequence()))) {
270    StaticVisitor::VisitDebugTarget(heap, this);
271#endif
272  } else if (mode == RelocInfo::RUNTIME_ENTRY) {
273    StaticVisitor::VisitRuntimeEntry(this);
274  }
275}
276
277
278Operand::Operand(int32_t immediate, RelocInfo::Mode rmode)  {
279  rm_ = no_reg;
280  imm32_ = immediate;
281  rmode_ = rmode;
282}
283
284
285Operand::Operand(const ExternalReference& f)  {
286  rm_ = no_reg;
287  imm32_ = reinterpret_cast<int32_t>(f.address());
288  rmode_ = RelocInfo::EXTERNAL_REFERENCE;
289}
290
291
292Operand::Operand(Smi* value) {
293  rm_ = no_reg;
294  imm32_ =  reinterpret_cast<intptr_t>(value);
295  rmode_ = RelocInfo::NONE;
296}
297
298
299Operand::Operand(Register rm) {
300  rm_ = rm;
301  rs_ = no_reg;
302  shift_op_ = LSL;
303  shift_imm_ = 0;
304}
305
306
307bool Operand::is_reg() const {
308  return rm_.is_valid() &&
309         rs_.is(no_reg) &&
310         shift_op_ == LSL &&
311         shift_imm_ == 0;
312}
313
314
315void Assembler::CheckBuffer() {
316  if (buffer_space() <= kGap) {
317    GrowBuffer();
318  }
319  if (pc_offset() >= next_buffer_check_) {
320    CheckConstPool(false, true);
321  }
322}
323
324
325void Assembler::emit(Instr x) {
326  CheckBuffer();
327  *reinterpret_cast<Instr*>(pc_) = x;
328  pc_ += kInstrSize;
329}
330
331
332Address Assembler::target_address_address_at(Address pc) {
333  Address target_pc = pc;
334  Instr instr = Memory::int32_at(target_pc);
335  // If we have a bx instruction, the instruction before the bx is
336  // what we need to patch.
337  static const int32_t kBxInstMask = 0x0ffffff0;
338  static const int32_t kBxInstPattern = 0x012fff10;
339  if ((instr & kBxInstMask) == kBxInstPattern) {
340    target_pc -= kInstrSize;
341    instr = Memory::int32_at(target_pc);
342  }
343
344#ifdef USE_BLX
345  // If we have a blx instruction, the instruction before it is
346  // what needs to be patched.
347  if ((instr & kBlxRegMask) == kBlxRegPattern) {
348    target_pc -= kInstrSize;
349    instr = Memory::int32_at(target_pc);
350  }
351#endif
352
353  ASSERT(IsLdrPcImmediateOffset(instr));
354  int offset = instr & 0xfff;  // offset_12 is unsigned
355  if ((instr & (1 << 23)) == 0) offset = -offset;  // U bit defines offset sign
356  // Verify that the constant pool comes after the instruction referencing it.
357  ASSERT(offset >= -4);
358  return target_pc + offset + 8;
359}
360
361
362Address Assembler::target_address_at(Address pc) {
363  return Memory::Address_at(target_address_address_at(pc));
364}
365
366
367void Assembler::deserialization_set_special_target_at(
368    Address constant_pool_entry, Address target) {
369  Memory::Address_at(constant_pool_entry) = target;
370}
371
372
373void Assembler::set_external_target_at(Address constant_pool_entry,
374                                       Address target) {
375  Memory::Address_at(constant_pool_entry) = target;
376}
377
378
379void Assembler::set_target_address_at(Address pc, Address target) {
380  Memory::Address_at(target_address_address_at(pc)) = target;
381  // Intuitively, we would think it is necessary to flush the instruction cache
382  // after patching a target address in the code as follows:
383  //   CPU::FlushICache(pc, sizeof(target));
384  // However, on ARM, no instruction was actually patched by the assignment
385  // above; the target address is not part of an instruction, it is patched in
386  // the constant pool and is read via a data access; the instruction accessing
387  // this address in the constant pool remains unchanged.
388}
389
390} }  // namespace v8::internal
391
392#endif  // V8_ARM_ASSEMBLER_ARM_INL_H_
393