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 2014 the V8 project authors. All rights reserved. 36 37#ifndef V8_CODEGEN_S390_ASSEMBLER_S390_INL_H_ 38#define V8_CODEGEN_S390_ASSEMBLER_S390_INL_H_ 39 40#include "src/codegen/s390/assembler-s390.h" 41 42#include "src/codegen/assembler.h" 43#include "src/debug/debug.h" 44#include "src/objects/objects-inl.h" 45 46namespace v8 { 47namespace internal { 48 49bool CpuFeatures::SupportsOptimizer() { return true; } 50 51void RelocInfo::apply(intptr_t delta) { 52 // Absolute code pointer inside code object moves with the code object. 53 if (IsInternalReference(rmode_)) { 54 // Jump table entry 55 Address target = Memory<Address>(pc_); 56 Memory<Address>(pc_) = target + delta; 57 } else if (IsCodeTarget(rmode_)) { 58 SixByteInstr instr = 59 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc_)); 60 int32_t dis = static_cast<int32_t>(instr & 0xFFFFFFFF) * 2 // halfwords 61 - static_cast<int32_t>(delta); 62 instr >>= 32; // Clear the 4-byte displacement field. 63 instr <<= 32; 64 instr |= static_cast<uint32_t>(dis / 2); 65 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc_), 66 instr); 67 } else { 68 // mov sequence 69 DCHECK(IsInternalReferenceEncoded(rmode_)); 70 Address target = Assembler::target_address_at(pc_, constant_pool_); 71 Assembler::set_target_address_at(pc_, constant_pool_, target + delta, 72 SKIP_ICACHE_FLUSH); 73 } 74} 75 76Address RelocInfo::target_internal_reference() { 77 if (IsInternalReference(rmode_)) { 78 // Jump table entry 79 return Memory<Address>(pc_); 80 } else { 81 // mov sequence 82 DCHECK(IsInternalReferenceEncoded(rmode_)); 83 return Assembler::target_address_at(pc_, constant_pool_); 84 } 85} 86 87Address RelocInfo::target_internal_reference_address() { 88 DCHECK(IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)); 89 return pc_; 90} 91 92Address RelocInfo::target_address() { 93 DCHECK(IsRelativeCodeTarget(rmode_) || IsCodeTarget(rmode_) || 94 IsRuntimeEntry(rmode_) || IsWasmCall(rmode_)); 95 return Assembler::target_address_at(pc_, constant_pool_); 96} 97 98Address RelocInfo::target_address_address() { 99 DCHECK(HasTargetAddressAddress()); 100 101 // Read the address of the word containing the target_address in an 102 // instruction stream. 103 // The only architecture-independent user of this function is the serializer. 104 // The serializer uses it to find out how many raw bytes of instruction to 105 // output before the next target. 106 // For an instruction like LIS/ORI where the target bits are mixed into the 107 // instruction bits, the size of the target will be zero, indicating that the 108 // serializer should not step forward in memory after a target is resolved 109 // and written. 110 return pc_; 111} 112 113Address RelocInfo::constant_pool_entry_address() { UNREACHABLE(); } 114 115void Assembler::set_target_compressed_address_at( 116 Address pc, Address constant_pool, Tagged_t target, 117 ICacheFlushMode icache_flush_mode) { 118 Assembler::set_target_address_at( 119 pc, constant_pool, static_cast<Address>(target), icache_flush_mode); 120} 121 122int RelocInfo::target_address_size() { 123 if (IsCodedSpecially()) { 124 return Assembler::kSpecialTargetSize; 125 } else { 126 return kSystemPointerSize; 127 } 128} 129 130Tagged_t Assembler::target_compressed_address_at(Address pc, 131 Address constant_pool) { 132 return static_cast<Tagged_t>(target_address_at(pc, constant_pool)); 133} 134 135Handle<Object> Assembler::code_target_object_handle_at(Address pc) { 136 SixByteInstr instr = 137 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc)); 138 int index = instr & 0xFFFFFFFF; 139 return GetCodeTarget(index); 140} 141 142HeapObject RelocInfo::target_object(PtrComprCageBase cage_base) { 143 DCHECK(IsCodeTarget(rmode_) || IsEmbeddedObjectMode(rmode_)); 144 if (IsDataEmbeddedObject(rmode_)) { 145 return HeapObject::cast(Object(ReadUnalignedValue<Address>(pc_))); 146 } else if (IsCompressedEmbeddedObject(rmode_)) { 147 return HeapObject::cast(Object(DecompressTaggedAny( 148 cage_base, 149 Assembler::target_compressed_address_at(pc_, constant_pool_)))); 150 } else { 151 return HeapObject::cast( 152 Object(Assembler::target_address_at(pc_, constant_pool_))); 153 } 154} 155 156Handle<HeapObject> Assembler::compressed_embedded_object_handle_at( 157 Address pc, Address const_pool) { 158 return GetEmbeddedObject(target_compressed_address_at(pc, const_pool)); 159} 160 161Handle<HeapObject> RelocInfo::target_object_handle(Assembler* origin) { 162 DCHECK(IsRelativeCodeTarget(rmode_) || IsCodeTarget(rmode_) || 163 IsEmbeddedObjectMode(rmode_)); 164 if (IsDataEmbeddedObject(rmode_)) { 165 return Handle<HeapObject>::cast(ReadUnalignedValue<Handle<Object>>(pc_)); 166 } else if (IsCodeTarget(rmode_) || IsRelativeCodeTarget(rmode_)) { 167 return Handle<HeapObject>::cast(origin->code_target_object_handle_at(pc_)); 168 } else { 169 if (IsCompressedEmbeddedObject(rmode_)) { 170 return origin->compressed_embedded_object_handle_at(pc_, constant_pool_); 171 } 172 return Handle<HeapObject>(reinterpret_cast<Address*>( 173 Assembler::target_address_at(pc_, constant_pool_))); 174 } 175} 176 177void RelocInfo::set_target_object(Heap* heap, HeapObject target, 178 WriteBarrierMode write_barrier_mode, 179 ICacheFlushMode icache_flush_mode) { 180 DCHECK(IsCodeTarget(rmode_) || IsEmbeddedObjectMode(rmode_)); 181 if (IsDataEmbeddedObject(rmode_)) { 182 WriteUnalignedValue(pc_, target.ptr()); 183 // No need to flush icache since no instructions were changed. 184 } else if (IsCompressedEmbeddedObject(rmode_)) { 185 Assembler::set_target_compressed_address_at( 186 pc_, constant_pool_, CompressTagged(target.ptr()), icache_flush_mode); 187 } else { 188 DCHECK(IsFullEmbeddedObject(rmode_)); 189 Assembler::set_target_address_at(pc_, constant_pool_, target.ptr(), 190 icache_flush_mode); 191 } 192 if (write_barrier_mode == UPDATE_WRITE_BARRIER && !host().is_null() && 193 !FLAG_disable_write_barriers) { 194 WriteBarrierForCode(host(), this, target); 195 } 196} 197 198Address RelocInfo::target_external_reference() { 199 DCHECK(rmode_ == EXTERNAL_REFERENCE); 200 return Assembler::target_address_at(pc_, constant_pool_); 201} 202 203void RelocInfo::set_target_external_reference( 204 Address target, ICacheFlushMode icache_flush_mode) { 205 DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE); 206 Assembler::set_target_address_at(pc_, constant_pool_, target, 207 icache_flush_mode); 208} 209 210Address RelocInfo::target_runtime_entry(Assembler* origin) { 211 DCHECK(IsRuntimeEntry(rmode_)); 212 return target_address(); 213} 214 215Address RelocInfo::target_off_heap_target() { 216 DCHECK(IsOffHeapTarget(rmode_)); 217 return Assembler::target_address_at(pc_, constant_pool_); 218} 219 220void RelocInfo::set_target_runtime_entry(Address target, 221 WriteBarrierMode write_barrier_mode, 222 ICacheFlushMode icache_flush_mode) { 223 DCHECK(IsRuntimeEntry(rmode_)); 224 if (target_address() != target) 225 set_target_address(target, write_barrier_mode, icache_flush_mode); 226} 227 228void RelocInfo::WipeOut() { 229 DCHECK(IsEmbeddedObjectMode(rmode_) || IsCodeTarget(rmode_) || 230 IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) || 231 IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_) || 232 IsOffHeapTarget(rmode_)); 233 if (IsInternalReference(rmode_)) { 234 // Jump table entry 235 Memory<Address>(pc_) = kNullAddress; 236 } else if (IsCompressedEmbeddedObject(rmode_)) { 237 Assembler::set_target_compressed_address_at(pc_, constant_pool_, 238 kNullAddress); 239 } else if (IsInternalReferenceEncoded(rmode_) || IsOffHeapTarget(rmode_)) { 240 // mov sequence 241 // Currently used only by deserializer, no need to flush. 242 Assembler::set_target_address_at(pc_, constant_pool_, kNullAddress, 243 SKIP_ICACHE_FLUSH); 244 } else { 245 Assembler::set_target_address_at(pc_, constant_pool_, kNullAddress); 246 } 247} 248 249// Operand constructors 250Operand::Operand(Register rm) : rm_(rm), rmode_(RelocInfo::NO_INFO) {} 251 252// Fetch the 32bit value from the FIXED_SEQUENCE IIHF / IILF 253Address Assembler::target_address_at(Address pc, Address constant_pool) { 254 // S390 Instruction! 255 // We want to check for instructions generated by Asm::mov() 256 Opcode op1 = Instruction::S390OpcodeValue(reinterpret_cast<const byte*>(pc)); 257 SixByteInstr instr_1 = 258 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc)); 259 260 if (BRASL == op1 || BRCL == op1) { 261 int32_t dis = static_cast<int32_t>(instr_1 & 0xFFFFFFFF) * 2; 262 return pc + dis; 263 } 264 265#if V8_TARGET_ARCH_S390X 266 int instr1_length = 267 Instruction::InstructionLength(reinterpret_cast<const byte*>(pc)); 268 Opcode op2 = Instruction::S390OpcodeValue( 269 reinterpret_cast<const byte*>(pc + instr1_length)); 270 SixByteInstr instr_2 = Instruction::InstructionBits( 271 reinterpret_cast<const byte*>(pc + instr1_length)); 272 // IIHF for hi_32, IILF for lo_32 273 if (IIHF == op1 && IILF == op2) { 274 return static_cast<Address>(((instr_1 & 0xFFFFFFFF) << 32) | 275 ((instr_2 & 0xFFFFFFFF))); 276 } 277#else 278 // IILF loads 32-bits 279 if (IILF == op1 || CFI == op1) { 280 return static_cast<Address>((instr_1 & 0xFFFFFFFF)); 281 } 282#endif 283 284 UNIMPLEMENTED(); 285 return 0; 286} 287 288// This sets the branch destination (which gets loaded at the call address). 289// This is for calls and branches within generated code. The serializer 290// has already deserialized the mov instructions etc. 291// There is a FIXED_SEQUENCE assumption here 292void Assembler::deserialization_set_special_target_at( 293 Address instruction_payload, Code code, Address target) { 294 set_target_address_at(instruction_payload, 295 !code.is_null() ? code.constant_pool() : kNullAddress, 296 target); 297} 298 299int Assembler::deserialization_special_target_size( 300 Address instruction_payload) { 301 return kSpecialTargetSize; 302} 303 304void Assembler::deserialization_set_target_internal_reference_at( 305 Address pc, Address target, RelocInfo::Mode mode) { 306 if (RelocInfo::IsInternalReferenceEncoded(mode)) { 307 set_target_address_at(pc, kNullAddress, target, SKIP_ICACHE_FLUSH); 308 } else { 309 Memory<Address>(pc) = target; 310 } 311} 312 313// This code assumes the FIXED_SEQUENCE of IIHF/IILF 314void Assembler::set_target_address_at(Address pc, Address constant_pool, 315 Address target, 316 ICacheFlushMode icache_flush_mode) { 317 // Check for instructions generated by Asm::mov() 318 Opcode op1 = Instruction::S390OpcodeValue(reinterpret_cast<const byte*>(pc)); 319 SixByteInstr instr_1 = 320 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc)); 321 bool patched = false; 322 323 if (BRASL == op1 || BRCL == op1) { 324 instr_1 >>= 32; // Zero out the lower 32-bits 325 instr_1 <<= 32; 326 int32_t halfwords = (target - pc) / 2; // number of halfwords 327 instr_1 |= static_cast<uint32_t>(halfwords); 328 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc), 329 instr_1); 330 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 331 FlushInstructionCache(pc, 6); 332 } 333 patched = true; 334 } else { 335#if V8_TARGET_ARCH_S390X 336 int instr1_length = 337 Instruction::InstructionLength(reinterpret_cast<const byte*>(pc)); 338 Opcode op2 = Instruction::S390OpcodeValue( 339 reinterpret_cast<const byte*>(pc + instr1_length)); 340 SixByteInstr instr_2 = Instruction::InstructionBits( 341 reinterpret_cast<const byte*>(pc + instr1_length)); 342 // IIHF for hi_32, IILF for lo_32 343 if (IIHF == op1 && IILF == op2) { 344 // IIHF 345 instr_1 >>= 32; // Zero out the lower 32-bits 346 instr_1 <<= 32; 347 instr_1 |= reinterpret_cast<uint64_t>(target) >> 32; 348 349 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc), 350 instr_1); 351 352 // IILF 353 instr_2 >>= 32; 354 instr_2 <<= 32; 355 instr_2 |= reinterpret_cast<uint64_t>(target) & 0xFFFFFFFF; 356 357 Instruction::SetInstructionBits<SixByteInstr>( 358 reinterpret_cast<byte*>(pc + instr1_length), instr_2); 359 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 360 FlushInstructionCache(pc, 12); 361 } 362 patched = true; 363 } 364#else 365 // IILF loads 32-bits 366 if (IILF == op1 || CFI == op1) { 367 instr_1 >>= 32; // Zero out the lower 32-bits 368 instr_1 <<= 32; 369 instr_1 |= reinterpret_cast<uint32_t>(target); 370 371 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc), 372 instr_1); 373 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 374 FlushInstructionCache(pc, 6); 375 } 376 patched = true; 377 } 378#endif 379 } 380 if (!patched) UNREACHABLE(); 381} 382 383} // namespace internal 384} // namespace v8 385 386#endif // V8_CODEGEN_S390_ASSEMBLER_S390_INL_H_ 387