Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef jit_x64_MacroAssembler_x64_h
8 : #define jit_x64_MacroAssembler_x64_h
9 :
10 : #include "jit/JitFrames.h"
11 : #include "jit/MoveResolver.h"
12 : #include "jit/x86-shared/MacroAssembler-x86-shared.h"
13 :
14 : namespace js {
15 : namespace jit {
16 :
17 : struct ImmShiftedTag : public ImmWord
18 : {
19 394 : explicit ImmShiftedTag(JSValueShiftedTag shtag)
20 394 : : ImmWord((uintptr_t)shtag)
21 394 : { }
22 :
23 898 : explicit ImmShiftedTag(JSValueType type)
24 898 : : ImmWord(uintptr_t(JSValueShiftedTag(JSVAL_TYPE_TO_SHIFTED_TAG(type))))
25 898 : { }
26 : };
27 :
28 : struct ImmTag : public Imm32
29 : {
30 5121 : explicit ImmTag(JSValueTag tag)
31 5121 : : Imm32(tag)
32 5121 : { }
33 : };
34 :
35 4503 : class MacroAssemblerX64 : public MacroAssemblerX86Shared
36 : {
37 : private:
38 : // Perform a downcast. Should be removed by Bug 996602.
39 : MacroAssembler& asMasm();
40 : const MacroAssembler& asMasm() const;
41 :
42 : void bindOffsets(const MacroAssemblerX86Shared::UsesVector&);
43 :
44 : public:
45 : using MacroAssemblerX86Shared::load32;
46 : using MacroAssemblerX86Shared::store32;
47 : using MacroAssemblerX86Shared::store16;
48 :
49 4503 : MacroAssemblerX64()
50 4503 : {
51 4503 : }
52 :
53 : // The buffer is about to be linked, make sure any constant pools or excess
54 : // bookkeeping has been flushed to the instruction stream.
55 : void finish();
56 :
57 : /////////////////////////////////////////////////////////////////
58 : // X64 helpers.
59 : /////////////////////////////////////////////////////////////////
60 4790 : void writeDataRelocation(const Value& val) {
61 4790 : if (val.isGCThing()) {
62 1415 : gc::Cell* cell = val.toGCThing();
63 1415 : if (cell && gc::IsInsideNursery(cell))
64 0 : embedsNurseryPointers_ = true;
65 1415 : dataRelocations_.writeUnsigned(masm.currentOffset());
66 : }
67 4790 : }
68 :
69 : // Refers to the upper 32 bits of a 64-bit Value operand.
70 : // On x86_64, the upper 32 bits do not necessarily only contain the type.
71 9 : Operand ToUpper32(Operand base) {
72 9 : switch (base.kind()) {
73 : case Operand::MEM_REG_DISP:
74 9 : return Operand(Register::FromCode(base.base()), base.disp() + 4);
75 :
76 : case Operand::MEM_SCALE:
77 0 : return Operand(Register::FromCode(base.base()), Register::FromCode(base.index()),
78 0 : base.scale(), base.disp() + 4);
79 :
80 : default:
81 0 : MOZ_CRASH("unexpected operand kind");
82 : }
83 : }
84 36 : static inline Operand ToUpper32(const Address& address) {
85 36 : return Operand(address.base, address.offset + 4);
86 : }
87 : static inline Operand ToUpper32(const BaseIndex& address) {
88 : return Operand(address.base, address.index, address.scale, address.offset + 4);
89 : }
90 :
91 45 : uint32_t Upper32Of(JSValueShiftedTag tag) {
92 : union { // Implemented in this way to appease MSVC++.
93 : uint64_t tag;
94 : struct {
95 : uint32_t lo32;
96 : uint32_t hi32;
97 : } s;
98 : } e;
99 45 : e.tag = tag;
100 45 : return e.s.hi32;
101 : }
102 :
103 45 : JSValueShiftedTag GetShiftedTag(JSValueType type) {
104 45 : return (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type);
105 : }
106 :
107 : /////////////////////////////////////////////////////////////////
108 : // X86/X64-common interface.
109 : /////////////////////////////////////////////////////////////////
110 0 : Address ToPayload(Address value) {
111 0 : return value;
112 : }
113 :
114 3414 : void storeValue(ValueOperand val, Operand dest) {
115 3414 : movq(val.valueReg(), dest);
116 3414 : }
117 3352 : void storeValue(ValueOperand val, const Address& dest) {
118 3352 : storeValue(val, Operand(dest));
119 3352 : }
120 : template <typename T>
121 68 : void storeValue(JSValueType type, Register reg, const T& dest) {
122 : // Value types with 32-bit payloads can be emitted as two 32-bit moves.
123 68 : if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
124 9 : movl(reg, Operand(dest));
125 9 : movl(Imm32(Upper32Of(GetShiftedTag(type))), ToUpper32(Operand(dest)));
126 : } else {
127 118 : ScratchRegisterScope scratch(asMasm());
128 59 : boxValue(type, reg, scratch);
129 59 : movq(scratch, Operand(dest));
130 : }
131 68 : }
132 : template <typename T>
133 1087 : void storeValue(const Value& val, const T& dest) {
134 2174 : ScratchRegisterScope scratch(asMasm());
135 1087 : if (val.isGCThing()) {
136 31 : movWithPatch(ImmWord(val.asRawBits()), scratch);
137 31 : writeDataRelocation(val);
138 : } else {
139 1056 : mov(ImmWord(val.asRawBits()), scratch);
140 : }
141 1087 : movq(scratch, Operand(dest));
142 1087 : }
143 54 : void storeValue(ValueOperand val, BaseIndex dest) {
144 54 : storeValue(val, Operand(dest));
145 54 : }
146 0 : void storeValue(const Address& src, const Address& dest, Register temp) {
147 0 : loadPtr(src, temp);
148 0 : storePtr(temp, dest);
149 0 : }
150 11884 : void loadValue(Operand src, ValueOperand val) {
151 11884 : movq(src, val.valueReg());
152 11884 : }
153 11613 : void loadValue(Address src, ValueOperand val) {
154 11613 : loadValue(Operand(src), val);
155 11613 : }
156 271 : void loadValue(const BaseIndex& src, ValueOperand val) {
157 271 : loadValue(Operand(src), val);
158 271 : }
159 898 : void tagValue(JSValueType type, Register payload, ValueOperand dest) {
160 1796 : ScratchRegisterScope scratch(asMasm());
161 898 : MOZ_ASSERT(dest.valueReg() != scratch);
162 898 : if (payload != dest.valueReg())
163 443 : movq(payload, dest.valueReg());
164 898 : mov(ImmShiftedTag(type), scratch);
165 898 : orq(scratch, dest.valueReg());
166 898 : }
167 16961 : void pushValue(ValueOperand val) {
168 16961 : push(val.valueReg());
169 16961 : }
170 5441 : void popValue(ValueOperand val) {
171 5441 : pop(val.valueReg());
172 5441 : }
173 4332 : void pushValue(const Value& val) {
174 4332 : if (val.isGCThing()) {
175 1424 : ScratchRegisterScope scratch(asMasm());
176 712 : movWithPatch(ImmWord(val.asRawBits()), scratch);
177 712 : writeDataRelocation(val);
178 712 : push(scratch);
179 : } else {
180 3620 : push(ImmWord(val.asRawBits()));
181 : }
182 4332 : }
183 99 : void pushValue(JSValueType type, Register reg) {
184 198 : ScratchRegisterScope scratch(asMasm());
185 99 : boxValue(type, reg, scratch);
186 99 : push(scratch);
187 99 : }
188 3625 : void pushValue(const Address& addr) {
189 3625 : push(Operand(addr));
190 3625 : }
191 :
192 4047 : void moveValue(const Value& val, Register dest) {
193 4047 : movWithPatch(ImmWord(val.asRawBits()), dest);
194 4047 : writeDataRelocation(val);
195 4047 : }
196 3870 : void moveValue(const Value& src, const ValueOperand& dest) {
197 3870 : moveValue(src, dest.valueReg());
198 3870 : }
199 12941 : void moveValue(const ValueOperand& src, const ValueOperand& dest) {
200 12941 : if (src.valueReg() != dest.valueReg())
201 4872 : movq(src.valueReg(), dest.valueReg());
202 12941 : }
203 : void boxValue(JSValueType type, Register src, Register dest);
204 :
205 444 : Condition testUndefined(Condition cond, Register tag) {
206 444 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
207 444 : cmp32(tag, ImmTag(JSVAL_TAG_UNDEFINED));
208 444 : return cond;
209 : }
210 606 : Condition testInt32(Condition cond, Register tag) {
211 606 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
212 606 : cmp32(tag, ImmTag(JSVAL_TAG_INT32));
213 606 : return cond;
214 : }
215 1679 : Condition testBoolean(Condition cond, Register tag) {
216 1679 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
217 1679 : cmp32(tag, ImmTag(JSVAL_TAG_BOOLEAN));
218 1679 : return cond;
219 : }
220 246 : Condition testNull(Condition cond, Register tag) {
221 246 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
222 246 : cmp32(tag, ImmTag(JSVAL_TAG_NULL));
223 246 : return cond;
224 : }
225 358 : Condition testString(Condition cond, Register tag) {
226 358 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
227 358 : cmp32(tag, ImmTag(JSVAL_TAG_STRING));
228 358 : return cond;
229 : }
230 21 : Condition testSymbol(Condition cond, Register tag) {
231 21 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
232 21 : cmp32(tag, ImmTag(JSVAL_TAG_SYMBOL));
233 21 : return cond;
234 : }
235 1702 : Condition testObject(Condition cond, Register tag) {
236 1702 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
237 1702 : cmp32(tag, ImmTag(JSVAL_TAG_OBJECT));
238 1702 : return cond;
239 : }
240 51 : Condition testDouble(Condition cond, Register tag) {
241 51 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
242 51 : cmp32(tag, Imm32(JSVAL_TAG_MAX_DOUBLE));
243 51 : return cond == Equal ? BelowOrEqual : Above;
244 : }
245 174 : Condition testNumber(Condition cond, Register tag) {
246 174 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
247 174 : cmp32(tag, Imm32(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET));
248 174 : return cond == Equal ? BelowOrEqual : Above;
249 : }
250 207 : Condition testGCThing(Condition cond, Register tag) {
251 207 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
252 207 : cmp32(tag, Imm32(JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET));
253 207 : return cond == Equal ? AboveOrEqual : Below;
254 : }
255 :
256 61 : Condition testMagic(Condition cond, Register tag) {
257 61 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
258 61 : cmp32(tag, ImmTag(JSVAL_TAG_MAGIC));
259 61 : return cond;
260 : }
261 : Condition testError(Condition cond, Register tag) {
262 : return testMagic(cond, tag);
263 : }
264 4 : Condition testPrimitive(Condition cond, Register tag) {
265 4 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
266 4 : cmp32(tag, ImmTag(JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET));
267 4 : return cond == Equal ? Below : AboveOrEqual;
268 : }
269 :
270 339 : Condition testUndefined(Condition cond, const ValueOperand& src) {
271 678 : ScratchRegisterScope scratch(asMasm());
272 339 : splitTag(src, scratch);
273 678 : return testUndefined(cond, scratch);
274 : }
275 572 : Condition testInt32(Condition cond, const ValueOperand& src) {
276 1144 : ScratchRegisterScope scratch(asMasm());
277 572 : splitTag(src, scratch);
278 1144 : return testInt32(cond, scratch);
279 : }
280 1627 : Condition testBoolean(Condition cond, const ValueOperand& src) {
281 3254 : ScratchRegisterScope scratch(asMasm());
282 1627 : splitTag(src, scratch);
283 3254 : return testBoolean(cond, scratch);
284 : }
285 27 : Condition testDouble(Condition cond, const ValueOperand& src) {
286 54 : ScratchRegisterScope scratch(asMasm());
287 27 : splitTag(src, scratch);
288 54 : return testDouble(cond, scratch);
289 : }
290 173 : Condition testNumber(Condition cond, const ValueOperand& src) {
291 346 : ScratchRegisterScope scratch(asMasm());
292 173 : splitTag(src, scratch);
293 346 : return testNumber(cond, scratch);
294 : }
295 243 : Condition testNull(Condition cond, const ValueOperand& src) {
296 486 : ScratchRegisterScope scratch(asMasm());
297 243 : splitTag(src, scratch);
298 486 : return testNull(cond, scratch);
299 : }
300 333 : Condition testString(Condition cond, const ValueOperand& src) {
301 666 : ScratchRegisterScope scratch(asMasm());
302 333 : splitTag(src, scratch);
303 666 : return testString(cond, scratch);
304 : }
305 21 : Condition testSymbol(Condition cond, const ValueOperand& src) {
306 42 : ScratchRegisterScope scratch(asMasm());
307 21 : splitTag(src, scratch);
308 42 : return testSymbol(cond, scratch);
309 : }
310 1638 : Condition testObject(Condition cond, const ValueOperand& src) {
311 3276 : ScratchRegisterScope scratch(asMasm());
312 1638 : splitTag(src, scratch);
313 3276 : return testObject(cond, scratch);
314 : }
315 : Condition testGCThing(Condition cond, const ValueOperand& src) {
316 : ScratchRegisterScope scratch(asMasm());
317 : splitTag(src, scratch);
318 : return testGCThing(cond, scratch);
319 : }
320 4 : Condition testPrimitive(Condition cond, const ValueOperand& src) {
321 8 : ScratchRegisterScope scratch(asMasm());
322 4 : splitTag(src, scratch);
323 8 : return testPrimitive(cond, scratch);
324 : }
325 :
326 :
327 0 : Condition testUndefined(Condition cond, const Address& src) {
328 0 : cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_UNDEFINED))));
329 0 : return cond;
330 : }
331 32 : Condition testInt32(Condition cond, const Address& src) {
332 32 : cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_INT32))));
333 32 : return cond;
334 : }
335 0 : Condition testBoolean(Condition cond, const Address& src) {
336 0 : cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_BOOLEAN))));
337 0 : return cond;
338 : }
339 0 : Condition testDouble(Condition cond, const Address& src) {
340 0 : ScratchRegisterScope scratch(asMasm());
341 0 : splitTag(src, scratch);
342 0 : return testDouble(cond, scratch);
343 : }
344 : Condition testNumber(Condition cond, const Address& src) {
345 : ScratchRegisterScope scratch(asMasm());
346 : splitTag(src, scratch);
347 : return testNumber(cond, scratch);
348 : }
349 4 : Condition testNull(Condition cond, const Address& src) {
350 4 : cmp32(ToUpper32(src), Imm32(Upper32Of(GetShiftedTag(JSVAL_TYPE_NULL))));
351 4 : return cond;
352 : }
353 : Condition testString(Condition cond, const Address& src) {
354 : ScratchRegisterScope scratch(asMasm());
355 : splitTag(src, scratch);
356 : return testString(cond, scratch);
357 : }
358 : Condition testSymbol(Condition cond, const Address& src) {
359 : ScratchRegisterScope scratch(asMasm());
360 : splitTag(src, scratch);
361 : return testSymbol(cond, scratch);
362 : }
363 24 : Condition testObject(Condition cond, const Address& src) {
364 48 : ScratchRegisterScope scratch(asMasm());
365 24 : splitTag(src, scratch);
366 48 : return testObject(cond, scratch);
367 : }
368 : Condition testPrimitive(Condition cond, const Address& src) {
369 : ScratchRegisterScope scratch(asMasm());
370 : splitTag(src, scratch);
371 : return testPrimitive(cond, scratch);
372 : }
373 190 : Condition testGCThing(Condition cond, const Address& src) {
374 380 : ScratchRegisterScope scratch(asMasm());
375 190 : splitTag(src, scratch);
376 380 : return testGCThing(cond, scratch);
377 : }
378 28 : Condition testMagic(Condition cond, const Address& src) {
379 56 : ScratchRegisterScope scratch(asMasm());
380 28 : splitTag(src, scratch);
381 56 : return testMagic(cond, scratch);
382 : }
383 :
384 :
385 : Condition testUndefined(Condition cond, const BaseIndex& src) {
386 : ScratchRegisterScope scratch(asMasm());
387 : splitTag(src, scratch);
388 : return testUndefined(cond, scratch);
389 : }
390 : Condition testNull(Condition cond, const BaseIndex& src) {
391 : ScratchRegisterScope scratch(asMasm());
392 : splitTag(src, scratch);
393 : return testNull(cond, scratch);
394 : }
395 : Condition testBoolean(Condition cond, const BaseIndex& src) {
396 : ScratchRegisterScope scratch(asMasm());
397 : splitTag(src, scratch);
398 : return testBoolean(cond, scratch);
399 : }
400 : Condition testString(Condition cond, const BaseIndex& src) {
401 : ScratchRegisterScope scratch(asMasm());
402 : splitTag(src, scratch);
403 : return testString(cond, scratch);
404 : }
405 : Condition testSymbol(Condition cond, const BaseIndex& src) {
406 : ScratchRegisterScope scratch(asMasm());
407 : splitTag(src, scratch);
408 : return testSymbol(cond, scratch);
409 : }
410 0 : Condition testInt32(Condition cond, const BaseIndex& src) {
411 0 : ScratchRegisterScope scratch(asMasm());
412 0 : splitTag(src, scratch);
413 0 : return testInt32(cond, scratch);
414 : }
415 2 : Condition testObject(Condition cond, const BaseIndex& src) {
416 4 : ScratchRegisterScope scratch(asMasm());
417 2 : splitTag(src, scratch);
418 4 : return testObject(cond, scratch);
419 : }
420 : Condition testDouble(Condition cond, const BaseIndex& src) {
421 : ScratchRegisterScope scratch(asMasm());
422 : splitTag(src, scratch);
423 : return testDouble(cond, scratch);
424 : }
425 21 : Condition testMagic(Condition cond, const BaseIndex& src) {
426 42 : ScratchRegisterScope scratch(asMasm());
427 21 : splitTag(src, scratch);
428 42 : return testMagic(cond, scratch);
429 : }
430 17 : Condition testGCThing(Condition cond, const BaseIndex& src) {
431 34 : ScratchRegisterScope scratch(asMasm());
432 17 : splitTag(src, scratch);
433 34 : return testGCThing(cond, scratch);
434 : }
435 :
436 : Condition isMagic(Condition cond, const ValueOperand& src, JSWhyMagic why) {
437 : uint64_t magic = MagicValue(why).asRawBits();
438 : cmpPtr(src.valueReg(), ImmWord(magic));
439 : return cond;
440 : }
441 :
442 0 : void cmpPtr(Register lhs, const ImmWord rhs) {
443 0 : ScratchRegisterScope scratch(asMasm());
444 0 : MOZ_ASSERT(lhs != scratch);
445 0 : if (intptr_t(rhs.value) <= INT32_MAX && intptr_t(rhs.value) >= INT32_MIN) {
446 0 : cmpPtr(lhs, Imm32(int32_t(rhs.value)));
447 : } else {
448 0 : movePtr(rhs, scratch);
449 0 : cmpPtr(lhs, scratch);
450 : }
451 0 : }
452 0 : void cmpPtr(Register lhs, const ImmPtr rhs) {
453 0 : cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
454 0 : }
455 : void cmpPtr(Register lhs, const ImmGCPtr rhs) {
456 : ScratchRegisterScope scratch(asMasm());
457 : MOZ_ASSERT(lhs != scratch);
458 : movePtr(rhs, scratch);
459 : cmpPtr(lhs, scratch);
460 : }
461 0 : void cmpPtr(Register lhs, const Imm32 rhs) {
462 0 : cmpq(rhs, lhs);
463 0 : }
464 134 : void cmpPtr(const Operand& lhs, const ImmGCPtr rhs) {
465 268 : ScratchRegisterScope scratch(asMasm());
466 134 : MOZ_ASSERT(!lhs.containsReg(scratch));
467 134 : movePtr(rhs, scratch);
468 134 : cmpPtr(lhs, scratch);
469 134 : }
470 1503 : void cmpPtr(const Operand& lhs, const ImmWord rhs) {
471 1503 : if ((intptr_t)rhs.value <= INT32_MAX && (intptr_t)rhs.value >= INT32_MIN) {
472 1419 : cmpPtr(lhs, Imm32((int32_t)rhs.value));
473 : } else {
474 168 : ScratchRegisterScope scratch(asMasm());
475 84 : movePtr(rhs, scratch);
476 84 : cmpPtr(lhs, scratch);
477 : }
478 1503 : }
479 1015 : void cmpPtr(const Operand& lhs, const ImmPtr rhs) {
480 1015 : cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
481 1015 : }
482 : void cmpPtr(const Address& lhs, const ImmGCPtr rhs) {
483 : cmpPtr(Operand(lhs), rhs);
484 : }
485 0 : void cmpPtr(const Address& lhs, const ImmWord rhs) {
486 0 : cmpPtr(Operand(lhs), rhs);
487 0 : }
488 0 : void cmpPtr(const Address& lhs, const ImmPtr rhs) {
489 0 : cmpPtr(lhs, ImmWord(uintptr_t(rhs.value)));
490 0 : }
491 1946 : void cmpPtr(const Operand& lhs, Register rhs) {
492 1946 : cmpq(rhs, lhs);
493 1946 : }
494 0 : void cmpPtr(Register lhs, const Operand& rhs) {
495 0 : cmpq(rhs, lhs);
496 0 : }
497 2748 : void cmpPtr(const Operand& lhs, const Imm32 rhs) {
498 2748 : cmpq(rhs, lhs);
499 2748 : }
500 : void cmpPtr(const Address& lhs, Register rhs) {
501 : cmpPtr(Operand(lhs), rhs);
502 : }
503 413 : void cmpPtr(Register lhs, Register rhs) {
504 413 : cmpq(rhs, lhs);
505 413 : }
506 357 : void testPtr(Register lhs, Register rhs) {
507 357 : testq(rhs, lhs);
508 357 : }
509 13390 : void testPtr(Register lhs, Imm32 rhs) {
510 13390 : testq(rhs, lhs);
511 13390 : }
512 57 : void testPtr(const Operand& lhs, Imm32 rhs) {
513 57 : testq(rhs, lhs);
514 57 : }
515 :
516 : /////////////////////////////////////////////////////////////////
517 : // Common interface.
518 : /////////////////////////////////////////////////////////////////
519 :
520 21 : CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr) {
521 21 : JmpSrc src = jmpSrc(label);
522 21 : return CodeOffsetJump(size(), addPatchableJump(src, Relocation::HARDCODED));
523 : }
524 :
525 0 : CodeOffsetJump jumpWithPatch(RepatchLabel* label, Condition cond,
526 : Label* documentation = nullptr)
527 : {
528 0 : JmpSrc src = jSrc(cond, label);
529 0 : return CodeOffsetJump(size(), addPatchableJump(src, Relocation::HARDCODED));
530 : }
531 :
532 0 : CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation = nullptr) {
533 0 : return jumpWithPatch(label);
534 : }
535 :
536 5583 : void movePtr(Register src, Register dest) {
537 5583 : movq(src, dest);
538 5583 : }
539 : void movePtr(Register src, const Operand& dest) {
540 : movq(src, dest);
541 : }
542 643 : void movePtr(ImmWord imm, Register dest) {
543 643 : mov(imm, dest);
544 643 : }
545 8876 : void movePtr(ImmPtr imm, Register dest) {
546 8876 : mov(imm, dest);
547 8876 : }
548 : void movePtr(wasm::SymbolicAddress imm, Register dest) {
549 : mov(imm, dest);
550 : }
551 3503 : void movePtr(ImmGCPtr imm, Register dest) {
552 3503 : movq(imm, dest);
553 3503 : }
554 5113 : void loadPtr(AbsoluteAddress address, Register dest) {
555 5113 : if (X86Encoding::IsAddressImmediate(address.addr)) {
556 0 : movq(Operand(address), dest);
557 : } else {
558 10226 : ScratchRegisterScope scratch(asMasm());
559 5113 : mov(ImmPtr(address.addr), scratch);
560 5113 : loadPtr(Address(scratch, 0x0), dest);
561 : }
562 5113 : }
563 39230 : void loadPtr(const Address& address, Register dest) {
564 39230 : movq(Operand(address), dest);
565 39230 : }
566 : void load64(const Address& address, Register dest) {
567 : movq(Operand(address), dest);
568 : }
569 : void loadPtr(const Operand& src, Register dest) {
570 : movq(src, dest);
571 : }
572 31 : void loadPtr(const BaseIndex& src, Register dest) {
573 31 : movq(Operand(src), dest);
574 31 : }
575 0 : void loadPrivate(const Address& src, Register dest) {
576 0 : loadPtr(src, dest);
577 0 : shlq(Imm32(1), dest);
578 0 : }
579 181 : void load32(AbsoluteAddress address, Register dest) {
580 181 : if (X86Encoding::IsAddressImmediate(address.addr)) {
581 0 : movl(Operand(address), dest);
582 : } else {
583 362 : ScratchRegisterScope scratch(asMasm());
584 181 : mov(ImmPtr(address.addr), scratch);
585 181 : load32(Address(scratch, 0x0), dest);
586 : }
587 181 : }
588 0 : void load64(const Address& address, Register64 dest) {
589 0 : movq(Operand(address), dest.reg);
590 0 : }
591 : template <typename T>
592 1452 : void storePtr(ImmWord imm, T address) {
593 1452 : if ((intptr_t)imm.value <= INT32_MAX && (intptr_t)imm.value >= INT32_MIN) {
594 1381 : movq(Imm32((int32_t)imm.value), Operand(address));
595 : } else {
596 142 : ScratchRegisterScope scratch(asMasm());
597 71 : mov(imm, scratch);
598 71 : movq(scratch, Operand(address));
599 : }
600 1452 : }
601 : template <typename T>
602 1401 : void storePtr(ImmPtr imm, T address) {
603 1401 : storePtr(ImmWord(uintptr_t(imm.value)), address);
604 1401 : }
605 : template <typename T>
606 196 : void storePtr(ImmGCPtr imm, T address) {
607 392 : ScratchRegisterScope scratch(asMasm());
608 196 : movq(imm, scratch);
609 196 : movq(scratch, Operand(address));
610 196 : }
611 4279 : void storePtr(Register src, const Address& address) {
612 4279 : movq(src, Operand(address));
613 4279 : }
614 : void store64(Register src, const Address& address) {
615 : movq(src, Operand(address));
616 : }
617 8 : void storePtr(Register src, const BaseIndex& address) {
618 8 : movq(src, Operand(address));
619 8 : }
620 : void storePtr(Register src, const Operand& dest) {
621 : movq(src, dest);
622 : }
623 95 : void storePtr(Register src, AbsoluteAddress address) {
624 95 : if (X86Encoding::IsAddressImmediate(address.addr)) {
625 0 : movq(src, Operand(address));
626 : } else {
627 190 : ScratchRegisterScope scratch(asMasm());
628 95 : mov(ImmPtr(address.addr), scratch);
629 95 : storePtr(src, Address(scratch, 0x0));
630 : }
631 95 : }
632 181 : void store32(Register src, AbsoluteAddress address) {
633 181 : if (X86Encoding::IsAddressImmediate(address.addr)) {
634 0 : movl(src, Operand(address));
635 : } else {
636 362 : ScratchRegisterScope scratch(asMasm());
637 181 : mov(ImmPtr(address.addr), scratch);
638 181 : store32(src, Address(scratch, 0x0));
639 : }
640 181 : }
641 : void store16(Register src, AbsoluteAddress address) {
642 : if (X86Encoding::IsAddressImmediate(address.addr)) {
643 : movw(src, Operand(address));
644 : } else {
645 : ScratchRegisterScope scratch(asMasm());
646 : mov(ImmPtr(address.addr), scratch);
647 : store16(src, Address(scratch, 0x0));
648 : }
649 : }
650 0 : void store64(Register64 src, Address address) {
651 0 : storePtr(src.reg, address);
652 0 : }
653 0 : void store64(Imm64 imm, Address address) {
654 0 : storePtr(ImmWord(imm.value), address);
655 0 : }
656 :
657 5228 : void splitTag(Register src, Register dest) {
658 5228 : if (src != dest)
659 5180 : movq(src, dest);
660 5228 : shrq(Imm32(JSVAL_TAG_SHIFT), dest);
661 5228 : }
662 5180 : void splitTag(const ValueOperand& operand, Register dest) {
663 5180 : splitTag(operand.valueReg(), dest);
664 5180 : }
665 282 : void splitTag(const Operand& operand, Register dest) {
666 282 : movq(operand, dest);
667 282 : shrq(Imm32(JSVAL_TAG_SHIFT), dest);
668 282 : }
669 242 : void splitTag(const Address& operand, Register dest) {
670 242 : splitTag(Operand(operand), dest);
671 242 : }
672 40 : void splitTag(const BaseIndex& operand, Register dest) {
673 40 : splitTag(Operand(operand), dest);
674 40 : }
675 :
676 : // Extracts the tag of a value and places it in ScratchReg.
677 61 : Register splitTagForTest(const ValueOperand& value) {
678 61 : splitTag(value, ScratchReg);
679 61 : return ScratchReg;
680 : }
681 : void cmpTag(const ValueOperand& operand, ImmTag tag) {
682 : Register reg = splitTagForTest(operand);
683 : cmp32(reg, tag);
684 : }
685 :
686 12 : Condition testMagic(Condition cond, const ValueOperand& src) {
687 24 : ScratchRegisterScope scratch(asMasm());
688 12 : splitTag(src, scratch);
689 24 : return testMagic(cond, scratch);
690 : }
691 : Condition testError(Condition cond, const ValueOperand& src) {
692 : return testMagic(cond, src);
693 : }
694 :
695 0 : void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
696 0 : cond = testNull(cond, value);
697 0 : emitSet(cond, dest);
698 0 : }
699 :
700 0 : void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
701 0 : cond = testObject(cond, value);
702 0 : emitSet(cond, dest);
703 0 : }
704 :
705 0 : void testUndefinedSet(Condition cond, const ValueOperand& value, Register dest) {
706 0 : cond = testUndefined(cond, value);
707 0 : emitSet(cond, dest);
708 0 : }
709 :
710 8 : void boxDouble(FloatRegister src, const ValueOperand& dest) {
711 8 : vmovq(src, dest.valueReg());
712 8 : }
713 15 : void boxNonDouble(JSValueType type, Register src, const ValueOperand& dest) {
714 15 : MOZ_ASSERT(src != dest.valueReg());
715 15 : boxValue(type, src, dest.valueReg());
716 15 : }
717 :
718 : // Note that the |dest| register here may be ScratchReg, so we shouldn't
719 : // use it.
720 141 : void unboxInt32(const ValueOperand& src, Register dest) {
721 141 : movl(src.valueReg(), dest);
722 141 : }
723 27 : void unboxInt32(const Operand& src, Register dest) {
724 27 : movl(src, dest);
725 27 : }
726 5 : void unboxInt32(const Address& src, Register dest) {
727 5 : unboxInt32(Operand(src), dest);
728 5 : }
729 0 : void unboxDouble(const Address& src, FloatRegister dest) {
730 0 : loadDouble(Operand(src), dest);
731 0 : }
732 :
733 : void unboxArgObjMagic(const ValueOperand& src, Register dest) {
734 : unboxArgObjMagic(Operand(src.valueReg()), dest);
735 : }
736 : void unboxArgObjMagic(const Operand& src, Register dest) {
737 : mov(ImmWord(0), dest);
738 : }
739 : void unboxArgObjMagic(const Address& src, Register dest) {
740 : unboxArgObjMagic(Operand(src), dest);
741 : }
742 :
743 2 : void unboxBoolean(const ValueOperand& src, Register dest) {
744 2 : movl(src.valueReg(), dest);
745 2 : }
746 24 : void unboxBoolean(const Operand& src, Register dest) {
747 24 : movl(src, dest);
748 24 : }
749 : void unboxBoolean(const Address& src, Register dest) {
750 : unboxBoolean(Operand(src), dest);
751 : }
752 :
753 : void unboxMagic(const ValueOperand& src, Register dest) {
754 : movl(src.valueReg(), dest);
755 : }
756 :
757 52 : void unboxDouble(const ValueOperand& src, FloatRegister dest) {
758 52 : vmovq(src.valueReg(), dest);
759 52 : }
760 : void unboxPrivate(const ValueOperand& src, const Register dest) {
761 : movq(src.valueReg(), dest);
762 : shlq(Imm32(1), dest);
763 : }
764 :
765 473 : void notBoolean(const ValueOperand& val) {
766 473 : xorq(Imm32(1), val.valueReg());
767 473 : }
768 :
769 : // Unbox any non-double value into dest. Prefer unboxInt32 or unboxBoolean
770 : // instead if the source type is known.
771 1109 : void unboxNonDouble(const ValueOperand& src, Register dest) {
772 1109 : if (src.valueReg() == dest) {
773 704 : ScratchRegisterScope scratch(asMasm());
774 352 : mov(ImmWord(JSVAL_PAYLOAD_MASK), scratch);
775 352 : andq(scratch, dest);
776 : } else {
777 757 : mov(ImmWord(JSVAL_PAYLOAD_MASK), dest);
778 757 : andq(src.valueReg(), dest);
779 : }
780 1109 : }
781 531 : void unboxNonDouble(const Operand& src, Register dest) {
782 : // Explicitly permits |dest| to be used in |src|.
783 1062 : ScratchRegisterScope scratch(asMasm());
784 531 : MOZ_ASSERT(dest != scratch);
785 531 : if (src.containsReg(dest)) {
786 335 : mov(ImmWord(JSVAL_PAYLOAD_MASK), scratch);
787 : // If src is already a register, then src and dest are the same
788 : // thing and we don't need to move anything into dest.
789 335 : if (src.kind() != Operand::REG)
790 314 : movq(src, dest);
791 335 : andq(scratch, dest);
792 : } else {
793 196 : mov(ImmWord(JSVAL_PAYLOAD_MASK), dest);
794 196 : andq(src, dest);
795 : }
796 531 : }
797 0 : void unboxNonDouble(const Address& src, Register dest) {
798 0 : unboxNonDouble(Operand(src), dest);
799 0 : }
800 :
801 49 : void unboxString(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
802 24 : void unboxString(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
803 :
804 : void unboxSymbol(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
805 0 : void unboxSymbol(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
806 :
807 1046 : void unboxObject(const ValueOperand& src, Register dest) { unboxNonDouble(src, dest); }
808 47 : void unboxObject(const Operand& src, Register dest) { unboxNonDouble(src, dest); }
809 450 : void unboxObject(const Address& src, Register dest) { unboxNonDouble(Operand(src), dest); }
810 2 : void unboxObject(const BaseIndex& src, Register dest) { unboxNonDouble(Operand(src), dest); }
811 :
812 : // Extended unboxing API. If the payload is already in a register, returns
813 : // that register. Otherwise, provides a move to the given scratch register,
814 : // and returns that.
815 398 : Register extractObject(const Address& address, Register scratch) {
816 398 : MOZ_ASSERT(scratch != ScratchReg);
817 398 : unboxObject(address, scratch);
818 398 : return scratch;
819 : }
820 704 : Register extractObject(const ValueOperand& value, Register scratch) {
821 704 : MOZ_ASSERT(scratch != ScratchReg);
822 704 : unboxObject(value, scratch);
823 704 : return scratch;
824 : }
825 37 : Register extractInt32(const ValueOperand& value, Register scratch) {
826 37 : MOZ_ASSERT(scratch != ScratchReg);
827 37 : unboxInt32(value, scratch);
828 37 : return scratch;
829 : }
830 2 : Register extractBoolean(const ValueOperand& value, Register scratch) {
831 2 : MOZ_ASSERT(scratch != ScratchReg);
832 2 : unboxBoolean(value, scratch);
833 2 : return scratch;
834 : }
835 48 : Register extractTag(const Address& address, Register scratch) {
836 48 : MOZ_ASSERT(scratch != ScratchReg);
837 48 : loadPtr(address, scratch);
838 48 : splitTag(scratch, scratch);
839 48 : return scratch;
840 : }
841 130 : Register extractTag(const ValueOperand& value, Register scratch) {
842 130 : MOZ_ASSERT(scratch != ScratchReg);
843 130 : splitTag(value, scratch);
844 130 : return scratch;
845 : }
846 :
847 : inline void unboxValue(const ValueOperand& src, AnyRegister dest);
848 :
849 : // These two functions use the low 32-bits of the full value register.
850 0 : void boolValueToDouble(const ValueOperand& operand, FloatRegister dest) {
851 0 : convertInt32ToDouble(operand.valueReg(), dest);
852 0 : }
853 0 : void int32ValueToDouble(const ValueOperand& operand, FloatRegister dest) {
854 0 : convertInt32ToDouble(operand.valueReg(), dest);
855 0 : }
856 :
857 0 : void boolValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
858 0 : convertInt32ToFloat32(operand.valueReg(), dest);
859 0 : }
860 0 : void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest) {
861 0 : convertInt32ToFloat32(operand.valueReg(), dest);
862 0 : }
863 :
864 : void loadConstantDouble(double d, FloatRegister dest);
865 : void loadConstantFloat32(float f, FloatRegister dest);
866 :
867 : void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
868 : void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
869 :
870 : void convertInt64ToDouble(Register64 input, FloatRegister output);
871 : void convertInt64ToFloat32(Register64 input, FloatRegister output);
872 : static bool convertUInt64ToDoubleNeedsTemp();
873 : void convertUInt64ToDouble(Register64 input, FloatRegister output, Register temp);
874 : void convertUInt64ToFloat32(Register64 input, FloatRegister output, Register temp);
875 :
876 : void wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
877 : Label* oolRejoin, FloatRegister tempDouble);
878 : void wasmTruncateDoubleToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
879 : Label* oolRejoin, FloatRegister tempDouble);
880 :
881 : void wasmTruncateFloat32ToInt64(FloatRegister input, Register64 output, Label* oolEntry,
882 : Label* oolRejoin, FloatRegister tempDouble);
883 : void wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
884 : Label* oolRejoin, FloatRegister tempDouble);
885 :
886 0 : void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
887 0 : loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalArea) + globalDataOffset), dest);
888 0 : }
889 0 : void loadWasmPinnedRegsFromTls() {
890 0 : loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg);
891 0 : }
892 :
893 : public:
894 11 : Condition testInt32Truthy(bool truthy, const ValueOperand& operand) {
895 11 : test32(operand.valueReg(), operand.valueReg());
896 11 : return truthy ? NonZero : Zero;
897 : }
898 21 : Condition testStringTruthy(bool truthy, const ValueOperand& value) {
899 42 : ScratchRegisterScope scratch(asMasm());
900 21 : unboxString(value, scratch);
901 21 : cmp32(Operand(scratch, JSString::offsetOfLength()), Imm32(0));
902 42 : return truthy ? Assembler::NotEqual : Assembler::Equal;
903 : }
904 :
905 : template <typename T>
906 : inline void loadInt32OrDouble(const T& src, FloatRegister dest);
907 :
908 : template <typename T>
909 14 : void loadUnboxedValue(const T& src, MIRType type, AnyRegister dest) {
910 14 : if (dest.isFloat())
911 0 : loadInt32OrDouble(src, dest.fpu());
912 14 : else if (type == MIRType::Int32 || type == MIRType::Boolean)
913 6 : movl(Operand(src), dest.gpr());
914 : else
915 8 : unboxNonDouble(Operand(src), dest.gpr());
916 14 : }
917 :
918 : template <typename T>
919 10 : void storeUnboxedPayload(ValueOperand value, T address, size_t nbytes) {
920 10 : switch (nbytes) {
921 : case 8: {
922 14 : ScratchRegisterScope scratch(asMasm());
923 7 : unboxNonDouble(value, scratch);
924 7 : storePtr(scratch, address);
925 7 : return;
926 : }
927 : case 4:
928 0 : store32(value.valueReg(), address);
929 0 : return;
930 : case 1:
931 3 : store8(value.valueReg(), address);
932 3 : return;
933 0 : default: MOZ_CRASH("Bad payload width");
934 : }
935 : }
936 :
937 : void loadInstructionPointerAfterCall(Register dest) {
938 : loadPtr(Address(StackPointer, 0x0), dest);
939 : }
940 :
941 0 : void convertUInt32ToDouble(Register src, FloatRegister dest) {
942 : // Zero the output register to break dependencies, see convertInt32ToDouble.
943 0 : zeroDouble(dest);
944 :
945 0 : vcvtsq2sd(src, dest, dest);
946 0 : }
947 :
948 0 : void convertUInt32ToFloat32(Register src, FloatRegister dest) {
949 : // Zero the output register to break dependencies, see convertInt32ToDouble.
950 0 : zeroDouble(dest);
951 :
952 0 : vcvtsq2ss(src, dest, dest);
953 0 : }
954 :
955 : inline void incrementInt32Value(const Address& addr);
956 :
957 : inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
958 :
959 : public:
960 : void handleFailureWithHandlerTail(void* handler);
961 :
962 : // Instrumentation for entering and leaving the profiler.
963 : void profilerEnterFrame(Register framePtr, Register scratch);
964 : void profilerExitFrame();
965 : };
966 :
967 : typedef MacroAssemblerX64 MacroAssemblerSpecific;
968 :
969 : } // namespace jit
970 : } // namespace js
971 :
972 : #endif /* jit_x64_MacroAssembler_x64_h */
|