Bug 1874684 - Part 29: Update spec fixme notes. r=mgaudet
[gecko.git] / js / src / jit / Lowering.cpp
blob45e06281c7453d49f583cb7cae5ae36a6375bfa7
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 auto argc = useFixedAtStart(apply->getArgc(), CallTempReg0);
658 auto thisValue =
659 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5);
660 auto tempObj = tempFixed(CallTempReg1); // object register
661 auto tempCopy = tempFixed(CallTempReg2); // copy register
663 auto* target = apply->getSingleTarget();
665 LInstruction* lir;
666 if (target && target->isNativeWithoutJitEntry()) {
667 auto temp = tempFixed(CallTempReg3);
669 lir = new (alloc())
670 LApplyArgsNative(argc, thisValue, tempObj, tempCopy, temp);
671 } else {
672 auto function = useFixedAtStart(apply->getFunction(), CallTempReg3);
674 lir = new (alloc())
675 LApplyArgsGeneric(function, argc, thisValue, tempObj, tempCopy);
678 // Bailout is needed in the case of too many values in the arguments array.
679 assignSnapshot(lir, apply->bailoutKind());
681 defineReturn(lir, apply);
682 assignSafepoint(lir, apply);
685 void LIRGenerator::visitApplyArgsObj(MApplyArgsObj* apply) {
686 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
688 // Assert if the return value is already erased.
689 static_assert(CallTempReg2 != JSReturnReg_Type);
690 static_assert(CallTempReg2 != JSReturnReg_Data);
692 auto argsObj = useFixedAtStart(apply->getArgsObj(), CallTempReg0);
693 auto thisValue =
694 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5);
695 auto tempObj = tempFixed(CallTempReg1); // object register
696 auto tempCopy = tempFixed(CallTempReg2); // copy register
698 auto* target = apply->getSingleTarget();
700 LInstruction* lir;
701 if (target && target->isNativeWithoutJitEntry()) {
702 auto temp = tempFixed(CallTempReg3);
704 lir = new (alloc())
705 LApplyArgsObjNative(argsObj, thisValue, tempObj, tempCopy, temp);
706 } else {
707 auto function = useFixedAtStart(apply->getFunction(), CallTempReg3);
709 lir = new (alloc())
710 LApplyArgsObj(function, argsObj, thisValue, tempObj, tempCopy);
713 // Bailout is needed in the case of too many values in the arguments array.
714 assignSnapshot(lir, apply->bailoutKind());
716 defineReturn(lir, apply);
717 assignSafepoint(lir, apply);
720 void LIRGenerator::visitApplyArray(MApplyArray* apply) {
721 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
723 // Assert if the return value is already erased.
724 static_assert(CallTempReg2 != JSReturnReg_Type);
725 static_assert(CallTempReg2 != JSReturnReg_Data);
727 auto elements = useFixedAtStart(apply->getElements(), CallTempReg0);
728 auto thisValue =
729 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5);
730 auto tempObj = tempFixed(CallTempReg1); // object register
731 auto tempCopy = tempFixed(CallTempReg2); // copy register
733 auto* target = apply->getSingleTarget();
735 LInstruction* lir;
736 if (target && target->isNativeWithoutJitEntry()) {
737 auto temp = tempFixed(CallTempReg3);
739 lir = new (alloc())
740 LApplyArrayNative(elements, thisValue, tempObj, tempCopy, temp);
741 } else {
742 auto function = useFixedAtStart(apply->getFunction(), CallTempReg3);
744 lir = new (alloc())
745 LApplyArrayGeneric(function, elements, thisValue, tempObj, tempCopy);
748 // Bailout is needed in the case of too many values in the array, or empty
749 // space at the end of the array.
750 assignSnapshot(lir, apply->bailoutKind());
752 defineReturn(lir, apply);
753 assignSafepoint(lir, apply);
756 void LIRGenerator::visitConstructArgs(MConstructArgs* mir) {
757 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object);
758 MOZ_ASSERT(mir->getArgc()->type() == MIRType::Int32);
759 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object);
760 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value);
762 // Assert if the return value is already erased.
763 static_assert(CallTempReg2 != JSReturnReg_Type);
764 static_assert(CallTempReg2 != JSReturnReg_Data);
766 auto argc = useFixedAtStart(mir->getArgc(), CallTempReg0);
767 auto newTarget = useFixedAtStart(mir->getNewTarget(), CallTempReg1);
768 auto temp = tempFixed(CallTempReg2);
770 auto* target = mir->getSingleTarget();
772 LInstruction* lir;
773 if (target && target->isNativeWithoutJitEntry()) {
774 auto temp2 = tempFixed(CallTempReg3);
775 auto temp3 = tempFixed(CallTempReg4);
777 lir =
778 new (alloc()) LConstructArgsNative(argc, newTarget, temp, temp2, temp3);
779 } else {
780 auto function = useFixedAtStart(mir->getFunction(), CallTempReg3);
781 auto thisValue =
782 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5);
784 lir = new (alloc())
785 LConstructArgsGeneric(function, argc, newTarget, thisValue, temp);
788 // Bailout is needed in the case of too many values in the arguments array.
789 assignSnapshot(lir, mir->bailoutKind());
791 defineReturn(lir, mir);
792 assignSafepoint(lir, mir);
795 void LIRGenerator::visitConstructArray(MConstructArray* mir) {
796 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object);
797 MOZ_ASSERT(mir->getElements()->type() == MIRType::Elements);
798 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object);
799 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value);
801 // Assert if the return value is already erased.
802 static_assert(CallTempReg2 != JSReturnReg_Type);
803 static_assert(CallTempReg2 != JSReturnReg_Data);
805 auto elements = useFixedAtStart(mir->getElements(), CallTempReg0);
806 auto newTarget = useFixedAtStart(mir->getNewTarget(), CallTempReg1);
807 auto temp = tempFixed(CallTempReg2);
809 auto* target = mir->getSingleTarget();
811 LInstruction* lir;
812 if (target && target->isNativeWithoutJitEntry()) {
813 auto temp2 = tempFixed(CallTempReg3);
814 auto temp3 = tempFixed(CallTempReg4);
816 lir = new (alloc())
817 LConstructArrayNative(elements, newTarget, temp, temp2, temp3);
818 } else {
819 auto function = useFixedAtStart(mir->getFunction(), CallTempReg3);
820 auto thisValue =
821 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5);
823 lir = new (alloc())
824 LConstructArrayGeneric(function, elements, newTarget, thisValue, temp);
827 // Bailout is needed in the case of too many values in the array, or empty
828 // space at the end of the array.
829 assignSnapshot(lir, mir->bailoutKind());
831 defineReturn(lir, mir);
832 assignSafepoint(lir, mir);
835 void LIRGenerator::visitBail(MBail* bail) {
836 LBail* lir = new (alloc()) LBail();
837 assignSnapshot(lir, bail->bailoutKind());
838 add(lir, bail);
841 void LIRGenerator::visitUnreachable(MUnreachable* unreachable) {
842 LUnreachable* lir = new (alloc()) LUnreachable();
843 add(lir, unreachable);
846 void LIRGenerator::visitEncodeSnapshot(MEncodeSnapshot* mir) {
847 LEncodeSnapshot* lir = new (alloc()) LEncodeSnapshot();
848 assignSnapshot(lir, mir->bailoutKind());
849 add(lir, mir);
852 void LIRGenerator::visitUnreachableResult(MUnreachableResult* mir) {
853 if (mir->type() == MIRType::Value) {
854 auto* lir = new (alloc()) LUnreachableResultV();
855 defineBox(lir, mir);
856 } else {
857 auto* lir = new (alloc()) LUnreachableResultT();
858 define(lir, mir);
862 void LIRGenerator::visitAssertFloat32(MAssertFloat32* assertion) {
863 MIRType type = assertion->input()->type();
864 DebugOnly<bool> checkIsFloat32 = assertion->mustBeFloat32();
866 if (type != MIRType::Value && !JitOptions.eagerIonCompilation()) {
867 MOZ_ASSERT_IF(checkIsFloat32, type == MIRType::Float32);
868 MOZ_ASSERT_IF(!checkIsFloat32, type != MIRType::Float32);
872 void LIRGenerator::visitAssertRecoveredOnBailout(
873 MAssertRecoveredOnBailout* assertion) {
874 MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
877 [[nodiscard]] static JSOp ReorderComparison(JSOp op, MDefinition** lhsp,
878 MDefinition** rhsp) {
879 MDefinition* lhs = *lhsp;
880 MDefinition* rhs = *rhsp;
882 if (lhs->maybeConstantValue()) {
883 *rhsp = lhs;
884 *lhsp = rhs;
885 return ReverseCompareOp(op);
887 return op;
890 void LIRGenerator::visitTest(MTest* test) {
891 MDefinition* opd = test->getOperand(0);
892 MBasicBlock* ifTrue = test->ifTrue();
893 MBasicBlock* ifFalse = test->ifFalse();
895 // String is converted to length of string in the type analysis phase (see
896 // TestPolicy).
897 MOZ_ASSERT(opd->type() != MIRType::String);
899 // Testing a constant.
900 if (MConstant* constant = opd->maybeConstantValue()) {
901 bool b;
902 if (constant->valueToBoolean(&b)) {
903 add(new (alloc()) LGoto(b ? ifTrue : ifFalse));
904 return;
908 if (opd->type() == MIRType::Value) {
909 auto* lir = new (alloc()) LTestVAndBranch(
910 ifTrue, ifFalse, useBox(opd), tempDouble(), tempToUnbox(), temp());
911 add(lir, test);
912 return;
915 // Objects are truthy, except if it might emulate undefined.
916 if (opd->type() == MIRType::Object) {
917 add(new (alloc())
918 LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp()),
919 test);
920 return;
923 // These must be explicitly sniffed out since they are constants and have
924 // no payload.
925 if (opd->type() == MIRType::Undefined || opd->type() == MIRType::Null) {
926 add(new (alloc()) LGoto(ifFalse));
927 return;
930 // All symbols are truthy.
931 if (opd->type() == MIRType::Symbol) {
932 add(new (alloc()) LGoto(ifTrue));
933 return;
936 // Try to match the pattern
937 // test=MTest(
938 // comp=MCompare(
939 // {EQ,NE} for {Int,UInt}{32,64},
940 // bitAnd={MBitAnd,MWasmBinaryBitwise(And{32,64})}(x, y),
941 // MConstant(0)
942 // )
943 // )
944 // and produce a single LBitAndAndBranch node. This requires both `comp`
945 // and `bitAnd` to be marked emit-at-uses. Since we can't use
946 // LBitAndAndBranch to represent a 64-bit AND on a 32-bit target, the 64-bit
947 // case is restricted to 64-bit targets.
948 if (opd->isCompare() && opd->isEmittedAtUses()) {
949 #ifdef JS_64BIT
950 constexpr bool targetIs64 = true;
951 #else
952 constexpr bool targetIs64 = false;
953 #endif
954 MCompare* comp = opd->toCompare();
955 Assembler::Condition compCond =
956 JSOpToCondition(comp->compareType(), comp->jsop());
957 MDefinition* compL = comp->getOperand(0);
958 MDefinition* compR = comp->getOperand(1);
959 if ((comp->compareType() == MCompare::Compare_Int32 ||
960 comp->compareType() == MCompare::Compare_UInt32 ||
961 (targetIs64 && comp->compareType() == MCompare::Compare_Int64) ||
962 (targetIs64 && comp->compareType() == MCompare::Compare_UInt64)) &&
963 (compCond == Assembler::Equal || compCond == Assembler::NotEqual) &&
964 compR->isConstant() &&
965 (compR->toConstant()->isInt32(0) ||
966 (targetIs64 && compR->toConstant()->isInt64(0))) &&
967 (compL->isBitAnd() || (compL->isWasmBinaryBitwise() &&
968 compL->toWasmBinaryBitwise()->subOpcode() ==
969 MWasmBinaryBitwise::SubOpcode::And))) {
970 // The MCompare is OK; now check its first operand (the and-ish node).
971 MDefinition* bitAnd = compL;
972 MDefinition* bitAndL = bitAnd->getOperand(0);
973 MDefinition* bitAndR = bitAnd->getOperand(1);
974 MIRType bitAndLTy = bitAndL->type();
975 MIRType bitAndRTy = bitAndR->type();
976 if (bitAnd->isEmittedAtUses() && bitAndLTy == bitAndRTy &&
977 (bitAndLTy == MIRType::Int32 ||
978 (targetIs64 && bitAndLTy == MIRType::Int64))) {
979 // Pattern match succeeded.
980 ReorderCommutative(&bitAndL, &bitAndR, test);
981 if (compCond == Assembler::Equal) {
982 compCond = Assembler::Zero;
983 } else if (compCond == Assembler::NotEqual) {
984 compCond = Assembler::NonZero;
985 } else {
986 MOZ_ASSERT_UNREACHABLE("inequality operators cannot be folded");
988 MOZ_ASSERT_IF(!targetIs64, bitAndLTy == MIRType::Int32);
989 lowerForBitAndAndBranch(
990 new (alloc()) LBitAndAndBranch(
991 ifTrue, ifFalse, bitAndLTy == MIRType::Int64, compCond),
992 test, bitAndL, bitAndR);
993 return;
998 // Check if the operand for this test is a compare operation. If it is, we
999 // want to emit an LCompare*AndBranch rather than an LTest*AndBranch, to fuse
1000 // the compare and jump instructions.
1001 if (opd->isCompare() && opd->isEmittedAtUses()) {
1002 MCompare* comp = opd->toCompare();
1003 MDefinition* left = comp->lhs();
1004 MDefinition* right = comp->rhs();
1006 // Try to fold the comparison so that we don't have to handle all cases.
1007 bool result;
1008 if (comp->tryFold(&result)) {
1009 add(new (alloc()) LGoto(result ? ifTrue : ifFalse));
1010 return;
1013 // Emit LCompare*AndBranch.
1015 // Compare and branch null/undefined.
1016 // The second operand has known null/undefined type,
1017 // so just test the first operand.
1018 if (comp->compareType() == MCompare::Compare_Null ||
1019 comp->compareType() == MCompare::Compare_Undefined) {
1020 if (left->type() == MIRType::Object) {
1021 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchT(
1022 comp, useRegister(left), ifTrue, ifFalse, temp());
1023 add(lir, test);
1024 return;
1027 if (IsLooseEqualityOp(comp->jsop())) {
1028 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchV(
1029 comp, ifTrue, ifFalse, useBox(left), temp(), tempToUnbox());
1030 add(lir, test);
1031 return;
1034 if (comp->compareType() == MCompare::Compare_Null) {
1035 auto* lir =
1036 new (alloc()) LIsNullAndBranch(comp, ifTrue, ifFalse, useBox(left));
1037 add(lir, test);
1038 return;
1041 auto* lir = new (alloc())
1042 LIsUndefinedAndBranch(comp, ifTrue, ifFalse, useBox(left));
1043 add(lir, test);
1044 return;
1047 // Compare and branch Int32, Symbol, Object, or WasmAnyRef pointers.
1048 if (comp->isInt32Comparison() ||
1049 comp->compareType() == MCompare::Compare_UInt32 ||
1050 comp->compareType() == MCompare::Compare_UIntPtr ||
1051 comp->compareType() == MCompare::Compare_Object ||
1052 comp->compareType() == MCompare::Compare_Symbol ||
1053 comp->compareType() == MCompare::Compare_WasmAnyRef) {
1054 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1055 LAllocation lhs = useRegister(left);
1056 LAllocation rhs;
1057 if (comp->isInt32Comparison() ||
1058 comp->compareType() == MCompare::Compare_UInt32 ||
1059 comp->compareType() == MCompare::Compare_UIntPtr) {
1060 rhs = useAnyOrInt32Constant(right);
1061 } else {
1062 rhs = useAny(right);
1064 LCompareAndBranch* lir =
1065 new (alloc()) LCompareAndBranch(comp, op, lhs, rhs, ifTrue, ifFalse);
1066 add(lir, test);
1067 return;
1070 // Compare and branch Int64.
1071 if (comp->compareType() == MCompare::Compare_Int64 ||
1072 comp->compareType() == MCompare::Compare_UInt64) {
1073 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1074 lowerForCompareI64AndBranch(test, comp, op, left, right, ifTrue, ifFalse);
1075 return;
1078 // Compare and branch doubles.
1079 if (comp->isDoubleComparison()) {
1080 LAllocation lhs = useRegister(left);
1081 LAllocation rhs = useRegister(right);
1082 LCompareDAndBranch* lir =
1083 new (alloc()) LCompareDAndBranch(comp, lhs, rhs, ifTrue, ifFalse);
1084 add(lir, test);
1085 return;
1088 // Compare and branch floats.
1089 if (comp->isFloat32Comparison()) {
1090 LAllocation lhs = useRegister(left);
1091 LAllocation rhs = useRegister(right);
1092 LCompareFAndBranch* lir =
1093 new (alloc()) LCompareFAndBranch(comp, lhs, rhs, ifTrue, ifFalse);
1094 add(lir, test);
1095 return;
1099 // Check if the operand for this test is a bitand operation. If it is, we want
1100 // to emit an LBitAndAndBranch rather than an LTest*AndBranch.
1101 if (opd->isBitAnd() && opd->isEmittedAtUses()) {
1102 MDefinition* lhs = opd->getOperand(0);
1103 MDefinition* rhs = opd->getOperand(1);
1104 if (lhs->type() == MIRType::Int32 && rhs->type() == MIRType::Int32) {
1105 ReorderCommutative(&lhs, &rhs, test);
1106 lowerForBitAndAndBranch(new (alloc()) LBitAndAndBranch(ifTrue, ifFalse,
1107 /*is64=*/false),
1108 test, lhs, rhs);
1109 return;
1113 #if defined(ENABLE_WASM_SIMD) && \
1114 (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || \
1115 defined(JS_CODEGEN_ARM64))
1116 // Check if the operand for this test is an any_true/all_true SIMD operation.
1117 // If it is, we want to emit an LWasmReduceAndBranchSimd128 node to avoid
1118 // generating an intermediate boolean result.
1119 if (opd->isWasmReduceSimd128() && opd->isEmittedAtUses()) {
1120 MWasmReduceSimd128* node = opd->toWasmReduceSimd128();
1121 if (canFoldReduceSimd128AndBranch(node->simdOp())) {
1122 # ifdef DEBUG
1123 js::wasm::ReportSimdAnalysis("simd128-to-scalar-and-branch -> folded");
1124 # endif
1125 auto* lir = new (alloc()) LWasmReduceAndBranchSimd128(
1126 useRegister(node->input()), node->simdOp(), ifTrue, ifFalse);
1127 add(lir, test);
1128 return;
1131 #endif
1133 if (opd->isIsObject() && opd->isEmittedAtUses()) {
1134 MDefinition* input = opd->toIsObject()->input();
1135 MOZ_ASSERT(input->type() == MIRType::Value);
1137 LIsObjectAndBranch* lir =
1138 new (alloc()) LIsObjectAndBranch(ifTrue, ifFalse, useBoxAtStart(input));
1139 add(lir, test);
1140 return;
1143 if (opd->isWasmRefIsSubtypeOfAbstract() && opd->isEmittedAtUses()) {
1144 MWasmRefIsSubtypeOfAbstract* isSubTypeOf =
1145 opd->toWasmRefIsSubtypeOfAbstract();
1147 LAllocation ref = useRegister(isSubTypeOf->ref());
1148 WasmRefIsSubtypeDefs regs =
1149 useWasmRefIsSubtype(isSubTypeOf->destType(), /*superSTV=*/nullptr);
1150 add(new (alloc()) LWasmRefIsSubtypeOfAbstractAndBranch(
1151 ifTrue, ifFalse, isSubTypeOf->sourceType(), isSubTypeOf->destType(),
1152 ref, regs.scratch1),
1153 test);
1154 return;
1157 if (opd->isWasmRefIsSubtypeOfConcrete() && opd->isEmittedAtUses()) {
1158 MWasmRefIsSubtypeOfConcrete* isSubTypeOf =
1159 opd->toWasmRefIsSubtypeOfConcrete();
1161 LAllocation ref = useRegister(isSubTypeOf->ref());
1162 WasmRefIsSubtypeDefs regs =
1163 useWasmRefIsSubtype(isSubTypeOf->destType(), isSubTypeOf->superSTV());
1164 add(new (alloc()) LWasmRefIsSubtypeOfConcreteAndBranch(
1165 ifTrue, ifFalse, isSubTypeOf->sourceType(), isSubTypeOf->destType(),
1166 ref, regs.superSTV, regs.scratch1, regs.scratch2),
1167 test);
1168 return;
1171 if (opd->isIsNullOrUndefined() && opd->isEmittedAtUses()) {
1172 MIsNullOrUndefined* isNullOrUndefined = opd->toIsNullOrUndefined();
1173 MDefinition* input = isNullOrUndefined->value();
1175 if (input->type() == MIRType::Value) {
1176 auto* lir = new (alloc()) LIsNullOrUndefinedAndBranch(
1177 isNullOrUndefined, ifTrue, ifFalse, useBoxAtStart(input));
1178 add(lir, test);
1179 } else {
1180 auto* target = IsNullOrUndefined(input->type()) ? ifTrue : ifFalse;
1181 add(new (alloc()) LGoto(target));
1183 return;
1186 if (opd->isIsNoIter()) {
1187 MOZ_ASSERT(opd->isEmittedAtUses());
1189 MDefinition* input = opd->toIsNoIter()->input();
1190 MOZ_ASSERT(input->type() == MIRType::Value);
1192 LIsNoIterAndBranch* lir =
1193 new (alloc()) LIsNoIterAndBranch(ifTrue, ifFalse, useBox(input));
1194 add(lir, test);
1195 return;
1198 if (opd->isIteratorHasIndices()) {
1199 MOZ_ASSERT(opd->isEmittedAtUses());
1201 MDefinition* object = opd->toIteratorHasIndices()->object();
1202 MDefinition* iterator = opd->toIteratorHasIndices()->iterator();
1203 LIteratorHasIndicesAndBranch* lir = new (alloc())
1204 LIteratorHasIndicesAndBranch(ifTrue, ifFalse, useRegister(object),
1205 useRegister(iterator), temp(), temp());
1206 add(lir, test);
1207 return;
1210 switch (opd->type()) {
1211 case MIRType::Double:
1212 add(new (alloc()) LTestDAndBranch(useRegister(opd), ifTrue, ifFalse));
1213 break;
1214 case MIRType::Float32:
1215 add(new (alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse));
1216 break;
1217 case MIRType::Int32:
1218 case MIRType::Boolean:
1219 add(new (alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse));
1220 break;
1221 case MIRType::Int64:
1222 add(new (alloc())
1223 LTestI64AndBranch(useInt64Register(opd), ifTrue, ifFalse));
1224 break;
1225 case MIRType::BigInt:
1226 add(new (alloc()) LTestBIAndBranch(useRegister(opd), ifTrue, ifFalse));
1227 break;
1228 default:
1229 MOZ_CRASH("Bad type");
1233 static inline bool CanEmitCompareAtUses(MInstruction* ins) {
1234 if (!ins->canEmitAtUses()) {
1235 return false;
1238 // If the result is never used, we can usefully defer emission to the use
1239 // point, since that will never happen.
1240 MUseIterator iter(ins->usesBegin());
1241 if (iter == ins->usesEnd()) {
1242 return true;
1245 // If the first use isn't of the expected form, the answer is No.
1246 MNode* node = iter->consumer();
1247 if (!node->isDefinition()) {
1248 return false;
1251 MDefinition* use = node->toDefinition();
1252 if (!use->isTest() && !use->isWasmSelect()) {
1253 return false;
1256 // Emission can be deferred to the first use point, but only if there are no
1257 // other use points.
1258 iter++;
1259 return iter == ins->usesEnd();
1262 void LIRGenerator::visitCompare(MCompare* comp) {
1263 MDefinition* left = comp->lhs();
1264 MDefinition* right = comp->rhs();
1266 // Try to fold the comparison so that we don't have to handle all cases.
1267 bool result;
1268 if (comp->tryFold(&result)) {
1269 define(new (alloc()) LInteger(result), comp);
1270 return;
1273 // Move below the emitAtUses call if we ever implement
1274 // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't
1275 // make sense and avoids confusion.
1276 if (comp->compareType() == MCompare::Compare_String) {
1277 MConstant* constant = nullptr;
1278 MDefinition* input = nullptr;
1279 if (left->isConstant()) {
1280 constant = left->toConstant();
1281 input = right;
1282 } else if (right->isConstant()) {
1283 constant = right->toConstant();
1284 input = left;
1287 if (constant) {
1288 JSLinearString* linear = &constant->toString()->asLinear();
1290 if (IsEqualityOp(comp->jsop())) {
1291 if (MacroAssembler::canCompareStringCharsInline(linear)) {
1292 auto* lir = new (alloc()) LCompareSInline(useRegister(input), linear);
1293 define(lir, comp);
1294 assignSafepoint(lir, comp);
1295 return;
1297 } else {
1298 MOZ_ASSERT(IsRelationalOp(comp->jsop()));
1300 if (linear->length() == 1) {
1301 // Move the constant value into the right-hand side operand.
1302 JSOp op = comp->jsop();
1303 if (left == constant) {
1304 op = ReverseCompareOp(op);
1307 auto* lir = new (alloc())
1308 LCompareSSingle(useRegister(input), temp(), op, linear);
1309 define(lir, comp);
1310 return;
1315 LCompareS* lir =
1316 new (alloc()) LCompareS(useRegister(left), useRegister(right));
1317 define(lir, comp);
1318 assignSafepoint(lir, comp);
1319 return;
1322 // Compare two BigInts.
1323 if (comp->compareType() == MCompare::Compare_BigInt) {
1324 auto* lir = new (alloc()) LCompareBigInt(
1325 useRegister(left), useRegister(right), temp(), temp(), temp());
1326 define(lir, comp);
1327 return;
1330 // Compare BigInt with Int32.
1331 if (comp->compareType() == MCompare::Compare_BigInt_Int32) {
1332 auto* lir = new (alloc()) LCompareBigIntInt32(
1333 useRegister(left), useRegister(right), temp(), temp());
1334 define(lir, comp);
1335 return;
1338 // Compare BigInt with Double.
1339 if (comp->compareType() == MCompare::Compare_BigInt_Double) {
1340 auto* lir = new (alloc()) LCompareBigIntDouble(useRegisterAtStart(left),
1341 useRegisterAtStart(right));
1342 defineReturn(lir, comp);
1343 return;
1346 // Compare BigInt with String.
1347 if (comp->compareType() == MCompare::Compare_BigInt_String) {
1348 auto* lir = new (alloc()) LCompareBigIntString(useRegisterAtStart(left),
1349 useRegisterAtStart(right));
1350 defineReturn(lir, comp);
1351 assignSafepoint(lir, comp);
1352 return;
1355 // Sniff out if the output of this compare is used only for a branching.
1356 // If it is, then we will emit an LCompare*AndBranch instruction in place
1357 // of this compare and any test that uses this compare. Thus, we can
1358 // ignore this Compare.
1359 if (CanEmitCompareAtUses(comp)) {
1360 emitAtUses(comp);
1361 return;
1364 // Compare Null and Undefined.
1365 if (comp->compareType() == MCompare::Compare_Null ||
1366 comp->compareType() == MCompare::Compare_Undefined) {
1367 if (left->type() == MIRType::Object) {
1368 define(new (alloc()) LIsNullOrLikeUndefinedT(useRegister(left)), comp);
1369 return;
1372 if (IsLooseEqualityOp(comp->jsop())) {
1373 auto* lir =
1374 new (alloc()) LIsNullOrLikeUndefinedV(useBox(left), tempToUnbox());
1375 define(lir, comp);
1376 return;
1379 if (comp->compareType() == MCompare::Compare_Null) {
1380 auto* lir = new (alloc()) LIsNull(useBox(left));
1381 define(lir, comp);
1382 return;
1385 auto* lir = new (alloc()) LIsUndefined(useBox(left));
1386 define(lir, comp);
1387 return;
1390 // Compare Int32, Symbol, Object or Wasm pointers.
1391 if (comp->isInt32Comparison() ||
1392 comp->compareType() == MCompare::Compare_UInt32 ||
1393 comp->compareType() == MCompare::Compare_UIntPtr ||
1394 comp->compareType() == MCompare::Compare_Object ||
1395 comp->compareType() == MCompare::Compare_Symbol ||
1396 comp->compareType() == MCompare::Compare_WasmAnyRef) {
1397 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1398 LAllocation lhs = useRegister(left);
1399 LAllocation rhs;
1400 if (comp->isInt32Comparison() ||
1401 comp->compareType() == MCompare::Compare_UInt32 ||
1402 comp->compareType() == MCompare::Compare_UIntPtr) {
1403 rhs = useAnyOrInt32Constant(right);
1404 } else {
1405 rhs = useAny(right);
1407 define(new (alloc()) LCompare(op, lhs, rhs), comp);
1408 return;
1411 // Compare Int64.
1412 if (comp->compareType() == MCompare::Compare_Int64 ||
1413 comp->compareType() == MCompare::Compare_UInt64) {
1414 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1415 define(new (alloc()) LCompareI64(op, useInt64Register(left),
1416 useInt64OrConstant(right)),
1417 comp);
1418 return;
1421 // Compare doubles.
1422 if (comp->isDoubleComparison()) {
1423 define(new (alloc()) LCompareD(useRegister(left), useRegister(right)),
1424 comp);
1425 return;
1428 // Compare float32.
1429 if (comp->isFloat32Comparison()) {
1430 define(new (alloc()) LCompareF(useRegister(left), useRegister(right)),
1431 comp);
1432 return;
1435 MOZ_CRASH("Unrecognized compare type.");
1438 void LIRGenerator::visitSameValueDouble(MSameValueDouble* ins) {
1439 MDefinition* lhs = ins->lhs();
1440 MDefinition* rhs = ins->rhs();
1442 MOZ_ASSERT(lhs->type() == MIRType::Double);
1443 MOZ_ASSERT(rhs->type() == MIRType::Double);
1445 auto* lir = new (alloc())
1446 LSameValueDouble(useRegister(lhs), useRegister(rhs), tempDouble());
1447 define(lir, ins);
1450 void LIRGenerator::visitSameValue(MSameValue* ins) {
1451 MDefinition* lhs = ins->lhs();
1452 MDefinition* rhs = ins->rhs();
1454 MOZ_ASSERT(lhs->type() == MIRType::Value);
1455 MOZ_ASSERT(rhs->type() == MIRType::Value);
1457 auto* lir = new (alloc()) LSameValue(useBox(lhs), useBox(rhs));
1458 define(lir, ins);
1459 assignSafepoint(lir, ins);
1462 void LIRGenerator::lowerBitOp(JSOp op, MBinaryInstruction* ins) {
1463 MDefinition* lhs = ins->getOperand(0);
1464 MDefinition* rhs = ins->getOperand(1);
1465 MOZ_ASSERT(IsIntType(ins->type()));
1467 if (ins->type() == MIRType::Int32) {
1468 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1469 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1470 ReorderCommutative(&lhs, &rhs, ins);
1471 lowerForALU(new (alloc()) LBitOpI(op), ins, lhs, rhs);
1472 return;
1475 if (ins->type() == MIRType::Int64) {
1476 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1477 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1478 ReorderCommutative(&lhs, &rhs, ins);
1479 lowerForALUInt64(new (alloc()) LBitOpI64(op), ins, lhs, rhs);
1480 return;
1483 MOZ_CRASH("Unhandled integer specialization");
1486 void LIRGenerator::visitTypeOf(MTypeOf* ins) {
1487 MDefinition* opd = ins->input();
1489 if (opd->type() == MIRType::Object) {
1490 auto* lir = new (alloc()) LTypeOfO(useRegister(opd));
1491 define(lir, ins);
1492 return;
1495 MOZ_ASSERT(opd->type() == MIRType::Value);
1497 LTypeOfV* lir = new (alloc()) LTypeOfV(useBox(opd), tempToUnbox());
1498 define(lir, ins);
1501 void LIRGenerator::visitTypeOfName(MTypeOfName* ins) {
1502 MDefinition* input = ins->input();
1503 MOZ_ASSERT(input->type() == MIRType::Int32);
1505 auto* lir = new (alloc()) LTypeOfName(useRegister(input));
1506 define(lir, ins);
1509 void LIRGenerator::visitTypeOfIs(MTypeOfIs* ins) {
1510 MDefinition* input = ins->input();
1512 MOZ_ASSERT(input->type() == MIRType::Object ||
1513 input->type() == MIRType::Value);
1515 switch (ins->jstype()) {
1516 case JSTYPE_UNDEFINED:
1517 case JSTYPE_OBJECT:
1518 case JSTYPE_FUNCTION: {
1519 if (input->type() == MIRType::Object) {
1520 auto* lir = new (alloc()) LTypeOfIsNonPrimitiveO(useRegister(input));
1521 define(lir, ins);
1522 } else {
1523 auto* lir =
1524 new (alloc()) LTypeOfIsNonPrimitiveV(useBox(input), tempToUnbox());
1525 define(lir, ins);
1527 return;
1530 case JSTYPE_STRING:
1531 case JSTYPE_NUMBER:
1532 case JSTYPE_BOOLEAN:
1533 case JSTYPE_SYMBOL:
1534 case JSTYPE_BIGINT: {
1535 MOZ_ASSERT(input->type() == MIRType::Value);
1537 auto* lir = new (alloc()) LTypeOfIsPrimitive(useBoxAtStart(input));
1538 define(lir, ins);
1539 return;
1542 #ifdef ENABLE_RECORD_TUPLE
1543 case JSTYPE_RECORD:
1544 case JSTYPE_TUPLE:
1545 #endif
1546 case JSTYPE_LIMIT:
1547 break;
1549 MOZ_CRASH("Unhandled JSType");
1552 void LIRGenerator::visitToAsyncIter(MToAsyncIter* ins) {
1553 LToAsyncIter* lir = new (alloc()) LToAsyncIter(
1554 useRegisterAtStart(ins->iterator()), useBoxAtStart(ins->nextMethod()));
1555 defineReturn(lir, ins);
1556 assignSafepoint(lir, ins);
1559 void LIRGenerator::visitToPropertyKeyCache(MToPropertyKeyCache* ins) {
1560 MDefinition* input = ins->getOperand(0);
1561 MOZ_ASSERT(ins->type() == MIRType::Value);
1563 auto* lir = new (alloc()) LToPropertyKeyCache(useBox(input));
1564 defineBox(lir, ins);
1565 assignSafepoint(lir, ins);
1568 void LIRGenerator::visitBitNot(MBitNot* ins) {
1569 MDefinition* input = ins->getOperand(0);
1571 if (ins->type() == MIRType::Int32) {
1572 MOZ_ASSERT(input->type() == MIRType::Int32);
1573 lowerForALU(new (alloc()) LBitNotI(), ins, input);
1574 return;
1577 if (ins->type() == MIRType::Int64) {
1578 MOZ_ASSERT(input->type() == MIRType::Int64);
1579 lowerForALUInt64(new (alloc()) LBitNotI64(), ins, input);
1580 return;
1583 MOZ_CRASH("Unhandled integer specialization");
1586 static bool CanEmitBitAndAtUses(MInstruction* ins) {
1587 if (!ins->canEmitAtUses()) {
1588 return false;
1591 MIRType tyL = ins->getOperand(0)->type();
1592 MIRType tyR = ins->getOperand(1)->type();
1593 if (tyL != tyR || (tyL != MIRType::Int32 && tyL != MIRType::Int64)) {
1594 return false;
1597 MUseIterator iter(ins->usesBegin());
1598 if (iter == ins->usesEnd()) {
1599 return false;
1602 MNode* node = iter->consumer();
1603 if (!node->isDefinition() || !node->toDefinition()->isInstruction()) {
1604 return false;
1607 MInstruction* use = node->toDefinition()->toInstruction();
1608 if (!use->isTest() && !(use->isCompare() && CanEmitCompareAtUses(use))) {
1609 return false;
1612 iter++;
1613 return iter == ins->usesEnd();
1616 void LIRGenerator::visitBitAnd(MBitAnd* ins) {
1617 // Sniff out if the output of this bitand is used only for a branching.
1618 // If it is, then we will emit an LBitAndAndBranch instruction in place
1619 // of this bitand and any test that uses this bitand. Thus, we can
1620 // ignore this BitAnd.
1621 if (CanEmitBitAndAtUses(ins)) {
1622 emitAtUses(ins);
1623 } else {
1624 lowerBitOp(JSOp::BitAnd, ins);
1628 void LIRGenerator::visitBitOr(MBitOr* ins) { lowerBitOp(JSOp::BitOr, ins); }
1630 void LIRGenerator::visitBitXor(MBitXor* ins) { lowerBitOp(JSOp::BitXor, ins); }
1632 void LIRGenerator::visitWasmBinaryBitwise(MWasmBinaryBitwise* ins) {
1633 switch (ins->subOpcode()) {
1634 case MWasmBinaryBitwise::SubOpcode::And:
1635 if (CanEmitBitAndAtUses(ins)) {
1636 emitAtUses(ins);
1637 } else {
1638 lowerBitOp(JSOp::BitAnd, ins);
1640 break;
1641 case MWasmBinaryBitwise::SubOpcode::Or:
1642 lowerBitOp(JSOp::BitOr, ins);
1643 break;
1644 case MWasmBinaryBitwise::SubOpcode::Xor:
1645 lowerBitOp(JSOp::BitXor, ins);
1646 break;
1647 default:
1648 MOZ_CRASH();
1652 void LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins) {
1653 MDefinition* lhs = ins->getOperand(0);
1654 MDefinition* rhs = ins->getOperand(1);
1656 if (op == JSOp::Ursh && ins->type() == MIRType::Double) {
1657 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1658 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1659 lowerUrshD(ins->toUrsh());
1660 return;
1663 MOZ_ASSERT(IsIntType(ins->type()));
1665 if (ins->type() == MIRType::Int32) {
1666 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1667 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1669 LShiftI* lir = new (alloc()) LShiftI(op);
1670 if (op == JSOp::Ursh) {
1671 if (ins->toUrsh()->fallible()) {
1672 assignSnapshot(lir, ins->bailoutKind());
1675 lowerForShift(lir, ins, lhs, rhs);
1676 return;
1679 if (ins->type() == MIRType::Int64) {
1680 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1681 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1682 lowerForShiftInt64(new (alloc()) LShiftI64(op), ins, lhs, rhs);
1683 return;
1686 MOZ_CRASH("Unhandled integer specialization");
1689 void LIRGenerator::visitLsh(MLsh* ins) { lowerShiftOp(JSOp::Lsh, ins); }
1691 void LIRGenerator::visitRsh(MRsh* ins) { lowerShiftOp(JSOp::Rsh, ins); }
1693 void LIRGenerator::visitUrsh(MUrsh* ins) { lowerShiftOp(JSOp::Ursh, ins); }
1695 void LIRGenerator::visitSignExtendInt32(MSignExtendInt32* ins) {
1696 LInstructionHelper<1, 1, 0>* lir;
1698 if (ins->mode() == MSignExtendInt32::Byte) {
1699 lir = new (alloc())
1700 LSignExtendInt32(useByteOpRegisterAtStart(ins->input()), ins->mode());
1701 } else {
1702 lir = new (alloc())
1703 LSignExtendInt32(useRegisterAtStart(ins->input()), ins->mode());
1706 define(lir, ins);
1709 void LIRGenerator::visitRotate(MRotate* ins) {
1710 MDefinition* input = ins->input();
1711 MDefinition* count = ins->count();
1713 if (ins->type() == MIRType::Int32) {
1714 auto* lir = new (alloc()) LRotate();
1715 lowerForShift(lir, ins, input, count);
1716 } else if (ins->type() == MIRType::Int64) {
1717 auto* lir = new (alloc()) LRotateI64();
1718 lowerForShiftInt64(lir, ins, input, count);
1719 } else {
1720 MOZ_CRASH("unexpected type in visitRotate");
1724 void LIRGenerator::visitFloor(MFloor* ins) {
1725 MIRType type = ins->input()->type();
1726 MOZ_ASSERT(IsFloatingPointType(type));
1728 LInstructionHelper<1, 1, 0>* lir;
1729 if (type == MIRType::Double) {
1730 lir = new (alloc()) LFloor(useRegister(ins->input()));
1731 } else {
1732 lir = new (alloc()) LFloorF(useRegister(ins->input()));
1735 assignSnapshot(lir, ins->bailoutKind());
1736 define(lir, ins);
1739 void LIRGenerator::visitCeil(MCeil* ins) {
1740 MIRType type = ins->input()->type();
1741 MOZ_ASSERT(IsFloatingPointType(type));
1743 LInstructionHelper<1, 1, 0>* lir;
1744 if (type == MIRType::Double) {
1745 lir = new (alloc()) LCeil(useRegister(ins->input()));
1746 } else {
1747 lir = new (alloc()) LCeilF(useRegister(ins->input()));
1750 assignSnapshot(lir, ins->bailoutKind());
1751 define(lir, ins);
1754 void LIRGenerator::visitRound(MRound* ins) {
1755 MIRType type = ins->input()->type();
1756 MOZ_ASSERT(IsFloatingPointType(type));
1758 LInstructionHelper<1, 1, 1>* lir;
1759 if (type == MIRType::Double) {
1760 lir = new (alloc()) LRound(useRegister(ins->input()), tempDouble());
1761 } else {
1762 lir = new (alloc()) LRoundF(useRegister(ins->input()), tempFloat32());
1765 assignSnapshot(lir, ins->bailoutKind());
1766 define(lir, ins);
1769 void LIRGenerator::visitTrunc(MTrunc* ins) {
1770 MIRType type = ins->input()->type();
1771 MOZ_ASSERT(IsFloatingPointType(type));
1773 LInstructionHelper<1, 1, 0>* lir;
1774 if (type == MIRType::Double) {
1775 lir = new (alloc()) LTrunc(useRegister(ins->input()));
1776 } else {
1777 lir = new (alloc()) LTruncF(useRegister(ins->input()));
1780 assignSnapshot(lir, ins->bailoutKind());
1781 define(lir, ins);
1784 void LIRGenerator::visitNearbyInt(MNearbyInt* ins) {
1785 MIRType inputType = ins->input()->type();
1786 MOZ_ASSERT(IsFloatingPointType(inputType));
1787 MOZ_ASSERT(ins->type() == inputType);
1789 LInstructionHelper<1, 1, 0>* lir;
1790 if (inputType == MIRType::Double) {
1791 lir = new (alloc()) LNearbyInt(useRegisterAtStart(ins->input()));
1792 } else {
1793 lir = new (alloc()) LNearbyIntF(useRegisterAtStart(ins->input()));
1796 define(lir, ins);
1799 void LIRGenerator::visitMinMax(MMinMax* ins) {
1800 MDefinition* first = ins->getOperand(0);
1801 MDefinition* second = ins->getOperand(1);
1803 ReorderCommutative(&first, &second, ins);
1805 LMinMaxBase* lir;
1806 switch (ins->type()) {
1807 case MIRType::Int32:
1808 lir = new (alloc())
1809 LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
1810 break;
1811 case MIRType::Float32:
1812 lir = new (alloc())
1813 LMinMaxF(useRegisterAtStart(first), useRegister(second));
1814 break;
1815 case MIRType::Double:
1816 lir = new (alloc())
1817 LMinMaxD(useRegisterAtStart(first), useRegister(second));
1818 break;
1819 default:
1820 MOZ_CRASH();
1823 // Input reuse is OK (for now) even on ARM64: floating min/max are fairly
1824 // expensive due to SNaN -> QNaN conversion, and int min/max is for asm.js.
1825 defineReuseInput(lir, ins, 0);
1828 void LIRGenerator::visitMinMaxArray(MMinMaxArray* ins) {
1829 LInstructionHelper<1, 1, 3>* lir;
1830 if (ins->type() == MIRType::Int32) {
1831 lir = new (alloc())
1832 LMinMaxArrayI(useRegisterAtStart(ins->array()), temp(), temp(), temp());
1833 } else {
1834 MOZ_ASSERT(ins->type() == MIRType::Double);
1835 lir = new (alloc()) LMinMaxArrayD(useRegisterAtStart(ins->array()),
1836 tempDouble(), temp(), temp());
1838 assignSnapshot(lir, ins->bailoutKind());
1839 define(lir, ins);
1842 LInstructionHelper<1, 1, 0>* LIRGenerator::allocateAbs(MAbs* ins,
1843 LAllocation input) {
1844 MDefinition* num = ins->input();
1845 MOZ_ASSERT(IsNumberType(num->type()));
1847 LInstructionHelper<1, 1, 0>* lir;
1848 switch (num->type()) {
1849 case MIRType::Int32:
1850 lir = new (alloc()) LAbsI(input);
1851 // needed to handle abs(INT32_MIN)
1852 if (ins->fallible()) {
1853 assignSnapshot(lir, ins->bailoutKind());
1855 break;
1856 case MIRType::Float32:
1857 lir = new (alloc()) LAbsF(input);
1858 break;
1859 case MIRType::Double:
1860 lir = new (alloc()) LAbsD(input);
1861 break;
1862 default:
1863 MOZ_CRASH();
1865 return lir;
1868 void LIRGenerator::visitClz(MClz* ins) {
1869 MDefinition* num = ins->num();
1871 MOZ_ASSERT(IsIntType(ins->type()));
1873 if (ins->type() == MIRType::Int32) {
1874 LClzI* lir = new (alloc()) LClzI(useRegisterAtStart(num));
1875 define(lir, ins);
1876 return;
1879 auto* lir = new (alloc()) LClzI64(useInt64RegisterAtStart(num));
1880 defineInt64(lir, ins);
1883 void LIRGenerator::visitCtz(MCtz* ins) {
1884 MDefinition* num = ins->num();
1886 MOZ_ASSERT(IsIntType(ins->type()));
1888 if (ins->type() == MIRType::Int32) {
1889 LCtzI* lir = new (alloc()) LCtzI(useRegisterAtStart(num));
1890 define(lir, ins);
1891 return;
1894 auto* lir = new (alloc()) LCtzI64(useInt64RegisterAtStart(num));
1895 defineInt64(lir, ins);
1898 void LIRGenerator::visitPopcnt(MPopcnt* ins) {
1899 MDefinition* num = ins->num();
1901 MOZ_ASSERT(IsIntType(ins->type()));
1903 if (ins->type() == MIRType::Int32) {
1904 LPopcntI* lir = new (alloc()) LPopcntI(useRegisterAtStart(num), temp());
1905 define(lir, ins);
1906 return;
1909 auto* lir = new (alloc()) LPopcntI64(useInt64RegisterAtStart(num), temp());
1910 defineInt64(lir, ins);
1913 void LIRGenerator::visitSqrt(MSqrt* ins) {
1914 MDefinition* num = ins->input();
1915 MOZ_ASSERT(IsFloatingPointType(num->type()));
1917 LInstructionHelper<1, 1, 0>* lir;
1918 if (num->type() == MIRType::Double) {
1919 lir = new (alloc()) LSqrtD(useRegisterAtStart(num));
1920 } else {
1921 lir = new (alloc()) LSqrtF(useRegisterAtStart(num));
1923 define(lir, ins);
1926 void LIRGenerator::visitAtan2(MAtan2* ins) {
1927 MDefinition* y = ins->y();
1928 MOZ_ASSERT(y->type() == MIRType::Double);
1930 MDefinition* x = ins->x();
1931 MOZ_ASSERT(x->type() == MIRType::Double);
1933 LAtan2D* lir =
1934 new (alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x));
1935 defineReturn(lir, ins);
1938 void LIRGenerator::visitHypot(MHypot* ins) {
1939 LHypot* lir = nullptr;
1940 uint32_t length = ins->numOperands();
1941 for (uint32_t i = 0; i < length; ++i) {
1942 MOZ_ASSERT(ins->getOperand(i)->type() == MIRType::Double);
1945 switch (length) {
1946 case 2:
1947 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1948 useRegisterAtStart(ins->getOperand(1)));
1949 break;
1950 case 3:
1951 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1952 useRegisterAtStart(ins->getOperand(1)),
1953 useRegisterAtStart(ins->getOperand(2)));
1954 break;
1955 case 4:
1956 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1957 useRegisterAtStart(ins->getOperand(1)),
1958 useRegisterAtStart(ins->getOperand(2)),
1959 useRegisterAtStart(ins->getOperand(3)));
1960 break;
1961 default:
1962 MOZ_CRASH("Unexpected number of arguments to LHypot.");
1965 defineReturn(lir, ins);
1968 void LIRGenerator::visitPow(MPow* ins) {
1969 MDefinition* input = ins->input();
1970 MDefinition* power = ins->power();
1972 if (ins->type() == MIRType::Int32) {
1973 MOZ_ASSERT(input->type() == MIRType::Int32);
1974 MOZ_ASSERT(power->type() == MIRType::Int32);
1976 if (input->isConstant()) {
1977 // Restrict this optimization to |base <= 256| to avoid generating too
1978 // many consecutive shift instructions.
1979 int32_t base = input->toConstant()->toInt32();
1980 if (2 <= base && base <= 256 && mozilla::IsPowerOfTwo(uint32_t(base))) {
1981 lowerPowOfTwoI(ins);
1982 return;
1986 auto* lir = new (alloc())
1987 LPowII(useRegister(input), useRegister(power), temp(), temp());
1988 assignSnapshot(lir, ins->bailoutKind());
1989 define(lir, ins);
1990 return;
1993 MOZ_ASSERT(ins->type() == MIRType::Double);
1994 MOZ_ASSERT(input->type() == MIRType::Double);
1995 MOZ_ASSERT(power->type() == MIRType::Int32 ||
1996 power->type() == MIRType::Double);
1998 LInstruction* lir;
1999 if (power->type() == MIRType::Int32) {
2000 lir = new (alloc())
2001 LPowI(useRegisterAtStart(input), useRegisterAtStart(power));
2002 } else {
2003 lir = new (alloc())
2004 LPowD(useRegisterAtStart(input), useRegisterAtStart(power));
2006 defineReturn(lir, ins);
2009 void LIRGenerator::visitSign(MSign* ins) {
2010 if (ins->type() == ins->input()->type()) {
2011 LInstructionHelper<1, 1, 0>* lir;
2012 if (ins->type() == MIRType::Int32) {
2013 lir = new (alloc()) LSignI(useRegister(ins->input()));
2014 } else {
2015 MOZ_ASSERT(ins->type() == MIRType::Double);
2016 lir = new (alloc()) LSignD(useRegister(ins->input()));
2018 define(lir, ins);
2019 } else {
2020 MOZ_ASSERT(ins->type() == MIRType::Int32);
2021 MOZ_ASSERT(ins->input()->type() == MIRType::Double);
2023 auto* lir = new (alloc()) LSignDI(useRegister(ins->input()), tempDouble());
2024 assignSnapshot(lir, ins->bailoutKind());
2025 define(lir, ins);
2029 void LIRGenerator::visitMathFunction(MMathFunction* ins) {
2030 MOZ_ASSERT(IsFloatingPointType(ins->type()));
2031 MOZ_ASSERT(ins->type() == ins->input()->type());
2033 LInstruction* lir;
2034 if (ins->type() == MIRType::Double) {
2035 lir = new (alloc()) LMathFunctionD(useRegisterAtStart(ins->input()));
2036 } else {
2037 lir = new (alloc()) LMathFunctionF(useRegisterAtStart(ins->input()));
2039 defineReturn(lir, ins);
2042 void LIRGenerator::visitRandom(MRandom* ins) {
2043 auto* lir = new (alloc()) LRandom(temp(), tempInt64(), tempInt64());
2044 define(lir, ins);
2047 // Try to mark an add or sub instruction as able to recover its input when
2048 // bailing out.
2049 template <typename S, typename T>
2050 static void MaybeSetRecoversInput(S* mir, T* lir) {
2051 MOZ_ASSERT(lir->mirRaw() == mir);
2052 if (!mir->fallible() || !lir->snapshot()) {
2053 return;
2056 if (lir->output()->policy() != LDefinition::MUST_REUSE_INPUT) {
2057 return;
2060 // The original operands to an add or sub can't be recovered if they both
2061 // use the same register.
2062 if (lir->lhs()->isUse() && lir->rhs()->isUse() &&
2063 lir->lhs()->toUse()->virtualRegister() ==
2064 lir->rhs()->toUse()->virtualRegister()) {
2065 return;
2068 // Add instructions that are on two different values can recover
2069 // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy
2070 // of that input does not need to be kept alive in the snapshot
2071 // for the instruction.
2073 lir->setRecoversInput();
2075 const LUse* input = lir->getOperand(lir->output()->getReusedInput())->toUse();
2076 lir->snapshot()->rewriteRecoveredInput(*input);
2079 void LIRGenerator::visitAdd(MAdd* ins) {
2080 MDefinition* lhs = ins->getOperand(0);
2081 MDefinition* rhs = ins->getOperand(1);
2083 MOZ_ASSERT(lhs->type() == rhs->type());
2084 MOZ_ASSERT(IsNumberType(ins->type()));
2086 if (ins->type() == MIRType::Int32) {
2087 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2088 ReorderCommutative(&lhs, &rhs, ins);
2089 LAddI* lir = new (alloc()) LAddI;
2091 if (ins->fallible()) {
2092 assignSnapshot(lir, ins->bailoutKind());
2095 lowerForALU(lir, ins, lhs, rhs);
2096 MaybeSetRecoversInput(ins, lir);
2097 return;
2100 if (ins->type() == MIRType::Int64) {
2101 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2102 ReorderCommutative(&lhs, &rhs, ins);
2103 LAddI64* lir = new (alloc()) LAddI64;
2104 lowerForALUInt64(lir, ins, lhs, rhs);
2105 return;
2108 if (ins->type() == MIRType::Double) {
2109 MOZ_ASSERT(lhs->type() == MIRType::Double);
2110 ReorderCommutative(&lhs, &rhs, ins);
2111 lowerForFPU(new (alloc()) LMathD(JSOp::Add), ins, lhs, rhs);
2112 return;
2115 if (ins->type() == MIRType::Float32) {
2116 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2117 ReorderCommutative(&lhs, &rhs, ins);
2118 lowerForFPU(new (alloc()) LMathF(JSOp::Add), ins, lhs, rhs);
2119 return;
2122 MOZ_CRASH("Unhandled number specialization");
2125 void LIRGenerator::visitSub(MSub* ins) {
2126 MDefinition* lhs = ins->lhs();
2127 MDefinition* rhs = ins->rhs();
2129 MOZ_ASSERT(lhs->type() == rhs->type());
2130 MOZ_ASSERT(IsNumberType(ins->type()));
2132 if (ins->type() == MIRType::Int32) {
2133 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2135 LSubI* lir = new (alloc()) LSubI;
2136 if (ins->fallible()) {
2137 assignSnapshot(lir, ins->bailoutKind());
2140 // If our LHS is a constant 0 and we don't have to worry about results that
2141 // can't be represented as an int32, we can optimize to an LNegI.
2142 if (!ins->fallible() && lhs->isConstant() &&
2143 lhs->toConstant()->toInt32() == 0) {
2144 lowerNegI(ins, rhs);
2145 return;
2148 lowerForALU(lir, ins, lhs, rhs);
2149 MaybeSetRecoversInput(ins, lir);
2150 return;
2153 if (ins->type() == MIRType::Int64) {
2154 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2156 // If our LHS is a constant 0, we can optimize to an LNegI64.
2157 if (lhs->isConstant() && lhs->toConstant()->toInt64() == 0) {
2158 lowerNegI64(ins, rhs);
2159 return;
2162 LSubI64* lir = new (alloc()) LSubI64;
2163 lowerForALUInt64(lir, ins, lhs, rhs);
2164 return;
2167 if (ins->type() == MIRType::Double) {
2168 MOZ_ASSERT(lhs->type() == MIRType::Double);
2169 lowerForFPU(new (alloc()) LMathD(JSOp::Sub), ins, lhs, rhs);
2170 return;
2173 if (ins->type() == MIRType::Float32) {
2174 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2175 lowerForFPU(new (alloc()) LMathF(JSOp::Sub), ins, lhs, rhs);
2176 return;
2179 MOZ_CRASH("Unhandled number specialization");
2182 void LIRGenerator::visitMul(MMul* ins) {
2183 MDefinition* lhs = ins->lhs();
2184 MDefinition* rhs = ins->rhs();
2185 MOZ_ASSERT(lhs->type() == rhs->type());
2186 MOZ_ASSERT(IsNumberType(ins->type()));
2188 if (ins->type() == MIRType::Int32) {
2189 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2190 ReorderCommutative(&lhs, &rhs, ins);
2192 // If our RHS is a constant -1 and we don't have to worry about results that
2193 // can't be represented as an int32, we can optimize to an LNegI.
2194 if (!ins->fallible() && rhs->isConstant() &&
2195 rhs->toConstant()->toInt32() == -1) {
2196 lowerNegI(ins, lhs);
2197 return;
2200 lowerMulI(ins, lhs, rhs);
2201 return;
2204 if (ins->type() == MIRType::Int64) {
2205 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2206 ReorderCommutative(&lhs, &rhs, ins);
2208 // If our RHS is a constant -1, we can optimize to an LNegI64.
2209 if (rhs->isConstant() && rhs->toConstant()->toInt64() == -1) {
2210 lowerNegI64(ins, lhs);
2211 return;
2214 LMulI64* lir = new (alloc()) LMulI64;
2215 lowerForMulInt64(lir, ins, lhs, rhs);
2216 return;
2219 if (ins->type() == MIRType::Double) {
2220 MOZ_ASSERT(lhs->type() == MIRType::Double);
2221 ReorderCommutative(&lhs, &rhs, ins);
2223 // If our RHS is a constant -1.0, we can optimize to an LNegD.
2224 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2225 rhs->toConstant()->toDouble() == -1.0) {
2226 defineReuseInput(new (alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0);
2227 return;
2230 lowerForFPU(new (alloc()) LMathD(JSOp::Mul), ins, lhs, rhs);
2231 return;
2234 if (ins->type() == MIRType::Float32) {
2235 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2236 ReorderCommutative(&lhs, &rhs, ins);
2238 // We apply the same optimizations as for doubles
2239 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2240 rhs->toConstant()->toFloat32() == -1.0f) {
2241 defineReuseInput(new (alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0);
2242 return;
2245 lowerForFPU(new (alloc()) LMathF(JSOp::Mul), ins, lhs, rhs);
2246 return;
2249 MOZ_CRASH("Unhandled number specialization");
2252 void LIRGenerator::visitDiv(MDiv* ins) {
2253 MDefinition* lhs = ins->lhs();
2254 MDefinition* rhs = ins->rhs();
2255 MOZ_ASSERT(lhs->type() == rhs->type());
2256 MOZ_ASSERT(IsNumberType(ins->type()));
2258 if (ins->type() == MIRType::Int32) {
2259 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2260 lowerDivI(ins);
2261 return;
2264 if (ins->type() == MIRType::Int64) {
2265 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2266 lowerDivI64(ins);
2267 return;
2270 if (ins->type() == MIRType::Double) {
2271 MOZ_ASSERT(lhs->type() == MIRType::Double);
2272 lowerForFPU(new (alloc()) LMathD(JSOp::Div), ins, lhs, rhs);
2273 return;
2276 if (ins->type() == MIRType::Float32) {
2277 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2278 lowerForFPU(new (alloc()) LMathF(JSOp::Div), ins, lhs, rhs);
2279 return;
2282 MOZ_CRASH("Unhandled number specialization");
2285 void LIRGenerator::visitWasmBuiltinDivI64(MWasmBuiltinDivI64* div) {
2286 lowerWasmBuiltinDivI64(div);
2289 void LIRGenerator::visitWasmBuiltinModI64(MWasmBuiltinModI64* mod) {
2290 lowerWasmBuiltinModI64(mod);
2293 void LIRGenerator::visitBuiltinInt64ToFloatingPoint(
2294 MBuiltinInt64ToFloatingPoint* ins) {
2295 lowerBuiltinInt64ToFloatingPoint(ins);
2298 void LIRGenerator::visitWasmBuiltinTruncateToInt64(
2299 MWasmBuiltinTruncateToInt64* ins) {
2300 lowerWasmBuiltinTruncateToInt64(ins);
2303 void LIRGenerator::visitWasmBuiltinModD(MWasmBuiltinModD* ins) {
2304 MOZ_ASSERT(gen->compilingWasm());
2305 LWasmBuiltinModD* lir = new (alloc()) LWasmBuiltinModD(
2306 useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()),
2307 useFixedAtStart(ins->instance(), InstanceReg));
2308 defineReturn(lir, ins);
2311 void LIRGenerator::visitMod(MMod* ins) {
2312 MOZ_ASSERT(ins->lhs()->type() == ins->rhs()->type());
2313 MOZ_ASSERT(IsNumberType(ins->type()));
2315 if (ins->type() == MIRType::Int32) {
2316 MOZ_ASSERT(ins->type() == MIRType::Int32);
2317 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int32);
2318 lowerModI(ins);
2319 return;
2322 if (ins->type() == MIRType::Int64) {
2323 MOZ_ASSERT(ins->type() == MIRType::Int64);
2324 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int64);
2325 lowerModI64(ins);
2326 return;
2329 if (ins->type() == MIRType::Double) {
2330 MOZ_ASSERT(ins->lhs()->type() == MIRType::Double);
2331 MOZ_ASSERT(ins->rhs()->type() == MIRType::Double);
2333 MOZ_ASSERT(!gen->compilingWasm());
2335 if (Assembler::HasRoundInstruction(RoundingMode::TowardsZero)) {
2336 if (ins->rhs()->isConstant()) {
2337 double d = ins->rhs()->toConstant()->toDouble();
2338 int32_t div;
2339 if (mozilla::NumberIsInt32(d, &div) && div > 0 &&
2340 mozilla::IsPowerOfTwo(uint32_t(div))) {
2341 auto* lir = new (alloc()) LModPowTwoD(useRegister(ins->lhs()), div);
2342 define(lir, ins);
2343 return;
2348 LModD* lir = new (alloc())
2349 LModD(useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()));
2350 defineReturn(lir, ins);
2351 return;
2354 MOZ_CRASH("Unhandled number specialization");
2357 void LIRGenerator::visitBigIntAdd(MBigIntAdd* ins) {
2358 auto* lir = new (alloc()) LBigIntAdd(useRegister(ins->lhs()),
2359 useRegister(ins->rhs()), temp(), temp());
2360 define(lir, ins);
2361 assignSafepoint(lir, ins);
2364 void LIRGenerator::visitBigIntSub(MBigIntSub* ins) {
2365 auto* lir = new (alloc()) LBigIntSub(useRegister(ins->lhs()),
2366 useRegister(ins->rhs()), temp(), temp());
2367 define(lir, ins);
2368 assignSafepoint(lir, ins);
2371 void LIRGenerator::visitBigIntMul(MBigIntMul* ins) {
2372 auto* lir = new (alloc()) LBigIntMul(useRegister(ins->lhs()),
2373 useRegister(ins->rhs()), temp(), temp());
2374 define(lir, ins);
2375 assignSafepoint(lir, ins);
2378 void LIRGenerator::visitBigIntDiv(MBigIntDiv* ins) { lowerBigIntDiv(ins); }
2380 void LIRGenerator::visitBigIntMod(MBigIntMod* ins) { lowerBigIntMod(ins); }
2382 void LIRGenerator::visitBigIntPow(MBigIntPow* ins) {
2383 auto* lir = new (alloc()) LBigIntPow(useRegister(ins->lhs()),
2384 useRegister(ins->rhs()), temp(), temp());
2385 define(lir, ins);
2386 assignSafepoint(lir, ins);
2389 void LIRGenerator::visitBigIntBitAnd(MBigIntBitAnd* ins) {
2390 auto* lir = new (alloc()) LBigIntBitAnd(
2391 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2392 define(lir, ins);
2393 assignSafepoint(lir, ins);
2396 void LIRGenerator::visitBigIntBitOr(MBigIntBitOr* ins) {
2397 auto* lir = new (alloc()) LBigIntBitOr(
2398 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2399 define(lir, ins);
2400 assignSafepoint(lir, ins);
2403 void LIRGenerator::visitBigIntBitXor(MBigIntBitXor* ins) {
2404 auto* lir = new (alloc()) LBigIntBitXor(
2405 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2406 define(lir, ins);
2407 assignSafepoint(lir, ins);
2410 void LIRGenerator::visitBigIntLsh(MBigIntLsh* ins) { lowerBigIntLsh(ins); }
2412 void LIRGenerator::visitBigIntRsh(MBigIntRsh* ins) { lowerBigIntRsh(ins); }
2414 void LIRGenerator::visitBigIntIncrement(MBigIntIncrement* ins) {
2415 auto* lir =
2416 new (alloc()) LBigIntIncrement(useRegister(ins->input()), temp(), temp());
2417 define(lir, ins);
2418 assignSafepoint(lir, ins);
2421 void LIRGenerator::visitBigIntDecrement(MBigIntDecrement* ins) {
2422 auto* lir =
2423 new (alloc()) LBigIntDecrement(useRegister(ins->input()), temp(), temp());
2424 define(lir, ins);
2425 assignSafepoint(lir, ins);
2428 void LIRGenerator::visitBigIntNegate(MBigIntNegate* ins) {
2429 auto* lir = new (alloc()) LBigIntNegate(useRegister(ins->input()), temp());
2430 define(lir, ins);
2431 assignSafepoint(lir, ins);
2434 void LIRGenerator::visitBigIntBitNot(MBigIntBitNot* ins) {
2435 auto* lir =
2436 new (alloc()) LBigIntBitNot(useRegister(ins->input()), temp(), temp());
2437 define(lir, ins);
2438 assignSafepoint(lir, ins);
2441 void LIRGenerator::visitInt32ToStringWithBase(MInt32ToStringWithBase* ins) {
2442 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2443 MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
2445 int32_t baseInt =
2446 ins->base()->isConstant() ? ins->base()->toConstant()->toInt32() : 0;
2448 LAllocation base;
2449 if (2 <= baseInt && baseInt <= 36) {
2450 base = useRegisterOrConstant(ins->base());
2451 } else {
2452 base = useRegister(ins->base());
2455 auto* lir = new (alloc())
2456 LInt32ToStringWithBase(useRegister(ins->input()), base, temp(), temp());
2457 define(lir, ins);
2458 assignSafepoint(lir, ins);
2461 void LIRGenerator::visitNumberParseInt(MNumberParseInt* ins) {
2462 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2463 MOZ_ASSERT(ins->radix()->type() == MIRType::Int32);
2465 auto* lir = new (alloc()) LNumberParseInt(useRegisterAtStart(ins->string()),
2466 useRegisterAtStart(ins->radix()),
2467 tempFixed(CallTempReg0));
2468 defineReturn(lir, ins);
2469 assignSafepoint(lir, ins);
2472 void LIRGenerator::visitDoubleParseInt(MDoubleParseInt* ins) {
2473 MOZ_ASSERT(ins->number()->type() == MIRType::Double);
2475 auto* lir =
2476 new (alloc()) LDoubleParseInt(useRegister(ins->number()), tempDouble());
2477 assignSnapshot(lir, ins->bailoutKind());
2478 define(lir, ins);
2481 void LIRGenerator::visitConcat(MConcat* ins) {
2482 MDefinition* lhs = ins->getOperand(0);
2483 MDefinition* rhs = ins->getOperand(1);
2485 MOZ_ASSERT(lhs->type() == MIRType::String);
2486 MOZ_ASSERT(rhs->type() == MIRType::String);
2487 MOZ_ASSERT(ins->type() == MIRType::String);
2489 LConcat* lir = new (alloc()) LConcat(
2490 useFixedAtStart(lhs, CallTempReg0), useFixedAtStart(rhs, CallTempReg1),
2491 tempFixed(CallTempReg0), tempFixed(CallTempReg1), tempFixed(CallTempReg2),
2492 tempFixed(CallTempReg3), tempFixed(CallTempReg4));
2493 defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5)));
2494 assignSafepoint(lir, ins);
2497 void LIRGenerator::visitLinearizeString(MLinearizeString* ins) {
2498 MDefinition* str = ins->string();
2499 MOZ_ASSERT(str->type() == MIRType::String);
2501 auto* lir = new (alloc()) LLinearizeString(useRegister(str));
2502 define(lir, ins);
2503 assignSafepoint(lir, ins);
2506 void LIRGenerator::visitLinearizeForCharAccess(MLinearizeForCharAccess* ins) {
2507 MDefinition* str = ins->string();
2508 MDefinition* idx = ins->index();
2510 MOZ_ASSERT(str->type() == MIRType::String);
2511 MOZ_ASSERT(idx->type() == MIRType::Int32);
2513 auto* lir =
2514 new (alloc()) LLinearizeForCharAccess(useRegister(str), useRegister(idx));
2515 define(lir, ins);
2516 assignSafepoint(lir, ins);
2519 void LIRGenerator::visitLinearizeForCodePointAccess(
2520 MLinearizeForCodePointAccess* ins) {
2521 MDefinition* str = ins->string();
2522 MDefinition* idx = ins->index();
2524 MOZ_ASSERT(str->type() == MIRType::String);
2525 MOZ_ASSERT(idx->type() == MIRType::Int32);
2527 auto* lir = new (alloc())
2528 LLinearizeForCodePointAccess(useRegister(str), useRegister(idx), temp());
2529 define(lir, ins);
2530 assignSafepoint(lir, ins);
2533 void LIRGenerator::visitToRelativeStringIndex(MToRelativeStringIndex* ins) {
2534 MDefinition* index = ins->index();
2535 MDefinition* length = ins->length();
2537 MOZ_ASSERT(index->type() == MIRType::Int32);
2538 MOZ_ASSERT(length->type() == MIRType::Int32);
2540 auto* lir = new (alloc())
2541 LToRelativeStringIndex(useRegister(index), useRegister(length));
2542 define(lir, ins);
2545 void LIRGenerator::visitCharCodeAt(MCharCodeAt* ins) {
2546 MDefinition* str = ins->string();
2547 MDefinition* idx = ins->index();
2549 MOZ_ASSERT(str->type() == MIRType::String);
2550 MOZ_ASSERT(idx->type() == MIRType::Int32);
2552 auto* lir = new (alloc())
2553 LCharCodeAt(useRegister(str), useRegisterOrZero(idx), temp(), temp());
2554 define(lir, ins);
2555 assignSafepoint(lir, ins);
2558 void LIRGenerator::visitCharCodeAtOrNegative(MCharCodeAtOrNegative* ins) {
2559 MDefinition* str = ins->string();
2560 MDefinition* idx = ins->index();
2562 MOZ_ASSERT(str->type() == MIRType::String);
2563 MOZ_ASSERT(idx->type() == MIRType::Int32);
2565 auto* lir = new (alloc()) LCharCodeAtOrNegative(
2566 useRegister(str), useRegisterOrZero(idx), temp(), temp());
2567 define(lir, ins);
2568 assignSafepoint(lir, ins);
2571 void LIRGenerator::visitCodePointAt(MCodePointAt* ins) {
2572 MDefinition* str = ins->string();
2573 MDefinition* idx = ins->index();
2575 MOZ_ASSERT(str->type() == MIRType::String);
2576 MOZ_ASSERT(idx->type() == MIRType::Int32);
2578 auto* lir = new (alloc())
2579 LCodePointAt(useRegister(str), useRegister(idx), temp(), temp());
2580 define(lir, ins);
2581 assignSafepoint(lir, ins);
2584 void LIRGenerator::visitCodePointAtOrNegative(MCodePointAtOrNegative* ins) {
2585 MDefinition* str = ins->string();
2586 MDefinition* idx = ins->index();
2588 MOZ_ASSERT(str->type() == MIRType::String);
2589 MOZ_ASSERT(idx->type() == MIRType::Int32);
2591 auto* lir = new (alloc()) LCodePointAtOrNegative(
2592 useRegister(str), useRegister(idx), temp(), temp());
2593 define(lir, ins);
2594 assignSafepoint(lir, ins);
2597 void LIRGenerator::visitNegativeToNaN(MNegativeToNaN* ins) {
2598 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2600 auto* lir = new (alloc()) LNegativeToNaN(useRegister(ins->input()));
2601 defineBox(lir, ins);
2604 void LIRGenerator::visitNegativeToUndefined(MNegativeToUndefined* ins) {
2605 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2607 auto* lir = new (alloc()) LNegativeToUndefined(useRegister(ins->input()));
2608 defineBox(lir, ins);
2611 void LIRGenerator::visitFromCharCode(MFromCharCode* ins) {
2612 MDefinition* code = ins->code();
2614 MOZ_ASSERT(code->type() == MIRType::Int32);
2616 LFromCharCode* lir = new (alloc()) LFromCharCode(useRegister(code));
2617 define(lir, ins);
2618 assignSafepoint(lir, ins);
2621 void LIRGenerator::visitFromCharCodeEmptyIfNegative(
2622 MFromCharCodeEmptyIfNegative* ins) {
2623 MDefinition* code = ins->code();
2625 MOZ_ASSERT(code->type() == MIRType::Int32);
2627 auto* lir = new (alloc()) LFromCharCodeEmptyIfNegative(useRegister(code));
2628 define(lir, ins);
2629 assignSafepoint(lir, ins);
2632 void LIRGenerator::visitFromCharCodeUndefinedIfNegative(
2633 MFromCharCodeUndefinedIfNegative* ins) {
2634 MDefinition* code = ins->code();
2636 MOZ_ASSERT(code->type() == MIRType::Int32);
2638 auto* lir = new (alloc()) LFromCharCodeUndefinedIfNegative(useRegister(code));
2639 defineBox(lir, ins);
2640 assignSafepoint(lir, ins);
2643 void LIRGenerator::visitFromCodePoint(MFromCodePoint* ins) {
2644 MDefinition* codePoint = ins->codePoint();
2646 MOZ_ASSERT(codePoint->type() == MIRType::Int32);
2648 LFromCodePoint* lir =
2649 new (alloc()) LFromCodePoint(useRegister(codePoint), temp(), temp());
2650 assignSnapshot(lir, ins->bailoutKind());
2651 define(lir, ins);
2652 assignSafepoint(lir, ins);
2655 void LIRGenerator::visitStringIncludes(MStringIncludes* ins) {
2656 auto* string = ins->string();
2657 MOZ_ASSERT(string->type() == MIRType::String);
2659 auto* searchStr = ins->searchString();
2660 MOZ_ASSERT(searchStr->type() == MIRType::String);
2662 if (searchStr->isConstant()) {
2663 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2664 size_t length = linear->length();
2665 if (length == 1 || length == 2) {
2666 LDefinition tempDef = LDefinition::BogusTemp();
2667 if (length > 1) {
2668 tempDef = temp();
2671 auto* lir = new (alloc()) LStringIncludesSIMD(useRegister(string), temp(),
2672 temp(), tempDef, linear);
2673 define(lir, ins);
2674 assignSafepoint(lir, ins);
2675 return;
2679 auto* lir = new (alloc()) LStringIncludes(useRegisterAtStart(string),
2680 useRegisterAtStart(searchStr));
2681 defineReturn(lir, ins);
2682 assignSafepoint(lir, ins);
2685 void LIRGenerator::visitStringIndexOf(MStringIndexOf* ins) {
2686 auto* string = ins->string();
2687 MOZ_ASSERT(string->type() == MIRType::String);
2689 auto* searchStr = ins->searchString();
2690 MOZ_ASSERT(searchStr->type() == MIRType::String);
2692 if (searchStr->isConstant()) {
2693 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2694 size_t length = linear->length();
2695 if (length == 1 || length == 2) {
2696 LDefinition tempDef = LDefinition::BogusTemp();
2697 if (length > 1) {
2698 tempDef = temp();
2701 auto* lir = new (alloc()) LStringIndexOfSIMD(useRegister(string), temp(),
2702 temp(), tempDef, linear);
2703 define(lir, ins);
2704 assignSafepoint(lir, ins);
2705 return;
2709 auto* lir = new (alloc())
2710 LStringIndexOf(useRegisterAtStart(string), useRegisterAtStart(searchStr));
2711 defineReturn(lir, ins);
2712 assignSafepoint(lir, ins);
2715 void LIRGenerator::visitStringLastIndexOf(MStringLastIndexOf* ins) {
2716 auto* string = ins->string();
2717 MOZ_ASSERT(string->type() == MIRType::String);
2719 auto* searchStr = ins->searchString();
2720 MOZ_ASSERT(searchStr->type() == MIRType::String);
2722 auto* lir = new (alloc()) LStringLastIndexOf(useRegisterAtStart(string),
2723 useRegisterAtStart(searchStr));
2724 defineReturn(lir, ins);
2725 assignSafepoint(lir, ins);
2728 void LIRGenerator::visitStringStartsWith(MStringStartsWith* ins) {
2729 auto* string = ins->string();
2730 MOZ_ASSERT(string->type() == MIRType::String);
2732 auto* searchStr = ins->searchString();
2733 MOZ_ASSERT(searchStr->type() == MIRType::String);
2735 if (searchStr->isConstant()) {
2736 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2738 if (MacroAssembler::canCompareStringCharsInline(linear)) {
2739 auto* lir = new (alloc())
2740 LStringStartsWithInline(useRegister(string), temp(), linear);
2741 define(lir, ins);
2742 assignSafepoint(lir, ins);
2743 return;
2747 auto* lir = new (alloc()) LStringStartsWith(useRegisterAtStart(string),
2748 useRegisterAtStart(searchStr));
2749 defineReturn(lir, ins);
2750 assignSafepoint(lir, ins);
2753 void LIRGenerator::visitStringEndsWith(MStringEndsWith* ins) {
2754 auto* string = ins->string();
2755 MOZ_ASSERT(string->type() == MIRType::String);
2757 auto* searchStr = ins->searchString();
2758 MOZ_ASSERT(searchStr->type() == MIRType::String);
2760 if (searchStr->isConstant()) {
2761 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2763 if (MacroAssembler::canCompareStringCharsInline(linear)) {
2764 auto* lir = new (alloc())
2765 LStringEndsWithInline(useRegister(string), temp(), linear);
2766 define(lir, ins);
2767 assignSafepoint(lir, ins);
2768 return;
2772 auto* lir = new (alloc()) LStringEndsWith(useRegisterAtStart(string),
2773 useRegisterAtStart(searchStr));
2774 defineReturn(lir, ins);
2775 assignSafepoint(lir, ins);
2778 void LIRGenerator::visitStringConvertCase(MStringConvertCase* ins) {
2779 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2781 if (ins->mode() == MStringConvertCase::LowerCase) {
2782 #ifdef JS_CODEGEN_X86
2783 // Due to lack of registers on x86, we reuse the string register as
2784 // temporary. As a result we only need four temporary registers and take a
2785 // bogus temporary as the fifth argument.
2786 LDefinition temp4 = LDefinition::BogusTemp();
2787 #else
2788 LDefinition temp4 = temp();
2789 #endif
2790 auto* lir = new (alloc())
2791 LStringToLowerCase(useRegister(ins->string()), temp(), temp(), temp(),
2792 temp4, tempByteOpRegister());
2793 define(lir, ins);
2794 assignSafepoint(lir, ins);
2795 } else {
2796 auto* lir =
2797 new (alloc()) LStringToUpperCase(useRegisterAtStart(ins->string()));
2798 defineReturn(lir, ins);
2799 assignSafepoint(lir, ins);
2803 void LIRGenerator::visitCharCodeConvertCase(MCharCodeConvertCase* ins) {
2804 MOZ_ASSERT(ins->code()->type() == MIRType::Int32);
2806 if (ins->mode() == MCharCodeConvertCase::LowerCase) {
2807 auto* lir = new (alloc())
2808 LCharCodeToLowerCase(useRegister(ins->code()), tempByteOpRegister());
2809 define(lir, ins);
2810 assignSafepoint(lir, ins);
2811 } else {
2812 auto* lir = new (alloc())
2813 LCharCodeToUpperCase(useRegister(ins->code()), tempByteOpRegister());
2814 define(lir, ins);
2815 assignSafepoint(lir, ins);
2819 void LIRGenerator::visitStringTrimStartIndex(MStringTrimStartIndex* ins) {
2820 auto* string = ins->string();
2821 MOZ_ASSERT(string->type() == MIRType::String);
2823 auto* lir = new (alloc()) LStringTrimStartIndex(useRegister(string));
2824 define(lir, ins);
2825 assignSafepoint(lir, ins);
2828 void LIRGenerator::visitStringTrimEndIndex(MStringTrimEndIndex* ins) {
2829 auto* string = ins->string();
2830 MOZ_ASSERT(string->type() == MIRType::String);
2832 auto* start = ins->start();
2833 MOZ_ASSERT(start->type() == MIRType::Int32);
2835 auto* lir = new (alloc())
2836 LStringTrimEndIndex(useRegister(string), useRegister(start));
2837 define(lir, ins);
2838 assignSafepoint(lir, ins);
2841 void LIRGenerator::visitStart(MStart* start) {}
2843 void LIRGenerator::visitNop(MNop* nop) {}
2845 void LIRGenerator::visitLimitedTruncate(MLimitedTruncate* nop) {
2846 redefine(nop, nop->input());
2849 void LIRGenerator::visitOsrEntry(MOsrEntry* entry) {
2850 LOsrEntry* lir = new (alloc()) LOsrEntry(temp());
2851 defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg)));
2854 void LIRGenerator::visitOsrValue(MOsrValue* value) {
2855 LOsrValue* lir = new (alloc()) LOsrValue(useRegister(value->entry()));
2856 defineBox(lir, value);
2859 void LIRGenerator::visitOsrReturnValue(MOsrReturnValue* value) {
2860 LOsrReturnValue* lir =
2861 new (alloc()) LOsrReturnValue(useRegister(value->entry()));
2862 defineBox(lir, value);
2865 void LIRGenerator::visitOsrEnvironmentChain(MOsrEnvironmentChain* object) {
2866 LOsrEnvironmentChain* lir =
2867 new (alloc()) LOsrEnvironmentChain(useRegister(object->entry()));
2868 define(lir, object);
2871 void LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject* object) {
2872 LOsrArgumentsObject* lir =
2873 new (alloc()) LOsrArgumentsObject(useRegister(object->entry()));
2874 define(lir, object);
2877 void LIRGenerator::visitToDouble(MToDouble* convert) {
2878 MDefinition* opd = convert->input();
2879 mozilla::DebugOnly<MToFPInstruction::ConversionKind> conversion =
2880 convert->conversion();
2882 switch (opd->type()) {
2883 case MIRType::Value: {
2884 LValueToDouble* lir = new (alloc()) LValueToDouble(useBox(opd));
2885 assignSnapshot(lir, convert->bailoutKind());
2886 define(lir, convert);
2887 break;
2890 case MIRType::Null:
2891 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2892 lowerConstantDouble(0, convert);
2893 break;
2895 case MIRType::Undefined:
2896 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2897 lowerConstantDouble(GenericNaN(), convert);
2898 break;
2900 case MIRType::Boolean:
2901 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2902 [[fallthrough]];
2904 case MIRType::Int32: {
2905 LInt32ToDouble* lir =
2906 new (alloc()) LInt32ToDouble(useRegisterAtStart(opd));
2907 define(lir, convert);
2908 break;
2911 case MIRType::Float32: {
2912 LFloat32ToDouble* lir =
2913 new (alloc()) LFloat32ToDouble(useRegisterAtStart(opd));
2914 define(lir, convert);
2915 break;
2918 case MIRType::Double:
2919 redefine(convert, opd);
2920 break;
2922 default:
2923 // Objects might be effectful. Symbols will throw.
2924 // Strings are complicated - we don't handle them yet.
2925 MOZ_CRASH("unexpected type");
2929 void LIRGenerator::visitToFloat32(MToFloat32* convert) {
2930 MDefinition* opd = convert->input();
2931 mozilla::DebugOnly<MToFloat32::ConversionKind> conversion =
2932 convert->conversion();
2934 switch (opd->type()) {
2935 case MIRType::Value: {
2936 LValueToFloat32* lir = new (alloc()) LValueToFloat32(useBox(opd));
2937 assignSnapshot(lir, convert->bailoutKind());
2938 define(lir, convert);
2939 break;
2942 case MIRType::Null:
2943 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2944 lowerConstantFloat32(0, convert);
2945 break;
2947 case MIRType::Undefined:
2948 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2949 lowerConstantFloat32(GenericNaN(), convert);
2950 break;
2952 case MIRType::Boolean:
2953 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2954 [[fallthrough]];
2956 case MIRType::Int32: {
2957 LInt32ToFloat32* lir =
2958 new (alloc()) LInt32ToFloat32(useRegisterAtStart(opd));
2959 define(lir, convert);
2960 break;
2963 case MIRType::Double: {
2964 LDoubleToFloat32* lir =
2965 new (alloc()) LDoubleToFloat32(useRegisterAtStart(opd));
2966 define(lir, convert);
2967 break;
2970 case MIRType::Float32:
2971 redefine(convert, opd);
2972 break;
2974 default:
2975 // Objects might be effectful. Symbols will throw.
2976 // Strings are complicated - we don't handle them yet.
2977 MOZ_CRASH("unexpected type");
2981 void LIRGenerator::visitToNumberInt32(MToNumberInt32* convert) {
2982 MDefinition* opd = convert->input();
2984 switch (opd->type()) {
2985 case MIRType::Value: {
2986 auto* lir = new (alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(),
2987 LValueToInt32::NORMAL);
2988 assignSnapshot(lir, convert->bailoutKind());
2989 define(lir, convert);
2990 if (lir->mode() == LValueToInt32::TRUNCATE) {
2991 assignSafepoint(lir, convert);
2993 break;
2996 case MIRType::Null:
2997 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any);
2998 define(new (alloc()) LInteger(0), convert);
2999 break;
3001 case MIRType::Boolean:
3002 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any ||
3003 convert->conversion() ==
3004 IntConversionInputKind::NumbersOrBoolsOnly);
3005 redefine(convert, opd);
3006 break;
3008 case MIRType::Int32:
3009 redefine(convert, opd);
3010 break;
3012 case MIRType::Float32: {
3013 LFloat32ToInt32* lir = new (alloc()) LFloat32ToInt32(useRegister(opd));
3014 assignSnapshot(lir, convert->bailoutKind());
3015 define(lir, convert);
3016 break;
3019 case MIRType::Double: {
3020 LDoubleToInt32* lir = new (alloc()) LDoubleToInt32(useRegister(opd));
3021 assignSnapshot(lir, convert->bailoutKind());
3022 define(lir, convert);
3023 break;
3026 case MIRType::String:
3027 case MIRType::Symbol:
3028 case MIRType::BigInt:
3029 case MIRType::Object:
3030 case MIRType::Undefined:
3031 // Objects might be effectful. Symbols and BigInts throw. Undefined
3032 // coerces to NaN, not int32.
3033 MOZ_CRASH("ToInt32 invalid input type");
3035 default:
3036 MOZ_CRASH("unexpected type");
3040 void LIRGenerator::visitBooleanToInt32(MBooleanToInt32* convert) {
3041 MDefinition* opd = convert->input();
3042 MOZ_ASSERT(opd->type() == MIRType::Boolean);
3043 redefine(convert, opd);
3046 void LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) {
3047 MDefinition* opd = truncate->input();
3049 switch (opd->type()) {
3050 case MIRType::Value: {
3051 LValueToInt32* lir = new (alloc()) LValueToInt32(
3052 useBox(opd), tempDouble(), temp(), LValueToInt32::TRUNCATE);
3053 assignSnapshot(lir, truncate->bailoutKind());
3054 define(lir, truncate);
3055 assignSafepoint(lir, truncate);
3056 break;
3059 case MIRType::Null:
3060 case MIRType::Undefined:
3061 define(new (alloc()) LInteger(0), truncate);
3062 break;
3064 case MIRType::Int32:
3065 case MIRType::Boolean:
3066 redefine(truncate, opd);
3067 break;
3069 case MIRType::Double:
3070 // May call into JS::ToInt32() on the slow OOL path.
3071 gen->setNeedsStaticStackAlignment();
3072 lowerTruncateDToInt32(truncate);
3073 break;
3075 case MIRType::Float32:
3076 // May call into JS::ToInt32() on the slow OOL path.
3077 gen->setNeedsStaticStackAlignment();
3078 lowerTruncateFToInt32(truncate);
3079 break;
3081 default:
3082 // Objects might be effectful. Symbols throw.
3083 // Strings are complicated - we don't handle them yet.
3084 MOZ_CRASH("unexpected type");
3088 void LIRGenerator::visitInt32ToIntPtr(MInt32ToIntPtr* ins) {
3089 MDefinition* input = ins->input();
3090 MOZ_ASSERT(input->type() == MIRType::Int32);
3091 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3093 #ifdef JS_64BIT
3094 // If the result is only used by instructions that expect a bounds-checked
3095 // index, we must have eliminated or hoisted a bounds check and we can assume
3096 // the index is non-negative. This lets us generate more efficient code.
3097 if (ins->canBeNegative()) {
3098 bool canBeNegative = false;
3099 for (MUseDefIterator iter(ins); iter; iter++) {
3100 if (!iter.def()->isSpectreMaskIndex() &&
3101 !iter.def()->isLoadUnboxedScalar() &&
3102 !iter.def()->isStoreUnboxedScalar() &&
3103 !iter.def()->isLoadDataViewElement() &&
3104 !iter.def()->isStoreDataViewElement()) {
3105 canBeNegative = true;
3106 break;
3109 if (!canBeNegative) {
3110 ins->setCanNotBeNegative();
3114 if (ins->canBeNegative()) {
3115 auto* lir = new (alloc()) LInt32ToIntPtr(useAnyAtStart(input));
3116 define(lir, ins);
3117 } else {
3118 redefine(ins, input);
3120 #else
3121 // On 32-bit platforms this is a no-op.
3122 redefine(ins, input);
3123 #endif
3126 void LIRGenerator::visitNonNegativeIntPtrToInt32(
3127 MNonNegativeIntPtrToInt32* ins) {
3128 MDefinition* input = ins->input();
3129 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3130 MOZ_ASSERT(ins->type() == MIRType::Int32);
3132 #ifdef JS_64BIT
3133 auto* lir =
3134 new (alloc()) LNonNegativeIntPtrToInt32(useRegisterAtStart(input));
3135 assignSnapshot(lir, ins->bailoutKind());
3136 defineReuseInput(lir, ins, 0);
3137 #else
3138 // On 32-bit platforms this is a no-op.
3139 redefine(ins, input);
3140 #endif
3143 void LIRGenerator::visitWasmExtendU32Index(MWasmExtendU32Index* ins) {
3144 #ifdef JS_64BIT
3145 // Technically this produces an Int64 register and I guess we could clean that
3146 // up, but it's a 64-bit only operation, so it doesn't actually matter.
3148 MDefinition* input = ins->input();
3149 MOZ_ASSERT(input->type() == MIRType::Int32);
3150 MOZ_ASSERT(ins->type() == MIRType::Int64);
3152 // Input reuse is OK even on ARM64 because this node *must* reuse its input in
3153 // order not to generate any code at all, as is the intent.
3154 auto* lir = new (alloc()) LWasmExtendU32Index(useRegisterAtStart(input));
3155 defineReuseInput(lir, ins, 0);
3156 #else
3157 MOZ_CRASH("64-bit only");
3158 #endif
3161 void LIRGenerator::visitWasmWrapU32Index(MWasmWrapU32Index* ins) {
3162 MDefinition* input = ins->input();
3163 MOZ_ASSERT(input->type() == MIRType::Int64);
3164 MOZ_ASSERT(ins->type() == MIRType::Int32);
3166 // Tricky: On 64-bit, this just returns its input (except on MIPS64 there may
3167 // be a sign/zero extension). On 32-bit, it returns the low register of the
3168 // input, and should generate no code.
3170 // If this assertion does not hold then using "input" unadorned as an alias
3171 // for the low register will not work.
3172 #if defined(JS_NUNBOX32)
3173 static_assert(INT64LOW_INDEX == 0);
3174 #endif
3176 auto* lir = new (alloc()) LWasmWrapU32Index(useRegisterAtStart(input));
3177 defineReuseInput(lir, ins, 0);
3180 void LIRGenerator::visitIntPtrToDouble(MIntPtrToDouble* ins) {
3181 MDefinition* input = ins->input();
3182 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3183 MOZ_ASSERT(ins->type() == MIRType::Double);
3185 auto* lir = new (alloc()) LIntPtrToDouble(useRegister(input));
3186 define(lir, ins);
3189 void LIRGenerator::visitAdjustDataViewLength(MAdjustDataViewLength* ins) {
3190 MDefinition* input = ins->input();
3191 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3193 auto* lir = new (alloc()) LAdjustDataViewLength(useRegisterAtStart(input));
3194 assignSnapshot(lir, ins->bailoutKind());
3195 defineReuseInput(lir, ins, 0);
3198 void LIRGenerator::visitToBigInt(MToBigInt* ins) {
3199 MDefinition* opd = ins->input();
3201 switch (opd->type()) {
3202 case MIRType::Value: {
3203 auto* lir = new (alloc()) LValueToBigInt(useBox(opd));
3204 assignSnapshot(lir, ins->bailoutKind());
3205 define(lir, ins);
3206 assignSafepoint(lir, ins);
3207 break;
3210 case MIRType::BigInt:
3211 redefine(ins, opd);
3212 break;
3214 default:
3215 MOZ_CRASH("unexpected type");
3219 void LIRGenerator::visitToInt64(MToInt64* ins) {
3220 MDefinition* opd = ins->input();
3222 switch (opd->type()) {
3223 case MIRType::Value: {
3224 auto* lir = new (alloc()) LValueToInt64(useBox(opd), temp());
3225 assignSnapshot(lir, ins->bailoutKind());
3226 defineInt64(lir, ins);
3227 assignSafepoint(lir, ins);
3228 break;
3231 case MIRType::Boolean: {
3232 auto* lir = new (alloc()) LBooleanToInt64(useRegisterAtStart(opd));
3233 defineInt64(lir, ins);
3234 break;
3237 case MIRType::String: {
3238 auto* lir = new (alloc()) LStringToInt64(useRegister(opd));
3239 defineInt64(lir, ins);
3240 assignSafepoint(lir, ins);
3241 break;
3244 // An Int64 may be passed here from a BigInt to Int64 conversion.
3245 case MIRType::Int64: {
3246 redefine(ins, opd);
3247 break;
3250 default:
3251 // Undefined, Null, Number, and Symbol throw.
3252 // Objects may be effectful.
3253 // BigInt operands are eliminated by the type policy.
3254 MOZ_CRASH("unexpected type");
3258 void LIRGenerator::visitTruncateBigIntToInt64(MTruncateBigIntToInt64* ins) {
3259 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
3260 auto* lir = new (alloc()) LTruncateBigIntToInt64(useRegister(ins->input()));
3261 defineInt64(lir, ins);
3264 void LIRGenerator::visitInt64ToBigInt(MInt64ToBigInt* ins) {
3265 MOZ_ASSERT(ins->input()->type() == MIRType::Int64);
3266 auto* lir =
3267 new (alloc()) LInt64ToBigInt(useInt64Register(ins->input()), temp());
3268 define(lir, ins);
3269 assignSafepoint(lir, ins);
3272 void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) {
3273 MDefinition* input = ins->input();
3274 switch (input->type()) {
3275 case MIRType::Double:
3276 case MIRType::Float32: {
3277 auto* lir = new (alloc()) LWasmTruncateToInt32(useRegisterAtStart(input));
3278 define(lir, ins);
3279 break;
3281 default:
3282 MOZ_CRASH("unexpected type in WasmTruncateToInt32");
3286 void LIRGenerator::visitWasmBuiltinTruncateToInt32(
3287 MWasmBuiltinTruncateToInt32* truncate) {
3288 mozilla::DebugOnly<MDefinition*> opd = truncate->input();
3289 MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
3291 // May call into JS::ToInt32() on the slow OOL path.
3292 gen->setNeedsStaticStackAlignment();
3293 lowerWasmBuiltinTruncateToInt32(truncate);
3296 void LIRGenerator::visitWasmAnyRefFromJSValue(MWasmAnyRefFromJSValue* ins) {
3297 LWasmAnyRefFromJSValue* lir =
3298 new (alloc()) LWasmAnyRefFromJSValue(useBox(ins->input()), tempDouble());
3299 define(lir, ins);
3300 assignSafepoint(lir, ins);
3303 void LIRGenerator::visitWasmAnyRefFromJSObject(MWasmAnyRefFromJSObject* ins) {
3304 LWasmAnyRefFromJSObject* lir =
3305 new (alloc()) LWasmAnyRefFromJSObject(useRegisterAtStart(ins->input()));
3306 define(lir, ins);
3309 void LIRGenerator::visitWasmAnyRefFromJSString(MWasmAnyRefFromJSString* ins) {
3310 LWasmAnyRefFromJSString* lir =
3311 new (alloc()) LWasmAnyRefFromJSString(useRegisterAtStart(ins->input()));
3312 define(lir, ins);
3315 void LIRGenerator::visitWasmNewI31Ref(MWasmNewI31Ref* ins) {
3316 // If it's a constant, it will be put directly into the register.
3317 LWasmNewI31Ref* lir =
3318 new (alloc()) LWasmNewI31Ref(useRegisterOrConstant(ins->input()));
3319 define(lir, ins);
3322 void LIRGenerator::visitWasmI31RefGet(MWasmI31RefGet* ins) {
3323 LWasmI31RefGet* lir = new (alloc()) LWasmI31RefGet(useRegister(ins->input()));
3324 define(lir, ins);
3327 void LIRGenerator::visitWrapInt64ToInt32(MWrapInt64ToInt32* ins) {
3328 define(new (alloc()) LWrapInt64ToInt32(useInt64AtStart(ins->input())), ins);
3331 void LIRGenerator::visitToString(MToString* ins) {
3332 MDefinition* opd = ins->input();
3334 switch (opd->type()) {
3335 case MIRType::Null: {
3336 const JSAtomState& names = gen->runtime->names();
3337 LPointer* lir = new (alloc()) LPointer(names.null);
3338 define(lir, ins);
3339 break;
3342 case MIRType::Undefined: {
3343 const JSAtomState& names = gen->runtime->names();
3344 LPointer* lir = new (alloc()) LPointer(names.undefined);
3345 define(lir, ins);
3346 break;
3349 case MIRType::Boolean: {
3350 LBooleanToString* lir = new (alloc()) LBooleanToString(useRegister(opd));
3351 define(lir, ins);
3352 break;
3355 case MIRType::Double: {
3356 LDoubleToString* lir =
3357 new (alloc()) LDoubleToString(useRegister(opd), temp());
3359 define(lir, ins);
3360 assignSafepoint(lir, ins);
3361 break;
3364 case MIRType::Int32: {
3365 LIntToString* lir = new (alloc()) LIntToString(useRegister(opd));
3367 define(lir, ins);
3368 assignSafepoint(lir, ins);
3369 break;
3372 case MIRType::String:
3373 redefine(ins, ins->input());
3374 break;
3376 case MIRType::Value: {
3377 LValueToString* lir =
3378 new (alloc()) LValueToString(useBox(opd), tempToUnbox());
3379 if (ins->needsSnapshot()) {
3380 assignSnapshot(lir, ins->bailoutKind());
3382 define(lir, ins);
3383 assignSafepoint(lir, ins);
3384 break;
3387 default:
3388 // Float32, symbols, bigint, and objects are not supported.
3389 MOZ_CRASH("unexpected type");
3393 void LIRGenerator::visitRegExp(MRegExp* ins) {
3394 LRegExp* lir = new (alloc()) LRegExp(temp());
3395 define(lir, ins);
3396 assignSafepoint(lir, ins);
3399 void LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins) {
3400 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3401 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3402 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
3404 LRegExpMatcher* lir = new (alloc()) LRegExpMatcher(
3405 useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
3406 useFixedAtStart(ins->string(), RegExpMatcherStringReg),
3407 useFixedAtStart(ins->lastIndex(), RegExpMatcherLastIndexReg));
3408 defineReturn(lir, ins);
3409 assignSafepoint(lir, ins);
3412 void LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins) {
3413 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3414 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3415 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
3417 LRegExpSearcher* lir = new (alloc()) LRegExpSearcher(
3418 useFixedAtStart(ins->regexp(), RegExpSearcherRegExpReg),
3419 useFixedAtStart(ins->string(), RegExpSearcherStringReg),
3420 useFixedAtStart(ins->lastIndex(), RegExpSearcherLastIndexReg));
3421 defineReturn(lir, ins);
3422 assignSafepoint(lir, ins);
3425 void LIRGenerator::visitRegExpSearcherLastLimit(MRegExpSearcherLastLimit* ins) {
3426 auto* lir = new (alloc()) LRegExpSearcherLastLimit(temp());
3427 define(lir, ins);
3430 void LIRGenerator::visitRegExpExecMatch(MRegExpExecMatch* ins) {
3431 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3432 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3434 auto* lir = new (alloc())
3435 LRegExpExecMatch(useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
3436 useFixedAtStart(ins->string(), RegExpMatcherStringReg));
3437 defineReturn(lir, ins);
3438 assignSafepoint(lir, ins);
3441 void LIRGenerator::visitRegExpExecTest(MRegExpExecTest* ins) {
3442 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3443 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3445 auto* lir = new (alloc())
3446 LRegExpExecTest(useFixedAtStart(ins->regexp(), RegExpExecTestRegExpReg),
3447 useFixedAtStart(ins->string(), RegExpExecTestStringReg));
3448 defineReturn(lir, ins);
3449 assignSafepoint(lir, ins);
3452 void LIRGenerator::visitRegExpHasCaptureGroups(MRegExpHasCaptureGroups* ins) {
3453 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3454 MOZ_ASSERT(ins->input()->type() == MIRType::String);
3455 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3457 auto* lir = new (alloc()) LRegExpHasCaptureGroups(useRegister(ins->regexp()),
3458 useRegister(ins->input()));
3459 define(lir, ins);
3460 assignSafepoint(lir, ins);
3463 void LIRGenerator::visitRegExpPrototypeOptimizable(
3464 MRegExpPrototypeOptimizable* ins) {
3465 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3466 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3467 LRegExpPrototypeOptimizable* lir = new (alloc())
3468 LRegExpPrototypeOptimizable(useRegister(ins->object()), temp());
3469 define(lir, ins);
3472 void LIRGenerator::visitRegExpInstanceOptimizable(
3473 MRegExpInstanceOptimizable* ins) {
3474 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3475 MOZ_ASSERT(ins->proto()->type() == MIRType::Object);
3476 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3477 LRegExpInstanceOptimizable* lir = new (alloc()) LRegExpInstanceOptimizable(
3478 useRegister(ins->object()), useRegister(ins->proto()), temp());
3479 define(lir, ins);
3482 void LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex* ins) {
3483 MOZ_ASSERT(ins->str()->type() == MIRType::String);
3484 MOZ_ASSERT(ins->type() == MIRType::Int32);
3485 LGetFirstDollarIndex* lir = new (alloc())
3486 LGetFirstDollarIndex(useRegister(ins->str()), temp(), temp(), temp());
3487 define(lir, ins);
3488 assignSafepoint(lir, ins);
3491 void LIRGenerator::visitStringReplace(MStringReplace* ins) {
3492 MOZ_ASSERT(ins->pattern()->type() == MIRType::String);
3493 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3494 MOZ_ASSERT(ins->replacement()->type() == MIRType::String);
3496 LStringReplace* lir = new (alloc())
3497 LStringReplace(useRegisterOrConstantAtStart(ins->string()),
3498 useRegisterAtStart(ins->pattern()),
3499 useRegisterOrConstantAtStart(ins->replacement()));
3500 defineReturn(lir, ins);
3501 assignSafepoint(lir, ins);
3504 void LIRGenerator::visitBinaryCache(MBinaryCache* ins) {
3505 MDefinition* lhs = ins->getOperand(0);
3506 MDefinition* rhs = ins->getOperand(1);
3508 MOZ_ASSERT(ins->type() == MIRType::Value || ins->type() == MIRType::Boolean);
3509 LInstruction* lir;
3510 if (ins->type() == MIRType::Value) {
3511 LBinaryValueCache* valueLir = new (alloc()) LBinaryValueCache(
3512 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
3513 defineBox(valueLir, ins);
3514 lir = valueLir;
3515 } else {
3516 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3517 LBinaryBoolCache* boolLir = new (alloc()) LBinaryBoolCache(
3518 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
3519 define(boolLir, ins);
3520 lir = boolLir;
3522 assignSafepoint(lir, ins);
3525 void LIRGenerator::visitUnaryCache(MUnaryCache* ins) {
3526 MDefinition* input = ins->getOperand(0);
3527 MOZ_ASSERT(ins->type() == MIRType::Value);
3529 LUnaryCache* lir = new (alloc()) LUnaryCache(useBox(input));
3530 defineBox(lir, ins);
3531 assignSafepoint(lir, ins);
3534 void LIRGenerator::visitModuleMetadata(MModuleMetadata* ins) {
3535 LModuleMetadata* lir = new (alloc()) LModuleMetadata();
3536 defineReturn(lir, ins);
3537 assignSafepoint(lir, ins);
3540 void LIRGenerator::visitDynamicImport(MDynamicImport* ins) {
3541 LDynamicImport* lir = new (alloc()) LDynamicImport(
3542 useBoxAtStart(ins->specifier()), useBoxAtStart(ins->options()));
3543 defineReturn(lir, ins);
3544 assignSafepoint(lir, ins);
3547 void LIRGenerator::visitLambda(MLambda* ins) {
3548 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3550 auto* lir =
3551 new (alloc()) LLambda(useRegister(ins->environmentChain()), temp());
3552 define(lir, ins);
3553 assignSafepoint(lir, ins);
3556 void LIRGenerator::visitFunctionWithProto(MFunctionWithProto* ins) {
3557 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3558 MOZ_ASSERT(ins->prototype()->type() == MIRType::Object);
3560 auto* lir = new (alloc())
3561 LFunctionWithProto(useRegisterAtStart(ins->environmentChain()),
3562 useRegisterAtStart(ins->prototype()));
3563 defineReturn(lir, ins);
3564 assignSafepoint(lir, ins);
3567 void LIRGenerator::visitSetFunName(MSetFunName* ins) {
3568 MOZ_ASSERT(ins->fun()->type() == MIRType::Object);
3569 MOZ_ASSERT(ins->name()->type() == MIRType::Value);
3571 LSetFunName* lir = new (alloc())
3572 LSetFunName(useRegisterAtStart(ins->fun()), useBoxAtStart(ins->name()));
3573 add(lir, ins);
3574 assignSafepoint(lir, ins);
3577 void LIRGenerator::visitNewLexicalEnvironmentObject(
3578 MNewLexicalEnvironmentObject* ins) {
3579 auto* lir = new (alloc()) LNewLexicalEnvironmentObject(temp());
3581 define(lir, ins);
3582 assignSafepoint(lir, ins);
3585 void LIRGenerator::visitNewClassBodyEnvironmentObject(
3586 MNewClassBodyEnvironmentObject* ins) {
3587 auto* lir = new (alloc()) LNewClassBodyEnvironmentObject(temp());
3589 define(lir, ins);
3590 assignSafepoint(lir, ins);
3593 void LIRGenerator::visitNewVarEnvironmentObject(MNewVarEnvironmentObject* ins) {
3594 auto* lir = new (alloc()) LNewVarEnvironmentObject(temp());
3596 define(lir, ins);
3597 assignSafepoint(lir, ins);
3600 void LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins) {
3601 MDefinition* obj = ins->object();
3602 MOZ_ASSERT(obj->type() == MIRType::Object);
3604 add(new (alloc()) LKeepAliveObject(useKeepalive(obj)), ins);
3607 void LIRGenerator::visitDebugEnterGCUnsafeRegion(
3608 MDebugEnterGCUnsafeRegion* ins) {
3609 add(new (alloc()) LDebugEnterGCUnsafeRegion(temp()), ins);
3612 void LIRGenerator::visitDebugLeaveGCUnsafeRegion(
3613 MDebugLeaveGCUnsafeRegion* ins) {
3614 add(new (alloc()) LDebugLeaveGCUnsafeRegion(temp()), ins);
3617 void LIRGenerator::visitSlots(MSlots* ins) {
3618 define(new (alloc()) LSlots(useRegisterAtStart(ins->object())), ins);
3621 void LIRGenerator::visitElements(MElements* ins) {
3622 define(new (alloc()) LElements(useRegisterAtStart(ins->object())), ins);
3625 void LIRGenerator::visitLoadDynamicSlot(MLoadDynamicSlot* ins) {
3626 MOZ_ASSERT(ins->type() == MIRType::Value);
3627 if (ins->usedAsPropertyKey()) {
3628 auto* lir = new (alloc())
3629 LLoadDynamicSlotAndAtomize(useRegister(ins->slots()), temp());
3630 defineBox(lir, ins);
3631 assignSafepoint(lir, ins);
3632 } else {
3633 defineBox(new (alloc()) LLoadDynamicSlotV(useRegisterAtStart(ins->slots())),
3634 ins);
3638 void LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment* ins) {
3639 define(new (alloc())
3640 LFunctionEnvironment(useRegisterAtStart(ins->function())),
3641 ins);
3644 void LIRGenerator::visitHomeObject(MHomeObject* ins) {
3645 define(new (alloc()) LHomeObject(useRegisterAtStart(ins->function())), ins);
3648 void LIRGenerator::visitHomeObjectSuperBase(MHomeObjectSuperBase* ins) {
3649 MOZ_ASSERT(ins->homeObject()->type() == MIRType::Object);
3650 MOZ_ASSERT(ins->type() == MIRType::Value);
3652 auto lir =
3653 new (alloc()) LHomeObjectSuperBase(useRegisterAtStart(ins->homeObject()));
3654 defineBox(lir, ins);
3657 void LIRGenerator::visitInterruptCheck(MInterruptCheck* ins) {
3658 LInstruction* lir = new (alloc()) LInterruptCheck();
3659 add(lir, ins);
3660 assignSafepoint(lir, ins);
3663 void LIRGenerator::visitWasmInterruptCheck(MWasmInterruptCheck* ins) {
3664 auto* lir =
3665 new (alloc()) LWasmInterruptCheck(useRegisterAtStart(ins->instance()));
3666 add(lir, ins);
3667 assignWasmSafepoint(lir);
3670 void LIRGenerator::visitWasmTrap(MWasmTrap* ins) {
3671 add(new (alloc()) LWasmTrap, ins);
3674 void LIRGenerator::visitWasmTrapIfNull(MWasmTrapIfNull* ins) {
3675 auto* lir = new (alloc()) LWasmTrapIfNull(useRegister(ins->ref()));
3676 add(lir, ins);
3679 void LIRGenerator::visitWasmReinterpret(MWasmReinterpret* ins) {
3680 if (ins->type() == MIRType::Int64) {
3681 defineInt64(new (alloc())
3682 LWasmReinterpretToI64(useRegisterAtStart(ins->input())),
3683 ins);
3684 } else if (ins->input()->type() == MIRType::Int64) {
3685 define(new (alloc())
3686 LWasmReinterpretFromI64(useInt64RegisterAtStart(ins->input())),
3687 ins);
3688 } else {
3689 define(new (alloc()) LWasmReinterpret(useRegisterAtStart(ins->input())),
3690 ins);
3694 void LIRGenerator::visitStoreDynamicSlot(MStoreDynamicSlot* ins) {
3695 LInstruction* lir;
3697 switch (ins->value()->type()) {
3698 case MIRType::Value:
3699 lir = new (alloc())
3700 LStoreDynamicSlotV(useRegister(ins->slots()), useBox(ins->value()));
3701 add(lir, ins);
3702 break;
3704 case MIRType::Double:
3705 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3706 useRegister(ins->value())),
3707 ins);
3708 break;
3710 case MIRType::Float32:
3711 MOZ_CRASH("Float32 shouldn't be stored in a slot.");
3713 default:
3714 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3715 useRegisterOrConstant(ins->value())),
3716 ins);
3717 break;
3721 // Returns true iff |def| is a constant that's either not a GC thing or is not
3722 // allocated in the nursery.
3723 static bool IsNonNurseryConstant(MDefinition* def) {
3724 if (!def->isConstant()) {
3725 return false;
3727 Value v = def->toConstant()->toJSValue();
3728 return !v.isGCThing() || !IsInsideNursery(v.toGCThing());
3731 void LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) {
3732 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3734 // LPostWriteBarrier assumes that if it has a constant object then that
3735 // object is tenured, and does not need to be tested for being in the
3736 // nursery. Ensure that assumption holds by lowering constant nursery
3737 // objects to a register.
3738 bool useConstantObject = IsNonNurseryConstant(ins->object());
3740 switch (ins->value()->type()) {
3741 case MIRType::Object: {
3742 LDefinition tmp =
3743 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3744 LPostWriteBarrierO* lir = new (alloc())
3745 LPostWriteBarrierO(useConstantObject ? useOrConstant(ins->object())
3746 : useRegister(ins->object()),
3747 useRegister(ins->value()), tmp);
3748 add(lir, ins);
3749 assignSafepoint(lir, ins);
3750 break;
3752 case MIRType::String: {
3753 LDefinition tmp =
3754 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3755 LPostWriteBarrierS* lir = new (alloc())
3756 LPostWriteBarrierS(useConstantObject ? useOrConstant(ins->object())
3757 : useRegister(ins->object()),
3758 useRegister(ins->value()), tmp);
3759 add(lir, ins);
3760 assignSafepoint(lir, ins);
3761 break;
3763 case MIRType::BigInt: {
3764 LDefinition tmp =
3765 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3766 auto* lir = new (alloc())
3767 LPostWriteBarrierBI(useConstantObject ? useOrConstant(ins->object())
3768 : useRegister(ins->object()),
3769 useRegister(ins->value()), tmp);
3770 add(lir, ins);
3771 assignSafepoint(lir, ins);
3772 break;
3774 case MIRType::Value: {
3775 LDefinition tmp =
3776 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3777 LPostWriteBarrierV* lir = new (alloc())
3778 LPostWriteBarrierV(useConstantObject ? useOrConstant(ins->object())
3779 : useRegister(ins->object()),
3780 useBox(ins->value()), tmp);
3781 add(lir, ins);
3782 assignSafepoint(lir, ins);
3783 break;
3785 default:
3786 // Currently, only objects and strings can be in the nursery. Other
3787 // instruction types cannot hold nursery pointers.
3788 break;
3792 void LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) {
3793 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3794 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3796 // LPostWriteElementBarrier assumes that if it has a constant object then that
3797 // object is tenured, and does not need to be tested for being in the
3798 // nursery. Ensure that assumption holds by lowering constant nursery
3799 // objects to a register.
3800 bool useConstantObject =
3801 ins->object()->isConstant() &&
3802 !IsInsideNursery(&ins->object()->toConstant()->toObject());
3804 switch (ins->value()->type()) {
3805 case MIRType::Object: {
3806 LDefinition tmp =
3807 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3808 LPostWriteElementBarrierO* lir = new (alloc()) LPostWriteElementBarrierO(
3809 useConstantObject ? useOrConstant(ins->object())
3810 : useRegister(ins->object()),
3811 useRegister(ins->value()), useRegister(ins->index()), tmp);
3812 add(lir, ins);
3813 assignSafepoint(lir, ins);
3814 break;
3816 case MIRType::String: {
3817 LDefinition tmp =
3818 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3819 LPostWriteElementBarrierS* lir = new (alloc()) LPostWriteElementBarrierS(
3820 useConstantObject ? useOrConstant(ins->object())
3821 : useRegister(ins->object()),
3822 useRegister(ins->value()), useRegister(ins->index()), tmp);
3823 add(lir, ins);
3824 assignSafepoint(lir, ins);
3825 break;
3827 case MIRType::BigInt: {
3828 LDefinition tmp =
3829 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3830 auto* lir = new (alloc()) LPostWriteElementBarrierBI(
3831 useConstantObject ? useOrConstant(ins->object())
3832 : useRegister(ins->object()),
3833 useRegister(ins->value()), useRegister(ins->index()), tmp);
3834 add(lir, ins);
3835 assignSafepoint(lir, ins);
3836 break;
3838 case MIRType::Value: {
3839 LDefinition tmp =
3840 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3841 LPostWriteElementBarrierV* lir = new (alloc()) LPostWriteElementBarrierV(
3842 useConstantObject ? useOrConstant(ins->object())
3843 : useRegister(ins->object()),
3844 useRegister(ins->index()), useBox(ins->value()), tmp);
3845 add(lir, ins);
3846 assignSafepoint(lir, ins);
3847 break;
3849 default:
3850 // Currently, only objects, strings, and bigints can be in the nursery.
3851 // Other instruction types cannot hold nursery pointers.
3852 break;
3856 void LIRGenerator::visitAssertCanElidePostWriteBarrier(
3857 MAssertCanElidePostWriteBarrier* ins) {
3858 auto* lir = new (alloc()) LAssertCanElidePostWriteBarrier(
3859 useRegister(ins->object()), useBox(ins->value()), temp());
3860 add(lir, ins);
3863 void LIRGenerator::visitArrayLength(MArrayLength* ins) {
3864 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3865 auto* lir = new (alloc()) LArrayLength(useRegisterAtStart(ins->elements()));
3866 assignSnapshot(lir, ins->bailoutKind());
3867 define(lir, ins);
3870 void LIRGenerator::visitSetArrayLength(MSetArrayLength* ins) {
3871 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3872 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3874 MOZ_ASSERT(ins->index()->isConstant());
3875 add(new (alloc()) LSetArrayLength(useRegister(ins->elements()),
3876 useRegisterOrConstant(ins->index())),
3877 ins);
3880 void LIRGenerator::visitFunctionLength(MFunctionLength* ins) {
3881 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3883 auto* lir = new (alloc()) LFunctionLength(useRegister(ins->function()));
3884 assignSnapshot(lir, ins->bailoutKind());
3885 define(lir, ins);
3888 void LIRGenerator::visitFunctionName(MFunctionName* ins) {
3889 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3891 auto* lir = new (alloc()) LFunctionName(useRegister(ins->function()));
3892 assignSnapshot(lir, ins->bailoutKind());
3893 define(lir, ins);
3896 void LIRGenerator::visitGetNextEntryForIterator(MGetNextEntryForIterator* ins) {
3897 MOZ_ASSERT(ins->iter()->type() == MIRType::Object);
3898 MOZ_ASSERT(ins->result()->type() == MIRType::Object);
3899 auto lir = new (alloc()) LGetNextEntryForIterator(useRegister(ins->iter()),
3900 useRegister(ins->result()),
3901 temp(), temp(), temp());
3902 define(lir, ins);
3905 static auto SynchronizeLoad(MemoryBarrierRequirement requiresBarrier) {
3906 if (requiresBarrier == MemoryBarrierRequirement::Required) {
3907 return Synchronization::Load();
3909 return Synchronization::None();
3912 static auto SynchronizeStore(MemoryBarrierRequirement requiresBarrier) {
3913 if (requiresBarrier == MemoryBarrierRequirement::Required) {
3914 return Synchronization::Store();
3916 return Synchronization::None();
3919 void LIRGenerator::visitArrayBufferByteLength(MArrayBufferByteLength* ins) {
3920 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3921 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3923 auto* lir =
3924 new (alloc()) LArrayBufferByteLength(useRegisterAtStart(ins->object()));
3925 define(lir, ins);
3928 void LIRGenerator::visitArrayBufferViewLength(MArrayBufferViewLength* ins) {
3929 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3930 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3932 auto* lir =
3933 new (alloc()) LArrayBufferViewLength(useRegisterAtStart(ins->object()));
3934 define(lir, ins);
3937 void LIRGenerator::visitArrayBufferViewByteOffset(
3938 MArrayBufferViewByteOffset* ins) {
3939 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3940 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3942 auto* lir = new (alloc())
3943 LArrayBufferViewByteOffset(useRegisterAtStart(ins->object()));
3944 define(lir, ins);
3947 void LIRGenerator::visitArrayBufferViewElements(MArrayBufferViewElements* ins) {
3948 MOZ_ASSERT(ins->type() == MIRType::Elements);
3949 define(new (alloc())
3950 LArrayBufferViewElements(useRegisterAtStart(ins->object())),
3951 ins);
3954 void LIRGenerator::visitTypedArrayElementSize(MTypedArrayElementSize* ins) {
3955 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3956 define(new (alloc())
3957 LTypedArrayElementSize(useRegisterAtStart(ins->object())),
3958 ins);
3961 void LIRGenerator::visitResizableTypedArrayLength(
3962 MResizableTypedArrayLength* ins) {
3963 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3964 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3966 auto sync = SynchronizeLoad(ins->requiresMemoryBarrier());
3967 auto* lir = new (alloc())
3968 LResizableTypedArrayLength(useRegister(ins->object()), temp(), sync);
3969 define(lir, ins);
3972 void LIRGenerator::visitResizableTypedArrayByteOffsetMaybeOutOfBounds(
3973 MResizableTypedArrayByteOffsetMaybeOutOfBounds* ins) {
3974 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3975 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3977 auto* lir = new (alloc()) LResizableTypedArrayByteOffsetMaybeOutOfBounds(
3978 useRegister(ins->object()), temp());
3979 define(lir, ins);
3982 void LIRGenerator::visitResizableDataViewByteLength(
3983 MResizableDataViewByteLength* ins) {
3984 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3985 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3987 auto sync = SynchronizeLoad(ins->requiresMemoryBarrier());
3988 auto* lir = new (alloc())
3989 LResizableDataViewByteLength(useRegister(ins->object()), temp(), sync);
3990 define(lir, ins);
3993 void LIRGenerator::visitGrowableSharedArrayBufferByteLength(
3994 MGrowableSharedArrayBufferByteLength* ins) {
3995 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3996 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3998 auto* lir = new (alloc())
3999 LGrowableSharedArrayBufferByteLength(useRegisterAtStart(ins->object()));
4000 define(lir, ins);
4003 void LIRGenerator::visitGuardResizableArrayBufferViewInBounds(
4004 MGuardResizableArrayBufferViewInBounds* ins) {
4005 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4007 auto* lir = new (alloc()) LGuardResizableArrayBufferViewInBounds(
4008 useRegister(ins->object()), temp());
4009 assignSnapshot(lir, ins->bailoutKind());
4010 add(lir, ins);
4011 redefine(ins, ins->object());
4014 void LIRGenerator::visitGuardResizableArrayBufferViewInBoundsOrDetached(
4015 MGuardResizableArrayBufferViewInBoundsOrDetached* ins) {
4016 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4018 auto* lir = new (alloc()) LGuardResizableArrayBufferViewInBoundsOrDetached(
4019 useRegister(ins->object()), temp());
4020 assignSnapshot(lir, ins->bailoutKind());
4021 add(lir, ins);
4022 redefine(ins, ins->object());
4025 void LIRGenerator::visitGuardHasAttachedArrayBuffer(
4026 MGuardHasAttachedArrayBuffer* ins) {
4027 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4029 auto* lir = new (alloc())
4030 LGuardHasAttachedArrayBuffer(useRegister(ins->object()), temp());
4031 assignSnapshot(lir, ins->bailoutKind());
4032 add(lir, ins);
4033 redefine(ins, ins->object());
4036 void LIRGenerator::visitGuardNumberToIntPtrIndex(
4037 MGuardNumberToIntPtrIndex* ins) {
4038 MDefinition* input = ins->input();
4039 MOZ_ASSERT(input->type() == MIRType::Double);
4041 auto* lir = new (alloc()) LGuardNumberToIntPtrIndex(useRegister(input));
4042 if (!ins->supportOOB()) {
4043 assignSnapshot(lir, ins->bailoutKind());
4045 define(lir, ins);
4048 void LIRGenerator::visitInitializedLength(MInitializedLength* ins) {
4049 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4050 define(new (alloc()) LInitializedLength(useRegisterAtStart(ins->elements())),
4051 ins);
4054 void LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins) {
4055 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4056 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4058 MOZ_ASSERT(ins->index()->isConstant());
4059 add(new (alloc()) LSetInitializedLength(useRegister(ins->elements()),
4060 useRegisterOrConstant(ins->index())),
4061 ins);
4064 void LIRGenerator::visitNot(MNot* ins) {
4065 MDefinition* op = ins->input();
4067 // String is converted to length of string in the type analysis phase (see
4068 // TestPolicy).
4069 MOZ_ASSERT(op->type() != MIRType::String);
4071 // - boolean: x xor 1
4072 // - int32: LCompare(x, 0)
4073 // - double: LCompare(x, 0)
4074 // - null or undefined: true
4075 // - symbol: false
4076 // - bigint: LNotBI(x)
4077 // - object: false if it never emulates undefined, else LNotO(x)
4078 switch (op->type()) {
4079 case MIRType::Boolean: {
4080 MConstant* cons = MConstant::New(alloc(), Int32Value(1));
4081 ins->block()->insertBefore(ins, cons);
4082 lowerForALU(new (alloc()) LBitOpI(JSOp::BitXor), ins, op, cons);
4083 break;
4085 case MIRType::Int32:
4086 define(new (alloc()) LNotI(useRegisterAtStart(op)), ins);
4087 break;
4088 case MIRType::Int64:
4089 define(new (alloc()) LNotI64(useInt64RegisterAtStart(op)), ins);
4090 break;
4091 case MIRType::Double:
4092 define(new (alloc()) LNotD(useRegister(op)), ins);
4093 break;
4094 case MIRType::Float32:
4095 define(new (alloc()) LNotF(useRegister(op)), ins);
4096 break;
4097 case MIRType::Undefined:
4098 case MIRType::Null:
4099 define(new (alloc()) LInteger(1), ins);
4100 break;
4101 case MIRType::Symbol:
4102 define(new (alloc()) LInteger(0), ins);
4103 break;
4104 case MIRType::BigInt:
4105 define(new (alloc()) LNotBI(useRegisterAtStart(op)), ins);
4106 break;
4107 case MIRType::Object:
4108 define(new (alloc()) LNotO(useRegister(op)), ins);
4109 break;
4110 case MIRType::Value: {
4111 auto* lir = new (alloc()) LNotV(useBox(op), tempDouble(), tempToUnbox());
4112 define(lir, ins);
4113 break;
4116 default:
4117 MOZ_CRASH("Unexpected MIRType.");
4121 void LIRGenerator::visitBoundsCheck(MBoundsCheck* ins) {
4122 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
4123 MOZ_ASSERT(ins->index()->type() == ins->type());
4124 MOZ_ASSERT(ins->length()->type() == ins->type());
4126 if (!ins->fallible()) {
4127 return;
4130 LInstruction* check;
4131 if (ins->minimum() || ins->maximum()) {
4132 check = new (alloc())
4133 LBoundsCheckRange(useRegisterOrInt32Constant(ins->index()),
4134 useAny(ins->length()), temp());
4135 } else {
4136 check = new (alloc()) LBoundsCheck(useRegisterOrInt32Constant(ins->index()),
4137 useAnyOrInt32Constant(ins->length()));
4139 assignSnapshot(check, ins->bailoutKind());
4140 add(check, ins);
4143 void LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex* ins) {
4144 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
4145 MOZ_ASSERT(ins->index()->type() == ins->type());
4146 MOZ_ASSERT(ins->length()->type() == ins->type());
4148 auto* lir = new (alloc())
4149 LSpectreMaskIndex(useRegister(ins->index()), useAny(ins->length()));
4150 define(lir, ins);
4153 void LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins) {
4154 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4156 if (!ins->fallible()) {
4157 return;
4160 LInstruction* check =
4161 new (alloc()) LBoundsCheckLower(useRegister(ins->index()));
4162 assignSnapshot(check, ins->bailoutKind());
4163 add(check, ins);
4166 void LIRGenerator::visitInArray(MInArray* ins) {
4167 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4168 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4169 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
4170 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4172 auto* lir = new (alloc()) LInArray(useRegister(ins->elements()),
4173 useRegisterOrConstant(ins->index()),
4174 useRegister(ins->initLength()));
4175 if (ins->needsNegativeIntCheck()) {
4176 assignSnapshot(lir, ins->bailoutKind());
4178 define(lir, ins);
4181 void LIRGenerator::visitGuardElementNotHole(MGuardElementNotHole* ins) {
4182 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4183 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4185 auto* guard = new (alloc())
4186 LGuardElementNotHole(useRegisterAtStart(ins->elements()),
4187 useRegisterOrConstantAtStart(ins->index()));
4188 assignSnapshot(guard, ins->bailoutKind());
4189 add(guard, ins);
4192 void LIRGenerator::visitLoadElement(MLoadElement* ins) {
4193 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4194 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4195 MOZ_ASSERT(ins->type() == MIRType::Value);
4197 auto* lir = new (alloc()) LLoadElementV(useRegister(ins->elements()),
4198 useRegisterOrConstant(ins->index()));
4199 assignSnapshot(lir, ins->bailoutKind());
4200 defineBox(lir, ins);
4203 void LIRGenerator::visitLoadElementHole(MLoadElementHole* ins) {
4204 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4205 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4206 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
4207 MOZ_ASSERT(ins->type() == MIRType::Value);
4209 LLoadElementHole* lir = new (alloc())
4210 LLoadElementHole(useRegister(ins->elements()), useRegister(ins->index()),
4211 useRegister(ins->initLength()));
4212 if (ins->needsNegativeIntCheck()) {
4213 assignSnapshot(lir, ins->bailoutKind());
4215 defineBox(lir, ins);
4218 void LIRGenerator::visitStoreElement(MStoreElement* ins) {
4219 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4220 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4222 const LUse elements = useRegister(ins->elements());
4223 const LAllocation index = useRegisterOrConstant(ins->index());
4225 switch (ins->value()->type()) {
4226 case MIRType::Value: {
4227 LInstruction* lir =
4228 new (alloc()) LStoreElementV(elements, index, useBox(ins->value()));
4229 if (ins->fallible()) {
4230 assignSnapshot(lir, ins->bailoutKind());
4232 add(lir, ins);
4233 break;
4236 default: {
4237 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
4238 LInstruction* lir = new (alloc()) LStoreElementT(elements, index, value);
4239 if (ins->fallible()) {
4240 assignSnapshot(lir, ins->bailoutKind());
4242 add(lir, ins);
4243 break;
4248 void LIRGenerator::visitStoreHoleValueElement(MStoreHoleValueElement* ins) {
4249 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4250 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4252 auto* lir = new (alloc()) LStoreHoleValueElement(useRegister(ins->elements()),
4253 useRegister(ins->index()));
4254 add(lir, ins);
4257 static bool BoundsCheckNeedsSpectreTemp() {
4258 // On x86, spectreBoundsCheck32 can emit better code if it has a scratch
4259 // register and index masking is enabled.
4260 #ifdef JS_CODEGEN_X86
4261 return JitOptions.spectreIndexMasking;
4262 #else
4263 return false;
4264 #endif
4267 void LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) {
4268 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4269 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4271 const LUse object = useRegister(ins->object());
4272 const LUse elements = useRegister(ins->elements());
4273 const LAllocation index = useRegister(ins->index());
4275 LInstruction* lir;
4276 switch (ins->value()->type()) {
4277 case MIRType::Value:
4278 lir = new (alloc()) LStoreElementHoleV(object, elements, index,
4279 useBox(ins->value()), temp());
4280 break;
4282 default: {
4283 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
4284 lir = new (alloc())
4285 LStoreElementHoleT(object, elements, index, value, temp());
4286 break;
4290 assignSnapshot(lir, ins->bailoutKind());
4291 add(lir, ins);
4292 assignSafepoint(lir, ins);
4295 void LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins) {
4296 define(new (alloc()) LEffectiveAddress(useRegister(ins->base()),
4297 useRegister(ins->index())),
4298 ins);
4301 void LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) {
4302 MOZ_ASSERT(ins->type() == MIRType::Value);
4304 auto* lir =
4305 new (alloc()) LArrayPopShift(useRegister(ins->object()), temp(), temp());
4306 assignSnapshot(lir, ins->bailoutKind());
4307 defineBox(lir, ins);
4309 if (ins->mode() == MArrayPopShift::Shift) {
4310 assignSafepoint(lir, ins);
4314 void LIRGenerator::visitArrayPush(MArrayPush* ins) {
4315 MOZ_ASSERT(ins->type() == MIRType::Int32);
4316 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4318 LUse object = useRegister(ins->object());
4320 LDefinition spectreTemp =
4321 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4323 auto* lir = new (alloc())
4324 LArrayPush(object, useBox(ins->value()), temp(), spectreTemp);
4325 // We will bailout before pushing if the length would overflow INT32_MAX.
4326 assignSnapshot(lir, ins->bailoutKind());
4327 define(lir, ins);
4328 assignSafepoint(lir, ins);
4331 void LIRGenerator::visitArraySlice(MArraySlice* ins) {
4332 MOZ_ASSERT(ins->type() == MIRType::Object);
4333 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4334 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4335 MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
4337 LArraySlice* lir = new (alloc()) LArraySlice(
4338 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()),
4339 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0),
4340 tempFixed(CallTempReg1));
4341 assignSnapshot(lir, ins->bailoutKind());
4342 defineReturn(lir, ins);
4343 assignSafepoint(lir, ins);
4346 void LIRGenerator::visitArgumentsSlice(MArgumentsSlice* ins) {
4347 MOZ_ASSERT(ins->type() == MIRType::Object);
4348 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4349 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4350 MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
4352 auto* lir = new (alloc()) LArgumentsSlice(
4353 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()),
4354 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0),
4355 tempFixed(CallTempReg1));
4356 defineReturn(lir, ins);
4357 assignSafepoint(lir, ins);
4360 void LIRGenerator::visitFrameArgumentsSlice(MFrameArgumentsSlice* ins) {
4361 MOZ_ASSERT(ins->type() == MIRType::Object);
4362 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4363 MOZ_ASSERT(ins->count()->type() == MIRType::Int32);
4365 auto* lir = new (alloc()) LFrameArgumentsSlice(
4366 useRegister(ins->begin()), useRegister(ins->count()), temp());
4367 define(lir, ins);
4368 assignSafepoint(lir, ins);
4371 void LIRGenerator::visitInlineArgumentsSlice(MInlineArgumentsSlice* ins) {
4372 LAllocation begin = useRegisterOrConstant(ins->begin());
4373 LAllocation count = useRegisterOrConstant(ins->count());
4374 uint32_t numActuals = ins->numActuals();
4375 uint32_t numOperands =
4376 numActuals * BOX_PIECES + LInlineArgumentsSlice::NumNonArgumentOperands;
4378 auto* lir = allocateVariadic<LInlineArgumentsSlice>(numOperands, temp());
4379 if (!lir) {
4380 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitInlineArgumentsSlice");
4381 return;
4384 lir->setOperand(LInlineArgumentsSlice::Begin, begin);
4385 lir->setOperand(LInlineArgumentsSlice::Count, count);
4386 for (uint32_t i = 0; i < numActuals; i++) {
4387 MDefinition* arg = ins->getArg(i);
4388 uint32_t index = LInlineArgumentsSlice::ArgIndex(i);
4389 lir->setBoxOperand(index,
4390 useBoxOrTypedOrConstant(arg, /*useConstant = */ true));
4392 define(lir, ins);
4393 assignSafepoint(lir, ins);
4396 void LIRGenerator::visitNormalizeSliceTerm(MNormalizeSliceTerm* ins) {
4397 MOZ_ASSERT(ins->type() == MIRType::Int32);
4398 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4399 MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
4401 auto* lir = new (alloc()) LNormalizeSliceTerm(useRegister(ins->value()),
4402 useRegister(ins->length()));
4403 define(lir, ins);
4406 void LIRGenerator::visitArrayJoin(MArrayJoin* ins) {
4407 MOZ_ASSERT(ins->type() == MIRType::String);
4408 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
4409 MOZ_ASSERT(ins->sep()->type() == MIRType::String);
4411 auto* lir = new (alloc())
4412 LArrayJoin(useRegisterAtStart(ins->array()),
4413 useRegisterAtStart(ins->sep()), tempFixed(CallTempReg0));
4414 defineReturn(lir, ins);
4415 assignSafepoint(lir, ins);
4418 void LIRGenerator::visitObjectKeys(MObjectKeys* ins) {
4419 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4420 MOZ_ASSERT(ins->type() == MIRType::Object);
4422 auto* lir = new (alloc()) LObjectKeys(useRegisterAtStart(ins->object()));
4423 defineReturn(lir, ins);
4424 assignSafepoint(lir, ins);
4427 void LIRGenerator::visitObjectKeysLength(MObjectKeysLength* ins) {
4428 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4429 MOZ_ASSERT(ins->type() == MIRType::Int32);
4431 auto* lir =
4432 new (alloc()) LObjectKeysLength(useRegisterAtStart(ins->object()));
4433 defineReturn(lir, ins);
4434 assignSafepoint(lir, ins);
4437 void LIRGenerator::visitStringSplit(MStringSplit* ins) {
4438 MOZ_ASSERT(ins->type() == MIRType::Object);
4439 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4440 MOZ_ASSERT(ins->separator()->type() == MIRType::String);
4442 LStringSplit* lir = new (alloc()) LStringSplit(
4443 useRegisterAtStart(ins->string()), useRegisterAtStart(ins->separator()));
4444 defineReturn(lir, ins);
4445 assignSafepoint(lir, ins);
4448 void LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) {
4449 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4450 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4451 MOZ_ASSERT(IsNumericType(ins->type()) || ins->type() == MIRType::Boolean);
4453 auto sync = SynchronizeLoad(ins->requiresMemoryBarrier());
4455 if (Scalar::isBigIntType(ins->storageType()) && !sync.isNone()) {
4456 lowerAtomicLoad64(ins);
4457 return;
4460 const LUse elements = useRegister(ins->elements());
4461 const LAllocation index = useRegisterOrIndexConstant(
4462 ins->index(), ins->storageType(), ins->offsetAdjustment());
4464 // NOTE: the generated code must match the assembly code in gen_load in
4465 // GenerateAtomicOperations.py
4466 if (!sync.isNone()) {
4467 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
4468 add(fence, ins);
4471 if (!Scalar::isBigIntType(ins->storageType())) {
4472 // We need a temp register for Uint32Array with known double result.
4473 LDefinition tempDef = LDefinition::BogusTemp();
4474 if (ins->storageType() == Scalar::Uint32 &&
4475 IsFloatingPointType(ins->type())) {
4476 tempDef = temp();
4479 auto* lir = new (alloc()) LLoadUnboxedScalar(elements, index, tempDef);
4480 if (ins->fallible()) {
4481 assignSnapshot(lir, ins->bailoutKind());
4483 define(lir, ins);
4484 } else {
4485 MOZ_ASSERT(ins->type() == MIRType::BigInt);
4487 auto* lir =
4488 new (alloc()) LLoadUnboxedBigInt(elements, index, temp(), tempInt64());
4489 define(lir, ins);
4490 assignSafepoint(lir, ins);
4493 if (!sync.isNone()) {
4494 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
4495 add(fence, ins);
4499 void LIRGenerator::visitLoadDataViewElement(MLoadDataViewElement* ins) {
4500 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4501 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4503 MOZ_ASSERT(IsNumericType(ins->type()));
4505 const LUse elements = useRegister(ins->elements());
4506 const LUse index = useRegister(ins->index());
4507 const LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
4509 // We need a temp register for:
4510 // - Uint32Array with known double result,
4511 // - Float32Array,
4512 // - and BigInt64Array and BigUint64Array.
4513 LDefinition tempDef = LDefinition::BogusTemp();
4514 if ((ins->storageType() == Scalar::Uint32 &&
4515 IsFloatingPointType(ins->type())) ||
4516 ins->storageType() == Scalar::Float32) {
4517 tempDef = temp();
4519 if (Scalar::isBigIntType(ins->storageType())) {
4520 #ifdef JS_CODEGEN_X86
4521 // There are not enough registers on x86.
4522 if (littleEndian.isConstant()) {
4523 tempDef = temp();
4525 #else
4526 tempDef = temp();
4527 #endif
4530 // We also need a separate 64-bit temp register for:
4531 // - Float64Array
4532 // - and BigInt64Array and BigUint64Array.
4533 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
4534 if (Scalar::byteSize(ins->storageType()) == 8) {
4535 temp64Def = tempInt64();
4538 auto* lir = new (alloc())
4539 LLoadDataViewElement(elements, index, littleEndian, tempDef, temp64Def);
4540 if (ins->fallible()) {
4541 assignSnapshot(lir, ins->bailoutKind());
4543 define(lir, ins);
4544 if (Scalar::isBigIntType(ins->storageType())) {
4545 assignSafepoint(lir, ins);
4549 void LIRGenerator::visitClampToUint8(MClampToUint8* ins) {
4550 MDefinition* in = ins->input();
4552 switch (in->type()) {
4553 case MIRType::Boolean:
4554 redefine(ins, in);
4555 break;
4557 case MIRType::Int32:
4558 defineReuseInput(new (alloc()) LClampIToUint8(useRegisterAtStart(in)),
4559 ins, 0);
4560 break;
4562 case MIRType::Double:
4563 // LClampDToUint8 clobbers its input register. Making it available as
4564 // a temp copy describes this behavior to the register allocator.
4565 define(new (alloc())
4566 LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)),
4567 ins);
4568 break;
4570 case MIRType::Value: {
4571 LClampVToUint8* lir =
4572 new (alloc()) LClampVToUint8(useBox(in), tempDouble());
4573 assignSnapshot(lir, ins->bailoutKind());
4574 define(lir, ins);
4575 assignSafepoint(lir, ins);
4576 break;
4579 default:
4580 MOZ_CRASH("unexpected type");
4584 void LIRGenerator::visitLoadTypedArrayElementHole(
4585 MLoadTypedArrayElementHole* ins) {
4586 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4587 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4588 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr);
4590 MOZ_ASSERT(ins->type() == MIRType::Value);
4592 const LUse elements = useRegister(ins->elements());
4593 const LAllocation index = useRegister(ins->index());
4594 const LAllocation length = useRegister(ins->length());
4596 if (!Scalar::isBigIntType(ins->arrayType())) {
4597 auto* lir =
4598 new (alloc()) LLoadTypedArrayElementHole(elements, index, length);
4599 if (ins->fallible()) {
4600 assignSnapshot(lir, ins->bailoutKind());
4602 defineBox(lir, ins);
4603 } else {
4604 #ifdef JS_CODEGEN_X86
4605 LInt64Definition temp64 = LInt64Definition::BogusTemp();
4606 #else
4607 LInt64Definition temp64 = tempInt64();
4608 #endif
4610 auto* lir = new (alloc()) LLoadTypedArrayElementHoleBigInt(
4611 elements, index, length, temp(), temp64);
4612 defineBox(lir, ins);
4613 assignSafepoint(lir, ins);
4617 void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) {
4618 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4619 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4621 if (ins->isFloatWrite()) {
4622 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
4623 ins->value()->type() == MIRType::Float32);
4624 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
4625 ins->value()->type() == MIRType::Double);
4626 } else if (ins->isBigIntWrite()) {
4627 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4628 } else {
4629 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4632 auto sync = SynchronizeStore(ins->requiresMemoryBarrier());
4634 if (ins->isBigIntWrite() && !sync.isNone()) {
4635 lowerAtomicStore64(ins);
4636 return;
4639 LUse elements = useRegister(ins->elements());
4640 LAllocation index =
4641 useRegisterOrIndexConstant(ins->index(), ins->writeType());
4642 LAllocation value;
4644 // For byte arrays, the value has to be in a byte register on x86.
4645 if (ins->isByteWrite()) {
4646 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
4647 } else if (ins->isBigIntWrite()) {
4648 value = useRegister(ins->value());
4649 } else {
4650 value = useRegisterOrNonDoubleConstant(ins->value());
4653 // Optimization opportunity for atomics: on some platforms there
4654 // is a store instruction that incorporates the necessary
4655 // barriers, and we could use that instead of separate barrier and
4656 // store instructions. See bug #1077027.
4658 // NOTE: the generated code must match the assembly code in gen_store in
4659 // GenerateAtomicOperations.py
4660 if (!sync.isNone()) {
4661 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
4662 add(fence, ins);
4664 if (!ins->isBigIntWrite()) {
4665 add(new (alloc()) LStoreUnboxedScalar(elements, index, value), ins);
4666 } else {
4667 add(new (alloc()) LStoreUnboxedBigInt(elements, index, value, tempInt64()),
4668 ins);
4670 if (!sync.isNone()) {
4671 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
4672 add(fence, ins);
4676 void LIRGenerator::visitStoreDataViewElement(MStoreDataViewElement* ins) {
4677 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4678 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4679 MOZ_ASSERT(ins->littleEndian()->type() == MIRType::Boolean);
4681 if (ins->isFloatWrite()) {
4682 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
4683 ins->value()->type() == MIRType::Float32);
4684 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
4685 ins->value()->type() == MIRType::Double);
4686 } else if (ins->isBigIntWrite()) {
4687 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4688 } else {
4689 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4692 LUse elements = useRegister(ins->elements());
4693 LUse index = useRegister(ins->index());
4694 LAllocation value;
4695 if (ins->isBigIntWrite()) {
4696 value = useRegister(ins->value());
4697 } else {
4698 value = useRegisterOrNonDoubleConstant(ins->value());
4700 LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
4702 LDefinition tempDef = LDefinition::BogusTemp();
4703 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
4704 if (Scalar::byteSize(ins->writeType()) < 8) {
4705 tempDef = temp();
4706 } else {
4707 temp64Def = tempInt64();
4710 add(new (alloc()) LStoreDataViewElement(elements, index, value, littleEndian,
4711 tempDef, temp64Def),
4712 ins);
4715 void LIRGenerator::visitStoreTypedArrayElementHole(
4716 MStoreTypedArrayElementHole* ins) {
4717 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4718 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4719 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr);
4721 if (ins->isFloatWrite()) {
4722 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32,
4723 ins->value()->type() == MIRType::Float32);
4724 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64,
4725 ins->value()->type() == MIRType::Double);
4726 } else if (ins->isBigIntWrite()) {
4727 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4728 } else {
4729 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4732 LUse elements = useRegister(ins->elements());
4733 LAllocation length = useAny(ins->length());
4734 LAllocation index = useRegister(ins->index());
4736 // For byte arrays, the value has to be in a byte register on x86.
4737 LAllocation value;
4738 if (ins->isByteWrite()) {
4739 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
4740 } else if (ins->isBigIntWrite()) {
4741 value = useRegister(ins->value());
4742 } else {
4743 value = useRegisterOrNonDoubleConstant(ins->value());
4746 if (!ins->isBigIntWrite()) {
4747 LDefinition spectreTemp =
4748 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4749 auto* lir = new (alloc()) LStoreTypedArrayElementHole(
4750 elements, length, index, value, spectreTemp);
4751 add(lir, ins);
4752 } else {
4753 auto* lir = new (alloc()) LStoreTypedArrayElementHoleBigInt(
4754 elements, length, index, value, tempInt64());
4755 add(lir, ins);
4759 void LIRGenerator::visitLoadScriptedProxyHandler(
4760 MLoadScriptedProxyHandler* ins) {
4761 LLoadScriptedProxyHandler* lir = new (alloc())
4762 LLoadScriptedProxyHandler(useRegisterAtStart(ins->object()));
4763 assignSnapshot(lir, ins->bailoutKind());
4764 define(lir, ins);
4767 void LIRGenerator::visitIdToStringOrSymbol(MIdToStringOrSymbol* ins) {
4768 LIdToStringOrSymbol* lir =
4769 new (alloc()) LIdToStringOrSymbol(useBoxAtStart(ins->idVal()), temp());
4770 assignSnapshot(lir, ins->bailoutKind());
4771 defineBox(lir, ins);
4772 assignSafepoint(lir, ins);
4775 void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins) {
4776 MDefinition* obj = ins->object();
4777 MOZ_ASSERT(obj->type() == MIRType::Object);
4779 MIRType type = ins->type();
4781 if (type == MIRType::Value) {
4782 if (ins->usedAsPropertyKey()) {
4783 LLoadFixedSlotAndAtomize* lir =
4784 new (alloc()) LLoadFixedSlotAndAtomize(useRegister(obj), temp());
4785 defineBox(lir, ins);
4786 assignSafepoint(lir, ins);
4787 } else {
4788 LLoadFixedSlotV* lir =
4789 new (alloc()) LLoadFixedSlotV(useRegisterAtStart(obj));
4790 defineBox(lir, ins);
4792 } else {
4793 LLoadFixedSlotT* lir =
4794 new (alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj, type));
4795 define(lir, ins);
4799 void LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) {
4800 MDefinition* obj = ins->object();
4801 MOZ_ASSERT(obj->type() == MIRType::Object);
4803 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) {
4804 LLoadFixedSlotUnboxAndAtomize* lir =
4805 new (alloc()) LLoadFixedSlotUnboxAndAtomize(useRegister(obj));
4806 if (ins->fallible()) {
4807 assignSnapshot(lir, ins->bailoutKind());
4809 define(lir, ins);
4810 assignSafepoint(lir, ins);
4811 } else {
4812 LLoadFixedSlotAndUnbox* lir =
4813 new (alloc()) LLoadFixedSlotAndUnbox(useRegisterAtStart(obj));
4814 if (ins->fallible()) {
4815 assignSnapshot(lir, ins->bailoutKind());
4817 define(lir, ins);
4821 void LIRGenerator::visitLoadDynamicSlotAndUnbox(MLoadDynamicSlotAndUnbox* ins) {
4822 MDefinition* slots = ins->slots();
4823 MOZ_ASSERT(slots->type() == MIRType::Slots);
4825 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) {
4826 auto* lir =
4827 new (alloc()) LLoadDynamicSlotUnboxAndAtomize(useRegister(slots));
4828 if (ins->fallible()) {
4829 assignSnapshot(lir, ins->bailoutKind());
4831 define(lir, ins);
4832 assignSafepoint(lir, ins);
4833 } else {
4834 auto* lir =
4835 new (alloc()) LLoadDynamicSlotAndUnbox(useRegisterAtStart(slots));
4836 if (ins->fallible()) {
4837 assignSnapshot(lir, ins->bailoutKind());
4839 define(lir, ins);
4843 void LIRGenerator::visitLoadElementAndUnbox(MLoadElementAndUnbox* ins) {
4844 MDefinition* elements = ins->elements();
4845 MDefinition* index = ins->index();
4846 MOZ_ASSERT(elements->type() == MIRType::Elements);
4847 MOZ_ASSERT(index->type() == MIRType::Int32);
4849 auto* lir = new (alloc())
4850 LLoadElementAndUnbox(useRegister(elements), useRegisterOrConstant(index));
4851 if (ins->fallible()) {
4852 assignSnapshot(lir, ins->bailoutKind());
4854 define(lir, ins);
4857 void LIRGenerator::visitAddAndStoreSlot(MAddAndStoreSlot* ins) {
4858 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4860 LDefinition maybeTemp = LDefinition::BogusTemp();
4861 if (ins->kind() != MAddAndStoreSlot::Kind::FixedSlot) {
4862 maybeTemp = temp();
4865 auto* lir = new (alloc()) LAddAndStoreSlot(useRegister(ins->object()),
4866 useBox(ins->value()), maybeTemp);
4867 add(lir, ins);
4870 void LIRGenerator::visitAllocateAndStoreSlot(MAllocateAndStoreSlot* ins) {
4871 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4873 auto* lir = new (alloc()) LAllocateAndStoreSlot(
4874 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()),
4875 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
4876 assignSnapshot(lir, ins->bailoutKind());
4877 add(lir, ins);
4880 void LIRGenerator::visitAddSlotAndCallAddPropHook(
4881 MAddSlotAndCallAddPropHook* ins) {
4882 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4883 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4885 auto* lir = new (alloc()) LAddSlotAndCallAddPropHook(
4886 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()));
4887 add(lir, ins);
4888 assignSafepoint(lir, ins);
4891 void LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins) {
4892 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4894 if (ins->value()->type() == MIRType::Value) {
4895 LStoreFixedSlotV* lir = new (alloc())
4896 LStoreFixedSlotV(useRegister(ins->object()), useBox(ins->value()));
4897 add(lir, ins);
4898 } else {
4899 LStoreFixedSlotT* lir = new (alloc()) LStoreFixedSlotT(
4900 useRegister(ins->object()), useRegisterOrConstant(ins->value()));
4901 add(lir, ins);
4905 void LIRGenerator::visitGetNameCache(MGetNameCache* ins) {
4906 MOZ_ASSERT(ins->envObj()->type() == MIRType::Object);
4908 // Emit an overrecursed check: this is necessary because the cache can
4909 // attach a scripted getter stub that calls this script recursively.
4910 gen->setNeedsOverrecursedCheck();
4912 LGetNameCache* lir =
4913 new (alloc()) LGetNameCache(useRegister(ins->envObj()), temp());
4914 defineBox(lir, ins);
4915 assignSafepoint(lir, ins);
4918 void LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins) {
4919 LCallGetIntrinsicValue* lir = new (alloc()) LCallGetIntrinsicValue();
4920 defineReturn(lir, ins);
4921 assignSafepoint(lir, ins);
4924 void LIRGenerator::visitGetPropSuperCache(MGetPropSuperCache* ins) {
4925 MDefinition* obj = ins->object();
4926 MDefinition* receiver = ins->receiver();
4927 MDefinition* id = ins->idval();
4929 gen->setNeedsOverrecursedCheck();
4931 bool useConstId =
4932 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4934 auto* lir = new (alloc())
4935 LGetPropSuperCache(useRegister(obj), useBoxOrTyped(receiver),
4936 useBoxOrTypedOrConstant(id, useConstId));
4937 defineBox(lir, ins);
4938 assignSafepoint(lir, ins);
4941 void LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) {
4942 MDefinition* value = ins->value();
4943 MOZ_ASSERT(value->type() == MIRType::Object ||
4944 value->type() == MIRType::Value);
4946 MDefinition* id = ins->idval();
4947 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
4948 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
4950 // Emit an overrecursed check: this is necessary because the cache can
4951 // attach a scripted getter stub that calls this script recursively.
4952 gen->setNeedsOverrecursedCheck();
4954 // If this is a GetProp, the id is a constant string. Allow passing it as a
4955 // constant to reduce register allocation pressure.
4956 bool useConstId =
4957 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4959 auto* lir = new (alloc()) LGetPropertyCache(
4960 useBoxOrTyped(value), useBoxOrTypedOrConstant(id, useConstId));
4961 defineBox(lir, ins);
4962 assignSafepoint(lir, ins);
4965 void LIRGenerator::visitBindNameCache(MBindNameCache* ins) {
4966 MOZ_ASSERT(ins->envChain()->type() == MIRType::Object);
4967 MOZ_ASSERT(ins->type() == MIRType::Object);
4969 LBindNameCache* lir =
4970 new (alloc()) LBindNameCache(useRegister(ins->envChain()), temp());
4971 define(lir, ins);
4972 assignSafepoint(lir, ins);
4975 void LIRGenerator::visitCallBindVar(MCallBindVar* ins) {
4976 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
4977 MOZ_ASSERT(ins->type() == MIRType::Object);
4979 LCallBindVar* lir =
4980 new (alloc()) LCallBindVar(useRegister(ins->environmentChain()));
4981 define(lir, ins);
4984 void LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins) {
4985 LGuardObjectIdentity* guard = new (alloc()) LGuardObjectIdentity(
4986 useRegister(ins->object()), useRegister(ins->expected()));
4987 assignSnapshot(guard, ins->bailoutKind());
4988 add(guard, ins);
4989 redefine(ins, ins->object());
4992 void LIRGenerator::visitGuardSpecificFunction(MGuardSpecificFunction* ins) {
4993 auto* guard = new (alloc()) LGuardSpecificFunction(
4994 useRegister(ins->function()), useRegister(ins->expected()));
4995 assignSnapshot(guard, ins->bailoutKind());
4996 add(guard, ins);
4997 redefine(ins, ins->function());
5000 void LIRGenerator::visitGuardSpecificAtom(MGuardSpecificAtom* ins) {
5001 auto* guard =
5002 new (alloc()) LGuardSpecificAtom(useRegister(ins->str()), temp());
5003 assignSnapshot(guard, ins->bailoutKind());
5004 add(guard, ins);
5005 redefine(ins, ins->str());
5006 assignSafepoint(guard, ins);
5009 void LIRGenerator::visitGuardSpecificSymbol(MGuardSpecificSymbol* ins) {
5010 auto* guard = new (alloc()) LGuardSpecificSymbol(useRegister(ins->symbol()));
5011 assignSnapshot(guard, ins->bailoutKind());
5012 add(guard, ins);
5013 redefine(ins, ins->symbol());
5016 void LIRGenerator::visitGuardSpecificInt32(MGuardSpecificInt32* ins) {
5017 auto* guard = new (alloc()) LGuardSpecificInt32(useRegister(ins->num()));
5018 assignSnapshot(guard, ins->bailoutKind());
5019 add(guard, ins);
5020 redefine(ins, ins->num());
5023 void LIRGenerator::visitGuardStringToIndex(MGuardStringToIndex* ins) {
5024 MOZ_ASSERT(ins->string()->type() == MIRType::String);
5025 auto* guard = new (alloc()) LGuardStringToIndex(useRegister(ins->string()));
5026 assignSnapshot(guard, ins->bailoutKind());
5027 define(guard, ins);
5028 assignSafepoint(guard, ins);
5031 void LIRGenerator::visitGuardStringToInt32(MGuardStringToInt32* ins) {
5032 MOZ_ASSERT(ins->string()->type() == MIRType::String);
5033 auto* guard =
5034 new (alloc()) LGuardStringToInt32(useRegister(ins->string()), temp());
5035 assignSnapshot(guard, ins->bailoutKind());
5036 define(guard, ins);
5037 assignSafepoint(guard, ins);
5040 void LIRGenerator::visitGuardStringToDouble(MGuardStringToDouble* ins) {
5041 MOZ_ASSERT(ins->string()->type() == MIRType::String);
5042 auto* guard = new (alloc())
5043 LGuardStringToDouble(useRegister(ins->string()), temp(), temp());
5044 assignSnapshot(guard, ins->bailoutKind());
5045 define(guard, ins);
5046 assignSafepoint(guard, ins);
5049 void LIRGenerator::visitGuardNoDenseElements(MGuardNoDenseElements* ins) {
5050 auto* guard =
5051 new (alloc()) LGuardNoDenseElements(useRegister(ins->object()), temp());
5052 assignSnapshot(guard, ins->bailoutKind());
5053 add(guard, ins);
5054 redefine(ins, ins->object());
5057 void LIRGenerator::visitGuardShape(MGuardShape* ins) {
5058 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5060 if (JitOptions.spectreObjectMitigations) {
5061 auto* lir =
5062 new (alloc()) LGuardShape(useRegisterAtStart(ins->object()), temp());
5063 assignSnapshot(lir, ins->bailoutKind());
5064 defineReuseInput(lir, ins, 0);
5065 } else {
5066 auto* lir = new (alloc())
5067 LGuardShape(useRegister(ins->object()), LDefinition::BogusTemp());
5068 assignSnapshot(lir, ins->bailoutKind());
5069 add(lir, ins);
5070 redefine(ins, ins->object());
5074 void LIRGenerator::visitGuardMultipleShapes(MGuardMultipleShapes* ins) {
5075 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5077 if (JitOptions.spectreObjectMitigations) {
5078 auto* lir = new (alloc()) LGuardMultipleShapes(
5079 useRegisterAtStart(ins->object()), useRegister(ins->shapeList()),
5080 temp(), temp(), temp(), temp());
5081 assignSnapshot(lir, ins->bailoutKind());
5082 defineReuseInput(lir, ins, 0);
5083 } else {
5084 auto* lir = new (alloc()) LGuardMultipleShapes(
5085 useRegister(ins->object()), useRegister(ins->shapeList()), temp(),
5086 temp(), temp(), LDefinition::BogusTemp());
5087 assignSnapshot(lir, ins->bailoutKind());
5088 add(lir, ins);
5089 redefine(ins, ins->object());
5093 void LIRGenerator::visitGuardProto(MGuardProto* ins) {
5094 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5095 MOZ_ASSERT(ins->expected()->type() == MIRType::Object);
5097 auto* lir = new (alloc()) LGuardProto(useRegister(ins->object()),
5098 useRegister(ins->expected()), temp());
5099 assignSnapshot(lir, ins->bailoutKind());
5100 add(lir, ins);
5101 redefine(ins, ins->object());
5104 void LIRGenerator::visitGuardNullProto(MGuardNullProto* ins) {
5105 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5107 auto* lir = new (alloc()) LGuardNullProto(useRegister(ins->object()), temp());
5108 assignSnapshot(lir, ins->bailoutKind());
5109 add(lir, ins);
5110 redefine(ins, ins->object());
5113 void LIRGenerator::visitGuardIsNativeObject(MGuardIsNativeObject* ins) {
5114 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5116 auto* lir =
5117 new (alloc()) LGuardIsNativeObject(useRegister(ins->object()), temp());
5118 assignSnapshot(lir, ins->bailoutKind());
5119 add(lir, ins);
5120 redefine(ins, ins->object());
5123 void LIRGenerator::visitGuardGlobalGeneration(MGuardGlobalGeneration* ins) {
5124 auto* lir = new (alloc()) LGuardGlobalGeneration(temp());
5125 assignSnapshot(lir, ins->bailoutKind());
5126 add(lir, ins);
5129 void LIRGenerator::visitGuardFuse(MGuardFuse* ins) {
5130 auto* lir = new (alloc()) LGuardFuse(temp());
5131 assignSnapshot(lir, ins->bailoutKind());
5132 add(lir, ins);
5135 void LIRGenerator::visitGuardIsProxy(MGuardIsProxy* ins) {
5136 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5138 auto* lir = new (alloc()) LGuardIsProxy(useRegister(ins->object()), temp());
5139 assignSnapshot(lir, ins->bailoutKind());
5140 add(lir, ins);
5141 redefine(ins, ins->object());
5144 void LIRGenerator::visitGuardIsNotProxy(MGuardIsNotProxy* ins) {
5145 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5147 auto* lir =
5148 new (alloc()) LGuardIsNotProxy(useRegister(ins->object()), temp());
5149 assignSnapshot(lir, ins->bailoutKind());
5150 add(lir, ins);
5151 redefine(ins, ins->object());
5154 void LIRGenerator::visitGuardIsNotDOMProxy(MGuardIsNotDOMProxy* ins) {
5155 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5157 auto* lir =
5158 new (alloc()) LGuardIsNotDOMProxy(useRegister(ins->proxy()), temp());
5159 assignSnapshot(lir, ins->bailoutKind());
5160 add(lir, ins);
5161 redefine(ins, ins->proxy());
5164 void LIRGenerator::visitProxyGet(MProxyGet* ins) {
5165 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5166 auto* lir = new (alloc())
5167 LProxyGet(useRegisterAtStart(ins->proxy()), tempFixed(CallTempReg0));
5168 defineReturn(lir, ins);
5169 assignSafepoint(lir, ins);
5172 void LIRGenerator::visitProxyGetByValue(MProxyGetByValue* ins) {
5173 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5174 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5175 auto* lir = new (alloc()) LProxyGetByValue(useRegisterAtStart(ins->proxy()),
5176 useBoxAtStart(ins->idVal()));
5177 defineReturn(lir, ins);
5178 assignSafepoint(lir, ins);
5181 void LIRGenerator::visitProxyHasProp(MProxyHasProp* ins) {
5182 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5183 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5184 auto* lir = new (alloc()) LProxyHasProp(useRegisterAtStart(ins->proxy()),
5185 useBoxAtStart(ins->idVal()));
5186 defineReturn(lir, ins);
5187 assignSafepoint(lir, ins);
5190 void LIRGenerator::visitProxySet(MProxySet* ins) {
5191 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5192 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5193 auto* lir = new (alloc())
5194 LProxySet(useRegisterAtStart(ins->proxy()), useBoxAtStart(ins->rhs()),
5195 tempFixed(CallTempReg0));
5196 add(lir, ins);
5197 assignSafepoint(lir, ins);
5200 void LIRGenerator::visitProxySetByValue(MProxySetByValue* ins) {
5201 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5202 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5203 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5204 auto* lir = new (alloc())
5205 LProxySetByValue(useRegisterAtStart(ins->proxy()),
5206 useBoxAtStart(ins->idVal()), useBoxAtStart(ins->rhs()));
5207 add(lir, ins);
5208 assignSafepoint(lir, ins);
5211 void LIRGenerator::visitCallSetArrayLength(MCallSetArrayLength* ins) {
5212 MOZ_ASSERT(ins->obj()->type() == MIRType::Object);
5213 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5214 auto* lir = new (alloc()) LCallSetArrayLength(useRegisterAtStart(ins->obj()),
5215 useBoxAtStart(ins->rhs()));
5216 add(lir, ins);
5217 assignSafepoint(lir, ins);
5220 void LIRGenerator::visitMegamorphicLoadSlot(MMegamorphicLoadSlot* ins) {
5221 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5222 auto* lir = new (alloc())
5223 LMegamorphicLoadSlot(useRegisterAtStart(ins->object()),
5224 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5225 tempFixed(CallTempReg2), tempFixed(CallTempReg3));
5226 assignSnapshot(lir, ins->bailoutKind());
5227 defineReturn(lir, ins);
5230 void LIRGenerator::visitMegamorphicLoadSlotByValue(
5231 MMegamorphicLoadSlotByValue* ins) {
5232 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5233 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5234 auto* lir = new (alloc()) LMegamorphicLoadSlotByValue(
5235 useRegisterAtStart(ins->object()), useBoxAtStart(ins->idVal()),
5236 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5237 tempFixed(CallTempReg2));
5238 assignSnapshot(lir, ins->bailoutKind());
5239 defineReturn(lir, ins);
5242 void LIRGenerator::visitMegamorphicStoreSlot(MMegamorphicStoreSlot* ins) {
5243 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5244 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5246 #ifdef JS_CODEGEN_X86
5247 auto* lir = new (alloc()) LMegamorphicStoreSlot(
5248 useFixedAtStart(ins->object(), CallTempReg0),
5249 useBoxFixedAtStart(ins->rhs(), CallTempReg1, CallTempReg2),
5250 tempFixed(CallTempReg5));
5251 #else
5252 auto* lir = new (alloc())
5253 LMegamorphicStoreSlot(useRegisterAtStart(ins->object()),
5254 useBoxAtStart(ins->rhs()), tempFixed(CallTempReg0),
5255 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5256 #endif
5258 add(lir, ins);
5259 assignSafepoint(lir, ins);
5262 void LIRGenerator::visitMegamorphicHasProp(MMegamorphicHasProp* ins) {
5263 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5264 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5265 auto* lir = new (alloc())
5266 LMegamorphicHasProp(useRegisterAtStart(ins->object()),
5267 useBoxAtStart(ins->idVal()), tempFixed(CallTempReg0),
5268 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5269 assignSnapshot(lir, ins->bailoutKind());
5270 defineReturn(lir, ins);
5273 void LIRGenerator::visitSmallObjectVariableKeyHasProp(
5274 MSmallObjectVariableKeyHasProp* ins) {
5275 MOZ_ASSERT(ins->idStr()->type() == MIRType::String);
5276 auto* lir = new (alloc())
5277 LSmallObjectVariableKeyHasProp(useRegisterAtStart(ins->idStr()));
5278 define(lir, ins);
5279 assignSafepoint(lir, ins);
5282 void LIRGenerator::visitGuardIsNotArrayBufferMaybeShared(
5283 MGuardIsNotArrayBufferMaybeShared* ins) {
5284 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5286 auto* lir = new (alloc())
5287 LGuardIsNotArrayBufferMaybeShared(useRegister(ins->object()), temp());
5288 assignSnapshot(lir, ins->bailoutKind());
5289 add(lir, ins);
5290 redefine(ins, ins->object());
5293 void LIRGenerator::visitGuardIsTypedArray(MGuardIsTypedArray* ins) {
5294 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5296 auto* lir =
5297 new (alloc()) LGuardIsTypedArray(useRegister(ins->object()), temp());
5298 assignSnapshot(lir, ins->bailoutKind());
5299 add(lir, ins);
5300 redefine(ins, ins->object());
5303 void LIRGenerator::visitGuardIsFixedLengthTypedArray(
5304 MGuardIsFixedLengthTypedArray* ins) {
5305 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5307 auto* lir = new (alloc())
5308 LGuardIsFixedLengthTypedArray(useRegister(ins->object()), temp());
5309 assignSnapshot(lir, ins->bailoutKind());
5310 add(lir, ins);
5311 redefine(ins, ins->object());
5314 void LIRGenerator::visitGuardIsResizableTypedArray(
5315 MGuardIsResizableTypedArray* ins) {
5316 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5318 auto* lir = new (alloc())
5319 LGuardIsResizableTypedArray(useRegister(ins->object()), temp());
5320 assignSnapshot(lir, ins->bailoutKind());
5321 add(lir, ins);
5322 redefine(ins, ins->object());
5325 void LIRGenerator::visitGuardHasProxyHandler(MGuardHasProxyHandler* ins) {
5326 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5328 auto* lir = new (alloc()) LGuardHasProxyHandler(useRegister(ins->object()));
5329 assignSnapshot(lir, ins->bailoutKind());
5330 add(lir, ins);
5331 redefine(ins, ins->object());
5334 void LIRGenerator::visitNurseryObject(MNurseryObject* ins) {
5335 MOZ_ASSERT(ins->type() == MIRType::Object);
5337 auto* lir = new (alloc()) LNurseryObject();
5338 define(lir, ins);
5341 void LIRGenerator::visitGuardValue(MGuardValue* ins) {
5342 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5343 auto* lir = new (alloc()) LGuardValue(useBox(ins->value()));
5344 assignSnapshot(lir, ins->bailoutKind());
5345 add(lir, ins);
5346 redefine(ins, ins->value());
5349 void LIRGenerator::visitGuardNullOrUndefined(MGuardNullOrUndefined* ins) {
5350 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5351 auto* lir = new (alloc()) LGuardNullOrUndefined(useBox(ins->value()));
5352 assignSnapshot(lir, ins->bailoutKind());
5353 add(lir, ins);
5354 redefine(ins, ins->value());
5357 void LIRGenerator::visitGuardIsNotObject(MGuardIsNotObject* ins) {
5358 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5359 auto* lir = new (alloc()) LGuardIsNotObject(useBox(ins->value()));
5360 assignSnapshot(lir, ins->bailoutKind());
5361 add(lir, ins);
5362 redefine(ins, ins->value());
5365 void LIRGenerator::visitGuardFunctionFlags(MGuardFunctionFlags* ins) {
5366 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5368 auto* lir = new (alloc()) LGuardFunctionFlags(useRegister(ins->function()));
5369 assignSnapshot(lir, ins->bailoutKind());
5370 add(lir, ins);
5371 redefine(ins, ins->function());
5374 void LIRGenerator::visitGuardFunctionIsNonBuiltinCtor(
5375 MGuardFunctionIsNonBuiltinCtor* ins) {
5376 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5378 auto* lir = new (alloc())
5379 LGuardFunctionIsNonBuiltinCtor(useRegister(ins->function()), temp());
5380 assignSnapshot(lir, ins->bailoutKind());
5381 add(lir, ins);
5382 redefine(ins, ins->function());
5385 void LIRGenerator::visitGuardFunctionKind(MGuardFunctionKind* ins) {
5386 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5388 auto* lir =
5389 new (alloc()) LGuardFunctionKind(useRegister(ins->function()), temp());
5390 assignSnapshot(lir, ins->bailoutKind());
5391 add(lir, ins);
5392 redefine(ins, ins->function());
5395 void LIRGenerator::visitGuardFunctionScript(MGuardFunctionScript* ins) {
5396 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5398 auto* lir = new (alloc()) LGuardFunctionScript(useRegister(ins->function()));
5399 assignSnapshot(lir, ins->bailoutKind());
5400 add(lir, ins);
5401 redefine(ins, ins->function());
5404 void LIRGenerator::visitAssertRange(MAssertRange* ins) {
5405 MDefinition* input = ins->input();
5406 LInstruction* lir = nullptr;
5408 switch (input->type()) {
5409 case MIRType::Boolean:
5410 case MIRType::Int32:
5411 case MIRType::IntPtr:
5412 lir = new (alloc()) LAssertRangeI(useRegisterAtStart(input));
5413 break;
5415 case MIRType::Double:
5416 lir = new (alloc()) LAssertRangeD(useRegister(input), tempDouble());
5417 break;
5419 case MIRType::Float32:
5420 lir = new (alloc())
5421 LAssertRangeF(useRegister(input), tempDouble(), tempDouble());
5422 break;
5424 case MIRType::Value:
5425 lir = new (alloc()) LAssertRangeV(useBox(input), tempToUnbox(),
5426 tempDouble(), tempDouble());
5427 break;
5429 default:
5430 MOZ_CRASH("Unexpected Range for MIRType");
5431 break;
5434 lir->setMir(ins);
5435 add(lir);
5438 void LIRGenerator::visitAssertClass(MAssertClass* ins) {
5439 auto* lir =
5440 new (alloc()) LAssertClass(useRegisterAtStart(ins->input()), temp());
5441 add(lir, ins);
5444 void LIRGenerator::visitAssertShape(MAssertShape* ins) {
5445 auto* lir = new (alloc()) LAssertShape(useRegisterAtStart(ins->input()));
5446 add(lir, ins);
5449 void LIRGenerator::visitDeleteProperty(MDeleteProperty* ins) {
5450 LCallDeleteProperty* lir =
5451 new (alloc()) LCallDeleteProperty(useBoxAtStart(ins->value()));
5452 defineReturn(lir, ins);
5453 assignSafepoint(lir, ins);
5456 void LIRGenerator::visitDeleteElement(MDeleteElement* ins) {
5457 LCallDeleteElement* lir = new (alloc()) LCallDeleteElement(
5458 useBoxAtStart(ins->value()), useBoxAtStart(ins->index()));
5459 defineReturn(lir, ins);
5460 assignSafepoint(lir, ins);
5463 void LIRGenerator::visitObjectToIterator(MObjectToIterator* ins) {
5464 auto* lir = new (alloc())
5465 LObjectToIterator(useRegister(ins->object()), temp(), temp(), temp());
5466 define(lir, ins);
5467 assignSafepoint(lir, ins);
5470 void LIRGenerator::visitValueToIterator(MValueToIterator* ins) {
5471 auto* lir = new (alloc()) LValueToIterator(useBoxAtStart(ins->value()));
5472 defineReturn(lir, ins);
5473 assignSafepoint(lir, ins);
5476 void LIRGenerator::visitLoadSlotByIteratorIndex(MLoadSlotByIteratorIndex* ins) {
5477 auto* lir = new (alloc()) LLoadSlotByIteratorIndex(
5478 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->iterator()),
5479 temp(), temp());
5480 defineBox(lir, ins);
5483 void LIRGenerator::visitStoreSlotByIteratorIndex(
5484 MStoreSlotByIteratorIndex* ins) {
5485 auto* lir = new (alloc()) LStoreSlotByIteratorIndex(
5486 useRegister(ins->object()), useRegister(ins->iterator()),
5487 useBox(ins->value()), temp(), temp());
5488 add(lir, ins);
5491 void LIRGenerator::visitIteratorHasIndices(MIteratorHasIndices* ins) {
5492 MOZ_ASSERT(ins->hasOneUse());
5493 emitAtUses(ins);
5496 void LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) {
5497 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5499 MDefinition* id = ins->idval();
5500 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5501 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5503 // If this is a SetProp, the id is a constant string. Allow passing it as a
5504 // constant to reduce register allocation pressure.
5505 bool useConstId =
5506 id->type() == MIRType::String || id->type() == MIRType::Symbol;
5507 bool useConstValue = IsNonNurseryConstant(ins->value());
5509 // Emit an overrecursed check: this is necessary because the cache can
5510 // attach a scripted setter stub that calls this script recursively.
5511 gen->setNeedsOverrecursedCheck();
5513 // We need a double temp register for TypedArray stubs.
5514 LDefinition tempD = tempFixed(FloatReg0);
5516 LInstruction* lir = new (alloc()) LSetPropertyCache(
5517 useRegister(ins->object()), useBoxOrTypedOrConstant(id, useConstId),
5518 useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD);
5519 add(lir, ins);
5520 assignSafepoint(lir, ins);
5523 void LIRGenerator::visitMegamorphicSetElement(MMegamorphicSetElement* ins) {
5524 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5525 MOZ_ASSERT(ins->index()->type() == MIRType::Value);
5526 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5528 // See comment in LIROps.yaml (x86 is short on registers)
5529 #ifdef JS_CODEGEN_X86
5530 auto* lir = new (alloc()) LMegamorphicSetElement(
5531 useFixedAtStart(ins->object(), CallTempReg0),
5532 useBoxFixedAtStart(ins->index(), CallTempReg1, CallTempReg2),
5533 useBoxFixedAtStart(ins->value(), CallTempReg3, CallTempReg4),
5534 tempFixed(CallTempReg5));
5535 #else
5536 auto* lir = new (alloc()) LMegamorphicSetElement(
5537 useRegisterAtStart(ins->object()), useBoxAtStart(ins->index()),
5538 useBoxAtStart(ins->value()), tempFixed(CallTempReg0),
5539 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5540 #endif
5541 add(lir, ins);
5542 assignSafepoint(lir, ins);
5545 void LIRGenerator::visitGetIteratorCache(MGetIteratorCache* ins) {
5546 MDefinition* value = ins->value();
5547 MOZ_ASSERT(value->type() == MIRType::Object ||
5548 value->type() == MIRType::Value);
5550 LGetIteratorCache* lir =
5551 new (alloc()) LGetIteratorCache(useBoxOrTyped(value), temp(), temp());
5552 define(lir, ins);
5553 assignSafepoint(lir, ins);
5556 void LIRGenerator::visitOptimizeSpreadCallCache(MOptimizeSpreadCallCache* ins) {
5557 MDefinition* value = ins->value();
5558 MOZ_ASSERT(value->type() == MIRType::Value);
5560 auto* lir = new (alloc()) LOptimizeSpreadCallCache(useBox(value), temp());
5561 defineBox(lir, ins);
5562 assignSafepoint(lir, ins);
5565 void LIRGenerator::visitIteratorMore(MIteratorMore* ins) {
5566 LIteratorMore* lir =
5567 new (alloc()) LIteratorMore(useRegister(ins->iterator()), temp());
5568 defineBox(lir, ins);
5571 void LIRGenerator::visitIsNoIter(MIsNoIter* ins) {
5572 MOZ_ASSERT(ins->hasOneUse());
5573 emitAtUses(ins);
5576 void LIRGenerator::visitIteratorEnd(MIteratorEnd* ins) {
5577 LIteratorEnd* lir = new (alloc())
5578 LIteratorEnd(useRegister(ins->iterator()), temp(), temp(), temp());
5579 add(lir, ins);
5582 void LIRGenerator::visitCloseIterCache(MCloseIterCache* ins) {
5583 LCloseIterCache* lir =
5584 new (alloc()) LCloseIterCache(useRegister(ins->iter()), temp());
5585 add(lir, ins);
5586 assignSafepoint(lir, ins);
5589 void LIRGenerator::visitOptimizeGetIteratorCache(
5590 MOptimizeGetIteratorCache* ins) {
5591 MDefinition* value = ins->value();
5592 MOZ_ASSERT(value->type() == MIRType::Value);
5594 auto* lir = new (alloc()) LOptimizeGetIteratorCache(useBox(value), temp());
5595 define(lir, ins);
5596 assignSafepoint(lir, ins);
5599 void LIRGenerator::visitStringLength(MStringLength* ins) {
5600 MOZ_ASSERT(ins->string()->type() == MIRType::String);
5601 define(new (alloc()) LStringLength(useRegisterAtStart(ins->string())), ins);
5604 void LIRGenerator::visitArgumentsLength(MArgumentsLength* ins) {
5605 define(new (alloc()) LArgumentsLength(), ins);
5608 void LIRGenerator::visitGetFrameArgument(MGetFrameArgument* ins) {
5609 LGetFrameArgument* lir =
5610 new (alloc()) LGetFrameArgument(useRegisterOrConstant(ins->index()));
5611 defineBox(lir, ins);
5614 void LIRGenerator::visitGetFrameArgumentHole(MGetFrameArgumentHole* ins) {
5615 LDefinition spectreTemp =
5616 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
5618 auto* lir = new (alloc()) LGetFrameArgumentHole(
5619 useRegister(ins->index()), useRegister(ins->length()), spectreTemp);
5620 assignSnapshot(lir, ins->bailoutKind());
5621 defineBox(lir, ins);
5624 void LIRGenerator::visitNewTarget(MNewTarget* ins) {
5625 LNewTarget* lir = new (alloc()) LNewTarget();
5626 defineBox(lir, ins);
5629 void LIRGenerator::visitRest(MRest* ins) {
5630 MOZ_ASSERT(ins->numActuals()->type() == MIRType::Int32);
5632 LRest* lir =
5633 new (alloc()) LRest(useRegisterAtStart(ins->numActuals()),
5634 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5635 tempFixed(CallTempReg2), tempFixed(CallTempReg3));
5636 defineReturn(lir, ins);
5637 assignSafepoint(lir, ins);
5640 void LIRGenerator::visitThrow(MThrow* ins) {
5641 MDefinition* value = ins->value();
5642 MOZ_ASSERT(value->type() == MIRType::Value);
5644 LThrow* lir = new (alloc()) LThrow(useBoxAtStart(value));
5645 add(lir, ins);
5646 assignSafepoint(lir, ins);
5649 void LIRGenerator::visitThrowWithStack(MThrowWithStack* ins) {
5650 MDefinition* value = ins->value();
5651 MOZ_ASSERT(value->type() == MIRType::Value);
5653 MDefinition* stack = ins->stack();
5654 MOZ_ASSERT(stack->type() == MIRType::Value);
5656 auto* lir =
5657 new (alloc()) LThrowWithStack(useBoxAtStart(value), useBoxAtStart(stack));
5658 add(lir, ins);
5659 assignSafepoint(lir, ins);
5662 void LIRGenerator::visitInCache(MInCache* ins) {
5663 MDefinition* lhs = ins->lhs();
5664 MDefinition* rhs = ins->rhs();
5666 MOZ_ASSERT(lhs->type() == MIRType::String || lhs->type() == MIRType::Symbol ||
5667 lhs->type() == MIRType::Int32 || lhs->type() == MIRType::Value);
5668 MOZ_ASSERT(rhs->type() == MIRType::Object);
5670 LInCache* lir =
5671 new (alloc()) LInCache(useBoxOrTyped(lhs), useRegister(rhs), temp());
5672 define(lir, ins);
5673 assignSafepoint(lir, ins);
5676 void LIRGenerator::visitHasOwnCache(MHasOwnCache* ins) {
5677 MDefinition* value = ins->value();
5678 MOZ_ASSERT(value->type() == MIRType::Object ||
5679 value->type() == MIRType::Value);
5681 MDefinition* id = ins->idval();
5682 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5683 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5685 // Emit an overrecursed check: this is necessary because the cache can
5686 // attach a scripted getter stub that calls this script recursively.
5687 gen->setNeedsOverrecursedCheck();
5689 LHasOwnCache* lir =
5690 new (alloc()) LHasOwnCache(useBoxOrTyped(value), useBoxOrTyped(id));
5691 define(lir, ins);
5692 assignSafepoint(lir, ins);
5695 void LIRGenerator::visitCheckPrivateFieldCache(MCheckPrivateFieldCache* ins) {
5696 MDefinition* value = ins->value();
5697 MOZ_ASSERT(value->type() == MIRType::Object ||
5698 value->type() == MIRType::Value);
5700 MDefinition* id = ins->idval();
5701 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5702 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5704 LCheckPrivateFieldCache* lir = new (alloc())
5705 LCheckPrivateFieldCache(useBoxOrTyped(value), useBoxOrTyped(id));
5706 define(lir, ins);
5707 assignSafepoint(lir, ins);
5710 void LIRGenerator::visitNewPrivateName(MNewPrivateName* ins) {
5711 auto* lir = new (alloc()) LNewPrivateName();
5712 defineReturn(lir, ins);
5713 assignSafepoint(lir, ins);
5716 void LIRGenerator::visitInstanceOf(MInstanceOf* ins) {
5717 MDefinition* lhs = ins->lhs();
5718 MDefinition* rhs = ins->rhs();
5720 MOZ_ASSERT(lhs->type() == MIRType::Value || lhs->type() == MIRType::Object);
5721 MOZ_ASSERT(rhs->type() == MIRType::Object);
5723 if (lhs->type() == MIRType::Object) {
5724 auto* lir = new (alloc()) LInstanceOfO(useRegister(lhs), useRegister(rhs));
5725 define(lir, ins);
5726 assignSafepoint(lir, ins);
5727 } else {
5728 auto* lir = new (alloc()) LInstanceOfV(useBox(lhs), useRegister(rhs));
5729 define(lir, ins);
5730 assignSafepoint(lir, ins);
5734 void LIRGenerator::visitInstanceOfCache(MInstanceOfCache* ins) {
5735 MDefinition* lhs = ins->lhs();
5736 MDefinition* rhs = ins->rhs();
5738 MOZ_ASSERT(lhs->type() == MIRType::Value);
5739 MOZ_ASSERT(rhs->type() == MIRType::Object);
5741 LInstanceOfCache* lir =
5742 new (alloc()) LInstanceOfCache(useBox(lhs), useRegister(rhs));
5743 define(lir, ins);
5744 assignSafepoint(lir, ins);
5747 void LIRGenerator::visitIsArray(MIsArray* ins) {
5748 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5750 if (ins->value()->type() == MIRType::Object) {
5751 LIsArrayO* lir = new (alloc()) LIsArrayO(useRegister(ins->value()));
5752 define(lir, ins);
5753 assignSafepoint(lir, ins);
5754 } else {
5755 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5756 LIsArrayV* lir = new (alloc()) LIsArrayV(useBox(ins->value()), temp());
5757 define(lir, ins);
5758 assignSafepoint(lir, ins);
5762 void LIRGenerator::visitIsTypedArray(MIsTypedArray* ins) {
5763 MOZ_ASSERT(ins->value()->type() == MIRType::Object);
5764 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5766 auto* lir = new (alloc()) LIsTypedArray(useRegister(ins->value()));
5767 define(lir, ins);
5769 if (ins->isPossiblyWrapped()) {
5770 assignSafepoint(lir, ins);
5774 void LIRGenerator::visitIsCallable(MIsCallable* ins) {
5775 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5777 if (ins->object()->type() == MIRType::Object) {
5778 define(new (alloc()) LIsCallableO(useRegister(ins->object())), ins);
5779 } else {
5780 MOZ_ASSERT(ins->object()->type() == MIRType::Value);
5781 define(new (alloc()) LIsCallableV(useBox(ins->object()), temp()), ins);
5785 void LIRGenerator::visitIsConstructor(MIsConstructor* ins) {
5786 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5787 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5788 define(new (alloc()) LIsConstructor(useRegister(ins->object())), ins);
5791 void LIRGenerator::visitIsCrossRealmArrayConstructor(
5792 MIsCrossRealmArrayConstructor* ins) {
5793 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5794 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5795 define(new (alloc())
5796 LIsCrossRealmArrayConstructor(useRegister(ins->object())),
5797 ins);
5800 static bool CanEmitAtUseForSingleTest(MInstruction* ins) {
5801 if (!ins->canEmitAtUses()) {
5802 return false;
5805 MUseIterator iter(ins->usesBegin());
5806 if (iter == ins->usesEnd()) {
5807 return false;
5810 MNode* node = iter->consumer();
5811 if (!node->isDefinition()) {
5812 return false;
5815 if (!node->toDefinition()->isTest()) {
5816 return false;
5819 iter++;
5820 return iter == ins->usesEnd();
5823 void LIRGenerator::visitIsObject(MIsObject* ins) {
5824 if (CanEmitAtUseForSingleTest(ins)) {
5825 emitAtUses(ins);
5826 return;
5829 MDefinition* opd = ins->input();
5830 MOZ_ASSERT(opd->type() == MIRType::Value);
5831 LIsObject* lir = new (alloc()) LIsObject(useBoxAtStart(opd));
5832 define(lir, ins);
5835 void LIRGenerator::visitIsNullOrUndefined(MIsNullOrUndefined* ins) {
5836 if (CanEmitAtUseForSingleTest(ins)) {
5837 emitAtUses(ins);
5838 return;
5841 MDefinition* opd = ins->input();
5842 if (opd->type() == MIRType::Value) {
5843 auto* lir = new (alloc()) LIsNullOrUndefined(useBoxAtStart(opd));
5844 define(lir, ins);
5845 } else {
5846 define(new (alloc()) LInteger(IsNullOrUndefined(opd->type())), ins);
5850 void LIRGenerator::visitHasClass(MHasClass* ins) {
5851 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5852 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5853 define(new (alloc()) LHasClass(useRegister(ins->object())), ins);
5856 void LIRGenerator::visitGuardToClass(MGuardToClass* ins) {
5857 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5858 MOZ_ASSERT(ins->type() == MIRType::Object);
5859 LGuardToClass* lir =
5860 new (alloc()) LGuardToClass(useRegisterAtStart(ins->object()), temp());
5861 assignSnapshot(lir, ins->bailoutKind());
5862 defineReuseInput(lir, ins, 0);
5865 void LIRGenerator::visitGuardToEitherClass(MGuardToEitherClass* ins) {
5866 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5867 MOZ_ASSERT(ins->type() == MIRType::Object);
5868 auto* lir = new (alloc())
5869 LGuardToEitherClass(useRegisterAtStart(ins->object()), temp());
5870 assignSnapshot(lir, ins->bailoutKind());
5871 defineReuseInput(lir, ins, 0);
5874 void LIRGenerator::visitGuardToFunction(MGuardToFunction* ins) {
5875 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5876 MOZ_ASSERT(ins->type() == MIRType::Object);
5877 LGuardToFunction* lir =
5878 new (alloc()) LGuardToFunction(useRegisterAtStart(ins->object()), temp());
5879 assignSnapshot(lir, ins->bailoutKind());
5880 defineReuseInput(lir, ins, 0);
5883 void LIRGenerator::visitObjectClassToString(MObjectClassToString* ins) {
5884 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5885 MOZ_ASSERT(ins->type() == MIRType::String);
5886 auto* lir = new (alloc()) LObjectClassToString(
5887 useRegisterAtStart(ins->object()), tempFixed(CallTempReg0));
5888 assignSnapshot(lir, ins->bailoutKind());
5889 defineReturn(lir, ins);
5892 void LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins) {
5893 MOZ_ASSERT(ins->offset());
5894 if (ins->base()->type() == MIRType::Int32) {
5895 MOZ_ASSERT(ins->type() == MIRType::Int32);
5896 MOZ_ASSERT(ins->offset() <= UINT32_MAX); // Because memory32
5897 define(new (alloc()) LWasmAddOffset(useRegisterAtStart(ins->base())), ins);
5898 } else {
5899 MOZ_ASSERT(ins->type() == MIRType::Int64);
5900 #ifdef JS_64BIT
5901 defineInt64(new (alloc())
5902 LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
5903 ins);
5904 #else
5905 // Avoid situation where the input is (a,b) and the output is (b,a).
5906 defineInt64ReuseInput(
5907 new (alloc()) LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
5908 ins, 0);
5909 #endif
5913 void LIRGenerator::visitWasmLoadInstance(MWasmLoadInstance* ins) {
5914 if (ins->type() == MIRType::Int64) {
5915 #ifdef JS_PUNBOX64
5916 LAllocation instance = useRegisterAtStart(ins->instance());
5917 #else
5918 // Avoid reusing instance for a 64-bit output pair as the load clobbers the
5919 // first half of that pair before loading the second half.
5920 LAllocation instance = useRegister(ins->instance());
5921 #endif
5922 auto* lir = new (alloc()) LWasmLoadInstance64(instance);
5923 defineInt64(lir, ins);
5924 } else {
5925 auto* lir =
5926 new (alloc()) LWasmLoadInstance(useRegisterAtStart(ins->instance()));
5927 define(lir, ins);
5931 void LIRGenerator::visitWasmStoreInstance(MWasmStoreInstance* ins) {
5932 MDefinition* value = ins->value();
5933 if (value->type() == MIRType::Int64) {
5934 #ifdef JS_PUNBOX64
5935 LAllocation instance = useRegisterAtStart(ins->instance());
5936 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5937 #else
5938 LAllocation instance = useRegister(ins->instance());
5939 LInt64Allocation valueAlloc = useInt64Register(value);
5940 #endif
5941 add(new (alloc()) LWasmStoreSlotI64(valueAlloc, instance, ins->offset(),
5942 mozilla::Nothing()),
5943 ins);
5944 } else {
5945 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5946 LAllocation instance = useRegisterAtStart(ins->instance());
5947 LAllocation valueAlloc = useRegisterAtStart(value);
5948 add(new (alloc())
5949 LWasmStoreSlot(valueAlloc, instance, ins->offset(), value->type(),
5950 MNarrowingOp::None, mozilla::Nothing()),
5951 ins);
5955 void LIRGenerator::visitWasmHeapReg(MWasmHeapReg* ins) {
5956 #ifdef WASM_HAS_HEAPREG
5957 auto* lir = new (alloc()) LWasmHeapReg();
5958 define(lir, ins);
5959 #else
5960 MOZ_CRASH();
5961 #endif
5964 void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) {
5965 MOZ_ASSERT(!ins->isRedundant());
5967 MDefinition* index = ins->index();
5968 MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
5970 MOZ_ASSERT(boundsCheckLimit->type() == index->type());
5972 if (index->type() == MIRType::Int64) {
5973 if (JitOptions.spectreIndexMasking) {
5974 auto* lir = new (alloc()) LWasmBoundsCheck64(
5975 useInt64RegisterAtStart(index), useInt64Register(boundsCheckLimit));
5976 defineInt64ReuseInput(lir, ins, 0);
5977 } else {
5978 auto* lir = new (alloc())
5979 LWasmBoundsCheck64(useInt64RegisterAtStart(index),
5980 useInt64RegisterAtStart(boundsCheckLimit));
5981 add(lir, ins);
5983 } else {
5984 MOZ_ASSERT(index->type() == MIRType::Int32);
5986 if (JitOptions.spectreIndexMasking) {
5987 auto* lir = new (alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
5988 useRegister(boundsCheckLimit));
5989 defineReuseInput(lir, ins, 0);
5990 } else {
5991 auto* lir = new (alloc()) LWasmBoundsCheck(
5992 useRegisterAtStart(index), useRegisterAtStart(boundsCheckLimit));
5993 add(lir, ins);
5998 void LIRGenerator::visitWasmBoundsCheckRange32(MWasmBoundsCheckRange32* ins) {
5999 MDefinition* index = ins->index();
6000 MDefinition* length = ins->length();
6001 MDefinition* limit = ins->limit();
6003 MOZ_ASSERT(index->type() == MIRType::Int32);
6004 MOZ_ASSERT(length->type() == MIRType::Int32);
6005 MOZ_ASSERT(limit->type() == MIRType::Int32);
6007 add(new (alloc()) LWasmBoundsCheckRange32(
6008 useRegister(index), useRegister(length), useRegister(limit), temp()),
6009 ins);
6012 void LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck* ins) {
6013 MDefinition* index = ins->index();
6014 if (index->type() == MIRType::Int64) {
6015 auto* lir =
6016 new (alloc()) LWasmAlignmentCheck64(useInt64RegisterAtStart(index));
6017 add(lir, ins);
6018 } else {
6019 auto* lir = new (alloc()) LWasmAlignmentCheck(useRegisterAtStart(index));
6020 add(lir, ins);
6024 void LIRGenerator::visitWasmLoadInstanceDataField(
6025 MWasmLoadInstanceDataField* ins) {
6026 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset());
6027 if (ins->type() == MIRType::Int64) {
6028 #ifdef JS_PUNBOX64
6029 LAllocation instance = useRegisterAtStart(ins->instance());
6030 #else
6031 // Avoid reusing instance for the output pair as the load clobbers the first
6032 // half of that pair before loading the second half.
6033 LAllocation instance = useRegister(ins->instance());
6034 #endif
6035 defineInt64(new (alloc())
6036 LWasmLoadSlotI64(instance, offs, mozilla::Nothing()),
6037 ins);
6038 } else {
6039 LAllocation instance = useRegisterAtStart(ins->instance());
6040 define(new (alloc()) LWasmLoadSlot(instance, offs, ins->type(),
6041 MWideningOp::None, mozilla::Nothing()),
6042 ins);
6046 void LIRGenerator::visitWasmLoadGlobalCell(MWasmLoadGlobalCell* ins) {
6047 if (ins->type() == MIRType::Int64) {
6048 #ifdef JS_PUNBOX64
6049 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
6050 #else
6051 // Avoid reusing cellPtr for the output pair as the load clobbers the first
6052 // half of that pair before loading the second half.
6053 LAllocation cellPtr = useRegister(ins->cellPtr());
6054 #endif
6055 defineInt64(new (alloc())
6056 LWasmLoadSlotI64(cellPtr, /*offset=*/0, mozilla::Nothing()),
6057 ins);
6058 } else {
6059 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
6060 define(new (alloc()) LWasmLoadSlot(cellPtr, /*offset=*/0, ins->type(),
6061 MWideningOp::None, mozilla::Nothing()),
6062 ins);
6066 void LIRGenerator::visitWasmLoadTableElement(MWasmLoadTableElement* ins) {
6067 LAllocation elements = useRegisterAtStart(ins->elements());
6068 LAllocation index = useRegisterAtStart(ins->index());
6069 define(new (alloc()) LWasmLoadTableElement(elements, index), ins);
6072 void LIRGenerator::visitWasmStoreInstanceDataField(
6073 MWasmStoreInstanceDataField* ins) {
6074 MDefinition* value = ins->value();
6075 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset());
6076 if (value->type() == MIRType::Int64) {
6077 #ifdef JS_PUNBOX64
6078 LAllocation instance = useRegisterAtStart(ins->instance());
6079 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
6080 #else
6081 LAllocation instance = useRegister(ins->instance());
6082 LInt64Allocation valueAlloc = useInt64Register(value);
6083 #endif
6084 add(new (alloc())
6085 LWasmStoreSlotI64(valueAlloc, instance, offs, mozilla::Nothing()),
6086 ins);
6087 } else {
6088 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
6089 LAllocation instance = useRegisterAtStart(ins->instance());
6090 LAllocation valueAlloc = useRegisterAtStart(value);
6091 add(new (alloc()) LWasmStoreSlot(valueAlloc, instance, offs, value->type(),
6092 MNarrowingOp::None, mozilla::Nothing()),
6093 ins);
6097 void LIRGenerator::visitWasmStoreGlobalCell(MWasmStoreGlobalCell* ins) {
6098 MDefinition* value = ins->value();
6099 size_t offs = 0;
6100 if (value->type() == MIRType::Int64) {
6101 #ifdef JS_PUNBOX64
6102 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
6103 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
6104 #else
6105 LAllocation cellPtr = useRegister(ins->cellPtr());
6106 LInt64Allocation valueAlloc = useInt64Register(value);
6107 #endif
6108 add(new (alloc())
6109 LWasmStoreSlotI64(valueAlloc, cellPtr, offs, mozilla::Nothing()));
6110 } else {
6111 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
6112 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
6113 LAllocation valueAlloc = useRegisterAtStart(value);
6114 add(new (alloc()) LWasmStoreSlot(valueAlloc, cellPtr, offs, value->type(),
6115 MNarrowingOp::None, mozilla::Nothing()));
6119 void LIRGenerator::visitWasmStoreStackResult(MWasmStoreStackResult* ins) {
6120 MDefinition* stackResultArea = ins->stackResultArea();
6121 MDefinition* value = ins->value();
6122 size_t offs = ins->offset();
6123 LInstruction* lir;
6124 if (value->type() == MIRType::Int64) {
6125 lir = new (alloc())
6126 LWasmStoreSlotI64(useInt64Register(value), useRegister(stackResultArea),
6127 offs, mozilla::Nothing());
6128 } else {
6129 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
6130 lir = new (alloc())
6131 LWasmStoreSlot(useRegister(value), useRegister(stackResultArea), offs,
6132 value->type(), MNarrowingOp::None, mozilla::Nothing());
6134 add(lir, ins);
6137 void LIRGenerator::visitWasmDerivedPointer(MWasmDerivedPointer* ins) {
6138 LAllocation base = useRegisterAtStart(ins->base());
6139 define(new (alloc()) LWasmDerivedPointer(base), ins);
6142 void LIRGenerator::visitWasmDerivedIndexPointer(MWasmDerivedIndexPointer* ins) {
6143 LAllocation base = useRegisterAtStart(ins->base());
6144 LAllocation index = useRegisterAtStart(ins->index());
6145 define(new (alloc()) LWasmDerivedIndexPointer(base, index), ins);
6148 void LIRGenerator::visitWasmStoreRef(MWasmStoreRef* ins) {
6149 LAllocation instance = useRegister(ins->instance());
6150 LAllocation valueBase = useFixed(ins->valueBase(), PreBarrierReg);
6151 LAllocation value = useRegister(ins->value());
6152 uint32_t valueOffset = ins->offset();
6153 add(new (alloc())
6154 LWasmStoreRef(instance, valueBase, value, temp(), valueOffset,
6155 mozilla::Nothing(), ins->preBarrierKind()),
6156 ins);
6159 void LIRGenerator::visitWasmPostWriteBarrierImmediate(
6160 MWasmPostWriteBarrierImmediate* ins) {
6161 LWasmPostWriteBarrierImmediate* lir =
6162 new (alloc()) LWasmPostWriteBarrierImmediate(
6163 useFixed(ins->instance(), InstanceReg), useRegister(ins->object()),
6164 useRegister(ins->valueBase()), useRegister(ins->value()), temp(),
6165 ins->valueOffset());
6166 add(lir, ins);
6167 assignWasmSafepoint(lir);
6170 void LIRGenerator::visitWasmPostWriteBarrierIndex(
6171 MWasmPostWriteBarrierIndex* ins) {
6172 LWasmPostWriteBarrierIndex* lir = new (alloc()) LWasmPostWriteBarrierIndex(
6173 useFixed(ins->instance(), InstanceReg), useRegister(ins->object()),
6174 useRegister(ins->valueBase()), useRegister(ins->index()),
6175 useRegister(ins->value()), temp(), ins->elemSize());
6176 add(lir, ins);
6177 assignWasmSafepoint(lir);
6180 void LIRGenerator::visitWasmParameter(MWasmParameter* ins) {
6181 ABIArg abi = ins->abi();
6182 if (ins->type() == MIRType::StackResults) {
6183 // Functions that return stack results receive an extra incoming parameter
6184 // with type MIRType::StackResults. This value is a pointer to fresh
6185 // memory. Here we treat it as if it were in fact MIRType::Pointer.
6186 auto* lir = new (alloc()) LWasmParameter;
6187 LDefinition def(LDefinition::TypeFrom(MIRType::Pointer),
6188 LDefinition::FIXED);
6189 def.setOutput(abi.argInRegister() ? LAllocation(abi.reg())
6190 : LArgument(abi.offsetFromArgBase()));
6191 define(lir, ins, def);
6192 return;
6194 if (abi.argInRegister()) {
6195 #if defined(JS_NUNBOX32)
6196 if (abi.isGeneralRegPair()) {
6197 defineInt64Fixed(
6198 new (alloc()) LWasmParameterI64, ins,
6199 LInt64Allocation(LAllocation(AnyRegister(abi.gpr64().high)),
6200 LAllocation(AnyRegister(abi.gpr64().low))));
6201 return;
6203 #endif
6204 defineFixed(new (alloc()) LWasmParameter, ins, LAllocation(abi.reg()));
6205 return;
6207 if (ins->type() == MIRType::Int64) {
6208 MOZ_ASSERT(!abi.argInRegister());
6209 defineInt64Fixed(
6210 new (alloc()) LWasmParameterI64, ins,
6211 #if defined(JS_NUNBOX32)
6212 LInt64Allocation(LArgument(abi.offsetFromArgBase() + INT64HIGH_OFFSET),
6213 LArgument(abi.offsetFromArgBase() + INT64LOW_OFFSET))
6214 #else
6215 LInt64Allocation(LArgument(abi.offsetFromArgBase()))
6216 #endif
6218 } else {
6219 MOZ_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType::WasmAnyRef
6220 #ifdef ENABLE_WASM_SIMD
6221 || ins->type() == MIRType::Simd128
6222 #endif
6224 defineFixed(new (alloc()) LWasmParameter, ins,
6225 LArgument(abi.offsetFromArgBase()));
6229 void LIRGenerator::visitWasmReturn(MWasmReturn* ins) {
6230 MDefinition* rval = ins->getOperand(0);
6231 MDefinition* instance = ins->getOperand(1);
6233 if (rval->type() == MIRType::Int64) {
6234 add(new (alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64),
6235 useFixed(instance, InstanceReg)));
6236 return;
6239 LAllocation returnReg;
6240 if (rval->type() == MIRType::Float32) {
6241 returnReg = useFixed(rval, ReturnFloat32Reg);
6242 } else if (rval->type() == MIRType::Double) {
6243 returnReg = useFixed(rval, ReturnDoubleReg);
6244 #ifdef ENABLE_WASM_SIMD
6245 } else if (rval->type() == MIRType::Simd128) {
6246 returnReg = useFixed(rval, ReturnSimd128Reg);
6247 #endif
6248 } else if (rval->type() == MIRType::Int32 ||
6249 rval->type() == MIRType::WasmAnyRef) {
6250 returnReg = useFixed(rval, ReturnReg);
6251 } else {
6252 MOZ_CRASH("Unexpected wasm return type");
6255 LWasmReturn* lir =
6256 new (alloc()) LWasmReturn(useFixed(instance, InstanceReg), returnReg);
6257 add(lir);
6260 void LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid* ins) {
6261 MDefinition* instance = ins->getOperand(0);
6262 LWasmReturnVoid* lir =
6263 new (alloc()) LWasmReturnVoid(useFixed(instance, InstanceReg));
6264 add(lir);
6267 void LIRGenerator::visitWasmStackArg(MWasmStackArg* ins) {
6268 if (ins->arg()->type() == MIRType::Int64) {
6269 add(new (alloc())
6270 LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins->arg())),
6271 ins);
6272 } else if (IsFloatingPointType(ins->arg()->type())) {
6273 MOZ_ASSERT(!ins->arg()->isEmittedAtUses());
6274 add(new (alloc()) LWasmStackArg(useRegisterAtStart(ins->arg())), ins);
6275 } else {
6276 add(new (alloc()) LWasmStackArg(useRegisterOrConstantAtStart(ins->arg())),
6277 ins);
6281 void LIRGenerator::visitWasmRegisterResult(MWasmRegisterResult* ins) {
6282 auto* lir = new (alloc()) LWasmRegisterResult();
6283 uint32_t vreg = getVirtualRegister();
6284 MOZ_ASSERT(ins->type() != MIRType::Int64);
6285 auto type = LDefinition::TypeFrom(ins->type());
6286 lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ins->loc())));
6287 ins->setVirtualRegister(vreg);
6288 add(lir, ins);
6291 void LIRGenerator::visitWasmFloatRegisterResult(MWasmFloatRegisterResult* ins) {
6292 auto* lir = new (alloc()) LWasmRegisterResult();
6293 uint32_t vreg = getVirtualRegister();
6294 auto type = LDefinition::TypeFrom(ins->type());
6295 lir->setDef(0, LDefinition(vreg, type, LFloatReg(ins->loc())));
6296 ins->setVirtualRegister(vreg);
6297 add(lir, ins);
6300 void LIRGenerator::visitWasmRegister64Result(MWasmRegister64Result* ins) {
6301 MOZ_ASSERT(ins->type() == MIRType::Int64);
6302 uint32_t vreg = getVirtualRegister();
6304 #if defined(JS_NUNBOX32)
6305 auto* lir = new (alloc()) LWasmRegisterPairResult();
6306 lir->setDef(INT64LOW_INDEX,
6307 LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL,
6308 LGeneralReg(ins->loc().low)));
6309 lir->setDef(INT64HIGH_INDEX,
6310 LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL,
6311 LGeneralReg(ins->loc().high)));
6312 getVirtualRegister();
6313 #elif defined(JS_PUNBOX64)
6314 auto* lir = new (alloc()) LWasmRegisterResult();
6315 lir->setDef(
6316 0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ins->loc().reg)));
6317 #else
6318 # error expected either JS_NUNBOX32 or JS_PUNBOX64
6319 #endif
6321 ins->setVirtualRegister(vreg);
6322 add(lir, ins);
6325 void LIRGenerator::visitWasmStackResultArea(MWasmStackResultArea* ins) {
6326 MOZ_ASSERT(ins->type() == MIRType::StackResults);
6327 auto* lir = new (alloc()) LWasmStackResultArea(temp());
6328 uint32_t vreg = getVirtualRegister();
6329 lir->setDef(0,
6330 LDefinition(vreg, LDefinition::STACKRESULTS, LDefinition::STACK));
6331 ins->setVirtualRegister(vreg);
6332 add(lir, ins);
6335 void LIRGenerator::visitWasmStackResult(MWasmStackResult* ins) {
6336 MWasmStackResultArea* area = ins->resultArea()->toWasmStackResultArea();
6337 LDefinition::Policy pol = LDefinition::STACK;
6339 if (ins->type() == MIRType::Int64) {
6340 auto* lir = new (alloc()) LWasmStackResult64;
6341 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
6342 uint32_t vreg = getVirtualRegister();
6343 LDefinition::Type typ = LDefinition::GENERAL;
6344 #if defined(JS_NUNBOX32)
6345 getVirtualRegister();
6346 lir->setDef(INT64LOW_INDEX, LDefinition(vreg + INT64LOW_INDEX, typ, pol));
6347 lir->setDef(INT64HIGH_INDEX, LDefinition(vreg + INT64HIGH_INDEX, typ, pol));
6348 #else
6349 lir->setDef(0, LDefinition(vreg, typ, pol));
6350 #endif
6351 ins->setVirtualRegister(vreg);
6352 add(lir, ins);
6353 return;
6356 auto* lir = new (alloc()) LWasmStackResult;
6357 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
6358 uint32_t vreg = getVirtualRegister();
6359 LDefinition::Type typ = LDefinition::TypeFrom(ins->type());
6360 lir->setDef(0, LDefinition(vreg, typ, pol));
6361 ins->setVirtualRegister(vreg);
6362 add(lir, ins);
6365 template <class MWasmCallT>
6366 void LIRGenerator::visitWasmCall(MWasmCallT ins) {
6367 bool needsBoundsCheck = true;
6368 mozilla::Maybe<uint32_t> tableSize;
6370 if (ins->callee().isTable()) {
6371 MDefinition* index = ins->getOperand(ins->numArgs());
6373 if (ins->callee().which() == wasm::CalleeDesc::WasmTable) {
6374 uint32_t minLength = ins->callee().wasmTableMinLength();
6375 mozilla::Maybe<uint32_t> maxLength = ins->callee().wasmTableMaxLength();
6376 if (index->isConstant() &&
6377 uint32_t(index->toConstant()->toInt32()) < minLength) {
6378 needsBoundsCheck = false;
6380 if (maxLength.isSome() && *maxLength == minLength) {
6381 tableSize = maxLength;
6386 auto* lir = allocateVariadic<LWasmCall>(ins->numOperands(), needsBoundsCheck,
6387 tableSize);
6388 if (!lir) {
6389 abort(AbortReason::Alloc, "OOM: LIRGenerator::lowerWasmCall");
6390 return;
6393 for (unsigned i = 0; i < ins->numArgs(); i++) {
6394 lir->setOperand(
6395 i, useFixedAtStart(ins->getOperand(i), ins->registerForArg(i)));
6398 if (ins->callee().isTable()) {
6399 MDefinition* index = ins->getOperand(ins->numArgs());
6400 lir->setOperand(ins->numArgs(),
6401 useFixedAtStart(index, WasmTableCallIndexReg));
6403 if (ins->callee().isFuncRef()) {
6404 MDefinition* ref = ins->getOperand(ins->numArgs());
6405 lir->setOperand(ins->numArgs(), useFixedAtStart(ref, WasmCallRefReg));
6408 add(lir, ins);
6409 assignWasmSafepoint(lir);
6411 // WasmCall with WasmTable has two call instructions, and they both need a
6412 // safepoint associated with them. Create a second safepoint here; the node
6413 // otherwise does nothing, and codegen for it only marks the safepoint at the
6414 // node.
6415 if (ins->callee().which() == wasm::CalleeDesc::WasmTable &&
6416 !ins->isWasmReturnCall()) {
6417 auto* adjunctSafepoint = new (alloc()) LWasmCallIndirectAdjunctSafepoint();
6418 add(adjunctSafepoint);
6419 assignWasmSafepoint(adjunctSafepoint);
6420 lir->setAdjunctSafepoint(adjunctSafepoint);
6424 void LIRGenerator::visitWasmCallCatchable(MWasmCallCatchable* ins) {
6425 visitWasmCall(ins);
6428 void LIRGenerator::visitWasmCallUncatchable(MWasmCallUncatchable* ins) {
6429 visitWasmCall(ins);
6432 void LIRGenerator::visitWasmReturnCall(MWasmReturnCall* ins) {
6433 visitWasmCall(ins);
6436 void LIRGenerator::visitWasmCallLandingPrePad(MWasmCallLandingPrePad* ins) {
6437 add(new (alloc()) LWasmCallLandingPrePad, ins);
6440 void LIRGenerator::visitSetDOMProperty(MSetDOMProperty* ins) {
6441 MDefinition* val = ins->value();
6443 Register cxReg, objReg, privReg, valueReg;
6444 GetTempRegForIntArg(0, 0, &cxReg);
6445 GetTempRegForIntArg(1, 0, &objReg);
6446 GetTempRegForIntArg(2, 0, &privReg);
6447 GetTempRegForIntArg(3, 0, &valueReg);
6449 // Keep using GetTempRegForIntArg, since we want to make sure we
6450 // don't clobber registers we're already using.
6451 Register tempReg1, tempReg2;
6452 GetTempRegForIntArg(4, 0, &tempReg1);
6453 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2);
6454 MOZ_ASSERT(ok, "How can we not have six temp registers?");
6456 LSetDOMProperty* lir = new (alloc())
6457 LSetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
6458 useBoxFixedAtStart(val, tempReg1, tempReg2),
6459 tempFixed(privReg), tempFixed(valueReg));
6460 add(lir, ins);
6461 assignSafepoint(lir, ins);
6464 void LIRGenerator::visitGetDOMProperty(MGetDOMProperty* ins) {
6465 Register cxReg, objReg, privReg, valueReg;
6466 GetTempRegForIntArg(0, 0, &cxReg);
6467 GetTempRegForIntArg(1, 0, &objReg);
6468 GetTempRegForIntArg(2, 0, &privReg);
6469 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg);
6470 MOZ_ASSERT(ok, "How can we not have four temp registers?");
6471 LGetDOMProperty* lir = new (alloc())
6472 LGetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
6473 tempFixed(privReg), tempFixed(valueReg));
6475 defineReturn(lir, ins);
6476 assignSafepoint(lir, ins);
6479 void LIRGenerator::visitGetDOMMember(MGetDOMMember* ins) {
6480 MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
6481 // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
6482 // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
6483 // value can in fact change as a result of DOM setters and method calls.
6484 MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
6485 "Member gets had better not alias the world");
6487 MDefinition* obj = ins->object();
6488 MOZ_ASSERT(obj->type() == MIRType::Object);
6490 MIRType type = ins->type();
6492 if (type == MIRType::Value) {
6493 LGetDOMMemberV* lir = new (alloc()) LGetDOMMemberV(useRegisterAtStart(obj));
6494 defineBox(lir, ins);
6495 } else {
6496 LGetDOMMemberT* lir =
6497 new (alloc()) LGetDOMMemberT(useRegisterForTypedLoad(obj, type));
6498 define(lir, ins);
6502 void LIRGenerator::visitLoadDOMExpandoValue(MLoadDOMExpandoValue* ins) {
6503 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6504 auto* lir =
6505 new (alloc()) LLoadDOMExpandoValue(useRegisterAtStart(ins->proxy()));
6506 defineBox(lir, ins);
6509 void LIRGenerator::visitLoadDOMExpandoValueGuardGeneration(
6510 MLoadDOMExpandoValueGuardGeneration* ins) {
6511 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6512 auto* lir = new (alloc())
6513 LLoadDOMExpandoValueGuardGeneration(useRegisterAtStart(ins->proxy()));
6514 assignSnapshot(lir, ins->bailoutKind());
6515 defineBox(lir, ins);
6518 void LIRGenerator::visitLoadDOMExpandoValueIgnoreGeneration(
6519 MLoadDOMExpandoValueIgnoreGeneration* ins) {
6520 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6521 auto* lir = new (alloc())
6522 LLoadDOMExpandoValueIgnoreGeneration(useRegisterAtStart(ins->proxy()));
6523 defineBox(lir, ins);
6526 void LIRGenerator::visitGuardDOMExpandoMissingOrGuardShape(
6527 MGuardDOMExpandoMissingOrGuardShape* ins) {
6528 MOZ_ASSERT(ins->expando()->type() == MIRType::Value);
6529 auto* lir = new (alloc())
6530 LGuardDOMExpandoMissingOrGuardShape(useBox(ins->expando()), temp());
6531 assignSnapshot(lir, ins->bailoutKind());
6532 add(lir, ins);
6533 redefine(ins, ins->expando());
6536 void LIRGenerator::visitIncrementWarmUpCounter(MIncrementWarmUpCounter* ins) {
6537 LIncrementWarmUpCounter* lir = new (alloc()) LIncrementWarmUpCounter(temp());
6538 add(lir, ins);
6541 void LIRGenerator::visitLexicalCheck(MLexicalCheck* ins) {
6542 MDefinition* input = ins->input();
6543 MOZ_ASSERT(input->type() == MIRType::Value);
6544 LLexicalCheck* lir = new (alloc()) LLexicalCheck(useBox(input));
6545 assignSnapshot(lir, ins->bailoutKind());
6546 add(lir, ins);
6547 redefine(ins, input);
6550 void LIRGenerator::visitThrowRuntimeLexicalError(
6551 MThrowRuntimeLexicalError* ins) {
6552 LThrowRuntimeLexicalError* lir = new (alloc()) LThrowRuntimeLexicalError();
6553 add(lir, ins);
6554 assignSafepoint(lir, ins);
6557 void LIRGenerator::visitThrowMsg(MThrowMsg* ins) {
6558 LThrowMsg* lir = new (alloc()) LThrowMsg();
6559 add(lir, ins);
6560 assignSafepoint(lir, ins);
6563 void LIRGenerator::visitGlobalDeclInstantiation(MGlobalDeclInstantiation* ins) {
6564 LGlobalDeclInstantiation* lir = new (alloc()) LGlobalDeclInstantiation();
6565 add(lir, ins);
6566 assignSafepoint(lir, ins);
6569 void LIRGenerator::visitDebugger(MDebugger* ins) {
6570 auto* lir = new (alloc()) LDebugger(tempFixed(CallTempReg0));
6571 assignSnapshot(lir, ins->bailoutKind());
6572 add(lir, ins);
6575 void LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins) {
6576 define(new (alloc()) LAtomicIsLockFree(useRegister(ins->input())), ins);
6579 void LIRGenerator::visitCheckReturn(MCheckReturn* ins) {
6580 MDefinition* retVal = ins->returnValue();
6581 MDefinition* thisVal = ins->thisValue();
6582 MOZ_ASSERT(retVal->type() == MIRType::Value);
6583 MOZ_ASSERT(thisVal->type() == MIRType::Value);
6585 auto* lir =
6586 new (alloc()) LCheckReturn(useBoxAtStart(retVal), useBoxAtStart(thisVal));
6587 defineBox(lir, ins);
6588 assignSafepoint(lir, ins);
6591 void LIRGenerator::visitCheckIsObj(MCheckIsObj* ins) {
6592 MDefinition* input = ins->input();
6593 MOZ_ASSERT(input->type() == MIRType::Value);
6595 LCheckIsObj* lir = new (alloc()) LCheckIsObj(useBox(input));
6596 define(lir, ins);
6597 assignSafepoint(lir, ins);
6600 #ifdef JS_PUNBOX64
6601 void LIRGenerator::visitCheckScriptedProxyGetResult(
6602 MCheckScriptedProxyGetResult* ins) {
6603 MDefinition* target = ins->target();
6604 MDefinition* id = ins->id();
6605 MDefinition* value = ins->value();
6607 LCheckScriptedProxyGetResult* lir =
6608 new (alloc()) LCheckScriptedProxyGetResult(useBox(target), useBox(id),
6609 useBox(value), temp(), temp());
6610 add(lir, ins);
6611 assignSafepoint(lir, ins);
6613 #endif
6615 void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) {
6616 MDefinition* checkVal = ins->checkValue();
6617 MOZ_ASSERT(checkVal->type() == MIRType::Value);
6619 auto* lir = new (alloc()) LCheckObjCoercible(useBoxAtStart(checkVal));
6620 redefine(ins, checkVal);
6621 add(lir, ins);
6622 assignSafepoint(lir, ins);
6625 void LIRGenerator::visitCheckClassHeritage(MCheckClassHeritage* ins) {
6626 MDefinition* heritage = ins->heritage();
6627 MOZ_ASSERT(heritage->type() == MIRType::Value);
6629 auto* lir =
6630 new (alloc()) LCheckClassHeritage(useBox(heritage), temp(), temp());
6631 redefine(ins, heritage);
6632 add(lir, ins);
6633 assignSafepoint(lir, ins);
6636 void LIRGenerator::visitCheckThis(MCheckThis* ins) {
6637 MDefinition* thisValue = ins->thisValue();
6638 MOZ_ASSERT(thisValue->type() == MIRType::Value);
6640 auto* lir = new (alloc()) LCheckThis(useBoxAtStart(thisValue));
6641 redefine(ins, thisValue);
6642 add(lir, ins);
6643 assignSafepoint(lir, ins);
6646 void LIRGenerator::visitCheckThisReinit(MCheckThisReinit* ins) {
6647 MDefinition* thisValue = ins->thisValue();
6648 MOZ_ASSERT(thisValue->type() == MIRType::Value);
6650 auto* lir = new (alloc()) LCheckThisReinit(useBoxAtStart(thisValue));
6651 redefine(ins, thisValue);
6652 add(lir, ins);
6653 assignSafepoint(lir, ins);
6656 void LIRGenerator::visitGenerator(MGenerator* ins) {
6657 auto* lir =
6658 new (alloc()) LGenerator(useRegisterAtStart(ins->callee()),
6659 useRegisterAtStart(ins->environmentChain()),
6660 useRegisterAtStart(ins->argsObject()));
6661 defineReturn(lir, ins);
6662 assignSafepoint(lir, ins);
6665 void LIRGenerator::visitAsyncResolve(MAsyncResolve* ins) {
6666 auto* lir = new (alloc()) LAsyncResolve(useRegisterAtStart(ins->generator()),
6667 useBoxAtStart(ins->value()));
6668 defineReturn(lir, ins);
6669 assignSafepoint(lir, ins);
6672 void LIRGenerator::visitAsyncReject(MAsyncReject* ins) {
6673 auto* lir = new (alloc())
6674 LAsyncReject(useRegisterAtStart(ins->generator()),
6675 useBoxAtStart(ins->reason()), useBoxAtStart(ins->stack()));
6676 defineReturn(lir, ins);
6677 assignSafepoint(lir, ins);
6680 void LIRGenerator::visitAsyncAwait(MAsyncAwait* ins) {
6681 MOZ_ASSERT(ins->generator()->type() == MIRType::Object);
6682 auto* lir = new (alloc()) LAsyncAwait(useBoxAtStart(ins->value()),
6683 useRegisterAtStart(ins->generator()));
6684 defineReturn(lir, ins);
6685 assignSafepoint(lir, ins);
6688 void LIRGenerator::visitCanSkipAwait(MCanSkipAwait* ins) {
6689 auto* lir = new (alloc()) LCanSkipAwait(useBoxAtStart(ins->value()));
6690 defineReturn(lir, ins);
6691 assignSafepoint(lir, ins);
6694 void LIRGenerator::visitMaybeExtractAwaitValue(MMaybeExtractAwaitValue* ins) {
6695 auto* lir = new (alloc()) LMaybeExtractAwaitValue(
6696 useBoxAtStart(ins->value()), useRegisterAtStart(ins->canSkip()));
6697 defineReturn(lir, ins);
6698 assignSafepoint(lir, ins);
6701 void LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins) {
6702 MDefinition* checkVal = ins->checkValue();
6703 MOZ_ASSERT(checkVal->type() == MIRType::Value);
6705 LDebugCheckSelfHosted* lir =
6706 new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal));
6707 redefine(ins, checkVal);
6708 add(lir, ins);
6709 assignSafepoint(lir, ins);
6712 void LIRGenerator::visitIsPackedArray(MIsPackedArray* ins) {
6713 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
6714 MOZ_ASSERT(ins->type() == MIRType::Boolean);
6716 auto lir = new (alloc()) LIsPackedArray(useRegister(ins->object()), temp());
6717 define(lir, ins);
6720 void LIRGenerator::visitGuardArrayIsPacked(MGuardArrayIsPacked* ins) {
6721 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
6723 auto* lir = new (alloc())
6724 LGuardArrayIsPacked(useRegister(ins->array()), temp(), temp());
6725 assignSnapshot(lir, ins->bailoutKind());
6726 add(lir, ins);
6727 redefine(ins, ins->array());
6730 void LIRGenerator::visitGetPrototypeOf(MGetPrototypeOf* ins) {
6731 MOZ_ASSERT(ins->target()->type() == MIRType::Object);
6732 MOZ_ASSERT(ins->type() == MIRType::Value);
6734 auto lir = new (alloc()) LGetPrototypeOf(useRegister(ins->target()));
6735 defineBox(lir, ins);
6736 assignSafepoint(lir, ins);
6739 void LIRGenerator::visitObjectWithProto(MObjectWithProto* ins) {
6740 MOZ_ASSERT(ins->prototype()->type() == MIRType::Value);
6741 MOZ_ASSERT(ins->type() == MIRType::Object);
6743 auto* lir = new (alloc()) LObjectWithProto(useBoxAtStart(ins->prototype()));
6744 defineReturn(lir, ins);
6745 assignSafepoint(lir, ins);
6748 void LIRGenerator::visitObjectStaticProto(MObjectStaticProto* ins) {
6749 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
6750 MOZ_ASSERT(ins->type() == MIRType::Object);
6752 auto* lir =
6753 new (alloc()) LObjectStaticProto(useRegisterAtStart(ins->object()));
6754 define(lir, ins);
6757 void LIRGenerator::visitBuiltinObject(MBuiltinObject* ins) {
6758 MOZ_ASSERT(ins->type() == MIRType::Object);
6760 auto* lir = new (alloc()) LBuiltinObject();
6761 defineReturn(lir, ins);
6762 assignSafepoint(lir, ins);
6765 void LIRGenerator::visitReturn(MReturn* ret) {
6766 return visitReturnImpl(ret->getOperand(0));
6769 void LIRGenerator::visitGeneratorReturn(MGeneratorReturn* ret) {
6770 return visitReturnImpl(ret->getOperand(0), true);
6773 void LIRGenerator::visitSuperFunction(MSuperFunction* ins) {
6774 MOZ_ASSERT(ins->callee()->type() == MIRType::Object);
6775 MOZ_ASSERT(ins->type() == MIRType::Value);
6777 auto* lir = new (alloc()) LSuperFunction(useRegister(ins->callee()), temp());
6778 defineBox(lir, ins);
6781 void LIRGenerator::visitInitHomeObject(MInitHomeObject* ins) {
6782 MDefinition* function = ins->function();
6783 MOZ_ASSERT(function->type() == MIRType::Object);
6785 MDefinition* homeObject = ins->homeObject();
6786 MOZ_ASSERT(homeObject->type() == MIRType::Value);
6788 MOZ_ASSERT(ins->type() == MIRType::Object);
6790 auto* lir = new (alloc())
6791 LInitHomeObject(useRegisterAtStart(function), useBoxAtStart(homeObject));
6792 redefine(ins, function);
6793 add(lir, ins);
6796 void LIRGenerator::visitIsTypedArrayConstructor(MIsTypedArrayConstructor* ins) {
6797 MDefinition* object = ins->object();
6798 MOZ_ASSERT(object->type() == MIRType::Object);
6800 auto* lir = new (alloc()) LIsTypedArrayConstructor(useRegister(object));
6801 define(lir, ins);
6804 void LIRGenerator::visitLoadValueTag(MLoadValueTag* ins) {
6805 MDefinition* value = ins->value();
6806 MOZ_ASSERT(value->type() == MIRType::Value);
6808 define(new (alloc()) LLoadValueTag(useBoxAtStart(value)), ins);
6811 void LIRGenerator::visitGuardTagNotEqual(MGuardTagNotEqual* ins) {
6812 MDefinition* lhs = ins->lhs();
6813 MOZ_ASSERT(lhs->type() == MIRType::Int32);
6815 MDefinition* rhs = ins->rhs();
6816 MOZ_ASSERT(rhs->type() == MIRType::Int32);
6818 auto* guard =
6819 new (alloc()) LGuardTagNotEqual(useRegister(lhs), useRegister(rhs));
6820 assignSnapshot(guard, ins->bailoutKind());
6821 add(guard, ins);
6824 void LIRGenerator::visitLoadWrapperTarget(MLoadWrapperTarget* ins) {
6825 MDefinition* object = ins->object();
6826 MOZ_ASSERT(object->type() == MIRType::Object);
6828 auto* lir = new (alloc()) LLoadWrapperTarget(useRegisterAtStart(object));
6829 if (ins->fallible()) {
6830 assignSnapshot(lir, ins->bailoutKind());
6832 define(lir, ins);
6835 void LIRGenerator::visitGuardHasGetterSetter(MGuardHasGetterSetter* ins) {
6836 MDefinition* object = ins->object();
6837 MOZ_ASSERT(object->type() == MIRType::Object);
6839 auto* guard = new (alloc())
6840 LGuardHasGetterSetter(useRegisterAtStart(object), tempFixed(CallTempReg0),
6841 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
6842 assignSnapshot(guard, ins->bailoutKind());
6843 add(guard, ins);
6844 redefine(ins, object);
6847 void LIRGenerator::visitGuardIsExtensible(MGuardIsExtensible* ins) {
6848 MDefinition* object = ins->object();
6849 MOZ_ASSERT(object->type() == MIRType::Object);
6851 auto* guard = new (alloc()) LGuardIsExtensible(useRegister(object), temp());
6852 assignSnapshot(guard, ins->bailoutKind());
6853 add(guard, ins);
6854 redefine(ins, object);
6857 void LIRGenerator::visitGuardInt32IsNonNegative(MGuardInt32IsNonNegative* ins) {
6858 MDefinition* index = ins->index();
6859 MOZ_ASSERT(index->type() == MIRType::Int32);
6861 auto* guard = new (alloc()) LGuardInt32IsNonNegative(useRegister(index));
6862 assignSnapshot(guard, ins->bailoutKind());
6863 add(guard, ins);
6864 redefine(ins, index);
6867 void LIRGenerator::visitGuardInt32Range(MGuardInt32Range* ins) {
6868 MDefinition* input = ins->input();
6869 MOZ_ASSERT(input->type() == MIRType::Int32);
6871 auto* guard = new (alloc()) LGuardInt32Range(useRegister(input));
6872 assignSnapshot(guard, ins->bailoutKind());
6873 add(guard, ins);
6874 redefine(ins, input);
6877 void LIRGenerator::visitGuardIndexIsNotDenseElement(
6878 MGuardIndexIsNotDenseElement* ins) {
6879 MDefinition* object = ins->object();
6880 MOZ_ASSERT(object->type() == MIRType::Object);
6882 MDefinition* index = ins->index();
6883 MOZ_ASSERT(index->type() == MIRType::Int32);
6885 LDefinition spectreTemp =
6886 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6888 auto* guard = new (alloc()) LGuardIndexIsNotDenseElement(
6889 useRegister(object), useRegister(index), temp(), spectreTemp);
6890 assignSnapshot(guard, ins->bailoutKind());
6891 add(guard, ins);
6892 redefine(ins, index);
6895 void LIRGenerator::visitGuardIndexIsValidUpdateOrAdd(
6896 MGuardIndexIsValidUpdateOrAdd* ins) {
6897 MDefinition* object = ins->object();
6898 MOZ_ASSERT(object->type() == MIRType::Object);
6900 MDefinition* index = ins->index();
6901 MOZ_ASSERT(index->type() == MIRType::Int32);
6903 LDefinition spectreTemp =
6904 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6906 auto* guard = new (alloc()) LGuardIndexIsValidUpdateOrAdd(
6907 useRegister(object), useRegister(index), temp(), spectreTemp);
6908 assignSnapshot(guard, ins->bailoutKind());
6909 add(guard, ins);
6910 redefine(ins, index);
6913 void LIRGenerator::visitCallAddOrUpdateSparseElement(
6914 MCallAddOrUpdateSparseElement* ins) {
6915 MDefinition* object = ins->object();
6916 MOZ_ASSERT(object->type() == MIRType::Object);
6918 MDefinition* index = ins->index();
6919 MOZ_ASSERT(index->type() == MIRType::Int32);
6921 MDefinition* value = ins->value();
6922 MOZ_ASSERT(value->type() == MIRType::Value);
6924 auto* lir = new (alloc()) LCallAddOrUpdateSparseElement(
6925 useRegisterAtStart(object), useRegisterAtStart(index),
6926 useBoxAtStart(value));
6927 add(lir, ins);
6928 assignSafepoint(lir, ins);
6931 void LIRGenerator::visitCallGetSparseElement(MCallGetSparseElement* ins) {
6932 MDefinition* object = ins->object();
6933 MOZ_ASSERT(object->type() == MIRType::Object);
6935 MDefinition* index = ins->index();
6936 MOZ_ASSERT(index->type() == MIRType::Int32);
6938 auto* lir = new (alloc()) LCallGetSparseElement(useRegisterAtStart(object),
6939 useRegisterAtStart(index));
6940 defineReturn(lir, ins);
6941 assignSafepoint(lir, ins);
6944 void LIRGenerator::visitCallNativeGetElement(MCallNativeGetElement* ins) {
6945 MDefinition* object = ins->object();
6946 MOZ_ASSERT(object->type() == MIRType::Object);
6948 MDefinition* index = ins->index();
6949 MOZ_ASSERT(index->type() == MIRType::Int32);
6951 auto* lir = new (alloc()) LCallNativeGetElement(useRegisterAtStart(object),
6952 useRegisterAtStart(index));
6953 defineReturn(lir, ins);
6954 assignSafepoint(lir, ins);
6957 void LIRGenerator::visitCallNativeGetElementSuper(
6958 MCallNativeGetElementSuper* ins) {
6959 MDefinition* object = ins->object();
6960 MOZ_ASSERT(object->type() == MIRType::Object);
6962 MDefinition* index = ins->index();
6963 MOZ_ASSERT(index->type() == MIRType::Int32);
6965 MDefinition* receiver = ins->receiver();
6967 auto* lir = new (alloc()) LCallNativeGetElementSuper(
6968 useRegisterAtStart(object), useRegisterAtStart(index),
6969 useBoxAtStart(receiver));
6970 defineReturn(lir, ins);
6971 assignSafepoint(lir, ins);
6974 void LIRGenerator::visitCallObjectHasSparseElement(
6975 MCallObjectHasSparseElement* ins) {
6976 MDefinition* object = ins->object();
6977 MOZ_ASSERT(object->type() == MIRType::Object);
6979 MDefinition* index = ins->index();
6980 MOZ_ASSERT(index->type() == MIRType::Int32);
6982 auto* lir = new (alloc()) LCallObjectHasSparseElement(
6983 useRegisterAtStart(object), useRegisterAtStart(index),
6984 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
6985 assignSnapshot(lir, ins->bailoutKind());
6986 defineReturn(lir, ins);
6989 void LIRGenerator::visitBigIntAsIntN(MBigIntAsIntN* ins) {
6990 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
6991 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
6993 if (ins->bits()->isConstant()) {
6994 int32_t bits = ins->bits()->toConstant()->toInt32();
6995 if (bits == 64) {
6996 auto* lir = new (alloc())
6997 LBigIntAsIntN64(useRegister(ins->input()), temp(), tempInt64());
6998 define(lir, ins);
6999 assignSafepoint(lir, ins);
7000 return;
7002 if (bits == 32) {
7003 auto* lir = new (alloc())
7004 LBigIntAsIntN32(useRegister(ins->input()), temp(), tempInt64());
7005 define(lir, ins);
7006 assignSafepoint(lir, ins);
7007 return;
7011 auto* lir = new (alloc()) LBigIntAsIntN(useRegisterAtStart(ins->bits()),
7012 useRegisterAtStart(ins->input()));
7013 defineReturn(lir, ins);
7014 assignSafepoint(lir, ins);
7017 void LIRGenerator::visitBigIntAsUintN(MBigIntAsUintN* ins) {
7018 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
7019 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
7021 if (ins->bits()->isConstant()) {
7022 int32_t bits = ins->bits()->toConstant()->toInt32();
7023 if (bits == 64) {
7024 auto* lir = new (alloc())
7025 LBigIntAsUintN64(useRegister(ins->input()), temp(), tempInt64());
7026 define(lir, ins);
7027 assignSafepoint(lir, ins);
7028 return;
7030 if (bits == 32) {
7031 auto* lir = new (alloc())
7032 LBigIntAsUintN32(useRegister(ins->input()), temp(), tempInt64());
7033 define(lir, ins);
7034 assignSafepoint(lir, ins);
7035 return;
7039 auto* lir = new (alloc()) LBigIntAsUintN(useRegisterAtStart(ins->bits()),
7040 useRegisterAtStart(ins->input()));
7041 defineReturn(lir, ins);
7042 assignSafepoint(lir, ins);
7045 void LIRGenerator::visitGuardNonGCThing(MGuardNonGCThing* ins) {
7046 MDefinition* input = ins->input();
7048 auto* guard = new (alloc()) LGuardNonGCThing(useBox(input));
7049 assignSnapshot(guard, ins->bailoutKind());
7050 add(guard, ins);
7051 redefine(ins, input);
7054 void LIRGenerator::visitToHashableNonGCThing(MToHashableNonGCThing* ins) {
7055 auto* lir =
7056 new (alloc()) LToHashableNonGCThing(useBox(ins->input()), tempDouble());
7057 defineBox(lir, ins);
7060 void LIRGenerator::visitToHashableString(MToHashableString* ins) {
7061 auto* lir = new (alloc()) LToHashableString(useRegister(ins->input()));
7062 define(lir, ins);
7063 assignSafepoint(lir, ins);
7066 void LIRGenerator::visitToHashableValue(MToHashableValue* ins) {
7067 auto* lir =
7068 new (alloc()) LToHashableValue(useBox(ins->input()), tempDouble());
7069 defineBox(lir, ins);
7070 assignSafepoint(lir, ins);
7073 void LIRGenerator::visitHashNonGCThing(MHashNonGCThing* ins) {
7074 auto* lir = new (alloc()) LHashNonGCThing(useBox(ins->input()), temp());
7075 define(lir, ins);
7078 void LIRGenerator::visitHashString(MHashString* ins) {
7079 auto* lir = new (alloc()) LHashString(useRegister(ins->input()), temp());
7080 define(lir, ins);
7083 void LIRGenerator::visitHashSymbol(MHashSymbol* ins) {
7084 auto* lir = new (alloc()) LHashSymbol(useRegister(ins->input()));
7085 define(lir, ins);
7088 void LIRGenerator::visitHashBigInt(MHashBigInt* ins) {
7089 auto* lir = new (alloc())
7090 LHashBigInt(useRegister(ins->input()), temp(), temp(), temp());
7091 define(lir, ins);
7094 void LIRGenerator::visitHashObject(MHashObject* ins) {
7095 auto* lir =
7096 new (alloc()) LHashObject(useRegister(ins->set()), useBox(ins->input()),
7097 temp(), temp(), temp(), temp());
7098 define(lir, ins);
7101 void LIRGenerator::visitHashValue(MHashValue* ins) {
7102 auto* lir =
7103 new (alloc()) LHashValue(useRegister(ins->set()), useBox(ins->input()),
7104 temp(), temp(), temp(), temp());
7105 define(lir, ins);
7108 void LIRGenerator::visitSetObjectHasNonBigInt(MSetObjectHasNonBigInt* ins) {
7109 auto* lir = new (alloc())
7110 LSetObjectHasNonBigInt(useRegister(ins->set()), useBox(ins->value()),
7111 useRegister(ins->hash()), temp(), temp());
7112 define(lir, ins);
7115 void LIRGenerator::visitSetObjectHasBigInt(MSetObjectHasBigInt* ins) {
7116 auto* lir = new (alloc()) LSetObjectHasBigInt(
7117 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
7118 temp(), temp(), temp(), temp());
7119 define(lir, ins);
7122 void LIRGenerator::visitSetObjectHasValue(MSetObjectHasValue* ins) {
7123 auto* lir = new (alloc()) LSetObjectHasValue(
7124 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
7125 temp(), temp(), temp(), temp());
7126 define(lir, ins);
7129 void LIRGenerator::visitSetObjectHasValueVMCall(MSetObjectHasValueVMCall* ins) {
7130 auto* lir = new (alloc()) LSetObjectHasValueVMCall(
7131 useRegisterAtStart(ins->set()), useBoxAtStart(ins->value()));
7132 defineReturn(lir, ins);
7133 assignSafepoint(lir, ins);
7136 void LIRGenerator::visitSetObjectSize(MSetObjectSize* ins) {
7137 auto* lir = new (alloc()) LSetObjectSize(useRegisterAtStart(ins->set()));
7138 define(lir, ins);
7141 void LIRGenerator::visitMapObjectHasNonBigInt(MMapObjectHasNonBigInt* ins) {
7142 auto* lir = new (alloc())
7143 LMapObjectHasNonBigInt(useRegister(ins->map()), useBox(ins->value()),
7144 useRegister(ins->hash()), temp(), temp());
7145 define(lir, ins);
7148 void LIRGenerator::visitMapObjectHasBigInt(MMapObjectHasBigInt* ins) {
7149 auto* lir = new (alloc()) LMapObjectHasBigInt(
7150 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7151 temp(), temp(), temp(), temp());
7152 define(lir, ins);
7155 void LIRGenerator::visitMapObjectHasValue(MMapObjectHasValue* ins) {
7156 auto* lir = new (alloc()) LMapObjectHasValue(
7157 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7158 temp(), temp(), temp(), temp());
7159 define(lir, ins);
7162 void LIRGenerator::visitMapObjectHasValueVMCall(MMapObjectHasValueVMCall* ins) {
7163 auto* lir = new (alloc()) LMapObjectHasValueVMCall(
7164 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
7165 defineReturn(lir, ins);
7166 assignSafepoint(lir, ins);
7169 void LIRGenerator::visitMapObjectGetNonBigInt(MMapObjectGetNonBigInt* ins) {
7170 auto* lir = new (alloc())
7171 LMapObjectGetNonBigInt(useRegister(ins->map()), useBox(ins->value()),
7172 useRegister(ins->hash()), temp(), temp());
7173 defineBox(lir, ins);
7176 void LIRGenerator::visitMapObjectGetBigInt(MMapObjectGetBigInt* ins) {
7177 auto* lir = new (alloc()) LMapObjectGetBigInt(
7178 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7179 temp(), temp(), temp(), temp());
7180 defineBox(lir, ins);
7183 void LIRGenerator::visitMapObjectGetValue(MMapObjectGetValue* ins) {
7184 auto* lir = new (alloc()) LMapObjectGetValue(
7185 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
7186 temp(), temp(), temp(), temp());
7187 defineBox(lir, ins);
7190 void LIRGenerator::visitMapObjectGetValueVMCall(MMapObjectGetValueVMCall* ins) {
7191 auto* lir = new (alloc()) LMapObjectGetValueVMCall(
7192 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
7193 defineReturn(lir, ins);
7194 assignSafepoint(lir, ins);
7197 void LIRGenerator::visitMapObjectSize(MMapObjectSize* ins) {
7198 auto* lir = new (alloc()) LMapObjectSize(useRegisterAtStart(ins->map()));
7199 define(lir, ins);
7202 void LIRGenerator::visitPostIntPtrConversion(MPostIntPtrConversion* ins) {
7203 // This operation is a no-op.
7204 redefine(ins, ins->input());
7207 void LIRGenerator::visitConstant(MConstant* ins) {
7208 if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
7209 emitAtUses(ins);
7210 return;
7213 switch (ins->type()) {
7214 case MIRType::Double:
7215 define(new (alloc()) LDouble(ins->toDouble()), ins);
7216 break;
7217 case MIRType::Float32:
7218 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
7219 break;
7220 case MIRType::Boolean:
7221 define(new (alloc()) LInteger(ins->toBoolean()), ins);
7222 break;
7223 case MIRType::Int32:
7224 define(new (alloc()) LInteger(ins->toInt32()), ins);
7225 break;
7226 case MIRType::Int64:
7227 defineInt64(new (alloc()) LInteger64(ins->toInt64()), ins);
7228 break;
7229 case MIRType::IntPtr:
7230 #ifdef JS_64BIT
7231 defineInt64(new (alloc()) LInteger64(ins->toIntPtr()), ins);
7232 #else
7233 define(new (alloc()) LInteger(ins->toIntPtr()), ins);
7234 #endif
7235 break;
7236 case MIRType::String:
7237 define(new (alloc()) LPointer(ins->toString()), ins);
7238 break;
7239 case MIRType::Symbol:
7240 define(new (alloc()) LPointer(ins->toSymbol()), ins);
7241 break;
7242 case MIRType::BigInt:
7243 define(new (alloc()) LPointer(ins->toBigInt()), ins);
7244 break;
7245 case MIRType::Object:
7246 define(new (alloc()) LPointer(&ins->toObject()), ins);
7247 break;
7248 case MIRType::Shape:
7249 MOZ_ASSERT(ins->isEmittedAtUses());
7250 break;
7251 default:
7252 // Constants of special types (undefined, null) should never flow into
7253 // here directly. Operations blindly consuming them require a Box.
7254 MOZ_CRASH("unexpected constant type");
7258 void LIRGenerator::visitConstantProto(MConstantProto* ins) {
7259 JSObject* obj = &ins->protoObject()->toConstant()->toObject();
7260 define(new (alloc()) LPointer(obj), ins);
7263 void LIRGenerator::visitWasmNullConstant(MWasmNullConstant* ins) {
7264 define(new (alloc()) LWasmNullConstant(), ins);
7267 void LIRGenerator::visitWasmFloatConstant(MWasmFloatConstant* ins) {
7268 switch (ins->type()) {
7269 case MIRType::Double:
7270 define(new (alloc()) LDouble(ins->toDouble()), ins);
7271 break;
7272 case MIRType::Float32:
7273 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
7274 break;
7275 #ifdef ENABLE_WASM_SIMD
7276 case MIRType::Simd128:
7277 define(new (alloc()) LSimd128(ins->toSimd128()), ins);
7278 break;
7279 #endif
7280 default:
7281 MOZ_CRASH("unexpected constant type");
7285 #ifdef JS_JITSPEW
7286 static void SpewResumePoint(MBasicBlock* block, MInstruction* ins,
7287 MResumePoint* resumePoint) {
7288 Fprinter& out = JitSpewPrinter();
7289 out.printf("Current resume point %p details:\n", (void*)resumePoint);
7290 out.printf(" frame count: %u\n", resumePoint->frameCount());
7292 if (ins) {
7293 out.printf(" taken after: ");
7294 ins->printName(out);
7295 } else {
7296 out.printf(" taken at block %u entry", block->id());
7298 out.printf("\n");
7300 out.printf(" pc: %p (script: %p, offset: %d)\n", (void*)resumePoint->pc(),
7301 (void*)resumePoint->block()->info().script(),
7302 int(resumePoint->block()->info().script()->pcToOffset(
7303 resumePoint->pc())));
7305 for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) {
7306 MDefinition* in = resumePoint->getOperand(i);
7307 out.printf(" slot%u: ", (unsigned)i);
7308 in->printName(out);
7309 out.printf("\n");
7312 #endif
7314 void LIRGenerator::visitInstructionDispatch(MInstruction* ins) {
7315 #ifdef JS_CODEGEN_NONE
7316 // Don't compile the switch-statement below so that we don't have to define
7317 // the platform-specific visit* methods for the none-backend.
7318 MOZ_CRASH();
7319 #else
7320 switch (ins->op()) {
7321 # define MIR_OP(op) \
7322 case MDefinition::Opcode::op: \
7323 visit##op(ins->to##op()); \
7324 break;
7325 MIR_OPCODE_LIST(MIR_OP)
7326 # undef MIR_OP
7327 default:
7328 MOZ_CRASH("Invalid instruction");
7330 #endif
7333 void LIRGeneratorShared::visitEmittedAtUses(MInstruction* ins) {
7334 static_cast<LIRGenerator*>(this)->visitInstructionDispatch(ins);
7337 bool LIRGenerator::visitInstruction(MInstruction* ins) {
7338 MOZ_ASSERT(!errored());
7340 if (ins->isRecoveredOnBailout()) {
7341 MOZ_ASSERT(!JitOptions.disableRecoverIns);
7342 return true;
7345 if (!gen->ensureBallast()) {
7346 return false;
7348 visitInstructionDispatch(ins);
7350 if (ins->resumePoint()) {
7351 updateResumeState(ins);
7354 #ifdef DEBUG
7355 ins->setInWorklistUnchecked();
7356 #endif
7358 // If no safepoint was created, there's no need for an OSI point.
7359 if (LOsiPoint* osiPoint = popOsiPoint()) {
7360 add(osiPoint);
7363 return !errored();
7366 bool LIRGenerator::definePhis() {
7367 size_t lirIndex = 0;
7368 MBasicBlock* block = current->mir();
7369 for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
7370 if (phi->type() == MIRType::Value) {
7371 defineUntypedPhi(*phi, lirIndex);
7372 lirIndex += BOX_PIECES;
7373 } else if (phi->type() == MIRType::Int64) {
7374 defineInt64Phi(*phi, lirIndex);
7375 lirIndex += INT64_PIECES;
7376 } else {
7377 defineTypedPhi(*phi, lirIndex);
7378 lirIndex += 1;
7381 return !errored();
7384 void LIRGenerator::updateResumeState(MInstruction* ins) {
7385 lastResumePoint_ = ins->resumePoint();
7386 #ifdef JS_JITSPEW
7387 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
7388 SpewResumePoint(nullptr, ins, lastResumePoint_);
7390 #endif
7393 void LIRGenerator::updateResumeState(MBasicBlock* block) {
7394 // Note: RangeAnalysis can flag blocks as unreachable, but they are only
7395 // removed iff GVN (including UCE) is enabled.
7396 MOZ_ASSERT_IF(!mir()->compilingWasm() && !block->unreachable(),
7397 block->entryResumePoint());
7398 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7399 lastResumePoint_ = block->entryResumePoint();
7400 #ifdef JS_JITSPEW
7401 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
7402 SpewResumePoint(block, nullptr, lastResumePoint_);
7404 #endif
7407 bool LIRGenerator::visitBlock(MBasicBlock* block) {
7408 current = block->lir();
7409 updateResumeState(block);
7411 if (!definePhis()) {
7412 return false;
7415 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7416 for (MInstructionIterator iter = block->begin(); *iter != block->lastIns();
7417 iter++) {
7418 if (!visitInstruction(*iter)) {
7419 return false;
7423 if (block->successorWithPhis()) {
7424 // If we have a successor with phis, lower the phi input now that we
7425 // are approaching the join point.
7426 MBasicBlock* successor = block->successorWithPhis();
7427 uint32_t position = block->positionInPhiSuccessor();
7428 size_t lirIndex = 0;
7429 for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd();
7430 phi++) {
7431 if (!gen->ensureBallast()) {
7432 return false;
7435 MDefinition* opd = phi->getOperand(position);
7436 ensureDefined(opd);
7438 MOZ_ASSERT(opd->type() == phi->type());
7440 if (phi->type() == MIRType::Value) {
7441 lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex);
7442 lirIndex += BOX_PIECES;
7443 } else if (phi->type() == MIRType::Int64) {
7444 lowerInt64PhiInput(*phi, position, successor->lir(), lirIndex);
7445 lirIndex += INT64_PIECES;
7446 } else {
7447 lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex);
7448 lirIndex += 1;
7453 // Now emit the last instruction, which is some form of branch.
7454 if (!visitInstruction(block->lastIns())) {
7455 return false;
7458 return true;
7461 void LIRGenerator::visitNaNToZero(MNaNToZero* ins) {
7462 MDefinition* input = ins->input();
7464 if (ins->operandIsNeverNaN() && ins->operandIsNeverNegativeZero()) {
7465 redefine(ins, input);
7466 return;
7468 LNaNToZero* lir =
7469 new (alloc()) LNaNToZero(useRegisterAtStart(input), tempDouble());
7470 defineReuseInput(lir, ins, 0);
7473 bool LIRGenerator::generate() {
7474 // Create all blocks and prep all phis beforehand.
7475 for (ReversePostorderIterator block(graph.rpoBegin());
7476 block != graph.rpoEnd(); block++) {
7477 if (gen->shouldCancel("Lowering (preparation loop)")) {
7478 return false;
7481 if (!lirGraph_.initBlock(*block)) {
7482 return false;
7486 for (ReversePostorderIterator block(graph.rpoBegin());
7487 block != graph.rpoEnd(); block++) {
7488 if (gen->shouldCancel("Lowering (main loop)")) {
7489 return false;
7492 if (!visitBlock(*block)) {
7493 return false;
7497 lirGraph_.setArgumentSlotCount(maxargslots_);
7498 return true;
7501 void LIRGenerator::visitPhi(MPhi* phi) {
7502 // Phi nodes are not lowered because they are only meaningful for the register
7503 // allocator.
7504 MOZ_CRASH("Unexpected Phi node during Lowering.");
7507 void LIRGenerator::visitBeta(MBeta* beta) {
7508 // Beta nodes are supposed to be removed before because they are
7509 // only used to carry the range information for Range analysis
7510 MOZ_CRASH("Unexpected Beta node during Lowering.");
7513 void LIRGenerator::visitObjectState(MObjectState* objState) {
7514 // ObjectState nodes are always recovered on bailouts
7515 MOZ_CRASH("Unexpected ObjectState node during Lowering.");
7518 void LIRGenerator::visitArrayState(MArrayState* objState) {
7519 // ArrayState nodes are always recovered on bailouts
7520 MOZ_CRASH("Unexpected ArrayState node during Lowering.");
7523 void LIRGenerator::visitIonToWasmCall(MIonToWasmCall* ins) {
7524 // The instruction needs a temp register:
7525 // - that's not the FramePointer, since wasm is going to use it in the
7526 // function.
7527 // - that's not aliasing an input register.
7528 LDefinition scratch = tempFixed(ABINonArgReg0);
7530 // Note that since this is a LIR call instruction, regalloc will prevent
7531 // the use*AtStart below from reusing any of the temporaries.
7533 LInstruction* lir;
7534 if (ins->type() == MIRType::Value) {
7535 lir = allocateVariadic<LIonToWasmCallV>(ins->numOperands(), scratch);
7536 } else if (ins->type() == MIRType::Int64) {
7537 lir = allocateVariadic<LIonToWasmCallI64>(ins->numOperands(), scratch);
7538 } else {
7539 lir = allocateVariadic<LIonToWasmCall>(ins->numOperands(), scratch);
7541 if (!lir) {
7542 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitIonToWasmCall");
7543 return;
7546 ABIArgGenerator abi;
7547 for (unsigned i = 0; i < ins->numOperands(); i++) {
7548 MDefinition* argDef = ins->getOperand(i);
7549 ABIArg arg = abi.next(ToMIRType(argDef->type()));
7550 switch (arg.kind()) {
7551 case ABIArg::GPR:
7552 case ABIArg::FPU:
7553 lir->setOperand(i, useFixedAtStart(argDef, arg.reg()));
7554 break;
7555 case ABIArg::Stack:
7556 lir->setOperand(i, useAtStart(argDef));
7557 break;
7558 #ifdef JS_CODEGEN_REGISTER_PAIR
7559 case ABIArg::GPR_PAIR:
7560 MOZ_CRASH(
7561 "no way to pass i64, and wasm uses hardfp for function calls");
7562 #endif
7563 case ABIArg::Uninitialized:
7564 MOZ_CRASH("Uninitialized ABIArg kind");
7568 defineReturn(lir, ins);
7569 assignSafepoint(lir, ins);
7572 void LIRGenerator::visitWasmSelect(MWasmSelect* ins) {
7573 MDefinition* condExpr = ins->condExpr();
7575 // Pick off specific cases that we can do with LWasmCompareAndSelect to avoid
7576 // generating a boolean that we then have to test again.
7577 if (condExpr->isCompare() && condExpr->isEmittedAtUses()) {
7578 MCompare* comp = condExpr->toCompare();
7579 MCompare::CompareType compTy = comp->compareType();
7580 if (canSpecializeWasmCompareAndSelect(compTy, ins->type())) {
7581 JSOp jsop = comp->jsop();
7582 // We don't currently generate any other JSOPs for the comparison, and if
7583 // that changes, we want to know about it. Hence this assertion.
7584 MOZ_ASSERT(jsop == JSOp::Eq || jsop == JSOp::Ne || jsop == JSOp::Lt ||
7585 jsop == JSOp::Gt || jsop == JSOp::Le || jsop == JSOp::Ge);
7586 MDefinition* lhs = comp->lhs();
7587 MDefinition* rhs = comp->rhs();
7588 jsop = ReorderComparison(jsop, &lhs, &rhs);
7589 lowerWasmCompareAndSelect(ins, lhs, rhs, compTy, jsop);
7590 return;
7593 // Fall through to code that generates a boolean and selects on that.
7595 if (ins->type() == MIRType::Int64) {
7596 lowerWasmSelectI64(ins);
7597 return;
7600 lowerWasmSelectI(ins);
7603 void LIRGenerator::visitWasmFence(MWasmFence* ins) {
7604 add(new (alloc()) LWasmFence, ins);
7607 void LIRGenerator::visitWasmLoadField(MWasmLoadField* ins) {
7608 uint32_t offs = ins->offset();
7609 LAllocation obj = useRegister(ins->obj());
7610 MWideningOp wideningOp = ins->wideningOp();
7611 if (ins->type() == MIRType::Int64) {
7612 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7613 defineInt64(new (alloc()) LWasmLoadSlotI64(obj, offs, ins->maybeTrap()),
7614 ins);
7615 } else {
7616 define(new (alloc()) LWasmLoadSlot(obj, offs, ins->type(), wideningOp,
7617 ins->maybeTrap()),
7618 ins);
7622 void LIRGenerator::visitWasmLoadFieldKA(MWasmLoadFieldKA* ins) {
7623 uint32_t offs = ins->offset();
7624 LAllocation obj = useRegister(ins->obj());
7625 MWideningOp wideningOp = ins->wideningOp();
7626 if (ins->type() == MIRType::Int64) {
7627 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7628 defineInt64(new (alloc()) LWasmLoadSlotI64(obj, offs, ins->maybeTrap()),
7629 ins);
7630 } else {
7631 define(new (alloc()) LWasmLoadSlot(obj, offs, ins->type(), wideningOp,
7632 ins->maybeTrap()),
7633 ins);
7635 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7638 void LIRGenerator::visitWasmLoadElementKA(MWasmLoadElementKA* ins) {
7639 LAllocation base = useRegister(ins->base());
7640 LAllocation index = useRegister(ins->index());
7641 MWideningOp wideningOp = ins->wideningOp();
7642 Scale scale = ins->scale();
7643 if (ins->type() == MIRType::Int64) {
7644 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7645 defineInt64(
7646 new (alloc()) LWasmLoadElementI64(base, index, ins->maybeTrap()), ins);
7647 } else {
7648 LDefinition tmp =
7649 ins->type() == MIRType::Simd128 ? temp() : LDefinition::BogusTemp();
7650 define(new (alloc()) LWasmLoadElement(base, index, tmp, ins->type(),
7651 wideningOp, scale, ins->maybeTrap()),
7652 ins);
7654 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7657 void LIRGenerator::visitWasmStoreFieldKA(MWasmStoreFieldKA* ins) {
7658 MDefinition* value = ins->value();
7659 uint32_t offs = ins->offset();
7660 MNarrowingOp narrowingOp = ins->narrowingOp();
7661 LAllocation obj = useRegister(ins->obj());
7662 LInstruction* lir;
7663 if (value->type() == MIRType::Int64) {
7664 MOZ_RELEASE_ASSERT(narrowingOp == MNarrowingOp::None);
7665 lir = new (alloc())
7666 LWasmStoreSlotI64(useInt64Register(value), obj, offs, ins->maybeTrap());
7667 } else {
7668 lir = new (alloc())
7669 LWasmStoreSlot(useRegister(value), obj, offs, value->type(),
7670 narrowingOp, ins->maybeTrap());
7672 add(lir, ins);
7673 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7676 void LIRGenerator::visitWasmStoreFieldRefKA(MWasmStoreFieldRefKA* ins) {
7677 LAllocation instance = useRegister(ins->instance());
7678 LAllocation obj = useFixed(ins->obj(), PreBarrierReg);
7679 LAllocation value = useRegister(ins->value());
7680 uint32_t offset = ins->offset();
7681 add(new (alloc()) LWasmStoreRef(instance, obj, value, temp(), offset,
7682 ins->maybeTrap(), ins->preBarrierKind()),
7683 ins);
7684 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7687 void LIRGenerator::visitWasmStoreElementKA(MWasmStoreElementKA* ins) {
7688 LAllocation base = useRegister(ins->base());
7689 LAllocation index = useRegister(ins->index());
7690 MDefinition* value = ins->value();
7691 MNarrowingOp narrowingOp = ins->narrowingOp();
7692 Scale scale = ins->scale();
7693 LInstruction* lir;
7694 if (value->type() == MIRType::Int64) {
7695 MOZ_RELEASE_ASSERT(narrowingOp == MNarrowingOp::None);
7696 lir = new (alloc()) LWasmStoreElementI64(
7697 base, index, useInt64Register(value), ins->maybeTrap());
7698 } else {
7699 LDefinition tmp =
7700 value->type() == MIRType::Simd128 ? temp() : LDefinition::BogusTemp();
7701 lir = new (alloc())
7702 LWasmStoreElement(base, index, useRegister(value), tmp, value->type(),
7703 narrowingOp, scale, ins->maybeTrap());
7705 add(lir, ins);
7706 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7709 void LIRGenerator::visitWasmStoreElementRefKA(MWasmStoreElementRefKA* ins) {
7710 LAllocation instance = useRegister(ins->instance());
7711 LAllocation base = useFixed(ins->base(), PreBarrierReg);
7712 LAllocation index = useRegister(ins->index());
7713 LAllocation value = useRegister(ins->value());
7714 bool needTemps = ins->preBarrierKind() == WasmPreBarrierKind::Normal;
7715 LDefinition temp0 = needTemps ? temp() : LDefinition::BogusTemp();
7716 LDefinition temp1 = needTemps ? temp() : LDefinition::BogusTemp();
7717 add(new (alloc())
7718 LWasmStoreElementRef(instance, base, index, value, temp0, temp1,
7719 ins->maybeTrap(), ins->preBarrierKind()),
7720 ins);
7721 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7724 WasmRefIsSubtypeDefs LIRGenerator::useWasmRefIsSubtype(wasm::RefType destType,
7725 MDefinition* superSTV) {
7726 BranchWasmRefIsSubtypeRegisters needs =
7727 MacroAssembler::regsForBranchWasmRefIsSubtype(destType);
7728 return WasmRefIsSubtypeDefs{
7729 .superSTV = needs.needSuperSTV ? useRegister(superSTV) : LAllocation(),
7730 .scratch1 = needs.needScratch1 ? temp() : LDefinition(),
7731 .scratch2 = needs.needScratch2 ? temp() : LDefinition(),
7735 void LIRGenerator::visitWasmRefIsSubtypeOfAbstract(
7736 MWasmRefIsSubtypeOfAbstract* ins) {
7737 if (CanEmitAtUseForSingleTest(ins)) {
7738 emitAtUses(ins);
7739 return;
7742 LAllocation ref = useRegister(ins->ref());
7743 WasmRefIsSubtypeDefs regs =
7744 useWasmRefIsSubtype(ins->destType(), /*superSTV=*/nullptr);
7745 define(new (alloc()) LWasmRefIsSubtypeOfAbstract(ref, regs.scratch1), ins);
7748 void LIRGenerator::visitWasmRefIsSubtypeOfConcrete(
7749 MWasmRefIsSubtypeOfConcrete* ins) {
7750 if (CanEmitAtUseForSingleTest(ins)) {
7751 emitAtUses(ins);
7752 return;
7755 LAllocation ref = useRegister(ins->ref());
7756 WasmRefIsSubtypeDefs regs =
7757 useWasmRefIsSubtype(ins->destType(), ins->superSTV());
7758 define(new (alloc()) LWasmRefIsSubtypeOfConcrete(
7759 ref, regs.superSTV, regs.scratch1, regs.scratch2),
7760 ins);
7763 void LIRGenerator::visitWasmNewStructObject(MWasmNewStructObject* ins) {
7764 LWasmNewStructObject* lir = new (alloc())
7765 LWasmNewStructObject(useFixed(ins->instance(), InstanceReg),
7766 useRegister(ins->typeDefData()), temp(), temp());
7767 define(lir, ins);
7768 assignWasmSafepoint(lir);
7771 void LIRGenerator::visitWasmNewArrayObject(MWasmNewArrayObject* ins) {
7772 LWasmNewArrayObject* lir = new (alloc())
7773 LWasmNewArrayObject(useFixed(ins->instance(), InstanceReg),
7774 useRegisterOrConstant(ins->numElements()),
7775 useRegister(ins->typeDefData()), temp(), temp());
7776 define(lir, ins);
7777 assignWasmSafepoint(lir);
7780 #ifdef FUZZING_JS_FUZZILLI
7781 void LIRGenerator::visitFuzzilliHash(MFuzzilliHash* ins) {
7782 MDefinition* value = ins->getOperand(0);
7784 if (value->type() == MIRType::Undefined || value->type() == MIRType::Null) {
7785 define(new (alloc()) LFuzzilliHashT(LAllocation(), temp(), tempDouble()),
7786 ins);
7787 } else if (value->type() == MIRType::Int32 ||
7788 value->type() == MIRType::Double ||
7789 value->type() == MIRType::Float32 ||
7790 value->type() == MIRType::Boolean ||
7791 value->type() == MIRType::BigInt) {
7792 define(new (alloc())
7793 LFuzzilliHashT(useRegister(value), temp(), tempDouble()),
7794 ins);
7795 } else if (value->type() == MIRType::Object) {
7796 LFuzzilliHashT* lir =
7797 new (alloc()) LFuzzilliHashT(useRegister(value), temp(), tempDouble());
7798 define(lir, ins);
7799 assignSafepoint(lir, ins);
7800 } else if (value->type() == MIRType::Value) {
7801 LFuzzilliHashV* lir =
7802 new (alloc()) LFuzzilliHashV(useBox(value), temp(), tempDouble());
7803 define(lir, ins);
7804 assignSafepoint(lir, ins);
7805 } else {
7806 define(new (alloc()) LInteger(0), ins);
7810 void LIRGenerator::visitFuzzilliHashStore(MFuzzilliHashStore* ins) {
7811 MDefinition* value = ins->getOperand(0);
7812 MOZ_ASSERT(value->type() == MIRType::Int32);
7813 add(new (alloc()) LFuzzilliHashStore(useRegister(value), temp(), temp()),
7814 ins);
7816 #endif
7818 static_assert(!std::is_polymorphic_v<LIRGenerator>,
7819 "LIRGenerator should not have any virtual methods");
7821 #ifdef JS_CODEGEN_NONE
7822 void LIRGenerator::visitReturnImpl(MDefinition*, bool) { MOZ_CRASH(); }
7823 #endif