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::SupportsOptimizer() { return true; }
19 :
20 : bool CpuFeatures::SupportsWasmSimd128() { return IsSupported(SSE4_1); }
21 :
22 : // -----------------------------------------------------------------------------
23 : // Implementation of Assembler
24 :
25 :
26 : void Assembler::emitl(uint32_t x) {
27 48993215 : WriteUnalignedValue(reinterpret_cast<Address>(pc_), x);
28 63234782 : pc_ += sizeof(uint32_t);
29 : }
30 :
31 : void Assembler::emitq(uint64_t x) {
32 50466791 : WriteUnalignedValue(reinterpret_cast<Address>(pc_), x);
33 50466791 : pc_ += sizeof(uint64_t);
34 : }
35 :
36 : void Assembler::emitw(uint16_t x) {
37 374865 : WriteUnalignedValue(reinterpret_cast<Address>(pc_), x);
38 374865 : pc_ += sizeof(uint16_t);
39 : }
40 :
41 3335848 : void Assembler::emit_runtime_entry(Address entry, RelocInfo::Mode rmode) {
42 : DCHECK(RelocInfo::IsRuntimeEntry(rmode));
43 3335848 : RecordRelocInfo(rmode);
44 3335854 : emitl(static_cast<uint32_t>(entry - options().code_range_start));
45 3335854 : }
46 :
47 10651942 : void Assembler::emit(Immediate x) {
48 10651942 : if (!RelocInfo::IsNone(x.rmode_)) {
49 0 : RecordRelocInfo(x.rmode_);
50 : }
51 10651942 : emitl(x.value_);
52 10651942 : }
53 :
54 50466793 : void Assembler::emit(Immediate64 x) {
55 50466793 : if (!RelocInfo::IsNone(x.rmode_)) {
56 48704436 : RecordRelocInfo(x.rmode_);
57 : }
58 50466791 : emitq(static_cast<uint64_t>(x.value_));
59 50466791 : }
60 :
61 : void Assembler::emit_rex_64(Register reg, Register rm_reg) {
62 33818118 : emit(0x48 | reg.high_bit() << 2 | rm_reg.high_bit());
63 : }
64 :
65 : void Assembler::emit_rex_64(XMMRegister reg, Register rm_reg) {
66 873 : emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
67 : }
68 :
69 : void Assembler::emit_rex_64(Register reg, XMMRegister rm_reg) {
70 416 : emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
71 : }
72 :
73 : void Assembler::emit_rex_64(XMMRegister reg, XMMRegister rm_reg) {
74 17 : emit(0x48 | (reg.code() & 0x8) >> 1 | rm_reg.code() >> 3);
75 : }
76 :
77 : void Assembler::emit_rex_64(Register reg, Operand op) {
78 44088019 : emit(0x48 | reg.high_bit() << 2 | op.data().rex);
79 : }
80 :
81 : void Assembler::emit_rex_64(XMMRegister reg, Operand op) {
82 10758 : emit(0x48 | (reg.code() & 0x8) >> 1 | op.data().rex);
83 : }
84 :
85 :
86 : void Assembler::emit_rex_64(Register rm_reg) {
87 : DCHECK_EQ(rm_reg.code() & 0xf, rm_reg.code());
88 62692647 : emit(0x48 | rm_reg.high_bit());
89 : }
90 :
91 465248 : void Assembler::emit_rex_64(Operand op) { emit(0x48 | op.data().rex); }
92 :
93 : void Assembler::emit_rex_32(Register reg, Register rm_reg) {
94 215782 : emit(0x40 | reg.high_bit() << 2 | rm_reg.high_bit());
95 : }
96 :
97 : void Assembler::emit_rex_32(Register reg, Operand op) {
98 44525 : emit(0x40 | reg.high_bit() << 2 | op.data().rex);
99 : }
100 :
101 :
102 : void Assembler::emit_rex_32(Register rm_reg) {
103 518027 : emit(0x40 | rm_reg.high_bit());
104 : }
105 :
106 : void Assembler::emit_rex_32(Operand op) { emit(0x40 | op.data().rex); }
107 :
108 : void Assembler::emit_optional_rex_32(Register reg, Register rm_reg) {
109 10020880 : byte rex_bits = reg.high_bit() << 2 | rm_reg.high_bit();
110 5010440 : if (rex_bits != 0) emit(0x40 | rex_bits);
111 : }
112 :
113 : void Assembler::emit_optional_rex_32(Register reg, Operand op) {
114 6106191 : byte rex_bits = reg.high_bit() << 2 | op.data().rex;
115 7472457 : if (rex_bits != 0) emit(0x40 | rex_bits);
116 : }
117 :
118 : void Assembler::emit_optional_rex_32(XMMRegister reg, Operand op) {
119 42048 : byte rex_bits = (reg.code() & 0x8) >> 1 | op.data().rex;
120 42048 : if (rex_bits != 0) emit(0x40 | rex_bits);
121 : }
122 :
123 :
124 : void Assembler::emit_optional_rex_32(XMMRegister reg, XMMRegister base) {
125 28127 : byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
126 28127 : if (rex_bits != 0) emit(0x40 | rex_bits);
127 : }
128 :
129 :
130 : void Assembler::emit_optional_rex_32(XMMRegister reg, Register base) {
131 46989 : byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
132 46989 : if (rex_bits != 0) emit(0x40 | rex_bits);
133 : }
134 :
135 :
136 : void Assembler::emit_optional_rex_32(Register reg, XMMRegister base) {
137 548 : byte rex_bits = (reg.code() & 0x8) >> 1 | (base.code() & 0x8) >> 3;
138 548 : if (rex_bits != 0) emit(0x40 | rex_bits);
139 : }
140 :
141 :
142 : void Assembler::emit_optional_rex_32(Register rm_reg) {
143 77639310 : if (rm_reg.high_bit()) emit(0x41);
144 : }
145 :
146 : void Assembler::emit_optional_rex_32(XMMRegister rm_reg) {
147 3767 : if (rm_reg.high_bit()) emit(0x41);
148 : }
149 :
150 : void Assembler::emit_optional_rex_32(Operand op) {
151 4523240 : if (op.data().rex != 0) emit(0x40 | op.data().rex);
152 : }
153 :
154 :
155 : // byte 1 of 3-byte VEX
156 : void Assembler::emit_vex3_byte1(XMMRegister reg, XMMRegister rm,
157 : LeadingOpcode m) {
158 : byte rxb = static_cast<byte>(~((reg.high_bit() << 2) | rm.high_bit())) << 5;
159 592285 : emit(rxb | m);
160 : }
161 :
162 :
163 : // byte 1 of 3-byte VEX
164 : void Assembler::emit_vex3_byte1(XMMRegister reg, Operand rm, LeadingOpcode m) {
165 166131 : byte rxb = static_cast<byte>(~((reg.high_bit() << 2) | rm.data().rex)) << 5;
166 166131 : emit(rxb | m);
167 : }
168 :
169 :
170 : // byte 1 of 2-byte VEX
171 : void Assembler::emit_vex2_byte1(XMMRegister reg, XMMRegister v, VectorLength l,
172 : SIMDPrefix pp) {
173 5981093 : byte rv = static_cast<byte>(~((reg.high_bit() << 4) | v.code())) << 3;
174 5981093 : emit(rv | l | pp);
175 : }
176 :
177 :
178 : // byte 2 of 3-byte VEX
179 : void Assembler::emit_vex3_byte2(VexW w, XMMRegister v, VectorLength l,
180 : SIMDPrefix pp) {
181 758416 : emit(w | ((~v.code() & 0xf) << 3) | l | pp);
182 : }
183 :
184 :
185 2997250 : void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg,
186 : XMMRegister rm, VectorLength l, SIMDPrefix pp,
187 : LeadingOpcode mm, VexW w) {
188 2997250 : if (rm.high_bit() || mm != k0F || w != kW0) {
189 : emit_vex3_byte0();
190 : emit_vex3_byte1(reg, rm, mm);
191 : emit_vex3_byte2(w, vreg, l, pp);
192 : } else {
193 : emit_vex2_byte0();
194 : emit_vex2_byte1(reg, vreg, l, pp);
195 : }
196 2997250 : }
197 :
198 :
199 : void Assembler::emit_vex_prefix(Register reg, Register vreg, Register rm,
200 : VectorLength l, SIMDPrefix pp, LeadingOpcode mm,
201 : VexW w) {
202 0 : XMMRegister ireg = XMMRegister::from_code(reg.code());
203 0 : XMMRegister ivreg = XMMRegister::from_code(vreg.code());
204 0 : XMMRegister irm = XMMRegister::from_code(rm.code());
205 0 : emit_vex_prefix(ireg, ivreg, irm, l, pp, mm, w);
206 : }
207 :
208 3742259 : void Assembler::emit_vex_prefix(XMMRegister reg, XMMRegister vreg, Operand rm,
209 : VectorLength l, SIMDPrefix pp, LeadingOpcode mm,
210 : VexW w) {
211 3742259 : if (rm.data().rex || mm != k0F || w != kW0) {
212 : emit_vex3_byte0();
213 : emit_vex3_byte1(reg, rm, mm);
214 : emit_vex3_byte2(w, vreg, l, pp);
215 : } else {
216 : emit_vex2_byte0();
217 : emit_vex2_byte1(reg, vreg, l, pp);
218 : }
219 3742259 : }
220 :
221 : void Assembler::emit_vex_prefix(Register reg, Register vreg, Operand rm,
222 : VectorLength l, SIMDPrefix pp, LeadingOpcode mm,
223 : VexW w) {
224 0 : XMMRegister ireg = XMMRegister::from_code(reg.code());
225 0 : XMMRegister ivreg = XMMRegister::from_code(vreg.code());
226 0 : emit_vex_prefix(ireg, ivreg, rm, l, pp, mm, w);
227 : }
228 :
229 :
230 191547 : Address Assembler::target_address_at(Address pc, Address constant_pool) {
231 5219235 : return ReadUnalignedValue<int32_t>(pc) + pc + 4;
232 : }
233 :
234 5661168 : void Assembler::set_target_address_at(Address pc, Address constant_pool,
235 : Address target,
236 : ICacheFlushMode icache_flush_mode) {
237 5661168 : WriteUnalignedValue(pc, static_cast<int32_t>(target - pc - 4));
238 5661168 : if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
239 : FlushInstructionCache(pc, sizeof(int32_t));
240 : }
241 5661168 : }
242 :
243 : void Assembler::deserialization_set_target_internal_reference_at(
244 : Address pc, Address target, RelocInfo::Mode mode) {
245 : WriteUnalignedValue(pc, target);
246 : }
247 :
248 :
249 : Address Assembler::target_address_from_return_address(Address pc) {
250 0 : return pc - kCallTargetAddressOffset;
251 : }
252 :
253 : void Assembler::deserialization_set_special_target_at(
254 : Address instruction_payload, Code code, Address target) {
255 0 : set_target_address_at(instruction_payload,
256 : !code.is_null() ? code->constant_pool() : kNullAddress,
257 0 : target);
258 : }
259 :
260 : int Assembler::deserialization_special_target_size(
261 : Address instruction_payload) {
262 : return kSpecialTargetSize;
263 : }
264 :
265 : Handle<Code> Assembler::code_target_object_handle_at(Address pc) {
266 532301 : return GetCodeTarget(ReadUnalignedValue<int32_t>(pc));
267 : }
268 :
269 : Address Assembler::runtime_entry_at(Address pc) {
270 3332856 : return ReadUnalignedValue<int32_t>(pc) + options().code_range_start;
271 : }
272 :
273 : // -----------------------------------------------------------------------------
274 : // Implementation of RelocInfo
275 :
276 : // The modes possibly affected by apply must be in kApplyMask.
277 : void RelocInfo::apply(intptr_t delta) {
278 170259 : if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
279 39605 : WriteUnalignedValue(
280 39605 : pc_, ReadUnalignedValue<int32_t>(pc_) - static_cast<int32_t>(delta));
281 130654 : } else if (IsInternalReference(rmode_)) {
282 : // Absolute code pointer inside code object moves with the code object.
283 261308 : WriteUnalignedValue(pc_, ReadUnalignedValue<Address>(pc_) + delta);
284 : }
285 : }
286 :
287 :
288 : Address RelocInfo::target_address() {
289 : DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_));
290 1886177 : return Assembler::target_address_at(pc_, constant_pool_);
291 : }
292 :
293 : Address RelocInfo::target_address_address() {
294 : DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_) || IsWasmCall(rmode_) ||
295 : IsWasmStubCall(rmode_) || IsEmbeddedObject(rmode_) ||
296 : IsExternalReference(rmode_) || IsOffHeapTarget(rmode_));
297 94849796 : return pc_;
298 : }
299 :
300 :
301 : Address RelocInfo::constant_pool_entry_address() {
302 0 : UNREACHABLE();
303 : }
304 :
305 :
306 : int RelocInfo::target_address_size() {
307 398926 : if (IsCodedSpecially()) {
308 : return Assembler::kSpecialTargetSize;
309 : } else {
310 : return kSystemPointerSize;
311 : }
312 : }
313 :
314 : HeapObject RelocInfo::target_object() {
315 : DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
316 18527712 : return HeapObject::cast(Object(ReadUnalignedValue<Address>(pc_)));
317 : }
318 :
319 : Handle<HeapObject> RelocInfo::target_object_handle(Assembler* origin) {
320 : DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
321 6821376 : if (rmode_ == EMBEDDED_OBJECT) {
322 12578150 : return Handle<HeapObject>::cast(ReadUnalignedValue<Handle<Object>>(pc_));
323 : } else {
324 532301 : return origin->code_target_object_handle_at(pc_);
325 : }
326 : }
327 :
328 : Address RelocInfo::target_external_reference() {
329 : DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
330 114 : return ReadUnalignedValue<Address>(pc_);
331 : }
332 :
333 : void RelocInfo::set_target_external_reference(
334 : Address target, ICacheFlushMode icache_flush_mode) {
335 : DCHECK(rmode_ == RelocInfo::EXTERNAL_REFERENCE);
336 16 : WriteUnalignedValue(pc_, target);
337 : if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
338 : FlushInstructionCache(pc_, sizeof(Address));
339 : }
340 : }
341 :
342 : Address RelocInfo::target_internal_reference() {
343 : DCHECK(rmode_ == INTERNAL_REFERENCE);
344 96 : return ReadUnalignedValue<Address>(pc_);
345 : }
346 :
347 :
348 : Address RelocInfo::target_internal_reference_address() {
349 : DCHECK(rmode_ == INTERNAL_REFERENCE);
350 : return pc_;
351 : }
352 :
353 : void RelocInfo::set_target_object(Heap* heap, HeapObject target,
354 : WriteBarrierMode write_barrier_mode,
355 : ICacheFlushMode icache_flush_mode) {
356 : DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
357 6716710 : WriteUnalignedValue(pc_, target->ptr());
358 : if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
359 427636 : FlushInstructionCache(pc_, sizeof(Address));
360 : }
361 6712418 : if (write_barrier_mode == UPDATE_WRITE_BARRIER && !host().is_null()) {
362 6289083 : WriteBarrierForCode(host(), this, target);
363 : }
364 : }
365 :
366 : Address RelocInfo::target_runtime_entry(Assembler* origin) {
367 : DCHECK(IsRuntimeEntry(rmode_));
368 3332856 : return origin->runtime_entry_at(pc_);
369 : }
370 :
371 : void RelocInfo::set_target_runtime_entry(Address target,
372 : WriteBarrierMode write_barrier_mode,
373 : ICacheFlushMode icache_flush_mode) {
374 : DCHECK(IsRuntimeEntry(rmode_));
375 3332856 : if (target_address() != target) {
376 3332856 : set_target_address(target, write_barrier_mode, icache_flush_mode);
377 : }
378 : }
379 :
380 : Address RelocInfo::target_off_heap_target() {
381 : DCHECK(IsOffHeapTarget(rmode_));
382 396981 : return ReadUnalignedValue<Address>(pc_);
383 : }
384 :
385 : void RelocInfo::WipeOut() {
386 1196758 : if (IsEmbeddedObject(rmode_) || IsExternalReference(rmode_) ||
387 797734 : IsInternalReference(rmode_) || IsOffHeapTarget(rmode_)) {
388 397099 : WriteUnalignedValue(pc_, kNullAddress);
389 1827 : } else if (IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)) {
390 : // Effectively write zero into the relocation.
391 1827 : Assembler::set_target_address_at(pc_, constant_pool_,
392 3654 : pc_ + sizeof(int32_t));
393 : } else {
394 0 : UNREACHABLE();
395 : }
396 : }
397 :
398 : } // namespace internal
399 : } // namespace v8
400 :
401 : #endif // V8_X64_ASSEMBLER_X64_INL_H_
|