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 are 6 // 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 distribution. 14 // 15 // - Neither the name of Sun Microsystems or the names of contributors may 16 // be used to endorse or promote products derived from this software without 17 // specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 // The original source code covered by the above license above has been 32 // modified significantly by Google Inc. 33 // Copyright 2012 the V8 project authors. All rights reserved. 34 35 36 #ifndef V8_MIPS_ASSEMBLER_MIPS_INL_H_ 37 #define V8_MIPS_ASSEMBLER_MIPS_INL_H_ 38 39 #include "mips/assembler-mips.h" 40 41 #include "cpu.h" 42 #include "debug.h" 43 44 45 namespace v8 { 46 namespace internal { 47 48 // ----------------------------------------------------------------------------- 49 // Operand and MemOperand. 50 51 Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) { 52 rm_ = no_reg; 53 imm32_ = immediate; 54 rmode_ = rmode; 55 } 56 57 58 Operand::Operand(const ExternalReference& f) { 59 rm_ = no_reg; 60 imm32_ = reinterpret_cast<int32_t>(f.address()); 61 rmode_ = RelocInfo::EXTERNAL_REFERENCE; 62 } 63 64 65 Operand::Operand(Smi* value) { 66 rm_ = no_reg; 67 imm32_ = reinterpret_cast<intptr_t>(value); 68 rmode_ = RelocInfo::NONE; 69 } 70 71 72 Operand::Operand(Register rm) { 73 rm_ = rm; 74 } 75 76 77 bool Operand::is_reg() const { 78 return rm_.is_valid(); 79 } 80 81 82 int FPURegister::ToAllocationIndex(FPURegister reg) { 83 ASSERT(reg.code() % 2 == 0); 84 ASSERT(reg.code() / 2 < kNumAllocatableRegisters); 85 ASSERT(reg.is_valid()); 86 ASSERT(!reg.is(kDoubleRegZero)); 87 ASSERT(!reg.is(kLithiumScratchDouble)); 88 return (reg.code() / 2); 89 } 90 91 92 // ----------------------------------------------------------------------------- 93 // RelocInfo. 94 95 void RelocInfo::apply(intptr_t delta) { 96 if (IsCodeTarget(rmode_)) { 97 uint32_t scope1 = (uint32_t) target_address() & ~kImm28Mask; 98 uint32_t scope2 = reinterpret_cast<uint32_t>(pc_) & ~kImm28Mask; 99 100 if (scope1 != scope2) { 101 Assembler::JumpLabelToJumpRegister(pc_); 102 } 103 } 104 if (IsInternalReference(rmode_)) { 105 // Absolute code pointer inside code object moves with the code object. 106 byte* p = reinterpret_cast<byte*>(pc_); 107 int count = Assembler::RelocateInternalReference(p, delta); 108 CPU::FlushICache(p, count * sizeof(uint32_t)); 109 } 110 } 111 112 113 Address RelocInfo::target_address() { 114 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); 115 return Assembler::target_address_at(pc_); 116 } 117 118 119 Address RelocInfo::target_address_address() { 120 ASSERT(IsCodeTarget(rmode_) || 121 rmode_ == RUNTIME_ENTRY || 122 rmode_ == EMBEDDED_OBJECT || 123 rmode_ == EXTERNAL_REFERENCE); 124 // Read the address of the word containing the target_address in an 125 // instruction stream. 126 // The only architecture-independent user of this function is the serializer. 127 // The serializer uses it to find out how many raw bytes of instruction to 128 // output before the next target. 129 // For an instruction like LUI/ORI where the target bits are mixed into the 130 // instruction bits, the size of the target will be zero, indicating that the 131 // serializer should not step forward in memory after a target is resolved 132 // and written. In this case the target_address_address function should 133 // return the end of the instructions to be patched, allowing the 134 // deserializer to deserialize the instructions as raw bytes and put them in 135 // place, ready to be patched with the target. After jump optimization, 136 // that is the address of the instruction that follows J/JAL/JR/JALR 137 // instruction. 138 return reinterpret_cast<Address>( 139 pc_ + Assembler::kInstructionsFor32BitConstant * Assembler::kInstrSize); 140 } 141 142 143 int RelocInfo::target_address_size() { 144 return Assembler::kSpecialTargetSize; 145 } 146 147 148 void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) { 149 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); 150 Assembler::set_target_address_at(pc_, target); 151 if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) { 152 Object* target_code = Code::GetCodeFromTargetAddress(target); 153 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( 154 host(), this, HeapObject::cast(target_code)); 155 } 156 } 157 158 159 Object* RelocInfo::target_object() { 160 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 161 return reinterpret_cast<Object*>(Assembler::target_address_at(pc_)); 162 } 163 164 165 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) { 166 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 167 return Handle<Object>(reinterpret_cast<Object**>( 168 Assembler::target_address_at(pc_))); 169 } 170 171 172 Object** RelocInfo::target_object_address() { 173 // Provide a "natural pointer" to the embedded object, 174 // which can be de-referenced during heap iteration. 175 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 176 reconstructed_obj_ptr_ = 177 reinterpret_cast<Object*>(Assembler::target_address_at(pc_)); 178 return &reconstructed_obj_ptr_; 179 } 180 181 182 void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) { 183 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 184 Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target)); 185 if (mode == UPDATE_WRITE_BARRIER && 186 host() != NULL && 187 target->IsHeapObject()) { 188 host()->GetHeap()->incremental_marking()->RecordWrite( 189 host(), &Memory::Object_at(pc_), HeapObject::cast(target)); 190 } 191 } 192 193 194 Address* RelocInfo::target_reference_address() { 195 ASSERT(rmode_ == EXTERNAL_REFERENCE); 196 reconstructed_adr_ptr_ = Assembler::target_address_at(pc_); 197 return &reconstructed_adr_ptr_; 198 } 199 200 201 Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() { 202 ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL); 203 Address address = Memory::Address_at(pc_); 204 return Handle<JSGlobalPropertyCell>( 205 reinterpret_cast<JSGlobalPropertyCell**>(address)); 206 } 207 208 209 JSGlobalPropertyCell* RelocInfo::target_cell() { 210 ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL); 211 Address address = Memory::Address_at(pc_); 212 Object* object = HeapObject::FromAddress( 213 address - JSGlobalPropertyCell::kValueOffset); 214 return reinterpret_cast<JSGlobalPropertyCell*>(object); 215 } 216 217 218 void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell, 219 WriteBarrierMode mode) { 220 ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL); 221 Address address = cell->address() + JSGlobalPropertyCell::kValueOffset; 222 Memory::Address_at(pc_) = address; 223 if (mode == UPDATE_WRITE_BARRIER && host() != NULL) { 224 // TODO(1550) We are passing NULL as a slot because cell can never be on 225 // evacuation candidate. 226 host()->GetHeap()->incremental_marking()->RecordWrite( 227 host(), NULL, cell); 228 } 229 } 230 231 232 Address RelocInfo::call_address() { 233 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || 234 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence())); 235 // The pc_ offset of 0 assumes mips patched return sequence per 236 // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or 237 // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot(). 238 return Assembler::target_address_at(pc_); 239 } 240 241 242 void RelocInfo::set_call_address(Address target) { 243 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || 244 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence())); 245 // The pc_ offset of 0 assumes mips patched return sequence per 246 // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or 247 // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot(). 248 Assembler::set_target_address_at(pc_, target); 249 if (host() != NULL) { 250 Object* target_code = Code::GetCodeFromTargetAddress(target); 251 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( 252 host(), this, HeapObject::cast(target_code)); 253 } 254 } 255 256 257 Object* RelocInfo::call_object() { 258 return *call_object_address(); 259 } 260 261 262 Object** RelocInfo::call_object_address() { 263 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || 264 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence())); 265 return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize); 266 } 267 268 269 void RelocInfo::set_call_object(Object* target) { 270 *call_object_address() = target; 271 } 272 273 274 bool RelocInfo::IsPatchedReturnSequence() { 275 Instr instr0 = Assembler::instr_at(pc_); 276 Instr instr1 = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize); 277 Instr instr2 = Assembler::instr_at(pc_ + 2 * Assembler::kInstrSize); 278 bool patched_return = ((instr0 & kOpcodeMask) == LUI && 279 (instr1 & kOpcodeMask) == ORI && 280 ((instr2 & kOpcodeMask) == JAL || 281 ((instr2 & kOpcodeMask) == SPECIAL && 282 (instr2 & kFunctionFieldMask) == JALR))); 283 return patched_return; 284 } 285 286 287 bool RelocInfo::IsPatchedDebugBreakSlotSequence() { 288 Instr current_instr = Assembler::instr_at(pc_); 289 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); 290 } 291 292 293 void RelocInfo::Visit(ObjectVisitor* visitor) { 294 RelocInfo::Mode mode = rmode(); 295 if (mode == RelocInfo::EMBEDDED_OBJECT) { 296 visitor->VisitEmbeddedPointer(this); 297 } else if (RelocInfo::IsCodeTarget(mode)) { 298 visitor->VisitCodeTarget(this); 299 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) { 300 visitor->VisitGlobalPropertyCell(this); 301 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { 302 visitor->VisitExternalReference(this); 303 #ifdef ENABLE_DEBUGGER_SUPPORT 304 // TODO(isolates): Get a cached isolate below. 305 } else if (((RelocInfo::IsJSReturn(mode) && 306 IsPatchedReturnSequence()) || 307 (RelocInfo::IsDebugBreakSlot(mode) && 308 IsPatchedDebugBreakSlotSequence())) && 309 Isolate::Current()->debug()->has_break_points()) { 310 visitor->VisitDebugTarget(this); 311 #endif 312 } else if (mode == RelocInfo::RUNTIME_ENTRY) { 313 visitor->VisitRuntimeEntry(this); 314 } 315 } 316 317 318 template<typename StaticVisitor> 319 void RelocInfo::Visit(Heap* heap) { 320 RelocInfo::Mode mode = rmode(); 321 if (mode == RelocInfo::EMBEDDED_OBJECT) { 322 StaticVisitor::VisitEmbeddedPointer(heap, this); 323 } else if (RelocInfo::IsCodeTarget(mode)) { 324 StaticVisitor::VisitCodeTarget(heap, this); 325 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) { 326 StaticVisitor::VisitGlobalPropertyCell(heap, this); 327 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { 328 StaticVisitor::VisitExternalReference(this); 329 #ifdef ENABLE_DEBUGGER_SUPPORT 330 } else if (heap->isolate()->debug()->has_break_points() && 331 ((RelocInfo::IsJSReturn(mode) && 332 IsPatchedReturnSequence()) || 333 (RelocInfo::IsDebugBreakSlot(mode) && 334 IsPatchedDebugBreakSlotSequence()))) { 335 StaticVisitor::VisitDebugTarget(heap, this); 336 #endif 337 } else if (mode == RelocInfo::RUNTIME_ENTRY) { 338 StaticVisitor::VisitRuntimeEntry(this); 339 } 340 } 341 342 343 // ----------------------------------------------------------------------------- 344 // Assembler. 345 346 347 void Assembler::CheckBuffer() { 348 if (buffer_space() <= kGap) { 349 GrowBuffer(); 350 } 351 } 352 353 354 void Assembler::CheckTrampolinePoolQuick() { 355 if (pc_offset() >= next_buffer_check_) { 356 CheckTrampolinePool(); 357 } 358 } 359 360 361 void Assembler::emit(Instr x) { 362 if (!is_buffer_growth_blocked()) { 363 CheckBuffer(); 364 } 365 *reinterpret_cast<Instr*>(pc_) = x; 366 pc_ += kInstrSize; 367 CheckTrampolinePoolQuick(); 368 } 369 370 371 } } // namespace v8::internal 372 373 #endif // V8_MIPS_ASSEMBLER_MIPS_INL_H_ 374