assembler-mips-inl.h revision 85b71799222b55eb5dd74ea26efe0c64ab655c8c
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 2011 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#include "cpu.h" 41#include "debug.h" 42 43 44namespace v8 { 45namespace internal { 46 47// ----------------------------------------------------------------------------- 48// Operand and MemOperand. 49 50Operand::Operand(int32_t immediate, RelocInfo::Mode rmode) { 51 rm_ = no_reg; 52 imm32_ = immediate; 53 rmode_ = rmode; 54} 55 56 57Operand::Operand(const ExternalReference& f) { 58 rm_ = no_reg; 59 imm32_ = reinterpret_cast<int32_t>(f.address()); 60 rmode_ = RelocInfo::EXTERNAL_REFERENCE; 61} 62 63 64Operand::Operand(Smi* value) { 65 rm_ = no_reg; 66 imm32_ = reinterpret_cast<intptr_t>(value); 67 rmode_ = RelocInfo::NONE; 68} 69 70 71Operand::Operand(Register rm) { 72 rm_ = rm; 73} 74 75 76bool Operand::is_reg() const { 77 return rm_.is_valid(); 78} 79 80 81 82// ----------------------------------------------------------------------------- 83// RelocInfo. 84 85void RelocInfo::apply(intptr_t delta) { 86 if (IsCodeTarget(rmode_)) { 87 uint32_t scope1 = (uint32_t) target_address() & ~kImm28Mask; 88 uint32_t scope2 = reinterpret_cast<uint32_t>(pc_) & ~kImm28Mask; 89 90 if (scope1 != scope2) { 91 Assembler::JumpLabelToJumpRegister(pc_); 92 } 93 } 94 if (IsInternalReference(rmode_)) { 95 // Absolute code pointer inside code object moves with the code object. 96 byte* p = reinterpret_cast<byte*>(pc_); 97 int count = Assembler::RelocateInternalReference(p, delta); 98 CPU::FlushICache(p, count * sizeof(uint32_t)); 99 } 100} 101 102 103Address RelocInfo::target_address() { 104 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); 105 return Assembler::target_address_at(pc_); 106} 107 108 109Address RelocInfo::target_address_address() { 110 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); 111 return reinterpret_cast<Address>(pc_); 112} 113 114 115int RelocInfo::target_address_size() { 116 return Assembler::kExternalTargetSize; 117} 118 119 120void RelocInfo::set_target_address(Address target) { 121 ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); 122 Assembler::set_target_address_at(pc_, target); 123} 124 125 126Object* RelocInfo::target_object() { 127 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 128 return reinterpret_cast<Object*>(Assembler::target_address_at(pc_)); 129} 130 131 132Handle<Object> RelocInfo::target_object_handle(Assembler *origin) { 133 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 134 return Handle<Object>(reinterpret_cast<Object**>( 135 Assembler::target_address_at(pc_))); 136} 137 138 139Object** RelocInfo::target_object_address() { 140 // Provide a "natural pointer" to the embedded object, 141 // which can be de-referenced during heap iteration. 142 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 143 reconstructed_obj_ptr_ = 144 reinterpret_cast<Object*>(Assembler::target_address_at(pc_)); 145 return &reconstructed_obj_ptr_; 146} 147 148 149void RelocInfo::set_target_object(Object* target) { 150 ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 151 Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target)); 152} 153 154 155Address* RelocInfo::target_reference_address() { 156 ASSERT(rmode_ == EXTERNAL_REFERENCE); 157 reconstructed_adr_ptr_ = Assembler::target_address_at(pc_); 158 return &reconstructed_adr_ptr_; 159} 160 161 162Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() { 163 ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL); 164 Address address = Memory::Address_at(pc_); 165 return Handle<JSGlobalPropertyCell>( 166 reinterpret_cast<JSGlobalPropertyCell**>(address)); 167} 168 169 170JSGlobalPropertyCell* RelocInfo::target_cell() { 171 ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL); 172 Address address = Memory::Address_at(pc_); 173 Object* object = HeapObject::FromAddress( 174 address - JSGlobalPropertyCell::kValueOffset); 175 return reinterpret_cast<JSGlobalPropertyCell*>(object); 176} 177 178 179void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell) { 180 ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL); 181 Address address = cell->address() + JSGlobalPropertyCell::kValueOffset; 182 Memory::Address_at(pc_) = address; 183} 184 185 186Address RelocInfo::call_address() { 187 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || 188 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence())); 189 // The pc_ offset of 0 assumes mips patched return sequence per 190 // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or 191 // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot(). 192 return Assembler::target_address_at(pc_); 193} 194 195 196void RelocInfo::set_call_address(Address target) { 197 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || 198 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence())); 199 // The pc_ offset of 0 assumes mips patched return sequence per 200 // debug-mips.cc BreakLocationIterator::SetDebugBreakAtReturn(), or 201 // debug break slot per BreakLocationIterator::SetDebugBreakAtSlot(). 202 Assembler::set_target_address_at(pc_, target); 203} 204 205 206Object* RelocInfo::call_object() { 207 return *call_object_address(); 208} 209 210 211Object** RelocInfo::call_object_address() { 212 ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) || 213 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence())); 214 return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize); 215} 216 217 218void RelocInfo::set_call_object(Object* target) { 219 *call_object_address() = target; 220} 221 222 223bool RelocInfo::IsPatchedReturnSequence() { 224 Instr instr0 = Assembler::instr_at(pc_); 225 Instr instr1 = Assembler::instr_at(pc_ + 1 * Assembler::kInstrSize); 226 Instr instr2 = Assembler::instr_at(pc_ + 2 * Assembler::kInstrSize); 227 bool patched_return = ((instr0 & kOpcodeMask) == LUI && 228 (instr1 & kOpcodeMask) == ORI && 229 ((instr2 & kOpcodeMask) == JAL || 230 ((instr2 & kOpcodeMask) == SPECIAL && 231 (instr2 & kFunctionFieldMask) == JALR))); 232 return patched_return; 233} 234 235 236bool RelocInfo::IsPatchedDebugBreakSlotSequence() { 237 Instr current_instr = Assembler::instr_at(pc_); 238 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); 239} 240 241 242void RelocInfo::Visit(ObjectVisitor* visitor) { 243 RelocInfo::Mode mode = rmode(); 244 if (mode == RelocInfo::EMBEDDED_OBJECT) { 245 Object** p = target_object_address(); 246 Object* orig = *p; 247 visitor->VisitPointer(p); 248 if (*p != orig) { 249 set_target_object(*p); 250 } 251 } else if (RelocInfo::IsCodeTarget(mode)) { 252 visitor->VisitCodeTarget(this); 253 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) { 254 visitor->VisitGlobalPropertyCell(this); 255 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { 256 visitor->VisitExternalReference(target_reference_address()); 257#ifdef ENABLE_DEBUGGER_SUPPORT 258 // TODO(isolates): Get a cached isolate below. 259 } else if (((RelocInfo::IsJSReturn(mode) && 260 IsPatchedReturnSequence()) || 261 (RelocInfo::IsDebugBreakSlot(mode) && 262 IsPatchedDebugBreakSlotSequence())) && 263 Isolate::Current()->debug()->has_break_points()) { 264 visitor->VisitDebugTarget(this); 265#endif 266 } else if (mode == RelocInfo::RUNTIME_ENTRY) { 267 visitor->VisitRuntimeEntry(this); 268 } 269} 270 271 272template<typename StaticVisitor> 273void RelocInfo::Visit(Heap* heap) { 274 RelocInfo::Mode mode = rmode(); 275 if (mode == RelocInfo::EMBEDDED_OBJECT) { 276 StaticVisitor::VisitPointer(heap, target_object_address()); 277 } else if (RelocInfo::IsCodeTarget(mode)) { 278 StaticVisitor::VisitCodeTarget(heap, this); 279 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) { 280 StaticVisitor::VisitGlobalPropertyCell(heap, this); 281 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { 282 StaticVisitor::VisitExternalReference(target_reference_address()); 283#ifdef ENABLE_DEBUGGER_SUPPORT 284 } else if (heap->isolate()->debug()->has_break_points() && 285 ((RelocInfo::IsJSReturn(mode) && 286 IsPatchedReturnSequence()) || 287 (RelocInfo::IsDebugBreakSlot(mode) && 288 IsPatchedDebugBreakSlotSequence()))) { 289 StaticVisitor::VisitDebugTarget(heap, this); 290#endif 291 } else if (mode == RelocInfo::RUNTIME_ENTRY) { 292 StaticVisitor::VisitRuntimeEntry(this); 293 } 294} 295 296 297// ----------------------------------------------------------------------------- 298// Assembler. 299 300 301void Assembler::CheckBuffer() { 302 if (buffer_space() <= kGap) { 303 GrowBuffer(); 304 } 305} 306 307 308void Assembler::CheckTrampolinePoolQuick() { 309 if (pc_offset() >= next_buffer_check_) { 310 CheckTrampolinePool(); 311 } 312} 313 314 315void Assembler::emit(Instr x) { 316 if (!is_buffer_growth_blocked()) { 317 CheckBuffer(); 318 } 319 *reinterpret_cast<Instr*>(pc_) = x; 320 pc_ += kInstrSize; 321 CheckTrampolinePoolQuick(); 322} 323 324 325} } // namespace v8::internal 326 327#endif // V8_MIPS_ASSEMBLER_MIPS_INL_H_ 328