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_IA32_ASSEMBLER_IA32_INL_H_ 38#define V8_IA32_ASSEMBLER_IA32_INL_H_ 39 40#include "src/ia32/assembler-ia32.h" 41 42#include "src/assembler.h" 43#include "src/debug/debug.h" 44#include "src/objects-inl.h" 45 46namespace v8 { 47namespace internal { 48 49bool CpuFeatures::SupportsCrankshaft() { return true; } 50 51bool CpuFeatures::SupportsSimd128() { return false; } 52 53static const byte kCallOpcode = 0xE8; 54static const int kNoCodeAgeSequenceLength = 5; 55 56 57// The modes possibly affected by apply must be in kApplyMask. 58void 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 81Address RelocInfo::target_address() { 82 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); 83 return Assembler::target_address_at(pc_, host_); 84} 85 86Address 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 94Address RelocInfo::constant_pool_entry_address() { 95 UNREACHABLE(); 96 return NULL; 97} 98 99 100int RelocInfo::target_address_size() { 101 return Assembler::kSpecialTargetSize; 102} 103 104 105Object* RelocInfo::target_object() { 106 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 107 return Memory::Object_at(pc_); 108} 109 110 111Handle<Object> RelocInfo::target_object_handle(Assembler* origin) { 112 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 113 return Memory::Object_Handle_at(pc_); 114} 115 116 117void 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 135Address RelocInfo::target_external_reference() { 136 DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE); 137 return Memory::Address_at(pc_); 138} 139 140 141Address RelocInfo::target_internal_reference() { 142 DCHECK(rmode_ == INTERNAL_REFERENCE); 143 return Memory::Address_at(pc_); 144} 145 146 147Address RelocInfo::target_internal_reference_address() { 148 DCHECK(rmode_ == INTERNAL_REFERENCE); 149 return reinterpret_cast<Address>(pc_); 150} 151 152 153Address RelocInfo::target_runtime_entry(Assembler* origin) { 154 DCHECK(IsRuntimeEntry(rmode_)); 155 return reinterpret_cast<Address>(*reinterpret_cast<int32_t*>(pc_)); 156} 157 158 159void 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 169Handle<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 176Cell* RelocInfo::target_cell() { 177 DCHECK(rmode_ == RelocInfo::CELL); 178 return Cell::FromValueAddress(Memory::Address_at(pc_)); 179} 180 181 182void 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 199Handle<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 206Code* 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 214void 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 223Address 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 230void 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 242void 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 255template <typename ObjectVisitor> 256void 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 280template<typename StaticVisitor> 281void 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 306Immediate::Immediate(int x) { 307 x_ = x; 308 rmode_ = RelocInfo::NONE32; 309} 310 311Immediate::Immediate(Address x, RelocInfo::Mode rmode) { 312 x_ = reinterpret_cast<int32_t>(x); 313 rmode_ = rmode; 314} 315 316Immediate::Immediate(const ExternalReference& ext) { 317 x_ = reinterpret_cast<int32_t>(ext.address()); 318 rmode_ = RelocInfo::EXTERNAL_REFERENCE; 319} 320 321 322Immediate::Immediate(Label* internal_offset) { 323 x_ = reinterpret_cast<int32_t>(internal_offset); 324 rmode_ = RelocInfo::INTERNAL_REFERENCE; 325} 326 327 328Immediate::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 343Immediate::Immediate(Smi* value) { 344 x_ = reinterpret_cast<intptr_t>(value); 345 rmode_ = RelocInfo::NONE32; 346} 347 348 349Immediate::Immediate(Address addr) { 350 x_ = reinterpret_cast<int32_t>(addr); 351 rmode_ = RelocInfo::NONE32; 352} 353 354 355void Assembler::emit(uint32_t x) { 356 *reinterpret_cast<uint32_t*>(pc_) = x; 357 pc_ += sizeof(uint32_t); 358} 359 360 361void Assembler::emit_q(uint64_t x) { 362 *reinterpret_cast<uint64_t*>(pc_) = x; 363 pc_ += sizeof(uint64_t); 364} 365 366 367void 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 381void 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 392void 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 400void 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 411void 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 421void 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 427void 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 435Address Assembler::target_address_at(Address pc, Address constant_pool) { 436 return pc + sizeof(int32_t) + *reinterpret_cast<int32_t*>(pc); 437} 438 439 440void 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 450Address 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 455void 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); 460} 461 462Address Assembler::target_address_from_return_address(Address pc) { 463 return pc - kCallTargetAddressOffset; 464} 465 466 467Displacement Assembler::disp_at(Label* L) { 468 return Displacement(long_at(L->pos())); 469} 470 471 472void Assembler::disp_at_put(Label* L, Displacement disp) { 473 long_at_put(L->pos(), disp.data()); 474} 475 476 477void 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 484void 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 496void 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 502void 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 509void 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 519void Operand::set_disp8(int8_t disp) { 520 DCHECK(len_ == 1 || len_ == 2); 521 *reinterpret_cast<int8_t*>(&buf_[len_++]) = disp; 522} 523 524 525void 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 533Operand::Operand(Register reg) { 534 // reg 535 set_modrm(3, reg); 536} 537 538 539Operand::Operand(XMMRegister xmm_reg) { 540 Register reg = { xmm_reg.code() }; 541 set_modrm(3, reg); 542} 543 544 545Operand::Operand(int32_t disp, RelocInfo::Mode rmode) { 546 // [disp/r] 547 set_modrm(0, ebp); 548 set_dispr(disp, rmode); 549} 550 551 552Operand::Operand(Immediate imm) { 553 // [disp/r] 554 set_modrm(0, ebp); 555 set_dispr(imm.x_, imm.rmode_); 556} 557} // namespace internal 558} // namespace v8 559 560#endif // V8_IA32_ASSEMBLER_IA32_INL_H_ 561