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