Home | History | Annotate | Download | only in mips64
      1 
      2 // Copyright (c) 1994-2006 Sun Microsystems Inc.
      3 // All Rights Reserved.
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 // - Redistributions of source code must retain the above copyright notice,
     10 // this list of conditions and the following disclaimer.
     11 //
     12 // - Redistribution in binary form must reproduce the above copyright
     13 // notice, this list of conditions and the following disclaimer in the
     14 // documentation and/or other materials provided with the 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 "AS
     21 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     22 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 
     32 // The original source code covered by the above license above has been
     33 // modified significantly by Google Inc.
     34 // Copyright 2012 the V8 project authors. All rights reserved.
     35 
     36 #ifndef V8_MIPS64_ASSEMBLER_MIPS64_INL_H_
     37 #define V8_MIPS64_ASSEMBLER_MIPS64_INL_H_
     38 
     39 #include "src/mips64/assembler-mips64.h"
     40 
     41 #include "src/assembler.h"
     42 #include "src/debug/debug.h"
     43 #include "src/objects-inl.h"
     44 
     45 namespace v8 {
     46 namespace internal {
     47 
     48 bool CpuFeatures::SupportsOptimizer() { return IsSupported(FPU); }
     49 
     50 bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(MIPS_SIMD); }
     51 
     52 // -----------------------------------------------------------------------------
     53 // Operand and MemOperand.
     54 
     55 bool Operand::is_reg() const {
     56   return rm_.is_valid();
     57 }
     58 
     59 int64_t Operand::immediate() const {
     60   DCHECK(!is_reg());
     61   DCHECK(!IsHeapObjectRequest());
     62   return value_.immediate;
     63 }
     64 
     65 // -----------------------------------------------------------------------------
     66 // RelocInfo.
     67 
     68 void RelocInfo::apply(intptr_t delta) {
     69   if (IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_)) {
     70     // Absolute code pointer inside code object moves with the code object.
     71     Assembler::RelocateInternalReference(rmode_, pc_, delta);
     72   }
     73 }
     74 
     75 
     76 Address RelocInfo::target_address() {
     77   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_));
     78   return Assembler::target_address_at(pc_, constant_pool_);
     79 }
     80 
     81 Address RelocInfo::target_address_address() {
     82   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
     83          IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
     84          IsOffHeapTarget(rmode_));
     85   // Read the address of the word containing the target_address in an
     86   // instruction stream.
     87   // The only architecture-independent user of this function is the serializer.
     88   // The serializer uses it to find out how many raw bytes of instruction to
     89   // output before the next target.
     90   // For an instruction like LUI/ORI where the target bits are mixed into the
     91   // instruction bits, the size of the target will be zero, indicating that the
     92   // serializer should not step forward in memory after a target is resolved
     93   // and written. In this case the target_address_address function should
     94   // return the end of the instructions to be patched, allowing the
     95   // deserializer to deserialize the instructions as raw bytes and put them in
     96   // place, ready to be patched with the target. After jump optimization,
     97   // that is the address of the instruction that follows J/JAL/JR/JALR
     98   // instruction.
     99   return pc_ + Assembler::kInstructionsFor64BitConstant * kInstrSize;
    100 }
    101 
    102 
    103 Address RelocInfo::constant_pool_entry_address() {
    104   UNREACHABLE();
    105 }
    106 
    107 
    108 int RelocInfo::target_address_size() {
    109   return Assembler::kSpecialTargetSize;
    110 }
    111 
    112 Address Assembler::target_address_from_return_address(Address pc) {
    113   return pc - kCallTargetAddressOffset;
    114 }
    115 
    116 void Assembler::deserialization_set_special_target_at(
    117     Address instruction_payload, Code* code, Address target) {
    118   set_target_address_at(
    119       instruction_payload - kInstructionsFor64BitConstant * kInstrSize,
    120       code ? code->constant_pool() : kNullAddress, target);
    121 }
    122 
    123 int Assembler::deserialization_special_target_size(
    124     Address instruction_payload) {
    125   return kSpecialTargetSize;
    126 }
    127 
    128 void Assembler::set_target_internal_reference_encoded_at(Address pc,
    129                                                          Address target) {
    130   // Encoded internal references are j/jal instructions.
    131   Instr instr = Assembler::instr_at(pc + 0 * kInstrSize);
    132 
    133   uint64_t imm28 = target & static_cast<uint64_t>(kImm28Mask);
    134 
    135   instr &= ~kImm26Mask;
    136   uint64_t imm26 = imm28 >> 2;
    137   DCHECK(is_uint26(imm26));
    138 
    139   instr_at_put(pc, instr | (imm26 & kImm26Mask));
    140   // Currently used only by deserializer, and all code will be flushed
    141   // after complete deserialization, no need to flush on each reference.
    142 }
    143 
    144 void Assembler::deserialization_set_target_internal_reference_at(
    145     Address pc, Address target, RelocInfo::Mode mode) {
    146   if (mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
    147     DCHECK(IsJ(instr_at(pc)));
    148     set_target_internal_reference_encoded_at(pc, target);
    149   } else {
    150     DCHECK(mode == RelocInfo::INTERNAL_REFERENCE);
    151     Memory<Address>(pc) = target;
    152   }
    153 }
    154 
    155 HeapObject* RelocInfo::target_object() {
    156   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    157   return HeapObject::cast(reinterpret_cast<Object*>(
    158       Assembler::target_address_at(pc_, constant_pool_)));
    159 }
    160 
    161 Handle<HeapObject> RelocInfo::target_object_handle(Assembler* origin) {
    162   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    163   return Handle<HeapObject>(reinterpret_cast<HeapObject**>(
    164       Assembler::target_address_at(pc_, constant_pool_)));
    165 }
    166 
    167 void RelocInfo::set_target_object(Heap* heap, HeapObject* target,
    168                                   WriteBarrierMode write_barrier_mode,
    169                                   ICacheFlushMode icache_flush_mode) {
    170   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    171   Assembler::set_target_address_at(pc_, constant_pool_,
    172                                    reinterpret_cast<Address>(target),
    173                                    icache_flush_mode);
    174   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != nullptr) {
    175     WriteBarrierForCode(host(), this, target);
    176   }
    177 }
    178 
    179 
    180 Address RelocInfo::target_external_reference() {
    181   DCHECK(rmode_ == EXTERNAL_REFERENCE);
    182   return Assembler::target_address_at(pc_, constant_pool_);
    183 }
    184 
    185 void RelocInfo::set_target_external_reference(
    186     Address target, ICacheFlushMode icache_flush_mode) {
    187   DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
    188   Assembler::set_target_address_at(pc_, constant_pool_, target,
    189                                    icache_flush_mode);
    190 }
    191 
    192 Address RelocInfo::target_internal_reference() {
    193   if (rmode_ == INTERNAL_REFERENCE) {
    194     return Memory<Address>(pc_);
    195   } else {
    196     // Encoded internal references are j/jal instructions.
    197     DCHECK(rmode_ == INTERNAL_REFERENCE_ENCODED);
    198     Instr instr = Assembler::instr_at(pc_ + 0 * kInstrSize);
    199     instr &= kImm26Mask;
    200     uint64_t imm28 = instr << 2;
    201     uint64_t segment = pc_ & ~static_cast<uint64_t>(kImm28Mask);
    202     return static_cast<Address>(segment | imm28);
    203   }
    204 }
    205 
    206 
    207 Address RelocInfo::target_internal_reference_address() {
    208   DCHECK(rmode_ == INTERNAL_REFERENCE || rmode_ == INTERNAL_REFERENCE_ENCODED);
    209   return pc_;
    210 }
    211 
    212 Address RelocInfo::target_runtime_entry(Assembler* origin) {
    213   DCHECK(IsRuntimeEntry(rmode_));
    214   return target_address();
    215 }
    216 
    217 void RelocInfo::set_target_runtime_entry(Address target,
    218                                          WriteBarrierMode write_barrier_mode,
    219                                          ICacheFlushMode icache_flush_mode) {
    220   DCHECK(IsRuntimeEntry(rmode_));
    221   if (target_address() != target)
    222     set_target_address(target, write_barrier_mode, icache_flush_mode);
    223 }
    224 
    225 Address RelocInfo::target_off_heap_target() {
    226   DCHECK(IsOffHeapTarget(rmode_));
    227   return Assembler::target_address_at(pc_, constant_pool_);
    228 }
    229 
    230 void RelocInfo::WipeOut() {
    231   DCHECK(IsEmbeddedObject(rmode_) || IsCodeTarget(rmode_) ||
    232          IsRuntimeEntry(rmode_) || IsExternalReference(rmode_) ||
    233          IsInternalReference(rmode_) || IsInternalReferenceEncoded(rmode_) ||
    234          IsOffHeapTarget(rmode_));
    235   if (IsInternalReference(rmode_)) {
    236     Memory<Address>(pc_) = kNullAddress;
    237   } else if (IsInternalReferenceEncoded(rmode_)) {
    238     Assembler::set_target_internal_reference_encoded_at(pc_, kNullAddress);
    239   } else {
    240     Assembler::set_target_address_at(pc_, constant_pool_, kNullAddress);
    241   }
    242 }
    243 
    244 template <typename ObjectVisitor>
    245 void RelocInfo::Visit(ObjectVisitor* visitor) {
    246   RelocInfo::Mode mode = rmode();
    247   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    248     visitor->VisitEmbeddedPointer(host(), this);
    249   } else if (RelocInfo::IsCodeTargetMode(mode)) {
    250     visitor->VisitCodeTarget(host(), this);
    251   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    252     visitor->VisitExternalReference(host(), this);
    253   } else if (mode == RelocInfo::INTERNAL_REFERENCE ||
    254              mode == RelocInfo::INTERNAL_REFERENCE_ENCODED) {
    255     visitor->VisitInternalReference(host(), this);
    256   } else if (RelocInfo::IsRuntimeEntry(mode)) {
    257     visitor->VisitRuntimeEntry(host(), this);
    258   } else if (RelocInfo::IsOffHeapTarget(mode)) {
    259     visitor->VisitOffHeapTarget(host(), this);
    260   }
    261 }
    262 
    263 // -----------------------------------------------------------------------------
    264 // Assembler.
    265 
    266 
    267 void Assembler::CheckBuffer() {
    268   if (buffer_space() <= kGap) {
    269     GrowBuffer();
    270   }
    271 }
    272 
    273 
    274 void Assembler::CheckForEmitInForbiddenSlot() {
    275   if (!is_buffer_growth_blocked()) {
    276     CheckBuffer();
    277   }
    278   if (IsPrevInstrCompactBranch()) {
    279     // Nop instruction to precede a CTI in forbidden slot:
    280     Instr nop = SPECIAL | SLL;
    281     *reinterpret_cast<Instr*>(pc_) = nop;
    282     pc_ += kInstrSize;
    283 
    284     ClearCompactBranchState();
    285   }
    286 }
    287 
    288 
    289 void Assembler::EmitHelper(Instr x, CompactBranchType is_compact_branch) {
    290   if (IsPrevInstrCompactBranch()) {
    291     if (Instruction::IsForbiddenAfterBranchInstr(x)) {
    292       // Nop instruction to precede a CTI in forbidden slot:
    293       Instr nop = SPECIAL | SLL;
    294       *reinterpret_cast<Instr*>(pc_) = nop;
    295       pc_ += kInstrSize;
    296     }
    297     ClearCompactBranchState();
    298   }
    299   *reinterpret_cast<Instr*>(pc_) = x;
    300   pc_ += kInstrSize;
    301   if (is_compact_branch == CompactBranchType::COMPACT_BRANCH) {
    302     EmittedCompactBranchInstruction();
    303   }
    304   CheckTrampolinePoolQuick();
    305 }
    306 
    307 template <>
    308 inline void Assembler::EmitHelper(uint8_t x);
    309 
    310 template <typename T>
    311 void Assembler::EmitHelper(T x) {
    312   *reinterpret_cast<T*>(pc_) = x;
    313   pc_ += sizeof(x);
    314   CheckTrampolinePoolQuick();
    315 }
    316 
    317 template <>
    318 void Assembler::EmitHelper(uint8_t x) {
    319   *reinterpret_cast<uint8_t*>(pc_) = x;
    320   pc_ += sizeof(x);
    321   if (reinterpret_cast<intptr_t>(pc_) % kInstrSize == 0) {
    322     CheckTrampolinePoolQuick();
    323   }
    324 }
    325 
    326 void Assembler::emit(Instr x, CompactBranchType is_compact_branch) {
    327   if (!is_buffer_growth_blocked()) {
    328     CheckBuffer();
    329   }
    330   EmitHelper(x, is_compact_branch);
    331 }
    332 
    333 
    334 void Assembler::emit(uint64_t data) {
    335   CheckForEmitInForbiddenSlot();
    336   EmitHelper(data);
    337 }
    338 
    339 EnsureSpace::EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); }
    340 
    341 }  // namespace internal
    342 }  // namespace v8
    343 
    344 #endif  // V8_MIPS64_ASSEMBLER_MIPS64_INL_H_
    345