Home | History | Annotate | Download | only in ppc
      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_PPC_ASSEMBLER_PPC_INL_H_
     38 #define V8_PPC_ASSEMBLER_PPC_INL_H_
     39 
     40 #include "src/ppc/assembler-ppc.h"
     41 
     42 #include "src/assembler.h"
     43 #include "src/debug/debug.h"
     44 
     45 
     46 namespace v8 {
     47 namespace internal {
     48 
     49 
     50 bool CpuFeatures::SupportsCrankshaft() { return true; }
     51 
     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 {
     60     // mov sequence
     61     DCHECK(IsInternalReferenceEncoded(rmode_));
     62     Address target = Assembler::target_address_at(pc_, host_);
     63     Assembler::set_target_address_at(isolate_, pc_, host_, target + delta,
     64                                      SKIP_ICACHE_FLUSH);
     65   }
     66 }
     67 
     68 
     69 Address RelocInfo::target_internal_reference() {
     70   if (IsInternalReference(rmode_)) {
     71     // Jump table entry
     72     return Memory::Address_at(pc_);
     73   } else {
     74     // mov sequence
     75     DCHECK(IsInternalReferenceEncoded(rmode_));
     76     return Assembler::target_address_at(pc_, host_);
     77   }
     78 }
     79 
     80 
     81 Address RelocInfo::target_internal_reference_address() {
     82   DCHECK(IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_));
     83   return reinterpret_cast<Address>(pc_);
     84 }
     85 
     86 
     87 Address RelocInfo::target_address() {
     88   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
     89   return Assembler::target_address_at(pc_, host_);
     90 }
     91 
     92 Address RelocInfo::target_address_address() {
     93   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) ||
     94          rmode_ == EMBEDDED_OBJECT || rmode_ == EXTERNAL_REFERENCE);
     95 
     96   if (FLAG_enable_embedded_constant_pool &&
     97       Assembler::IsConstantPoolLoadStart(pc_)) {
     98     // We return the PC for embedded constant pool since this function is used
     99     // by the serializer and expects the address to reside within the code
    100     // object.
    101     return reinterpret_cast<Address>(pc_);
    102   }
    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 reinterpret_cast<Address>(pc_);
    114 }
    115 
    116 
    117 Address RelocInfo::constant_pool_entry_address() {
    118   if (FLAG_enable_embedded_constant_pool) {
    119     Address constant_pool = host_->constant_pool();
    120     DCHECK(constant_pool);
    121     ConstantPoolEntry::Access access;
    122     if (Assembler::IsConstantPoolLoadStart(pc_, &access))
    123       return Assembler::target_constant_pool_address_at(
    124           pc_, constant_pool, access, ConstantPoolEntry::INTPTR);
    125   }
    126   UNREACHABLE();
    127   return NULL;
    128 }
    129 
    130 
    131 int RelocInfo::target_address_size() { return Assembler::kSpecialTargetSize; }
    132 
    133 
    134 void RelocInfo::set_target_address(Address target,
    135                                    WriteBarrierMode write_barrier_mode,
    136                                    ICacheFlushMode icache_flush_mode) {
    137   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
    138   Assembler::set_target_address_at(isolate_, pc_, host_, target,
    139                                    icache_flush_mode);
    140   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
    141       IsCodeTarget(rmode_)) {
    142     Object* target_code = Code::GetCodeFromTargetAddress(target);
    143     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
    144         host(), this, HeapObject::cast(target_code));
    145   }
    146 }
    147 
    148 
    149 Address Assembler::target_address_from_return_address(Address pc) {
    150 // Returns the address of the call target from the return address that will
    151 // be returned to after a call.
    152 // Call sequence is :
    153 //  mov   ip, @ call address
    154 //  mtlr  ip
    155 //  blrl
    156 //                      @ return address
    157   int len;
    158   ConstantPoolEntry::Access access;
    159   if (FLAG_enable_embedded_constant_pool &&
    160       IsConstantPoolLoadEnd(pc - 3 * kInstrSize, &access)) {
    161     len = (access == ConstantPoolEntry::OVERFLOWED) ? 2 : 1;
    162   } else {
    163     len = kMovInstructionsNoConstantPool;
    164   }
    165   return pc - (len + 2) * kInstrSize;
    166 }
    167 
    168 
    169 Address Assembler::return_address_from_call_start(Address pc) {
    170   int len;
    171   ConstantPoolEntry::Access access;
    172   if (FLAG_enable_embedded_constant_pool &&
    173       IsConstantPoolLoadStart(pc, &access)) {
    174     len = (access == ConstantPoolEntry::OVERFLOWED) ? 2 : 1;
    175   } else {
    176     len = kMovInstructionsNoConstantPool;
    177   }
    178   return pc + (len + 2) * kInstrSize;
    179 }
    180 
    181 Object* RelocInfo::target_object() {
    182   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    183   return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
    184 }
    185 
    186 
    187 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
    188   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    189   return Handle<Object>(
    190       reinterpret_cast<Object**>(Assembler::target_address_at(pc_, host_)));
    191 }
    192 
    193 
    194 void RelocInfo::set_target_object(Object* target,
    195                                   WriteBarrierMode write_barrier_mode,
    196                                   ICacheFlushMode icache_flush_mode) {
    197   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    198   Assembler::set_target_address_at(isolate_, pc_, host_,
    199                                    reinterpret_cast<Address>(target),
    200                                    icache_flush_mode);
    201   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
    202       target->IsHeapObject()) {
    203     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
    204         host(), this, HeapObject::cast(target));
    205   }
    206 }
    207 
    208 
    209 Address RelocInfo::target_external_reference() {
    210   DCHECK(rmode_ == EXTERNAL_REFERENCE);
    211   return Assembler::target_address_at(pc_, host_);
    212 }
    213 
    214 
    215 Address RelocInfo::target_runtime_entry(Assembler* origin) {
    216   DCHECK(IsRuntimeEntry(rmode_));
    217   return target_address();
    218 }
    219 
    220 
    221 void RelocInfo::set_target_runtime_entry(Address target,
    222                                          WriteBarrierMode write_barrier_mode,
    223                                          ICacheFlushMode icache_flush_mode) {
    224   DCHECK(IsRuntimeEntry(rmode_));
    225   if (target_address() != target)
    226     set_target_address(target, write_barrier_mode, icache_flush_mode);
    227 }
    228 
    229 
    230 Handle<Cell> RelocInfo::target_cell_handle() {
    231   DCHECK(rmode_ == RelocInfo::CELL);
    232   Address address = Memory::Address_at(pc_);
    233   return Handle<Cell>(reinterpret_cast<Cell**>(address));
    234 }
    235 
    236 
    237 Cell* RelocInfo::target_cell() {
    238   DCHECK(rmode_ == RelocInfo::CELL);
    239   return Cell::FromValueAddress(Memory::Address_at(pc_));
    240 }
    241 
    242 
    243 void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode write_barrier_mode,
    244                                 ICacheFlushMode icache_flush_mode) {
    245   DCHECK(rmode_ == RelocInfo::CELL);
    246   Address address = cell->address() + Cell::kValueOffset;
    247   Memory::Address_at(pc_) = address;
    248   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
    249     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this,
    250                                                                   cell);
    251   }
    252 }
    253 
    254 
    255 static const int kNoCodeAgeInstructions =
    256     FLAG_enable_embedded_constant_pool ? 7 : 6;
    257 static const int kCodeAgingInstructions =
    258     Assembler::kMovInstructionsNoConstantPool + 3;
    259 static const int kNoCodeAgeSequenceInstructions =
    260     ((kNoCodeAgeInstructions >= kCodeAgingInstructions)
    261          ? kNoCodeAgeInstructions
    262          : kCodeAgingInstructions);
    263 static const int kNoCodeAgeSequenceNops =
    264     (kNoCodeAgeSequenceInstructions - kNoCodeAgeInstructions);
    265 static const int kCodeAgingSequenceNops =
    266     (kNoCodeAgeSequenceInstructions - kCodeAgingInstructions);
    267 static const int kCodeAgingTargetDelta = 1 * Assembler::kInstrSize;
    268 static const int kNoCodeAgeSequenceLength =
    269     (kNoCodeAgeSequenceInstructions * Assembler::kInstrSize);
    270 
    271 
    272 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
    273   UNREACHABLE();  // This should never be reached on PPC.
    274   return Handle<Object>();
    275 }
    276 
    277 
    278 Code* RelocInfo::code_age_stub() {
    279   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
    280   return Code::GetCodeFromTargetAddress(
    281       Assembler::target_address_at(pc_ + kCodeAgingTargetDelta, host_));
    282 }
    283 
    284 
    285 void RelocInfo::set_code_age_stub(Code* stub,
    286                                   ICacheFlushMode icache_flush_mode) {
    287   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
    288   Assembler::set_target_address_at(isolate_, pc_ + kCodeAgingTargetDelta, host_,
    289                                    stub->instruction_start(),
    290                                    icache_flush_mode);
    291 }
    292 
    293 
    294 Address RelocInfo::debug_call_address() {
    295   DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
    296   return Assembler::target_address_at(pc_, host_);
    297 }
    298 
    299 
    300 void RelocInfo::set_debug_call_address(Address target) {
    301   DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
    302   Assembler::set_target_address_at(isolate_, pc_, host_, target);
    303   if (host() != NULL) {
    304     Object* target_code = Code::GetCodeFromTargetAddress(target);
    305     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
    306         host(), this, HeapObject::cast(target_code));
    307   }
    308 }
    309 
    310 
    311 void RelocInfo::WipeOut() {
    312   DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
    313          IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
    314          IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_));
    315   if (IsInternalReference(rmode_)) {
    316     // Jump table entry
    317     Memory::Address_at(pc_) = NULL;
    318   } else if (IsInternalReferenceEncoded(rmode_)) {
    319     // mov sequence
    320     // Currently used only by deserializer, no need to flush.
    321     Assembler::set_target_address_at(isolate_, pc_, host_, NULL,
    322                                      SKIP_ICACHE_FLUSH);
    323   } else {
    324     Assembler::set_target_address_at(isolate_, pc_, host_, NULL);
    325   }
    326 }
    327 
    328 template <typename ObjectVisitor>
    329 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
    330   RelocInfo::Mode mode = rmode();
    331   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    332     visitor->VisitEmbeddedPointer(this);
    333   } else if (RelocInfo::IsCodeTarget(mode)) {
    334     visitor->VisitCodeTarget(this);
    335   } else if (mode == RelocInfo::CELL) {
    336     visitor->VisitCell(this);
    337   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    338     visitor->VisitExternalReference(this);
    339   } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
    340              mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
    341     visitor->VisitInternalReference(this);
    342   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    343     visitor->VisitCodeAgeSequence(this);
    344   } else if (RelocInfo::IsDebugBreakSlot(mode) &&
    345              IsPatchedDebugBreakSlotSequence()) {
    346     visitor->VisitDebugTarget(this);
    347   } else if (IsRuntimeEntry(mode)) {
    348     visitor->VisitRuntimeEntry(this);
    349   }
    350 }
    351 
    352 
    353 template <typename StaticVisitor>
    354 void RelocInfo::Visit(Heap* heap) {
    355   RelocInfo::Mode mode = rmode();
    356   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    357     StaticVisitor::VisitEmbeddedPointer(heap, this);
    358   } else if (RelocInfo::IsCodeTarget(mode)) {
    359     StaticVisitor::VisitCodeTarget(heap, this);
    360   } else if (mode == RelocInfo::CELL) {
    361     StaticVisitor::VisitCell(heap, this);
    362   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    363     StaticVisitor::VisitExternalReference(this);
    364   } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
    365              mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
    366     StaticVisitor::VisitInternalReference(this);
    367   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    368     StaticVisitor::VisitCodeAgeSequence(heap, this);
    369   } else if (RelocInfo::IsDebugBreakSlot(mode) &&
    370              IsPatchedDebugBreakSlotSequence()) {
    371     StaticVisitor::VisitDebugTarget(heap, this);
    372   } else if (IsRuntimeEntry(mode)) {
    373     StaticVisitor::VisitRuntimeEntry(this);
    374   }
    375 }
    376 
    377 Operand::Operand(intptr_t immediate, RelocInfo::Mode rmode) {
    378   rm_ = no_reg;
    379   imm_ = immediate;
    380   rmode_ = rmode;
    381 }
    382 
    383 Operand::Operand(const ExternalReference& f) {
    384   rm_ = no_reg;
    385   imm_ = reinterpret_cast<intptr_t>(f.address());
    386   rmode_ = RelocInfo::EXTERNAL_REFERENCE;
    387 }
    388 
    389 Operand::Operand(Smi* value) {
    390   rm_ = no_reg;
    391   imm_ = reinterpret_cast<intptr_t>(value);
    392   rmode_ = kRelocInfo_NONEPTR;
    393 }
    394 
    395 Operand::Operand(Register rm) {
    396   rm_ = rm;
    397   rmode_ = kRelocInfo_NONEPTR;  // PPC -why doesn't ARM do this?
    398 }
    399 
    400 void Assembler::CheckBuffer() {
    401   if (buffer_space() <= kGap) {
    402     GrowBuffer();
    403   }
    404 }
    405 
    406 void Assembler::TrackBranch() {
    407   DCHECK(!trampoline_emitted_);
    408   int count = tracked_branch_count_++;
    409   if (count == 0) {
    410     // We leave space (kMaxBlockTrampolineSectionSize)
    411     // for BlockTrampolinePoolScope buffer.
    412     next_trampoline_check_ =
    413         pc_offset() + kMaxCondBranchReach - kMaxBlockTrampolineSectionSize;
    414   } else {
    415     next_trampoline_check_ -= kTrampolineSlotsSize;
    416   }
    417 }
    418 
    419 void Assembler::UntrackBranch() {
    420   DCHECK(!trampoline_emitted_);
    421   DCHECK(tracked_branch_count_ > 0);
    422   int count = --tracked_branch_count_;
    423   if (count == 0) {
    424     // Reset
    425     next_trampoline_check_ = kMaxInt;
    426   } else {
    427     next_trampoline_check_ += kTrampolineSlotsSize;
    428   }
    429 }
    430 
    431 void Assembler::CheckTrampolinePoolQuick() {
    432   if (pc_offset() >= next_trampoline_check_) {
    433     CheckTrampolinePool();
    434   }
    435 }
    436 
    437 void Assembler::emit(Instr x) {
    438   CheckBuffer();
    439   *reinterpret_cast<Instr*>(pc_) = x;
    440   pc_ += kInstrSize;
    441   CheckTrampolinePoolQuick();
    442 }
    443 
    444 bool Operand::is_reg() const { return rm_.is_valid(); }
    445 
    446 
    447 // Fetch the 32bit value from the FIXED_SEQUENCE lis/ori
    448 Address Assembler::target_address_at(Address pc, Address constant_pool) {
    449   if (FLAG_enable_embedded_constant_pool && constant_pool) {
    450     ConstantPoolEntry::Access access;
    451     if (IsConstantPoolLoadStart(pc, &access))
    452       return Memory::Address_at(target_constant_pool_address_at(
    453           pc, constant_pool, access, ConstantPoolEntry::INTPTR));
    454   }
    455 
    456   Instr instr1 = instr_at(pc);
    457   Instr instr2 = instr_at(pc + kInstrSize);
    458   // Interpret 2 instructions generated by lis/ori
    459   if (IsLis(instr1) && IsOri(instr2)) {
    460 #if V8_TARGET_ARCH_PPC64
    461     Instr instr4 = instr_at(pc + (3 * kInstrSize));
    462     Instr instr5 = instr_at(pc + (4 * kInstrSize));
    463     // Assemble the 64 bit value.
    464     uint64_t hi = (static_cast<uint32_t>((instr1 & kImm16Mask) << 16) |
    465                    static_cast<uint32_t>(instr2 & kImm16Mask));
    466     uint64_t lo = (static_cast<uint32_t>((instr4 & kImm16Mask) << 16) |
    467                    static_cast<uint32_t>(instr5 & kImm16Mask));
    468     return reinterpret_cast<Address>((hi << 32) | lo);
    469 #else
    470     // Assemble the 32 bit value.
    471     return reinterpret_cast<Address>(((instr1 & kImm16Mask) << 16) |
    472                                      (instr2 & kImm16Mask));
    473 #endif
    474   }
    475 
    476   UNREACHABLE();
    477   return NULL;
    478 }
    479 
    480 
    481 #if V8_TARGET_ARCH_PPC64
    482 const int kLoadIntptrOpcode = LD;
    483 #else
    484 const int kLoadIntptrOpcode = LWZ;
    485 #endif
    486 
    487 // Constant pool load sequence detection:
    488 // 1) REGULAR access:
    489 //    load <dst>, kConstantPoolRegister + <offset>
    490 //
    491 // 2) OVERFLOWED access:
    492 //    addis <scratch>, kConstantPoolRegister, <offset_high>
    493 //    load <dst>, <scratch> + <offset_low>
    494 bool Assembler::IsConstantPoolLoadStart(Address pc,
    495                                         ConstantPoolEntry::Access* access) {
    496   Instr instr = instr_at(pc);
    497   int opcode = instr & kOpcodeMask;
    498   if (!GetRA(instr).is(kConstantPoolRegister)) return false;
    499   bool overflowed = (opcode == ADDIS);
    500 #ifdef DEBUG
    501   if (overflowed) {
    502     opcode = instr_at(pc + kInstrSize) & kOpcodeMask;
    503   }
    504   DCHECK(opcode == kLoadIntptrOpcode || opcode == LFD);
    505 #endif
    506   if (access) {
    507     *access = (overflowed ? ConstantPoolEntry::OVERFLOWED
    508                           : ConstantPoolEntry::REGULAR);
    509   }
    510   return true;
    511 }
    512 
    513 
    514 bool Assembler::IsConstantPoolLoadEnd(Address pc,
    515                                       ConstantPoolEntry::Access* access) {
    516   Instr instr = instr_at(pc);
    517   int opcode = instr & kOpcodeMask;
    518   bool overflowed = false;
    519   if (!(opcode == kLoadIntptrOpcode || opcode == LFD)) return false;
    520   if (!GetRA(instr).is(kConstantPoolRegister)) {
    521     instr = instr_at(pc - kInstrSize);
    522     opcode = instr & kOpcodeMask;
    523     if ((opcode != ADDIS) || !GetRA(instr).is(kConstantPoolRegister)) {
    524       return false;
    525     }
    526     overflowed = true;
    527   }
    528   if (access) {
    529     *access = (overflowed ? ConstantPoolEntry::OVERFLOWED
    530                           : ConstantPoolEntry::REGULAR);
    531   }
    532   return true;
    533 }
    534 
    535 
    536 int Assembler::GetConstantPoolOffset(Address pc,
    537                                      ConstantPoolEntry::Access access,
    538                                      ConstantPoolEntry::Type type) {
    539   bool overflowed = (access == ConstantPoolEntry::OVERFLOWED);
    540 #ifdef DEBUG
    541   ConstantPoolEntry::Access access_check =
    542       static_cast<ConstantPoolEntry::Access>(-1);
    543   DCHECK(IsConstantPoolLoadStart(pc, &access_check));
    544   DCHECK(access_check == access);
    545 #endif
    546   int offset;
    547   if (overflowed) {
    548     offset = (instr_at(pc) & kImm16Mask) << 16;
    549     offset += SIGN_EXT_IMM16(instr_at(pc + kInstrSize) & kImm16Mask);
    550     DCHECK(!is_int16(offset));
    551   } else {
    552     offset = SIGN_EXT_IMM16((instr_at(pc) & kImm16Mask));
    553   }
    554   return offset;
    555 }
    556 
    557 
    558 void Assembler::PatchConstantPoolAccessInstruction(
    559     int pc_offset, int offset, ConstantPoolEntry::Access access,
    560     ConstantPoolEntry::Type type) {
    561   Address pc = buffer_ + pc_offset;
    562   bool overflowed = (access == ConstantPoolEntry::OVERFLOWED);
    563   CHECK(overflowed != is_int16(offset));
    564 #ifdef DEBUG
    565   ConstantPoolEntry::Access access_check =
    566       static_cast<ConstantPoolEntry::Access>(-1);
    567   DCHECK(IsConstantPoolLoadStart(pc, &access_check));
    568   DCHECK(access_check == access);
    569 #endif
    570   if (overflowed) {
    571     int hi_word = static_cast<int>(offset >> 16);
    572     int lo_word = static_cast<int>(offset & 0xffff);
    573     if (lo_word & 0x8000) hi_word++;
    574 
    575     Instr instr1 = instr_at(pc);
    576     Instr instr2 = instr_at(pc + kInstrSize);
    577     instr1 &= ~kImm16Mask;
    578     instr1 |= (hi_word & kImm16Mask);
    579     instr2 &= ~kImm16Mask;
    580     instr2 |= (lo_word & kImm16Mask);
    581     instr_at_put(pc, instr1);
    582     instr_at_put(pc + kInstrSize, instr2);
    583   } else {
    584     Instr instr = instr_at(pc);
    585     instr &= ~kImm16Mask;
    586     instr |= (offset & kImm16Mask);
    587     instr_at_put(pc, instr);
    588   }
    589 }
    590 
    591 
    592 Address Assembler::target_constant_pool_address_at(
    593     Address pc, Address constant_pool, ConstantPoolEntry::Access access,
    594     ConstantPoolEntry::Type type) {
    595   Address addr = constant_pool;
    596   DCHECK(addr);
    597   addr += GetConstantPoolOffset(pc, access, type);
    598   return addr;
    599 }
    600 
    601 
    602 // This sets the branch destination (which gets loaded at the call address).
    603 // This is for calls and branches within generated code.  The serializer
    604 // has already deserialized the mov instructions etc.
    605 // There is a FIXED_SEQUENCE assumption here
    606 void Assembler::deserialization_set_special_target_at(
    607     Isolate* isolate, Address instruction_payload, Code* code, Address target) {
    608   set_target_address_at(isolate, instruction_payload, code, target);
    609 }
    610 
    611 
    612 void Assembler::deserialization_set_target_internal_reference_at(
    613     Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) {
    614   if (RelocInfo::IsInternalReferenceEncoded(mode)) {
    615     Code* code = NULL;
    616     set_target_address_at(isolate, pc, code, target, SKIP_ICACHE_FLUSH);
    617   } else {
    618     Memory::Address_at(pc) = target;
    619   }
    620 }
    621 
    622 
    623 // This code assumes the FIXED_SEQUENCE of lis/ori
    624 void Assembler::set_target_address_at(Isolate* isolate, Address pc,
    625                                       Address constant_pool, Address target,
    626                                       ICacheFlushMode icache_flush_mode) {
    627   if (FLAG_enable_embedded_constant_pool && constant_pool) {
    628     ConstantPoolEntry::Access access;
    629     if (IsConstantPoolLoadStart(pc, &access)) {
    630       Memory::Address_at(target_constant_pool_address_at(
    631           pc, constant_pool, access, ConstantPoolEntry::INTPTR)) = target;
    632       return;
    633     }
    634   }
    635 
    636   Instr instr1 = instr_at(pc);
    637   Instr instr2 = instr_at(pc + kInstrSize);
    638   // Interpret 2 instructions generated by lis/ori
    639   if (IsLis(instr1) && IsOri(instr2)) {
    640 #if V8_TARGET_ARCH_PPC64
    641     Instr instr4 = instr_at(pc + (3 * kInstrSize));
    642     Instr instr5 = instr_at(pc + (4 * kInstrSize));
    643     // Needs to be fixed up when mov changes to handle 64-bit values.
    644     uint32_t* p = reinterpret_cast<uint32_t*>(pc);
    645     uintptr_t itarget = reinterpret_cast<uintptr_t>(target);
    646 
    647     instr5 &= ~kImm16Mask;
    648     instr5 |= itarget & kImm16Mask;
    649     itarget = itarget >> 16;
    650 
    651     instr4 &= ~kImm16Mask;
    652     instr4 |= itarget & kImm16Mask;
    653     itarget = itarget >> 16;
    654 
    655     instr2 &= ~kImm16Mask;
    656     instr2 |= itarget & kImm16Mask;
    657     itarget = itarget >> 16;
    658 
    659     instr1 &= ~kImm16Mask;
    660     instr1 |= itarget & kImm16Mask;
    661     itarget = itarget >> 16;
    662 
    663     *p = instr1;
    664     *(p + 1) = instr2;
    665     *(p + 3) = instr4;
    666     *(p + 4) = instr5;
    667     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
    668       Assembler::FlushICache(isolate, p, 5 * kInstrSize);
    669     }
    670 #else
    671     uint32_t* p = reinterpret_cast<uint32_t*>(pc);
    672     uint32_t itarget = reinterpret_cast<uint32_t>(target);
    673     int lo_word = itarget & kImm16Mask;
    674     int hi_word = itarget >> 16;
    675     instr1 &= ~kImm16Mask;
    676     instr1 |= hi_word;
    677     instr2 &= ~kImm16Mask;
    678     instr2 |= lo_word;
    679 
    680     *p = instr1;
    681     *(p + 1) = instr2;
    682     if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
    683       Assembler::FlushICache(isolate, p, 2 * kInstrSize);
    684     }
    685 #endif
    686     return;
    687   }
    688   UNREACHABLE();
    689 }
    690 }  // namespace internal
    691 }  // namespace v8
    692 
    693 #endif  // V8_PPC_ASSEMBLER_PPC_INL_H_
    694