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