Bug 1885489 - Part 5: Add SnapshotIterator::readInt32(). r=iain
[gecko.git] / js / src / jit / Lowering.cpp
blob46b738a65937ae3098dca6481298d92a098fe9df
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"
20 #include "jit/LIR.h"
21 #include "jit/MacroAssembler.h"
22 #include "jit/MIR.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"
34 using namespace js;
35 using namespace jit;
37 using JS::GenericNaN;
38 using mozilla::DebugOnly;
40 LBoxAllocation LIRGenerator::useBoxFixedAtStart(MDefinition* mir,
41 ValueOperand op) {
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);
46 #endif
49 LBoxAllocation LIRGenerator::useBoxAtStart(MDefinition* mir,
50 LUse::Policy policy) {
51 return useBox(mir, policy, /* useAtStart = */ true);
54 void LIRGenerator::visitParameter(MParameter* param) {
55 ptrdiff_t offset;
56 if (param->index() == MParameter::THIS_SLOT) {
57 offset = THIS_FRAME_ARGSLOT;
58 } else {
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)
67 # if MOZ_BIG_ENDIAN()
68 ins->getDef(0)->setOutput(LArgument(offset));
69 ins->getDef(1)->setOutput(LArgument(offset + 4));
70 # else
71 ins->getDef(0)->setOutput(LArgument(offset + 4));
72 ins->getDef(1)->setOutput(LArgument(offset));
73 # endif
74 #elif defined(JS_PUNBOX64)
75 ins->getDef(0)->setOutput(LArgument(offset));
76 #endif
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()));
100 return;
103 // If we don't know the type.
104 if (opd->type() == MIRType::Value) {
105 LTableSwitchV* lir = newLTableSwitchV(tableswitch);
106 add(lir);
107 return;
110 // Case indices are numeric, so other types will always go to the default
111 // case.
112 if (opd->type() != MIRType::Int32 && opd->type() != MIRType::Double) {
113 add(new (alloc()) LGoto(tableswitch->getDefault()));
114 return;
117 // Return an LTableSwitch, capable of handling either an integer or
118 // floating-point index.
119 LAllocation index;
120 LDefinition tempInt;
121 if (opd->type() == MIRType::Int32) {
122 index = useRegisterAtStart(opd);
123 tempInt = tempCopy(opd, 0);
124 } else {
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();
133 add(lir, ins);
134 assignSafepoint(lir, ins);
137 void LIRGenerator::visitNewArray(MNewArray* ins) {
138 LNewArray* lir = new (alloc()) LNewArray(temp());
139 define(lir, ins);
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());
149 define(lir, ins);
150 assignSafepoint(lir, ins);
153 void LIRGenerator::visitNewIterator(MNewIterator* ins) {
154 LNewIterator* lir = new (alloc()) LNewIterator(temp());
155 define(lir, ins);
156 assignSafepoint(lir, ins);
159 void LIRGenerator::visitNewTypedArray(MNewTypedArray* ins) {
160 LNewTypedArray* lir = new (alloc()) LNewTypedArray(temp(), temp());
161 define(lir, ins);
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());
172 define(lir, ins);
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());
203 define(lir, ins);
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");
213 return;
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());
225 define(lir, ins);
226 assignSafepoint(lir, ins);
229 void LIRGenerator::visitNewPlainObject(MNewPlainObject* ins) {
230 LNewPlainObject* lir = new (alloc()) LNewPlainObject(temp(), temp(), temp());
231 define(lir, ins);
232 assignSafepoint(lir, ins);
235 void LIRGenerator::visitNewArrayObject(MNewArrayObject* ins) {
236 LNewArrayObject* lir = new (alloc()) LNewArrayObject(temp(), temp());
237 define(lir, ins);
238 assignSafepoint(lir, ins);
241 void LIRGenerator::visitNewNamedLambdaObject(MNewNamedLambdaObject* ins) {
242 LNewNamedLambdaObject* lir = new (alloc()) LNewNamedLambdaObject(temp());
243 define(lir, ins);
244 assignSafepoint(lir, ins);
247 void LIRGenerator::visitNewCallObject(MNewCallObject* ins) {
248 LNewCallObject* lir = new (alloc()) LNewCallObject(temp());
249 define(lir, ins);
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());
258 define(lir, ins);
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()));
266 add(lir, ins);
267 assignSafepoint(lir, ins);
270 void LIRGenerator::visitMutateProto(MMutateProto* ins) {
271 LMutateProto* lir = new (alloc()) LMutateProto(
272 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()));
273 add(lir, ins);
274 assignSafepoint(lir, ins);
277 void LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter* ins) {
278 LInitPropGetterSetter* lir = new (alloc()) LInitPropGetterSetter(
279 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->value()));
280 add(lir, ins);
281 assignSafepoint(lir, ins);
284 void LIRGenerator::visitCreateThis(MCreateThis* ins) {
285 LCreateThis* lir =
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));
311 if (!lir) {
312 abort(AbortReason::Alloc,
313 "OOM: LIRGenerator::visitCreateInlinedArgumentsObject");
314 return;
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;
338 #else
339 const bool useAtStart = true;
340 #endif
342 LAllocation index =
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);
349 if (!lir) {
350 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgument");
351 return;
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);
358 lir->setBoxOperand(
359 index, useBoxOrTypedOrConstant(arg,
360 /*useConstant = */ true, useAtStart));
362 defineBox(lir, ins);
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;
372 #else
373 const bool useAtStart = true;
374 #endif
376 LAllocation index =
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);
383 if (!lir) {
384 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgumentHole");
385 return;
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);
392 lir->setBoxOperand(
393 index, useBoxOrTypedOrConstant(arg,
394 /*useConstant = */ true, useAtStart));
396 assignSnapshot(lir, ins->bailoutKind());
397 defineBox(lir, ins);
400 void LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins) {
401 LAllocation argsObj = useRegister(ins->argsObject());
402 LGetArgumentsObjectArg* lir =
403 new (alloc()) LGetArgumentsObjectArg(argsObj, temp());
404 defineBox(lir, ins);
407 void LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins) {
408 LAllocation argsObj = useRegister(ins->argsObject());
409 LSetArgumentsObjectArg* lir = new (alloc())
410 LSetArgumentsObjectArg(argsObj, useBox(ins->value()), temp());
411 add(lir, ins);
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());
424 defineBox(lir, ins);
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());
438 defineBox(lir, ins);
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());
451 define(lir, ins);
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());
460 define(lir, ins);
463 void LIRGenerator::visitArrayFromArgumentsObject(
464 MArrayFromArgumentsObject* ins) {
465 MDefinition* argsObj = ins->argsObject();
466 MOZ_ASSERT(argsObj->type() == MIRType::Object);
468 auto* lir =
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);
479 auto* lir =
480 new (alloc()) LGuardArgumentsObjectFlags(useRegister(argsObj), temp());
481 assignSnapshot(lir, ins->bailoutKind());
482 add(lir, ins);
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));
491 define(lir, ins);
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());
501 add(lir, ins);
502 redefine(ins, ins->object());
505 void LIRGenerator::visitReturnFromCtor(MReturnFromCtor* ins) {
506 LReturnFromCtor* lir = new (alloc())
507 LReturnFromCtor(useBox(ins->value()), useRegister(ins->object()));
508 define(lir, ins);
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()));
516 define(lir, ins);
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);
538 } else {
539 baseSlot = argc;
542 // Save the maximum number of argument, such that we can have one unique
543 // frame size.
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);
555 add(stack);
556 } else {
557 // Known types can move constant types and/or payloads.
558 LStackArgT* stack = new (alloc())
559 LStackArgT(useRegisterOrConstant(arg), argslot, arg->type());
560 add(stack);
563 if (!alloc().ensureBallast()) {
564 return false;
567 return true;
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");
576 return;
579 WrappedFunction* target = call->getSingleTarget();
581 LInstruction* lir;
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));
594 } else if (target) {
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));
609 } else {
610 lir = new (alloc()) LCallKnown(useRegisterAtStart(call->getCallee()),
611 tempFixed(CallTempReg0));
613 } else {
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");
630 return;
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());
766 add(lir, bail);
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());
777 add(lir, mir);
780 void LIRGenerator::visitUnreachableResult(MUnreachableResult* mir) {
781 if (mir->type() == MIRType::Value) {
782 auto* lir = new (alloc()) LUnreachableResultV();
783 defineBox(lir, mir);
784 } else {
785 auto* lir = new (alloc()) LUnreachableResultT();
786 define(lir, mir);
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()) {
811 *rhsp = lhs;
812 *lhsp = rhs;
813 return ReverseCompareOp(op);
815 return 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
824 // TestPolicy).
825 MOZ_ASSERT(opd->type() != MIRType::String);
827 // Testing a constant.
828 if (MConstant* constant = opd->maybeConstantValue()) {
829 bool b;
830 if (constant->valueToBoolean(&b)) {
831 add(new (alloc()) LGoto(b ? ifTrue : ifFalse));
832 return;
836 if (opd->type() == MIRType::Value) {
837 auto* lir = new (alloc()) LTestVAndBranch(
838 ifTrue, ifFalse, useBox(opd), tempDouble(), tempToUnbox(), temp());
839 add(lir, test);
840 return;
843 // Objects are truthy, except if it might emulate undefined.
844 if (opd->type() == MIRType::Object) {
845 add(new (alloc())
846 LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp()),
847 test);
848 return;
851 // These must be explicitly sniffed out since they are constants and have
852 // no payload.
853 if (opd->type() == MIRType::Undefined || opd->type() == MIRType::Null) {
854 add(new (alloc()) LGoto(ifFalse));
855 return;
858 // All symbols are truthy.
859 if (opd->type() == MIRType::Symbol) {
860 add(new (alloc()) LGoto(ifTrue));
861 return;
864 // Try to match the pattern
865 // test=MTest(
866 // comp=MCompare(
867 // {EQ,NE} for {Int,UInt}{32,64},
868 // bitAnd={MBitAnd,MWasmBinaryBitwise(And{32,64})}(x, y),
869 // MConstant(0)
870 // )
871 // )
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()) {
877 #ifdef JS_64BIT
878 constexpr bool targetIs64 = true;
879 #else
880 constexpr bool targetIs64 = false;
881 #endif
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;
913 } else {
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);
921 return;
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.
935 bool result;
936 if (comp->tryFold(&result)) {
937 add(new (alloc()) LGoto(result ? ifTrue : ifFalse));
938 return;
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());
951 add(lir, test);
952 return;
955 if (IsLooseEqualityOp(comp->jsop())) {
956 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchV(
957 comp, ifTrue, ifFalse, useBox(left), temp(), tempToUnbox());
958 add(lir, test);
959 return;
962 if (comp->compareType() == MCompare::Compare_Null) {
963 auto* lir =
964 new (alloc()) LIsNullAndBranch(comp, ifTrue, ifFalse, useBox(left));
965 add(lir, test);
966 return;
969 auto* lir = new (alloc())
970 LIsUndefinedAndBranch(comp, ifTrue, ifFalse, useBox(left));
971 add(lir, test);
972 return;
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);
984 LAllocation rhs;
985 if (comp->isInt32Comparison() ||
986 comp->compareType() == MCompare::Compare_UInt32 ||
987 comp->compareType() == MCompare::Compare_UIntPtr) {
988 rhs = useAnyOrInt32Constant(right);
989 } else {
990 rhs = useAny(right);
992 LCompareAndBranch* lir =
993 new (alloc()) LCompareAndBranch(comp, op, lhs, rhs, ifTrue, ifFalse);
994 add(lir, test);
995 return;
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);
1003 return;
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);
1012 add(lir, test);
1013 return;
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);
1022 add(lir, test);
1023 return;
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,
1035 /*is64=*/false),
1036 test, lhs, rhs);
1037 return;
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())) {
1050 # ifdef DEBUG
1051 js::wasm::ReportSimdAnalysis("simd128-to-scalar-and-branch -> folded");
1052 # endif
1053 auto* lir = new (alloc()) LWasmReduceAndBranchSimd128(
1054 useRegister(node->input()), node->simdOp(), ifTrue, ifFalse);
1055 add(lir, test);
1056 return;
1059 #endif
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));
1067 add(lir, test);
1068 return;
1071 if (opd->isWasmRefIsSubtypeOfAbstract() && opd->isEmittedAtUses()) {
1072 MWasmRefIsSubtypeOfAbstract* isSubTypeOf =
1073 opd->toWasmRefIsSubtypeOfAbstract();
1075 LAllocation ref = useRegister(isSubTypeOf->ref());
1076 WasmRefIsSubtypeDefs regs =
1077 useWasmRefIsSubtype(isSubTypeOf->destType(), /*superSTV=*/nullptr);
1078 add(new (alloc()) LWasmRefIsSubtypeOfAbstractAndBranch(
1079 ifTrue, ifFalse, isSubTypeOf->sourceType(), isSubTypeOf->destType(),
1080 ref, regs.scratch1),
1081 test);
1082 return;
1085 if (opd->isWasmRefIsSubtypeOfConcrete() && opd->isEmittedAtUses()) {
1086 MWasmRefIsSubtypeOfConcrete* isSubTypeOf =
1087 opd->toWasmRefIsSubtypeOfConcrete();
1089 LAllocation ref = useRegister(isSubTypeOf->ref());
1090 WasmRefIsSubtypeDefs regs =
1091 useWasmRefIsSubtype(isSubTypeOf->destType(), isSubTypeOf->superSTV());
1092 add(new (alloc()) LWasmRefIsSubtypeOfConcreteAndBranch(
1093 ifTrue, ifFalse, isSubTypeOf->sourceType(), isSubTypeOf->destType(),
1094 ref, regs.superSTV, regs.scratch1, regs.scratch2),
1095 test);
1096 return;
1099 if (opd->isIsNullOrUndefined() && opd->isEmittedAtUses()) {
1100 MIsNullOrUndefined* isNullOrUndefined = opd->toIsNullOrUndefined();
1101 MDefinition* input = isNullOrUndefined->value();
1103 if (input->type() == MIRType::Value) {
1104 auto* lir = new (alloc()) LIsNullOrUndefinedAndBranch(
1105 isNullOrUndefined, ifTrue, ifFalse, useBoxAtStart(input));
1106 add(lir, test);
1107 } else {
1108 auto* target = IsNullOrUndefined(input->type()) ? ifTrue : ifFalse;
1109 add(new (alloc()) LGoto(target));
1111 return;
1114 if (opd->isIsNoIter()) {
1115 MOZ_ASSERT(opd->isEmittedAtUses());
1117 MDefinition* input = opd->toIsNoIter()->input();
1118 MOZ_ASSERT(input->type() == MIRType::Value);
1120 LIsNoIterAndBranch* lir =
1121 new (alloc()) LIsNoIterAndBranch(ifTrue, ifFalse, useBox(input));
1122 add(lir, test);
1123 return;
1126 if (opd->isIteratorHasIndices()) {
1127 MOZ_ASSERT(opd->isEmittedAtUses());
1129 MDefinition* object = opd->toIteratorHasIndices()->object();
1130 MDefinition* iterator = opd->toIteratorHasIndices()->iterator();
1131 LIteratorHasIndicesAndBranch* lir = new (alloc())
1132 LIteratorHasIndicesAndBranch(ifTrue, ifFalse, useRegister(object),
1133 useRegister(iterator), temp(), temp());
1134 add(lir, test);
1135 return;
1138 switch (opd->type()) {
1139 case MIRType::Double:
1140 add(new (alloc()) LTestDAndBranch(useRegister(opd), ifTrue, ifFalse));
1141 break;
1142 case MIRType::Float32:
1143 add(new (alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse));
1144 break;
1145 case MIRType::Int32:
1146 case MIRType::Boolean:
1147 add(new (alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse));
1148 break;
1149 case MIRType::Int64:
1150 add(new (alloc())
1151 LTestI64AndBranch(useInt64Register(opd), ifTrue, ifFalse));
1152 break;
1153 case MIRType::BigInt:
1154 add(new (alloc()) LTestBIAndBranch(useRegister(opd), ifTrue, ifFalse));
1155 break;
1156 default:
1157 MOZ_CRASH("Bad type");
1161 static inline bool CanEmitCompareAtUses(MInstruction* ins) {
1162 if (!ins->canEmitAtUses()) {
1163 return false;
1166 // If the result is never used, we can usefully defer emission to the use
1167 // point, since that will never happen.
1168 MUseIterator iter(ins->usesBegin());
1169 if (iter == ins->usesEnd()) {
1170 return true;
1173 // If the first use isn't of the expected form, the answer is No.
1174 MNode* node = iter->consumer();
1175 if (!node->isDefinition()) {
1176 return false;
1179 MDefinition* use = node->toDefinition();
1180 if (!use->isTest() && !use->isWasmSelect()) {
1181 return false;
1184 // Emission can be deferred to the first use point, but only if there are no
1185 // other use points.
1186 iter++;
1187 return iter == ins->usesEnd();
1190 void LIRGenerator::visitCompare(MCompare* comp) {
1191 MDefinition* left = comp->lhs();
1192 MDefinition* right = comp->rhs();
1194 // Try to fold the comparison so that we don't have to handle all cases.
1195 bool result;
1196 if (comp->tryFold(&result)) {
1197 define(new (alloc()) LInteger(result), comp);
1198 return;
1201 // Move below the emitAtUses call if we ever implement
1202 // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't
1203 // make sense and avoids confusion.
1204 if (comp->compareType() == MCompare::Compare_String) {
1205 MConstant* constant = nullptr;
1206 MDefinition* input = nullptr;
1207 if (left->isConstant()) {
1208 constant = left->toConstant();
1209 input = right;
1210 } else if (right->isConstant()) {
1211 constant = right->toConstant();
1212 input = left;
1215 if (constant) {
1216 JSLinearString* linear = &constant->toString()->asLinear();
1218 if (IsEqualityOp(comp->jsop())) {
1219 if (MacroAssembler::canCompareStringCharsInline(linear)) {
1220 auto* lir = new (alloc()) LCompareSInline(useRegister(input), linear);
1221 define(lir, comp);
1222 assignSafepoint(lir, comp);
1223 return;
1225 } else {
1226 MOZ_ASSERT(IsRelationalOp(comp->jsop()));
1228 if (linear->length() == 1) {
1229 // Move the constant value into the right-hand side operand.
1230 JSOp op = comp->jsop();
1231 if (left == constant) {
1232 op = ReverseCompareOp(op);
1235 auto* lir = new (alloc())
1236 LCompareSSingle(useRegister(input), temp(), op, linear);
1237 define(lir, comp);
1238 return;
1243 LCompareS* lir =
1244 new (alloc()) LCompareS(useRegister(left), useRegister(right));
1245 define(lir, comp);
1246 assignSafepoint(lir, comp);
1247 return;
1250 // Compare two BigInts.
1251 if (comp->compareType() == MCompare::Compare_BigInt) {
1252 auto* lir = new (alloc()) LCompareBigInt(
1253 useRegister(left), useRegister(right), temp(), temp(), temp());
1254 define(lir, comp);
1255 return;
1258 // Compare BigInt with Int32.
1259 if (comp->compareType() == MCompare::Compare_BigInt_Int32) {
1260 auto* lir = new (alloc()) LCompareBigIntInt32(
1261 useRegister(left), useRegister(right), temp(), temp());
1262 define(lir, comp);
1263 return;
1266 // Compare BigInt with Double.
1267 if (comp->compareType() == MCompare::Compare_BigInt_Double) {
1268 auto* lir = new (alloc()) LCompareBigIntDouble(useRegisterAtStart(left),
1269 useRegisterAtStart(right));
1270 defineReturn(lir, comp);
1271 return;
1274 // Compare BigInt with String.
1275 if (comp->compareType() == MCompare::Compare_BigInt_String) {
1276 auto* lir = new (alloc()) LCompareBigIntString(useRegisterAtStart(left),
1277 useRegisterAtStart(right));
1278 defineReturn(lir, comp);
1279 assignSafepoint(lir, comp);
1280 return;
1283 // Sniff out if the output of this compare is used only for a branching.
1284 // If it is, then we will emit an LCompare*AndBranch instruction in place
1285 // of this compare and any test that uses this compare. Thus, we can
1286 // ignore this Compare.
1287 if (CanEmitCompareAtUses(comp)) {
1288 emitAtUses(comp);
1289 return;
1292 // Compare Null and Undefined.
1293 if (comp->compareType() == MCompare::Compare_Null ||
1294 comp->compareType() == MCompare::Compare_Undefined) {
1295 if (left->type() == MIRType::Object) {
1296 define(new (alloc()) LIsNullOrLikeUndefinedT(useRegister(left)), comp);
1297 return;
1300 if (IsLooseEqualityOp(comp->jsop())) {
1301 auto* lir =
1302 new (alloc()) LIsNullOrLikeUndefinedV(useBox(left), tempToUnbox());
1303 define(lir, comp);
1304 return;
1307 if (comp->compareType() == MCompare::Compare_Null) {
1308 auto* lir = new (alloc()) LIsNull(useBox(left));
1309 define(lir, comp);
1310 return;
1313 auto* lir = new (alloc()) LIsUndefined(useBox(left));
1314 define(lir, comp);
1315 return;
1318 // Compare Int32, Symbol, Object or Wasm pointers.
1319 if (comp->isInt32Comparison() ||
1320 comp->compareType() == MCompare::Compare_UInt32 ||
1321 comp->compareType() == MCompare::Compare_UIntPtr ||
1322 comp->compareType() == MCompare::Compare_Object ||
1323 comp->compareType() == MCompare::Compare_Symbol ||
1324 comp->compareType() == MCompare::Compare_WasmAnyRef) {
1325 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1326 LAllocation lhs = useRegister(left);
1327 LAllocation rhs;
1328 if (comp->isInt32Comparison() ||
1329 comp->compareType() == MCompare::Compare_UInt32 ||
1330 comp->compareType() == MCompare::Compare_UIntPtr) {
1331 rhs = useAnyOrInt32Constant(right);
1332 } else {
1333 rhs = useAny(right);
1335 define(new (alloc()) LCompare(op, lhs, rhs), comp);
1336 return;
1339 // Compare Int64.
1340 if (comp->compareType() == MCompare::Compare_Int64 ||
1341 comp->compareType() == MCompare::Compare_UInt64) {
1342 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1343 define(new (alloc()) LCompareI64(op, useInt64Register(left),
1344 useInt64OrConstant(right)),
1345 comp);
1346 return;
1349 // Compare doubles.
1350 if (comp->isDoubleComparison()) {
1351 define(new (alloc()) LCompareD(useRegister(left), useRegister(right)),
1352 comp);
1353 return;
1356 // Compare float32.
1357 if (comp->isFloat32Comparison()) {
1358 define(new (alloc()) LCompareF(useRegister(left), useRegister(right)),
1359 comp);
1360 return;
1363 MOZ_CRASH("Unrecognized compare type.");
1366 void LIRGenerator::visitSameValueDouble(MSameValueDouble* ins) {
1367 MDefinition* lhs = ins->lhs();
1368 MDefinition* rhs = ins->rhs();
1370 MOZ_ASSERT(lhs->type() == MIRType::Double);
1371 MOZ_ASSERT(rhs->type() == MIRType::Double);
1373 auto* lir = new (alloc())
1374 LSameValueDouble(useRegister(lhs), useRegister(rhs), tempDouble());
1375 define(lir, ins);
1378 void LIRGenerator::visitSameValue(MSameValue* ins) {
1379 MDefinition* lhs = ins->lhs();
1380 MDefinition* rhs = ins->rhs();
1382 MOZ_ASSERT(lhs->type() == MIRType::Value);
1383 MOZ_ASSERT(rhs->type() == MIRType::Value);
1385 auto* lir = new (alloc()) LSameValue(useBox(lhs), useBox(rhs));
1386 define(lir, ins);
1387 assignSafepoint(lir, ins);
1390 void LIRGenerator::lowerBitOp(JSOp op, MBinaryInstruction* ins) {
1391 MDefinition* lhs = ins->getOperand(0);
1392 MDefinition* rhs = ins->getOperand(1);
1393 MOZ_ASSERT(IsIntType(ins->type()));
1395 if (ins->type() == MIRType::Int32) {
1396 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1397 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1398 ReorderCommutative(&lhs, &rhs, ins);
1399 lowerForALU(new (alloc()) LBitOpI(op), ins, lhs, rhs);
1400 return;
1403 if (ins->type() == MIRType::Int64) {
1404 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1405 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1406 ReorderCommutative(&lhs, &rhs, ins);
1407 lowerForALUInt64(new (alloc()) LBitOpI64(op), ins, lhs, rhs);
1408 return;
1411 MOZ_CRASH("Unhandled integer specialization");
1414 void LIRGenerator::visitTypeOf(MTypeOf* ins) {
1415 MDefinition* opd = ins->input();
1417 if (opd->type() == MIRType::Object) {
1418 auto* lir = new (alloc()) LTypeOfO(useRegister(opd));
1419 define(lir, ins);
1420 return;
1423 MOZ_ASSERT(opd->type() == MIRType::Value);
1425 LTypeOfV* lir = new (alloc()) LTypeOfV(useBox(opd), tempToUnbox());
1426 define(lir, ins);
1429 void LIRGenerator::visitTypeOfName(MTypeOfName* ins) {
1430 MDefinition* input = ins->input();
1431 MOZ_ASSERT(input->type() == MIRType::Int32);
1433 auto* lir = new (alloc()) LTypeOfName(useRegister(input));
1434 define(lir, ins);
1437 void LIRGenerator::visitTypeOfIs(MTypeOfIs* ins) {
1438 MDefinition* input = ins->input();
1440 MOZ_ASSERT(input->type() == MIRType::Object ||
1441 input->type() == MIRType::Value);
1443 switch (ins->jstype()) {
1444 case JSTYPE_UNDEFINED:
1445 case JSTYPE_OBJECT:
1446 case JSTYPE_FUNCTION: {
1447 if (input->type() == MIRType::Object) {
1448 auto* lir = new (alloc()) LTypeOfIsNonPrimitiveO(useRegister(input));
1449 define(lir, ins);
1450 } else {
1451 auto* lir =
1452 new (alloc()) LTypeOfIsNonPrimitiveV(useBox(input), tempToUnbox());
1453 define(lir, ins);
1455 return;
1458 case JSTYPE_STRING:
1459 case JSTYPE_NUMBER:
1460 case JSTYPE_BOOLEAN:
1461 case JSTYPE_SYMBOL:
1462 case JSTYPE_BIGINT: {
1463 MOZ_ASSERT(input->type() == MIRType::Value);
1465 auto* lir = new (alloc()) LTypeOfIsPrimitive(useBoxAtStart(input));
1466 define(lir, ins);
1467 return;
1470 #ifdef ENABLE_RECORD_TUPLE
1471 case JSTYPE_RECORD:
1472 case JSTYPE_TUPLE:
1473 #endif
1474 case JSTYPE_LIMIT:
1475 break;
1477 MOZ_CRASH("Unhandled JSType");
1480 void LIRGenerator::visitToAsyncIter(MToAsyncIter* ins) {
1481 LToAsyncIter* lir = new (alloc()) LToAsyncIter(
1482 useRegisterAtStart(ins->iterator()), useBoxAtStart(ins->nextMethod()));
1483 defineReturn(lir, ins);
1484 assignSafepoint(lir, ins);
1487 void LIRGenerator::visitToPropertyKeyCache(MToPropertyKeyCache* ins) {
1488 MDefinition* input = ins->getOperand(0);
1489 MOZ_ASSERT(ins->type() == MIRType::Value);
1491 auto* lir = new (alloc()) LToPropertyKeyCache(useBox(input));
1492 defineBox(lir, ins);
1493 assignSafepoint(lir, ins);
1496 void LIRGenerator::visitBitNot(MBitNot* ins) {
1497 MDefinition* input = ins->getOperand(0);
1499 if (ins->type() == MIRType::Int32) {
1500 MOZ_ASSERT(input->type() == MIRType::Int32);
1501 lowerForALU(new (alloc()) LBitNotI(), ins, input);
1502 return;
1505 if (ins->type() == MIRType::Int64) {
1506 MOZ_ASSERT(input->type() == MIRType::Int64);
1507 lowerForALUInt64(new (alloc()) LBitNotI64(), ins, input);
1508 return;
1511 MOZ_CRASH("Unhandled integer specialization");
1514 static bool CanEmitBitAndAtUses(MInstruction* ins) {
1515 if (!ins->canEmitAtUses()) {
1516 return false;
1519 MIRType tyL = ins->getOperand(0)->type();
1520 MIRType tyR = ins->getOperand(1)->type();
1521 if (tyL != tyR || (tyL != MIRType::Int32 && tyL != MIRType::Int64)) {
1522 return false;
1525 MUseIterator iter(ins->usesBegin());
1526 if (iter == ins->usesEnd()) {
1527 return false;
1530 MNode* node = iter->consumer();
1531 if (!node->isDefinition() || !node->toDefinition()->isInstruction()) {
1532 return false;
1535 MInstruction* use = node->toDefinition()->toInstruction();
1536 if (!use->isTest() && !(use->isCompare() && CanEmitCompareAtUses(use))) {
1537 return false;
1540 iter++;
1541 return iter == ins->usesEnd();
1544 void LIRGenerator::visitBitAnd(MBitAnd* ins) {
1545 // Sniff out if the output of this bitand is used only for a branching.
1546 // If it is, then we will emit an LBitAndAndBranch instruction in place
1547 // of this bitand and any test that uses this bitand. Thus, we can
1548 // ignore this BitAnd.
1549 if (CanEmitBitAndAtUses(ins)) {
1550 emitAtUses(ins);
1551 } else {
1552 lowerBitOp(JSOp::BitAnd, ins);
1556 void LIRGenerator::visitBitOr(MBitOr* ins) { lowerBitOp(JSOp::BitOr, ins); }
1558 void LIRGenerator::visitBitXor(MBitXor* ins) { lowerBitOp(JSOp::BitXor, ins); }
1560 void LIRGenerator::visitWasmBinaryBitwise(MWasmBinaryBitwise* ins) {
1561 switch (ins->subOpcode()) {
1562 case MWasmBinaryBitwise::SubOpcode::And:
1563 if (CanEmitBitAndAtUses(ins)) {
1564 emitAtUses(ins);
1565 } else {
1566 lowerBitOp(JSOp::BitAnd, ins);
1568 break;
1569 case MWasmBinaryBitwise::SubOpcode::Or:
1570 lowerBitOp(JSOp::BitOr, ins);
1571 break;
1572 case MWasmBinaryBitwise::SubOpcode::Xor:
1573 lowerBitOp(JSOp::BitXor, ins);
1574 break;
1575 default:
1576 MOZ_CRASH();
1580 void LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins) {
1581 MDefinition* lhs = ins->getOperand(0);
1582 MDefinition* rhs = ins->getOperand(1);
1584 if (op == JSOp::Ursh && ins->type() == MIRType::Double) {
1585 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1586 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1587 lowerUrshD(ins->toUrsh());
1588 return;
1591 MOZ_ASSERT(IsIntType(ins->type()));
1593 if (ins->type() == MIRType::Int32) {
1594 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1595 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1597 LShiftI* lir = new (alloc()) LShiftI(op);
1598 if (op == JSOp::Ursh) {
1599 if (ins->toUrsh()->fallible()) {
1600 assignSnapshot(lir, ins->bailoutKind());
1603 lowerForShift(lir, ins, lhs, rhs);
1604 return;
1607 if (ins->type() == MIRType::Int64) {
1608 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1609 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1610 lowerForShiftInt64(new (alloc()) LShiftI64(op), ins, lhs, rhs);
1611 return;
1614 MOZ_CRASH("Unhandled integer specialization");
1617 void LIRGenerator::visitLsh(MLsh* ins) { lowerShiftOp(JSOp::Lsh, ins); }
1619 void LIRGenerator::visitRsh(MRsh* ins) { lowerShiftOp(JSOp::Rsh, ins); }
1621 void LIRGenerator::visitUrsh(MUrsh* ins) { lowerShiftOp(JSOp::Ursh, ins); }
1623 void LIRGenerator::visitSignExtendInt32(MSignExtendInt32* ins) {
1624 LInstructionHelper<1, 1, 0>* lir;
1626 if (ins->mode() == MSignExtendInt32::Byte) {
1627 lir = new (alloc())
1628 LSignExtendInt32(useByteOpRegisterAtStart(ins->input()), ins->mode());
1629 } else {
1630 lir = new (alloc())
1631 LSignExtendInt32(useRegisterAtStart(ins->input()), ins->mode());
1634 define(lir, ins);
1637 void LIRGenerator::visitRotate(MRotate* ins) {
1638 MDefinition* input = ins->input();
1639 MDefinition* count = ins->count();
1641 if (ins->type() == MIRType::Int32) {
1642 auto* lir = new (alloc()) LRotate();
1643 lowerForShift(lir, ins, input, count);
1644 } else if (ins->type() == MIRType::Int64) {
1645 auto* lir = new (alloc()) LRotateI64();
1646 lowerForShiftInt64(lir, ins, input, count);
1647 } else {
1648 MOZ_CRASH("unexpected type in visitRotate");
1652 void LIRGenerator::visitFloor(MFloor* ins) {
1653 MIRType type = ins->input()->type();
1654 MOZ_ASSERT(IsFloatingPointType(type));
1656 LInstructionHelper<1, 1, 0>* lir;
1657 if (type == MIRType::Double) {
1658 lir = new (alloc()) LFloor(useRegister(ins->input()));
1659 } else {
1660 lir = new (alloc()) LFloorF(useRegister(ins->input()));
1663 assignSnapshot(lir, ins->bailoutKind());
1664 define(lir, ins);
1667 void LIRGenerator::visitCeil(MCeil* ins) {
1668 MIRType type = ins->input()->type();
1669 MOZ_ASSERT(IsFloatingPointType(type));
1671 LInstructionHelper<1, 1, 0>* lir;
1672 if (type == MIRType::Double) {
1673 lir = new (alloc()) LCeil(useRegister(ins->input()));
1674 } else {
1675 lir = new (alloc()) LCeilF(useRegister(ins->input()));
1678 assignSnapshot(lir, ins->bailoutKind());
1679 define(lir, ins);
1682 void LIRGenerator::visitRound(MRound* ins) {
1683 MIRType type = ins->input()->type();
1684 MOZ_ASSERT(IsFloatingPointType(type));
1686 LInstructionHelper<1, 1, 1>* lir;
1687 if (type == MIRType::Double) {
1688 lir = new (alloc()) LRound(useRegister(ins->input()), tempDouble());
1689 } else {
1690 lir = new (alloc()) LRoundF(useRegister(ins->input()), tempFloat32());
1693 assignSnapshot(lir, ins->bailoutKind());
1694 define(lir, ins);
1697 void LIRGenerator::visitTrunc(MTrunc* ins) {
1698 MIRType type = ins->input()->type();
1699 MOZ_ASSERT(IsFloatingPointType(type));
1701 LInstructionHelper<1, 1, 0>* lir;
1702 if (type == MIRType::Double) {
1703 lir = new (alloc()) LTrunc(useRegister(ins->input()));
1704 } else {
1705 lir = new (alloc()) LTruncF(useRegister(ins->input()));
1708 assignSnapshot(lir, ins->bailoutKind());
1709 define(lir, ins);
1712 void LIRGenerator::visitNearbyInt(MNearbyInt* ins) {
1713 MIRType inputType = ins->input()->type();
1714 MOZ_ASSERT(IsFloatingPointType(inputType));
1715 MOZ_ASSERT(ins->type() == inputType);
1717 LInstructionHelper<1, 1, 0>* lir;
1718 if (inputType == MIRType::Double) {
1719 lir = new (alloc()) LNearbyInt(useRegisterAtStart(ins->input()));
1720 } else {
1721 lir = new (alloc()) LNearbyIntF(useRegisterAtStart(ins->input()));
1724 define(lir, ins);
1727 void LIRGenerator::visitMinMax(MMinMax* ins) {
1728 MDefinition* first = ins->getOperand(0);
1729 MDefinition* second = ins->getOperand(1);
1731 ReorderCommutative(&first, &second, ins);
1733 LMinMaxBase* lir;
1734 switch (ins->type()) {
1735 case MIRType::Int32:
1736 lir = new (alloc())
1737 LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
1738 break;
1739 case MIRType::Float32:
1740 lir = new (alloc())
1741 LMinMaxF(useRegisterAtStart(first), useRegister(second));
1742 break;
1743 case MIRType::Double:
1744 lir = new (alloc())
1745 LMinMaxD(useRegisterAtStart(first), useRegister(second));
1746 break;
1747 default:
1748 MOZ_CRASH();
1751 // Input reuse is OK (for now) even on ARM64: floating min/max are fairly
1752 // expensive due to SNaN -> QNaN conversion, and int min/max is for asm.js.
1753 defineReuseInput(lir, ins, 0);
1756 void LIRGenerator::visitMinMaxArray(MMinMaxArray* ins) {
1757 LInstructionHelper<1, 1, 3>* lir;
1758 if (ins->type() == MIRType::Int32) {
1759 lir = new (alloc())
1760 LMinMaxArrayI(useRegisterAtStart(ins->array()), temp(), temp(), temp());
1761 } else {
1762 MOZ_ASSERT(ins->type() == MIRType::Double);
1763 lir = new (alloc()) LMinMaxArrayD(useRegisterAtStart(ins->array()),
1764 tempDouble(), temp(), temp());
1766 assignSnapshot(lir, ins->bailoutKind());
1767 define(lir, ins);
1770 LInstructionHelper<1, 1, 0>* LIRGenerator::allocateAbs(MAbs* ins,
1771 LAllocation input) {
1772 MDefinition* num = ins->input();
1773 MOZ_ASSERT(IsNumberType(num->type()));
1775 LInstructionHelper<1, 1, 0>* lir;
1776 switch (num->type()) {
1777 case MIRType::Int32:
1778 lir = new (alloc()) LAbsI(input);
1779 // needed to handle abs(INT32_MIN)
1780 if (ins->fallible()) {
1781 assignSnapshot(lir, ins->bailoutKind());
1783 break;
1784 case MIRType::Float32:
1785 lir = new (alloc()) LAbsF(input);
1786 break;
1787 case MIRType::Double:
1788 lir = new (alloc()) LAbsD(input);
1789 break;
1790 default:
1791 MOZ_CRASH();
1793 return lir;
1796 void LIRGenerator::visitClz(MClz* ins) {
1797 MDefinition* num = ins->num();
1799 MOZ_ASSERT(IsIntType(ins->type()));
1801 if (ins->type() == MIRType::Int32) {
1802 LClzI* lir = new (alloc()) LClzI(useRegisterAtStart(num));
1803 define(lir, ins);
1804 return;
1807 auto* lir = new (alloc()) LClzI64(useInt64RegisterAtStart(num));
1808 defineInt64(lir, ins);
1811 void LIRGenerator::visitCtz(MCtz* ins) {
1812 MDefinition* num = ins->num();
1814 MOZ_ASSERT(IsIntType(ins->type()));
1816 if (ins->type() == MIRType::Int32) {
1817 LCtzI* lir = new (alloc()) LCtzI(useRegisterAtStart(num));
1818 define(lir, ins);
1819 return;
1822 auto* lir = new (alloc()) LCtzI64(useInt64RegisterAtStart(num));
1823 defineInt64(lir, ins);
1826 void LIRGenerator::visitPopcnt(MPopcnt* ins) {
1827 MDefinition* num = ins->num();
1829 MOZ_ASSERT(IsIntType(ins->type()));
1831 if (ins->type() == MIRType::Int32) {
1832 LPopcntI* lir = new (alloc()) LPopcntI(useRegisterAtStart(num), temp());
1833 define(lir, ins);
1834 return;
1837 auto* lir = new (alloc()) LPopcntI64(useInt64RegisterAtStart(num), temp());
1838 defineInt64(lir, ins);
1841 void LIRGenerator::visitSqrt(MSqrt* ins) {
1842 MDefinition* num = ins->input();
1843 MOZ_ASSERT(IsFloatingPointType(num->type()));
1845 LInstructionHelper<1, 1, 0>* lir;
1846 if (num->type() == MIRType::Double) {
1847 lir = new (alloc()) LSqrtD(useRegisterAtStart(num));
1848 } else {
1849 lir = new (alloc()) LSqrtF(useRegisterAtStart(num));
1851 define(lir, ins);
1854 void LIRGenerator::visitAtan2(MAtan2* ins) {
1855 MDefinition* y = ins->y();
1856 MOZ_ASSERT(y->type() == MIRType::Double);
1858 MDefinition* x = ins->x();
1859 MOZ_ASSERT(x->type() == MIRType::Double);
1861 LAtan2D* lir =
1862 new (alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x));
1863 defineReturn(lir, ins);
1866 void LIRGenerator::visitHypot(MHypot* ins) {
1867 LHypot* lir = nullptr;
1868 uint32_t length = ins->numOperands();
1869 for (uint32_t i = 0; i < length; ++i) {
1870 MOZ_ASSERT(ins->getOperand(i)->type() == MIRType::Double);
1873 switch (length) {
1874 case 2:
1875 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1876 useRegisterAtStart(ins->getOperand(1)));
1877 break;
1878 case 3:
1879 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1880 useRegisterAtStart(ins->getOperand(1)),
1881 useRegisterAtStart(ins->getOperand(2)));
1882 break;
1883 case 4:
1884 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1885 useRegisterAtStart(ins->getOperand(1)),
1886 useRegisterAtStart(ins->getOperand(2)),
1887 useRegisterAtStart(ins->getOperand(3)));
1888 break;
1889 default:
1890 MOZ_CRASH("Unexpected number of arguments to LHypot.");
1893 defineReturn(lir, ins);
1896 void LIRGenerator::visitPow(MPow* ins) {
1897 MDefinition* input = ins->input();
1898 MDefinition* power = ins->power();
1900 if (ins->type() == MIRType::Int32) {
1901 MOZ_ASSERT(input->type() == MIRType::Int32);
1902 MOZ_ASSERT(power->type() == MIRType::Int32);
1904 if (input->isConstant()) {
1905 // Restrict this optimization to |base <= 256| to avoid generating too
1906 // many consecutive shift instructions.
1907 int32_t base = input->toConstant()->toInt32();
1908 if (2 <= base && base <= 256 && mozilla::IsPowerOfTwo(uint32_t(base))) {
1909 lowerPowOfTwoI(ins);
1910 return;
1914 auto* lir = new (alloc())
1915 LPowII(useRegister(input), useRegister(power), temp(), temp());
1916 assignSnapshot(lir, ins->bailoutKind());
1917 define(lir, ins);
1918 return;
1921 MOZ_ASSERT(ins->type() == MIRType::Double);
1922 MOZ_ASSERT(input->type() == MIRType::Double);
1923 MOZ_ASSERT(power->type() == MIRType::Int32 ||
1924 power->type() == MIRType::Double);
1926 LInstruction* lir;
1927 if (power->type() == MIRType::Int32) {
1928 lir = new (alloc())
1929 LPowI(useRegisterAtStart(input), useRegisterAtStart(power));
1930 } else {
1931 lir = new (alloc())
1932 LPowD(useRegisterAtStart(input), useRegisterAtStart(power));
1934 defineReturn(lir, ins);
1937 void LIRGenerator::visitSign(MSign* ins) {
1938 if (ins->type() == ins->input()->type()) {
1939 LInstructionHelper<1, 1, 0>* lir;
1940 if (ins->type() == MIRType::Int32) {
1941 lir = new (alloc()) LSignI(useRegister(ins->input()));
1942 } else {
1943 MOZ_ASSERT(ins->type() == MIRType::Double);
1944 lir = new (alloc()) LSignD(useRegister(ins->input()));
1946 define(lir, ins);
1947 } else {
1948 MOZ_ASSERT(ins->type() == MIRType::Int32);
1949 MOZ_ASSERT(ins->input()->type() == MIRType::Double);
1951 auto* lir = new (alloc()) LSignDI(useRegister(ins->input()), tempDouble());
1952 assignSnapshot(lir, ins->bailoutKind());
1953 define(lir, ins);
1957 void LIRGenerator::visitMathFunction(MMathFunction* ins) {
1958 MOZ_ASSERT(IsFloatingPointType(ins->type()));
1959 MOZ_ASSERT(ins->type() == ins->input()->type());
1961 LInstruction* lir;
1962 if (ins->type() == MIRType::Double) {
1963 lir = new (alloc()) LMathFunctionD(useRegisterAtStart(ins->input()));
1964 } else {
1965 lir = new (alloc()) LMathFunctionF(useRegisterAtStart(ins->input()));
1967 defineReturn(lir, ins);
1970 void LIRGenerator::visitRandom(MRandom* ins) {
1971 auto* lir = new (alloc()) LRandom(temp(), tempInt64(), tempInt64());
1972 define(lir, ins);
1975 // Try to mark an add or sub instruction as able to recover its input when
1976 // bailing out.
1977 template <typename S, typename T>
1978 static void MaybeSetRecoversInput(S* mir, T* lir) {
1979 MOZ_ASSERT(lir->mirRaw() == mir);
1980 if (!mir->fallible() || !lir->snapshot()) {
1981 return;
1984 if (lir->output()->policy() != LDefinition::MUST_REUSE_INPUT) {
1985 return;
1988 // The original operands to an add or sub can't be recovered if they both
1989 // use the same register.
1990 if (lir->lhs()->isUse() && lir->rhs()->isUse() &&
1991 lir->lhs()->toUse()->virtualRegister() ==
1992 lir->rhs()->toUse()->virtualRegister()) {
1993 return;
1996 // Add instructions that are on two different values can recover
1997 // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy
1998 // of that input does not need to be kept alive in the snapshot
1999 // for the instruction.
2001 lir->setRecoversInput();
2003 const LUse* input = lir->getOperand(lir->output()->getReusedInput())->toUse();
2004 lir->snapshot()->rewriteRecoveredInput(*input);
2007 void LIRGenerator::visitAdd(MAdd* ins) {
2008 MDefinition* lhs = ins->getOperand(0);
2009 MDefinition* rhs = ins->getOperand(1);
2011 MOZ_ASSERT(lhs->type() == rhs->type());
2012 MOZ_ASSERT(IsNumberType(ins->type()));
2014 if (ins->type() == MIRType::Int32) {
2015 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2016 ReorderCommutative(&lhs, &rhs, ins);
2017 LAddI* lir = new (alloc()) LAddI;
2019 if (ins->fallible()) {
2020 assignSnapshot(lir, ins->bailoutKind());
2023 lowerForALU(lir, ins, lhs, rhs);
2024 MaybeSetRecoversInput(ins, lir);
2025 return;
2028 if (ins->type() == MIRType::Int64) {
2029 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2030 ReorderCommutative(&lhs, &rhs, ins);
2031 LAddI64* lir = new (alloc()) LAddI64;
2032 lowerForALUInt64(lir, ins, lhs, rhs);
2033 return;
2036 if (ins->type() == MIRType::Double) {
2037 MOZ_ASSERT(lhs->type() == MIRType::Double);
2038 ReorderCommutative(&lhs, &rhs, ins);
2039 lowerForFPU(new (alloc()) LMathD(JSOp::Add), ins, lhs, rhs);
2040 return;
2043 if (ins->type() == MIRType::Float32) {
2044 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2045 ReorderCommutative(&lhs, &rhs, ins);
2046 lowerForFPU(new (alloc()) LMathF(JSOp::Add), ins, lhs, rhs);
2047 return;
2050 MOZ_CRASH("Unhandled number specialization");
2053 void LIRGenerator::visitSub(MSub* ins) {
2054 MDefinition* lhs = ins->lhs();
2055 MDefinition* rhs = ins->rhs();
2057 MOZ_ASSERT(lhs->type() == rhs->type());
2058 MOZ_ASSERT(IsNumberType(ins->type()));
2060 if (ins->type() == MIRType::Int32) {
2061 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2063 LSubI* lir = new (alloc()) LSubI;
2064 if (ins->fallible()) {
2065 assignSnapshot(lir, ins->bailoutKind());
2068 // If our LHS is a constant 0 and we don't have to worry about results that
2069 // can't be represented as an int32, we can optimize to an LNegI.
2070 if (!ins->fallible() && lhs->isConstant() &&
2071 lhs->toConstant()->toInt32() == 0) {
2072 lowerNegI(ins, rhs);
2073 return;
2076 lowerForALU(lir, ins, lhs, rhs);
2077 MaybeSetRecoversInput(ins, lir);
2078 return;
2081 if (ins->type() == MIRType::Int64) {
2082 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2084 // If our LHS is a constant 0, we can optimize to an LNegI64.
2085 if (lhs->isConstant() && lhs->toConstant()->toInt64() == 0) {
2086 lowerNegI64(ins, rhs);
2087 return;
2090 LSubI64* lir = new (alloc()) LSubI64;
2091 lowerForALUInt64(lir, ins, lhs, rhs);
2092 return;
2095 if (ins->type() == MIRType::Double) {
2096 MOZ_ASSERT(lhs->type() == MIRType::Double);
2097 lowerForFPU(new (alloc()) LMathD(JSOp::Sub), ins, lhs, rhs);
2098 return;
2101 if (ins->type() == MIRType::Float32) {
2102 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2103 lowerForFPU(new (alloc()) LMathF(JSOp::Sub), ins, lhs, rhs);
2104 return;
2107 MOZ_CRASH("Unhandled number specialization");
2110 void LIRGenerator::visitMul(MMul* ins) {
2111 MDefinition* lhs = ins->lhs();
2112 MDefinition* rhs = ins->rhs();
2113 MOZ_ASSERT(lhs->type() == rhs->type());
2114 MOZ_ASSERT(IsNumberType(ins->type()));
2116 if (ins->type() == MIRType::Int32) {
2117 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2118 ReorderCommutative(&lhs, &rhs, ins);
2120 // If our RHS is a constant -1 and we don't have to worry about results that
2121 // can't be represented as an int32, we can optimize to an LNegI.
2122 if (!ins->fallible() && rhs->isConstant() &&
2123 rhs->toConstant()->toInt32() == -1) {
2124 lowerNegI(ins, lhs);
2125 return;
2128 lowerMulI(ins, lhs, rhs);
2129 return;
2132 if (ins->type() == MIRType::Int64) {
2133 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2134 ReorderCommutative(&lhs, &rhs, ins);
2136 // If our RHS is a constant -1, we can optimize to an LNegI64.
2137 if (rhs->isConstant() && rhs->toConstant()->toInt64() == -1) {
2138 lowerNegI64(ins, lhs);
2139 return;
2142 LMulI64* lir = new (alloc()) LMulI64;
2143 lowerForMulInt64(lir, ins, lhs, rhs);
2144 return;
2147 if (ins->type() == MIRType::Double) {
2148 MOZ_ASSERT(lhs->type() == MIRType::Double);
2149 ReorderCommutative(&lhs, &rhs, ins);
2151 // If our RHS is a constant -1.0, we can optimize to an LNegD.
2152 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2153 rhs->toConstant()->toDouble() == -1.0) {
2154 defineReuseInput(new (alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0);
2155 return;
2158 lowerForFPU(new (alloc()) LMathD(JSOp::Mul), ins, lhs, rhs);
2159 return;
2162 if (ins->type() == MIRType::Float32) {
2163 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2164 ReorderCommutative(&lhs, &rhs, ins);
2166 // We apply the same optimizations as for doubles
2167 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2168 rhs->toConstant()->toFloat32() == -1.0f) {
2169 defineReuseInput(new (alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0);
2170 return;
2173 lowerForFPU(new (alloc()) LMathF(JSOp::Mul), ins, lhs, rhs);
2174 return;
2177 MOZ_CRASH("Unhandled number specialization");
2180 void LIRGenerator::visitDiv(MDiv* ins) {
2181 MDefinition* lhs = ins->lhs();
2182 MDefinition* rhs = ins->rhs();
2183 MOZ_ASSERT(lhs->type() == rhs->type());
2184 MOZ_ASSERT(IsNumberType(ins->type()));
2186 if (ins->type() == MIRType::Int32) {
2187 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2188 lowerDivI(ins);
2189 return;
2192 if (ins->type() == MIRType::Int64) {
2193 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2194 lowerDivI64(ins);
2195 return;
2198 if (ins->type() == MIRType::Double) {
2199 MOZ_ASSERT(lhs->type() == MIRType::Double);
2200 lowerForFPU(new (alloc()) LMathD(JSOp::Div), ins, lhs, rhs);
2201 return;
2204 if (ins->type() == MIRType::Float32) {
2205 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2206 lowerForFPU(new (alloc()) LMathF(JSOp::Div), ins, lhs, rhs);
2207 return;
2210 MOZ_CRASH("Unhandled number specialization");
2213 void LIRGenerator::visitWasmBuiltinDivI64(MWasmBuiltinDivI64* div) {
2214 lowerWasmBuiltinDivI64(div);
2217 void LIRGenerator::visitWasmBuiltinModI64(MWasmBuiltinModI64* mod) {
2218 lowerWasmBuiltinModI64(mod);
2221 void LIRGenerator::visitBuiltinInt64ToFloatingPoint(
2222 MBuiltinInt64ToFloatingPoint* ins) {
2223 lowerBuiltinInt64ToFloatingPoint(ins);
2226 void LIRGenerator::visitWasmBuiltinTruncateToInt64(
2227 MWasmBuiltinTruncateToInt64* ins) {
2228 lowerWasmBuiltinTruncateToInt64(ins);
2231 void LIRGenerator::visitWasmBuiltinModD(MWasmBuiltinModD* ins) {
2232 MOZ_ASSERT(gen->compilingWasm());
2233 LWasmBuiltinModD* lir = new (alloc()) LWasmBuiltinModD(
2234 useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()),
2235 useFixedAtStart(ins->instance(), InstanceReg));
2236 defineReturn(lir, ins);
2239 void LIRGenerator::visitMod(MMod* ins) {
2240 MOZ_ASSERT(ins->lhs()->type() == ins->rhs()->type());
2241 MOZ_ASSERT(IsNumberType(ins->type()));
2243 if (ins->type() == MIRType::Int32) {
2244 MOZ_ASSERT(ins->type() == MIRType::Int32);
2245 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int32);
2246 lowerModI(ins);
2247 return;
2250 if (ins->type() == MIRType::Int64) {
2251 MOZ_ASSERT(ins->type() == MIRType::Int64);
2252 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int64);
2253 lowerModI64(ins);
2254 return;
2257 if (ins->type() == MIRType::Double) {
2258 MOZ_ASSERT(ins->lhs()->type() == MIRType::Double);
2259 MOZ_ASSERT(ins->rhs()->type() == MIRType::Double);
2261 MOZ_ASSERT(!gen->compilingWasm());
2263 if (Assembler::HasRoundInstruction(RoundingMode::TowardsZero)) {
2264 if (ins->rhs()->isConstant()) {
2265 double d = ins->rhs()->toConstant()->toDouble();
2266 int32_t div;
2267 if (mozilla::NumberIsInt32(d, &div) && div > 0 &&
2268 mozilla::IsPowerOfTwo(uint32_t(div))) {
2269 auto* lir = new (alloc()) LModPowTwoD(useRegister(ins->lhs()), div);
2270 define(lir, ins);
2271 return;
2276 LModD* lir = new (alloc())
2277 LModD(useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()));
2278 defineReturn(lir, ins);
2279 return;
2282 MOZ_CRASH("Unhandled number specialization");
2285 void LIRGenerator::visitBigIntAdd(MBigIntAdd* ins) {
2286 auto* lir = new (alloc()) LBigIntAdd(useRegister(ins->lhs()),
2287 useRegister(ins->rhs()), temp(), temp());
2288 define(lir, ins);
2289 assignSafepoint(lir, ins);
2292 void LIRGenerator::visitBigIntSub(MBigIntSub* ins) {
2293 auto* lir = new (alloc()) LBigIntSub(useRegister(ins->lhs()),
2294 useRegister(ins->rhs()), temp(), temp());
2295 define(lir, ins);
2296 assignSafepoint(lir, ins);
2299 void LIRGenerator::visitBigIntMul(MBigIntMul* ins) {
2300 auto* lir = new (alloc()) LBigIntMul(useRegister(ins->lhs()),
2301 useRegister(ins->rhs()), temp(), temp());
2302 define(lir, ins);
2303 assignSafepoint(lir, ins);
2306 void LIRGenerator::visitBigIntDiv(MBigIntDiv* ins) { lowerBigIntDiv(ins); }
2308 void LIRGenerator::visitBigIntMod(MBigIntMod* ins) { lowerBigIntMod(ins); }
2310 void LIRGenerator::visitBigIntPow(MBigIntPow* ins) {
2311 auto* lir = new (alloc()) LBigIntPow(useRegister(ins->lhs()),
2312 useRegister(ins->rhs()), temp(), temp());
2313 define(lir, ins);
2314 assignSafepoint(lir, ins);
2317 void LIRGenerator::visitBigIntBitAnd(MBigIntBitAnd* ins) {
2318 auto* lir = new (alloc()) LBigIntBitAnd(
2319 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2320 define(lir, ins);
2321 assignSafepoint(lir, ins);
2324 void LIRGenerator::visitBigIntBitOr(MBigIntBitOr* ins) {
2325 auto* lir = new (alloc()) LBigIntBitOr(
2326 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2327 define(lir, ins);
2328 assignSafepoint(lir, ins);
2331 void LIRGenerator::visitBigIntBitXor(MBigIntBitXor* ins) {
2332 auto* lir = new (alloc()) LBigIntBitXor(
2333 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2334 define(lir, ins);
2335 assignSafepoint(lir, ins);
2338 void LIRGenerator::visitBigIntLsh(MBigIntLsh* ins) { lowerBigIntLsh(ins); }
2340 void LIRGenerator::visitBigIntRsh(MBigIntRsh* ins) { lowerBigIntRsh(ins); }
2342 void LIRGenerator::visitBigIntIncrement(MBigIntIncrement* ins) {
2343 auto* lir =
2344 new (alloc()) LBigIntIncrement(useRegister(ins->input()), temp(), temp());
2345 define(lir, ins);
2346 assignSafepoint(lir, ins);
2349 void LIRGenerator::visitBigIntDecrement(MBigIntDecrement* ins) {
2350 auto* lir =
2351 new (alloc()) LBigIntDecrement(useRegister(ins->input()), temp(), temp());
2352 define(lir, ins);
2353 assignSafepoint(lir, ins);
2356 void LIRGenerator::visitBigIntNegate(MBigIntNegate* ins) {
2357 auto* lir = new (alloc()) LBigIntNegate(useRegister(ins->input()), temp());
2358 define(lir, ins);
2359 assignSafepoint(lir, ins);
2362 void LIRGenerator::visitBigIntBitNot(MBigIntBitNot* ins) {
2363 auto* lir =
2364 new (alloc()) LBigIntBitNot(useRegister(ins->input()), temp(), temp());
2365 define(lir, ins);
2366 assignSafepoint(lir, ins);
2369 void LIRGenerator::visitInt32ToStringWithBase(MInt32ToStringWithBase* ins) {
2370 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2371 MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
2373 int32_t baseInt =
2374 ins->base()->isConstant() ? ins->base()->toConstant()->toInt32() : 0;
2376 LAllocation base;
2377 if (2 <= baseInt && baseInt <= 36) {
2378 base = useRegisterOrConstant(ins->base());
2379 } else {
2380 base = useRegister(ins->base());
2383 auto* lir = new (alloc())
2384 LInt32ToStringWithBase(useRegister(ins->input()), base, temp(), temp());
2385 define(lir, ins);
2386 assignSafepoint(lir, ins);
2389 void LIRGenerator::visitNumberParseInt(MNumberParseInt* ins) {
2390 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2391 MOZ_ASSERT(ins->radix()->type() == MIRType::Int32);
2393 auto* lir = new (alloc()) LNumberParseInt(useRegisterAtStart(ins->string()),
2394 useRegisterAtStart(ins->radix()),
2395 tempFixed(CallTempReg0));
2396 defineReturn(lir, ins);
2397 assignSafepoint(lir, ins);
2400 void LIRGenerator::visitDoubleParseInt(MDoubleParseInt* ins) {
2401 MOZ_ASSERT(ins->number()->type() == MIRType::Double);
2403 auto* lir =
2404 new (alloc()) LDoubleParseInt(useRegister(ins->number()), tempDouble());
2405 assignSnapshot(lir, ins->bailoutKind());
2406 define(lir, ins);
2409 void LIRGenerator::visitConcat(MConcat* ins) {
2410 MDefinition* lhs = ins->getOperand(0);
2411 MDefinition* rhs = ins->getOperand(1);
2413 MOZ_ASSERT(lhs->type() == MIRType::String);
2414 MOZ_ASSERT(rhs->type() == MIRType::String);
2415 MOZ_ASSERT(ins->type() == MIRType::String);
2417 LConcat* lir = new (alloc()) LConcat(
2418 useFixedAtStart(lhs, CallTempReg0), useFixedAtStart(rhs, CallTempReg1),
2419 tempFixed(CallTempReg0), tempFixed(CallTempReg1), tempFixed(CallTempReg2),
2420 tempFixed(CallTempReg3), tempFixed(CallTempReg4));
2421 defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5)));
2422 assignSafepoint(lir, ins);
2425 void LIRGenerator::visitLinearizeString(MLinearizeString* ins) {
2426 MDefinition* str = ins->string();
2427 MOZ_ASSERT(str->type() == MIRType::String);
2429 auto* lir = new (alloc()) LLinearizeString(useRegister(str));
2430 define(lir, ins);
2431 assignSafepoint(lir, ins);
2434 void LIRGenerator::visitLinearizeForCharAccess(MLinearizeForCharAccess* ins) {
2435 MDefinition* str = ins->string();
2436 MDefinition* idx = ins->index();
2438 MOZ_ASSERT(str->type() == MIRType::String);
2439 MOZ_ASSERT(idx->type() == MIRType::Int32);
2441 auto* lir =
2442 new (alloc()) LLinearizeForCharAccess(useRegister(str), useRegister(idx));
2443 define(lir, ins);
2444 assignSafepoint(lir, ins);
2447 void LIRGenerator::visitLinearizeForCodePointAccess(
2448 MLinearizeForCodePointAccess* ins) {
2449 MDefinition* str = ins->string();
2450 MDefinition* idx = ins->index();
2452 MOZ_ASSERT(str->type() == MIRType::String);
2453 MOZ_ASSERT(idx->type() == MIRType::Int32);
2455 auto* lir = new (alloc())
2456 LLinearizeForCodePointAccess(useRegister(str), useRegister(idx), temp());
2457 define(lir, ins);
2458 assignSafepoint(lir, ins);
2461 void LIRGenerator::visitToRelativeStringIndex(MToRelativeStringIndex* ins) {
2462 MDefinition* index = ins->index();
2463 MDefinition* length = ins->length();
2465 MOZ_ASSERT(index->type() == MIRType::Int32);
2466 MOZ_ASSERT(length->type() == MIRType::Int32);
2468 auto* lir = new (alloc())
2469 LToRelativeStringIndex(useRegister(index), useRegister(length));
2470 define(lir, ins);
2473 void LIRGenerator::visitCharCodeAt(MCharCodeAt* ins) {
2474 MDefinition* str = ins->string();
2475 MDefinition* idx = ins->index();
2477 MOZ_ASSERT(str->type() == MIRType::String);
2478 MOZ_ASSERT(idx->type() == MIRType::Int32);
2480 auto* lir = new (alloc())
2481 LCharCodeAt(useRegister(str), useRegisterOrZero(idx), temp(), temp());
2482 define(lir, ins);
2483 assignSafepoint(lir, ins);
2486 void LIRGenerator::visitCharCodeAtOrNegative(MCharCodeAtOrNegative* ins) {
2487 MDefinition* str = ins->string();
2488 MDefinition* idx = ins->index();
2490 MOZ_ASSERT(str->type() == MIRType::String);
2491 MOZ_ASSERT(idx->type() == MIRType::Int32);
2493 auto* lir = new (alloc()) LCharCodeAtOrNegative(
2494 useRegister(str), useRegisterOrZero(idx), temp(), temp());
2495 define(lir, ins);
2496 assignSafepoint(lir, ins);
2499 void LIRGenerator::visitCodePointAt(MCodePointAt* ins) {
2500 MDefinition* str = ins->string();
2501 MDefinition* idx = ins->index();
2503 MOZ_ASSERT(str->type() == MIRType::String);
2504 MOZ_ASSERT(idx->type() == MIRType::Int32);
2506 auto* lir = new (alloc())
2507 LCodePointAt(useRegister(str), useRegister(idx), temp(), temp());
2508 define(lir, ins);
2509 assignSafepoint(lir, ins);
2512 void LIRGenerator::visitCodePointAtOrNegative(MCodePointAtOrNegative* ins) {
2513 MDefinition* str = ins->string();
2514 MDefinition* idx = ins->index();
2516 MOZ_ASSERT(str->type() == MIRType::String);
2517 MOZ_ASSERT(idx->type() == MIRType::Int32);
2519 auto* lir = new (alloc()) LCodePointAtOrNegative(
2520 useRegister(str), useRegister(idx), temp(), temp());
2521 define(lir, ins);
2522 assignSafepoint(lir, ins);
2525 void LIRGenerator::visitNegativeToNaN(MNegativeToNaN* ins) {
2526 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2528 auto* lir = new (alloc()) LNegativeToNaN(useRegister(ins->input()));
2529 defineBox(lir, ins);
2532 void LIRGenerator::visitNegativeToUndefined(MNegativeToUndefined* ins) {
2533 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2535 auto* lir = new (alloc()) LNegativeToUndefined(useRegister(ins->input()));
2536 defineBox(lir, ins);
2539 void LIRGenerator::visitFromCharCode(MFromCharCode* ins) {
2540 MDefinition* code = ins->code();
2542 MOZ_ASSERT(code->type() == MIRType::Int32);
2544 LFromCharCode* lir = new (alloc()) LFromCharCode(useRegister(code));
2545 define(lir, ins);
2546 assignSafepoint(lir, ins);
2549 void LIRGenerator::visitFromCharCodeEmptyIfNegative(
2550 MFromCharCodeEmptyIfNegative* ins) {
2551 MDefinition* code = ins->code();
2553 MOZ_ASSERT(code->type() == MIRType::Int32);
2555 auto* lir = new (alloc()) LFromCharCodeEmptyIfNegative(useRegister(code));
2556 define(lir, ins);
2557 assignSafepoint(lir, ins);
2560 void LIRGenerator::visitFromCharCodeUndefinedIfNegative(
2561 MFromCharCodeUndefinedIfNegative* ins) {
2562 MDefinition* code = ins->code();
2564 MOZ_ASSERT(code->type() == MIRType::Int32);
2566 auto* lir = new (alloc()) LFromCharCodeUndefinedIfNegative(useRegister(code));
2567 defineBox(lir, ins);
2568 assignSafepoint(lir, ins);
2571 void LIRGenerator::visitFromCodePoint(MFromCodePoint* ins) {
2572 MDefinition* codePoint = ins->codePoint();
2574 MOZ_ASSERT(codePoint->type() == MIRType::Int32);
2576 LFromCodePoint* lir =
2577 new (alloc()) LFromCodePoint(useRegister(codePoint), temp(), temp());
2578 assignSnapshot(lir, ins->bailoutKind());
2579 define(lir, ins);
2580 assignSafepoint(lir, ins);
2583 void LIRGenerator::visitStringIncludes(MStringIncludes* ins) {
2584 auto* string = ins->string();
2585 MOZ_ASSERT(string->type() == MIRType::String);
2587 auto* searchStr = ins->searchString();
2588 MOZ_ASSERT(searchStr->type() == MIRType::String);
2590 if (searchStr->isConstant()) {
2591 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2592 size_t length = linear->length();
2593 if (length == 1 || length == 2) {
2594 LDefinition tempDef = LDefinition::BogusTemp();
2595 if (length > 1) {
2596 tempDef = temp();
2599 auto* lir = new (alloc()) LStringIncludesSIMD(useRegister(string), temp(),
2600 temp(), tempDef, linear);
2601 define(lir, ins);
2602 assignSafepoint(lir, ins);
2603 return;
2607 auto* lir = new (alloc()) LStringIncludes(useRegisterAtStart(string),
2608 useRegisterAtStart(searchStr));
2609 defineReturn(lir, ins);
2610 assignSafepoint(lir, ins);
2613 void LIRGenerator::visitStringIndexOf(MStringIndexOf* ins) {
2614 auto* string = ins->string();
2615 MOZ_ASSERT(string->type() == MIRType::String);
2617 auto* searchStr = ins->searchString();
2618 MOZ_ASSERT(searchStr->type() == MIRType::String);
2620 if (searchStr->isConstant()) {
2621 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2622 size_t length = linear->length();
2623 if (length == 1 || length == 2) {
2624 LDefinition tempDef = LDefinition::BogusTemp();
2625 if (length > 1) {
2626 tempDef = temp();
2629 auto* lir = new (alloc()) LStringIndexOfSIMD(useRegister(string), temp(),
2630 temp(), tempDef, linear);
2631 define(lir, ins);
2632 assignSafepoint(lir, ins);
2633 return;
2637 auto* lir = new (alloc())
2638 LStringIndexOf(useRegisterAtStart(string), useRegisterAtStart(searchStr));
2639 defineReturn(lir, ins);
2640 assignSafepoint(lir, ins);
2643 void LIRGenerator::visitStringLastIndexOf(MStringLastIndexOf* ins) {
2644 auto* string = ins->string();
2645 MOZ_ASSERT(string->type() == MIRType::String);
2647 auto* searchStr = ins->searchString();
2648 MOZ_ASSERT(searchStr->type() == MIRType::String);
2650 auto* lir = new (alloc()) LStringLastIndexOf(useRegisterAtStart(string),
2651 useRegisterAtStart(searchStr));
2652 defineReturn(lir, ins);
2653 assignSafepoint(lir, ins);
2656 void LIRGenerator::visitStringStartsWith(MStringStartsWith* ins) {
2657 auto* string = ins->string();
2658 MOZ_ASSERT(string->type() == MIRType::String);
2660 auto* searchStr = ins->searchString();
2661 MOZ_ASSERT(searchStr->type() == MIRType::String);
2663 if (searchStr->isConstant()) {
2664 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2666 if (MacroAssembler::canCompareStringCharsInline(linear)) {
2667 auto* lir = new (alloc())
2668 LStringStartsWithInline(useRegister(string), temp(), linear);
2669 define(lir, ins);
2670 assignSafepoint(lir, ins);
2671 return;
2675 auto* lir = new (alloc()) LStringStartsWith(useRegisterAtStart(string),
2676 useRegisterAtStart(searchStr));
2677 defineReturn(lir, ins);
2678 assignSafepoint(lir, ins);
2681 void LIRGenerator::visitStringEndsWith(MStringEndsWith* ins) {
2682 auto* string = ins->string();
2683 MOZ_ASSERT(string->type() == MIRType::String);
2685 auto* searchStr = ins->searchString();
2686 MOZ_ASSERT(searchStr->type() == MIRType::String);
2688 if (searchStr->isConstant()) {
2689 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2691 if (MacroAssembler::canCompareStringCharsInline(linear)) {
2692 auto* lir = new (alloc())
2693 LStringEndsWithInline(useRegister(string), temp(), linear);
2694 define(lir, ins);
2695 assignSafepoint(lir, ins);
2696 return;
2700 auto* lir = new (alloc()) LStringEndsWith(useRegisterAtStart(string),
2701 useRegisterAtStart(searchStr));
2702 defineReturn(lir, ins);
2703 assignSafepoint(lir, ins);
2706 void LIRGenerator::visitStringConvertCase(MStringConvertCase* ins) {
2707 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2709 if (ins->mode() == MStringConvertCase::LowerCase) {
2710 #ifdef JS_CODEGEN_X86
2711 // Due to lack of registers on x86, we reuse the string register as
2712 // temporary. As a result we only need four temporary registers and take a
2713 // bogus temporary as the fifth argument.
2714 LDefinition temp4 = LDefinition::BogusTemp();
2715 #else
2716 LDefinition temp4 = temp();
2717 #endif
2718 auto* lir = new (alloc())
2719 LStringToLowerCase(useRegister(ins->string()), temp(), temp(), temp(),
2720 temp4, tempByteOpRegister());
2721 define(lir, ins);
2722 assignSafepoint(lir, ins);
2723 } else {
2724 auto* lir =
2725 new (alloc()) LStringToUpperCase(useRegisterAtStart(ins->string()));
2726 defineReturn(lir, ins);
2727 assignSafepoint(lir, ins);
2731 void LIRGenerator::visitCharCodeConvertCase(MCharCodeConvertCase* ins) {
2732 MOZ_ASSERT(ins->code()->type() == MIRType::Int32);
2734 if (ins->mode() == MCharCodeConvertCase::LowerCase) {
2735 auto* lir = new (alloc())
2736 LCharCodeToLowerCase(useRegister(ins->code()), tempByteOpRegister());
2737 define(lir, ins);
2738 assignSafepoint(lir, ins);
2739 } else {
2740 auto* lir = new (alloc())
2741 LCharCodeToUpperCase(useRegister(ins->code()), tempByteOpRegister());
2742 define(lir, ins);
2743 assignSafepoint(lir, ins);
2747 void LIRGenerator::visitStringTrimStartIndex(MStringTrimStartIndex* ins) {
2748 auto* string = ins->string();
2749 MOZ_ASSERT(string->type() == MIRType::String);
2751 auto* lir = new (alloc()) LStringTrimStartIndex(useRegister(string));
2752 define(lir, ins);
2753 assignSafepoint(lir, ins);
2756 void LIRGenerator::visitStringTrimEndIndex(MStringTrimEndIndex* ins) {
2757 auto* string = ins->string();
2758 MOZ_ASSERT(string->type() == MIRType::String);
2760 auto* start = ins->start();
2761 MOZ_ASSERT(start->type() == MIRType::Int32);
2763 auto* lir = new (alloc())
2764 LStringTrimEndIndex(useRegister(string), useRegister(start));
2765 define(lir, ins);
2766 assignSafepoint(lir, ins);
2769 void LIRGenerator::visitStart(MStart* start) {}
2771 void LIRGenerator::visitNop(MNop* nop) {}
2773 void LIRGenerator::visitLimitedTruncate(MLimitedTruncate* nop) {
2774 redefine(nop, nop->input());
2777 void LIRGenerator::visitOsrEntry(MOsrEntry* entry) {
2778 LOsrEntry* lir = new (alloc()) LOsrEntry(temp());
2779 defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg)));
2782 void LIRGenerator::visitOsrValue(MOsrValue* value) {
2783 LOsrValue* lir = new (alloc()) LOsrValue(useRegister(value->entry()));
2784 defineBox(lir, value);
2787 void LIRGenerator::visitOsrReturnValue(MOsrReturnValue* value) {
2788 LOsrReturnValue* lir =
2789 new (alloc()) LOsrReturnValue(useRegister(value->entry()));
2790 defineBox(lir, value);
2793 void LIRGenerator::visitOsrEnvironmentChain(MOsrEnvironmentChain* object) {
2794 LOsrEnvironmentChain* lir =
2795 new (alloc()) LOsrEnvironmentChain(useRegister(object->entry()));
2796 define(lir, object);
2799 void LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject* object) {
2800 LOsrArgumentsObject* lir =
2801 new (alloc()) LOsrArgumentsObject(useRegister(object->entry()));
2802 define(lir, object);
2805 void LIRGenerator::visitToDouble(MToDouble* convert) {
2806 MDefinition* opd = convert->input();
2807 mozilla::DebugOnly<MToFPInstruction::ConversionKind> conversion =
2808 convert->conversion();
2810 switch (opd->type()) {
2811 case MIRType::Value: {
2812 LValueToDouble* lir = new (alloc()) LValueToDouble(useBox(opd));
2813 assignSnapshot(lir, convert->bailoutKind());
2814 define(lir, convert);
2815 break;
2818 case MIRType::Null:
2819 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2820 lowerConstantDouble(0, convert);
2821 break;
2823 case MIRType::Undefined:
2824 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2825 lowerConstantDouble(GenericNaN(), convert);
2826 break;
2828 case MIRType::Boolean:
2829 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2830 [[fallthrough]];
2832 case MIRType::Int32: {
2833 LInt32ToDouble* lir =
2834 new (alloc()) LInt32ToDouble(useRegisterAtStart(opd));
2835 define(lir, convert);
2836 break;
2839 case MIRType::Float32: {
2840 LFloat32ToDouble* lir =
2841 new (alloc()) LFloat32ToDouble(useRegisterAtStart(opd));
2842 define(lir, convert);
2843 break;
2846 case MIRType::Double:
2847 redefine(convert, opd);
2848 break;
2850 default:
2851 // Objects might be effectful. Symbols will throw.
2852 // Strings are complicated - we don't handle them yet.
2853 MOZ_CRASH("unexpected type");
2857 void LIRGenerator::visitToFloat32(MToFloat32* convert) {
2858 MDefinition* opd = convert->input();
2859 mozilla::DebugOnly<MToFloat32::ConversionKind> conversion =
2860 convert->conversion();
2862 switch (opd->type()) {
2863 case MIRType::Value: {
2864 LValueToFloat32* lir = new (alloc()) LValueToFloat32(useBox(opd));
2865 assignSnapshot(lir, convert->bailoutKind());
2866 define(lir, convert);
2867 break;
2870 case MIRType::Null:
2871 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2872 lowerConstantFloat32(0, convert);
2873 break;
2875 case MIRType::Undefined:
2876 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2877 lowerConstantFloat32(GenericNaN(), convert);
2878 break;
2880 case MIRType::Boolean:
2881 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2882 [[fallthrough]];
2884 case MIRType::Int32: {
2885 LInt32ToFloat32* lir =
2886 new (alloc()) LInt32ToFloat32(useRegisterAtStart(opd));
2887 define(lir, convert);
2888 break;
2891 case MIRType::Double: {
2892 LDoubleToFloat32* lir =
2893 new (alloc()) LDoubleToFloat32(useRegisterAtStart(opd));
2894 define(lir, convert);
2895 break;
2898 case MIRType::Float32:
2899 redefine(convert, opd);
2900 break;
2902 default:
2903 // Objects might be effectful. Symbols will throw.
2904 // Strings are complicated - we don't handle them yet.
2905 MOZ_CRASH("unexpected type");
2909 void LIRGenerator::visitToNumberInt32(MToNumberInt32* convert) {
2910 MDefinition* opd = convert->input();
2912 switch (opd->type()) {
2913 case MIRType::Value: {
2914 auto* lir = new (alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(),
2915 LValueToInt32::NORMAL);
2916 assignSnapshot(lir, convert->bailoutKind());
2917 define(lir, convert);
2918 if (lir->mode() == LValueToInt32::TRUNCATE) {
2919 assignSafepoint(lir, convert);
2921 break;
2924 case MIRType::Null:
2925 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any);
2926 define(new (alloc()) LInteger(0), convert);
2927 break;
2929 case MIRType::Boolean:
2930 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any ||
2931 convert->conversion() ==
2932 IntConversionInputKind::NumbersOrBoolsOnly);
2933 redefine(convert, opd);
2934 break;
2936 case MIRType::Int32:
2937 redefine(convert, opd);
2938 break;
2940 case MIRType::Float32: {
2941 LFloat32ToInt32* lir = new (alloc()) LFloat32ToInt32(useRegister(opd));
2942 assignSnapshot(lir, convert->bailoutKind());
2943 define(lir, convert);
2944 break;
2947 case MIRType::Double: {
2948 LDoubleToInt32* lir = new (alloc()) LDoubleToInt32(useRegister(opd));
2949 assignSnapshot(lir, convert->bailoutKind());
2950 define(lir, convert);
2951 break;
2954 case MIRType::String:
2955 case MIRType::Symbol:
2956 case MIRType::BigInt:
2957 case MIRType::Object:
2958 case MIRType::Undefined:
2959 // Objects might be effectful. Symbols and BigInts throw. Undefined
2960 // coerces to NaN, not int32.
2961 MOZ_CRASH("ToInt32 invalid input type");
2963 default:
2964 MOZ_CRASH("unexpected type");
2968 void LIRGenerator::visitBooleanToInt32(MBooleanToInt32* convert) {
2969 MDefinition* opd = convert->input();
2970 MOZ_ASSERT(opd->type() == MIRType::Boolean);
2971 redefine(convert, opd);
2974 void LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) {
2975 MDefinition* opd = truncate->input();
2977 switch (opd->type()) {
2978 case MIRType::Value: {
2979 LValueToInt32* lir = new (alloc()) LValueToInt32(
2980 useBox(opd), tempDouble(), temp(), LValueToInt32::TRUNCATE);
2981 assignSnapshot(lir, truncate->bailoutKind());
2982 define(lir, truncate);
2983 assignSafepoint(lir, truncate);
2984 break;
2987 case MIRType::Null:
2988 case MIRType::Undefined:
2989 define(new (alloc()) LInteger(0), truncate);
2990 break;
2992 case MIRType::Int32:
2993 case MIRType::Boolean:
2994 redefine(truncate, opd);
2995 break;
2997 case MIRType::Double:
2998 // May call into JS::ToInt32() on the slow OOL path.
2999 gen->setNeedsStaticStackAlignment();
3000 lowerTruncateDToInt32(truncate);
3001 break;
3003 case MIRType::Float32:
3004 // May call into JS::ToInt32() on the slow OOL path.
3005 gen->setNeedsStaticStackAlignment();
3006 lowerTruncateFToInt32(truncate);
3007 break;
3009 default:
3010 // Objects might be effectful. Symbols throw.
3011 // Strings are complicated - we don't handle them yet.
3012 MOZ_CRASH("unexpected type");
3016 void LIRGenerator::visitInt32ToIntPtr(MInt32ToIntPtr* ins) {
3017 MDefinition* input = ins->input();
3018 MOZ_ASSERT(input->type() == MIRType::Int32);
3019 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3021 #ifdef JS_64BIT
3022 // If the result is only used by instructions that expect a bounds-checked
3023 // index, we must have eliminated or hoisted a bounds check and we can assume
3024 // the index is non-negative. This lets us generate more efficient code.
3025 if (ins->canBeNegative()) {
3026 bool canBeNegative = false;
3027 for (MUseDefIterator iter(ins); iter; iter++) {
3028 if (!iter.def()->isSpectreMaskIndex() &&
3029 !iter.def()->isLoadUnboxedScalar() &&
3030 !iter.def()->isStoreUnboxedScalar() &&
3031 !iter.def()->isLoadDataViewElement() &&
3032 !iter.def()->isStoreDataViewElement()) {
3033 canBeNegative = true;
3034 break;
3037 if (!canBeNegative) {
3038 ins->setCanNotBeNegative();
3042 if (ins->canBeNegative()) {
3043 auto* lir = new (alloc()) LInt32ToIntPtr(useAnyAtStart(input));
3044 define(lir, ins);
3045 } else {
3046 redefine(ins, input);
3048 #else
3049 // On 32-bit platforms this is a no-op.
3050 redefine(ins, input);
3051 #endif
3054 void LIRGenerator::visitNonNegativeIntPtrToInt32(
3055 MNonNegativeIntPtrToInt32* ins) {
3056 MDefinition* input = ins->input();
3057 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3058 MOZ_ASSERT(ins->type() == MIRType::Int32);
3060 #ifdef JS_64BIT
3061 auto* lir =
3062 new (alloc()) LNonNegativeIntPtrToInt32(useRegisterAtStart(input));
3063 assignSnapshot(lir, ins->bailoutKind());
3064 defineReuseInput(lir, ins, 0);
3065 #else
3066 // On 32-bit platforms this is a no-op.
3067 redefine(ins, input);
3068 #endif
3071 void LIRGenerator::visitWasmExtendU32Index(MWasmExtendU32Index* ins) {
3072 #ifdef JS_64BIT
3073 // Technically this produces an Int64 register and I guess we could clean that
3074 // up, but it's a 64-bit only operation, so it doesn't actually matter.
3076 MDefinition* input = ins->input();
3077 MOZ_ASSERT(input->type() == MIRType::Int32);
3078 MOZ_ASSERT(ins->type() == MIRType::Int64);
3080 // Input reuse is OK even on ARM64 because this node *must* reuse its input in
3081 // order not to generate any code at all, as is the intent.
3082 auto* lir = new (alloc()) LWasmExtendU32Index(useRegisterAtStart(input));
3083 defineReuseInput(lir, ins, 0);
3084 #else
3085 MOZ_CRASH("64-bit only");
3086 #endif
3089 void LIRGenerator::visitWasmWrapU32Index(MWasmWrapU32Index* ins) {
3090 MDefinition* input = ins->input();
3091 MOZ_ASSERT(input->type() == MIRType::Int64);
3092 MOZ_ASSERT(ins->type() == MIRType::Int32);
3094 // Tricky: On 64-bit, this just returns its input (except on MIPS64 there may
3095 // be a sign/zero extension). On 32-bit, it returns the low register of the
3096 // input, and should generate no code.
3098 // If this assertion does not hold then using "input" unadorned as an alias
3099 // for the low register will not work.
3100 #if defined(JS_NUNBOX32)
3101 static_assert(INT64LOW_INDEX == 0);
3102 #endif
3104 auto* lir = new (alloc()) LWasmWrapU32Index(useRegisterAtStart(input));
3105 defineReuseInput(lir, ins, 0);
3108 void LIRGenerator::visitIntPtrToDouble(MIntPtrToDouble* ins) {
3109 MDefinition* input = ins->input();
3110 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3111 MOZ_ASSERT(ins->type() == MIRType::Double);
3113 auto* lir = new (alloc()) LIntPtrToDouble(useRegister(input));
3114 define(lir, ins);
3117 void LIRGenerator::visitAdjustDataViewLength(MAdjustDataViewLength* ins) {
3118 MDefinition* input = ins->input();
3119 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3121 auto* lir = new (alloc()) LAdjustDataViewLength(useRegisterAtStart(input));
3122 assignSnapshot(lir, ins->bailoutKind());
3123 defineReuseInput(lir, ins, 0);
3126 void LIRGenerator::visitToBigInt(MToBigInt* ins) {
3127 MDefinition* opd = ins->input();
3129 switch (opd->type()) {
3130 case MIRType::Value: {
3131 auto* lir = new (alloc()) LValueToBigInt(useBox(opd));
3132 assignSnapshot(lir, ins->bailoutKind());
3133 define(lir, ins);
3134 assignSafepoint(lir, ins);
3135 break;
3138 case MIRType::BigInt:
3139 redefine(ins, opd);
3140 break;
3142 default:
3143 MOZ_CRASH("unexpected type");
3147 void LIRGenerator::visitToInt64(MToInt64* ins) {
3148 MDefinition* opd = ins->input();
3150 switch (opd->type()) {
3151 case MIRType::Value: {
3152 auto* lir = new (alloc()) LValueToInt64(useBox(opd), temp());
3153 assignSnapshot(lir, ins->bailoutKind());
3154 defineInt64(lir, ins);
3155 assignSafepoint(lir, ins);
3156 break;
3159 case MIRType::Boolean: {
3160 auto* lir = new (alloc()) LBooleanToInt64(useRegisterAtStart(opd));
3161 defineInt64(lir, ins);
3162 break;
3165 case MIRType::String: {
3166 auto* lir = new (alloc()) LStringToInt64(useRegister(opd));
3167 defineInt64(lir, ins);
3168 assignSafepoint(lir, ins);
3169 break;
3172 // An Int64 may be passed here from a BigInt to Int64 conversion.
3173 case MIRType::Int64: {
3174 redefine(ins, opd);
3175 break;
3178 default:
3179 // Undefined, Null, Number, and Symbol throw.
3180 // Objects may be effectful.
3181 // BigInt operands are eliminated by the type policy.
3182 MOZ_CRASH("unexpected type");
3186 void LIRGenerator::visitTruncateBigIntToInt64(MTruncateBigIntToInt64* ins) {
3187 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
3188 auto* lir = new (alloc()) LTruncateBigIntToInt64(useRegister(ins->input()));
3189 defineInt64(lir, ins);
3192 void LIRGenerator::visitInt64ToBigInt(MInt64ToBigInt* ins) {
3193 MOZ_ASSERT(ins->input()->type() == MIRType::Int64);
3194 auto* lir =
3195 new (alloc()) LInt64ToBigInt(useInt64Register(ins->input()), temp());
3196 define(lir, ins);
3197 assignSafepoint(lir, ins);
3200 void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) {
3201 MDefinition* input = ins->input();
3202 switch (input->type()) {
3203 case MIRType::Double:
3204 case MIRType::Float32: {
3205 auto* lir = new (alloc()) LWasmTruncateToInt32(useRegisterAtStart(input));
3206 define(lir, ins);
3207 break;
3209 default:
3210 MOZ_CRASH("unexpected type in WasmTruncateToInt32");
3214 void LIRGenerator::visitWasmBuiltinTruncateToInt32(
3215 MWasmBuiltinTruncateToInt32* truncate) {
3216 mozilla::DebugOnly<MDefinition*> opd = truncate->input();
3217 MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
3219 // May call into JS::ToInt32() on the slow OOL path.
3220 gen->setNeedsStaticStackAlignment();
3221 lowerWasmBuiltinTruncateToInt32(truncate);
3224 void LIRGenerator::visitWasmAnyRefFromJSValue(MWasmAnyRefFromJSValue* ins) {
3225 LWasmAnyRefFromJSValue* lir =
3226 new (alloc()) LWasmAnyRefFromJSValue(useBox(ins->input()), tempDouble());
3227 define(lir, ins);
3228 assignSafepoint(lir, ins);
3231 void LIRGenerator::visitWasmAnyRefFromJSObject(MWasmAnyRefFromJSObject* ins) {
3232 LWasmAnyRefFromJSObject* lir =
3233 new (alloc()) LWasmAnyRefFromJSObject(useRegisterAtStart(ins->input()));
3234 define(lir, ins);
3237 void LIRGenerator::visitWasmAnyRefFromJSString(MWasmAnyRefFromJSString* ins) {
3238 LWasmAnyRefFromJSString* lir =
3239 new (alloc()) LWasmAnyRefFromJSString(useRegisterAtStart(ins->input()));
3240 define(lir, ins);
3243 void LIRGenerator::visitWasmNewI31Ref(MWasmNewI31Ref* ins) {
3244 // If it's a constant, it will be put directly into the register.
3245 LWasmNewI31Ref* lir =
3246 new (alloc()) LWasmNewI31Ref(useRegisterOrConstant(ins->input()));
3247 define(lir, ins);
3250 void LIRGenerator::visitWasmI31RefGet(MWasmI31RefGet* ins) {
3251 LWasmI31RefGet* lir = new (alloc()) LWasmI31RefGet(useRegister(ins->input()));
3252 define(lir, ins);
3255 void LIRGenerator::visitWrapInt64ToInt32(MWrapInt64ToInt32* ins) {
3256 define(new (alloc()) LWrapInt64ToInt32(useInt64AtStart(ins->input())), ins);
3259 void LIRGenerator::visitToString(MToString* ins) {
3260 MDefinition* opd = ins->input();
3262 switch (opd->type()) {
3263 case MIRType::Null: {
3264 const JSAtomState& names = gen->runtime->names();
3265 LPointer* lir = new (alloc()) LPointer(names.null);
3266 define(lir, ins);
3267 break;
3270 case MIRType::Undefined: {
3271 const JSAtomState& names = gen->runtime->names();
3272 LPointer* lir = new (alloc()) LPointer(names.undefined);
3273 define(lir, ins);
3274 break;
3277 case MIRType::Boolean: {
3278 LBooleanToString* lir = new (alloc()) LBooleanToString(useRegister(opd));
3279 define(lir, ins);
3280 break;
3283 case MIRType::Double: {
3284 LDoubleToString* lir =
3285 new (alloc()) LDoubleToString(useRegister(opd), temp());
3287 define(lir, ins);
3288 assignSafepoint(lir, ins);
3289 break;
3292 case MIRType::Int32: {
3293 LIntToString* lir = new (alloc()) LIntToString(useRegister(opd));
3295 define(lir, ins);
3296 assignSafepoint(lir, ins);
3297 break;
3300 case MIRType::String:
3301 redefine(ins, ins->input());
3302 break;
3304 case MIRType::Value: {
3305 LValueToString* lir =
3306 new (alloc()) LValueToString(useBox(opd), tempToUnbox());
3307 if (ins->needsSnapshot()) {
3308 assignSnapshot(lir, ins->bailoutKind());
3310 define(lir, ins);
3311 assignSafepoint(lir, ins);
3312 break;
3315 default:
3316 // Float32, symbols, bigint, and objects are not supported.
3317 MOZ_CRASH("unexpected type");
3321 void LIRGenerator::visitRegExp(MRegExp* ins) {
3322 LRegExp* lir = new (alloc()) LRegExp(temp());
3323 define(lir, ins);
3324 assignSafepoint(lir, ins);
3327 void LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins) {
3328 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3329 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3330 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
3332 LRegExpMatcher* lir = new (alloc()) LRegExpMatcher(
3333 useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
3334 useFixedAtStart(ins->string(), RegExpMatcherStringReg),
3335 useFixedAtStart(ins->lastIndex(), RegExpMatcherLastIndexReg));
3336 defineReturn(lir, ins);
3337 assignSafepoint(lir, ins);
3340 void LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins) {
3341 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3342 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3343 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
3345 LRegExpSearcher* lir = new (alloc()) LRegExpSearcher(
3346 useFixedAtStart(ins->regexp(), RegExpSearcherRegExpReg),
3347 useFixedAtStart(ins->string(), RegExpSearcherStringReg),
3348 useFixedAtStart(ins->lastIndex(), RegExpSearcherLastIndexReg));
3349 defineReturn(lir, ins);
3350 assignSafepoint(lir, ins);
3353 void LIRGenerator::visitRegExpSearcherLastLimit(MRegExpSearcherLastLimit* ins) {
3354 auto* lir = new (alloc()) LRegExpSearcherLastLimit(temp());
3355 define(lir, ins);
3358 void LIRGenerator::visitRegExpExecMatch(MRegExpExecMatch* ins) {
3359 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3360 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3362 auto* lir = new (alloc())
3363 LRegExpExecMatch(useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
3364 useFixedAtStart(ins->string(), RegExpMatcherStringReg));
3365 defineReturn(lir, ins);
3366 assignSafepoint(lir, ins);
3369 void LIRGenerator::visitRegExpExecTest(MRegExpExecTest* ins) {
3370 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3371 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3373 auto* lir = new (alloc())
3374 LRegExpExecTest(useFixedAtStart(ins->regexp(), RegExpExecTestRegExpReg),
3375 useFixedAtStart(ins->string(), RegExpExecTestStringReg));
3376 defineReturn(lir, ins);
3377 assignSafepoint(lir, ins);
3380 void LIRGenerator::visitRegExpHasCaptureGroups(MRegExpHasCaptureGroups* ins) {
3381 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3382 MOZ_ASSERT(ins->input()->type() == MIRType::String);
3383 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3385 auto* lir = new (alloc()) LRegExpHasCaptureGroups(useRegister(ins->regexp()),
3386 useRegister(ins->input()));
3387 define(lir, ins);
3388 assignSafepoint(lir, ins);
3391 void LIRGenerator::visitRegExpPrototypeOptimizable(
3392 MRegExpPrototypeOptimizable* ins) {
3393 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3394 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3395 LRegExpPrototypeOptimizable* lir = new (alloc())
3396 LRegExpPrototypeOptimizable(useRegister(ins->object()), temp());
3397 define(lir, ins);
3400 void LIRGenerator::visitRegExpInstanceOptimizable(
3401 MRegExpInstanceOptimizable* ins) {
3402 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3403 MOZ_ASSERT(ins->proto()->type() == MIRType::Object);
3404 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3405 LRegExpInstanceOptimizable* lir = new (alloc()) LRegExpInstanceOptimizable(
3406 useRegister(ins->object()), useRegister(ins->proto()), temp());
3407 define(lir, ins);
3410 void LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex* ins) {
3411 MOZ_ASSERT(ins->str()->type() == MIRType::String);
3412 MOZ_ASSERT(ins->type() == MIRType::Int32);
3413 LGetFirstDollarIndex* lir = new (alloc())
3414 LGetFirstDollarIndex(useRegister(ins->str()), temp(), temp(), temp());
3415 define(lir, ins);
3416 assignSafepoint(lir, ins);
3419 void LIRGenerator::visitStringReplace(MStringReplace* ins) {
3420 MOZ_ASSERT(ins->pattern()->type() == MIRType::String);
3421 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3422 MOZ_ASSERT(ins->replacement()->type() == MIRType::String);
3424 LStringReplace* lir = new (alloc())
3425 LStringReplace(useRegisterOrConstantAtStart(ins->string()),
3426 useRegisterAtStart(ins->pattern()),
3427 useRegisterOrConstantAtStart(ins->replacement()));
3428 defineReturn(lir, ins);
3429 assignSafepoint(lir, ins);
3432 void LIRGenerator::visitBinaryCache(MBinaryCache* ins) {
3433 MDefinition* lhs = ins->getOperand(0);
3434 MDefinition* rhs = ins->getOperand(1);
3436 MOZ_ASSERT(ins->type() == MIRType::Value || ins->type() == MIRType::Boolean);
3437 LInstruction* lir;
3438 if (ins->type() == MIRType::Value) {
3439 LBinaryValueCache* valueLir = new (alloc()) LBinaryValueCache(
3440 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
3441 defineBox(valueLir, ins);
3442 lir = valueLir;
3443 } else {
3444 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3445 LBinaryBoolCache* boolLir = new (alloc()) LBinaryBoolCache(
3446 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
3447 define(boolLir, ins);
3448 lir = boolLir;
3450 assignSafepoint(lir, ins);
3453 void LIRGenerator::visitUnaryCache(MUnaryCache* ins) {
3454 MDefinition* input = ins->getOperand(0);
3455 MOZ_ASSERT(ins->type() == MIRType::Value);
3457 LUnaryCache* lir = new (alloc()) LUnaryCache(useBox(input));
3458 defineBox(lir, ins);
3459 assignSafepoint(lir, ins);
3462 void LIRGenerator::visitModuleMetadata(MModuleMetadata* ins) {
3463 LModuleMetadata* lir = new (alloc()) LModuleMetadata();
3464 defineReturn(lir, ins);
3465 assignSafepoint(lir, ins);
3468 void LIRGenerator::visitDynamicImport(MDynamicImport* ins) {
3469 LDynamicImport* lir = new (alloc()) LDynamicImport(
3470 useBoxAtStart(ins->specifier()), useBoxAtStart(ins->options()));
3471 defineReturn(lir, ins);
3472 assignSafepoint(lir, ins);
3475 void LIRGenerator::visitLambda(MLambda* ins) {
3476 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3478 auto* lir =
3479 new (alloc()) LLambda(useRegister(ins->environmentChain()), temp());
3480 define(lir, ins);
3481 assignSafepoint(lir, ins);
3484 void LIRGenerator::visitFunctionWithProto(MFunctionWithProto* ins) {
3485 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3486 MOZ_ASSERT(ins->prototype()->type() == MIRType::Object);
3488 auto* lir = new (alloc())
3489 LFunctionWithProto(useRegisterAtStart(ins->environmentChain()),
3490 useRegisterAtStart(ins->prototype()));
3491 defineReturn(lir, ins);
3492 assignSafepoint(lir, ins);
3495 void LIRGenerator::visitSetFunName(MSetFunName* ins) {
3496 MOZ_ASSERT(ins->fun()->type() == MIRType::Object);
3497 MOZ_ASSERT(ins->name()->type() == MIRType::Value);
3499 LSetFunName* lir = new (alloc())
3500 LSetFunName(useRegisterAtStart(ins->fun()), useBoxAtStart(ins->name()));
3501 add(lir, ins);
3502 assignSafepoint(lir, ins);
3505 void LIRGenerator::visitNewLexicalEnvironmentObject(
3506 MNewLexicalEnvironmentObject* ins) {
3507 auto* lir = new (alloc()) LNewLexicalEnvironmentObject(temp());
3509 define(lir, ins);
3510 assignSafepoint(lir, ins);
3513 void LIRGenerator::visitNewClassBodyEnvironmentObject(
3514 MNewClassBodyEnvironmentObject* ins) {
3515 auto* lir = new (alloc()) LNewClassBodyEnvironmentObject(temp());
3517 define(lir, ins);
3518 assignSafepoint(lir, ins);
3521 void LIRGenerator::visitNewVarEnvironmentObject(MNewVarEnvironmentObject* ins) {
3522 auto* lir = new (alloc()) LNewVarEnvironmentObject(temp());
3524 define(lir, ins);
3525 assignSafepoint(lir, ins);
3528 void LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins) {
3529 MDefinition* obj = ins->object();
3530 MOZ_ASSERT(obj->type() == MIRType::Object);
3532 add(new (alloc()) LKeepAliveObject(useKeepalive(obj)), ins);
3535 void LIRGenerator::visitDebugEnterGCUnsafeRegion(
3536 MDebugEnterGCUnsafeRegion* ins) {
3537 add(new (alloc()) LDebugEnterGCUnsafeRegion(temp()), ins);
3540 void LIRGenerator::visitDebugLeaveGCUnsafeRegion(
3541 MDebugLeaveGCUnsafeRegion* ins) {
3542 add(new (alloc()) LDebugLeaveGCUnsafeRegion(temp()), ins);
3545 void LIRGenerator::visitSlots(MSlots* ins) {
3546 define(new (alloc()) LSlots(useRegisterAtStart(ins->object())), ins);
3549 void LIRGenerator::visitElements(MElements* ins) {
3550 define(new (alloc()) LElements(useRegisterAtStart(ins->object())), ins);
3553 void LIRGenerator::visitLoadDynamicSlot(MLoadDynamicSlot* ins) {
3554 MOZ_ASSERT(ins->type() == MIRType::Value);
3555 if (ins->usedAsPropertyKey()) {
3556 auto* lir = new (alloc())
3557 LLoadDynamicSlotAndAtomize(useRegister(ins->slots()), temp());
3558 defineBox(lir, ins);
3559 assignSafepoint(lir, ins);
3560 } else {
3561 defineBox(new (alloc()) LLoadDynamicSlotV(useRegisterAtStart(ins->slots())),
3562 ins);
3566 void LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment* ins) {
3567 define(new (alloc())
3568 LFunctionEnvironment(useRegisterAtStart(ins->function())),
3569 ins);
3572 void LIRGenerator::visitHomeObject(MHomeObject* ins) {
3573 define(new (alloc()) LHomeObject(useRegisterAtStart(ins->function())), ins);
3576 void LIRGenerator::visitHomeObjectSuperBase(MHomeObjectSuperBase* ins) {
3577 MOZ_ASSERT(ins->homeObject()->type() == MIRType::Object);
3578 MOZ_ASSERT(ins->type() == MIRType::Value);
3580 auto lir =
3581 new (alloc()) LHomeObjectSuperBase(useRegisterAtStart(ins->homeObject()));
3582 defineBox(lir, ins);
3585 void LIRGenerator::visitInterruptCheck(MInterruptCheck* ins) {
3586 LInstruction* lir = new (alloc()) LInterruptCheck();
3587 add(lir, ins);
3588 assignSafepoint(lir, ins);
3591 void LIRGenerator::visitWasmInterruptCheck(MWasmInterruptCheck* ins) {
3592 auto* lir =
3593 new (alloc()) LWasmInterruptCheck(useRegisterAtStart(ins->instance()));
3594 add(lir, ins);
3595 assignWasmSafepoint(lir);
3598 void LIRGenerator::visitWasmTrap(MWasmTrap* ins) {
3599 add(new (alloc()) LWasmTrap, ins);
3602 void LIRGenerator::visitWasmTrapIfNull(MWasmTrapIfNull* ins) {
3603 auto* lir = new (alloc()) LWasmTrapIfNull(useRegister(ins->ref()));
3604 add(lir, ins);
3607 void LIRGenerator::visitWasmReinterpret(MWasmReinterpret* ins) {
3608 if (ins->type() == MIRType::Int64) {
3609 defineInt64(new (alloc())
3610 LWasmReinterpretToI64(useRegisterAtStart(ins->input())),
3611 ins);
3612 } else if (ins->input()->type() == MIRType::Int64) {
3613 define(new (alloc())
3614 LWasmReinterpretFromI64(useInt64RegisterAtStart(ins->input())),
3615 ins);
3616 } else {
3617 define(new (alloc()) LWasmReinterpret(useRegisterAtStart(ins->input())),
3618 ins);
3622 void LIRGenerator::visitStoreDynamicSlot(MStoreDynamicSlot* ins) {
3623 LInstruction* lir;
3625 switch (ins->value()->type()) {
3626 case MIRType::Value:
3627 lir = new (alloc())
3628 LStoreDynamicSlotV(useRegister(ins->slots()), useBox(ins->value()));
3629 add(lir, ins);
3630 break;
3632 case MIRType::Double:
3633 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3634 useRegister(ins->value())),
3635 ins);
3636 break;
3638 case MIRType::Float32:
3639 MOZ_CRASH("Float32 shouldn't be stored in a slot.");
3641 default:
3642 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3643 useRegisterOrConstant(ins->value())),
3644 ins);
3645 break;
3649 // Returns true iff |def| is a constant that's either not a GC thing or is not
3650 // allocated in the nursery.
3651 static bool IsNonNurseryConstant(MDefinition* def) {
3652 if (!def->isConstant()) {
3653 return false;
3655 Value v = def->toConstant()->toJSValue();
3656 return !v.isGCThing() || !IsInsideNursery(v.toGCThing());
3659 void LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) {
3660 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3662 // LPostWriteBarrier assumes that if it has a constant object then that
3663 // object is tenured, and does not need to be tested for being in the
3664 // nursery. Ensure that assumption holds by lowering constant nursery
3665 // objects to a register.
3666 bool useConstantObject = IsNonNurseryConstant(ins->object());
3668 switch (ins->value()->type()) {
3669 case MIRType::Object: {
3670 LDefinition tmp =
3671 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3672 LPostWriteBarrierO* lir = new (alloc())
3673 LPostWriteBarrierO(useConstantObject ? useOrConstant(ins->object())
3674 : useRegister(ins->object()),
3675 useRegister(ins->value()), tmp);
3676 add(lir, ins);
3677 assignSafepoint(lir, ins);
3678 break;
3680 case MIRType::String: {
3681 LDefinition tmp =
3682 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3683 LPostWriteBarrierS* lir = new (alloc())
3684 LPostWriteBarrierS(useConstantObject ? useOrConstant(ins->object())
3685 : useRegister(ins->object()),
3686 useRegister(ins->value()), tmp);
3687 add(lir, ins);
3688 assignSafepoint(lir, ins);
3689 break;
3691 case MIRType::BigInt: {
3692 LDefinition tmp =
3693 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3694 auto* lir = new (alloc())
3695 LPostWriteBarrierBI(useConstantObject ? useOrConstant(ins->object())
3696 : useRegister(ins->object()),
3697 useRegister(ins->value()), tmp);
3698 add(lir, ins);
3699 assignSafepoint(lir, ins);
3700 break;
3702 case MIRType::Value: {
3703 LDefinition tmp =
3704 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3705 LPostWriteBarrierV* lir = new (alloc())
3706 LPostWriteBarrierV(useConstantObject ? useOrConstant(ins->object())
3707 : useRegister(ins->object()),
3708 useBox(ins->value()), tmp);
3709 add(lir, ins);
3710 assignSafepoint(lir, ins);
3711 break;
3713 default:
3714 // Currently, only objects and strings can be in the nursery. Other
3715 // instruction types cannot hold nursery pointers.
3716 break;
3720 void LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) {
3721 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3722 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3724 // LPostWriteElementBarrier assumes that if it has a constant object then that
3725 // object is tenured, and does not need to be tested for being in the
3726 // nursery. Ensure that assumption holds by lowering constant nursery
3727 // objects to a register.
3728 bool useConstantObject =
3729 ins->object()->isConstant() &&
3730 !IsInsideNursery(&ins->object()->toConstant()->toObject());
3732 switch (ins->value()->type()) {
3733 case MIRType::Object: {
3734 LDefinition tmp =
3735 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3736 LPostWriteElementBarrierO* lir = new (alloc()) LPostWriteElementBarrierO(
3737 useConstantObject ? useOrConstant(ins->object())
3738 : useRegister(ins->object()),
3739 useRegister(ins->value()), useRegister(ins->index()), tmp);
3740 add(lir, ins);
3741 assignSafepoint(lir, ins);
3742 break;
3744 case MIRType::String: {
3745 LDefinition tmp =
3746 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3747 LPostWriteElementBarrierS* lir = new (alloc()) LPostWriteElementBarrierS(
3748 useConstantObject ? useOrConstant(ins->object())
3749 : useRegister(ins->object()),
3750 useRegister(ins->value()), useRegister(ins->index()), tmp);
3751 add(lir, ins);
3752 assignSafepoint(lir, ins);
3753 break;
3755 case MIRType::BigInt: {
3756 LDefinition tmp =
3757 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3758 auto* lir = new (alloc()) LPostWriteElementBarrierBI(
3759 useConstantObject ? useOrConstant(ins->object())
3760 : useRegister(ins->object()),
3761 useRegister(ins->value()), useRegister(ins->index()), tmp);
3762 add(lir, ins);
3763 assignSafepoint(lir, ins);
3764 break;
3766 case MIRType::Value: {
3767 LDefinition tmp =
3768 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3769 LPostWriteElementBarrierV* lir = new (alloc()) LPostWriteElementBarrierV(
3770 useConstantObject ? useOrConstant(ins->object())
3771 : useRegister(ins->object()),
3772 useRegister(ins->index()), useBox(ins->value()), tmp);
3773 add(lir, ins);
3774 assignSafepoint(lir, ins);
3775 break;
3777 default:
3778 // Currently, only objects, strings, and bigints can be in the nursery.
3779 // Other instruction types cannot hold nursery pointers.
3780 break;
3784 void LIRGenerator::visitAssertCanElidePostWriteBarrier(
3785 MAssertCanElidePostWriteBarrier* ins) {
3786 auto* lir = new (alloc()) LAssertCanElidePostWriteBarrier(
3787 useRegister(ins->object()), useBox(ins->value()), temp());
3788 add(lir, ins);
3791 void LIRGenerator::visitArrayLength(MArrayLength* ins) {
3792 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3793 auto* lir = new (alloc()) LArrayLength(useRegisterAtStart(ins->elements()));
3794 assignSnapshot(lir, ins->bailoutKind());
3795 define(lir, ins);
3798 void LIRGenerator::visitSetArrayLength(MSetArrayLength* ins) {
3799 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3800 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3802 MOZ_ASSERT(ins->index()->isConstant());
3803 add(new (alloc()) LSetArrayLength(useRegister(ins->elements()),
3804 useRegisterOrConstant(ins->index())),
3805 ins);
3808 void LIRGenerator::visitFunctionLength(MFunctionLength* ins) {
3809 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3811 auto* lir = new (alloc()) LFunctionLength(useRegister(ins->function()));
3812 assignSnapshot(lir, ins->bailoutKind());
3813 define(lir, ins);
3816 void LIRGenerator::visitFunctionName(MFunctionName* ins) {
3817 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3819 auto* lir = new (alloc()) LFunctionName(useRegister(ins->function()));
3820 assignSnapshot(lir, ins->bailoutKind());
3821 define(lir, ins);
3824 void LIRGenerator::visitGetNextEntryForIterator(MGetNextEntryForIterator* ins) {
3825 MOZ_ASSERT(ins->iter()->type() == MIRType::Object);
3826 MOZ_ASSERT(ins->result()->type() == MIRType::Object);
3827 auto lir = new (alloc()) LGetNextEntryForIterator(useRegister(ins->iter()),
3828 useRegister(ins->result()),
3829 temp(), temp(), temp());
3830 define(lir, ins);
3833 static auto SynchronizeLoad(MemoryBarrierRequirement requiresBarrier) {
3834 if (requiresBarrier == MemoryBarrierRequirement::Required) {
3835 return Synchronization::Load();
3837 return Synchronization::None();
3840 static auto SynchronizeStore(MemoryBarrierRequirement requiresBarrier) {
3841 if (requiresBarrier == MemoryBarrierRequirement::Required) {
3842 return Synchronization::Store();
3844 return Synchronization::None();
3847 void LIRGenerator::visitArrayBufferByteLength(MArrayBufferByteLength* ins) {
3848 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3849 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3851 auto* lir =
3852 new (alloc()) LArrayBufferByteLength(useRegisterAtStart(ins->object()));
3853 define(lir, ins);
3856 void LIRGenerator::visitArrayBufferViewLength(MArrayBufferViewLength* ins) {
3857 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3858 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3860 auto* lir =
3861 new (alloc()) LArrayBufferViewLength(useRegisterAtStart(ins->object()));
3862 define(lir, ins);
3865 void LIRGenerator::visitArrayBufferViewByteOffset(
3866 MArrayBufferViewByteOffset* ins) {
3867 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3868 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3870 auto* lir = new (alloc())
3871 LArrayBufferViewByteOffset(useRegisterAtStart(ins->object()));
3872 define(lir, ins);
3875 void LIRGenerator::visitArrayBufferViewElements(MArrayBufferViewElements* ins) {
3876 MOZ_ASSERT(ins->type() == MIRType::Elements);
3877 define(new (alloc())
3878 LArrayBufferViewElements(useRegisterAtStart(ins->object())),
3879 ins);
3882 void LIRGenerator::visitTypedArrayElementSize(MTypedArrayElementSize* ins) {
3883 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3884 define(new (alloc())
3885 LTypedArrayElementSize(useRegisterAtStart(ins->object())),
3886 ins);
3889 void LIRGenerator::visitResizableTypedArrayLength(
3890 MResizableTypedArrayLength* ins) {
3891 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3892 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3894 auto sync = SynchronizeLoad(ins->requiresMemoryBarrier());
3895 auto* lir = new (alloc())
3896 LResizableTypedArrayLength(useRegister(ins->object()), temp(), sync);
3897 define(lir, ins);
3900 void LIRGenerator::visitResizableTypedArrayByteOffsetMaybeOutOfBounds(
3901 MResizableTypedArrayByteOffsetMaybeOutOfBounds* ins) {
3902 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3903 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3905 auto* lir = new (alloc()) LResizableTypedArrayByteOffsetMaybeOutOfBounds(
3906 useRegister(ins->object()), temp());
3907 define(lir, ins);
3910 void LIRGenerator::visitResizableDataViewByteLength(
3911 MResizableDataViewByteLength* ins) {
3912 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3913 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3915 auto sync = SynchronizeLoad(ins->requiresMemoryBarrier());
3916 auto* lir = new (alloc())
3917 LResizableDataViewByteLength(useRegister(ins->object()), temp(), sync);
3918 define(lir, ins);
3921 void LIRGenerator::visitGrowableSharedArrayBufferByteLength(
3922 MGrowableSharedArrayBufferByteLength* ins) {
3923 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3924 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3926 auto* lir = new (alloc())
3927 LGrowableSharedArrayBufferByteLength(useRegisterAtStart(ins->object()));
3928 define(lir, ins);
3931 void LIRGenerator::visitGuardResizableArrayBufferViewInBounds(
3932 MGuardResizableArrayBufferViewInBounds* ins) {
3933 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3935 auto* lir = new (alloc()) LGuardResizableArrayBufferViewInBounds(
3936 useRegister(ins->object()), temp());
3937 assignSnapshot(lir, ins->bailoutKind());
3938 add(lir, ins);
3939 redefine(ins, ins->object());
3942 void LIRGenerator::visitGuardResizableArrayBufferViewInBoundsOrDetached(
3943 MGuardResizableArrayBufferViewInBoundsOrDetached* ins) {
3944 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3946 auto* lir = new (alloc()) LGuardResizableArrayBufferViewInBoundsOrDetached(
3947 useRegister(ins->object()), temp());
3948 assignSnapshot(lir, ins->bailoutKind());
3949 add(lir, ins);
3950 redefine(ins, ins->object());
3953 void LIRGenerator::visitGuardHasAttachedArrayBuffer(
3954 MGuardHasAttachedArrayBuffer* ins) {
3955 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3957 auto* lir = new (alloc())
3958 LGuardHasAttachedArrayBuffer(useRegister(ins->object()), temp());
3959 assignSnapshot(lir, ins->bailoutKind());
3960 add(lir, ins);
3961 redefine(ins, ins->object());
3964 void LIRGenerator::visitGuardNumberToIntPtrIndex(
3965 MGuardNumberToIntPtrIndex* ins) {
3966 MDefinition* input = ins->input();
3967 MOZ_ASSERT(input->type() == MIRType::Double);
3969 auto* lir = new (alloc()) LGuardNumberToIntPtrIndex(useRegister(input));
3970 if (!ins->supportOOB()) {
3971 assignSnapshot(lir, ins->bailoutKind());
3973 define(lir, ins);
3976 void LIRGenerator::visitInitializedLength(MInitializedLength* ins) {
3977 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3978 define(new (alloc()) LInitializedLength(useRegisterAtStart(ins->elements())),
3979 ins);
3982 void LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins) {
3983 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3984 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3986 MOZ_ASSERT(ins->index()->isConstant());
3987 add(new (alloc()) LSetInitializedLength(useRegister(ins->elements()),
3988 useRegisterOrConstant(ins->index())),
3989 ins);
3992 void LIRGenerator::visitNot(MNot* ins) {
3993 MDefinition* op = ins->input();
3995 // String is converted to length of string in the type analysis phase (see
3996 // TestPolicy).
3997 MOZ_ASSERT(op->type() != MIRType::String);
3999 // - boolean: x xor 1
4000 // - int32: LCompare(x, 0)
4001 // - double: LCompare(x, 0)
4002 // - null or undefined: true
4003 // - symbol: false
4004 // - bigint: LNotBI(x)
4005 // - object: false if it never emulates undefined, else LNotO(x)
4006 switch (op->type()) {
4007 case MIRType::Boolean: {
4008 MConstant* cons = MConstant::New(alloc(), Int32Value(1));
4009 ins->block()->insertBefore(ins, cons);
4010 lowerForALU(new (alloc()) LBitOpI(JSOp::BitXor), ins, op, cons);
4011 break;
4013 case MIRType::Int32:
4014 define(new (alloc()) LNotI(useRegisterAtStart(op)), ins);
4015 break;
4016 case MIRType::Int64:
4017 define(new (alloc()) LNotI64(useInt64RegisterAtStart(op)), ins);
4018 break;
4019 case MIRType::Double:
4020 define(new (alloc()) LNotD(useRegister(op)), ins);
4021 break;
4022 case MIRType::Float32:
4023 define(new (alloc()) LNotF(useRegister(op)), ins);
4024 break;
4025 case MIRType::Undefined:
4026 case MIRType::Null:
4027 define(new (alloc()) LInteger(1), ins);
4028 break;
4029 case MIRType::Symbol:
4030 define(new (alloc()) LInteger(0), ins);
4031 break;
4032 case MIRType::BigInt:
4033 define(new (alloc()) LNotBI(useRegisterAtStart(op)), ins);
4034 break;
4035 case MIRType::Object:
4036 define(new (alloc()) LNotO(useRegister(op)), ins);
4037 break;
4038 case MIRType::Value: {
4039 auto* lir = new (alloc()) LNotV(useBox(op), tempDouble(), tempToUnbox());
4040 define(lir, ins);
4041 break;
4044 default:
4045 MOZ_CRASH("Unexpected MIRType.");
4049 void LIRGenerator::visitBoundsCheck(MBoundsCheck* ins) {
4050 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
4051 MOZ_ASSERT(ins->index()->type() == ins->type());
4052 MOZ_ASSERT(ins->length()->type() == ins->type());
4054 if (!ins->fallible()) {
4055 return;
4058 LInstruction* check;
4059 if (ins->minimum() || ins->maximum()) {
4060 check = new (alloc())
4061 LBoundsCheckRange(useRegisterOrInt32Constant(ins->index()),
4062 useAny(ins->length()), temp());
4063 } else {
4064 check = new (alloc()) LBoundsCheck(useRegisterOrInt32Constant(ins->index()),
4065 useAnyOrInt32Constant(ins->length()));
4067 assignSnapshot(check, ins->bailoutKind());
4068 add(check, ins);
4071 void LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex* ins) {
4072 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
4073 MOZ_ASSERT(ins->index()->type() == ins->type());
4074 MOZ_ASSERT(ins->length()->type() == ins->type());
4076 auto* lir = new (alloc())
4077 LSpectreMaskIndex(useRegister(ins->index()), useAny(ins->length()));
4078 define(lir, ins);
4081 void LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins) {
4082 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4084 if (!ins->fallible()) {
4085 return;
4088 LInstruction* check =
4089 new (alloc()) LBoundsCheckLower(useRegister(ins->index()));
4090 assignSnapshot(check, ins->bailoutKind());
4091 add(check, ins);
4094 void LIRGenerator::visitInArray(MInArray* ins) {
4095 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4096 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4097 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
4098 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4100 auto* lir = new (alloc()) LInArray(useRegister(ins->elements()),
4101 useRegisterOrConstant(ins->index()),
4102 useRegister(ins->initLength()));
4103 if (ins->needsNegativeIntCheck()) {
4104 assignSnapshot(lir, ins->bailoutKind());
4106 define(lir, ins);
4109 void LIRGenerator::visitGuardElementNotHole(MGuardElementNotHole* ins) {
4110 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4111 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4113 auto* guard = new (alloc())
4114 LGuardElementNotHole(useRegisterAtStart(ins->elements()),
4115 useRegisterOrConstantAtStart(ins->index()));
4116 assignSnapshot(guard, ins->bailoutKind());
4117 add(guard, ins);
4120 void LIRGenerator::visitLoadElement(MLoadElement* ins) {
4121 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4122 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4123 MOZ_ASSERT(ins->type() == MIRType::Value);
4125 auto* lir = new (alloc()) LLoadElementV(useRegister(ins->elements()),
4126 useRegisterOrConstant(ins->index()));
4127 assignSnapshot(lir, ins->bailoutKind());
4128 defineBox(lir, ins);
4131 void LIRGenerator::visitLoadElementHole(MLoadElementHole* ins) {
4132 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4133 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4134 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
4135 MOZ_ASSERT(ins->type() == MIRType::Value);
4137 LLoadElementHole* lir = new (alloc())
4138 LLoadElementHole(useRegister(ins->elements()), useRegister(ins->index()),
4139 useRegister(ins->initLength()));
4140 if (ins->needsNegativeIntCheck()) {
4141 assignSnapshot(lir, ins->bailoutKind());
4143 defineBox(lir, ins);
4146 void LIRGenerator::visitStoreElement(MStoreElement* ins) {
4147 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4148 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4150 const LUse elements = useRegister(ins->elements());
4151 const LAllocation index = useRegisterOrConstant(ins->index());
4153 switch (ins->value()->type()) {
4154 case MIRType::Value: {
4155 LInstruction* lir =
4156 new (alloc()) LStoreElementV(elements, index, useBox(ins->value()));
4157 if (ins->fallible()) {
4158 assignSnapshot(lir, ins->bailoutKind());
4160 add(lir, ins);
4161 break;
4164 default: {
4165 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
4166 LInstruction* lir = new (alloc()) LStoreElementT(elements, index, value);
4167 if (ins->fallible()) {
4168 assignSnapshot(lir, ins->bailoutKind());
4170 add(lir, ins);
4171 break;
4176 void LIRGenerator::visitStoreHoleValueElement(MStoreHoleValueElement* ins) {
4177 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4178 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4180 auto* lir = new (alloc()) LStoreHoleValueElement(useRegister(ins->elements()),
4181 useRegister(ins->index()));
4182 add(lir, ins);
4185 static bool BoundsCheckNeedsSpectreTemp() {
4186 // On x86, spectreBoundsCheck32 can emit better code if it has a scratch
4187 // register and index masking is enabled.
4188 #ifdef JS_CODEGEN_X86
4189 return JitOptions.spectreIndexMasking;
4190 #else
4191 return false;
4192 #endif
4195 void LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) {
4196 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4197 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4199 const LUse object = useRegister(ins->object());
4200 const LUse elements = useRegister(ins->elements());
4201 const LAllocation index = useRegister(ins->index());
4203 LInstruction* lir;
4204 switch (ins->value()->type()) {
4205 case MIRType::Value:
4206 lir = new (alloc()) LStoreElementHoleV(object, elements, index,
4207 useBox(ins->value()), temp());
4208 break;
4210 default: {
4211 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
4212 lir = new (alloc())
4213 LStoreElementHoleT(object, elements, index, value, temp());
4214 break;
4218 assignSnapshot(lir, ins->bailoutKind());
4219 add(lir, ins);
4220 assignSafepoint(lir, ins);
4223 void LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins) {
4224 define(new (alloc()) LEffectiveAddress(useRegister(ins->base()),
4225 useRegister(ins->index())),
4226 ins);
4229 void LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) {
4230 MOZ_ASSERT(ins->type() == MIRType::Value);
4232 auto* lir =
4233 new (alloc()) LArrayPopShift(useRegister(ins->object()), temp(), temp());
4234 assignSnapshot(lir, ins->bailoutKind());
4235 defineBox(lir, ins);
4237 if (ins->mode() == MArrayPopShift::Shift) {
4238 assignSafepoint(lir, ins);
4242 void LIRGenerator::visitArrayPush(MArrayPush* ins) {
4243 MOZ_ASSERT(ins->type() == MIRType::Int32);
4244 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4246 LUse object = useRegister(ins->object());
4248 LDefinition spectreTemp =
4249 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4251 auto* lir = new (alloc())
4252 LArrayPush(object, useBox(ins->value()), temp(), spectreTemp);
4253 // We will bailout before pushing if the length would overflow INT32_MAX.
4254 assignSnapshot(lir, ins->bailoutKind());
4255 define(lir, ins);
4256 assignSafepoint(lir, ins);
4259 void LIRGenerator::visitArraySlice(MArraySlice* ins) {
4260 MOZ_ASSERT(ins->type() == MIRType::Object);
4261 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4262 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4263 MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
4265 LArraySlice* lir = new (alloc()) LArraySlice(
4266 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()),
4267 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0),
4268 tempFixed(CallTempReg1));
4269 assignSnapshot(lir, ins->bailoutKind());
4270 defineReturn(lir, ins);
4271 assignSafepoint(lir, ins);
4274 void LIRGenerator::visitArgumentsSlice(MArgumentsSlice* ins) {
4275 MOZ_ASSERT(ins->type() == MIRType::Object);
4276 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4277 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4278 MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
4280 auto* lir = new (alloc()) LArgumentsSlice(
4281 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()),
4282 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0),
4283 tempFixed(CallTempReg1));
4284 defineReturn(lir, ins);
4285 assignSafepoint(lir, ins);
4288 void LIRGenerator::visitFrameArgumentsSlice(MFrameArgumentsSlice* ins) {
4289 MOZ_ASSERT(ins->type() == MIRType::Object);
4290 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4291 MOZ_ASSERT(ins->count()->type() == MIRType::Int32);
4293 auto* lir = new (alloc()) LFrameArgumentsSlice(
4294 useRegister(ins->begin()), useRegister(ins->count()), temp());
4295 define(lir, ins);
4296 assignSafepoint(lir, ins);
4299 void LIRGenerator::visitInlineArgumentsSlice(MInlineArgumentsSlice* ins) {
4300 LAllocation begin = useRegisterOrConstant(ins->begin());
4301 LAllocation count = useRegisterOrConstant(ins->count());
4302 uint32_t numActuals = ins->numActuals();
4303 uint32_t numOperands =
4304 numActuals * BOX_PIECES + LInlineArgumentsSlice::NumNonArgumentOperands;
4306 auto* lir = allocateVariadic<LInlineArgumentsSlice>(numOperands, temp());
4307 if (!lir) {
4308 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitInlineArgumentsSlice");
4309 return;
4312 lir->setOperand(LInlineArgumentsSlice::Begin, begin);
4313 lir->setOperand(LInlineArgumentsSlice::Count, count);
4314 for (uint32_t i = 0; i < numActuals; i++) {
4315 MDefinition* arg = ins->getArg(i);
4316 uint32_t index = LInlineArgumentsSlice::ArgIndex(i);
4317 lir->setBoxOperand(index,
4318 useBoxOrTypedOrConstant(arg, /*useConstant = */ true));
4320 define(lir, ins);
4321 assignSafepoint(lir, ins);
4324 void LIRGenerator::visitNormalizeSliceTerm(MNormalizeSliceTerm* ins) {
4325 MOZ_ASSERT(ins->type() == MIRType::Int32);
4326 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4327 MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
4329 auto* lir = new (alloc()) LNormalizeSliceTerm(useRegister(ins->value()),
4330 useRegister(ins->length()));
4331 define(lir, ins);
4334 void LIRGenerator::visitArrayJoin(MArrayJoin* ins) {
4335 MOZ_ASSERT(ins->type() == MIRType::String);
4336 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
4337 MOZ_ASSERT(ins->sep()->type() == MIRType::String);
4339 auto* lir = new (alloc())
4340 LArrayJoin(useRegisterAtStart(ins->array()),
4341 useRegisterAtStart(ins->sep()), tempFixed(CallTempReg0));
4342 defineReturn(lir, ins);
4343 assignSafepoint(lir, ins);
4346 void LIRGenerator::visitObjectKeys(MObjectKeys* ins) {
4347 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4348 MOZ_ASSERT(ins->type() == MIRType::Object);
4350 auto* lir = new (alloc()) LObjectKeys(useRegisterAtStart(ins->object()));
4351 defineReturn(lir, ins);
4352 assignSafepoint(lir, ins);
4355 void LIRGenerator::visitObjectKeysLength(MObjectKeysLength* ins) {
4356 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4357 MOZ_ASSERT(ins->type() == MIRType::Int32);
4359 auto* lir =
4360 new (alloc()) LObjectKeysLength(useRegisterAtStart(ins->object()));
4361 defineReturn(lir, ins);
4362 assignSafepoint(lir, ins);
4365 void LIRGenerator::visitStringSplit(MStringSplit* ins) {
4366 MOZ_ASSERT(ins->type() == MIRType::Object);
4367 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4368 MOZ_ASSERT(ins->separator()->type() == MIRType::String);
4370 LStringSplit* lir = new (alloc()) LStringSplit(
4371 useRegisterAtStart(ins->string()), useRegisterAtStart(ins->separator()));
4372 defineReturn(lir, ins);
4373 assignSafepoint(lir, ins);
4376 void LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) {
4377 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4378 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4379 MOZ_ASSERT(IsNumericType(ins->type()) || ins->type() == MIRType::Boolean);
4381 auto sync = SynchronizeLoad(ins->requiresMemoryBarrier());
4383 if (Scalar::isBigIntType(ins->storageType()) && !sync.isNone()) {
4384 lowerAtomicLoad64(ins);
4385 return;
4388 const LUse elements = useRegister(ins->elements());
4389 const LAllocation index = useRegisterOrIndexConstant(
4390 ins->index(), ins->storageType(), ins->offsetAdjustment());
4392 // NOTE: the generated code must match the assembly code in gen_load in
4393 // GenerateAtomicOperations.py
4394 if (!sync.isNone()) {
4395 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
4396 add(fence, ins);
4399 if (!Scalar::isBigIntType(ins->storageType())) {
4400 // We need a temp register for Uint32Array with known double result.
4401 LDefinition tempDef = LDefinition::BogusTemp();
4402 if (ins->storageType() == Scalar::Uint32 &&
4403 IsFloatingPointType(ins->type())) {
4404 tempDef = temp();
4407 auto* lir = new (alloc()) LLoadUnboxedScalar(elements, index, tempDef);
4408 if (ins->fallible()) {
4409 assignSnapshot(lir, ins->bailoutKind());
4411 define(lir, ins);
4412 } else {
4413 MOZ_ASSERT(ins->type() == MIRType::BigInt);
4415 auto* lir =
4416 new (alloc()) LLoadUnboxedBigInt(elements, index, temp(), tempInt64());
4417 define(lir, ins);
4418 assignSafepoint(lir, ins);
4421 if (!sync.isNone()) {
4422 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
4423 add(fence, ins);
4427 void LIRGenerator::visitLoadDataViewElement(MLoadDataViewElement* ins) {
4428 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4429 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4431 MOZ_ASSERT(IsNumericType(ins->type()));
4433 const LUse elements = useRegister(ins->elements());
4434 const LUse index = useRegister(ins->index());
4435 const LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
4437 // We need a temp register for:
4438 // - Uint32Array with known double result,
4439 // - Float32Array,
4440 // - and BigInt64Array and BigUint64Array.
4441 LDefinition tempDef = LDefinition::BogusTemp();
4442 if ((ins->storageType() == Scalar::Uint32 &&
4443 IsFloatingPointType(ins->type())) ||
4444 ins->storageType() == Scalar::Float32) {
4445 tempDef = temp();
4447 if (Scalar::isBigIntType(ins->storageType())) {
4448 #ifdef JS_CODEGEN_X86
4449 // There are not enough registers on x86.
4450 if (littleEndian.isConstant()) {
4451 tempDef = temp();
4453 #else
4454 tempDef = temp();
4455 #endif
4458 // We also need a separate 64-bit temp register for:
4459 // - Float64Array
4460 // - and BigInt64Array and BigUint64Array.
4461 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
4462 if (Scalar::byteSize(ins->storageType()) == 8) {
4463 temp64Def = tempInt64();
4466 auto* lir = new (alloc())
4467 LLoadDataViewElement(elements, index, littleEndian, tempDef, temp64Def);
4468 if (ins->fallible()) {
4469 assignSnapshot(lir, ins->bailoutKind());
4471 define(lir, ins);
4472 if (Scalar::isBigIntType(ins->storageType())) {
4473 assignSafepoint(lir, ins);
4477 void LIRGenerator::visitClampToUint8(MClampToUint8* ins) {
4478 MDefinition* in = ins->input();
4480 switch (in->type()) {
4481 case MIRType::Boolean:
4482 redefine(ins, in);
4483 break;
4485 case MIRType::Int32:
4486 defineReuseInput(new (alloc()) LClampIToUint8(useRegisterAtStart(in)),
4487 ins, 0);
4488 break;
4490 case MIRType::Double:
4491 // LClampDToUint8 clobbers its input register. Making it available as
4492 // a temp copy describes this behavior to the register allocator.
4493 define(new (alloc())
4494 LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)),
4495 ins);
4496 break;
4498 case MIRType::Value: {
4499 LClampVToUint8* lir =
4500 new (alloc()) LClampVToUint8(useBox(in), tempDouble());
4501 assignSnapshot(lir, ins->bailoutKind());
4502 define(lir, ins);
4503 assignSafepoint(lir, ins);
4504 break;
4507 default:
4508 MOZ_CRASH("unexpected type");
4512 void LIRGenerator::visitLoadTypedArrayElementHole(
4513 MLoadTypedArrayElementHole* ins) {
4514 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4515 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4516 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr);
4518 MOZ_ASSERT(ins->type() == MIRType::Value);
4520 const LUse elements = useRegister(ins->elements());
4521 const LAllocation index = useRegister(ins->index());
4522 const LAllocation length = useRegister(ins->length());
4524 if (!Scalar::isBigIntType(ins->arrayType())) {
4525 auto* lir =
4526 new (alloc()) LLoadTypedArrayElementHole(elements, index, length);
4527 if (ins->fallible()) {
4528 assignSnapshot(lir, ins->bailoutKind());
4530 defineBox(lir, ins);
4531 } else {
4532 #ifdef JS_CODEGEN_X86
4533 LInt64Definition temp64 = LInt64Definition::BogusTemp();
4534 #else
4535 LInt64Definition temp64 = tempInt64();
4536 #endif
4538 auto* lir = new (alloc()) LLoadTypedArrayElementHoleBigInt(
4539 elements, index, length, temp(), temp64);
4540 defineBox(lir, ins);
4541 assignSafepoint(lir, ins);
4545 void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) {
4546 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4547 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4549 if (ins->isFloatWrite()) {
4550 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
4551 ins->value()->type() == MIRType::Float32);
4552 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
4553 ins->value()->type() == MIRType::Double);
4554 } else if (ins->isBigIntWrite()) {
4555 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4556 } else {
4557 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4560 auto sync = SynchronizeStore(ins->requiresMemoryBarrier());
4562 if (ins->isBigIntWrite() && !sync.isNone()) {
4563 lowerAtomicStore64(ins);
4564 return;
4567 LUse elements = useRegister(ins->elements());
4568 LAllocation index =
4569 useRegisterOrIndexConstant(ins->index(), ins->writeType());
4570 LAllocation value;
4572 // For byte arrays, the value has to be in a byte register on x86.
4573 if (ins->isByteWrite()) {
4574 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
4575 } else if (ins->isBigIntWrite()) {
4576 value = useRegister(ins->value());
4577 } else {
4578 value = useRegisterOrNonDoubleConstant(ins->value());
4581 // Optimization opportunity for atomics: on some platforms there
4582 // is a store instruction that incorporates the necessary
4583 // barriers, and we could use that instead of separate barrier and
4584 // store instructions. See bug #1077027.
4586 // NOTE: the generated code must match the assembly code in gen_store in
4587 // GenerateAtomicOperations.py
4588 if (!sync.isNone()) {
4589 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
4590 add(fence, ins);
4592 if (!ins->isBigIntWrite()) {
4593 add(new (alloc()) LStoreUnboxedScalar(elements, index, value), ins);
4594 } else {
4595 add(new (alloc()) LStoreUnboxedBigInt(elements, index, value, tempInt64()),
4596 ins);
4598 if (!sync.isNone()) {
4599 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
4600 add(fence, ins);
4604 void LIRGenerator::visitStoreDataViewElement(MStoreDataViewElement* ins) {
4605 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4606 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4607 MOZ_ASSERT(ins->littleEndian()->type() == MIRType::Boolean);
4609 if (ins->isFloatWrite()) {
4610 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
4611 ins->value()->type() == MIRType::Float32);
4612 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
4613 ins->value()->type() == MIRType::Double);
4614 } else if (ins->isBigIntWrite()) {
4615 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4616 } else {
4617 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4620 LUse elements = useRegister(ins->elements());
4621 LUse index = useRegister(ins->index());
4622 LAllocation value;
4623 if (ins->isBigIntWrite()) {
4624 value = useRegister(ins->value());
4625 } else {
4626 value = useRegisterOrNonDoubleConstant(ins->value());
4628 LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
4630 LDefinition tempDef = LDefinition::BogusTemp();
4631 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
4632 if (Scalar::byteSize(ins->writeType()) < 8) {
4633 tempDef = temp();
4634 } else {
4635 temp64Def = tempInt64();
4638 add(new (alloc()) LStoreDataViewElement(elements, index, value, littleEndian,
4639 tempDef, temp64Def),
4640 ins);
4643 void LIRGenerator::visitStoreTypedArrayElementHole(
4644 MStoreTypedArrayElementHole* ins) {
4645 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4646 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4647 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr);
4649 if (ins->isFloatWrite()) {
4650 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32,
4651 ins->value()->type() == MIRType::Float32);
4652 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64,
4653 ins->value()->type() == MIRType::Double);
4654 } else if (ins->isBigIntWrite()) {
4655 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4656 } else {
4657 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4660 LUse elements = useRegister(ins->elements());
4661 LAllocation length = useAny(ins->length());
4662 LAllocation index = useRegister(ins->index());
4664 // For byte arrays, the value has to be in a byte register on x86.
4665 LAllocation value;
4666 if (ins->isByteWrite()) {
4667 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
4668 } else if (ins->isBigIntWrite()) {
4669 value = useRegister(ins->value());
4670 } else {
4671 value = useRegisterOrNonDoubleConstant(ins->value());
4674 if (!ins->isBigIntWrite()) {
4675 LDefinition spectreTemp =
4676 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4677 auto* lir = new (alloc()) LStoreTypedArrayElementHole(
4678 elements, length, index, value, spectreTemp);
4679 add(lir, ins);
4680 } else {
4681 auto* lir = new (alloc()) LStoreTypedArrayElementHoleBigInt(
4682 elements, length, index, value, tempInt64());
4683 add(lir, ins);
4687 void LIRGenerator::visitLoadScriptedProxyHandler(
4688 MLoadScriptedProxyHandler* ins) {
4689 LLoadScriptedProxyHandler* lir = new (alloc())
4690 LLoadScriptedProxyHandler(useRegisterAtStart(ins->object()));
4691 assignSnapshot(lir, ins->bailoutKind());
4692 define(lir, ins);
4695 void LIRGenerator::visitIdToStringOrSymbol(MIdToStringOrSymbol* ins) {
4696 LIdToStringOrSymbol* lir =
4697 new (alloc()) LIdToStringOrSymbol(useBoxAtStart(ins->idVal()), temp());
4698 assignSnapshot(lir, ins->bailoutKind());
4699 defineBox(lir, ins);
4700 assignSafepoint(lir, ins);
4703 void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins) {
4704 MDefinition* obj = ins->object();
4705 MOZ_ASSERT(obj->type() == MIRType::Object);
4707 MIRType type = ins->type();
4709 if (type == MIRType::Value) {
4710 if (ins->usedAsPropertyKey()) {
4711 LLoadFixedSlotAndAtomize* lir =
4712 new (alloc()) LLoadFixedSlotAndAtomize(useRegister(obj), temp());
4713 defineBox(lir, ins);
4714 assignSafepoint(lir, ins);
4715 } else {
4716 LLoadFixedSlotV* lir =
4717 new (alloc()) LLoadFixedSlotV(useRegisterAtStart(obj));
4718 defineBox(lir, ins);
4720 } else {
4721 LLoadFixedSlotT* lir =
4722 new (alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj, type));
4723 define(lir, ins);
4727 void LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) {
4728 MDefinition* obj = ins->object();
4729 MOZ_ASSERT(obj->type() == MIRType::Object);
4731 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) {
4732 LLoadFixedSlotUnboxAndAtomize* lir =
4733 new (alloc()) LLoadFixedSlotUnboxAndAtomize(useRegister(obj));
4734 if (ins->fallible()) {
4735 assignSnapshot(lir, ins->bailoutKind());
4737 define(lir, ins);
4738 assignSafepoint(lir, ins);
4739 } else {
4740 LLoadFixedSlotAndUnbox* lir =
4741 new (alloc()) LLoadFixedSlotAndUnbox(useRegisterAtStart(obj));
4742 if (ins->fallible()) {
4743 assignSnapshot(lir, ins->bailoutKind());
4745 define(lir, ins);
4749 void LIRGenerator::visitLoadDynamicSlotAndUnbox(MLoadDynamicSlotAndUnbox* ins) {
4750 MDefinition* slots = ins->slots();
4751 MOZ_ASSERT(slots->type() == MIRType::Slots);
4753 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) {
4754 auto* lir =
4755 new (alloc()) LLoadDynamicSlotUnboxAndAtomize(useRegister(slots));
4756 if (ins->fallible()) {
4757 assignSnapshot(lir, ins->bailoutKind());
4759 define(lir, ins);
4760 assignSafepoint(lir, ins);
4761 } else {
4762 auto* lir =
4763 new (alloc()) LLoadDynamicSlotAndUnbox(useRegisterAtStart(slots));
4764 if (ins->fallible()) {
4765 assignSnapshot(lir, ins->bailoutKind());
4767 define(lir, ins);
4771 void LIRGenerator::visitLoadElementAndUnbox(MLoadElementAndUnbox* ins) {
4772 MDefinition* elements = ins->elements();
4773 MDefinition* index = ins->index();
4774 MOZ_ASSERT(elements->type() == MIRType::Elements);
4775 MOZ_ASSERT(index->type() == MIRType::Int32);
4777 auto* lir = new (alloc())
4778 LLoadElementAndUnbox(useRegister(elements), useRegisterOrConstant(index));
4779 if (ins->fallible()) {
4780 assignSnapshot(lir, ins->bailoutKind());
4782 define(lir, ins);
4785 void LIRGenerator::visitAddAndStoreSlot(MAddAndStoreSlot* ins) {
4786 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4788 LDefinition maybeTemp = LDefinition::BogusTemp();
4789 if (ins->kind() != MAddAndStoreSlot::Kind::FixedSlot) {
4790 maybeTemp = temp();
4793 auto* lir = new (alloc()) LAddAndStoreSlot(useRegister(ins->object()),
4794 useBox(ins->value()), maybeTemp);
4795 add(lir, ins);
4798 void LIRGenerator::visitAllocateAndStoreSlot(MAllocateAndStoreSlot* ins) {
4799 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4801 auto* lir = new (alloc()) LAllocateAndStoreSlot(
4802 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()),
4803 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
4804 assignSnapshot(lir, ins->bailoutKind());
4805 add(lir, ins);
4808 void LIRGenerator::visitAddSlotAndCallAddPropHook(
4809 MAddSlotAndCallAddPropHook* ins) {
4810 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4811 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4813 auto* lir = new (alloc()) LAddSlotAndCallAddPropHook(
4814 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()));
4815 add(lir, ins);
4816 assignSafepoint(lir, ins);
4819 void LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins) {
4820 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4822 if (ins->value()->type() == MIRType::Value) {
4823 LStoreFixedSlotV* lir = new (alloc())
4824 LStoreFixedSlotV(useRegister(ins->object()), useBox(ins->value()));
4825 add(lir, ins);
4826 } else {
4827 LStoreFixedSlotT* lir = new (alloc()) LStoreFixedSlotT(
4828 useRegister(ins->object()), useRegisterOrConstant(ins->value()));
4829 add(lir, ins);
4833 void LIRGenerator::visitGetNameCache(MGetNameCache* ins) {
4834 MOZ_ASSERT(ins->envObj()->type() == MIRType::Object);
4836 // Emit an overrecursed check: this is necessary because the cache can
4837 // attach a scripted getter stub that calls this script recursively.
4838 gen->setNeedsOverrecursedCheck();
4840 LGetNameCache* lir =
4841 new (alloc()) LGetNameCache(useRegister(ins->envObj()), temp());
4842 defineBox(lir, ins);
4843 assignSafepoint(lir, ins);
4846 void LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins) {
4847 LCallGetIntrinsicValue* lir = new (alloc()) LCallGetIntrinsicValue();
4848 defineReturn(lir, ins);
4849 assignSafepoint(lir, ins);
4852 void LIRGenerator::visitGetPropSuperCache(MGetPropSuperCache* ins) {
4853 MDefinition* obj = ins->object();
4854 MDefinition* receiver = ins->receiver();
4855 MDefinition* id = ins->idval();
4857 gen->setNeedsOverrecursedCheck();
4859 bool useConstId =
4860 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4862 auto* lir = new (alloc())
4863 LGetPropSuperCache(useRegister(obj), useBoxOrTyped(receiver),
4864 useBoxOrTypedOrConstant(id, useConstId));
4865 defineBox(lir, ins);
4866 assignSafepoint(lir, ins);
4869 void LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) {
4870 MDefinition* value = ins->value();
4871 MOZ_ASSERT(value->type() == MIRType::Object ||
4872 value->type() == MIRType::Value);
4874 MDefinition* id = ins->idval();
4875 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
4876 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
4878 // Emit an overrecursed check: this is necessary because the cache can
4879 // attach a scripted getter stub that calls this script recursively.
4880 gen->setNeedsOverrecursedCheck();
4882 // If this is a GetProp, the id is a constant string. Allow passing it as a
4883 // constant to reduce register allocation pressure.
4884 bool useConstId =
4885 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4887 auto* lir = new (alloc()) LGetPropertyCache(
4888 useBoxOrTyped(value), useBoxOrTypedOrConstant(id, useConstId));
4889 defineBox(lir, ins);
4890 assignSafepoint(lir, ins);
4893 void LIRGenerator::visitBindNameCache(MBindNameCache* ins) {
4894 MOZ_ASSERT(ins->envChain()->type() == MIRType::Object);
4895 MOZ_ASSERT(ins->type() == MIRType::Object);
4897 LBindNameCache* lir =
4898 new (alloc()) LBindNameCache(useRegister(ins->envChain()), temp());
4899 define(lir, ins);
4900 assignSafepoint(lir, ins);
4903 void LIRGenerator::visitCallBindVar(MCallBindVar* ins) {
4904 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
4905 MOZ_ASSERT(ins->type() == MIRType::Object);
4907 LCallBindVar* lir =
4908 new (alloc()) LCallBindVar(useRegister(ins->environmentChain()));
4909 define(lir, ins);
4912 void LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins) {
4913 LGuardObjectIdentity* guard = new (alloc()) LGuardObjectIdentity(
4914 useRegister(ins->object()), useRegister(ins->expected()));
4915 assignSnapshot(guard, ins->bailoutKind());
4916 add(guard, ins);
4917 redefine(ins, ins->object());
4920 void LIRGenerator::visitGuardSpecificFunction(MGuardSpecificFunction* ins) {
4921 auto* guard = new (alloc()) LGuardSpecificFunction(
4922 useRegister(ins->function()), useRegister(ins->expected()));
4923 assignSnapshot(guard, ins->bailoutKind());
4924 add(guard, ins);
4925 redefine(ins, ins->function());
4928 void LIRGenerator::visitGuardSpecificAtom(MGuardSpecificAtom* ins) {
4929 auto* guard =
4930 new (alloc()) LGuardSpecificAtom(useRegister(ins->str()), temp());
4931 assignSnapshot(guard, ins->bailoutKind());
4932 add(guard, ins);
4933 redefine(ins, ins->str());
4934 assignSafepoint(guard, ins);
4937 void LIRGenerator::visitGuardSpecificSymbol(MGuardSpecificSymbol* ins) {
4938 auto* guard = new (alloc()) LGuardSpecificSymbol(useRegister(ins->symbol()));
4939 assignSnapshot(guard, ins->bailoutKind());
4940 add(guard, ins);
4941 redefine(ins, ins->symbol());
4944 void LIRGenerator::visitGuardSpecificInt32(MGuardSpecificInt32* ins) {
4945 auto* guard = new (alloc()) LGuardSpecificInt32(useRegister(ins->num()));
4946 assignSnapshot(guard, ins->bailoutKind());
4947 add(guard, ins);
4948 redefine(ins, ins->num());
4951 void LIRGenerator::visitGuardStringToIndex(MGuardStringToIndex* ins) {
4952 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4953 auto* guard = new (alloc()) LGuardStringToIndex(useRegister(ins->string()));
4954 assignSnapshot(guard, ins->bailoutKind());
4955 define(guard, ins);
4956 assignSafepoint(guard, ins);
4959 void LIRGenerator::visitGuardStringToInt32(MGuardStringToInt32* ins) {
4960 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4961 auto* guard =
4962 new (alloc()) LGuardStringToInt32(useRegister(ins->string()), temp());
4963 assignSnapshot(guard, ins->bailoutKind());
4964 define(guard, ins);
4965 assignSafepoint(guard, ins);
4968 void LIRGenerator::visitGuardStringToDouble(MGuardStringToDouble* ins) {
4969 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4970 auto* guard = new (alloc())
4971 LGuardStringToDouble(useRegister(ins->string()), temp(), temp());
4972 assignSnapshot(guard, ins->bailoutKind());
4973 define(guard, ins);
4974 assignSafepoint(guard, ins);
4977 void LIRGenerator::visitGuardNoDenseElements(MGuardNoDenseElements* ins) {
4978 auto* guard =
4979 new (alloc()) LGuardNoDenseElements(useRegister(ins->object()), temp());
4980 assignSnapshot(guard, ins->bailoutKind());
4981 add(guard, ins);
4982 redefine(ins, ins->object());
4985 void LIRGenerator::visitGuardShape(MGuardShape* ins) {
4986 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4988 if (JitOptions.spectreObjectMitigations) {
4989 auto* lir =
4990 new (alloc()) LGuardShape(useRegisterAtStart(ins->object()), temp());
4991 assignSnapshot(lir, ins->bailoutKind());
4992 defineReuseInput(lir, ins, 0);
4993 } else {
4994 auto* lir = new (alloc())
4995 LGuardShape(useRegister(ins->object()), LDefinition::BogusTemp());
4996 assignSnapshot(lir, ins->bailoutKind());
4997 add(lir, ins);
4998 redefine(ins, ins->object());
5002 void LIRGenerator::visitGuardMultipleShapes(MGuardMultipleShapes* ins) {
5003 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5005 if (JitOptions.spectreObjectMitigations) {
5006 auto* lir = new (alloc()) LGuardMultipleShapes(
5007 useRegisterAtStart(ins->object()), useRegister(ins->shapeList()),
5008 temp(), temp(), temp(), temp());
5009 assignSnapshot(lir, ins->bailoutKind());
5010 defineReuseInput(lir, ins, 0);
5011 } else {
5012 auto* lir = new (alloc()) LGuardMultipleShapes(
5013 useRegister(ins->object()), useRegister(ins->shapeList()), temp(),
5014 temp(), temp(), LDefinition::BogusTemp());
5015 assignSnapshot(lir, ins->bailoutKind());
5016 add(lir, ins);
5017 redefine(ins, ins->object());
5021 void LIRGenerator::visitGuardProto(MGuardProto* ins) {
5022 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5023 MOZ_ASSERT(ins->expected()->type() == MIRType::Object);
5025 auto* lir = new (alloc()) LGuardProto(useRegister(ins->object()),
5026 useRegister(ins->expected()), temp());
5027 assignSnapshot(lir, ins->bailoutKind());
5028 add(lir, ins);
5029 redefine(ins, ins->object());
5032 void LIRGenerator::visitGuardNullProto(MGuardNullProto* ins) {
5033 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5035 auto* lir = new (alloc()) LGuardNullProto(useRegister(ins->object()), temp());
5036 assignSnapshot(lir, ins->bailoutKind());
5037 add(lir, ins);
5038 redefine(ins, ins->object());
5041 void LIRGenerator::visitGuardIsNativeObject(MGuardIsNativeObject* ins) {
5042 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5044 auto* lir =
5045 new (alloc()) LGuardIsNativeObject(useRegister(ins->object()), temp());
5046 assignSnapshot(lir, ins->bailoutKind());
5047 add(lir, ins);
5048 redefine(ins, ins->object());
5051 void LIRGenerator::visitGuardGlobalGeneration(MGuardGlobalGeneration* ins) {
5052 auto* lir = new (alloc()) LGuardGlobalGeneration(temp());
5053 assignSnapshot(lir, ins->bailoutKind());
5054 add(lir, ins);
5057 void LIRGenerator::visitGuardFuse(MGuardFuse* ins) {
5058 auto* lir = new (alloc()) LGuardFuse(temp());
5059 assignSnapshot(lir, ins->bailoutKind());
5060 add(lir, ins);
5063 void LIRGenerator::visitGuardIsProxy(MGuardIsProxy* ins) {
5064 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5066 auto* lir = new (alloc()) LGuardIsProxy(useRegister(ins->object()), temp());
5067 assignSnapshot(lir, ins->bailoutKind());
5068 add(lir, ins);
5069 redefine(ins, ins->object());
5072 void LIRGenerator::visitGuardIsNotProxy(MGuardIsNotProxy* ins) {
5073 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5075 auto* lir =
5076 new (alloc()) LGuardIsNotProxy(useRegister(ins->object()), temp());
5077 assignSnapshot(lir, ins->bailoutKind());
5078 add(lir, ins);
5079 redefine(ins, ins->object());
5082 void LIRGenerator::visitGuardIsNotDOMProxy(MGuardIsNotDOMProxy* ins) {
5083 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5085 auto* lir =
5086 new (alloc()) LGuardIsNotDOMProxy(useRegister(ins->proxy()), temp());
5087 assignSnapshot(lir, ins->bailoutKind());
5088 add(lir, ins);
5089 redefine(ins, ins->proxy());
5092 void LIRGenerator::visitProxyGet(MProxyGet* ins) {
5093 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5094 auto* lir = new (alloc())
5095 LProxyGet(useRegisterAtStart(ins->proxy()), tempFixed(CallTempReg0));
5096 defineReturn(lir, ins);
5097 assignSafepoint(lir, ins);
5100 void LIRGenerator::visitProxyGetByValue(MProxyGetByValue* ins) {
5101 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5102 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5103 auto* lir = new (alloc()) LProxyGetByValue(useRegisterAtStart(ins->proxy()),
5104 useBoxAtStart(ins->idVal()));
5105 defineReturn(lir, ins);
5106 assignSafepoint(lir, ins);
5109 void LIRGenerator::visitProxyHasProp(MProxyHasProp* ins) {
5110 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5111 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5112 auto* lir = new (alloc()) LProxyHasProp(useRegisterAtStart(ins->proxy()),
5113 useBoxAtStart(ins->idVal()));
5114 defineReturn(lir, ins);
5115 assignSafepoint(lir, ins);
5118 void LIRGenerator::visitProxySet(MProxySet* ins) {
5119 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5120 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5121 auto* lir = new (alloc())
5122 LProxySet(useRegisterAtStart(ins->proxy()), useBoxAtStart(ins->rhs()),
5123 tempFixed(CallTempReg0));
5124 add(lir, ins);
5125 assignSafepoint(lir, ins);
5128 void LIRGenerator::visitProxySetByValue(MProxySetByValue* ins) {
5129 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5130 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5131 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5132 auto* lir = new (alloc())
5133 LProxySetByValue(useRegisterAtStart(ins->proxy()),
5134 useBoxAtStart(ins->idVal()), useBoxAtStart(ins->rhs()));
5135 add(lir, ins);
5136 assignSafepoint(lir, ins);
5139 void LIRGenerator::visitCallSetArrayLength(MCallSetArrayLength* ins) {
5140 MOZ_ASSERT(ins->obj()->type() == MIRType::Object);
5141 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5142 auto* lir = new (alloc()) LCallSetArrayLength(useRegisterAtStart(ins->obj()),
5143 useBoxAtStart(ins->rhs()));
5144 add(lir, ins);
5145 assignSafepoint(lir, ins);
5148 void LIRGenerator::visitMegamorphicLoadSlot(MMegamorphicLoadSlot* ins) {
5149 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5150 auto* lir = new (alloc())
5151 LMegamorphicLoadSlot(useRegisterAtStart(ins->object()),
5152 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5153 tempFixed(CallTempReg2), tempFixed(CallTempReg3));
5154 assignSnapshot(lir, ins->bailoutKind());
5155 defineReturn(lir, ins);
5158 void LIRGenerator::visitMegamorphicLoadSlotByValue(
5159 MMegamorphicLoadSlotByValue* ins) {
5160 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5161 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5162 auto* lir = new (alloc()) LMegamorphicLoadSlotByValue(
5163 useRegisterAtStart(ins->object()), useBoxAtStart(ins->idVal()),
5164 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5165 tempFixed(CallTempReg2));
5166 assignSnapshot(lir, ins->bailoutKind());
5167 defineReturn(lir, ins);
5170 void LIRGenerator::visitMegamorphicStoreSlot(MMegamorphicStoreSlot* ins) {
5171 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5172 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5174 #ifdef JS_CODEGEN_X86
5175 auto* lir = new (alloc()) LMegamorphicStoreSlot(
5176 useFixedAtStart(ins->object(), CallTempReg0),
5177 useBoxFixedAtStart(ins->rhs(), CallTempReg1, CallTempReg2),
5178 tempFixed(CallTempReg5));
5179 #else
5180 auto* lir = new (alloc())
5181 LMegamorphicStoreSlot(useRegisterAtStart(ins->object()),
5182 useBoxAtStart(ins->rhs()), tempFixed(CallTempReg0),
5183 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5184 #endif
5186 add(lir, ins);
5187 assignSafepoint(lir, ins);
5190 void LIRGenerator::visitMegamorphicHasProp(MMegamorphicHasProp* ins) {
5191 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5192 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5193 auto* lir = new (alloc())
5194 LMegamorphicHasProp(useRegisterAtStart(ins->object()),
5195 useBoxAtStart(ins->idVal()), tempFixed(CallTempReg0),
5196 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5197 assignSnapshot(lir, ins->bailoutKind());
5198 defineReturn(lir, ins);
5201 void LIRGenerator::visitSmallObjectVariableKeyHasProp(
5202 MSmallObjectVariableKeyHasProp* ins) {
5203 MOZ_ASSERT(ins->idStr()->type() == MIRType::String);
5204 auto* lir = new (alloc())
5205 LSmallObjectVariableKeyHasProp(useRegisterAtStart(ins->idStr()));
5206 define(lir, ins);
5207 assignSafepoint(lir, ins);
5210 void LIRGenerator::visitGuardIsNotArrayBufferMaybeShared(
5211 MGuardIsNotArrayBufferMaybeShared* ins) {
5212 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5214 auto* lir = new (alloc())
5215 LGuardIsNotArrayBufferMaybeShared(useRegister(ins->object()), temp());
5216 assignSnapshot(lir, ins->bailoutKind());
5217 add(lir, ins);
5218 redefine(ins, ins->object());
5221 void LIRGenerator::visitGuardIsTypedArray(MGuardIsTypedArray* ins) {
5222 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5224 auto* lir =
5225 new (alloc()) LGuardIsTypedArray(useRegister(ins->object()), temp());
5226 assignSnapshot(lir, ins->bailoutKind());
5227 add(lir, ins);
5228 redefine(ins, ins->object());
5231 void LIRGenerator::visitGuardIsFixedLengthTypedArray(
5232 MGuardIsFixedLengthTypedArray* ins) {
5233 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5235 auto* lir = new (alloc())
5236 LGuardIsFixedLengthTypedArray(useRegister(ins->object()), temp());
5237 assignSnapshot(lir, ins->bailoutKind());
5238 add(lir, ins);
5239 redefine(ins, ins->object());
5242 void LIRGenerator::visitGuardIsResizableTypedArray(
5243 MGuardIsResizableTypedArray* ins) {
5244 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5246 auto* lir = new (alloc())
5247 LGuardIsResizableTypedArray(useRegister(ins->object()), temp());
5248 assignSnapshot(lir, ins->bailoutKind());
5249 add(lir, ins);
5250 redefine(ins, ins->object());
5253 void LIRGenerator::visitGuardHasProxyHandler(MGuardHasProxyHandler* ins) {
5254 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5256 auto* lir = new (alloc()) LGuardHasProxyHandler(useRegister(ins->object()));
5257 assignSnapshot(lir, ins->bailoutKind());
5258 add(lir, ins);
5259 redefine(ins, ins->object());
5262 void LIRGenerator::visitNurseryObject(MNurseryObject* ins) {
5263 MOZ_ASSERT(ins->type() == MIRType::Object);
5265 auto* lir = new (alloc()) LNurseryObject();
5266 define(lir, ins);
5269 void LIRGenerator::visitGuardValue(MGuardValue* ins) {
5270 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5271 auto* lir = new (alloc()) LGuardValue(useBox(ins->value()));
5272 assignSnapshot(lir, ins->bailoutKind());
5273 add(lir, ins);
5274 redefine(ins, ins->value());
5277 void LIRGenerator::visitGuardNullOrUndefined(MGuardNullOrUndefined* ins) {
5278 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5279 auto* lir = new (alloc()) LGuardNullOrUndefined(useBox(ins->value()));
5280 assignSnapshot(lir, ins->bailoutKind());
5281 add(lir, ins);
5282 redefine(ins, ins->value());
5285 void LIRGenerator::visitGuardIsNotObject(MGuardIsNotObject* ins) {
5286 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5287 auto* lir = new (alloc()) LGuardIsNotObject(useBox(ins->value()));
5288 assignSnapshot(lir, ins->bailoutKind());
5289 add(lir, ins);
5290 redefine(ins, ins->value());
5293 void LIRGenerator::visitGuardFunctionFlags(MGuardFunctionFlags* ins) {
5294 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5296 auto* lir = new (alloc()) LGuardFunctionFlags(useRegister(ins->function()));
5297 assignSnapshot(lir, ins->bailoutKind());
5298 add(lir, ins);
5299 redefine(ins, ins->function());
5302 void LIRGenerator::visitGuardFunctionIsNonBuiltinCtor(
5303 MGuardFunctionIsNonBuiltinCtor* ins) {
5304 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5306 auto* lir = new (alloc())
5307 LGuardFunctionIsNonBuiltinCtor(useRegister(ins->function()), temp());
5308 assignSnapshot(lir, ins->bailoutKind());
5309 add(lir, ins);
5310 redefine(ins, ins->function());
5313 void LIRGenerator::visitGuardFunctionKind(MGuardFunctionKind* ins) {
5314 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5316 auto* lir =
5317 new (alloc()) LGuardFunctionKind(useRegister(ins->function()), temp());
5318 assignSnapshot(lir, ins->bailoutKind());
5319 add(lir, ins);
5320 redefine(ins, ins->function());
5323 void LIRGenerator::visitGuardFunctionScript(MGuardFunctionScript* ins) {
5324 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5326 auto* lir = new (alloc()) LGuardFunctionScript(useRegister(ins->function()));
5327 assignSnapshot(lir, ins->bailoutKind());
5328 add(lir, ins);
5329 redefine(ins, ins->function());
5332 void LIRGenerator::visitAssertRange(MAssertRange* ins) {
5333 MDefinition* input = ins->input();
5334 LInstruction* lir = nullptr;
5336 switch (input->type()) {
5337 case MIRType::Boolean:
5338 case MIRType::Int32:
5339 case MIRType::IntPtr:
5340 lir = new (alloc()) LAssertRangeI(useRegisterAtStart(input));
5341 break;
5343 case MIRType::Double:
5344 lir = new (alloc()) LAssertRangeD(useRegister(input), tempDouble());
5345 break;
5347 case MIRType::Float32:
5348 lir = new (alloc())
5349 LAssertRangeF(useRegister(input), tempDouble(), tempDouble());
5350 break;
5352 case MIRType::Value:
5353 lir = new (alloc()) LAssertRangeV(useBox(input), tempToUnbox(),
5354 tempDouble(), tempDouble());
5355 break;
5357 default:
5358 MOZ_CRASH("Unexpected Range for MIRType");
5359 break;
5362 lir->setMir(ins);
5363 add(lir);
5366 void LIRGenerator::visitAssertClass(MAssertClass* ins) {
5367 auto* lir =
5368 new (alloc()) LAssertClass(useRegisterAtStart(ins->input()), temp());
5369 add(lir, ins);
5372 void LIRGenerator::visitAssertShape(MAssertShape* ins) {
5373 auto* lir = new (alloc()) LAssertShape(useRegisterAtStart(ins->input()));
5374 add(lir, ins);
5377 void LIRGenerator::visitDeleteProperty(MDeleteProperty* ins) {
5378 LCallDeleteProperty* lir =
5379 new (alloc()) LCallDeleteProperty(useBoxAtStart(ins->value()));
5380 defineReturn(lir, ins);
5381 assignSafepoint(lir, ins);
5384 void LIRGenerator::visitDeleteElement(MDeleteElement* ins) {
5385 LCallDeleteElement* lir = new (alloc()) LCallDeleteElement(
5386 useBoxAtStart(ins->value()), useBoxAtStart(ins->index()));
5387 defineReturn(lir, ins);
5388 assignSafepoint(lir, ins);
5391 void LIRGenerator::visitObjectToIterator(MObjectToIterator* ins) {
5392 auto* lir = new (alloc())
5393 LObjectToIterator(useRegister(ins->object()), temp(), temp(), temp());
5394 define(lir, ins);
5395 assignSafepoint(lir, ins);
5398 void LIRGenerator::visitValueToIterator(MValueToIterator* ins) {
5399 auto* lir = new (alloc()) LValueToIterator(useBoxAtStart(ins->value()));
5400 defineReturn(lir, ins);
5401 assignSafepoint(lir, ins);
5404 void LIRGenerator::visitLoadSlotByIteratorIndex(MLoadSlotByIteratorIndex* ins) {
5405 auto* lir = new (alloc()) LLoadSlotByIteratorIndex(
5406 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->iterator()),
5407 temp(), temp());
5408 defineBox(lir, ins);
5411 void LIRGenerator::visitStoreSlotByIteratorIndex(
5412 MStoreSlotByIteratorIndex* ins) {
5413 auto* lir = new (alloc()) LStoreSlotByIteratorIndex(
5414 useRegister(ins->object()), useRegister(ins->iterator()),
5415 useBox(ins->value()), temp(), temp());
5416 add(lir, ins);
5419 void LIRGenerator::visitIteratorHasIndices(MIteratorHasIndices* ins) {
5420 MOZ_ASSERT(ins->hasOneUse());
5421 emitAtUses(ins);
5424 void LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) {
5425 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5427 MDefinition* id = ins->idval();
5428 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5429 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5431 // If this is a SetProp, the id is a constant string. Allow passing it as a
5432 // constant to reduce register allocation pressure.
5433 bool useConstId =
5434 id->type() == MIRType::String || id->type() == MIRType::Symbol;
5435 bool useConstValue = IsNonNurseryConstant(ins->value());
5437 // Emit an overrecursed check: this is necessary because the cache can
5438 // attach a scripted setter stub that calls this script recursively.
5439 gen->setNeedsOverrecursedCheck();
5441 // We need a double temp register for TypedArray stubs.
5442 LDefinition tempD = tempFixed(FloatReg0);
5444 LInstruction* lir = new (alloc()) LSetPropertyCache(
5445 useRegister(ins->object()), useBoxOrTypedOrConstant(id, useConstId),
5446 useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD);
5447 add(lir, ins);
5448 assignSafepoint(lir, ins);
5451 void LIRGenerator::visitMegamorphicSetElement(MMegamorphicSetElement* ins) {
5452 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5453 MOZ_ASSERT(ins->index()->type() == MIRType::Value);
5454 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5456 // See comment in LIROps.yaml (x86 is short on registers)
5457 #ifdef JS_CODEGEN_X86
5458 auto* lir = new (alloc()) LMegamorphicSetElement(
5459 useFixedAtStart(ins->object(), CallTempReg0),
5460 useBoxFixedAtStart(ins->index(), CallTempReg1, CallTempReg2),
5461 useBoxFixedAtStart(ins->value(), CallTempReg3, CallTempReg4),
5462 tempFixed(CallTempReg5));
5463 #else
5464 auto* lir = new (alloc()) LMegamorphicSetElement(
5465 useRegisterAtStart(ins->object()), useBoxAtStart(ins->index()),
5466 useBoxAtStart(ins->value()), tempFixed(CallTempReg0),
5467 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5468 #endif
5469 add(lir, ins);
5470 assignSafepoint(lir, ins);
5473 void LIRGenerator::visitGetIteratorCache(MGetIteratorCache* ins) {
5474 MDefinition* value = ins->value();
5475 MOZ_ASSERT(value->type() == MIRType::Object ||
5476 value->type() == MIRType::Value);
5478 LGetIteratorCache* lir =
5479 new (alloc()) LGetIteratorCache(useBoxOrTyped(value), temp(), temp());
5480 define(lir, ins);
5481 assignSafepoint(lir, ins);
5484 void LIRGenerator::visitOptimizeSpreadCallCache(MOptimizeSpreadCallCache* ins) {
5485 MDefinition* value = ins->value();
5486 MOZ_ASSERT(value->type() == MIRType::Value);
5488 auto* lir = new (alloc()) LOptimizeSpreadCallCache(useBox(value), temp());
5489 defineBox(lir, ins);
5490 assignSafepoint(lir, ins);
5493 void LIRGenerator::visitIteratorMore(MIteratorMore* ins) {
5494 LIteratorMore* lir =
5495 new (alloc()) LIteratorMore(useRegister(ins->iterator()), temp());
5496 defineBox(lir, ins);
5499 void LIRGenerator::visitIsNoIter(MIsNoIter* ins) {
5500 MOZ_ASSERT(ins->hasOneUse());
5501 emitAtUses(ins);
5504 void LIRGenerator::visitIteratorEnd(MIteratorEnd* ins) {
5505 LIteratorEnd* lir = new (alloc())
5506 LIteratorEnd(useRegister(ins->iterator()), temp(), temp(), temp());
5507 add(lir, ins);
5510 void LIRGenerator::visitCloseIterCache(MCloseIterCache* ins) {
5511 LCloseIterCache* lir =
5512 new (alloc()) LCloseIterCache(useRegister(ins->iter()), temp());
5513 add(lir, ins);
5514 assignSafepoint(lir, ins);
5517 void LIRGenerator::visitOptimizeGetIteratorCache(
5518 MOptimizeGetIteratorCache* ins) {
5519 MDefinition* value = ins->value();
5520 MOZ_ASSERT(value->type() == MIRType::Value);
5522 auto* lir = new (alloc()) LOptimizeGetIteratorCache(useBox(value), temp());
5523 define(lir, ins);
5524 assignSafepoint(lir, ins);
5527 void LIRGenerator::visitStringLength(MStringLength* ins) {
5528 MOZ_ASSERT(ins->string()->type() == MIRType::String);
5529 define(new (alloc()) LStringLength(useRegisterAtStart(ins->string())), ins);
5532 void LIRGenerator::visitArgumentsLength(MArgumentsLength* ins) {
5533 define(new (alloc()) LArgumentsLength(), ins);
5536 void LIRGenerator::visitGetFrameArgument(MGetFrameArgument* ins) {
5537 LGetFrameArgument* lir =
5538 new (alloc()) LGetFrameArgument(useRegisterOrConstant(ins->index()));
5539 defineBox(lir, ins);
5542 void LIRGenerator::visitGetFrameArgumentHole(MGetFrameArgumentHole* ins) {
5543 LDefinition spectreTemp =
5544 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
5546 auto* lir = new (alloc()) LGetFrameArgumentHole(
5547 useRegister(ins->index()), useRegister(ins->length()), spectreTemp);
5548 assignSnapshot(lir, ins->bailoutKind());
5549 defineBox(lir, ins);
5552 void LIRGenerator::visitNewTarget(MNewTarget* ins) {
5553 LNewTarget* lir = new (alloc()) LNewTarget();
5554 defineBox(lir, ins);
5557 void LIRGenerator::visitRest(MRest* ins) {
5558 MOZ_ASSERT(ins->numActuals()->type() == MIRType::Int32);
5560 LRest* lir =
5561 new (alloc()) LRest(useRegisterAtStart(ins->numActuals()),
5562 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5563 tempFixed(CallTempReg2), tempFixed(CallTempReg3));
5564 defineReturn(lir, ins);
5565 assignSafepoint(lir, ins);
5568 void LIRGenerator::visitThrow(MThrow* ins) {
5569 MDefinition* value = ins->value();
5570 MOZ_ASSERT(value->type() == MIRType::Value);
5572 LThrow* lir = new (alloc()) LThrow(useBoxAtStart(value));
5573 add(lir, ins);
5574 assignSafepoint(lir, ins);
5577 void LIRGenerator::visitThrowWithStack(MThrowWithStack* ins) {
5578 MDefinition* value = ins->value();
5579 MOZ_ASSERT(value->type() == MIRType::Value);
5581 MDefinition* stack = ins->stack();
5582 MOZ_ASSERT(stack->type() == MIRType::Value);
5584 auto* lir =
5585 new (alloc()) LThrowWithStack(useBoxAtStart(value), useBoxAtStart(stack));
5586 add(lir, ins);
5587 assignSafepoint(lir, ins);
5590 void LIRGenerator::visitInCache(MInCache* ins) {
5591 MDefinition* lhs = ins->lhs();
5592 MDefinition* rhs = ins->rhs();
5594 MOZ_ASSERT(lhs->type() == MIRType::String || lhs->type() == MIRType::Symbol ||
5595 lhs->type() == MIRType::Int32 || lhs->type() == MIRType::Value);
5596 MOZ_ASSERT(rhs->type() == MIRType::Object);
5598 LInCache* lir =
5599 new (alloc()) LInCache(useBoxOrTyped(lhs), useRegister(rhs), temp());
5600 define(lir, ins);
5601 assignSafepoint(lir, ins);
5604 void LIRGenerator::visitHasOwnCache(MHasOwnCache* ins) {
5605 MDefinition* value = ins->value();
5606 MOZ_ASSERT(value->type() == MIRType::Object ||
5607 value->type() == MIRType::Value);
5609 MDefinition* id = ins->idval();
5610 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5611 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5613 // Emit an overrecursed check: this is necessary because the cache can
5614 // attach a scripted getter stub that calls this script recursively.
5615 gen->setNeedsOverrecursedCheck();
5617 LHasOwnCache* lir =
5618 new (alloc()) LHasOwnCache(useBoxOrTyped(value), useBoxOrTyped(id));
5619 define(lir, ins);
5620 assignSafepoint(lir, ins);
5623 void LIRGenerator::visitCheckPrivateFieldCache(MCheckPrivateFieldCache* ins) {
5624 MDefinition* value = ins->value();
5625 MOZ_ASSERT(value->type() == MIRType::Object ||
5626 value->type() == MIRType::Value);
5628 MDefinition* id = ins->idval();
5629 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5630 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5632 LCheckPrivateFieldCache* lir = new (alloc())
5633 LCheckPrivateFieldCache(useBoxOrTyped(value), useBoxOrTyped(id));
5634 define(lir, ins);
5635 assignSafepoint(lir, ins);
5638 void LIRGenerator::visitNewPrivateName(MNewPrivateName* ins) {
5639 auto* lir = new (alloc()) LNewPrivateName();
5640 defineReturn(lir, ins);
5641 assignSafepoint(lir, ins);
5644 void LIRGenerator::visitInstanceOf(MInstanceOf* ins) {
5645 MDefinition* lhs = ins->lhs();
5646 MDefinition* rhs = ins->rhs();
5648 MOZ_ASSERT(lhs->type() == MIRType::Value || lhs->type() == MIRType::Object);
5649 MOZ_ASSERT(rhs->type() == MIRType::Object);
5651 if (lhs->type() == MIRType::Object) {
5652 auto* lir = new (alloc()) LInstanceOfO(useRegister(lhs), useRegister(rhs));
5653 define(lir, ins);
5654 assignSafepoint(lir, ins);
5655 } else {
5656 auto* lir = new (alloc()) LInstanceOfV(useBox(lhs), useRegister(rhs));
5657 define(lir, ins);
5658 assignSafepoint(lir, ins);
5662 void LIRGenerator::visitInstanceOfCache(MInstanceOfCache* ins) {
5663 MDefinition* lhs = ins->lhs();
5664 MDefinition* rhs = ins->rhs();
5666 MOZ_ASSERT(lhs->type() == MIRType::Value);
5667 MOZ_ASSERT(rhs->type() == MIRType::Object);
5669 LInstanceOfCache* lir =
5670 new (alloc()) LInstanceOfCache(useBox(lhs), useRegister(rhs));
5671 define(lir, ins);
5672 assignSafepoint(lir, ins);
5675 void LIRGenerator::visitIsArray(MIsArray* ins) {
5676 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5678 if (ins->value()->type() == MIRType::Object) {
5679 LIsArrayO* lir = new (alloc()) LIsArrayO(useRegister(ins->value()));
5680 define(lir, ins);
5681 assignSafepoint(lir, ins);
5682 } else {
5683 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5684 LIsArrayV* lir = new (alloc()) LIsArrayV(useBox(ins->value()), temp());
5685 define(lir, ins);
5686 assignSafepoint(lir, ins);
5690 void LIRGenerator::visitIsTypedArray(MIsTypedArray* ins) {
5691 MOZ_ASSERT(ins->value()->type() == MIRType::Object);
5692 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5694 auto* lir = new (alloc()) LIsTypedArray(useRegister(ins->value()));
5695 define(lir, ins);
5697 if (ins->isPossiblyWrapped()) {
5698 assignSafepoint(lir, ins);
5702 void LIRGenerator::visitIsCallable(MIsCallable* ins) {
5703 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5705 if (ins->object()->type() == MIRType::Object) {
5706 define(new (alloc()) LIsCallableO(useRegister(ins->object())), ins);
5707 } else {
5708 MOZ_ASSERT(ins->object()->type() == MIRType::Value);
5709 define(new (alloc()) LIsCallableV(useBox(ins->object()), temp()), ins);
5713 void LIRGenerator::visitIsConstructor(MIsConstructor* ins) {
5714 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5715 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5716 define(new (alloc()) LIsConstructor(useRegister(ins->object())), ins);
5719 void LIRGenerator::visitIsCrossRealmArrayConstructor(
5720 MIsCrossRealmArrayConstructor* ins) {
5721 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5722 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5723 define(new (alloc())
5724 LIsCrossRealmArrayConstructor(useRegister(ins->object())),
5725 ins);
5728 static bool CanEmitAtUseForSingleTest(MInstruction* ins) {
5729 if (!ins->canEmitAtUses()) {
5730 return false;
5733 MUseIterator iter(ins->usesBegin());
5734 if (iter == ins->usesEnd()) {
5735 return false;
5738 MNode* node = iter->consumer();
5739 if (!node->isDefinition()) {
5740 return false;
5743 if (!node->toDefinition()->isTest()) {
5744 return false;
5747 iter++;
5748 return iter == ins->usesEnd();
5751 void LIRGenerator::visitIsObject(MIsObject* ins) {
5752 if (CanEmitAtUseForSingleTest(ins)) {
5753 emitAtUses(ins);
5754 return;
5757 MDefinition* opd = ins->input();
5758 MOZ_ASSERT(opd->type() == MIRType::Value);
5759 LIsObject* lir = new (alloc()) LIsObject(useBoxAtStart(opd));
5760 define(lir, ins);
5763 void LIRGenerator::visitIsNullOrUndefined(MIsNullOrUndefined* ins) {
5764 if (CanEmitAtUseForSingleTest(ins)) {
5765 emitAtUses(ins);
5766 return;
5769 MDefinition* opd = ins->input();
5770 if (opd->type() == MIRType::Value) {
5771 auto* lir = new (alloc()) LIsNullOrUndefined(useBoxAtStart(opd));
5772 define(lir, ins);
5773 } else {
5774 define(new (alloc()) LInteger(IsNullOrUndefined(opd->type())), ins);
5778 void LIRGenerator::visitHasClass(MHasClass* ins) {
5779 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5780 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5781 define(new (alloc()) LHasClass(useRegister(ins->object())), ins);
5784 void LIRGenerator::visitGuardToClass(MGuardToClass* ins) {
5785 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5786 MOZ_ASSERT(ins->type() == MIRType::Object);
5787 LGuardToClass* lir =
5788 new (alloc()) LGuardToClass(useRegisterAtStart(ins->object()), temp());
5789 assignSnapshot(lir, ins->bailoutKind());
5790 defineReuseInput(lir, ins, 0);
5793 void LIRGenerator::visitGuardToEitherClass(MGuardToEitherClass* ins) {
5794 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5795 MOZ_ASSERT(ins->type() == MIRType::Object);
5796 auto* lir = new (alloc())
5797 LGuardToEitherClass(useRegisterAtStart(ins->object()), temp());
5798 assignSnapshot(lir, ins->bailoutKind());
5799 defineReuseInput(lir, ins, 0);
5802 void LIRGenerator::visitGuardToFunction(MGuardToFunction* ins) {
5803 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5804 MOZ_ASSERT(ins->type() == MIRType::Object);
5805 LGuardToFunction* lir =
5806 new (alloc()) LGuardToFunction(useRegisterAtStart(ins->object()), temp());
5807 assignSnapshot(lir, ins->bailoutKind());
5808 defineReuseInput(lir, ins, 0);
5811 void LIRGenerator::visitObjectClassToString(MObjectClassToString* ins) {
5812 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5813 MOZ_ASSERT(ins->type() == MIRType::String);
5814 auto* lir = new (alloc()) LObjectClassToString(
5815 useRegisterAtStart(ins->object()), tempFixed(CallTempReg0));
5816 assignSnapshot(lir, ins->bailoutKind());
5817 defineReturn(lir, ins);
5820 void LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins) {
5821 MOZ_ASSERT(ins->offset());
5822 if (ins->base()->type() == MIRType::Int32) {
5823 MOZ_ASSERT(ins->type() == MIRType::Int32);
5824 MOZ_ASSERT(ins->offset() <= UINT32_MAX); // Because memory32
5825 define(new (alloc()) LWasmAddOffset(useRegisterAtStart(ins->base())), ins);
5826 } else {
5827 MOZ_ASSERT(ins->type() == MIRType::Int64);
5828 #ifdef JS_64BIT
5829 defineInt64(new (alloc())
5830 LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
5831 ins);
5832 #else
5833 // Avoid situation where the input is (a,b) and the output is (b,a).
5834 defineInt64ReuseInput(
5835 new (alloc()) LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
5836 ins, 0);
5837 #endif
5841 void LIRGenerator::visitWasmLoadInstance(MWasmLoadInstance* ins) {
5842 if (ins->type() == MIRType::Int64) {
5843 #ifdef JS_PUNBOX64
5844 LAllocation instance = useRegisterAtStart(ins->instance());
5845 #else
5846 // Avoid reusing instance for a 64-bit output pair as the load clobbers the
5847 // first half of that pair before loading the second half.
5848 LAllocation instance = useRegister(ins->instance());
5849 #endif
5850 auto* lir = new (alloc()) LWasmLoadInstance64(instance);
5851 defineInt64(lir, ins);
5852 } else {
5853 auto* lir =
5854 new (alloc()) LWasmLoadInstance(useRegisterAtStart(ins->instance()));
5855 define(lir, ins);
5859 void LIRGenerator::visitWasmStoreInstance(MWasmStoreInstance* ins) {
5860 MDefinition* value = ins->value();
5861 if (value->type() == MIRType::Int64) {
5862 #ifdef JS_PUNBOX64
5863 LAllocation instance = useRegisterAtStart(ins->instance());
5864 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5865 #else
5866 LAllocation instance = useRegister(ins->instance());
5867 LInt64Allocation valueAlloc = useInt64Register(value);
5868 #endif
5869 add(new (alloc()) LWasmStoreSlotI64(valueAlloc, instance, ins->offset(),
5870 mozilla::Nothing()),
5871 ins);
5872 } else {
5873 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5874 LAllocation instance = useRegisterAtStart(ins->instance());
5875 LAllocation valueAlloc = useRegisterAtStart(value);
5876 add(new (alloc())
5877 LWasmStoreSlot(valueAlloc, instance, ins->offset(), value->type(),
5878 MNarrowingOp::None, mozilla::Nothing()),
5879 ins);
5883 void LIRGenerator::visitWasmHeapReg(MWasmHeapReg* ins) {
5884 #ifdef WASM_HAS_HEAPREG
5885 auto* lir = new (alloc()) LWasmHeapReg();
5886 define(lir, ins);
5887 #else
5888 MOZ_CRASH();
5889 #endif
5892 void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) {
5893 MOZ_ASSERT(!ins->isRedundant());
5895 MDefinition* index = ins->index();
5896 MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
5898 MOZ_ASSERT(boundsCheckLimit->type() == index->type());
5900 if (index->type() == MIRType::Int64) {
5901 if (JitOptions.spectreIndexMasking) {
5902 auto* lir = new (alloc()) LWasmBoundsCheck64(
5903 useInt64RegisterAtStart(index), useInt64Register(boundsCheckLimit));
5904 defineInt64ReuseInput(lir, ins, 0);
5905 } else {
5906 auto* lir = new (alloc())
5907 LWasmBoundsCheck64(useInt64RegisterAtStart(index),
5908 useInt64RegisterAtStart(boundsCheckLimit));
5909 add(lir, ins);
5911 } else {
5912 MOZ_ASSERT(index->type() == MIRType::Int32);
5914 if (JitOptions.spectreIndexMasking) {
5915 auto* lir = new (alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
5916 useRegister(boundsCheckLimit));
5917 defineReuseInput(lir, ins, 0);
5918 } else {
5919 auto* lir = new (alloc()) LWasmBoundsCheck(
5920 useRegisterAtStart(index), useRegisterAtStart(boundsCheckLimit));
5921 add(lir, ins);
5926 void LIRGenerator::visitWasmBoundsCheckRange32(MWasmBoundsCheckRange32* ins) {
5927 MDefinition* index = ins->index();
5928 MDefinition* length = ins->length();
5929 MDefinition* limit = ins->limit();
5931 MOZ_ASSERT(index->type() == MIRType::Int32);
5932 MOZ_ASSERT(length->type() == MIRType::Int32);
5933 MOZ_ASSERT(limit->type() == MIRType::Int32);
5935 add(new (alloc()) LWasmBoundsCheckRange32(
5936 useRegister(index), useRegister(length), useRegister(limit), temp()),
5937 ins);
5940 void LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck* ins) {
5941 MDefinition* index = ins->index();
5942 if (index->type() == MIRType::Int64) {
5943 auto* lir =
5944 new (alloc()) LWasmAlignmentCheck64(useInt64RegisterAtStart(index));
5945 add(lir, ins);
5946 } else {
5947 auto* lir = new (alloc()) LWasmAlignmentCheck(useRegisterAtStart(index));
5948 add(lir, ins);
5952 void LIRGenerator::visitWasmLoadInstanceDataField(
5953 MWasmLoadInstanceDataField* ins) {
5954 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset());
5955 if (ins->type() == MIRType::Int64) {
5956 #ifdef JS_PUNBOX64
5957 LAllocation instance = useRegisterAtStart(ins->instance());
5958 #else
5959 // Avoid reusing instance for the output pair as the load clobbers the first
5960 // half of that pair before loading the second half.
5961 LAllocation instance = useRegister(ins->instance());
5962 #endif
5963 defineInt64(new (alloc())
5964 LWasmLoadSlotI64(instance, offs, mozilla::Nothing()),
5965 ins);
5966 } else {
5967 LAllocation instance = useRegisterAtStart(ins->instance());
5968 define(new (alloc()) LWasmLoadSlot(instance, offs, ins->type(),
5969 MWideningOp::None, mozilla::Nothing()),
5970 ins);
5974 void LIRGenerator::visitWasmLoadGlobalCell(MWasmLoadGlobalCell* ins) {
5975 if (ins->type() == MIRType::Int64) {
5976 #ifdef JS_PUNBOX64
5977 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5978 #else
5979 // Avoid reusing cellPtr for the output pair as the load clobbers the first
5980 // half of that pair before loading the second half.
5981 LAllocation cellPtr = useRegister(ins->cellPtr());
5982 #endif
5983 defineInt64(new (alloc())
5984 LWasmLoadSlotI64(cellPtr, /*offset=*/0, mozilla::Nothing()),
5985 ins);
5986 } else {
5987 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5988 define(new (alloc()) LWasmLoadSlot(cellPtr, /*offset=*/0, ins->type(),
5989 MWideningOp::None, mozilla::Nothing()),
5990 ins);
5994 void LIRGenerator::visitWasmLoadTableElement(MWasmLoadTableElement* ins) {
5995 LAllocation elements = useRegisterAtStart(ins->elements());
5996 LAllocation index = useRegisterAtStart(ins->index());
5997 define(new (alloc()) LWasmLoadTableElement(elements, index), ins);
6000 void LIRGenerator::visitWasmStoreInstanceDataField(
6001 MWasmStoreInstanceDataField* ins) {
6002 MDefinition* value = ins->value();
6003 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset());
6004 if (value->type() == MIRType::Int64) {
6005 #ifdef JS_PUNBOX64
6006 LAllocation instance = useRegisterAtStart(ins->instance());
6007 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
6008 #else
6009 LAllocation instance = useRegister(ins->instance());
6010 LInt64Allocation valueAlloc = useInt64Register(value);
6011 #endif
6012 add(new (alloc())
6013 LWasmStoreSlotI64(valueAlloc, instance, offs, mozilla::Nothing()),
6014 ins);
6015 } else {
6016 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
6017 LAllocation instance = useRegisterAtStart(ins->instance());
6018 LAllocation valueAlloc = useRegisterAtStart(value);
6019 add(new (alloc()) LWasmStoreSlot(valueAlloc, instance, offs, value->type(),
6020 MNarrowingOp::None, mozilla::Nothing()),
6021 ins);
6025 void LIRGenerator::visitWasmStoreGlobalCell(MWasmStoreGlobalCell* ins) {
6026 MDefinition* value = ins->value();
6027 size_t offs = 0;
6028 if (value->type() == MIRType::Int64) {
6029 #ifdef JS_PUNBOX64
6030 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
6031 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
6032 #else
6033 LAllocation cellPtr = useRegister(ins->cellPtr());
6034 LInt64Allocation valueAlloc = useInt64Register(value);
6035 #endif
6036 add(new (alloc())
6037 LWasmStoreSlotI64(valueAlloc, cellPtr, offs, mozilla::Nothing()));
6038 } else {
6039 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
6040 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
6041 LAllocation valueAlloc = useRegisterAtStart(value);
6042 add(new (alloc()) LWasmStoreSlot(valueAlloc, cellPtr, offs, value->type(),
6043 MNarrowingOp::None, mozilla::Nothing()));
6047 void LIRGenerator::visitWasmStoreStackResult(MWasmStoreStackResult* ins) {
6048 MDefinition* stackResultArea = ins->stackResultArea();
6049 MDefinition* value = ins->value();
6050 size_t offs = ins->offset();
6051 LInstruction* lir;
6052 if (value->type() == MIRType::Int64) {
6053 lir = new (alloc())
6054 LWasmStoreSlotI64(useInt64Register(value), useRegister(stackResultArea),
6055 offs, mozilla::Nothing());
6056 } else {
6057 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
6058 lir = new (alloc())
6059 LWasmStoreSlot(useRegister(value), useRegister(stackResultArea), offs,
6060 value->type(), MNarrowingOp::None, mozilla::Nothing());
6062 add(lir, ins);
6065 void LIRGenerator::visitWasmDerivedPointer(MWasmDerivedPointer* ins) {
6066 LAllocation base = useRegisterAtStart(ins->base());
6067 define(new (alloc()) LWasmDerivedPointer(base), ins);
6070 void LIRGenerator::visitWasmDerivedIndexPointer(MWasmDerivedIndexPointer* ins) {
6071 LAllocation base = useRegisterAtStart(ins->base());
6072 LAllocation index = useRegisterAtStart(ins->index());
6073 define(new (alloc()) LWasmDerivedIndexPointer(base, index), ins);
6076 void LIRGenerator::visitWasmStoreRef(MWasmStoreRef* ins) {
6077 LAllocation instance = useRegister(ins->instance());
6078 LAllocation valueBase = useFixed(ins->valueBase(), PreBarrierReg);
6079 LAllocation value = useRegister(ins->value());
6080 uint32_t valueOffset = ins->offset();
6081 add(new (alloc())
6082 LWasmStoreRef(instance, valueBase, value, temp(), valueOffset,
6083 mozilla::Nothing(), ins->preBarrierKind()),
6084 ins);
6087 void LIRGenerator::visitWasmPostWriteBarrierImmediate(
6088 MWasmPostWriteBarrierImmediate* ins) {
6089 LWasmPostWriteBarrierImmediate* lir =
6090 new (alloc()) LWasmPostWriteBarrierImmediate(
6091 useFixed(ins->instance(), InstanceReg), useRegister(ins->object()),
6092 useRegister(ins->valueBase()), useRegister(ins->value()), temp(),
6093 ins->valueOffset());
6094 add(lir, ins);
6095 assignWasmSafepoint(lir);
6098 void LIRGenerator::visitWasmPostWriteBarrierIndex(
6099 MWasmPostWriteBarrierIndex* ins) {
6100 LWasmPostWriteBarrierIndex* lir = new (alloc()) LWasmPostWriteBarrierIndex(
6101 useFixed(ins->instance(), InstanceReg), useRegister(ins->object()),
6102 useRegister(ins->valueBase()), useRegister(ins->index()),
6103 useRegister(ins->value()), temp(), ins->elemSize());
6104 add(lir, ins);
6105 assignWasmSafepoint(lir);
6108 void LIRGenerator::visitWasmParameter(MWasmParameter* ins) {
6109 ABIArg abi = ins->abi();
6110 if (ins->type() == MIRType::StackResults) {
6111 // Functions that return stack results receive an extra incoming parameter
6112 // with type MIRType::StackResults. This value is a pointer to fresh
6113 // memory. Here we treat it as if it were in fact MIRType::Pointer.
6114 auto* lir = new (alloc()) LWasmParameter;
6115 LDefinition def(LDefinition::TypeFrom(MIRType::Pointer),
6116 LDefinition::FIXED);
6117 def.setOutput(abi.argInRegister() ? LAllocation(abi.reg())
6118 : LArgument(abi.offsetFromArgBase()));
6119 define(lir, ins, def);
6120 return;
6122 if (abi.argInRegister()) {
6123 #if defined(JS_NUNBOX32)
6124 if (abi.isGeneralRegPair()) {
6125 defineInt64Fixed(
6126 new (alloc()) LWasmParameterI64, ins,
6127 LInt64Allocation(LAllocation(AnyRegister(abi.gpr64().high)),
6128 LAllocation(AnyRegister(abi.gpr64().low))));
6129 return;
6131 #endif
6132 defineFixed(new (alloc()) LWasmParameter, ins, LAllocation(abi.reg()));
6133 return;
6135 if (ins->type() == MIRType::Int64) {
6136 MOZ_ASSERT(!abi.argInRegister());
6137 defineInt64Fixed(
6138 new (alloc()) LWasmParameterI64, ins,
6139 #if defined(JS_NUNBOX32)
6140 LInt64Allocation(LArgument(abi.offsetFromArgBase() + INT64HIGH_OFFSET),
6141 LArgument(abi.offsetFromArgBase() + INT64LOW_OFFSET))
6142 #else
6143 LInt64Allocation(LArgument(abi.offsetFromArgBase()))
6144 #endif
6146 } else {
6147 MOZ_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType::WasmAnyRef
6148 #ifdef ENABLE_WASM_SIMD
6149 || ins->type() == MIRType::Simd128
6150 #endif
6152 defineFixed(new (alloc()) LWasmParameter, ins,
6153 LArgument(abi.offsetFromArgBase()));
6157 void LIRGenerator::visitWasmReturn(MWasmReturn* ins) {
6158 MDefinition* rval = ins->getOperand(0);
6159 MDefinition* instance = ins->getOperand(1);
6161 if (rval->type() == MIRType::Int64) {
6162 add(new (alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64),
6163 useFixed(instance, InstanceReg)));
6164 return;
6167 LAllocation returnReg;
6168 if (rval->type() == MIRType::Float32) {
6169 returnReg = useFixed(rval, ReturnFloat32Reg);
6170 } else if (rval->type() == MIRType::Double) {
6171 returnReg = useFixed(rval, ReturnDoubleReg);
6172 #ifdef ENABLE_WASM_SIMD
6173 } else if (rval->type() == MIRType::Simd128) {
6174 returnReg = useFixed(rval, ReturnSimd128Reg);
6175 #endif
6176 } else if (rval->type() == MIRType::Int32 ||
6177 rval->type() == MIRType::WasmAnyRef) {
6178 returnReg = useFixed(rval, ReturnReg);
6179 } else {
6180 MOZ_CRASH("Unexpected wasm return type");
6183 LWasmReturn* lir =
6184 new (alloc()) LWasmReturn(useFixed(instance, InstanceReg), returnReg);
6185 add(lir);
6188 void LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid* ins) {
6189 MDefinition* instance = ins->getOperand(0);
6190 LWasmReturnVoid* lir =
6191 new (alloc()) LWasmReturnVoid(useFixed(instance, InstanceReg));
6192 add(lir);
6195 void LIRGenerator::visitWasmStackArg(MWasmStackArg* ins) {
6196 if (ins->arg()->type() == MIRType::Int64) {
6197 add(new (alloc())
6198 LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins->arg())),
6199 ins);
6200 } else if (IsFloatingPointType(ins->arg()->type())) {
6201 MOZ_ASSERT(!ins->arg()->isEmittedAtUses());
6202 add(new (alloc()) LWasmStackArg(useRegisterAtStart(ins->arg())), ins);
6203 } else {
6204 add(new (alloc()) LWasmStackArg(useRegisterOrConstantAtStart(ins->arg())),
6205 ins);
6209 void LIRGenerator::visitWasmRegisterResult(MWasmRegisterResult* ins) {
6210 auto* lir = new (alloc()) LWasmRegisterResult();
6211 uint32_t vreg = getVirtualRegister();
6212 MOZ_ASSERT(ins->type() != MIRType::Int64);
6213 auto type = LDefinition::TypeFrom(ins->type());
6214 lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ins->loc())));
6215 ins->setVirtualRegister(vreg);
6216 add(lir, ins);
6219 void LIRGenerator::visitWasmFloatRegisterResult(MWasmFloatRegisterResult* ins) {
6220 auto* lir = new (alloc()) LWasmRegisterResult();
6221 uint32_t vreg = getVirtualRegister();
6222 auto type = LDefinition::TypeFrom(ins->type());
6223 lir->setDef(0, LDefinition(vreg, type, LFloatReg(ins->loc())));
6224 ins->setVirtualRegister(vreg);
6225 add(lir, ins);
6228 void LIRGenerator::visitWasmRegister64Result(MWasmRegister64Result* ins) {
6229 MOZ_ASSERT(ins->type() == MIRType::Int64);
6230 uint32_t vreg = getVirtualRegister();
6232 #if defined(JS_NUNBOX32)
6233 auto* lir = new (alloc()) LWasmRegisterPairResult();
6234 lir->setDef(INT64LOW_INDEX,
6235 LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL,
6236 LGeneralReg(ins->loc().low)));
6237 lir->setDef(INT64HIGH_INDEX,
6238 LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL,
6239 LGeneralReg(ins->loc().high)));
6240 getVirtualRegister();
6241 #elif defined(JS_PUNBOX64)
6242 auto* lir = new (alloc()) LWasmRegisterResult();
6243 lir->setDef(
6244 0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ins->loc().reg)));
6245 #else
6246 # error expected either JS_NUNBOX32 or JS_PUNBOX64
6247 #endif
6249 ins->setVirtualRegister(vreg);
6250 add(lir, ins);
6253 void LIRGenerator::visitWasmStackResultArea(MWasmStackResultArea* ins) {
6254 MOZ_ASSERT(ins->type() == MIRType::StackResults);
6255 auto* lir = new (alloc()) LWasmStackResultArea(temp());
6256 uint32_t vreg = getVirtualRegister();
6257 lir->setDef(0,
6258 LDefinition(vreg, LDefinition::STACKRESULTS, LDefinition::STACK));
6259 ins->setVirtualRegister(vreg);
6260 add(lir, ins);
6263 void LIRGenerator::visitWasmStackResult(MWasmStackResult* ins) {
6264 MWasmStackResultArea* area = ins->resultArea()->toWasmStackResultArea();
6265 LDefinition::Policy pol = LDefinition::STACK;
6267 if (ins->type() == MIRType::Int64) {
6268 auto* lir = new (alloc()) LWasmStackResult64;
6269 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
6270 uint32_t vreg = getVirtualRegister();
6271 LDefinition::Type typ = LDefinition::GENERAL;
6272 #if defined(JS_NUNBOX32)
6273 getVirtualRegister();
6274 lir->setDef(INT64LOW_INDEX, LDefinition(vreg + INT64LOW_INDEX, typ, pol));
6275 lir->setDef(INT64HIGH_INDEX, LDefinition(vreg + INT64HIGH_INDEX, typ, pol));
6276 #else
6277 lir->setDef(0, LDefinition(vreg, typ, pol));
6278 #endif
6279 ins->setVirtualRegister(vreg);
6280 add(lir, ins);
6281 return;
6284 auto* lir = new (alloc()) LWasmStackResult;
6285 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
6286 uint32_t vreg = getVirtualRegister();
6287 LDefinition::Type typ = LDefinition::TypeFrom(ins->type());
6288 lir->setDef(0, LDefinition(vreg, typ, pol));
6289 ins->setVirtualRegister(vreg);
6290 add(lir, ins);
6293 template <class MWasmCallT>
6294 void LIRGenerator::visitWasmCall(MWasmCallT ins) {
6295 bool needsBoundsCheck = true;
6296 mozilla::Maybe<uint32_t> tableSize;
6298 if (ins->callee().isTable()) {
6299 MDefinition* index = ins->getOperand(ins->numArgs());
6301 if (ins->callee().which() == wasm::CalleeDesc::WasmTable) {
6302 uint32_t minLength = ins->callee().wasmTableMinLength();
6303 mozilla::Maybe<uint32_t> maxLength = ins->callee().wasmTableMaxLength();
6304 if (index->isConstant() &&
6305 uint32_t(index->toConstant()->toInt32()) < minLength) {
6306 needsBoundsCheck = false;
6308 if (maxLength.isSome() && *maxLength == minLength) {
6309 tableSize = maxLength;
6314 auto* lir = allocateVariadic<LWasmCall>(ins->numOperands(), needsBoundsCheck,
6315 tableSize);
6316 if (!lir) {
6317 abort(AbortReason::Alloc, "OOM: LIRGenerator::lowerWasmCall");
6318 return;
6321 for (unsigned i = 0; i < ins->numArgs(); i++) {
6322 lir->setOperand(
6323 i, useFixedAtStart(ins->getOperand(i), ins->registerForArg(i)));
6326 if (ins->callee().isTable()) {
6327 MDefinition* index = ins->getOperand(ins->numArgs());
6328 lir->setOperand(ins->numArgs(),
6329 useFixedAtStart(index, WasmTableCallIndexReg));
6331 if (ins->callee().isFuncRef()) {
6332 MDefinition* ref = ins->getOperand(ins->numArgs());
6333 lir->setOperand(ins->numArgs(), useFixedAtStart(ref, WasmCallRefReg));
6336 add(lir, ins);
6337 assignWasmSafepoint(lir);
6339 // WasmCall with WasmTable has two call instructions, and they both need a
6340 // safepoint associated with them. Create a second safepoint here; the node
6341 // otherwise does nothing, and codegen for it only marks the safepoint at the
6342 // node.
6343 if (ins->callee().which() == wasm::CalleeDesc::WasmTable &&
6344 !ins->isWasmReturnCall()) {
6345 auto* adjunctSafepoint = new (alloc()) LWasmCallIndirectAdjunctSafepoint();
6346 add(adjunctSafepoint);
6347 assignWasmSafepoint(adjunctSafepoint);
6348 lir->setAdjunctSafepoint(adjunctSafepoint);
6352 void LIRGenerator::visitWasmCallCatchable(MWasmCallCatchable* ins) {
6353 visitWasmCall(ins);
6356 void LIRGenerator::visitWasmCallUncatchable(MWasmCallUncatchable* ins) {
6357 visitWasmCall(ins);
6360 void LIRGenerator::visitWasmReturnCall(MWasmReturnCall* ins) {
6361 visitWasmCall(ins);
6364 void LIRGenerator::visitWasmCallLandingPrePad(MWasmCallLandingPrePad* ins) {
6365 add(new (alloc()) LWasmCallLandingPrePad, ins);
6368 void LIRGenerator::visitSetDOMProperty(MSetDOMProperty* ins) {
6369 MDefinition* val = ins->value();
6371 Register cxReg, objReg, privReg, valueReg;
6372 GetTempRegForIntArg(0, 0, &cxReg);
6373 GetTempRegForIntArg(1, 0, &objReg);
6374 GetTempRegForIntArg(2, 0, &privReg);
6375 GetTempRegForIntArg(3, 0, &valueReg);
6377 // Keep using GetTempRegForIntArg, since we want to make sure we
6378 // don't clobber registers we're already using.
6379 Register tempReg1, tempReg2;
6380 GetTempRegForIntArg(4, 0, &tempReg1);
6381 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2);
6382 MOZ_ASSERT(ok, "How can we not have six temp registers?");
6384 LSetDOMProperty* lir = new (alloc())
6385 LSetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
6386 useBoxFixedAtStart(val, tempReg1, tempReg2),
6387 tempFixed(privReg), tempFixed(valueReg));
6388 add(lir, ins);
6389 assignSafepoint(lir, ins);
6392 void LIRGenerator::visitGetDOMProperty(MGetDOMProperty* ins) {
6393 Register cxReg, objReg, privReg, valueReg;
6394 GetTempRegForIntArg(0, 0, &cxReg);
6395 GetTempRegForIntArg(1, 0, &objReg);
6396 GetTempRegForIntArg(2, 0, &privReg);
6397 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg);
6398 MOZ_ASSERT(ok, "How can we not have four temp registers?");
6399 LGetDOMProperty* lir = new (alloc())
6400 LGetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
6401 tempFixed(privReg), tempFixed(valueReg));
6403 defineReturn(lir, ins);
6404 assignSafepoint(lir, ins);
6407 void LIRGenerator::visitGetDOMMember(MGetDOMMember* ins) {
6408 MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
6409 // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
6410 // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
6411 // value can in fact change as a result of DOM setters and method calls.
6412 MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
6413 "Member gets had better not alias the world");
6415 MDefinition* obj = ins->object();
6416 MOZ_ASSERT(obj->type() == MIRType::Object);
6418 MIRType type = ins->type();
6420 if (type == MIRType::Value) {
6421 LGetDOMMemberV* lir = new (alloc()) LGetDOMMemberV(useRegisterAtStart(obj));
6422 defineBox(lir, ins);
6423 } else {
6424 LGetDOMMemberT* lir =
6425 new (alloc()) LGetDOMMemberT(useRegisterForTypedLoad(obj, type));
6426 define(lir, ins);
6430 void LIRGenerator::visitLoadDOMExpandoValue(MLoadDOMExpandoValue* ins) {
6431 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6432 auto* lir =
6433 new (alloc()) LLoadDOMExpandoValue(useRegisterAtStart(ins->proxy()));
6434 defineBox(lir, ins);
6437 void LIRGenerator::visitLoadDOMExpandoValueGuardGeneration(
6438 MLoadDOMExpandoValueGuardGeneration* ins) {
6439 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6440 auto* lir = new (alloc())
6441 LLoadDOMExpandoValueGuardGeneration(useRegisterAtStart(ins->proxy()));
6442 assignSnapshot(lir, ins->bailoutKind());
6443 defineBox(lir, ins);
6446 void LIRGenerator::visitLoadDOMExpandoValueIgnoreGeneration(
6447 MLoadDOMExpandoValueIgnoreGeneration* ins) {
6448 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6449 auto* lir = new (alloc())
6450 LLoadDOMExpandoValueIgnoreGeneration(useRegisterAtStart(ins->proxy()));
6451 defineBox(lir, ins);
6454 void LIRGenerator::visitGuardDOMExpandoMissingOrGuardShape(
6455 MGuardDOMExpandoMissingOrGuardShape* ins) {
6456 MOZ_ASSERT(ins->expando()->type() == MIRType::Value);
6457 auto* lir = new (alloc())
6458 LGuardDOMExpandoMissingOrGuardShape(useBox(ins->expando()), temp());
6459 assignSnapshot(lir, ins->bailoutKind());
6460 add(lir, ins);
6461 redefine(ins, ins->expando());
6464 void LIRGenerator::visitIncrementWarmUpCounter(MIncrementWarmUpCounter* ins) {
6465 LIncrementWarmUpCounter* lir = new (alloc()) LIncrementWarmUpCounter(temp());
6466 add(lir, ins);
6469 void LIRGenerator::visitLexicalCheck(MLexicalCheck* ins) {
6470 MDefinition* input = ins->input();
6471 MOZ_ASSERT(input->type() == MIRType::Value);
6472 LLexicalCheck* lir = new (alloc()) LLexicalCheck(useBox(input));
6473 assignSnapshot(lir, ins->bailoutKind());
6474 add(lir, ins);
6475 redefine(ins, input);
6478 void LIRGenerator::visitThrowRuntimeLexicalError(
6479 MThrowRuntimeLexicalError* ins) {
6480 LThrowRuntimeLexicalError* lir = new (alloc()) LThrowRuntimeLexicalError();
6481 add(lir, ins);
6482 assignSafepoint(lir, ins);
6485 void LIRGenerator::visitThrowMsg(MThrowMsg* ins) {
6486 LThrowMsg* lir = new (alloc()) LThrowMsg();
6487 add(lir, ins);
6488 assignSafepoint(lir, ins);
6491 void LIRGenerator::visitGlobalDeclInstantiation(MGlobalDeclInstantiation* ins) {
6492 LGlobalDeclInstantiation* lir = new (alloc()) LGlobalDeclInstantiation();
6493 add(lir, ins);
6494 assignSafepoint(lir, ins);
6497 void LIRGenerator::visitDebugger(MDebugger* ins) {
6498 auto* lir = new (alloc()) LDebugger(tempFixed(CallTempReg0));
6499 assignSnapshot(lir, ins->bailoutKind());
6500 add(lir, ins);
6503 void LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins) {
6504 define(new (alloc()) LAtomicIsLockFree(useRegister(ins->input())), ins);
6507 void LIRGenerator::visitCheckReturn(MCheckReturn* ins) {
6508 MDefinition* retVal = ins->returnValue();
6509 MDefinition* thisVal = ins->thisValue();
6510 MOZ_ASSERT(retVal->type() == MIRType::Value);
6511 MOZ_ASSERT(thisVal->type() == MIRType::Value);
6513 auto* lir =
6514 new (alloc()) LCheckReturn(useBoxAtStart(retVal), useBoxAtStart(thisVal));
6515 defineBox(lir, ins);
6516 assignSafepoint(lir, ins);
6519 void LIRGenerator::visitCheckIsObj(MCheckIsObj* ins) {
6520 MDefinition* input = ins->input();
6521 MOZ_ASSERT(input->type() == MIRType::Value);
6523 LCheckIsObj* lir = new (alloc()) LCheckIsObj(useBox(input));
6524 define(lir, ins);
6525 assignSafepoint(lir, ins);
6528 #ifdef JS_PUNBOX64
6529 void LIRGenerator::visitCheckScriptedProxyGetResult(
6530 MCheckScriptedProxyGetResult* ins) {
6531 MDefinition* target = ins->target();
6532 MDefinition* id = ins->id();
6533 MDefinition* value = ins->value();
6535 LCheckScriptedProxyGetResult* lir =
6536 new (alloc()) LCheckScriptedProxyGetResult(useBox(target), useBox(id),
6537 useBox(value), temp(), temp());
6538 add(lir, ins);
6539 assignSafepoint(lir, ins);
6541 #endif
6543 void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) {
6544 MDefinition* checkVal = ins->checkValue();
6545 MOZ_ASSERT(checkVal->type() == MIRType::Value);
6547 auto* lir = new (alloc()) LCheckObjCoercible(useBoxAtStart(checkVal));
6548 redefine(ins, checkVal);
6549 add(lir, ins);
6550 assignSafepoint(lir, ins);
6553 void LIRGenerator::visitCheckClassHeritage(MCheckClassHeritage* ins) {
6554 MDefinition* heritage = ins->heritage();
6555 MOZ_ASSERT(heritage->type() == MIRType::Value);
6557 auto* lir =
6558 new (alloc()) LCheckClassHeritage(useBox(heritage), temp(), temp());
6559 redefine(ins, heritage);
6560 add(lir, ins);
6561 assignSafepoint(lir, ins);
6564 void LIRGenerator::visitCheckThis(MCheckThis* ins) {
6565 MDefinition* thisValue = ins->thisValue();
6566 MOZ_ASSERT(thisValue->type() == MIRType::Value);
6568 auto* lir = new (alloc()) LCheckThis(useBoxAtStart(thisValue));
6569 redefine(ins, thisValue);
6570 add(lir, ins);
6571 assignSafepoint(lir, ins);
6574 void LIRGenerator::visitCheckThisReinit(MCheckThisReinit* ins) {
6575 MDefinition* thisValue = ins->thisValue();
6576 MOZ_ASSERT(thisValue->type() == MIRType::Value);
6578 auto* lir = new (alloc()) LCheckThisReinit(useBoxAtStart(thisValue));
6579 redefine(ins, thisValue);
6580 add(lir, ins);
6581 assignSafepoint(lir, ins);
6584 void LIRGenerator::visitGenerator(MGenerator* ins) {
6585 auto* lir =
6586 new (alloc()) LGenerator(useRegisterAtStart(ins->callee()),
6587 useRegisterAtStart(ins->environmentChain()),
6588 useRegisterAtStart(ins->argsObject()));
6589 defineReturn(lir, ins);
6590 assignSafepoint(lir, ins);
6593 void LIRGenerator::visitAsyncResolve(MAsyncResolve* ins) {
6594 auto* lir = new (alloc()) LAsyncResolve(useRegisterAtStart(ins->generator()),
6595 useBoxAtStart(ins->value()));
6596 defineReturn(lir, ins);
6597 assignSafepoint(lir, ins);
6600 void LIRGenerator::visitAsyncReject(MAsyncReject* ins) {
6601 auto* lir = new (alloc())
6602 LAsyncReject(useRegisterAtStart(ins->generator()),
6603 useBoxAtStart(ins->reason()), useBoxAtStart(ins->stack()));
6604 defineReturn(lir, ins);
6605 assignSafepoint(lir, ins);
6608 void LIRGenerator::visitAsyncAwait(MAsyncAwait* ins) {
6609 MOZ_ASSERT(ins->generator()->type() == MIRType::Object);
6610 auto* lir = new (alloc()) LAsyncAwait(useBoxAtStart(ins->value()),
6611 useRegisterAtStart(ins->generator()));
6612 defineReturn(lir, ins);
6613 assignSafepoint(lir, ins);
6616 void LIRGenerator::visitCanSkipAwait(MCanSkipAwait* ins) {
6617 auto* lir = new (alloc()) LCanSkipAwait(useBoxAtStart(ins->value()));
6618 defineReturn(lir, ins);
6619 assignSafepoint(lir, ins);
6622 void LIRGenerator::visitMaybeExtractAwaitValue(MMaybeExtractAwaitValue* ins) {
6623 auto* lir = new (alloc()) LMaybeExtractAwaitValue(
6624 useBoxAtStart(ins->value()), useRegisterAtStart(ins->canSkip()));
6625 defineReturn(lir, ins);
6626 assignSafepoint(lir, ins);
6629 void LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins) {
6630 MDefinition* checkVal = ins->checkValue();
6631 MOZ_ASSERT(checkVal->type() == MIRType::Value);
6633 LDebugCheckSelfHosted* lir =
6634 new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal));
6635 redefine(ins, checkVal);
6636 add(lir, ins);
6637 assignSafepoint(lir, ins);
6640 void LIRGenerator::visitIsPackedArray(MIsPackedArray* ins) {
6641 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
6642 MOZ_ASSERT(ins->type() == MIRType::Boolean);
6644 auto lir = new (alloc()) LIsPackedArray(useRegister(ins->object()), temp());
6645 define(lir, ins);
6648 void LIRGenerator::visitGuardArrayIsPacked(MGuardArrayIsPacked* ins) {
6649 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
6651 auto* lir = new (alloc())
6652 LGuardArrayIsPacked(useRegister(ins->array()), temp(), temp());
6653 assignSnapshot(lir, ins->bailoutKind());
6654 add(lir, ins);
6655 redefine(ins, ins->array());
6658 void LIRGenerator::visitGetPrototypeOf(MGetPrototypeOf* ins) {
6659 MOZ_ASSERT(ins->target()->type() == MIRType::Object);
6660 MOZ_ASSERT(ins->type() == MIRType::Value);
6662 auto lir = new (alloc()) LGetPrototypeOf(useRegister(ins->target()));
6663 defineBox(lir, ins);
6664 assignSafepoint(lir, ins);
6667 void LIRGenerator::visitObjectWithProto(MObjectWithProto* ins) {
6668 MOZ_ASSERT(ins->prototype()->type() == MIRType::Value);
6669 MOZ_ASSERT(ins->type() == MIRType::Object);
6671 auto* lir = new (alloc()) LObjectWithProto(useBoxAtStart(ins->prototype()));
6672 defineReturn(lir, ins);
6673 assignSafepoint(lir, ins);
6676 void LIRGenerator::visitObjectStaticProto(MObjectStaticProto* ins) {
6677 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
6678 MOZ_ASSERT(ins->type() == MIRType::Object);
6680 auto* lir =
6681 new (alloc()) LObjectStaticProto(useRegisterAtStart(ins->object()));
6682 define(lir, ins);
6685 void LIRGenerator::visitBuiltinObject(MBuiltinObject* ins) {
6686 MOZ_ASSERT(ins->type() == MIRType::Object);
6688 auto* lir = new (alloc()) LBuiltinObject();
6689 defineReturn(lir, ins);
6690 assignSafepoint(lir, ins);
6693 void LIRGenerator::visitReturn(MReturn* ret) {
6694 return visitReturnImpl(ret->getOperand(0));
6697 void LIRGenerator::visitGeneratorReturn(MGeneratorReturn* ret) {
6698 return visitReturnImpl(ret->getOperand(0), true);
6701 void LIRGenerator::visitSuperFunction(MSuperFunction* ins) {
6702 MOZ_ASSERT(ins->callee()->type() == MIRType::Object);
6703 MOZ_ASSERT(ins->type() == MIRType::Value);
6705 auto* lir = new (alloc()) LSuperFunction(useRegister(ins->callee()), temp());
6706 defineBox(lir, ins);
6709 void LIRGenerator::visitInitHomeObject(MInitHomeObject* ins) {
6710 MDefinition* function = ins->function();
6711 MOZ_ASSERT(function->type() == MIRType::Object);
6713 MDefinition* homeObject = ins->homeObject();
6714 MOZ_ASSERT(homeObject->type() == MIRType::Value);
6716 MOZ_ASSERT(ins->type() == MIRType::Object);
6718 auto* lir = new (alloc())
6719 LInitHomeObject(useRegisterAtStart(function), useBoxAtStart(homeObject));
6720 redefine(ins, function);
6721 add(lir, ins);
6724 void LIRGenerator::visitIsTypedArrayConstructor(MIsTypedArrayConstructor* ins) {
6725 MDefinition* object = ins->object();
6726 MOZ_ASSERT(object->type() == MIRType::Object);
6728 auto* lir = new (alloc()) LIsTypedArrayConstructor(useRegister(object));
6729 define(lir, ins);
6732 void LIRGenerator::visitLoadValueTag(MLoadValueTag* ins) {
6733 MDefinition* value = ins->value();
6734 MOZ_ASSERT(value->type() == MIRType::Value);
6736 define(new (alloc()) LLoadValueTag(useBoxAtStart(value)), ins);
6739 void LIRGenerator::visitGuardTagNotEqual(MGuardTagNotEqual* ins) {
6740 MDefinition* lhs = ins->lhs();
6741 MOZ_ASSERT(lhs->type() == MIRType::Int32);
6743 MDefinition* rhs = ins->rhs();
6744 MOZ_ASSERT(rhs->type() == MIRType::Int32);
6746 auto* guard =
6747 new (alloc()) LGuardTagNotEqual(useRegister(lhs), useRegister(rhs));
6748 assignSnapshot(guard, ins->bailoutKind());
6749 add(guard, ins);
6752 void LIRGenerator::visitLoadWrapperTarget(MLoadWrapperTarget* ins) {
6753 MDefinition* object = ins->object();
6754 MOZ_ASSERT(object->type() == MIRType::Object);
6756 auto* lir = new (alloc()) LLoadWrapperTarget(useRegisterAtStart(object));
6757 if (ins->fallible()) {
6758 assignSnapshot(lir, ins->bailoutKind());
6760 define(lir, ins);
6763 void LIRGenerator::visitGuardHasGetterSetter(MGuardHasGetterSetter* ins) {
6764 MDefinition* object = ins->object();
6765 MOZ_ASSERT(object->type() == MIRType::Object);
6767 auto* guard = new (alloc())
6768 LGuardHasGetterSetter(useRegisterAtStart(object), tempFixed(CallTempReg0),
6769 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
6770 assignSnapshot(guard, ins->bailoutKind());
6771 add(guard, ins);
6772 redefine(ins, object);
6775 void LIRGenerator::visitGuardIsExtensible(MGuardIsExtensible* ins) {
6776 MDefinition* object = ins->object();
6777 MOZ_ASSERT(object->type() == MIRType::Object);
6779 auto* guard = new (alloc()) LGuardIsExtensible(useRegister(object), temp());
6780 assignSnapshot(guard, ins->bailoutKind());
6781 add(guard, ins);
6782 redefine(ins, object);
6785 void LIRGenerator::visitGuardInt32IsNonNegative(MGuardInt32IsNonNegative* ins) {
6786 MDefinition* index = ins->index();
6787 MOZ_ASSERT(index->type() == MIRType::Int32);
6789 auto* guard = new (alloc()) LGuardInt32IsNonNegative(useRegister(index));
6790 assignSnapshot(guard, ins->bailoutKind());
6791 add(guard, ins);
6792 redefine(ins, index);
6795 void LIRGenerator::visitGuardInt32Range(MGuardInt32Range* ins) {
6796 MDefinition* input = ins->input();
6797 MOZ_ASSERT(input->type() == MIRType::Int32);
6799 auto* guard = new (alloc()) LGuardInt32Range(useRegister(input));
6800 assignSnapshot(guard, ins->bailoutKind());
6801 add(guard, ins);
6802 redefine(ins, input);
6805 void LIRGenerator::visitGuardIndexIsNotDenseElement(
6806 MGuardIndexIsNotDenseElement* ins) {
6807 MDefinition* object = ins->object();
6808 MOZ_ASSERT(object->type() == MIRType::Object);
6810 MDefinition* index = ins->index();
6811 MOZ_ASSERT(index->type() == MIRType::Int32);
6813 LDefinition spectreTemp =
6814 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6816 auto* guard = new (alloc()) LGuardIndexIsNotDenseElement(
6817 useRegister(object), useRegister(index), temp(), spectreTemp);
6818 assignSnapshot(guard, ins->bailoutKind());
6819 add(guard, ins);
6820 redefine(ins, index);
6823 void LIRGenerator::visitGuardIndexIsValidUpdateOrAdd(
6824 MGuardIndexIsValidUpdateOrAdd* ins) {
6825 MDefinition* object = ins->object();
6826 MOZ_ASSERT(object->type() == MIRType::Object);
6828 MDefinition* index = ins->index();
6829 MOZ_ASSERT(index->type() == MIRType::Int32);
6831 LDefinition spectreTemp =
6832 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6834 auto* guard = new (alloc()) LGuardIndexIsValidUpdateOrAdd(
6835 useRegister(object), useRegister(index), temp(), spectreTemp);
6836 assignSnapshot(guard, ins->bailoutKind());
6837 add(guard, ins);
6838 redefine(ins, index);
6841 void LIRGenerator::visitCallAddOrUpdateSparseElement(
6842 MCallAddOrUpdateSparseElement* ins) {
6843 MDefinition* object = ins->object();
6844 MOZ_ASSERT(object->type() == MIRType::Object);
6846 MDefinition* index = ins->index();
6847 MOZ_ASSERT(index->type() == MIRType::Int32);
6849 MDefinition* value = ins->value();
6850 MOZ_ASSERT(value->type() == MIRType::Value);
6852 auto* lir = new (alloc()) LCallAddOrUpdateSparseElement(
6853 useRegisterAtStart(object), useRegisterAtStart(index),
6854 useBoxAtStart(value));
6855 add(lir, ins);
6856 assignSafepoint(lir, ins);
6859 void LIRGenerator::visitCallGetSparseElement(MCallGetSparseElement* ins) {
6860 MDefinition* object = ins->object();
6861 MOZ_ASSERT(object->type() == MIRType::Object);
6863 MDefinition* index = ins->index();
6864 MOZ_ASSERT(index->type() == MIRType::Int32);
6866 auto* lir = new (alloc()) LCallGetSparseElement(useRegisterAtStart(object),
6867 useRegisterAtStart(index));
6868 defineReturn(lir, ins);
6869 assignSafepoint(lir, ins);
6872 void LIRGenerator::visitCallNativeGetElement(MCallNativeGetElement* ins) {
6873 MDefinition* object = ins->object();
6874 MOZ_ASSERT(object->type() == MIRType::Object);
6876 MDefinition* index = ins->index();
6877 MOZ_ASSERT(index->type() == MIRType::Int32);
6879 auto* lir = new (alloc()) LCallNativeGetElement(useRegisterAtStart(object),
6880 useRegisterAtStart(index));
6881 defineReturn(lir, ins);
6882 assignSafepoint(lir, ins);
6885 void LIRGenerator::visitCallNativeGetElementSuper(
6886 MCallNativeGetElementSuper* ins) {
6887 MDefinition* object = ins->object();
6888 MOZ_ASSERT(object->type() == MIRType::Object);
6890 MDefinition* index = ins->index();
6891 MOZ_ASSERT(index->type() == MIRType::Int32);
6893 MDefinition* receiver = ins->receiver();
6895 auto* lir = new (alloc()) LCallNativeGetElementSuper(
6896 useRegisterAtStart(object), useRegisterAtStart(index),
6897 useBoxAtStart(receiver));
6898 defineReturn(lir, ins);
6899 assignSafepoint(lir, ins);
6902 void LIRGenerator::visitCallObjectHasSparseElement(
6903 MCallObjectHasSparseElement* ins) {
6904 MDefinition* object = ins->object();
6905 MOZ_ASSERT(object->type() == MIRType::Object);
6907 MDefinition* index = ins->index();
6908 MOZ_ASSERT(index->type() == MIRType::Int32);
6910 auto* lir = new (alloc()) LCallObjectHasSparseElement(
6911 useRegisterAtStart(object), useRegisterAtStart(index),
6912 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
6913 assignSnapshot(lir, ins->bailoutKind());
6914 defineReturn(lir, ins);
6917 void LIRGenerator::visitBigIntAsIntN(MBigIntAsIntN* ins) {
6918 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
6919 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
6921 if (ins->bits()->isConstant()) {
6922 int32_t bits = ins->bits()->toConstant()->toInt32();
6923 if (bits == 64) {
6924 auto* lir = new (alloc())
6925 LBigIntAsIntN64(useRegister(ins->input()), temp(), tempInt64());
6926 define(lir, ins);
6927 assignSafepoint(lir, ins);
6928 return;
6930 if (bits == 32) {
6931 auto* lir = new (alloc())
6932 LBigIntAsIntN32(useRegister(ins->input()), temp(), tempInt64());
6933 define(lir, ins);
6934 assignSafepoint(lir, ins);
6935 return;
6939 auto* lir = new (alloc()) LBigIntAsIntN(useRegisterAtStart(ins->bits()),
6940 useRegisterAtStart(ins->input()));
6941 defineReturn(lir, ins);
6942 assignSafepoint(lir, ins);
6945 void LIRGenerator::visitBigIntAsUintN(MBigIntAsUintN* ins) {
6946 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
6947 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
6949 if (ins->bits()->isConstant()) {
6950 int32_t bits = ins->bits()->toConstant()->toInt32();
6951 if (bits == 64) {
6952 auto* lir = new (alloc())
6953 LBigIntAsUintN64(useRegister(ins->input()), temp(), tempInt64());
6954 define(lir, ins);
6955 assignSafepoint(lir, ins);
6956 return;
6958 if (bits == 32) {
6959 auto* lir = new (alloc())
6960 LBigIntAsUintN32(useRegister(ins->input()), temp(), tempInt64());
6961 define(lir, ins);
6962 assignSafepoint(lir, ins);
6963 return;
6967 auto* lir = new (alloc()) LBigIntAsUintN(useRegisterAtStart(ins->bits()),
6968 useRegisterAtStart(ins->input()));
6969 defineReturn(lir, ins);
6970 assignSafepoint(lir, ins);
6973 void LIRGenerator::visitGuardNonGCThing(MGuardNonGCThing* ins) {
6974 MDefinition* input = ins->input();
6976 auto* guard = new (alloc()) LGuardNonGCThing(useBox(input));
6977 assignSnapshot(guard, ins->bailoutKind());
6978 add(guard, ins);
6979 redefine(ins, input);
6982 void LIRGenerator::visitToHashableNonGCThing(MToHashableNonGCThing* ins) {
6983 auto* lir =
6984 new (alloc()) LToHashableNonGCThing(useBox(ins->input()), tempDouble());
6985 defineBox(lir, ins);
6988 void LIRGenerator::visitToHashableString(MToHashableString* ins) {
6989 auto* lir = new (alloc()) LToHashableString(useRegister(ins->input()));
6990 define(lir, ins);
6991 assignSafepoint(lir, ins);
6994 void LIRGenerator::visitToHashableValue(MToHashableValue* ins) {
6995 auto* lir =
6996 new (alloc()) LToHashableValue(useBox(ins->input()), tempDouble());
6997 defineBox(lir, ins);
6998 assignSafepoint(lir, ins);
7001 void LIRGenerator::visitHashNonGCThing(MHashNonGCThing* ins) {
7002 auto* lir = new (alloc()) LHashNonGCThing(useBox(ins->input()), temp());
7003 define(lir, ins);
7006 void LIRGenerator::visitHashString(MHashString* ins) {
7007 auto* lir = new (alloc()) LHashString(useRegister(ins->input()), temp());
7008 define(lir, ins);
7011 void LIRGenerator::visitHashSymbol(MHashSymbol* ins) {
7012 auto* lir = new (alloc()) LHashSymbol(useRegister(ins->input()));
7013 define(lir, ins);
7016 void LIRGenerator::visitHashBigInt(MHashBigInt* ins) {
7017 auto* lir = new (alloc())
7018 LHashBigInt(useRegister(ins->input()), temp(), temp(), temp());
7019 define(lir, ins);
7022 void LIRGenerator::visitHashObject(MHashObject* ins) {
7023 auto* lir =
7024 new (alloc()) LHashObject(useRegister(ins->set()), useBox(ins->input()),
7025 temp(), temp(), temp(), temp());
7026 define(lir, ins);
7029 void LIRGenerator::visitHashValue(MHashValue* ins) {
7030 auto* lir =
7031 new (alloc()) LHashValue(useRegister(ins->set()), useBox(ins->input()),
7032 temp(), temp(), temp(), temp());
7033 define(lir, ins);
7036 void LIRGenerator::visitSetObjectHasNonBigInt(MSetObjectHasNonBigInt* ins) {
7037 auto* lir = new (alloc())
7038 LSetObjectHasNonBigInt(useRegister(ins->set()), useBox(ins->value()),
7039 useRegister(ins->hash()), temp(), temp());
7040 define(lir, ins);
7043 void LIRGenerator::visitSetObjectHasBigInt(MSetObjectHasBigInt* ins) {
7044 auto* lir = new (alloc()) LSetObjectHasBigInt(
7045 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
7046 temp(), temp(), temp(), temp());
7047 define(lir, ins);
7050 void LIRGenerator::visitSetObjectHasValue(MSetObjectHasValue* ins) {
7051 auto* lir = new (alloc()) LSetObjectHasValue(
7052 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
7053 temp(), temp(), temp(), temp());
7054 define(lir, ins);
7057 void LIRGenerator::visitSetObjectHasValueVMCall(MSetObjectHasValueVMCall* ins) {
7058 auto* lir = new (alloc()) LSetObjectHasValueVMCall(
7059 useRegisterAtStart(ins->set()), useBoxAtStart(ins->value()));
7060 defineReturn(lir, ins);
7061 assignSafepoint(lir, ins);
7064 void LIRGenerator::visitSetObjectSize(MSetObjectSize* ins) {
7065 auto* lir = new (alloc()) LSetObjectSize(useRegisterAtStart(ins->set()));
7066 define(lir, ins);
7069 void LIRGenerator::visitMapObjectHasNonBigInt(MMapObjectHasNonBigInt* ins) {
7070 auto* lir = new (alloc())
7071 LMapObjectHasNonBigInt(useRegister(ins->map()), useBox(ins->value()),
7072 useRegister(ins->hash()), temp(), temp());
7073 define(lir, ins);
7076 void LIRGenerator::visitMapObjectHasBigInt(MMapObjectHasBigInt* ins) {
7077 auto* lir = new (alloc()) LMapObjectHasBigInt(
7078 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7079 temp(), temp(), temp(), temp());
7080 define(lir, ins);
7083 void LIRGenerator::visitMapObjectHasValue(MMapObjectHasValue* ins) {
7084 auto* lir = new (alloc()) LMapObjectHasValue(
7085 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7086 temp(), temp(), temp(), temp());
7087 define(lir, ins);
7090 void LIRGenerator::visitMapObjectHasValueVMCall(MMapObjectHasValueVMCall* ins) {
7091 auto* lir = new (alloc()) LMapObjectHasValueVMCall(
7092 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
7093 defineReturn(lir, ins);
7094 assignSafepoint(lir, ins);
7097 void LIRGenerator::visitMapObjectGetNonBigInt(MMapObjectGetNonBigInt* ins) {
7098 auto* lir = new (alloc())
7099 LMapObjectGetNonBigInt(useRegister(ins->map()), useBox(ins->value()),
7100 useRegister(ins->hash()), temp(), temp());
7101 defineBox(lir, ins);
7104 void LIRGenerator::visitMapObjectGetBigInt(MMapObjectGetBigInt* ins) {
7105 auto* lir = new (alloc()) LMapObjectGetBigInt(
7106 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7107 temp(), temp(), temp(), temp());
7108 defineBox(lir, ins);
7111 void LIRGenerator::visitMapObjectGetValue(MMapObjectGetValue* ins) {
7112 auto* lir = new (alloc()) LMapObjectGetValue(
7113 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7114 temp(), temp(), temp(), temp());
7115 defineBox(lir, ins);
7118 void LIRGenerator::visitMapObjectGetValueVMCall(MMapObjectGetValueVMCall* ins) {
7119 auto* lir = new (alloc()) LMapObjectGetValueVMCall(
7120 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
7121 defineReturn(lir, ins);
7122 assignSafepoint(lir, ins);
7125 void LIRGenerator::visitMapObjectSize(MMapObjectSize* ins) {
7126 auto* lir = new (alloc()) LMapObjectSize(useRegisterAtStart(ins->map()));
7127 define(lir, ins);
7130 void LIRGenerator::visitPostIntPtrConversion(MPostIntPtrConversion* ins) {
7131 // This operation is a no-op.
7132 redefine(ins, ins->input());
7135 void LIRGenerator::visitConstant(MConstant* ins) {
7136 if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
7137 emitAtUses(ins);
7138 return;
7141 switch (ins->type()) {
7142 case MIRType::Double:
7143 define(new (alloc()) LDouble(ins->toDouble()), ins);
7144 break;
7145 case MIRType::Float32:
7146 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
7147 break;
7148 case MIRType::Boolean:
7149 define(new (alloc()) LInteger(ins->toBoolean()), ins);
7150 break;
7151 case MIRType::Int32:
7152 define(new (alloc()) LInteger(ins->toInt32()), ins);
7153 break;
7154 case MIRType::Int64:
7155 defineInt64(new (alloc()) LInteger64(ins->toInt64()), ins);
7156 break;
7157 case MIRType::IntPtr:
7158 #ifdef JS_64BIT
7159 defineInt64(new (alloc()) LInteger64(ins->toIntPtr()), ins);
7160 #else
7161 define(new (alloc()) LInteger(ins->toIntPtr()), ins);
7162 #endif
7163 break;
7164 case MIRType::String:
7165 define(new (alloc()) LPointer(ins->toString()), ins);
7166 break;
7167 case MIRType::Symbol:
7168 define(new (alloc()) LPointer(ins->toSymbol()), ins);
7169 break;
7170 case MIRType::BigInt:
7171 define(new (alloc()) LPointer(ins->toBigInt()), ins);
7172 break;
7173 case MIRType::Object:
7174 define(new (alloc()) LPointer(&ins->toObject()), ins);
7175 break;
7176 case MIRType::Shape:
7177 MOZ_ASSERT(ins->isEmittedAtUses());
7178 break;
7179 default:
7180 // Constants of special types (undefined, null) should never flow into
7181 // here directly. Operations blindly consuming them require a Box.
7182 MOZ_CRASH("unexpected constant type");
7186 void LIRGenerator::visitConstantProto(MConstantProto* ins) {
7187 JSObject* obj = &ins->protoObject()->toConstant()->toObject();
7188 define(new (alloc()) LPointer(obj), ins);
7191 void LIRGenerator::visitWasmNullConstant(MWasmNullConstant* ins) {
7192 define(new (alloc()) LWasmNullConstant(), ins);
7195 void LIRGenerator::visitWasmFloatConstant(MWasmFloatConstant* ins) {
7196 switch (ins->type()) {
7197 case MIRType::Double:
7198 define(new (alloc()) LDouble(ins->toDouble()), ins);
7199 break;
7200 case MIRType::Float32:
7201 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
7202 break;
7203 #ifdef ENABLE_WASM_SIMD
7204 case MIRType::Simd128:
7205 define(new (alloc()) LSimd128(ins->toSimd128()), ins);
7206 break;
7207 #endif
7208 default:
7209 MOZ_CRASH("unexpected constant type");
7213 #ifdef JS_JITSPEW
7214 static void SpewResumePoint(MBasicBlock* block, MInstruction* ins,
7215 MResumePoint* resumePoint) {
7216 Fprinter& out = JitSpewPrinter();
7217 out.printf("Current resume point %p details:\n", (void*)resumePoint);
7218 out.printf(" frame count: %u\n", resumePoint->frameCount());
7220 if (ins) {
7221 out.printf(" taken after: ");
7222 ins->printName(out);
7223 } else {
7224 out.printf(" taken at block %u entry", block->id());
7226 out.printf("\n");
7228 out.printf(" pc: %p (script: %p, offset: %d)\n", (void*)resumePoint->pc(),
7229 (void*)resumePoint->block()->info().script(),
7230 int(resumePoint->block()->info().script()->pcToOffset(
7231 resumePoint->pc())));
7233 for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) {
7234 MDefinition* in = resumePoint->getOperand(i);
7235 out.printf(" slot%u: ", (unsigned)i);
7236 in->printName(out);
7237 out.printf("\n");
7240 #endif
7242 void LIRGenerator::visitInstructionDispatch(MInstruction* ins) {
7243 #ifdef JS_CODEGEN_NONE
7244 // Don't compile the switch-statement below so that we don't have to define
7245 // the platform-specific visit* methods for the none-backend.
7246 MOZ_CRASH();
7247 #else
7248 switch (ins->op()) {
7249 # define MIR_OP(op) \
7250 case MDefinition::Opcode::op: \
7251 visit##op(ins->to##op()); \
7252 break;
7253 MIR_OPCODE_LIST(MIR_OP)
7254 # undef MIR_OP
7255 default:
7256 MOZ_CRASH("Invalid instruction");
7258 #endif
7261 void LIRGeneratorShared::visitEmittedAtUses(MInstruction* ins) {
7262 static_cast<LIRGenerator*>(this)->visitInstructionDispatch(ins);
7265 bool LIRGenerator::visitInstruction(MInstruction* ins) {
7266 MOZ_ASSERT(!errored());
7268 if (ins->isRecoveredOnBailout()) {
7269 MOZ_ASSERT(!JitOptions.disableRecoverIns);
7270 return true;
7273 if (!gen->ensureBallast()) {
7274 return false;
7276 visitInstructionDispatch(ins);
7278 if (ins->resumePoint()) {
7279 updateResumeState(ins);
7282 #ifdef DEBUG
7283 ins->setInWorklistUnchecked();
7284 #endif
7286 // If no safepoint was created, there's no need for an OSI point.
7287 if (LOsiPoint* osiPoint = popOsiPoint()) {
7288 add(osiPoint);
7291 return !errored();
7294 bool LIRGenerator::definePhis() {
7295 size_t lirIndex = 0;
7296 MBasicBlock* block = current->mir();
7297 for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
7298 if (phi->type() == MIRType::Value) {
7299 defineUntypedPhi(*phi, lirIndex);
7300 lirIndex += BOX_PIECES;
7301 } else if (phi->type() == MIRType::Int64) {
7302 defineInt64Phi(*phi, lirIndex);
7303 lirIndex += INT64_PIECES;
7304 } else {
7305 defineTypedPhi(*phi, lirIndex);
7306 lirIndex += 1;
7309 return !errored();
7312 void LIRGenerator::updateResumeState(MInstruction* ins) {
7313 lastResumePoint_ = ins->resumePoint();
7314 #ifdef JS_JITSPEW
7315 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
7316 SpewResumePoint(nullptr, ins, lastResumePoint_);
7318 #endif
7321 void LIRGenerator::updateResumeState(MBasicBlock* block) {
7322 // Note: RangeAnalysis can flag blocks as unreachable, but they are only
7323 // removed iff GVN (including UCE) is enabled.
7324 MOZ_ASSERT_IF(!mir()->compilingWasm() && !block->unreachable(),
7325 block->entryResumePoint());
7326 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7327 lastResumePoint_ = block->entryResumePoint();
7328 #ifdef JS_JITSPEW
7329 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
7330 SpewResumePoint(block, nullptr, lastResumePoint_);
7332 #endif
7335 bool LIRGenerator::visitBlock(MBasicBlock* block) {
7336 current = block->lir();
7337 updateResumeState(block);
7339 if (!definePhis()) {
7340 return false;
7343 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7344 for (MInstructionIterator iter = block->begin(); *iter != block->lastIns();
7345 iter++) {
7346 if (!visitInstruction(*iter)) {
7347 return false;
7351 if (block->successorWithPhis()) {
7352 // If we have a successor with phis, lower the phi input now that we
7353 // are approaching the join point.
7354 MBasicBlock* successor = block->successorWithPhis();
7355 uint32_t position = block->positionInPhiSuccessor();
7356 size_t lirIndex = 0;
7357 for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd();
7358 phi++) {
7359 if (!gen->ensureBallast()) {
7360 return false;
7363 MDefinition* opd = phi->getOperand(position);
7364 ensureDefined(opd);
7366 MOZ_ASSERT(opd->type() == phi->type());
7368 if (phi->type() == MIRType::Value) {
7369 lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex);
7370 lirIndex += BOX_PIECES;
7371 } else if (phi->type() == MIRType::Int64) {
7372 lowerInt64PhiInput(*phi, position, successor->lir(), lirIndex);
7373 lirIndex += INT64_PIECES;
7374 } else {
7375 lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex);
7376 lirIndex += 1;
7381 // Now emit the last instruction, which is some form of branch.
7382 if (!visitInstruction(block->lastIns())) {
7383 return false;
7386 return true;
7389 void LIRGenerator::visitNaNToZero(MNaNToZero* ins) {
7390 MDefinition* input = ins->input();
7392 if (ins->operandIsNeverNaN() && ins->operandIsNeverNegativeZero()) {
7393 redefine(ins, input);
7394 return;
7396 LNaNToZero* lir =
7397 new (alloc()) LNaNToZero(useRegisterAtStart(input), tempDouble());
7398 defineReuseInput(lir, ins, 0);
7401 bool LIRGenerator::generate() {
7402 // Create all blocks and prep all phis beforehand.
7403 for (ReversePostorderIterator block(graph.rpoBegin());
7404 block != graph.rpoEnd(); block++) {
7405 if (gen->shouldCancel("Lowering (preparation loop)")) {
7406 return false;
7409 if (!lirGraph_.initBlock(*block)) {
7410 return false;
7414 for (ReversePostorderIterator block(graph.rpoBegin());
7415 block != graph.rpoEnd(); block++) {
7416 if (gen->shouldCancel("Lowering (main loop)")) {
7417 return false;
7420 if (!visitBlock(*block)) {
7421 return false;
7425 lirGraph_.setArgumentSlotCount(maxargslots_);
7426 return true;
7429 void LIRGenerator::visitPhi(MPhi* phi) {
7430 // Phi nodes are not lowered because they are only meaningful for the register
7431 // allocator.
7432 MOZ_CRASH("Unexpected Phi node during Lowering.");
7435 void LIRGenerator::visitBeta(MBeta* beta) {
7436 // Beta nodes are supposed to be removed before because they are
7437 // only used to carry the range information for Range analysis
7438 MOZ_CRASH("Unexpected Beta node during Lowering.");
7441 void LIRGenerator::visitObjectState(MObjectState* objState) {
7442 // ObjectState nodes are always recovered on bailouts
7443 MOZ_CRASH("Unexpected ObjectState node during Lowering.");
7446 void LIRGenerator::visitArrayState(MArrayState* objState) {
7447 // ArrayState nodes are always recovered on bailouts
7448 MOZ_CRASH("Unexpected ArrayState node during Lowering.");
7451 void LIRGenerator::visitIonToWasmCall(MIonToWasmCall* ins) {
7452 // The instruction needs a temp register:
7453 // - that's not the FramePointer, since wasm is going to use it in the
7454 // function.
7455 // - that's not aliasing an input register.
7456 LDefinition scratch = tempFixed(ABINonArgReg0);
7458 // Note that since this is a LIR call instruction, regalloc will prevent
7459 // the use*AtStart below from reusing any of the temporaries.
7461 LInstruction* lir;
7462 if (ins->type() == MIRType::Value) {
7463 lir = allocateVariadic<LIonToWasmCallV>(ins->numOperands(), scratch);
7464 } else if (ins->type() == MIRType::Int64) {
7465 lir = allocateVariadic<LIonToWasmCallI64>(ins->numOperands(), scratch);
7466 } else {
7467 lir = allocateVariadic<LIonToWasmCall>(ins->numOperands(), scratch);
7469 if (!lir) {
7470 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitIonToWasmCall");
7471 return;
7474 ABIArgGenerator abi;
7475 for (unsigned i = 0; i < ins->numOperands(); i++) {
7476 MDefinition* argDef = ins->getOperand(i);
7477 ABIArg arg = abi.next(ToMIRType(argDef->type()));
7478 switch (arg.kind()) {
7479 case ABIArg::GPR:
7480 case ABIArg::FPU:
7481 lir->setOperand(i, useFixedAtStart(argDef, arg.reg()));
7482 break;
7483 case ABIArg::Stack:
7484 lir->setOperand(i, useAtStart(argDef));
7485 break;
7486 #ifdef JS_CODEGEN_REGISTER_PAIR
7487 case ABIArg::GPR_PAIR:
7488 MOZ_CRASH(
7489 "no way to pass i64, and wasm uses hardfp for function calls");
7490 #endif
7491 case ABIArg::Uninitialized:
7492 MOZ_CRASH("Uninitialized ABIArg kind");
7496 defineReturn(lir, ins);
7497 assignSafepoint(lir, ins);
7500 void LIRGenerator::visitWasmSelect(MWasmSelect* ins) {
7501 MDefinition* condExpr = ins->condExpr();
7503 // Pick off specific cases that we can do with LWasmCompareAndSelect to avoid
7504 // generating a boolean that we then have to test again.
7505 if (condExpr->isCompare() && condExpr->isEmittedAtUses()) {
7506 MCompare* comp = condExpr->toCompare();
7507 MCompare::CompareType compTy = comp->compareType();
7508 if (canSpecializeWasmCompareAndSelect(compTy, ins->type())) {
7509 JSOp jsop = comp->jsop();
7510 // We don't currently generate any other JSOPs for the comparison, and if
7511 // that changes, we want to know about it. Hence this assertion.
7512 MOZ_ASSERT(jsop == JSOp::Eq || jsop == JSOp::Ne || jsop == JSOp::Lt ||
7513 jsop == JSOp::Gt || jsop == JSOp::Le || jsop == JSOp::Ge);
7514 MDefinition* lhs = comp->lhs();
7515 MDefinition* rhs = comp->rhs();
7516 jsop = ReorderComparison(jsop, &lhs, &rhs);
7517 lowerWasmCompareAndSelect(ins, lhs, rhs, compTy, jsop);
7518 return;
7521 // Fall through to code that generates a boolean and selects on that.
7523 if (ins->type() == MIRType::Int64) {
7524 lowerWasmSelectI64(ins);
7525 return;
7528 lowerWasmSelectI(ins);
7531 void LIRGenerator::visitWasmFence(MWasmFence* ins) {
7532 add(new (alloc()) LWasmFence, ins);
7535 void LIRGenerator::visitWasmLoadField(MWasmLoadField* ins) {
7536 uint32_t offs = ins->offset();
7537 LAllocation obj = useRegister(ins->obj());
7538 MWideningOp wideningOp = ins->wideningOp();
7539 if (ins->type() == MIRType::Int64) {
7540 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7541 defineInt64(new (alloc()) LWasmLoadSlotI64(obj, offs, ins->maybeTrap()),
7542 ins);
7543 } else {
7544 define(new (alloc()) LWasmLoadSlot(obj, offs, ins->type(), wideningOp,
7545 ins->maybeTrap()),
7546 ins);
7550 void LIRGenerator::visitWasmLoadFieldKA(MWasmLoadFieldKA* ins) {
7551 uint32_t offs = ins->offset();
7552 LAllocation obj = useRegister(ins->obj());
7553 MWideningOp wideningOp = ins->wideningOp();
7554 if (ins->type() == MIRType::Int64) {
7555 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7556 defineInt64(new (alloc()) LWasmLoadSlotI64(obj, offs, ins->maybeTrap()),
7557 ins);
7558 } else {
7559 define(new (alloc()) LWasmLoadSlot(obj, offs, ins->type(), wideningOp,
7560 ins->maybeTrap()),
7561 ins);
7563 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7566 void LIRGenerator::visitWasmLoadElementKA(MWasmLoadElementKA* ins) {
7567 LAllocation base = useRegister(ins->base());
7568 LAllocation index = useRegister(ins->index());
7569 MWideningOp wideningOp = ins->wideningOp();
7570 Scale scale = ins->scale();
7571 if (ins->type() == MIRType::Int64) {
7572 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7573 defineInt64(
7574 new (alloc()) LWasmLoadElementI64(base, index, ins->maybeTrap()), ins);
7575 } else {
7576 LDefinition tmp =
7577 ins->type() == MIRType::Simd128 ? temp() : LDefinition::BogusTemp();
7578 define(new (alloc()) LWasmLoadElement(base, index, tmp, ins->type(),
7579 wideningOp, scale, ins->maybeTrap()),
7580 ins);
7582 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7585 void LIRGenerator::visitWasmStoreFieldKA(MWasmStoreFieldKA* ins) {
7586 MDefinition* value = ins->value();
7587 uint32_t offs = ins->offset();
7588 MNarrowingOp narrowingOp = ins->narrowingOp();
7589 LAllocation obj = useRegister(ins->obj());
7590 LInstruction* lir;
7591 if (value->type() == MIRType::Int64) {
7592 MOZ_RELEASE_ASSERT(narrowingOp == MNarrowingOp::None);
7593 lir = new (alloc())
7594 LWasmStoreSlotI64(useInt64Register(value), obj, offs, ins->maybeTrap());
7595 } else {
7596 lir = new (alloc())
7597 LWasmStoreSlot(useRegister(value), obj, offs, value->type(),
7598 narrowingOp, ins->maybeTrap());
7600 add(lir, ins);
7601 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7604 void LIRGenerator::visitWasmStoreFieldRefKA(MWasmStoreFieldRefKA* ins) {
7605 LAllocation instance = useRegister(ins->instance());
7606 LAllocation obj = useFixed(ins->obj(), PreBarrierReg);
7607 LAllocation value = useRegister(ins->value());
7608 uint32_t offset = ins->offset();
7609 add(new (alloc()) LWasmStoreRef(instance, obj, value, temp(), offset,
7610 ins->maybeTrap(), ins->preBarrierKind()),
7611 ins);
7612 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7615 void LIRGenerator::visitWasmStoreElementKA(MWasmStoreElementKA* ins) {
7616 LAllocation base = useRegister(ins->base());
7617 LAllocation index = useRegister(ins->index());
7618 MDefinition* value = ins->value();
7619 MNarrowingOp narrowingOp = ins->narrowingOp();
7620 Scale scale = ins->scale();
7621 LInstruction* lir;
7622 if (value->type() == MIRType::Int64) {
7623 MOZ_RELEASE_ASSERT(narrowingOp == MNarrowingOp::None);
7624 lir = new (alloc()) LWasmStoreElementI64(
7625 base, index, useInt64Register(value), ins->maybeTrap());
7626 } else {
7627 LDefinition tmp =
7628 value->type() == MIRType::Simd128 ? temp() : LDefinition::BogusTemp();
7629 lir = new (alloc())
7630 LWasmStoreElement(base, index, useRegister(value), tmp, value->type(),
7631 narrowingOp, scale, ins->maybeTrap());
7633 add(lir, ins);
7634 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7637 void LIRGenerator::visitWasmStoreElementRefKA(MWasmStoreElementRefKA* ins) {
7638 LAllocation instance = useRegister(ins->instance());
7639 LAllocation base = useFixed(ins->base(), PreBarrierReg);
7640 LAllocation index = useRegister(ins->index());
7641 LAllocation value = useRegister(ins->value());
7642 bool needTemps = ins->preBarrierKind() == WasmPreBarrierKind::Normal;
7643 LDefinition temp0 = needTemps ? temp() : LDefinition::BogusTemp();
7644 LDefinition temp1 = needTemps ? temp() : LDefinition::BogusTemp();
7645 add(new (alloc())
7646 LWasmStoreElementRef(instance, base, index, value, temp0, temp1,
7647 ins->maybeTrap(), ins->preBarrierKind()),
7648 ins);
7649 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7652 WasmRefIsSubtypeDefs LIRGenerator::useWasmRefIsSubtype(wasm::RefType destType,
7653 MDefinition* superSTV) {
7654 BranchWasmRefIsSubtypeRegisters needs =
7655 MacroAssembler::regsForBranchWasmRefIsSubtype(destType);
7656 return WasmRefIsSubtypeDefs{
7657 .superSTV = needs.needSuperSTV ? useRegister(superSTV) : LAllocation(),
7658 .scratch1 = needs.needScratch1 ? temp() : LDefinition(),
7659 .scratch2 = needs.needScratch2 ? temp() : LDefinition(),
7663 void LIRGenerator::visitWasmRefIsSubtypeOfAbstract(
7664 MWasmRefIsSubtypeOfAbstract* ins) {
7665 if (CanEmitAtUseForSingleTest(ins)) {
7666 emitAtUses(ins);
7667 return;
7670 LAllocation ref = useRegister(ins->ref());
7671 WasmRefIsSubtypeDefs regs =
7672 useWasmRefIsSubtype(ins->destType(), /*superSTV=*/nullptr);
7673 define(new (alloc()) LWasmRefIsSubtypeOfAbstract(ref, regs.scratch1), ins);
7676 void LIRGenerator::visitWasmRefIsSubtypeOfConcrete(
7677 MWasmRefIsSubtypeOfConcrete* ins) {
7678 if (CanEmitAtUseForSingleTest(ins)) {
7679 emitAtUses(ins);
7680 return;
7683 LAllocation ref = useRegister(ins->ref());
7684 WasmRefIsSubtypeDefs regs =
7685 useWasmRefIsSubtype(ins->destType(), ins->superSTV());
7686 define(new (alloc()) LWasmRefIsSubtypeOfConcrete(
7687 ref, regs.superSTV, regs.scratch1, regs.scratch2),
7688 ins);
7691 void LIRGenerator::visitWasmNewStructObject(MWasmNewStructObject* ins) {
7692 LWasmNewStructObject* lir = new (alloc())
7693 LWasmNewStructObject(useFixed(ins->instance(), InstanceReg),
7694 useRegister(ins->typeDefData()), temp(), temp());
7695 define(lir, ins);
7696 assignWasmSafepoint(lir);
7699 void LIRGenerator::visitWasmNewArrayObject(MWasmNewArrayObject* ins) {
7700 LWasmNewArrayObject* lir = new (alloc())
7701 LWasmNewArrayObject(useFixed(ins->instance(), InstanceReg),
7702 useRegisterOrConstant(ins->numElements()),
7703 useRegister(ins->typeDefData()), temp(), temp());
7704 define(lir, ins);
7705 assignWasmSafepoint(lir);
7708 #ifdef FUZZING_JS_FUZZILLI
7709 void LIRGenerator::visitFuzzilliHash(MFuzzilliHash* ins) {
7710 MDefinition* value = ins->getOperand(0);
7712 if (value->type() == MIRType::Undefined || value->type() == MIRType::Null) {
7713 define(new (alloc()) LFuzzilliHashT(LAllocation(), temp(), tempDouble()),
7714 ins);
7715 } else if (value->type() == MIRType::Int32 ||
7716 value->type() == MIRType::Double ||
7717 value->type() == MIRType::Float32 ||
7718 value->type() == MIRType::Boolean ||
7719 value->type() == MIRType::BigInt) {
7720 define(new (alloc())
7721 LFuzzilliHashT(useRegister(value), temp(), tempDouble()),
7722 ins);
7723 } else if (value->type() == MIRType::Object) {
7724 LFuzzilliHashT* lir =
7725 new (alloc()) LFuzzilliHashT(useRegister(value), temp(), tempDouble());
7726 define(lir, ins);
7727 assignSafepoint(lir, ins);
7728 } else if (value->type() == MIRType::Value) {
7729 LFuzzilliHashV* lir =
7730 new (alloc()) LFuzzilliHashV(useBox(value), temp(), tempDouble());
7731 define(lir, ins);
7732 assignSafepoint(lir, ins);
7733 } else {
7734 define(new (alloc()) LInteger(0), ins);
7738 void LIRGenerator::visitFuzzilliHashStore(MFuzzilliHashStore* ins) {
7739 MDefinition* value = ins->getOperand(0);
7740 MOZ_ASSERT(value->type() == MIRType::Int32);
7741 add(new (alloc()) LFuzzilliHashStore(useRegister(value), temp(), temp()),
7742 ins);
7744 #endif
7746 static_assert(!std::is_polymorphic_v<LIRGenerator>,
7747 "LIRGenerator should not have any virtual methods");
7749 #ifdef JS_CODEGEN_NONE
7750 void LIRGenerator::visitReturnImpl(MDefinition*, bool) { MOZ_CRASH(); }
7751 #endif