Line data Source code
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/objects-inl.h"
13 : #include "src/v8memory.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : bool CpuFeatures::SupportsCrankshaft() { return true; }
19 :
20 : bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(SSE4_1); }
21 :
22 : // -----------------------------------------------------------------------------
23 : // Implementation of Assembler
24 :
25 :
26 : static const byte kCallOpcode = 0xE8;
27 :
28 :
29 : void Assembler::emitl(uint32_t x) {
30 1243083785 : Memory::uint32_at(pc_) = x;
31 1243083785 : pc_ += sizeof(uint32_t);
32 : }
33 :
34 :
35 11546013 : void Assembler::emitp(void* x, RelocInfo::Mode rmode) {
36 11546013 : uintptr_t value = reinterpret_cast<uintptr_t>(x);
37 11546013 : Memory::uintptr_at(pc_) = value;
38 11546013 : if (!RelocInfo::IsNone(rmode)) {
39 8551797 : RecordRelocInfo(rmode, value);
40 : }
41 11546019 : pc_ += sizeof(uintptr_t);
42 11546019 : }
43 :
44 :
45 : void Assembler::emitq(uint64_t x) {
46 1104730 : Memory::uint64_at(pc_) = x;
47 1104730 : pc_ += sizeof(uint64_t);
48 : }
49 :
50 :
51 : void Assembler::emitw(uint16_t x) {
52 9466 : Memory::uint16_at(pc_) = x;
53 9466 : pc_ += sizeof(uint16_t);
54 : }
55 :
56 6032360 : void Assembler::emit_code_target(Handle<Code> target, RelocInfo::Mode rmode) {
57 : DCHECK(RelocInfo::IsCodeTarget(rmode));
58 6032360 : RecordRelocInfo(rmode);
59 12064888 : int current = static_cast<int>(code_targets_.size());
60 15535693 : if (current > 0 && !target.is_null() &&
61 : code_targets_.back().address() == target.address()) {
62 : // Optimization if we keep jumping to the same code target.
63 1169360 : emitl(current - 1);
64 : } else {
65 4863084 : code_targets_.push_back(target);
66 4863088 : emitl(current);
67 : }
68 6032448 : }
69 :
70 :
71 : void Assembler::emit_runtime_entry(Address entry, RelocInfo::Mode rmode) {
72 : DCHECK(RelocInfo::IsRuntimeEntry(rmode));
73 3087699 : RecordRelocInfo(rmode);
74 3087704 : emitl(static_cast<uint32_t>(entry - isolate_data().code_range_start_));
75 : }
76 :
77 4830838 : void Assembler::emit(Immediate x) {
78 4830838 : if (!RelocInfo::IsNone(x.rmode_)) {
79 3261 : RecordRelocInfo(x.rmode_);
80 : }
81 4830839 : emitl(x.value_);
82 4830839 : }
83 :
84 : void Assembler::emit_rex_64(Register reg, Register rm_reg) {
85 21457034 : emit(0x48 | reg.high_bit() << 2 | rm_reg.high_bit());
86 : }
87 :
88 :
89 : void Assembler::emit_rex_64(XMMRegister reg, Register rm_reg) {
90 856 : emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
91 : }
92 :
93 :
94 : void Assembler::emit_rex_64(Register reg, XMMRegister rm_reg) {
95 241 : emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
96 : }
97 :
98 :
99 : void Assembler::emit_rex_64(Register reg, const Operand& op) {
100 26528067 : emit(0x48 | reg.high_bit() << 2 | op.rex_);
101 : }
102 :
103 :
104 : void Assembler::emit_rex_64(XMMRegister reg, const Operand& op) {
105 516 : emit(0x48 | (reg.code() & 0x8) >> 1 | op.rex_);
106 : }
107 :
108 :
109 : void Assembler::emit_rex_64(Register rm_reg) {
110 : DCHECK_EQ(rm_reg.code() & 0xf, rm_reg.code());
111 19422243 : emit(0x48 | rm_reg.high_bit());
112 : }
113 :
114 :
115 : void Assembler::emit_rex_64(const Operand& op) {
116 133941 : emit(0x48 | op.rex_);
117 : }
118 :
119 :
120 : void Assembler::emit_rex_32(Register reg, Register rm_reg) {
121 35372 : emit(0x40 | reg.high_bit() << 2 | rm_reg.high_bit());
122 : }
123 :
124 :
125 : void Assembler::emit_rex_32(Register reg, const Operand& op) {
126 8744 : emit(0x40 | reg.high_bit() << 2 | op.rex_);
127 : }
128 :
129 :
130 : void Assembler::emit_rex_32(Register rm_reg) {
131 181606 : emit(0x40 | rm_reg.high_bit());
132 : }
133 :
134 :
135 : void Assembler::emit_rex_32(const Operand& op) {
136 : emit(0x40 | op.rex_);
137 : }
138 :
139 :
140 : void Assembler::emit_optional_rex_32(Register reg, Register rm_reg) {
141 5277432 : byte rex_bits = reg.high_bit() << 2 | rm_reg.high_bit();
142 2638716 : if (rex_bits != 0) emit(0x40 | rex_bits);
143 : }
144 :
145 :
146 : void Assembler::emit_optional_rex_32(Register reg, const Operand& op) {
147 5461392 : byte rex_bits = reg.high_bit() << 2 | op.rex_;
148 5461392 : if (rex_bits != 0) emit(0x40 | rex_bits);
149 : }
150 :
151 :
152 : void Assembler::emit_optional_rex_32(XMMRegister reg, const Operand& op) {
153 23548 : byte rex_bits = (reg.code() & 0x8) >> 1 | op.rex_;
154 23548 : if (rex_bits != 0) emit(0x40 | rex_bits);
155 : }
156 :
157 :
158 : void Assembler::emit_optional_rex_32(XMMRegister reg, XMMRegister base) {
159 9378 : byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
160 9378 : if (rex_bits != 0) emit(0x40 | rex_bits);
161 : }
162 :
163 :
164 : void Assembler::emit_optional_rex_32(XMMRegister reg, Register base) {
165 37720 : byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
166 37720 : if (rex_bits != 0) emit(0x40 | rex_bits);
167 : }
168 :
169 :
170 : void Assembler::emit_optional_rex_32(Register reg, XMMRegister base) {
171 240 : byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
172 240 : if (rex_bits != 0) emit(0x40 | rex_bits);
173 : }
174 :
175 :
176 : void Assembler::emit_optional_rex_32(Register rm_reg) {
177 25242341 : if (rm_reg.high_bit()) emit(0x41);
178 : }
179 :
180 : void Assembler::emit_optional_rex_32(XMMRegister rm_reg) {
181 268 : if (rm_reg.high_bit()) emit(0x41);
182 : }
183 :
184 : void Assembler::emit_optional_rex_32(const Operand& op) {
185 3916916 : if (op.rex_ != 0) emit(0x40 | op.rex_);
186 : }
187 :
188 :
189 : // byte 1 of 3-byte VEX
190 : void Assembler::emit_vex3_byte1(XMMRegister reg, XMMRegister rm,
191 : LeadingOpcode m) {
192 634465 : byte rxb = ~((reg.high_bit() << 2) | rm.high_bit()) << 5;
193 634465 : emit(rxb | m);
194 : }
195 :
196 :
197 : // byte 1 of 3-byte VEX
198 : void Assembler::emit_vex3_byte1(XMMRegister reg, const Operand& rm,
199 : LeadingOpcode m) {
200 24125 : byte rxb = ~((reg.high_bit() << 2) | rm.rex_) << 5;
201 24125 : emit(rxb | m);
202 : }
203 :
204 :
205 : // byte 1 of 2-byte VEX
206 : void Assembler::emit_vex2_byte1(XMMRegister reg, XMMRegister v, VectorLength l,
207 : SIMDPrefix pp) {
208 4302341 : byte rv = ~((reg.high_bit() << 4) | v.code()) << 3;
209 4302341 : emit(rv | l | pp);
210 : }
211 :
212 :
213 : // byte 2 of 3-byte VEX
214 : void Assembler::emit_vex3_byte2(VexW w, XMMRegister v, VectorLength l,
215 : SIMDPrefix pp) {
216 658590 : emit(w | ((~v.code() & 0xf) << 3) | l | pp);
217 : }
218 :
219 :
220 1981977 : void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg,
221 : XMMRegister rm, VectorLength l, SIMDPrefix pp,
222 : LeadingOpcode mm, VexW w) {
223 1981977 : if (rm.high_bit() || mm != k0F || w != kW0) {
224 : emit_vex3_byte0();
225 : emit_vex3_byte1(reg, rm, mm);
226 : emit_vex3_byte2(w, vreg, l, pp);
227 : } else {
228 : emit_vex2_byte0();
229 : emit_vex2_byte1(reg, vreg, l, pp);
230 : }
231 1981977 : }
232 :
233 :
234 : void Assembler::emit_vex_prefix(Register reg, Register vreg, Register rm,
235 : VectorLength l, SIMDPrefix pp, LeadingOpcode mm,
236 : VexW w) {
237 312 : XMMRegister ireg = XMMRegister::from_code(reg.code());
238 312 : XMMRegister ivreg = XMMRegister::from_code(vreg.code());
239 312 : XMMRegister irm = XMMRegister::from_code(rm.code());
240 312 : emit_vex_prefix(ireg, ivreg, irm, l, pp, mm, w);
241 : }
242 :
243 :
244 2978954 : void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg,
245 24125 : const Operand& rm, VectorLength l,
246 : SIMDPrefix pp, LeadingOpcode mm, VexW w) {
247 2978954 : if (rm.rex_ || mm != k0F || w != kW0) {
248 : emit_vex3_byte0();
249 : emit_vex3_byte1(reg, rm, mm);
250 : emit_vex3_byte2(w, vreg, l, pp);
251 : } else {
252 : emit_vex2_byte0();
253 : emit_vex2_byte1(reg, vreg, l, pp);
254 : }
255 2978954 : }
256 :
257 :
258 : void Assembler::emit_vex_prefix(Register reg, Register vreg, const Operand& rm,
259 : VectorLength l, SIMDPrefix pp, LeadingOpcode mm,
260 : VexW w) {
261 312 : XMMRegister ireg = XMMRegister::from_code(reg.code());
262 312 : XMMRegister ivreg = XMMRegister::from_code(vreg.code());
263 312 : emit_vex_prefix(ireg, ivreg, rm, l, pp, mm, w);
264 : }
265 :
266 :
267 : Address Assembler::target_address_at(Address pc, Address constant_pool) {
268 207424870 : return Memory::int32_at(pc) + pc + 4;
269 : }
270 :
271 :
272 : void Assembler::set_target_address_at(Isolate* isolate, Address pc,
273 : Address constant_pool, Address target,
274 : ICacheFlushMode icache_flush_mode) {
275 : DCHECK_IMPLIES(isolate == nullptr, icache_flush_mode == SKIP_ICACHE_FLUSH);
276 192412557 : Memory::int32_at(pc) = static_cast<int32_t>(target - pc - 4);
277 9617953 : if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
278 182799923 : Assembler::FlushICache(isolate, pc, sizeof(int32_t));
279 : }
280 : }
281 :
282 207424870 : Address Assembler::target_address_at(Address pc, Code* code) {
283 : Address constant_pool = code ? code->constant_pool() : nullptr;
284 207424870 : return target_address_at(pc, constant_pool);
285 : }
286 :
287 5319 : void Assembler::set_target_address_at(Isolate* isolate, Address pc, Code* code,
288 : Address target,
289 : ICacheFlushMode icache_flush_mode) {
290 : Address constant_pool = code ? code->constant_pool() : nullptr;
291 : set_target_address_at(isolate, pc, constant_pool, target, icache_flush_mode);
292 5319 : }
293 :
294 : void Assembler::deserialization_set_target_internal_reference_at(
295 : Isolate* isolate, Address pc, Address target, RelocInfo::Mode mode) {
296 35924336 : Memory::Address_at(pc) = target;
297 : }
298 :
299 :
300 : Address Assembler::target_address_from_return_address(Address pc) {
301 : return pc - kCallTargetAddressOffset;
302 : }
303 :
304 : void Assembler::deserialization_set_special_target_at(
305 : Isolate* isolate, Address instruction_payload, Code* code, Address target) {
306 : set_target_address_at(isolate, instruction_payload, code, target);
307 : }
308 :
309 6025821 : Handle<Code> Assembler::code_target_object_handle_at(Address pc) {
310 12051642 : return code_targets_[Memory::int32_at(pc)];
311 : }
312 :
313 3077632 : Address Assembler::runtime_entry_at(Address pc) {
314 3077632 : return Memory::int32_at(pc) + isolate_data().code_range_start_;
315 : }
316 :
317 : // -----------------------------------------------------------------------------
318 : // Implementation of RelocInfo
319 :
320 : // The modes possibly affected by apply must be in kApplyMask.
321 : void RelocInfo::apply(intptr_t delta) {
322 500415 : if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
323 173830 : Memory::int32_at(pc_) -= static_cast<int32_t>(delta);
324 326585 : } else if (IsInternalReference(rmode_)) {
325 : // absolute code pointer inside code object moves with the code object.
326 326585 : Memory::Address_at(pc_) += delta;
327 : }
328 : }
329 :
330 :
331 : Address RelocInfo::target_address() {
332 : DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
333 207424855 : return Assembler::target_address_at(pc_, host_);
334 : }
335 :
336 : Address RelocInfo::target_address_address() {
337 : DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
338 : || rmode_ == EMBEDDED_OBJECT
339 : || rmode_ == EXTERNAL_REFERENCE);
340 : return reinterpret_cast<Address>(pc_);
341 : }
342 :
343 :
344 : Address RelocInfo::constant_pool_entry_address() {
345 0 : UNREACHABLE();
346 : }
347 :
348 :
349 : int RelocInfo::target_address_size() {
350 1719180 : if (IsCodedSpecially()) {
351 : return Assembler::kSpecialTargetSize;
352 : } else {
353 : return kPointerSize;
354 : }
355 : }
356 :
357 : HeapObject* RelocInfo::target_object() {
358 : DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
359 13038687 : return HeapObject::cast(Memory::Object_at(pc_));
360 : }
361 :
362 : Handle<HeapObject> RelocInfo::target_object_handle(Assembler* origin) {
363 : DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
364 11015353 : if (rmode_ == EMBEDDED_OBJECT) {
365 4989532 : return Handle<HeapObject>::cast(Memory::Object_Handle_at(pc_));
366 : } else {
367 6025821 : return origin->code_target_object_handle_at(pc_);
368 : }
369 : }
370 :
371 :
372 : Address RelocInfo::target_external_reference() {
373 : DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
374 817925 : return Memory::Address_at(pc_);
375 : }
376 :
377 :
378 : Address RelocInfo::target_internal_reference() {
379 : DCHECK(rmode_ == INTERNAL_REFERENCE);
380 172753 : return Memory::Address_at(pc_);
381 : }
382 :
383 :
384 : Address RelocInfo::target_internal_reference_address() {
385 : DCHECK(rmode_ == INTERNAL_REFERENCE);
386 : return reinterpret_cast<Address>(pc_);
387 : }
388 :
389 : void RelocInfo::set_target_object(HeapObject* target,
390 : WriteBarrierMode write_barrier_mode,
391 10164206 : ICacheFlushMode icache_flush_mode) {
392 : DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
393 8349923 : Memory::Object_at(pc_) = target;
394 : if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
395 3359351 : Assembler::FlushICache(target->GetIsolate(), pc_, sizeof(Address));
396 : }
397 5173093 : if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != nullptr) {
398 : host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(host(), this,
399 4991113 : target);
400 4991113 : host()->GetHeap()->RecordWriteIntoCode(host(), this, target);
401 : }
402 : }
403 :
404 :
405 : Address RelocInfo::target_runtime_entry(Assembler* origin) {
406 : DCHECK(IsRuntimeEntry(rmode_));
407 3077632 : return origin->runtime_entry_at(pc_);
408 : }
409 :
410 : void RelocInfo::set_target_runtime_entry(Isolate* isolate, Address target,
411 : WriteBarrierMode write_barrier_mode,
412 : ICacheFlushMode icache_flush_mode) {
413 : DCHECK(IsRuntimeEntry(rmode_));
414 3077632 : if (target_address() != target) {
415 3077632 : set_target_address(isolate, target, write_barrier_mode, icache_flush_mode);
416 : }
417 : }
418 :
419 : void RelocInfo::WipeOut(Isolate* isolate) {
420 18140 : if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
421 6392 : IsInternalReference(rmode_)) {
422 6429 : Memory::Address_at(pc_) = nullptr;
423 5319 : } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
424 : // Effectively write zero into the relocation.
425 : Assembler::set_target_address_at(isolate, pc_, host_,
426 5319 : pc_ + sizeof(int32_t));
427 : } else {
428 0 : UNREACHABLE();
429 : }
430 : }
431 :
432 : template <typename ObjectVisitor>
433 880550615 : void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
434 : RelocInfo::Mode mode = rmode();
435 440277063 : if (mode == RelocInfo::EMBEDDED_OBJECT) {
436 716326 : visitor->VisitEmbeddedPointer(host(), this);
437 8260229 : Assembler::FlushICache(isolate, pc_, sizeof(Address));
438 432016834 : } else if (RelocInfo::IsCodeTarget(mode)) {
439 13310220 : visitor->VisitCodeTarget(host(), this);
440 229409952 : } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
441 375407730 : visitor->VisitExternalReference(host(), this);
442 41706087 : } else if (mode == RelocInfo::INTERNAL_REFERENCE) {
443 78044544 : visitor->VisitInternalReference(host(), this);
444 2683815 : } else if (RelocInfo::IsRuntimeEntry(mode)) {
445 5367630 : visitor->VisitRuntimeEntry(host(), this);
446 : }
447 440277137 : }
448 :
449 : // -----------------------------------------------------------------------------
450 : // Implementation of Operand
451 :
452 : void Operand::set_modrm(int mod, Register rm_reg) {
453 : DCHECK(is_uint2(mod));
454 38714461 : buf_[0] = mod << 6 | rm_reg.low_bits();
455 : // Set REX.B to the high bit of rm.code().
456 38200323 : rex_ |= rm_reg.high_bit();
457 : }
458 :
459 :
460 : void Operand::set_sib(ScaleFactor scale, Register index, Register base) {
461 : DCHECK_EQ(len_, 1);
462 : DCHECK(is_uint2(scale));
463 : // Use SIB with no index register only for base rsp or r12. Otherwise we
464 : // would skip the SIB byte entirely.
465 : DCHECK(index != rsp || base == rsp || base == r12);
466 10119355 : buf_[1] = (scale << 6) | (index.low_bits() << 3) | base.low_bits();
467 7960532 : rex_ |= index.high_bit() << 1 | base.high_bit();
468 5864685 : len_ = 2;
469 : }
470 :
471 : void Operand::set_disp8(int disp) {
472 : DCHECK(is_int8(disp));
473 : DCHECK(len_ == 1 || len_ == 2);
474 26296494 : int8_t* p = reinterpret_cast<int8_t*>(&buf_[len_]);
475 26296494 : *p = disp;
476 26296494 : len_ += sizeof(int8_t);
477 : }
478 :
479 : void Operand::set_disp32(int disp) {
480 : DCHECK(len_ == 1 || len_ == 2);
481 6842800 : int32_t* p = reinterpret_cast<int32_t*>(&buf_[len_]);
482 6842800 : *p = disp;
483 6842800 : len_ += sizeof(int32_t);
484 : }
485 :
486 : void Operand::set_disp64(int64_t disp) {
487 : DCHECK_EQ(1, len_);
488 451162 : int64_t* p = reinterpret_cast<int64_t*>(&buf_[len_]);
489 451162 : *p = disp;
490 451162 : len_ += sizeof(disp);
491 : }
492 : } // namespace internal
493 : } // namespace v8
494 :
495 : #endif // V8_X64_ASSEMBLER_X64_INL_H_
|