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 46 namespace v8 { 47 namespace internal { 48 49 50 int DwVfpRegister::ToAllocationIndex(DwVfpRegister reg) { 51 ASSERT(!reg.is(kDoubleRegZero)); 52 ASSERT(!reg.is(kScratchDoubleReg)); 53 return reg.code(); 54 } 55 56 57 void 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 68 Address RelocInfo::target_address() { 69 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); 70 return Assembler::target_address_at(pc_); 71 } 72 73 74 Address 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 82 int RelocInfo::target_address_size() { 83 return kPointerSize; 84 } 85 86 87 void 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 98 Object* RelocInfo::target_object() { 99 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 100 return Memory::Object_at(Assembler::target_address_address_at(pc_)); 101 } 102 103 104 Handle<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 110 Object** 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 116 void 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 128 Address* RelocInfo::target_reference_address() { 129 ASSERT(rmode_ == EXTERNAL_REFERENCE); 130 return reinterpret_cast<Address*>(Assembler::target_address_address_at(pc_)); 131 } 132 133 134 Handle<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 142 JSGlobalPropertyCell* 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 151 void 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 165 Address 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 174 void 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 186 Object* RelocInfo::call_object() { 187 return *call_object_address(); 188 } 189 190 191 void RelocInfo::set_call_object(Object* target) { 192 *call_object_address() = target; 193 } 194 195 196 Object** 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 203 bool 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 222 bool RelocInfo::IsPatchedDebugBreakSlotSequence() { 223 Instr current_instr = Assembler::instr_at(pc_); 224 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); 225 } 226 227 228 void 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 253 template<typename StaticVisitor> 254 void 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 278 Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) { 279 rm_ = no_reg; 280 imm32_ = immediate; 281 rmode_ = rmode; 282 } 283 284 285 Operand::Operand(const ExternalReference& f) { 286 rm_ = no_reg; 287 imm32_ = reinterpret_cast<int32_t>(f.address()); 288 rmode_ = RelocInfo::EXTERNAL_REFERENCE; 289 } 290 291 292 Operand::Operand(Smi* value) { 293 rm_ = no_reg; 294 imm32_ = reinterpret_cast<intptr_t>(value); 295 rmode_ = RelocInfo::NONE; 296 } 297 298 299 Operand::Operand(Register rm) { 300 rm_ = rm; 301 rs_ = no_reg; 302 shift_op_ = LSL; 303 shift_imm_ = 0; 304 } 305 306 307 bool 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 315 void 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 325 void Assembler::emit(Instr x) { 326 CheckBuffer(); 327 *reinterpret_cast<Instr*>(pc_) = x; 328 pc_ += kInstrSize; 329 } 330 331 332 Address 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 362 Address Assembler::target_address_at(Address pc) { 363 return Memory::Address_at(target_address_address_at(pc)); 364 } 365 366 367 void Assembler::deserialization_set_special_target_at( 368 Address constant_pool_entry, Address target) { 369 Memory::Address_at(constant_pool_entry) = target; 370 } 371 372 373 void Assembler::set_external_target_at(Address constant_pool_entry, 374 Address target) { 375 Memory::Address_at(constant_pool_entry) = target; 376 } 377 378 379 void 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