Home | History | Annotate | Download | only in ia32
      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 are
      6 // 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 distribution.
     14 //
     15 // - Neither the name of Sun Microsystems or the names of contributors may
     16 // be used to endorse or promote products derived from this software without
     17 // specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     20 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     21 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     23 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     24 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     26 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     27 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     28 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     29 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 // The original source code covered by the above license above has been
     32 // modified significantly by Google Inc.
     33 // Copyright 2006-2008 the V8 project authors. All rights reserved.
     34 
     35 // A light-weight IA32 Assembler.
     36 
     37 #ifndef V8_IA32_ASSEMBLER_IA32_INL_H_
     38 #define V8_IA32_ASSEMBLER_IA32_INL_H_
     39 
     40 #include "cpu.h"
     41 #include "debug.h"
     42 
     43 namespace v8 {
     44 namespace internal {
     45 
     46 
     47 // The modes possibly affected by apply must be in kApplyMask.
     48 void RelocInfo::apply(intptr_t delta) {
     49   if (rmode_ == RUNTIME_ENTRY || IsCodeTarget(rmode_)) {
     50     int32_t* p = reinterpret_cast<int32_t*>(pc_);
     51     *p -= delta;  // Relocate entry.
     52     CPU::FlushICache(p, sizeof(uint32_t));
     53   } else if (rmode_ == JS_RETURN && IsPatchedReturnSequence()) {
     54     // Special handling of js_return when a break point is set (call
     55     // instruction has been inserted).
     56     int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
     57     *p -= delta;  // Relocate entry.
     58     CPU::FlushICache(p, sizeof(uint32_t));
     59   } else if (rmode_ == DEBUG_BREAK_SLOT && IsPatchedDebugBreakSlotSequence()) {
     60     // Special handling of a debug break slot when a break point is set (call
     61     // instruction has been inserted).
     62     int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
     63     *p -= delta;  // Relocate entry.
     64     CPU::FlushICache(p, sizeof(uint32_t));
     65   } else if (IsInternalReference(rmode_)) {
     66     // absolute code pointer inside code object moves with the code object.
     67     int32_t* p = reinterpret_cast<int32_t*>(pc_);
     68     *p += delta;  // Relocate entry.
     69     CPU::FlushICache(p, sizeof(uint32_t));
     70   }
     71 }
     72 
     73 
     74 Address RelocInfo::target_address() {
     75   ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
     76   return Assembler::target_address_at(pc_);
     77 }
     78 
     79 
     80 Address RelocInfo::target_address_address() {
     81   ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
     82   return reinterpret_cast<Address>(pc_);
     83 }
     84 
     85 
     86 int RelocInfo::target_address_size() {
     87   return Assembler::kExternalTargetSize;
     88 }
     89 
     90 
     91 void RelocInfo::set_target_address(Address target) {
     92   ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY);
     93   Assembler::set_target_address_at(pc_, target);
     94 }
     95 
     96 
     97 Object* RelocInfo::target_object() {
     98   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
     99   return Memory::Object_at(pc_);
    100 }
    101 
    102 
    103 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
    104   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    105   return Memory::Object_Handle_at(pc_);
    106 }
    107 
    108 
    109 Object** RelocInfo::target_object_address() {
    110   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    111   return &Memory::Object_at(pc_);
    112 }
    113 
    114 
    115 void RelocInfo::set_target_object(Object* target) {
    116   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    117   Memory::Object_at(pc_) = target;
    118   CPU::FlushICache(pc_, sizeof(Address));
    119 }
    120 
    121 
    122 Address* RelocInfo::target_reference_address() {
    123   ASSERT(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
    124   return reinterpret_cast<Address*>(pc_);
    125 }
    126 
    127 
    128 Handle<JSGlobalPropertyCell> RelocInfo::target_cell_handle() {
    129   ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
    130   Address address = Memory::Address_at(pc_);
    131   return Handle<JSGlobalPropertyCell>(
    132       reinterpret_cast<JSGlobalPropertyCell**>(address));
    133 }
    134 
    135 
    136 JSGlobalPropertyCell* RelocInfo::target_cell() {
    137   ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
    138   Address address = Memory::Address_at(pc_);
    139   Object* object = HeapObject::FromAddress(
    140       address - JSGlobalPropertyCell::kValueOffset);
    141   return reinterpret_cast<JSGlobalPropertyCell*>(object);
    142 }
    143 
    144 
    145 void RelocInfo::set_target_cell(JSGlobalPropertyCell* cell) {
    146   ASSERT(rmode_ == RelocInfo::GLOBAL_PROPERTY_CELL);
    147   Address address = cell->address() + JSGlobalPropertyCell::kValueOffset;
    148   Memory::Address_at(pc_) = address;
    149   CPU::FlushICache(pc_, sizeof(Address));
    150 }
    151 
    152 
    153 Address RelocInfo::call_address() {
    154   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
    155          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
    156   return Assembler::target_address_at(pc_ + 1);
    157 }
    158 
    159 
    160 void RelocInfo::set_call_address(Address target) {
    161   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
    162          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
    163   Assembler::set_target_address_at(pc_ + 1, target);
    164 }
    165 
    166 
    167 Object* RelocInfo::call_object() {
    168   return *call_object_address();
    169 }
    170 
    171 
    172 void RelocInfo::set_call_object(Object* target) {
    173   *call_object_address() = target;
    174 }
    175 
    176 
    177 Object** RelocInfo::call_object_address() {
    178   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
    179          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
    180   return reinterpret_cast<Object**>(pc_ + 1);
    181 }
    182 
    183 
    184 bool RelocInfo::IsPatchedReturnSequence() {
    185   return *pc_ == 0xE8;
    186 }
    187 
    188 
    189 bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
    190   return !Assembler::IsNop(pc());
    191 }
    192 
    193 
    194 void RelocInfo::Visit(ObjectVisitor* visitor) {
    195   RelocInfo::Mode mode = rmode();
    196   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    197     visitor->VisitPointer(target_object_address());
    198     CPU::FlushICache(pc_, sizeof(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     CPU::FlushICache(pc_, sizeof(Address));
    206 #ifdef ENABLE_DEBUGGER_SUPPORT
    207   // TODO(isolates): Get a cached isolate below.
    208   } else if (((RelocInfo::IsJSReturn(mode) &&
    209               IsPatchedReturnSequence()) ||
    210              (RelocInfo::IsDebugBreakSlot(mode) &&
    211               IsPatchedDebugBreakSlotSequence())) &&
    212              Isolate::Current()->debug()->has_break_points()) {
    213     visitor->VisitDebugTarget(this);
    214 #endif
    215   } else if (mode == RelocInfo::RUNTIME_ENTRY) {
    216     visitor->VisitRuntimeEntry(this);
    217   }
    218 }
    219 
    220 
    221 template<typename StaticVisitor>
    222 void RelocInfo::Visit(Heap* heap) {
    223   RelocInfo::Mode mode = rmode();
    224   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    225     StaticVisitor::VisitPointer(heap, target_object_address());
    226     CPU::FlushICache(pc_, sizeof(Address));
    227   } else if (RelocInfo::IsCodeTarget(mode)) {
    228     StaticVisitor::VisitCodeTarget(heap, this);
    229   } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
    230     StaticVisitor::VisitGlobalPropertyCell(heap, this);
    231   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    232     StaticVisitor::VisitExternalReference(target_reference_address());
    233     CPU::FlushICache(pc_, sizeof(Address));
    234 #ifdef ENABLE_DEBUGGER_SUPPORT
    235   } else if (heap->isolate()->debug()->has_break_points() &&
    236              ((RelocInfo::IsJSReturn(mode) &&
    237               IsPatchedReturnSequence()) ||
    238              (RelocInfo::IsDebugBreakSlot(mode) &&
    239               IsPatchedDebugBreakSlotSequence()))) {
    240     StaticVisitor::VisitDebugTarget(heap, this);
    241 #endif
    242   } else if (mode == RelocInfo::RUNTIME_ENTRY) {
    243     StaticVisitor::VisitRuntimeEntry(this);
    244   }
    245 }
    246 
    247 
    248 
    249 Immediate::Immediate(int x)  {
    250   x_ = x;
    251   rmode_ = RelocInfo::NONE;
    252 }
    253 
    254 
    255 Immediate::Immediate(const ExternalReference& ext) {
    256   x_ = reinterpret_cast<int32_t>(ext.address());
    257   rmode_ = RelocInfo::EXTERNAL_REFERENCE;
    258 }
    259 
    260 
    261 Immediate::Immediate(Label* internal_offset) {
    262   x_ = reinterpret_cast<int32_t>(internal_offset);
    263   rmode_ = RelocInfo::INTERNAL_REFERENCE;
    264 }
    265 
    266 
    267 Immediate::Immediate(Handle<Object> handle) {
    268   // Verify all Objects referred by code are NOT in new space.
    269   Object* obj = *handle;
    270   ASSERT(!HEAP->InNewSpace(obj));
    271   if (obj->IsHeapObject()) {
    272     x_ = reinterpret_cast<intptr_t>(handle.location());
    273     rmode_ = RelocInfo::EMBEDDED_OBJECT;
    274   } else {
    275     // no relocation needed
    276     x_ =  reinterpret_cast<intptr_t>(obj);
    277     rmode_ = RelocInfo::NONE;
    278   }
    279 }
    280 
    281 
    282 Immediate::Immediate(Smi* value) {
    283   x_ = reinterpret_cast<intptr_t>(value);
    284   rmode_ = RelocInfo::NONE;
    285 }
    286 
    287 
    288 Immediate::Immediate(Address addr) {
    289   x_ = reinterpret_cast<int32_t>(addr);
    290   rmode_ = RelocInfo::NONE;
    291 }
    292 
    293 
    294 void Assembler::emit(uint32_t x) {
    295   *reinterpret_cast<uint32_t*>(pc_) = x;
    296   pc_ += sizeof(uint32_t);
    297 }
    298 
    299 
    300 void Assembler::emit(Handle<Object> handle) {
    301   // Verify all Objects referred by code are NOT in new space.
    302   Object* obj = *handle;
    303   ASSERT(!isolate()->heap()->InNewSpace(obj));
    304   if (obj->IsHeapObject()) {
    305     emit(reinterpret_cast<intptr_t>(handle.location()),
    306          RelocInfo::EMBEDDED_OBJECT);
    307   } else {
    308     // no relocation needed
    309     emit(reinterpret_cast<intptr_t>(obj));
    310   }
    311 }
    312 
    313 
    314 void Assembler::emit(uint32_t x, RelocInfo::Mode rmode) {
    315   if (rmode != RelocInfo::NONE) RecordRelocInfo(rmode);
    316   emit(x);
    317 }
    318 
    319 
    320 void Assembler::emit(const Immediate& x) {
    321   if (x.rmode_ == RelocInfo::INTERNAL_REFERENCE) {
    322     Label* label = reinterpret_cast<Label*>(x.x_);
    323     emit_code_relative_offset(label);
    324     return;
    325   }
    326   if (x.rmode_ != RelocInfo::NONE) RecordRelocInfo(x.rmode_);
    327   emit(x.x_);
    328 }
    329 
    330 
    331 void Assembler::emit_code_relative_offset(Label* label) {
    332   if (label->is_bound()) {
    333     int32_t pos;
    334     pos = label->pos() + Code::kHeaderSize - kHeapObjectTag;
    335     emit(pos);
    336   } else {
    337     emit_disp(label, Displacement::CODE_RELATIVE);
    338   }
    339 }
    340 
    341 
    342 void Assembler::emit_w(const Immediate& x) {
    343   ASSERT(x.rmode_ == RelocInfo::NONE);
    344   uint16_t value = static_cast<uint16_t>(x.x_);
    345   reinterpret_cast<uint16_t*>(pc_)[0] = value;
    346   pc_ += sizeof(uint16_t);
    347 }
    348 
    349 
    350 Address Assembler::target_address_at(Address pc) {
    351   return pc + sizeof(int32_t) + *reinterpret_cast<int32_t*>(pc);
    352 }
    353 
    354 
    355 void Assembler::set_target_address_at(Address pc, Address target) {
    356   int32_t* p = reinterpret_cast<int32_t*>(pc);
    357   *p = target - (pc + sizeof(int32_t));
    358   CPU::FlushICache(p, sizeof(int32_t));
    359 }
    360 
    361 
    362 Displacement Assembler::disp_at(Label* L) {
    363   return Displacement(long_at(L->pos()));
    364 }
    365 
    366 
    367 void Assembler::disp_at_put(Label* L, Displacement disp) {
    368   long_at_put(L->pos(), disp.data());
    369 }
    370 
    371 
    372 void Assembler::emit_disp(Label* L, Displacement::Type type) {
    373   Displacement disp(L, type);
    374   L->link_to(pc_offset());
    375   emit(static_cast<int>(disp.data()));
    376 }
    377 
    378 
    379 void Operand::set_modrm(int mod, Register rm) {
    380   ASSERT((mod & -4) == 0);
    381   buf_[0] = mod << 6 | rm.code();
    382   len_ = 1;
    383 }
    384 
    385 
    386 void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
    387   ASSERT(len_ == 1);
    388   ASSERT((scale & -4) == 0);
    389   // Use SIB with no index register only for base esp.
    390   ASSERT(!index.is(esp) || base.is(esp));
    391   buf_[1] = scale << 6 | index.code() << 3 | base.code();
    392   len_ = 2;
    393 }
    394 
    395 
    396 void Operand::set_disp8(int8_t disp) {
    397   ASSERT(len_ == 1 || len_ == 2);
    398   *reinterpret_cast<int8_t*>(&buf_[len_++]) = disp;
    399 }
    400 
    401 
    402 void Operand::set_dispr(int32_t disp, RelocInfo::Mode rmode) {
    403   ASSERT(len_ == 1 || len_ == 2);
    404   int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]);
    405   *p = disp;
    406   len_ += sizeof(int32_t);
    407   rmode_ = rmode;
    408 }
    409 
    410 Operand::Operand(Register reg) {
    411   // reg
    412   set_modrm(3, reg);
    413 }
    414 
    415 
    416 Operand::Operand(XMMRegister xmm_reg) {
    417   Register reg = { xmm_reg.code() };
    418   set_modrm(3, reg);
    419 }
    420 
    421 
    422 Operand::Operand(int32_t disp, RelocInfo::Mode rmode) {
    423   // [disp/r]
    424   set_modrm(0, ebp);
    425   set_dispr(disp, rmode);
    426 }
    427 
    428 } }  // namespace v8::internal
    429 
    430 #endif  // V8_IA32_ASSEMBLER_IA32_INL_H_
    431