1 2 // Copyright (c) 1994-2006 Sun Microsystems Inc. 3 // All Rights Reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // - Redistributions of source code must retain the above copyright notice, 10 // this list of conditions and the following disclaimer. 11 // 12 // - Redistribution in binary form must reproduce the above copyright 13 // notice, this list of conditions and the following disclaimer in the 14 // documentation and/or other materials provided with the 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 "AS 21 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32 // The original source code covered by the above license above has been 33 // modified significantly by Google Inc. 34 // Copyright 2012 the V8 project authors. All rights reserved. 35 36 #ifndef V8_MIPS64_ASSEMBLER_MIPS64_INL_H_ 37 #define V8_MIPS64_ASSEMBLER_MIPS64_INL_H_ 38 39 #include "src/mips64/assembler-mips64.h" 40 41 #include "src/assembler.h" 42 #include "src/debug/debug.h" 43 #include "src/objects-inl.h" 44 45 namespace v8 { 46 namespace internal { 47 48 bool CpuFeatures::SupportsOptimizer() { return IsSupported(FPU); } 49 50 bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(MIPS_SIMD); } 51 52 // ----------------------------------------------------------------------------- 53 // Operand and MemOperand. 54 55 bool Operand::is_reg() const { 56 return rm_.is_valid(); 57 } 58 59 int64_t Operand::immediate() const { 60 DCHECK(!is_reg()); 61 DCHECK(!IsHeapObjectRequest()); 62 return value_.immediate; 63 } 64 65 // ----------------------------------------------------------------------------- 66 // RelocInfo. 67 68 void RelocInfo::apply(intptr_t delta) { 69 if (IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)) { 70 // Absolute code pointer inside code object moves with the code object. 71 Assembler::RelocateInternalReference(rmode_, pc_, delta); 72 } 73 } 74 75 76 Address RelocInfo::target_address() { 77 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_)); 78 return Assembler::target_address_at(pc_, constant_pool_); 79 } 80 81 Address RelocInfo::target_address_address() { 82 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) || 83 IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) || 84 IsOffHeapTarget(rmode_)); 85 // Read the address of the word containing the target_address in an 86 // instruction stream. 87 // The only architecture-independent user of this function is the serializer. 88 // The serializer uses it to find out how many raw bytes of instruction to 89 // output before the next target. 90 // For an instruction like LUI/ORI where the target bits are mixed into the 91 // instruction bits, the size of the target will be zero, indicating that the 92 // serializer should not step forward in memory after a target is resolved 93 // and written. In this case the target_address_address function should 94 // return the end of the instructions to be patched, allowing the 95 // deserializer to deserialize the instructions as raw bytes and put them in 96 // place, ready to be patched with the target. After jump optimization, 97 // that is the address of the instruction that follows J/JAL/JR/JALR 98 // instruction. 99 return pc_ + Assembler::kInstructionsFor64BitConstant * kInstrSize; 100 } 101 102 103 Address RelocInfo::constant_pool_entry_address() { 104 UNREACHABLE(); 105 } 106 107 108 int RelocInfo::target_address_size() { 109 return Assembler::kSpecialTargetSize; 110 } 111 112 Address Assembler::target_address_from_return_address(Address pc) { 113 return pc - kCallTargetAddressOffset; 114 } 115 116 void Assembler::deserialization_set_special_target_at( 117 Address instruction_payload, Code* code, Address target) { 118 set_target_address_at( 119 instruction_payload - kInstructionsFor64BitConstant * kInstrSize, 120 code ? code->constant_pool() : kNullAddress, target); 121 } 122 123 int Assembler::deserialization_special_target_size( 124 Address instruction_payload) { 125 return kSpecialTargetSize; 126 } 127 128 void Assembler::set_target_internal_reference_encoded_at(Address pc, 129 Address target) { 130 // Encoded internal references are j/jal instructions. 131 Instr instr = Assembler::instr_at(pc + 0 * kInstrSize); 132 133 uint64_t imm28 = target & static_cast<uint64_t>(kImm28Mask); 134 135 instr &= ~kImm26Mask; 136 uint64_t imm26 = imm28 >> 2; 137 DCHECK(is_uint26(imm26)); 138 139 instr_at_put(pc, instr | (imm26 & kImm26Mask)); 140 // Currently used only by deserializer, and all code will be flushed 141 // after complete deserialization, no need to flush on each reference. 142 } 143 144 void Assembler::deserialization_set_target_internal_reference_at( 145 Address pc, Address target, RelocInfo::Mode mode) { 146 if (mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) { 147 DCHECK(IsJ(instr_at(pc))); 148 set_target_internal_reference_encoded_at(pc, target); 149 } else { 150 DCHECK(mode == RelocInfo::INTERNAL_REFERENCE); 151 Memory<Address>(pc) = target; 152 } 153 } 154 155 HeapObject* RelocInfo::target_object() { 156 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 157 return HeapObject::cast(reinterpret_cast<Object*>( 158 Assembler::target_address_at(pc_, constant_pool_))); 159 } 160 161 Handle<HeapObject> RelocInfo::target_object_handle(Assembler* origin) { 162 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 163 return Handle<HeapObject>(reinterpret_cast<HeapObject**>( 164 Assembler::target_address_at(pc_, constant_pool_))); 165 } 166 167 void RelocInfo::set_target_object(Heap* heap, HeapObject* target, 168 WriteBarrierMode write_barrier_mode, 169 ICacheFlushMode icache_flush_mode) { 170 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 171 Assembler::set_target_address_at(pc_, constant_pool_, 172 reinterpret_cast<Address>(target), 173 icache_flush_mode); 174 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != nullptr) { 175 WriteBarrierForCode(host(), this, target); 176 } 177 } 178 179 180 Address RelocInfo::target_external_reference() { 181 DCHECK(rmode_ == EXTERNAL_REFERENCE); 182 return Assembler::target_address_at(pc_, constant_pool_); 183 } 184 185 void RelocInfo::set_target_external_reference( 186 Address target, ICacheFlushMode icache_flush_mode) { 187 DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE); 188 Assembler::set_target_address_at(pc_, constant_pool_, target, 189 icache_flush_mode); 190 } 191 192 Address RelocInfo::target_internal_reference() { 193 if (rmode_ == INTERNAL_REFERENCE) { 194 return Memory<Address>(pc_); 195 } else { 196 // Encoded internal references are j/jal instructions. 197 DCHECK(rmode_ == INTERNAL_REFERENCE_ENCODED); 198 Instr instr = Assembler::instr_at(pc_ + 0 * kInstrSize); 199 instr &= kImm26Mask; 200 uint64_t imm28 = instr << 2; 201 uint64_t segment = pc_ & ~static_cast<uint64_t>(kImm28Mask); 202 return static_cast<Address>(segment | imm28); 203 } 204 } 205 206 207 Address RelocInfo::target_internal_reference_address() { 208 DCHECK(rmode_ == INTERNAL_REFERENCE || rmode_ == INTERNAL_REFERENCE_ENCODED); 209 return pc_; 210 } 211 212 Address RelocInfo::target_runtime_entry(Assembler* origin) { 213 DCHECK(IsRuntimeEntry(rmode_)); 214 return target_address(); 215 } 216 217 void RelocInfo::set_target_runtime_entry(Address target, 218 WriteBarrierMode write_barrier_mode, 219 ICacheFlushMode icache_flush_mode) { 220 DCHECK(IsRuntimeEntry(rmode_)); 221 if (target_address() != target) 222 set_target_address(target, write_barrier_mode, icache_flush_mode); 223 } 224 225 Address RelocInfo::target_off_heap_target() { 226 DCHECK(IsOffHeapTarget(rmode_)); 227 return Assembler::target_address_at(pc_, constant_pool_); 228 } 229 230 void RelocInfo::WipeOut() { 231 DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) || 232 IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) || 233 IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_) || 234 IsOffHeapTarget(rmode_)); 235 if (IsInternalReference(rmode_)) { 236 Memory<Address>(pc_) = kNullAddress; 237 } else if (IsInternalReferenceEncoded(rmode_)) { 238 Assembler::set_target_internal_reference_encoded_at(pc_, kNullAddress); 239 } else { 240 Assembler::set_target_address_at(pc_, constant_pool_, kNullAddress); 241 } 242 } 243 244 template <typename ObjectVisitor> 245 void RelocInfo::Visit(ObjectVisitor* visitor) { 246 RelocInfo::Mode mode = rmode(); 247 if (mode == RelocInfo::EMBEDDED_OBJECT) { 248 visitor->VisitEmbeddedPointer(host(), this); 249 } else if (RelocInfo::IsCodeTargetMode(mode)) { 250 visitor->VisitCodeTarget(host(), this); 251 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { 252 visitor->VisitExternalReference(host(), this); 253 } else if (mode == RelocInfo::INTERNAL_REFERENCE || 254 mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) { 255 visitor->VisitInternalReference(host(), this); 256 } else if (RelocInfo::IsRuntimeEntry(mode)) { 257 visitor->VisitRuntimeEntry(host(), this); 258 } else if (RelocInfo::IsOffHeapTarget(mode)) { 259 visitor->VisitOffHeapTarget(host(), this); 260 } 261 } 262 263 // ----------------------------------------------------------------------------- 264 // Assembler. 265 266 267 void Assembler::CheckBuffer() { 268 if (buffer_space() <= kGap) { 269 GrowBuffer(); 270 } 271 } 272 273 274 void Assembler::CheckForEmitInForbiddenSlot() { 275 if (!is_buffer_growth_blocked()) { 276 CheckBuffer(); 277 } 278 if (IsPrevInstrCompactBranch()) { 279 // Nop instruction to precede a CTI in forbidden slot: 280 Instr nop = SPECIAL | SLL; 281 *reinterpret_cast<Instr*>(pc_) = nop; 282 pc_ += kInstrSize; 283 284 ClearCompactBranchState(); 285 } 286 } 287 288 289 void Assembler::EmitHelper(Instr x, CompactBranchType is_compact_branch) { 290 if (IsPrevInstrCompactBranch()) { 291 if (Instruction::IsForbiddenAfterBranchInstr(x)) { 292 // Nop instruction to precede a CTI in forbidden slot: 293 Instr nop = SPECIAL | SLL; 294 *reinterpret_cast<Instr*>(pc_) = nop; 295 pc_ += kInstrSize; 296 } 297 ClearCompactBranchState(); 298 } 299 *reinterpret_cast<Instr*>(pc_) = x; 300 pc_ += kInstrSize; 301 if (is_compact_branch == CompactBranchType::COMPACT_BRANCH) { 302 EmittedCompactBranchInstruction(); 303 } 304 CheckTrampolinePoolQuick(); 305 } 306 307 template <> 308 inline void Assembler::EmitHelper(uint8_t x); 309 310 template <typename T> 311 void Assembler::EmitHelper(T x) { 312 *reinterpret_cast<T*>(pc_) = x; 313 pc_ += sizeof(x); 314 CheckTrampolinePoolQuick(); 315 } 316 317 template <> 318 void Assembler::EmitHelper(uint8_t x) { 319 *reinterpret_cast<uint8_t*>(pc_) = x; 320 pc_ += sizeof(x); 321 if (reinterpret_cast<intptr_t>(pc_) % kInstrSize == 0) { 322 CheckTrampolinePoolQuick(); 323 } 324 } 325 326 void Assembler::emit(Instr x, CompactBranchType is_compact_branch) { 327 if (!is_buffer_growth_blocked()) { 328 CheckBuffer(); 329 } 330 EmitHelper(x, is_compact_branch); 331 } 332 333 334 void Assembler::emit(uint64_t data) { 335 CheckForEmitInForbiddenSlot(); 336 EmitHelper(data); 337 } 338 339 EnsureSpace::EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); } 340 341 } // namespace internal 342 } // namespace v8 343 344 #endif // V8_MIPS64_ASSEMBLER_MIPS64_INL_H_ 345