Home | History | Annotate | Download | only in x87
      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 2012 the V8 project authors. All rights reserved.
     34 
     35 // A light-weight IA32 Assembler.
     36 
     37 #ifndef V8_X87_ASSEMBLER_X87_INL_H_
     38 #define V8_X87_ASSEMBLER_X87_INL_H_
     39 
     40 #include "src/x87/assembler-x87.h"
     41 
     42 #include "src/assembler.h"
     43 #include "src/debug/debug.h"
     44 #include "src/objects-inl.h"
     45 
     46 namespace v8 {
     47 namespace internal {
     48 
     49 bool CpuFeatures::SupportsCrankshaft() { return true; }
     50 
     51 bool CpuFeatures::SupportsSimd128() { return false; }
     52 
     53 static const byte kCallOpcode = 0xE8;
     54 static const int kNoCodeAgeSequenceLength = 5;
     55 
     56 
     57 // The modes possibly affected by apply must be in kApplyMask.
     58 void RelocInfo::apply(intptr_t delta) {
     59   if (IsRuntimeEntry(rmode_) || IsCodeTarget(rmode_)) {
     60     int32_t* p = reinterpret_cast<int32_t*>(pc_);
     61     *p -= delta;  // Relocate entry.
     62   } else if (IsCodeAgeSequence(rmode_)) {
     63     if (*pc_ == kCallOpcode) {
     64       int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
     65       *p -= delta;  // Relocate entry.
     66     }
     67   } else if (IsDebugBreakSlot(rmode_) && IsPatchedDebugBreakSlotSequence()) {
     68     // Special handling of a debug break slot when a break point is set (call
     69     // instruction has been inserted).
     70     int32_t* p = reinterpret_cast<int32_t*>(
     71         pc_ + Assembler::kPatchDebugBreakSlotAddressOffset);
     72     *p -= delta;  // Relocate entry.
     73   } else if (IsInternalReference(rmode_)) {
     74     // absolute code pointer inside code object moves with the code object.
     75     int32_t* p = reinterpret_cast<int32_t*>(pc_);
     76     *p += delta;  // Relocate entry.
     77   }
     78 }
     79 
     80 
     81 Address RelocInfo::target_address() {
     82   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
     83   return Assembler::target_address_at(pc_, host_);
     84 }
     85 
     86 Address RelocInfo::target_address_address() {
     87   DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
     88                               || rmode_ == EMBEDDED_OBJECT
     89                               || rmode_ == EXTERNAL_REFERENCE);
     90   return reinterpret_cast<Address>(pc_);
     91 }
     92 
     93 
     94 Address RelocInfo::constant_pool_entry_address() {
     95   UNREACHABLE();
     96   return NULL;
     97 }
     98 
     99 
    100 int RelocInfo::target_address_size() {
    101   return Assembler::kSpecialTargetSize;
    102 }
    103 
    104 
    105 Object* RelocInfo::target_object() {
    106   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    107   return Memory::Object_at(pc_);
    108 }
    109 
    110 
    111 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
    112   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    113   return Memory::Object_Handle_at(pc_);
    114 }
    115 
    116 
    117 void RelocInfo::set_target_object(Object* target,
    118                                   WriteBarrierMode write_barrier_mode,
    119                                   ICacheFlushMode icache_flush_mode) {
    120   DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
    121   Memory::Object_at(pc_) = target;
    122   if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
    123     Assembler::FlushICache(isolate_, pc_, sizeof(Address));
    124   }
    125   if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
    126       host() != NULL &&
    127       target->IsHeapObject()) {
    128     host()->GetHeap()->RecordWriteIntoCode(host(), this, target);
    129     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
    130         host(), this, HeapObject::cast(target));
    131   }
    132 }
    133 
    134 
    135 Address RelocInfo::target_external_reference() {
    136   DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
    137   return Memory::Address_at(pc_);
    138 }
    139 
    140 
    141 Address RelocInfo::target_internal_reference() {
    142   DCHECK(rmode_ == INTERNAL_REFERENCE);
    143   return Memory::Address_at(pc_);
    144 }
    145 
    146 
    147 Address RelocInfo::target_internal_reference_address() {
    148   DCHECK(rmode_ == INTERNAL_REFERENCE);
    149   return reinterpret_cast<Address>(pc_);
    150 }
    151 
    152 
    153 Address RelocInfo::target_runtime_entry(Assembler* origin) {
    154   DCHECK(IsRuntimeEntry(rmode_));
    155   return reinterpret_cast<Address>(*reinterpret_cast<int32_t*>(pc_));
    156 }
    157 
    158 
    159 void RelocInfo::set_target_runtime_entry(Address target,
    160                                          WriteBarrierMode write_barrier_mode,
    161                                          ICacheFlushMode icache_flush_mode) {
    162   DCHECK(IsRuntimeEntry(rmode_));
    163   if (target_address() != target) {
    164     set_target_address(target, write_barrier_mode, icache_flush_mode);
    165   }
    166 }
    167 
    168 
    169 Handle<Cell> RelocInfo::target_cell_handle() {
    170   DCHECK(rmode_ == RelocInfo::CELL);
    171   Address address = Memory::Address_at(pc_);
    172   return Handle<Cell>(reinterpret_cast<Cell**>(address));
    173 }
    174 
    175 
    176 Cell* RelocInfo::target_cell() {
    177   DCHECK(rmode_ == RelocInfo::CELL);
    178   return Cell::FromValueAddress(Memory::Address_at(pc_));
    179 }
    180 
    181 
    182 void RelocInfo::set_target_cell(Cell* cell,
    183                                 WriteBarrierMode write_barrier_mode,
    184                                 ICacheFlushMode icache_flush_mode) {
    185   DCHECK(cell->IsCell());
    186   DCHECK(rmode_ == RelocInfo::CELL);
    187   Address address = cell->address() + Cell::kValueOffset;
    188   Memory::Address_at(pc_) = address;
    189   if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
    190     Assembler::FlushICache(isolate_, pc_, sizeof(Address));
    191   }
    192   if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL) {
    193     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this,
    194                                                                   cell);
    195   }
    196 }
    197 
    198 
    199 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
    200   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
    201   DCHECK(*pc_ == kCallOpcode);
    202   return Memory::Object_Handle_at(pc_ + 1);
    203 }
    204 
    205 
    206 Code* RelocInfo::code_age_stub() {
    207   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
    208   DCHECK(*pc_ == kCallOpcode);
    209   return Code::GetCodeFromTargetAddress(
    210       Assembler::target_address_at(pc_ + 1, host_));
    211 }
    212 
    213 
    214 void RelocInfo::set_code_age_stub(Code* stub,
    215                                   ICacheFlushMode icache_flush_mode) {
    216   DCHECK(*pc_ == kCallOpcode);
    217   DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
    218   Assembler::set_target_address_at(
    219       isolate_, pc_ + 1, host_, stub->instruction_start(), icache_flush_mode);
    220 }
    221 
    222 
    223 Address RelocInfo::debug_call_address() {
    224   DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
    225   Address location = pc_ + Assembler::kPatchDebugBreakSlotAddressOffset;
    226   return Assembler::target_address_at(location, host_);
    227 }
    228 
    229 
    230 void RelocInfo::set_debug_call_address(Address target) {
    231   DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence());
    232   Address location = pc_ + Assembler::kPatchDebugBreakSlotAddressOffset;
    233   Assembler::set_target_address_at(isolate_, location, host_, target);
    234   if (host() != NULL) {
    235     Object* target_code = Code::GetCodeFromTargetAddress(target);
    236     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
    237         host(), this, HeapObject::cast(target_code));
    238   }
    239 }
    240 
    241 
    242 void RelocInfo::WipeOut() {
    243   if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
    244       IsInternalReference(rmode_)) {
    245     Memory::Address_at(pc_) = NULL;
    246   } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
    247     // Effectively write zero into the relocation.
    248     Assembler::set_target_address_at(isolate_, pc_, host_,
    249                                      pc_ + sizeof(int32_t));
    250   } else {
    251     UNREACHABLE();
    252   }
    253 }
    254 
    255 template <typename ObjectVisitor>
    256 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
    257   RelocInfo::Mode mode = rmode();
    258   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    259     visitor->VisitEmbeddedPointer(this);
    260     Assembler::FlushICache(isolate, pc_, sizeof(Address));
    261   } else if (RelocInfo::IsCodeTarget(mode)) {
    262     visitor->VisitCodeTarget(this);
    263   } else if (mode == RelocInfo::CELL) {
    264     visitor->VisitCell(this);
    265   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    266     visitor->VisitExternalReference(this);
    267   } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
    268     visitor->VisitInternalReference(this);
    269   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    270     visitor->VisitCodeAgeSequence(this);
    271   } else if (RelocInfo::IsDebugBreakSlot(mode) &&
    272              IsPatchedDebugBreakSlotSequence()) {
    273     visitor->VisitDebugTarget(this);
    274   } else if (IsRuntimeEntry(mode)) {
    275     visitor->VisitRuntimeEntry(this);
    276   }
    277 }
    278 
    279 
    280 template<typename StaticVisitor>
    281 void RelocInfo::Visit(Heap* heap) {
    282   RelocInfo::Mode mode = rmode();
    283   if (mode == RelocInfo::EMBEDDED_OBJECT) {
    284     StaticVisitor::VisitEmbeddedPointer(heap, this);
    285     Assembler::FlushICache(heap->isolate(), pc_, sizeof(Address));
    286   } else if (RelocInfo::IsCodeTarget(mode)) {
    287     StaticVisitor::VisitCodeTarget(heap, this);
    288   } else if (mode == RelocInfo::CELL) {
    289     StaticVisitor::VisitCell(heap, this);
    290   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
    291     StaticVisitor::VisitExternalReference(this);
    292   } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
    293     StaticVisitor::VisitInternalReference(this);
    294   } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    295     StaticVisitor::VisitCodeAgeSequence(heap, this);
    296   } else if (RelocInfo::IsDebugBreakSlot(mode) &&
    297              IsPatchedDebugBreakSlotSequence()) {
    298     StaticVisitor::VisitDebugTarget(heap, this);
    299   } else if (IsRuntimeEntry(mode)) {
    300     StaticVisitor::VisitRuntimeEntry(this);
    301   }
    302 }
    303 
    304 
    305 
    306 Immediate::Immediate(int x)  {
    307   x_ = x;
    308   rmode_ = RelocInfo::NONE32;
    309 }
    310 
    311 Immediate::Immediate(Address x, RelocInfo::Mode rmode) {
    312   x_ = reinterpret_cast<int32_t>(x);
    313   rmode_ = rmode;
    314 }
    315 
    316 Immediate::Immediate(const ExternalReference& ext) {
    317   x_ = reinterpret_cast<int32_t>(ext.address());
    318   rmode_ = RelocInfo::EXTERNAL_REFERENCE;
    319 }
    320 
    321 
    322 Immediate::Immediate(Label* internal_offset) {
    323   x_ = reinterpret_cast<int32_t>(internal_offset);
    324   rmode_ = RelocInfo::INTERNAL_REFERENCE;
    325 }
    326 
    327 
    328 Immediate::Immediate(Handle<Object> handle) {
    329   AllowDeferredHandleDereference using_raw_address;
    330   // Verify all Objects referred by code are NOT in new space.
    331   Object* obj = *handle;
    332   if (obj->IsHeapObject()) {
    333     x_ = reinterpret_cast<intptr_t>(handle.location());
    334     rmode_ = RelocInfo::EMBEDDED_OBJECT;
    335   } else {
    336     // no relocation needed
    337     x_ =  reinterpret_cast<intptr_t>(obj);
    338     rmode_ = RelocInfo::NONE32;
    339   }
    340 }
    341 
    342 
    343 Immediate::Immediate(Smi* value) {
    344   x_ = reinterpret_cast<intptr_t>(value);
    345   rmode_ = RelocInfo::NONE32;
    346 }
    347 
    348 
    349 Immediate::Immediate(Address addr) {
    350   x_ = reinterpret_cast<int32_t>(addr);
    351   rmode_ = RelocInfo::NONE32;
    352 }
    353 
    354 
    355 void Assembler::emit(uint32_t x) {
    356   *reinterpret_cast<uint32_t*>(pc_) = x;
    357   pc_ += sizeof(uint32_t);
    358 }
    359 
    360 
    361 void Assembler::emit_q(uint64_t x) {
    362   *reinterpret_cast<uint64_t*>(pc_) = x;
    363   pc_ += sizeof(uint64_t);
    364 }
    365 
    366 
    367 void Assembler::emit(Handle<Object> handle) {
    368   AllowDeferredHandleDereference heap_object_check;
    369   // Verify all Objects referred by code are NOT in new space.
    370   Object* obj = *handle;
    371   if (obj->IsHeapObject()) {
    372     emit(reinterpret_cast<intptr_t>(handle.location()),
    373          RelocInfo::EMBEDDED_OBJECT);
    374   } else {
    375     // no relocation needed
    376     emit(reinterpret_cast<intptr_t>(obj));
    377   }
    378 }
    379 
    380 
    381 void Assembler::emit(uint32_t x, RelocInfo::Mode rmode, TypeFeedbackId id) {
    382   if (rmode == RelocInfo::CODE_TARGET && !id.IsNone()) {
    383     RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID, id.ToInt());
    384   } else if (!RelocInfo::IsNone(rmode)
    385       && rmode != RelocInfo::CODE_AGE_SEQUENCE) {
    386     RecordRelocInfo(rmode);
    387   }
    388   emit(x);
    389 }
    390 
    391 
    392 void Assembler::emit(Handle<Code> code,
    393                      RelocInfo::Mode rmode,
    394                      TypeFeedbackId id) {
    395   AllowDeferredHandleDereference embedding_raw_address;
    396   emit(reinterpret_cast<intptr_t>(code.location()), rmode, id);
    397 }
    398 
    399 
    400 void Assembler::emit(const Immediate& x) {
    401   if (x.rmode_ == RelocInfo::INTERNAL_REFERENCE) {
    402     Label* label = reinterpret_cast<Label*>(x.x_);
    403     emit_code_relative_offset(label);
    404     return;
    405   }
    406   if (!RelocInfo::IsNone(x.rmode_)) RecordRelocInfo(x.rmode_);
    407   emit(x.x_);
    408 }
    409 
    410 
    411 void Assembler::emit_code_relative_offset(Label* label) {
    412   if (label->is_bound()) {
    413     int32_t pos;
    414     pos = label->pos() + Code::kHeaderSize - kHeapObjectTag;
    415     emit(pos);
    416   } else {
    417     emit_disp(label, Displacement::CODE_RELATIVE);
    418   }
    419 }
    420 
    421 void Assembler::emit_b(Immediate x) {
    422   DCHECK(x.is_int8() || x.is_uint8());
    423   uint8_t value = static_cast<uint8_t>(x.x_);
    424   *pc_++ = value;
    425 }
    426 
    427 void Assembler::emit_w(const Immediate& x) {
    428   DCHECK(RelocInfo::IsNone(x.rmode_));
    429   uint16_t value = static_cast<uint16_t>(x.x_);
    430   reinterpret_cast<uint16_t*>(pc_)[0] = value;
    431   pc_ += sizeof(uint16_t);
    432 }
    433 
    434 
    435 Address Assembler::target_address_at(Address pc, Address constant_pool) {
    436   return pc + sizeof(int32_t) + *reinterpret_cast<int32_t*>(pc);
    437 }
    438 
    439 
    440 void Assembler::set_target_address_at(Isolate* isolate, Address pc,
    441                                       Address constant_pool, Address target,
    442                                       ICacheFlushMode icache_flush_mode) {
    443   int32_t* p = reinterpret_cast<int32_t*>(pc);
    444   *p = target - (pc + sizeof(int32_t));
    445   if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
    446     Assembler::FlushICache(isolate, p, sizeof(int32_t));
    447   }
    448 }
    449 
    450 Address Assembler::target_address_at(Address pc, Code* code) {
    451   Address constant_pool = code ? code->constant_pool() : NULL;
    452   return target_address_at(pc, constant_pool);
    453 }
    454 
    455 void Assembler::set_target_address_at(Isolate* isolate, Address pc, Code* code,
    456                                       Address target,
    457                                       ICacheFlushMode icache_flush_mode) {
    458   Address constant_pool = code ? code->constant_pool() : NULL;
    459   set_target_address_at(isolate, pc, constant_pool, target, icache_flush_mode);
    460 }
    461 
    462 Address Assembler::target_address_from_return_address(Address pc) {
    463   return pc - kCallTargetAddressOffset;
    464 }
    465 
    466 
    467 Displacement Assembler::disp_at(Label* L) {
    468   return Displacement(long_at(L->pos()));
    469 }
    470 
    471 
    472 void Assembler::disp_at_put(Label* L, Displacement disp) {
    473   long_at_put(L->pos(), disp.data());
    474 }
    475 
    476 
    477 void Assembler::emit_disp(Label* L, Displacement::Type type) {
    478   Displacement disp(L, type);
    479   L->link_to(pc_offset());
    480   emit(static_cast<int>(disp.data()));
    481 }
    482 
    483 
    484 void Assembler::emit_near_disp(Label* L) {
    485   byte disp = 0x00;
    486   if (L->is_near_linked()) {
    487     int offset = L->near_link_pos() - pc_offset();
    488     DCHECK(is_int8(offset));
    489     disp = static_cast<byte>(offset & 0xFF);
    490   }
    491   L->link_to(pc_offset(), Label::kNear);
    492   *pc_++ = disp;
    493 }
    494 
    495 
    496 void Assembler::deserialization_set_target_internal_reference_at(
    497     Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) {
    498   Memory::Address_at(pc) = target;
    499 }
    500 
    501 
    502 void Operand::set_modrm(int mod, Register rm) {
    503   DCHECK((mod & -4) == 0);
    504   buf_[0] = mod << 6 | rm.code();
    505   len_ = 1;
    506 }
    507 
    508 
    509 void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
    510   DCHECK(len_ == 1);
    511   DCHECK((scale & -4) == 0);
    512   // Use SIB with no index register only for base esp.
    513   DCHECK(!index.is(esp) || base.is(esp));
    514   buf_[1] = scale << 6 | index.code() << 3 | base.code();
    515   len_ = 2;
    516 }
    517 
    518 
    519 void Operand::set_disp8(int8_t disp) {
    520   DCHECK(len_ == 1 || len_ == 2);
    521   *reinterpret_cast<int8_t*>(&buf_[len_++]) = disp;
    522 }
    523 
    524 
    525 void Operand::set_dispr(int32_t disp, RelocInfo::Mode rmode) {
    526   DCHECK(len_ == 1 || len_ == 2);
    527   int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]);
    528   *p = disp;
    529   len_ += sizeof(int32_t);
    530   rmode_ = rmode;
    531 }
    532 
    533 Operand::Operand(Register reg) {
    534   // reg
    535   set_modrm(3, reg);
    536 }
    537 
    538 
    539 Operand::Operand(int32_t disp, RelocInfo::Mode rmode) {
    540   // [disp/r]
    541   set_modrm(0, ebp);
    542   set_dispr(disp, rmode);
    543 }
    544 
    545 
    546 Operand::Operand(Immediate imm) {
    547   // [disp/r]
    548   set_modrm(0, ebp);
    549   set_dispr(imm.x_, imm.rmode_);
    550 }
    551 }  // namespace internal
    552 }  // namespace v8
    553 
    554 #endif  // V8_X87_ASSEMBLER_X87_INL_H_
    555