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_ARM_INL_H_
     38 #define V8_ARM_ASSEMBLER_ARM_INL_H_
     39 
     40 #include "arm/assembler-arm.h"
     41 #include "cpu.h"
     42 #include "debug.h"
     43 
     44 
     45 namespace v8 {
     46 namespace internal {
     47 
     48 
     49 void RelocInfo::apply(intptr_t delta) {
     50   if (RelocInfo::IsInternalReference(rmode_)) {
     51     // absolute code pointer inside code object moves with the code object.
     52     int32_t* p = reinterpret_cast<int32_t*>(pc_);
     53     *p += delta;  // relocate entry
     54   }
     55   // We do not use pc relative addressing on ARM, so there is
     56   // nothing else to do.
     57 }
     58 
     59 
     60 Address RelocInfo::target_address() {
     61   ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
     62   return Assembler::target_address_at(pc_);
     63 }
     64 
     65 
     66 Address RelocInfo::target_address_address() {
     67   ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
     68   return reinterpret_cast<Address>(Assembler::target_address_address_at(pc_));
     69 }
     70 
     71 
     72 int RelocInfo::target_address_size() {
     73   return Assembler::kExternalTargetSize;
     74 }
     75 
     76 
     77 void RelocInfo::set_target_address(Address target) {
     78   ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
     79   Assembler::set_target_address_at(pc_, target);
     80 }
     81 
     82 
     83 Object* RelocInfo::target_object() {
     84   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
     85   return Memory::Object_at(Assembler::target_address_address_at(pc_));
     86 }
     87 
     88 
     89 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
     90   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
     91   return Memory::Object_Handle_at(Assembler::target_address_address_at(pc_));
     92 }
     93 
     94 
     95 Object** RelocInfo::target_object_address() {
     96   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
     97   return reinterpret_cast<Object**>(Assembler::target_address_address_at(pc_));
     98 }
     99 
    100 
    101 void RelocInfo::set_target_object(Object* target) {
    102   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    103   Assembler::set_target_address_at(pc_, reinterpret_cast<Address>(target));
    104 }
    105 
    106 
    107 Address* RelocInfo::target_reference_address() {
    108   ASSERT(rmode_ == EXTERNAL_REFERENCE);
    109   return reinterpret_cast<Address*>(Assembler::target_address_address_at(pc_));
    110 }
    111 
    112 
    113 Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() {
    114   ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
    115   Address address = Memory::Address_at(pc_);
    116   return Handle<JSGlobalPropertyCell>(
    117       reinterpret_cast<JSGlobalPropertyCell**>(address));
    118 }
    119 
    120 
    121 JSGlobalPropertyCell* RelocInfo::target_cell() {
    122   ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
    123   Address address = Memory::Address_at(pc_);
    124   Object* object = HeapObject::FromAddress(
    125       address - JSGlobalPropertyCell::kValueOffset);
    126   return reinterpret_cast<JSGlobalPropertyCell*>(object);
    127 }
    128 
    129 
    130 void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell) {
    131   ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
    132   Address address = cell->address() + JSGlobalPropertyCell::kValueOffset;
    133   Memory::Address_at(pc_) = address;
    134 }
    135 
    136 
    137 Address RelocInfo::call_address() {
    138   // The 2 instructions offset assumes patched debug break slot or return
    139   // sequence.
    140   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
    141          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
    142   return Memory::Address_at(pc_ + 2 * Assembler::kInstrSize);
    143 }
    144 
    145 
    146 void RelocInfo::set_call_address(Address target) {
    147   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
    148          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
    149   Memory::Address_at(pc_ + 2 * Assembler::kInstrSize) = target;
    150 }
    151 
    152 
    153 Object* RelocInfo::call_object() {
    154   return *call_object_address();
    155 }
    156 
    157 
    158 void RelocInfo::set_call_object(Object* target) {
    159   *call_object_address() = target;
    160 }
    161 
    162 
    163 Object** RelocInfo::call_object_address() {
    164   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
    165          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
    166   return reinterpret_cast<Object**>(pc_ + 2 * Assembler::kInstrSize);
    167 }
    168 
    169 
    170 bool RelocInfo::IsPatchedReturnSequence() {
    171   Instr current_instr = Assembler::instr_at(pc_);
    172   Instr next_instr = Assembler::instr_at(pc_ + Assembler::kInstrSize);
    173 #ifdef USE_BLX
    174   // A patched return sequence is:
    175   //  ldr ip, [pc, #0]
    176   //  blx ip
    177   return ((current_instr & kLdrPCMask) == kLdrPCPattern)
    178           && ((next_instr & kBlxRegMask) == kBlxRegPattern);
    179 #else
    180   // A patched return sequence is:
    181   //  mov lr, pc
    182   //  ldr pc, [pc, #-4]
    183   return (current_instr == kMovLrPc)
    184           && ((next_instr & kLdrPCMask) == kLdrPCPattern);
    185 #endif
    186 }
    187 
    188 
    189 bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
    190   Instr current_instr = Assembler::instr_at(pc_);
    191   return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
    192 }
    193 
    194 
    195 void RelocInfo::Visit(ObjectVisitor* visitor) {
    196   RelocInfo::Mode mode = rmode();
    197   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    198     visitor->VisitPointer(target_object_address());
    199   } else if (RelocInfo::IsCodeTarget(mode)) {
    200     visitor->VisitCodeTarget(this);
    201   } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
    202     visitor->VisitGlobalPropertyCell(this);
    203   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    204     visitor->VisitExternalReference(target_reference_address());
    205 #ifdef ENABLE_DEBUGGER_SUPPORT
    206   // TODO(isolates): Get a cached isolate below.
    207   } else if (((RelocInfo::IsJSReturn(mode) &&
    208               IsPatchedReturnSequence()) ||
    209              (RelocInfo::IsDebugBreakSlot(mode) &&
    210               IsPatchedDebugBreakSlotSequence())) &&
    211              Isolate::Current()->debug()->has_break_points()) {
    212     visitor->VisitDebugTarget(this);
    213 #endif
    214   } else if (mode == RelocInfo::RUNTIME_ENTRY) {
    215     visitor->VisitRuntimeEntry(this);
    216   }
    217 }
    218 
    219 
    220 template<typename StaticVisitor>
    221 void RelocInfo::Visit(Heap* heap) {
    222   RelocInfo::Mode mode = rmode();
    223   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    224     StaticVisitor::VisitPointer(heap, target_object_address());
    225   } else if (RelocInfo::IsCodeTarget(mode)) {
    226     StaticVisitor::VisitCodeTarget(heap, this);
    227   } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
    228     StaticVisitor::VisitGlobalPropertyCell(heap, this);
    229   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    230     StaticVisitor::VisitExternalReference(target_reference_address());
    231 #ifdef ENABLE_DEBUGGER_SUPPORT
    232   } else if (heap->isolate()->debug()->has_break_points() &&
    233              ((RelocInfo::IsJSReturn(mode) &&
    234               IsPatchedReturnSequence()) ||
    235              (RelocInfo::IsDebugBreakSlot(mode) &&
    236               IsPatchedDebugBreakSlotSequence()))) {
    237     StaticVisitor::VisitDebugTarget(heap, this);
    238 #endif
    239   } else if (mode == RelocInfo::RUNTIME_ENTRY) {
    240     StaticVisitor::VisitRuntimeEntry(this);
    241   }
    242 }
    243 
    244 
    245 Operand::Operand(int32_t immediate, RelocInfo::Mode rmode)  {
    246   rm_ = no_reg;
    247   imm32_ = immediate;
    248   rmode_ = rmode;
    249 }
    250 
    251 
    252 Operand::Operand(const ExternalReference& f)  {
    253   rm_ = no_reg;
    254   imm32_ = reinterpret_cast<int32_t>(f.address());
    255   rmode_ = RelocInfo::EXTERNAL_REFERENCE;
    256 }
    257 
    258 
    259 Operand::Operand(Smi* value) {
    260   rm_ = no_reg;
    261   imm32_ =  reinterpret_cast<intptr_t>(value);
    262   rmode_ = RelocInfo::NONE;
    263 }
    264 
    265 
    266 Operand::Operand(Register rm) {
    267   rm_ = rm;
    268   rs_ = no_reg;
    269   shift_op_ = LSL;
    270   shift_imm_ = 0;
    271 }
    272 
    273 
    274 bool Operand::is_reg() const {
    275   return rm_.is_valid() &&
    276          rs_.is(no_reg) &&
    277          shift_op_ == LSL &&
    278          shift_imm_ == 0;
    279 }
    280 
    281 
    282 void Assembler::CheckBuffer() {
    283   if (buffer_space() <= kGap) {
    284     GrowBuffer();
    285   }
    286   if (pc_offset() >= next_buffer_check_) {
    287     CheckConstPool(false, true);
    288   }
    289 }
    290 
    291 
    292 void Assembler::emit(Instr x) {
    293   CheckBuffer();
    294   *reinterpret_cast<Instr*>(pc_) = x;
    295   pc_ += kInstrSize;
    296 }
    297 
    298 
    299 Address Assembler::target_address_address_at(Address pc) {
    300   Address target_pc = pc;
    301   Instr instr = Memory::int32_at(target_pc);
    302   // If we have a bx instruction, the instruction before the bx is
    303   // what we need to patch.
    304   static const int32_t kBxInstMask = 0x0ffffff0;
    305   static const int32_t kBxInstPattern = 0x012fff10;
    306   if ((instr & kBxInstMask) == kBxInstPattern) {
    307     target_pc -= kInstrSize;
    308     instr = Memory::int32_at(target_pc);
    309   }
    310 
    311 #ifdef USE_BLX
    312   // If we have a blx instruction, the instruction before it is
    313   // what needs to be patched.
    314   if ((instr & kBlxRegMask) == kBlxRegPattern) {
    315     target_pc -= kInstrSize;
    316     instr = Memory::int32_at(target_pc);
    317   }
    318 #endif
    319 
    320   ASSERT(IsLdrPcImmediateOffset(instr));
    321   int offset = instr & 0xfff;  // offset_12 is unsigned
    322   if ((instr & (1 << 23)) == 0) offset = -offset;  // U bit defines offset sign
    323   // Verify that the constant pool comes after the instruction referencing it.
    324   ASSERT(offset >= -4);
    325   return target_pc + offset + 8;
    326 }
    327 
    328 
    329 Address Assembler::target_address_at(Address pc) {
    330   return Memory::Address_at(target_address_address_at(pc));
    331 }
    332 
    333 
    334 void Assembler::set_target_at(Address constant_pool_entry,
    335                               Address target) {
    336   Memory::Address_at(constant_pool_entry) = target;
    337 }
    338 
    339 
    340 void Assembler::set_target_address_at(Address pc, Address target) {
    341   Memory::Address_at(target_address_address_at(pc)) = target;
    342   // Intuitively, we would think it is necessary to flush the instruction cache
    343   // after patching a target address in the code as follows:
    344   //   CPU::FlushICache(pc, sizeof(target));
    345   // However, on ARM, no instruction was actually patched by the assignment
    346   // above; the target address is not part of an instruction, it is patched in
    347   // the constant pool and is read via a data access; the instruction accessing
    348   // this address in the constant pool remains unchanged.
    349 }
    350 
    351 } }  // namespace v8::internal
    352 
    353 #endif  // V8_ARM_ASSEMBLER_ARM_INL_H_
    354