V8 Project
assembler-x64-inl.h
Go to the documentation of this file.
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 
9 
10 #include "src/base/cpu.h"
11 #include "src/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 
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) {
47  pc_ += sizeof(uint64_t);
48 }
49 
50 
53  pc_ += sizeof(uint16_t);
54 }
55 
56 
58  RelocInfo::Mode rmode,
59  TypeFeedbackId ast_id) {
62  if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) {
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 
80  RecordRelocInfo(rmode);
81  emitl(static_cast<uint32_t>(entry - isolate()->code_range()->start()));
82 }
83 
84 
86  emit(0x48 | reg.high_bit() << 2 | rm_reg.high_bit());
87 }
88 
89 
91  emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
92 }
93 
94 
96  emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
97 }
98 
99 
101  emit(0x48 | reg.high_bit() << 2 | op.rex_);
102 }
103 
104 
106  emit(0x48 | (reg.code() & 0x8) >> 1 | op.rex_);
107 }
108 
109 
111  DCHECK_EQ(rm_reg.code() & 0xf, rm_reg.code());
112  emit(0x48 | rm_reg.high_bit());
113 }
114 
115 
117  emit(0x48 | op.rex_);
118 }
119 
120 
122  emit(0x40 | reg.high_bit() << 2 | rm_reg.high_bit());
123 }
124 
125 
127  emit(0x40 | reg.high_bit() << 2 | op.rex_);
128 }
129 
130 
132  emit(0x40 | rm_reg.high_bit());
133 }
134 
135 
137  emit(0x40 | op.rex_);
138 }
139 
140 
142  byte rex_bits = reg.high_bit() << 2 | rm_reg.high_bit();
143  if (rex_bits != 0) emit(0x40 | rex_bits);
144 }
145 
146 
148  byte rex_bits = reg.high_bit() << 2 | op.rex_;
149  if (rex_bits != 0) emit(0x40 | rex_bits);
150 }
151 
152 
154  byte rex_bits = (reg.code() & 0x8) >> 1 | op.rex_;
155  if (rex_bits != 0) emit(0x40 | rex_bits);
156 }
157 
158 
160  byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
161  if (rex_bits != 0) emit(0x40 | rex_bits);
162 }
163 
164 
166  byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
167  if (rex_bits != 0) emit(0x40 | rex_bits);
168 }
169 
170 
172  byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
173  if (rex_bits != 0) emit(0x40 | rex_bits);
174 }
175 
176 
178  if (rm_reg.high_bit()) emit(0x41);
179 }
180 
181 
183  if (op.rex_ != 0) emit(0x40 | op.rex_);
184 }
185 
186 
188  ConstantPoolArray* constant_pool) {
189  return Memory::int32_at(pc) + pc + 4;
190 }
191 
192 
194  ConstantPoolArray* constant_pool,
195  Address target,
196  ICacheFlushMode icache_flush_mode) {
197  Memory::int32_at(pc) = static_cast<int32_t>(target - pc - 4);
198  if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
200  }
201 }
202 
203 
205  return pc - kCallTargetAddressOffset;
206 }
207 
208 
211 }
212 
213 
216 }
217 
218 
220  return Memory::int32_at(pc) + isolate()->code_range()->start();
221 }
222 
223 // -----------------------------------------------------------------------------
224 // Implementation of RelocInfo
225 
226 // The modes possibly affected by apply must be in kApplyMask.
227 void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
228  bool flush_icache = icache_flush_mode != SKIP_ICACHE_FLUSH;
230  // absolute code pointer inside code object moves with the code object.
231  Memory::Address_at(pc_) += static_cast<int32_t>(delta);
232  if (flush_icache) CpuFeatures::FlushICache(pc_, sizeof(Address));
233  } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
234  Memory::int32_at(pc_) -= static_cast<int32_t>(delta);
235  if (flush_icache) CpuFeatures::FlushICache(pc_, sizeof(int32_t));
236  } else if (rmode_ == CODE_AGE_SEQUENCE) {
237  if (*pc_ == kCallOpcode) {
238  int32_t* p = reinterpret_cast<int32_t*>(pc_ + 1);
239  *p -= static_cast<int32_t>(delta); // Relocate entry.
240  if (flush_icache) CpuFeatures::FlushICache(p, sizeof(uint32_t));
241  }
242  }
243 }
244 
245 
246 Address RelocInfo::target_address() {
249 }
250 
251 
252 Address RelocInfo::target_address_address() {
254  || rmode_ == EMBEDDED_OBJECT
255  || rmode_ == EXTERNAL_REFERENCE);
256  return reinterpret_cast<Address>(pc_);
257 }
258 
259 
260 Address RelocInfo::constant_pool_entry_address() {
261  UNREACHABLE();
262  return NULL;
263 }
264 
265 
266 int RelocInfo::target_address_size() {
267  if (IsCodedSpecially()) {
269  } else {
270  return kPointerSize;
271  }
272 }
273 
274 
275 void RelocInfo::set_target_address(Address target,
276  WriteBarrierMode write_barrier_mode,
277  ICacheFlushMode icache_flush_mode) {
279  Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
280  if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
281  IsCodeTarget(rmode_)) {
282  Object* target_code = Code::GetCodeFromTargetAddress(target);
283  host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
284  host(), this, HeapObject::cast(target_code));
285  }
286 }
287 
288 
289 Object* RelocInfo::target_object() {
291  return Memory::Object_at(pc_);
292 }
293 
294 
295 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
297  if (rmode_ == EMBEDDED_OBJECT) {
299  } else {
300  return origin->code_target_object_handle_at(pc_);
301  }
302 }
303 
304 
305 Address RelocInfo::target_reference() {
307  return Memory::Address_at(pc_);
308 }
309 
310 
311 void RelocInfo::set_target_object(Object* target,
312  WriteBarrierMode write_barrier_mode,
313  ICacheFlushMode icache_flush_mode) {
315  Memory::Object_at(pc_) = target;
316  if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
318  }
319  if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
320  host() != NULL &&
321  target->IsHeapObject()) {
322  host()->GetHeap()->incremental_marking()->RecordWrite(
323  host(), &Memory::Object_at(pc_), HeapObject::cast(target));
324  }
325 }
326 
327 
328 Address RelocInfo::target_runtime_entry(Assembler* origin) {
330  return origin->runtime_entry_at(pc_);
331 }
332 
333 
334 void RelocInfo::set_target_runtime_entry(Address target,
335  WriteBarrierMode write_barrier_mode,
336  ICacheFlushMode icache_flush_mode) {
338  if (target_address() != target) {
339  set_target_address(target, write_barrier_mode, icache_flush_mode);
340  }
341 }
342 
343 
344 Handle<Cell> RelocInfo::target_cell_handle() {
346  Address address = Memory::Address_at(pc_);
347  return Handle<Cell>(reinterpret_cast<Cell**>(address));
348 }
349 
350 
351 Cell* RelocInfo::target_cell() {
354 }
355 
356 
357 void RelocInfo::set_target_cell(Cell* cell,
358  WriteBarrierMode write_barrier_mode,
359  ICacheFlushMode icache_flush_mode) {
361  Address address = cell->address() + Cell::kValueOffset;
362  Memory::Address_at(pc_) = address;
363  if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
365  }
366  if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
367  host() != NULL) {
368  // TODO(1550) We are passing NULL as a slot because cell can never be on
369  // evacuation candidate.
370  host()->GetHeap()->incremental_marking()->RecordWrite(
371  host(), NULL, cell);
372  }
373 }
374 
375 
376 void RelocInfo::WipeOut() {
379  } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
380  // Effectively write zero into the relocation.
382  } else {
383  UNREACHABLE();
384  }
385 }
386 
387 
388 bool RelocInfo::IsPatchedReturnSequence() {
389  // The recognized call sequence is:
390  // movq(kScratchRegister, address); call(kScratchRegister);
391  // It only needs to be distinguished from a return sequence
392  // movq(rsp, rbp); pop(rbp); ret(n); int3 *6
393  // The 11th byte is int3 (0xCC) in the return sequence and
394  // REX.WB (0x48+register bit) for the call sequence.
396  0xCC;
397 }
398 
399 
400 bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
401  return !Assembler::IsNop(pc());
402 }
403 
404 
405 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
407  DCHECK(*pc_ == kCallOpcode);
408  return origin->code_target_object_handle_at(pc_ + 1);
409 }
410 
411 
412 Code* RelocInfo::code_age_stub() {
414  DCHECK(*pc_ == kCallOpcode);
417 }
418 
419 
420 void RelocInfo::set_code_age_stub(Code* stub,
421  ICacheFlushMode icache_flush_mode) {
422  DCHECK(*pc_ == kCallOpcode);
425  icache_flush_mode);
426 }
427 
428 
429 Address RelocInfo::call_address() {
430  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
431  (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
432  return Memory::Address_at(
434 }
435 
436 
437 void RelocInfo::set_call_address(Address target) {
438  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
439  (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
441  target;
444  if (host() != NULL) {
445  Object* target_code = Code::GetCodeFromTargetAddress(target);
446  host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
447  host(), this, HeapObject::cast(target_code));
448  }
449 }
450 
451 
452 Object* RelocInfo::call_object() {
453  return *call_object_address();
454 }
455 
456 
457 void RelocInfo::set_call_object(Object* target) {
458  *call_object_address() = target;
459 }
460 
461 
462 Object** RelocInfo::call_object_address() {
463  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
464  (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
465  return reinterpret_cast<Object**>(
467 }
468 
469 
470 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
473  visitor->VisitEmbeddedPointer(this);
475  } else if (RelocInfo::IsCodeTarget(mode)) {
476  visitor->VisitCodeTarget(this);
477  } else if (mode == RelocInfo::CELL) {
478  visitor->VisitCell(this);
479  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
480  visitor->VisitExternalReference(this);
482  } else if (RelocInfo::IsCodeAgeSequence(mode)) {
483  visitor->VisitCodeAgeSequence(this);
484  } else if (((RelocInfo::IsJSReturn(mode) &&
485  IsPatchedReturnSequence()) ||
487  IsPatchedDebugBreakSlotSequence())) &&
488  isolate->debug()->has_break_points()) {
489  visitor->VisitDebugTarget(this);
490  } else if (RelocInfo::IsRuntimeEntry(mode)) {
491  visitor->VisitRuntimeEntry(this);
492  }
493 }
494 
495 
496 template<typename StaticVisitor>
497 void RelocInfo::Visit(Heap* heap) {
500  StaticVisitor::VisitEmbeddedPointer(heap, this);
502  } else if (RelocInfo::IsCodeTarget(mode)) {
503  StaticVisitor::VisitCodeTarget(heap, this);
504  } else if (mode == RelocInfo::CELL) {
505  StaticVisitor::VisitCell(heap, this);
506  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
507  StaticVisitor::VisitExternalReference(this);
509  } else if (RelocInfo::IsCodeAgeSequence(mode)) {
510  StaticVisitor::VisitCodeAgeSequence(heap, this);
511  } else if (heap->isolate()->debug()->has_break_points() &&
513  IsPatchedReturnSequence()) ||
515  IsPatchedDebugBreakSlotSequence()))) {
516  StaticVisitor::VisitDebugTarget(heap, this);
517  } else if (RelocInfo::IsRuntimeEntry(mode)) {
518  StaticVisitor::VisitRuntimeEntry(this);
519  }
520 }
521 
522 
523 // -----------------------------------------------------------------------------
524 // Implementation of Operand
525 
526 void Operand::set_modrm(int mod, Register rm_reg) {
527  DCHECK(is_uint2(mod));
528  buf_[0] = mod << 6 | rm_reg.low_bits();
529  // Set REX.B to the high bit of rm.code().
530  rex_ |= rm_reg.high_bit();
531 }
532 
533 
534 void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
535  DCHECK(len_ == 1);
536  DCHECK(is_uint2(scale));
537  // Use SIB with no index register only for base rsp or r12. Otherwise we
538  // would skip the SIB byte entirely.
539  DCHECK(!index.is(rsp) || base.is(rsp) || base.is(r12));
540  buf_[1] = (scale << 6) | (index.low_bits() << 3) | base.low_bits();
541  rex_ |= index.high_bit() << 1 | base.high_bit();
542  len_ = 2;
543 }
544 
545 void Operand::set_disp8(int disp) {
546  DCHECK(is_int8(disp));
547  DCHECK(len_ == 1 || len_ == 2);
548  int8_t* p = reinterpret_cast<int8_t*>(&buf_[len_]);
549  *p = disp;
550  len_ += sizeof(int8_t);
551 }
552 
553 void Operand::set_disp32(int disp) {
554  DCHECK(len_ == 1 || len_ == 2);
555  int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]);
556  *p = disp;
557  len_ += sizeof(int32_t);
558 }
559 
560 
561 } } // namespace v8::internal
562 
563 #endif // V8_X64_ASSEMBLER_X64_INL_H_
Isolate * isolate() const
Definition: assembler.h:62
static const int kSpecialTargetSize
Instruction * pc() const
Address runtime_entry_at(Address pc)
static Address target_address_at(Address pc, ConstantPoolArray *constant_pool)
static bool IsNop(Instr instr, int type=NON_MARKING_NOP)
void emit_optional_rex_32(Register reg, Register rm_reg)
static const int kPatchDebugBreakSlotReturnOffset
List< Handle< Code > > code_targets_
static Address break_address_from_return_address(Address pc)
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data=0)
void emit_code_target(Handle< Code > target, RelocInfo::Mode rmode, TypeFeedbackId ast_id=TypeFeedbackId::None())
void emit_rex_32(Register reg, Register rm_reg)
void emit_runtime_entry(Address entry, RelocInfo::Mode rmode)
static void set_target_address_at(Address pc, ConstantPoolArray *constant_pool, Address target, ICacheFlushMode icache_flush_mode=FLUSH_ICACHE_IF_NEEDED)
static Address target_address_from_return_address(Address pc)
Handle< Object > code_target_object_handle_at(Address pc)
static const int kMoveAddressIntoScratchRegisterInstructionLength
void emitp(void *x, RelocInfo::Mode rmode)
static const int kRealPatchReturnSequenceAddressOffset
static const int kCallTargetAddressOffset
static const int kPatchReturnSequenceAddressOffset
static const int kValueOffset
Definition: objects.h:9446
static Cell * FromValueAddress(Address value)
Definition: objects.h:9431
static Code * GetCodeFromTargetAddress(Address address)
Definition: objects-inl.h:5018
byte * instruction_start()
Definition: objects-inl.h:6176
static void FlushICache(void *start, size_t size)
Heap * GetHeap() const
Definition: objects-inl.h:1379
IncrementalMarking * incremental_marking()
Definition: heap.h:1205
CodeRange * code_range()
Definition: isolate.h:863
static uint32_t & uint32_at(Address addr)
Definition: v8memory.h:24
static Object *& Object_at(Address addr)
Definition: v8memory.h:60
static Address & Address_at(Address addr)
Definition: v8memory.h:56
static Handle< Object > & Object_Handle_at(Address addr)
Definition: v8memory.h:64
static uint16_t & uint16_at(Address addr)
Definition: v8memory.h:20
static uint64_t & uint64_at(Address addr)
Definition: v8memory.h:32
static uintptr_t & uintptr_at(Address addr)
Definition: v8memory.h:48
static int32_t & int32_at(Address addr)
Definition: v8memory.h:28
static bool IsDebugBreakSlot(Mode mode)
Definition: assembler.h:436
static bool IsJSReturn(Mode mode)
Definition: assembler.h:412
static bool IsEmbeddedObject(Mode mode)
Definition: assembler.h:402
static bool IsRuntimeEntry(Mode mode)
Definition: assembler.h:405
static bool IsCodeTarget(Mode mode)
Definition: assembler.h:399
static bool IsNone(Mode mode)
Definition: assembler.h:439
static bool IsExternalReference(Mode mode)
Definition: assembler.h:430
byte * pc() const
Definition: assembler.h:457
Code * host() const
Definition: assembler.h:463
Mode rmode() const
Definition: assembler.h:459
static bool IsInternalReference(Mode mode)
Definition: assembler.h:433
static bool IsCodeAgeSequence(Mode mode)
Definition: assembler.h:442
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
unsigned short uint16_t
Definition: unicode.cc:23
int int32_t
Definition: unicode.cc:24
const int kPointerSize
Definition: globals.h:129
@ UPDATE_WRITE_BARRIER
Definition: objects.h:235
kSerializedDataOffset Object
Definition: objects-inl.h:5322
const Register r12
const int kInt64Size
Definition: globals.h:126
const Register pc
byte * Address
Definition: globals.h:101
static const byte kCallOpcode
@ SKIP_ICACHE_FLUSH
Definition: assembler.h:293
static const int kNoCodeAgeSequenceLength
const Register rsp
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20