assembler-x64-inl.h 18.6 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6 7
#ifndef V8_X64_ASSEMBLER_X64_INL_H_
#define V8_X64_ASSEMBLER_X64_INL_H_

8
#include "src/x64/assembler-x64.h"
9

10
#include "src/base/cpu.h"
11 12
#include "src/debug.h"
#include "src/v8memory.h"
13

14 15
namespace v8 {
namespace internal {
16

17 18
bool CpuFeatures::SupportsCrankshaft() { return true; }

19

20 21 22 23
// -----------------------------------------------------------------------------
// Implementation of Assembler


24
static const byte kCallOpcode = 0xE8;
25 26
// The length of pushq(rbp), movp(rbp, rsp), Push(rsi) and Push(rdi).
static const int kNoCodeAgeSequenceLength = kPointerSize == kInt64Size ? 6 : 17;
27 28


29 30
void Assembler::emitl(uint32_t x) {
  Memory::uint32_at(pc_) = x;
31 32
  pc_ += sizeof(uint32_t);
}
33

34

35 36 37 38 39 40 41 42 43 44
void Assembler::emitp(void* x, RelocInfo::Mode rmode) {
  uintptr_t value = reinterpret_cast<uintptr_t>(x);
  Memory::uintptr_at(pc_) = value;
  if (!RelocInfo::IsNone(rmode)) {
    RecordRelocInfo(rmode, value);
  }
  pc_ += sizeof(uintptr_t);
}


45
void Assembler::emitq(uint64_t x) {
46
  Memory::uint64_at(pc_) = x;
lrn@chromium.org's avatar
lrn@chromium.org committed
47
  pc_ += sizeof(uint64_t);
48 49 50
}


51 52 53 54 55 56
void Assembler::emitw(uint16_t x) {
  Memory::uint16_at(pc_) = x;
  pc_ += sizeof(uint16_t);
}


57 58
void Assembler::emit_code_target(Handle<Code> target,
                                 RelocInfo::Mode rmode,
59
                                 TypeFeedbackId ast_id) {
60
  DCHECK(RelocInfo::IsCodeTarget(rmode) ||
61
      rmode == RelocInfo::CODE_AGE_SEQUENCE);
62 63
  if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) {
    RecordRelocInfo(RelocInfo::CODE_TARGET_WITH_ID, ast_id.ToInt());
64 65 66
  } else {
    RecordRelocInfo(rmode);
  }
67 68 69 70 71 72 73 74 75 76 77
  int current = code_targets_.length();
  if (current > 0 && code_targets_.last().is_identical_to(target)) {
    // Optimization if we keep jumping to the same code target.
    emitl(current - 1);
  } else {
    code_targets_.Add(target);
    emitl(current);
  }
}


78
void Assembler::emit_runtime_entry(Address entry, RelocInfo::Mode rmode) {
79
  DCHECK(RelocInfo::IsRuntimeEntry(rmode));
80 81 82 83 84
  RecordRelocInfo(rmode);
  emitl(static_cast<uint32_t>(entry - isolate()->code_range()->start()));
}


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 91 92 93 94
void Assembler::emit_rex_64(XMMRegister reg, Register rm_reg) {
  emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
}


95 96 97 98 99
void Assembler::emit_rex_64(Register reg, XMMRegister rm_reg) {
  emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
}


100
void Assembler::emit_rex_64(Register reg, const Operand& op) {
101
  emit(0x48 | reg.high_bit() << 2 | op.rex_);
102 103 104
}


105 106 107 108 109
void Assembler::emit_rex_64(XMMRegister reg, const Operand& op) {
  emit(0x48 | (reg.code() & 0x8) >> 1 | op.rex_);
}


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 117 118 119 120
}


void Assembler::emit_rex_64(const Operand& op) {
  emit(0x48 | op.rex_);
}


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 137 138 139 140
}


void Assembler::emit_rex_32(const Operand& op) {
  emit(0x40 | op.rex_);
}


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 150 151 152
  if (rex_bits != 0) emit(0x40 | rex_bits);
}


153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
void Assembler::emit_optional_rex_32(XMMRegister reg, const Operand& op) {
  byte rex_bits =  (reg.code() & 0x8) >> 1 | op.rex_;
  if (rex_bits != 0) emit(0x40 | rex_bits);
}


void Assembler::emit_optional_rex_32(XMMRegister reg, XMMRegister base) {
  byte rex_bits =  (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
  if (rex_bits != 0) emit(0x40 | rex_bits);
}


void Assembler::emit_optional_rex_32(XMMRegister reg, Register base) {
  byte rex_bits =  (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
  if (rex_bits != 0) emit(0x40 | rex_bits);
}


171 172 173 174 175 176
void Assembler::emit_optional_rex_32(Register reg, XMMRegister base) {
  byte rex_bits =  (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
  if (rex_bits != 0) emit(0x40 | rex_bits);
}


177
void Assembler::emit_optional_rex_32(Register rm_reg) {
178
  if (rm_reg.high_bit()) emit(0x41);
179 180 181
}


182 183 184 185 186
void Assembler::emit_optional_rex_32(XMMRegister rm_reg) {
  if (rm_reg.high_bit()) emit(0x41);
}


187 188
void Assembler::emit_optional_rex_32(const Operand& op) {
  if (op.rex_ != 0) emit(0x40 | op.rex_);
189 190 191
}


192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
// byte 1 of 3-byte VEX
void Assembler::emit_vex3_byte1(XMMRegister reg, XMMRegister rm,
                                LeadingOpcode m) {
  byte rxb = ~((reg.high_bit() << 2) | rm.high_bit()) << 5;
  emit(rxb | m);
}


// byte 1 of 3-byte VEX
void Assembler::emit_vex3_byte1(XMMRegister reg, const Operand& rm,
                                LeadingOpcode m) {
  byte rxb = ~((reg.high_bit() << 2) | rm.rex_) << 5;
  emit(rxb | m);
}


// byte 1 of 2-byte VEX
void Assembler::emit_vex2_byte1(XMMRegister reg, XMMRegister v, VectorLength l,
                                SIMDPrefix pp) {
  byte rv = ~((reg.high_bit() << 4) | v.code()) << 3;
  emit(rv | l | pp);
}


// byte 2 of 3-byte VEX
void Assembler::emit_vex3_byte2(VexW w, XMMRegister v, VectorLength l,
                                SIMDPrefix pp) {
  emit(w | ((~v.code() & 0xf) << 3) | l | pp);
}


void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg,
                                XMMRegister rm, VectorLength l, SIMDPrefix pp,
                                LeadingOpcode mm, VexW w) {
  if (rm.high_bit() || mm != k0F || w != kW0) {
    emit_vex3_byte0();
    emit_vex3_byte1(reg, rm, mm);
    emit_vex3_byte2(w, vreg, l, pp);
  } else {
    emit_vex2_byte0();
    emit_vex2_byte1(reg, vreg, l, pp);
  }
}


void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg,
                                const Operand& rm, VectorLength l,
                                SIMDPrefix pp, LeadingOpcode mm, VexW w) {
  if (rm.rex_ || mm != k0F || w != kW0) {
    emit_vex3_byte0();
    emit_vex3_byte1(reg, rm, mm);
    emit_vex3_byte2(w, vreg, l, pp);
  } else {
    emit_vex2_byte0();
    emit_vex2_byte1(reg, vreg, l, pp);
  }
}


251 252
Address Assembler::target_address_at(Address pc,
                                     ConstantPoolArray* constant_pool) {
253
  return Memory::int32_at(pc) + pc + 4;
254 255 256
}


257 258
void Assembler::set_target_address_at(Address pc,
                                      ConstantPoolArray* constant_pool,
259 260
                                      Address target,
                                      ICacheFlushMode icache_flush_mode) {
261
  Memory::int32_at(pc) = static_cast<int32_t>(target - pc - 4);
262
  if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
263
    CpuFeatures::FlushICache(pc, sizeof(int32_t));
264
  }
265 266
}

267 268 269 270 271 272

Address Assembler::target_address_from_return_address(Address pc) {
  return pc - kCallTargetAddressOffset;
}


273 274 275 276 277
Address Assembler::break_address_from_return_address(Address pc) {
  return pc - Assembler::kPatchDebugBreakSlotReturnOffset;
}


278 279 280
Handle<Object> Assembler::code_target_object_handle_at(Address pc) {
  return code_targets_[Memory::int32_at(pc)];
}
281

282 283 284 285 286

Address Assembler::runtime_entry_at(Address pc) {
  return Memory::int32_at(pc) + isolate()->code_range()->start();
}

287 288 289
// -----------------------------------------------------------------------------
// Implementation of RelocInfo

290
// The modes possibly affected by apply must be in kApplyMask.
291 292
void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
  bool flush_icache = icache_flush_mode != SKIP_ICACHE_FLUSH;
293
  if (IsInternalReference(rmode_)) {
294
    // absolute code pointer inside code object moves with the code object.
295
    Memory::Address_at(pc_) += delta;
296
    if (flush_icache) CpuFeatures::FlushICache(pc_, sizeof(Address));
297
  } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
298
    Memory::int32_at(pc_) -= static_cast<int32_t>(delta);
299
    if (flush_icache) CpuFeatures::FlushICache(pc_, sizeof(int32_t));
300 301 302
  } else if (rmode_ == CODE_AGE_SEQUENCE) {
    if (*pc_ == kCallOpcode) {
      int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
303
      *p -= static_cast<int32_t>(delta);  // Relocate entry.
304
      if (flush_icache) CpuFeatures::FlushICache(p, sizeof(uint32_t));
305
    }
306 307 308 309
  }
}


310
Address RelocInfo::target_address() {
311
  DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
312
  return Assembler::target_address_at(pc_, host_);
313 314 315 316
}


Address RelocInfo::target_address_address() {
317
  DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
318 319
                              || rmode_ == EMBEDDED_OBJECT
                              || rmode_ == EXTERNAL_REFERENCE);
320 321 322 323
  return reinterpret_cast<Address>(pc_);
}


324 325 326 327 328 329
Address RelocInfo::constant_pool_entry_address() {
  UNREACHABLE();
  return NULL;
}


330 331
int RelocInfo::target_address_size() {
  if (IsCodedSpecially()) {
332
    return Assembler::kSpecialTargetSize;
333
  } else {
334
    return kPointerSize;
335 336 337 338
  }
}


339 340 341
void RelocInfo::set_target_address(Address target,
                                   WriteBarrierMode write_barrier_mode,
                                   ICacheFlushMode icache_flush_mode) {
342
  DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
343 344 345
  Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
  if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
      IsCodeTarget(rmode_)) {
346
    Object* target_code = Code::GetCodeFromTargetAddress(target);
347 348
    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
        host(), this, HeapObject::cast(target_code));
349
  }
350
}
351 352


353
Object* RelocInfo::target_object() {
354
  DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
355 356 357 358
  return Memory::Object_at(pc_);
}


359
Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
360
  DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
361 362 363 364 365
  if (rmode_ == EMBEDDED_OBJECT) {
    return Memory::Object_Handle_at(pc_);
  } else {
    return origin->code_target_object_handle_at(pc_);
  }
366 367 368
}


369
Address RelocInfo::target_reference() {
370
  DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
371
  return Memory::Address_at(pc_);
372 373 374
}


375 376 377
void RelocInfo::set_target_object(Object* target,
                                  WriteBarrierMode write_barrier_mode,
                                  ICacheFlushMode icache_flush_mode) {
378
  DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
379
  Memory::Object_at(pc_) = target;
380
  if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
381
    CpuFeatures::FlushICache(pc_, sizeof(Address));
382 383
  }
  if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
384 385
      host() != NULL &&
      target->IsHeapObject()) {
386 387 388
    host()->GetHeap()->incremental_marking()->RecordWrite(
        host(), &Memory::Object_at(pc_), HeapObject::cast(target));
  }
389 390 391
}


392
Address RelocInfo::target_runtime_entry(Assembler* origin) {
393
  DCHECK(IsRuntimeEntry(rmode_));
394 395 396 397 398
  return origin->runtime_entry_at(pc_);
}


void RelocInfo::set_target_runtime_entry(Address target,
399 400
                                         WriteBarrierMode write_barrier_mode,
                                         ICacheFlushMode icache_flush_mode) {
401
  DCHECK(IsRuntimeEntry(rmode_));
402 403 404
  if (target_address() != target) {
    set_target_address(target, write_barrier_mode, icache_flush_mode);
  }
405 406 407
}


408
Handle<Cell> RelocInfo::target_cell_handle() {
409
  DCHECK(rmode_ == RelocInfo::CELL);
410
  Address address = Memory::Address_at(pc_);
411
  return Handle<Cell>(reinterpret_cast<Cell**>(address));
412 413 414
}


415
Cell* RelocInfo::target_cell() {
416
  DCHECK(rmode_ == RelocInfo::CELL);
417
  return Cell::FromValueAddress(Memory::Address_at(pc_));
418 419 420
}


421 422 423
void RelocInfo::set_target_cell(Cell* cell,
                                WriteBarrierMode write_barrier_mode,
                                ICacheFlushMode icache_flush_mode) {
424
  DCHECK(rmode_ == RelocInfo::CELL);
425
  Address address = cell->address() + Cell::kValueOffset;
426
  Memory::Address_at(pc_) = address;
427
  if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
428
    CpuFeatures::FlushICache(pc_, sizeof(Address));
429 430
  }
  if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
431
      host() != NULL) {
432 433 434 435 436
    // TODO(1550) We are passing NULL as a slot because cell can never be on
    // evacuation candidate.
    host()->GetHeap()->incremental_marking()->RecordWrite(
        host(), NULL, cell);
  }
437 438 439
}


440 441 442 443 444
void RelocInfo::WipeOut() {
  if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_)) {
    Memory::Address_at(pc_) = NULL;
  } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
    // Effectively write zero into the relocation.
445
    Assembler::set_target_address_at(pc_, host_, pc_ + sizeof(int32_t));
446 447 448 449 450 451
  } else {
    UNREACHABLE();
  }
}


452
bool RelocInfo::IsPatchedReturnSequence() {
453
  // The recognized call sequence is:
454
  //  movq(kScratchRegister, address); call(kScratchRegister);
455 456 457 458
  // It only needs to be distinguished from a return sequence
  //  movq(rsp, rbp); pop(rbp); ret(n); int3 *6
  // The 11th byte is int3 (0xCC) in the return sequence and
  // REX.WB (0x48+register bit) for the call sequence.
459 460
  return pc_[Assembler::kMoveAddressIntoScratchRegisterInstructionLength] !=
         0xCC;
461 462 463
}


464 465 466 467 468
bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
  return !Assembler::IsNop(pc());
}


469
Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
470 471
  DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
  DCHECK(*pc_ == kCallOpcode);
472 473 474 475
  return origin->code_target_object_handle_at(pc_ + 1);
}


476
Code* RelocInfo::code_age_stub() {
477 478
  DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
  DCHECK(*pc_ == kCallOpcode);
479
  return Code::GetCodeFromTargetAddress(
480
      Assembler::target_address_at(pc_ + 1, host_));
481 482 483
}


484 485
void RelocInfo::set_code_age_stub(Code* stub,
                                  ICacheFlushMode icache_flush_mode) {
486 487
  DCHECK(*pc_ == kCallOpcode);
  DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
488 489
  Assembler::set_target_address_at(pc_ + 1, host_, stub->instruction_start(),
                                   icache_flush_mode);
490 491 492
}


493
Address RelocInfo::call_address() {
494
  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
495
         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
496 497
  return Memory::Address_at(
      pc_ + Assembler::kRealPatchReturnSequenceAddressOffset);
498 499 500 501
}


void RelocInfo::set_call_address(Address target) {
502
  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
503
         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
504 505
  Memory::Address_at(pc_ + Assembler::kRealPatchReturnSequenceAddressOffset) =
      target;
506 507
  CpuFeatures::FlushICache(
      pc_ + Assembler::kRealPatchReturnSequenceAddressOffset, sizeof(Address));
508 509 510 511 512
  if (host() != NULL) {
    Object* target_code = Code::GetCodeFromTargetAddress(target);
    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
        host(), this, HeapObject::cast(target_code));
  }
513 514 515 516 517 518 519 520 521 522 523 524 525 526
}


Object* RelocInfo::call_object() {
  return *call_object_address();
}


void RelocInfo::set_call_object(Object* target) {
  *call_object_address() = target;
}


Object** RelocInfo::call_object_address() {
527
  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
528
         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
529 530
  return reinterpret_cast<Object**>(
      pc_ + Assembler::kPatchReturnSequenceAddressOffset);
531 532
}

533

534
void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
535 536
  RelocInfo::Mode mode = rmode();
  if (mode == RelocInfo::EMBEDDED_OBJECT) {
537
    visitor->VisitEmbeddedPointer(this);
538
    CpuFeatures::FlushICache(pc_, sizeof(Address));
539 540
  } else if (RelocInfo::IsCodeTarget(mode)) {
    visitor->VisitCodeTarget(this);
541 542
  } else if (mode == RelocInfo::CELL) {
    visitor->VisitCell(this);
543
  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
544
    visitor->VisitExternalReference(this);
545
    CpuFeatures::FlushICache(pc_, sizeof(Address));
546 547
  } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    visitor->VisitCodeAgeSequence(this);
548
  } else if (((RelocInfo::IsJSReturn(mode) &&
549 550
              IsPatchedReturnSequence()) ||
             (RelocInfo::IsDebugBreakSlot(mode) &&
551
              IsPatchedDebugBreakSlotSequence())) &&
552
             isolate->debug()->has_break_points()) {
553
    visitor->VisitDebugTarget(this);
554
  } else if (RelocInfo::IsRuntimeEntry(mode)) {
555 556 557 558 559
    visitor->VisitRuntimeEntry(this);
  }
}


560
template<typename StaticVisitor>
561
void RelocInfo::Visit(Heap* heap) {
562 563
  RelocInfo::Mode mode = rmode();
  if (mode == RelocInfo::EMBEDDED_OBJECT) {
564
    StaticVisitor::VisitEmbeddedPointer(heap, this);
565
    CpuFeatures::FlushICache(pc_, sizeof(Address));
566
  } else if (RelocInfo::IsCodeTarget(mode)) {
567
    StaticVisitor::VisitCodeTarget(heap, this);
568 569
  } else if (mode == RelocInfo::CELL) {
    StaticVisitor::VisitCell(heap, this);
570
  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
571
    StaticVisitor::VisitExternalReference(this);
572
    CpuFeatures::FlushICache(pc_, sizeof(Address));
573 574
  } else if (RelocInfo::IsCodeAgeSequence(mode)) {
    StaticVisitor::VisitCodeAgeSequence(heap, this);
575
  } else if (heap->isolate()->debug()->has_break_points() &&
576 577 578 579
             ((RelocInfo::IsJSReturn(mode) &&
              IsPatchedReturnSequence()) ||
             (RelocInfo::IsDebugBreakSlot(mode) &&
              IsPatchedDebugBreakSlotSequence()))) {
580
    StaticVisitor::VisitDebugTarget(heap, this);
581
  } else if (RelocInfo::IsRuntimeEntry(mode)) {
582 583 584 585 586
    StaticVisitor::VisitRuntimeEntry(this);
  }
}


587 588 589
// -----------------------------------------------------------------------------
// Implementation of Operand

590
void Operand::set_modrm(int mod, Register rm_reg) {
591
  DCHECK(is_uint2(mod));
592
  buf_[0] = mod << 6 | rm_reg.low_bits();
593
  // Set REX.B to the high bit of rm.code().
594
  rex_ |= rm_reg.high_bit();
595 596 597 598
}


void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
599 600
  DCHECK(len_ == 1);
  DCHECK(is_uint2(scale));
601 602
  // Use SIB with no index register only for base rsp or r12. Otherwise we
  // would skip the SIB byte entirely.
603
  DCHECK(!index.is(rsp) || base.is(rsp) || base.is(r12));
604
  buf_[1] = (scale << 6) | (index.low_bits() << 3) | base.low_bits();
605
  rex_ |= index.high_bit() << 1 | base.high_bit();
606 607 608
  len_ = 2;
}

609
void Operand::set_disp8(int disp) {
610 611
  DCHECK(is_int8(disp));
  DCHECK(len_ == 1 || len_ == 2);
612 613 614 615
  int8_t* p = reinterpret_cast<int8_t*>(&buf_[len_]);
  *p = disp;
  len_ += sizeof(int8_t);
}
616

617
void Operand::set_disp32(int disp) {
618
  DCHECK(len_ == 1 || len_ == 2);
619 620 621 622 623
  int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]);
  *p = disp;
  len_ += sizeof(int32_t);
}

624 625 626 627 628 629
void Operand::set_disp64(int64_t disp) {
  DCHECK_EQ(1, len_);
  int64_t* p = reinterpret_cast<int64_t*>(&buf_[len_]);
  *p = disp;
  len_ += sizeof(disp);
}
630 631 632
} }  // namespace v8::internal

#endif  // V8_X64_ASSEMBLER_X64_INL_H_