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 46namespace v8 { 47namespace internal { 48 49bool CpuFeatures::SupportsCrankshaft() { return true; } 50 51bool CpuFeatures::SupportsSimd128() { return false; } 52 53void 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 78Address 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 89Address RelocInfo::target_internal_reference_address() { 90 DCHECK(IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)); 91 return reinterpret_cast<Address>(pc_); 92} 93 94Address RelocInfo::target_address() { 95 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); 96 return Assembler::target_address_at(pc_, host_); 97} 98 99Address 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 115Address RelocInfo::constant_pool_entry_address() { 116 UNREACHABLE(); 117 return NULL; 118} 119 120int RelocInfo::target_address_size() { return Assembler::kSpecialTargetSize; } 121 122Address 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 127void 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 134Address 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 142Address Assembler::return_address_from_call_start(Address pc) { 143 // Sequence is: 144 // BRASL r14, RI 145 return pc + kCallTargetAddressOffset; 146} 147 148Handle<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 155Object* RelocInfo::target_object() { 156 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 157 return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_)); 158} 159 160Handle<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 170void 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 185Address RelocInfo::target_external_reference() { 186 DCHECK(rmode_ == EXTERNAL_REFERENCE); 187 return Assembler::target_address_at(pc_, host_); 188} 189 190Address RelocInfo::target_runtime_entry(Assembler* origin) { 191 DCHECK(IsRuntimeEntry(rmode_)); 192 return target_address(); 193} 194 195void 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 203Handle<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 209Cell* RelocInfo::target_cell() { 210 DCHECK(rmode_ == RelocInfo::CELL); 211 return Cell::FromValueAddress(Memory::Address_at(pc_)); 212} 213 214void 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 228static const int kCodeAgingSequenceLength = 28; 229static const int kCodeAgingTargetDelta = 14; // Jump past NOP + PUSH to IIHF 230 // LAY + 4 * STG + LA 231static const int kNoCodeAgeSequenceLength = 34; 232#else 233#if (V8_HOST_ARCH_S390) 234// NOP + NILH + LAY + ST + IILF + BASR 235static const int kCodeAgingSequenceLength = 24; 236static const int kCodeAgingTargetDelta = 16; // Jump past NOP to IILF 237// NILH + LAY + 4 * ST + LA 238static const int kNoCodeAgeSequenceLength = 30; 239#else 240// NOP + LAY + ST + IILF + BASR 241static const int kCodeAgingSequenceLength = 20; 242static const int kCodeAgingTargetDelta = 12; // Jump past NOP to IILF 243// LAY + 4 * ST + LA 244static const int kNoCodeAgeSequenceLength = 26; 245#endif 246#endif 247 248Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) { 249 UNREACHABLE(); // This should never be reached on S390. 250 return Handle<Object>(); 251} 252 253Code* 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 259void 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 267Address RelocInfo::debug_call_address() { 268 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); 269 return Assembler::target_address_at(pc_, host_); 270} 271 272void 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 282void 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 299template <typename ObjectVisitor> 300void 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 322template <typename StaticVisitor> 323void 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 346Operand::Operand(intptr_t immediate, RelocInfo::Mode rmode) { 347 rm_ = no_reg; 348 imm_ = immediate; 349 rmode_ = rmode; 350} 351 352Operand::Operand(const ExternalReference& f) { 353 rm_ = no_reg; 354 imm_ = reinterpret_cast<intptr_t>(f.address()); 355 rmode_ = RelocInfo::EXTERNAL_REFERENCE; 356} 357 358Operand::Operand(Smi* value) { 359 rm_ = no_reg; 360 imm_ = reinterpret_cast<intptr_t>(value); 361 rmode_ = kRelocInfo_NONEPTR; 362} 363 364Operand::Operand(Register rm) { 365 rm_ = rm; 366 rmode_ = kRelocInfo_NONEPTR; // S390 -why doesn't ARM do this? 367} 368 369void Assembler::CheckBuffer() { 370 if (buffer_space() <= kGap) { 371 GrowBuffer(); 372 } 373} 374 375int32_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 396void 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 409void 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 423void 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 448bool Operand::is_reg() const { return rm_.is_valid(); } 449 450// Fetch the 32bit value from the FIXED_SEQUENCE IIHF / IILF 451Address 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 490void 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 495void 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 506void 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