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_MacroAssembler_inl_h
8 : #define jit_MacroAssembler_inl_h
9 :
10 : #include "jit/MacroAssembler.h"
11 :
12 : #include "mozilla/FloatingPoint.h"
13 : #include "mozilla/MathAlgorithms.h"
14 :
15 : #if defined(JS_CODEGEN_X86)
16 : # include "jit/x86/MacroAssembler-x86-inl.h"
17 : #elif defined(JS_CODEGEN_X64)
18 : # include "jit/x64/MacroAssembler-x64-inl.h"
19 : #elif defined(JS_CODEGEN_ARM)
20 : # include "jit/arm/MacroAssembler-arm-inl.h"
21 : #elif defined(JS_CODEGEN_ARM64)
22 : # include "jit/arm64/MacroAssembler-arm64-inl.h"
23 : #elif defined(JS_CODEGEN_MIPS32)
24 : # include "jit/mips32/MacroAssembler-mips32-inl.h"
25 : #elif defined(JS_CODEGEN_MIPS64)
26 : # include "jit/mips64/MacroAssembler-mips64-inl.h"
27 : #elif !defined(JS_CODEGEN_NONE)
28 : # error "Unknown architecture!"
29 : #endif
30 :
31 : #include "wasm/WasmBuiltins.h"
32 :
33 : namespace js {
34 : namespace jit {
35 :
36 : //{{{ check_macroassembler_style
37 : // ===============================================================
38 : // Stack manipulation functions.
39 :
40 : CodeOffset
41 : MacroAssembler::PushWithPatch(ImmWord word)
42 : {
43 0 : framePushed_ += sizeof(word.value);
44 474 : return pushWithPatch(word);
45 : }
46 :
47 : CodeOffset
48 : MacroAssembler::PushWithPatch(ImmPtr imm)
49 : {
50 170 : return PushWithPatch(ImmWord(uintptr_t(imm.value)));
51 : }
52 :
53 : // ===============================================================
54 : // Simple call functions.
55 :
56 : void
57 48 : MacroAssembler::call(TrampolinePtr code)
58 : {
59 0 : call(ImmPtr(code.value));
60 48 : }
61 :
62 : void
63 : MacroAssembler::call(const wasm::CallSiteDesc& desc, const Register reg)
64 : {
65 0 : CodeOffset l = call(reg);
66 0 : append(desc, l);
67 : }
68 :
69 : void
70 : MacroAssembler::call(const wasm::CallSiteDesc& desc, uint32_t funcIndex)
71 : {
72 0 : CodeOffset l = callWithPatch();
73 0 : append(desc, l, funcIndex);
74 : }
75 :
76 : void
77 : MacroAssembler::call(const wasm::CallSiteDesc& desc, wasm::Trap trap)
78 : {
79 : CodeOffset l = callWithPatch();
80 : append(desc, l, trap);
81 : }
82 :
83 : void
84 0 : MacroAssembler::call(const wasm::CallSiteDesc& desc, wasm::SymbolicAddress imm)
85 : {
86 0 : MOZ_ASSERT(wasm::NeedsBuiltinThunk(imm), "only for functions which may appear in profiler");
87 0 : call(imm);
88 0 : append(desc, CodeOffset(currentOffset()));
89 0 : }
90 :
91 : // ===============================================================
92 : // ABI function calls.
93 :
94 : void
95 : MacroAssembler::passABIArg(Register reg)
96 : {
97 31132 : passABIArg(MoveOperand(reg), MoveOp::GENERAL);
98 : }
99 :
100 : void
101 1 : MacroAssembler::passABIArg(FloatRegister reg, MoveOp::Type type)
102 : {
103 0 : passABIArg(MoveOperand(reg), type);
104 1 : }
105 :
106 : void
107 25309 : MacroAssembler::callWithABI(void* fun, MoveOp::Type result, CheckUnsafeCallWithABI check)
108 : {
109 0 : AutoProfilerCallInstrumentation profiler(*this);
110 0 : callWithABINoProfiler(fun, result, check);
111 25309 : }
112 :
113 : void
114 3 : MacroAssembler::callWithABI(Register fun, MoveOp::Type result)
115 : {
116 0 : AutoProfilerCallInstrumentation profiler(*this);
117 0 : callWithABINoProfiler(fun, result);
118 3 : }
119 :
120 : void
121 25 : MacroAssembler::callWithABI(const Address& fun, MoveOp::Type result)
122 : {
123 0 : AutoProfilerCallInstrumentation profiler(*this);
124 0 : callWithABINoProfiler(fun, result);
125 25 : }
126 :
127 : void
128 : MacroAssembler::appendSignatureType(MoveOp::Type type)
129 : {
130 : #ifdef JS_SIMULATOR
131 : signature_ <<= ArgType_Shift;
132 : switch (type) {
133 : case MoveOp::GENERAL: signature_ |= ArgType_General; break;
134 : case MoveOp::DOUBLE: signature_ |= ArgType_Double; break;
135 : case MoveOp::FLOAT32: signature_ |= ArgType_Float32; break;
136 : default: MOZ_CRASH("Invalid argument type");
137 : }
138 : #endif
139 : }
140 :
141 : ABIFunctionType
142 : MacroAssembler::signature() const
143 : {
144 : #ifdef JS_SIMULATOR
145 : #ifdef DEBUG
146 : switch (signature_) {
147 : case Args_General0:
148 : case Args_General1:
149 : case Args_General2:
150 : case Args_General3:
151 : case Args_General4:
152 : case Args_General5:
153 : case Args_General6:
154 : case Args_General7:
155 : case Args_General8:
156 : case Args_Double_None:
157 : case Args_Int_Double:
158 : case Args_Float32_Float32:
159 : case Args_Double_Double:
160 : case Args_Double_Int:
161 : case Args_Double_DoubleInt:
162 : case Args_Double_DoubleDouble:
163 : case Args_Double_IntDouble:
164 : case Args_Int_IntDouble:
165 : case Args_Int_DoubleIntInt:
166 : case Args_Int_IntDoubleIntInt:
167 : case Args_Double_DoubleDoubleDouble:
168 : case Args_Double_DoubleDoubleDoubleDouble:
169 : break;
170 : default:
171 : MOZ_CRASH("Unexpected type");
172 : }
173 : #endif // DEBUG
174 :
175 : return ABIFunctionType(signature_);
176 : #else
177 : // No simulator enabled.
178 : MOZ_CRASH("Only available for making calls within a simulator.");
179 : #endif
180 : }
181 :
182 : // ===============================================================
183 : // Jit Frames.
184 :
185 : uint32_t
186 4 : MacroAssembler::callJitNoProfiler(Register callee)
187 : {
188 : #ifdef JS_USE_LINK_REGISTER
189 : // The return address is pushed by the callee.
190 : call(callee);
191 : #else
192 219 : callAndPushReturnAddress(callee);
193 : #endif
194 438 : return currentOffset();
195 : }
196 :
197 : uint32_t
198 211 : MacroAssembler::callJit(Register callee)
199 : {
200 0 : AutoProfilerCallInstrumentation profiler(*this);
201 0 : uint32_t ret = callJitNoProfiler(callee);
202 422 : return ret;
203 : }
204 :
205 : uint32_t
206 : MacroAssembler::callJit(JitCode* callee)
207 : {
208 : AutoProfilerCallInstrumentation profiler(*this);
209 : call(callee);
210 : return currentOffset();
211 : }
212 :
213 : uint32_t
214 1078 : MacroAssembler::callJit(TrampolinePtr code)
215 : {
216 0 : AutoProfilerCallInstrumentation profiler(*this);
217 0 : call(code);
218 3234 : return currentOffset();
219 : }
220 :
221 : void
222 704 : MacroAssembler::makeFrameDescriptor(Register frameSizeReg, FrameType type, uint32_t headerSize)
223 : {
224 : // See JitFrames.h for a description of the frame descriptor format.
225 : // The saved-frame bit is zero for new frames. See js::SavedStacks.
226 :
227 704 : lshiftPtr(Imm32(FRAMESIZE_SHIFT), frameSizeReg);
228 :
229 0 : headerSize = EncodeFrameHeaderSize(headerSize);
230 0 : orPtr(Imm32((headerSize << FRAME_HEADER_SIZE_SHIFT) | type), frameSizeReg);
231 704 : }
232 :
233 : void
234 1151 : MacroAssembler::pushStaticFrameDescriptor(FrameType type, uint32_t headerSize)
235 : {
236 0 : uint32_t descriptor = MakeFrameDescriptor(framePushed(), type, headerSize);
237 0 : Push(Imm32(descriptor));
238 1151 : }
239 :
240 : void
241 159 : MacroAssembler::PushCalleeToken(Register callee, bool constructing)
242 : {
243 0 : if (constructing) {
244 0 : orPtr(Imm32(CalleeToken_FunctionConstructing), callee);
245 0 : Push(callee);
246 5 : andPtr(Imm32(uint32_t(CalleeTokenMask)), callee);
247 : } else {
248 : static_assert(CalleeToken_Function == 0, "Non-constructing call requires no tagging");
249 154 : Push(callee);
250 : }
251 159 : }
252 :
253 : void
254 882 : MacroAssembler::loadFunctionFromCalleeToken(Address token, Register dest)
255 : {
256 : #ifdef DEBUG
257 0 : Label ok;
258 0 : loadPtr(token, dest);
259 0 : andPtr(Imm32(uint32_t(~CalleeTokenMask)), dest);
260 0 : branchPtr(Assembler::Equal, dest, Imm32(CalleeToken_Function), &ok);
261 0 : branchPtr(Assembler::Equal, dest, Imm32(CalleeToken_FunctionConstructing), &ok);
262 0 : assumeUnreachable("Unexpected CalleeToken tag");
263 882 : bind(&ok);
264 : #endif
265 0 : loadPtr(token, dest);
266 0 : andPtr(Imm32(uint32_t(CalleeTokenMask)), dest);
267 882 : }
268 :
269 : uint32_t
270 81 : MacroAssembler::buildFakeExitFrame(Register scratch)
271 : {
272 243 : mozilla::DebugOnly<uint32_t> initialDepth = framePushed();
273 :
274 0 : pushStaticFrameDescriptor(JitFrame_IonJS, ExitFrameLayout::Size());
275 81 : uint32_t retAddr = pushFakeReturnAddress(scratch);
276 :
277 0 : MOZ_ASSERT(framePushed() == initialDepth + ExitFrameLayout::Size());
278 162 : return retAddr;
279 : }
280 :
281 : // ===============================================================
282 : // Exit frame footer.
283 :
284 : void
285 908 : MacroAssembler::enterExitFrame(Register cxreg, Register scratch, const VMFunction* f)
286 : {
287 0 : MOZ_ASSERT(f);
288 908 : linkExitFrame(cxreg, scratch);
289 : // Push VMFunction pointer, to mark arguments.
290 0 : Push(ImmPtr(f));
291 908 : }
292 :
293 : void
294 : MacroAssembler::enterFakeExitFrame(Register cxreg, Register scratch, ExitFrameType type)
295 : {
296 0 : linkExitFrame(cxreg, scratch);
297 332 : Push(Imm32(int32_t(type)));
298 : }
299 :
300 : void
301 106 : MacroAssembler::enterFakeExitFrameForNative(Register cxreg, Register scratch, bool isConstructing)
302 : {
303 0 : enterFakeExitFrame(cxreg, scratch, isConstructing ? ExitFrameType::ConstructNative
304 0 : : ExitFrameType::CallNative);
305 106 : }
306 :
307 : void
308 : MacroAssembler::leaveExitFrame(size_t extraFrame)
309 : {
310 916 : freeStack(ExitFooterFrame::Size() + extraFrame);
311 : }
312 :
313 : // ===============================================================
314 : // Move instructions
315 :
316 : void
317 0 : MacroAssembler::moveValue(const ConstantOrRegister& src, const ValueOperand& dest)
318 : {
319 0 : if (src.constant()) {
320 0 : moveValue(src.value(), dest);
321 0 : return;
322 : }
323 :
324 0 : moveValue(src.reg(), dest);
325 : }
326 :
327 : // ===============================================================
328 : // Arithmetic functions
329 :
330 : void
331 : MacroAssembler::addPtr(ImmPtr imm, Register dest)
332 : {
333 : addPtr(ImmWord(uintptr_t(imm.value)), dest);
334 : }
335 :
336 : // ===============================================================
337 : // Branch functions
338 :
339 : template <class L>
340 : void
341 : MacroAssembler::branchIfFalseBool(Register reg, L label)
342 : {
343 : // Note that C++ bool is only 1 byte, so ignore the higher-order bits.
344 501 : branchTest32(Assembler::Zero, reg, Imm32(0xFF), label);
345 : }
346 :
347 : void
348 : MacroAssembler::branchIfTrueBool(Register reg, Label* label)
349 : {
350 : // Note that C++ bool is only 1 byte, so ignore the higher-order bits.
351 87 : branchTest32(Assembler::NonZero, reg, Imm32(0xFF), label);
352 : }
353 :
354 : void
355 : MacroAssembler::branchIfRope(Register str, Label* label)
356 : {
357 0 : Address flags(str, JSString::offsetOfFlags());
358 6 : branchTest32(Assembler::Zero, flags, Imm32(JSString::LINEAR_BIT), label);
359 : }
360 :
361 : void
362 6 : MacroAssembler::branchIfRopeOrExternal(Register str, Register temp, Label* label)
363 : {
364 0 : Address flags(str, JSString::offsetOfFlags());
365 0 : move32(Imm32(JSString::TYPE_FLAGS_MASK), temp);
366 6 : and32(flags, temp);
367 :
368 0 : branchTest32(Assembler::Zero, temp, Imm32(JSString::LINEAR_BIT), label);
369 0 : branch32(Assembler::Equal, temp, Imm32(JSString::EXTERNAL_FLAGS), label);
370 6 : }
371 :
372 : void
373 : MacroAssembler::branchIfNotRope(Register str, Label* label)
374 : {
375 0 : Address flags(str, JSString::offsetOfFlags());
376 2 : branchTest32(Assembler::NonZero, flags, Imm32(JSString::LINEAR_BIT), label);
377 : }
378 :
379 : void
380 : MacroAssembler::branchLatin1String(Register string, Label* label)
381 : {
382 0 : branchTest32(Assembler::NonZero, Address(string, JSString::offsetOfFlags()),
383 17 : Imm32(JSString::LATIN1_CHARS_BIT), label);
384 : }
385 :
386 : void
387 : MacroAssembler::branchTwoByteString(Register string, Label* label)
388 : {
389 : branchTest32(Assembler::Zero, Address(string, JSString::offsetOfFlags()),
390 : Imm32(JSString::LATIN1_CHARS_BIT), label);
391 : }
392 :
393 : void
394 : MacroAssembler::branchIfFunctionHasNoJitEntry(Register fun, bool isConstructing, Label* label)
395 : {
396 : // 16-bit loads are slow and unaligned 32-bit loads may be too so
397 : // perform an aligned 32-bit load and adjust the bitmask accordingly.
398 :
399 : static_assert(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0,
400 : "The code in this function and the ones below must change");
401 : static_assert(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2,
402 : "The code in this function and the ones below must change");
403 :
404 0 : Address address(fun, JSFunction::offsetOfNargs());
405 0 : int32_t bit = JSFunction::INTERPRETED;
406 0 : if (!isConstructing)
407 0 : bit |= JSFunction::WASM_OPTIMIZED;
408 0 : bit = IMM32_16ADJ(bit);
409 344 : branchTest32(Assembler::Zero, address, Imm32(bit), label);
410 : }
411 :
412 : void
413 : MacroAssembler::branchIfInterpreted(Register fun, Label* label)
414 : {
415 : // 16-bit loads are slow and unaligned 32-bit loads may be too so
416 : // perform an aligned 32-bit load and adjust the bitmask accordingly.
417 : Address address(fun, JSFunction::offsetOfNargs());
418 : int32_t bit = IMM32_16ADJ(JSFunction::INTERPRETED);
419 : branchTest32(Assembler::NonZero, address, Imm32(bit), label);
420 : }
421 :
422 : void
423 29 : MacroAssembler::branchIfObjectEmulatesUndefined(Register objReg, Register scratch,
424 : Label* slowCheck, Label* label)
425 : {
426 : // The branches to out-of-line code here implement a conservative version
427 : // of the JSObject::isWrapper test performed in EmulatesUndefined.
428 29 : loadObjClassUnsafe(objReg, scratch);
429 :
430 29 : branchTestClassIsProxy(true, scratch, slowCheck);
431 :
432 0 : Address flags(scratch, Class::offsetOfFlags());
433 0 : branchTest32(Assembler::NonZero, flags, Imm32(JSCLASS_EMULATES_UNDEFINED), label);
434 29 : }
435 :
436 : void
437 120 : MacroAssembler::branchFunctionKind(Condition cond, JSFunction::FunctionKind kind, Register fun,
438 : Register scratch, Label* label)
439 : {
440 : // 16-bit loads are slow and unaligned 32-bit loads may be too so
441 : // perform an aligned 32-bit load and adjust the bitmask accordingly.
442 : MOZ_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0);
443 : MOZ_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2);
444 0 : Address address(fun, JSFunction::offsetOfNargs());
445 0 : int32_t mask = IMM32_16ADJ(JSFunction::FUNCTION_KIND_MASK);
446 0 : int32_t bit = IMM32_16ADJ(kind << JSFunction::FUNCTION_KIND_SHIFT);
447 0 : load32(address, scratch);
448 0 : and32(Imm32(mask), scratch);
449 0 : branch32(cond, scratch, Imm32(bit), label);
450 120 : }
451 :
452 : void
453 210 : MacroAssembler::branchTestObjClass(Condition cond, Register obj, const js::Class* clasp,
454 : Register scratch, Register spectreRegToZero, Label* label)
455 : {
456 0 : MOZ_ASSERT(obj != scratch);
457 210 : MOZ_ASSERT(scratch != spectreRegToZero);
458 :
459 0 : loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
460 630 : branchPtr(cond, Address(scratch, ObjectGroup::offsetOfClasp()), ImmPtr(clasp), label);
461 :
462 0 : if (JitOptions.spectreObjectMitigationsMisc)
463 0 : spectreZeroRegister(cond, scratch, spectreRegToZero);
464 210 : }
465 :
466 : void
467 12 : MacroAssembler::branchTestObjClassNoSpectreMitigations(Condition cond, Register obj,
468 : const js::Class* clasp,
469 : Register scratch, Label* label)
470 : {
471 0 : loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
472 0 : branchPtr(cond, Address(scratch, ObjectGroup::offsetOfClasp()), ImmPtr(clasp), label);
473 12 : }
474 :
475 : void
476 5 : MacroAssembler::branchTestObjClass(Condition cond, Register obj, const Address& clasp,
477 : Register scratch, Register spectreRegToZero, Label* label)
478 : {
479 0 : MOZ_ASSERT(obj != scratch);
480 5 : MOZ_ASSERT(scratch != spectreRegToZero);
481 :
482 0 : loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
483 0 : loadPtr(Address(scratch, ObjectGroup::offsetOfClasp()), scratch);
484 5 : branchPtr(cond, clasp, scratch, label);
485 :
486 0 : if (JitOptions.spectreObjectMitigationsMisc)
487 0 : spectreZeroRegister(cond, scratch, spectreRegToZero);
488 5 : }
489 :
490 : void
491 0 : MacroAssembler::branchTestObjClassNoSpectreMitigations(Condition cond, Register obj,
492 : const Address& clasp, Register scratch,
493 : Label* label)
494 : {
495 0 : MOZ_ASSERT(obj != scratch);
496 0 : loadPtr(Address(obj, JSObject::offsetOfGroup()), scratch);
497 0 : loadPtr(Address(scratch, ObjectGroup::offsetOfClasp()), scratch);
498 0 : branchPtr(cond, clasp, scratch, label);
499 0 : }
500 :
501 : void
502 488 : MacroAssembler::branchTestObjShape(Condition cond, Register obj, const Shape* shape, Register scratch,
503 : Register spectreRegToZero, Label* label)
504 : {
505 0 : MOZ_ASSERT(obj != scratch);
506 488 : MOZ_ASSERT(spectreRegToZero != scratch);
507 :
508 0 : if (JitOptions.spectreObjectMitigationsMisc)
509 976 : move32(Imm32(0), scratch);
510 :
511 1464 : branchPtr(cond, Address(obj, ShapedObject::offsetOfShape()), ImmGCPtr(shape), label);
512 :
513 0 : if (JitOptions.spectreObjectMitigationsMisc)
514 0 : spectreMovePtr(cond, scratch, spectreRegToZero);
515 488 : }
516 :
517 : void
518 169 : MacroAssembler::branchTestObjShapeNoSpectreMitigations(Condition cond, Register obj,
519 : const Shape* shape, Label* label)
520 : {
521 0 : branchPtr(cond, Address(obj, ShapedObject::offsetOfShape()), ImmGCPtr(shape), label);
522 169 : }
523 :
524 : void
525 329 : MacroAssembler::branchTestObjShape(Condition cond, Register obj, Register shape, Register scratch,
526 : Register spectreRegToZero, Label* label)
527 : {
528 0 : MOZ_ASSERT(obj != scratch);
529 0 : MOZ_ASSERT(obj != shape);
530 329 : MOZ_ASSERT(spectreRegToZero != scratch);
531 :
532 0 : if (JitOptions.spectreObjectMitigationsMisc)
533 658 : move32(Imm32(0), scratch);
534 :
535 658 : branchPtr(cond, Address(obj, ShapedObject::offsetOfShape()), shape, label);
536 :
537 0 : if (JitOptions.spectreObjectMitigationsMisc)
538 0 : spectreMovePtr(cond, scratch, spectreRegToZero);
539 329 : }
540 :
541 : void
542 : MacroAssembler::branchTestObjShapeNoSpectreMitigations(Condition cond, Register obj, Register shape,
543 : Label* label)
544 : {
545 236 : branchPtr(cond, Address(obj, ShapedObject::offsetOfShape()), shape, label);
546 : }
547 :
548 : void
549 : MacroAssembler::branchTestObjShapeUnsafe(Condition cond, Register obj, Register shape,
550 : Label* label)
551 : {
552 0 : branchTestObjShapeNoSpectreMitigations(cond, obj, shape, label);
553 : }
554 :
555 : void
556 116 : MacroAssembler::branchTestObjGroup(Condition cond, Register obj, const ObjectGroup* group,
557 : Register scratch, Register spectreRegToZero, Label* label)
558 : {
559 0 : MOZ_ASSERT(obj != scratch);
560 116 : MOZ_ASSERT(spectreRegToZero != scratch);
561 :
562 0 : if (JitOptions.spectreObjectMitigationsMisc)
563 232 : move32(Imm32(0), scratch);
564 :
565 348 : branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), ImmGCPtr(group), label);
566 :
567 0 : if (JitOptions.spectreObjectMitigationsMisc)
568 0 : spectreMovePtr(cond, scratch, spectreRegToZero);
569 116 : }
570 :
571 : void
572 4 : MacroAssembler::branchTestObjGroupNoSpectreMitigations(Condition cond, Register obj,
573 : const ObjectGroup* group, Label* label)
574 : {
575 0 : branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), ImmGCPtr(group), label);
576 4 : }
577 :
578 : void
579 : MacroAssembler::branchTestObjGroupUnsafe(Condition cond, Register obj, const ObjectGroup* group,
580 : Label* label)
581 : {
582 0 : branchTestObjGroupNoSpectreMitigations(cond, obj, group, label);
583 : }
584 :
585 : void
586 100 : MacroAssembler::branchTestObjGroup(Condition cond, Register obj, Register group, Register scratch,
587 : Register spectreRegToZero, Label* label)
588 : {
589 0 : MOZ_ASSERT(obj != scratch);
590 0 : MOZ_ASSERT(obj != group);
591 100 : MOZ_ASSERT(spectreRegToZero != scratch);
592 :
593 0 : if (JitOptions.spectreObjectMitigationsMisc)
594 200 : move32(Imm32(0), scratch);
595 :
596 200 : branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), group, label);
597 :
598 0 : if (JitOptions.spectreObjectMitigationsMisc)
599 0 : spectreMovePtr(cond, scratch, spectreRegToZero);
600 100 : }
601 :
602 : void
603 5 : MacroAssembler::branchTestObjGroupNoSpectreMitigations(Condition cond, Register obj, Register group,
604 : Label* label)
605 : {
606 0 : MOZ_ASSERT(obj != group);
607 0 : branchPtr(cond, Address(obj, JSObject::offsetOfGroup()), group, label);
608 5 : }
609 :
610 : void
611 : MacroAssembler::branchTestClassIsProxy(bool proxy, Register clasp, Label* label)
612 : {
613 0 : branchTest32(proxy ? Assembler::NonZero : Assembler::Zero,
614 0 : Address(clasp, Class::offsetOfFlags()),
615 160 : Imm32(JSCLASS_IS_PROXY), label);
616 : }
617 :
618 : void
619 104 : MacroAssembler::branchTestObjectIsProxy(bool proxy, Register object, Register scratch, Label* label)
620 : {
621 0 : loadObjClassUnsafe(object, scratch);
622 0 : branchTestClassIsProxy(proxy, scratch, label);
623 104 : }
624 :
625 : void
626 46 : MacroAssembler::branchTestProxyHandlerFamily(Condition cond, Register proxy, Register scratch,
627 : const void* handlerp, Label* label)
628 : {
629 0 : Address handlerAddr(proxy, ProxyObject::offsetOfHandler());
630 0 : loadPtr(handlerAddr, scratch);
631 0 : Address familyAddr(scratch, BaseProxyHandler::offsetOfFamily());
632 0 : branchPtr(cond, familyAddr, ImmPtr(handlerp), label);
633 46 : }
634 :
635 : void
636 957 : MacroAssembler::branchTestNeedsIncrementalBarrier(Condition cond, Label* label)
637 : {
638 0 : MOZ_ASSERT(cond == Zero || cond == NonZero);
639 0 : CompileZone* zone = GetJitContext()->realm->zone();
640 0 : AbsoluteAddress needsBarrierAddr(zone->addressOfNeedsIncrementalBarrier());
641 0 : branchTest32(cond, needsBarrierAddr, Imm32(0x1), label);
642 957 : }
643 :
644 : void
645 153 : MacroAssembler::branchTestMagicValue(Condition cond, const ValueOperand& val, JSWhyMagic why,
646 : Label* label)
647 : {
648 0 : MOZ_ASSERT(cond == Equal || cond == NotEqual);
649 0 : branchTestValue(cond, val, MagicValue(why), label);
650 153 : }
651 :
652 : void
653 : MacroAssembler::branchDoubleNotInInt64Range(Address src, Register temp, Label* fail)
654 : {
655 : using mozilla::FloatingPoint;
656 :
657 : // Tests if double is in [INT64_MIN; INT64_MAX] range
658 : uint32_t EXPONENT_MASK = 0x7ff00000;
659 : uint32_t EXPONENT_SHIFT = FloatingPoint<double>::kExponentShift - 32;
660 : uint32_t TOO_BIG_EXPONENT = (FloatingPoint<double>::kExponentBias + 63) << EXPONENT_SHIFT;
661 :
662 : load32(Address(src.base, src.offset + sizeof(int32_t)), temp);
663 : and32(Imm32(EXPONENT_MASK), temp);
664 : branch32(Assembler::GreaterThanOrEqual, temp, Imm32(TOO_BIG_EXPONENT), fail);
665 : }
666 :
667 : void
668 : MacroAssembler::branchDoubleNotInUInt64Range(Address src, Register temp, Label* fail)
669 : {
670 : using mozilla::FloatingPoint;
671 :
672 : // Note: returns failure on -0.0
673 : // Tests if double is in [0; UINT64_MAX] range
674 : // Take the sign also in the equation. That way we can compare in one test?
675 : uint32_t EXPONENT_MASK = 0xfff00000;
676 : uint32_t EXPONENT_SHIFT = FloatingPoint<double>::kExponentShift - 32;
677 : uint32_t TOO_BIG_EXPONENT = (FloatingPoint<double>::kExponentBias + 64) << EXPONENT_SHIFT;
678 :
679 : load32(Address(src.base, src.offset + sizeof(int32_t)), temp);
680 : and32(Imm32(EXPONENT_MASK), temp);
681 : branch32(Assembler::AboveOrEqual, temp, Imm32(TOO_BIG_EXPONENT), fail);
682 : }
683 :
684 : void
685 : MacroAssembler::branchFloat32NotInInt64Range(Address src, Register temp, Label* fail)
686 : {
687 : using mozilla::FloatingPoint;
688 :
689 : // Tests if float is in [INT64_MIN; INT64_MAX] range
690 : uint32_t EXPONENT_MASK = 0x7f800000;
691 : uint32_t EXPONENT_SHIFT = FloatingPoint<float>::kExponentShift;
692 : uint32_t TOO_BIG_EXPONENT = (FloatingPoint<float>::kExponentBias + 63) << EXPONENT_SHIFT;
693 :
694 : load32(src, temp);
695 : and32(Imm32(EXPONENT_MASK), temp);
696 : branch32(Assembler::GreaterThanOrEqual, temp, Imm32(TOO_BIG_EXPONENT), fail);
697 : }
698 :
699 : void
700 : MacroAssembler::branchFloat32NotInUInt64Range(Address src, Register temp, Label* fail)
701 : {
702 : using mozilla::FloatingPoint;
703 :
704 : // Note: returns failure on -0.0
705 : // Tests if float is in [0; UINT64_MAX] range
706 : // Take the sign also in the equation. That way we can compare in one test?
707 : uint32_t EXPONENT_MASK = 0xff800000;
708 : uint32_t EXPONENT_SHIFT = FloatingPoint<float>::kExponentShift;
709 : uint32_t TOO_BIG_EXPONENT = (FloatingPoint<float>::kExponentBias + 64) << EXPONENT_SHIFT;
710 :
711 : load32(src, temp);
712 : and32(Imm32(EXPONENT_MASK), temp);
713 : branch32(Assembler::AboveOrEqual, temp, Imm32(TOO_BIG_EXPONENT), fail);
714 : }
715 :
716 : // ========================================================================
717 : // Canonicalization primitives.
718 : void
719 0 : MacroAssembler::canonicalizeFloat(FloatRegister reg)
720 : {
721 0 : Label notNaN;
722 0 : branchFloat(DoubleOrdered, reg, reg, ¬NaN);
723 0 : loadConstantFloat32(float(JS::GenericNaN()), reg);
724 0 : bind(¬NaN);
725 0 : }
726 :
727 : void
728 : MacroAssembler::canonicalizeFloatIfDeterministic(FloatRegister reg)
729 : {
730 : #ifdef JS_MORE_DETERMINISTIC
731 : // See the comment in TypedArrayObjectTemplate::getIndexValue.
732 : canonicalizeFloat(reg);
733 : #endif // JS_MORE_DETERMINISTIC
734 : }
735 :
736 : void
737 0 : MacroAssembler::canonicalizeDouble(FloatRegister reg)
738 : {
739 0 : Label notNaN;
740 0 : branchDouble(DoubleOrdered, reg, reg, ¬NaN);
741 0 : loadConstantDouble(JS::GenericNaN(), reg);
742 0 : bind(¬NaN);
743 0 : }
744 :
745 : void
746 : MacroAssembler::canonicalizeDoubleIfDeterministic(FloatRegister reg)
747 : {
748 : #ifdef JS_MORE_DETERMINISTIC
749 : // See the comment in TypedArrayObjectTemplate::getIndexValue.
750 : canonicalizeDouble(reg);
751 : #endif // JS_MORE_DETERMINISTIC
752 : }
753 :
754 : // ========================================================================
755 : // Memory access primitives.
756 : template<class T> void
757 0 : MacroAssembler::storeDouble(FloatRegister src, const T& dest)
758 : {
759 218 : canonicalizeDoubleIfDeterministic(src);
760 0 : storeUncanonicalizedDouble(src, dest);
761 0 : }
762 :
763 : template void MacroAssembler::storeDouble(FloatRegister src, const Address& dest);
764 : template void MacroAssembler::storeDouble(FloatRegister src, const BaseIndex& dest);
765 :
766 : void
767 : MacroAssembler::boxDouble(FloatRegister src, const Address& dest)
768 : {
769 0 : storeDouble(src, dest);
770 : }
771 :
772 : template<class T> void
773 0 : MacroAssembler::storeFloat32(FloatRegister src, const T& dest)
774 : {
775 0 : canonicalizeFloatIfDeterministic(src);
776 0 : storeUncanonicalizedFloat32(src, dest);
777 0 : }
778 :
779 : template void MacroAssembler::storeFloat32(FloatRegister src, const Address& dest);
780 : template void MacroAssembler::storeFloat32(FloatRegister src, const BaseIndex& dest);
781 :
782 : //}}} check_macroassembler_style
783 : // ===============================================================
784 :
785 : #ifndef JS_CODEGEN_ARM64
786 :
787 : template <typename T>
788 : void
789 0 : MacroAssembler::branchTestStackPtr(Condition cond, T t, Label* label)
790 : {
791 51276 : branchTestPtr(cond, getStackPointer(), t, label);
792 25638 : }
793 :
794 : template <typename T>
795 : void
796 : MacroAssembler::branchStackPtr(Condition cond, T rhs, Label* label)
797 : {
798 12 : branchPtr(cond, getStackPointer(), rhs, label);
799 : }
800 :
801 : template <typename T>
802 : void
803 : MacroAssembler::branchStackPtrRhs(Condition cond, T lhs, Label* label)
804 : {
805 193 : branchPtr(cond, lhs, getStackPointer(), label);
806 : }
807 :
808 : template <typename T> void
809 : MacroAssembler::addToStackPtr(T t)
810 : {
811 62477 : addPtr(t, getStackPointer());
812 : }
813 :
814 : template <typename T> void
815 : MacroAssembler::addStackPtrTo(T t)
816 : {
817 6 : addPtr(getStackPointer(), t);
818 : }
819 :
820 : void
821 : MacroAssembler::reserveStack(uint32_t amount)
822 : {
823 0 : subFromStackPtr(Imm32(amount));
824 0 : adjustFrame(amount);
825 : }
826 : #endif // !JS_CODEGEN_ARM64
827 :
828 : template <typename EmitPreBarrier>
829 : void
830 3 : MacroAssembler::storeObjGroup(Register group, Register obj, EmitPreBarrier emitPreBarrier)
831 : {
832 3 : MOZ_ASSERT(group != obj);
833 0 : Address groupAddr(obj, JSObject::offsetOfGroup());
834 0 : emitPreBarrier(*this, groupAddr);
835 0 : storePtr(group, groupAddr);
836 0 : }
837 :
838 : template <typename EmitPreBarrier>
839 : void
840 0 : MacroAssembler::storeObjGroup(ObjectGroup* group, Register obj, EmitPreBarrier emitPreBarrier)
841 : {
842 0 : Address groupAddr(obj, JSObject::offsetOfGroup());
843 0 : emitPreBarrier(*this, groupAddr);
844 0 : storePtr(ImmGCPtr(group), groupAddr);
845 0 : }
846 :
847 : template <typename EmitPreBarrier>
848 : void
849 43 : MacroAssembler::storeObjShape(Register shape, Register obj, EmitPreBarrier emitPreBarrier)
850 : {
851 43 : MOZ_ASSERT(shape != obj);
852 0 : Address shapeAddr(obj, ShapedObject::offsetOfShape());
853 0 : emitPreBarrier(*this, shapeAddr);
854 0 : storePtr(shape, shapeAddr);
855 0 : }
856 :
857 : template <typename EmitPreBarrier>
858 : void
859 0 : MacroAssembler::storeObjShape(Shape* shape, Register obj, EmitPreBarrier emitPreBarrier)
860 : {
861 0 : Address shapeAddr(obj, ShapedObject::offsetOfShape());
862 0 : emitPreBarrier(*this, shapeAddr);
863 0 : storePtr(ImmGCPtr(shape), shapeAddr);
864 0 : }
865 :
866 : template <typename T>
867 : void
868 0 : MacroAssembler::storeObjectOrNull(Register src, const T& dest)
869 : {
870 0 : Label notNull, done;
871 0 : branchTestPtr(Assembler::NonZero, src, src, ¬Null);
872 0 : storeValue(NullValue(), dest);
873 0 : jump(&done);
874 0 : bind(¬Null);
875 0 : storeValue(JSVAL_TYPE_OBJECT, src, dest);
876 0 : bind(&done);
877 0 : }
878 :
879 : void
880 1 : MacroAssembler::assertStackAlignment(uint32_t alignment, int32_t offset /* = 0 */)
881 : {
882 : #ifdef DEBUG
883 0 : Label ok, bad;
884 0 : MOZ_ASSERT(mozilla::IsPowerOfTwo(alignment));
885 :
886 : // Wrap around the offset to be a non-negative number.
887 0 : offset %= alignment;
888 25544 : if (offset < 0)
889 0 : offset += alignment;
890 :
891 : // Test if each bit from offset is set.
892 25544 : uint32_t off = offset;
893 0 : while (off) {
894 0 : uint32_t lowestBit = 1 << mozilla::CountTrailingZeroes32(off);
895 0 : branchTestStackPtr(Assembler::Zero, Imm32(lowestBit), &bad);
896 51 : off ^= lowestBit;
897 : }
898 :
899 : // Check that all remaining bits are zero.
900 0 : branchTestStackPtr(Assembler::Zero, Imm32((alignment - 1) ^ offset), &ok);
901 :
902 0 : bind(&bad);
903 0 : breakpoint();
904 25544 : bind(&ok);
905 : #endif
906 0 : }
907 :
908 : void
909 172 : MacroAssembler::storeCallBoolResult(Register reg)
910 : {
911 172 : if (reg != ReturnReg)
912 156 : mov(ReturnReg, reg);
913 : // C++ compilers like to only use the bottom byte for bools, but we
914 : // need to maintain the entire register.
915 172 : and32(Imm32(0xFF), reg);
916 0 : }
917 :
918 : void
919 : MacroAssembler::storeCallInt32Result(Register reg)
920 : {
921 : #if JS_BITS_PER_WORD == 32
922 : storeCallPointerResult(reg);
923 : #else
924 : // Ensure the upper 32 bits are cleared.
925 2 : move32(ReturnReg, reg);
926 : #endif
927 : }
928 :
929 : void
930 : MacroAssembler::storeCallResultValue(AnyRegister dest, JSValueType type)
931 : {
932 0 : unboxValue(JSReturnOperand, dest, type);
933 : }
934 :
935 : void
936 : MacroAssembler::storeCallResultValue(TypedOrValueRegister dest)
937 : {
938 : if (dest.hasValue())
939 : storeCallResultValue(dest.valueReg());
940 : else
941 : storeCallResultValue(dest.typedReg(), ValueTypeFromMIRType(dest.type()));
942 : }
943 :
944 : } // namespace jit
945 : } // namespace js
946 :
947 : #endif /* jit_MacroAssembler_inl_h */
|