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/. */
7 #include "jit/Lowering.h"
9 #include "mozilla/DebugOnly.h"
10 #include "mozilla/EndianUtils.h"
11 #include "mozilla/FloatingPoint.h"
12 #include "mozilla/MathAlgorithms.h"
14 #include <type_traits>
16 #include "jit/ABIArgGenerator.h"
17 #include "jit/IonGenericCallStub.h"
18 #include "jit/IonOptimizationLevels.h"
19 #include "jit/JitSpewer.h"
21 #include "jit/MacroAssembler.h"
23 #include "jit/MIRGraph.h"
24 #include "jit/SharedICRegisters.h"
25 #include "js/experimental/JitInfo.h" // JSJitInfo
26 #include "util/Memory.h"
27 #include "wasm/WasmCodegenTypes.h"
28 #include "wasm/WasmFeatures.h" // for wasm::ReportSimdAnalysis
29 #include "wasm/WasmInstanceData.h"
31 #include "jit/shared/Lowering-shared-inl.h"
32 #include "vm/BytecodeUtil-inl.h"
38 using mozilla::DebugOnly
;
40 LBoxAllocation
LIRGenerator::useBoxFixedAtStart(MDefinition
* mir
,
42 #if defined(JS_NUNBOX32)
43 return useBoxFixed(mir
, op
.typeReg(), op
.payloadReg(), true);
44 #elif defined(JS_PUNBOX64)
45 return useBoxFixed(mir
, op
.valueReg(), op
.scratchReg(), true);
49 LBoxAllocation
LIRGenerator::useBoxAtStart(MDefinition
* mir
,
50 LUse::Policy policy
) {
51 return useBox(mir
, policy
, /* useAtStart = */ true);
54 void LIRGenerator::visitParameter(MParameter
* param
) {
56 if (param
->index() == MParameter::THIS_SLOT
) {
57 offset
= THIS_FRAME_ARGSLOT
;
59 offset
= 1 + param
->index();
62 LParameter
* ins
= new (alloc()) LParameter
;
63 defineBox(ins
, param
, LDefinition::FIXED
);
65 offset
*= sizeof(Value
);
66 #if defined(JS_NUNBOX32)
68 ins
->getDef(0)->setOutput(LArgument(offset
));
69 ins
->getDef(1)->setOutput(LArgument(offset
+ 4));
71 ins
->getDef(0)->setOutput(LArgument(offset
+ 4));
72 ins
->getDef(1)->setOutput(LArgument(offset
));
74 #elif defined(JS_PUNBOX64)
75 ins
->getDef(0)->setOutput(LArgument(offset
));
79 void LIRGenerator::visitCallee(MCallee
* ins
) {
80 define(new (alloc()) LCallee(), ins
);
83 void LIRGenerator::visitIsConstructing(MIsConstructing
* ins
) {
84 define(new (alloc()) LIsConstructing(), ins
);
87 void LIRGenerator::visitGoto(MGoto
* ins
) {
88 add(new (alloc()) LGoto(ins
->target()));
91 void LIRGenerator::visitTableSwitch(MTableSwitch
* tableswitch
) {
92 MDefinition
* opd
= tableswitch
->getOperand(0);
94 // There should be at least 1 successor. The default case!
95 MOZ_ASSERT(tableswitch
->numSuccessors() > 0);
97 // If there are no cases, the default case is always taken.
98 if (tableswitch
->numSuccessors() == 1) {
99 add(new (alloc()) LGoto(tableswitch
->getDefault()));
103 // If we don't know the type.
104 if (opd
->type() == MIRType::Value
) {
105 LTableSwitchV
* lir
= newLTableSwitchV(tableswitch
);
110 // Case indices are numeric, so other types will always go to the default
112 if (opd
->type() != MIRType::Int32
&& opd
->type() != MIRType::Double
) {
113 add(new (alloc()) LGoto(tableswitch
->getDefault()));
117 // Return an LTableSwitch, capable of handling either an integer or
118 // floating-point index.
121 if (opd
->type() == MIRType::Int32
) {
122 index
= useRegisterAtStart(opd
);
123 tempInt
= tempCopy(opd
, 0);
125 index
= useRegister(opd
);
126 tempInt
= temp(LDefinition::GENERAL
);
128 add(newLTableSwitch(index
, tempInt
, tableswitch
));
131 void LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed
* ins
) {
132 LCheckOverRecursed
* lir
= new (alloc()) LCheckOverRecursed();
134 assignSafepoint(lir
, ins
);
137 void LIRGenerator::visitNewArray(MNewArray
* ins
) {
138 LNewArray
* lir
= new (alloc()) LNewArray(temp());
140 assignSafepoint(lir
, ins
);
143 void LIRGenerator::visitNewArrayDynamicLength(MNewArrayDynamicLength
* ins
) {
144 MDefinition
* length
= ins
->length();
145 MOZ_ASSERT(length
->type() == MIRType::Int32
);
147 LNewArrayDynamicLength
* lir
=
148 new (alloc()) LNewArrayDynamicLength(useRegister(length
), temp());
150 assignSafepoint(lir
, ins
);
153 void LIRGenerator::visitNewIterator(MNewIterator
* ins
) {
154 LNewIterator
* lir
= new (alloc()) LNewIterator(temp());
156 assignSafepoint(lir
, ins
);
159 void LIRGenerator::visitNewTypedArray(MNewTypedArray
* ins
) {
160 LNewTypedArray
* lir
= new (alloc()) LNewTypedArray(temp(), temp());
162 assignSafepoint(lir
, ins
);
165 void LIRGenerator::visitNewTypedArrayDynamicLength(
166 MNewTypedArrayDynamicLength
* ins
) {
167 MDefinition
* length
= ins
->length();
168 MOZ_ASSERT(length
->type() == MIRType::Int32
);
170 LNewTypedArrayDynamicLength
* lir
=
171 new (alloc()) LNewTypedArrayDynamicLength(useRegister(length
), temp());
173 assignSafepoint(lir
, ins
);
176 void LIRGenerator::visitNewTypedArrayFromArray(MNewTypedArrayFromArray
* ins
) {
177 MDefinition
* array
= ins
->array();
178 MOZ_ASSERT(array
->type() == MIRType::Object
);
180 auto* lir
= new (alloc()) LNewTypedArrayFromArray(useRegisterAtStart(array
));
181 defineReturn(lir
, ins
);
182 assignSafepoint(lir
, ins
);
185 void LIRGenerator::visitNewTypedArrayFromArrayBuffer(
186 MNewTypedArrayFromArrayBuffer
* ins
) {
187 MDefinition
* arrayBuffer
= ins
->arrayBuffer();
188 MDefinition
* byteOffset
= ins
->byteOffset();
189 MDefinition
* length
= ins
->length();
190 MOZ_ASSERT(arrayBuffer
->type() == MIRType::Object
);
191 MOZ_ASSERT(byteOffset
->type() == MIRType::Value
);
192 MOZ_ASSERT(length
->type() == MIRType::Value
);
194 auto* lir
= new (alloc()) LNewTypedArrayFromArrayBuffer(
195 useRegisterAtStart(arrayBuffer
), useBoxAtStart(byteOffset
),
196 useBoxAtStart(length
));
197 defineReturn(lir
, ins
);
198 assignSafepoint(lir
, ins
);
201 void LIRGenerator::visitNewObject(MNewObject
* ins
) {
202 LNewObject
* lir
= new (alloc()) LNewObject(temp());
204 assignSafepoint(lir
, ins
);
207 void LIRGenerator::visitBindFunction(MBindFunction
* ins
) {
208 MDefinition
* target
= ins
->target();
209 MOZ_ASSERT(target
->type() == MIRType::Object
);
211 if (!lowerCallArguments(ins
)) {
212 abort(AbortReason::Alloc
, "OOM: LIRGenerator::visitBindFunction");
216 auto* lir
= new (alloc())
217 LBindFunction(useFixedAtStart(target
, CallTempReg0
),
218 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
219 defineReturn(lir
, ins
);
220 assignSafepoint(lir
, ins
);
223 void LIRGenerator::visitNewBoundFunction(MNewBoundFunction
* ins
) {
224 auto* lir
= new (alloc()) LNewBoundFunction(temp());
226 assignSafepoint(lir
, ins
);
229 void LIRGenerator::visitNewPlainObject(MNewPlainObject
* ins
) {
230 LNewPlainObject
* lir
= new (alloc()) LNewPlainObject(temp(), temp(), temp());
232 assignSafepoint(lir
, ins
);
235 void LIRGenerator::visitNewArrayObject(MNewArrayObject
* ins
) {
236 LNewArrayObject
* lir
= new (alloc()) LNewArrayObject(temp(), temp());
238 assignSafepoint(lir
, ins
);
241 void LIRGenerator::visitNewNamedLambdaObject(MNewNamedLambdaObject
* ins
) {
242 LNewNamedLambdaObject
* lir
= new (alloc()) LNewNamedLambdaObject(temp());
244 assignSafepoint(lir
, ins
);
247 void LIRGenerator::visitNewCallObject(MNewCallObject
* ins
) {
248 LNewCallObject
* lir
= new (alloc()) LNewCallObject(temp());
250 assignSafepoint(lir
, ins
);
253 void LIRGenerator::visitNewStringObject(MNewStringObject
* ins
) {
254 MOZ_ASSERT(ins
->input()->type() == MIRType::String
);
256 LNewStringObject
* lir
=
257 new (alloc()) LNewStringObject(useRegister(ins
->input()), temp());
259 assignSafepoint(lir
, ins
);
262 void LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter
* ins
) {
263 LInitElemGetterSetter
* lir
= new (alloc()) LInitElemGetterSetter(
264 useRegisterAtStart(ins
->object()), useBoxAtStart(ins
->id()),
265 useRegisterAtStart(ins
->value()));
267 assignSafepoint(lir
, ins
);
270 void LIRGenerator::visitMutateProto(MMutateProto
* ins
) {
271 LMutateProto
* lir
= new (alloc()) LMutateProto(
272 useRegisterAtStart(ins
->object()), useBoxAtStart(ins
->value()));
274 assignSafepoint(lir
, ins
);
277 void LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter
* ins
) {
278 LInitPropGetterSetter
* lir
= new (alloc()) LInitPropGetterSetter(
279 useRegisterAtStart(ins
->object()), useRegisterAtStart(ins
->value()));
281 assignSafepoint(lir
, ins
);
284 void LIRGenerator::visitCreateThis(MCreateThis
* ins
) {
286 new (alloc()) LCreateThis(useRegisterOrConstantAtStart(ins
->callee()),
287 useRegisterOrConstantAtStart(ins
->newTarget()));
288 defineReturn(lir
, ins
);
289 assignSafepoint(lir
, ins
);
292 void LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject
* ins
) {
293 LAllocation callObj
= useRegisterAtStart(ins
->getCallObject());
294 LCreateArgumentsObject
* lir
= new (alloc())
295 LCreateArgumentsObject(callObj
, tempFixed(CallTempReg0
),
296 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
297 defineReturn(lir
, ins
);
298 assignSafepoint(lir
, ins
);
301 void LIRGenerator::visitCreateInlinedArgumentsObject(
302 MCreateInlinedArgumentsObject
* ins
) {
303 LAllocation callObj
= useRegisterAtStart(ins
->getCallObject());
304 LAllocation callee
= useRegisterAtStart(ins
->getCallee());
305 uint32_t numActuals
= ins
->numActuals();
306 uint32_t numOperands
= numActuals
* BOX_PIECES
+
307 LCreateInlinedArgumentsObject::NumNonArgumentOperands
;
309 auto* lir
= allocateVariadic
<LCreateInlinedArgumentsObject
>(
310 numOperands
, tempFixed(CallTempReg0
), tempFixed(CallTempReg1
));
312 abort(AbortReason::Alloc
,
313 "OOM: LIRGenerator::visitCreateInlinedArgumentsObject");
317 lir
->setOperand(LCreateInlinedArgumentsObject::CallObj
, callObj
);
318 lir
->setOperand(LCreateInlinedArgumentsObject::Callee
, callee
);
319 for (uint32_t i
= 0; i
< numActuals
; i
++) {
320 MDefinition
* arg
= ins
->getArg(i
);
321 uint32_t index
= LCreateInlinedArgumentsObject::ArgIndex(i
);
322 lir
->setBoxOperand(index
, useBoxOrTypedOrConstant(arg
,
323 /*useConstant = */ true,
324 /*useAtStart = */ true));
327 defineReturn(lir
, ins
);
328 assignSafepoint(lir
, ins
);
331 void LIRGenerator::visitGetInlinedArgument(MGetInlinedArgument
* ins
) {
332 #if defined(JS_PUNBOX64)
333 // On 64-bit architectures, we don't support boxing a typed register
334 // in-place without using a scratch register, so the result register
335 // can't be the same as any of the inputs. Fortunately, those
336 // architectures have registers to spare.
337 const bool useAtStart
= false;
339 const bool useAtStart
= true;
343 useAtStart
? useRegisterAtStart(ins
->index()) : useRegister(ins
->index());
344 uint32_t numActuals
= ins
->numActuals();
345 uint32_t numOperands
=
346 numActuals
* BOX_PIECES
+ LGetInlinedArgument::NumNonArgumentOperands
;
348 auto* lir
= allocateVariadic
<LGetInlinedArgument
>(numOperands
);
350 abort(AbortReason::Alloc
, "OOM: LIRGenerator::visitGetInlinedArgument");
354 lir
->setOperand(LGetInlinedArgument::Index
, index
);
355 for (uint32_t i
= 0; i
< numActuals
; i
++) {
356 MDefinition
* arg
= ins
->getArg(i
);
357 uint32_t index
= LGetInlinedArgument::ArgIndex(i
);
359 index
, useBoxOrTypedOrConstant(arg
,
360 /*useConstant = */ true, useAtStart
));
365 void LIRGenerator::visitGetInlinedArgumentHole(MGetInlinedArgumentHole
* ins
) {
366 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_MIPS64)
367 // On some 64-bit architectures, we don't support boxing a typed
368 // register in-place without using a scratch register, so the result
369 // register can't be the same as any of the inputs. Fortunately,
370 // those architectures have registers to spare.
371 const bool useAtStart
= false;
373 const bool useAtStart
= true;
377 useAtStart
? useRegisterAtStart(ins
->index()) : useRegister(ins
->index());
378 uint32_t numActuals
= ins
->numActuals();
379 uint32_t numOperands
=
380 numActuals
* BOX_PIECES
+ LGetInlinedArgumentHole::NumNonArgumentOperands
;
382 auto* lir
= allocateVariadic
<LGetInlinedArgumentHole
>(numOperands
);
384 abort(AbortReason::Alloc
, "OOM: LIRGenerator::visitGetInlinedArgumentHole");
388 lir
->setOperand(LGetInlinedArgumentHole::Index
, index
);
389 for (uint32_t i
= 0; i
< numActuals
; i
++) {
390 MDefinition
* arg
= ins
->getArg(i
);
391 uint32_t index
= LGetInlinedArgumentHole::ArgIndex(i
);
393 index
, useBoxOrTypedOrConstant(arg
,
394 /*useConstant = */ true, useAtStart
));
396 assignSnapshot(lir
, ins
->bailoutKind());
400 void LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg
* ins
) {
401 LAllocation argsObj
= useRegister(ins
->argsObject());
402 LGetArgumentsObjectArg
* lir
=
403 new (alloc()) LGetArgumentsObjectArg(argsObj
, temp());
407 void LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg
* ins
) {
408 LAllocation argsObj
= useRegister(ins
->argsObject());
409 LSetArgumentsObjectArg
* lir
= new (alloc())
410 LSetArgumentsObjectArg(argsObj
, useBox(ins
->value()), temp());
414 void LIRGenerator::visitLoadArgumentsObjectArg(MLoadArgumentsObjectArg
* ins
) {
415 MDefinition
* argsObj
= ins
->argsObject();
416 MOZ_ASSERT(argsObj
->type() == MIRType::Object
);
418 MDefinition
* index
= ins
->index();
419 MOZ_ASSERT(index
->type() == MIRType::Int32
);
421 auto* lir
= new (alloc())
422 LLoadArgumentsObjectArg(useRegister(argsObj
), useRegister(index
), temp());
423 assignSnapshot(lir
, ins
->bailoutKind());
427 void LIRGenerator::visitLoadArgumentsObjectArgHole(
428 MLoadArgumentsObjectArgHole
* ins
) {
429 MDefinition
* argsObj
= ins
->argsObject();
430 MOZ_ASSERT(argsObj
->type() == MIRType::Object
);
432 MDefinition
* index
= ins
->index();
433 MOZ_ASSERT(index
->type() == MIRType::Int32
);
435 auto* lir
= new (alloc()) LLoadArgumentsObjectArgHole(
436 useRegister(argsObj
), useRegister(index
), temp());
437 assignSnapshot(lir
, ins
->bailoutKind());
441 void LIRGenerator::visitInArgumentsObjectArg(MInArgumentsObjectArg
* ins
) {
442 MDefinition
* argsObj
= ins
->argsObject();
443 MOZ_ASSERT(argsObj
->type() == MIRType::Object
);
445 MDefinition
* index
= ins
->index();
446 MOZ_ASSERT(index
->type() == MIRType::Int32
);
448 auto* lir
= new (alloc())
449 LInArgumentsObjectArg(useRegister(argsObj
), useRegister(index
), temp());
450 assignSnapshot(lir
, ins
->bailoutKind());
454 void LIRGenerator::visitArgumentsObjectLength(MArgumentsObjectLength
* ins
) {
455 MDefinition
* argsObj
= ins
->argsObject();
456 MOZ_ASSERT(argsObj
->type() == MIRType::Object
);
458 auto* lir
= new (alloc()) LArgumentsObjectLength(useRegister(argsObj
));
459 assignSnapshot(lir
, ins
->bailoutKind());
463 void LIRGenerator::visitArrayFromArgumentsObject(
464 MArrayFromArgumentsObject
* ins
) {
465 MDefinition
* argsObj
= ins
->argsObject();
466 MOZ_ASSERT(argsObj
->type() == MIRType::Object
);
469 new (alloc()) LArrayFromArgumentsObject(useRegisterAtStart(argsObj
));
470 defineReturn(lir
, ins
);
471 assignSafepoint(lir
, ins
);
474 void LIRGenerator::visitGuardArgumentsObjectFlags(
475 MGuardArgumentsObjectFlags
* ins
) {
476 MDefinition
* argsObj
= ins
->argsObject();
477 MOZ_ASSERT(argsObj
->type() == MIRType::Object
);
480 new (alloc()) LGuardArgumentsObjectFlags(useRegister(argsObj
), temp());
481 assignSnapshot(lir
, ins
->bailoutKind());
483 redefine(ins
, argsObj
);
486 void LIRGenerator::visitBoundFunctionNumArgs(MBoundFunctionNumArgs
* ins
) {
487 MDefinition
* obj
= ins
->object();
488 MOZ_ASSERT(obj
->type() == MIRType::Object
);
490 auto* lir
= new (alloc()) LBoundFunctionNumArgs(useRegisterAtStart(obj
));
494 void LIRGenerator::visitGuardBoundFunctionIsConstructor(
495 MGuardBoundFunctionIsConstructor
* ins
) {
496 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
498 auto* lir
= new (alloc())
499 LGuardBoundFunctionIsConstructor(useRegister(ins
->object()));
500 assignSnapshot(lir
, ins
->bailoutKind());
502 redefine(ins
, ins
->object());
505 void LIRGenerator::visitReturnFromCtor(MReturnFromCtor
* ins
) {
506 LReturnFromCtor
* lir
= new (alloc())
507 LReturnFromCtor(useBox(ins
->value()), useRegister(ins
->object()));
511 void LIRGenerator::visitBoxNonStrictThis(MBoxNonStrictThis
* ins
) {
512 MOZ_ASSERT(ins
->type() == MIRType::Object
);
513 MOZ_ASSERT(ins
->input()->type() == MIRType::Value
);
515 auto* lir
= new (alloc()) LBoxNonStrictThis(useBox(ins
->input()));
517 assignSafepoint(lir
, ins
);
520 void LIRGenerator::visitImplicitThis(MImplicitThis
* ins
) {
521 MDefinition
* env
= ins
->envChain();
522 MOZ_ASSERT(env
->type() == MIRType::Object
);
524 LImplicitThis
* lir
= new (alloc()) LImplicitThis(useRegisterAtStart(env
));
525 defineReturn(lir
, ins
);
526 assignSafepoint(lir
, ins
);
529 template <typename T
>
530 bool LIRGenerator::lowerCallArguments(T
* call
) {
531 uint32_t argc
= call
->numStackArgs();
533 // Align the arguments of a call such that the callee would keep the same
534 // alignment as the caller.
535 uint32_t baseSlot
= 0;
536 if (JitStackValueAlignment
> 1) {
537 baseSlot
= AlignBytes(argc
, JitStackValueAlignment
);
542 // Save the maximum number of argument, such that we can have one unique
544 if (baseSlot
> maxargslots_
) {
545 maxargslots_
= baseSlot
;
548 for (size_t i
= 0; i
< argc
; i
++) {
549 MDefinition
* arg
= call
->getArg(i
);
550 uint32_t argslot
= baseSlot
- i
;
552 // Values take a slow path.
553 if (arg
->type() == MIRType::Value
) {
554 LStackArgV
* stack
= new (alloc()) LStackArgV(useBox(arg
), argslot
);
557 // Known types can move constant types and/or payloads.
558 LStackArgT
* stack
= new (alloc())
559 LStackArgT(useRegisterOrConstant(arg
), argslot
, arg
->type());
563 if (!alloc().ensureBallast()) {
570 void LIRGenerator::visitCall(MCall
* call
) {
571 MOZ_ASSERT(call
->getCallee()->type() == MIRType::Object
);
573 // In case of oom, skip the rest of the allocations.
574 if (!lowerCallArguments(call
)) {
575 abort(AbortReason::Alloc
, "OOM: LIRGenerator::visitCall");
579 WrappedFunction
* target
= call
->getSingleTarget();
583 if (call
->isCallDOMNative()) {
584 // Call DOM functions.
585 MOZ_ASSERT(target
&& target
->isNativeWithoutJitEntry());
586 Register cxReg
, objReg
, privReg
, argsReg
;
587 GetTempRegForIntArg(0, 0, &cxReg
);
588 GetTempRegForIntArg(1, 0, &objReg
);
589 GetTempRegForIntArg(2, 0, &privReg
);
590 mozilla::DebugOnly
<bool> ok
= GetTempRegForIntArg(3, 0, &argsReg
);
591 MOZ_ASSERT(ok
, "How can we not have four temp registers?");
592 lir
= new (alloc()) LCallDOMNative(tempFixed(cxReg
), tempFixed(objReg
),
593 tempFixed(privReg
), tempFixed(argsReg
));
595 // Call known functions.
596 if (target
->isNativeWithoutJitEntry()) {
597 Register cxReg
, numReg
, vpReg
, tmpReg
;
598 GetTempRegForIntArg(0, 0, &cxReg
);
599 GetTempRegForIntArg(1, 0, &numReg
);
600 GetTempRegForIntArg(2, 0, &vpReg
);
602 // Even though this is just a temp reg, use the same API to avoid
603 // register collisions.
604 mozilla::DebugOnly
<bool> ok
= GetTempRegForIntArg(3, 0, &tmpReg
);
605 MOZ_ASSERT(ok
, "How can we not have four temp registers?");
607 lir
= new (alloc()) LCallNative(tempFixed(cxReg
), tempFixed(numReg
),
608 tempFixed(vpReg
), tempFixed(tmpReg
));
610 lir
= new (alloc()) LCallKnown(useRegisterAtStart(call
->getCallee()),
611 tempFixed(CallTempReg0
));
614 // Call anything, using the most generic code.
615 lir
= new (alloc()) LCallGeneric(
616 useFixedAtStart(call
->getCallee(), IonGenericCallCalleeReg
),
617 tempFixed(IonGenericCallArgcReg
));
619 defineReturn(lir
, call
);
620 assignSafepoint(lir
, call
);
623 void LIRGenerator::visitCallClassHook(MCallClassHook
* call
) {
624 MDefinition
* callee
= call
->getCallee();
625 MOZ_ASSERT(callee
->type() == MIRType::Object
);
627 // In case of oom, skip the rest of the allocations.
628 if (!lowerCallArguments(call
)) {
629 abort(AbortReason::Alloc
, "OOM: LIRGenerator::visitCallClassHook");
633 Register cxReg
, numReg
, vpReg
, tmpReg
;
634 GetTempRegForIntArg(0, 0, &cxReg
);
635 GetTempRegForIntArg(1, 0, &numReg
);
636 GetTempRegForIntArg(2, 0, &vpReg
);
638 // Even though this is just a temp reg, use the same API to avoid
639 // register collisions.
640 mozilla::DebugOnly
<bool> ok
= GetTempRegForIntArg(3, 0, &tmpReg
);
641 MOZ_ASSERT(ok
, "How can we not have four temp registers?");
643 auto* lir
= new (alloc())
644 LCallClassHook(useRegisterAtStart(callee
), tempFixed(cxReg
),
645 tempFixed(numReg
), tempFixed(vpReg
), tempFixed(tmpReg
));
646 defineReturn(lir
, call
);
647 assignSafepoint(lir
, call
);
650 void LIRGenerator::visitApplyArgs(MApplyArgs
* apply
) {
651 MOZ_ASSERT(apply
->getFunction()->type() == MIRType::Object
);
653 // Assert if the return value is already erased.
654 static_assert(CallTempReg2
!= JSReturnReg_Type
);
655 static_assert(CallTempReg2
!= JSReturnReg_Data
);
657 LApplyArgsGeneric
* lir
= new (alloc()) LApplyArgsGeneric(
658 useFixedAtStart(apply
->getFunction(), CallTempReg3
),
659 useFixedAtStart(apply
->getArgc(), CallTempReg0
),
660 useBoxFixedAtStart(apply
->getThis(), CallTempReg4
, CallTempReg5
),
661 tempFixed(CallTempReg1
), // object register
662 tempFixed(CallTempReg2
)); // stack counter register
664 // Bailout is needed in the case of too many values in the arguments array.
665 assignSnapshot(lir
, apply
->bailoutKind());
667 defineReturn(lir
, apply
);
668 assignSafepoint(lir
, apply
);
671 void LIRGenerator::visitApplyArgsObj(MApplyArgsObj
* apply
) {
672 MOZ_ASSERT(apply
->getFunction()->type() == MIRType::Object
);
674 // Assert if the return value is already erased.
675 static_assert(CallTempReg2
!= JSReturnReg_Type
);
676 static_assert(CallTempReg2
!= JSReturnReg_Data
);
678 LApplyArgsObj
* lir
= new (alloc()) LApplyArgsObj(
679 useFixedAtStart(apply
->getFunction(), CallTempReg3
),
680 useFixedAtStart(apply
->getArgsObj(), CallTempReg0
),
681 useBoxFixedAtStart(apply
->getThis(), CallTempReg4
, CallTempReg5
),
682 tempFixed(CallTempReg1
), // object register
683 tempFixed(CallTempReg2
)); // stack counter register
685 // Bailout is needed in the case of too many values in the arguments array.
686 assignSnapshot(lir
, apply
->bailoutKind());
688 defineReturn(lir
, apply
);
689 assignSafepoint(lir
, apply
);
692 void LIRGenerator::visitApplyArray(MApplyArray
* apply
) {
693 MOZ_ASSERT(apply
->getFunction()->type() == MIRType::Object
);
695 // Assert if the return value is already erased.
696 static_assert(CallTempReg2
!= JSReturnReg_Type
);
697 static_assert(CallTempReg2
!= JSReturnReg_Data
);
699 LApplyArrayGeneric
* lir
= new (alloc()) LApplyArrayGeneric(
700 useFixedAtStart(apply
->getFunction(), CallTempReg3
),
701 useFixedAtStart(apply
->getElements(), CallTempReg0
),
702 useBoxFixedAtStart(apply
->getThis(), CallTempReg4
, CallTempReg5
),
703 tempFixed(CallTempReg1
), // object register
704 tempFixed(CallTempReg2
)); // stack counter register
706 // Bailout is needed in the case of too many values in the array, or empty
707 // space at the end of the array.
708 assignSnapshot(lir
, apply
->bailoutKind());
710 defineReturn(lir
, apply
);
711 assignSafepoint(lir
, apply
);
714 void LIRGenerator::visitConstructArgs(MConstructArgs
* mir
) {
715 MOZ_ASSERT(mir
->getFunction()->type() == MIRType::Object
);
716 MOZ_ASSERT(mir
->getArgc()->type() == MIRType::Int32
);
717 MOZ_ASSERT(mir
->getNewTarget()->type() == MIRType::Object
);
718 MOZ_ASSERT(mir
->getThis()->type() == MIRType::Value
);
720 // Assert if the return value is already erased.
721 static_assert(CallTempReg2
!= JSReturnReg_Type
);
722 static_assert(CallTempReg2
!= JSReturnReg_Data
);
724 auto* lir
= new (alloc()) LConstructArgsGeneric(
725 useFixedAtStart(mir
->getFunction(), CallTempReg3
),
726 useFixedAtStart(mir
->getArgc(), CallTempReg0
),
727 useFixedAtStart(mir
->getNewTarget(), CallTempReg1
),
728 useBoxFixedAtStart(mir
->getThis(), CallTempReg4
, CallTempReg5
),
729 tempFixed(CallTempReg2
));
731 // Bailout is needed in the case of too many values in the arguments array.
732 assignSnapshot(lir
, mir
->bailoutKind());
734 defineReturn(lir
, mir
);
735 assignSafepoint(lir
, mir
);
738 void LIRGenerator::visitConstructArray(MConstructArray
* mir
) {
739 MOZ_ASSERT(mir
->getFunction()->type() == MIRType::Object
);
740 MOZ_ASSERT(mir
->getElements()->type() == MIRType::Elements
);
741 MOZ_ASSERT(mir
->getNewTarget()->type() == MIRType::Object
);
742 MOZ_ASSERT(mir
->getThis()->type() == MIRType::Value
);
744 // Assert if the return value is already erased.
745 static_assert(CallTempReg2
!= JSReturnReg_Type
);
746 static_assert(CallTempReg2
!= JSReturnReg_Data
);
748 auto* lir
= new (alloc()) LConstructArrayGeneric(
749 useFixedAtStart(mir
->getFunction(), CallTempReg3
),
750 useFixedAtStart(mir
->getElements(), CallTempReg0
),
751 useFixedAtStart(mir
->getNewTarget(), CallTempReg1
),
752 useBoxFixedAtStart(mir
->getThis(), CallTempReg4
, CallTempReg5
),
753 tempFixed(CallTempReg2
));
755 // Bailout is needed in the case of too many values in the array, or empty
756 // space at the end of the array.
757 assignSnapshot(lir
, mir
->bailoutKind());
759 defineReturn(lir
, mir
);
760 assignSafepoint(lir
, mir
);
763 void LIRGenerator::visitBail(MBail
* bail
) {
764 LBail
* lir
= new (alloc()) LBail();
765 assignSnapshot(lir
, bail
->bailoutKind());
769 void LIRGenerator::visitUnreachable(MUnreachable
* unreachable
) {
770 LUnreachable
* lir
= new (alloc()) LUnreachable();
771 add(lir
, unreachable
);
774 void LIRGenerator::visitEncodeSnapshot(MEncodeSnapshot
* mir
) {
775 LEncodeSnapshot
* lir
= new (alloc()) LEncodeSnapshot();
776 assignSnapshot(lir
, mir
->bailoutKind());
780 void LIRGenerator::visitUnreachableResult(MUnreachableResult
* mir
) {
781 if (mir
->type() == MIRType::Value
) {
782 auto* lir
= new (alloc()) LUnreachableResultV();
785 auto* lir
= new (alloc()) LUnreachableResultT();
790 void LIRGenerator::visitAssertFloat32(MAssertFloat32
* assertion
) {
791 MIRType type
= assertion
->input()->type();
792 DebugOnly
<bool> checkIsFloat32
= assertion
->mustBeFloat32();
794 if (type
!= MIRType::Value
&& !JitOptions
.eagerIonCompilation()) {
795 MOZ_ASSERT_IF(checkIsFloat32
, type
== MIRType::Float32
);
796 MOZ_ASSERT_IF(!checkIsFloat32
, type
!= MIRType::Float32
);
800 void LIRGenerator::visitAssertRecoveredOnBailout(
801 MAssertRecoveredOnBailout
* assertion
) {
802 MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
805 [[nodiscard
]] static JSOp
ReorderComparison(JSOp op
, MDefinition
** lhsp
,
806 MDefinition
** rhsp
) {
807 MDefinition
* lhs
= *lhsp
;
808 MDefinition
* rhs
= *rhsp
;
810 if (lhs
->maybeConstantValue()) {
813 return ReverseCompareOp(op
);
818 void LIRGenerator::visitTest(MTest
* test
) {
819 MDefinition
* opd
= test
->getOperand(0);
820 MBasicBlock
* ifTrue
= test
->ifTrue();
821 MBasicBlock
* ifFalse
= test
->ifFalse();
823 // String is converted to length of string in the type analysis phase (see
825 MOZ_ASSERT(opd
->type() != MIRType::String
);
827 // Testing a constant.
828 if (MConstant
* constant
= opd
->maybeConstantValue()) {
830 if (constant
->valueToBoolean(&b
)) {
831 add(new (alloc()) LGoto(b
? ifTrue
: ifFalse
));
836 if (opd
->type() == MIRType::Value
) {
837 auto* lir
= new (alloc()) LTestVAndBranch(
838 ifTrue
, ifFalse
, useBox(opd
), tempDouble(), tempToUnbox(), temp());
843 // Objects are truthy, except if it might emulate undefined.
844 if (opd
->type() == MIRType::Object
) {
846 LTestOAndBranch(useRegister(opd
), ifTrue
, ifFalse
, temp()),
851 // These must be explicitly sniffed out since they are constants and have
853 if (opd
->type() == MIRType::Undefined
|| opd
->type() == MIRType::Null
) {
854 add(new (alloc()) LGoto(ifFalse
));
858 // All symbols are truthy.
859 if (opd
->type() == MIRType::Symbol
) {
860 add(new (alloc()) LGoto(ifTrue
));
864 // Try to match the pattern
867 // {EQ,NE} for {Int,UInt}{32,64},
868 // bitAnd={MBitAnd,MWasmBinaryBitwise(And{32,64})}(x, y),
872 // and produce a single LBitAndAndBranch node. This requires both `comp`
873 // and `bitAnd` to be marked emit-at-uses. Since we can't use
874 // LBitAndAndBranch to represent a 64-bit AND on a 32-bit target, the 64-bit
875 // case is restricted to 64-bit targets.
876 if (opd
->isCompare() && opd
->isEmittedAtUses()) {
878 constexpr bool targetIs64
= true;
880 constexpr bool targetIs64
= false;
882 MCompare
* comp
= opd
->toCompare();
883 Assembler::Condition compCond
=
884 JSOpToCondition(comp
->compareType(), comp
->jsop());
885 MDefinition
* compL
= comp
->getOperand(0);
886 MDefinition
* compR
= comp
->getOperand(1);
887 if ((comp
->compareType() == MCompare::Compare_Int32
||
888 comp
->compareType() == MCompare::Compare_UInt32
||
889 (targetIs64
&& comp
->compareType() == MCompare::Compare_Int64
) ||
890 (targetIs64
&& comp
->compareType() == MCompare::Compare_UInt64
)) &&
891 (compCond
== Assembler::Equal
|| compCond
== Assembler::NotEqual
) &&
892 compR
->isConstant() &&
893 (compR
->toConstant()->isInt32(0) ||
894 (targetIs64
&& compR
->toConstant()->isInt64(0))) &&
895 (compL
->isBitAnd() || (compL
->isWasmBinaryBitwise() &&
896 compL
->toWasmBinaryBitwise()->subOpcode() ==
897 MWasmBinaryBitwise::SubOpcode::And
))) {
898 // The MCompare is OK; now check its first operand (the and-ish node).
899 MDefinition
* bitAnd
= compL
;
900 MDefinition
* bitAndL
= bitAnd
->getOperand(0);
901 MDefinition
* bitAndR
= bitAnd
->getOperand(1);
902 MIRType bitAndLTy
= bitAndL
->type();
903 MIRType bitAndRTy
= bitAndR
->type();
904 if (bitAnd
->isEmittedAtUses() && bitAndLTy
== bitAndRTy
&&
905 (bitAndLTy
== MIRType::Int32
||
906 (targetIs64
&& bitAndLTy
== MIRType::Int64
))) {
907 // Pattern match succeeded.
908 ReorderCommutative(&bitAndL
, &bitAndR
, test
);
909 if (compCond
== Assembler::Equal
) {
910 compCond
= Assembler::Zero
;
911 } else if (compCond
== Assembler::NotEqual
) {
912 compCond
= Assembler::NonZero
;
914 MOZ_ASSERT_UNREACHABLE("inequality operators cannot be folded");
916 MOZ_ASSERT_IF(!targetIs64
, bitAndLTy
== MIRType::Int32
);
917 lowerForBitAndAndBranch(
918 new (alloc()) LBitAndAndBranch(
919 ifTrue
, ifFalse
, bitAndLTy
== MIRType::Int64
, compCond
),
920 test
, bitAndL
, bitAndR
);
926 // Check if the operand for this test is a compare operation. If it is, we
927 // want to emit an LCompare*AndBranch rather than an LTest*AndBranch, to fuse
928 // the compare and jump instructions.
929 if (opd
->isCompare() && opd
->isEmittedAtUses()) {
930 MCompare
* comp
= opd
->toCompare();
931 MDefinition
* left
= comp
->lhs();
932 MDefinition
* right
= comp
->rhs();
934 // Try to fold the comparison so that we don't have to handle all cases.
936 if (comp
->tryFold(&result
)) {
937 add(new (alloc()) LGoto(result
? ifTrue
: ifFalse
));
941 // Emit LCompare*AndBranch.
943 // Compare and branch null/undefined.
944 // The second operand has known null/undefined type,
945 // so just test the first operand.
946 if (comp
->compareType() == MCompare::Compare_Null
||
947 comp
->compareType() == MCompare::Compare_Undefined
) {
948 if (left
->type() == MIRType::Object
) {
949 auto* lir
= new (alloc()) LIsNullOrLikeUndefinedAndBranchT(
950 comp
, useRegister(left
), ifTrue
, ifFalse
, temp());
955 if (IsLooseEqualityOp(comp
->jsop())) {
956 auto* lir
= new (alloc()) LIsNullOrLikeUndefinedAndBranchV(
957 comp
, ifTrue
, ifFalse
, useBox(left
), temp(), tempToUnbox());
962 if (comp
->compareType() == MCompare::Compare_Null
) {
964 new (alloc()) LIsNullAndBranch(comp
, ifTrue
, ifFalse
, useBox(left
));
969 auto* lir
= new (alloc())
970 LIsUndefinedAndBranch(comp
, ifTrue
, ifFalse
, useBox(left
));
975 // Compare and branch Int32, Symbol, Object, or WasmAnyRef pointers.
976 if (comp
->isInt32Comparison() ||
977 comp
->compareType() == MCompare::Compare_UInt32
||
978 comp
->compareType() == MCompare::Compare_UIntPtr
||
979 comp
->compareType() == MCompare::Compare_Object
||
980 comp
->compareType() == MCompare::Compare_Symbol
||
981 comp
->compareType() == MCompare::Compare_WasmAnyRef
) {
982 JSOp op
= ReorderComparison(comp
->jsop(), &left
, &right
);
983 LAllocation lhs
= useRegister(left
);
985 if (comp
->isInt32Comparison() ||
986 comp
->compareType() == MCompare::Compare_UInt32
||
987 comp
->compareType() == MCompare::Compare_UIntPtr
) {
988 rhs
= useAnyOrInt32Constant(right
);
992 LCompareAndBranch
* lir
=
993 new (alloc()) LCompareAndBranch(comp
, op
, lhs
, rhs
, ifTrue
, ifFalse
);
998 // Compare and branch Int64.
999 if (comp
->compareType() == MCompare::Compare_Int64
||
1000 comp
->compareType() == MCompare::Compare_UInt64
) {
1001 JSOp op
= ReorderComparison(comp
->jsop(), &left
, &right
);
1002 lowerForCompareI64AndBranch(test
, comp
, op
, left
, right
, ifTrue
, ifFalse
);
1006 // Compare and branch doubles.
1007 if (comp
->isDoubleComparison()) {
1008 LAllocation lhs
= useRegister(left
);
1009 LAllocation rhs
= useRegister(right
);
1010 LCompareDAndBranch
* lir
=
1011 new (alloc()) LCompareDAndBranch(comp
, lhs
, rhs
, ifTrue
, ifFalse
);
1016 // Compare and branch floats.
1017 if (comp
->isFloat32Comparison()) {
1018 LAllocation lhs
= useRegister(left
);
1019 LAllocation rhs
= useRegister(right
);
1020 LCompareFAndBranch
* lir
=
1021 new (alloc()) LCompareFAndBranch(comp
, lhs
, rhs
, ifTrue
, ifFalse
);
1027 // Check if the operand for this test is a bitand operation. If it is, we want
1028 // to emit an LBitAndAndBranch rather than an LTest*AndBranch.
1029 if (opd
->isBitAnd() && opd
->isEmittedAtUses()) {
1030 MDefinition
* lhs
= opd
->getOperand(0);
1031 MDefinition
* rhs
= opd
->getOperand(1);
1032 if (lhs
->type() == MIRType::Int32
&& rhs
->type() == MIRType::Int32
) {
1033 ReorderCommutative(&lhs
, &rhs
, test
);
1034 lowerForBitAndAndBranch(new (alloc()) LBitAndAndBranch(ifTrue
, ifFalse
,
1041 #if defined(ENABLE_WASM_SIMD) && \
1042 (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || \
1043 defined(JS_CODEGEN_ARM64))
1044 // Check if the operand for this test is an any_true/all_true SIMD operation.
1045 // If it is, we want to emit an LWasmReduceAndBranchSimd128 node to avoid
1046 // generating an intermediate boolean result.
1047 if (opd
->isWasmReduceSimd128() && opd
->isEmittedAtUses()) {
1048 MWasmReduceSimd128
* node
= opd
->toWasmReduceSimd128();
1049 if (canFoldReduceSimd128AndBranch(node
->simdOp())) {
1051 js::wasm::ReportSimdAnalysis("simd128-to-scalar-and-branch -> folded");
1053 auto* lir
= new (alloc()) LWasmReduceAndBranchSimd128(
1054 useRegister(node
->input()), node
->simdOp(), ifTrue
, ifFalse
);
1061 if (opd
->isIsObject() && opd
->isEmittedAtUses()) {
1062 MDefinition
* input
= opd
->toIsObject()->input();
1063 MOZ_ASSERT(input
->type() == MIRType::Value
);
1065 LIsObjectAndBranch
* lir
=
1066 new (alloc()) LIsObjectAndBranch(ifTrue
, ifFalse
, useBoxAtStart(input
));
1071 if (opd
->isWasmRefIsSubtypeOfAbstract() && opd
->isEmittedAtUses()) {
1072 MWasmRefIsSubtypeOfAbstract
* isSubTypeOf
=
1073 opd
->toWasmRefIsSubtypeOfAbstract();
1074 LAllocation ref
= useRegister(isSubTypeOf
->ref());
1075 LDefinition scratch1
= LDefinition();
1076 if (isSubTypeOf
->destType().isAnyHierarchy()) {
1077 // As in visitWasmRefIsSubtypeOfAbstract, we know we do not need
1078 // scratch2 and superSTV because we know this is not a
1080 scratch1
= MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
1081 isSubTypeOf
->destType())
1084 } else if (isSubTypeOf
->destType().isFuncHierarchy() ||
1085 isSubTypeOf
->destType().isExternHierarchy()) {
1086 // scratch1 is not necessary for abstract casts in other hierarchies
1088 MOZ_CRASH("unknown type hierarchy when folding abstract casts");
1091 add(new (alloc()) LWasmRefIsSubtypeOfAbstractAndBranch(
1092 ifTrue
, ifFalse
, isSubTypeOf
->sourceType(), isSubTypeOf
->destType(),
1098 if (opd
->isWasmRefIsSubtypeOfConcrete() && opd
->isEmittedAtUses()) {
1099 MWasmRefIsSubtypeOfConcrete
* isSubTypeOf
=
1100 opd
->toWasmRefIsSubtypeOfConcrete();
1101 LAllocation ref
= useRegister(isSubTypeOf
->ref());
1102 LAllocation superSTV
= useRegister(isSubTypeOf
->superSTV());
1103 LDefinition scratch1
= LDefinition();
1104 LDefinition scratch2
= LDefinition();
1105 if (isSubTypeOf
->destType().isAnyHierarchy()) {
1106 // As in visitWasmRefIsSubtypeOfConcrete, we know we need scratch1 because
1107 // we know this is a concrete type.
1109 scratch2
= MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
1110 isSubTypeOf
->destType())
1113 } else if (isSubTypeOf
->destType().isFuncHierarchy()) {
1114 // As in visitWasmRefIsSubtypeOfConcrete again...
1116 scratch2
= MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
1117 isSubTypeOf
->destType())
1120 } else if (isSubTypeOf
->destType().isExternHierarchy()) {
1121 MOZ_CRASH("concrete casts are not possible in the extern hierarchy");
1123 MOZ_CRASH("unknown type hierarchy when folding abstract casts");
1126 add(new (alloc()) LWasmRefIsSubtypeOfConcreteAndBranch(
1127 ifTrue
, ifFalse
, isSubTypeOf
->sourceType(), isSubTypeOf
->destType(),
1128 ref
, superSTV
, scratch1
, scratch2
),
1133 if (opd
->isIsNullOrUndefined() && opd
->isEmittedAtUses()) {
1134 MIsNullOrUndefined
* isNullOrUndefined
= opd
->toIsNullOrUndefined();
1135 MDefinition
* input
= isNullOrUndefined
->value();
1137 if (input
->type() == MIRType::Value
) {
1138 auto* lir
= new (alloc()) LIsNullOrUndefinedAndBranch(
1139 isNullOrUndefined
, ifTrue
, ifFalse
, useBoxAtStart(input
));
1142 auto* target
= IsNullOrUndefined(input
->type()) ? ifTrue
: ifFalse
;
1143 add(new (alloc()) LGoto(target
));
1148 if (opd
->isIsNoIter()) {
1149 MOZ_ASSERT(opd
->isEmittedAtUses());
1151 MDefinition
* input
= opd
->toIsNoIter()->input();
1152 MOZ_ASSERT(input
->type() == MIRType::Value
);
1154 LIsNoIterAndBranch
* lir
=
1155 new (alloc()) LIsNoIterAndBranch(ifTrue
, ifFalse
, useBox(input
));
1160 if (opd
->isIteratorHasIndices()) {
1161 MOZ_ASSERT(opd
->isEmittedAtUses());
1163 MDefinition
* object
= opd
->toIteratorHasIndices()->object();
1164 MDefinition
* iterator
= opd
->toIteratorHasIndices()->iterator();
1165 LIteratorHasIndicesAndBranch
* lir
= new (alloc())
1166 LIteratorHasIndicesAndBranch(ifTrue
, ifFalse
, useRegister(object
),
1167 useRegister(iterator
), temp(), temp());
1172 switch (opd
->type()) {
1173 case MIRType::Double
:
1174 add(new (alloc()) LTestDAndBranch(useRegister(opd
), ifTrue
, ifFalse
));
1176 case MIRType::Float32
:
1177 add(new (alloc()) LTestFAndBranch(useRegister(opd
), ifTrue
, ifFalse
));
1179 case MIRType::Int32
:
1180 case MIRType::Boolean
:
1181 add(new (alloc()) LTestIAndBranch(useRegister(opd
), ifTrue
, ifFalse
));
1183 case MIRType::Int64
:
1185 LTestI64AndBranch(useInt64Register(opd
), ifTrue
, ifFalse
));
1187 case MIRType::BigInt
:
1188 add(new (alloc()) LTestBIAndBranch(useRegister(opd
), ifTrue
, ifFalse
));
1191 MOZ_CRASH("Bad type");
1195 static inline bool CanEmitCompareAtUses(MInstruction
* ins
) {
1196 if (!ins
->canEmitAtUses()) {
1200 // If the result is never used, we can usefully defer emission to the use
1201 // point, since that will never happen.
1202 MUseIterator
iter(ins
->usesBegin());
1203 if (iter
== ins
->usesEnd()) {
1207 // If the first use isn't of the expected form, the answer is No.
1208 MNode
* node
= iter
->consumer();
1209 if (!node
->isDefinition()) {
1213 MDefinition
* use
= node
->toDefinition();
1214 if (!use
->isTest() && !use
->isWasmSelect()) {
1218 // Emission can be deferred to the first use point, but only if there are no
1219 // other use points.
1221 return iter
== ins
->usesEnd();
1224 void LIRGenerator::visitCompare(MCompare
* comp
) {
1225 MDefinition
* left
= comp
->lhs();
1226 MDefinition
* right
= comp
->rhs();
1228 // Try to fold the comparison so that we don't have to handle all cases.
1230 if (comp
->tryFold(&result
)) {
1231 define(new (alloc()) LInteger(result
), comp
);
1235 // Move below the emitAtUses call if we ever implement
1236 // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't
1237 // make sense and avoids confusion.
1238 if (comp
->compareType() == MCompare::Compare_String
) {
1239 MConstant
* constant
= nullptr;
1240 MDefinition
* input
= nullptr;
1241 if (left
->isConstant()) {
1242 constant
= left
->toConstant();
1244 } else if (right
->isConstant()) {
1245 constant
= right
->toConstant();
1250 JSLinearString
* linear
= &constant
->toString()->asLinear();
1252 if (IsEqualityOp(comp
->jsop())) {
1253 if (MacroAssembler::canCompareStringCharsInline(linear
)) {
1254 auto* lir
= new (alloc()) LCompareSInline(useRegister(input
), linear
);
1256 assignSafepoint(lir
, comp
);
1260 MOZ_ASSERT(IsRelationalOp(comp
->jsop()));
1262 if (linear
->length() == 1) {
1263 // Move the constant value into the right-hand side operand.
1264 JSOp op
= comp
->jsop();
1265 if (left
== constant
) {
1266 op
= ReverseCompareOp(op
);
1269 auto* lir
= new (alloc())
1270 LCompareSSingle(useRegister(input
), temp(), op
, linear
);
1278 new (alloc()) LCompareS(useRegister(left
), useRegister(right
));
1280 assignSafepoint(lir
, comp
);
1284 // Compare two BigInts.
1285 if (comp
->compareType() == MCompare::Compare_BigInt
) {
1286 auto* lir
= new (alloc()) LCompareBigInt(
1287 useRegister(left
), useRegister(right
), temp(), temp(), temp());
1292 // Compare BigInt with Int32.
1293 if (comp
->compareType() == MCompare::Compare_BigInt_Int32
) {
1294 auto* lir
= new (alloc()) LCompareBigIntInt32(
1295 useRegister(left
), useRegister(right
), temp(), temp());
1300 // Compare BigInt with Double.
1301 if (comp
->compareType() == MCompare::Compare_BigInt_Double
) {
1302 auto* lir
= new (alloc()) LCompareBigIntDouble(useRegisterAtStart(left
),
1303 useRegisterAtStart(right
));
1304 defineReturn(lir
, comp
);
1308 // Compare BigInt with String.
1309 if (comp
->compareType() == MCompare::Compare_BigInt_String
) {
1310 auto* lir
= new (alloc()) LCompareBigIntString(useRegisterAtStart(left
),
1311 useRegisterAtStart(right
));
1312 defineReturn(lir
, comp
);
1313 assignSafepoint(lir
, comp
);
1317 // Sniff out if the output of this compare is used only for a branching.
1318 // If it is, then we will emit an LCompare*AndBranch instruction in place
1319 // of this compare and any test that uses this compare. Thus, we can
1320 // ignore this Compare.
1321 if (CanEmitCompareAtUses(comp
)) {
1326 // Compare Null and Undefined.
1327 if (comp
->compareType() == MCompare::Compare_Null
||
1328 comp
->compareType() == MCompare::Compare_Undefined
) {
1329 if (left
->type() == MIRType::Object
) {
1330 define(new (alloc()) LIsNullOrLikeUndefinedT(useRegister(left
)), comp
);
1334 if (IsLooseEqualityOp(comp
->jsop())) {
1336 new (alloc()) LIsNullOrLikeUndefinedV(useBox(left
), tempToUnbox());
1341 if (comp
->compareType() == MCompare::Compare_Null
) {
1342 auto* lir
= new (alloc()) LIsNull(useBox(left
));
1347 auto* lir
= new (alloc()) LIsUndefined(useBox(left
));
1352 // Compare Int32, Symbol, Object or Wasm pointers.
1353 if (comp
->isInt32Comparison() ||
1354 comp
->compareType() == MCompare::Compare_UInt32
||
1355 comp
->compareType() == MCompare::Compare_UIntPtr
||
1356 comp
->compareType() == MCompare::Compare_Object
||
1357 comp
->compareType() == MCompare::Compare_Symbol
||
1358 comp
->compareType() == MCompare::Compare_WasmAnyRef
) {
1359 JSOp op
= ReorderComparison(comp
->jsop(), &left
, &right
);
1360 LAllocation lhs
= useRegister(left
);
1362 if (comp
->isInt32Comparison() ||
1363 comp
->compareType() == MCompare::Compare_UInt32
||
1364 comp
->compareType() == MCompare::Compare_UIntPtr
) {
1365 rhs
= useAnyOrInt32Constant(right
);
1367 rhs
= useAny(right
);
1369 define(new (alloc()) LCompare(op
, lhs
, rhs
), comp
);
1374 if (comp
->compareType() == MCompare::Compare_Int64
||
1375 comp
->compareType() == MCompare::Compare_UInt64
) {
1376 JSOp op
= ReorderComparison(comp
->jsop(), &left
, &right
);
1377 define(new (alloc()) LCompareI64(op
, useInt64Register(left
),
1378 useInt64OrConstant(right
)),
1384 if (comp
->isDoubleComparison()) {
1385 define(new (alloc()) LCompareD(useRegister(left
), useRegister(right
)),
1391 if (comp
->isFloat32Comparison()) {
1392 define(new (alloc()) LCompareF(useRegister(left
), useRegister(right
)),
1397 MOZ_CRASH("Unrecognized compare type.");
1400 void LIRGenerator::visitSameValueDouble(MSameValueDouble
* ins
) {
1401 MDefinition
* lhs
= ins
->lhs();
1402 MDefinition
* rhs
= ins
->rhs();
1404 MOZ_ASSERT(lhs
->type() == MIRType::Double
);
1405 MOZ_ASSERT(rhs
->type() == MIRType::Double
);
1407 auto* lir
= new (alloc())
1408 LSameValueDouble(useRegister(lhs
), useRegister(rhs
), tempDouble());
1412 void LIRGenerator::visitSameValue(MSameValue
* ins
) {
1413 MDefinition
* lhs
= ins
->lhs();
1414 MDefinition
* rhs
= ins
->rhs();
1416 MOZ_ASSERT(lhs
->type() == MIRType::Value
);
1417 MOZ_ASSERT(rhs
->type() == MIRType::Value
);
1419 auto* lir
= new (alloc()) LSameValue(useBox(lhs
), useBox(rhs
));
1421 assignSafepoint(lir
, ins
);
1424 void LIRGenerator::lowerBitOp(JSOp op
, MBinaryInstruction
* ins
) {
1425 MDefinition
* lhs
= ins
->getOperand(0);
1426 MDefinition
* rhs
= ins
->getOperand(1);
1427 MOZ_ASSERT(IsIntType(ins
->type()));
1429 if (ins
->type() == MIRType::Int32
) {
1430 MOZ_ASSERT(lhs
->type() == MIRType::Int32
);
1431 MOZ_ASSERT(rhs
->type() == MIRType::Int32
);
1432 ReorderCommutative(&lhs
, &rhs
, ins
);
1433 lowerForALU(new (alloc()) LBitOpI(op
), ins
, lhs
, rhs
);
1437 if (ins
->type() == MIRType::Int64
) {
1438 MOZ_ASSERT(lhs
->type() == MIRType::Int64
);
1439 MOZ_ASSERT(rhs
->type() == MIRType::Int64
);
1440 ReorderCommutative(&lhs
, &rhs
, ins
);
1441 lowerForALUInt64(new (alloc()) LBitOpI64(op
), ins
, lhs
, rhs
);
1445 MOZ_CRASH("Unhandled integer specialization");
1448 void LIRGenerator::visitTypeOf(MTypeOf
* ins
) {
1449 MDefinition
* opd
= ins
->input();
1451 if (opd
->type() == MIRType::Object
) {
1452 auto* lir
= new (alloc()) LTypeOfO(useRegister(opd
));
1457 MOZ_ASSERT(opd
->type() == MIRType::Value
);
1459 LTypeOfV
* lir
= new (alloc()) LTypeOfV(useBox(opd
), tempToUnbox());
1463 void LIRGenerator::visitTypeOfName(MTypeOfName
* ins
) {
1464 MDefinition
* input
= ins
->input();
1465 MOZ_ASSERT(input
->type() == MIRType::Int32
);
1467 auto* lir
= new (alloc()) LTypeOfName(useRegister(input
));
1471 void LIRGenerator::visitTypeOfIs(MTypeOfIs
* ins
) {
1472 MDefinition
* input
= ins
->input();
1474 MOZ_ASSERT(input
->type() == MIRType::Object
||
1475 input
->type() == MIRType::Value
);
1477 switch (ins
->jstype()) {
1478 case JSTYPE_UNDEFINED
:
1480 case JSTYPE_FUNCTION
: {
1481 if (input
->type() == MIRType::Object
) {
1482 auto* lir
= new (alloc()) LTypeOfIsNonPrimitiveO(useRegister(input
));
1486 new (alloc()) LTypeOfIsNonPrimitiveV(useBox(input
), tempToUnbox());
1494 case JSTYPE_BOOLEAN
:
1496 case JSTYPE_BIGINT
: {
1497 MOZ_ASSERT(input
->type() == MIRType::Value
);
1499 auto* lir
= new (alloc()) LTypeOfIsPrimitive(useBoxAtStart(input
));
1504 #ifdef ENABLE_RECORD_TUPLE
1511 MOZ_CRASH("Unhandled JSType");
1514 void LIRGenerator::visitToAsyncIter(MToAsyncIter
* ins
) {
1515 LToAsyncIter
* lir
= new (alloc()) LToAsyncIter(
1516 useRegisterAtStart(ins
->iterator()), useBoxAtStart(ins
->nextMethod()));
1517 defineReturn(lir
, ins
);
1518 assignSafepoint(lir
, ins
);
1521 void LIRGenerator::visitToPropertyKeyCache(MToPropertyKeyCache
* ins
) {
1522 MDefinition
* input
= ins
->getOperand(0);
1523 MOZ_ASSERT(ins
->type() == MIRType::Value
);
1525 auto* lir
= new (alloc()) LToPropertyKeyCache(useBox(input
));
1526 defineBox(lir
, ins
);
1527 assignSafepoint(lir
, ins
);
1530 void LIRGenerator::visitBitNot(MBitNot
* ins
) {
1531 MDefinition
* input
= ins
->getOperand(0);
1533 if (ins
->type() == MIRType::Int32
) {
1534 MOZ_ASSERT(input
->type() == MIRType::Int32
);
1535 lowerForALU(new (alloc()) LBitNotI(), ins
, input
);
1539 if (ins
->type() == MIRType::Int64
) {
1540 MOZ_ASSERT(input
->type() == MIRType::Int64
);
1541 lowerForALUInt64(new (alloc()) LBitNotI64(), ins
, input
);
1545 MOZ_CRASH("Unhandled integer specialization");
1548 static bool CanEmitBitAndAtUses(MInstruction
* ins
) {
1549 if (!ins
->canEmitAtUses()) {
1553 MIRType tyL
= ins
->getOperand(0)->type();
1554 MIRType tyR
= ins
->getOperand(1)->type();
1555 if (tyL
!= tyR
|| (tyL
!= MIRType::Int32
&& tyL
!= MIRType::Int64
)) {
1559 MUseIterator
iter(ins
->usesBegin());
1560 if (iter
== ins
->usesEnd()) {
1564 MNode
* node
= iter
->consumer();
1565 if (!node
->isDefinition() || !node
->toDefinition()->isInstruction()) {
1569 MInstruction
* use
= node
->toDefinition()->toInstruction();
1570 if (!use
->isTest() && !(use
->isCompare() && CanEmitCompareAtUses(use
))) {
1575 return iter
== ins
->usesEnd();
1578 void LIRGenerator::visitBitAnd(MBitAnd
* ins
) {
1579 // Sniff out if the output of this bitand is used only for a branching.
1580 // If it is, then we will emit an LBitAndAndBranch instruction in place
1581 // of this bitand and any test that uses this bitand. Thus, we can
1582 // ignore this BitAnd.
1583 if (CanEmitBitAndAtUses(ins
)) {
1586 lowerBitOp(JSOp::BitAnd
, ins
);
1590 void LIRGenerator::visitBitOr(MBitOr
* ins
) { lowerBitOp(JSOp::BitOr
, ins
); }
1592 void LIRGenerator::visitBitXor(MBitXor
* ins
) { lowerBitOp(JSOp::BitXor
, ins
); }
1594 void LIRGenerator::visitWasmBinaryBitwise(MWasmBinaryBitwise
* ins
) {
1595 switch (ins
->subOpcode()) {
1596 case MWasmBinaryBitwise::SubOpcode::And
:
1597 if (CanEmitBitAndAtUses(ins
)) {
1600 lowerBitOp(JSOp::BitAnd
, ins
);
1603 case MWasmBinaryBitwise::SubOpcode::Or
:
1604 lowerBitOp(JSOp::BitOr
, ins
);
1606 case MWasmBinaryBitwise::SubOpcode::Xor
:
1607 lowerBitOp(JSOp::BitXor
, ins
);
1614 void LIRGenerator::lowerShiftOp(JSOp op
, MShiftInstruction
* ins
) {
1615 MDefinition
* lhs
= ins
->getOperand(0);
1616 MDefinition
* rhs
= ins
->getOperand(1);
1618 if (op
== JSOp::Ursh
&& ins
->type() == MIRType::Double
) {
1619 MOZ_ASSERT(lhs
->type() == MIRType::Int32
);
1620 MOZ_ASSERT(rhs
->type() == MIRType::Int32
);
1621 lowerUrshD(ins
->toUrsh());
1625 MOZ_ASSERT(IsIntType(ins
->type()));
1627 if (ins
->type() == MIRType::Int32
) {
1628 MOZ_ASSERT(lhs
->type() == MIRType::Int32
);
1629 MOZ_ASSERT(rhs
->type() == MIRType::Int32
);
1631 LShiftI
* lir
= new (alloc()) LShiftI(op
);
1632 if (op
== JSOp::Ursh
) {
1633 if (ins
->toUrsh()->fallible()) {
1634 assignSnapshot(lir
, ins
->bailoutKind());
1637 lowerForShift(lir
, ins
, lhs
, rhs
);
1641 if (ins
->type() == MIRType::Int64
) {
1642 MOZ_ASSERT(lhs
->type() == MIRType::Int64
);
1643 MOZ_ASSERT(rhs
->type() == MIRType::Int64
);
1644 lowerForShiftInt64(new (alloc()) LShiftI64(op
), ins
, lhs
, rhs
);
1648 MOZ_CRASH("Unhandled integer specialization");
1651 void LIRGenerator::visitLsh(MLsh
* ins
) { lowerShiftOp(JSOp::Lsh
, ins
); }
1653 void LIRGenerator::visitRsh(MRsh
* ins
) { lowerShiftOp(JSOp::Rsh
, ins
); }
1655 void LIRGenerator::visitUrsh(MUrsh
* ins
) { lowerShiftOp(JSOp::Ursh
, ins
); }
1657 void LIRGenerator::visitSignExtendInt32(MSignExtendInt32
* ins
) {
1658 LInstructionHelper
<1, 1, 0>* lir
;
1660 if (ins
->mode() == MSignExtendInt32::Byte
) {
1662 LSignExtendInt32(useByteOpRegisterAtStart(ins
->input()), ins
->mode());
1665 LSignExtendInt32(useRegisterAtStart(ins
->input()), ins
->mode());
1671 void LIRGenerator::visitRotate(MRotate
* ins
) {
1672 MDefinition
* input
= ins
->input();
1673 MDefinition
* count
= ins
->count();
1675 if (ins
->type() == MIRType::Int32
) {
1676 auto* lir
= new (alloc()) LRotate();
1677 lowerForShift(lir
, ins
, input
, count
);
1678 } else if (ins
->type() == MIRType::Int64
) {
1679 auto* lir
= new (alloc()) LRotateI64();
1680 lowerForShiftInt64(lir
, ins
, input
, count
);
1682 MOZ_CRASH("unexpected type in visitRotate");
1686 void LIRGenerator::visitFloor(MFloor
* ins
) {
1687 MIRType type
= ins
->input()->type();
1688 MOZ_ASSERT(IsFloatingPointType(type
));
1690 LInstructionHelper
<1, 1, 0>* lir
;
1691 if (type
== MIRType::Double
) {
1692 lir
= new (alloc()) LFloor(useRegister(ins
->input()));
1694 lir
= new (alloc()) LFloorF(useRegister(ins
->input()));
1697 assignSnapshot(lir
, ins
->bailoutKind());
1701 void LIRGenerator::visitCeil(MCeil
* ins
) {
1702 MIRType type
= ins
->input()->type();
1703 MOZ_ASSERT(IsFloatingPointType(type
));
1705 LInstructionHelper
<1, 1, 0>* lir
;
1706 if (type
== MIRType::Double
) {
1707 lir
= new (alloc()) LCeil(useRegister(ins
->input()));
1709 lir
= new (alloc()) LCeilF(useRegister(ins
->input()));
1712 assignSnapshot(lir
, ins
->bailoutKind());
1716 void LIRGenerator::visitRound(MRound
* ins
) {
1717 MIRType type
= ins
->input()->type();
1718 MOZ_ASSERT(IsFloatingPointType(type
));
1720 LInstructionHelper
<1, 1, 1>* lir
;
1721 if (type
== MIRType::Double
) {
1722 lir
= new (alloc()) LRound(useRegister(ins
->input()), tempDouble());
1724 lir
= new (alloc()) LRoundF(useRegister(ins
->input()), tempFloat32());
1727 assignSnapshot(lir
, ins
->bailoutKind());
1731 void LIRGenerator::visitTrunc(MTrunc
* ins
) {
1732 MIRType type
= ins
->input()->type();
1733 MOZ_ASSERT(IsFloatingPointType(type
));
1735 LInstructionHelper
<1, 1, 0>* lir
;
1736 if (type
== MIRType::Double
) {
1737 lir
= new (alloc()) LTrunc(useRegister(ins
->input()));
1739 lir
= new (alloc()) LTruncF(useRegister(ins
->input()));
1742 assignSnapshot(lir
, ins
->bailoutKind());
1746 void LIRGenerator::visitNearbyInt(MNearbyInt
* ins
) {
1747 MIRType inputType
= ins
->input()->type();
1748 MOZ_ASSERT(IsFloatingPointType(inputType
));
1749 MOZ_ASSERT(ins
->type() == inputType
);
1751 LInstructionHelper
<1, 1, 0>* lir
;
1752 if (inputType
== MIRType::Double
) {
1753 lir
= new (alloc()) LNearbyInt(useRegisterAtStart(ins
->input()));
1755 lir
= new (alloc()) LNearbyIntF(useRegisterAtStart(ins
->input()));
1761 void LIRGenerator::visitMinMax(MMinMax
* ins
) {
1762 MDefinition
* first
= ins
->getOperand(0);
1763 MDefinition
* second
= ins
->getOperand(1);
1765 ReorderCommutative(&first
, &second
, ins
);
1768 switch (ins
->type()) {
1769 case MIRType::Int32
:
1771 LMinMaxI(useRegisterAtStart(first
), useRegisterOrConstant(second
));
1773 case MIRType::Float32
:
1775 LMinMaxF(useRegisterAtStart(first
), useRegister(second
));
1777 case MIRType::Double
:
1779 LMinMaxD(useRegisterAtStart(first
), useRegister(second
));
1785 // Input reuse is OK (for now) even on ARM64: floating min/max are fairly
1786 // expensive due to SNaN -> QNaN conversion, and int min/max is for asm.js.
1787 defineReuseInput(lir
, ins
, 0);
1790 void LIRGenerator::visitMinMaxArray(MMinMaxArray
* ins
) {
1791 LInstructionHelper
<1, 1, 3>* lir
;
1792 if (ins
->type() == MIRType::Int32
) {
1794 LMinMaxArrayI(useRegisterAtStart(ins
->array()), temp(), temp(), temp());
1796 MOZ_ASSERT(ins
->type() == MIRType::Double
);
1797 lir
= new (alloc()) LMinMaxArrayD(useRegisterAtStart(ins
->array()),
1798 tempDouble(), temp(), temp());
1800 assignSnapshot(lir
, ins
->bailoutKind());
1804 LInstructionHelper
<1, 1, 0>* LIRGenerator::allocateAbs(MAbs
* ins
,
1805 LAllocation input
) {
1806 MDefinition
* num
= ins
->input();
1807 MOZ_ASSERT(IsNumberType(num
->type()));
1809 LInstructionHelper
<1, 1, 0>* lir
;
1810 switch (num
->type()) {
1811 case MIRType::Int32
:
1812 lir
= new (alloc()) LAbsI(input
);
1813 // needed to handle abs(INT32_MIN)
1814 if (ins
->fallible()) {
1815 assignSnapshot(lir
, ins
->bailoutKind());
1818 case MIRType::Float32
:
1819 lir
= new (alloc()) LAbsF(input
);
1821 case MIRType::Double
:
1822 lir
= new (alloc()) LAbsD(input
);
1830 void LIRGenerator::visitClz(MClz
* ins
) {
1831 MDefinition
* num
= ins
->num();
1833 MOZ_ASSERT(IsIntType(ins
->type()));
1835 if (ins
->type() == MIRType::Int32
) {
1836 LClzI
* lir
= new (alloc()) LClzI(useRegisterAtStart(num
));
1841 auto* lir
= new (alloc()) LClzI64(useInt64RegisterAtStart(num
));
1842 defineInt64(lir
, ins
);
1845 void LIRGenerator::visitCtz(MCtz
* ins
) {
1846 MDefinition
* num
= ins
->num();
1848 MOZ_ASSERT(IsIntType(ins
->type()));
1850 if (ins
->type() == MIRType::Int32
) {
1851 LCtzI
* lir
= new (alloc()) LCtzI(useRegisterAtStart(num
));
1856 auto* lir
= new (alloc()) LCtzI64(useInt64RegisterAtStart(num
));
1857 defineInt64(lir
, ins
);
1860 void LIRGenerator::visitPopcnt(MPopcnt
* ins
) {
1861 MDefinition
* num
= ins
->num();
1863 MOZ_ASSERT(IsIntType(ins
->type()));
1865 if (ins
->type() == MIRType::Int32
) {
1866 LPopcntI
* lir
= new (alloc()) LPopcntI(useRegisterAtStart(num
), temp());
1871 auto* lir
= new (alloc()) LPopcntI64(useInt64RegisterAtStart(num
), temp());
1872 defineInt64(lir
, ins
);
1875 void LIRGenerator::visitSqrt(MSqrt
* ins
) {
1876 MDefinition
* num
= ins
->input();
1877 MOZ_ASSERT(IsFloatingPointType(num
->type()));
1879 LInstructionHelper
<1, 1, 0>* lir
;
1880 if (num
->type() == MIRType::Double
) {
1881 lir
= new (alloc()) LSqrtD(useRegisterAtStart(num
));
1883 lir
= new (alloc()) LSqrtF(useRegisterAtStart(num
));
1888 void LIRGenerator::visitAtan2(MAtan2
* ins
) {
1889 MDefinition
* y
= ins
->y();
1890 MOZ_ASSERT(y
->type() == MIRType::Double
);
1892 MDefinition
* x
= ins
->x();
1893 MOZ_ASSERT(x
->type() == MIRType::Double
);
1896 new (alloc()) LAtan2D(useRegisterAtStart(y
), useRegisterAtStart(x
));
1897 defineReturn(lir
, ins
);
1900 void LIRGenerator::visitHypot(MHypot
* ins
) {
1901 LHypot
* lir
= nullptr;
1902 uint32_t length
= ins
->numOperands();
1903 for (uint32_t i
= 0; i
< length
; ++i
) {
1904 MOZ_ASSERT(ins
->getOperand(i
)->type() == MIRType::Double
);
1909 lir
= new (alloc()) LHypot(useRegisterAtStart(ins
->getOperand(0)),
1910 useRegisterAtStart(ins
->getOperand(1)));
1913 lir
= new (alloc()) LHypot(useRegisterAtStart(ins
->getOperand(0)),
1914 useRegisterAtStart(ins
->getOperand(1)),
1915 useRegisterAtStart(ins
->getOperand(2)));
1918 lir
= new (alloc()) LHypot(useRegisterAtStart(ins
->getOperand(0)),
1919 useRegisterAtStart(ins
->getOperand(1)),
1920 useRegisterAtStart(ins
->getOperand(2)),
1921 useRegisterAtStart(ins
->getOperand(3)));
1924 MOZ_CRASH("Unexpected number of arguments to LHypot.");
1927 defineReturn(lir
, ins
);
1930 void LIRGenerator::visitPow(MPow
* ins
) {
1931 MDefinition
* input
= ins
->input();
1932 MDefinition
* power
= ins
->power();
1934 if (ins
->type() == MIRType::Int32
) {
1935 MOZ_ASSERT(input
->type() == MIRType::Int32
);
1936 MOZ_ASSERT(power
->type() == MIRType::Int32
);
1938 if (input
->isConstant()) {
1939 // Restrict this optimization to |base <= 256| to avoid generating too
1940 // many consecutive shift instructions.
1941 int32_t base
= input
->toConstant()->toInt32();
1942 if (2 <= base
&& base
<= 256 && mozilla::IsPowerOfTwo(uint32_t(base
))) {
1943 lowerPowOfTwoI(ins
);
1948 auto* lir
= new (alloc())
1949 LPowII(useRegister(input
), useRegister(power
), temp(), temp());
1950 assignSnapshot(lir
, ins
->bailoutKind());
1955 MOZ_ASSERT(ins
->type() == MIRType::Double
);
1956 MOZ_ASSERT(input
->type() == MIRType::Double
);
1957 MOZ_ASSERT(power
->type() == MIRType::Int32
||
1958 power
->type() == MIRType::Double
);
1961 if (power
->type() == MIRType::Int32
) {
1963 LPowI(useRegisterAtStart(input
), useRegisterAtStart(power
));
1966 LPowD(useRegisterAtStart(input
), useRegisterAtStart(power
));
1968 defineReturn(lir
, ins
);
1971 void LIRGenerator::visitSign(MSign
* ins
) {
1972 if (ins
->type() == ins
->input()->type()) {
1973 LInstructionHelper
<1, 1, 0>* lir
;
1974 if (ins
->type() == MIRType::Int32
) {
1975 lir
= new (alloc()) LSignI(useRegister(ins
->input()));
1977 MOZ_ASSERT(ins
->type() == MIRType::Double
);
1978 lir
= new (alloc()) LSignD(useRegister(ins
->input()));
1982 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
1983 MOZ_ASSERT(ins
->input()->type() == MIRType::Double
);
1985 auto* lir
= new (alloc()) LSignDI(useRegister(ins
->input()), tempDouble());
1986 assignSnapshot(lir
, ins
->bailoutKind());
1991 void LIRGenerator::visitMathFunction(MMathFunction
* ins
) {
1992 MOZ_ASSERT(IsFloatingPointType(ins
->type()));
1993 MOZ_ASSERT(ins
->type() == ins
->input()->type());
1996 if (ins
->type() == MIRType::Double
) {
1997 lir
= new (alloc()) LMathFunctionD(useRegisterAtStart(ins
->input()));
1999 lir
= new (alloc()) LMathFunctionF(useRegisterAtStart(ins
->input()));
2001 defineReturn(lir
, ins
);
2004 void LIRGenerator::visitRandom(MRandom
* ins
) {
2005 auto* lir
= new (alloc()) LRandom(temp(), tempInt64(), tempInt64());
2009 // Try to mark an add or sub instruction as able to recover its input when
2011 template <typename S
, typename T
>
2012 static void MaybeSetRecoversInput(S
* mir
, T
* lir
) {
2013 MOZ_ASSERT(lir
->mirRaw() == mir
);
2014 if (!mir
->fallible() || !lir
->snapshot()) {
2018 if (lir
->output()->policy() != LDefinition::MUST_REUSE_INPUT
) {
2022 // The original operands to an add or sub can't be recovered if they both
2023 // use the same register.
2024 if (lir
->lhs()->isUse() && lir
->rhs()->isUse() &&
2025 lir
->lhs()->toUse()->virtualRegister() ==
2026 lir
->rhs()->toUse()->virtualRegister()) {
2030 // Add instructions that are on two different values can recover
2031 // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy
2032 // of that input does not need to be kept alive in the snapshot
2033 // for the instruction.
2035 lir
->setRecoversInput();
2037 const LUse
* input
= lir
->getOperand(lir
->output()->getReusedInput())->toUse();
2038 lir
->snapshot()->rewriteRecoveredInput(*input
);
2041 void LIRGenerator::visitAdd(MAdd
* ins
) {
2042 MDefinition
* lhs
= ins
->getOperand(0);
2043 MDefinition
* rhs
= ins
->getOperand(1);
2045 MOZ_ASSERT(lhs
->type() == rhs
->type());
2046 MOZ_ASSERT(IsNumberType(ins
->type()));
2048 if (ins
->type() == MIRType::Int32
) {
2049 MOZ_ASSERT(lhs
->type() == MIRType::Int32
);
2050 ReorderCommutative(&lhs
, &rhs
, ins
);
2051 LAddI
* lir
= new (alloc()) LAddI
;
2053 if (ins
->fallible()) {
2054 assignSnapshot(lir
, ins
->bailoutKind());
2057 lowerForALU(lir
, ins
, lhs
, rhs
);
2058 MaybeSetRecoversInput(ins
, lir
);
2062 if (ins
->type() == MIRType::Int64
) {
2063 MOZ_ASSERT(lhs
->type() == MIRType::Int64
);
2064 ReorderCommutative(&lhs
, &rhs
, ins
);
2065 LAddI64
* lir
= new (alloc()) LAddI64
;
2066 lowerForALUInt64(lir
, ins
, lhs
, rhs
);
2070 if (ins
->type() == MIRType::Double
) {
2071 MOZ_ASSERT(lhs
->type() == MIRType::Double
);
2072 ReorderCommutative(&lhs
, &rhs
, ins
);
2073 lowerForFPU(new (alloc()) LMathD(JSOp::Add
), ins
, lhs
, rhs
);
2077 if (ins
->type() == MIRType::Float32
) {
2078 MOZ_ASSERT(lhs
->type() == MIRType::Float32
);
2079 ReorderCommutative(&lhs
, &rhs
, ins
);
2080 lowerForFPU(new (alloc()) LMathF(JSOp::Add
), ins
, lhs
, rhs
);
2084 MOZ_CRASH("Unhandled number specialization");
2087 void LIRGenerator::visitSub(MSub
* ins
) {
2088 MDefinition
* lhs
= ins
->lhs();
2089 MDefinition
* rhs
= ins
->rhs();
2091 MOZ_ASSERT(lhs
->type() == rhs
->type());
2092 MOZ_ASSERT(IsNumberType(ins
->type()));
2094 if (ins
->type() == MIRType::Int32
) {
2095 MOZ_ASSERT(lhs
->type() == MIRType::Int32
);
2097 LSubI
* lir
= new (alloc()) LSubI
;
2098 if (ins
->fallible()) {
2099 assignSnapshot(lir
, ins
->bailoutKind());
2102 // If our LHS is a constant 0 and we don't have to worry about results that
2103 // can't be represented as an int32, we can optimize to an LNegI.
2104 if (!ins
->fallible() && lhs
->isConstant() &&
2105 lhs
->toConstant()->toInt32() == 0) {
2106 lowerNegI(ins
, rhs
);
2110 lowerForALU(lir
, ins
, lhs
, rhs
);
2111 MaybeSetRecoversInput(ins
, lir
);
2115 if (ins
->type() == MIRType::Int64
) {
2116 MOZ_ASSERT(lhs
->type() == MIRType::Int64
);
2118 // If our LHS is a constant 0, we can optimize to an LNegI64.
2119 if (lhs
->isConstant() && lhs
->toConstant()->toInt64() == 0) {
2120 lowerNegI64(ins
, rhs
);
2124 LSubI64
* lir
= new (alloc()) LSubI64
;
2125 lowerForALUInt64(lir
, ins
, lhs
, rhs
);
2129 if (ins
->type() == MIRType::Double
) {
2130 MOZ_ASSERT(lhs
->type() == MIRType::Double
);
2131 lowerForFPU(new (alloc()) LMathD(JSOp::Sub
), ins
, lhs
, rhs
);
2135 if (ins
->type() == MIRType::Float32
) {
2136 MOZ_ASSERT(lhs
->type() == MIRType::Float32
);
2137 lowerForFPU(new (alloc()) LMathF(JSOp::Sub
), ins
, lhs
, rhs
);
2141 MOZ_CRASH("Unhandled number specialization");
2144 void LIRGenerator::visitMul(MMul
* ins
) {
2145 MDefinition
* lhs
= ins
->lhs();
2146 MDefinition
* rhs
= ins
->rhs();
2147 MOZ_ASSERT(lhs
->type() == rhs
->type());
2148 MOZ_ASSERT(IsNumberType(ins
->type()));
2150 if (ins
->type() == MIRType::Int32
) {
2151 MOZ_ASSERT(lhs
->type() == MIRType::Int32
);
2152 ReorderCommutative(&lhs
, &rhs
, ins
);
2154 // If our RHS is a constant -1 and we don't have to worry about results that
2155 // can't be represented as an int32, we can optimize to an LNegI.
2156 if (!ins
->fallible() && rhs
->isConstant() &&
2157 rhs
->toConstant()->toInt32() == -1) {
2158 lowerNegI(ins
, lhs
);
2162 lowerMulI(ins
, lhs
, rhs
);
2166 if (ins
->type() == MIRType::Int64
) {
2167 MOZ_ASSERT(lhs
->type() == MIRType::Int64
);
2168 ReorderCommutative(&lhs
, &rhs
, ins
);
2170 // If our RHS is a constant -1, we can optimize to an LNegI64.
2171 if (rhs
->isConstant() && rhs
->toConstant()->toInt64() == -1) {
2172 lowerNegI64(ins
, lhs
);
2176 LMulI64
* lir
= new (alloc()) LMulI64
;
2177 lowerForMulInt64(lir
, ins
, lhs
, rhs
);
2181 if (ins
->type() == MIRType::Double
) {
2182 MOZ_ASSERT(lhs
->type() == MIRType::Double
);
2183 ReorderCommutative(&lhs
, &rhs
, ins
);
2185 // If our RHS is a constant -1.0, we can optimize to an LNegD.
2186 if (!ins
->mustPreserveNaN() && rhs
->isConstant() &&
2187 rhs
->toConstant()->toDouble() == -1.0) {
2188 defineReuseInput(new (alloc()) LNegD(useRegisterAtStart(lhs
)), ins
, 0);
2192 lowerForFPU(new (alloc()) LMathD(JSOp::Mul
), ins
, lhs
, rhs
);
2196 if (ins
->type() == MIRType::Float32
) {
2197 MOZ_ASSERT(lhs
->type() == MIRType::Float32
);
2198 ReorderCommutative(&lhs
, &rhs
, ins
);
2200 // We apply the same optimizations as for doubles
2201 if (!ins
->mustPreserveNaN() && rhs
->isConstant() &&
2202 rhs
->toConstant()->toFloat32() == -1.0f
) {
2203 defineReuseInput(new (alloc()) LNegF(useRegisterAtStart(lhs
)), ins
, 0);
2207 lowerForFPU(new (alloc()) LMathF(JSOp::Mul
), ins
, lhs
, rhs
);
2211 MOZ_CRASH("Unhandled number specialization");
2214 void LIRGenerator::visitDiv(MDiv
* ins
) {
2215 MDefinition
* lhs
= ins
->lhs();
2216 MDefinition
* rhs
= ins
->rhs();
2217 MOZ_ASSERT(lhs
->type() == rhs
->type());
2218 MOZ_ASSERT(IsNumberType(ins
->type()));
2220 if (ins
->type() == MIRType::Int32
) {
2221 MOZ_ASSERT(lhs
->type() == MIRType::Int32
);
2226 if (ins
->type() == MIRType::Int64
) {
2227 MOZ_ASSERT(lhs
->type() == MIRType::Int64
);
2232 if (ins
->type() == MIRType::Double
) {
2233 MOZ_ASSERT(lhs
->type() == MIRType::Double
);
2234 lowerForFPU(new (alloc()) LMathD(JSOp::Div
), ins
, lhs
, rhs
);
2238 if (ins
->type() == MIRType::Float32
) {
2239 MOZ_ASSERT(lhs
->type() == MIRType::Float32
);
2240 lowerForFPU(new (alloc()) LMathF(JSOp::Div
), ins
, lhs
, rhs
);
2244 MOZ_CRASH("Unhandled number specialization");
2247 void LIRGenerator::visitWasmBuiltinDivI64(MWasmBuiltinDivI64
* div
) {
2248 lowerWasmBuiltinDivI64(div
);
2251 void LIRGenerator::visitWasmBuiltinModI64(MWasmBuiltinModI64
* mod
) {
2252 lowerWasmBuiltinModI64(mod
);
2255 void LIRGenerator::visitBuiltinInt64ToFloatingPoint(
2256 MBuiltinInt64ToFloatingPoint
* ins
) {
2257 lowerBuiltinInt64ToFloatingPoint(ins
);
2260 void LIRGenerator::visitWasmBuiltinTruncateToInt64(
2261 MWasmBuiltinTruncateToInt64
* ins
) {
2262 lowerWasmBuiltinTruncateToInt64(ins
);
2265 void LIRGenerator::visitWasmBuiltinModD(MWasmBuiltinModD
* ins
) {
2266 MOZ_ASSERT(gen
->compilingWasm());
2267 LWasmBuiltinModD
* lir
= new (alloc()) LWasmBuiltinModD(
2268 useRegisterAtStart(ins
->lhs()), useRegisterAtStart(ins
->rhs()),
2269 useFixedAtStart(ins
->instance(), InstanceReg
));
2270 defineReturn(lir
, ins
);
2273 void LIRGenerator::visitMod(MMod
* ins
) {
2274 MOZ_ASSERT(ins
->lhs()->type() == ins
->rhs()->type());
2275 MOZ_ASSERT(IsNumberType(ins
->type()));
2277 if (ins
->type() == MIRType::Int32
) {
2278 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
2279 MOZ_ASSERT(ins
->lhs()->type() == MIRType::Int32
);
2284 if (ins
->type() == MIRType::Int64
) {
2285 MOZ_ASSERT(ins
->type() == MIRType::Int64
);
2286 MOZ_ASSERT(ins
->lhs()->type() == MIRType::Int64
);
2291 if (ins
->type() == MIRType::Double
) {
2292 MOZ_ASSERT(ins
->lhs()->type() == MIRType::Double
);
2293 MOZ_ASSERT(ins
->rhs()->type() == MIRType::Double
);
2295 MOZ_ASSERT(!gen
->compilingWasm());
2297 if (Assembler::HasRoundInstruction(RoundingMode::TowardsZero
)) {
2298 if (ins
->rhs()->isConstant()) {
2299 double d
= ins
->rhs()->toConstant()->toDouble();
2301 if (mozilla::NumberIsInt32(d
, &div
) && div
> 0 &&
2302 mozilla::IsPowerOfTwo(uint32_t(div
))) {
2303 auto* lir
= new (alloc()) LModPowTwoD(useRegister(ins
->lhs()), div
);
2310 LModD
* lir
= new (alloc())
2311 LModD(useRegisterAtStart(ins
->lhs()), useRegisterAtStart(ins
->rhs()));
2312 defineReturn(lir
, ins
);
2316 MOZ_CRASH("Unhandled number specialization");
2319 void LIRGenerator::visitBigIntAdd(MBigIntAdd
* ins
) {
2320 auto* lir
= new (alloc()) LBigIntAdd(useRegister(ins
->lhs()),
2321 useRegister(ins
->rhs()), temp(), temp());
2323 assignSafepoint(lir
, ins
);
2326 void LIRGenerator::visitBigIntSub(MBigIntSub
* ins
) {
2327 auto* lir
= new (alloc()) LBigIntSub(useRegister(ins
->lhs()),
2328 useRegister(ins
->rhs()), temp(), temp());
2330 assignSafepoint(lir
, ins
);
2333 void LIRGenerator::visitBigIntMul(MBigIntMul
* ins
) {
2334 auto* lir
= new (alloc()) LBigIntMul(useRegister(ins
->lhs()),
2335 useRegister(ins
->rhs()), temp(), temp());
2337 assignSafepoint(lir
, ins
);
2340 void LIRGenerator::visitBigIntDiv(MBigIntDiv
* ins
) { lowerBigIntDiv(ins
); }
2342 void LIRGenerator::visitBigIntMod(MBigIntMod
* ins
) { lowerBigIntMod(ins
); }
2344 void LIRGenerator::visitBigIntPow(MBigIntPow
* ins
) {
2345 auto* lir
= new (alloc()) LBigIntPow(useRegister(ins
->lhs()),
2346 useRegister(ins
->rhs()), temp(), temp());
2348 assignSafepoint(lir
, ins
);
2351 void LIRGenerator::visitBigIntBitAnd(MBigIntBitAnd
* ins
) {
2352 auto* lir
= new (alloc()) LBigIntBitAnd(
2353 useRegister(ins
->lhs()), useRegister(ins
->rhs()), temp(), temp());
2355 assignSafepoint(lir
, ins
);
2358 void LIRGenerator::visitBigIntBitOr(MBigIntBitOr
* ins
) {
2359 auto* lir
= new (alloc()) LBigIntBitOr(
2360 useRegister(ins
->lhs()), useRegister(ins
->rhs()), temp(), temp());
2362 assignSafepoint(lir
, ins
);
2365 void LIRGenerator::visitBigIntBitXor(MBigIntBitXor
* ins
) {
2366 auto* lir
= new (alloc()) LBigIntBitXor(
2367 useRegister(ins
->lhs()), useRegister(ins
->rhs()), temp(), temp());
2369 assignSafepoint(lir
, ins
);
2372 void LIRGenerator::visitBigIntLsh(MBigIntLsh
* ins
) { lowerBigIntLsh(ins
); }
2374 void LIRGenerator::visitBigIntRsh(MBigIntRsh
* ins
) { lowerBigIntRsh(ins
); }
2376 void LIRGenerator::visitBigIntIncrement(MBigIntIncrement
* ins
) {
2378 new (alloc()) LBigIntIncrement(useRegister(ins
->input()), temp(), temp());
2380 assignSafepoint(lir
, ins
);
2383 void LIRGenerator::visitBigIntDecrement(MBigIntDecrement
* ins
) {
2385 new (alloc()) LBigIntDecrement(useRegister(ins
->input()), temp(), temp());
2387 assignSafepoint(lir
, ins
);
2390 void LIRGenerator::visitBigIntNegate(MBigIntNegate
* ins
) {
2391 auto* lir
= new (alloc()) LBigIntNegate(useRegister(ins
->input()), temp());
2393 assignSafepoint(lir
, ins
);
2396 void LIRGenerator::visitBigIntBitNot(MBigIntBitNot
* ins
) {
2398 new (alloc()) LBigIntBitNot(useRegister(ins
->input()), temp(), temp());
2400 assignSafepoint(lir
, ins
);
2403 void LIRGenerator::visitInt32ToStringWithBase(MInt32ToStringWithBase
* ins
) {
2404 MOZ_ASSERT(ins
->input()->type() == MIRType::Int32
);
2405 MOZ_ASSERT(ins
->base()->type() == MIRType::Int32
);
2408 ins
->base()->isConstant() ? ins
->base()->toConstant()->toInt32() : 0;
2411 if (2 <= baseInt
&& baseInt
<= 36) {
2412 base
= useRegisterOrConstant(ins
->base());
2414 base
= useRegister(ins
->base());
2417 auto* lir
= new (alloc())
2418 LInt32ToStringWithBase(useRegister(ins
->input()), base
, temp(), temp());
2420 assignSafepoint(lir
, ins
);
2423 void LIRGenerator::visitNumberParseInt(MNumberParseInt
* ins
) {
2424 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
2425 MOZ_ASSERT(ins
->radix()->type() == MIRType::Int32
);
2427 auto* lir
= new (alloc()) LNumberParseInt(useRegisterAtStart(ins
->string()),
2428 useRegisterAtStart(ins
->radix()),
2429 tempFixed(CallTempReg0
));
2430 defineReturn(lir
, ins
);
2431 assignSafepoint(lir
, ins
);
2434 void LIRGenerator::visitDoubleParseInt(MDoubleParseInt
* ins
) {
2435 MOZ_ASSERT(ins
->number()->type() == MIRType::Double
);
2438 new (alloc()) LDoubleParseInt(useRegister(ins
->number()), tempDouble());
2439 assignSnapshot(lir
, ins
->bailoutKind());
2443 void LIRGenerator::visitConcat(MConcat
* ins
) {
2444 MDefinition
* lhs
= ins
->getOperand(0);
2445 MDefinition
* rhs
= ins
->getOperand(1);
2447 MOZ_ASSERT(lhs
->type() == MIRType::String
);
2448 MOZ_ASSERT(rhs
->type() == MIRType::String
);
2449 MOZ_ASSERT(ins
->type() == MIRType::String
);
2451 LConcat
* lir
= new (alloc()) LConcat(
2452 useFixedAtStart(lhs
, CallTempReg0
), useFixedAtStart(rhs
, CallTempReg1
),
2453 tempFixed(CallTempReg0
), tempFixed(CallTempReg1
), tempFixed(CallTempReg2
),
2454 tempFixed(CallTempReg3
), tempFixed(CallTempReg4
));
2455 defineFixed(lir
, ins
, LAllocation(AnyRegister(CallTempReg5
)));
2456 assignSafepoint(lir
, ins
);
2459 void LIRGenerator::visitLinearizeString(MLinearizeString
* ins
) {
2460 MDefinition
* str
= ins
->string();
2461 MOZ_ASSERT(str
->type() == MIRType::String
);
2463 auto* lir
= new (alloc()) LLinearizeString(useRegister(str
));
2465 assignSafepoint(lir
, ins
);
2468 void LIRGenerator::visitLinearizeForCharAccess(MLinearizeForCharAccess
* ins
) {
2469 MDefinition
* str
= ins
->string();
2470 MDefinition
* idx
= ins
->index();
2472 MOZ_ASSERT(str
->type() == MIRType::String
);
2473 MOZ_ASSERT(idx
->type() == MIRType::Int32
);
2476 new (alloc()) LLinearizeForCharAccess(useRegister(str
), useRegister(idx
));
2478 assignSafepoint(lir
, ins
);
2481 void LIRGenerator::visitLinearizeForCodePointAccess(
2482 MLinearizeForCodePointAccess
* ins
) {
2483 MDefinition
* str
= ins
->string();
2484 MDefinition
* idx
= ins
->index();
2486 MOZ_ASSERT(str
->type() == MIRType::String
);
2487 MOZ_ASSERT(idx
->type() == MIRType::Int32
);
2489 auto* lir
= new (alloc())
2490 LLinearizeForCodePointAccess(useRegister(str
), useRegister(idx
), temp());
2492 assignSafepoint(lir
, ins
);
2495 void LIRGenerator::visitToRelativeStringIndex(MToRelativeStringIndex
* ins
) {
2496 MDefinition
* index
= ins
->index();
2497 MDefinition
* length
= ins
->length();
2499 MOZ_ASSERT(index
->type() == MIRType::Int32
);
2500 MOZ_ASSERT(length
->type() == MIRType::Int32
);
2502 auto* lir
= new (alloc())
2503 LToRelativeStringIndex(useRegister(index
), useRegister(length
));
2507 void LIRGenerator::visitCharCodeAt(MCharCodeAt
* ins
) {
2508 MDefinition
* str
= ins
->string();
2509 MDefinition
* idx
= ins
->index();
2511 MOZ_ASSERT(str
->type() == MIRType::String
);
2512 MOZ_ASSERT(idx
->type() == MIRType::Int32
);
2514 auto* lir
= new (alloc())
2515 LCharCodeAt(useRegister(str
), useRegisterOrZero(idx
), temp(), temp());
2517 assignSafepoint(lir
, ins
);
2520 void LIRGenerator::visitCharCodeAtOrNegative(MCharCodeAtOrNegative
* ins
) {
2521 MDefinition
* str
= ins
->string();
2522 MDefinition
* idx
= ins
->index();
2524 MOZ_ASSERT(str
->type() == MIRType::String
);
2525 MOZ_ASSERT(idx
->type() == MIRType::Int32
);
2527 auto* lir
= new (alloc()) LCharCodeAtOrNegative(
2528 useRegister(str
), useRegisterOrZero(idx
), temp(), temp());
2530 assignSafepoint(lir
, ins
);
2533 void LIRGenerator::visitCodePointAt(MCodePointAt
* ins
) {
2534 MDefinition
* str
= ins
->string();
2535 MDefinition
* idx
= ins
->index();
2537 MOZ_ASSERT(str
->type() == MIRType::String
);
2538 MOZ_ASSERT(idx
->type() == MIRType::Int32
);
2540 auto* lir
= new (alloc())
2541 LCodePointAt(useRegister(str
), useRegister(idx
), temp(), temp());
2543 assignSafepoint(lir
, ins
);
2546 void LIRGenerator::visitCodePointAtOrNegative(MCodePointAtOrNegative
* ins
) {
2547 MDefinition
* str
= ins
->string();
2548 MDefinition
* idx
= ins
->index();
2550 MOZ_ASSERT(str
->type() == MIRType::String
);
2551 MOZ_ASSERT(idx
->type() == MIRType::Int32
);
2553 auto* lir
= new (alloc()) LCodePointAtOrNegative(
2554 useRegister(str
), useRegister(idx
), temp(), temp());
2556 assignSafepoint(lir
, ins
);
2559 void LIRGenerator::visitNegativeToNaN(MNegativeToNaN
* ins
) {
2560 MOZ_ASSERT(ins
->input()->type() == MIRType::Int32
);
2562 auto* lir
= new (alloc()) LNegativeToNaN(useRegister(ins
->input()));
2563 defineBox(lir
, ins
);
2566 void LIRGenerator::visitNegativeToUndefined(MNegativeToUndefined
* ins
) {
2567 MOZ_ASSERT(ins
->input()->type() == MIRType::Int32
);
2569 auto* lir
= new (alloc()) LNegativeToUndefined(useRegister(ins
->input()));
2570 defineBox(lir
, ins
);
2573 void LIRGenerator::visitFromCharCode(MFromCharCode
* ins
) {
2574 MDefinition
* code
= ins
->code();
2576 MOZ_ASSERT(code
->type() == MIRType::Int32
);
2578 LFromCharCode
* lir
= new (alloc()) LFromCharCode(useRegister(code
));
2580 assignSafepoint(lir
, ins
);
2583 void LIRGenerator::visitFromCharCodeEmptyIfNegative(
2584 MFromCharCodeEmptyIfNegative
* ins
) {
2585 MDefinition
* code
= ins
->code();
2587 MOZ_ASSERT(code
->type() == MIRType::Int32
);
2589 auto* lir
= new (alloc()) LFromCharCodeEmptyIfNegative(useRegister(code
));
2591 assignSafepoint(lir
, ins
);
2594 void LIRGenerator::visitFromCharCodeUndefinedIfNegative(
2595 MFromCharCodeUndefinedIfNegative
* ins
) {
2596 MDefinition
* code
= ins
->code();
2598 MOZ_ASSERT(code
->type() == MIRType::Int32
);
2600 auto* lir
= new (alloc()) LFromCharCodeUndefinedIfNegative(useRegister(code
));
2601 defineBox(lir
, ins
);
2602 assignSafepoint(lir
, ins
);
2605 void LIRGenerator::visitFromCodePoint(MFromCodePoint
* ins
) {
2606 MDefinition
* codePoint
= ins
->codePoint();
2608 MOZ_ASSERT(codePoint
->type() == MIRType::Int32
);
2610 LFromCodePoint
* lir
=
2611 new (alloc()) LFromCodePoint(useRegister(codePoint
), temp(), temp());
2612 assignSnapshot(lir
, ins
->bailoutKind());
2614 assignSafepoint(lir
, ins
);
2617 void LIRGenerator::visitStringIncludes(MStringIncludes
* ins
) {
2618 auto* string
= ins
->string();
2619 MOZ_ASSERT(string
->type() == MIRType::String
);
2621 auto* searchStr
= ins
->searchString();
2622 MOZ_ASSERT(searchStr
->type() == MIRType::String
);
2624 if (searchStr
->isConstant()) {
2625 JSLinearString
* linear
= &searchStr
->toConstant()->toString()->asLinear();
2626 size_t length
= linear
->length();
2627 if (length
== 1 || length
== 2) {
2628 LDefinition tempDef
= LDefinition::BogusTemp();
2633 auto* lir
= new (alloc()) LStringIncludesSIMD(useRegister(string
), temp(),
2634 temp(), tempDef
, linear
);
2636 assignSafepoint(lir
, ins
);
2641 auto* lir
= new (alloc()) LStringIncludes(useRegisterAtStart(string
),
2642 useRegisterAtStart(searchStr
));
2643 defineReturn(lir
, ins
);
2644 assignSafepoint(lir
, ins
);
2647 void LIRGenerator::visitStringIndexOf(MStringIndexOf
* ins
) {
2648 auto* string
= ins
->string();
2649 MOZ_ASSERT(string
->type() == MIRType::String
);
2651 auto* searchStr
= ins
->searchString();
2652 MOZ_ASSERT(searchStr
->type() == MIRType::String
);
2654 if (searchStr
->isConstant()) {
2655 JSLinearString
* linear
= &searchStr
->toConstant()->toString()->asLinear();
2656 size_t length
= linear
->length();
2657 if (length
== 1 || length
== 2) {
2658 LDefinition tempDef
= LDefinition::BogusTemp();
2663 auto* lir
= new (alloc()) LStringIndexOfSIMD(useRegister(string
), temp(),
2664 temp(), tempDef
, linear
);
2666 assignSafepoint(lir
, ins
);
2671 auto* lir
= new (alloc())
2672 LStringIndexOf(useRegisterAtStart(string
), useRegisterAtStart(searchStr
));
2673 defineReturn(lir
, ins
);
2674 assignSafepoint(lir
, ins
);
2677 void LIRGenerator::visitStringLastIndexOf(MStringLastIndexOf
* ins
) {
2678 auto* string
= ins
->string();
2679 MOZ_ASSERT(string
->type() == MIRType::String
);
2681 auto* searchStr
= ins
->searchString();
2682 MOZ_ASSERT(searchStr
->type() == MIRType::String
);
2684 auto* lir
= new (alloc()) LStringLastIndexOf(useRegisterAtStart(string
),
2685 useRegisterAtStart(searchStr
));
2686 defineReturn(lir
, ins
);
2687 assignSafepoint(lir
, ins
);
2690 void LIRGenerator::visitStringStartsWith(MStringStartsWith
* ins
) {
2691 auto* string
= ins
->string();
2692 MOZ_ASSERT(string
->type() == MIRType::String
);
2694 auto* searchStr
= ins
->searchString();
2695 MOZ_ASSERT(searchStr
->type() == MIRType::String
);
2697 if (searchStr
->isConstant()) {
2698 JSLinearString
* linear
= &searchStr
->toConstant()->toString()->asLinear();
2700 if (MacroAssembler::canCompareStringCharsInline(linear
)) {
2701 auto* lir
= new (alloc())
2702 LStringStartsWithInline(useRegister(string
), temp(), linear
);
2704 assignSafepoint(lir
, ins
);
2709 auto* lir
= new (alloc()) LStringStartsWith(useRegisterAtStart(string
),
2710 useRegisterAtStart(searchStr
));
2711 defineReturn(lir
, ins
);
2712 assignSafepoint(lir
, ins
);
2715 void LIRGenerator::visitStringEndsWith(MStringEndsWith
* ins
) {
2716 auto* string
= ins
->string();
2717 MOZ_ASSERT(string
->type() == MIRType::String
);
2719 auto* searchStr
= ins
->searchString();
2720 MOZ_ASSERT(searchStr
->type() == MIRType::String
);
2722 if (searchStr
->isConstant()) {
2723 JSLinearString
* linear
= &searchStr
->toConstant()->toString()->asLinear();
2725 if (MacroAssembler::canCompareStringCharsInline(linear
)) {
2726 auto* lir
= new (alloc())
2727 LStringEndsWithInline(useRegister(string
), temp(), linear
);
2729 assignSafepoint(lir
, ins
);
2734 auto* lir
= new (alloc()) LStringEndsWith(useRegisterAtStart(string
),
2735 useRegisterAtStart(searchStr
));
2736 defineReturn(lir
, ins
);
2737 assignSafepoint(lir
, ins
);
2740 void LIRGenerator::visitStringConvertCase(MStringConvertCase
* ins
) {
2741 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
2743 if (ins
->mode() == MStringConvertCase::LowerCase
) {
2744 #ifdef JS_CODEGEN_X86
2745 // Due to lack of registers on x86, we reuse the string register as
2746 // temporary. As a result we only need four temporary registers and take a
2747 // bogus temporary as the fifth argument.
2748 LDefinition temp4
= LDefinition::BogusTemp();
2750 LDefinition temp4
= temp();
2752 auto* lir
= new (alloc())
2753 LStringToLowerCase(useRegister(ins
->string()), temp(), temp(), temp(),
2754 temp4
, tempByteOpRegister());
2756 assignSafepoint(lir
, ins
);
2759 new (alloc()) LStringToUpperCase(useRegisterAtStart(ins
->string()));
2760 defineReturn(lir
, ins
);
2761 assignSafepoint(lir
, ins
);
2765 void LIRGenerator::visitCharCodeConvertCase(MCharCodeConvertCase
* ins
) {
2766 MOZ_ASSERT(ins
->code()->type() == MIRType::Int32
);
2768 if (ins
->mode() == MCharCodeConvertCase::LowerCase
) {
2769 auto* lir
= new (alloc())
2770 LCharCodeToLowerCase(useRegister(ins
->code()), tempByteOpRegister());
2772 assignSafepoint(lir
, ins
);
2774 auto* lir
= new (alloc())
2775 LCharCodeToUpperCase(useRegister(ins
->code()), tempByteOpRegister());
2777 assignSafepoint(lir
, ins
);
2781 void LIRGenerator::visitStringTrimStartIndex(MStringTrimStartIndex
* ins
) {
2782 auto* string
= ins
->string();
2783 MOZ_ASSERT(string
->type() == MIRType::String
);
2785 auto* lir
= new (alloc()) LStringTrimStartIndex(useRegister(string
));
2787 assignSafepoint(lir
, ins
);
2790 void LIRGenerator::visitStringTrimEndIndex(MStringTrimEndIndex
* ins
) {
2791 auto* string
= ins
->string();
2792 MOZ_ASSERT(string
->type() == MIRType::String
);
2794 auto* start
= ins
->start();
2795 MOZ_ASSERT(start
->type() == MIRType::Int32
);
2797 auto* lir
= new (alloc())
2798 LStringTrimEndIndex(useRegister(string
), useRegister(start
));
2800 assignSafepoint(lir
, ins
);
2803 void LIRGenerator::visitStart(MStart
* start
) {}
2805 void LIRGenerator::visitNop(MNop
* nop
) {}
2807 void LIRGenerator::visitLimitedTruncate(MLimitedTruncate
* nop
) {
2808 redefine(nop
, nop
->input());
2811 void LIRGenerator::visitOsrEntry(MOsrEntry
* entry
) {
2812 LOsrEntry
* lir
= new (alloc()) LOsrEntry(temp());
2813 defineFixed(lir
, entry
, LAllocation(AnyRegister(OsrFrameReg
)));
2816 void LIRGenerator::visitOsrValue(MOsrValue
* value
) {
2817 LOsrValue
* lir
= new (alloc()) LOsrValue(useRegister(value
->entry()));
2818 defineBox(lir
, value
);
2821 void LIRGenerator::visitOsrReturnValue(MOsrReturnValue
* value
) {
2822 LOsrReturnValue
* lir
=
2823 new (alloc()) LOsrReturnValue(useRegister(value
->entry()));
2824 defineBox(lir
, value
);
2827 void LIRGenerator::visitOsrEnvironmentChain(MOsrEnvironmentChain
* object
) {
2828 LOsrEnvironmentChain
* lir
=
2829 new (alloc()) LOsrEnvironmentChain(useRegister(object
->entry()));
2830 define(lir
, object
);
2833 void LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject
* object
) {
2834 LOsrArgumentsObject
* lir
=
2835 new (alloc()) LOsrArgumentsObject(useRegister(object
->entry()));
2836 define(lir
, object
);
2839 void LIRGenerator::visitToDouble(MToDouble
* convert
) {
2840 MDefinition
* opd
= convert
->input();
2841 mozilla::DebugOnly
<MToFPInstruction::ConversionKind
> conversion
=
2842 convert
->conversion();
2844 switch (opd
->type()) {
2845 case MIRType::Value
: {
2846 LValueToDouble
* lir
= new (alloc()) LValueToDouble(useBox(opd
));
2847 assignSnapshot(lir
, convert
->bailoutKind());
2848 define(lir
, convert
);
2853 MOZ_ASSERT(conversion
== MToFPInstruction::NonStringPrimitives
);
2854 lowerConstantDouble(0, convert
);
2857 case MIRType::Undefined
:
2858 MOZ_ASSERT(conversion
== MToFPInstruction::NonStringPrimitives
);
2859 lowerConstantDouble(GenericNaN(), convert
);
2862 case MIRType::Boolean
:
2863 MOZ_ASSERT(conversion
== MToFPInstruction::NonStringPrimitives
);
2866 case MIRType::Int32
: {
2867 LInt32ToDouble
* lir
=
2868 new (alloc()) LInt32ToDouble(useRegisterAtStart(opd
));
2869 define(lir
, convert
);
2873 case MIRType::Float32
: {
2874 LFloat32ToDouble
* lir
=
2875 new (alloc()) LFloat32ToDouble(useRegisterAtStart(opd
));
2876 define(lir
, convert
);
2880 case MIRType::Double
:
2881 redefine(convert
, opd
);
2885 // Objects might be effectful. Symbols will throw.
2886 // Strings are complicated - we don't handle them yet.
2887 MOZ_CRASH("unexpected type");
2891 void LIRGenerator::visitToFloat32(MToFloat32
* convert
) {
2892 MDefinition
* opd
= convert
->input();
2893 mozilla::DebugOnly
<MToFloat32::ConversionKind
> conversion
=
2894 convert
->conversion();
2896 switch (opd
->type()) {
2897 case MIRType::Value
: {
2898 LValueToFloat32
* lir
= new (alloc()) LValueToFloat32(useBox(opd
));
2899 assignSnapshot(lir
, convert
->bailoutKind());
2900 define(lir
, convert
);
2905 MOZ_ASSERT(conversion
== MToFPInstruction::NonStringPrimitives
);
2906 lowerConstantFloat32(0, convert
);
2909 case MIRType::Undefined
:
2910 MOZ_ASSERT(conversion
== MToFPInstruction::NonStringPrimitives
);
2911 lowerConstantFloat32(GenericNaN(), convert
);
2914 case MIRType::Boolean
:
2915 MOZ_ASSERT(conversion
== MToFPInstruction::NonStringPrimitives
);
2918 case MIRType::Int32
: {
2919 LInt32ToFloat32
* lir
=
2920 new (alloc()) LInt32ToFloat32(useRegisterAtStart(opd
));
2921 define(lir
, convert
);
2925 case MIRType::Double
: {
2926 LDoubleToFloat32
* lir
=
2927 new (alloc()) LDoubleToFloat32(useRegisterAtStart(opd
));
2928 define(lir
, convert
);
2932 case MIRType::Float32
:
2933 redefine(convert
, opd
);
2937 // Objects might be effectful. Symbols will throw.
2938 // Strings are complicated - we don't handle them yet.
2939 MOZ_CRASH("unexpected type");
2943 void LIRGenerator::visitToNumberInt32(MToNumberInt32
* convert
) {
2944 MDefinition
* opd
= convert
->input();
2946 switch (opd
->type()) {
2947 case MIRType::Value
: {
2948 auto* lir
= new (alloc()) LValueToInt32(useBox(opd
), tempDouble(), temp(),
2949 LValueToInt32::NORMAL
);
2950 assignSnapshot(lir
, convert
->bailoutKind());
2951 define(lir
, convert
);
2952 if (lir
->mode() == LValueToInt32::TRUNCATE
) {
2953 assignSafepoint(lir
, convert
);
2959 MOZ_ASSERT(convert
->conversion() == IntConversionInputKind::Any
);
2960 define(new (alloc()) LInteger(0), convert
);
2963 case MIRType::Boolean
:
2964 MOZ_ASSERT(convert
->conversion() == IntConversionInputKind::Any
||
2965 convert
->conversion() ==
2966 IntConversionInputKind::NumbersOrBoolsOnly
);
2967 redefine(convert
, opd
);
2970 case MIRType::Int32
:
2971 redefine(convert
, opd
);
2974 case MIRType::Float32
: {
2975 LFloat32ToInt32
* lir
= new (alloc()) LFloat32ToInt32(useRegister(opd
));
2976 assignSnapshot(lir
, convert
->bailoutKind());
2977 define(lir
, convert
);
2981 case MIRType::Double
: {
2982 LDoubleToInt32
* lir
= new (alloc()) LDoubleToInt32(useRegister(opd
));
2983 assignSnapshot(lir
, convert
->bailoutKind());
2984 define(lir
, convert
);
2988 case MIRType::String
:
2989 case MIRType::Symbol
:
2990 case MIRType::BigInt
:
2991 case MIRType::Object
:
2992 case MIRType::Undefined
:
2993 // Objects might be effectful. Symbols and BigInts throw. Undefined
2994 // coerces to NaN, not int32.
2995 MOZ_CRASH("ToInt32 invalid input type");
2998 MOZ_CRASH("unexpected type");
3002 void LIRGenerator::visitBooleanToInt32(MBooleanToInt32
* convert
) {
3003 MDefinition
* opd
= convert
->input();
3004 MOZ_ASSERT(opd
->type() == MIRType::Boolean
);
3005 redefine(convert
, opd
);
3008 void LIRGenerator::visitTruncateToInt32(MTruncateToInt32
* truncate
) {
3009 MDefinition
* opd
= truncate
->input();
3011 switch (opd
->type()) {
3012 case MIRType::Value
: {
3013 LValueToInt32
* lir
= new (alloc()) LValueToInt32(
3014 useBox(opd
), tempDouble(), temp(), LValueToInt32::TRUNCATE
);
3015 assignSnapshot(lir
, truncate
->bailoutKind());
3016 define(lir
, truncate
);
3017 assignSafepoint(lir
, truncate
);
3022 case MIRType::Undefined
:
3023 define(new (alloc()) LInteger(0), truncate
);
3026 case MIRType::Int32
:
3027 case MIRType::Boolean
:
3028 redefine(truncate
, opd
);
3031 case MIRType::Double
:
3032 // May call into JS::ToInt32() on the slow OOL path.
3033 gen
->setNeedsStaticStackAlignment();
3034 lowerTruncateDToInt32(truncate
);
3037 case MIRType::Float32
:
3038 // May call into JS::ToInt32() on the slow OOL path.
3039 gen
->setNeedsStaticStackAlignment();
3040 lowerTruncateFToInt32(truncate
);
3044 // Objects might be effectful. Symbols throw.
3045 // Strings are complicated - we don't handle them yet.
3046 MOZ_CRASH("unexpected type");
3050 void LIRGenerator::visitInt32ToIntPtr(MInt32ToIntPtr
* ins
) {
3051 MDefinition
* input
= ins
->input();
3052 MOZ_ASSERT(input
->type() == MIRType::Int32
);
3053 MOZ_ASSERT(ins
->type() == MIRType::IntPtr
);
3056 // If the result is only used by instructions that expect a bounds-checked
3057 // index, we must have eliminated or hoisted a bounds check and we can assume
3058 // the index is non-negative. This lets us generate more efficient code.
3059 if (ins
->canBeNegative()) {
3060 bool canBeNegative
= false;
3061 for (MUseDefIterator
iter(ins
); iter
; iter
++) {
3062 if (!iter
.def()->isSpectreMaskIndex() &&
3063 !iter
.def()->isLoadUnboxedScalar() &&
3064 !iter
.def()->isStoreUnboxedScalar() &&
3065 !iter
.def()->isLoadDataViewElement() &&
3066 !iter
.def()->isStoreDataViewElement()) {
3067 canBeNegative
= true;
3071 if (!canBeNegative
) {
3072 ins
->setCanNotBeNegative();
3076 if (ins
->canBeNegative()) {
3077 auto* lir
= new (alloc()) LInt32ToIntPtr(useAnyAtStart(input
));
3080 redefine(ins
, input
);
3083 // On 32-bit platforms this is a no-op.
3084 redefine(ins
, input
);
3088 void LIRGenerator::visitNonNegativeIntPtrToInt32(
3089 MNonNegativeIntPtrToInt32
* ins
) {
3090 MDefinition
* input
= ins
->input();
3091 MOZ_ASSERT(input
->type() == MIRType::IntPtr
);
3092 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
3096 new (alloc()) LNonNegativeIntPtrToInt32(useRegisterAtStart(input
));
3097 assignSnapshot(lir
, ins
->bailoutKind());
3098 defineReuseInput(lir
, ins
, 0);
3100 // On 32-bit platforms this is a no-op.
3101 redefine(ins
, input
);
3105 void LIRGenerator::visitWasmExtendU32Index(MWasmExtendU32Index
* ins
) {
3107 // Technically this produces an Int64 register and I guess we could clean that
3108 // up, but it's a 64-bit only operation, so it doesn't actually matter.
3110 MDefinition
* input
= ins
->input();
3111 MOZ_ASSERT(input
->type() == MIRType::Int32
);
3112 MOZ_ASSERT(ins
->type() == MIRType::Int64
);
3114 // Input reuse is OK even on ARM64 because this node *must* reuse its input in
3115 // order not to generate any code at all, as is the intent.
3116 auto* lir
= new (alloc()) LWasmExtendU32Index(useRegisterAtStart(input
));
3117 defineReuseInput(lir
, ins
, 0);
3119 MOZ_CRASH("64-bit only");
3123 void LIRGenerator::visitWasmWrapU32Index(MWasmWrapU32Index
* ins
) {
3124 MDefinition
* input
= ins
->input();
3125 MOZ_ASSERT(input
->type() == MIRType::Int64
);
3126 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
3128 // Tricky: On 64-bit, this just returns its input (except on MIPS64 there may
3129 // be a sign/zero extension). On 32-bit, it returns the low register of the
3130 // input, and should generate no code.
3132 // If this assertion does not hold then using "input" unadorned as an alias
3133 // for the low register will not work.
3134 #if defined(JS_NUNBOX32)
3135 static_assert(INT64LOW_INDEX
== 0);
3138 auto* lir
= new (alloc()) LWasmWrapU32Index(useRegisterAtStart(input
));
3139 defineReuseInput(lir
, ins
, 0);
3142 void LIRGenerator::visitIntPtrToDouble(MIntPtrToDouble
* ins
) {
3143 MDefinition
* input
= ins
->input();
3144 MOZ_ASSERT(input
->type() == MIRType::IntPtr
);
3145 MOZ_ASSERT(ins
->type() == MIRType::Double
);
3147 auto* lir
= new (alloc()) LIntPtrToDouble(useRegister(input
));
3151 void LIRGenerator::visitAdjustDataViewLength(MAdjustDataViewLength
* ins
) {
3152 MDefinition
* input
= ins
->input();
3153 MOZ_ASSERT(input
->type() == MIRType::IntPtr
);
3155 auto* lir
= new (alloc()) LAdjustDataViewLength(useRegisterAtStart(input
));
3156 assignSnapshot(lir
, ins
->bailoutKind());
3157 defineReuseInput(lir
, ins
, 0);
3160 void LIRGenerator::visitToBigInt(MToBigInt
* ins
) {
3161 MDefinition
* opd
= ins
->input();
3163 switch (opd
->type()) {
3164 case MIRType::Value
: {
3165 auto* lir
= new (alloc()) LValueToBigInt(useBox(opd
));
3166 assignSnapshot(lir
, ins
->bailoutKind());
3168 assignSafepoint(lir
, ins
);
3172 case MIRType::BigInt
:
3177 MOZ_CRASH("unexpected type");
3181 void LIRGenerator::visitToInt64(MToInt64
* ins
) {
3182 MDefinition
* opd
= ins
->input();
3184 switch (opd
->type()) {
3185 case MIRType::Value
: {
3186 auto* lir
= new (alloc()) LValueToInt64(useBox(opd
), temp());
3187 assignSnapshot(lir
, ins
->bailoutKind());
3188 defineInt64(lir
, ins
);
3189 assignSafepoint(lir
, ins
);
3193 case MIRType::Boolean
: {
3194 auto* lir
= new (alloc()) LBooleanToInt64(useRegisterAtStart(opd
));
3195 defineInt64(lir
, ins
);
3199 case MIRType::String
: {
3200 auto* lir
= new (alloc()) LStringToInt64(useRegister(opd
));
3201 defineInt64(lir
, ins
);
3202 assignSafepoint(lir
, ins
);
3206 // An Int64 may be passed here from a BigInt to Int64 conversion.
3207 case MIRType::Int64
: {
3213 // Undefined, Null, Number, and Symbol throw.
3214 // Objects may be effectful.
3215 // BigInt operands are eliminated by the type policy.
3216 MOZ_CRASH("unexpected type");
3220 void LIRGenerator::visitTruncateBigIntToInt64(MTruncateBigIntToInt64
* ins
) {
3221 MOZ_ASSERT(ins
->input()->type() == MIRType::BigInt
);
3222 auto* lir
= new (alloc()) LTruncateBigIntToInt64(useRegister(ins
->input()));
3223 defineInt64(lir
, ins
);
3226 void LIRGenerator::visitInt64ToBigInt(MInt64ToBigInt
* ins
) {
3227 MOZ_ASSERT(ins
->input()->type() == MIRType::Int64
);
3229 new (alloc()) LInt64ToBigInt(useInt64Register(ins
->input()), temp());
3231 assignSafepoint(lir
, ins
);
3234 void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32
* ins
) {
3235 MDefinition
* input
= ins
->input();
3236 switch (input
->type()) {
3237 case MIRType::Double
:
3238 case MIRType::Float32
: {
3239 auto* lir
= new (alloc()) LWasmTruncateToInt32(useRegisterAtStart(input
));
3244 MOZ_CRASH("unexpected type in WasmTruncateToInt32");
3248 void LIRGenerator::visitWasmBuiltinTruncateToInt32(
3249 MWasmBuiltinTruncateToInt32
* truncate
) {
3250 mozilla::DebugOnly
<MDefinition
*> opd
= truncate
->input();
3251 MOZ_ASSERT(opd
->type() == MIRType::Double
|| opd
->type() == MIRType::Float32
);
3253 // May call into JS::ToInt32() on the slow OOL path.
3254 gen
->setNeedsStaticStackAlignment();
3255 lowerWasmBuiltinTruncateToInt32(truncate
);
3258 void LIRGenerator::visitWasmAnyRefFromJSValue(MWasmAnyRefFromJSValue
* ins
) {
3259 LWasmAnyRefFromJSValue
* lir
=
3260 new (alloc()) LWasmAnyRefFromJSValue(useBox(ins
->input()), tempDouble());
3262 assignSafepoint(lir
, ins
);
3265 void LIRGenerator::visitWasmAnyRefFromJSObject(MWasmAnyRefFromJSObject
* ins
) {
3266 LWasmAnyRefFromJSObject
* lir
=
3267 new (alloc()) LWasmAnyRefFromJSObject(useRegisterAtStart(ins
->input()));
3271 void LIRGenerator::visitWasmAnyRefFromJSString(MWasmAnyRefFromJSString
* ins
) {
3272 LWasmAnyRefFromJSString
* lir
=
3273 new (alloc()) LWasmAnyRefFromJSString(useRegisterAtStart(ins
->input()));
3277 void LIRGenerator::visitWasmNewI31Ref(MWasmNewI31Ref
* ins
) {
3278 LWasmNewI31Ref
* lir
= new (alloc()) LWasmNewI31Ref(useRegister(ins
->input()));
3282 void LIRGenerator::visitWasmI31RefGet(MWasmI31RefGet
* ins
) {
3283 LWasmI31RefGet
* lir
= new (alloc()) LWasmI31RefGet(useRegister(ins
->input()));
3287 void LIRGenerator::visitWrapInt64ToInt32(MWrapInt64ToInt32
* ins
) {
3288 define(new (alloc()) LWrapInt64ToInt32(useInt64AtStart(ins
->input())), ins
);
3291 void LIRGenerator::visitToString(MToString
* ins
) {
3292 MDefinition
* opd
= ins
->input();
3294 switch (opd
->type()) {
3295 case MIRType::Null
: {
3296 const JSAtomState
& names
= gen
->runtime
->names();
3297 LPointer
* lir
= new (alloc()) LPointer(names
.null
);
3302 case MIRType::Undefined
: {
3303 const JSAtomState
& names
= gen
->runtime
->names();
3304 LPointer
* lir
= new (alloc()) LPointer(names
.undefined
);
3309 case MIRType::Boolean
: {
3310 LBooleanToString
* lir
= new (alloc()) LBooleanToString(useRegister(opd
));
3315 case MIRType::Double
: {
3316 LDoubleToString
* lir
=
3317 new (alloc()) LDoubleToString(useRegister(opd
), temp());
3320 assignSafepoint(lir
, ins
);
3324 case MIRType::Int32
: {
3325 LIntToString
* lir
= new (alloc()) LIntToString(useRegister(opd
));
3328 assignSafepoint(lir
, ins
);
3332 case MIRType::String
:
3333 redefine(ins
, ins
->input());
3336 case MIRType::Value
: {
3337 LValueToString
* lir
=
3338 new (alloc()) LValueToString(useBox(opd
), tempToUnbox());
3339 if (ins
->needsSnapshot()) {
3340 assignSnapshot(lir
, ins
->bailoutKind());
3343 assignSafepoint(lir
, ins
);
3348 // Float32, symbols, bigint, and objects are not supported.
3349 MOZ_CRASH("unexpected type");
3353 void LIRGenerator::visitRegExp(MRegExp
* ins
) {
3354 LRegExp
* lir
= new (alloc()) LRegExp(temp());
3356 assignSafepoint(lir
, ins
);
3359 void LIRGenerator::visitRegExpMatcher(MRegExpMatcher
* ins
) {
3360 MOZ_ASSERT(ins
->regexp()->type() == MIRType::Object
);
3361 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
3362 MOZ_ASSERT(ins
->lastIndex()->type() == MIRType::Int32
);
3364 LRegExpMatcher
* lir
= new (alloc()) LRegExpMatcher(
3365 useFixedAtStart(ins
->regexp(), RegExpMatcherRegExpReg
),
3366 useFixedAtStart(ins
->string(), RegExpMatcherStringReg
),
3367 useFixedAtStart(ins
->lastIndex(), RegExpMatcherLastIndexReg
));
3368 defineReturn(lir
, ins
);
3369 assignSafepoint(lir
, ins
);
3372 void LIRGenerator::visitRegExpSearcher(MRegExpSearcher
* ins
) {
3373 MOZ_ASSERT(ins
->regexp()->type() == MIRType::Object
);
3374 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
3375 MOZ_ASSERT(ins
->lastIndex()->type() == MIRType::Int32
);
3377 LRegExpSearcher
* lir
= new (alloc()) LRegExpSearcher(
3378 useFixedAtStart(ins
->regexp(), RegExpSearcherRegExpReg
),
3379 useFixedAtStart(ins
->string(), RegExpSearcherStringReg
),
3380 useFixedAtStart(ins
->lastIndex(), RegExpSearcherLastIndexReg
));
3381 defineReturn(lir
, ins
);
3382 assignSafepoint(lir
, ins
);
3385 void LIRGenerator::visitRegExpSearcherLastLimit(MRegExpSearcherLastLimit
* ins
) {
3386 auto* lir
= new (alloc()) LRegExpSearcherLastLimit(temp());
3390 void LIRGenerator::visitRegExpExecMatch(MRegExpExecMatch
* ins
) {
3391 MOZ_ASSERT(ins
->regexp()->type() == MIRType::Object
);
3392 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
3394 auto* lir
= new (alloc())
3395 LRegExpExecMatch(useFixedAtStart(ins
->regexp(), RegExpMatcherRegExpReg
),
3396 useFixedAtStart(ins
->string(), RegExpMatcherStringReg
));
3397 defineReturn(lir
, ins
);
3398 assignSafepoint(lir
, ins
);
3401 void LIRGenerator::visitRegExpExecTest(MRegExpExecTest
* ins
) {
3402 MOZ_ASSERT(ins
->regexp()->type() == MIRType::Object
);
3403 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
3405 auto* lir
= new (alloc())
3406 LRegExpExecTest(useFixedAtStart(ins
->regexp(), RegExpExecTestRegExpReg
),
3407 useFixedAtStart(ins
->string(), RegExpExecTestStringReg
));
3408 defineReturn(lir
, ins
);
3409 assignSafepoint(lir
, ins
);
3412 void LIRGenerator::visitRegExpHasCaptureGroups(MRegExpHasCaptureGroups
* ins
) {
3413 MOZ_ASSERT(ins
->regexp()->type() == MIRType::Object
);
3414 MOZ_ASSERT(ins
->input()->type() == MIRType::String
);
3415 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
3417 auto* lir
= new (alloc()) LRegExpHasCaptureGroups(useRegister(ins
->regexp()),
3418 useRegister(ins
->input()));
3420 assignSafepoint(lir
, ins
);
3423 void LIRGenerator::visitRegExpPrototypeOptimizable(
3424 MRegExpPrototypeOptimizable
* ins
) {
3425 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
3426 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
3427 LRegExpPrototypeOptimizable
* lir
= new (alloc())
3428 LRegExpPrototypeOptimizable(useRegister(ins
->object()), temp());
3432 void LIRGenerator::visitRegExpInstanceOptimizable(
3433 MRegExpInstanceOptimizable
* ins
) {
3434 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
3435 MOZ_ASSERT(ins
->proto()->type() == MIRType::Object
);
3436 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
3437 LRegExpInstanceOptimizable
* lir
= new (alloc()) LRegExpInstanceOptimizable(
3438 useRegister(ins
->object()), useRegister(ins
->proto()), temp());
3442 void LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex
* ins
) {
3443 MOZ_ASSERT(ins
->str()->type() == MIRType::String
);
3444 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
3445 LGetFirstDollarIndex
* lir
= new (alloc())
3446 LGetFirstDollarIndex(useRegister(ins
->str()), temp(), temp(), temp());
3448 assignSafepoint(lir
, ins
);
3451 void LIRGenerator::visitStringReplace(MStringReplace
* ins
) {
3452 MOZ_ASSERT(ins
->pattern()->type() == MIRType::String
);
3453 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
3454 MOZ_ASSERT(ins
->replacement()->type() == MIRType::String
);
3456 LStringReplace
* lir
= new (alloc())
3457 LStringReplace(useRegisterOrConstantAtStart(ins
->string()),
3458 useRegisterAtStart(ins
->pattern()),
3459 useRegisterOrConstantAtStart(ins
->replacement()));
3460 defineReturn(lir
, ins
);
3461 assignSafepoint(lir
, ins
);
3464 void LIRGenerator::visitBinaryCache(MBinaryCache
* ins
) {
3465 MDefinition
* lhs
= ins
->getOperand(0);
3466 MDefinition
* rhs
= ins
->getOperand(1);
3468 MOZ_ASSERT(ins
->type() == MIRType::Value
|| ins
->type() == MIRType::Boolean
);
3470 if (ins
->type() == MIRType::Value
) {
3471 LBinaryValueCache
* valueLir
= new (alloc()) LBinaryValueCache(
3472 useBox(lhs
), useBox(rhs
), tempFixed(FloatReg0
), tempFixed(FloatReg1
));
3473 defineBox(valueLir
, ins
);
3476 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
3477 LBinaryBoolCache
* boolLir
= new (alloc()) LBinaryBoolCache(
3478 useBox(lhs
), useBox(rhs
), tempFixed(FloatReg0
), tempFixed(FloatReg1
));
3479 define(boolLir
, ins
);
3482 assignSafepoint(lir
, ins
);
3485 void LIRGenerator::visitUnaryCache(MUnaryCache
* ins
) {
3486 MDefinition
* input
= ins
->getOperand(0);
3487 MOZ_ASSERT(ins
->type() == MIRType::Value
);
3489 LUnaryCache
* lir
= new (alloc()) LUnaryCache(useBox(input
));
3490 defineBox(lir
, ins
);
3491 assignSafepoint(lir
, ins
);
3494 void LIRGenerator::visitModuleMetadata(MModuleMetadata
* ins
) {
3495 LModuleMetadata
* lir
= new (alloc()) LModuleMetadata();
3496 defineReturn(lir
, ins
);
3497 assignSafepoint(lir
, ins
);
3500 void LIRGenerator::visitDynamicImport(MDynamicImport
* ins
) {
3501 LDynamicImport
* lir
= new (alloc()) LDynamicImport(
3502 useBoxAtStart(ins
->specifier()), useBoxAtStart(ins
->options()));
3503 defineReturn(lir
, ins
);
3504 assignSafepoint(lir
, ins
);
3507 void LIRGenerator::visitLambda(MLambda
* ins
) {
3508 MOZ_ASSERT(ins
->environmentChain()->type() == MIRType::Object
);
3511 new (alloc()) LLambda(useRegister(ins
->environmentChain()), temp());
3513 assignSafepoint(lir
, ins
);
3516 void LIRGenerator::visitFunctionWithProto(MFunctionWithProto
* ins
) {
3517 MOZ_ASSERT(ins
->environmentChain()->type() == MIRType::Object
);
3518 MOZ_ASSERT(ins
->prototype()->type() == MIRType::Object
);
3520 auto* lir
= new (alloc())
3521 LFunctionWithProto(useRegisterAtStart(ins
->environmentChain()),
3522 useRegisterAtStart(ins
->prototype()));
3523 defineReturn(lir
, ins
);
3524 assignSafepoint(lir
, ins
);
3527 void LIRGenerator::visitSetFunName(MSetFunName
* ins
) {
3528 MOZ_ASSERT(ins
->fun()->type() == MIRType::Object
);
3529 MOZ_ASSERT(ins
->name()->type() == MIRType::Value
);
3531 LSetFunName
* lir
= new (alloc())
3532 LSetFunName(useRegisterAtStart(ins
->fun()), useBoxAtStart(ins
->name()));
3534 assignSafepoint(lir
, ins
);
3537 void LIRGenerator::visitNewLexicalEnvironmentObject(
3538 MNewLexicalEnvironmentObject
* ins
) {
3539 auto* lir
= new (alloc()) LNewLexicalEnvironmentObject(temp());
3542 assignSafepoint(lir
, ins
);
3545 void LIRGenerator::visitNewClassBodyEnvironmentObject(
3546 MNewClassBodyEnvironmentObject
* ins
) {
3547 auto* lir
= new (alloc()) LNewClassBodyEnvironmentObject(temp());
3550 assignSafepoint(lir
, ins
);
3553 void LIRGenerator::visitNewVarEnvironmentObject(MNewVarEnvironmentObject
* ins
) {
3554 auto* lir
= new (alloc()) LNewVarEnvironmentObject(temp());
3557 assignSafepoint(lir
, ins
);
3560 void LIRGenerator::visitKeepAliveObject(MKeepAliveObject
* ins
) {
3561 MDefinition
* obj
= ins
->object();
3562 MOZ_ASSERT(obj
->type() == MIRType::Object
);
3564 add(new (alloc()) LKeepAliveObject(useKeepalive(obj
)), ins
);
3567 void LIRGenerator::visitDebugEnterGCUnsafeRegion(
3568 MDebugEnterGCUnsafeRegion
* ins
) {
3569 add(new (alloc()) LDebugEnterGCUnsafeRegion(temp()), ins
);
3572 void LIRGenerator::visitDebugLeaveGCUnsafeRegion(
3573 MDebugLeaveGCUnsafeRegion
* ins
) {
3574 add(new (alloc()) LDebugLeaveGCUnsafeRegion(temp()), ins
);
3577 void LIRGenerator::visitSlots(MSlots
* ins
) {
3578 define(new (alloc()) LSlots(useRegisterAtStart(ins
->object())), ins
);
3581 void LIRGenerator::visitElements(MElements
* ins
) {
3582 define(new (alloc()) LElements(useRegisterAtStart(ins
->object())), ins
);
3585 void LIRGenerator::visitLoadDynamicSlot(MLoadDynamicSlot
* ins
) {
3586 MOZ_ASSERT(ins
->type() == MIRType::Value
);
3587 if (ins
->usedAsPropertyKey()) {
3588 auto* lir
= new (alloc())
3589 LLoadDynamicSlotAndAtomize(useRegister(ins
->slots()), temp());
3590 defineBox(lir
, ins
);
3591 assignSafepoint(lir
, ins
);
3593 defineBox(new (alloc()) LLoadDynamicSlotV(useRegisterAtStart(ins
->slots())),
3598 void LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment
* ins
) {
3599 define(new (alloc())
3600 LFunctionEnvironment(useRegisterAtStart(ins
->function())),
3604 void LIRGenerator::visitHomeObject(MHomeObject
* ins
) {
3605 define(new (alloc()) LHomeObject(useRegisterAtStart(ins
->function())), ins
);
3608 void LIRGenerator::visitHomeObjectSuperBase(MHomeObjectSuperBase
* ins
) {
3609 MOZ_ASSERT(ins
->homeObject()->type() == MIRType::Object
);
3610 MOZ_ASSERT(ins
->type() == MIRType::Value
);
3613 new (alloc()) LHomeObjectSuperBase(useRegisterAtStart(ins
->homeObject()));
3614 defineBox(lir
, ins
);
3617 void LIRGenerator::visitInterruptCheck(MInterruptCheck
* ins
) {
3618 LInstruction
* lir
= new (alloc()) LInterruptCheck();
3620 assignSafepoint(lir
, ins
);
3623 void LIRGenerator::visitWasmInterruptCheck(MWasmInterruptCheck
* ins
) {
3625 new (alloc()) LWasmInterruptCheck(useRegisterAtStart(ins
->instance()));
3627 assignWasmSafepoint(lir
);
3630 void LIRGenerator::visitWasmTrap(MWasmTrap
* ins
) {
3631 add(new (alloc()) LWasmTrap
, ins
);
3634 void LIRGenerator::visitWasmTrapIfNull(MWasmTrapIfNull
* ins
) {
3635 auto* lir
= new (alloc()) LWasmTrapIfNull(useRegister(ins
->ref()));
3639 void LIRGenerator::visitWasmReinterpret(MWasmReinterpret
* ins
) {
3640 if (ins
->type() == MIRType::Int64
) {
3641 defineInt64(new (alloc())
3642 LWasmReinterpretToI64(useRegisterAtStart(ins
->input())),
3644 } else if (ins
->input()->type() == MIRType::Int64
) {
3645 define(new (alloc())
3646 LWasmReinterpretFromI64(useInt64RegisterAtStart(ins
->input())),
3649 define(new (alloc()) LWasmReinterpret(useRegisterAtStart(ins
->input())),
3654 void LIRGenerator::visitStoreDynamicSlot(MStoreDynamicSlot
* ins
) {
3657 switch (ins
->value()->type()) {
3658 case MIRType::Value
:
3660 LStoreDynamicSlotV(useRegister(ins
->slots()), useBox(ins
->value()));
3664 case MIRType::Double
:
3665 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins
->slots()),
3666 useRegister(ins
->value())),
3670 case MIRType::Float32
:
3671 MOZ_CRASH("Float32 shouldn't be stored in a slot.");
3674 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins
->slots()),
3675 useRegisterOrConstant(ins
->value())),
3681 // Returns true iff |def| is a constant that's either not a GC thing or is not
3682 // allocated in the nursery.
3683 static bool IsNonNurseryConstant(MDefinition
* def
) {
3684 if (!def
->isConstant()) {
3687 Value v
= def
->toConstant()->toJSValue();
3688 return !v
.isGCThing() || !IsInsideNursery(v
.toGCThing());
3691 void LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier
* ins
) {
3692 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
3694 // LPostWriteBarrier assumes that if it has a constant object then that
3695 // object is tenured, and does not need to be tested for being in the
3696 // nursery. Ensure that assumption holds by lowering constant nursery
3697 // objects to a register.
3698 bool useConstantObject
= IsNonNurseryConstant(ins
->object());
3700 switch (ins
->value()->type()) {
3701 case MIRType::Object
: {
3703 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3704 LPostWriteBarrierO
* lir
= new (alloc())
3705 LPostWriteBarrierO(useConstantObject
? useOrConstant(ins
->object())
3706 : useRegister(ins
->object()),
3707 useRegister(ins
->value()), tmp
);
3709 assignSafepoint(lir
, ins
);
3712 case MIRType::String
: {
3714 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3715 LPostWriteBarrierS
* lir
= new (alloc())
3716 LPostWriteBarrierS(useConstantObject
? useOrConstant(ins
->object())
3717 : useRegister(ins
->object()),
3718 useRegister(ins
->value()), tmp
);
3720 assignSafepoint(lir
, ins
);
3723 case MIRType::BigInt
: {
3725 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3726 auto* lir
= new (alloc())
3727 LPostWriteBarrierBI(useConstantObject
? useOrConstant(ins
->object())
3728 : useRegister(ins
->object()),
3729 useRegister(ins
->value()), tmp
);
3731 assignSafepoint(lir
, ins
);
3734 case MIRType::Value
: {
3736 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3737 LPostWriteBarrierV
* lir
= new (alloc())
3738 LPostWriteBarrierV(useConstantObject
? useOrConstant(ins
->object())
3739 : useRegister(ins
->object()),
3740 useBox(ins
->value()), tmp
);
3742 assignSafepoint(lir
, ins
);
3746 // Currently, only objects and strings can be in the nursery. Other
3747 // instruction types cannot hold nursery pointers.
3752 void LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier
* ins
) {
3753 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
3754 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
3756 // LPostWriteElementBarrier assumes that if it has a constant object then that
3757 // object is tenured, and does not need to be tested for being in the
3758 // nursery. Ensure that assumption holds by lowering constant nursery
3759 // objects to a register.
3760 bool useConstantObject
=
3761 ins
->object()->isConstant() &&
3762 !IsInsideNursery(&ins
->object()->toConstant()->toObject());
3764 switch (ins
->value()->type()) {
3765 case MIRType::Object
: {
3767 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3768 LPostWriteElementBarrierO
* lir
= new (alloc()) LPostWriteElementBarrierO(
3769 useConstantObject
? useOrConstant(ins
->object())
3770 : useRegister(ins
->object()),
3771 useRegister(ins
->value()), useRegister(ins
->index()), tmp
);
3773 assignSafepoint(lir
, ins
);
3776 case MIRType::String
: {
3778 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3779 LPostWriteElementBarrierS
* lir
= new (alloc()) LPostWriteElementBarrierS(
3780 useConstantObject
? useOrConstant(ins
->object())
3781 : useRegister(ins
->object()),
3782 useRegister(ins
->value()), useRegister(ins
->index()), tmp
);
3784 assignSafepoint(lir
, ins
);
3787 case MIRType::BigInt
: {
3789 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3790 auto* lir
= new (alloc()) LPostWriteElementBarrierBI(
3791 useConstantObject
? useOrConstant(ins
->object())
3792 : useRegister(ins
->object()),
3793 useRegister(ins
->value()), useRegister(ins
->index()), tmp
);
3795 assignSafepoint(lir
, ins
);
3798 case MIRType::Value
: {
3800 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3801 LPostWriteElementBarrierV
* lir
= new (alloc()) LPostWriteElementBarrierV(
3802 useConstantObject
? useOrConstant(ins
->object())
3803 : useRegister(ins
->object()),
3804 useRegister(ins
->index()), useBox(ins
->value()), tmp
);
3806 assignSafepoint(lir
, ins
);
3810 // Currently, only objects, strings, and bigints can be in the nursery.
3811 // Other instruction types cannot hold nursery pointers.
3816 void LIRGenerator::visitAssertCanElidePostWriteBarrier(
3817 MAssertCanElidePostWriteBarrier
* ins
) {
3818 auto* lir
= new (alloc()) LAssertCanElidePostWriteBarrier(
3819 useRegister(ins
->object()), useBox(ins
->value()), temp());
3823 void LIRGenerator::visitArrayLength(MArrayLength
* ins
) {
3824 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
3825 auto* lir
= new (alloc()) LArrayLength(useRegisterAtStart(ins
->elements()));
3826 assignSnapshot(lir
, ins
->bailoutKind());
3830 void LIRGenerator::visitSetArrayLength(MSetArrayLength
* ins
) {
3831 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
3832 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
3834 MOZ_ASSERT(ins
->index()->isConstant());
3835 add(new (alloc()) LSetArrayLength(useRegister(ins
->elements()),
3836 useRegisterOrConstant(ins
->index())),
3840 void LIRGenerator::visitFunctionLength(MFunctionLength
* ins
) {
3841 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
3843 auto* lir
= new (alloc()) LFunctionLength(useRegister(ins
->function()));
3844 assignSnapshot(lir
, ins
->bailoutKind());
3848 void LIRGenerator::visitFunctionName(MFunctionName
* ins
) {
3849 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
3851 auto* lir
= new (alloc()) LFunctionName(useRegister(ins
->function()));
3852 assignSnapshot(lir
, ins
->bailoutKind());
3856 void LIRGenerator::visitGetNextEntryForIterator(MGetNextEntryForIterator
* ins
) {
3857 MOZ_ASSERT(ins
->iter()->type() == MIRType::Object
);
3858 MOZ_ASSERT(ins
->result()->type() == MIRType::Object
);
3859 auto lir
= new (alloc()) LGetNextEntryForIterator(useRegister(ins
->iter()),
3860 useRegister(ins
->result()),
3861 temp(), temp(), temp());
3865 void LIRGenerator::visitArrayBufferByteLength(MArrayBufferByteLength
* ins
) {
3866 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
3867 MOZ_ASSERT(ins
->type() == MIRType::IntPtr
);
3870 new (alloc()) LArrayBufferByteLength(useRegisterAtStart(ins
->object()));
3874 void LIRGenerator::visitArrayBufferViewLength(MArrayBufferViewLength
* ins
) {
3875 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
3876 MOZ_ASSERT(ins
->type() == MIRType::IntPtr
);
3879 new (alloc()) LArrayBufferViewLength(useRegisterAtStart(ins
->object()));
3883 void LIRGenerator::visitArrayBufferViewByteOffset(
3884 MArrayBufferViewByteOffset
* ins
) {
3885 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
3886 MOZ_ASSERT(ins
->type() == MIRType::IntPtr
);
3888 auto* lir
= new (alloc())
3889 LArrayBufferViewByteOffset(useRegisterAtStart(ins
->object()));
3893 void LIRGenerator::visitArrayBufferViewElements(MArrayBufferViewElements
* ins
) {
3894 MOZ_ASSERT(ins
->type() == MIRType::Elements
);
3895 define(new (alloc())
3896 LArrayBufferViewElements(useRegisterAtStart(ins
->object())),
3900 void LIRGenerator::visitTypedArrayElementSize(MTypedArrayElementSize
* ins
) {
3901 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
3902 define(new (alloc())
3903 LTypedArrayElementSize(useRegisterAtStart(ins
->object())),
3907 void LIRGenerator::visitGuardHasAttachedArrayBuffer(
3908 MGuardHasAttachedArrayBuffer
* ins
) {
3909 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
3911 auto* lir
= new (alloc())
3912 LGuardHasAttachedArrayBuffer(useRegister(ins
->object()), temp());
3913 assignSnapshot(lir
, ins
->bailoutKind());
3915 redefine(ins
, ins
->object());
3918 void LIRGenerator::visitGuardNumberToIntPtrIndex(
3919 MGuardNumberToIntPtrIndex
* ins
) {
3920 MDefinition
* input
= ins
->input();
3921 MOZ_ASSERT(input
->type() == MIRType::Double
);
3923 auto* lir
= new (alloc()) LGuardNumberToIntPtrIndex(useRegister(input
));
3924 if (!ins
->supportOOB()) {
3925 assignSnapshot(lir
, ins
->bailoutKind());
3930 void LIRGenerator::visitInitializedLength(MInitializedLength
* ins
) {
3931 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
3932 define(new (alloc()) LInitializedLength(useRegisterAtStart(ins
->elements())),
3936 void LIRGenerator::visitSetInitializedLength(MSetInitializedLength
* ins
) {
3937 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
3938 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
3940 MOZ_ASSERT(ins
->index()->isConstant());
3941 add(new (alloc()) LSetInitializedLength(useRegister(ins
->elements()),
3942 useRegisterOrConstant(ins
->index())),
3946 void LIRGenerator::visitNot(MNot
* ins
) {
3947 MDefinition
* op
= ins
->input();
3949 // String is converted to length of string in the type analysis phase (see
3951 MOZ_ASSERT(op
->type() != MIRType::String
);
3953 // - boolean: x xor 1
3954 // - int32: LCompare(x, 0)
3955 // - double: LCompare(x, 0)
3956 // - null or undefined: true
3958 // - bigint: LNotBI(x)
3959 // - object: false if it never emulates undefined, else LNotO(x)
3960 switch (op
->type()) {
3961 case MIRType::Boolean
: {
3962 MConstant
* cons
= MConstant::New(alloc(), Int32Value(1));
3963 ins
->block()->insertBefore(ins
, cons
);
3964 lowerForALU(new (alloc()) LBitOpI(JSOp::BitXor
), ins
, op
, cons
);
3967 case MIRType::Int32
:
3968 define(new (alloc()) LNotI(useRegisterAtStart(op
)), ins
);
3970 case MIRType::Int64
:
3971 define(new (alloc()) LNotI64(useInt64RegisterAtStart(op
)), ins
);
3973 case MIRType::Double
:
3974 define(new (alloc()) LNotD(useRegister(op
)), ins
);
3976 case MIRType::Float32
:
3977 define(new (alloc()) LNotF(useRegister(op
)), ins
);
3979 case MIRType::Undefined
:
3981 define(new (alloc()) LInteger(1), ins
);
3983 case MIRType::Symbol
:
3984 define(new (alloc()) LInteger(0), ins
);
3986 case MIRType::BigInt
:
3987 define(new (alloc()) LNotBI(useRegisterAtStart(op
)), ins
);
3989 case MIRType::Object
:
3990 define(new (alloc()) LNotO(useRegister(op
)), ins
);
3992 case MIRType::Value
: {
3993 auto* lir
= new (alloc()) LNotV(useBox(op
), tempDouble(), tempToUnbox());
3999 MOZ_CRASH("Unexpected MIRType.");
4003 void LIRGenerator::visitBoundsCheck(MBoundsCheck
* ins
) {
4004 MOZ_ASSERT(ins
->type() == MIRType::Int32
|| ins
->type() == MIRType::IntPtr
);
4005 MOZ_ASSERT(ins
->index()->type() == ins
->type());
4006 MOZ_ASSERT(ins
->length()->type() == ins
->type());
4008 if (!ins
->fallible()) {
4012 LInstruction
* check
;
4013 if (ins
->minimum() || ins
->maximum()) {
4014 check
= new (alloc())
4015 LBoundsCheckRange(useRegisterOrInt32Constant(ins
->index()),
4016 useAny(ins
->length()), temp());
4018 check
= new (alloc()) LBoundsCheck(useRegisterOrInt32Constant(ins
->index()),
4019 useAnyOrInt32Constant(ins
->length()));
4021 assignSnapshot(check
, ins
->bailoutKind());
4025 void LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex
* ins
) {
4026 MOZ_ASSERT(ins
->type() == MIRType::Int32
|| ins
->type() == MIRType::IntPtr
);
4027 MOZ_ASSERT(ins
->index()->type() == ins
->type());
4028 MOZ_ASSERT(ins
->length()->type() == ins
->type());
4030 auto* lir
= new (alloc())
4031 LSpectreMaskIndex(useRegister(ins
->index()), useAny(ins
->length()));
4035 void LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower
* ins
) {
4036 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
4038 if (!ins
->fallible()) {
4042 LInstruction
* check
=
4043 new (alloc()) LBoundsCheckLower(useRegister(ins
->index()));
4044 assignSnapshot(check
, ins
->bailoutKind());
4048 void LIRGenerator::visitInArray(MInArray
* ins
) {
4049 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4050 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
4051 MOZ_ASSERT(ins
->initLength()->type() == MIRType::Int32
);
4052 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
4054 auto* lir
= new (alloc()) LInArray(useRegister(ins
->elements()),
4055 useRegisterOrConstant(ins
->index()),
4056 useRegister(ins
->initLength()));
4057 if (ins
->needsNegativeIntCheck()) {
4058 assignSnapshot(lir
, ins
->bailoutKind());
4063 void LIRGenerator::visitGuardElementNotHole(MGuardElementNotHole
* ins
) {
4064 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4065 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
4067 auto* guard
= new (alloc())
4068 LGuardElementNotHole(useRegisterAtStart(ins
->elements()),
4069 useRegisterOrConstantAtStart(ins
->index()));
4070 assignSnapshot(guard
, ins
->bailoutKind());
4074 void LIRGenerator::visitLoadElement(MLoadElement
* ins
) {
4075 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4076 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
4077 MOZ_ASSERT(ins
->type() == MIRType::Value
);
4079 auto* lir
= new (alloc()) LLoadElementV(useRegister(ins
->elements()),
4080 useRegisterOrConstant(ins
->index()));
4081 assignSnapshot(lir
, ins
->bailoutKind());
4082 defineBox(lir
, ins
);
4085 void LIRGenerator::visitLoadElementHole(MLoadElementHole
* ins
) {
4086 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4087 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
4088 MOZ_ASSERT(ins
->initLength()->type() == MIRType::Int32
);
4089 MOZ_ASSERT(ins
->type() == MIRType::Value
);
4091 LLoadElementHole
* lir
= new (alloc())
4092 LLoadElementHole(useRegister(ins
->elements()), useRegister(ins
->index()),
4093 useRegister(ins
->initLength()));
4094 if (ins
->needsNegativeIntCheck()) {
4095 assignSnapshot(lir
, ins
->bailoutKind());
4097 defineBox(lir
, ins
);
4100 void LIRGenerator::visitStoreElement(MStoreElement
* ins
) {
4101 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4102 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
4104 const LUse elements
= useRegister(ins
->elements());
4105 const LAllocation index
= useRegisterOrConstant(ins
->index());
4107 switch (ins
->value()->type()) {
4108 case MIRType::Value
: {
4110 new (alloc()) LStoreElementV(elements
, index
, useBox(ins
->value()));
4111 if (ins
->fallible()) {
4112 assignSnapshot(lir
, ins
->bailoutKind());
4119 const LAllocation value
= useRegisterOrNonDoubleConstant(ins
->value());
4120 LInstruction
* lir
= new (alloc()) LStoreElementT(elements
, index
, value
);
4121 if (ins
->fallible()) {
4122 assignSnapshot(lir
, ins
->bailoutKind());
4130 void LIRGenerator::visitStoreHoleValueElement(MStoreHoleValueElement
* ins
) {
4131 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4132 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
4134 auto* lir
= new (alloc()) LStoreHoleValueElement(useRegister(ins
->elements()),
4135 useRegister(ins
->index()));
4139 static bool BoundsCheckNeedsSpectreTemp() {
4140 // On x86, spectreBoundsCheck32 can emit better code if it has a scratch
4141 // register and index masking is enabled.
4142 #ifdef JS_CODEGEN_X86
4143 return JitOptions
.spectreIndexMasking
;
4149 void LIRGenerator::visitStoreElementHole(MStoreElementHole
* ins
) {
4150 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4151 MOZ_ASSERT(ins
->index()->type() == MIRType::Int32
);
4153 const LUse object
= useRegister(ins
->object());
4154 const LUse elements
= useRegister(ins
->elements());
4155 const LAllocation index
= useRegister(ins
->index());
4158 switch (ins
->value()->type()) {
4159 case MIRType::Value
:
4160 lir
= new (alloc()) LStoreElementHoleV(object
, elements
, index
,
4161 useBox(ins
->value()), temp());
4165 const LAllocation value
= useRegisterOrNonDoubleConstant(ins
->value());
4167 LStoreElementHoleT(object
, elements
, index
, value
, temp());
4172 assignSnapshot(lir
, ins
->bailoutKind());
4174 assignSafepoint(lir
, ins
);
4177 void LIRGenerator::visitEffectiveAddress(MEffectiveAddress
* ins
) {
4178 define(new (alloc()) LEffectiveAddress(useRegister(ins
->base()),
4179 useRegister(ins
->index())),
4183 void LIRGenerator::visitArrayPopShift(MArrayPopShift
* ins
) {
4184 MOZ_ASSERT(ins
->type() == MIRType::Value
);
4187 new (alloc()) LArrayPopShift(useRegister(ins
->object()), temp(), temp());
4188 assignSnapshot(lir
, ins
->bailoutKind());
4189 defineBox(lir
, ins
);
4191 if (ins
->mode() == MArrayPopShift::Shift
) {
4192 assignSafepoint(lir
, ins
);
4196 void LIRGenerator::visitArrayPush(MArrayPush
* ins
) {
4197 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
4198 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
4200 LUse object
= useRegister(ins
->object());
4202 LDefinition spectreTemp
=
4203 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4205 auto* lir
= new (alloc())
4206 LArrayPush(object
, useBox(ins
->value()), temp(), spectreTemp
);
4207 // We will bailout before pushing if the length would overflow INT32_MAX.
4208 assignSnapshot(lir
, ins
->bailoutKind());
4210 assignSafepoint(lir
, ins
);
4213 void LIRGenerator::visitArraySlice(MArraySlice
* ins
) {
4214 MOZ_ASSERT(ins
->type() == MIRType::Object
);
4215 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4216 MOZ_ASSERT(ins
->begin()->type() == MIRType::Int32
);
4217 MOZ_ASSERT(ins
->end()->type() == MIRType::Int32
);
4219 LArraySlice
* lir
= new (alloc()) LArraySlice(
4220 useRegisterAtStart(ins
->object()), useRegisterAtStart(ins
->begin()),
4221 useRegisterAtStart(ins
->end()), tempFixed(CallTempReg0
),
4222 tempFixed(CallTempReg1
));
4223 assignSnapshot(lir
, ins
->bailoutKind());
4224 defineReturn(lir
, ins
);
4225 assignSafepoint(lir
, ins
);
4228 void LIRGenerator::visitArgumentsSlice(MArgumentsSlice
* ins
) {
4229 MOZ_ASSERT(ins
->type() == MIRType::Object
);
4230 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4231 MOZ_ASSERT(ins
->begin()->type() == MIRType::Int32
);
4232 MOZ_ASSERT(ins
->end()->type() == MIRType::Int32
);
4234 auto* lir
= new (alloc()) LArgumentsSlice(
4235 useRegisterAtStart(ins
->object()), useRegisterAtStart(ins
->begin()),
4236 useRegisterAtStart(ins
->end()), tempFixed(CallTempReg0
),
4237 tempFixed(CallTempReg1
));
4238 defineReturn(lir
, ins
);
4239 assignSafepoint(lir
, ins
);
4242 void LIRGenerator::visitFrameArgumentsSlice(MFrameArgumentsSlice
* ins
) {
4243 MOZ_ASSERT(ins
->type() == MIRType::Object
);
4244 MOZ_ASSERT(ins
->begin()->type() == MIRType::Int32
);
4245 MOZ_ASSERT(ins
->count()->type() == MIRType::Int32
);
4247 auto* lir
= new (alloc()) LFrameArgumentsSlice(
4248 useRegister(ins
->begin()), useRegister(ins
->count()), temp());
4250 assignSafepoint(lir
, ins
);
4253 void LIRGenerator::visitInlineArgumentsSlice(MInlineArgumentsSlice
* ins
) {
4254 LAllocation begin
= useRegisterOrConstant(ins
->begin());
4255 LAllocation count
= useRegisterOrConstant(ins
->count());
4256 uint32_t numActuals
= ins
->numActuals();
4257 uint32_t numOperands
=
4258 numActuals
* BOX_PIECES
+ LInlineArgumentsSlice::NumNonArgumentOperands
;
4260 auto* lir
= allocateVariadic
<LInlineArgumentsSlice
>(numOperands
, temp());
4262 abort(AbortReason::Alloc
, "OOM: LIRGenerator::visitInlineArgumentsSlice");
4266 lir
->setOperand(LInlineArgumentsSlice::Begin
, begin
);
4267 lir
->setOperand(LInlineArgumentsSlice::Count
, count
);
4268 for (uint32_t i
= 0; i
< numActuals
; i
++) {
4269 MDefinition
* arg
= ins
->getArg(i
);
4270 uint32_t index
= LInlineArgumentsSlice::ArgIndex(i
);
4271 lir
->setBoxOperand(index
,
4272 useBoxOrTypedOrConstant(arg
, /*useConstant = */ true));
4275 assignSafepoint(lir
, ins
);
4278 void LIRGenerator::visitNormalizeSliceTerm(MNormalizeSliceTerm
* ins
) {
4279 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
4280 MOZ_ASSERT(ins
->value()->type() == MIRType::Int32
);
4281 MOZ_ASSERT(ins
->length()->type() == MIRType::Int32
);
4283 auto* lir
= new (alloc()) LNormalizeSliceTerm(useRegister(ins
->value()),
4284 useRegister(ins
->length()));
4288 void LIRGenerator::visitArrayJoin(MArrayJoin
* ins
) {
4289 MOZ_ASSERT(ins
->type() == MIRType::String
);
4290 MOZ_ASSERT(ins
->array()->type() == MIRType::Object
);
4291 MOZ_ASSERT(ins
->sep()->type() == MIRType::String
);
4293 auto* lir
= new (alloc())
4294 LArrayJoin(useRegisterAtStart(ins
->array()),
4295 useRegisterAtStart(ins
->sep()), tempFixed(CallTempReg0
));
4296 defineReturn(lir
, ins
);
4297 assignSafepoint(lir
, ins
);
4300 void LIRGenerator::visitObjectKeys(MObjectKeys
* ins
) {
4301 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4302 MOZ_ASSERT(ins
->type() == MIRType::Object
);
4304 auto* lir
= new (alloc()) LObjectKeys(useRegisterAtStart(ins
->object()));
4305 defineReturn(lir
, ins
);
4306 assignSafepoint(lir
, ins
);
4309 void LIRGenerator::visitObjectKeysLength(MObjectKeysLength
* ins
) {
4310 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4311 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
4314 new (alloc()) LObjectKeysLength(useRegisterAtStart(ins
->object()));
4315 defineReturn(lir
, ins
);
4316 assignSafepoint(lir
, ins
);
4319 void LIRGenerator::visitStringSplit(MStringSplit
* ins
) {
4320 MOZ_ASSERT(ins
->type() == MIRType::Object
);
4321 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
4322 MOZ_ASSERT(ins
->separator()->type() == MIRType::String
);
4324 LStringSplit
* lir
= new (alloc()) LStringSplit(
4325 useRegisterAtStart(ins
->string()), useRegisterAtStart(ins
->separator()));
4326 defineReturn(lir
, ins
);
4327 assignSafepoint(lir
, ins
);
4330 void LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar
* ins
) {
4331 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4332 MOZ_ASSERT(ins
->index()->type() == MIRType::IntPtr
);
4333 MOZ_ASSERT(IsNumericType(ins
->type()) || ins
->type() == MIRType::Boolean
);
4335 if (Scalar::isBigIntType(ins
->storageType()) &&
4336 ins
->requiresMemoryBarrier()) {
4337 lowerAtomicLoad64(ins
);
4341 const LUse elements
= useRegister(ins
->elements());
4342 const LAllocation index
= useRegisterOrIndexConstant(
4343 ins
->index(), ins
->storageType(), ins
->offsetAdjustment());
4345 // NOTE: the generated code must match the assembly code in gen_load in
4346 // GenerateAtomicOperations.py
4347 Synchronization sync
= Synchronization::Load();
4348 if (ins
->requiresMemoryBarrier()) {
4349 LMemoryBarrier
* fence
= new (alloc()) LMemoryBarrier(sync
.barrierBefore
);
4353 if (!Scalar::isBigIntType(ins
->storageType())) {
4354 // We need a temp register for Uint32Array with known double result.
4355 LDefinition tempDef
= LDefinition::BogusTemp();
4356 if (ins
->storageType() == Scalar::Uint32
&&
4357 IsFloatingPointType(ins
->type())) {
4361 auto* lir
= new (alloc()) LLoadUnboxedScalar(elements
, index
, tempDef
);
4362 if (ins
->fallible()) {
4363 assignSnapshot(lir
, ins
->bailoutKind());
4367 MOZ_ASSERT(ins
->type() == MIRType::BigInt
);
4370 new (alloc()) LLoadUnboxedBigInt(elements
, index
, temp(), tempInt64());
4372 assignSafepoint(lir
, ins
);
4375 if (ins
->requiresMemoryBarrier()) {
4376 LMemoryBarrier
* fence
= new (alloc()) LMemoryBarrier(sync
.barrierAfter
);
4381 void LIRGenerator::visitLoadDataViewElement(MLoadDataViewElement
* ins
) {
4382 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4383 MOZ_ASSERT(ins
->index()->type() == MIRType::IntPtr
);
4385 MOZ_ASSERT(IsNumericType(ins
->type()));
4387 const LUse elements
= useRegister(ins
->elements());
4388 const LUse index
= useRegister(ins
->index());
4389 const LAllocation littleEndian
= useRegisterOrConstant(ins
->littleEndian());
4391 // We need a temp register for:
4392 // - Uint32Array with known double result,
4394 // - and BigInt64Array and BigUint64Array.
4395 LDefinition tempDef
= LDefinition::BogusTemp();
4396 if ((ins
->storageType() == Scalar::Uint32
&&
4397 IsFloatingPointType(ins
->type())) ||
4398 ins
->storageType() == Scalar::Float32
) {
4401 if (Scalar::isBigIntType(ins
->storageType())) {
4402 #ifdef JS_CODEGEN_X86
4403 // There are not enough registers on x86.
4404 if (littleEndian
.isConstant()) {
4412 // We also need a separate 64-bit temp register for:
4414 // - and BigInt64Array and BigUint64Array.
4415 LInt64Definition temp64Def
= LInt64Definition::BogusTemp();
4416 if (Scalar::byteSize(ins
->storageType()) == 8) {
4417 temp64Def
= tempInt64();
4420 auto* lir
= new (alloc())
4421 LLoadDataViewElement(elements
, index
, littleEndian
, tempDef
, temp64Def
);
4422 if (ins
->fallible()) {
4423 assignSnapshot(lir
, ins
->bailoutKind());
4426 if (Scalar::isBigIntType(ins
->storageType())) {
4427 assignSafepoint(lir
, ins
);
4431 void LIRGenerator::visitClampToUint8(MClampToUint8
* ins
) {
4432 MDefinition
* in
= ins
->input();
4434 switch (in
->type()) {
4435 case MIRType::Boolean
:
4439 case MIRType::Int32
:
4440 defineReuseInput(new (alloc()) LClampIToUint8(useRegisterAtStart(in
)),
4444 case MIRType::Double
:
4445 // LClampDToUint8 clobbers its input register. Making it available as
4446 // a temp copy describes this behavior to the register allocator.
4447 define(new (alloc())
4448 LClampDToUint8(useRegisterAtStart(in
), tempCopy(in
, 0)),
4452 case MIRType::Value
: {
4453 LClampVToUint8
* lir
=
4454 new (alloc()) LClampVToUint8(useBox(in
), tempDouble());
4455 assignSnapshot(lir
, ins
->bailoutKind());
4457 assignSafepoint(lir
, ins
);
4462 MOZ_CRASH("unexpected type");
4466 void LIRGenerator::visitLoadTypedArrayElementHole(
4467 MLoadTypedArrayElementHole
* ins
) {
4468 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4469 MOZ_ASSERT(ins
->index()->type() == MIRType::IntPtr
);
4471 MOZ_ASSERT(ins
->type() == MIRType::Value
);
4473 const LUse object
= useRegister(ins
->object());
4474 const LAllocation index
= useRegister(ins
->index());
4476 if (!Scalar::isBigIntType(ins
->arrayType())) {
4477 auto* lir
= new (alloc()) LLoadTypedArrayElementHole(object
, index
, temp());
4478 if (ins
->fallible()) {
4479 assignSnapshot(lir
, ins
->bailoutKind());
4481 defineBox(lir
, ins
);
4483 #ifdef JS_CODEGEN_X86
4484 LDefinition tmp
= LDefinition::BogusTemp();
4486 LDefinition tmp
= temp();
4489 auto* lir
= new (alloc())
4490 LLoadTypedArrayElementHoleBigInt(object
, index
, tmp
, tempInt64());
4491 defineBox(lir
, ins
);
4492 assignSafepoint(lir
, ins
);
4496 void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar
* ins
) {
4497 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4498 MOZ_ASSERT(ins
->index()->type() == MIRType::IntPtr
);
4500 if (ins
->isFloatWrite()) {
4501 MOZ_ASSERT_IF(ins
->writeType() == Scalar::Float32
,
4502 ins
->value()->type() == MIRType::Float32
);
4503 MOZ_ASSERT_IF(ins
->writeType() == Scalar::Float64
,
4504 ins
->value()->type() == MIRType::Double
);
4505 } else if (ins
->isBigIntWrite()) {
4506 MOZ_ASSERT(ins
->value()->type() == MIRType::BigInt
);
4508 MOZ_ASSERT(ins
->value()->type() == MIRType::Int32
);
4511 if (ins
->isBigIntWrite() && ins
->requiresMemoryBarrier()) {
4512 lowerAtomicStore64(ins
);
4516 LUse elements
= useRegister(ins
->elements());
4518 useRegisterOrIndexConstant(ins
->index(), ins
->writeType());
4521 // For byte arrays, the value has to be in a byte register on x86.
4522 if (ins
->isByteWrite()) {
4523 value
= useByteOpRegisterOrNonDoubleConstant(ins
->value());
4524 } else if (ins
->isBigIntWrite()) {
4525 value
= useRegister(ins
->value());
4527 value
= useRegisterOrNonDoubleConstant(ins
->value());
4530 // Optimization opportunity for atomics: on some platforms there
4531 // is a store instruction that incorporates the necessary
4532 // barriers, and we could use that instead of separate barrier and
4533 // store instructions. See bug #1077027.
4535 // NOTE: the generated code must match the assembly code in gen_store in
4536 // GenerateAtomicOperations.py
4537 Synchronization sync
= Synchronization::Store();
4538 if (ins
->requiresMemoryBarrier()) {
4539 LMemoryBarrier
* fence
= new (alloc()) LMemoryBarrier(sync
.barrierBefore
);
4542 if (!ins
->isBigIntWrite()) {
4543 add(new (alloc()) LStoreUnboxedScalar(elements
, index
, value
), ins
);
4545 add(new (alloc()) LStoreUnboxedBigInt(elements
, index
, value
, tempInt64()),
4548 if (ins
->requiresMemoryBarrier()) {
4549 LMemoryBarrier
* fence
= new (alloc()) LMemoryBarrier(sync
.barrierAfter
);
4554 void LIRGenerator::visitStoreDataViewElement(MStoreDataViewElement
* ins
) {
4555 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4556 MOZ_ASSERT(ins
->index()->type() == MIRType::IntPtr
);
4557 MOZ_ASSERT(ins
->littleEndian()->type() == MIRType::Boolean
);
4559 if (ins
->isFloatWrite()) {
4560 MOZ_ASSERT_IF(ins
->writeType() == Scalar::Float32
,
4561 ins
->value()->type() == MIRType::Float32
);
4562 MOZ_ASSERT_IF(ins
->writeType() == Scalar::Float64
,
4563 ins
->value()->type() == MIRType::Double
);
4564 } else if (ins
->isBigIntWrite()) {
4565 MOZ_ASSERT(ins
->value()->type() == MIRType::BigInt
);
4567 MOZ_ASSERT(ins
->value()->type() == MIRType::Int32
);
4570 LUse elements
= useRegister(ins
->elements());
4571 LUse index
= useRegister(ins
->index());
4573 if (ins
->isBigIntWrite()) {
4574 value
= useRegister(ins
->value());
4576 value
= useRegisterOrNonDoubleConstant(ins
->value());
4578 LAllocation littleEndian
= useRegisterOrConstant(ins
->littleEndian());
4580 LDefinition tempDef
= LDefinition::BogusTemp();
4581 LInt64Definition temp64Def
= LInt64Definition::BogusTemp();
4582 if (Scalar::byteSize(ins
->writeType()) < 8) {
4585 temp64Def
= tempInt64();
4588 add(new (alloc()) LStoreDataViewElement(elements
, index
, value
, littleEndian
,
4589 tempDef
, temp64Def
),
4593 void LIRGenerator::visitStoreTypedArrayElementHole(
4594 MStoreTypedArrayElementHole
* ins
) {
4595 MOZ_ASSERT(ins
->elements()->type() == MIRType::Elements
);
4596 MOZ_ASSERT(ins
->index()->type() == MIRType::IntPtr
);
4597 MOZ_ASSERT(ins
->length()->type() == MIRType::IntPtr
);
4599 if (ins
->isFloatWrite()) {
4600 MOZ_ASSERT_IF(ins
->arrayType() == Scalar::Float32
,
4601 ins
->value()->type() == MIRType::Float32
);
4602 MOZ_ASSERT_IF(ins
->arrayType() == Scalar::Float64
,
4603 ins
->value()->type() == MIRType::Double
);
4604 } else if (ins
->isBigIntWrite()) {
4605 MOZ_ASSERT(ins
->value()->type() == MIRType::BigInt
);
4607 MOZ_ASSERT(ins
->value()->type() == MIRType::Int32
);
4610 LUse elements
= useRegister(ins
->elements());
4611 LAllocation length
= useAny(ins
->length());
4612 LAllocation index
= useRegister(ins
->index());
4614 // For byte arrays, the value has to be in a byte register on x86.
4616 if (ins
->isByteWrite()) {
4617 value
= useByteOpRegisterOrNonDoubleConstant(ins
->value());
4618 } else if (ins
->isBigIntWrite()) {
4619 value
= useRegister(ins
->value());
4621 value
= useRegisterOrNonDoubleConstant(ins
->value());
4624 if (!ins
->isBigIntWrite()) {
4625 LDefinition spectreTemp
=
4626 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4627 auto* lir
= new (alloc()) LStoreTypedArrayElementHole(
4628 elements
, length
, index
, value
, spectreTemp
);
4631 auto* lir
= new (alloc()) LStoreTypedArrayElementHoleBigInt(
4632 elements
, length
, index
, value
, tempInt64());
4637 void LIRGenerator::visitLoadScriptedProxyHandler(
4638 MLoadScriptedProxyHandler
* ins
) {
4639 LLoadScriptedProxyHandler
* lir
= new (alloc())
4640 LLoadScriptedProxyHandler(useRegisterAtStart(ins
->object()));
4641 defineBox(lir
, ins
);
4644 void LIRGenerator::visitIdToStringOrSymbol(MIdToStringOrSymbol
* ins
) {
4645 LIdToStringOrSymbol
* lir
=
4646 new (alloc()) LIdToStringOrSymbol(useBoxAtStart(ins
->idVal()), temp());
4647 assignSnapshot(lir
, ins
->bailoutKind());
4648 defineBox(lir
, ins
);
4649 assignSafepoint(lir
, ins
);
4652 void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot
* ins
) {
4653 MDefinition
* obj
= ins
->object();
4654 MOZ_ASSERT(obj
->type() == MIRType::Object
);
4656 MIRType type
= ins
->type();
4658 if (type
== MIRType::Value
) {
4659 if (ins
->usedAsPropertyKey()) {
4660 LLoadFixedSlotAndAtomize
* lir
=
4661 new (alloc()) LLoadFixedSlotAndAtomize(useRegister(obj
), temp());
4662 defineBox(lir
, ins
);
4663 assignSafepoint(lir
, ins
);
4665 LLoadFixedSlotV
* lir
=
4666 new (alloc()) LLoadFixedSlotV(useRegisterAtStart(obj
));
4667 defineBox(lir
, ins
);
4670 LLoadFixedSlotT
* lir
=
4671 new (alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj
, type
));
4676 void LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox
* ins
) {
4677 MDefinition
* obj
= ins
->object();
4678 MOZ_ASSERT(obj
->type() == MIRType::Object
);
4680 if (ins
->usedAsPropertyKey() && ins
->type() == MIRType::String
) {
4681 LLoadFixedSlotUnboxAndAtomize
* lir
=
4682 new (alloc()) LLoadFixedSlotUnboxAndAtomize(useRegister(obj
));
4683 if (ins
->fallible()) {
4684 assignSnapshot(lir
, ins
->bailoutKind());
4687 assignSafepoint(lir
, ins
);
4689 LLoadFixedSlotAndUnbox
* lir
=
4690 new (alloc()) LLoadFixedSlotAndUnbox(useRegisterAtStart(obj
));
4691 if (ins
->fallible()) {
4692 assignSnapshot(lir
, ins
->bailoutKind());
4698 void LIRGenerator::visitLoadDynamicSlotAndUnbox(MLoadDynamicSlotAndUnbox
* ins
) {
4699 MDefinition
* slots
= ins
->slots();
4700 MOZ_ASSERT(slots
->type() == MIRType::Slots
);
4702 if (ins
->usedAsPropertyKey() && ins
->type() == MIRType::String
) {
4704 new (alloc()) LLoadDynamicSlotUnboxAndAtomize(useRegister(slots
));
4705 if (ins
->fallible()) {
4706 assignSnapshot(lir
, ins
->bailoutKind());
4709 assignSafepoint(lir
, ins
);
4712 new (alloc()) LLoadDynamicSlotAndUnbox(useRegisterAtStart(slots
));
4713 if (ins
->fallible()) {
4714 assignSnapshot(lir
, ins
->bailoutKind());
4720 void LIRGenerator::visitLoadElementAndUnbox(MLoadElementAndUnbox
* ins
) {
4721 MDefinition
* elements
= ins
->elements();
4722 MDefinition
* index
= ins
->index();
4723 MOZ_ASSERT(elements
->type() == MIRType::Elements
);
4724 MOZ_ASSERT(index
->type() == MIRType::Int32
);
4726 auto* lir
= new (alloc())
4727 LLoadElementAndUnbox(useRegister(elements
), useRegisterOrConstant(index
));
4728 if (ins
->fallible()) {
4729 assignSnapshot(lir
, ins
->bailoutKind());
4734 void LIRGenerator::visitAddAndStoreSlot(MAddAndStoreSlot
* ins
) {
4735 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4737 LDefinition maybeTemp
= LDefinition::BogusTemp();
4738 if (ins
->kind() != MAddAndStoreSlot::Kind::FixedSlot
) {
4742 auto* lir
= new (alloc()) LAddAndStoreSlot(useRegister(ins
->object()),
4743 useBox(ins
->value()), maybeTemp
);
4747 void LIRGenerator::visitAllocateAndStoreSlot(MAllocateAndStoreSlot
* ins
) {
4748 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4750 auto* lir
= new (alloc()) LAllocateAndStoreSlot(
4751 useRegisterAtStart(ins
->object()), useBoxAtStart(ins
->value()),
4752 tempFixed(CallTempReg0
), tempFixed(CallTempReg1
));
4753 assignSnapshot(lir
, ins
->bailoutKind());
4757 void LIRGenerator::visitAddSlotAndCallAddPropHook(
4758 MAddSlotAndCallAddPropHook
* ins
) {
4759 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4760 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
4762 auto* lir
= new (alloc()) LAddSlotAndCallAddPropHook(
4763 useRegisterAtStart(ins
->object()), useBoxAtStart(ins
->value()));
4765 assignSafepoint(lir
, ins
);
4768 void LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot
* ins
) {
4769 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4771 if (ins
->value()->type() == MIRType::Value
) {
4772 LStoreFixedSlotV
* lir
= new (alloc())
4773 LStoreFixedSlotV(useRegister(ins
->object()), useBox(ins
->value()));
4776 LStoreFixedSlotT
* lir
= new (alloc()) LStoreFixedSlotT(
4777 useRegister(ins
->object()), useRegisterOrConstant(ins
->value()));
4782 void LIRGenerator::visitGetNameCache(MGetNameCache
* ins
) {
4783 MOZ_ASSERT(ins
->envObj()->type() == MIRType::Object
);
4785 // Emit an overrecursed check: this is necessary because the cache can
4786 // attach a scripted getter stub that calls this script recursively.
4787 gen
->setNeedsOverrecursedCheck();
4789 LGetNameCache
* lir
=
4790 new (alloc()) LGetNameCache(useRegister(ins
->envObj()), temp());
4791 defineBox(lir
, ins
);
4792 assignSafepoint(lir
, ins
);
4795 void LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue
* ins
) {
4796 LCallGetIntrinsicValue
* lir
= new (alloc()) LCallGetIntrinsicValue();
4797 defineReturn(lir
, ins
);
4798 assignSafepoint(lir
, ins
);
4801 void LIRGenerator::visitGetPropSuperCache(MGetPropSuperCache
* ins
) {
4802 MDefinition
* obj
= ins
->object();
4803 MDefinition
* receiver
= ins
->receiver();
4804 MDefinition
* id
= ins
->idval();
4806 gen
->setNeedsOverrecursedCheck();
4809 id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
;
4811 auto* lir
= new (alloc())
4812 LGetPropSuperCache(useRegister(obj
), useBoxOrTyped(receiver
),
4813 useBoxOrTypedOrConstant(id
, useConstId
));
4814 defineBox(lir
, ins
);
4815 assignSafepoint(lir
, ins
);
4818 void LIRGenerator::visitGetPropertyCache(MGetPropertyCache
* ins
) {
4819 MDefinition
* value
= ins
->value();
4820 MOZ_ASSERT(value
->type() == MIRType::Object
||
4821 value
->type() == MIRType::Value
);
4823 MDefinition
* id
= ins
->idval();
4824 MOZ_ASSERT(id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
||
4825 id
->type() == MIRType::Int32
|| id
->type() == MIRType::Value
);
4827 // Emit an overrecursed check: this is necessary because the cache can
4828 // attach a scripted getter stub that calls this script recursively.
4829 gen
->setNeedsOverrecursedCheck();
4831 // If this is a GetProp, the id is a constant string. Allow passing it as a
4832 // constant to reduce register allocation pressure.
4834 id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
;
4836 auto* lir
= new (alloc()) LGetPropertyCache(
4837 useBoxOrTyped(value
), useBoxOrTypedOrConstant(id
, useConstId
));
4838 defineBox(lir
, ins
);
4839 assignSafepoint(lir
, ins
);
4842 void LIRGenerator::visitBindNameCache(MBindNameCache
* ins
) {
4843 MOZ_ASSERT(ins
->envChain()->type() == MIRType::Object
);
4844 MOZ_ASSERT(ins
->type() == MIRType::Object
);
4846 LBindNameCache
* lir
=
4847 new (alloc()) LBindNameCache(useRegister(ins
->envChain()), temp());
4849 assignSafepoint(lir
, ins
);
4852 void LIRGenerator::visitCallBindVar(MCallBindVar
* ins
) {
4853 MOZ_ASSERT(ins
->environmentChain()->type() == MIRType::Object
);
4854 MOZ_ASSERT(ins
->type() == MIRType::Object
);
4857 new (alloc()) LCallBindVar(useRegister(ins
->environmentChain()));
4861 void LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity
* ins
) {
4862 LGuardObjectIdentity
* guard
= new (alloc()) LGuardObjectIdentity(
4863 useRegister(ins
->object()), useRegister(ins
->expected()));
4864 assignSnapshot(guard
, ins
->bailoutKind());
4866 redefine(ins
, ins
->object());
4869 void LIRGenerator::visitGuardSpecificFunction(MGuardSpecificFunction
* ins
) {
4870 auto* guard
= new (alloc()) LGuardSpecificFunction(
4871 useRegister(ins
->function()), useRegister(ins
->expected()));
4872 assignSnapshot(guard
, ins
->bailoutKind());
4874 redefine(ins
, ins
->function());
4877 void LIRGenerator::visitGuardSpecificAtom(MGuardSpecificAtom
* ins
) {
4879 new (alloc()) LGuardSpecificAtom(useRegister(ins
->str()), temp());
4880 assignSnapshot(guard
, ins
->bailoutKind());
4882 redefine(ins
, ins
->str());
4883 assignSafepoint(guard
, ins
);
4886 void LIRGenerator::visitGuardSpecificSymbol(MGuardSpecificSymbol
* ins
) {
4887 auto* guard
= new (alloc()) LGuardSpecificSymbol(useRegister(ins
->symbol()));
4888 assignSnapshot(guard
, ins
->bailoutKind());
4890 redefine(ins
, ins
->symbol());
4893 void LIRGenerator::visitGuardSpecificInt32(MGuardSpecificInt32
* ins
) {
4894 auto* guard
= new (alloc()) LGuardSpecificInt32(useRegister(ins
->num()));
4895 assignSnapshot(guard
, ins
->bailoutKind());
4897 redefine(ins
, ins
->num());
4900 void LIRGenerator::visitGuardStringToIndex(MGuardStringToIndex
* ins
) {
4901 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
4902 auto* guard
= new (alloc()) LGuardStringToIndex(useRegister(ins
->string()));
4903 assignSnapshot(guard
, ins
->bailoutKind());
4905 assignSafepoint(guard
, ins
);
4908 void LIRGenerator::visitGuardStringToInt32(MGuardStringToInt32
* ins
) {
4909 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
4911 new (alloc()) LGuardStringToInt32(useRegister(ins
->string()), temp());
4912 assignSnapshot(guard
, ins
->bailoutKind());
4914 assignSafepoint(guard
, ins
);
4917 void LIRGenerator::visitGuardStringToDouble(MGuardStringToDouble
* ins
) {
4918 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
4919 auto* guard
= new (alloc())
4920 LGuardStringToDouble(useRegister(ins
->string()), temp(), temp());
4921 assignSnapshot(guard
, ins
->bailoutKind());
4923 assignSafepoint(guard
, ins
);
4926 void LIRGenerator::visitGuardNoDenseElements(MGuardNoDenseElements
* ins
) {
4928 new (alloc()) LGuardNoDenseElements(useRegister(ins
->object()), temp());
4929 assignSnapshot(guard
, ins
->bailoutKind());
4931 redefine(ins
, ins
->object());
4934 void LIRGenerator::visitGuardShape(MGuardShape
* ins
) {
4935 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4937 if (JitOptions
.spectreObjectMitigations
) {
4939 new (alloc()) LGuardShape(useRegisterAtStart(ins
->object()), temp());
4940 assignSnapshot(lir
, ins
->bailoutKind());
4941 defineReuseInput(lir
, ins
, 0);
4943 auto* lir
= new (alloc())
4944 LGuardShape(useRegister(ins
->object()), LDefinition::BogusTemp());
4945 assignSnapshot(lir
, ins
->bailoutKind());
4947 redefine(ins
, ins
->object());
4951 void LIRGenerator::visitGuardMultipleShapes(MGuardMultipleShapes
* ins
) {
4952 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4954 if (JitOptions
.spectreObjectMitigations
) {
4955 auto* lir
= new (alloc()) LGuardMultipleShapes(
4956 useRegisterAtStart(ins
->object()), useRegister(ins
->shapeList()),
4957 temp(), temp(), temp(), temp());
4958 assignSnapshot(lir
, ins
->bailoutKind());
4959 defineReuseInput(lir
, ins
, 0);
4961 auto* lir
= new (alloc()) LGuardMultipleShapes(
4962 useRegister(ins
->object()), useRegister(ins
->shapeList()), temp(),
4963 temp(), temp(), LDefinition::BogusTemp());
4964 assignSnapshot(lir
, ins
->bailoutKind());
4966 redefine(ins
, ins
->object());
4970 void LIRGenerator::visitGuardProto(MGuardProto
* ins
) {
4971 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4972 MOZ_ASSERT(ins
->expected()->type() == MIRType::Object
);
4974 auto* lir
= new (alloc()) LGuardProto(useRegister(ins
->object()),
4975 useRegister(ins
->expected()), temp());
4976 assignSnapshot(lir
, ins
->bailoutKind());
4978 redefine(ins
, ins
->object());
4981 void LIRGenerator::visitGuardNullProto(MGuardNullProto
* ins
) {
4982 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4984 auto* lir
= new (alloc()) LGuardNullProto(useRegister(ins
->object()), temp());
4985 assignSnapshot(lir
, ins
->bailoutKind());
4987 redefine(ins
, ins
->object());
4990 void LIRGenerator::visitGuardIsNativeObject(MGuardIsNativeObject
* ins
) {
4991 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
4994 new (alloc()) LGuardIsNativeObject(useRegister(ins
->object()), temp());
4995 assignSnapshot(lir
, ins
->bailoutKind());
4997 redefine(ins
, ins
->object());
5000 void LIRGenerator::visitGuardGlobalGeneration(MGuardGlobalGeneration
* ins
) {
5001 auto* lir
= new (alloc()) LGuardGlobalGeneration(temp());
5002 assignSnapshot(lir
, ins
->bailoutKind());
5006 void LIRGenerator::visitGuardFuse(MGuardFuse
* ins
) {
5007 auto* lir
= new (alloc()) LGuardFuse(temp());
5008 assignSnapshot(lir
, ins
->bailoutKind());
5012 void LIRGenerator::visitGuardIsProxy(MGuardIsProxy
* ins
) {
5013 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5015 auto* lir
= new (alloc()) LGuardIsProxy(useRegister(ins
->object()), temp());
5016 assignSnapshot(lir
, ins
->bailoutKind());
5018 redefine(ins
, ins
->object());
5021 void LIRGenerator::visitGuardIsNotProxy(MGuardIsNotProxy
* ins
) {
5022 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5025 new (alloc()) LGuardIsNotProxy(useRegister(ins
->object()), temp());
5026 assignSnapshot(lir
, ins
->bailoutKind());
5028 redefine(ins
, ins
->object());
5031 void LIRGenerator::visitGuardIsNotDOMProxy(MGuardIsNotDOMProxy
* ins
) {
5032 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
5035 new (alloc()) LGuardIsNotDOMProxy(useRegister(ins
->proxy()), temp());
5036 assignSnapshot(lir
, ins
->bailoutKind());
5038 redefine(ins
, ins
->proxy());
5041 void LIRGenerator::visitProxyGet(MProxyGet
* ins
) {
5042 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
5043 auto* lir
= new (alloc())
5044 LProxyGet(useRegisterAtStart(ins
->proxy()), tempFixed(CallTempReg0
));
5045 defineReturn(lir
, ins
);
5046 assignSafepoint(lir
, ins
);
5049 void LIRGenerator::visitProxyGetByValue(MProxyGetByValue
* ins
) {
5050 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
5051 MOZ_ASSERT(ins
->idVal()->type() == MIRType::Value
);
5052 auto* lir
= new (alloc()) LProxyGetByValue(useRegisterAtStart(ins
->proxy()),
5053 useBoxAtStart(ins
->idVal()));
5054 defineReturn(lir
, ins
);
5055 assignSafepoint(lir
, ins
);
5058 void LIRGenerator::visitProxyHasProp(MProxyHasProp
* ins
) {
5059 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
5060 MOZ_ASSERT(ins
->idVal()->type() == MIRType::Value
);
5061 auto* lir
= new (alloc()) LProxyHasProp(useRegisterAtStart(ins
->proxy()),
5062 useBoxAtStart(ins
->idVal()));
5063 defineReturn(lir
, ins
);
5064 assignSafepoint(lir
, ins
);
5067 void LIRGenerator::visitProxySet(MProxySet
* ins
) {
5068 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
5069 MOZ_ASSERT(ins
->rhs()->type() == MIRType::Value
);
5070 auto* lir
= new (alloc())
5071 LProxySet(useRegisterAtStart(ins
->proxy()), useBoxAtStart(ins
->rhs()),
5072 tempFixed(CallTempReg0
));
5074 assignSafepoint(lir
, ins
);
5077 void LIRGenerator::visitProxySetByValue(MProxySetByValue
* ins
) {
5078 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
5079 MOZ_ASSERT(ins
->idVal()->type() == MIRType::Value
);
5080 MOZ_ASSERT(ins
->rhs()->type() == MIRType::Value
);
5081 auto* lir
= new (alloc())
5082 LProxySetByValue(useRegisterAtStart(ins
->proxy()),
5083 useBoxAtStart(ins
->idVal()), useBoxAtStart(ins
->rhs()));
5085 assignSafepoint(lir
, ins
);
5088 void LIRGenerator::visitCallSetArrayLength(MCallSetArrayLength
* ins
) {
5089 MOZ_ASSERT(ins
->obj()->type() == MIRType::Object
);
5090 MOZ_ASSERT(ins
->rhs()->type() == MIRType::Value
);
5091 auto* lir
= new (alloc()) LCallSetArrayLength(useRegisterAtStart(ins
->obj()),
5092 useBoxAtStart(ins
->rhs()));
5094 assignSafepoint(lir
, ins
);
5097 void LIRGenerator::visitMegamorphicLoadSlot(MMegamorphicLoadSlot
* ins
) {
5098 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5099 auto* lir
= new (alloc())
5100 LMegamorphicLoadSlot(useRegisterAtStart(ins
->object()),
5101 tempFixed(CallTempReg0
), tempFixed(CallTempReg1
),
5102 tempFixed(CallTempReg2
), tempFixed(CallTempReg3
));
5103 assignSnapshot(lir
, ins
->bailoutKind());
5104 defineReturn(lir
, ins
);
5107 void LIRGenerator::visitMegamorphicLoadSlotByValue(
5108 MMegamorphicLoadSlotByValue
* ins
) {
5109 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5110 MOZ_ASSERT(ins
->idVal()->type() == MIRType::Value
);
5111 auto* lir
= new (alloc()) LMegamorphicLoadSlotByValue(
5112 useRegisterAtStart(ins
->object()), useBoxAtStart(ins
->idVal()),
5113 tempFixed(CallTempReg0
), tempFixed(CallTempReg1
),
5114 tempFixed(CallTempReg2
));
5115 assignSnapshot(lir
, ins
->bailoutKind());
5116 defineReturn(lir
, ins
);
5119 void LIRGenerator::visitMegamorphicStoreSlot(MMegamorphicStoreSlot
* ins
) {
5120 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5121 MOZ_ASSERT(ins
->rhs()->type() == MIRType::Value
);
5123 #ifdef JS_CODEGEN_X86
5124 auto* lir
= new (alloc()) LMegamorphicStoreSlot(
5125 useFixedAtStart(ins
->object(), CallTempReg0
),
5126 useBoxFixedAtStart(ins
->rhs(), CallTempReg1
, CallTempReg2
),
5127 tempFixed(CallTempReg5
));
5129 auto* lir
= new (alloc())
5130 LMegamorphicStoreSlot(useRegisterAtStart(ins
->object()),
5131 useBoxAtStart(ins
->rhs()), tempFixed(CallTempReg0
),
5132 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
5136 assignSafepoint(lir
, ins
);
5139 void LIRGenerator::visitMegamorphicHasProp(MMegamorphicHasProp
* ins
) {
5140 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5141 MOZ_ASSERT(ins
->idVal()->type() == MIRType::Value
);
5142 auto* lir
= new (alloc())
5143 LMegamorphicHasProp(useRegisterAtStart(ins
->object()),
5144 useBoxAtStart(ins
->idVal()), tempFixed(CallTempReg0
),
5145 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
5146 assignSnapshot(lir
, ins
->bailoutKind());
5147 defineReturn(lir
, ins
);
5150 void LIRGenerator::visitGuardIsNotArrayBufferMaybeShared(
5151 MGuardIsNotArrayBufferMaybeShared
* ins
) {
5152 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5154 auto* lir
= new (alloc())
5155 LGuardIsNotArrayBufferMaybeShared(useRegister(ins
->object()), temp());
5156 assignSnapshot(lir
, ins
->bailoutKind());
5158 redefine(ins
, ins
->object());
5161 void LIRGenerator::visitGuardIsTypedArray(MGuardIsTypedArray
* ins
) {
5162 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5165 new (alloc()) LGuardIsTypedArray(useRegister(ins
->object()), temp());
5166 assignSnapshot(lir
, ins
->bailoutKind());
5168 redefine(ins
, ins
->object());
5171 void LIRGenerator::visitGuardIsFixedLengthTypedArray(
5172 MGuardIsFixedLengthTypedArray
* ins
) {
5173 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5175 auto* lir
= new (alloc())
5176 LGuardIsFixedLengthTypedArray(useRegister(ins
->object()), temp());
5177 assignSnapshot(lir
, ins
->bailoutKind());
5179 redefine(ins
, ins
->object());
5182 void LIRGenerator::visitGuardHasProxyHandler(MGuardHasProxyHandler
* ins
) {
5183 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5185 auto* lir
= new (alloc()) LGuardHasProxyHandler(useRegister(ins
->object()));
5186 assignSnapshot(lir
, ins
->bailoutKind());
5188 redefine(ins
, ins
->object());
5191 void LIRGenerator::visitNurseryObject(MNurseryObject
* ins
) {
5192 MOZ_ASSERT(ins
->type() == MIRType::Object
);
5194 auto* lir
= new (alloc()) LNurseryObject();
5198 void LIRGenerator::visitGuardValue(MGuardValue
* ins
) {
5199 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5200 auto* lir
= new (alloc()) LGuardValue(useBox(ins
->value()));
5201 assignSnapshot(lir
, ins
->bailoutKind());
5203 redefine(ins
, ins
->value());
5206 void LIRGenerator::visitGuardNullOrUndefined(MGuardNullOrUndefined
* ins
) {
5207 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5208 auto* lir
= new (alloc()) LGuardNullOrUndefined(useBox(ins
->value()));
5209 assignSnapshot(lir
, ins
->bailoutKind());
5211 redefine(ins
, ins
->value());
5214 void LIRGenerator::visitGuardIsNotObject(MGuardIsNotObject
* ins
) {
5215 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5216 auto* lir
= new (alloc()) LGuardIsNotObject(useBox(ins
->value()));
5217 assignSnapshot(lir
, ins
->bailoutKind());
5219 redefine(ins
, ins
->value());
5222 void LIRGenerator::visitGuardFunctionFlags(MGuardFunctionFlags
* ins
) {
5223 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
5225 auto* lir
= new (alloc()) LGuardFunctionFlags(useRegister(ins
->function()));
5226 assignSnapshot(lir
, ins
->bailoutKind());
5228 redefine(ins
, ins
->function());
5231 void LIRGenerator::visitGuardFunctionIsNonBuiltinCtor(
5232 MGuardFunctionIsNonBuiltinCtor
* ins
) {
5233 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
5235 auto* lir
= new (alloc())
5236 LGuardFunctionIsNonBuiltinCtor(useRegister(ins
->function()), temp());
5237 assignSnapshot(lir
, ins
->bailoutKind());
5239 redefine(ins
, ins
->function());
5242 void LIRGenerator::visitGuardFunctionKind(MGuardFunctionKind
* ins
) {
5243 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
5246 new (alloc()) LGuardFunctionKind(useRegister(ins
->function()), temp());
5247 assignSnapshot(lir
, ins
->bailoutKind());
5249 redefine(ins
, ins
->function());
5252 void LIRGenerator::visitGuardFunctionScript(MGuardFunctionScript
* ins
) {
5253 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
5255 auto* lir
= new (alloc()) LGuardFunctionScript(useRegister(ins
->function()));
5256 assignSnapshot(lir
, ins
->bailoutKind());
5258 redefine(ins
, ins
->function());
5261 void LIRGenerator::visitAssertRange(MAssertRange
* ins
) {
5262 MDefinition
* input
= ins
->input();
5263 LInstruction
* lir
= nullptr;
5265 switch (input
->type()) {
5266 case MIRType::Boolean
:
5267 case MIRType::Int32
:
5268 case MIRType::IntPtr
:
5269 lir
= new (alloc()) LAssertRangeI(useRegisterAtStart(input
));
5272 case MIRType::Double
:
5273 lir
= new (alloc()) LAssertRangeD(useRegister(input
), tempDouble());
5276 case MIRType::Float32
:
5278 LAssertRangeF(useRegister(input
), tempDouble(), tempDouble());
5281 case MIRType::Value
:
5282 lir
= new (alloc()) LAssertRangeV(useBox(input
), tempToUnbox(),
5283 tempDouble(), tempDouble());
5287 MOZ_CRASH("Unexpected Range for MIRType");
5295 void LIRGenerator::visitAssertClass(MAssertClass
* ins
) {
5297 new (alloc()) LAssertClass(useRegisterAtStart(ins
->input()), temp());
5301 void LIRGenerator::visitAssertShape(MAssertShape
* ins
) {
5302 auto* lir
= new (alloc()) LAssertShape(useRegisterAtStart(ins
->input()));
5306 void LIRGenerator::visitDeleteProperty(MDeleteProperty
* ins
) {
5307 LCallDeleteProperty
* lir
=
5308 new (alloc()) LCallDeleteProperty(useBoxAtStart(ins
->value()));
5309 defineReturn(lir
, ins
);
5310 assignSafepoint(lir
, ins
);
5313 void LIRGenerator::visitDeleteElement(MDeleteElement
* ins
) {
5314 LCallDeleteElement
* lir
= new (alloc()) LCallDeleteElement(
5315 useBoxAtStart(ins
->value()), useBoxAtStart(ins
->index()));
5316 defineReturn(lir
, ins
);
5317 assignSafepoint(lir
, ins
);
5320 void LIRGenerator::visitObjectToIterator(MObjectToIterator
* ins
) {
5321 auto* lir
= new (alloc())
5322 LObjectToIterator(useRegister(ins
->object()), temp(), temp(), temp());
5324 assignSafepoint(lir
, ins
);
5327 void LIRGenerator::visitValueToIterator(MValueToIterator
* ins
) {
5328 auto* lir
= new (alloc()) LValueToIterator(useBoxAtStart(ins
->value()));
5329 defineReturn(lir
, ins
);
5330 assignSafepoint(lir
, ins
);
5333 void LIRGenerator::visitLoadSlotByIteratorIndex(MLoadSlotByIteratorIndex
* ins
) {
5334 auto* lir
= new (alloc()) LLoadSlotByIteratorIndex(
5335 useRegisterAtStart(ins
->object()), useRegisterAtStart(ins
->iterator()),
5337 defineBox(lir
, ins
);
5340 void LIRGenerator::visitStoreSlotByIteratorIndex(
5341 MStoreSlotByIteratorIndex
* ins
) {
5342 auto* lir
= new (alloc()) LStoreSlotByIteratorIndex(
5343 useRegister(ins
->object()), useRegister(ins
->iterator()),
5344 useBox(ins
->value()), temp(), temp());
5348 void LIRGenerator::visitIteratorHasIndices(MIteratorHasIndices
* ins
) {
5349 MOZ_ASSERT(ins
->hasOneUse());
5353 void LIRGenerator::visitSetPropertyCache(MSetPropertyCache
* ins
) {
5354 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5356 MDefinition
* id
= ins
->idval();
5357 MOZ_ASSERT(id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
||
5358 id
->type() == MIRType::Int32
|| id
->type() == MIRType::Value
);
5360 // If this is a SetProp, the id is a constant string. Allow passing it as a
5361 // constant to reduce register allocation pressure.
5363 id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
;
5364 bool useConstValue
= IsNonNurseryConstant(ins
->value());
5366 // Emit an overrecursed check: this is necessary because the cache can
5367 // attach a scripted setter stub that calls this script recursively.
5368 gen
->setNeedsOverrecursedCheck();
5370 // We need a double temp register for TypedArray stubs.
5371 LDefinition tempD
= tempFixed(FloatReg0
);
5373 LInstruction
* lir
= new (alloc()) LSetPropertyCache(
5374 useRegister(ins
->object()), useBoxOrTypedOrConstant(id
, useConstId
),
5375 useBoxOrTypedOrConstant(ins
->value(), useConstValue
), temp(), tempD
);
5377 assignSafepoint(lir
, ins
);
5380 void LIRGenerator::visitMegamorphicSetElement(MMegamorphicSetElement
* ins
) {
5381 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5382 MOZ_ASSERT(ins
->index()->type() == MIRType::Value
);
5383 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5385 // See comment in LIROps.yaml (x86 is short on registers)
5386 #ifdef JS_CODEGEN_X86
5387 auto* lir
= new (alloc()) LMegamorphicSetElement(
5388 useFixedAtStart(ins
->object(), CallTempReg0
),
5389 useBoxFixedAtStart(ins
->index(), CallTempReg1
, CallTempReg2
),
5390 useBoxFixedAtStart(ins
->value(), CallTempReg3
, CallTempReg4
),
5391 tempFixed(CallTempReg5
));
5393 auto* lir
= new (alloc()) LMegamorphicSetElement(
5394 useRegisterAtStart(ins
->object()), useBoxAtStart(ins
->index()),
5395 useBoxAtStart(ins
->value()), tempFixed(CallTempReg0
),
5396 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
5399 assignSafepoint(lir
, ins
);
5402 void LIRGenerator::visitGetIteratorCache(MGetIteratorCache
* ins
) {
5403 MDefinition
* value
= ins
->value();
5404 MOZ_ASSERT(value
->type() == MIRType::Object
||
5405 value
->type() == MIRType::Value
);
5407 LGetIteratorCache
* lir
=
5408 new (alloc()) LGetIteratorCache(useBoxOrTyped(value
), temp(), temp());
5410 assignSafepoint(lir
, ins
);
5413 void LIRGenerator::visitOptimizeSpreadCallCache(MOptimizeSpreadCallCache
* ins
) {
5414 MDefinition
* value
= ins
->value();
5415 MOZ_ASSERT(value
->type() == MIRType::Value
);
5417 auto* lir
= new (alloc()) LOptimizeSpreadCallCache(useBox(value
), temp());
5418 defineBox(lir
, ins
);
5419 assignSafepoint(lir
, ins
);
5422 void LIRGenerator::visitIteratorMore(MIteratorMore
* ins
) {
5423 LIteratorMore
* lir
=
5424 new (alloc()) LIteratorMore(useRegister(ins
->iterator()), temp());
5425 defineBox(lir
, ins
);
5428 void LIRGenerator::visitIsNoIter(MIsNoIter
* ins
) {
5429 MOZ_ASSERT(ins
->hasOneUse());
5433 void LIRGenerator::visitIteratorEnd(MIteratorEnd
* ins
) {
5434 LIteratorEnd
* lir
= new (alloc())
5435 LIteratorEnd(useRegister(ins
->iterator()), temp(), temp(), temp());
5439 void LIRGenerator::visitCloseIterCache(MCloseIterCache
* ins
) {
5440 LCloseIterCache
* lir
=
5441 new (alloc()) LCloseIterCache(useRegister(ins
->iter()), temp());
5443 assignSafepoint(lir
, ins
);
5446 void LIRGenerator::visitOptimizeGetIteratorCache(
5447 MOptimizeGetIteratorCache
* ins
) {
5448 MDefinition
* value
= ins
->value();
5449 MOZ_ASSERT(value
->type() == MIRType::Value
);
5451 auto* lir
= new (alloc()) LOptimizeGetIteratorCache(useBox(value
), temp());
5453 assignSafepoint(lir
, ins
);
5456 void LIRGenerator::visitStringLength(MStringLength
* ins
) {
5457 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
5458 define(new (alloc()) LStringLength(useRegisterAtStart(ins
->string())), ins
);
5461 void LIRGenerator::visitArgumentsLength(MArgumentsLength
* ins
) {
5462 define(new (alloc()) LArgumentsLength(), ins
);
5465 void LIRGenerator::visitGetFrameArgument(MGetFrameArgument
* ins
) {
5466 LGetFrameArgument
* lir
=
5467 new (alloc()) LGetFrameArgument(useRegisterOrConstant(ins
->index()));
5468 defineBox(lir
, ins
);
5471 void LIRGenerator::visitGetFrameArgumentHole(MGetFrameArgumentHole
* ins
) {
5472 LDefinition spectreTemp
=
5473 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
5475 auto* lir
= new (alloc()) LGetFrameArgumentHole(
5476 useRegister(ins
->index()), useRegister(ins
->length()), spectreTemp
);
5477 assignSnapshot(lir
, ins
->bailoutKind());
5478 defineBox(lir
, ins
);
5481 void LIRGenerator::visitNewTarget(MNewTarget
* ins
) {
5482 LNewTarget
* lir
= new (alloc()) LNewTarget();
5483 defineBox(lir
, ins
);
5486 void LIRGenerator::visitRest(MRest
* ins
) {
5487 MOZ_ASSERT(ins
->numActuals()->type() == MIRType::Int32
);
5489 LRest
* lir
= new (alloc())
5490 LRest(useRegisterAtStart(ins
->numActuals()), tempFixed(CallTempReg0
),
5491 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
5492 defineReturn(lir
, ins
);
5493 assignSafepoint(lir
, ins
);
5496 void LIRGenerator::visitThrow(MThrow
* ins
) {
5497 MDefinition
* value
= ins
->value();
5498 MOZ_ASSERT(value
->type() == MIRType::Value
);
5500 LThrow
* lir
= new (alloc()) LThrow(useBoxAtStart(value
));
5502 assignSafepoint(lir
, ins
);
5505 void LIRGenerator::visitThrowWithStack(MThrowWithStack
* ins
) {
5506 MDefinition
* value
= ins
->value();
5507 MOZ_ASSERT(value
->type() == MIRType::Value
);
5509 MDefinition
* stack
= ins
->stack();
5510 MOZ_ASSERT(stack
->type() == MIRType::Value
);
5513 new (alloc()) LThrowWithStack(useBoxAtStart(value
), useBoxAtStart(stack
));
5515 assignSafepoint(lir
, ins
);
5518 void LIRGenerator::visitInCache(MInCache
* ins
) {
5519 MDefinition
* lhs
= ins
->lhs();
5520 MDefinition
* rhs
= ins
->rhs();
5522 MOZ_ASSERT(lhs
->type() == MIRType::String
|| lhs
->type() == MIRType::Symbol
||
5523 lhs
->type() == MIRType::Int32
|| lhs
->type() == MIRType::Value
);
5524 MOZ_ASSERT(rhs
->type() == MIRType::Object
);
5527 new (alloc()) LInCache(useBoxOrTyped(lhs
), useRegister(rhs
), temp());
5529 assignSafepoint(lir
, ins
);
5532 void LIRGenerator::visitHasOwnCache(MHasOwnCache
* ins
) {
5533 MDefinition
* value
= ins
->value();
5534 MOZ_ASSERT(value
->type() == MIRType::Object
||
5535 value
->type() == MIRType::Value
);
5537 MDefinition
* id
= ins
->idval();
5538 MOZ_ASSERT(id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
||
5539 id
->type() == MIRType::Int32
|| id
->type() == MIRType::Value
);
5541 // Emit an overrecursed check: this is necessary because the cache can
5542 // attach a scripted getter stub that calls this script recursively.
5543 gen
->setNeedsOverrecursedCheck();
5546 new (alloc()) LHasOwnCache(useBoxOrTyped(value
), useBoxOrTyped(id
));
5548 assignSafepoint(lir
, ins
);
5551 void LIRGenerator::visitCheckPrivateFieldCache(MCheckPrivateFieldCache
* ins
) {
5552 MDefinition
* value
= ins
->value();
5553 MOZ_ASSERT(value
->type() == MIRType::Object
||
5554 value
->type() == MIRType::Value
);
5556 MDefinition
* id
= ins
->idval();
5557 MOZ_ASSERT(id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
||
5558 id
->type() == MIRType::Int32
|| id
->type() == MIRType::Value
);
5560 LCheckPrivateFieldCache
* lir
= new (alloc())
5561 LCheckPrivateFieldCache(useBoxOrTyped(value
), useBoxOrTyped(id
));
5563 assignSafepoint(lir
, ins
);
5566 void LIRGenerator::visitNewPrivateName(MNewPrivateName
* ins
) {
5567 auto* lir
= new (alloc()) LNewPrivateName();
5568 defineReturn(lir
, ins
);
5569 assignSafepoint(lir
, ins
);
5572 void LIRGenerator::visitInstanceOf(MInstanceOf
* ins
) {
5573 MDefinition
* lhs
= ins
->lhs();
5574 MDefinition
* rhs
= ins
->rhs();
5576 MOZ_ASSERT(lhs
->type() == MIRType::Value
|| lhs
->type() == MIRType::Object
);
5577 MOZ_ASSERT(rhs
->type() == MIRType::Object
);
5579 if (lhs
->type() == MIRType::Object
) {
5580 auto* lir
= new (alloc()) LInstanceOfO(useRegister(lhs
), useRegister(rhs
));
5582 assignSafepoint(lir
, ins
);
5584 auto* lir
= new (alloc()) LInstanceOfV(useBox(lhs
), useRegister(rhs
));
5586 assignSafepoint(lir
, ins
);
5590 void LIRGenerator::visitInstanceOfCache(MInstanceOfCache
* ins
) {
5591 MDefinition
* lhs
= ins
->lhs();
5592 MDefinition
* rhs
= ins
->rhs();
5594 MOZ_ASSERT(lhs
->type() == MIRType::Value
);
5595 MOZ_ASSERT(rhs
->type() == MIRType::Object
);
5597 LInstanceOfCache
* lir
=
5598 new (alloc()) LInstanceOfCache(useBox(lhs
), useRegister(rhs
));
5600 assignSafepoint(lir
, ins
);
5603 void LIRGenerator::visitIsArray(MIsArray
* ins
) {
5604 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5606 if (ins
->value()->type() == MIRType::Object
) {
5607 LIsArrayO
* lir
= new (alloc()) LIsArrayO(useRegister(ins
->value()));
5609 assignSafepoint(lir
, ins
);
5611 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5612 LIsArrayV
* lir
= new (alloc()) LIsArrayV(useBox(ins
->value()), temp());
5614 assignSafepoint(lir
, ins
);
5618 void LIRGenerator::visitIsTypedArray(MIsTypedArray
* ins
) {
5619 MOZ_ASSERT(ins
->value()->type() == MIRType::Object
);
5620 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5622 auto* lir
= new (alloc()) LIsTypedArray(useRegister(ins
->value()));
5625 if (ins
->isPossiblyWrapped()) {
5626 assignSafepoint(lir
, ins
);
5630 void LIRGenerator::visitIsCallable(MIsCallable
* ins
) {
5631 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5633 if (ins
->object()->type() == MIRType::Object
) {
5634 define(new (alloc()) LIsCallableO(useRegister(ins
->object())), ins
);
5636 MOZ_ASSERT(ins
->object()->type() == MIRType::Value
);
5637 define(new (alloc()) LIsCallableV(useBox(ins
->object()), temp()), ins
);
5641 void LIRGenerator::visitIsConstructor(MIsConstructor
* ins
) {
5642 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5643 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5644 define(new (alloc()) LIsConstructor(useRegister(ins
->object())), ins
);
5647 void LIRGenerator::visitIsCrossRealmArrayConstructor(
5648 MIsCrossRealmArrayConstructor
* ins
) {
5649 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5650 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5651 define(new (alloc())
5652 LIsCrossRealmArrayConstructor(useRegister(ins
->object())),
5656 static bool CanEmitAtUseForSingleTest(MInstruction
* ins
) {
5657 if (!ins
->canEmitAtUses()) {
5661 MUseIterator
iter(ins
->usesBegin());
5662 if (iter
== ins
->usesEnd()) {
5666 MNode
* node
= iter
->consumer();
5667 if (!node
->isDefinition()) {
5671 if (!node
->toDefinition()->isTest()) {
5676 return iter
== ins
->usesEnd();
5679 void LIRGenerator::visitIsObject(MIsObject
* ins
) {
5680 if (CanEmitAtUseForSingleTest(ins
)) {
5685 MDefinition
* opd
= ins
->input();
5686 MOZ_ASSERT(opd
->type() == MIRType::Value
);
5687 LIsObject
* lir
= new (alloc()) LIsObject(useBoxAtStart(opd
));
5691 void LIRGenerator::visitIsNullOrUndefined(MIsNullOrUndefined
* ins
) {
5692 if (CanEmitAtUseForSingleTest(ins
)) {
5697 MDefinition
* opd
= ins
->input();
5698 if (opd
->type() == MIRType::Value
) {
5699 auto* lir
= new (alloc()) LIsNullOrUndefined(useBoxAtStart(opd
));
5702 define(new (alloc()) LInteger(IsNullOrUndefined(opd
->type())), ins
);
5706 void LIRGenerator::visitHasClass(MHasClass
* ins
) {
5707 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5708 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5709 define(new (alloc()) LHasClass(useRegister(ins
->object())), ins
);
5712 void LIRGenerator::visitGuardToClass(MGuardToClass
* ins
) {
5713 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5714 MOZ_ASSERT(ins
->type() == MIRType::Object
);
5715 LGuardToClass
* lir
=
5716 new (alloc()) LGuardToClass(useRegisterAtStart(ins
->object()), temp());
5717 assignSnapshot(lir
, ins
->bailoutKind());
5718 defineReuseInput(lir
, ins
, 0);
5721 void LIRGenerator::visitGuardToFunction(MGuardToFunction
* ins
) {
5722 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5723 MOZ_ASSERT(ins
->type() == MIRType::Object
);
5724 LGuardToFunction
* lir
=
5725 new (alloc()) LGuardToFunction(useRegisterAtStart(ins
->object()), temp());
5726 assignSnapshot(lir
, ins
->bailoutKind());
5727 defineReuseInput(lir
, ins
, 0);
5730 void LIRGenerator::visitObjectClassToString(MObjectClassToString
* ins
) {
5731 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5732 MOZ_ASSERT(ins
->type() == MIRType::String
);
5733 auto* lir
= new (alloc()) LObjectClassToString(
5734 useRegisterAtStart(ins
->object()), tempFixed(CallTempReg0
));
5735 assignSnapshot(lir
, ins
->bailoutKind());
5736 defineReturn(lir
, ins
);
5739 void LIRGenerator::visitWasmAddOffset(MWasmAddOffset
* ins
) {
5740 MOZ_ASSERT(ins
->offset());
5741 if (ins
->base()->type() == MIRType::Int32
) {
5742 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
5743 MOZ_ASSERT(ins
->offset() <= UINT32_MAX
); // Because memory32
5744 define(new (alloc()) LWasmAddOffset(useRegisterAtStart(ins
->base())), ins
);
5746 MOZ_ASSERT(ins
->type() == MIRType::Int64
);
5748 defineInt64(new (alloc())
5749 LWasmAddOffset64(useInt64RegisterAtStart(ins
->base())),
5752 // Avoid situation where the input is (a,b) and the output is (b,a).
5753 defineInt64ReuseInput(
5754 new (alloc()) LWasmAddOffset64(useInt64RegisterAtStart(ins
->base())),
5760 void LIRGenerator::visitWasmLoadInstance(MWasmLoadInstance
* ins
) {
5761 if (ins
->type() == MIRType::Int64
) {
5763 LAllocation instance
= useRegisterAtStart(ins
->instance());
5765 // Avoid reusing instance for a 64-bit output pair as the load clobbers the
5766 // first half of that pair before loading the second half.
5767 LAllocation instance
= useRegister(ins
->instance());
5769 auto* lir
= new (alloc()) LWasmLoadInstance64(instance
);
5770 defineInt64(lir
, ins
);
5773 new (alloc()) LWasmLoadInstance(useRegisterAtStart(ins
->instance()));
5778 void LIRGenerator::visitWasmStoreInstance(MWasmStoreInstance
* ins
) {
5779 MDefinition
* value
= ins
->value();
5780 if (value
->type() == MIRType::Int64
) {
5782 LAllocation instance
= useRegisterAtStart(ins
->instance());
5783 LInt64Allocation valueAlloc
= useInt64RegisterAtStart(value
);
5785 LAllocation instance
= useRegister(ins
->instance());
5786 LInt64Allocation valueAlloc
= useInt64Register(value
);
5788 add(new (alloc()) LWasmStoreSlotI64(valueAlloc
, instance
, ins
->offset(),
5789 mozilla::Nothing()),
5792 MOZ_ASSERT(value
->type() != MIRType::WasmAnyRef
);
5793 LAllocation instance
= useRegisterAtStart(ins
->instance());
5794 LAllocation valueAlloc
= useRegisterAtStart(value
);
5796 LWasmStoreSlot(valueAlloc
, instance
, ins
->offset(), value
->type(),
5797 MNarrowingOp::None
, mozilla::Nothing()),
5802 void LIRGenerator::visitWasmHeapReg(MWasmHeapReg
* ins
) {
5803 #ifdef WASM_HAS_HEAPREG
5804 auto* lir
= new (alloc()) LWasmHeapReg();
5811 void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck
* ins
) {
5812 MOZ_ASSERT(!ins
->isRedundant());
5814 MDefinition
* index
= ins
->index();
5815 MDefinition
* boundsCheckLimit
= ins
->boundsCheckLimit();
5817 MOZ_ASSERT(boundsCheckLimit
->type() == index
->type());
5819 if (index
->type() == MIRType::Int64
) {
5820 if (JitOptions
.spectreIndexMasking
) {
5821 auto* lir
= new (alloc()) LWasmBoundsCheck64(
5822 useInt64RegisterAtStart(index
), useInt64Register(boundsCheckLimit
));
5823 defineInt64ReuseInput(lir
, ins
, 0);
5825 auto* lir
= new (alloc())
5826 LWasmBoundsCheck64(useInt64RegisterAtStart(index
),
5827 useInt64RegisterAtStart(boundsCheckLimit
));
5831 MOZ_ASSERT(index
->type() == MIRType::Int32
);
5833 if (JitOptions
.spectreIndexMasking
) {
5834 auto* lir
= new (alloc()) LWasmBoundsCheck(useRegisterAtStart(index
),
5835 useRegister(boundsCheckLimit
));
5836 defineReuseInput(lir
, ins
, 0);
5838 auto* lir
= new (alloc()) LWasmBoundsCheck(
5839 useRegisterAtStart(index
), useRegisterAtStart(boundsCheckLimit
));
5845 void LIRGenerator::visitWasmBoundsCheckRange32(MWasmBoundsCheckRange32
* ins
) {
5846 MDefinition
* index
= ins
->index();
5847 MDefinition
* length
= ins
->length();
5848 MDefinition
* limit
= ins
->limit();
5850 MOZ_ASSERT(index
->type() == MIRType::Int32
);
5851 MOZ_ASSERT(length
->type() == MIRType::Int32
);
5852 MOZ_ASSERT(limit
->type() == MIRType::Int32
);
5854 add(new (alloc()) LWasmBoundsCheckRange32(
5855 useRegister(index
), useRegister(length
), useRegister(limit
), temp()),
5859 void LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck
* ins
) {
5860 MDefinition
* index
= ins
->index();
5861 if (index
->type() == MIRType::Int64
) {
5863 new (alloc()) LWasmAlignmentCheck64(useInt64RegisterAtStart(index
));
5866 auto* lir
= new (alloc()) LWasmAlignmentCheck(useRegisterAtStart(index
));
5871 void LIRGenerator::visitWasmLoadInstanceDataField(
5872 MWasmLoadInstanceDataField
* ins
) {
5873 size_t offs
= wasm::Instance::offsetInData(ins
->instanceDataOffset());
5874 if (ins
->type() == MIRType::Int64
) {
5876 LAllocation instance
= useRegisterAtStart(ins
->instance());
5878 // Avoid reusing instance for the output pair as the load clobbers the first
5879 // half of that pair before loading the second half.
5880 LAllocation instance
= useRegister(ins
->instance());
5882 defineInt64(new (alloc())
5883 LWasmLoadSlotI64(instance
, offs
, mozilla::Nothing()),
5886 LAllocation instance
= useRegisterAtStart(ins
->instance());
5887 define(new (alloc()) LWasmLoadSlot(instance
, offs
, ins
->type(),
5888 MWideningOp::None
, mozilla::Nothing()),
5893 void LIRGenerator::visitWasmLoadGlobalCell(MWasmLoadGlobalCell
* ins
) {
5894 if (ins
->type() == MIRType::Int64
) {
5896 LAllocation cellPtr
= useRegisterAtStart(ins
->cellPtr());
5898 // Avoid reusing cellPtr for the output pair as the load clobbers the first
5899 // half of that pair before loading the second half.
5900 LAllocation cellPtr
= useRegister(ins
->cellPtr());
5902 defineInt64(new (alloc())
5903 LWasmLoadSlotI64(cellPtr
, /*offset=*/0, mozilla::Nothing()),
5906 LAllocation cellPtr
= useRegisterAtStart(ins
->cellPtr());
5907 define(new (alloc()) LWasmLoadSlot(cellPtr
, /*offset=*/0, ins
->type(),
5908 MWideningOp::None
, mozilla::Nothing()),
5913 void LIRGenerator::visitWasmLoadTableElement(MWasmLoadTableElement
* ins
) {
5914 LAllocation elements
= useRegisterAtStart(ins
->elements());
5915 LAllocation index
= useRegisterAtStart(ins
->index());
5916 define(new (alloc()) LWasmLoadTableElement(elements
, index
), ins
);
5919 void LIRGenerator::visitWasmStoreInstanceDataField(
5920 MWasmStoreInstanceDataField
* ins
) {
5921 MDefinition
* value
= ins
->value();
5922 size_t offs
= wasm::Instance::offsetInData(ins
->instanceDataOffset());
5923 if (value
->type() == MIRType::Int64
) {
5925 LAllocation instance
= useRegisterAtStart(ins
->instance());
5926 LInt64Allocation valueAlloc
= useInt64RegisterAtStart(value
);
5928 LAllocation instance
= useRegister(ins
->instance());
5929 LInt64Allocation valueAlloc
= useInt64Register(value
);
5932 LWasmStoreSlotI64(valueAlloc
, instance
, offs
, mozilla::Nothing()),
5935 MOZ_ASSERT(value
->type() != MIRType::WasmAnyRef
);
5936 LAllocation instance
= useRegisterAtStart(ins
->instance());
5937 LAllocation valueAlloc
= useRegisterAtStart(value
);
5938 add(new (alloc()) LWasmStoreSlot(valueAlloc
, instance
, offs
, value
->type(),
5939 MNarrowingOp::None
, mozilla::Nothing()),
5944 void LIRGenerator::visitWasmStoreGlobalCell(MWasmStoreGlobalCell
* ins
) {
5945 MDefinition
* value
= ins
->value();
5947 if (value
->type() == MIRType::Int64
) {
5949 LAllocation cellPtr
= useRegisterAtStart(ins
->cellPtr());
5950 LInt64Allocation valueAlloc
= useInt64RegisterAtStart(value
);
5952 LAllocation cellPtr
= useRegister(ins
->cellPtr());
5953 LInt64Allocation valueAlloc
= useInt64Register(value
);
5956 LWasmStoreSlotI64(valueAlloc
, cellPtr
, offs
, mozilla::Nothing()));
5958 MOZ_ASSERT(value
->type() != MIRType::WasmAnyRef
);
5959 LAllocation cellPtr
= useRegisterAtStart(ins
->cellPtr());
5960 LAllocation valueAlloc
= useRegisterAtStart(value
);
5961 add(new (alloc()) LWasmStoreSlot(valueAlloc
, cellPtr
, offs
, value
->type(),
5962 MNarrowingOp::None
, mozilla::Nothing()));
5966 void LIRGenerator::visitWasmStoreStackResult(MWasmStoreStackResult
* ins
) {
5967 MDefinition
* stackResultArea
= ins
->stackResultArea();
5968 MDefinition
* value
= ins
->value();
5969 size_t offs
= ins
->offset();
5971 if (value
->type() == MIRType::Int64
) {
5973 LWasmStoreSlotI64(useInt64Register(value
), useRegister(stackResultArea
),
5974 offs
, mozilla::Nothing());
5976 MOZ_ASSERT(value
->type() != MIRType::WasmAnyRef
);
5978 LWasmStoreSlot(useRegister(value
), useRegister(stackResultArea
), offs
,
5979 value
->type(), MNarrowingOp::None
, mozilla::Nothing());
5984 void LIRGenerator::visitWasmDerivedPointer(MWasmDerivedPointer
* ins
) {
5985 LAllocation base
= useRegisterAtStart(ins
->base());
5986 define(new (alloc()) LWasmDerivedPointer(base
), ins
);
5989 void LIRGenerator::visitWasmDerivedIndexPointer(MWasmDerivedIndexPointer
* ins
) {
5990 LAllocation base
= useRegisterAtStart(ins
->base());
5991 LAllocation index
= useRegisterAtStart(ins
->index());
5992 define(new (alloc()) LWasmDerivedIndexPointer(base
, index
), ins
);
5995 void LIRGenerator::visitWasmStoreRef(MWasmStoreRef
* ins
) {
5996 LAllocation instance
= useRegister(ins
->instance());
5997 LAllocation valueBase
= useFixed(ins
->valueBase(), PreBarrierReg
);
5998 LAllocation value
= useRegister(ins
->value());
5999 uint32_t valueOffset
= ins
->offset();
6001 LWasmStoreRef(instance
, valueBase
, value
, temp(), valueOffset
,
6002 mozilla::Nothing(), ins
->preBarrierKind()),
6006 void LIRGenerator::visitWasmPostWriteBarrier(MWasmPostWriteBarrier
* ins
) {
6007 LWasmPostWriteBarrier
* lir
= new (alloc()) LWasmPostWriteBarrier(
6008 useFixed(ins
->instance(), InstanceReg
), useRegister(ins
->object()),
6009 useRegister(ins
->valueBase()), useRegister(ins
->value()), temp(),
6010 ins
->valueOffset());
6012 assignWasmSafepoint(lir
);
6015 void LIRGenerator::visitWasmParameter(MWasmParameter
* ins
) {
6016 ABIArg abi
= ins
->abi();
6017 if (ins
->type() == MIRType::StackResults
) {
6018 // Functions that return stack results receive an extra incoming parameter
6019 // with type MIRType::StackResults. This value is a pointer to fresh
6020 // memory. Here we treat it as if it were in fact MIRType::Pointer.
6021 auto* lir
= new (alloc()) LWasmParameter
;
6022 LDefinition
def(LDefinition::TypeFrom(MIRType::Pointer
),
6023 LDefinition::FIXED
);
6024 def
.setOutput(abi
.argInRegister() ? LAllocation(abi
.reg())
6025 : LArgument(abi
.offsetFromArgBase()));
6026 define(lir
, ins
, def
);
6029 if (abi
.argInRegister()) {
6030 #if defined(JS_NUNBOX32)
6031 if (abi
.isGeneralRegPair()) {
6033 new (alloc()) LWasmParameterI64
, ins
,
6034 LInt64Allocation(LAllocation(AnyRegister(abi
.gpr64().high
)),
6035 LAllocation(AnyRegister(abi
.gpr64().low
))));
6039 defineFixed(new (alloc()) LWasmParameter
, ins
, LAllocation(abi
.reg()));
6042 if (ins
->type() == MIRType::Int64
) {
6043 MOZ_ASSERT(!abi
.argInRegister());
6045 new (alloc()) LWasmParameterI64
, ins
,
6046 #if defined(JS_NUNBOX32)
6047 LInt64Allocation(LArgument(abi
.offsetFromArgBase() + INT64HIGH_OFFSET
),
6048 LArgument(abi
.offsetFromArgBase() + INT64LOW_OFFSET
))
6050 LInt64Allocation(LArgument(abi
.offsetFromArgBase()))
6054 MOZ_ASSERT(IsNumberType(ins
->type()) || ins
->type() == MIRType::WasmAnyRef
6055 #ifdef ENABLE_WASM_SIMD
6056 || ins
->type() == MIRType::Simd128
6059 defineFixed(new (alloc()) LWasmParameter
, ins
,
6060 LArgument(abi
.offsetFromArgBase()));
6064 void LIRGenerator::visitWasmReturn(MWasmReturn
* ins
) {
6065 MDefinition
* rval
= ins
->getOperand(0);
6066 MDefinition
* instance
= ins
->getOperand(1);
6068 if (rval
->type() == MIRType::Int64
) {
6069 add(new (alloc()) LWasmReturnI64(useInt64Fixed(rval
, ReturnReg64
),
6070 useFixed(instance
, InstanceReg
)));
6074 LAllocation returnReg
;
6075 if (rval
->type() == MIRType::Float32
) {
6076 returnReg
= useFixed(rval
, ReturnFloat32Reg
);
6077 } else if (rval
->type() == MIRType::Double
) {
6078 returnReg
= useFixed(rval
, ReturnDoubleReg
);
6079 #ifdef ENABLE_WASM_SIMD
6080 } else if (rval
->type() == MIRType::Simd128
) {
6081 returnReg
= useFixed(rval
, ReturnSimd128Reg
);
6083 } else if (rval
->type() == MIRType::Int32
||
6084 rval
->type() == MIRType::WasmAnyRef
) {
6085 returnReg
= useFixed(rval
, ReturnReg
);
6087 MOZ_CRASH("Unexpected wasm return type");
6091 new (alloc()) LWasmReturn(useFixed(instance
, InstanceReg
), returnReg
);
6095 void LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid
* ins
) {
6096 MDefinition
* instance
= ins
->getOperand(0);
6097 LWasmReturnVoid
* lir
=
6098 new (alloc()) LWasmReturnVoid(useFixed(instance
, InstanceReg
));
6102 void LIRGenerator::visitWasmStackArg(MWasmStackArg
* ins
) {
6103 if (ins
->arg()->type() == MIRType::Int64
) {
6105 LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins
->arg())),
6107 } else if (IsFloatingPointType(ins
->arg()->type())) {
6108 MOZ_ASSERT(!ins
->arg()->isEmittedAtUses());
6109 add(new (alloc()) LWasmStackArg(useRegisterAtStart(ins
->arg())), ins
);
6111 add(new (alloc()) LWasmStackArg(useRegisterOrConstantAtStart(ins
->arg())),
6116 void LIRGenerator::visitWasmRegisterResult(MWasmRegisterResult
* ins
) {
6117 auto* lir
= new (alloc()) LWasmRegisterResult();
6118 uint32_t vreg
= getVirtualRegister();
6119 MOZ_ASSERT(ins
->type() != MIRType::Int64
);
6120 auto type
= LDefinition::TypeFrom(ins
->type());
6121 lir
->setDef(0, LDefinition(vreg
, type
, LGeneralReg(ins
->loc())));
6122 ins
->setVirtualRegister(vreg
);
6126 void LIRGenerator::visitWasmFloatRegisterResult(MWasmFloatRegisterResult
* ins
) {
6127 auto* lir
= new (alloc()) LWasmRegisterResult();
6128 uint32_t vreg
= getVirtualRegister();
6129 auto type
= LDefinition::TypeFrom(ins
->type());
6130 lir
->setDef(0, LDefinition(vreg
, type
, LFloatReg(ins
->loc())));
6131 ins
->setVirtualRegister(vreg
);
6135 void LIRGenerator::visitWasmRegister64Result(MWasmRegister64Result
* ins
) {
6136 MOZ_ASSERT(ins
->type() == MIRType::Int64
);
6137 uint32_t vreg
= getVirtualRegister();
6139 #if defined(JS_NUNBOX32)
6140 auto* lir
= new (alloc()) LWasmRegisterPairResult();
6141 lir
->setDef(INT64LOW_INDEX
,
6142 LDefinition(vreg
+ INT64LOW_INDEX
, LDefinition::GENERAL
,
6143 LGeneralReg(ins
->loc().low
)));
6144 lir
->setDef(INT64HIGH_INDEX
,
6145 LDefinition(vreg
+ INT64HIGH_INDEX
, LDefinition::GENERAL
,
6146 LGeneralReg(ins
->loc().high
)));
6147 getVirtualRegister();
6148 #elif defined(JS_PUNBOX64)
6149 auto* lir
= new (alloc()) LWasmRegisterResult();
6151 0, LDefinition(vreg
, LDefinition::GENERAL
, LGeneralReg(ins
->loc().reg
)));
6153 # error expected either JS_NUNBOX32 or JS_PUNBOX64
6156 ins
->setVirtualRegister(vreg
);
6160 void LIRGenerator::visitWasmStackResultArea(MWasmStackResultArea
* ins
) {
6161 MOZ_ASSERT(ins
->type() == MIRType::StackResults
);
6162 auto* lir
= new (alloc()) LWasmStackResultArea(temp());
6163 uint32_t vreg
= getVirtualRegister();
6165 LDefinition(vreg
, LDefinition::STACKRESULTS
, LDefinition::STACK
));
6166 ins
->setVirtualRegister(vreg
);
6170 void LIRGenerator::visitWasmStackResult(MWasmStackResult
* ins
) {
6171 MWasmStackResultArea
* area
= ins
->resultArea()->toWasmStackResultArea();
6172 LDefinition::Policy pol
= LDefinition::STACK
;
6174 if (ins
->type() == MIRType::Int64
) {
6175 auto* lir
= new (alloc()) LWasmStackResult64
;
6176 lir
->setOperand(0, use(area
, LUse(LUse::STACK
, /* usedAtStart = */ true)));
6177 uint32_t vreg
= getVirtualRegister();
6178 LDefinition::Type typ
= LDefinition::GENERAL
;
6179 #if defined(JS_NUNBOX32)
6180 getVirtualRegister();
6181 lir
->setDef(INT64LOW_INDEX
, LDefinition(vreg
+ INT64LOW_INDEX
, typ
, pol
));
6182 lir
->setDef(INT64HIGH_INDEX
, LDefinition(vreg
+ INT64HIGH_INDEX
, typ
, pol
));
6184 lir
->setDef(0, LDefinition(vreg
, typ
, pol
));
6186 ins
->setVirtualRegister(vreg
);
6191 auto* lir
= new (alloc()) LWasmStackResult
;
6192 lir
->setOperand(0, use(area
, LUse(LUse::STACK
, /* usedAtStart = */ true)));
6193 uint32_t vreg
= getVirtualRegister();
6194 LDefinition::Type typ
= LDefinition::TypeFrom(ins
->type());
6195 lir
->setDef(0, LDefinition(vreg
, typ
, pol
));
6196 ins
->setVirtualRegister(vreg
);
6200 template <class MWasmCallT
>
6201 void LIRGenerator::visitWasmCall(MWasmCallT ins
) {
6202 bool needsBoundsCheck
= true;
6203 mozilla::Maybe
<uint32_t> tableSize
;
6205 if (ins
->callee().isTable()) {
6206 MDefinition
* index
= ins
->getOperand(ins
->numArgs());
6208 if (ins
->callee().which() == wasm::CalleeDesc::WasmTable
) {
6209 uint32_t minLength
= ins
->callee().wasmTableMinLength();
6210 mozilla::Maybe
<uint32_t> maxLength
= ins
->callee().wasmTableMaxLength();
6211 if (index
->isConstant() &&
6212 uint32_t(index
->toConstant()->toInt32()) < minLength
) {
6213 needsBoundsCheck
= false;
6215 if (maxLength
.isSome() && *maxLength
== minLength
) {
6216 tableSize
= maxLength
;
6221 auto* lir
= allocateVariadic
<LWasmCall
>(ins
->numOperands(), needsBoundsCheck
,
6224 abort(AbortReason::Alloc
, "OOM: LIRGenerator::lowerWasmCall");
6228 for (unsigned i
= 0; i
< ins
->numArgs(); i
++) {
6230 i
, useFixedAtStart(ins
->getOperand(i
), ins
->registerForArg(i
)));
6233 if (ins
->callee().isTable()) {
6234 MDefinition
* index
= ins
->getOperand(ins
->numArgs());
6235 lir
->setOperand(ins
->numArgs(),
6236 useFixedAtStart(index
, WasmTableCallIndexReg
));
6238 if (ins
->callee().isFuncRef()) {
6239 MDefinition
* ref
= ins
->getOperand(ins
->numArgs());
6240 lir
->setOperand(ins
->numArgs(), useFixedAtStart(ref
, WasmCallRefReg
));
6244 assignWasmSafepoint(lir
);
6246 // WasmCall with WasmTable has two call instructions, and they both need a
6247 // safepoint associated with them. Create a second safepoint here; the node
6248 // otherwise does nothing, and codegen for it only marks the safepoint at the
6250 if (ins
->callee().which() == wasm::CalleeDesc::WasmTable
&&
6251 !ins
->isWasmReturnCall()) {
6252 auto* adjunctSafepoint
= new (alloc()) LWasmCallIndirectAdjunctSafepoint();
6253 add(adjunctSafepoint
);
6254 assignWasmSafepoint(adjunctSafepoint
);
6255 lir
->setAdjunctSafepoint(adjunctSafepoint
);
6259 void LIRGenerator::visitWasmCallCatchable(MWasmCallCatchable
* ins
) {
6263 void LIRGenerator::visitWasmCallUncatchable(MWasmCallUncatchable
* ins
) {
6267 void LIRGenerator::visitWasmReturnCall(MWasmReturnCall
* ins
) {
6271 void LIRGenerator::visitWasmCallLandingPrePad(MWasmCallLandingPrePad
* ins
) {
6272 add(new (alloc()) LWasmCallLandingPrePad
, ins
);
6275 void LIRGenerator::visitSetDOMProperty(MSetDOMProperty
* ins
) {
6276 MDefinition
* val
= ins
->value();
6278 Register cxReg
, objReg
, privReg
, valueReg
;
6279 GetTempRegForIntArg(0, 0, &cxReg
);
6280 GetTempRegForIntArg(1, 0, &objReg
);
6281 GetTempRegForIntArg(2, 0, &privReg
);
6282 GetTempRegForIntArg(3, 0, &valueReg
);
6284 // Keep using GetTempRegForIntArg, since we want to make sure we
6285 // don't clobber registers we're already using.
6286 Register tempReg1
, tempReg2
;
6287 GetTempRegForIntArg(4, 0, &tempReg1
);
6288 mozilla::DebugOnly
<bool> ok
= GetTempRegForIntArg(5, 0, &tempReg2
);
6289 MOZ_ASSERT(ok
, "How can we not have six temp registers?");
6291 LSetDOMProperty
* lir
= new (alloc())
6292 LSetDOMProperty(tempFixed(cxReg
), useFixedAtStart(ins
->object(), objReg
),
6293 useBoxFixedAtStart(val
, tempReg1
, tempReg2
),
6294 tempFixed(privReg
), tempFixed(valueReg
));
6296 assignSafepoint(lir
, ins
);
6299 void LIRGenerator::visitGetDOMProperty(MGetDOMProperty
* ins
) {
6300 Register cxReg
, objReg
, privReg
, valueReg
;
6301 GetTempRegForIntArg(0, 0, &cxReg
);
6302 GetTempRegForIntArg(1, 0, &objReg
);
6303 GetTempRegForIntArg(2, 0, &privReg
);
6304 mozilla::DebugOnly
<bool> ok
= GetTempRegForIntArg(3, 0, &valueReg
);
6305 MOZ_ASSERT(ok
, "How can we not have four temp registers?");
6306 LGetDOMProperty
* lir
= new (alloc())
6307 LGetDOMProperty(tempFixed(cxReg
), useFixedAtStart(ins
->object(), objReg
),
6308 tempFixed(privReg
), tempFixed(valueReg
));
6310 defineReturn(lir
, ins
);
6311 assignSafepoint(lir
, ins
);
6314 void LIRGenerator::visitGetDOMMember(MGetDOMMember
* ins
) {
6315 MOZ_ASSERT(ins
->isDomMovable(), "Members had better be movable");
6316 // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
6317 // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
6318 // value can in fact change as a result of DOM setters and method calls.
6319 MOZ_ASSERT(ins
->domAliasSet() != JSJitInfo::AliasEverything
,
6320 "Member gets had better not alias the world");
6322 MDefinition
* obj
= ins
->object();
6323 MOZ_ASSERT(obj
->type() == MIRType::Object
);
6325 MIRType type
= ins
->type();
6327 if (type
== MIRType::Value
) {
6328 LGetDOMMemberV
* lir
= new (alloc()) LGetDOMMemberV(useRegisterAtStart(obj
));
6329 defineBox(lir
, ins
);
6331 LGetDOMMemberT
* lir
=
6332 new (alloc()) LGetDOMMemberT(useRegisterForTypedLoad(obj
, type
));
6337 void LIRGenerator::visitLoadDOMExpandoValue(MLoadDOMExpandoValue
* ins
) {
6338 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
6340 new (alloc()) LLoadDOMExpandoValue(useRegisterAtStart(ins
->proxy()));
6341 defineBox(lir
, ins
);
6344 void LIRGenerator::visitLoadDOMExpandoValueGuardGeneration(
6345 MLoadDOMExpandoValueGuardGeneration
* ins
) {
6346 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
6347 auto* lir
= new (alloc())
6348 LLoadDOMExpandoValueGuardGeneration(useRegisterAtStart(ins
->proxy()));
6349 assignSnapshot(lir
, ins
->bailoutKind());
6350 defineBox(lir
, ins
);
6353 void LIRGenerator::visitLoadDOMExpandoValueIgnoreGeneration(
6354 MLoadDOMExpandoValueIgnoreGeneration
* ins
) {
6355 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
6356 auto* lir
= new (alloc())
6357 LLoadDOMExpandoValueIgnoreGeneration(useRegisterAtStart(ins
->proxy()));
6358 defineBox(lir
, ins
);
6361 void LIRGenerator::visitGuardDOMExpandoMissingOrGuardShape(
6362 MGuardDOMExpandoMissingOrGuardShape
* ins
) {
6363 MOZ_ASSERT(ins
->expando()->type() == MIRType::Value
);
6364 auto* lir
= new (alloc())
6365 LGuardDOMExpandoMissingOrGuardShape(useBox(ins
->expando()), temp());
6366 assignSnapshot(lir
, ins
->bailoutKind());
6368 redefine(ins
, ins
->expando());
6371 void LIRGenerator::visitIncrementWarmUpCounter(MIncrementWarmUpCounter
* ins
) {
6372 LIncrementWarmUpCounter
* lir
= new (alloc()) LIncrementWarmUpCounter(temp());
6376 void LIRGenerator::visitLexicalCheck(MLexicalCheck
* ins
) {
6377 MDefinition
* input
= ins
->input();
6378 MOZ_ASSERT(input
->type() == MIRType::Value
);
6379 LLexicalCheck
* lir
= new (alloc()) LLexicalCheck(useBox(input
));
6380 assignSnapshot(lir
, ins
->bailoutKind());
6382 redefine(ins
, input
);
6385 void LIRGenerator::visitThrowRuntimeLexicalError(
6386 MThrowRuntimeLexicalError
* ins
) {
6387 LThrowRuntimeLexicalError
* lir
= new (alloc()) LThrowRuntimeLexicalError();
6389 assignSafepoint(lir
, ins
);
6392 void LIRGenerator::visitThrowMsg(MThrowMsg
* ins
) {
6393 LThrowMsg
* lir
= new (alloc()) LThrowMsg();
6395 assignSafepoint(lir
, ins
);
6398 void LIRGenerator::visitGlobalDeclInstantiation(MGlobalDeclInstantiation
* ins
) {
6399 LGlobalDeclInstantiation
* lir
= new (alloc()) LGlobalDeclInstantiation();
6401 assignSafepoint(lir
, ins
);
6404 void LIRGenerator::visitDebugger(MDebugger
* ins
) {
6405 auto* lir
= new (alloc()) LDebugger(tempFixed(CallTempReg0
));
6406 assignSnapshot(lir
, ins
->bailoutKind());
6410 void LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree
* ins
) {
6411 define(new (alloc()) LAtomicIsLockFree(useRegister(ins
->input())), ins
);
6414 void LIRGenerator::visitCheckReturn(MCheckReturn
* ins
) {
6415 MDefinition
* retVal
= ins
->returnValue();
6416 MDefinition
* thisVal
= ins
->thisValue();
6417 MOZ_ASSERT(retVal
->type() == MIRType::Value
);
6418 MOZ_ASSERT(thisVal
->type() == MIRType::Value
);
6421 new (alloc()) LCheckReturn(useBoxAtStart(retVal
), useBoxAtStart(thisVal
));
6422 defineBox(lir
, ins
);
6423 assignSafepoint(lir
, ins
);
6426 void LIRGenerator::visitCheckIsObj(MCheckIsObj
* ins
) {
6427 MDefinition
* input
= ins
->input();
6428 MOZ_ASSERT(input
->type() == MIRType::Value
);
6430 LCheckIsObj
* lir
= new (alloc()) LCheckIsObj(useBox(input
));
6432 assignSafepoint(lir
, ins
);
6436 void LIRGenerator::visitCheckScriptedProxyGetResult(
6437 MCheckScriptedProxyGetResult
* ins
) {
6438 MDefinition
* target
= ins
->target();
6439 MDefinition
* id
= ins
->id();
6440 MDefinition
* value
= ins
->value();
6442 LCheckScriptedProxyGetResult
* lir
=
6443 new (alloc()) LCheckScriptedProxyGetResult(useBox(target
), useBox(id
),
6444 useBox(value
), temp(), temp());
6446 assignSafepoint(lir
, ins
);
6450 void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible
* ins
) {
6451 MDefinition
* checkVal
= ins
->checkValue();
6452 MOZ_ASSERT(checkVal
->type() == MIRType::Value
);
6454 auto* lir
= new (alloc()) LCheckObjCoercible(useBoxAtStart(checkVal
));
6455 redefine(ins
, checkVal
);
6457 assignSafepoint(lir
, ins
);
6460 void LIRGenerator::visitCheckClassHeritage(MCheckClassHeritage
* ins
) {
6461 MDefinition
* heritage
= ins
->heritage();
6462 MOZ_ASSERT(heritage
->type() == MIRType::Value
);
6465 new (alloc()) LCheckClassHeritage(useBox(heritage
), temp(), temp());
6466 redefine(ins
, heritage
);
6468 assignSafepoint(lir
, ins
);
6471 void LIRGenerator::visitCheckThis(MCheckThis
* ins
) {
6472 MDefinition
* thisValue
= ins
->thisValue();
6473 MOZ_ASSERT(thisValue
->type() == MIRType::Value
);
6475 auto* lir
= new (alloc()) LCheckThis(useBoxAtStart(thisValue
));
6476 redefine(ins
, thisValue
);
6478 assignSafepoint(lir
, ins
);
6481 void LIRGenerator::visitCheckThisReinit(MCheckThisReinit
* ins
) {
6482 MDefinition
* thisValue
= ins
->thisValue();
6483 MOZ_ASSERT(thisValue
->type() == MIRType::Value
);
6485 auto* lir
= new (alloc()) LCheckThisReinit(useBoxAtStart(thisValue
));
6486 redefine(ins
, thisValue
);
6488 assignSafepoint(lir
, ins
);
6491 void LIRGenerator::visitGenerator(MGenerator
* ins
) {
6493 new (alloc()) LGenerator(useRegisterAtStart(ins
->callee()),
6494 useRegisterAtStart(ins
->environmentChain()),
6495 useRegisterAtStart(ins
->argsObject()));
6496 defineReturn(lir
, ins
);
6497 assignSafepoint(lir
, ins
);
6500 void LIRGenerator::visitAsyncResolve(MAsyncResolve
* ins
) {
6501 auto* lir
= new (alloc()) LAsyncResolve(useRegisterAtStart(ins
->generator()),
6502 useBoxAtStart(ins
->value()));
6503 defineReturn(lir
, ins
);
6504 assignSafepoint(lir
, ins
);
6507 void LIRGenerator::visitAsyncReject(MAsyncReject
* ins
) {
6508 auto* lir
= new (alloc())
6509 LAsyncReject(useRegisterAtStart(ins
->generator()),
6510 useBoxAtStart(ins
->reason()), useBoxAtStart(ins
->stack()));
6511 defineReturn(lir
, ins
);
6512 assignSafepoint(lir
, ins
);
6515 void LIRGenerator::visitAsyncAwait(MAsyncAwait
* ins
) {
6516 MOZ_ASSERT(ins
->generator()->type() == MIRType::Object
);
6517 auto* lir
= new (alloc()) LAsyncAwait(useBoxAtStart(ins
->value()),
6518 useRegisterAtStart(ins
->generator()));
6519 defineReturn(lir
, ins
);
6520 assignSafepoint(lir
, ins
);
6523 void LIRGenerator::visitCanSkipAwait(MCanSkipAwait
* ins
) {
6524 auto* lir
= new (alloc()) LCanSkipAwait(useBoxAtStart(ins
->value()));
6525 defineReturn(lir
, ins
);
6526 assignSafepoint(lir
, ins
);
6529 void LIRGenerator::visitMaybeExtractAwaitValue(MMaybeExtractAwaitValue
* ins
) {
6530 auto* lir
= new (alloc()) LMaybeExtractAwaitValue(
6531 useBoxAtStart(ins
->value()), useRegisterAtStart(ins
->canSkip()));
6532 defineReturn(lir
, ins
);
6533 assignSafepoint(lir
, ins
);
6536 void LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted
* ins
) {
6537 MDefinition
* checkVal
= ins
->checkValue();
6538 MOZ_ASSERT(checkVal
->type() == MIRType::Value
);
6540 LDebugCheckSelfHosted
* lir
=
6541 new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal
));
6542 redefine(ins
, checkVal
);
6544 assignSafepoint(lir
, ins
);
6547 void LIRGenerator::visitIsPackedArray(MIsPackedArray
* ins
) {
6548 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
6549 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
6551 auto lir
= new (alloc()) LIsPackedArray(useRegister(ins
->object()), temp());
6555 void LIRGenerator::visitGuardArrayIsPacked(MGuardArrayIsPacked
* ins
) {
6556 MOZ_ASSERT(ins
->array()->type() == MIRType::Object
);
6558 auto* lir
= new (alloc())
6559 LGuardArrayIsPacked(useRegister(ins
->array()), temp(), temp());
6560 assignSnapshot(lir
, ins
->bailoutKind());
6562 redefine(ins
, ins
->array());
6565 void LIRGenerator::visitGetPrototypeOf(MGetPrototypeOf
* ins
) {
6566 MOZ_ASSERT(ins
->target()->type() == MIRType::Object
);
6567 MOZ_ASSERT(ins
->type() == MIRType::Value
);
6569 auto lir
= new (alloc()) LGetPrototypeOf(useRegister(ins
->target()));
6570 defineBox(lir
, ins
);
6571 assignSafepoint(lir
, ins
);
6574 void LIRGenerator::visitObjectWithProto(MObjectWithProto
* ins
) {
6575 MOZ_ASSERT(ins
->prototype()->type() == MIRType::Value
);
6576 MOZ_ASSERT(ins
->type() == MIRType::Object
);
6578 auto* lir
= new (alloc()) LObjectWithProto(useBoxAtStart(ins
->prototype()));
6579 defineReturn(lir
, ins
);
6580 assignSafepoint(lir
, ins
);
6583 void LIRGenerator::visitObjectStaticProto(MObjectStaticProto
* ins
) {
6584 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
6585 MOZ_ASSERT(ins
->type() == MIRType::Object
);
6588 new (alloc()) LObjectStaticProto(useRegisterAtStart(ins
->object()));
6592 void LIRGenerator::visitBuiltinObject(MBuiltinObject
* ins
) {
6593 MOZ_ASSERT(ins
->type() == MIRType::Object
);
6595 auto* lir
= new (alloc()) LBuiltinObject();
6596 defineReturn(lir
, ins
);
6597 assignSafepoint(lir
, ins
);
6600 void LIRGenerator::visitReturn(MReturn
* ret
) {
6601 return visitReturnImpl(ret
->getOperand(0));
6604 void LIRGenerator::visitGeneratorReturn(MGeneratorReturn
* ret
) {
6605 return visitReturnImpl(ret
->getOperand(0), true);
6608 void LIRGenerator::visitSuperFunction(MSuperFunction
* ins
) {
6609 MOZ_ASSERT(ins
->callee()->type() == MIRType::Object
);
6610 MOZ_ASSERT(ins
->type() == MIRType::Value
);
6612 auto* lir
= new (alloc()) LSuperFunction(useRegister(ins
->callee()), temp());
6613 defineBox(lir
, ins
);
6616 void LIRGenerator::visitInitHomeObject(MInitHomeObject
* ins
) {
6617 MDefinition
* function
= ins
->function();
6618 MOZ_ASSERT(function
->type() == MIRType::Object
);
6620 MDefinition
* homeObject
= ins
->homeObject();
6621 MOZ_ASSERT(homeObject
->type() == MIRType::Value
);
6623 MOZ_ASSERT(ins
->type() == MIRType::Object
);
6625 auto* lir
= new (alloc())
6626 LInitHomeObject(useRegisterAtStart(function
), useBoxAtStart(homeObject
));
6627 redefine(ins
, function
);
6631 void LIRGenerator::visitIsTypedArrayConstructor(MIsTypedArrayConstructor
* ins
) {
6632 MDefinition
* object
= ins
->object();
6633 MOZ_ASSERT(object
->type() == MIRType::Object
);
6635 auto* lir
= new (alloc()) LIsTypedArrayConstructor(useRegister(object
));
6639 void LIRGenerator::visitLoadValueTag(MLoadValueTag
* ins
) {
6640 MDefinition
* value
= ins
->value();
6641 MOZ_ASSERT(value
->type() == MIRType::Value
);
6643 define(new (alloc()) LLoadValueTag(useBoxAtStart(value
)), ins
);
6646 void LIRGenerator::visitGuardTagNotEqual(MGuardTagNotEqual
* ins
) {
6647 MDefinition
* lhs
= ins
->lhs();
6648 MOZ_ASSERT(lhs
->type() == MIRType::Int32
);
6650 MDefinition
* rhs
= ins
->rhs();
6651 MOZ_ASSERT(rhs
->type() == MIRType::Int32
);
6654 new (alloc()) LGuardTagNotEqual(useRegister(lhs
), useRegister(rhs
));
6655 assignSnapshot(guard
, ins
->bailoutKind());
6659 void LIRGenerator::visitLoadWrapperTarget(MLoadWrapperTarget
* ins
) {
6660 MDefinition
* object
= ins
->object();
6661 MOZ_ASSERT(object
->type() == MIRType::Object
);
6663 define(new (alloc()) LLoadWrapperTarget(useRegisterAtStart(object
)), ins
);
6666 void LIRGenerator::visitGuardHasGetterSetter(MGuardHasGetterSetter
* ins
) {
6667 MDefinition
* object
= ins
->object();
6668 MOZ_ASSERT(object
->type() == MIRType::Object
);
6670 auto* guard
= new (alloc())
6671 LGuardHasGetterSetter(useRegisterAtStart(object
), tempFixed(CallTempReg0
),
6672 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
6673 assignSnapshot(guard
, ins
->bailoutKind());
6675 redefine(ins
, object
);
6678 void LIRGenerator::visitGuardIsExtensible(MGuardIsExtensible
* ins
) {
6679 MDefinition
* object
= ins
->object();
6680 MOZ_ASSERT(object
->type() == MIRType::Object
);
6682 auto* guard
= new (alloc()) LGuardIsExtensible(useRegister(object
), temp());
6683 assignSnapshot(guard
, ins
->bailoutKind());
6685 redefine(ins
, object
);
6688 void LIRGenerator::visitGuardInt32IsNonNegative(MGuardInt32IsNonNegative
* ins
) {
6689 MDefinition
* index
= ins
->index();
6690 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6692 auto* guard
= new (alloc()) LGuardInt32IsNonNegative(useRegister(index
));
6693 assignSnapshot(guard
, ins
->bailoutKind());
6695 redefine(ins
, index
);
6698 void LIRGenerator::visitGuardInt32Range(MGuardInt32Range
* ins
) {
6699 MDefinition
* input
= ins
->input();
6700 MOZ_ASSERT(input
->type() == MIRType::Int32
);
6702 auto* guard
= new (alloc()) LGuardInt32Range(useRegister(input
));
6703 assignSnapshot(guard
, ins
->bailoutKind());
6705 redefine(ins
, input
);
6708 void LIRGenerator::visitGuardIndexIsNotDenseElement(
6709 MGuardIndexIsNotDenseElement
* ins
) {
6710 MDefinition
* object
= ins
->object();
6711 MOZ_ASSERT(object
->type() == MIRType::Object
);
6713 MDefinition
* index
= ins
->index();
6714 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6716 LDefinition spectreTemp
=
6717 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6719 auto* guard
= new (alloc()) LGuardIndexIsNotDenseElement(
6720 useRegister(object
), useRegister(index
), temp(), spectreTemp
);
6721 assignSnapshot(guard
, ins
->bailoutKind());
6723 redefine(ins
, index
);
6726 void LIRGenerator::visitGuardIndexIsValidUpdateOrAdd(
6727 MGuardIndexIsValidUpdateOrAdd
* ins
) {
6728 MDefinition
* object
= ins
->object();
6729 MOZ_ASSERT(object
->type() == MIRType::Object
);
6731 MDefinition
* index
= ins
->index();
6732 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6734 LDefinition spectreTemp
=
6735 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6737 auto* guard
= new (alloc()) LGuardIndexIsValidUpdateOrAdd(
6738 useRegister(object
), useRegister(index
), temp(), spectreTemp
);
6739 assignSnapshot(guard
, ins
->bailoutKind());
6741 redefine(ins
, index
);
6744 void LIRGenerator::visitCallAddOrUpdateSparseElement(
6745 MCallAddOrUpdateSparseElement
* ins
) {
6746 MDefinition
* object
= ins
->object();
6747 MOZ_ASSERT(object
->type() == MIRType::Object
);
6749 MDefinition
* index
= ins
->index();
6750 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6752 MDefinition
* value
= ins
->value();
6753 MOZ_ASSERT(value
->type() == MIRType::Value
);
6755 auto* lir
= new (alloc()) LCallAddOrUpdateSparseElement(
6756 useRegisterAtStart(object
), useRegisterAtStart(index
),
6757 useBoxAtStart(value
));
6759 assignSafepoint(lir
, ins
);
6762 void LIRGenerator::visitCallGetSparseElement(MCallGetSparseElement
* ins
) {
6763 MDefinition
* object
= ins
->object();
6764 MOZ_ASSERT(object
->type() == MIRType::Object
);
6766 MDefinition
* index
= ins
->index();
6767 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6769 auto* lir
= new (alloc()) LCallGetSparseElement(useRegisterAtStart(object
),
6770 useRegisterAtStart(index
));
6771 defineReturn(lir
, ins
);
6772 assignSafepoint(lir
, ins
);
6775 void LIRGenerator::visitCallNativeGetElement(MCallNativeGetElement
* ins
) {
6776 MDefinition
* object
= ins
->object();
6777 MOZ_ASSERT(object
->type() == MIRType::Object
);
6779 MDefinition
* index
= ins
->index();
6780 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6782 auto* lir
= new (alloc()) LCallNativeGetElement(useRegisterAtStart(object
),
6783 useRegisterAtStart(index
));
6784 defineReturn(lir
, ins
);
6785 assignSafepoint(lir
, ins
);
6788 void LIRGenerator::visitCallNativeGetElementSuper(
6789 MCallNativeGetElementSuper
* ins
) {
6790 MDefinition
* object
= ins
->object();
6791 MOZ_ASSERT(object
->type() == MIRType::Object
);
6793 MDefinition
* index
= ins
->index();
6794 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6796 MDefinition
* receiver
= ins
->receiver();
6798 auto* lir
= new (alloc()) LCallNativeGetElementSuper(
6799 useRegisterAtStart(object
), useRegisterAtStart(index
),
6800 useBoxAtStart(receiver
));
6801 defineReturn(lir
, ins
);
6802 assignSafepoint(lir
, ins
);
6805 void LIRGenerator::visitCallObjectHasSparseElement(
6806 MCallObjectHasSparseElement
* ins
) {
6807 MDefinition
* object
= ins
->object();
6808 MOZ_ASSERT(object
->type() == MIRType::Object
);
6810 MDefinition
* index
= ins
->index();
6811 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6813 auto* lir
= new (alloc()) LCallObjectHasSparseElement(
6814 useRegisterAtStart(object
), useRegisterAtStart(index
),
6815 tempFixed(CallTempReg0
), tempFixed(CallTempReg1
));
6816 assignSnapshot(lir
, ins
->bailoutKind());
6817 defineReturn(lir
, ins
);
6820 void LIRGenerator::visitBigIntAsIntN(MBigIntAsIntN
* ins
) {
6821 MOZ_ASSERT(ins
->bits()->type() == MIRType::Int32
);
6822 MOZ_ASSERT(ins
->input()->type() == MIRType::BigInt
);
6824 if (ins
->bits()->isConstant()) {
6825 int32_t bits
= ins
->bits()->toConstant()->toInt32();
6827 auto* lir
= new (alloc())
6828 LBigIntAsIntN64(useRegister(ins
->input()), temp(), tempInt64());
6830 assignSafepoint(lir
, ins
);
6834 auto* lir
= new (alloc())
6835 LBigIntAsIntN32(useRegister(ins
->input()), temp(), tempInt64());
6837 assignSafepoint(lir
, ins
);
6842 auto* lir
= new (alloc()) LBigIntAsIntN(useRegisterAtStart(ins
->bits()),
6843 useRegisterAtStart(ins
->input()));
6844 defineReturn(lir
, ins
);
6845 assignSafepoint(lir
, ins
);
6848 void LIRGenerator::visitBigIntAsUintN(MBigIntAsUintN
* ins
) {
6849 MOZ_ASSERT(ins
->bits()->type() == MIRType::Int32
);
6850 MOZ_ASSERT(ins
->input()->type() == MIRType::BigInt
);
6852 if (ins
->bits()->isConstant()) {
6853 int32_t bits
= ins
->bits()->toConstant()->toInt32();
6855 auto* lir
= new (alloc())
6856 LBigIntAsUintN64(useRegister(ins
->input()), temp(), tempInt64());
6858 assignSafepoint(lir
, ins
);
6862 auto* lir
= new (alloc())
6863 LBigIntAsUintN32(useRegister(ins
->input()), temp(), tempInt64());
6865 assignSafepoint(lir
, ins
);
6870 auto* lir
= new (alloc()) LBigIntAsUintN(useRegisterAtStart(ins
->bits()),
6871 useRegisterAtStart(ins
->input()));
6872 defineReturn(lir
, ins
);
6873 assignSafepoint(lir
, ins
);
6876 void LIRGenerator::visitGuardNonGCThing(MGuardNonGCThing
* ins
) {
6877 MDefinition
* input
= ins
->input();
6879 auto* guard
= new (alloc()) LGuardNonGCThing(useBox(input
));
6880 assignSnapshot(guard
, ins
->bailoutKind());
6882 redefine(ins
, input
);
6885 void LIRGenerator::visitToHashableNonGCThing(MToHashableNonGCThing
* ins
) {
6887 new (alloc()) LToHashableNonGCThing(useBox(ins
->input()), tempDouble());
6888 defineBox(lir
, ins
);
6891 void LIRGenerator::visitToHashableString(MToHashableString
* ins
) {
6892 auto* lir
= new (alloc()) LToHashableString(useRegister(ins
->input()));
6894 assignSafepoint(lir
, ins
);
6897 void LIRGenerator::visitToHashableValue(MToHashableValue
* ins
) {
6899 new (alloc()) LToHashableValue(useBox(ins
->input()), tempDouble());
6900 defineBox(lir
, ins
);
6901 assignSafepoint(lir
, ins
);
6904 void LIRGenerator::visitHashNonGCThing(MHashNonGCThing
* ins
) {
6905 auto* lir
= new (alloc()) LHashNonGCThing(useBox(ins
->input()), temp());
6909 void LIRGenerator::visitHashString(MHashString
* ins
) {
6910 auto* lir
= new (alloc()) LHashString(useRegister(ins
->input()), temp());
6914 void LIRGenerator::visitHashSymbol(MHashSymbol
* ins
) {
6915 auto* lir
= new (alloc()) LHashSymbol(useRegister(ins
->input()));
6919 void LIRGenerator::visitHashBigInt(MHashBigInt
* ins
) {
6920 auto* lir
= new (alloc())
6921 LHashBigInt(useRegister(ins
->input()), temp(), temp(), temp());
6925 void LIRGenerator::visitHashObject(MHashObject
* ins
) {
6927 new (alloc()) LHashObject(useRegister(ins
->set()), useBox(ins
->input()),
6928 temp(), temp(), temp(), temp());
6932 void LIRGenerator::visitHashValue(MHashValue
* ins
) {
6934 new (alloc()) LHashValue(useRegister(ins
->set()), useBox(ins
->input()),
6935 temp(), temp(), temp(), temp());
6939 void LIRGenerator::visitSetObjectHasNonBigInt(MSetObjectHasNonBigInt
* ins
) {
6940 auto* lir
= new (alloc())
6941 LSetObjectHasNonBigInt(useRegister(ins
->set()), useBox(ins
->value()),
6942 useRegister(ins
->hash()), temp(), temp());
6946 void LIRGenerator::visitSetObjectHasBigInt(MSetObjectHasBigInt
* ins
) {
6947 auto* lir
= new (alloc()) LSetObjectHasBigInt(
6948 useRegister(ins
->set()), useBox(ins
->value()), useRegister(ins
->hash()),
6949 temp(), temp(), temp(), temp());
6953 void LIRGenerator::visitSetObjectHasValue(MSetObjectHasValue
* ins
) {
6954 auto* lir
= new (alloc()) LSetObjectHasValue(
6955 useRegister(ins
->set()), useBox(ins
->value()), useRegister(ins
->hash()),
6956 temp(), temp(), temp(), temp());
6960 void LIRGenerator::visitSetObjectHasValueVMCall(MSetObjectHasValueVMCall
* ins
) {
6961 auto* lir
= new (alloc()) LSetObjectHasValueVMCall(
6962 useRegisterAtStart(ins
->set()), useBoxAtStart(ins
->value()));
6963 defineReturn(lir
, ins
);
6964 assignSafepoint(lir
, ins
);
6967 void LIRGenerator::visitSetObjectSize(MSetObjectSize
* ins
) {
6968 auto* lir
= new (alloc()) LSetObjectSize(useRegisterAtStart(ins
->set()));
6972 void LIRGenerator::visitMapObjectHasNonBigInt(MMapObjectHasNonBigInt
* ins
) {
6973 auto* lir
= new (alloc())
6974 LMapObjectHasNonBigInt(useRegister(ins
->map()), useBox(ins
->value()),
6975 useRegister(ins
->hash()), temp(), temp());
6979 void LIRGenerator::visitMapObjectHasBigInt(MMapObjectHasBigInt
* ins
) {
6980 auto* lir
= new (alloc()) LMapObjectHasBigInt(
6981 useRegister(ins
->map()), useBox(ins
->value()), useRegister(ins
->hash()),
6982 temp(), temp(), temp(), temp());
6986 void LIRGenerator::visitMapObjectHasValue(MMapObjectHasValue
* ins
) {
6987 auto* lir
= new (alloc()) LMapObjectHasValue(
6988 useRegister(ins
->map()), useBox(ins
->value()), useRegister(ins
->hash()),
6989 temp(), temp(), temp(), temp());
6993 void LIRGenerator::visitMapObjectHasValueVMCall(MMapObjectHasValueVMCall
* ins
) {
6994 auto* lir
= new (alloc()) LMapObjectHasValueVMCall(
6995 useRegisterAtStart(ins
->map()), useBoxAtStart(ins
->value()));
6996 defineReturn(lir
, ins
);
6997 assignSafepoint(lir
, ins
);
7000 void LIRGenerator::visitMapObjectGetNonBigInt(MMapObjectGetNonBigInt
* ins
) {
7001 auto* lir
= new (alloc())
7002 LMapObjectGetNonBigInt(useRegister(ins
->map()), useBox(ins
->value()),
7003 useRegister(ins
->hash()), temp(), temp());
7004 defineBox(lir
, ins
);
7007 void LIRGenerator::visitMapObjectGetBigInt(MMapObjectGetBigInt
* ins
) {
7008 auto* lir
= new (alloc()) LMapObjectGetBigInt(
7009 useRegister(ins
->map()), useBox(ins
->value()), useRegister(ins
->hash()),
7010 temp(), temp(), temp(), temp());
7011 defineBox(lir
, ins
);
7014 void LIRGenerator::visitMapObjectGetValue(MMapObjectGetValue
* ins
) {
7015 auto* lir
= new (alloc()) LMapObjectGetValue(
7016 useRegister(ins
->map()), useBox(ins
->value()), useRegister(ins
->hash()),
7017 temp(), temp(), temp(), temp());
7018 defineBox(lir
, ins
);
7021 void LIRGenerator::visitMapObjectGetValueVMCall(MMapObjectGetValueVMCall
* ins
) {
7022 auto* lir
= new (alloc()) LMapObjectGetValueVMCall(
7023 useRegisterAtStart(ins
->map()), useBoxAtStart(ins
->value()));
7024 defineReturn(lir
, ins
);
7025 assignSafepoint(lir
, ins
);
7028 void LIRGenerator::visitMapObjectSize(MMapObjectSize
* ins
) {
7029 auto* lir
= new (alloc()) LMapObjectSize(useRegisterAtStart(ins
->map()));
7033 void LIRGenerator::visitConstant(MConstant
* ins
) {
7034 if (!IsFloatingPointType(ins
->type()) && ins
->canEmitAtUses()) {
7039 switch (ins
->type()) {
7040 case MIRType::Double
:
7041 define(new (alloc()) LDouble(ins
->toDouble()), ins
);
7043 case MIRType::Float32
:
7044 define(new (alloc()) LFloat32(ins
->toFloat32()), ins
);
7046 case MIRType::Boolean
:
7047 define(new (alloc()) LInteger(ins
->toBoolean()), ins
);
7049 case MIRType::Int32
:
7050 define(new (alloc()) LInteger(ins
->toInt32()), ins
);
7052 case MIRType::Int64
:
7053 defineInt64(new (alloc()) LInteger64(ins
->toInt64()), ins
);
7055 case MIRType::IntPtr
:
7057 defineInt64(new (alloc()) LInteger64(ins
->toIntPtr()), ins
);
7059 define(new (alloc()) LInteger(ins
->toIntPtr()), ins
);
7062 case MIRType::String
:
7063 define(new (alloc()) LPointer(ins
->toString()), ins
);
7065 case MIRType::Symbol
:
7066 define(new (alloc()) LPointer(ins
->toSymbol()), ins
);
7068 case MIRType::BigInt
:
7069 define(new (alloc()) LPointer(ins
->toBigInt()), ins
);
7071 case MIRType::Object
:
7072 define(new (alloc()) LPointer(&ins
->toObject()), ins
);
7074 case MIRType::Shape
:
7075 MOZ_ASSERT(ins
->isEmittedAtUses());
7078 // Constants of special types (undefined, null) should never flow into
7079 // here directly. Operations blindly consuming them require a Box.
7080 MOZ_CRASH("unexpected constant type");
7084 void LIRGenerator::visitConstantProto(MConstantProto
* ins
) {
7085 JSObject
* obj
= &ins
->protoObject()->toConstant()->toObject();
7086 define(new (alloc()) LPointer(obj
), ins
);
7089 void LIRGenerator::visitWasmNullConstant(MWasmNullConstant
* ins
) {
7090 define(new (alloc()) LWasmNullConstant(), ins
);
7093 void LIRGenerator::visitWasmFloatConstant(MWasmFloatConstant
* ins
) {
7094 switch (ins
->type()) {
7095 case MIRType::Double
:
7096 define(new (alloc()) LDouble(ins
->toDouble()), ins
);
7098 case MIRType::Float32
:
7099 define(new (alloc()) LFloat32(ins
->toFloat32()), ins
);
7101 #ifdef ENABLE_WASM_SIMD
7102 case MIRType::Simd128
:
7103 define(new (alloc()) LSimd128(ins
->toSimd128()), ins
);
7107 MOZ_CRASH("unexpected constant type");
7112 static void SpewResumePoint(MBasicBlock
* block
, MInstruction
* ins
,
7113 MResumePoint
* resumePoint
) {
7114 Fprinter
& out
= JitSpewPrinter();
7115 out
.printf("Current resume point %p details:\n", (void*)resumePoint
);
7116 out
.printf(" frame count: %u\n", resumePoint
->frameCount());
7119 out
.printf(" taken after: ");
7120 ins
->printName(out
);
7122 out
.printf(" taken at block %u entry", block
->id());
7126 out
.printf(" pc: %p (script: %p, offset: %d)\n", (void*)resumePoint
->pc(),
7127 (void*)resumePoint
->block()->info().script(),
7128 int(resumePoint
->block()->info().script()->pcToOffset(
7129 resumePoint
->pc())));
7131 for (size_t i
= 0, e
= resumePoint
->numOperands(); i
< e
; i
++) {
7132 MDefinition
* in
= resumePoint
->getOperand(i
);
7133 out
.printf(" slot%u: ", (unsigned)i
);
7140 void LIRGenerator::visitInstructionDispatch(MInstruction
* ins
) {
7141 #ifdef JS_CODEGEN_NONE
7142 // Don't compile the switch-statement below so that we don't have to define
7143 // the platform-specific visit* methods for the none-backend.
7146 switch (ins
->op()) {
7147 # define MIR_OP(op) \
7148 case MDefinition::Opcode::op: \
7149 visit##op(ins->to##op()); \
7151 MIR_OPCODE_LIST(MIR_OP
)
7154 MOZ_CRASH("Invalid instruction");
7159 void LIRGeneratorShared::visitEmittedAtUses(MInstruction
* ins
) {
7160 static_cast<LIRGenerator
*>(this)->visitInstructionDispatch(ins
);
7163 bool LIRGenerator::visitInstruction(MInstruction
* ins
) {
7164 MOZ_ASSERT(!errored());
7166 if (ins
->isRecoveredOnBailout()) {
7167 MOZ_ASSERT(!JitOptions
.disableRecoverIns
);
7171 if (!gen
->ensureBallast()) {
7174 visitInstructionDispatch(ins
);
7176 if (ins
->resumePoint()) {
7177 updateResumeState(ins
);
7181 ins
->setInWorklistUnchecked();
7184 // If no safepoint was created, there's no need for an OSI point.
7185 if (LOsiPoint
* osiPoint
= popOsiPoint()) {
7192 bool LIRGenerator::definePhis() {
7193 size_t lirIndex
= 0;
7194 MBasicBlock
* block
= current
->mir();
7195 for (MPhiIterator
phi(block
->phisBegin()); phi
!= block
->phisEnd(); phi
++) {
7196 if (phi
->type() == MIRType::Value
) {
7197 defineUntypedPhi(*phi
, lirIndex
);
7198 lirIndex
+= BOX_PIECES
;
7199 } else if (phi
->type() == MIRType::Int64
) {
7200 defineInt64Phi(*phi
, lirIndex
);
7201 lirIndex
+= INT64_PIECES
;
7203 defineTypedPhi(*phi
, lirIndex
);
7210 void LIRGenerator::updateResumeState(MInstruction
* ins
) {
7211 lastResumePoint_
= ins
->resumePoint();
7213 if (JitSpewEnabled(JitSpew_IonSnapshots
) && lastResumePoint_
) {
7214 SpewResumePoint(nullptr, ins
, lastResumePoint_
);
7219 void LIRGenerator::updateResumeState(MBasicBlock
* block
) {
7220 // Note: RangeAnalysis can flag blocks as unreachable, but they are only
7221 // removed iff GVN (including UCE) is enabled.
7222 MOZ_ASSERT_IF(!mir()->compilingWasm() && !block
->unreachable(),
7223 block
->entryResumePoint());
7224 MOZ_ASSERT_IF(block
->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7225 lastResumePoint_
= block
->entryResumePoint();
7227 if (JitSpewEnabled(JitSpew_IonSnapshots
) && lastResumePoint_
) {
7228 SpewResumePoint(block
, nullptr, lastResumePoint_
);
7233 bool LIRGenerator::visitBlock(MBasicBlock
* block
) {
7234 current
= block
->lir();
7235 updateResumeState(block
);
7237 if (!definePhis()) {
7241 MOZ_ASSERT_IF(block
->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7242 for (MInstructionIterator iter
= block
->begin(); *iter
!= block
->lastIns();
7244 if (!visitInstruction(*iter
)) {
7249 if (block
->successorWithPhis()) {
7250 // If we have a successor with phis, lower the phi input now that we
7251 // are approaching the join point.
7252 MBasicBlock
* successor
= block
->successorWithPhis();
7253 uint32_t position
= block
->positionInPhiSuccessor();
7254 size_t lirIndex
= 0;
7255 for (MPhiIterator
phi(successor
->phisBegin()); phi
!= successor
->phisEnd();
7257 if (!gen
->ensureBallast()) {
7261 MDefinition
* opd
= phi
->getOperand(position
);
7264 MOZ_ASSERT(opd
->type() == phi
->type());
7266 if (phi
->type() == MIRType::Value
) {
7267 lowerUntypedPhiInput(*phi
, position
, successor
->lir(), lirIndex
);
7268 lirIndex
+= BOX_PIECES
;
7269 } else if (phi
->type() == MIRType::Int64
) {
7270 lowerInt64PhiInput(*phi
, position
, successor
->lir(), lirIndex
);
7271 lirIndex
+= INT64_PIECES
;
7273 lowerTypedPhiInput(*phi
, position
, successor
->lir(), lirIndex
);
7279 // Now emit the last instruction, which is some form of branch.
7280 if (!visitInstruction(block
->lastIns())) {
7287 void LIRGenerator::visitNaNToZero(MNaNToZero
* ins
) {
7288 MDefinition
* input
= ins
->input();
7290 if (ins
->operandIsNeverNaN() && ins
->operandIsNeverNegativeZero()) {
7291 redefine(ins
, input
);
7295 new (alloc()) LNaNToZero(useRegisterAtStart(input
), tempDouble());
7296 defineReuseInput(lir
, ins
, 0);
7299 bool LIRGenerator::generate() {
7300 // Create all blocks and prep all phis beforehand.
7301 for (ReversePostorderIterator
block(graph
.rpoBegin());
7302 block
!= graph
.rpoEnd(); block
++) {
7303 if (gen
->shouldCancel("Lowering (preparation loop)")) {
7307 if (!lirGraph_
.initBlock(*block
)) {
7312 for (ReversePostorderIterator
block(graph
.rpoBegin());
7313 block
!= graph
.rpoEnd(); block
++) {
7314 if (gen
->shouldCancel("Lowering (main loop)")) {
7318 if (!visitBlock(*block
)) {
7323 lirGraph_
.setArgumentSlotCount(maxargslots_
);
7327 void LIRGenerator::visitPhi(MPhi
* phi
) {
7328 // Phi nodes are not lowered because they are only meaningful for the register
7330 MOZ_CRASH("Unexpected Phi node during Lowering.");
7333 void LIRGenerator::visitBeta(MBeta
* beta
) {
7334 // Beta nodes are supposed to be removed before because they are
7335 // only used to carry the range information for Range analysis
7336 MOZ_CRASH("Unexpected Beta node during Lowering.");
7339 void LIRGenerator::visitObjectState(MObjectState
* objState
) {
7340 // ObjectState nodes are always recovered on bailouts
7341 MOZ_CRASH("Unexpected ObjectState node during Lowering.");
7344 void LIRGenerator::visitArrayState(MArrayState
* objState
) {
7345 // ArrayState nodes are always recovered on bailouts
7346 MOZ_CRASH("Unexpected ArrayState node during Lowering.");
7349 void LIRGenerator::visitIonToWasmCall(MIonToWasmCall
* ins
) {
7350 // The instruction needs a temp register:
7351 // - that's not the FramePointer, since wasm is going to use it in the
7353 // - that's not aliasing an input register.
7354 LDefinition scratch
= tempFixed(ABINonArgReg0
);
7356 // Note that since this is a LIR call instruction, regalloc will prevent
7357 // the use*AtStart below from reusing any of the temporaries.
7360 if (ins
->type() == MIRType::Value
) {
7361 lir
= allocateVariadic
<LIonToWasmCallV
>(ins
->numOperands(), scratch
);
7362 } else if (ins
->type() == MIRType::Int64
) {
7363 lir
= allocateVariadic
<LIonToWasmCallI64
>(ins
->numOperands(), scratch
);
7365 lir
= allocateVariadic
<LIonToWasmCall
>(ins
->numOperands(), scratch
);
7368 abort(AbortReason::Alloc
, "OOM: LIRGenerator::visitIonToWasmCall");
7372 ABIArgGenerator abi
;
7373 for (unsigned i
= 0; i
< ins
->numOperands(); i
++) {
7374 MDefinition
* argDef
= ins
->getOperand(i
);
7375 ABIArg arg
= abi
.next(ToMIRType(argDef
->type()));
7376 switch (arg
.kind()) {
7379 lir
->setOperand(i
, useFixedAtStart(argDef
, arg
.reg()));
7382 lir
->setOperand(i
, useAtStart(argDef
));
7384 #ifdef JS_CODEGEN_REGISTER_PAIR
7385 case ABIArg::GPR_PAIR
:
7387 "no way to pass i64, and wasm uses hardfp for function calls");
7389 case ABIArg::Uninitialized
:
7390 MOZ_CRASH("Uninitialized ABIArg kind");
7394 defineReturn(lir
, ins
);
7395 assignSafepoint(lir
, ins
);
7398 void LIRGenerator::visitWasmSelect(MWasmSelect
* ins
) {
7399 MDefinition
* condExpr
= ins
->condExpr();
7401 // Pick off specific cases that we can do with LWasmCompareAndSelect to avoid
7402 // generating a boolean that we then have to test again.
7403 if (condExpr
->isCompare() && condExpr
->isEmittedAtUses()) {
7404 MCompare
* comp
= condExpr
->toCompare();
7405 MCompare::CompareType compTy
= comp
->compareType();
7406 if (canSpecializeWasmCompareAndSelect(compTy
, ins
->type())) {
7407 JSOp jsop
= comp
->jsop();
7408 // We don't currently generate any other JSOPs for the comparison, and if
7409 // that changes, we want to know about it. Hence this assertion.
7410 MOZ_ASSERT(jsop
== JSOp::Eq
|| jsop
== JSOp::Ne
|| jsop
== JSOp::Lt
||
7411 jsop
== JSOp::Gt
|| jsop
== JSOp::Le
|| jsop
== JSOp::Ge
);
7412 MDefinition
* lhs
= comp
->lhs();
7413 MDefinition
* rhs
= comp
->rhs();
7414 jsop
= ReorderComparison(jsop
, &lhs
, &rhs
);
7415 lowerWasmCompareAndSelect(ins
, lhs
, rhs
, compTy
, jsop
);
7419 // Fall through to code that generates a boolean and selects on that.
7421 if (ins
->type() == MIRType::Int64
) {
7422 lowerWasmSelectI64(ins
);
7426 lowerWasmSelectI(ins
);
7429 void LIRGenerator::visitWasmFence(MWasmFence
* ins
) {
7430 add(new (alloc()) LWasmFence
, ins
);
7433 void LIRGenerator::visitWasmLoadField(MWasmLoadField
* ins
) {
7434 uint32_t offs
= ins
->offset();
7435 LAllocation obj
= useRegister(ins
->obj());
7436 MWideningOp wideningOp
= ins
->wideningOp();
7437 if (ins
->type() == MIRType::Int64
) {
7438 MOZ_RELEASE_ASSERT(wideningOp
== MWideningOp::None
);
7439 defineInt64(new (alloc()) LWasmLoadSlotI64(obj
, offs
, ins
->maybeTrap()),
7442 define(new (alloc()) LWasmLoadSlot(obj
, offs
, ins
->type(), wideningOp
,
7448 void LIRGenerator::visitWasmLoadFieldKA(MWasmLoadFieldKA
* ins
) {
7449 uint32_t offs
= ins
->offset();
7450 LAllocation obj
= useRegister(ins
->obj());
7451 MWideningOp wideningOp
= ins
->wideningOp();
7452 if (ins
->type() == MIRType::Int64
) {
7453 MOZ_RELEASE_ASSERT(wideningOp
== MWideningOp::None
);
7454 defineInt64(new (alloc()) LWasmLoadSlotI64(obj
, offs
, ins
->maybeTrap()),
7457 define(new (alloc()) LWasmLoadSlot(obj
, offs
, ins
->type(), wideningOp
,
7461 add(new (alloc()) LKeepAliveObject(useKeepalive(ins
->ka())), ins
);
7464 void LIRGenerator::visitWasmStoreFieldKA(MWasmStoreFieldKA
* ins
) {
7465 MDefinition
* value
= ins
->value();
7466 uint32_t offs
= ins
->offset();
7467 MNarrowingOp narrowingOp
= ins
->narrowingOp();
7468 LAllocation obj
= useRegister(ins
->obj());
7470 if (value
->type() == MIRType::Int64
) {
7471 MOZ_RELEASE_ASSERT(narrowingOp
== MNarrowingOp::None
);
7473 LWasmStoreSlotI64(useInt64Register(value
), obj
, offs
, ins
->maybeTrap());
7476 LWasmStoreSlot(useRegister(value
), obj
, offs
, value
->type(),
7477 narrowingOp
, ins
->maybeTrap());
7480 add(new (alloc()) LKeepAliveObject(useKeepalive(ins
->ka())), ins
);
7483 void LIRGenerator::visitWasmStoreFieldRefKA(MWasmStoreFieldRefKA
* ins
) {
7484 LAllocation instance
= useRegister(ins
->instance());
7485 LAllocation obj
= useFixed(ins
->obj(), PreBarrierReg
);
7486 LAllocation value
= useRegister(ins
->value());
7487 uint32_t offset
= ins
->offset();
7488 add(new (alloc()) LWasmStoreRef(instance
, obj
, value
, temp(), offset
,
7489 ins
->maybeTrap(), ins
->preBarrierKind()),
7491 add(new (alloc()) LKeepAliveObject(useKeepalive(ins
->ka())), ins
);
7494 void LIRGenerator::visitWasmRefIsSubtypeOfAbstract(
7495 MWasmRefIsSubtypeOfAbstract
* ins
) {
7496 if (CanEmitAtUseForSingleTest(ins
)) {
7501 LAllocation ref
= useRegister(ins
->ref());
7502 LDefinition scratch1
= LDefinition();
7503 if (ins
->destType().isAnyHierarchy()) {
7504 // See comment on MacroAssembler::branchWasmRefIsSubtypeAny.
7505 // We know we do not need scratch2 and superSTV because we know
7506 // this is not a concrete type.
7507 MOZ_ASSERT(!MacroAssembler::needSuperSTVForBranchWasmRefIsSubtypeAny(
7509 MOZ_ASSERT(!MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
7512 scratch1
= MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
7516 } else if (ins
->destType().isFuncHierarchy()) {
7517 // See comment on MacroAssembler::branchWasmRefIsSubtypeFunc.
7518 // We know we do not need any supertype vectors or scratch registers because
7519 // this is not a concrete cast.
7521 !MacroAssembler::needSuperSTVAndScratch1ForBranchWasmRefIsSubtypeFunc(
7523 MOZ_ASSERT(!MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
7525 } else if (ins
->destType().isExternHierarchy()) {
7526 // no scratch registers needed for casts in the extern hierarchy
7528 MOZ_CRASH("unknown type hierarchy for abstract cast");
7531 define(new (alloc()) LWasmRefIsSubtypeOfAbstract(ref
, scratch1
), ins
);
7534 void LIRGenerator::visitWasmRefIsSubtypeOfConcrete(
7535 MWasmRefIsSubtypeOfConcrete
* ins
) {
7536 if (CanEmitAtUseForSingleTest(ins
)) {
7541 // This gets a bit wild because it needs to handle concrete casts in all
7542 // hierarchies. Supertype vectors are always required (that's what concrete
7543 // means) but the scratch registers can vary.
7545 LAllocation ref
= useRegister(ins
->ref());
7546 LAllocation superSTV
= useRegister(ins
->superSTV());
7547 LDefinition scratch1
= LDefinition();
7548 LDefinition scratch2
= LDefinition();
7549 if (ins
->destType().isAnyHierarchy()) {
7550 // See comment on MacroAssembler::branchWasmRefIsSubtypeAny.
7551 // We know we need scratch1 because we know this is a concrete type.
7552 MOZ_ASSERT(MacroAssembler::needSuperSTVForBranchWasmRefIsSubtypeAny(
7554 MOZ_ASSERT(MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
7557 scratch2
= MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
7561 } else if (ins
->destType().isFuncHierarchy()) {
7562 // See comment on MacroAssembler::branchWasmRefIsSubtypeFunc.
7563 // We know we need scratch1 because we know this is a concrete type.
7565 MacroAssembler::needSuperSTVAndScratch1ForBranchWasmRefIsSubtypeFunc(
7568 scratch2
= MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
7572 } else if (ins
->destType().isExternHierarchy()) {
7573 MOZ_CRASH("concrete casts are impossible in the extern hierarchy");
7575 MOZ_CRASH("unknown type hierarchy for concrete cast");
7578 define(new (alloc())
7579 LWasmRefIsSubtypeOfConcrete(ref
, superSTV
, scratch1
, scratch2
),
7583 void LIRGenerator::visitWasmNewStructObject(MWasmNewStructObject
* ins
) {
7584 LWasmNewStructObject
* lir
= new (alloc())
7585 LWasmNewStructObject(useFixed(ins
->instance(), InstanceReg
),
7586 useRegister(ins
->typeDefData()), temp(), temp());
7588 assignWasmSafepoint(lir
);
7591 #ifdef FUZZING_JS_FUZZILLI
7592 void LIRGenerator::visitFuzzilliHash(MFuzzilliHash
* ins
) {
7593 MDefinition
* value
= ins
->getOperand(0);
7595 if (value
->type() == MIRType::Undefined
|| value
->type() == MIRType::Null
) {
7596 define(new (alloc()) LFuzzilliHashT(LAllocation(), temp(), tempDouble()),
7598 } else if (value
->type() == MIRType::Int32
||
7599 value
->type() == MIRType::Double
||
7600 value
->type() == MIRType::Float32
||
7601 value
->type() == MIRType::Boolean
||
7602 value
->type() == MIRType::BigInt
) {
7603 define(new (alloc())
7604 LFuzzilliHashT(useRegister(value
), temp(), tempDouble()),
7606 } else if (value
->type() == MIRType::Object
) {
7607 LFuzzilliHashT
* lir
=
7608 new (alloc()) LFuzzilliHashT(useRegister(value
), temp(), tempDouble());
7610 assignSafepoint(lir
, ins
);
7611 } else if (value
->type() == MIRType::Value
) {
7612 LFuzzilliHashV
* lir
=
7613 new (alloc()) LFuzzilliHashV(useBox(value
), temp(), tempDouble());
7615 assignSafepoint(lir
, ins
);
7617 define(new (alloc()) LInteger(0), ins
);
7621 void LIRGenerator::visitFuzzilliHashStore(MFuzzilliHashStore
* ins
) {
7622 MDefinition
* value
= ins
->getOperand(0);
7623 MOZ_ASSERT(value
->type() == MIRType::Int32
);
7624 add(new (alloc()) LFuzzilliHashStore(useRegister(value
), temp(), temp()),
7629 static_assert(!std::is_polymorphic_v
<LIRGenerator
>,
7630 "LIRGenerator should not have any virtual methods");
7632 #ifdef JS_CODEGEN_NONE
7633 void LIRGenerator::visitReturnImpl(MDefinition
*, bool) { MOZ_CRASH(); }