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::visitGuardHasProxyHandler(MGuardHasProxyHandler
* ins
) {
5172 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5174 auto* lir
= new (alloc()) LGuardHasProxyHandler(useRegister(ins
->object()));
5175 assignSnapshot(lir
, ins
->bailoutKind());
5177 redefine(ins
, ins
->object());
5180 void LIRGenerator::visitNurseryObject(MNurseryObject
* ins
) {
5181 MOZ_ASSERT(ins
->type() == MIRType::Object
);
5183 auto* lir
= new (alloc()) LNurseryObject();
5187 void LIRGenerator::visitGuardValue(MGuardValue
* ins
) {
5188 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5189 auto* lir
= new (alloc()) LGuardValue(useBox(ins
->value()));
5190 assignSnapshot(lir
, ins
->bailoutKind());
5192 redefine(ins
, ins
->value());
5195 void LIRGenerator::visitGuardNullOrUndefined(MGuardNullOrUndefined
* ins
) {
5196 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5197 auto* lir
= new (alloc()) LGuardNullOrUndefined(useBox(ins
->value()));
5198 assignSnapshot(lir
, ins
->bailoutKind());
5200 redefine(ins
, ins
->value());
5203 void LIRGenerator::visitGuardIsNotObject(MGuardIsNotObject
* ins
) {
5204 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5205 auto* lir
= new (alloc()) LGuardIsNotObject(useBox(ins
->value()));
5206 assignSnapshot(lir
, ins
->bailoutKind());
5208 redefine(ins
, ins
->value());
5211 void LIRGenerator::visitGuardFunctionFlags(MGuardFunctionFlags
* ins
) {
5212 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
5214 auto* lir
= new (alloc()) LGuardFunctionFlags(useRegister(ins
->function()));
5215 assignSnapshot(lir
, ins
->bailoutKind());
5217 redefine(ins
, ins
->function());
5220 void LIRGenerator::visitGuardFunctionIsNonBuiltinCtor(
5221 MGuardFunctionIsNonBuiltinCtor
* ins
) {
5222 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
5224 auto* lir
= new (alloc())
5225 LGuardFunctionIsNonBuiltinCtor(useRegister(ins
->function()), temp());
5226 assignSnapshot(lir
, ins
->bailoutKind());
5228 redefine(ins
, ins
->function());
5231 void LIRGenerator::visitGuardFunctionKind(MGuardFunctionKind
* ins
) {
5232 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
5235 new (alloc()) LGuardFunctionKind(useRegister(ins
->function()), temp());
5236 assignSnapshot(lir
, ins
->bailoutKind());
5238 redefine(ins
, ins
->function());
5241 void LIRGenerator::visitGuardFunctionScript(MGuardFunctionScript
* ins
) {
5242 MOZ_ASSERT(ins
->function()->type() == MIRType::Object
);
5244 auto* lir
= new (alloc()) LGuardFunctionScript(useRegister(ins
->function()));
5245 assignSnapshot(lir
, ins
->bailoutKind());
5247 redefine(ins
, ins
->function());
5250 void LIRGenerator::visitAssertRange(MAssertRange
* ins
) {
5251 MDefinition
* input
= ins
->input();
5252 LInstruction
* lir
= nullptr;
5254 switch (input
->type()) {
5255 case MIRType::Boolean
:
5256 case MIRType::Int32
:
5257 case MIRType::IntPtr
:
5258 lir
= new (alloc()) LAssertRangeI(useRegisterAtStart(input
));
5261 case MIRType::Double
:
5262 lir
= new (alloc()) LAssertRangeD(useRegister(input
), tempDouble());
5265 case MIRType::Float32
:
5267 LAssertRangeF(useRegister(input
), tempDouble(), tempDouble());
5270 case MIRType::Value
:
5271 lir
= new (alloc()) LAssertRangeV(useBox(input
), tempToUnbox(),
5272 tempDouble(), tempDouble());
5276 MOZ_CRASH("Unexpected Range for MIRType");
5284 void LIRGenerator::visitAssertClass(MAssertClass
* ins
) {
5286 new (alloc()) LAssertClass(useRegisterAtStart(ins
->input()), temp());
5290 void LIRGenerator::visitAssertShape(MAssertShape
* ins
) {
5291 auto* lir
= new (alloc()) LAssertShape(useRegisterAtStart(ins
->input()));
5295 void LIRGenerator::visitDeleteProperty(MDeleteProperty
* ins
) {
5296 LCallDeleteProperty
* lir
=
5297 new (alloc()) LCallDeleteProperty(useBoxAtStart(ins
->value()));
5298 defineReturn(lir
, ins
);
5299 assignSafepoint(lir
, ins
);
5302 void LIRGenerator::visitDeleteElement(MDeleteElement
* ins
) {
5303 LCallDeleteElement
* lir
= new (alloc()) LCallDeleteElement(
5304 useBoxAtStart(ins
->value()), useBoxAtStart(ins
->index()));
5305 defineReturn(lir
, ins
);
5306 assignSafepoint(lir
, ins
);
5309 void LIRGenerator::visitObjectToIterator(MObjectToIterator
* ins
) {
5310 auto* lir
= new (alloc())
5311 LObjectToIterator(useRegister(ins
->object()), temp(), temp(), temp());
5313 assignSafepoint(lir
, ins
);
5316 void LIRGenerator::visitValueToIterator(MValueToIterator
* ins
) {
5317 auto* lir
= new (alloc()) LValueToIterator(useBoxAtStart(ins
->value()));
5318 defineReturn(lir
, ins
);
5319 assignSafepoint(lir
, ins
);
5322 void LIRGenerator::visitLoadSlotByIteratorIndex(MLoadSlotByIteratorIndex
* ins
) {
5323 auto* lir
= new (alloc()) LLoadSlotByIteratorIndex(
5324 useRegisterAtStart(ins
->object()), useRegisterAtStart(ins
->iterator()),
5326 defineBox(lir
, ins
);
5329 void LIRGenerator::visitStoreSlotByIteratorIndex(
5330 MStoreSlotByIteratorIndex
* ins
) {
5331 auto* lir
= new (alloc()) LStoreSlotByIteratorIndex(
5332 useRegister(ins
->object()), useRegister(ins
->iterator()),
5333 useBox(ins
->value()), temp(), temp());
5337 void LIRGenerator::visitIteratorHasIndices(MIteratorHasIndices
* ins
) {
5338 MOZ_ASSERT(ins
->hasOneUse());
5342 void LIRGenerator::visitSetPropertyCache(MSetPropertyCache
* ins
) {
5343 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5345 MDefinition
* id
= ins
->idval();
5346 MOZ_ASSERT(id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
||
5347 id
->type() == MIRType::Int32
|| id
->type() == MIRType::Value
);
5349 // If this is a SetProp, the id is a constant string. Allow passing it as a
5350 // constant to reduce register allocation pressure.
5352 id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
;
5353 bool useConstValue
= IsNonNurseryConstant(ins
->value());
5355 // Emit an overrecursed check: this is necessary because the cache can
5356 // attach a scripted setter stub that calls this script recursively.
5357 gen
->setNeedsOverrecursedCheck();
5359 // We need a double temp register for TypedArray stubs.
5360 LDefinition tempD
= tempFixed(FloatReg0
);
5362 LInstruction
* lir
= new (alloc()) LSetPropertyCache(
5363 useRegister(ins
->object()), useBoxOrTypedOrConstant(id
, useConstId
),
5364 useBoxOrTypedOrConstant(ins
->value(), useConstValue
), temp(), tempD
);
5366 assignSafepoint(lir
, ins
);
5369 void LIRGenerator::visitMegamorphicSetElement(MMegamorphicSetElement
* ins
) {
5370 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5371 MOZ_ASSERT(ins
->index()->type() == MIRType::Value
);
5372 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5374 // See comment in LIROps.yaml (x86 is short on registers)
5375 #ifdef JS_CODEGEN_X86
5376 auto* lir
= new (alloc()) LMegamorphicSetElement(
5377 useFixedAtStart(ins
->object(), CallTempReg0
),
5378 useBoxFixedAtStart(ins
->index(), CallTempReg1
, CallTempReg2
),
5379 useBoxFixedAtStart(ins
->value(), CallTempReg3
, CallTempReg4
),
5380 tempFixed(CallTempReg5
));
5382 auto* lir
= new (alloc()) LMegamorphicSetElement(
5383 useRegisterAtStart(ins
->object()), useBoxAtStart(ins
->index()),
5384 useBoxAtStart(ins
->value()), tempFixed(CallTempReg0
),
5385 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
5388 assignSafepoint(lir
, ins
);
5391 void LIRGenerator::visitGetIteratorCache(MGetIteratorCache
* ins
) {
5392 MDefinition
* value
= ins
->value();
5393 MOZ_ASSERT(value
->type() == MIRType::Object
||
5394 value
->type() == MIRType::Value
);
5396 LGetIteratorCache
* lir
=
5397 new (alloc()) LGetIteratorCache(useBoxOrTyped(value
), temp(), temp());
5399 assignSafepoint(lir
, ins
);
5402 void LIRGenerator::visitOptimizeSpreadCallCache(MOptimizeSpreadCallCache
* ins
) {
5403 MDefinition
* value
= ins
->value();
5404 MOZ_ASSERT(value
->type() == MIRType::Value
);
5406 auto* lir
= new (alloc()) LOptimizeSpreadCallCache(useBox(value
), temp());
5407 defineBox(lir
, ins
);
5408 assignSafepoint(lir
, ins
);
5411 void LIRGenerator::visitIteratorMore(MIteratorMore
* ins
) {
5412 LIteratorMore
* lir
=
5413 new (alloc()) LIteratorMore(useRegister(ins
->iterator()), temp());
5414 defineBox(lir
, ins
);
5417 void LIRGenerator::visitIsNoIter(MIsNoIter
* ins
) {
5418 MOZ_ASSERT(ins
->hasOneUse());
5422 void LIRGenerator::visitIteratorEnd(MIteratorEnd
* ins
) {
5423 LIteratorEnd
* lir
= new (alloc())
5424 LIteratorEnd(useRegister(ins
->iterator()), temp(), temp(), temp());
5428 void LIRGenerator::visitCloseIterCache(MCloseIterCache
* ins
) {
5429 LCloseIterCache
* lir
=
5430 new (alloc()) LCloseIterCache(useRegister(ins
->iter()), temp());
5432 assignSafepoint(lir
, ins
);
5435 void LIRGenerator::visitOptimizeGetIteratorCache(
5436 MOptimizeGetIteratorCache
* ins
) {
5437 MDefinition
* value
= ins
->value();
5438 MOZ_ASSERT(value
->type() == MIRType::Value
);
5440 auto* lir
= new (alloc()) LOptimizeGetIteratorCache(useBox(value
), temp());
5442 assignSafepoint(lir
, ins
);
5445 void LIRGenerator::visitStringLength(MStringLength
* ins
) {
5446 MOZ_ASSERT(ins
->string()->type() == MIRType::String
);
5447 define(new (alloc()) LStringLength(useRegisterAtStart(ins
->string())), ins
);
5450 void LIRGenerator::visitArgumentsLength(MArgumentsLength
* ins
) {
5451 define(new (alloc()) LArgumentsLength(), ins
);
5454 void LIRGenerator::visitGetFrameArgument(MGetFrameArgument
* ins
) {
5455 LGetFrameArgument
* lir
=
5456 new (alloc()) LGetFrameArgument(useRegisterOrConstant(ins
->index()));
5457 defineBox(lir
, ins
);
5460 void LIRGenerator::visitGetFrameArgumentHole(MGetFrameArgumentHole
* ins
) {
5461 LDefinition spectreTemp
=
5462 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
5464 auto* lir
= new (alloc()) LGetFrameArgumentHole(
5465 useRegister(ins
->index()), useRegister(ins
->length()), spectreTemp
);
5466 assignSnapshot(lir
, ins
->bailoutKind());
5467 defineBox(lir
, ins
);
5470 void LIRGenerator::visitNewTarget(MNewTarget
* ins
) {
5471 LNewTarget
* lir
= new (alloc()) LNewTarget();
5472 defineBox(lir
, ins
);
5475 void LIRGenerator::visitRest(MRest
* ins
) {
5476 MOZ_ASSERT(ins
->numActuals()->type() == MIRType::Int32
);
5478 LRest
* lir
= new (alloc())
5479 LRest(useRegisterAtStart(ins
->numActuals()), tempFixed(CallTempReg0
),
5480 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
5481 defineReturn(lir
, ins
);
5482 assignSafepoint(lir
, ins
);
5485 void LIRGenerator::visitThrow(MThrow
* ins
) {
5486 MDefinition
* value
= ins
->value();
5487 MOZ_ASSERT(value
->type() == MIRType::Value
);
5489 LThrow
* lir
= new (alloc()) LThrow(useBoxAtStart(value
));
5491 assignSafepoint(lir
, ins
);
5494 void LIRGenerator::visitThrowWithStack(MThrowWithStack
* ins
) {
5495 MDefinition
* value
= ins
->value();
5496 MOZ_ASSERT(value
->type() == MIRType::Value
);
5498 MDefinition
* stack
= ins
->stack();
5499 MOZ_ASSERT(stack
->type() == MIRType::Value
);
5502 new (alloc()) LThrowWithStack(useBoxAtStart(value
), useBoxAtStart(stack
));
5504 assignSafepoint(lir
, ins
);
5507 void LIRGenerator::visitInCache(MInCache
* ins
) {
5508 MDefinition
* lhs
= ins
->lhs();
5509 MDefinition
* rhs
= ins
->rhs();
5511 MOZ_ASSERT(lhs
->type() == MIRType::String
|| lhs
->type() == MIRType::Symbol
||
5512 lhs
->type() == MIRType::Int32
|| lhs
->type() == MIRType::Value
);
5513 MOZ_ASSERT(rhs
->type() == MIRType::Object
);
5516 new (alloc()) LInCache(useBoxOrTyped(lhs
), useRegister(rhs
), temp());
5518 assignSafepoint(lir
, ins
);
5521 void LIRGenerator::visitHasOwnCache(MHasOwnCache
* ins
) {
5522 MDefinition
* value
= ins
->value();
5523 MOZ_ASSERT(value
->type() == MIRType::Object
||
5524 value
->type() == MIRType::Value
);
5526 MDefinition
* id
= ins
->idval();
5527 MOZ_ASSERT(id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
||
5528 id
->type() == MIRType::Int32
|| id
->type() == MIRType::Value
);
5530 // Emit an overrecursed check: this is necessary because the cache can
5531 // attach a scripted getter stub that calls this script recursively.
5532 gen
->setNeedsOverrecursedCheck();
5535 new (alloc()) LHasOwnCache(useBoxOrTyped(value
), useBoxOrTyped(id
));
5537 assignSafepoint(lir
, ins
);
5540 void LIRGenerator::visitCheckPrivateFieldCache(MCheckPrivateFieldCache
* ins
) {
5541 MDefinition
* value
= ins
->value();
5542 MOZ_ASSERT(value
->type() == MIRType::Object
||
5543 value
->type() == MIRType::Value
);
5545 MDefinition
* id
= ins
->idval();
5546 MOZ_ASSERT(id
->type() == MIRType::String
|| id
->type() == MIRType::Symbol
||
5547 id
->type() == MIRType::Int32
|| id
->type() == MIRType::Value
);
5549 LCheckPrivateFieldCache
* lir
= new (alloc())
5550 LCheckPrivateFieldCache(useBoxOrTyped(value
), useBoxOrTyped(id
));
5552 assignSafepoint(lir
, ins
);
5555 void LIRGenerator::visitNewPrivateName(MNewPrivateName
* ins
) {
5556 auto* lir
= new (alloc()) LNewPrivateName();
5557 defineReturn(lir
, ins
);
5558 assignSafepoint(lir
, ins
);
5561 void LIRGenerator::visitInstanceOf(MInstanceOf
* ins
) {
5562 MDefinition
* lhs
= ins
->lhs();
5563 MDefinition
* rhs
= ins
->rhs();
5565 MOZ_ASSERT(lhs
->type() == MIRType::Value
|| lhs
->type() == MIRType::Object
);
5566 MOZ_ASSERT(rhs
->type() == MIRType::Object
);
5568 if (lhs
->type() == MIRType::Object
) {
5569 auto* lir
= new (alloc()) LInstanceOfO(useRegister(lhs
), useRegister(rhs
));
5571 assignSafepoint(lir
, ins
);
5573 auto* lir
= new (alloc()) LInstanceOfV(useBox(lhs
), useRegister(rhs
));
5575 assignSafepoint(lir
, ins
);
5579 void LIRGenerator::visitInstanceOfCache(MInstanceOfCache
* ins
) {
5580 MDefinition
* lhs
= ins
->lhs();
5581 MDefinition
* rhs
= ins
->rhs();
5583 MOZ_ASSERT(lhs
->type() == MIRType::Value
);
5584 MOZ_ASSERT(rhs
->type() == MIRType::Object
);
5586 LInstanceOfCache
* lir
=
5587 new (alloc()) LInstanceOfCache(useBox(lhs
), useRegister(rhs
));
5589 assignSafepoint(lir
, ins
);
5592 void LIRGenerator::visitIsArray(MIsArray
* ins
) {
5593 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5595 if (ins
->value()->type() == MIRType::Object
) {
5596 LIsArrayO
* lir
= new (alloc()) LIsArrayO(useRegister(ins
->value()));
5598 assignSafepoint(lir
, ins
);
5600 MOZ_ASSERT(ins
->value()->type() == MIRType::Value
);
5601 LIsArrayV
* lir
= new (alloc()) LIsArrayV(useBox(ins
->value()), temp());
5603 assignSafepoint(lir
, ins
);
5607 void LIRGenerator::visitIsTypedArray(MIsTypedArray
* ins
) {
5608 MOZ_ASSERT(ins
->value()->type() == MIRType::Object
);
5609 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5611 auto* lir
= new (alloc()) LIsTypedArray(useRegister(ins
->value()));
5614 if (ins
->isPossiblyWrapped()) {
5615 assignSafepoint(lir
, ins
);
5619 void LIRGenerator::visitIsCallable(MIsCallable
* ins
) {
5620 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5622 if (ins
->object()->type() == MIRType::Object
) {
5623 define(new (alloc()) LIsCallableO(useRegister(ins
->object())), ins
);
5625 MOZ_ASSERT(ins
->object()->type() == MIRType::Value
);
5626 define(new (alloc()) LIsCallableV(useBox(ins
->object()), temp()), ins
);
5630 void LIRGenerator::visitIsConstructor(MIsConstructor
* ins
) {
5631 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5632 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5633 define(new (alloc()) LIsConstructor(useRegister(ins
->object())), ins
);
5636 void LIRGenerator::visitIsCrossRealmArrayConstructor(
5637 MIsCrossRealmArrayConstructor
* ins
) {
5638 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5639 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5640 define(new (alloc())
5641 LIsCrossRealmArrayConstructor(useRegister(ins
->object())),
5645 static bool CanEmitAtUseForSingleTest(MInstruction
* ins
) {
5646 if (!ins
->canEmitAtUses()) {
5650 MUseIterator
iter(ins
->usesBegin());
5651 if (iter
== ins
->usesEnd()) {
5655 MNode
* node
= iter
->consumer();
5656 if (!node
->isDefinition()) {
5660 if (!node
->toDefinition()->isTest()) {
5665 return iter
== ins
->usesEnd();
5668 void LIRGenerator::visitIsObject(MIsObject
* ins
) {
5669 if (CanEmitAtUseForSingleTest(ins
)) {
5674 MDefinition
* opd
= ins
->input();
5675 MOZ_ASSERT(opd
->type() == MIRType::Value
);
5676 LIsObject
* lir
= new (alloc()) LIsObject(useBoxAtStart(opd
));
5680 void LIRGenerator::visitIsNullOrUndefined(MIsNullOrUndefined
* ins
) {
5681 if (CanEmitAtUseForSingleTest(ins
)) {
5686 MDefinition
* opd
= ins
->input();
5687 if (opd
->type() == MIRType::Value
) {
5688 auto* lir
= new (alloc()) LIsNullOrUndefined(useBoxAtStart(opd
));
5691 define(new (alloc()) LInteger(IsNullOrUndefined(opd
->type())), ins
);
5695 void LIRGenerator::visitHasClass(MHasClass
* ins
) {
5696 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5697 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
5698 define(new (alloc()) LHasClass(useRegister(ins
->object())), ins
);
5701 void LIRGenerator::visitGuardToClass(MGuardToClass
* ins
) {
5702 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5703 MOZ_ASSERT(ins
->type() == MIRType::Object
);
5704 LGuardToClass
* lir
=
5705 new (alloc()) LGuardToClass(useRegisterAtStart(ins
->object()), temp());
5706 assignSnapshot(lir
, ins
->bailoutKind());
5707 defineReuseInput(lir
, ins
, 0);
5710 void LIRGenerator::visitGuardToFunction(MGuardToFunction
* ins
) {
5711 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5712 MOZ_ASSERT(ins
->type() == MIRType::Object
);
5713 LGuardToFunction
* lir
=
5714 new (alloc()) LGuardToFunction(useRegisterAtStart(ins
->object()), temp());
5715 assignSnapshot(lir
, ins
->bailoutKind());
5716 defineReuseInput(lir
, ins
, 0);
5719 void LIRGenerator::visitObjectClassToString(MObjectClassToString
* ins
) {
5720 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
5721 MOZ_ASSERT(ins
->type() == MIRType::String
);
5722 auto* lir
= new (alloc()) LObjectClassToString(
5723 useRegisterAtStart(ins
->object()), tempFixed(CallTempReg0
));
5724 assignSnapshot(lir
, ins
->bailoutKind());
5725 defineReturn(lir
, ins
);
5728 void LIRGenerator::visitWasmAddOffset(MWasmAddOffset
* ins
) {
5729 MOZ_ASSERT(ins
->offset());
5730 if (ins
->base()->type() == MIRType::Int32
) {
5731 MOZ_ASSERT(ins
->type() == MIRType::Int32
);
5732 MOZ_ASSERT(ins
->offset() <= UINT32_MAX
); // Because memory32
5733 define(new (alloc()) LWasmAddOffset(useRegisterAtStart(ins
->base())), ins
);
5735 MOZ_ASSERT(ins
->type() == MIRType::Int64
);
5737 defineInt64(new (alloc())
5738 LWasmAddOffset64(useInt64RegisterAtStart(ins
->base())),
5741 // Avoid situation where the input is (a,b) and the output is (b,a).
5742 defineInt64ReuseInput(
5743 new (alloc()) LWasmAddOffset64(useInt64RegisterAtStart(ins
->base())),
5749 void LIRGenerator::visitWasmLoadInstance(MWasmLoadInstance
* ins
) {
5750 if (ins
->type() == MIRType::Int64
) {
5752 LAllocation instance
= useRegisterAtStart(ins
->instance());
5754 // Avoid reusing instance for a 64-bit output pair as the load clobbers the
5755 // first half of that pair before loading the second half.
5756 LAllocation instance
= useRegister(ins
->instance());
5758 auto* lir
= new (alloc()) LWasmLoadInstance64(instance
);
5759 defineInt64(lir
, ins
);
5762 new (alloc()) LWasmLoadInstance(useRegisterAtStart(ins
->instance()));
5767 void LIRGenerator::visitWasmStoreInstance(MWasmStoreInstance
* ins
) {
5768 MDefinition
* value
= ins
->value();
5769 if (value
->type() == MIRType::Int64
) {
5771 LAllocation instance
= useRegisterAtStart(ins
->instance());
5772 LInt64Allocation valueAlloc
= useInt64RegisterAtStart(value
);
5774 LAllocation instance
= useRegister(ins
->instance());
5775 LInt64Allocation valueAlloc
= useInt64Register(value
);
5777 add(new (alloc()) LWasmStoreSlotI64(valueAlloc
, instance
, ins
->offset(),
5778 mozilla::Nothing()),
5781 MOZ_ASSERT(value
->type() != MIRType::WasmAnyRef
);
5782 LAllocation instance
= useRegisterAtStart(ins
->instance());
5783 LAllocation valueAlloc
= useRegisterAtStart(value
);
5785 LWasmStoreSlot(valueAlloc
, instance
, ins
->offset(), value
->type(),
5786 MNarrowingOp::None
, mozilla::Nothing()),
5791 void LIRGenerator::visitWasmHeapReg(MWasmHeapReg
* ins
) {
5792 #ifdef WASM_HAS_HEAPREG
5793 auto* lir
= new (alloc()) LWasmHeapReg();
5800 void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck
* ins
) {
5801 MOZ_ASSERT(!ins
->isRedundant());
5803 MDefinition
* index
= ins
->index();
5804 MDefinition
* boundsCheckLimit
= ins
->boundsCheckLimit();
5806 MOZ_ASSERT(boundsCheckLimit
->type() == index
->type());
5808 if (index
->type() == MIRType::Int64
) {
5809 if (JitOptions
.spectreIndexMasking
) {
5810 auto* lir
= new (alloc()) LWasmBoundsCheck64(
5811 useInt64RegisterAtStart(index
), useInt64Register(boundsCheckLimit
));
5812 defineInt64ReuseInput(lir
, ins
, 0);
5814 auto* lir
= new (alloc())
5815 LWasmBoundsCheck64(useInt64RegisterAtStart(index
),
5816 useInt64RegisterAtStart(boundsCheckLimit
));
5820 MOZ_ASSERT(index
->type() == MIRType::Int32
);
5822 if (JitOptions
.spectreIndexMasking
) {
5823 auto* lir
= new (alloc()) LWasmBoundsCheck(useRegisterAtStart(index
),
5824 useRegister(boundsCheckLimit
));
5825 defineReuseInput(lir
, ins
, 0);
5827 auto* lir
= new (alloc()) LWasmBoundsCheck(
5828 useRegisterAtStart(index
), useRegisterAtStart(boundsCheckLimit
));
5834 void LIRGenerator::visitWasmBoundsCheckRange32(MWasmBoundsCheckRange32
* ins
) {
5835 MDefinition
* index
= ins
->index();
5836 MDefinition
* length
= ins
->length();
5837 MDefinition
* limit
= ins
->limit();
5839 MOZ_ASSERT(index
->type() == MIRType::Int32
);
5840 MOZ_ASSERT(length
->type() == MIRType::Int32
);
5841 MOZ_ASSERT(limit
->type() == MIRType::Int32
);
5843 add(new (alloc()) LWasmBoundsCheckRange32(
5844 useRegister(index
), useRegister(length
), useRegister(limit
), temp()),
5848 void LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck
* ins
) {
5849 MDefinition
* index
= ins
->index();
5850 if (index
->type() == MIRType::Int64
) {
5852 new (alloc()) LWasmAlignmentCheck64(useInt64RegisterAtStart(index
));
5855 auto* lir
= new (alloc()) LWasmAlignmentCheck(useRegisterAtStart(index
));
5860 void LIRGenerator::visitWasmLoadInstanceDataField(
5861 MWasmLoadInstanceDataField
* ins
) {
5862 size_t offs
= wasm::Instance::offsetInData(ins
->instanceDataOffset());
5863 if (ins
->type() == MIRType::Int64
) {
5865 LAllocation instance
= useRegisterAtStart(ins
->instance());
5867 // Avoid reusing instance for the output pair as the load clobbers the first
5868 // half of that pair before loading the second half.
5869 LAllocation instance
= useRegister(ins
->instance());
5871 defineInt64(new (alloc())
5872 LWasmLoadSlotI64(instance
, offs
, mozilla::Nothing()),
5875 LAllocation instance
= useRegisterAtStart(ins
->instance());
5876 define(new (alloc()) LWasmLoadSlot(instance
, offs
, ins
->type(),
5877 MWideningOp::None
, mozilla::Nothing()),
5882 void LIRGenerator::visitWasmLoadGlobalCell(MWasmLoadGlobalCell
* ins
) {
5883 if (ins
->type() == MIRType::Int64
) {
5885 LAllocation cellPtr
= useRegisterAtStart(ins
->cellPtr());
5887 // Avoid reusing cellPtr for the output pair as the load clobbers the first
5888 // half of that pair before loading the second half.
5889 LAllocation cellPtr
= useRegister(ins
->cellPtr());
5891 defineInt64(new (alloc())
5892 LWasmLoadSlotI64(cellPtr
, /*offset=*/0, mozilla::Nothing()),
5895 LAllocation cellPtr
= useRegisterAtStart(ins
->cellPtr());
5896 define(new (alloc()) LWasmLoadSlot(cellPtr
, /*offset=*/0, ins
->type(),
5897 MWideningOp::None
, mozilla::Nothing()),
5902 void LIRGenerator::visitWasmLoadTableElement(MWasmLoadTableElement
* ins
) {
5903 LAllocation elements
= useRegisterAtStart(ins
->elements());
5904 LAllocation index
= useRegisterAtStart(ins
->index());
5905 define(new (alloc()) LWasmLoadTableElement(elements
, index
), ins
);
5908 void LIRGenerator::visitWasmStoreInstanceDataField(
5909 MWasmStoreInstanceDataField
* ins
) {
5910 MDefinition
* value
= ins
->value();
5911 size_t offs
= wasm::Instance::offsetInData(ins
->instanceDataOffset());
5912 if (value
->type() == MIRType::Int64
) {
5914 LAllocation instance
= useRegisterAtStart(ins
->instance());
5915 LInt64Allocation valueAlloc
= useInt64RegisterAtStart(value
);
5917 LAllocation instance
= useRegister(ins
->instance());
5918 LInt64Allocation valueAlloc
= useInt64Register(value
);
5921 LWasmStoreSlotI64(valueAlloc
, instance
, offs
, mozilla::Nothing()),
5924 MOZ_ASSERT(value
->type() != MIRType::WasmAnyRef
);
5925 LAllocation instance
= useRegisterAtStart(ins
->instance());
5926 LAllocation valueAlloc
= useRegisterAtStart(value
);
5927 add(new (alloc()) LWasmStoreSlot(valueAlloc
, instance
, offs
, value
->type(),
5928 MNarrowingOp::None
, mozilla::Nothing()),
5933 void LIRGenerator::visitWasmStoreGlobalCell(MWasmStoreGlobalCell
* ins
) {
5934 MDefinition
* value
= ins
->value();
5936 if (value
->type() == MIRType::Int64
) {
5938 LAllocation cellPtr
= useRegisterAtStart(ins
->cellPtr());
5939 LInt64Allocation valueAlloc
= useInt64RegisterAtStart(value
);
5941 LAllocation cellPtr
= useRegister(ins
->cellPtr());
5942 LInt64Allocation valueAlloc
= useInt64Register(value
);
5945 LWasmStoreSlotI64(valueAlloc
, cellPtr
, offs
, mozilla::Nothing()));
5947 MOZ_ASSERT(value
->type() != MIRType::WasmAnyRef
);
5948 LAllocation cellPtr
= useRegisterAtStart(ins
->cellPtr());
5949 LAllocation valueAlloc
= useRegisterAtStart(value
);
5950 add(new (alloc()) LWasmStoreSlot(valueAlloc
, cellPtr
, offs
, value
->type(),
5951 MNarrowingOp::None
, mozilla::Nothing()));
5955 void LIRGenerator::visitWasmStoreStackResult(MWasmStoreStackResult
* ins
) {
5956 MDefinition
* stackResultArea
= ins
->stackResultArea();
5957 MDefinition
* value
= ins
->value();
5958 size_t offs
= ins
->offset();
5960 if (value
->type() == MIRType::Int64
) {
5962 LWasmStoreSlotI64(useInt64Register(value
), useRegister(stackResultArea
),
5963 offs
, mozilla::Nothing());
5965 MOZ_ASSERT(value
->type() != MIRType::WasmAnyRef
);
5967 LWasmStoreSlot(useRegister(value
), useRegister(stackResultArea
), offs
,
5968 value
->type(), MNarrowingOp::None
, mozilla::Nothing());
5973 void LIRGenerator::visitWasmDerivedPointer(MWasmDerivedPointer
* ins
) {
5974 LAllocation base
= useRegisterAtStart(ins
->base());
5975 define(new (alloc()) LWasmDerivedPointer(base
), ins
);
5978 void LIRGenerator::visitWasmDerivedIndexPointer(MWasmDerivedIndexPointer
* ins
) {
5979 LAllocation base
= useRegisterAtStart(ins
->base());
5980 LAllocation index
= useRegisterAtStart(ins
->index());
5981 define(new (alloc()) LWasmDerivedIndexPointer(base
, index
), ins
);
5984 void LIRGenerator::visitWasmStoreRef(MWasmStoreRef
* ins
) {
5985 LAllocation instance
= useRegister(ins
->instance());
5986 LAllocation valueBase
= useFixed(ins
->valueBase(), PreBarrierReg
);
5987 LAllocation value
= useRegister(ins
->value());
5988 uint32_t valueOffset
= ins
->offset();
5990 LWasmStoreRef(instance
, valueBase
, value
, temp(), valueOffset
,
5991 mozilla::Nothing(), ins
->preBarrierKind()),
5995 void LIRGenerator::visitWasmPostWriteBarrier(MWasmPostWriteBarrier
* ins
) {
5996 LWasmPostWriteBarrier
* lir
= new (alloc()) LWasmPostWriteBarrier(
5997 useFixed(ins
->instance(), InstanceReg
), useRegister(ins
->object()),
5998 useRegister(ins
->valueBase()), useRegister(ins
->value()), temp(),
5999 ins
->valueOffset());
6001 assignWasmSafepoint(lir
);
6004 void LIRGenerator::visitWasmParameter(MWasmParameter
* ins
) {
6005 ABIArg abi
= ins
->abi();
6006 if (ins
->type() == MIRType::StackResults
) {
6007 // Functions that return stack results receive an extra incoming parameter
6008 // with type MIRType::StackResults. This value is a pointer to fresh
6009 // memory. Here we treat it as if it were in fact MIRType::Pointer.
6010 auto* lir
= new (alloc()) LWasmParameter
;
6011 LDefinition
def(LDefinition::TypeFrom(MIRType::Pointer
),
6012 LDefinition::FIXED
);
6013 def
.setOutput(abi
.argInRegister() ? LAllocation(abi
.reg())
6014 : LArgument(abi
.offsetFromArgBase()));
6015 define(lir
, ins
, def
);
6018 if (abi
.argInRegister()) {
6019 #if defined(JS_NUNBOX32)
6020 if (abi
.isGeneralRegPair()) {
6022 new (alloc()) LWasmParameterI64
, ins
,
6023 LInt64Allocation(LAllocation(AnyRegister(abi
.gpr64().high
)),
6024 LAllocation(AnyRegister(abi
.gpr64().low
))));
6028 defineFixed(new (alloc()) LWasmParameter
, ins
, LAllocation(abi
.reg()));
6031 if (ins
->type() == MIRType::Int64
) {
6032 MOZ_ASSERT(!abi
.argInRegister());
6034 new (alloc()) LWasmParameterI64
, ins
,
6035 #if defined(JS_NUNBOX32)
6036 LInt64Allocation(LArgument(abi
.offsetFromArgBase() + INT64HIGH_OFFSET
),
6037 LArgument(abi
.offsetFromArgBase() + INT64LOW_OFFSET
))
6039 LInt64Allocation(LArgument(abi
.offsetFromArgBase()))
6043 MOZ_ASSERT(IsNumberType(ins
->type()) || ins
->type() == MIRType::WasmAnyRef
6044 #ifdef ENABLE_WASM_SIMD
6045 || ins
->type() == MIRType::Simd128
6048 defineFixed(new (alloc()) LWasmParameter
, ins
,
6049 LArgument(abi
.offsetFromArgBase()));
6053 void LIRGenerator::visitWasmReturn(MWasmReturn
* ins
) {
6054 MDefinition
* rval
= ins
->getOperand(0);
6055 MDefinition
* instance
= ins
->getOperand(1);
6057 if (rval
->type() == MIRType::Int64
) {
6058 add(new (alloc()) LWasmReturnI64(useInt64Fixed(rval
, ReturnReg64
),
6059 useFixed(instance
, InstanceReg
)));
6063 LAllocation returnReg
;
6064 if (rval
->type() == MIRType::Float32
) {
6065 returnReg
= useFixed(rval
, ReturnFloat32Reg
);
6066 } else if (rval
->type() == MIRType::Double
) {
6067 returnReg
= useFixed(rval
, ReturnDoubleReg
);
6068 #ifdef ENABLE_WASM_SIMD
6069 } else if (rval
->type() == MIRType::Simd128
) {
6070 returnReg
= useFixed(rval
, ReturnSimd128Reg
);
6072 } else if (rval
->type() == MIRType::Int32
||
6073 rval
->type() == MIRType::WasmAnyRef
) {
6074 returnReg
= useFixed(rval
, ReturnReg
);
6076 MOZ_CRASH("Unexpected wasm return type");
6080 new (alloc()) LWasmReturn(useFixed(instance
, InstanceReg
), returnReg
);
6084 void LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid
* ins
) {
6085 MDefinition
* instance
= ins
->getOperand(0);
6086 LWasmReturnVoid
* lir
=
6087 new (alloc()) LWasmReturnVoid(useFixed(instance
, InstanceReg
));
6091 void LIRGenerator::visitWasmStackArg(MWasmStackArg
* ins
) {
6092 if (ins
->arg()->type() == MIRType::Int64
) {
6094 LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins
->arg())),
6096 } else if (IsFloatingPointType(ins
->arg()->type())) {
6097 MOZ_ASSERT(!ins
->arg()->isEmittedAtUses());
6098 add(new (alloc()) LWasmStackArg(useRegisterAtStart(ins
->arg())), ins
);
6100 add(new (alloc()) LWasmStackArg(useRegisterOrConstantAtStart(ins
->arg())),
6105 void LIRGenerator::visitWasmRegisterResult(MWasmRegisterResult
* ins
) {
6106 auto* lir
= new (alloc()) LWasmRegisterResult();
6107 uint32_t vreg
= getVirtualRegister();
6108 MOZ_ASSERT(ins
->type() != MIRType::Int64
);
6109 auto type
= LDefinition::TypeFrom(ins
->type());
6110 lir
->setDef(0, LDefinition(vreg
, type
, LGeneralReg(ins
->loc())));
6111 ins
->setVirtualRegister(vreg
);
6115 void LIRGenerator::visitWasmFloatRegisterResult(MWasmFloatRegisterResult
* ins
) {
6116 auto* lir
= new (alloc()) LWasmRegisterResult();
6117 uint32_t vreg
= getVirtualRegister();
6118 auto type
= LDefinition::TypeFrom(ins
->type());
6119 lir
->setDef(0, LDefinition(vreg
, type
, LFloatReg(ins
->loc())));
6120 ins
->setVirtualRegister(vreg
);
6124 void LIRGenerator::visitWasmRegister64Result(MWasmRegister64Result
* ins
) {
6125 MOZ_ASSERT(ins
->type() == MIRType::Int64
);
6126 uint32_t vreg
= getVirtualRegister();
6128 #if defined(JS_NUNBOX32)
6129 auto* lir
= new (alloc()) LWasmRegisterPairResult();
6130 lir
->setDef(INT64LOW_INDEX
,
6131 LDefinition(vreg
+ INT64LOW_INDEX
, LDefinition::GENERAL
,
6132 LGeneralReg(ins
->loc().low
)));
6133 lir
->setDef(INT64HIGH_INDEX
,
6134 LDefinition(vreg
+ INT64HIGH_INDEX
, LDefinition::GENERAL
,
6135 LGeneralReg(ins
->loc().high
)));
6136 getVirtualRegister();
6137 #elif defined(JS_PUNBOX64)
6138 auto* lir
= new (alloc()) LWasmRegisterResult();
6140 0, LDefinition(vreg
, LDefinition::GENERAL
, LGeneralReg(ins
->loc().reg
)));
6142 # error expected either JS_NUNBOX32 or JS_PUNBOX64
6145 ins
->setVirtualRegister(vreg
);
6149 void LIRGenerator::visitWasmStackResultArea(MWasmStackResultArea
* ins
) {
6150 MOZ_ASSERT(ins
->type() == MIRType::StackResults
);
6151 auto* lir
= new (alloc()) LWasmStackResultArea(temp());
6152 uint32_t vreg
= getVirtualRegister();
6154 LDefinition(vreg
, LDefinition::STACKRESULTS
, LDefinition::STACK
));
6155 ins
->setVirtualRegister(vreg
);
6159 void LIRGenerator::visitWasmStackResult(MWasmStackResult
* ins
) {
6160 MWasmStackResultArea
* area
= ins
->resultArea()->toWasmStackResultArea();
6161 LDefinition::Policy pol
= LDefinition::STACK
;
6163 if (ins
->type() == MIRType::Int64
) {
6164 auto* lir
= new (alloc()) LWasmStackResult64
;
6165 lir
->setOperand(0, use(area
, LUse(LUse::STACK
, /* usedAtStart = */ true)));
6166 uint32_t vreg
= getVirtualRegister();
6167 LDefinition::Type typ
= LDefinition::GENERAL
;
6168 #if defined(JS_NUNBOX32)
6169 getVirtualRegister();
6170 lir
->setDef(INT64LOW_INDEX
, LDefinition(vreg
+ INT64LOW_INDEX
, typ
, pol
));
6171 lir
->setDef(INT64HIGH_INDEX
, LDefinition(vreg
+ INT64HIGH_INDEX
, typ
, pol
));
6173 lir
->setDef(0, LDefinition(vreg
, typ
, pol
));
6175 ins
->setVirtualRegister(vreg
);
6180 auto* lir
= new (alloc()) LWasmStackResult
;
6181 lir
->setOperand(0, use(area
, LUse(LUse::STACK
, /* usedAtStart = */ true)));
6182 uint32_t vreg
= getVirtualRegister();
6183 LDefinition::Type typ
= LDefinition::TypeFrom(ins
->type());
6184 lir
->setDef(0, LDefinition(vreg
, typ
, pol
));
6185 ins
->setVirtualRegister(vreg
);
6189 template <class MWasmCallT
>
6190 void LIRGenerator::visitWasmCall(MWasmCallT ins
) {
6191 bool needsBoundsCheck
= true;
6192 mozilla::Maybe
<uint32_t> tableSize
;
6194 if (ins
->callee().isTable()) {
6195 MDefinition
* index
= ins
->getOperand(ins
->numArgs());
6197 if (ins
->callee().which() == wasm::CalleeDesc::WasmTable
) {
6198 uint32_t minLength
= ins
->callee().wasmTableMinLength();
6199 mozilla::Maybe
<uint32_t> maxLength
= ins
->callee().wasmTableMaxLength();
6200 if (index
->isConstant() &&
6201 uint32_t(index
->toConstant()->toInt32()) < minLength
) {
6202 needsBoundsCheck
= false;
6204 if (maxLength
.isSome() && *maxLength
== minLength
) {
6205 tableSize
= maxLength
;
6210 auto* lir
= allocateVariadic
<LWasmCall
>(ins
->numOperands(), needsBoundsCheck
,
6213 abort(AbortReason::Alloc
, "OOM: LIRGenerator::lowerWasmCall");
6217 for (unsigned i
= 0; i
< ins
->numArgs(); i
++) {
6219 i
, useFixedAtStart(ins
->getOperand(i
), ins
->registerForArg(i
)));
6222 if (ins
->callee().isTable()) {
6223 MDefinition
* index
= ins
->getOperand(ins
->numArgs());
6224 lir
->setOperand(ins
->numArgs(),
6225 useFixedAtStart(index
, WasmTableCallIndexReg
));
6227 if (ins
->callee().isFuncRef()) {
6228 MDefinition
* ref
= ins
->getOperand(ins
->numArgs());
6229 lir
->setOperand(ins
->numArgs(), useFixedAtStart(ref
, WasmCallRefReg
));
6233 assignWasmSafepoint(lir
);
6235 // WasmCall with WasmTable has two call instructions, and they both need a
6236 // safepoint associated with them. Create a second safepoint here; the node
6237 // otherwise does nothing, and codegen for it only marks the safepoint at the
6239 if (ins
->callee().which() == wasm::CalleeDesc::WasmTable
&&
6240 !ins
->isWasmReturnCall()) {
6241 auto* adjunctSafepoint
= new (alloc()) LWasmCallIndirectAdjunctSafepoint();
6242 add(adjunctSafepoint
);
6243 assignWasmSafepoint(adjunctSafepoint
);
6244 lir
->setAdjunctSafepoint(adjunctSafepoint
);
6248 void LIRGenerator::visitWasmCallCatchable(MWasmCallCatchable
* ins
) {
6252 void LIRGenerator::visitWasmCallUncatchable(MWasmCallUncatchable
* ins
) {
6256 void LIRGenerator::visitWasmReturnCall(MWasmReturnCall
* ins
) {
6260 void LIRGenerator::visitWasmCallLandingPrePad(MWasmCallLandingPrePad
* ins
) {
6261 add(new (alloc()) LWasmCallLandingPrePad
, ins
);
6264 void LIRGenerator::visitSetDOMProperty(MSetDOMProperty
* ins
) {
6265 MDefinition
* val
= ins
->value();
6267 Register cxReg
, objReg
, privReg
, valueReg
;
6268 GetTempRegForIntArg(0, 0, &cxReg
);
6269 GetTempRegForIntArg(1, 0, &objReg
);
6270 GetTempRegForIntArg(2, 0, &privReg
);
6271 GetTempRegForIntArg(3, 0, &valueReg
);
6273 // Keep using GetTempRegForIntArg, since we want to make sure we
6274 // don't clobber registers we're already using.
6275 Register tempReg1
, tempReg2
;
6276 GetTempRegForIntArg(4, 0, &tempReg1
);
6277 mozilla::DebugOnly
<bool> ok
= GetTempRegForIntArg(5, 0, &tempReg2
);
6278 MOZ_ASSERT(ok
, "How can we not have six temp registers?");
6280 LSetDOMProperty
* lir
= new (alloc())
6281 LSetDOMProperty(tempFixed(cxReg
), useFixedAtStart(ins
->object(), objReg
),
6282 useBoxFixedAtStart(val
, tempReg1
, tempReg2
),
6283 tempFixed(privReg
), tempFixed(valueReg
));
6285 assignSafepoint(lir
, ins
);
6288 void LIRGenerator::visitGetDOMProperty(MGetDOMProperty
* ins
) {
6289 Register cxReg
, objReg
, privReg
, valueReg
;
6290 GetTempRegForIntArg(0, 0, &cxReg
);
6291 GetTempRegForIntArg(1, 0, &objReg
);
6292 GetTempRegForIntArg(2, 0, &privReg
);
6293 mozilla::DebugOnly
<bool> ok
= GetTempRegForIntArg(3, 0, &valueReg
);
6294 MOZ_ASSERT(ok
, "How can we not have four temp registers?");
6295 LGetDOMProperty
* lir
= new (alloc())
6296 LGetDOMProperty(tempFixed(cxReg
), useFixedAtStart(ins
->object(), objReg
),
6297 tempFixed(privReg
), tempFixed(valueReg
));
6299 defineReturn(lir
, ins
);
6300 assignSafepoint(lir
, ins
);
6303 void LIRGenerator::visitGetDOMMember(MGetDOMMember
* ins
) {
6304 MOZ_ASSERT(ins
->isDomMovable(), "Members had better be movable");
6305 // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
6306 // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
6307 // value can in fact change as a result of DOM setters and method calls.
6308 MOZ_ASSERT(ins
->domAliasSet() != JSJitInfo::AliasEverything
,
6309 "Member gets had better not alias the world");
6311 MDefinition
* obj
= ins
->object();
6312 MOZ_ASSERT(obj
->type() == MIRType::Object
);
6314 MIRType type
= ins
->type();
6316 if (type
== MIRType::Value
) {
6317 LGetDOMMemberV
* lir
= new (alloc()) LGetDOMMemberV(useRegisterAtStart(obj
));
6318 defineBox(lir
, ins
);
6320 LGetDOMMemberT
* lir
=
6321 new (alloc()) LGetDOMMemberT(useRegisterForTypedLoad(obj
, type
));
6326 void LIRGenerator::visitLoadDOMExpandoValue(MLoadDOMExpandoValue
* ins
) {
6327 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
6329 new (alloc()) LLoadDOMExpandoValue(useRegisterAtStart(ins
->proxy()));
6330 defineBox(lir
, ins
);
6333 void LIRGenerator::visitLoadDOMExpandoValueGuardGeneration(
6334 MLoadDOMExpandoValueGuardGeneration
* ins
) {
6335 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
6336 auto* lir
= new (alloc())
6337 LLoadDOMExpandoValueGuardGeneration(useRegisterAtStart(ins
->proxy()));
6338 assignSnapshot(lir
, ins
->bailoutKind());
6339 defineBox(lir
, ins
);
6342 void LIRGenerator::visitLoadDOMExpandoValueIgnoreGeneration(
6343 MLoadDOMExpandoValueIgnoreGeneration
* ins
) {
6344 MOZ_ASSERT(ins
->proxy()->type() == MIRType::Object
);
6345 auto* lir
= new (alloc())
6346 LLoadDOMExpandoValueIgnoreGeneration(useRegisterAtStart(ins
->proxy()));
6347 defineBox(lir
, ins
);
6350 void LIRGenerator::visitGuardDOMExpandoMissingOrGuardShape(
6351 MGuardDOMExpandoMissingOrGuardShape
* ins
) {
6352 MOZ_ASSERT(ins
->expando()->type() == MIRType::Value
);
6353 auto* lir
= new (alloc())
6354 LGuardDOMExpandoMissingOrGuardShape(useBox(ins
->expando()), temp());
6355 assignSnapshot(lir
, ins
->bailoutKind());
6357 redefine(ins
, ins
->expando());
6360 void LIRGenerator::visitIncrementWarmUpCounter(MIncrementWarmUpCounter
* ins
) {
6361 LIncrementWarmUpCounter
* lir
= new (alloc()) LIncrementWarmUpCounter(temp());
6365 void LIRGenerator::visitLexicalCheck(MLexicalCheck
* ins
) {
6366 MDefinition
* input
= ins
->input();
6367 MOZ_ASSERT(input
->type() == MIRType::Value
);
6368 LLexicalCheck
* lir
= new (alloc()) LLexicalCheck(useBox(input
));
6369 assignSnapshot(lir
, ins
->bailoutKind());
6371 redefine(ins
, input
);
6374 void LIRGenerator::visitThrowRuntimeLexicalError(
6375 MThrowRuntimeLexicalError
* ins
) {
6376 LThrowRuntimeLexicalError
* lir
= new (alloc()) LThrowRuntimeLexicalError();
6378 assignSafepoint(lir
, ins
);
6381 void LIRGenerator::visitThrowMsg(MThrowMsg
* ins
) {
6382 LThrowMsg
* lir
= new (alloc()) LThrowMsg();
6384 assignSafepoint(lir
, ins
);
6387 void LIRGenerator::visitGlobalDeclInstantiation(MGlobalDeclInstantiation
* ins
) {
6388 LGlobalDeclInstantiation
* lir
= new (alloc()) LGlobalDeclInstantiation();
6390 assignSafepoint(lir
, ins
);
6393 void LIRGenerator::visitDebugger(MDebugger
* ins
) {
6394 auto* lir
= new (alloc()) LDebugger(tempFixed(CallTempReg0
));
6395 assignSnapshot(lir
, ins
->bailoutKind());
6399 void LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree
* ins
) {
6400 define(new (alloc()) LAtomicIsLockFree(useRegister(ins
->input())), ins
);
6403 void LIRGenerator::visitCheckReturn(MCheckReturn
* ins
) {
6404 MDefinition
* retVal
= ins
->returnValue();
6405 MDefinition
* thisVal
= ins
->thisValue();
6406 MOZ_ASSERT(retVal
->type() == MIRType::Value
);
6407 MOZ_ASSERT(thisVal
->type() == MIRType::Value
);
6410 new (alloc()) LCheckReturn(useBoxAtStart(retVal
), useBoxAtStart(thisVal
));
6411 defineBox(lir
, ins
);
6412 assignSafepoint(lir
, ins
);
6415 void LIRGenerator::visitCheckIsObj(MCheckIsObj
* ins
) {
6416 MDefinition
* input
= ins
->input();
6417 MOZ_ASSERT(input
->type() == MIRType::Value
);
6419 LCheckIsObj
* lir
= new (alloc()) LCheckIsObj(useBox(input
));
6421 assignSafepoint(lir
, ins
);
6425 void LIRGenerator::visitCheckScriptedProxyGetResult(
6426 MCheckScriptedProxyGetResult
* ins
) {
6427 MDefinition
* target
= ins
->target();
6428 MDefinition
* id
= ins
->id();
6429 MDefinition
* value
= ins
->value();
6431 LCheckScriptedProxyGetResult
* lir
=
6432 new (alloc()) LCheckScriptedProxyGetResult(useBox(target
), useBox(id
),
6433 useBox(value
), temp(), temp());
6435 assignSafepoint(lir
, ins
);
6439 void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible
* ins
) {
6440 MDefinition
* checkVal
= ins
->checkValue();
6441 MOZ_ASSERT(checkVal
->type() == MIRType::Value
);
6443 auto* lir
= new (alloc()) LCheckObjCoercible(useBoxAtStart(checkVal
));
6444 redefine(ins
, checkVal
);
6446 assignSafepoint(lir
, ins
);
6449 void LIRGenerator::visitCheckClassHeritage(MCheckClassHeritage
* ins
) {
6450 MDefinition
* heritage
= ins
->heritage();
6451 MOZ_ASSERT(heritage
->type() == MIRType::Value
);
6454 new (alloc()) LCheckClassHeritage(useBox(heritage
), temp(), temp());
6455 redefine(ins
, heritage
);
6457 assignSafepoint(lir
, ins
);
6460 void LIRGenerator::visitCheckThis(MCheckThis
* ins
) {
6461 MDefinition
* thisValue
= ins
->thisValue();
6462 MOZ_ASSERT(thisValue
->type() == MIRType::Value
);
6464 auto* lir
= new (alloc()) LCheckThis(useBoxAtStart(thisValue
));
6465 redefine(ins
, thisValue
);
6467 assignSafepoint(lir
, ins
);
6470 void LIRGenerator::visitCheckThisReinit(MCheckThisReinit
* ins
) {
6471 MDefinition
* thisValue
= ins
->thisValue();
6472 MOZ_ASSERT(thisValue
->type() == MIRType::Value
);
6474 auto* lir
= new (alloc()) LCheckThisReinit(useBoxAtStart(thisValue
));
6475 redefine(ins
, thisValue
);
6477 assignSafepoint(lir
, ins
);
6480 void LIRGenerator::visitGenerator(MGenerator
* ins
) {
6482 new (alloc()) LGenerator(useRegisterAtStart(ins
->callee()),
6483 useRegisterAtStart(ins
->environmentChain()),
6484 useRegisterAtStart(ins
->argsObject()));
6485 defineReturn(lir
, ins
);
6486 assignSafepoint(lir
, ins
);
6489 void LIRGenerator::visitAsyncResolve(MAsyncResolve
* ins
) {
6490 auto* lir
= new (alloc()) LAsyncResolve(useRegisterAtStart(ins
->generator()),
6491 useBoxAtStart(ins
->valueOrReason()));
6492 defineReturn(lir
, ins
);
6493 assignSafepoint(lir
, ins
);
6496 void LIRGenerator::visitAsyncAwait(MAsyncAwait
* ins
) {
6497 MOZ_ASSERT(ins
->generator()->type() == MIRType::Object
);
6498 auto* lir
= new (alloc()) LAsyncAwait(useBoxAtStart(ins
->value()),
6499 useRegisterAtStart(ins
->generator()));
6500 defineReturn(lir
, ins
);
6501 assignSafepoint(lir
, ins
);
6504 void LIRGenerator::visitCanSkipAwait(MCanSkipAwait
* ins
) {
6505 auto* lir
= new (alloc()) LCanSkipAwait(useBoxAtStart(ins
->value()));
6506 defineReturn(lir
, ins
);
6507 assignSafepoint(lir
, ins
);
6510 void LIRGenerator::visitMaybeExtractAwaitValue(MMaybeExtractAwaitValue
* ins
) {
6511 auto* lir
= new (alloc()) LMaybeExtractAwaitValue(
6512 useBoxAtStart(ins
->value()), useRegisterAtStart(ins
->canSkip()));
6513 defineReturn(lir
, ins
);
6514 assignSafepoint(lir
, ins
);
6517 void LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted
* ins
) {
6518 MDefinition
* checkVal
= ins
->checkValue();
6519 MOZ_ASSERT(checkVal
->type() == MIRType::Value
);
6521 LDebugCheckSelfHosted
* lir
=
6522 new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal
));
6523 redefine(ins
, checkVal
);
6525 assignSafepoint(lir
, ins
);
6528 void LIRGenerator::visitIsPackedArray(MIsPackedArray
* ins
) {
6529 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
6530 MOZ_ASSERT(ins
->type() == MIRType::Boolean
);
6532 auto lir
= new (alloc()) LIsPackedArray(useRegister(ins
->object()), temp());
6536 void LIRGenerator::visitGuardArrayIsPacked(MGuardArrayIsPacked
* ins
) {
6537 MOZ_ASSERT(ins
->array()->type() == MIRType::Object
);
6539 auto* lir
= new (alloc())
6540 LGuardArrayIsPacked(useRegister(ins
->array()), temp(), temp());
6541 assignSnapshot(lir
, ins
->bailoutKind());
6543 redefine(ins
, ins
->array());
6546 void LIRGenerator::visitGetPrototypeOf(MGetPrototypeOf
* ins
) {
6547 MOZ_ASSERT(ins
->target()->type() == MIRType::Object
);
6548 MOZ_ASSERT(ins
->type() == MIRType::Value
);
6550 auto lir
= new (alloc()) LGetPrototypeOf(useRegister(ins
->target()));
6551 defineBox(lir
, ins
);
6552 assignSafepoint(lir
, ins
);
6555 void LIRGenerator::visitObjectWithProto(MObjectWithProto
* ins
) {
6556 MOZ_ASSERT(ins
->prototype()->type() == MIRType::Value
);
6557 MOZ_ASSERT(ins
->type() == MIRType::Object
);
6559 auto* lir
= new (alloc()) LObjectWithProto(useBoxAtStart(ins
->prototype()));
6560 defineReturn(lir
, ins
);
6561 assignSafepoint(lir
, ins
);
6564 void LIRGenerator::visitObjectStaticProto(MObjectStaticProto
* ins
) {
6565 MOZ_ASSERT(ins
->object()->type() == MIRType::Object
);
6566 MOZ_ASSERT(ins
->type() == MIRType::Object
);
6569 new (alloc()) LObjectStaticProto(useRegisterAtStart(ins
->object()));
6573 void LIRGenerator::visitBuiltinObject(MBuiltinObject
* ins
) {
6574 MOZ_ASSERT(ins
->type() == MIRType::Object
);
6576 auto* lir
= new (alloc()) LBuiltinObject();
6577 defineReturn(lir
, ins
);
6578 assignSafepoint(lir
, ins
);
6581 void LIRGenerator::visitReturn(MReturn
* ret
) {
6582 return visitReturnImpl(ret
->getOperand(0));
6585 void LIRGenerator::visitGeneratorReturn(MGeneratorReturn
* ret
) {
6586 return visitReturnImpl(ret
->getOperand(0), true);
6589 void LIRGenerator::visitSuperFunction(MSuperFunction
* ins
) {
6590 MOZ_ASSERT(ins
->callee()->type() == MIRType::Object
);
6591 MOZ_ASSERT(ins
->type() == MIRType::Value
);
6593 auto* lir
= new (alloc()) LSuperFunction(useRegister(ins
->callee()), temp());
6594 defineBox(lir
, ins
);
6597 void LIRGenerator::visitInitHomeObject(MInitHomeObject
* ins
) {
6598 MDefinition
* function
= ins
->function();
6599 MOZ_ASSERT(function
->type() == MIRType::Object
);
6601 MDefinition
* homeObject
= ins
->homeObject();
6602 MOZ_ASSERT(homeObject
->type() == MIRType::Value
);
6604 MOZ_ASSERT(ins
->type() == MIRType::Object
);
6606 auto* lir
= new (alloc())
6607 LInitHomeObject(useRegisterAtStart(function
), useBoxAtStart(homeObject
));
6608 redefine(ins
, function
);
6612 void LIRGenerator::visitIsTypedArrayConstructor(MIsTypedArrayConstructor
* ins
) {
6613 MDefinition
* object
= ins
->object();
6614 MOZ_ASSERT(object
->type() == MIRType::Object
);
6616 auto* lir
= new (alloc()) LIsTypedArrayConstructor(useRegister(object
));
6620 void LIRGenerator::visitLoadValueTag(MLoadValueTag
* ins
) {
6621 MDefinition
* value
= ins
->value();
6622 MOZ_ASSERT(value
->type() == MIRType::Value
);
6624 define(new (alloc()) LLoadValueTag(useBoxAtStart(value
)), ins
);
6627 void LIRGenerator::visitGuardTagNotEqual(MGuardTagNotEqual
* ins
) {
6628 MDefinition
* lhs
= ins
->lhs();
6629 MOZ_ASSERT(lhs
->type() == MIRType::Int32
);
6631 MDefinition
* rhs
= ins
->rhs();
6632 MOZ_ASSERT(rhs
->type() == MIRType::Int32
);
6635 new (alloc()) LGuardTagNotEqual(useRegister(lhs
), useRegister(rhs
));
6636 assignSnapshot(guard
, ins
->bailoutKind());
6640 void LIRGenerator::visitLoadWrapperTarget(MLoadWrapperTarget
* ins
) {
6641 MDefinition
* object
= ins
->object();
6642 MOZ_ASSERT(object
->type() == MIRType::Object
);
6644 define(new (alloc()) LLoadWrapperTarget(useRegisterAtStart(object
)), ins
);
6647 void LIRGenerator::visitGuardHasGetterSetter(MGuardHasGetterSetter
* ins
) {
6648 MDefinition
* object
= ins
->object();
6649 MOZ_ASSERT(object
->type() == MIRType::Object
);
6651 auto* guard
= new (alloc())
6652 LGuardHasGetterSetter(useRegisterAtStart(object
), tempFixed(CallTempReg0
),
6653 tempFixed(CallTempReg1
), tempFixed(CallTempReg2
));
6654 assignSnapshot(guard
, ins
->bailoutKind());
6656 redefine(ins
, object
);
6659 void LIRGenerator::visitGuardIsExtensible(MGuardIsExtensible
* ins
) {
6660 MDefinition
* object
= ins
->object();
6661 MOZ_ASSERT(object
->type() == MIRType::Object
);
6663 auto* guard
= new (alloc()) LGuardIsExtensible(useRegister(object
), temp());
6664 assignSnapshot(guard
, ins
->bailoutKind());
6666 redefine(ins
, object
);
6669 void LIRGenerator::visitGuardInt32IsNonNegative(MGuardInt32IsNonNegative
* ins
) {
6670 MDefinition
* index
= ins
->index();
6671 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6673 auto* guard
= new (alloc()) LGuardInt32IsNonNegative(useRegister(index
));
6674 assignSnapshot(guard
, ins
->bailoutKind());
6676 redefine(ins
, index
);
6679 void LIRGenerator::visitGuardInt32Range(MGuardInt32Range
* ins
) {
6680 MDefinition
* input
= ins
->input();
6681 MOZ_ASSERT(input
->type() == MIRType::Int32
);
6683 auto* guard
= new (alloc()) LGuardInt32Range(useRegister(input
));
6684 assignSnapshot(guard
, ins
->bailoutKind());
6686 redefine(ins
, input
);
6689 void LIRGenerator::visitGuardIndexIsNotDenseElement(
6690 MGuardIndexIsNotDenseElement
* ins
) {
6691 MDefinition
* object
= ins
->object();
6692 MOZ_ASSERT(object
->type() == MIRType::Object
);
6694 MDefinition
* index
= ins
->index();
6695 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6697 LDefinition spectreTemp
=
6698 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6700 auto* guard
= new (alloc()) LGuardIndexIsNotDenseElement(
6701 useRegister(object
), useRegister(index
), temp(), spectreTemp
);
6702 assignSnapshot(guard
, ins
->bailoutKind());
6704 redefine(ins
, index
);
6707 void LIRGenerator::visitGuardIndexIsValidUpdateOrAdd(
6708 MGuardIndexIsValidUpdateOrAdd
* ins
) {
6709 MDefinition
* object
= ins
->object();
6710 MOZ_ASSERT(object
->type() == MIRType::Object
);
6712 MDefinition
* index
= ins
->index();
6713 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6715 LDefinition spectreTemp
=
6716 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6718 auto* guard
= new (alloc()) LGuardIndexIsValidUpdateOrAdd(
6719 useRegister(object
), useRegister(index
), temp(), spectreTemp
);
6720 assignSnapshot(guard
, ins
->bailoutKind());
6722 redefine(ins
, index
);
6725 void LIRGenerator::visitCallAddOrUpdateSparseElement(
6726 MCallAddOrUpdateSparseElement
* ins
) {
6727 MDefinition
* object
= ins
->object();
6728 MOZ_ASSERT(object
->type() == MIRType::Object
);
6730 MDefinition
* index
= ins
->index();
6731 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6733 MDefinition
* value
= ins
->value();
6734 MOZ_ASSERT(value
->type() == MIRType::Value
);
6736 auto* lir
= new (alloc()) LCallAddOrUpdateSparseElement(
6737 useRegisterAtStart(object
), useRegisterAtStart(index
),
6738 useBoxAtStart(value
));
6740 assignSafepoint(lir
, ins
);
6743 void LIRGenerator::visitCallGetSparseElement(MCallGetSparseElement
* ins
) {
6744 MDefinition
* object
= ins
->object();
6745 MOZ_ASSERT(object
->type() == MIRType::Object
);
6747 MDefinition
* index
= ins
->index();
6748 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6750 auto* lir
= new (alloc()) LCallGetSparseElement(useRegisterAtStart(object
),
6751 useRegisterAtStart(index
));
6752 defineReturn(lir
, ins
);
6753 assignSafepoint(lir
, ins
);
6756 void LIRGenerator::visitCallNativeGetElement(MCallNativeGetElement
* ins
) {
6757 MDefinition
* object
= ins
->object();
6758 MOZ_ASSERT(object
->type() == MIRType::Object
);
6760 MDefinition
* index
= ins
->index();
6761 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6763 auto* lir
= new (alloc()) LCallNativeGetElement(useRegisterAtStart(object
),
6764 useRegisterAtStart(index
));
6765 defineReturn(lir
, ins
);
6766 assignSafepoint(lir
, ins
);
6769 void LIRGenerator::visitCallNativeGetElementSuper(
6770 MCallNativeGetElementSuper
* ins
) {
6771 MDefinition
* object
= ins
->object();
6772 MOZ_ASSERT(object
->type() == MIRType::Object
);
6774 MDefinition
* index
= ins
->index();
6775 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6777 MDefinition
* receiver
= ins
->receiver();
6779 auto* lir
= new (alloc()) LCallNativeGetElementSuper(
6780 useRegisterAtStart(object
), useRegisterAtStart(index
),
6781 useBoxAtStart(receiver
));
6782 defineReturn(lir
, ins
);
6783 assignSafepoint(lir
, ins
);
6786 void LIRGenerator::visitCallObjectHasSparseElement(
6787 MCallObjectHasSparseElement
* ins
) {
6788 MDefinition
* object
= ins
->object();
6789 MOZ_ASSERT(object
->type() == MIRType::Object
);
6791 MDefinition
* index
= ins
->index();
6792 MOZ_ASSERT(index
->type() == MIRType::Int32
);
6794 auto* lir
= new (alloc()) LCallObjectHasSparseElement(
6795 useRegisterAtStart(object
), useRegisterAtStart(index
),
6796 tempFixed(CallTempReg0
), tempFixed(CallTempReg1
));
6797 assignSnapshot(lir
, ins
->bailoutKind());
6798 defineReturn(lir
, ins
);
6801 void LIRGenerator::visitBigIntAsIntN(MBigIntAsIntN
* ins
) {
6802 MOZ_ASSERT(ins
->bits()->type() == MIRType::Int32
);
6803 MOZ_ASSERT(ins
->input()->type() == MIRType::BigInt
);
6805 if (ins
->bits()->isConstant()) {
6806 int32_t bits
= ins
->bits()->toConstant()->toInt32();
6808 auto* lir
= new (alloc())
6809 LBigIntAsIntN64(useRegister(ins
->input()), temp(), tempInt64());
6811 assignSafepoint(lir
, ins
);
6815 auto* lir
= new (alloc())
6816 LBigIntAsIntN32(useRegister(ins
->input()), temp(), tempInt64());
6818 assignSafepoint(lir
, ins
);
6823 auto* lir
= new (alloc()) LBigIntAsIntN(useRegisterAtStart(ins
->bits()),
6824 useRegisterAtStart(ins
->input()));
6825 defineReturn(lir
, ins
);
6826 assignSafepoint(lir
, ins
);
6829 void LIRGenerator::visitBigIntAsUintN(MBigIntAsUintN
* ins
) {
6830 MOZ_ASSERT(ins
->bits()->type() == MIRType::Int32
);
6831 MOZ_ASSERT(ins
->input()->type() == MIRType::BigInt
);
6833 if (ins
->bits()->isConstant()) {
6834 int32_t bits
= ins
->bits()->toConstant()->toInt32();
6836 auto* lir
= new (alloc())
6837 LBigIntAsUintN64(useRegister(ins
->input()), temp(), tempInt64());
6839 assignSafepoint(lir
, ins
);
6843 auto* lir
= new (alloc())
6844 LBigIntAsUintN32(useRegister(ins
->input()), temp(), tempInt64());
6846 assignSafepoint(lir
, ins
);
6851 auto* lir
= new (alloc()) LBigIntAsUintN(useRegisterAtStart(ins
->bits()),
6852 useRegisterAtStart(ins
->input()));
6853 defineReturn(lir
, ins
);
6854 assignSafepoint(lir
, ins
);
6857 void LIRGenerator::visitGuardNonGCThing(MGuardNonGCThing
* ins
) {
6858 MDefinition
* input
= ins
->input();
6860 auto* guard
= new (alloc()) LGuardNonGCThing(useBox(input
));
6861 assignSnapshot(guard
, ins
->bailoutKind());
6863 redefine(ins
, input
);
6866 void LIRGenerator::visitToHashableNonGCThing(MToHashableNonGCThing
* ins
) {
6868 new (alloc()) LToHashableNonGCThing(useBox(ins
->input()), tempDouble());
6869 defineBox(lir
, ins
);
6872 void LIRGenerator::visitToHashableString(MToHashableString
* ins
) {
6873 auto* lir
= new (alloc()) LToHashableString(useRegister(ins
->input()));
6875 assignSafepoint(lir
, ins
);
6878 void LIRGenerator::visitToHashableValue(MToHashableValue
* ins
) {
6880 new (alloc()) LToHashableValue(useBox(ins
->input()), tempDouble());
6881 defineBox(lir
, ins
);
6882 assignSafepoint(lir
, ins
);
6885 void LIRGenerator::visitHashNonGCThing(MHashNonGCThing
* ins
) {
6886 auto* lir
= new (alloc()) LHashNonGCThing(useBox(ins
->input()), temp());
6890 void LIRGenerator::visitHashString(MHashString
* ins
) {
6891 auto* lir
= new (alloc()) LHashString(useRegister(ins
->input()), temp());
6895 void LIRGenerator::visitHashSymbol(MHashSymbol
* ins
) {
6896 auto* lir
= new (alloc()) LHashSymbol(useRegister(ins
->input()));
6900 void LIRGenerator::visitHashBigInt(MHashBigInt
* ins
) {
6901 auto* lir
= new (alloc())
6902 LHashBigInt(useRegister(ins
->input()), temp(), temp(), temp());
6906 void LIRGenerator::visitHashObject(MHashObject
* ins
) {
6908 new (alloc()) LHashObject(useRegister(ins
->set()), useBox(ins
->input()),
6909 temp(), temp(), temp(), temp());
6913 void LIRGenerator::visitHashValue(MHashValue
* ins
) {
6915 new (alloc()) LHashValue(useRegister(ins
->set()), useBox(ins
->input()),
6916 temp(), temp(), temp(), temp());
6920 void LIRGenerator::visitSetObjectHasNonBigInt(MSetObjectHasNonBigInt
* ins
) {
6921 auto* lir
= new (alloc())
6922 LSetObjectHasNonBigInt(useRegister(ins
->set()), useBox(ins
->value()),
6923 useRegister(ins
->hash()), temp(), temp());
6927 void LIRGenerator::visitSetObjectHasBigInt(MSetObjectHasBigInt
* ins
) {
6928 auto* lir
= new (alloc()) LSetObjectHasBigInt(
6929 useRegister(ins
->set()), useBox(ins
->value()), useRegister(ins
->hash()),
6930 temp(), temp(), temp(), temp());
6934 void LIRGenerator::visitSetObjectHasValue(MSetObjectHasValue
* ins
) {
6935 auto* lir
= new (alloc()) LSetObjectHasValue(
6936 useRegister(ins
->set()), useBox(ins
->value()), useRegister(ins
->hash()),
6937 temp(), temp(), temp(), temp());
6941 void LIRGenerator::visitSetObjectHasValueVMCall(MSetObjectHasValueVMCall
* ins
) {
6942 auto* lir
= new (alloc()) LSetObjectHasValueVMCall(
6943 useRegisterAtStart(ins
->set()), useBoxAtStart(ins
->value()));
6944 defineReturn(lir
, ins
);
6945 assignSafepoint(lir
, ins
);
6948 void LIRGenerator::visitSetObjectSize(MSetObjectSize
* ins
) {
6949 auto* lir
= new (alloc()) LSetObjectSize(useRegisterAtStart(ins
->set()));
6953 void LIRGenerator::visitMapObjectHasNonBigInt(MMapObjectHasNonBigInt
* ins
) {
6954 auto* lir
= new (alloc())
6955 LMapObjectHasNonBigInt(useRegister(ins
->map()), useBox(ins
->value()),
6956 useRegister(ins
->hash()), temp(), temp());
6960 void LIRGenerator::visitMapObjectHasBigInt(MMapObjectHasBigInt
* ins
) {
6961 auto* lir
= new (alloc()) LMapObjectHasBigInt(
6962 useRegister(ins
->map()), useBox(ins
->value()), useRegister(ins
->hash()),
6963 temp(), temp(), temp(), temp());
6967 void LIRGenerator::visitMapObjectHasValue(MMapObjectHasValue
* ins
) {
6968 auto* lir
= new (alloc()) LMapObjectHasValue(
6969 useRegister(ins
->map()), useBox(ins
->value()), useRegister(ins
->hash()),
6970 temp(), temp(), temp(), temp());
6974 void LIRGenerator::visitMapObjectHasValueVMCall(MMapObjectHasValueVMCall
* ins
) {
6975 auto* lir
= new (alloc()) LMapObjectHasValueVMCall(
6976 useRegisterAtStart(ins
->map()), useBoxAtStart(ins
->value()));
6977 defineReturn(lir
, ins
);
6978 assignSafepoint(lir
, ins
);
6981 void LIRGenerator::visitMapObjectGetNonBigInt(MMapObjectGetNonBigInt
* ins
) {
6982 auto* lir
= new (alloc())
6983 LMapObjectGetNonBigInt(useRegister(ins
->map()), useBox(ins
->value()),
6984 useRegister(ins
->hash()), temp(), temp());
6985 defineBox(lir
, ins
);
6988 void LIRGenerator::visitMapObjectGetBigInt(MMapObjectGetBigInt
* ins
) {
6989 auto* lir
= new (alloc()) LMapObjectGetBigInt(
6990 useRegister(ins
->map()), useBox(ins
->value()), useRegister(ins
->hash()),
6991 temp(), temp(), temp(), temp());
6992 defineBox(lir
, ins
);
6995 void LIRGenerator::visitMapObjectGetValue(MMapObjectGetValue
* ins
) {
6996 auto* lir
= new (alloc()) LMapObjectGetValue(
6997 useRegister(ins
->map()), useBox(ins
->value()), useRegister(ins
->hash()),
6998 temp(), temp(), temp(), temp());
6999 defineBox(lir
, ins
);
7002 void LIRGenerator::visitMapObjectGetValueVMCall(MMapObjectGetValueVMCall
* ins
) {
7003 auto* lir
= new (alloc()) LMapObjectGetValueVMCall(
7004 useRegisterAtStart(ins
->map()), useBoxAtStart(ins
->value()));
7005 defineReturn(lir
, ins
);
7006 assignSafepoint(lir
, ins
);
7009 void LIRGenerator::visitMapObjectSize(MMapObjectSize
* ins
) {
7010 auto* lir
= new (alloc()) LMapObjectSize(useRegisterAtStart(ins
->map()));
7014 void LIRGenerator::visitConstant(MConstant
* ins
) {
7015 if (!IsFloatingPointType(ins
->type()) && ins
->canEmitAtUses()) {
7020 switch (ins
->type()) {
7021 case MIRType::Double
:
7022 define(new (alloc()) LDouble(ins
->toDouble()), ins
);
7024 case MIRType::Float32
:
7025 define(new (alloc()) LFloat32(ins
->toFloat32()), ins
);
7027 case MIRType::Boolean
:
7028 define(new (alloc()) LInteger(ins
->toBoolean()), ins
);
7030 case MIRType::Int32
:
7031 define(new (alloc()) LInteger(ins
->toInt32()), ins
);
7033 case MIRType::Int64
:
7034 defineInt64(new (alloc()) LInteger64(ins
->toInt64()), ins
);
7036 case MIRType::IntPtr
:
7038 defineInt64(new (alloc()) LInteger64(ins
->toIntPtr()), ins
);
7040 define(new (alloc()) LInteger(ins
->toIntPtr()), ins
);
7043 case MIRType::String
:
7044 define(new (alloc()) LPointer(ins
->toString()), ins
);
7046 case MIRType::Symbol
:
7047 define(new (alloc()) LPointer(ins
->toSymbol()), ins
);
7049 case MIRType::BigInt
:
7050 define(new (alloc()) LPointer(ins
->toBigInt()), ins
);
7052 case MIRType::Object
:
7053 define(new (alloc()) LPointer(&ins
->toObject()), ins
);
7055 case MIRType::Shape
:
7056 MOZ_ASSERT(ins
->isEmittedAtUses());
7059 // Constants of special types (undefined, null) should never flow into
7060 // here directly. Operations blindly consuming them require a Box.
7061 MOZ_CRASH("unexpected constant type");
7065 void LIRGenerator::visitConstantProto(MConstantProto
* ins
) {
7066 JSObject
* obj
= &ins
->protoObject()->toConstant()->toObject();
7067 define(new (alloc()) LPointer(obj
), ins
);
7070 void LIRGenerator::visitWasmNullConstant(MWasmNullConstant
* ins
) {
7071 define(new (alloc()) LWasmNullConstant(), ins
);
7074 void LIRGenerator::visitWasmFloatConstant(MWasmFloatConstant
* ins
) {
7075 switch (ins
->type()) {
7076 case MIRType::Double
:
7077 define(new (alloc()) LDouble(ins
->toDouble()), ins
);
7079 case MIRType::Float32
:
7080 define(new (alloc()) LFloat32(ins
->toFloat32()), ins
);
7082 #ifdef ENABLE_WASM_SIMD
7083 case MIRType::Simd128
:
7084 define(new (alloc()) LSimd128(ins
->toSimd128()), ins
);
7088 MOZ_CRASH("unexpected constant type");
7093 static void SpewResumePoint(MBasicBlock
* block
, MInstruction
* ins
,
7094 MResumePoint
* resumePoint
) {
7095 Fprinter
& out
= JitSpewPrinter();
7096 out
.printf("Current resume point %p details:\n", (void*)resumePoint
);
7097 out
.printf(" frame count: %u\n", resumePoint
->frameCount());
7100 out
.printf(" taken after: ");
7101 ins
->printName(out
);
7103 out
.printf(" taken at block %u entry", block
->id());
7107 out
.printf(" pc: %p (script: %p, offset: %d)\n", (void*)resumePoint
->pc(),
7108 (void*)resumePoint
->block()->info().script(),
7109 int(resumePoint
->block()->info().script()->pcToOffset(
7110 resumePoint
->pc())));
7112 for (size_t i
= 0, e
= resumePoint
->numOperands(); i
< e
; i
++) {
7113 MDefinition
* in
= resumePoint
->getOperand(i
);
7114 out
.printf(" slot%u: ", (unsigned)i
);
7121 void LIRGenerator::visitInstructionDispatch(MInstruction
* ins
) {
7122 #ifdef JS_CODEGEN_NONE
7123 // Don't compile the switch-statement below so that we don't have to define
7124 // the platform-specific visit* methods for the none-backend.
7127 switch (ins
->op()) {
7128 # define MIR_OP(op) \
7129 case MDefinition::Opcode::op: \
7130 visit##op(ins->to##op()); \
7132 MIR_OPCODE_LIST(MIR_OP
)
7135 MOZ_CRASH("Invalid instruction");
7140 void LIRGeneratorShared::visitEmittedAtUses(MInstruction
* ins
) {
7141 static_cast<LIRGenerator
*>(this)->visitInstructionDispatch(ins
);
7144 bool LIRGenerator::visitInstruction(MInstruction
* ins
) {
7145 MOZ_ASSERT(!errored());
7147 if (ins
->isRecoveredOnBailout()) {
7148 MOZ_ASSERT(!JitOptions
.disableRecoverIns
);
7152 if (!gen
->ensureBallast()) {
7155 visitInstructionDispatch(ins
);
7157 if (ins
->resumePoint()) {
7158 updateResumeState(ins
);
7162 ins
->setInWorklistUnchecked();
7165 // If no safepoint was created, there's no need for an OSI point.
7166 if (LOsiPoint
* osiPoint
= popOsiPoint()) {
7173 bool LIRGenerator::definePhis() {
7174 size_t lirIndex
= 0;
7175 MBasicBlock
* block
= current
->mir();
7176 for (MPhiIterator
phi(block
->phisBegin()); phi
!= block
->phisEnd(); phi
++) {
7177 if (phi
->type() == MIRType::Value
) {
7178 defineUntypedPhi(*phi
, lirIndex
);
7179 lirIndex
+= BOX_PIECES
;
7180 } else if (phi
->type() == MIRType::Int64
) {
7181 defineInt64Phi(*phi
, lirIndex
);
7182 lirIndex
+= INT64_PIECES
;
7184 defineTypedPhi(*phi
, lirIndex
);
7191 void LIRGenerator::updateResumeState(MInstruction
* ins
) {
7192 lastResumePoint_
= ins
->resumePoint();
7194 if (JitSpewEnabled(JitSpew_IonSnapshots
) && lastResumePoint_
) {
7195 SpewResumePoint(nullptr, ins
, lastResumePoint_
);
7200 void LIRGenerator::updateResumeState(MBasicBlock
* block
) {
7201 // Note: RangeAnalysis can flag blocks as unreachable, but they are only
7202 // removed iff GVN (including UCE) is enabled.
7203 MOZ_ASSERT_IF(!mir()->compilingWasm() && !block
->unreachable(),
7204 block
->entryResumePoint());
7205 MOZ_ASSERT_IF(block
->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7206 lastResumePoint_
= block
->entryResumePoint();
7208 if (JitSpewEnabled(JitSpew_IonSnapshots
) && lastResumePoint_
) {
7209 SpewResumePoint(block
, nullptr, lastResumePoint_
);
7214 bool LIRGenerator::visitBlock(MBasicBlock
* block
) {
7215 current
= block
->lir();
7216 updateResumeState(block
);
7218 if (!definePhis()) {
7222 MOZ_ASSERT_IF(block
->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7223 for (MInstructionIterator iter
= block
->begin(); *iter
!= block
->lastIns();
7225 if (!visitInstruction(*iter
)) {
7230 if (block
->successorWithPhis()) {
7231 // If we have a successor with phis, lower the phi input now that we
7232 // are approaching the join point.
7233 MBasicBlock
* successor
= block
->successorWithPhis();
7234 uint32_t position
= block
->positionInPhiSuccessor();
7235 size_t lirIndex
= 0;
7236 for (MPhiIterator
phi(successor
->phisBegin()); phi
!= successor
->phisEnd();
7238 if (!gen
->ensureBallast()) {
7242 MDefinition
* opd
= phi
->getOperand(position
);
7245 MOZ_ASSERT(opd
->type() == phi
->type());
7247 if (phi
->type() == MIRType::Value
) {
7248 lowerUntypedPhiInput(*phi
, position
, successor
->lir(), lirIndex
);
7249 lirIndex
+= BOX_PIECES
;
7250 } else if (phi
->type() == MIRType::Int64
) {
7251 lowerInt64PhiInput(*phi
, position
, successor
->lir(), lirIndex
);
7252 lirIndex
+= INT64_PIECES
;
7254 lowerTypedPhiInput(*phi
, position
, successor
->lir(), lirIndex
);
7260 // Now emit the last instruction, which is some form of branch.
7261 if (!visitInstruction(block
->lastIns())) {
7268 void LIRGenerator::visitNaNToZero(MNaNToZero
* ins
) {
7269 MDefinition
* input
= ins
->input();
7271 if (ins
->operandIsNeverNaN() && ins
->operandIsNeverNegativeZero()) {
7272 redefine(ins
, input
);
7276 new (alloc()) LNaNToZero(useRegisterAtStart(input
), tempDouble());
7277 defineReuseInput(lir
, ins
, 0);
7280 bool LIRGenerator::generate() {
7281 // Create all blocks and prep all phis beforehand.
7282 for (ReversePostorderIterator
block(graph
.rpoBegin());
7283 block
!= graph
.rpoEnd(); block
++) {
7284 if (gen
->shouldCancel("Lowering (preparation loop)")) {
7288 if (!lirGraph_
.initBlock(*block
)) {
7293 for (ReversePostorderIterator
block(graph
.rpoBegin());
7294 block
!= graph
.rpoEnd(); block
++) {
7295 if (gen
->shouldCancel("Lowering (main loop)")) {
7299 if (!visitBlock(*block
)) {
7304 lirGraph_
.setArgumentSlotCount(maxargslots_
);
7308 void LIRGenerator::visitPhi(MPhi
* phi
) {
7309 // Phi nodes are not lowered because they are only meaningful for the register
7311 MOZ_CRASH("Unexpected Phi node during Lowering.");
7314 void LIRGenerator::visitBeta(MBeta
* beta
) {
7315 // Beta nodes are supposed to be removed before because they are
7316 // only used to carry the range information for Range analysis
7317 MOZ_CRASH("Unexpected Beta node during Lowering.");
7320 void LIRGenerator::visitObjectState(MObjectState
* objState
) {
7321 // ObjectState nodes are always recovered on bailouts
7322 MOZ_CRASH("Unexpected ObjectState node during Lowering.");
7325 void LIRGenerator::visitArrayState(MArrayState
* objState
) {
7326 // ArrayState nodes are always recovered on bailouts
7327 MOZ_CRASH("Unexpected ArrayState node during Lowering.");
7330 void LIRGenerator::visitIonToWasmCall(MIonToWasmCall
* ins
) {
7331 // The instruction needs a temp register:
7332 // - that's not the FramePointer, since wasm is going to use it in the
7334 // - that's not aliasing an input register.
7335 LDefinition scratch
= tempFixed(ABINonArgReg0
);
7337 // Note that since this is a LIR call instruction, regalloc will prevent
7338 // the use*AtStart below from reusing any of the temporaries.
7341 if (ins
->type() == MIRType::Value
) {
7342 lir
= allocateVariadic
<LIonToWasmCallV
>(ins
->numOperands(), scratch
);
7343 } else if (ins
->type() == MIRType::Int64
) {
7344 lir
= allocateVariadic
<LIonToWasmCallI64
>(ins
->numOperands(), scratch
);
7346 lir
= allocateVariadic
<LIonToWasmCall
>(ins
->numOperands(), scratch
);
7349 abort(AbortReason::Alloc
, "OOM: LIRGenerator::visitIonToWasmCall");
7353 ABIArgGenerator abi
;
7354 for (unsigned i
= 0; i
< ins
->numOperands(); i
++) {
7355 MDefinition
* argDef
= ins
->getOperand(i
);
7356 ABIArg arg
= abi
.next(ToMIRType(argDef
->type()));
7357 switch (arg
.kind()) {
7360 lir
->setOperand(i
, useFixedAtStart(argDef
, arg
.reg()));
7363 lir
->setOperand(i
, useAtStart(argDef
));
7365 #ifdef JS_CODEGEN_REGISTER_PAIR
7366 case ABIArg::GPR_PAIR
:
7368 "no way to pass i64, and wasm uses hardfp for function calls");
7370 case ABIArg::Uninitialized
:
7371 MOZ_CRASH("Uninitialized ABIArg kind");
7375 defineReturn(lir
, ins
);
7376 assignSafepoint(lir
, ins
);
7379 void LIRGenerator::visitWasmSelect(MWasmSelect
* ins
) {
7380 MDefinition
* condExpr
= ins
->condExpr();
7382 // Pick off specific cases that we can do with LWasmCompareAndSelect to avoid
7383 // generating a boolean that we then have to test again.
7384 if (condExpr
->isCompare() && condExpr
->isEmittedAtUses()) {
7385 MCompare
* comp
= condExpr
->toCompare();
7386 MCompare::CompareType compTy
= comp
->compareType();
7387 if (canSpecializeWasmCompareAndSelect(compTy
, ins
->type())) {
7388 JSOp jsop
= comp
->jsop();
7389 // We don't currently generate any other JSOPs for the comparison, and if
7390 // that changes, we want to know about it. Hence this assertion.
7391 MOZ_ASSERT(jsop
== JSOp::Eq
|| jsop
== JSOp::Ne
|| jsop
== JSOp::Lt
||
7392 jsop
== JSOp::Gt
|| jsop
== JSOp::Le
|| jsop
== JSOp::Ge
);
7393 MDefinition
* lhs
= comp
->lhs();
7394 MDefinition
* rhs
= comp
->rhs();
7395 jsop
= ReorderComparison(jsop
, &lhs
, &rhs
);
7396 lowerWasmCompareAndSelect(ins
, lhs
, rhs
, compTy
, jsop
);
7400 // Fall through to code that generates a boolean and selects on that.
7402 if (ins
->type() == MIRType::Int64
) {
7403 lowerWasmSelectI64(ins
);
7407 lowerWasmSelectI(ins
);
7410 void LIRGenerator::visitWasmFence(MWasmFence
* ins
) {
7411 add(new (alloc()) LWasmFence
, ins
);
7414 void LIRGenerator::visitWasmLoadField(MWasmLoadField
* ins
) {
7415 uint32_t offs
= ins
->offset();
7416 LAllocation obj
= useRegister(ins
->obj());
7417 MWideningOp wideningOp
= ins
->wideningOp();
7418 if (ins
->type() == MIRType::Int64
) {
7419 MOZ_RELEASE_ASSERT(wideningOp
== MWideningOp::None
);
7420 defineInt64(new (alloc()) LWasmLoadSlotI64(obj
, offs
, ins
->maybeTrap()),
7423 define(new (alloc()) LWasmLoadSlot(obj
, offs
, ins
->type(), wideningOp
,
7429 void LIRGenerator::visitWasmLoadFieldKA(MWasmLoadFieldKA
* ins
) {
7430 uint32_t offs
= ins
->offset();
7431 LAllocation obj
= useRegister(ins
->obj());
7432 MWideningOp wideningOp
= ins
->wideningOp();
7433 if (ins
->type() == MIRType::Int64
) {
7434 MOZ_RELEASE_ASSERT(wideningOp
== MWideningOp::None
);
7435 defineInt64(new (alloc()) LWasmLoadSlotI64(obj
, offs
, ins
->maybeTrap()),
7438 define(new (alloc()) LWasmLoadSlot(obj
, offs
, ins
->type(), wideningOp
,
7442 add(new (alloc()) LKeepAliveObject(useKeepalive(ins
->ka())), ins
);
7445 void LIRGenerator::visitWasmStoreFieldKA(MWasmStoreFieldKA
* ins
) {
7446 MDefinition
* value
= ins
->value();
7447 uint32_t offs
= ins
->offset();
7448 MNarrowingOp narrowingOp
= ins
->narrowingOp();
7449 LAllocation obj
= useRegister(ins
->obj());
7451 if (value
->type() == MIRType::Int64
) {
7452 MOZ_RELEASE_ASSERT(narrowingOp
== MNarrowingOp::None
);
7454 LWasmStoreSlotI64(useInt64Register(value
), obj
, offs
, ins
->maybeTrap());
7457 LWasmStoreSlot(useRegister(value
), obj
, offs
, value
->type(),
7458 narrowingOp
, ins
->maybeTrap());
7461 add(new (alloc()) LKeepAliveObject(useKeepalive(ins
->ka())), ins
);
7464 void LIRGenerator::visitWasmStoreFieldRefKA(MWasmStoreFieldRefKA
* ins
) {
7465 LAllocation instance
= useRegister(ins
->instance());
7466 LAllocation obj
= useFixed(ins
->obj(), PreBarrierReg
);
7467 LAllocation value
= useRegister(ins
->value());
7468 uint32_t offset
= ins
->offset();
7469 add(new (alloc()) LWasmStoreRef(instance
, obj
, value
, temp(), offset
,
7470 ins
->maybeTrap(), ins
->preBarrierKind()),
7472 add(new (alloc()) LKeepAliveObject(useKeepalive(ins
->ka())), ins
);
7475 void LIRGenerator::visitWasmRefIsSubtypeOfAbstract(
7476 MWasmRefIsSubtypeOfAbstract
* ins
) {
7477 if (CanEmitAtUseForSingleTest(ins
)) {
7482 LAllocation ref
= useRegister(ins
->ref());
7483 LDefinition scratch1
= LDefinition();
7484 if (ins
->destType().isAnyHierarchy()) {
7485 // See comment on MacroAssembler::branchWasmRefIsSubtypeAny.
7486 // We know we do not need scratch2 and superSTV because we know
7487 // this is not a concrete type.
7488 MOZ_ASSERT(!MacroAssembler::needSuperSTVForBranchWasmRefIsSubtypeAny(
7490 MOZ_ASSERT(!MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
7493 scratch1
= MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
7497 } else if (ins
->destType().isFuncHierarchy()) {
7498 // See comment on MacroAssembler::branchWasmRefIsSubtypeFunc.
7499 // We know we do not need any supertype vectors or scratch registers because
7500 // this is not a concrete cast.
7502 !MacroAssembler::needSuperSTVAndScratch1ForBranchWasmRefIsSubtypeFunc(
7504 MOZ_ASSERT(!MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
7506 } else if (ins
->destType().isExternHierarchy()) {
7507 // no scratch registers needed for casts in the extern hierarchy
7509 MOZ_CRASH("unknown type hierarchy for abstract cast");
7512 define(new (alloc()) LWasmRefIsSubtypeOfAbstract(ref
, scratch1
), ins
);
7515 void LIRGenerator::visitWasmRefIsSubtypeOfConcrete(
7516 MWasmRefIsSubtypeOfConcrete
* ins
) {
7517 if (CanEmitAtUseForSingleTest(ins
)) {
7522 // This gets a bit wild because it needs to handle concrete casts in all
7523 // hierarchies. Supertype vectors are always required (that's what concrete
7524 // means) but the scratch registers can vary.
7526 LAllocation ref
= useRegister(ins
->ref());
7527 LAllocation superSTV
= useRegister(ins
->superSTV());
7528 LDefinition scratch1
= LDefinition();
7529 LDefinition scratch2
= LDefinition();
7530 if (ins
->destType().isAnyHierarchy()) {
7531 // See comment on MacroAssembler::branchWasmRefIsSubtypeAny.
7532 // We know we need scratch1 because we know this is a concrete type.
7533 MOZ_ASSERT(MacroAssembler::needSuperSTVForBranchWasmRefIsSubtypeAny(
7535 MOZ_ASSERT(MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
7538 scratch2
= MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
7542 } else if (ins
->destType().isFuncHierarchy()) {
7543 // See comment on MacroAssembler::branchWasmRefIsSubtypeFunc.
7544 // We know we need scratch1 because we know this is a concrete type.
7546 MacroAssembler::needSuperSTVAndScratch1ForBranchWasmRefIsSubtypeFunc(
7549 scratch2
= MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
7553 } else if (ins
->destType().isExternHierarchy()) {
7554 MOZ_CRASH("concrete casts are impossible in the extern hierarchy");
7556 MOZ_CRASH("unknown type hierarchy for concrete cast");
7559 define(new (alloc())
7560 LWasmRefIsSubtypeOfConcrete(ref
, superSTV
, scratch1
, scratch2
),
7564 void LIRGenerator::visitWasmNewStructObject(MWasmNewStructObject
* ins
) {
7565 LWasmNewStructObject
* lir
= new (alloc())
7566 LWasmNewStructObject(useFixed(ins
->instance(), InstanceReg
),
7567 useRegister(ins
->typeDefData()), temp(), temp());
7569 assignWasmSafepoint(lir
);
7572 #ifdef FUZZING_JS_FUZZILLI
7573 void LIRGenerator::visitFuzzilliHash(MFuzzilliHash
* ins
) {
7574 MDefinition
* value
= ins
->getOperand(0);
7576 if (value
->type() == MIRType::Undefined
|| value
->type() == MIRType::Null
) {
7577 define(new (alloc()) LFuzzilliHashT(LAllocation(), temp(), tempDouble()),
7579 } else if (value
->type() == MIRType::Int32
||
7580 value
->type() == MIRType::Double
||
7581 value
->type() == MIRType::Float32
||
7582 value
->type() == MIRType::Boolean
||
7583 value
->type() == MIRType::BigInt
) {
7584 define(new (alloc())
7585 LFuzzilliHashT(useRegister(value
), temp(), tempDouble()),
7587 } else if (value
->type() == MIRType::Object
) {
7588 LFuzzilliHashT
* lir
=
7589 new (alloc()) LFuzzilliHashT(useRegister(value
), temp(), tempDouble());
7591 assignSafepoint(lir
, ins
);
7592 } else if (value
->type() == MIRType::Value
) {
7593 LFuzzilliHashV
* lir
=
7594 new (alloc()) LFuzzilliHashV(useBox(value
), temp(), tempDouble());
7596 assignSafepoint(lir
, ins
);
7598 define(new (alloc()) LInteger(0), ins
);
7602 void LIRGenerator::visitFuzzilliHashStore(MFuzzilliHashStore
* ins
) {
7603 MDefinition
* value
= ins
->getOperand(0);
7604 MOZ_ASSERT(value
->type() == MIRType::Int32
);
7605 add(new (alloc()) LFuzzilliHashStore(useRegister(value
), temp(), temp()),
7610 static_assert(!std::is_polymorphic_v
<LIRGenerator
>,
7611 "LIRGenerator should not have any virtual methods");
7613 #ifdef JS_CODEGEN_NONE
7614 void LIRGenerator::visitReturnImpl(MDefinition
*, bool) { MOZ_CRASH(); }