1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_X64_ASSEMBLER_X64_INL_H_ 6 #define V8_X64_ASSEMBLER_X64_INL_H_ 7 8 #include "src/x64/assembler-x64.h" 9 10 #include "src/base/cpu.h" 11 #include "src/debug/debug.h" 12 #include "src/v8memory.h" 13 14 namespace v8 { 15 namespace internal { 16 17 bool CpuFeatures::SupportsCrankshaft() { return true; } 18 19 20 // ----------------------------------------------------------------------------- 21 // Implementation of Assembler 22 23 24 static const byte kCallOpcode = 0xE8; 25 // The length of pushq(rbp), movp(rbp, rsp), Push(rsi) and Push(rdi). 26 static const int kNoCodeAgeSequenceLength = kPointerSize == kInt64Size ? 6 : 17; 27 28 29 void Assembler::emitl(uint32_t x) { 30 Memory::uint32_at(pc_) = x; 31 pc_ += sizeof(uint32_t); 32 } 33 34 35 void Assembler::emitp(void* x, RelocInfo::Mode rmode) { 36 uintptr_t value = reinterpret_cast<uintptr_t>(x); 37 Memory::uintptr_at(pc_) = value; 38 if (!RelocInfo::IsNone(rmode)) { 39 RecordRelocInfo(rmode, value); 40 } 41 pc_ += sizeof(uintptr_t); 42 } 43 44 45 void Assembler::emitq(uint64_t x) { 46 Memory::uint64_at(pc_) = x; 47 pc_ += sizeof(uint64_t); 48 } 49 50 51 void Assembler::emitw(uint16_t x) { 52 Memory::uint16_at(pc_) = x; 53 pc_ += sizeof(uint16_t); 54 } 55 56 57 void Assembler::emit_code_target(Handle<Code> target, 58 RelocInfo::Mode rmode, 59 TypeFeedbackId ast_id) { 60 DCHECK(RelocInfo::IsCodeTarget(rmode) || 61 rmode == RelocInfo::CODE_AGE_SEQUENCE); 62 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) { 63 RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID, ast_id.ToInt()); 64 } else { 65 RecordRelocInfo(rmode); 66 } 67 int current = code_targets_.length(); 68 if (current > 0 && code_targets_.last().is_identical_to(target)) { 69 // Optimization if we keep jumping to the same code target. 70 emitl(current - 1); 71 } else { 72 code_targets_.Add(target); 73 emitl(current); 74 } 75 } 76 77 78 void Assembler::emit_runtime_entry(Address entry, RelocInfo::Mode rmode) { 79 DCHECK(RelocInfo::IsRuntimeEntry(rmode)); 80 RecordRelocInfo(rmode); 81 emitl(static_cast<uint32_t>(entry - isolate()->code_range()->start())); 82 } 83 84 85 void Assembler::emit_rex_64(Register reg, Register rm_reg) { 86 emit(0x48 | reg.high_bit() << 2 | rm_reg.high_bit()); 87 } 88 89 90 void Assembler::emit_rex_64(XMMRegister reg, Register rm_reg) { 91 emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3); 92 } 93 94 95 void Assembler::emit_rex_64(Register reg, XMMRegister rm_reg) { 96 emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3); 97 } 98 99 100 void Assembler::emit_rex_64(Register reg, const Operand& op) { 101 emit(0x48 | reg.high_bit() << 2 | op.rex_); 102 } 103 104 105 void Assembler::emit_rex_64(XMMRegister reg, const Operand& op) { 106 emit(0x48 | (reg.code() & 0x8) >> 1 | op.rex_); 107 } 108 109 110 void Assembler::emit_rex_64(Register rm_reg) { 111 DCHECK_EQ(rm_reg.code() & 0xf, rm_reg.code()); 112 emit(0x48 | rm_reg.high_bit()); 113 } 114 115 116 void Assembler::emit_rex_64(const Operand& op) { 117 emit(0x48 | op.rex_); 118 } 119 120 121 void Assembler::emit_rex_32(Register reg, Register rm_reg) { 122 emit(0x40 | reg.high_bit() << 2 | rm_reg.high_bit()); 123 } 124 125 126 void Assembler::emit_rex_32(Register reg, const Operand& op) { 127 emit(0x40 | reg.high_bit() << 2 | op.rex_); 128 } 129 130 131 void Assembler::emit_rex_32(Register rm_reg) { 132 emit(0x40 | rm_reg.high_bit()); 133 } 134 135 136 void Assembler::emit_rex_32(const Operand& op) { 137 emit(0x40 | op.rex_); 138 } 139 140 141 void Assembler::emit_optional_rex_32(Register reg, Register rm_reg) { 142 byte rex_bits = reg.high_bit() << 2 | rm_reg.high_bit(); 143 if (rex_bits != 0) emit(0x40 | rex_bits); 144 } 145 146 147 void Assembler::emit_optional_rex_32(Register reg, const Operand& op) { 148 byte rex_bits = reg.high_bit() << 2 | op.rex_; 149 if (rex_bits != 0) emit(0x40 | rex_bits); 150 } 151 152 153 void Assembler::emit_optional_rex_32(XMMRegister reg, const Operand& op) { 154 byte rex_bits = (reg.code() & 0x8) >> 1 | op.rex_; 155 if (rex_bits != 0) emit(0x40 | rex_bits); 156 } 157 158 159 void Assembler::emit_optional_rex_32(XMMRegister reg, XMMRegister base) { 160 byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3; 161 if (rex_bits != 0) emit(0x40 | rex_bits); 162 } 163 164 165 void Assembler::emit_optional_rex_32(XMMRegister reg, Register base) { 166 byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3; 167 if (rex_bits != 0) emit(0x40 | rex_bits); 168 } 169 170 171 void Assembler::emit_optional_rex_32(Register reg, XMMRegister base) { 172 byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3; 173 if (rex_bits != 0) emit(0x40 | rex_bits); 174 } 175 176 177 void Assembler::emit_optional_rex_32(Register rm_reg) { 178 if (rm_reg.high_bit()) emit(0x41); 179 } 180 181 182 void Assembler::emit_optional_rex_32(XMMRegister rm_reg) { 183 if (rm_reg.high_bit()) emit(0x41); 184 } 185 186 187 void Assembler::emit_optional_rex_32(const Operand& op) { 188 if (op.rex_ != 0) emit(0x40 | op.rex_); 189 } 190 191 192 // byte 1 of 3-byte VEX 193 void Assembler::emit_vex3_byte1(XMMRegister reg, XMMRegister rm, 194 LeadingOpcode m) { 195 byte rxb = ~((reg.high_bit() << 2) | rm.high_bit()) << 5; 196 emit(rxb | m); 197 } 198 199 200 // byte 1 of 3-byte VEX 201 void Assembler::emit_vex3_byte1(XMMRegister reg, const Operand& rm, 202 LeadingOpcode m) { 203 byte rxb = ~((reg.high_bit() << 2) | rm.rex_) << 5; 204 emit(rxb | m); 205 } 206 207 208 // byte 1 of 2-byte VEX 209 void Assembler::emit_vex2_byte1(XMMRegister reg, XMMRegister v, VectorLength l, 210 SIMDPrefix pp) { 211 byte rv = ~((reg.high_bit() << 4) | v.code()) << 3; 212 emit(rv | l | pp); 213 } 214 215 216 // byte 2 of 3-byte VEX 217 void Assembler::emit_vex3_byte2(VexW w, XMMRegister v, VectorLength l, 218 SIMDPrefix pp) { 219 emit(w | ((~v.code() & 0xf) << 3) | l | pp); 220 } 221 222 223 void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg, 224 XMMRegister rm, VectorLength l, SIMDPrefix pp, 225 LeadingOpcode mm, VexW w) { 226 if (rm.high_bit() || mm != k0F || w != kW0) { 227 emit_vex3_byte0(); 228 emit_vex3_byte1(reg, rm, mm); 229 emit_vex3_byte2(w, vreg, l, pp); 230 } else { 231 emit_vex2_byte0(); 232 emit_vex2_byte1(reg, vreg, l, pp); 233 } 234 } 235 236 237 void Assembler::emit_vex_prefix(Register reg, Register vreg, Register rm, 238 VectorLength l, SIMDPrefix pp, LeadingOpcode mm, 239 VexW w) { 240 XMMRegister ireg = {reg.code()}; 241 XMMRegister ivreg = {vreg.code()}; 242 XMMRegister irm = {rm.code()}; 243 emit_vex_prefix(ireg, ivreg, irm, l, pp, mm, w); 244 } 245 246 247 void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg, 248 const Operand& rm, VectorLength l, 249 SIMDPrefix pp, LeadingOpcode mm, VexW w) { 250 if (rm.rex_ || mm != k0F || w != kW0) { 251 emit_vex3_byte0(); 252 emit_vex3_byte1(reg, rm, mm); 253 emit_vex3_byte2(w, vreg, l, pp); 254 } else { 255 emit_vex2_byte0(); 256 emit_vex2_byte1(reg, vreg, l, pp); 257 } 258 } 259 260 261 void Assembler::emit_vex_prefix(Register reg, Register vreg, const Operand& rm, 262 VectorLength l, SIMDPrefix pp, LeadingOpcode mm, 263 VexW w) { 264 XMMRegister ireg = {reg.code()}; 265 XMMRegister ivreg = {vreg.code()}; 266 emit_vex_prefix(ireg, ivreg, rm, l, pp, mm, w); 267 } 268 269 270 Address Assembler::target_address_at(Address pc, Address constant_pool) { 271 return Memory::int32_at(pc) + pc + 4; 272 } 273 274 275 void Assembler::set_target_address_at(Isolate* isolate, Address pc, 276 Address constant_pool, Address target, 277 ICacheFlushMode icache_flush_mode) { 278 Memory::int32_at(pc) = static_cast<int32_t>(target - pc - 4); 279 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 280 Assembler::FlushICache(isolate, pc, sizeof(int32_t)); 281 } 282 } 283 284 285 void Assembler::deserialization_set_target_internal_reference_at( 286 Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) { 287 Memory::Address_at(pc) = target; 288 } 289 290 291 Address Assembler::target_address_from_return_address(Address pc) { 292 return pc - kCallTargetAddressOffset; 293 } 294 295 296 Handle<Object> Assembler::code_target_object_handle_at(Address pc) { 297 return code_targets_[Memory::int32_at(pc)]; 298 } 299 300 301 Address Assembler::runtime_entry_at(Address pc) { 302 return Memory::int32_at(pc) + isolate()->code_range()->start(); 303 } 304 305 // ----------------------------------------------------------------------------- 306 // Implementation of RelocInfo 307 308 // The modes possibly affected by apply must be in kApplyMask. 309 void RelocInfo::apply(intptr_t delta) { 310 if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) { 311 Memory::int32_at(pc_) -= static_cast<int32_t>(delta); 312 } else if (IsCodeAgeSequence(rmode_)) { 313 if (*pc_ == kCallOpcode) { 314 int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1); 315 *p -= static_cast<int32_t>(delta); // Relocate entry. 316 } 317 } else if (IsInternalReference(rmode_)) { 318 // absolute code pointer inside code object moves with the code object. 319 Memory::Address_at(pc_) += delta; 320 } 321 } 322 323 324 Address RelocInfo::target_address() { 325 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); 326 return Assembler::target_address_at(pc_, host_); 327 } 328 329 330 Address RelocInfo::target_address_address() { 331 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) 332 || rmode_ == EMBEDDED_OBJECT 333 || rmode_ == EXTERNAL_REFERENCE); 334 return reinterpret_cast<Address>(pc_); 335 } 336 337 338 Address RelocInfo::constant_pool_entry_address() { 339 UNREACHABLE(); 340 return NULL; 341 } 342 343 344 int RelocInfo::target_address_size() { 345 if (IsCodedSpecially()) { 346 return Assembler::kSpecialTargetSize; 347 } else { 348 return kPointerSize; 349 } 350 } 351 352 353 void RelocInfo::set_target_address(Address target, 354 WriteBarrierMode write_barrier_mode, 355 ICacheFlushMode icache_flush_mode) { 356 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)); 357 Assembler::set_target_address_at(isolate_, pc_, host_, target, 358 icache_flush_mode); 359 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL && 360 IsCodeTarget(rmode_)) { 361 Object* target_code = Code::GetCodeFromTargetAddress(target); 362 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( 363 host(), this, HeapObject::cast(target_code)); 364 } 365 } 366 367 368 Object* RelocInfo::target_object() { 369 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 370 return Memory::Object_at(pc_); 371 } 372 373 374 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) { 375 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 376 if (rmode_ == EMBEDDED_OBJECT) { 377 return Memory::Object_Handle_at(pc_); 378 } else { 379 return origin->code_target_object_handle_at(pc_); 380 } 381 } 382 383 384 Address RelocInfo::target_external_reference() { 385 DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE); 386 return Memory::Address_at(pc_); 387 } 388 389 390 Address RelocInfo::target_internal_reference() { 391 DCHECK(rmode_ == INTERNAL_REFERENCE); 392 return Memory::Address_at(pc_); 393 } 394 395 396 Address RelocInfo::target_internal_reference_address() { 397 DCHECK(rmode_ == INTERNAL_REFERENCE); 398 return reinterpret_cast<Address>(pc_); 399 } 400 401 402 void RelocInfo::set_target_object(Object* target, 403 WriteBarrierMode write_barrier_mode, 404 ICacheFlushMode icache_flush_mode) { 405 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); 406 Memory::Object_at(pc_) = target; 407 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 408 Assembler::FlushICache(isolate_, pc_, sizeof(Address)); 409 } 410 if (write_barrier_mode == UPDATE_WRITE_BARRIER && 411 host() != NULL && 412 target->IsHeapObject()) { 413 host()->GetHeap()->incremental_marking()->RecordWrite( 414 host(), &Memory::Object_at(pc_), HeapObject::cast(target)); 415 } 416 } 417 418 419 Address RelocInfo::target_runtime_entry(Assembler* origin) { 420 DCHECK(IsRuntimeEntry(rmode_)); 421 return origin->runtime_entry_at(pc_); 422 } 423 424 425 void RelocInfo::set_target_runtime_entry(Address target, 426 WriteBarrierMode write_barrier_mode, 427 ICacheFlushMode icache_flush_mode) { 428 DCHECK(IsRuntimeEntry(rmode_)); 429 if (target_address() != target) { 430 set_target_address(target, write_barrier_mode, icache_flush_mode); 431 } 432 } 433 434 435 Handle<Cell> RelocInfo::target_cell_handle() { 436 DCHECK(rmode_ == RelocInfo::CELL); 437 Address address = Memory::Address_at(pc_); 438 return Handle<Cell>(reinterpret_cast<Cell**>(address)); 439 } 440 441 442 Cell* RelocInfo::target_cell() { 443 DCHECK(rmode_ == RelocInfo::CELL); 444 return Cell::FromValueAddress(Memory::Address_at(pc_)); 445 } 446 447 448 void RelocInfo::set_target_cell(Cell* cell, 449 WriteBarrierMode write_barrier_mode, 450 ICacheFlushMode icache_flush_mode) { 451 DCHECK(rmode_ == RelocInfo::CELL); 452 Address address = cell->address() + Cell::kValueOffset; 453 Memory::Address_at(pc_) = address; 454 if (icache_flush_mode != SKIP_ICACHE_FLUSH) { 455 Assembler::FlushICache(isolate_, pc_, sizeof(Address)); 456 } 457 if (write_barrier_mode == UPDATE_WRITE_BARRIER && 458 host() != NULL) { 459 // TODO(1550) We are passing NULL as a slot because cell can never be on 460 // evacuation candidate. 461 host()->GetHeap()->incremental_marking()->RecordWrite( 462 host(), NULL, cell); 463 } 464 } 465 466 467 void RelocInfo::WipeOut() { 468 if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) || 469 IsInternalReference(rmode_)) { 470 Memory::Address_at(pc_) = NULL; 471 } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) { 472 // Effectively write zero into the relocation. 473 Assembler::set_target_address_at(isolate_, pc_, host_, 474 pc_ + sizeof(int32_t)); 475 } else { 476 UNREACHABLE(); 477 } 478 } 479 480 481 bool RelocInfo::IsPatchedReturnSequence() { 482 // The recognized call sequence is: 483 // movq(kScratchRegister, address); call(kScratchRegister); 484 // It only needs to be distinguished from a return sequence 485 // movq(rsp, rbp); pop(rbp); ret(n); int3 *6 486 // The 11th byte is int3 (0xCC) in the return sequence and 487 // REX.WB (0x48+register bit) for the call sequence. 488 return pc_[Assembler::kMoveAddressIntoScratchRegisterInstructionLength] != 489 0xCC; 490 } 491 492 493 bool RelocInfo::IsPatchedDebugBreakSlotSequence() { 494 return !Assembler::IsNop(pc()); 495 } 496 497 498 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) { 499 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); 500 DCHECK(*pc_ == kCallOpcode); 501 return origin->code_target_object_handle_at(pc_ + 1); 502 } 503 504 505 Code* RelocInfo::code_age_stub() { 506 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); 507 DCHECK(*pc_ == kCallOpcode); 508 return Code::GetCodeFromTargetAddress( 509 Assembler::target_address_at(pc_ + 1, host_)); 510 } 511 512 513 void RelocInfo::set_code_age_stub(Code* stub, 514 ICacheFlushMode icache_flush_mode) { 515 DCHECK(*pc_ == kCallOpcode); 516 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE); 517 Assembler::set_target_address_at( 518 isolate_, pc_ + 1, host_, stub->instruction_start(), icache_flush_mode); 519 } 520 521 522 Address RelocInfo::debug_call_address() { 523 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); 524 return Memory::Address_at(pc_ + Assembler::kPatchDebugBreakSlotAddressOffset); 525 } 526 527 528 void RelocInfo::set_debug_call_address(Address target) { 529 DCHECK(IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()); 530 Memory::Address_at(pc_ + Assembler::kPatchDebugBreakSlotAddressOffset) = 531 target; 532 Assembler::FlushICache(isolate_, 533 pc_ + Assembler::kPatchDebugBreakSlotAddressOffset, 534 sizeof(Address)); 535 if (host() != NULL) { 536 Object* target_code = Code::GetCodeFromTargetAddress(target); 537 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode( 538 host(), this, HeapObject::cast(target_code)); 539 } 540 } 541 542 543 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) { 544 RelocInfo::Mode mode = rmode(); 545 if (mode == RelocInfo::EMBEDDED_OBJECT) { 546 visitor->VisitEmbeddedPointer(this); 547 Assembler::FlushICache(isolate, pc_, sizeof(Address)); 548 } else if (RelocInfo::IsCodeTarget(mode)) { 549 visitor->VisitCodeTarget(this); 550 } else if (mode == RelocInfo::CELL) { 551 visitor->VisitCell(this); 552 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { 553 visitor->VisitExternalReference(this); 554 } else if (mode == RelocInfo::INTERNAL_REFERENCE) { 555 visitor->VisitInternalReference(this); 556 } else if (RelocInfo::IsCodeAgeSequence(mode)) { 557 visitor->VisitCodeAgeSequence(this); 558 } else if (RelocInfo::IsDebugBreakSlot(mode) && 559 IsPatchedDebugBreakSlotSequence()) { 560 visitor->VisitDebugTarget(this); 561 } else if (RelocInfo::IsRuntimeEntry(mode)) { 562 visitor->VisitRuntimeEntry(this); 563 } 564 } 565 566 567 template<typename StaticVisitor> 568 void RelocInfo::Visit(Heap* heap) { 569 RelocInfo::Mode mode = rmode(); 570 if (mode == RelocInfo::EMBEDDED_OBJECT) { 571 StaticVisitor::VisitEmbeddedPointer(heap, this); 572 Assembler::FlushICache(heap->isolate(), pc_, sizeof(Address)); 573 } else if (RelocInfo::IsCodeTarget(mode)) { 574 StaticVisitor::VisitCodeTarget(heap, this); 575 } else if (mode == RelocInfo::CELL) { 576 StaticVisitor::VisitCell(heap, this); 577 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) { 578 StaticVisitor::VisitExternalReference(this); 579 } else if (mode == RelocInfo::INTERNAL_REFERENCE) { 580 StaticVisitor::VisitInternalReference(this); 581 } else if (RelocInfo::IsCodeAgeSequence(mode)) { 582 StaticVisitor::VisitCodeAgeSequence(heap, this); 583 } else if (RelocInfo::IsDebugBreakSlot(mode) && 584 IsPatchedDebugBreakSlotSequence()) { 585 StaticVisitor::VisitDebugTarget(heap, this); 586 } else if (RelocInfo::IsRuntimeEntry(mode)) { 587 StaticVisitor::VisitRuntimeEntry(this); 588 } 589 } 590 591 592 // ----------------------------------------------------------------------------- 593 // Implementation of Operand 594 595 void Operand::set_modrm(int mod, Register rm_reg) { 596 DCHECK(is_uint2(mod)); 597 buf_[0] = mod << 6 | rm_reg.low_bits(); 598 // Set REX.B to the high bit of rm.code(). 599 rex_ |= rm_reg.high_bit(); 600 } 601 602 603 void Operand::set_sib(ScaleFactor scale, Register index, Register base) { 604 DCHECK(len_ == 1); 605 DCHECK(is_uint2(scale)); 606 // Use SIB with no index register only for base rsp or r12. Otherwise we 607 // would skip the SIB byte entirely. 608 DCHECK(!index.is(rsp) || base.is(rsp) || base.is(r12)); 609 buf_[1] = (scale << 6) | (index.low_bits() << 3) | base.low_bits(); 610 rex_ |= index.high_bit() << 1 | base.high_bit(); 611 len_ = 2; 612 } 613 614 void Operand::set_disp8(int disp) { 615 DCHECK(is_int8(disp)); 616 DCHECK(len_ == 1 || len_ == 2); 617 int8_t* p = reinterpret_cast<int8_t*>(&buf_[len_]); 618 *p = disp; 619 len_ += sizeof(int8_t); 620 } 621 622 void Operand::set_disp32(int disp) { 623 DCHECK(len_ == 1 || len_ == 2); 624 int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]); 625 *p = disp; 626 len_ += sizeof(int32_t); 627 } 628 629 void Operand::set_disp64(int64_t disp) { 630 DCHECK_EQ(1, len_); 631 int64_t* p = reinterpret_cast<int64_t*>(&buf_[len_]); 632 *p = disp; 633 len_ += sizeof(disp); 634 } 635 } // namespace internal 636 } // namespace v8 637 638 #endif // V8_X64_ASSEMBLER_X64_INL_H_ 639