Home | History | Annotate | Download | only in arm
      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 2006-2008 the V8 project authors. All rights reserved.
     36 
     37 #ifndef V8_ARM_ASSEMBLER_THUMB2_INL_H_
     38 #define V8_ARM_ASSEMBLER_THUMB2_INL_H_
     39 
     40 #include "arm/assembler-thumb2.h"
     41 #include "cpu.h"
     42 
     43 
     44 namespace v8 {
     45 namespace internal {
     46 
     47 Condition NegateCondition(Condition cc) {
     48   ASSERT(cc != al);
     49   return static_cast<Condition>(cc ^ ne);
     50 }
     51 
     52 
     53 void RelocInfo::apply(intptr_t delta) {
     54   if (RelocInfo::IsInternalReference(rmode_)) {
     55     // absolute code pointer inside code object moves with the code object.
     56     int32_t* p = reinterpret_cast<int32_t*>(pc_);
     57     *p += delta;  // relocate entry
     58   }
     59   // We do not use pc relative addressing on ARM, so there is
     60   // nothing else to do.
     61 }
     62 
     63 
     64 Address RelocInfo::target_address() {
     65   ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
     66   return Assembler::target_address_at(pc_);
     67 }
     68 
     69 
     70 Address RelocInfo::target_address_address() {
     71   ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
     72   return reinterpret_cast<Address>(Assembler::target_address_address_at(pc_));
     73 }
     74 
     75 
     76 void RelocInfo::set_target_address(Address target) {
     77   ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
     78   Assembler::set_target_address_at(pc_, target);
     79 }
     80 
     81 
     82 Object* RelocInfo::target_object() {
     83   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
     84   return Memory::Object_at(Assembler::target_address_address_at(pc_));
     85 }
     86 
     87 
     88 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
     89   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
     90   return Memory::Object_Handle_at(Assembler::target_address_address_at(pc_));
     91 }
     92 
     93 
     94 Object** RelocInfo::target_object_address() {
     95   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
     96   return reinterpret_cast<Object**>(Assembler::target_address_address_at(pc_));
     97 }
     98 
     99 
    100 void RelocInfo::set_target_object(Object* target) {
    101   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    102   Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target));
    103 }
    104 
    105 
    106 Address* RelocInfo::target_reference_address() {
    107   ASSERT(rmode_ == EXTERNAL_REFERENCE);
    108   return reinterpret_cast<Address*>(Assembler::target_address_address_at(pc_));
    109 }
    110 
    111 
    112 Address RelocInfo::call_address() {
    113   ASSERT(IsPatchedReturnSequence());
    114   // The 2 instructions offset assumes patched return sequence.
    115   ASSERT(IsJSReturn(rmode()));
    116   return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize);
    117 }
    118 
    119 
    120 void RelocInfo::set_call_address(Address target) {
    121   ASSERT(IsPatchedReturnSequence());
    122   // The 2 instructions offset assumes patched return sequence.
    123   ASSERT(IsJSReturn(rmode()));
    124   Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target;
    125 }
    126 
    127 
    128 Object* RelocInfo::call_object() {
    129   return *call_object_address();
    130 }
    131 
    132 
    133 Object** RelocInfo::call_object_address() {
    134   ASSERT(IsPatchedReturnSequence());
    135   // The 2 instructions offset assumes patched return sequence.
    136   ASSERT(IsJSReturn(rmode()));
    137   return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
    138 }
    139 
    140 
    141 void RelocInfo::set_call_object(Object* target) {
    142   *call_object_address() = target;
    143 }
    144 
    145 
    146 bool RelocInfo::IsPatchedReturnSequence() {
    147   // On ARM a "call instruction" is actually two instructions.
    148   //   mov lr, pc
    149   //   ldr pc, [pc, #XXX]
    150   return (Assembler::instr_at(pc_) == kMovLrPc)
    151           && ((Assembler::instr_at(pc_ + Assembler::kInstrSize) & kLdrPCPattern)
    152               == kLdrPCPattern);
    153 }
    154 
    155 
    156 Operand::Operand(int32_t immediate, RelocInfo::Mode rmode)  {
    157   rm_ = no_reg;
    158   imm32_ = immediate;
    159   rmode_ = rmode;
    160 }
    161 
    162 
    163 Operand::Operand(const char* s) {
    164   rm_ = no_reg;
    165   imm32_ = reinterpret_cast<int32_t>(s);
    166   rmode_ = RelocInfo::EMBEDDED_STRING;
    167 }
    168 
    169 
    170 Operand::Operand(const ExternalReference& f)  {
    171   rm_ = no_reg;
    172   imm32_ = reinterpret_cast<int32_t>(f.address());
    173   rmode_ = RelocInfo::EXTERNAL_REFERENCE;
    174 }
    175 
    176 
    177 Operand::Operand(Smi* value) {
    178   rm_ = no_reg;
    179   imm32_ =  reinterpret_cast<intptr_t>(value);
    180   rmode_ = RelocInfo::NONE;
    181 }
    182 
    183 
    184 Operand::Operand(Register rm) {
    185   rm_ = rm;
    186   rs_ = no_reg;
    187   shift_op_ = LSL;
    188   shift_imm_ = 0;
    189 }
    190 
    191 
    192 bool Operand::is_reg() const {
    193   return rm_.is_valid() &&
    194          rs_.is(no_reg) &&
    195          shift_op_ == LSL &&
    196          shift_imm_ == 0;
    197 }
    198 
    199 
    200 void Assembler::CheckBuffer() {
    201   if (buffer_space() <= kGap) {
    202     GrowBuffer();
    203   }
    204   if (pc_offset() >= next_buffer_check_) {
    205     CheckConstPool(false, true);
    206   }
    207 }
    208 
    209 
    210 void Assembler::emit(Instr x) {
    211   CheckBuffer();
    212   *reinterpret_cast<Instr*>(pc_) = x;
    213   pc_ += kInstrSize;
    214 }
    215 
    216 
    217 Address Assembler::target_address_address_at(Address pc) {
    218   Address target_pc = pc;
    219   Instr instr = Memory::int32_at(target_pc);
    220   // If we have a bx instruction, the instruction before the bx is
    221   // what we need to patch.
    222   static const int32_t kBxInstMask = 0x0ffffff0;
    223   static const int32_t kBxInstPattern = 0x012fff10;
    224   if ((instr & kBxInstMask) == kBxInstPattern) {
    225     target_pc -= kInstrSize;
    226     instr = Memory::int32_at(target_pc);
    227   }
    228   // Verify that the instruction to patch is a
    229   // ldr<cond> <Rd>, [pc +/- offset_12].
    230   ASSERT((instr & 0x0f7f0000) == 0x051f0000);
    231   int offset = instr & 0xfff;  // offset_12 is unsigned
    232   if ((instr & (1 << 23)) == 0) offset = -offset;  // U bit defines offset sign
    233   // Verify that the constant pool comes after the instruction referencing it.
    234   ASSERT(offset >= -4);
    235   return target_pc + offset + 8;
    236 }
    237 
    238 
    239 Address Assembler::target_address_at(Address pc) {
    240   return Memory::Address_at(target_address_address_at(pc));
    241 }
    242 
    243 
    244 void Assembler::set_target_at(Address constant_pool_entry,
    245                               Address target) {
    246   Memory::Address_at(constant_pool_entry) = target;
    247 }
    248 
    249 
    250 void Assembler::set_target_address_at(Address pc, Address target) {
    251   Memory::Address_at(target_address_address_at(pc)) = target;
    252   // Intuitively, we would think it is necessary to flush the instruction cache
    253   // after patching a target address in the code as follows:
    254   //   CPU::FlushICache(pc, sizeof(target));
    255   // However, on ARM, no instruction was actually patched by the assignment
    256   // above; the target address is not part of an instruction, it is patched in
    257   // the constant pool and is read via a data access; the instruction accessing
    258   // this address in the constant pool remains unchanged.
    259 }
    260 
    261 } }  // namespace v8::internal
    262 
    263 #endif  // V8_ARM_ASSEMBLER_THUMB2_INL_H_
    264