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 2021 the V8 project authors. All rights reserved. 34 35#ifndef V8_CODEGEN_RISCV64_ASSEMBLER_RISCV64_INL_H_ 36#define V8_CODEGEN_RISCV64_ASSEMBLER_RISCV64_INL_H_ 37 38#include "src/codegen/assembler.h" 39#include "src/codegen/riscv64/assembler-riscv64.h" 40#include "src/debug/debug.h" 41#include "src/objects/objects-inl.h" 42 43namespace v8 { 44namespace internal { 45 46bool CpuFeatures::SupportsOptimizer() { return IsSupported(FPU); } 47 48// ----------------------------------------------------------------------------- 49// Operand and MemOperand. 50 51bool Operand::is_reg() const { return rm_.is_valid(); } 52 53int64_t Operand::immediate() const { 54 DCHECK(!is_reg()); 55 DCHECK(!IsHeapObjectRequest()); 56 return value_.immediate; 57} 58 59// ----------------------------------------------------------------------------- 60// RelocInfo. 61 62void RelocInfo::apply(intptr_t delta) { 63 if (IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)) { 64 // Absolute code pointer inside code object moves with the code object. 65 Assembler::RelocateInternalReference(rmode_, pc_, delta); 66 } else { 67 DCHECK(IsRelativeCodeTarget(rmode_)); 68 Assembler::RelocateRelativeReference(rmode_, pc_, delta); 69 } 70} 71 72Address RelocInfo::target_address() { 73 DCHECK(IsCodeTargetMode(rmode_) || IsRuntimeEntry(rmode_) || 74 IsWasmCall(rmode_)); 75 return Assembler::target_address_at(pc_, constant_pool_); 76} 77 78Address RelocInfo::target_address_address() { 79 DCHECK(HasTargetAddressAddress()); 80 // Read the address of the word containing the target_address in an 81 // instruction stream. 82 // The only architecture-independent user of this function is the serializer. 83 // The serializer uses it to find out how many raw bytes of instruction to 84 // output before the next target. 85 // For an instruction like LUI/ORI where the target bits are mixed into the 86 // instruction bits, the size of the target will be zero, indicating that the 87 // serializer should not step forward in memory after a target is resolved 88 // and written. In this case the target_address_address function should 89 // return the end of the instructions to be patched, allowing the 90 // deserializer to deserialize the instructions as raw bytes and put them in 91 // place, ready to be patched with the target. After jump optimization, 92 // that is the address of the instruction that follows J/JAL/JR/JALR 93 // instruction. 94 return pc_ + Assembler::kInstructionsFor64BitConstant * kInstrSize; 95} 96 97Address RelocInfo::constant_pool_entry_address() { UNREACHABLE(); } 98 99int RelocInfo::target_address_size() { 100 if (IsCodedSpecially()) { 101 return Assembler::kSpecialTargetSize; 102 } else { 103 return kSystemPointerSize; 104 } 105} 106 107void Assembler::set_target_compressed_address_at( 108 Address pc, Address constant_pool, Tagged_t target, 109 ICacheFlushMode icache_flush_mode) { 110 Assembler::set_target_address_at( 111 pc, constant_pool, static_cast<Address>(target), icache_flush_mode); 112} 113 114Tagged_t Assembler::target_compressed_address_at(Address pc, 115 Address constant_pool) { 116 return static_cast<Tagged_t>(target_address_at(pc, constant_pool)); 117} 118 119Handle<Object> Assembler::code_target_object_handle_at(Address pc, 120 Address constant_pool) { 121 int index = 122 static_cast<int>(target_address_at(pc, constant_pool)) & 0xFFFFFFFF; 123 return GetCodeTarget(index); 124} 125 126Handle<HeapObject> Assembler::compressed_embedded_object_handle_at( 127 Address pc, Address const_pool) { 128 return GetEmbeddedObject(target_compressed_address_at(pc, const_pool)); 129} 130 131void Assembler::deserialization_set_special_target_at( 132 Address instruction_payload, Code code, Address target) { 133 set_target_address_at(instruction_payload, 134 !code.is_null() ? code.constant_pool() : kNullAddress, 135 target); 136} 137 138int Assembler::deserialization_special_target_size( 139 Address instruction_payload) { 140 return kSpecialTargetSize; 141} 142 143void Assembler::set_target_internal_reference_encoded_at(Address pc, 144 Address target) { 145 set_target_value_at(pc, static_cast<uint64_t>(target)); 146} 147 148void Assembler::deserialization_set_target_internal_reference_at( 149 Address pc, Address target, RelocInfo::Mode mode) { 150 if (RelocInfo::IsInternalReferenceEncoded(mode)) { 151 DCHECK(IsLui(instr_at(pc))); 152 set_target_internal_reference_encoded_at(pc, target); 153 } else { 154 DCHECK(RelocInfo::IsInternalReference(mode)); 155 Memory<Address>(pc) = target; 156 } 157} 158 159HeapObject RelocInfo::target_object(PtrComprCageBase cage_base) { 160 DCHECK(IsCodeTarget(rmode_) || IsEmbeddedObjectMode(rmode_)); 161 if (IsDataEmbeddedObject(rmode_)) { 162 return HeapObject::cast(Object(ReadUnalignedValue<Address>(pc_))); 163 } else if (IsCompressedEmbeddedObject(rmode_)) { 164 return HeapObject::cast(Object(DecompressTaggedAny( 165 cage_base, 166 Assembler::target_compressed_address_at(pc_, constant_pool_)))); 167 } else { 168 return HeapObject::cast( 169 Object(Assembler::target_address_at(pc_, constant_pool_))); 170 } 171} 172 173Handle<HeapObject> RelocInfo::target_object_handle(Assembler* origin) { 174 if (IsDataEmbeddedObject(rmode_)) { 175 return Handle<HeapObject>::cast(ReadUnalignedValue<Handle<Object>>(pc_)); 176 } else if (IsCodeTarget(rmode_)) { 177 return Handle<HeapObject>::cast( 178 origin->code_target_object_handle_at(pc_, constant_pool_)); 179 } else if (IsCompressedEmbeddedObject(rmode_)) { 180 return origin->compressed_embedded_object_handle_at(pc_, constant_pool_); 181 } else if (IsFullEmbeddedObject(rmode_)) { 182 return Handle<HeapObject>(reinterpret_cast<Address*>( 183 Assembler::target_address_at(pc_, constant_pool_))); 184 } else { 185 DCHECK(IsRelativeCodeTarget(rmode_)); 186 return origin->relative_code_target_object_handle_at(pc_); 187 } 188} 189 190void RelocInfo::set_target_object(Heap* heap, HeapObject target, 191 WriteBarrierMode write_barrier_mode, 192 ICacheFlushMode icache_flush_mode) { 193 DCHECK(IsCodeTarget(rmode_) || IsEmbeddedObjectMode(rmode_)); 194 if (IsDataEmbeddedObject(rmode_)) { 195 WriteUnalignedValue(pc_, target.ptr()); 196 // No need to flush icache since no instructions were changed. 197 } else if (IsCompressedEmbeddedObject(rmode_)) { 198 Assembler::set_target_compressed_address_at( 199 pc_, constant_pool_, CompressTagged(target.ptr()), icache_flush_mode); 200 } else { 201 DCHECK(IsFullEmbeddedObject(rmode_)); 202 Assembler::set_target_address_at(pc_, constant_pool_, target.ptr(), 203 icache_flush_mode); 204 } 205 if (write_barrier_mode == UPDATE_WRITE_BARRIER && !host().is_null() && 206 !FLAG_disable_write_barriers) { 207 WriteBarrierForCode(host(), this, target); 208 } 209} 210 211Address RelocInfo::target_external_reference() { 212 DCHECK(rmode_ == EXTERNAL_REFERENCE); 213 return Assembler::target_address_at(pc_, constant_pool_); 214} 215 216void RelocInfo::set_target_external_reference( 217 Address target, ICacheFlushMode icache_flush_mode) { 218 DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE); 219 Assembler::set_target_address_at(pc_, constant_pool_, target, 220 icache_flush_mode); 221} 222 223Address RelocInfo::target_internal_reference() { 224 if (IsInternalReference(rmode_)) { 225 return Memory<Address>(pc_); 226 } else { 227 // Encoded internal references are j/jal instructions. 228 DCHECK(IsInternalReferenceEncoded(rmode_)); 229 DCHECK(Assembler::IsLui(Assembler::instr_at(pc_ + 0 * kInstrSize))); 230 Address address = Assembler::target_address_at(pc_); 231 return address; 232 } 233} 234 235Address RelocInfo::target_internal_reference_address() { 236 DCHECK(IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)); 237 return pc_; 238} 239 240Handle<Code> Assembler::relative_code_target_object_handle_at( 241 Address pc) const { 242 Instr instr1 = Assembler::instr_at(pc); 243 Instr instr2 = Assembler::instr_at(pc + kInstrSize); 244 DCHECK(IsAuipc(instr1)); 245 DCHECK(IsJalr(instr2)); 246 int32_t code_target_index = BrachlongOffset(instr1, instr2); 247 return GetCodeTarget(code_target_index); 248} 249 250Address RelocInfo::target_runtime_entry(Assembler* origin) { 251 DCHECK(IsRuntimeEntry(rmode_)); 252 return target_address(); 253} 254 255void RelocInfo::set_target_runtime_entry(Address target, 256 WriteBarrierMode write_barrier_mode, 257 ICacheFlushMode icache_flush_mode) { 258 DCHECK(IsRuntimeEntry(rmode_)); 259 if (target_address() != target) 260 set_target_address(target, write_barrier_mode, icache_flush_mode); 261} 262 263Address RelocInfo::target_off_heap_target() { 264 DCHECK(IsOffHeapTarget(rmode_)); 265 return Assembler::target_address_at(pc_, constant_pool_); 266} 267 268void RelocInfo::WipeOut() { 269 DCHECK(IsFullEmbeddedObject(rmode_) || IsCodeTarget(rmode_) || 270 IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) || 271 IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_) || 272 IsOffHeapTarget(rmode_)); 273 if (IsInternalReference(rmode_)) { 274 Memory<Address>(pc_) = kNullAddress; 275 } else if (IsInternalReferenceEncoded(rmode_)) { 276 Assembler::set_target_internal_reference_encoded_at(pc_, kNullAddress); 277 } else { 278 Assembler::set_target_address_at(pc_, constant_pool_, kNullAddress); 279 } 280} 281 282// ----------------------------------------------------------------------------- 283// Assembler. 284 285void Assembler::CheckBuffer() { 286 if (buffer_space() <= kGap) { 287 GrowBuffer(); 288 } 289} 290 291template <typename T> 292void Assembler::EmitHelper(T x) { 293 *reinterpret_cast<T*>(pc_) = x; 294 pc_ += sizeof(x); 295} 296 297void Assembler::emit(Instr x) { 298 if (!is_buffer_growth_blocked()) { 299 CheckBuffer(); 300 } 301 DEBUG_PRINTF("%p: ", pc_); 302 disassembleInstr(x); 303 EmitHelper(x); 304 CheckTrampolinePoolQuick(); 305} 306 307void Assembler::emit(ShortInstr x) { 308 if (!is_buffer_growth_blocked()) { 309 CheckBuffer(); 310 } 311 DEBUG_PRINTF("%p: ", pc_); 312 disassembleInstr(x); 313 EmitHelper(x); 314 CheckTrampolinePoolQuick(); 315} 316 317void Assembler::emit(uint64_t data) { 318 if (!is_buffer_growth_blocked()) CheckBuffer(); 319 EmitHelper(data); 320} 321 322EnsureSpace::EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); } 323 324} // namespace internal 325} // namespace v8 326 327#endif // V8_CODEGEN_RISCV64_ASSEMBLER_RISCV64_INL_H_ 328