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::SupportsCrankshaft() { return true; } 50 51 bool CpuFeatures::SupportsSimd128() { 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_at(pc_); 58 Memory::Address_at(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_, host_); 73 Assembler::set_target_address_at(isolate_, pc_, host_, 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_at(pc_); 82 } else { 83 // mov sequence 84 DCHECK(IsInternalReferenceEncoded(rmode_)); 85 return Assembler::target_address_at(pc_, host_); 86 } 87 } 88 89 Address RelocInfo::target_internal_reference_address() { 90 DCHECK(IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)); 91 return reinterpret_cast<Address>(pc_); 92 } 93 94 Address RelocInfo::target_address() { 95 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); 96 return Assembler::target_address_at(pc_, host_); 97 } 98 99 Address RelocInfo::target_address_address() { 100 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || 101 rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE); 102 103 // Read the address of the word containing the target_address in an 104 // instruction stream. 105 // The only architecture-independent user of this function is the serializer. 106 // The serializer uses it to find out how many raw bytes of instruction to 107 // output before the next target. 108 // For an instruction like LIS/ORI where the target bits are mixed into the 109 // instruction bits, the size of the target will be zero, indicating that the 110 // serializer should not step forward in memory after a target is resolved 111 // and written. 112 return reinterpret_cast<Address>(pc_); 113 } 114 115 Address RelocInfo::constant_pool_entry_address() { 116 UNREACHABLE(); 117 return NULL; 118 } 119 120 int RelocInfo::target_address_size() { return Assembler::kSpecialTargetSize; } 121 122 Address Assembler::target_address_at(Address pc, Code* code) { 123 Address constant_pool = code ? code->constant_pool() : NULL; 124 return target_address_at(pc, constant_pool); 125 } 126 127 void Assembler::set_target_address_at(Isolate* isolate, Address pc, Code* code, 128 Address target, 129 ICacheFlushMode icache_flush_mode) { 130 Address constant_pool = code ? code->constant_pool() : NULL; 131 set_target_address_at(isolate, pc, constant_pool, target, icache_flush_mode); 132 } 133 134 Address Assembler::target_address_from_return_address(Address pc) { 135 // Returns the address of the call target from the return address that will 136 // be returned to after a call. 137 // Sequence is: 138 // BRASL r14, RI 139 return pc - kCallTargetAddressOffset; 140 } 141 142 Address Assembler::return_address_from_call_start(Address pc) { 143 // Sequence is: 144 // BRASL r14, RI 145 return pc + kCallTargetAddressOffset; 146 } 147 148 Handle<Object> Assembler::code_target_object_handle_at(Address pc) { 149 SixByteInstr instr = 150 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc)); 151 int index = instr & 0xFFFFFFFF; 152 return code_targets_[index]; 153 } 154 155 Object* RelocInfo::target_object() { 156 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 157 return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_)); 158 } 159 160 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) { 161 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 162 if (rmode_ == EMBEDDED_OBJECT) { 163 return Handle<Object>( 164 reinterpret_cast<Object**>(Assembler::target_address_at(pc_, host_))); 165 } else { 166 return origin->code_target_object_handle_at(pc_); 167 } 168 } 169 170 void RelocInfo::set_target_object(Object* target, 171 WriteBarrierMode write_barrier_mode, 172 ICacheFlushMode icache_flush_mode) { 173 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 174 Assembler::set_target_address_at(isolate_, pc_, host_, 175 reinterpret_cast<Address>(target), 176 icache_flush_mode); 177 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL && 178 target->IsHeapObject()) { 179 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( 180 host(), this, HeapObject::cast(target)); 181 host()->GetHeap()->RecordWriteIntoCode(host(), this, target); 182 } 183 } 184 185 Address RelocInfo::target_external_reference() { 186 DCHECK(rmode_ == EXTERNAL_REFERENCE); 187 return Assembler::target_address_at(pc_, host_); 188 } 189 190 Address RelocInfo::target_runtime_entry(Assembler* origin) { 191 DCHECK(IsRuntimeEntry(rmode_)); 192 return target_address(); 193 } 194 195 void RelocInfo::set_target_runtime_entry(Address target, 196 WriteBarrierMode write_barrier_mode, 197 ICacheFlushMode icache_flush_mode) { 198 DCHECK(IsRuntimeEntry(rmode_)); 199 if (target_address() != target) 200 set_target_address(target, write_barrier_mode, icache_flush_mode); 201 } 202 203 Handle<Cell> RelocInfo::target_cell_handle() { 204 DCHECK(rmode_ == RelocInfo::CELL); 205 Address address = Memory::Address_at(pc_); 206 return Handle<Cell>(reinterpret_cast<Cell**>(address)); 207 } 208 209 Cell* RelocInfo::target_cell() { 210 DCHECK(rmode_ == RelocInfo::CELL); 211 return Cell::FromValueAddress(Memory::Address_at(pc_)); 212 } 213 214 void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode write_barrier_mode, 215 ICacheFlushMode icache_flush_mode) { 216 DCHECK(rmode_ == RelocInfo::CELL); 217 Address address = cell->address() + Cell::kValueOffset; 218 Memory::Address_at(pc_) = address; 219 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) { 220 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this, 221 cell); 222 } 223 } 224 225 #if V8_TARGET_ARCH_S390X 226 // NOP(2byte) + PUSH + MOV + BASR = 227 // NOP + LAY + STG + IIHF + IILF + BASR 228 static const int kCodeAgingSequenceLength = 28; 229 static const int kCodeAgingTargetDelta = 14; // Jump past NOP + PUSH to IIHF 230 // LAY + 4 * STG + LA 231 static const int kNoCodeAgeSequenceLength = 34; 232 #else 233 #if (V8_HOST_ARCH_S390) 234 // NOP + NILH + LAY + ST + IILF + BASR 235 static const int kCodeAgingSequenceLength = 24; 236 static const int kCodeAgingTargetDelta = 16; // Jump past NOP to IILF 237 // NILH + LAY + 4 * ST + LA 238 static const int kNoCodeAgeSequenceLength = 30; 239 #else 240 // NOP + LAY + ST + IILF + BASR 241 static const int kCodeAgingSequenceLength = 20; 242 static const int kCodeAgingTargetDelta = 12; // Jump past NOP to IILF 243 // LAY + 4 * ST + LA 244 static const int kNoCodeAgeSequenceLength = 26; 245 #endif 246 #endif 247 248 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) { 249 UNREACHABLE(); // This should never be reached on S390. 250 return Handle<Object>(); 251 } 252 253 Code* RelocInfo::code_age_stub() { 254 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); 255 return Code::GetCodeFromTargetAddress( 256 Assembler::target_address_at(pc_ + kCodeAgingTargetDelta, host_)); 257 } 258 259 void RelocInfo::set_code_age_stub(Code* stub, 260 ICacheFlushMode icache_flush_mode) { 261 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); 262 Assembler::set_target_address_at(isolate_, pc_ + kCodeAgingTargetDelta, host_, 263 stub->instruction_start(), 264 icache_flush_mode); 265 } 266 267 Address RelocInfo::debug_call_address() { 268 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); 269 return Assembler::target_address_at(pc_, host_); 270 } 271 272 void RelocInfo::set_debug_call_address(Address target) { 273 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); 274 Assembler::set_target_address_at(isolate_, pc_, host_, target); 275 if (host() != NULL) { 276 Object* target_code = Code::GetCodeFromTargetAddress(target); 277 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( 278 host(), this, HeapObject::cast(target_code)); 279 } 280 } 281 282 void RelocInfo::WipeOut() { 283 DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) || 284 IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) || 285 IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)); 286 if (IsInternalReference(rmode_)) { 287 // Jump table entry 288 Memory::Address_at(pc_) = NULL; 289 } else if (IsInternalReferenceEncoded(rmode_)) { 290 // mov sequence 291 // Currently used only by deserializer, no need to flush. 292 Assembler::set_target_address_at(isolate_, pc_, host_, NULL, 293 SKIP_ICACHE_FLUSH); 294 } else { 295 Assembler::set_target_address_at(isolate_, pc_, host_, NULL); 296 } 297 } 298 299 template <typename ObjectVisitor> 300 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) { 301 RelocInfo::Mode mode = rmode(); 302 if (mode == RelocInfo::EMBEDDED_OBJECT) { 303 visitor->VisitEmbeddedPointer(this); 304 } else if (RelocInfo::IsCodeTarget(mode)) { 305 visitor->VisitCodeTarget(this); 306 } else if (mode == RelocInfo::CELL) { 307 visitor->VisitCell(this); 308 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { 309 visitor->VisitExternalReference(this); 310 } else if (mode == RelocInfo::INTERNAL_REFERENCE) { 311 visitor->VisitInternalReference(this); 312 } else if (RelocInfo::IsCodeAgeSequence(mode)) { 313 visitor->VisitCodeAgeSequence(this); 314 } else if (RelocInfo::IsDebugBreakSlot(mode) && 315 IsPatchedDebugBreakSlotSequence()) { 316 visitor->VisitDebugTarget(this); 317 } else if (IsRuntimeEntry(mode)) { 318 visitor->VisitRuntimeEntry(this); 319 } 320 } 321 322 template <typename StaticVisitor> 323 void RelocInfo::Visit(Heap* heap) { 324 RelocInfo::Mode mode = rmode(); 325 if (mode == RelocInfo::EMBEDDED_OBJECT) { 326 StaticVisitor::VisitEmbeddedPointer(heap, this); 327 } else if (RelocInfo::IsCodeTarget(mode)) { 328 StaticVisitor::VisitCodeTarget(heap, this); 329 } else if (mode == RelocInfo::CELL) { 330 StaticVisitor::VisitCell(heap, this); 331 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { 332 StaticVisitor::VisitExternalReference(this); 333 } else if (mode == RelocInfo::INTERNAL_REFERENCE) { 334 StaticVisitor::VisitInternalReference(this); 335 } else if (RelocInfo::IsCodeAgeSequence(mode)) { 336 StaticVisitor::VisitCodeAgeSequence(heap, this); 337 } else if (RelocInfo::IsDebugBreakSlot(mode) && 338 IsPatchedDebugBreakSlotSequence()) { 339 StaticVisitor::VisitDebugTarget(heap, this); 340 } else if (IsRuntimeEntry(mode)) { 341 StaticVisitor::VisitRuntimeEntry(this); 342 } 343 } 344 345 // Operand constructors 346 Operand::Operand(intptr_t immediate, RelocInfo::Mode rmode) { 347 rm_ = no_reg; 348 imm_ = immediate; 349 rmode_ = rmode; 350 } 351 352 Operand::Operand(const ExternalReference& f) { 353 rm_ = no_reg; 354 imm_ = reinterpret_cast<intptr_t>(f.address()); 355 rmode_ = RelocInfo::EXTERNAL_REFERENCE; 356 } 357 358 Operand::Operand(Smi* value) { 359 rm_ = no_reg; 360 imm_ = reinterpret_cast<intptr_t>(value); 361 rmode_ = kRelocInfo_NONEPTR; 362 } 363 364 Operand::Operand(Register rm) { 365 rm_ = rm; 366 rmode_ = kRelocInfo_NONEPTR; // S390 -why doesn't ARM do this? 367 } 368 369 void Assembler::CheckBuffer() { 370 if (buffer_space() <= kGap) { 371 GrowBuffer(); 372 } 373 } 374 375 int32_t Assembler::emit_code_target(Handle<Code> target, RelocInfo::Mode rmode, 376 TypeFeedbackId ast_id) { 377 DCHECK(RelocInfo::IsCodeTarget(rmode)); 378 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) { 379 SetRecordedAstId(ast_id); 380 RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID); 381 } else { 382 RecordRelocInfo(rmode); 383 } 384 385 int current = code_targets_.length(); 386 if (current > 0 && code_targets_.last().is_identical_to(target)) { 387 // Optimization if we keep jumping to the same code target. 388 current--; 389 } else { 390 code_targets_.Add(target); 391 } 392 return current; 393 } 394 395 // Helper to emit the binary encoding of a 2 byte instruction 396 void Assembler::emit2bytes(uint16_t x) { 397 CheckBuffer(); 398 #if V8_TARGET_LITTLE_ENDIAN 399 // We need to emit instructions in big endian format as disassembler / 400 // simulator require the first byte of the instruction in order to decode 401 // the instruction length. Swap the bytes. 402 x = ((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8); 403 #endif 404 *reinterpret_cast<uint16_t*>(pc_) = x; 405 pc_ += 2; 406 } 407 408 // Helper to emit the binary encoding of a 4 byte instruction 409 void Assembler::emit4bytes(uint32_t x) { 410 CheckBuffer(); 411 #if V8_TARGET_LITTLE_ENDIAN 412 // We need to emit instructions in big endian format as disassembler / 413 // simulator require the first byte of the instruction in order to decode 414 // the instruction length. Swap the bytes. 415 x = ((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | 416 ((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24); 417 #endif 418 *reinterpret_cast<uint32_t*>(pc_) = x; 419 pc_ += 4; 420 } 421 422 // Helper to emit the binary encoding of a 6 byte instruction 423 void Assembler::emit6bytes(uint64_t x) { 424 CheckBuffer(); 425 #if V8_TARGET_LITTLE_ENDIAN 426 // We need to emit instructions in big endian format as disassembler / 427 // simulator require the first byte of the instruction in order to decode 428 // the instruction length. Swap the bytes. 429 x = (static_cast<uint64_t>(x & 0xFF) << 40) | 430 (static_cast<uint64_t>((x >> 8) & 0xFF) << 32) | 431 (static_cast<uint64_t>((x >> 16) & 0xFF) << 24) | 432 (static_cast<uint64_t>((x >> 24) & 0xFF) << 16) | 433 (static_cast<uint64_t>((x >> 32) & 0xFF) << 8) | 434 (static_cast<uint64_t>((x >> 40) & 0xFF)); 435 x |= (*reinterpret_cast<uint64_t*>(pc_) >> 48) << 48; 436 #else 437 // We need to pad two bytes of zeros in order to get the 6-bytes 438 // stored from low address. 439 x = x << 16; 440 x |= *reinterpret_cast<uint64_t*>(pc_) & 0xFFFF; 441 #endif 442 // It is safe to store 8-bytes, as CheckBuffer() guarantees we have kGap 443 // space left over. 444 *reinterpret_cast<uint64_t*>(pc_) = x; 445 pc_ += 6; 446 } 447 448 bool Operand::is_reg() const { return rm_.is_valid(); } 449 450 // Fetch the 32bit value from the FIXED_SEQUENCE IIHF / IILF 451 Address Assembler::target_address_at(Address pc, Address constant_pool) { 452 // S390 Instruction! 453 // We want to check for instructions generated by Asm::mov() 454 Opcode op1 = Instruction::S390OpcodeValue(reinterpret_cast<const byte*>(pc)); 455 SixByteInstr instr_1 = 456 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc)); 457 458 if (BRASL == op1 || BRCL == op1) { 459 int32_t dis = static_cast<int32_t>(instr_1 & 0xFFFFFFFF) * 2; 460 return reinterpret_cast<Address>(reinterpret_cast<uint64_t>(pc) + dis); 461 } 462 463 #if V8_TARGET_ARCH_S390X 464 int instr1_length = 465 Instruction::InstructionLength(reinterpret_cast<const byte*>(pc)); 466 Opcode op2 = Instruction::S390OpcodeValue( 467 reinterpret_cast<const byte*>(pc + instr1_length)); 468 SixByteInstr instr_2 = Instruction::InstructionBits( 469 reinterpret_cast<const byte*>(pc + instr1_length)); 470 // IIHF for hi_32, IILF for lo_32 471 if (IIHF == op1 && IILF == op2) { 472 return reinterpret_cast<Address>(((instr_1 & 0xFFFFFFFF) << 32) | 473 ((instr_2 & 0xFFFFFFFF))); 474 } 475 #else 476 // IILF loads 32-bits 477 if (IILF == op1 || CFI == op1) { 478 return reinterpret_cast<Address>((instr_1 & 0xFFFFFFFF)); 479 } 480 #endif 481 482 UNIMPLEMENTED(); 483 return (Address)0; 484 } 485 486 // This sets the branch destination (which gets loaded at the call address). 487 // This is for calls and branches within generated code. The serializer 488 // has already deserialized the mov instructions etc. 489 // There is a FIXED_SEQUENCE assumption here 490 void Assembler::deserialization_set_special_target_at( 491 Isolate* isolate, Address instruction_payload, Code* code, Address target) { 492 set_target_address_at(isolate, instruction_payload, code, target); 493 } 494 495 void Assembler::deserialization_set_target_internal_reference_at( 496 Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) { 497 if (RelocInfo::IsInternalReferenceEncoded(mode)) { 498 Code* code = NULL; 499 set_target_address_at(isolate, pc, code, target, SKIP_ICACHE_FLUSH); 500 } else { 501 Memory::Address_at(pc) = target; 502 } 503 } 504 505 // This code assumes the FIXED_SEQUENCE of IIHF/IILF 506 void Assembler::set_target_address_at(Isolate* isolate, Address pc, 507 Address constant_pool, Address target, 508 ICacheFlushMode icache_flush_mode) { 509 // Check for instructions generated by Asm::mov() 510 Opcode op1 = Instruction::S390OpcodeValue(reinterpret_cast<const byte*>(pc)); 511 SixByteInstr instr_1 = 512 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc)); 513 bool patched = false; 514 515 if (BRASL == op1 || BRCL == op1) { 516 instr_1 >>= 32; // Zero out the lower 32-bits 517 instr_1 <<= 32; 518 int32_t halfwords = (target - pc) / 2; // number of halfwords 519 instr_1 |= static_cast<uint32_t>(halfwords); 520 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc), 521 instr_1); 522 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 523 Assembler::FlushICache(isolate, pc, 6); 524 } 525 patched = true; 526 } else { 527 #if V8_TARGET_ARCH_S390X 528 int instr1_length = 529 Instruction::InstructionLength(reinterpret_cast<const byte*>(pc)); 530 Opcode op2 = Instruction::S390OpcodeValue( 531 reinterpret_cast<const byte*>(pc + instr1_length)); 532 SixByteInstr instr_2 = Instruction::InstructionBits( 533 reinterpret_cast<const byte*>(pc + instr1_length)); 534 // IIHF for hi_32, IILF for lo_32 535 if (IIHF == op1 && IILF == op2) { 536 // IIHF 537 instr_1 >>= 32; // Zero out the lower 32-bits 538 instr_1 <<= 32; 539 instr_1 |= reinterpret_cast<uint64_t>(target) >> 32; 540 541 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc), 542 instr_1); 543 544 // IILF 545 instr_2 >>= 32; 546 instr_2 <<= 32; 547 instr_2 |= reinterpret_cast<uint64_t>(target) & 0xFFFFFFFF; 548 549 Instruction::SetInstructionBits<SixByteInstr>( 550 reinterpret_cast<byte*>(pc + instr1_length), instr_2); 551 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 552 Assembler::FlushICache(isolate, pc, 12); 553 } 554 patched = true; 555 } 556 #else 557 // IILF loads 32-bits 558 if (IILF == op1 || CFI == op1) { 559 instr_1 >>= 32; // Zero out the lower 32-bits 560 instr_1 <<= 32; 561 instr_1 |= reinterpret_cast<uint32_t>(target); 562 563 Instruction::SetInstructionBits<SixByteInstr>(reinterpret_cast<byte*>(pc), 564 instr_1); 565 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 566 Assembler::FlushICache(isolate, pc, 6); 567 } 568 patched = true; 569 } 570 #endif 571 } 572 if (!patched) UNREACHABLE(); 573 } 574 575 } // namespace internal 576 } // namespace v8 577 578 #endif // V8_S390_ASSEMBLER_S390_INL_H_ 579