Bug 1843499 - Part 1: Add ThrowWithStack and ExceptionAndStack opcodes. r=iain
[gecko.git] / js / src / jit / Lowering.cpp
blobd48d5d648cd2ced8fed41e876e4beaab3a78c057
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/Lowering.h"
9 #include "mozilla/DebugOnly.h"
10 #include "mozilla/EndianUtils.h"
11 #include "mozilla/FloatingPoint.h"
12 #include "mozilla/MathAlgorithms.h"
14 #include <type_traits>
16 #include "jit/ABIArgGenerator.h"
17 #include "jit/IonGenericCallStub.h"
18 #include "jit/IonOptimizationLevels.h"
19 #include "jit/JitSpewer.h"
20 #include "jit/LIR.h"
21 #include "jit/MacroAssembler.h"
22 #include "jit/MIR.h"
23 #include "jit/MIRGraph.h"
24 #include "jit/SharedICRegisters.h"
25 #include "js/experimental/JitInfo.h" // JSJitInfo
26 #include "util/Memory.h"
27 #include "wasm/WasmCodegenTypes.h"
28 #include "wasm/WasmFeatures.h" // for wasm::ReportSimdAnalysis
29 #include "wasm/WasmInstanceData.h"
31 #include "jit/shared/Lowering-shared-inl.h"
32 #include "vm/BytecodeUtil-inl.h"
34 using namespace js;
35 using namespace jit;
37 using JS::GenericNaN;
38 using mozilla::DebugOnly;
40 LBoxAllocation LIRGenerator::useBoxFixedAtStart(MDefinition* mir,
41 ValueOperand op) {
42 #if defined(JS_NUNBOX32)
43 return useBoxFixed(mir, op.typeReg(), op.payloadReg(), true);
44 #elif defined(JS_PUNBOX64)
45 return useBoxFixed(mir, op.valueReg(), op.scratchReg(), true);
46 #endif
49 LBoxAllocation LIRGenerator::useBoxAtStart(MDefinition* mir,
50 LUse::Policy policy) {
51 return useBox(mir, policy, /* useAtStart = */ true);
54 void LIRGenerator::visitParameter(MParameter* param) {
55 ptrdiff_t offset;
56 if (param->index() == MParameter::THIS_SLOT) {
57 offset = THIS_FRAME_ARGSLOT;
58 } else {
59 offset = 1 + param->index();
62 LParameter* ins = new (alloc()) LParameter;
63 defineBox(ins, param, LDefinition::FIXED);
65 offset *= sizeof(Value);
66 #if defined(JS_NUNBOX32)
67 # if MOZ_BIG_ENDIAN()
68 ins->getDef(0)->setOutput(LArgument(offset));
69 ins->getDef(1)->setOutput(LArgument(offset + 4));
70 # else
71 ins->getDef(0)->setOutput(LArgument(offset + 4));
72 ins->getDef(1)->setOutput(LArgument(offset));
73 # endif
74 #elif defined(JS_PUNBOX64)
75 ins->getDef(0)->setOutput(LArgument(offset));
76 #endif
79 void LIRGenerator::visitCallee(MCallee* ins) {
80 define(new (alloc()) LCallee(), ins);
83 void LIRGenerator::visitIsConstructing(MIsConstructing* ins) {
84 define(new (alloc()) LIsConstructing(), ins);
87 void LIRGenerator::visitGoto(MGoto* ins) {
88 add(new (alloc()) LGoto(ins->target()));
91 void LIRGenerator::visitTableSwitch(MTableSwitch* tableswitch) {
92 MDefinition* opd = tableswitch->getOperand(0);
94 // There should be at least 1 successor. The default case!
95 MOZ_ASSERT(tableswitch->numSuccessors() > 0);
97 // If there are no cases, the default case is always taken.
98 if (tableswitch->numSuccessors() == 1) {
99 add(new (alloc()) LGoto(tableswitch->getDefault()));
100 return;
103 // If we don't know the type.
104 if (opd->type() == MIRType::Value) {
105 LTableSwitchV* lir = newLTableSwitchV(tableswitch);
106 add(lir);
107 return;
110 // Case indices are numeric, so other types will always go to the default
111 // case.
112 if (opd->type() != MIRType::Int32 && opd->type() != MIRType::Double) {
113 add(new (alloc()) LGoto(tableswitch->getDefault()));
114 return;
117 // Return an LTableSwitch, capable of handling either an integer or
118 // floating-point index.
119 LAllocation index;
120 LDefinition tempInt;
121 if (opd->type() == MIRType::Int32) {
122 index = useRegisterAtStart(opd);
123 tempInt = tempCopy(opd, 0);
124 } else {
125 index = useRegister(opd);
126 tempInt = temp(LDefinition::GENERAL);
128 add(newLTableSwitch(index, tempInt, tableswitch));
131 void LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed* ins) {
132 LCheckOverRecursed* lir = new (alloc()) LCheckOverRecursed();
133 add(lir, ins);
134 assignSafepoint(lir, ins);
137 void LIRGenerator::visitNewArray(MNewArray* ins) {
138 LNewArray* lir = new (alloc()) LNewArray(temp());
139 define(lir, ins);
140 assignSafepoint(lir, ins);
143 void LIRGenerator::visitNewArrayDynamicLength(MNewArrayDynamicLength* ins) {
144 MDefinition* length = ins->length();
145 MOZ_ASSERT(length->type() == MIRType::Int32);
147 LNewArrayDynamicLength* lir =
148 new (alloc()) LNewArrayDynamicLength(useRegister(length), temp());
149 define(lir, ins);
150 assignSafepoint(lir, ins);
153 void LIRGenerator::visitNewIterator(MNewIterator* ins) {
154 LNewIterator* lir = new (alloc()) LNewIterator(temp());
155 define(lir, ins);
156 assignSafepoint(lir, ins);
159 void LIRGenerator::visitNewTypedArray(MNewTypedArray* ins) {
160 LNewTypedArray* lir = new (alloc()) LNewTypedArray(temp(), temp());
161 define(lir, ins);
162 assignSafepoint(lir, ins);
165 void LIRGenerator::visitNewTypedArrayDynamicLength(
166 MNewTypedArrayDynamicLength* ins) {
167 MDefinition* length = ins->length();
168 MOZ_ASSERT(length->type() == MIRType::Int32);
170 LNewTypedArrayDynamicLength* lir =
171 new (alloc()) LNewTypedArrayDynamicLength(useRegister(length), temp());
172 define(lir, ins);
173 assignSafepoint(lir, ins);
176 void LIRGenerator::visitNewTypedArrayFromArray(MNewTypedArrayFromArray* ins) {
177 MDefinition* array = ins->array();
178 MOZ_ASSERT(array->type() == MIRType::Object);
180 auto* lir = new (alloc()) LNewTypedArrayFromArray(useRegisterAtStart(array));
181 defineReturn(lir, ins);
182 assignSafepoint(lir, ins);
185 void LIRGenerator::visitNewTypedArrayFromArrayBuffer(
186 MNewTypedArrayFromArrayBuffer* ins) {
187 MDefinition* arrayBuffer = ins->arrayBuffer();
188 MDefinition* byteOffset = ins->byteOffset();
189 MDefinition* length = ins->length();
190 MOZ_ASSERT(arrayBuffer->type() == MIRType::Object);
191 MOZ_ASSERT(byteOffset->type() == MIRType::Value);
192 MOZ_ASSERT(length->type() == MIRType::Value);
194 auto* lir = new (alloc()) LNewTypedArrayFromArrayBuffer(
195 useRegisterAtStart(arrayBuffer), useBoxAtStart(byteOffset),
196 useBoxAtStart(length));
197 defineReturn(lir, ins);
198 assignSafepoint(lir, ins);
201 void LIRGenerator::visitNewObject(MNewObject* ins) {
202 LNewObject* lir = new (alloc()) LNewObject(temp());
203 define(lir, ins);
204 assignSafepoint(lir, ins);
207 void LIRGenerator::visitBindFunction(MBindFunction* ins) {
208 MDefinition* target = ins->target();
209 MOZ_ASSERT(target->type() == MIRType::Object);
211 if (!lowerCallArguments(ins)) {
212 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitBindFunction");
213 return;
216 auto* lir = new (alloc())
217 LBindFunction(useFixedAtStart(target, CallTempReg0),
218 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
219 defineReturn(lir, ins);
220 assignSafepoint(lir, ins);
223 void LIRGenerator::visitNewBoundFunction(MNewBoundFunction* ins) {
224 auto* lir = new (alloc()) LNewBoundFunction(temp());
225 define(lir, ins);
226 assignSafepoint(lir, ins);
229 void LIRGenerator::visitNewPlainObject(MNewPlainObject* ins) {
230 LNewPlainObject* lir = new (alloc()) LNewPlainObject(temp(), temp(), temp());
231 define(lir, ins);
232 assignSafepoint(lir, ins);
235 void LIRGenerator::visitNewArrayObject(MNewArrayObject* ins) {
236 LNewArrayObject* lir = new (alloc()) LNewArrayObject(temp(), temp());
237 define(lir, ins);
238 assignSafepoint(lir, ins);
241 void LIRGenerator::visitNewNamedLambdaObject(MNewNamedLambdaObject* ins) {
242 LNewNamedLambdaObject* lir = new (alloc()) LNewNamedLambdaObject(temp());
243 define(lir, ins);
244 assignSafepoint(lir, ins);
247 void LIRGenerator::visitNewCallObject(MNewCallObject* ins) {
248 LNewCallObject* lir = new (alloc()) LNewCallObject(temp());
249 define(lir, ins);
250 assignSafepoint(lir, ins);
253 void LIRGenerator::visitNewStringObject(MNewStringObject* ins) {
254 MOZ_ASSERT(ins->input()->type() == MIRType::String);
256 LNewStringObject* lir =
257 new (alloc()) LNewStringObject(useRegister(ins->input()), temp());
258 define(lir, ins);
259 assignSafepoint(lir, ins);
262 void LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter* ins) {
263 LInitElemGetterSetter* lir = new (alloc()) LInitElemGetterSetter(
264 useRegisterAtStart(ins->object()), useBoxAtStart(ins->id()),
265 useRegisterAtStart(ins->value()));
266 add(lir, ins);
267 assignSafepoint(lir, ins);
270 void LIRGenerator::visitMutateProto(MMutateProto* ins) {
271 LMutateProto* lir = new (alloc()) LMutateProto(
272 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()));
273 add(lir, ins);
274 assignSafepoint(lir, ins);
277 void LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter* ins) {
278 LInitPropGetterSetter* lir = new (alloc()) LInitPropGetterSetter(
279 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->value()));
280 add(lir, ins);
281 assignSafepoint(lir, ins);
284 void LIRGenerator::visitCreateThis(MCreateThis* ins) {
285 LCreateThis* lir =
286 new (alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->callee()),
287 useRegisterOrConstantAtStart(ins->newTarget()));
288 defineReturn(lir, ins);
289 assignSafepoint(lir, ins);
292 void LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject* ins) {
293 LAllocation callObj = useRegisterAtStart(ins->getCallObject());
294 LCreateArgumentsObject* lir = new (alloc())
295 LCreateArgumentsObject(callObj, tempFixed(CallTempReg0),
296 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
297 defineReturn(lir, ins);
298 assignSafepoint(lir, ins);
301 void LIRGenerator::visitCreateInlinedArgumentsObject(
302 MCreateInlinedArgumentsObject* ins) {
303 LAllocation callObj = useRegisterAtStart(ins->getCallObject());
304 LAllocation callee = useRegisterAtStart(ins->getCallee());
305 uint32_t numActuals = ins->numActuals();
306 uint32_t numOperands = numActuals * BOX_PIECES +
307 LCreateInlinedArgumentsObject::NumNonArgumentOperands;
309 auto* lir = allocateVariadic<LCreateInlinedArgumentsObject>(
310 numOperands, tempFixed(CallTempReg0), tempFixed(CallTempReg1));
311 if (!lir) {
312 abort(AbortReason::Alloc,
313 "OOM: LIRGenerator::visitCreateInlinedArgumentsObject");
314 return;
317 lir->setOperand(LCreateInlinedArgumentsObject::CallObj, callObj);
318 lir->setOperand(LCreateInlinedArgumentsObject::Callee, callee);
319 for (uint32_t i = 0; i < numActuals; i++) {
320 MDefinition* arg = ins->getArg(i);
321 uint32_t index = LCreateInlinedArgumentsObject::ArgIndex(i);
322 lir->setBoxOperand(index, useBoxOrTypedOrConstant(arg,
323 /*useConstant = */ true,
324 /*useAtStart = */ true));
327 defineReturn(lir, ins);
328 assignSafepoint(lir, ins);
331 void LIRGenerator::visitGetInlinedArgument(MGetInlinedArgument* ins) {
332 #if defined(JS_PUNBOX64)
333 // On 64-bit architectures, we don't support boxing a typed register
334 // in-place without using a scratch register, so the result register
335 // can't be the same as any of the inputs. Fortunately, those
336 // architectures have registers to spare.
337 const bool useAtStart = false;
338 #else
339 const bool useAtStart = true;
340 #endif
342 LAllocation index =
343 useAtStart ? useRegisterAtStart(ins->index()) : useRegister(ins->index());
344 uint32_t numActuals = ins->numActuals();
345 uint32_t numOperands =
346 numActuals * BOX_PIECES + LGetInlinedArgument::NumNonArgumentOperands;
348 auto* lir = allocateVariadic<LGetInlinedArgument>(numOperands);
349 if (!lir) {
350 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgument");
351 return;
354 lir->setOperand(LGetInlinedArgument::Index, index);
355 for (uint32_t i = 0; i < numActuals; i++) {
356 MDefinition* arg = ins->getArg(i);
357 uint32_t index = LGetInlinedArgument::ArgIndex(i);
358 lir->setBoxOperand(
359 index, useBoxOrTypedOrConstant(arg,
360 /*useConstant = */ true, useAtStart));
362 defineBox(lir, ins);
365 void LIRGenerator::visitGetInlinedArgumentHole(MGetInlinedArgumentHole* ins) {
366 #if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_MIPS64)
367 // On some 64-bit architectures, we don't support boxing a typed
368 // register in-place without using a scratch register, so the result
369 // register can't be the same as any of the inputs. Fortunately,
370 // those architectures have registers to spare.
371 const bool useAtStart = false;
372 #else
373 const bool useAtStart = true;
374 #endif
376 LAllocation index =
377 useAtStart ? useRegisterAtStart(ins->index()) : useRegister(ins->index());
378 uint32_t numActuals = ins->numActuals();
379 uint32_t numOperands =
380 numActuals * BOX_PIECES + LGetInlinedArgumentHole::NumNonArgumentOperands;
382 auto* lir = allocateVariadic<LGetInlinedArgumentHole>(numOperands);
383 if (!lir) {
384 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgumentHole");
385 return;
388 lir->setOperand(LGetInlinedArgumentHole::Index, index);
389 for (uint32_t i = 0; i < numActuals; i++) {
390 MDefinition* arg = ins->getArg(i);
391 uint32_t index = LGetInlinedArgumentHole::ArgIndex(i);
392 lir->setBoxOperand(
393 index, useBoxOrTypedOrConstant(arg,
394 /*useConstant = */ true, useAtStart));
396 assignSnapshot(lir, ins->bailoutKind());
397 defineBox(lir, ins);
400 void LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins) {
401 LAllocation argsObj = useRegister(ins->argsObject());
402 LGetArgumentsObjectArg* lir =
403 new (alloc()) LGetArgumentsObjectArg(argsObj, temp());
404 defineBox(lir, ins);
407 void LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins) {
408 LAllocation argsObj = useRegister(ins->argsObject());
409 LSetArgumentsObjectArg* lir = new (alloc())
410 LSetArgumentsObjectArg(argsObj, useBox(ins->value()), temp());
411 add(lir, ins);
414 void LIRGenerator::visitLoadArgumentsObjectArg(MLoadArgumentsObjectArg* ins) {
415 MDefinition* argsObj = ins->argsObject();
416 MOZ_ASSERT(argsObj->type() == MIRType::Object);
418 MDefinition* index = ins->index();
419 MOZ_ASSERT(index->type() == MIRType::Int32);
421 auto* lir = new (alloc())
422 LLoadArgumentsObjectArg(useRegister(argsObj), useRegister(index), temp());
423 assignSnapshot(lir, ins->bailoutKind());
424 defineBox(lir, ins);
427 void LIRGenerator::visitLoadArgumentsObjectArgHole(
428 MLoadArgumentsObjectArgHole* ins) {
429 MDefinition* argsObj = ins->argsObject();
430 MOZ_ASSERT(argsObj->type() == MIRType::Object);
432 MDefinition* index = ins->index();
433 MOZ_ASSERT(index->type() == MIRType::Int32);
435 auto* lir = new (alloc()) LLoadArgumentsObjectArgHole(
436 useRegister(argsObj), useRegister(index), temp());
437 assignSnapshot(lir, ins->bailoutKind());
438 defineBox(lir, ins);
441 void LIRGenerator::visitInArgumentsObjectArg(MInArgumentsObjectArg* ins) {
442 MDefinition* argsObj = ins->argsObject();
443 MOZ_ASSERT(argsObj->type() == MIRType::Object);
445 MDefinition* index = ins->index();
446 MOZ_ASSERT(index->type() == MIRType::Int32);
448 auto* lir = new (alloc())
449 LInArgumentsObjectArg(useRegister(argsObj), useRegister(index), temp());
450 assignSnapshot(lir, ins->bailoutKind());
451 define(lir, ins);
454 void LIRGenerator::visitArgumentsObjectLength(MArgumentsObjectLength* ins) {
455 MDefinition* argsObj = ins->argsObject();
456 MOZ_ASSERT(argsObj->type() == MIRType::Object);
458 auto* lir = new (alloc()) LArgumentsObjectLength(useRegister(argsObj));
459 assignSnapshot(lir, ins->bailoutKind());
460 define(lir, ins);
463 void LIRGenerator::visitArrayFromArgumentsObject(
464 MArrayFromArgumentsObject* ins) {
465 MDefinition* argsObj = ins->argsObject();
466 MOZ_ASSERT(argsObj->type() == MIRType::Object);
468 auto* lir =
469 new (alloc()) LArrayFromArgumentsObject(useRegisterAtStart(argsObj));
470 defineReturn(lir, ins);
471 assignSafepoint(lir, ins);
474 void LIRGenerator::visitGuardArgumentsObjectFlags(
475 MGuardArgumentsObjectFlags* ins) {
476 MDefinition* argsObj = ins->argsObject();
477 MOZ_ASSERT(argsObj->type() == MIRType::Object);
479 auto* lir =
480 new (alloc()) LGuardArgumentsObjectFlags(useRegister(argsObj), temp());
481 assignSnapshot(lir, ins->bailoutKind());
482 add(lir, ins);
483 redefine(ins, argsObj);
486 void LIRGenerator::visitBoundFunctionNumArgs(MBoundFunctionNumArgs* ins) {
487 MDefinition* obj = ins->object();
488 MOZ_ASSERT(obj->type() == MIRType::Object);
490 auto* lir = new (alloc()) LBoundFunctionNumArgs(useRegisterAtStart(obj));
491 define(lir, ins);
494 void LIRGenerator::visitGuardBoundFunctionIsConstructor(
495 MGuardBoundFunctionIsConstructor* ins) {
496 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
498 auto* lir = new (alloc())
499 LGuardBoundFunctionIsConstructor(useRegister(ins->object()));
500 assignSnapshot(lir, ins->bailoutKind());
501 add(lir, ins);
502 redefine(ins, ins->object());
505 void LIRGenerator::visitReturnFromCtor(MReturnFromCtor* ins) {
506 LReturnFromCtor* lir = new (alloc())
507 LReturnFromCtor(useBox(ins->value()), useRegister(ins->object()));
508 define(lir, ins);
511 void LIRGenerator::visitBoxNonStrictThis(MBoxNonStrictThis* ins) {
512 MOZ_ASSERT(ins->type() == MIRType::Object);
513 MOZ_ASSERT(ins->input()->type() == MIRType::Value);
515 auto* lir = new (alloc()) LBoxNonStrictThis(useBox(ins->input()));
516 define(lir, ins);
517 assignSafepoint(lir, ins);
520 void LIRGenerator::visitImplicitThis(MImplicitThis* ins) {
521 MDefinition* env = ins->envChain();
522 MOZ_ASSERT(env->type() == MIRType::Object);
524 LImplicitThis* lir = new (alloc()) LImplicitThis(useRegisterAtStart(env));
525 defineReturn(lir, ins);
526 assignSafepoint(lir, ins);
529 template <typename T>
530 bool LIRGenerator::lowerCallArguments(T* call) {
531 uint32_t argc = call->numStackArgs();
533 // Align the arguments of a call such that the callee would keep the same
534 // alignment as the caller.
535 uint32_t baseSlot = 0;
536 if (JitStackValueAlignment > 1) {
537 baseSlot = AlignBytes(argc, JitStackValueAlignment);
538 } else {
539 baseSlot = argc;
542 // Save the maximum number of argument, such that we can have one unique
543 // frame size.
544 if (baseSlot > maxargslots_) {
545 maxargslots_ = baseSlot;
548 for (size_t i = 0; i < argc; i++) {
549 MDefinition* arg = call->getArg(i);
550 uint32_t argslot = baseSlot - i;
552 // Values take a slow path.
553 if (arg->type() == MIRType::Value) {
554 LStackArgV* stack = new (alloc()) LStackArgV(useBox(arg), argslot);
555 add(stack);
556 } else {
557 // Known types can move constant types and/or payloads.
558 LStackArgT* stack = new (alloc())
559 LStackArgT(useRegisterOrConstant(arg), argslot, arg->type());
560 add(stack);
563 if (!alloc().ensureBallast()) {
564 return false;
567 return true;
570 void LIRGenerator::visitCall(MCall* call) {
571 MOZ_ASSERT(call->getCallee()->type() == MIRType::Object);
573 // In case of oom, skip the rest of the allocations.
574 if (!lowerCallArguments(call)) {
575 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitCall");
576 return;
579 WrappedFunction* target = call->getSingleTarget();
581 LInstruction* lir;
583 if (call->isCallDOMNative()) {
584 // Call DOM functions.
585 MOZ_ASSERT(target && target->isNativeWithoutJitEntry());
586 Register cxReg, objReg, privReg, argsReg;
587 GetTempRegForIntArg(0, 0, &cxReg);
588 GetTempRegForIntArg(1, 0, &objReg);
589 GetTempRegForIntArg(2, 0, &privReg);
590 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &argsReg);
591 MOZ_ASSERT(ok, "How can we not have four temp registers?");
592 lir = new (alloc()) LCallDOMNative(tempFixed(cxReg), tempFixed(objReg),
593 tempFixed(privReg), tempFixed(argsReg));
594 } else if (target) {
595 // Call known functions.
596 if (target->isNativeWithoutJitEntry()) {
597 Register cxReg, numReg, vpReg, tmpReg;
598 GetTempRegForIntArg(0, 0, &cxReg);
599 GetTempRegForIntArg(1, 0, &numReg);
600 GetTempRegForIntArg(2, 0, &vpReg);
602 // Even though this is just a temp reg, use the same API to avoid
603 // register collisions.
604 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
605 MOZ_ASSERT(ok, "How can we not have four temp registers?");
607 lir = new (alloc()) LCallNative(tempFixed(cxReg), tempFixed(numReg),
608 tempFixed(vpReg), tempFixed(tmpReg));
609 } else {
610 lir = new (alloc()) LCallKnown(useRegisterAtStart(call->getCallee()),
611 tempFixed(CallTempReg0));
613 } else {
614 // Call anything, using the most generic code.
615 lir = new (alloc()) LCallGeneric(
616 useFixedAtStart(call->getCallee(), IonGenericCallCalleeReg),
617 tempFixed(IonGenericCallArgcReg));
619 defineReturn(lir, call);
620 assignSafepoint(lir, call);
623 void LIRGenerator::visitCallClassHook(MCallClassHook* call) {
624 MDefinition* callee = call->getCallee();
625 MOZ_ASSERT(callee->type() == MIRType::Object);
627 // In case of oom, skip the rest of the allocations.
628 if (!lowerCallArguments(call)) {
629 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitCallClassHook");
630 return;
633 Register cxReg, numReg, vpReg, tmpReg;
634 GetTempRegForIntArg(0, 0, &cxReg);
635 GetTempRegForIntArg(1, 0, &numReg);
636 GetTempRegForIntArg(2, 0, &vpReg);
638 // Even though this is just a temp reg, use the same API to avoid
639 // register collisions.
640 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
641 MOZ_ASSERT(ok, "How can we not have four temp registers?");
643 auto* lir = new (alloc())
644 LCallClassHook(useRegisterAtStart(callee), tempFixed(cxReg),
645 tempFixed(numReg), tempFixed(vpReg), tempFixed(tmpReg));
646 defineReturn(lir, call);
647 assignSafepoint(lir, call);
650 void LIRGenerator::visitApplyArgs(MApplyArgs* apply) {
651 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
653 // Assert if the return value is already erased.
654 static_assert(CallTempReg2 != JSReturnReg_Type);
655 static_assert(CallTempReg2 != JSReturnReg_Data);
657 LApplyArgsGeneric* lir = new (alloc()) LApplyArgsGeneric(
658 useFixedAtStart(apply->getFunction(), CallTempReg3),
659 useFixedAtStart(apply->getArgc(), CallTempReg0),
660 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
661 tempFixed(CallTempReg1), // object register
662 tempFixed(CallTempReg2)); // stack counter register
664 // Bailout is needed in the case of too many values in the arguments array.
665 assignSnapshot(lir, apply->bailoutKind());
667 defineReturn(lir, apply);
668 assignSafepoint(lir, apply);
671 void LIRGenerator::visitApplyArgsObj(MApplyArgsObj* apply) {
672 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
674 // Assert if the return value is already erased.
675 static_assert(CallTempReg2 != JSReturnReg_Type);
676 static_assert(CallTempReg2 != JSReturnReg_Data);
678 LApplyArgsObj* lir = new (alloc()) LApplyArgsObj(
679 useFixedAtStart(apply->getFunction(), CallTempReg3),
680 useFixedAtStart(apply->getArgsObj(), CallTempReg0),
681 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
682 tempFixed(CallTempReg1), // object register
683 tempFixed(CallTempReg2)); // stack counter register
685 // Bailout is needed in the case of too many values in the arguments array.
686 assignSnapshot(lir, apply->bailoutKind());
688 defineReturn(lir, apply);
689 assignSafepoint(lir, apply);
692 void LIRGenerator::visitApplyArray(MApplyArray* apply) {
693 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
695 // Assert if the return value is already erased.
696 static_assert(CallTempReg2 != JSReturnReg_Type);
697 static_assert(CallTempReg2 != JSReturnReg_Data);
699 LApplyArrayGeneric* lir = new (alloc()) LApplyArrayGeneric(
700 useFixedAtStart(apply->getFunction(), CallTempReg3),
701 useFixedAtStart(apply->getElements(), CallTempReg0),
702 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
703 tempFixed(CallTempReg1), // object register
704 tempFixed(CallTempReg2)); // stack counter register
706 // Bailout is needed in the case of too many values in the array, or empty
707 // space at the end of the array.
708 assignSnapshot(lir, apply->bailoutKind());
710 defineReturn(lir, apply);
711 assignSafepoint(lir, apply);
714 void LIRGenerator::visitConstructArgs(MConstructArgs* mir) {
715 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object);
716 MOZ_ASSERT(mir->getArgc()->type() == MIRType::Int32);
717 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object);
718 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value);
720 // Assert if the return value is already erased.
721 static_assert(CallTempReg2 != JSReturnReg_Type);
722 static_assert(CallTempReg2 != JSReturnReg_Data);
724 auto* lir = new (alloc()) LConstructArgsGeneric(
725 useFixedAtStart(mir->getFunction(), CallTempReg3),
726 useFixedAtStart(mir->getArgc(), CallTempReg0),
727 useFixedAtStart(mir->getNewTarget(), CallTempReg1),
728 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5),
729 tempFixed(CallTempReg2));
731 // Bailout is needed in the case of too many values in the arguments array.
732 assignSnapshot(lir, mir->bailoutKind());
734 defineReturn(lir, mir);
735 assignSafepoint(lir, mir);
738 void LIRGenerator::visitConstructArray(MConstructArray* mir) {
739 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object);
740 MOZ_ASSERT(mir->getElements()->type() == MIRType::Elements);
741 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object);
742 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value);
744 // Assert if the return value is already erased.
745 static_assert(CallTempReg2 != JSReturnReg_Type);
746 static_assert(CallTempReg2 != JSReturnReg_Data);
748 auto* lir = new (alloc()) LConstructArrayGeneric(
749 useFixedAtStart(mir->getFunction(), CallTempReg3),
750 useFixedAtStart(mir->getElements(), CallTempReg0),
751 useFixedAtStart(mir->getNewTarget(), CallTempReg1),
752 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5),
753 tempFixed(CallTempReg2));
755 // Bailout is needed in the case of too many values in the array, or empty
756 // space at the end of the array.
757 assignSnapshot(lir, mir->bailoutKind());
759 defineReturn(lir, mir);
760 assignSafepoint(lir, mir);
763 void LIRGenerator::visitBail(MBail* bail) {
764 LBail* lir = new (alloc()) LBail();
765 assignSnapshot(lir, bail->bailoutKind());
766 add(lir, bail);
769 void LIRGenerator::visitUnreachable(MUnreachable* unreachable) {
770 LUnreachable* lir = new (alloc()) LUnreachable();
771 add(lir, unreachable);
774 void LIRGenerator::visitEncodeSnapshot(MEncodeSnapshot* mir) {
775 LEncodeSnapshot* lir = new (alloc()) LEncodeSnapshot();
776 assignSnapshot(lir, mir->bailoutKind());
777 add(lir, mir);
780 void LIRGenerator::visitUnreachableResult(MUnreachableResult* mir) {
781 if (mir->type() == MIRType::Value) {
782 auto* lir = new (alloc()) LUnreachableResultV();
783 defineBox(lir, mir);
784 } else {
785 auto* lir = new (alloc()) LUnreachableResultT();
786 define(lir, mir);
790 void LIRGenerator::visitAssertFloat32(MAssertFloat32* assertion) {
791 MIRType type = assertion->input()->type();
792 DebugOnly<bool> checkIsFloat32 = assertion->mustBeFloat32();
794 if (type != MIRType::Value && !JitOptions.eagerIonCompilation()) {
795 MOZ_ASSERT_IF(checkIsFloat32, type == MIRType::Float32);
796 MOZ_ASSERT_IF(!checkIsFloat32, type != MIRType::Float32);
800 void LIRGenerator::visitAssertRecoveredOnBailout(
801 MAssertRecoveredOnBailout* assertion) {
802 MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
805 [[nodiscard]] static JSOp ReorderComparison(JSOp op, MDefinition** lhsp,
806 MDefinition** rhsp) {
807 MDefinition* lhs = *lhsp;
808 MDefinition* rhs = *rhsp;
810 if (lhs->maybeConstantValue()) {
811 *rhsp = lhs;
812 *lhsp = rhs;
813 return ReverseCompareOp(op);
815 return op;
818 void LIRGenerator::visitTest(MTest* test) {
819 MDefinition* opd = test->getOperand(0);
820 MBasicBlock* ifTrue = test->ifTrue();
821 MBasicBlock* ifFalse = test->ifFalse();
823 // String is converted to length of string in the type analysis phase (see
824 // TestPolicy).
825 MOZ_ASSERT(opd->type() != MIRType::String);
827 // Testing a constant.
828 if (MConstant* constant = opd->maybeConstantValue()) {
829 bool b;
830 if (constant->valueToBoolean(&b)) {
831 add(new (alloc()) LGoto(b ? ifTrue : ifFalse));
832 return;
836 if (opd->type() == MIRType::Value) {
837 auto* lir = new (alloc()) LTestVAndBranch(
838 ifTrue, ifFalse, useBox(opd), tempDouble(), tempToUnbox(), temp());
839 add(lir, test);
840 return;
843 // Objects are truthy, except if it might emulate undefined.
844 if (opd->type() == MIRType::Object) {
845 add(new (alloc())
846 LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp()),
847 test);
848 return;
851 // These must be explicitly sniffed out since they are constants and have
852 // no payload.
853 if (opd->type() == MIRType::Undefined || opd->type() == MIRType::Null) {
854 add(new (alloc()) LGoto(ifFalse));
855 return;
858 // All symbols are truthy.
859 if (opd->type() == MIRType::Symbol) {
860 add(new (alloc()) LGoto(ifTrue));
861 return;
864 // Try to match the pattern
865 // test=MTest(
866 // comp=MCompare(
867 // {EQ,NE} for {Int,UInt}{32,64},
868 // bitAnd={MBitAnd,MWasmBinaryBitwise(And{32,64})}(x, y),
869 // MConstant(0)
870 // )
871 // )
872 // and produce a single LBitAndAndBranch node. This requires both `comp`
873 // and `bitAnd` to be marked emit-at-uses. Since we can't use
874 // LBitAndAndBranch to represent a 64-bit AND on a 32-bit target, the 64-bit
875 // case is restricted to 64-bit targets.
876 if (opd->isCompare() && opd->isEmittedAtUses()) {
877 #ifdef JS_64BIT
878 constexpr bool targetIs64 = true;
879 #else
880 constexpr bool targetIs64 = false;
881 #endif
882 MCompare* comp = opd->toCompare();
883 Assembler::Condition compCond =
884 JSOpToCondition(comp->compareType(), comp->jsop());
885 MDefinition* compL = comp->getOperand(0);
886 MDefinition* compR = comp->getOperand(1);
887 if ((comp->compareType() == MCompare::Compare_Int32 ||
888 comp->compareType() == MCompare::Compare_UInt32 ||
889 (targetIs64 && comp->compareType() == MCompare::Compare_Int64) ||
890 (targetIs64 && comp->compareType() == MCompare::Compare_UInt64)) &&
891 (compCond == Assembler::Equal || compCond == Assembler::NotEqual) &&
892 compR->isConstant() &&
893 (compR->toConstant()->isInt32(0) ||
894 (targetIs64 && compR->toConstant()->isInt64(0))) &&
895 (compL->isBitAnd() || (compL->isWasmBinaryBitwise() &&
896 compL->toWasmBinaryBitwise()->subOpcode() ==
897 MWasmBinaryBitwise::SubOpcode::And))) {
898 // The MCompare is OK; now check its first operand (the and-ish node).
899 MDefinition* bitAnd = compL;
900 MDefinition* bitAndL = bitAnd->getOperand(0);
901 MDefinition* bitAndR = bitAnd->getOperand(1);
902 MIRType bitAndLTy = bitAndL->type();
903 MIRType bitAndRTy = bitAndR->type();
904 if (bitAnd->isEmittedAtUses() && bitAndLTy == bitAndRTy &&
905 (bitAndLTy == MIRType::Int32 ||
906 (targetIs64 && bitAndLTy == MIRType::Int64))) {
907 // Pattern match succeeded.
908 ReorderCommutative(&bitAndL, &bitAndR, test);
909 if (compCond == Assembler::Equal) {
910 compCond = Assembler::Zero;
911 } else if (compCond == Assembler::NotEqual) {
912 compCond = Assembler::NonZero;
913 } else {
914 MOZ_ASSERT_UNREACHABLE("inequality operators cannot be folded");
916 MOZ_ASSERT_IF(!targetIs64, bitAndLTy == MIRType::Int32);
917 lowerForBitAndAndBranch(
918 new (alloc()) LBitAndAndBranch(
919 ifTrue, ifFalse, bitAndLTy == MIRType::Int64, compCond),
920 test, bitAndL, bitAndR);
921 return;
926 // Check if the operand for this test is a compare operation. If it is, we
927 // want to emit an LCompare*AndBranch rather than an LTest*AndBranch, to fuse
928 // the compare and jump instructions.
929 if (opd->isCompare() && opd->isEmittedAtUses()) {
930 MCompare* comp = opd->toCompare();
931 MDefinition* left = comp->lhs();
932 MDefinition* right = comp->rhs();
934 // Try to fold the comparison so that we don't have to handle all cases.
935 bool result;
936 if (comp->tryFold(&result)) {
937 add(new (alloc()) LGoto(result ? ifTrue : ifFalse));
938 return;
941 // Emit LCompare*AndBranch.
943 // Compare and branch null/undefined.
944 // The second operand has known null/undefined type,
945 // so just test the first operand.
946 if (comp->compareType() == MCompare::Compare_Null ||
947 comp->compareType() == MCompare::Compare_Undefined) {
948 if (left->type() == MIRType::Object) {
949 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchT(
950 comp, useRegister(left), ifTrue, ifFalse, temp());
951 add(lir, test);
952 return;
955 if (IsLooseEqualityOp(comp->jsop())) {
956 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchV(
957 comp, ifTrue, ifFalse, useBox(left), temp(), tempToUnbox());
958 add(lir, test);
959 return;
962 if (comp->compareType() == MCompare::Compare_Null) {
963 auto* lir =
964 new (alloc()) LIsNullAndBranch(comp, ifTrue, ifFalse, useBox(left));
965 add(lir, test);
966 return;
969 auto* lir = new (alloc())
970 LIsUndefinedAndBranch(comp, ifTrue, ifFalse, useBox(left));
971 add(lir, test);
972 return;
975 // Compare and branch Int32, Symbol, Object, or WasmAnyRef pointers.
976 if (comp->isInt32Comparison() ||
977 comp->compareType() == MCompare::Compare_UInt32 ||
978 comp->compareType() == MCompare::Compare_UIntPtr ||
979 comp->compareType() == MCompare::Compare_Object ||
980 comp->compareType() == MCompare::Compare_Symbol ||
981 comp->compareType() == MCompare::Compare_WasmAnyRef) {
982 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
983 LAllocation lhs = useRegister(left);
984 LAllocation rhs;
985 if (comp->isInt32Comparison() ||
986 comp->compareType() == MCompare::Compare_UInt32 ||
987 comp->compareType() == MCompare::Compare_UIntPtr) {
988 rhs = useAnyOrInt32Constant(right);
989 } else {
990 rhs = useAny(right);
992 LCompareAndBranch* lir =
993 new (alloc()) LCompareAndBranch(comp, op, lhs, rhs, ifTrue, ifFalse);
994 add(lir, test);
995 return;
998 // Compare and branch Int64.
999 if (comp->compareType() == MCompare::Compare_Int64 ||
1000 comp->compareType() == MCompare::Compare_UInt64) {
1001 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1002 lowerForCompareI64AndBranch(test, comp, op, left, right, ifTrue, ifFalse);
1003 return;
1006 // Compare and branch doubles.
1007 if (comp->isDoubleComparison()) {
1008 LAllocation lhs = useRegister(left);
1009 LAllocation rhs = useRegister(right);
1010 LCompareDAndBranch* lir =
1011 new (alloc()) LCompareDAndBranch(comp, lhs, rhs, ifTrue, ifFalse);
1012 add(lir, test);
1013 return;
1016 // Compare and branch floats.
1017 if (comp->isFloat32Comparison()) {
1018 LAllocation lhs = useRegister(left);
1019 LAllocation rhs = useRegister(right);
1020 LCompareFAndBranch* lir =
1021 new (alloc()) LCompareFAndBranch(comp, lhs, rhs, ifTrue, ifFalse);
1022 add(lir, test);
1023 return;
1027 // Check if the operand for this test is a bitand operation. If it is, we want
1028 // to emit an LBitAndAndBranch rather than an LTest*AndBranch.
1029 if (opd->isBitAnd() && opd->isEmittedAtUses()) {
1030 MDefinition* lhs = opd->getOperand(0);
1031 MDefinition* rhs = opd->getOperand(1);
1032 if (lhs->type() == MIRType::Int32 && rhs->type() == MIRType::Int32) {
1033 ReorderCommutative(&lhs, &rhs, test);
1034 lowerForBitAndAndBranch(new (alloc()) LBitAndAndBranch(ifTrue, ifFalse,
1035 /*is64=*/false),
1036 test, lhs, rhs);
1037 return;
1041 #if defined(ENABLE_WASM_SIMD) && \
1042 (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || \
1043 defined(JS_CODEGEN_ARM64))
1044 // Check if the operand for this test is an any_true/all_true SIMD operation.
1045 // If it is, we want to emit an LWasmReduceAndBranchSimd128 node to avoid
1046 // generating an intermediate boolean result.
1047 if (opd->isWasmReduceSimd128() && opd->isEmittedAtUses()) {
1048 MWasmReduceSimd128* node = opd->toWasmReduceSimd128();
1049 if (canFoldReduceSimd128AndBranch(node->simdOp())) {
1050 # ifdef DEBUG
1051 js::wasm::ReportSimdAnalysis("simd128-to-scalar-and-branch -> folded");
1052 # endif
1053 auto* lir = new (alloc()) LWasmReduceAndBranchSimd128(
1054 useRegister(node->input()), node->simdOp(), ifTrue, ifFalse);
1055 add(lir, test);
1056 return;
1059 #endif
1061 if (opd->isIsObject() && opd->isEmittedAtUses()) {
1062 MDefinition* input = opd->toIsObject()->input();
1063 MOZ_ASSERT(input->type() == MIRType::Value);
1065 LIsObjectAndBranch* lir =
1066 new (alloc()) LIsObjectAndBranch(ifTrue, ifFalse, useBoxAtStart(input));
1067 add(lir, test);
1068 return;
1071 if (opd->isWasmRefIsSubtypeOfAbstract() && opd->isEmittedAtUses()) {
1072 MWasmRefIsSubtypeOfAbstract* isSubTypeOf =
1073 opd->toWasmRefIsSubtypeOfAbstract();
1074 LAllocation ref = useRegister(isSubTypeOf->ref());
1075 LDefinition scratch1 = LDefinition();
1076 if (isSubTypeOf->destType().isAnyHierarchy()) {
1077 // As in visitWasmRefIsSubtypeOfAbstract, we know we do not need
1078 // scratch2 and superSTV because we know this is not a
1079 // concrete type.
1080 scratch1 = MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
1081 isSubTypeOf->destType())
1082 ? temp()
1083 : LDefinition();
1084 } else if (isSubTypeOf->destType().isFuncHierarchy() ||
1085 isSubTypeOf->destType().isExternHierarchy()) {
1086 // scratch1 is not necessary for abstract casts in other hierarchies
1087 } else {
1088 MOZ_CRASH("unknown type hierarchy when folding abstract casts");
1091 add(new (alloc()) LWasmRefIsSubtypeOfAbstractAndBranch(
1092 ifTrue, ifFalse, isSubTypeOf->sourceType(), isSubTypeOf->destType(),
1093 ref, scratch1),
1094 test);
1095 return;
1098 if (opd->isWasmRefIsSubtypeOfConcrete() && opd->isEmittedAtUses()) {
1099 MWasmRefIsSubtypeOfConcrete* isSubTypeOf =
1100 opd->toWasmRefIsSubtypeOfConcrete();
1101 LAllocation ref = useRegister(isSubTypeOf->ref());
1102 LAllocation superSTV = useRegister(isSubTypeOf->superSTV());
1103 LDefinition scratch1 = LDefinition();
1104 LDefinition scratch2 = LDefinition();
1105 if (isSubTypeOf->destType().isAnyHierarchy()) {
1106 // As in visitWasmRefIsSubtypeOfConcrete, we know we need scratch1 because
1107 // we know this is a concrete type.
1108 scratch1 = temp();
1109 scratch2 = MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
1110 isSubTypeOf->destType())
1111 ? temp()
1112 : LDefinition();
1113 } else if (isSubTypeOf->destType().isFuncHierarchy()) {
1114 // As in visitWasmRefIsSubtypeOfConcrete again...
1115 scratch1 = temp();
1116 scratch2 = MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
1117 isSubTypeOf->destType())
1118 ? temp()
1119 : LDefinition();
1120 } else if (isSubTypeOf->destType().isExternHierarchy()) {
1121 MOZ_CRASH("concrete casts are not possible in the extern hierarchy");
1122 } else {
1123 MOZ_CRASH("unknown type hierarchy when folding abstract casts");
1126 add(new (alloc()) LWasmRefIsSubtypeOfConcreteAndBranch(
1127 ifTrue, ifFalse, isSubTypeOf->sourceType(), isSubTypeOf->destType(),
1128 ref, superSTV, scratch1, scratch2),
1129 test);
1130 return;
1133 if (opd->isIsNullOrUndefined() && opd->isEmittedAtUses()) {
1134 MIsNullOrUndefined* isNullOrUndefined = opd->toIsNullOrUndefined();
1135 MDefinition* input = isNullOrUndefined->value();
1137 if (input->type() == MIRType::Value) {
1138 auto* lir = new (alloc()) LIsNullOrUndefinedAndBranch(
1139 isNullOrUndefined, ifTrue, ifFalse, useBoxAtStart(input));
1140 add(lir, test);
1141 } else {
1142 auto* target = IsNullOrUndefined(input->type()) ? ifTrue : ifFalse;
1143 add(new (alloc()) LGoto(target));
1145 return;
1148 if (opd->isIsNoIter()) {
1149 MOZ_ASSERT(opd->isEmittedAtUses());
1151 MDefinition* input = opd->toIsNoIter()->input();
1152 MOZ_ASSERT(input->type() == MIRType::Value);
1154 LIsNoIterAndBranch* lir =
1155 new (alloc()) LIsNoIterAndBranch(ifTrue, ifFalse, useBox(input));
1156 add(lir, test);
1157 return;
1160 if (opd->isIteratorHasIndices()) {
1161 MOZ_ASSERT(opd->isEmittedAtUses());
1163 MDefinition* object = opd->toIteratorHasIndices()->object();
1164 MDefinition* iterator = opd->toIteratorHasIndices()->iterator();
1165 LIteratorHasIndicesAndBranch* lir = new (alloc())
1166 LIteratorHasIndicesAndBranch(ifTrue, ifFalse, useRegister(object),
1167 useRegister(iterator), temp(), temp());
1168 add(lir, test);
1169 return;
1172 switch (opd->type()) {
1173 case MIRType::Double:
1174 add(new (alloc()) LTestDAndBranch(useRegister(opd), ifTrue, ifFalse));
1175 break;
1176 case MIRType::Float32:
1177 add(new (alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse));
1178 break;
1179 case MIRType::Int32:
1180 case MIRType::Boolean:
1181 add(new (alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse));
1182 break;
1183 case MIRType::Int64:
1184 add(new (alloc())
1185 LTestI64AndBranch(useInt64Register(opd), ifTrue, ifFalse));
1186 break;
1187 case MIRType::BigInt:
1188 add(new (alloc()) LTestBIAndBranch(useRegister(opd), ifTrue, ifFalse));
1189 break;
1190 default:
1191 MOZ_CRASH("Bad type");
1195 static inline bool CanEmitCompareAtUses(MInstruction* ins) {
1196 if (!ins->canEmitAtUses()) {
1197 return false;
1200 // If the result is never used, we can usefully defer emission to the use
1201 // point, since that will never happen.
1202 MUseIterator iter(ins->usesBegin());
1203 if (iter == ins->usesEnd()) {
1204 return true;
1207 // If the first use isn't of the expected form, the answer is No.
1208 MNode* node = iter->consumer();
1209 if (!node->isDefinition()) {
1210 return false;
1213 MDefinition* use = node->toDefinition();
1214 if (!use->isTest() && !use->isWasmSelect()) {
1215 return false;
1218 // Emission can be deferred to the first use point, but only if there are no
1219 // other use points.
1220 iter++;
1221 return iter == ins->usesEnd();
1224 void LIRGenerator::visitCompare(MCompare* comp) {
1225 MDefinition* left = comp->lhs();
1226 MDefinition* right = comp->rhs();
1228 // Try to fold the comparison so that we don't have to handle all cases.
1229 bool result;
1230 if (comp->tryFold(&result)) {
1231 define(new (alloc()) LInteger(result), comp);
1232 return;
1235 // Move below the emitAtUses call if we ever implement
1236 // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't
1237 // make sense and avoids confusion.
1238 if (comp->compareType() == MCompare::Compare_String) {
1239 MConstant* constant = nullptr;
1240 MDefinition* input = nullptr;
1241 if (left->isConstant()) {
1242 constant = left->toConstant();
1243 input = right;
1244 } else if (right->isConstant()) {
1245 constant = right->toConstant();
1246 input = left;
1249 if (constant) {
1250 JSLinearString* linear = &constant->toString()->asLinear();
1252 if (IsEqualityOp(comp->jsop())) {
1253 if (MacroAssembler::canCompareStringCharsInline(linear)) {
1254 auto* lir = new (alloc()) LCompareSInline(useRegister(input), linear);
1255 define(lir, comp);
1256 assignSafepoint(lir, comp);
1257 return;
1259 } else {
1260 MOZ_ASSERT(IsRelationalOp(comp->jsop()));
1262 if (linear->length() == 1) {
1263 // Move the constant value into the right-hand side operand.
1264 JSOp op = comp->jsop();
1265 if (left == constant) {
1266 op = ReverseCompareOp(op);
1269 auto* lir = new (alloc())
1270 LCompareSSingle(useRegister(input), temp(), op, linear);
1271 define(lir, comp);
1272 return;
1277 LCompareS* lir =
1278 new (alloc()) LCompareS(useRegister(left), useRegister(right));
1279 define(lir, comp);
1280 assignSafepoint(lir, comp);
1281 return;
1284 // Compare two BigInts.
1285 if (comp->compareType() == MCompare::Compare_BigInt) {
1286 auto* lir = new (alloc()) LCompareBigInt(
1287 useRegister(left), useRegister(right), temp(), temp(), temp());
1288 define(lir, comp);
1289 return;
1292 // Compare BigInt with Int32.
1293 if (comp->compareType() == MCompare::Compare_BigInt_Int32) {
1294 auto* lir = new (alloc()) LCompareBigIntInt32(
1295 useRegister(left), useRegister(right), temp(), temp());
1296 define(lir, comp);
1297 return;
1300 // Compare BigInt with Double.
1301 if (comp->compareType() == MCompare::Compare_BigInt_Double) {
1302 auto* lir = new (alloc()) LCompareBigIntDouble(useRegisterAtStart(left),
1303 useRegisterAtStart(right));
1304 defineReturn(lir, comp);
1305 return;
1308 // Compare BigInt with String.
1309 if (comp->compareType() == MCompare::Compare_BigInt_String) {
1310 auto* lir = new (alloc()) LCompareBigIntString(useRegisterAtStart(left),
1311 useRegisterAtStart(right));
1312 defineReturn(lir, comp);
1313 assignSafepoint(lir, comp);
1314 return;
1317 // Sniff out if the output of this compare is used only for a branching.
1318 // If it is, then we will emit an LCompare*AndBranch instruction in place
1319 // of this compare and any test that uses this compare. Thus, we can
1320 // ignore this Compare.
1321 if (CanEmitCompareAtUses(comp)) {
1322 emitAtUses(comp);
1323 return;
1326 // Compare Null and Undefined.
1327 if (comp->compareType() == MCompare::Compare_Null ||
1328 comp->compareType() == MCompare::Compare_Undefined) {
1329 if (left->type() == MIRType::Object) {
1330 define(new (alloc()) LIsNullOrLikeUndefinedT(useRegister(left)), comp);
1331 return;
1334 if (IsLooseEqualityOp(comp->jsop())) {
1335 auto* lir =
1336 new (alloc()) LIsNullOrLikeUndefinedV(useBox(left), tempToUnbox());
1337 define(lir, comp);
1338 return;
1341 if (comp->compareType() == MCompare::Compare_Null) {
1342 auto* lir = new (alloc()) LIsNull(useBox(left));
1343 define(lir, comp);
1344 return;
1347 auto* lir = new (alloc()) LIsUndefined(useBox(left));
1348 define(lir, comp);
1349 return;
1352 // Compare Int32, Symbol, Object or Wasm pointers.
1353 if (comp->isInt32Comparison() ||
1354 comp->compareType() == MCompare::Compare_UInt32 ||
1355 comp->compareType() == MCompare::Compare_UIntPtr ||
1356 comp->compareType() == MCompare::Compare_Object ||
1357 comp->compareType() == MCompare::Compare_Symbol ||
1358 comp->compareType() == MCompare::Compare_WasmAnyRef) {
1359 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1360 LAllocation lhs = useRegister(left);
1361 LAllocation rhs;
1362 if (comp->isInt32Comparison() ||
1363 comp->compareType() == MCompare::Compare_UInt32 ||
1364 comp->compareType() == MCompare::Compare_UIntPtr) {
1365 rhs = useAnyOrInt32Constant(right);
1366 } else {
1367 rhs = useAny(right);
1369 define(new (alloc()) LCompare(op, lhs, rhs), comp);
1370 return;
1373 // Compare Int64.
1374 if (comp->compareType() == MCompare::Compare_Int64 ||
1375 comp->compareType() == MCompare::Compare_UInt64) {
1376 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1377 define(new (alloc()) LCompareI64(op, useInt64Register(left),
1378 useInt64OrConstant(right)),
1379 comp);
1380 return;
1383 // Compare doubles.
1384 if (comp->isDoubleComparison()) {
1385 define(new (alloc()) LCompareD(useRegister(left), useRegister(right)),
1386 comp);
1387 return;
1390 // Compare float32.
1391 if (comp->isFloat32Comparison()) {
1392 define(new (alloc()) LCompareF(useRegister(left), useRegister(right)),
1393 comp);
1394 return;
1397 MOZ_CRASH("Unrecognized compare type.");
1400 void LIRGenerator::visitSameValueDouble(MSameValueDouble* ins) {
1401 MDefinition* lhs = ins->lhs();
1402 MDefinition* rhs = ins->rhs();
1404 MOZ_ASSERT(lhs->type() == MIRType::Double);
1405 MOZ_ASSERT(rhs->type() == MIRType::Double);
1407 auto* lir = new (alloc())
1408 LSameValueDouble(useRegister(lhs), useRegister(rhs), tempDouble());
1409 define(lir, ins);
1412 void LIRGenerator::visitSameValue(MSameValue* ins) {
1413 MDefinition* lhs = ins->lhs();
1414 MDefinition* rhs = ins->rhs();
1416 MOZ_ASSERT(lhs->type() == MIRType::Value);
1417 MOZ_ASSERT(rhs->type() == MIRType::Value);
1419 auto* lir = new (alloc()) LSameValue(useBox(lhs), useBox(rhs));
1420 define(lir, ins);
1421 assignSafepoint(lir, ins);
1424 void LIRGenerator::lowerBitOp(JSOp op, MBinaryInstruction* ins) {
1425 MDefinition* lhs = ins->getOperand(0);
1426 MDefinition* rhs = ins->getOperand(1);
1427 MOZ_ASSERT(IsIntType(ins->type()));
1429 if (ins->type() == MIRType::Int32) {
1430 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1431 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1432 ReorderCommutative(&lhs, &rhs, ins);
1433 lowerForALU(new (alloc()) LBitOpI(op), ins, lhs, rhs);
1434 return;
1437 if (ins->type() == MIRType::Int64) {
1438 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1439 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1440 ReorderCommutative(&lhs, &rhs, ins);
1441 lowerForALUInt64(new (alloc()) LBitOpI64(op), ins, lhs, rhs);
1442 return;
1445 MOZ_CRASH("Unhandled integer specialization");
1448 void LIRGenerator::visitTypeOf(MTypeOf* ins) {
1449 MDefinition* opd = ins->input();
1451 if (opd->type() == MIRType::Object) {
1452 auto* lir = new (alloc()) LTypeOfO(useRegister(opd));
1453 define(lir, ins);
1454 return;
1457 MOZ_ASSERT(opd->type() == MIRType::Value);
1459 LTypeOfV* lir = new (alloc()) LTypeOfV(useBox(opd), tempToUnbox());
1460 define(lir, ins);
1463 void LIRGenerator::visitTypeOfName(MTypeOfName* ins) {
1464 MDefinition* input = ins->input();
1465 MOZ_ASSERT(input->type() == MIRType::Int32);
1467 auto* lir = new (alloc()) LTypeOfName(useRegister(input));
1468 define(lir, ins);
1471 void LIRGenerator::visitTypeOfIs(MTypeOfIs* ins) {
1472 MDefinition* input = ins->input();
1474 MOZ_ASSERT(input->type() == MIRType::Object ||
1475 input->type() == MIRType::Value);
1477 switch (ins->jstype()) {
1478 case JSTYPE_UNDEFINED:
1479 case JSTYPE_OBJECT:
1480 case JSTYPE_FUNCTION: {
1481 if (input->type() == MIRType::Object) {
1482 auto* lir = new (alloc()) LTypeOfIsNonPrimitiveO(useRegister(input));
1483 define(lir, ins);
1484 } else {
1485 auto* lir =
1486 new (alloc()) LTypeOfIsNonPrimitiveV(useBox(input), tempToUnbox());
1487 define(lir, ins);
1489 return;
1492 case JSTYPE_STRING:
1493 case JSTYPE_NUMBER:
1494 case JSTYPE_BOOLEAN:
1495 case JSTYPE_SYMBOL:
1496 case JSTYPE_BIGINT: {
1497 MOZ_ASSERT(input->type() == MIRType::Value);
1499 auto* lir = new (alloc()) LTypeOfIsPrimitive(useBoxAtStart(input));
1500 define(lir, ins);
1501 return;
1504 #ifdef ENABLE_RECORD_TUPLE
1505 case JSTYPE_RECORD:
1506 case JSTYPE_TUPLE:
1507 #endif
1508 case JSTYPE_LIMIT:
1509 break;
1511 MOZ_CRASH("Unhandled JSType");
1514 void LIRGenerator::visitToAsyncIter(MToAsyncIter* ins) {
1515 LToAsyncIter* lir = new (alloc()) LToAsyncIter(
1516 useRegisterAtStart(ins->iterator()), useBoxAtStart(ins->nextMethod()));
1517 defineReturn(lir, ins);
1518 assignSafepoint(lir, ins);
1521 void LIRGenerator::visitToPropertyKeyCache(MToPropertyKeyCache* ins) {
1522 MDefinition* input = ins->getOperand(0);
1523 MOZ_ASSERT(ins->type() == MIRType::Value);
1525 auto* lir = new (alloc()) LToPropertyKeyCache(useBox(input));
1526 defineBox(lir, ins);
1527 assignSafepoint(lir, ins);
1530 void LIRGenerator::visitBitNot(MBitNot* ins) {
1531 MDefinition* input = ins->getOperand(0);
1533 if (ins->type() == MIRType::Int32) {
1534 MOZ_ASSERT(input->type() == MIRType::Int32);
1535 lowerForALU(new (alloc()) LBitNotI(), ins, input);
1536 return;
1539 if (ins->type() == MIRType::Int64) {
1540 MOZ_ASSERT(input->type() == MIRType::Int64);
1541 lowerForALUInt64(new (alloc()) LBitNotI64(), ins, input);
1542 return;
1545 MOZ_CRASH("Unhandled integer specialization");
1548 static bool CanEmitBitAndAtUses(MInstruction* ins) {
1549 if (!ins->canEmitAtUses()) {
1550 return false;
1553 MIRType tyL = ins->getOperand(0)->type();
1554 MIRType tyR = ins->getOperand(1)->type();
1555 if (tyL != tyR || (tyL != MIRType::Int32 && tyL != MIRType::Int64)) {
1556 return false;
1559 MUseIterator iter(ins->usesBegin());
1560 if (iter == ins->usesEnd()) {
1561 return false;
1564 MNode* node = iter->consumer();
1565 if (!node->isDefinition() || !node->toDefinition()->isInstruction()) {
1566 return false;
1569 MInstruction* use = node->toDefinition()->toInstruction();
1570 if (!use->isTest() && !(use->isCompare() && CanEmitCompareAtUses(use))) {
1571 return false;
1574 iter++;
1575 return iter == ins->usesEnd();
1578 void LIRGenerator::visitBitAnd(MBitAnd* ins) {
1579 // Sniff out if the output of this bitand is used only for a branching.
1580 // If it is, then we will emit an LBitAndAndBranch instruction in place
1581 // of this bitand and any test that uses this bitand. Thus, we can
1582 // ignore this BitAnd.
1583 if (CanEmitBitAndAtUses(ins)) {
1584 emitAtUses(ins);
1585 } else {
1586 lowerBitOp(JSOp::BitAnd, ins);
1590 void LIRGenerator::visitBitOr(MBitOr* ins) { lowerBitOp(JSOp::BitOr, ins); }
1592 void LIRGenerator::visitBitXor(MBitXor* ins) { lowerBitOp(JSOp::BitXor, ins); }
1594 void LIRGenerator::visitWasmBinaryBitwise(MWasmBinaryBitwise* ins) {
1595 switch (ins->subOpcode()) {
1596 case MWasmBinaryBitwise::SubOpcode::And:
1597 if (CanEmitBitAndAtUses(ins)) {
1598 emitAtUses(ins);
1599 } else {
1600 lowerBitOp(JSOp::BitAnd, ins);
1602 break;
1603 case MWasmBinaryBitwise::SubOpcode::Or:
1604 lowerBitOp(JSOp::BitOr, ins);
1605 break;
1606 case MWasmBinaryBitwise::SubOpcode::Xor:
1607 lowerBitOp(JSOp::BitXor, ins);
1608 break;
1609 default:
1610 MOZ_CRASH();
1614 void LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins) {
1615 MDefinition* lhs = ins->getOperand(0);
1616 MDefinition* rhs = ins->getOperand(1);
1618 if (op == JSOp::Ursh && ins->type() == MIRType::Double) {
1619 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1620 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1621 lowerUrshD(ins->toUrsh());
1622 return;
1625 MOZ_ASSERT(IsIntType(ins->type()));
1627 if (ins->type() == MIRType::Int32) {
1628 MOZ_ASSERT(lhs->type() == MIRType::Int32);
1629 MOZ_ASSERT(rhs->type() == MIRType::Int32);
1631 LShiftI* lir = new (alloc()) LShiftI(op);
1632 if (op == JSOp::Ursh) {
1633 if (ins->toUrsh()->fallible()) {
1634 assignSnapshot(lir, ins->bailoutKind());
1637 lowerForShift(lir, ins, lhs, rhs);
1638 return;
1641 if (ins->type() == MIRType::Int64) {
1642 MOZ_ASSERT(lhs->type() == MIRType::Int64);
1643 MOZ_ASSERT(rhs->type() == MIRType::Int64);
1644 lowerForShiftInt64(new (alloc()) LShiftI64(op), ins, lhs, rhs);
1645 return;
1648 MOZ_CRASH("Unhandled integer specialization");
1651 void LIRGenerator::visitLsh(MLsh* ins) { lowerShiftOp(JSOp::Lsh, ins); }
1653 void LIRGenerator::visitRsh(MRsh* ins) { lowerShiftOp(JSOp::Rsh, ins); }
1655 void LIRGenerator::visitUrsh(MUrsh* ins) { lowerShiftOp(JSOp::Ursh, ins); }
1657 void LIRGenerator::visitSignExtendInt32(MSignExtendInt32* ins) {
1658 LInstructionHelper<1, 1, 0>* lir;
1660 if (ins->mode() == MSignExtendInt32::Byte) {
1661 lir = new (alloc())
1662 LSignExtendInt32(useByteOpRegisterAtStart(ins->input()), ins->mode());
1663 } else {
1664 lir = new (alloc())
1665 LSignExtendInt32(useRegisterAtStart(ins->input()), ins->mode());
1668 define(lir, ins);
1671 void LIRGenerator::visitRotate(MRotate* ins) {
1672 MDefinition* input = ins->input();
1673 MDefinition* count = ins->count();
1675 if (ins->type() == MIRType::Int32) {
1676 auto* lir = new (alloc()) LRotate();
1677 lowerForShift(lir, ins, input, count);
1678 } else if (ins->type() == MIRType::Int64) {
1679 auto* lir = new (alloc()) LRotateI64();
1680 lowerForShiftInt64(lir, ins, input, count);
1681 } else {
1682 MOZ_CRASH("unexpected type in visitRotate");
1686 void LIRGenerator::visitFloor(MFloor* ins) {
1687 MIRType type = ins->input()->type();
1688 MOZ_ASSERT(IsFloatingPointType(type));
1690 LInstructionHelper<1, 1, 0>* lir;
1691 if (type == MIRType::Double) {
1692 lir = new (alloc()) LFloor(useRegister(ins->input()));
1693 } else {
1694 lir = new (alloc()) LFloorF(useRegister(ins->input()));
1697 assignSnapshot(lir, ins->bailoutKind());
1698 define(lir, ins);
1701 void LIRGenerator::visitCeil(MCeil* ins) {
1702 MIRType type = ins->input()->type();
1703 MOZ_ASSERT(IsFloatingPointType(type));
1705 LInstructionHelper<1, 1, 0>* lir;
1706 if (type == MIRType::Double) {
1707 lir = new (alloc()) LCeil(useRegister(ins->input()));
1708 } else {
1709 lir = new (alloc()) LCeilF(useRegister(ins->input()));
1712 assignSnapshot(lir, ins->bailoutKind());
1713 define(lir, ins);
1716 void LIRGenerator::visitRound(MRound* ins) {
1717 MIRType type = ins->input()->type();
1718 MOZ_ASSERT(IsFloatingPointType(type));
1720 LInstructionHelper<1, 1, 1>* lir;
1721 if (type == MIRType::Double) {
1722 lir = new (alloc()) LRound(useRegister(ins->input()), tempDouble());
1723 } else {
1724 lir = new (alloc()) LRoundF(useRegister(ins->input()), tempFloat32());
1727 assignSnapshot(lir, ins->bailoutKind());
1728 define(lir, ins);
1731 void LIRGenerator::visitTrunc(MTrunc* ins) {
1732 MIRType type = ins->input()->type();
1733 MOZ_ASSERT(IsFloatingPointType(type));
1735 LInstructionHelper<1, 1, 0>* lir;
1736 if (type == MIRType::Double) {
1737 lir = new (alloc()) LTrunc(useRegister(ins->input()));
1738 } else {
1739 lir = new (alloc()) LTruncF(useRegister(ins->input()));
1742 assignSnapshot(lir, ins->bailoutKind());
1743 define(lir, ins);
1746 void LIRGenerator::visitNearbyInt(MNearbyInt* ins) {
1747 MIRType inputType = ins->input()->type();
1748 MOZ_ASSERT(IsFloatingPointType(inputType));
1749 MOZ_ASSERT(ins->type() == inputType);
1751 LInstructionHelper<1, 1, 0>* lir;
1752 if (inputType == MIRType::Double) {
1753 lir = new (alloc()) LNearbyInt(useRegisterAtStart(ins->input()));
1754 } else {
1755 lir = new (alloc()) LNearbyIntF(useRegisterAtStart(ins->input()));
1758 define(lir, ins);
1761 void LIRGenerator::visitMinMax(MMinMax* ins) {
1762 MDefinition* first = ins->getOperand(0);
1763 MDefinition* second = ins->getOperand(1);
1765 ReorderCommutative(&first, &second, ins);
1767 LMinMaxBase* lir;
1768 switch (ins->type()) {
1769 case MIRType::Int32:
1770 lir = new (alloc())
1771 LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
1772 break;
1773 case MIRType::Float32:
1774 lir = new (alloc())
1775 LMinMaxF(useRegisterAtStart(first), useRegister(second));
1776 break;
1777 case MIRType::Double:
1778 lir = new (alloc())
1779 LMinMaxD(useRegisterAtStart(first), useRegister(second));
1780 break;
1781 default:
1782 MOZ_CRASH();
1785 // Input reuse is OK (for now) even on ARM64: floating min/max are fairly
1786 // expensive due to SNaN -> QNaN conversion, and int min/max is for asm.js.
1787 defineReuseInput(lir, ins, 0);
1790 void LIRGenerator::visitMinMaxArray(MMinMaxArray* ins) {
1791 LInstructionHelper<1, 1, 3>* lir;
1792 if (ins->type() == MIRType::Int32) {
1793 lir = new (alloc())
1794 LMinMaxArrayI(useRegisterAtStart(ins->array()), temp(), temp(), temp());
1795 } else {
1796 MOZ_ASSERT(ins->type() == MIRType::Double);
1797 lir = new (alloc()) LMinMaxArrayD(useRegisterAtStart(ins->array()),
1798 tempDouble(), temp(), temp());
1800 assignSnapshot(lir, ins->bailoutKind());
1801 define(lir, ins);
1804 LInstructionHelper<1, 1, 0>* LIRGenerator::allocateAbs(MAbs* ins,
1805 LAllocation input) {
1806 MDefinition* num = ins->input();
1807 MOZ_ASSERT(IsNumberType(num->type()));
1809 LInstructionHelper<1, 1, 0>* lir;
1810 switch (num->type()) {
1811 case MIRType::Int32:
1812 lir = new (alloc()) LAbsI(input);
1813 // needed to handle abs(INT32_MIN)
1814 if (ins->fallible()) {
1815 assignSnapshot(lir, ins->bailoutKind());
1817 break;
1818 case MIRType::Float32:
1819 lir = new (alloc()) LAbsF(input);
1820 break;
1821 case MIRType::Double:
1822 lir = new (alloc()) LAbsD(input);
1823 break;
1824 default:
1825 MOZ_CRASH();
1827 return lir;
1830 void LIRGenerator::visitClz(MClz* ins) {
1831 MDefinition* num = ins->num();
1833 MOZ_ASSERT(IsIntType(ins->type()));
1835 if (ins->type() == MIRType::Int32) {
1836 LClzI* lir = new (alloc()) LClzI(useRegisterAtStart(num));
1837 define(lir, ins);
1838 return;
1841 auto* lir = new (alloc()) LClzI64(useInt64RegisterAtStart(num));
1842 defineInt64(lir, ins);
1845 void LIRGenerator::visitCtz(MCtz* ins) {
1846 MDefinition* num = ins->num();
1848 MOZ_ASSERT(IsIntType(ins->type()));
1850 if (ins->type() == MIRType::Int32) {
1851 LCtzI* lir = new (alloc()) LCtzI(useRegisterAtStart(num));
1852 define(lir, ins);
1853 return;
1856 auto* lir = new (alloc()) LCtzI64(useInt64RegisterAtStart(num));
1857 defineInt64(lir, ins);
1860 void LIRGenerator::visitPopcnt(MPopcnt* ins) {
1861 MDefinition* num = ins->num();
1863 MOZ_ASSERT(IsIntType(ins->type()));
1865 if (ins->type() == MIRType::Int32) {
1866 LPopcntI* lir = new (alloc()) LPopcntI(useRegisterAtStart(num), temp());
1867 define(lir, ins);
1868 return;
1871 auto* lir = new (alloc()) LPopcntI64(useInt64RegisterAtStart(num), temp());
1872 defineInt64(lir, ins);
1875 void LIRGenerator::visitSqrt(MSqrt* ins) {
1876 MDefinition* num = ins->input();
1877 MOZ_ASSERT(IsFloatingPointType(num->type()));
1879 LInstructionHelper<1, 1, 0>* lir;
1880 if (num->type() == MIRType::Double) {
1881 lir = new (alloc()) LSqrtD(useRegisterAtStart(num));
1882 } else {
1883 lir = new (alloc()) LSqrtF(useRegisterAtStart(num));
1885 define(lir, ins);
1888 void LIRGenerator::visitAtan2(MAtan2* ins) {
1889 MDefinition* y = ins->y();
1890 MOZ_ASSERT(y->type() == MIRType::Double);
1892 MDefinition* x = ins->x();
1893 MOZ_ASSERT(x->type() == MIRType::Double);
1895 LAtan2D* lir =
1896 new (alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x));
1897 defineReturn(lir, ins);
1900 void LIRGenerator::visitHypot(MHypot* ins) {
1901 LHypot* lir = nullptr;
1902 uint32_t length = ins->numOperands();
1903 for (uint32_t i = 0; i < length; ++i) {
1904 MOZ_ASSERT(ins->getOperand(i)->type() == MIRType::Double);
1907 switch (length) {
1908 case 2:
1909 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1910 useRegisterAtStart(ins->getOperand(1)));
1911 break;
1912 case 3:
1913 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1914 useRegisterAtStart(ins->getOperand(1)),
1915 useRegisterAtStart(ins->getOperand(2)));
1916 break;
1917 case 4:
1918 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1919 useRegisterAtStart(ins->getOperand(1)),
1920 useRegisterAtStart(ins->getOperand(2)),
1921 useRegisterAtStart(ins->getOperand(3)));
1922 break;
1923 default:
1924 MOZ_CRASH("Unexpected number of arguments to LHypot.");
1927 defineReturn(lir, ins);
1930 void LIRGenerator::visitPow(MPow* ins) {
1931 MDefinition* input = ins->input();
1932 MDefinition* power = ins->power();
1934 if (ins->type() == MIRType::Int32) {
1935 MOZ_ASSERT(input->type() == MIRType::Int32);
1936 MOZ_ASSERT(power->type() == MIRType::Int32);
1938 if (input->isConstant()) {
1939 // Restrict this optimization to |base <= 256| to avoid generating too
1940 // many consecutive shift instructions.
1941 int32_t base = input->toConstant()->toInt32();
1942 if (2 <= base && base <= 256 && mozilla::IsPowerOfTwo(uint32_t(base))) {
1943 lowerPowOfTwoI(ins);
1944 return;
1948 auto* lir = new (alloc())
1949 LPowII(useRegister(input), useRegister(power), temp(), temp());
1950 assignSnapshot(lir, ins->bailoutKind());
1951 define(lir, ins);
1952 return;
1955 MOZ_ASSERT(ins->type() == MIRType::Double);
1956 MOZ_ASSERT(input->type() == MIRType::Double);
1957 MOZ_ASSERT(power->type() == MIRType::Int32 ||
1958 power->type() == MIRType::Double);
1960 LInstruction* lir;
1961 if (power->type() == MIRType::Int32) {
1962 lir = new (alloc())
1963 LPowI(useRegisterAtStart(input), useRegisterAtStart(power));
1964 } else {
1965 lir = new (alloc())
1966 LPowD(useRegisterAtStart(input), useRegisterAtStart(power));
1968 defineReturn(lir, ins);
1971 void LIRGenerator::visitSign(MSign* ins) {
1972 if (ins->type() == ins->input()->type()) {
1973 LInstructionHelper<1, 1, 0>* lir;
1974 if (ins->type() == MIRType::Int32) {
1975 lir = new (alloc()) LSignI(useRegister(ins->input()));
1976 } else {
1977 MOZ_ASSERT(ins->type() == MIRType::Double);
1978 lir = new (alloc()) LSignD(useRegister(ins->input()));
1980 define(lir, ins);
1981 } else {
1982 MOZ_ASSERT(ins->type() == MIRType::Int32);
1983 MOZ_ASSERT(ins->input()->type() == MIRType::Double);
1985 auto* lir = new (alloc()) LSignDI(useRegister(ins->input()), tempDouble());
1986 assignSnapshot(lir, ins->bailoutKind());
1987 define(lir, ins);
1991 void LIRGenerator::visitMathFunction(MMathFunction* ins) {
1992 MOZ_ASSERT(IsFloatingPointType(ins->type()));
1993 MOZ_ASSERT(ins->type() == ins->input()->type());
1995 LInstruction* lir;
1996 if (ins->type() == MIRType::Double) {
1997 lir = new (alloc()) LMathFunctionD(useRegisterAtStart(ins->input()));
1998 } else {
1999 lir = new (alloc()) LMathFunctionF(useRegisterAtStart(ins->input()));
2001 defineReturn(lir, ins);
2004 void LIRGenerator::visitRandom(MRandom* ins) {
2005 auto* lir = new (alloc()) LRandom(temp(), tempInt64(), tempInt64());
2006 define(lir, ins);
2009 // Try to mark an add or sub instruction as able to recover its input when
2010 // bailing out.
2011 template <typename S, typename T>
2012 static void MaybeSetRecoversInput(S* mir, T* lir) {
2013 MOZ_ASSERT(lir->mirRaw() == mir);
2014 if (!mir->fallible() || !lir->snapshot()) {
2015 return;
2018 if (lir->output()->policy() != LDefinition::MUST_REUSE_INPUT) {
2019 return;
2022 // The original operands to an add or sub can't be recovered if they both
2023 // use the same register.
2024 if (lir->lhs()->isUse() && lir->rhs()->isUse() &&
2025 lir->lhs()->toUse()->virtualRegister() ==
2026 lir->rhs()->toUse()->virtualRegister()) {
2027 return;
2030 // Add instructions that are on two different values can recover
2031 // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy
2032 // of that input does not need to be kept alive in the snapshot
2033 // for the instruction.
2035 lir->setRecoversInput();
2037 const LUse* input = lir->getOperand(lir->output()->getReusedInput())->toUse();
2038 lir->snapshot()->rewriteRecoveredInput(*input);
2041 void LIRGenerator::visitAdd(MAdd* ins) {
2042 MDefinition* lhs = ins->getOperand(0);
2043 MDefinition* rhs = ins->getOperand(1);
2045 MOZ_ASSERT(lhs->type() == rhs->type());
2046 MOZ_ASSERT(IsNumberType(ins->type()));
2048 if (ins->type() == MIRType::Int32) {
2049 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2050 ReorderCommutative(&lhs, &rhs, ins);
2051 LAddI* lir = new (alloc()) LAddI;
2053 if (ins->fallible()) {
2054 assignSnapshot(lir, ins->bailoutKind());
2057 lowerForALU(lir, ins, lhs, rhs);
2058 MaybeSetRecoversInput(ins, lir);
2059 return;
2062 if (ins->type() == MIRType::Int64) {
2063 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2064 ReorderCommutative(&lhs, &rhs, ins);
2065 LAddI64* lir = new (alloc()) LAddI64;
2066 lowerForALUInt64(lir, ins, lhs, rhs);
2067 return;
2070 if (ins->type() == MIRType::Double) {
2071 MOZ_ASSERT(lhs->type() == MIRType::Double);
2072 ReorderCommutative(&lhs, &rhs, ins);
2073 lowerForFPU(new (alloc()) LMathD(JSOp::Add), ins, lhs, rhs);
2074 return;
2077 if (ins->type() == MIRType::Float32) {
2078 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2079 ReorderCommutative(&lhs, &rhs, ins);
2080 lowerForFPU(new (alloc()) LMathF(JSOp::Add), ins, lhs, rhs);
2081 return;
2084 MOZ_CRASH("Unhandled number specialization");
2087 void LIRGenerator::visitSub(MSub* ins) {
2088 MDefinition* lhs = ins->lhs();
2089 MDefinition* rhs = ins->rhs();
2091 MOZ_ASSERT(lhs->type() == rhs->type());
2092 MOZ_ASSERT(IsNumberType(ins->type()));
2094 if (ins->type() == MIRType::Int32) {
2095 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2097 LSubI* lir = new (alloc()) LSubI;
2098 if (ins->fallible()) {
2099 assignSnapshot(lir, ins->bailoutKind());
2102 // If our LHS is a constant 0 and we don't have to worry about results that
2103 // can't be represented as an int32, we can optimize to an LNegI.
2104 if (!ins->fallible() && lhs->isConstant() &&
2105 lhs->toConstant()->toInt32() == 0) {
2106 lowerNegI(ins, rhs);
2107 return;
2110 lowerForALU(lir, ins, lhs, rhs);
2111 MaybeSetRecoversInput(ins, lir);
2112 return;
2115 if (ins->type() == MIRType::Int64) {
2116 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2118 // If our LHS is a constant 0, we can optimize to an LNegI64.
2119 if (lhs->isConstant() && lhs->toConstant()->toInt64() == 0) {
2120 lowerNegI64(ins, rhs);
2121 return;
2124 LSubI64* lir = new (alloc()) LSubI64;
2125 lowerForALUInt64(lir, ins, lhs, rhs);
2126 return;
2129 if (ins->type() == MIRType::Double) {
2130 MOZ_ASSERT(lhs->type() == MIRType::Double);
2131 lowerForFPU(new (alloc()) LMathD(JSOp::Sub), ins, lhs, rhs);
2132 return;
2135 if (ins->type() == MIRType::Float32) {
2136 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2137 lowerForFPU(new (alloc()) LMathF(JSOp::Sub), ins, lhs, rhs);
2138 return;
2141 MOZ_CRASH("Unhandled number specialization");
2144 void LIRGenerator::visitMul(MMul* ins) {
2145 MDefinition* lhs = ins->lhs();
2146 MDefinition* rhs = ins->rhs();
2147 MOZ_ASSERT(lhs->type() == rhs->type());
2148 MOZ_ASSERT(IsNumberType(ins->type()));
2150 if (ins->type() == MIRType::Int32) {
2151 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2152 ReorderCommutative(&lhs, &rhs, ins);
2154 // If our RHS is a constant -1 and we don't have to worry about results that
2155 // can't be represented as an int32, we can optimize to an LNegI.
2156 if (!ins->fallible() && rhs->isConstant() &&
2157 rhs->toConstant()->toInt32() == -1) {
2158 lowerNegI(ins, lhs);
2159 return;
2162 lowerMulI(ins, lhs, rhs);
2163 return;
2166 if (ins->type() == MIRType::Int64) {
2167 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2168 ReorderCommutative(&lhs, &rhs, ins);
2170 // If our RHS is a constant -1, we can optimize to an LNegI64.
2171 if (rhs->isConstant() && rhs->toConstant()->toInt64() == -1) {
2172 lowerNegI64(ins, lhs);
2173 return;
2176 LMulI64* lir = new (alloc()) LMulI64;
2177 lowerForMulInt64(lir, ins, lhs, rhs);
2178 return;
2181 if (ins->type() == MIRType::Double) {
2182 MOZ_ASSERT(lhs->type() == MIRType::Double);
2183 ReorderCommutative(&lhs, &rhs, ins);
2185 // If our RHS is a constant -1.0, we can optimize to an LNegD.
2186 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2187 rhs->toConstant()->toDouble() == -1.0) {
2188 defineReuseInput(new (alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0);
2189 return;
2192 lowerForFPU(new (alloc()) LMathD(JSOp::Mul), ins, lhs, rhs);
2193 return;
2196 if (ins->type() == MIRType::Float32) {
2197 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2198 ReorderCommutative(&lhs, &rhs, ins);
2200 // We apply the same optimizations as for doubles
2201 if (!ins->mustPreserveNaN() && rhs->isConstant() &&
2202 rhs->toConstant()->toFloat32() == -1.0f) {
2203 defineReuseInput(new (alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0);
2204 return;
2207 lowerForFPU(new (alloc()) LMathF(JSOp::Mul), ins, lhs, rhs);
2208 return;
2211 MOZ_CRASH("Unhandled number specialization");
2214 void LIRGenerator::visitDiv(MDiv* ins) {
2215 MDefinition* lhs = ins->lhs();
2216 MDefinition* rhs = ins->rhs();
2217 MOZ_ASSERT(lhs->type() == rhs->type());
2218 MOZ_ASSERT(IsNumberType(ins->type()));
2220 if (ins->type() == MIRType::Int32) {
2221 MOZ_ASSERT(lhs->type() == MIRType::Int32);
2222 lowerDivI(ins);
2223 return;
2226 if (ins->type() == MIRType::Int64) {
2227 MOZ_ASSERT(lhs->type() == MIRType::Int64);
2228 lowerDivI64(ins);
2229 return;
2232 if (ins->type() == MIRType::Double) {
2233 MOZ_ASSERT(lhs->type() == MIRType::Double);
2234 lowerForFPU(new (alloc()) LMathD(JSOp::Div), ins, lhs, rhs);
2235 return;
2238 if (ins->type() == MIRType::Float32) {
2239 MOZ_ASSERT(lhs->type() == MIRType::Float32);
2240 lowerForFPU(new (alloc()) LMathF(JSOp::Div), ins, lhs, rhs);
2241 return;
2244 MOZ_CRASH("Unhandled number specialization");
2247 void LIRGenerator::visitWasmBuiltinDivI64(MWasmBuiltinDivI64* div) {
2248 lowerWasmBuiltinDivI64(div);
2251 void LIRGenerator::visitWasmBuiltinModI64(MWasmBuiltinModI64* mod) {
2252 lowerWasmBuiltinModI64(mod);
2255 void LIRGenerator::visitBuiltinInt64ToFloatingPoint(
2256 MBuiltinInt64ToFloatingPoint* ins) {
2257 lowerBuiltinInt64ToFloatingPoint(ins);
2260 void LIRGenerator::visitWasmBuiltinTruncateToInt64(
2261 MWasmBuiltinTruncateToInt64* ins) {
2262 lowerWasmBuiltinTruncateToInt64(ins);
2265 void LIRGenerator::visitWasmBuiltinModD(MWasmBuiltinModD* ins) {
2266 MOZ_ASSERT(gen->compilingWasm());
2267 LWasmBuiltinModD* lir = new (alloc()) LWasmBuiltinModD(
2268 useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()),
2269 useFixedAtStart(ins->instance(), InstanceReg));
2270 defineReturn(lir, ins);
2273 void LIRGenerator::visitMod(MMod* ins) {
2274 MOZ_ASSERT(ins->lhs()->type() == ins->rhs()->type());
2275 MOZ_ASSERT(IsNumberType(ins->type()));
2277 if (ins->type() == MIRType::Int32) {
2278 MOZ_ASSERT(ins->type() == MIRType::Int32);
2279 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int32);
2280 lowerModI(ins);
2281 return;
2284 if (ins->type() == MIRType::Int64) {
2285 MOZ_ASSERT(ins->type() == MIRType::Int64);
2286 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int64);
2287 lowerModI64(ins);
2288 return;
2291 if (ins->type() == MIRType::Double) {
2292 MOZ_ASSERT(ins->lhs()->type() == MIRType::Double);
2293 MOZ_ASSERT(ins->rhs()->type() == MIRType::Double);
2295 MOZ_ASSERT(!gen->compilingWasm());
2297 if (Assembler::HasRoundInstruction(RoundingMode::TowardsZero)) {
2298 if (ins->rhs()->isConstant()) {
2299 double d = ins->rhs()->toConstant()->toDouble();
2300 int32_t div;
2301 if (mozilla::NumberIsInt32(d, &div) && div > 0 &&
2302 mozilla::IsPowerOfTwo(uint32_t(div))) {
2303 auto* lir = new (alloc()) LModPowTwoD(useRegister(ins->lhs()), div);
2304 define(lir, ins);
2305 return;
2310 LModD* lir = new (alloc())
2311 LModD(useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()));
2312 defineReturn(lir, ins);
2313 return;
2316 MOZ_CRASH("Unhandled number specialization");
2319 void LIRGenerator::visitBigIntAdd(MBigIntAdd* ins) {
2320 auto* lir = new (alloc()) LBigIntAdd(useRegister(ins->lhs()),
2321 useRegister(ins->rhs()), temp(), temp());
2322 define(lir, ins);
2323 assignSafepoint(lir, ins);
2326 void LIRGenerator::visitBigIntSub(MBigIntSub* ins) {
2327 auto* lir = new (alloc()) LBigIntSub(useRegister(ins->lhs()),
2328 useRegister(ins->rhs()), temp(), temp());
2329 define(lir, ins);
2330 assignSafepoint(lir, ins);
2333 void LIRGenerator::visitBigIntMul(MBigIntMul* ins) {
2334 auto* lir = new (alloc()) LBigIntMul(useRegister(ins->lhs()),
2335 useRegister(ins->rhs()), temp(), temp());
2336 define(lir, ins);
2337 assignSafepoint(lir, ins);
2340 void LIRGenerator::visitBigIntDiv(MBigIntDiv* ins) { lowerBigIntDiv(ins); }
2342 void LIRGenerator::visitBigIntMod(MBigIntMod* ins) { lowerBigIntMod(ins); }
2344 void LIRGenerator::visitBigIntPow(MBigIntPow* ins) {
2345 auto* lir = new (alloc()) LBigIntPow(useRegister(ins->lhs()),
2346 useRegister(ins->rhs()), temp(), temp());
2347 define(lir, ins);
2348 assignSafepoint(lir, ins);
2351 void LIRGenerator::visitBigIntBitAnd(MBigIntBitAnd* ins) {
2352 auto* lir = new (alloc()) LBigIntBitAnd(
2353 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2354 define(lir, ins);
2355 assignSafepoint(lir, ins);
2358 void LIRGenerator::visitBigIntBitOr(MBigIntBitOr* ins) {
2359 auto* lir = new (alloc()) LBigIntBitOr(
2360 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2361 define(lir, ins);
2362 assignSafepoint(lir, ins);
2365 void LIRGenerator::visitBigIntBitXor(MBigIntBitXor* ins) {
2366 auto* lir = new (alloc()) LBigIntBitXor(
2367 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp());
2368 define(lir, ins);
2369 assignSafepoint(lir, ins);
2372 void LIRGenerator::visitBigIntLsh(MBigIntLsh* ins) { lowerBigIntLsh(ins); }
2374 void LIRGenerator::visitBigIntRsh(MBigIntRsh* ins) { lowerBigIntRsh(ins); }
2376 void LIRGenerator::visitBigIntIncrement(MBigIntIncrement* ins) {
2377 auto* lir =
2378 new (alloc()) LBigIntIncrement(useRegister(ins->input()), temp(), temp());
2379 define(lir, ins);
2380 assignSafepoint(lir, ins);
2383 void LIRGenerator::visitBigIntDecrement(MBigIntDecrement* ins) {
2384 auto* lir =
2385 new (alloc()) LBigIntDecrement(useRegister(ins->input()), temp(), temp());
2386 define(lir, ins);
2387 assignSafepoint(lir, ins);
2390 void LIRGenerator::visitBigIntNegate(MBigIntNegate* ins) {
2391 auto* lir = new (alloc()) LBigIntNegate(useRegister(ins->input()), temp());
2392 define(lir, ins);
2393 assignSafepoint(lir, ins);
2396 void LIRGenerator::visitBigIntBitNot(MBigIntBitNot* ins) {
2397 auto* lir =
2398 new (alloc()) LBigIntBitNot(useRegister(ins->input()), temp(), temp());
2399 define(lir, ins);
2400 assignSafepoint(lir, ins);
2403 void LIRGenerator::visitInt32ToStringWithBase(MInt32ToStringWithBase* ins) {
2404 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2405 MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
2407 int32_t baseInt =
2408 ins->base()->isConstant() ? ins->base()->toConstant()->toInt32() : 0;
2410 LAllocation base;
2411 if (2 <= baseInt && baseInt <= 36) {
2412 base = useRegisterOrConstant(ins->base());
2413 } else {
2414 base = useRegister(ins->base());
2417 auto* lir = new (alloc())
2418 LInt32ToStringWithBase(useRegister(ins->input()), base, temp(), temp());
2419 define(lir, ins);
2420 assignSafepoint(lir, ins);
2423 void LIRGenerator::visitNumberParseInt(MNumberParseInt* ins) {
2424 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2425 MOZ_ASSERT(ins->radix()->type() == MIRType::Int32);
2427 auto* lir = new (alloc()) LNumberParseInt(useRegisterAtStart(ins->string()),
2428 useRegisterAtStart(ins->radix()),
2429 tempFixed(CallTempReg0));
2430 defineReturn(lir, ins);
2431 assignSafepoint(lir, ins);
2434 void LIRGenerator::visitDoubleParseInt(MDoubleParseInt* ins) {
2435 MOZ_ASSERT(ins->number()->type() == MIRType::Double);
2437 auto* lir =
2438 new (alloc()) LDoubleParseInt(useRegister(ins->number()), tempDouble());
2439 assignSnapshot(lir, ins->bailoutKind());
2440 define(lir, ins);
2443 void LIRGenerator::visitConcat(MConcat* ins) {
2444 MDefinition* lhs = ins->getOperand(0);
2445 MDefinition* rhs = ins->getOperand(1);
2447 MOZ_ASSERT(lhs->type() == MIRType::String);
2448 MOZ_ASSERT(rhs->type() == MIRType::String);
2449 MOZ_ASSERT(ins->type() == MIRType::String);
2451 LConcat* lir = new (alloc()) LConcat(
2452 useFixedAtStart(lhs, CallTempReg0), useFixedAtStart(rhs, CallTempReg1),
2453 tempFixed(CallTempReg0), tempFixed(CallTempReg1), tempFixed(CallTempReg2),
2454 tempFixed(CallTempReg3), tempFixed(CallTempReg4));
2455 defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5)));
2456 assignSafepoint(lir, ins);
2459 void LIRGenerator::visitLinearizeString(MLinearizeString* ins) {
2460 MDefinition* str = ins->string();
2461 MOZ_ASSERT(str->type() == MIRType::String);
2463 auto* lir = new (alloc()) LLinearizeString(useRegister(str));
2464 define(lir, ins);
2465 assignSafepoint(lir, ins);
2468 void LIRGenerator::visitLinearizeForCharAccess(MLinearizeForCharAccess* ins) {
2469 MDefinition* str = ins->string();
2470 MDefinition* idx = ins->index();
2472 MOZ_ASSERT(str->type() == MIRType::String);
2473 MOZ_ASSERT(idx->type() == MIRType::Int32);
2475 auto* lir =
2476 new (alloc()) LLinearizeForCharAccess(useRegister(str), useRegister(idx));
2477 define(lir, ins);
2478 assignSafepoint(lir, ins);
2481 void LIRGenerator::visitLinearizeForCodePointAccess(
2482 MLinearizeForCodePointAccess* ins) {
2483 MDefinition* str = ins->string();
2484 MDefinition* idx = ins->index();
2486 MOZ_ASSERT(str->type() == MIRType::String);
2487 MOZ_ASSERT(idx->type() == MIRType::Int32);
2489 auto* lir = new (alloc())
2490 LLinearizeForCodePointAccess(useRegister(str), useRegister(idx), temp());
2491 define(lir, ins);
2492 assignSafepoint(lir, ins);
2495 void LIRGenerator::visitToRelativeStringIndex(MToRelativeStringIndex* ins) {
2496 MDefinition* index = ins->index();
2497 MDefinition* length = ins->length();
2499 MOZ_ASSERT(index->type() == MIRType::Int32);
2500 MOZ_ASSERT(length->type() == MIRType::Int32);
2502 auto* lir = new (alloc())
2503 LToRelativeStringIndex(useRegister(index), useRegister(length));
2504 define(lir, ins);
2507 void LIRGenerator::visitCharCodeAt(MCharCodeAt* ins) {
2508 MDefinition* str = ins->string();
2509 MDefinition* idx = ins->index();
2511 MOZ_ASSERT(str->type() == MIRType::String);
2512 MOZ_ASSERT(idx->type() == MIRType::Int32);
2514 auto* lir = new (alloc())
2515 LCharCodeAt(useRegister(str), useRegisterOrZero(idx), temp(), temp());
2516 define(lir, ins);
2517 assignSafepoint(lir, ins);
2520 void LIRGenerator::visitCharCodeAtOrNegative(MCharCodeAtOrNegative* ins) {
2521 MDefinition* str = ins->string();
2522 MDefinition* idx = ins->index();
2524 MOZ_ASSERT(str->type() == MIRType::String);
2525 MOZ_ASSERT(idx->type() == MIRType::Int32);
2527 auto* lir = new (alloc()) LCharCodeAtOrNegative(
2528 useRegister(str), useRegisterOrZero(idx), temp(), temp());
2529 define(lir, ins);
2530 assignSafepoint(lir, ins);
2533 void LIRGenerator::visitCodePointAt(MCodePointAt* ins) {
2534 MDefinition* str = ins->string();
2535 MDefinition* idx = ins->index();
2537 MOZ_ASSERT(str->type() == MIRType::String);
2538 MOZ_ASSERT(idx->type() == MIRType::Int32);
2540 auto* lir = new (alloc())
2541 LCodePointAt(useRegister(str), useRegister(idx), temp(), temp());
2542 define(lir, ins);
2543 assignSafepoint(lir, ins);
2546 void LIRGenerator::visitCodePointAtOrNegative(MCodePointAtOrNegative* ins) {
2547 MDefinition* str = ins->string();
2548 MDefinition* idx = ins->index();
2550 MOZ_ASSERT(str->type() == MIRType::String);
2551 MOZ_ASSERT(idx->type() == MIRType::Int32);
2553 auto* lir = new (alloc()) LCodePointAtOrNegative(
2554 useRegister(str), useRegister(idx), temp(), temp());
2555 define(lir, ins);
2556 assignSafepoint(lir, ins);
2559 void LIRGenerator::visitNegativeToNaN(MNegativeToNaN* ins) {
2560 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2562 auto* lir = new (alloc()) LNegativeToNaN(useRegister(ins->input()));
2563 defineBox(lir, ins);
2566 void LIRGenerator::visitNegativeToUndefined(MNegativeToUndefined* ins) {
2567 MOZ_ASSERT(ins->input()->type() == MIRType::Int32);
2569 auto* lir = new (alloc()) LNegativeToUndefined(useRegister(ins->input()));
2570 defineBox(lir, ins);
2573 void LIRGenerator::visitFromCharCode(MFromCharCode* ins) {
2574 MDefinition* code = ins->code();
2576 MOZ_ASSERT(code->type() == MIRType::Int32);
2578 LFromCharCode* lir = new (alloc()) LFromCharCode(useRegister(code));
2579 define(lir, ins);
2580 assignSafepoint(lir, ins);
2583 void LIRGenerator::visitFromCharCodeEmptyIfNegative(
2584 MFromCharCodeEmptyIfNegative* ins) {
2585 MDefinition* code = ins->code();
2587 MOZ_ASSERT(code->type() == MIRType::Int32);
2589 auto* lir = new (alloc()) LFromCharCodeEmptyIfNegative(useRegister(code));
2590 define(lir, ins);
2591 assignSafepoint(lir, ins);
2594 void LIRGenerator::visitFromCharCodeUndefinedIfNegative(
2595 MFromCharCodeUndefinedIfNegative* ins) {
2596 MDefinition* code = ins->code();
2598 MOZ_ASSERT(code->type() == MIRType::Int32);
2600 auto* lir = new (alloc()) LFromCharCodeUndefinedIfNegative(useRegister(code));
2601 defineBox(lir, ins);
2602 assignSafepoint(lir, ins);
2605 void LIRGenerator::visitFromCodePoint(MFromCodePoint* ins) {
2606 MDefinition* codePoint = ins->codePoint();
2608 MOZ_ASSERT(codePoint->type() == MIRType::Int32);
2610 LFromCodePoint* lir =
2611 new (alloc()) LFromCodePoint(useRegister(codePoint), temp(), temp());
2612 assignSnapshot(lir, ins->bailoutKind());
2613 define(lir, ins);
2614 assignSafepoint(lir, ins);
2617 void LIRGenerator::visitStringIncludes(MStringIncludes* ins) {
2618 auto* string = ins->string();
2619 MOZ_ASSERT(string->type() == MIRType::String);
2621 auto* searchStr = ins->searchString();
2622 MOZ_ASSERT(searchStr->type() == MIRType::String);
2624 if (searchStr->isConstant()) {
2625 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2626 size_t length = linear->length();
2627 if (length == 1 || length == 2) {
2628 LDefinition tempDef = LDefinition::BogusTemp();
2629 if (length > 1) {
2630 tempDef = temp();
2633 auto* lir = new (alloc()) LStringIncludesSIMD(useRegister(string), temp(),
2634 temp(), tempDef, linear);
2635 define(lir, ins);
2636 assignSafepoint(lir, ins);
2637 return;
2641 auto* lir = new (alloc()) LStringIncludes(useRegisterAtStart(string),
2642 useRegisterAtStart(searchStr));
2643 defineReturn(lir, ins);
2644 assignSafepoint(lir, ins);
2647 void LIRGenerator::visitStringIndexOf(MStringIndexOf* ins) {
2648 auto* string = ins->string();
2649 MOZ_ASSERT(string->type() == MIRType::String);
2651 auto* searchStr = ins->searchString();
2652 MOZ_ASSERT(searchStr->type() == MIRType::String);
2654 if (searchStr->isConstant()) {
2655 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2656 size_t length = linear->length();
2657 if (length == 1 || length == 2) {
2658 LDefinition tempDef = LDefinition::BogusTemp();
2659 if (length > 1) {
2660 tempDef = temp();
2663 auto* lir = new (alloc()) LStringIndexOfSIMD(useRegister(string), temp(),
2664 temp(), tempDef, linear);
2665 define(lir, ins);
2666 assignSafepoint(lir, ins);
2667 return;
2671 auto* lir = new (alloc())
2672 LStringIndexOf(useRegisterAtStart(string), useRegisterAtStart(searchStr));
2673 defineReturn(lir, ins);
2674 assignSafepoint(lir, ins);
2677 void LIRGenerator::visitStringLastIndexOf(MStringLastIndexOf* ins) {
2678 auto* string = ins->string();
2679 MOZ_ASSERT(string->type() == MIRType::String);
2681 auto* searchStr = ins->searchString();
2682 MOZ_ASSERT(searchStr->type() == MIRType::String);
2684 auto* lir = new (alloc()) LStringLastIndexOf(useRegisterAtStart(string),
2685 useRegisterAtStart(searchStr));
2686 defineReturn(lir, ins);
2687 assignSafepoint(lir, ins);
2690 void LIRGenerator::visitStringStartsWith(MStringStartsWith* ins) {
2691 auto* string = ins->string();
2692 MOZ_ASSERT(string->type() == MIRType::String);
2694 auto* searchStr = ins->searchString();
2695 MOZ_ASSERT(searchStr->type() == MIRType::String);
2697 if (searchStr->isConstant()) {
2698 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2700 if (MacroAssembler::canCompareStringCharsInline(linear)) {
2701 auto* lir = new (alloc())
2702 LStringStartsWithInline(useRegister(string), temp(), linear);
2703 define(lir, ins);
2704 assignSafepoint(lir, ins);
2705 return;
2709 auto* lir = new (alloc()) LStringStartsWith(useRegisterAtStart(string),
2710 useRegisterAtStart(searchStr));
2711 defineReturn(lir, ins);
2712 assignSafepoint(lir, ins);
2715 void LIRGenerator::visitStringEndsWith(MStringEndsWith* ins) {
2716 auto* string = ins->string();
2717 MOZ_ASSERT(string->type() == MIRType::String);
2719 auto* searchStr = ins->searchString();
2720 MOZ_ASSERT(searchStr->type() == MIRType::String);
2722 if (searchStr->isConstant()) {
2723 JSLinearString* linear = &searchStr->toConstant()->toString()->asLinear();
2725 if (MacroAssembler::canCompareStringCharsInline(linear)) {
2726 auto* lir = new (alloc())
2727 LStringEndsWithInline(useRegister(string), temp(), linear);
2728 define(lir, ins);
2729 assignSafepoint(lir, ins);
2730 return;
2734 auto* lir = new (alloc()) LStringEndsWith(useRegisterAtStart(string),
2735 useRegisterAtStart(searchStr));
2736 defineReturn(lir, ins);
2737 assignSafepoint(lir, ins);
2740 void LIRGenerator::visitStringConvertCase(MStringConvertCase* ins) {
2741 MOZ_ASSERT(ins->string()->type() == MIRType::String);
2743 if (ins->mode() == MStringConvertCase::LowerCase) {
2744 #ifdef JS_CODEGEN_X86
2745 // Due to lack of registers on x86, we reuse the string register as
2746 // temporary. As a result we only need four temporary registers and take a
2747 // bogus temporary as the fifth argument.
2748 LDefinition temp4 = LDefinition::BogusTemp();
2749 #else
2750 LDefinition temp4 = temp();
2751 #endif
2752 auto* lir = new (alloc())
2753 LStringToLowerCase(useRegister(ins->string()), temp(), temp(), temp(),
2754 temp4, tempByteOpRegister());
2755 define(lir, ins);
2756 assignSafepoint(lir, ins);
2757 } else {
2758 auto* lir =
2759 new (alloc()) LStringToUpperCase(useRegisterAtStart(ins->string()));
2760 defineReturn(lir, ins);
2761 assignSafepoint(lir, ins);
2765 void LIRGenerator::visitCharCodeConvertCase(MCharCodeConvertCase* ins) {
2766 MOZ_ASSERT(ins->code()->type() == MIRType::Int32);
2768 if (ins->mode() == MCharCodeConvertCase::LowerCase) {
2769 auto* lir = new (alloc())
2770 LCharCodeToLowerCase(useRegister(ins->code()), tempByteOpRegister());
2771 define(lir, ins);
2772 assignSafepoint(lir, ins);
2773 } else {
2774 auto* lir = new (alloc())
2775 LCharCodeToUpperCase(useRegister(ins->code()), tempByteOpRegister());
2776 define(lir, ins);
2777 assignSafepoint(lir, ins);
2781 void LIRGenerator::visitStringTrimStartIndex(MStringTrimStartIndex* ins) {
2782 auto* string = ins->string();
2783 MOZ_ASSERT(string->type() == MIRType::String);
2785 auto* lir = new (alloc()) LStringTrimStartIndex(useRegister(string));
2786 define(lir, ins);
2787 assignSafepoint(lir, ins);
2790 void LIRGenerator::visitStringTrimEndIndex(MStringTrimEndIndex* ins) {
2791 auto* string = ins->string();
2792 MOZ_ASSERT(string->type() == MIRType::String);
2794 auto* start = ins->start();
2795 MOZ_ASSERT(start->type() == MIRType::Int32);
2797 auto* lir = new (alloc())
2798 LStringTrimEndIndex(useRegister(string), useRegister(start));
2799 define(lir, ins);
2800 assignSafepoint(lir, ins);
2803 void LIRGenerator::visitStart(MStart* start) {}
2805 void LIRGenerator::visitNop(MNop* nop) {}
2807 void LIRGenerator::visitLimitedTruncate(MLimitedTruncate* nop) {
2808 redefine(nop, nop->input());
2811 void LIRGenerator::visitOsrEntry(MOsrEntry* entry) {
2812 LOsrEntry* lir = new (alloc()) LOsrEntry(temp());
2813 defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg)));
2816 void LIRGenerator::visitOsrValue(MOsrValue* value) {
2817 LOsrValue* lir = new (alloc()) LOsrValue(useRegister(value->entry()));
2818 defineBox(lir, value);
2821 void LIRGenerator::visitOsrReturnValue(MOsrReturnValue* value) {
2822 LOsrReturnValue* lir =
2823 new (alloc()) LOsrReturnValue(useRegister(value->entry()));
2824 defineBox(lir, value);
2827 void LIRGenerator::visitOsrEnvironmentChain(MOsrEnvironmentChain* object) {
2828 LOsrEnvironmentChain* lir =
2829 new (alloc()) LOsrEnvironmentChain(useRegister(object->entry()));
2830 define(lir, object);
2833 void LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject* object) {
2834 LOsrArgumentsObject* lir =
2835 new (alloc()) LOsrArgumentsObject(useRegister(object->entry()));
2836 define(lir, object);
2839 void LIRGenerator::visitToDouble(MToDouble* convert) {
2840 MDefinition* opd = convert->input();
2841 mozilla::DebugOnly<MToFPInstruction::ConversionKind> conversion =
2842 convert->conversion();
2844 switch (opd->type()) {
2845 case MIRType::Value: {
2846 LValueToDouble* lir = new (alloc()) LValueToDouble(useBox(opd));
2847 assignSnapshot(lir, convert->bailoutKind());
2848 define(lir, convert);
2849 break;
2852 case MIRType::Null:
2853 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2854 lowerConstantDouble(0, convert);
2855 break;
2857 case MIRType::Undefined:
2858 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2859 lowerConstantDouble(GenericNaN(), convert);
2860 break;
2862 case MIRType::Boolean:
2863 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2864 [[fallthrough]];
2866 case MIRType::Int32: {
2867 LInt32ToDouble* lir =
2868 new (alloc()) LInt32ToDouble(useRegisterAtStart(opd));
2869 define(lir, convert);
2870 break;
2873 case MIRType::Float32: {
2874 LFloat32ToDouble* lir =
2875 new (alloc()) LFloat32ToDouble(useRegisterAtStart(opd));
2876 define(lir, convert);
2877 break;
2880 case MIRType::Double:
2881 redefine(convert, opd);
2882 break;
2884 default:
2885 // Objects might be effectful. Symbols will throw.
2886 // Strings are complicated - we don't handle them yet.
2887 MOZ_CRASH("unexpected type");
2891 void LIRGenerator::visitToFloat32(MToFloat32* convert) {
2892 MDefinition* opd = convert->input();
2893 mozilla::DebugOnly<MToFloat32::ConversionKind> conversion =
2894 convert->conversion();
2896 switch (opd->type()) {
2897 case MIRType::Value: {
2898 LValueToFloat32* lir = new (alloc()) LValueToFloat32(useBox(opd));
2899 assignSnapshot(lir, convert->bailoutKind());
2900 define(lir, convert);
2901 break;
2904 case MIRType::Null:
2905 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2906 lowerConstantFloat32(0, convert);
2907 break;
2909 case MIRType::Undefined:
2910 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2911 lowerConstantFloat32(GenericNaN(), convert);
2912 break;
2914 case MIRType::Boolean:
2915 MOZ_ASSERT(conversion == MToFPInstruction::NonStringPrimitives);
2916 [[fallthrough]];
2918 case MIRType::Int32: {
2919 LInt32ToFloat32* lir =
2920 new (alloc()) LInt32ToFloat32(useRegisterAtStart(opd));
2921 define(lir, convert);
2922 break;
2925 case MIRType::Double: {
2926 LDoubleToFloat32* lir =
2927 new (alloc()) LDoubleToFloat32(useRegisterAtStart(opd));
2928 define(lir, convert);
2929 break;
2932 case MIRType::Float32:
2933 redefine(convert, opd);
2934 break;
2936 default:
2937 // Objects might be effectful. Symbols will throw.
2938 // Strings are complicated - we don't handle them yet.
2939 MOZ_CRASH("unexpected type");
2943 void LIRGenerator::visitToNumberInt32(MToNumberInt32* convert) {
2944 MDefinition* opd = convert->input();
2946 switch (opd->type()) {
2947 case MIRType::Value: {
2948 auto* lir = new (alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(),
2949 LValueToInt32::NORMAL);
2950 assignSnapshot(lir, convert->bailoutKind());
2951 define(lir, convert);
2952 if (lir->mode() == LValueToInt32::TRUNCATE) {
2953 assignSafepoint(lir, convert);
2955 break;
2958 case MIRType::Null:
2959 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any);
2960 define(new (alloc()) LInteger(0), convert);
2961 break;
2963 case MIRType::Boolean:
2964 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any ||
2965 convert->conversion() ==
2966 IntConversionInputKind::NumbersOrBoolsOnly);
2967 redefine(convert, opd);
2968 break;
2970 case MIRType::Int32:
2971 redefine(convert, opd);
2972 break;
2974 case MIRType::Float32: {
2975 LFloat32ToInt32* lir = new (alloc()) LFloat32ToInt32(useRegister(opd));
2976 assignSnapshot(lir, convert->bailoutKind());
2977 define(lir, convert);
2978 break;
2981 case MIRType::Double: {
2982 LDoubleToInt32* lir = new (alloc()) LDoubleToInt32(useRegister(opd));
2983 assignSnapshot(lir, convert->bailoutKind());
2984 define(lir, convert);
2985 break;
2988 case MIRType::String:
2989 case MIRType::Symbol:
2990 case MIRType::BigInt:
2991 case MIRType::Object:
2992 case MIRType::Undefined:
2993 // Objects might be effectful. Symbols and BigInts throw. Undefined
2994 // coerces to NaN, not int32.
2995 MOZ_CRASH("ToInt32 invalid input type");
2997 default:
2998 MOZ_CRASH("unexpected type");
3002 void LIRGenerator::visitBooleanToInt32(MBooleanToInt32* convert) {
3003 MDefinition* opd = convert->input();
3004 MOZ_ASSERT(opd->type() == MIRType::Boolean);
3005 redefine(convert, opd);
3008 void LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) {
3009 MDefinition* opd = truncate->input();
3011 switch (opd->type()) {
3012 case MIRType::Value: {
3013 LValueToInt32* lir = new (alloc()) LValueToInt32(
3014 useBox(opd), tempDouble(), temp(), LValueToInt32::TRUNCATE);
3015 assignSnapshot(lir, truncate->bailoutKind());
3016 define(lir, truncate);
3017 assignSafepoint(lir, truncate);
3018 break;
3021 case MIRType::Null:
3022 case MIRType::Undefined:
3023 define(new (alloc()) LInteger(0), truncate);
3024 break;
3026 case MIRType::Int32:
3027 case MIRType::Boolean:
3028 redefine(truncate, opd);
3029 break;
3031 case MIRType::Double:
3032 // May call into JS::ToInt32() on the slow OOL path.
3033 gen->setNeedsStaticStackAlignment();
3034 lowerTruncateDToInt32(truncate);
3035 break;
3037 case MIRType::Float32:
3038 // May call into JS::ToInt32() on the slow OOL path.
3039 gen->setNeedsStaticStackAlignment();
3040 lowerTruncateFToInt32(truncate);
3041 break;
3043 default:
3044 // Objects might be effectful. Symbols throw.
3045 // Strings are complicated - we don't handle them yet.
3046 MOZ_CRASH("unexpected type");
3050 void LIRGenerator::visitInt32ToIntPtr(MInt32ToIntPtr* ins) {
3051 MDefinition* input = ins->input();
3052 MOZ_ASSERT(input->type() == MIRType::Int32);
3053 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3055 #ifdef JS_64BIT
3056 // If the result is only used by instructions that expect a bounds-checked
3057 // index, we must have eliminated or hoisted a bounds check and we can assume
3058 // the index is non-negative. This lets us generate more efficient code.
3059 if (ins->canBeNegative()) {
3060 bool canBeNegative = false;
3061 for (MUseDefIterator iter(ins); iter; iter++) {
3062 if (!iter.def()->isSpectreMaskIndex() &&
3063 !iter.def()->isLoadUnboxedScalar() &&
3064 !iter.def()->isStoreUnboxedScalar() &&
3065 !iter.def()->isLoadDataViewElement() &&
3066 !iter.def()->isStoreDataViewElement()) {
3067 canBeNegative = true;
3068 break;
3071 if (!canBeNegative) {
3072 ins->setCanNotBeNegative();
3076 if (ins->canBeNegative()) {
3077 auto* lir = new (alloc()) LInt32ToIntPtr(useAnyAtStart(input));
3078 define(lir, ins);
3079 } else {
3080 redefine(ins, input);
3082 #else
3083 // On 32-bit platforms this is a no-op.
3084 redefine(ins, input);
3085 #endif
3088 void LIRGenerator::visitNonNegativeIntPtrToInt32(
3089 MNonNegativeIntPtrToInt32* ins) {
3090 MDefinition* input = ins->input();
3091 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3092 MOZ_ASSERT(ins->type() == MIRType::Int32);
3094 #ifdef JS_64BIT
3095 auto* lir =
3096 new (alloc()) LNonNegativeIntPtrToInt32(useRegisterAtStart(input));
3097 assignSnapshot(lir, ins->bailoutKind());
3098 defineReuseInput(lir, ins, 0);
3099 #else
3100 // On 32-bit platforms this is a no-op.
3101 redefine(ins, input);
3102 #endif
3105 void LIRGenerator::visitWasmExtendU32Index(MWasmExtendU32Index* ins) {
3106 #ifdef JS_64BIT
3107 // Technically this produces an Int64 register and I guess we could clean that
3108 // up, but it's a 64-bit only operation, so it doesn't actually matter.
3110 MDefinition* input = ins->input();
3111 MOZ_ASSERT(input->type() == MIRType::Int32);
3112 MOZ_ASSERT(ins->type() == MIRType::Int64);
3114 // Input reuse is OK even on ARM64 because this node *must* reuse its input in
3115 // order not to generate any code at all, as is the intent.
3116 auto* lir = new (alloc()) LWasmExtendU32Index(useRegisterAtStart(input));
3117 defineReuseInput(lir, ins, 0);
3118 #else
3119 MOZ_CRASH("64-bit only");
3120 #endif
3123 void LIRGenerator::visitWasmWrapU32Index(MWasmWrapU32Index* ins) {
3124 MDefinition* input = ins->input();
3125 MOZ_ASSERT(input->type() == MIRType::Int64);
3126 MOZ_ASSERT(ins->type() == MIRType::Int32);
3128 // Tricky: On 64-bit, this just returns its input (except on MIPS64 there may
3129 // be a sign/zero extension). On 32-bit, it returns the low register of the
3130 // input, and should generate no code.
3132 // If this assertion does not hold then using "input" unadorned as an alias
3133 // for the low register will not work.
3134 #if defined(JS_NUNBOX32)
3135 static_assert(INT64LOW_INDEX == 0);
3136 #endif
3138 auto* lir = new (alloc()) LWasmWrapU32Index(useRegisterAtStart(input));
3139 defineReuseInput(lir, ins, 0);
3142 void LIRGenerator::visitIntPtrToDouble(MIntPtrToDouble* ins) {
3143 MDefinition* input = ins->input();
3144 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3145 MOZ_ASSERT(ins->type() == MIRType::Double);
3147 auto* lir = new (alloc()) LIntPtrToDouble(useRegister(input));
3148 define(lir, ins);
3151 void LIRGenerator::visitAdjustDataViewLength(MAdjustDataViewLength* ins) {
3152 MDefinition* input = ins->input();
3153 MOZ_ASSERT(input->type() == MIRType::IntPtr);
3155 auto* lir = new (alloc()) LAdjustDataViewLength(useRegisterAtStart(input));
3156 assignSnapshot(lir, ins->bailoutKind());
3157 defineReuseInput(lir, ins, 0);
3160 void LIRGenerator::visitToBigInt(MToBigInt* ins) {
3161 MDefinition* opd = ins->input();
3163 switch (opd->type()) {
3164 case MIRType::Value: {
3165 auto* lir = new (alloc()) LValueToBigInt(useBox(opd));
3166 assignSnapshot(lir, ins->bailoutKind());
3167 define(lir, ins);
3168 assignSafepoint(lir, ins);
3169 break;
3172 case MIRType::BigInt:
3173 redefine(ins, opd);
3174 break;
3176 default:
3177 MOZ_CRASH("unexpected type");
3181 void LIRGenerator::visitToInt64(MToInt64* ins) {
3182 MDefinition* opd = ins->input();
3184 switch (opd->type()) {
3185 case MIRType::Value: {
3186 auto* lir = new (alloc()) LValueToInt64(useBox(opd), temp());
3187 assignSnapshot(lir, ins->bailoutKind());
3188 defineInt64(lir, ins);
3189 assignSafepoint(lir, ins);
3190 break;
3193 case MIRType::Boolean: {
3194 auto* lir = new (alloc()) LBooleanToInt64(useRegisterAtStart(opd));
3195 defineInt64(lir, ins);
3196 break;
3199 case MIRType::String: {
3200 auto* lir = new (alloc()) LStringToInt64(useRegister(opd));
3201 defineInt64(lir, ins);
3202 assignSafepoint(lir, ins);
3203 break;
3206 // An Int64 may be passed here from a BigInt to Int64 conversion.
3207 case MIRType::Int64: {
3208 redefine(ins, opd);
3209 break;
3212 default:
3213 // Undefined, Null, Number, and Symbol throw.
3214 // Objects may be effectful.
3215 // BigInt operands are eliminated by the type policy.
3216 MOZ_CRASH("unexpected type");
3220 void LIRGenerator::visitTruncateBigIntToInt64(MTruncateBigIntToInt64* ins) {
3221 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
3222 auto* lir = new (alloc()) LTruncateBigIntToInt64(useRegister(ins->input()));
3223 defineInt64(lir, ins);
3226 void LIRGenerator::visitInt64ToBigInt(MInt64ToBigInt* ins) {
3227 MOZ_ASSERT(ins->input()->type() == MIRType::Int64);
3228 auto* lir =
3229 new (alloc()) LInt64ToBigInt(useInt64Register(ins->input()), temp());
3230 define(lir, ins);
3231 assignSafepoint(lir, ins);
3234 void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) {
3235 MDefinition* input = ins->input();
3236 switch (input->type()) {
3237 case MIRType::Double:
3238 case MIRType::Float32: {
3239 auto* lir = new (alloc()) LWasmTruncateToInt32(useRegisterAtStart(input));
3240 define(lir, ins);
3241 break;
3243 default:
3244 MOZ_CRASH("unexpected type in WasmTruncateToInt32");
3248 void LIRGenerator::visitWasmBuiltinTruncateToInt32(
3249 MWasmBuiltinTruncateToInt32* truncate) {
3250 mozilla::DebugOnly<MDefinition*> opd = truncate->input();
3251 MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32);
3253 // May call into JS::ToInt32() on the slow OOL path.
3254 gen->setNeedsStaticStackAlignment();
3255 lowerWasmBuiltinTruncateToInt32(truncate);
3258 void LIRGenerator::visitWasmAnyRefFromJSValue(MWasmAnyRefFromJSValue* ins) {
3259 LWasmAnyRefFromJSValue* lir =
3260 new (alloc()) LWasmAnyRefFromJSValue(useBox(ins->input()), tempDouble());
3261 define(lir, ins);
3262 assignSafepoint(lir, ins);
3265 void LIRGenerator::visitWasmAnyRefFromJSObject(MWasmAnyRefFromJSObject* ins) {
3266 LWasmAnyRefFromJSObject* lir =
3267 new (alloc()) LWasmAnyRefFromJSObject(useRegisterAtStart(ins->input()));
3268 define(lir, ins);
3271 void LIRGenerator::visitWasmAnyRefFromJSString(MWasmAnyRefFromJSString* ins) {
3272 LWasmAnyRefFromJSString* lir =
3273 new (alloc()) LWasmAnyRefFromJSString(useRegisterAtStart(ins->input()));
3274 define(lir, ins);
3277 void LIRGenerator::visitWasmNewI31Ref(MWasmNewI31Ref* ins) {
3278 LWasmNewI31Ref* lir = new (alloc()) LWasmNewI31Ref(useRegister(ins->input()));
3279 define(lir, ins);
3282 void LIRGenerator::visitWasmI31RefGet(MWasmI31RefGet* ins) {
3283 LWasmI31RefGet* lir = new (alloc()) LWasmI31RefGet(useRegister(ins->input()));
3284 define(lir, ins);
3287 void LIRGenerator::visitWrapInt64ToInt32(MWrapInt64ToInt32* ins) {
3288 define(new (alloc()) LWrapInt64ToInt32(useInt64AtStart(ins->input())), ins);
3291 void LIRGenerator::visitToString(MToString* ins) {
3292 MDefinition* opd = ins->input();
3294 switch (opd->type()) {
3295 case MIRType::Null: {
3296 const JSAtomState& names = gen->runtime->names();
3297 LPointer* lir = new (alloc()) LPointer(names.null);
3298 define(lir, ins);
3299 break;
3302 case MIRType::Undefined: {
3303 const JSAtomState& names = gen->runtime->names();
3304 LPointer* lir = new (alloc()) LPointer(names.undefined);
3305 define(lir, ins);
3306 break;
3309 case MIRType::Boolean: {
3310 LBooleanToString* lir = new (alloc()) LBooleanToString(useRegister(opd));
3311 define(lir, ins);
3312 break;
3315 case MIRType::Double: {
3316 LDoubleToString* lir =
3317 new (alloc()) LDoubleToString(useRegister(opd), temp());
3319 define(lir, ins);
3320 assignSafepoint(lir, ins);
3321 break;
3324 case MIRType::Int32: {
3325 LIntToString* lir = new (alloc()) LIntToString(useRegister(opd));
3327 define(lir, ins);
3328 assignSafepoint(lir, ins);
3329 break;
3332 case MIRType::String:
3333 redefine(ins, ins->input());
3334 break;
3336 case MIRType::Value: {
3337 LValueToString* lir =
3338 new (alloc()) LValueToString(useBox(opd), tempToUnbox());
3339 if (ins->needsSnapshot()) {
3340 assignSnapshot(lir, ins->bailoutKind());
3342 define(lir, ins);
3343 assignSafepoint(lir, ins);
3344 break;
3347 default:
3348 // Float32, symbols, bigint, and objects are not supported.
3349 MOZ_CRASH("unexpected type");
3353 void LIRGenerator::visitRegExp(MRegExp* ins) {
3354 LRegExp* lir = new (alloc()) LRegExp(temp());
3355 define(lir, ins);
3356 assignSafepoint(lir, ins);
3359 void LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins) {
3360 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3361 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3362 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
3364 LRegExpMatcher* lir = new (alloc()) LRegExpMatcher(
3365 useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
3366 useFixedAtStart(ins->string(), RegExpMatcherStringReg),
3367 useFixedAtStart(ins->lastIndex(), RegExpMatcherLastIndexReg));
3368 defineReturn(lir, ins);
3369 assignSafepoint(lir, ins);
3372 void LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins) {
3373 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3374 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3375 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
3377 LRegExpSearcher* lir = new (alloc()) LRegExpSearcher(
3378 useFixedAtStart(ins->regexp(), RegExpSearcherRegExpReg),
3379 useFixedAtStart(ins->string(), RegExpSearcherStringReg),
3380 useFixedAtStart(ins->lastIndex(), RegExpSearcherLastIndexReg));
3381 defineReturn(lir, ins);
3382 assignSafepoint(lir, ins);
3385 void LIRGenerator::visitRegExpSearcherLastLimit(MRegExpSearcherLastLimit* ins) {
3386 auto* lir = new (alloc()) LRegExpSearcherLastLimit(temp());
3387 define(lir, ins);
3390 void LIRGenerator::visitRegExpExecMatch(MRegExpExecMatch* ins) {
3391 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3392 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3394 auto* lir = new (alloc())
3395 LRegExpExecMatch(useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
3396 useFixedAtStart(ins->string(), RegExpMatcherStringReg));
3397 defineReturn(lir, ins);
3398 assignSafepoint(lir, ins);
3401 void LIRGenerator::visitRegExpExecTest(MRegExpExecTest* ins) {
3402 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3403 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3405 auto* lir = new (alloc())
3406 LRegExpExecTest(useFixedAtStart(ins->regexp(), RegExpExecTestRegExpReg),
3407 useFixedAtStart(ins->string(), RegExpExecTestStringReg));
3408 defineReturn(lir, ins);
3409 assignSafepoint(lir, ins);
3412 void LIRGenerator::visitRegExpHasCaptureGroups(MRegExpHasCaptureGroups* ins) {
3413 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
3414 MOZ_ASSERT(ins->input()->type() == MIRType::String);
3415 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3417 auto* lir = new (alloc()) LRegExpHasCaptureGroups(useRegister(ins->regexp()),
3418 useRegister(ins->input()));
3419 define(lir, ins);
3420 assignSafepoint(lir, ins);
3423 void LIRGenerator::visitRegExpPrototypeOptimizable(
3424 MRegExpPrototypeOptimizable* ins) {
3425 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3426 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3427 LRegExpPrototypeOptimizable* lir = new (alloc())
3428 LRegExpPrototypeOptimizable(useRegister(ins->object()), temp());
3429 define(lir, ins);
3432 void LIRGenerator::visitRegExpInstanceOptimizable(
3433 MRegExpInstanceOptimizable* ins) {
3434 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3435 MOZ_ASSERT(ins->proto()->type() == MIRType::Object);
3436 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3437 LRegExpInstanceOptimizable* lir = new (alloc()) LRegExpInstanceOptimizable(
3438 useRegister(ins->object()), useRegister(ins->proto()), temp());
3439 define(lir, ins);
3442 void LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex* ins) {
3443 MOZ_ASSERT(ins->str()->type() == MIRType::String);
3444 MOZ_ASSERT(ins->type() == MIRType::Int32);
3445 LGetFirstDollarIndex* lir = new (alloc())
3446 LGetFirstDollarIndex(useRegister(ins->str()), temp(), temp(), temp());
3447 define(lir, ins);
3448 assignSafepoint(lir, ins);
3451 void LIRGenerator::visitStringReplace(MStringReplace* ins) {
3452 MOZ_ASSERT(ins->pattern()->type() == MIRType::String);
3453 MOZ_ASSERT(ins->string()->type() == MIRType::String);
3454 MOZ_ASSERT(ins->replacement()->type() == MIRType::String);
3456 LStringReplace* lir = new (alloc())
3457 LStringReplace(useRegisterOrConstantAtStart(ins->string()),
3458 useRegisterAtStart(ins->pattern()),
3459 useRegisterOrConstantAtStart(ins->replacement()));
3460 defineReturn(lir, ins);
3461 assignSafepoint(lir, ins);
3464 void LIRGenerator::visitBinaryCache(MBinaryCache* ins) {
3465 MDefinition* lhs = ins->getOperand(0);
3466 MDefinition* rhs = ins->getOperand(1);
3468 MOZ_ASSERT(ins->type() == MIRType::Value || ins->type() == MIRType::Boolean);
3469 LInstruction* lir;
3470 if (ins->type() == MIRType::Value) {
3471 LBinaryValueCache* valueLir = new (alloc()) LBinaryValueCache(
3472 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
3473 defineBox(valueLir, ins);
3474 lir = valueLir;
3475 } else {
3476 MOZ_ASSERT(ins->type() == MIRType::Boolean);
3477 LBinaryBoolCache* boolLir = new (alloc()) LBinaryBoolCache(
3478 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1));
3479 define(boolLir, ins);
3480 lir = boolLir;
3482 assignSafepoint(lir, ins);
3485 void LIRGenerator::visitUnaryCache(MUnaryCache* ins) {
3486 MDefinition* input = ins->getOperand(0);
3487 MOZ_ASSERT(ins->type() == MIRType::Value);
3489 LUnaryCache* lir = new (alloc()) LUnaryCache(useBox(input));
3490 defineBox(lir, ins);
3491 assignSafepoint(lir, ins);
3494 void LIRGenerator::visitModuleMetadata(MModuleMetadata* ins) {
3495 LModuleMetadata* lir = new (alloc()) LModuleMetadata();
3496 defineReturn(lir, ins);
3497 assignSafepoint(lir, ins);
3500 void LIRGenerator::visitDynamicImport(MDynamicImport* ins) {
3501 LDynamicImport* lir = new (alloc()) LDynamicImport(
3502 useBoxAtStart(ins->specifier()), useBoxAtStart(ins->options()));
3503 defineReturn(lir, ins);
3504 assignSafepoint(lir, ins);
3507 void LIRGenerator::visitLambda(MLambda* ins) {
3508 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3510 auto* lir =
3511 new (alloc()) LLambda(useRegister(ins->environmentChain()), temp());
3512 define(lir, ins);
3513 assignSafepoint(lir, ins);
3516 void LIRGenerator::visitFunctionWithProto(MFunctionWithProto* ins) {
3517 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3518 MOZ_ASSERT(ins->prototype()->type() == MIRType::Object);
3520 auto* lir = new (alloc())
3521 LFunctionWithProto(useRegisterAtStart(ins->environmentChain()),
3522 useRegisterAtStart(ins->prototype()));
3523 defineReturn(lir, ins);
3524 assignSafepoint(lir, ins);
3527 void LIRGenerator::visitSetFunName(MSetFunName* ins) {
3528 MOZ_ASSERT(ins->fun()->type() == MIRType::Object);
3529 MOZ_ASSERT(ins->name()->type() == MIRType::Value);
3531 LSetFunName* lir = new (alloc())
3532 LSetFunName(useRegisterAtStart(ins->fun()), useBoxAtStart(ins->name()));
3533 add(lir, ins);
3534 assignSafepoint(lir, ins);
3537 void LIRGenerator::visitNewLexicalEnvironmentObject(
3538 MNewLexicalEnvironmentObject* ins) {
3539 auto* lir = new (alloc()) LNewLexicalEnvironmentObject(temp());
3541 define(lir, ins);
3542 assignSafepoint(lir, ins);
3545 void LIRGenerator::visitNewClassBodyEnvironmentObject(
3546 MNewClassBodyEnvironmentObject* ins) {
3547 auto* lir = new (alloc()) LNewClassBodyEnvironmentObject(temp());
3549 define(lir, ins);
3550 assignSafepoint(lir, ins);
3553 void LIRGenerator::visitNewVarEnvironmentObject(MNewVarEnvironmentObject* ins) {
3554 auto* lir = new (alloc()) LNewVarEnvironmentObject(temp());
3556 define(lir, ins);
3557 assignSafepoint(lir, ins);
3560 void LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins) {
3561 MDefinition* obj = ins->object();
3562 MOZ_ASSERT(obj->type() == MIRType::Object);
3564 add(new (alloc()) LKeepAliveObject(useKeepalive(obj)), ins);
3567 void LIRGenerator::visitDebugEnterGCUnsafeRegion(
3568 MDebugEnterGCUnsafeRegion* ins) {
3569 add(new (alloc()) LDebugEnterGCUnsafeRegion(temp()), ins);
3572 void LIRGenerator::visitDebugLeaveGCUnsafeRegion(
3573 MDebugLeaveGCUnsafeRegion* ins) {
3574 add(new (alloc()) LDebugLeaveGCUnsafeRegion(temp()), ins);
3577 void LIRGenerator::visitSlots(MSlots* ins) {
3578 define(new (alloc()) LSlots(useRegisterAtStart(ins->object())), ins);
3581 void LIRGenerator::visitElements(MElements* ins) {
3582 define(new (alloc()) LElements(useRegisterAtStart(ins->object())), ins);
3585 void LIRGenerator::visitLoadDynamicSlot(MLoadDynamicSlot* ins) {
3586 MOZ_ASSERT(ins->type() == MIRType::Value);
3587 if (ins->usedAsPropertyKey()) {
3588 auto* lir = new (alloc())
3589 LLoadDynamicSlotAndAtomize(useRegister(ins->slots()), temp());
3590 defineBox(lir, ins);
3591 assignSafepoint(lir, ins);
3592 } else {
3593 defineBox(new (alloc()) LLoadDynamicSlotV(useRegisterAtStart(ins->slots())),
3594 ins);
3598 void LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment* ins) {
3599 define(new (alloc())
3600 LFunctionEnvironment(useRegisterAtStart(ins->function())),
3601 ins);
3604 void LIRGenerator::visitHomeObject(MHomeObject* ins) {
3605 define(new (alloc()) LHomeObject(useRegisterAtStart(ins->function())), ins);
3608 void LIRGenerator::visitHomeObjectSuperBase(MHomeObjectSuperBase* ins) {
3609 MOZ_ASSERT(ins->homeObject()->type() == MIRType::Object);
3610 MOZ_ASSERT(ins->type() == MIRType::Value);
3612 auto lir =
3613 new (alloc()) LHomeObjectSuperBase(useRegisterAtStart(ins->homeObject()));
3614 defineBox(lir, ins);
3617 void LIRGenerator::visitInterruptCheck(MInterruptCheck* ins) {
3618 LInstruction* lir = new (alloc()) LInterruptCheck();
3619 add(lir, ins);
3620 assignSafepoint(lir, ins);
3623 void LIRGenerator::visitWasmInterruptCheck(MWasmInterruptCheck* ins) {
3624 auto* lir =
3625 new (alloc()) LWasmInterruptCheck(useRegisterAtStart(ins->instance()));
3626 add(lir, ins);
3627 assignWasmSafepoint(lir);
3630 void LIRGenerator::visitWasmTrap(MWasmTrap* ins) {
3631 add(new (alloc()) LWasmTrap, ins);
3634 void LIRGenerator::visitWasmTrapIfNull(MWasmTrapIfNull* ins) {
3635 auto* lir = new (alloc()) LWasmTrapIfNull(useRegister(ins->ref()));
3636 add(lir, ins);
3639 void LIRGenerator::visitWasmReinterpret(MWasmReinterpret* ins) {
3640 if (ins->type() == MIRType::Int64) {
3641 defineInt64(new (alloc())
3642 LWasmReinterpretToI64(useRegisterAtStart(ins->input())),
3643 ins);
3644 } else if (ins->input()->type() == MIRType::Int64) {
3645 define(new (alloc())
3646 LWasmReinterpretFromI64(useInt64RegisterAtStart(ins->input())),
3647 ins);
3648 } else {
3649 define(new (alloc()) LWasmReinterpret(useRegisterAtStart(ins->input())),
3650 ins);
3654 void LIRGenerator::visitStoreDynamicSlot(MStoreDynamicSlot* ins) {
3655 LInstruction* lir;
3657 switch (ins->value()->type()) {
3658 case MIRType::Value:
3659 lir = new (alloc())
3660 LStoreDynamicSlotV(useRegister(ins->slots()), useBox(ins->value()));
3661 add(lir, ins);
3662 break;
3664 case MIRType::Double:
3665 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3666 useRegister(ins->value())),
3667 ins);
3668 break;
3670 case MIRType::Float32:
3671 MOZ_CRASH("Float32 shouldn't be stored in a slot.");
3673 default:
3674 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()),
3675 useRegisterOrConstant(ins->value())),
3676 ins);
3677 break;
3681 // Returns true iff |def| is a constant that's either not a GC thing or is not
3682 // allocated in the nursery.
3683 static bool IsNonNurseryConstant(MDefinition* def) {
3684 if (!def->isConstant()) {
3685 return false;
3687 Value v = def->toConstant()->toJSValue();
3688 return !v.isGCThing() || !IsInsideNursery(v.toGCThing());
3691 void LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) {
3692 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3694 // LPostWriteBarrier assumes that if it has a constant object then that
3695 // object is tenured, and does not need to be tested for being in the
3696 // nursery. Ensure that assumption holds by lowering constant nursery
3697 // objects to a register.
3698 bool useConstantObject = IsNonNurseryConstant(ins->object());
3700 switch (ins->value()->type()) {
3701 case MIRType::Object: {
3702 LDefinition tmp =
3703 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3704 LPostWriteBarrierO* lir = new (alloc())
3705 LPostWriteBarrierO(useConstantObject ? useOrConstant(ins->object())
3706 : useRegister(ins->object()),
3707 useRegister(ins->value()), tmp);
3708 add(lir, ins);
3709 assignSafepoint(lir, ins);
3710 break;
3712 case MIRType::String: {
3713 LDefinition tmp =
3714 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3715 LPostWriteBarrierS* lir = new (alloc())
3716 LPostWriteBarrierS(useConstantObject ? useOrConstant(ins->object())
3717 : useRegister(ins->object()),
3718 useRegister(ins->value()), tmp);
3719 add(lir, ins);
3720 assignSafepoint(lir, ins);
3721 break;
3723 case MIRType::BigInt: {
3724 LDefinition tmp =
3725 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3726 auto* lir = new (alloc())
3727 LPostWriteBarrierBI(useConstantObject ? useOrConstant(ins->object())
3728 : useRegister(ins->object()),
3729 useRegister(ins->value()), tmp);
3730 add(lir, ins);
3731 assignSafepoint(lir, ins);
3732 break;
3734 case MIRType::Value: {
3735 LDefinition tmp =
3736 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3737 LPostWriteBarrierV* lir = new (alloc())
3738 LPostWriteBarrierV(useConstantObject ? useOrConstant(ins->object())
3739 : useRegister(ins->object()),
3740 useBox(ins->value()), tmp);
3741 add(lir, ins);
3742 assignSafepoint(lir, ins);
3743 break;
3745 default:
3746 // Currently, only objects and strings can be in the nursery. Other
3747 // instruction types cannot hold nursery pointers.
3748 break;
3752 void LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) {
3753 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3754 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3756 // LPostWriteElementBarrier assumes that if it has a constant object then that
3757 // object is tenured, and does not need to be tested for being in the
3758 // nursery. Ensure that assumption holds by lowering constant nursery
3759 // objects to a register.
3760 bool useConstantObject =
3761 ins->object()->isConstant() &&
3762 !IsInsideNursery(&ins->object()->toConstant()->toObject());
3764 switch (ins->value()->type()) {
3765 case MIRType::Object: {
3766 LDefinition tmp =
3767 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3768 LPostWriteElementBarrierO* lir = new (alloc()) LPostWriteElementBarrierO(
3769 useConstantObject ? useOrConstant(ins->object())
3770 : useRegister(ins->object()),
3771 useRegister(ins->value()), useRegister(ins->index()), tmp);
3772 add(lir, ins);
3773 assignSafepoint(lir, ins);
3774 break;
3776 case MIRType::String: {
3777 LDefinition tmp =
3778 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3779 LPostWriteElementBarrierS* lir = new (alloc()) LPostWriteElementBarrierS(
3780 useConstantObject ? useOrConstant(ins->object())
3781 : useRegister(ins->object()),
3782 useRegister(ins->value()), useRegister(ins->index()), tmp);
3783 add(lir, ins);
3784 assignSafepoint(lir, ins);
3785 break;
3787 case MIRType::BigInt: {
3788 LDefinition tmp =
3789 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3790 auto* lir = new (alloc()) LPostWriteElementBarrierBI(
3791 useConstantObject ? useOrConstant(ins->object())
3792 : useRegister(ins->object()),
3793 useRegister(ins->value()), useRegister(ins->index()), tmp);
3794 add(lir, ins);
3795 assignSafepoint(lir, ins);
3796 break;
3798 case MIRType::Value: {
3799 LDefinition tmp =
3800 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
3801 LPostWriteElementBarrierV* lir = new (alloc()) LPostWriteElementBarrierV(
3802 useConstantObject ? useOrConstant(ins->object())
3803 : useRegister(ins->object()),
3804 useRegister(ins->index()), useBox(ins->value()), tmp);
3805 add(lir, ins);
3806 assignSafepoint(lir, ins);
3807 break;
3809 default:
3810 // Currently, only objects, strings, and bigints can be in the nursery.
3811 // Other instruction types cannot hold nursery pointers.
3812 break;
3816 void LIRGenerator::visitAssertCanElidePostWriteBarrier(
3817 MAssertCanElidePostWriteBarrier* ins) {
3818 auto* lir = new (alloc()) LAssertCanElidePostWriteBarrier(
3819 useRegister(ins->object()), useBox(ins->value()), temp());
3820 add(lir, ins);
3823 void LIRGenerator::visitArrayLength(MArrayLength* ins) {
3824 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3825 auto* lir = new (alloc()) LArrayLength(useRegisterAtStart(ins->elements()));
3826 assignSnapshot(lir, ins->bailoutKind());
3827 define(lir, ins);
3830 void LIRGenerator::visitSetArrayLength(MSetArrayLength* ins) {
3831 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3832 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3834 MOZ_ASSERT(ins->index()->isConstant());
3835 add(new (alloc()) LSetArrayLength(useRegister(ins->elements()),
3836 useRegisterOrConstant(ins->index())),
3837 ins);
3840 void LIRGenerator::visitFunctionLength(MFunctionLength* ins) {
3841 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3843 auto* lir = new (alloc()) LFunctionLength(useRegister(ins->function()));
3844 assignSnapshot(lir, ins->bailoutKind());
3845 define(lir, ins);
3848 void LIRGenerator::visitFunctionName(MFunctionName* ins) {
3849 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
3851 auto* lir = new (alloc()) LFunctionName(useRegister(ins->function()));
3852 assignSnapshot(lir, ins->bailoutKind());
3853 define(lir, ins);
3856 void LIRGenerator::visitGetNextEntryForIterator(MGetNextEntryForIterator* ins) {
3857 MOZ_ASSERT(ins->iter()->type() == MIRType::Object);
3858 MOZ_ASSERT(ins->result()->type() == MIRType::Object);
3859 auto lir = new (alloc()) LGetNextEntryForIterator(useRegister(ins->iter()),
3860 useRegister(ins->result()),
3861 temp(), temp(), temp());
3862 define(lir, ins);
3865 void LIRGenerator::visitArrayBufferByteLength(MArrayBufferByteLength* ins) {
3866 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3867 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3869 auto* lir =
3870 new (alloc()) LArrayBufferByteLength(useRegisterAtStart(ins->object()));
3871 define(lir, ins);
3874 void LIRGenerator::visitArrayBufferViewLength(MArrayBufferViewLength* ins) {
3875 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3876 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3878 auto* lir =
3879 new (alloc()) LArrayBufferViewLength(useRegisterAtStart(ins->object()));
3880 define(lir, ins);
3883 void LIRGenerator::visitArrayBufferViewByteOffset(
3884 MArrayBufferViewByteOffset* ins) {
3885 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3886 MOZ_ASSERT(ins->type() == MIRType::IntPtr);
3888 auto* lir = new (alloc())
3889 LArrayBufferViewByteOffset(useRegisterAtStart(ins->object()));
3890 define(lir, ins);
3893 void LIRGenerator::visitArrayBufferViewElements(MArrayBufferViewElements* ins) {
3894 MOZ_ASSERT(ins->type() == MIRType::Elements);
3895 define(new (alloc())
3896 LArrayBufferViewElements(useRegisterAtStart(ins->object())),
3897 ins);
3900 void LIRGenerator::visitTypedArrayElementSize(MTypedArrayElementSize* ins) {
3901 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3902 define(new (alloc())
3903 LTypedArrayElementSize(useRegisterAtStart(ins->object())),
3904 ins);
3907 void LIRGenerator::visitGuardHasAttachedArrayBuffer(
3908 MGuardHasAttachedArrayBuffer* ins) {
3909 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3911 auto* lir = new (alloc())
3912 LGuardHasAttachedArrayBuffer(useRegister(ins->object()), temp());
3913 assignSnapshot(lir, ins->bailoutKind());
3914 add(lir, ins);
3915 redefine(ins, ins->object());
3918 void LIRGenerator::visitGuardNumberToIntPtrIndex(
3919 MGuardNumberToIntPtrIndex* ins) {
3920 MDefinition* input = ins->input();
3921 MOZ_ASSERT(input->type() == MIRType::Double);
3923 auto* lir = new (alloc()) LGuardNumberToIntPtrIndex(useRegister(input));
3924 if (!ins->supportOOB()) {
3925 assignSnapshot(lir, ins->bailoutKind());
3927 define(lir, ins);
3930 void LIRGenerator::visitInitializedLength(MInitializedLength* ins) {
3931 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3932 define(new (alloc()) LInitializedLength(useRegisterAtStart(ins->elements())),
3933 ins);
3936 void LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins) {
3937 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3938 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3940 MOZ_ASSERT(ins->index()->isConstant());
3941 add(new (alloc()) LSetInitializedLength(useRegister(ins->elements()),
3942 useRegisterOrConstant(ins->index())),
3943 ins);
3946 void LIRGenerator::visitNot(MNot* ins) {
3947 MDefinition* op = ins->input();
3949 // String is converted to length of string in the type analysis phase (see
3950 // TestPolicy).
3951 MOZ_ASSERT(op->type() != MIRType::String);
3953 // - boolean: x xor 1
3954 // - int32: LCompare(x, 0)
3955 // - double: LCompare(x, 0)
3956 // - null or undefined: true
3957 // - symbol: false
3958 // - bigint: LNotBI(x)
3959 // - object: false if it never emulates undefined, else LNotO(x)
3960 switch (op->type()) {
3961 case MIRType::Boolean: {
3962 MConstant* cons = MConstant::New(alloc(), Int32Value(1));
3963 ins->block()->insertBefore(ins, cons);
3964 lowerForALU(new (alloc()) LBitOpI(JSOp::BitXor), ins, op, cons);
3965 break;
3967 case MIRType::Int32:
3968 define(new (alloc()) LNotI(useRegisterAtStart(op)), ins);
3969 break;
3970 case MIRType::Int64:
3971 define(new (alloc()) LNotI64(useInt64RegisterAtStart(op)), ins);
3972 break;
3973 case MIRType::Double:
3974 define(new (alloc()) LNotD(useRegister(op)), ins);
3975 break;
3976 case MIRType::Float32:
3977 define(new (alloc()) LNotF(useRegister(op)), ins);
3978 break;
3979 case MIRType::Undefined:
3980 case MIRType::Null:
3981 define(new (alloc()) LInteger(1), ins);
3982 break;
3983 case MIRType::Symbol:
3984 define(new (alloc()) LInteger(0), ins);
3985 break;
3986 case MIRType::BigInt:
3987 define(new (alloc()) LNotBI(useRegisterAtStart(op)), ins);
3988 break;
3989 case MIRType::Object:
3990 define(new (alloc()) LNotO(useRegister(op)), ins);
3991 break;
3992 case MIRType::Value: {
3993 auto* lir = new (alloc()) LNotV(useBox(op), tempDouble(), tempToUnbox());
3994 define(lir, ins);
3995 break;
3998 default:
3999 MOZ_CRASH("Unexpected MIRType.");
4003 void LIRGenerator::visitBoundsCheck(MBoundsCheck* ins) {
4004 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
4005 MOZ_ASSERT(ins->index()->type() == ins->type());
4006 MOZ_ASSERT(ins->length()->type() == ins->type());
4008 if (!ins->fallible()) {
4009 return;
4012 LInstruction* check;
4013 if (ins->minimum() || ins->maximum()) {
4014 check = new (alloc())
4015 LBoundsCheckRange(useRegisterOrInt32Constant(ins->index()),
4016 useAny(ins->length()), temp());
4017 } else {
4018 check = new (alloc()) LBoundsCheck(useRegisterOrInt32Constant(ins->index()),
4019 useAnyOrInt32Constant(ins->length()));
4021 assignSnapshot(check, ins->bailoutKind());
4022 add(check, ins);
4025 void LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex* ins) {
4026 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr);
4027 MOZ_ASSERT(ins->index()->type() == ins->type());
4028 MOZ_ASSERT(ins->length()->type() == ins->type());
4030 auto* lir = new (alloc())
4031 LSpectreMaskIndex(useRegister(ins->index()), useAny(ins->length()));
4032 define(lir, ins);
4035 void LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins) {
4036 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4038 if (!ins->fallible()) {
4039 return;
4042 LInstruction* check =
4043 new (alloc()) LBoundsCheckLower(useRegister(ins->index()));
4044 assignSnapshot(check, ins->bailoutKind());
4045 add(check, ins);
4048 void LIRGenerator::visitInArray(MInArray* ins) {
4049 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4050 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4051 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
4052 MOZ_ASSERT(ins->type() == MIRType::Boolean);
4054 auto* lir = new (alloc()) LInArray(useRegister(ins->elements()),
4055 useRegisterOrConstant(ins->index()),
4056 useRegister(ins->initLength()));
4057 if (ins->needsNegativeIntCheck()) {
4058 assignSnapshot(lir, ins->bailoutKind());
4060 define(lir, ins);
4063 void LIRGenerator::visitGuardElementNotHole(MGuardElementNotHole* ins) {
4064 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4065 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4067 auto* guard = new (alloc())
4068 LGuardElementNotHole(useRegisterAtStart(ins->elements()),
4069 useRegisterOrConstantAtStart(ins->index()));
4070 assignSnapshot(guard, ins->bailoutKind());
4071 add(guard, ins);
4074 void LIRGenerator::visitLoadElement(MLoadElement* ins) {
4075 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4076 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4077 MOZ_ASSERT(ins->type() == MIRType::Value);
4079 auto* lir = new (alloc()) LLoadElementV(useRegister(ins->elements()),
4080 useRegisterOrConstant(ins->index()));
4081 assignSnapshot(lir, ins->bailoutKind());
4082 defineBox(lir, ins);
4085 void LIRGenerator::visitLoadElementHole(MLoadElementHole* ins) {
4086 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4087 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4088 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
4089 MOZ_ASSERT(ins->type() == MIRType::Value);
4091 LLoadElementHole* lir = new (alloc())
4092 LLoadElementHole(useRegister(ins->elements()), useRegister(ins->index()),
4093 useRegister(ins->initLength()));
4094 if (ins->needsNegativeIntCheck()) {
4095 assignSnapshot(lir, ins->bailoutKind());
4097 defineBox(lir, ins);
4100 void LIRGenerator::visitStoreElement(MStoreElement* ins) {
4101 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4102 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4104 const LUse elements = useRegister(ins->elements());
4105 const LAllocation index = useRegisterOrConstant(ins->index());
4107 switch (ins->value()->type()) {
4108 case MIRType::Value: {
4109 LInstruction* lir =
4110 new (alloc()) LStoreElementV(elements, index, useBox(ins->value()));
4111 if (ins->fallible()) {
4112 assignSnapshot(lir, ins->bailoutKind());
4114 add(lir, ins);
4115 break;
4118 default: {
4119 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
4120 LInstruction* lir = new (alloc()) LStoreElementT(elements, index, value);
4121 if (ins->fallible()) {
4122 assignSnapshot(lir, ins->bailoutKind());
4124 add(lir, ins);
4125 break;
4130 void LIRGenerator::visitStoreHoleValueElement(MStoreHoleValueElement* ins) {
4131 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4132 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4134 auto* lir = new (alloc()) LStoreHoleValueElement(useRegister(ins->elements()),
4135 useRegister(ins->index()));
4136 add(lir, ins);
4139 static bool BoundsCheckNeedsSpectreTemp() {
4140 // On x86, spectreBoundsCheck32 can emit better code if it has a scratch
4141 // register and index masking is enabled.
4142 #ifdef JS_CODEGEN_X86
4143 return JitOptions.spectreIndexMasking;
4144 #else
4145 return false;
4146 #endif
4149 void LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) {
4150 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4151 MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
4153 const LUse object = useRegister(ins->object());
4154 const LUse elements = useRegister(ins->elements());
4155 const LAllocation index = useRegister(ins->index());
4157 LInstruction* lir;
4158 switch (ins->value()->type()) {
4159 case MIRType::Value:
4160 lir = new (alloc()) LStoreElementHoleV(object, elements, index,
4161 useBox(ins->value()), temp());
4162 break;
4164 default: {
4165 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
4166 lir = new (alloc())
4167 LStoreElementHoleT(object, elements, index, value, temp());
4168 break;
4172 assignSnapshot(lir, ins->bailoutKind());
4173 add(lir, ins);
4174 assignSafepoint(lir, ins);
4177 void LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins) {
4178 define(new (alloc()) LEffectiveAddress(useRegister(ins->base()),
4179 useRegister(ins->index())),
4180 ins);
4183 void LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) {
4184 MOZ_ASSERT(ins->type() == MIRType::Value);
4186 auto* lir =
4187 new (alloc()) LArrayPopShift(useRegister(ins->object()), temp(), temp());
4188 assignSnapshot(lir, ins->bailoutKind());
4189 defineBox(lir, ins);
4191 if (ins->mode() == MArrayPopShift::Shift) {
4192 assignSafepoint(lir, ins);
4196 void LIRGenerator::visitArrayPush(MArrayPush* ins) {
4197 MOZ_ASSERT(ins->type() == MIRType::Int32);
4198 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4200 LUse object = useRegister(ins->object());
4202 LDefinition spectreTemp =
4203 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4205 auto* lir = new (alloc())
4206 LArrayPush(object, useBox(ins->value()), temp(), spectreTemp);
4207 // We will bailout before pushing if the length would overflow INT32_MAX.
4208 assignSnapshot(lir, ins->bailoutKind());
4209 define(lir, ins);
4210 assignSafepoint(lir, ins);
4213 void LIRGenerator::visitArraySlice(MArraySlice* ins) {
4214 MOZ_ASSERT(ins->type() == MIRType::Object);
4215 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4216 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4217 MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
4219 LArraySlice* lir = new (alloc()) LArraySlice(
4220 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()),
4221 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0),
4222 tempFixed(CallTempReg1));
4223 assignSnapshot(lir, ins->bailoutKind());
4224 defineReturn(lir, ins);
4225 assignSafepoint(lir, ins);
4228 void LIRGenerator::visitArgumentsSlice(MArgumentsSlice* ins) {
4229 MOZ_ASSERT(ins->type() == MIRType::Object);
4230 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4231 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4232 MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
4234 auto* lir = new (alloc()) LArgumentsSlice(
4235 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()),
4236 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0),
4237 tempFixed(CallTempReg1));
4238 defineReturn(lir, ins);
4239 assignSafepoint(lir, ins);
4242 void LIRGenerator::visitFrameArgumentsSlice(MFrameArgumentsSlice* ins) {
4243 MOZ_ASSERT(ins->type() == MIRType::Object);
4244 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
4245 MOZ_ASSERT(ins->count()->type() == MIRType::Int32);
4247 auto* lir = new (alloc()) LFrameArgumentsSlice(
4248 useRegister(ins->begin()), useRegister(ins->count()), temp());
4249 define(lir, ins);
4250 assignSafepoint(lir, ins);
4253 void LIRGenerator::visitInlineArgumentsSlice(MInlineArgumentsSlice* ins) {
4254 LAllocation begin = useRegisterOrConstant(ins->begin());
4255 LAllocation count = useRegisterOrConstant(ins->count());
4256 uint32_t numActuals = ins->numActuals();
4257 uint32_t numOperands =
4258 numActuals * BOX_PIECES + LInlineArgumentsSlice::NumNonArgumentOperands;
4260 auto* lir = allocateVariadic<LInlineArgumentsSlice>(numOperands, temp());
4261 if (!lir) {
4262 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitInlineArgumentsSlice");
4263 return;
4266 lir->setOperand(LInlineArgumentsSlice::Begin, begin);
4267 lir->setOperand(LInlineArgumentsSlice::Count, count);
4268 for (uint32_t i = 0; i < numActuals; i++) {
4269 MDefinition* arg = ins->getArg(i);
4270 uint32_t index = LInlineArgumentsSlice::ArgIndex(i);
4271 lir->setBoxOperand(index,
4272 useBoxOrTypedOrConstant(arg, /*useConstant = */ true));
4274 define(lir, ins);
4275 assignSafepoint(lir, ins);
4278 void LIRGenerator::visitNormalizeSliceTerm(MNormalizeSliceTerm* ins) {
4279 MOZ_ASSERT(ins->type() == MIRType::Int32);
4280 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4281 MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
4283 auto* lir = new (alloc()) LNormalizeSliceTerm(useRegister(ins->value()),
4284 useRegister(ins->length()));
4285 define(lir, ins);
4288 void LIRGenerator::visitArrayJoin(MArrayJoin* ins) {
4289 MOZ_ASSERT(ins->type() == MIRType::String);
4290 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
4291 MOZ_ASSERT(ins->sep()->type() == MIRType::String);
4293 auto* lir = new (alloc())
4294 LArrayJoin(useRegisterAtStart(ins->array()),
4295 useRegisterAtStart(ins->sep()), tempFixed(CallTempReg0));
4296 defineReturn(lir, ins);
4297 assignSafepoint(lir, ins);
4300 void LIRGenerator::visitObjectKeys(MObjectKeys* ins) {
4301 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4302 MOZ_ASSERT(ins->type() == MIRType::Object);
4304 auto* lir = new (alloc()) LObjectKeys(useRegisterAtStart(ins->object()));
4305 defineReturn(lir, ins);
4306 assignSafepoint(lir, ins);
4309 void LIRGenerator::visitObjectKeysLength(MObjectKeysLength* ins) {
4310 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4311 MOZ_ASSERT(ins->type() == MIRType::Int32);
4313 auto* lir =
4314 new (alloc()) LObjectKeysLength(useRegisterAtStart(ins->object()));
4315 defineReturn(lir, ins);
4316 assignSafepoint(lir, ins);
4319 void LIRGenerator::visitStringSplit(MStringSplit* ins) {
4320 MOZ_ASSERT(ins->type() == MIRType::Object);
4321 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4322 MOZ_ASSERT(ins->separator()->type() == MIRType::String);
4324 LStringSplit* lir = new (alloc()) LStringSplit(
4325 useRegisterAtStart(ins->string()), useRegisterAtStart(ins->separator()));
4326 defineReturn(lir, ins);
4327 assignSafepoint(lir, ins);
4330 void LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) {
4331 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4332 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4333 MOZ_ASSERT(IsNumericType(ins->type()) || ins->type() == MIRType::Boolean);
4335 if (Scalar::isBigIntType(ins->storageType()) &&
4336 ins->requiresMemoryBarrier()) {
4337 lowerAtomicLoad64(ins);
4338 return;
4341 const LUse elements = useRegister(ins->elements());
4342 const LAllocation index = useRegisterOrIndexConstant(
4343 ins->index(), ins->storageType(), ins->offsetAdjustment());
4345 // NOTE: the generated code must match the assembly code in gen_load in
4346 // GenerateAtomicOperations.py
4347 Synchronization sync = Synchronization::Load();
4348 if (ins->requiresMemoryBarrier()) {
4349 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
4350 add(fence, ins);
4353 if (!Scalar::isBigIntType(ins->storageType())) {
4354 // We need a temp register for Uint32Array with known double result.
4355 LDefinition tempDef = LDefinition::BogusTemp();
4356 if (ins->storageType() == Scalar::Uint32 &&
4357 IsFloatingPointType(ins->type())) {
4358 tempDef = temp();
4361 auto* lir = new (alloc()) LLoadUnboxedScalar(elements, index, tempDef);
4362 if (ins->fallible()) {
4363 assignSnapshot(lir, ins->bailoutKind());
4365 define(lir, ins);
4366 } else {
4367 MOZ_ASSERT(ins->type() == MIRType::BigInt);
4369 auto* lir =
4370 new (alloc()) LLoadUnboxedBigInt(elements, index, temp(), tempInt64());
4371 define(lir, ins);
4372 assignSafepoint(lir, ins);
4375 if (ins->requiresMemoryBarrier()) {
4376 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
4377 add(fence, ins);
4381 void LIRGenerator::visitLoadDataViewElement(MLoadDataViewElement* ins) {
4382 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4383 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4385 MOZ_ASSERT(IsNumericType(ins->type()));
4387 const LUse elements = useRegister(ins->elements());
4388 const LUse index = useRegister(ins->index());
4389 const LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
4391 // We need a temp register for:
4392 // - Uint32Array with known double result,
4393 // - Float32Array,
4394 // - and BigInt64Array and BigUint64Array.
4395 LDefinition tempDef = LDefinition::BogusTemp();
4396 if ((ins->storageType() == Scalar::Uint32 &&
4397 IsFloatingPointType(ins->type())) ||
4398 ins->storageType() == Scalar::Float32) {
4399 tempDef = temp();
4401 if (Scalar::isBigIntType(ins->storageType())) {
4402 #ifdef JS_CODEGEN_X86
4403 // There are not enough registers on x86.
4404 if (littleEndian.isConstant()) {
4405 tempDef = temp();
4407 #else
4408 tempDef = temp();
4409 #endif
4412 // We also need a separate 64-bit temp register for:
4413 // - Float64Array
4414 // - and BigInt64Array and BigUint64Array.
4415 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
4416 if (Scalar::byteSize(ins->storageType()) == 8) {
4417 temp64Def = tempInt64();
4420 auto* lir = new (alloc())
4421 LLoadDataViewElement(elements, index, littleEndian, tempDef, temp64Def);
4422 if (ins->fallible()) {
4423 assignSnapshot(lir, ins->bailoutKind());
4425 define(lir, ins);
4426 if (Scalar::isBigIntType(ins->storageType())) {
4427 assignSafepoint(lir, ins);
4431 void LIRGenerator::visitClampToUint8(MClampToUint8* ins) {
4432 MDefinition* in = ins->input();
4434 switch (in->type()) {
4435 case MIRType::Boolean:
4436 redefine(ins, in);
4437 break;
4439 case MIRType::Int32:
4440 defineReuseInput(new (alloc()) LClampIToUint8(useRegisterAtStart(in)),
4441 ins, 0);
4442 break;
4444 case MIRType::Double:
4445 // LClampDToUint8 clobbers its input register. Making it available as
4446 // a temp copy describes this behavior to the register allocator.
4447 define(new (alloc())
4448 LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)),
4449 ins);
4450 break;
4452 case MIRType::Value: {
4453 LClampVToUint8* lir =
4454 new (alloc()) LClampVToUint8(useBox(in), tempDouble());
4455 assignSnapshot(lir, ins->bailoutKind());
4456 define(lir, ins);
4457 assignSafepoint(lir, ins);
4458 break;
4461 default:
4462 MOZ_CRASH("unexpected type");
4466 void LIRGenerator::visitLoadTypedArrayElementHole(
4467 MLoadTypedArrayElementHole* ins) {
4468 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4469 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4471 MOZ_ASSERT(ins->type() == MIRType::Value);
4473 const LUse object = useRegister(ins->object());
4474 const LAllocation index = useRegister(ins->index());
4476 if (!Scalar::isBigIntType(ins->arrayType())) {
4477 auto* lir = new (alloc()) LLoadTypedArrayElementHole(object, index, temp());
4478 if (ins->fallible()) {
4479 assignSnapshot(lir, ins->bailoutKind());
4481 defineBox(lir, ins);
4482 } else {
4483 #ifdef JS_CODEGEN_X86
4484 LDefinition tmp = LDefinition::BogusTemp();
4485 #else
4486 LDefinition tmp = temp();
4487 #endif
4489 auto* lir = new (alloc())
4490 LLoadTypedArrayElementHoleBigInt(object, index, tmp, tempInt64());
4491 defineBox(lir, ins);
4492 assignSafepoint(lir, ins);
4496 void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) {
4497 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4498 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4500 if (ins->isFloatWrite()) {
4501 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
4502 ins->value()->type() == MIRType::Float32);
4503 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
4504 ins->value()->type() == MIRType::Double);
4505 } else if (ins->isBigIntWrite()) {
4506 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4507 } else {
4508 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4511 if (ins->isBigIntWrite() && ins->requiresMemoryBarrier()) {
4512 lowerAtomicStore64(ins);
4513 return;
4516 LUse elements = useRegister(ins->elements());
4517 LAllocation index =
4518 useRegisterOrIndexConstant(ins->index(), ins->writeType());
4519 LAllocation value;
4521 // For byte arrays, the value has to be in a byte register on x86.
4522 if (ins->isByteWrite()) {
4523 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
4524 } else if (ins->isBigIntWrite()) {
4525 value = useRegister(ins->value());
4526 } else {
4527 value = useRegisterOrNonDoubleConstant(ins->value());
4530 // Optimization opportunity for atomics: on some platforms there
4531 // is a store instruction that incorporates the necessary
4532 // barriers, and we could use that instead of separate barrier and
4533 // store instructions. See bug #1077027.
4535 // NOTE: the generated code must match the assembly code in gen_store in
4536 // GenerateAtomicOperations.py
4537 Synchronization sync = Synchronization::Store();
4538 if (ins->requiresMemoryBarrier()) {
4539 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore);
4540 add(fence, ins);
4542 if (!ins->isBigIntWrite()) {
4543 add(new (alloc()) LStoreUnboxedScalar(elements, index, value), ins);
4544 } else {
4545 add(new (alloc()) LStoreUnboxedBigInt(elements, index, value, tempInt64()),
4546 ins);
4548 if (ins->requiresMemoryBarrier()) {
4549 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter);
4550 add(fence, ins);
4554 void LIRGenerator::visitStoreDataViewElement(MStoreDataViewElement* ins) {
4555 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4556 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4557 MOZ_ASSERT(ins->littleEndian()->type() == MIRType::Boolean);
4559 if (ins->isFloatWrite()) {
4560 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32,
4561 ins->value()->type() == MIRType::Float32);
4562 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64,
4563 ins->value()->type() == MIRType::Double);
4564 } else if (ins->isBigIntWrite()) {
4565 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4566 } else {
4567 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4570 LUse elements = useRegister(ins->elements());
4571 LUse index = useRegister(ins->index());
4572 LAllocation value;
4573 if (ins->isBigIntWrite()) {
4574 value = useRegister(ins->value());
4575 } else {
4576 value = useRegisterOrNonDoubleConstant(ins->value());
4578 LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian());
4580 LDefinition tempDef = LDefinition::BogusTemp();
4581 LInt64Definition temp64Def = LInt64Definition::BogusTemp();
4582 if (Scalar::byteSize(ins->writeType()) < 8) {
4583 tempDef = temp();
4584 } else {
4585 temp64Def = tempInt64();
4588 add(new (alloc()) LStoreDataViewElement(elements, index, value, littleEndian,
4589 tempDef, temp64Def),
4590 ins);
4593 void LIRGenerator::visitStoreTypedArrayElementHole(
4594 MStoreTypedArrayElementHole* ins) {
4595 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
4596 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr);
4597 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr);
4599 if (ins->isFloatWrite()) {
4600 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32,
4601 ins->value()->type() == MIRType::Float32);
4602 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64,
4603 ins->value()->type() == MIRType::Double);
4604 } else if (ins->isBigIntWrite()) {
4605 MOZ_ASSERT(ins->value()->type() == MIRType::BigInt);
4606 } else {
4607 MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
4610 LUse elements = useRegister(ins->elements());
4611 LAllocation length = useAny(ins->length());
4612 LAllocation index = useRegister(ins->index());
4614 // For byte arrays, the value has to be in a byte register on x86.
4615 LAllocation value;
4616 if (ins->isByteWrite()) {
4617 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
4618 } else if (ins->isBigIntWrite()) {
4619 value = useRegister(ins->value());
4620 } else {
4621 value = useRegisterOrNonDoubleConstant(ins->value());
4624 if (!ins->isBigIntWrite()) {
4625 LDefinition spectreTemp =
4626 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
4627 auto* lir = new (alloc()) LStoreTypedArrayElementHole(
4628 elements, length, index, value, spectreTemp);
4629 add(lir, ins);
4630 } else {
4631 auto* lir = new (alloc()) LStoreTypedArrayElementHoleBigInt(
4632 elements, length, index, value, tempInt64());
4633 add(lir, ins);
4637 void LIRGenerator::visitLoadScriptedProxyHandler(
4638 MLoadScriptedProxyHandler* ins) {
4639 LLoadScriptedProxyHandler* lir = new (alloc())
4640 LLoadScriptedProxyHandler(useRegisterAtStart(ins->object()));
4641 defineBox(lir, ins);
4644 void LIRGenerator::visitIdToStringOrSymbol(MIdToStringOrSymbol* ins) {
4645 LIdToStringOrSymbol* lir =
4646 new (alloc()) LIdToStringOrSymbol(useBoxAtStart(ins->idVal()), temp());
4647 assignSnapshot(lir, ins->bailoutKind());
4648 defineBox(lir, ins);
4649 assignSafepoint(lir, ins);
4652 void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins) {
4653 MDefinition* obj = ins->object();
4654 MOZ_ASSERT(obj->type() == MIRType::Object);
4656 MIRType type = ins->type();
4658 if (type == MIRType::Value) {
4659 if (ins->usedAsPropertyKey()) {
4660 LLoadFixedSlotAndAtomize* lir =
4661 new (alloc()) LLoadFixedSlotAndAtomize(useRegister(obj), temp());
4662 defineBox(lir, ins);
4663 assignSafepoint(lir, ins);
4664 } else {
4665 LLoadFixedSlotV* lir =
4666 new (alloc()) LLoadFixedSlotV(useRegisterAtStart(obj));
4667 defineBox(lir, ins);
4669 } else {
4670 LLoadFixedSlotT* lir =
4671 new (alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj, type));
4672 define(lir, ins);
4676 void LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) {
4677 MDefinition* obj = ins->object();
4678 MOZ_ASSERT(obj->type() == MIRType::Object);
4680 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) {
4681 LLoadFixedSlotUnboxAndAtomize* lir =
4682 new (alloc()) LLoadFixedSlotUnboxAndAtomize(useRegister(obj));
4683 if (ins->fallible()) {
4684 assignSnapshot(lir, ins->bailoutKind());
4686 define(lir, ins);
4687 assignSafepoint(lir, ins);
4688 } else {
4689 LLoadFixedSlotAndUnbox* lir =
4690 new (alloc()) LLoadFixedSlotAndUnbox(useRegisterAtStart(obj));
4691 if (ins->fallible()) {
4692 assignSnapshot(lir, ins->bailoutKind());
4694 define(lir, ins);
4698 void LIRGenerator::visitLoadDynamicSlotAndUnbox(MLoadDynamicSlotAndUnbox* ins) {
4699 MDefinition* slots = ins->slots();
4700 MOZ_ASSERT(slots->type() == MIRType::Slots);
4702 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) {
4703 auto* lir =
4704 new (alloc()) LLoadDynamicSlotUnboxAndAtomize(useRegister(slots));
4705 if (ins->fallible()) {
4706 assignSnapshot(lir, ins->bailoutKind());
4708 define(lir, ins);
4709 assignSafepoint(lir, ins);
4710 } else {
4711 auto* lir =
4712 new (alloc()) LLoadDynamicSlotAndUnbox(useRegisterAtStart(slots));
4713 if (ins->fallible()) {
4714 assignSnapshot(lir, ins->bailoutKind());
4716 define(lir, ins);
4720 void LIRGenerator::visitLoadElementAndUnbox(MLoadElementAndUnbox* ins) {
4721 MDefinition* elements = ins->elements();
4722 MDefinition* index = ins->index();
4723 MOZ_ASSERT(elements->type() == MIRType::Elements);
4724 MOZ_ASSERT(index->type() == MIRType::Int32);
4726 auto* lir = new (alloc())
4727 LLoadElementAndUnbox(useRegister(elements), useRegisterOrConstant(index));
4728 if (ins->fallible()) {
4729 assignSnapshot(lir, ins->bailoutKind());
4731 define(lir, ins);
4734 void LIRGenerator::visitAddAndStoreSlot(MAddAndStoreSlot* ins) {
4735 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4737 LDefinition maybeTemp = LDefinition::BogusTemp();
4738 if (ins->kind() != MAddAndStoreSlot::Kind::FixedSlot) {
4739 maybeTemp = temp();
4742 auto* lir = new (alloc()) LAddAndStoreSlot(useRegister(ins->object()),
4743 useBox(ins->value()), maybeTemp);
4744 add(lir, ins);
4747 void LIRGenerator::visitAllocateAndStoreSlot(MAllocateAndStoreSlot* ins) {
4748 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4750 auto* lir = new (alloc()) LAllocateAndStoreSlot(
4751 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()),
4752 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
4753 assignSnapshot(lir, ins->bailoutKind());
4754 add(lir, ins);
4757 void LIRGenerator::visitAddSlotAndCallAddPropHook(
4758 MAddSlotAndCallAddPropHook* ins) {
4759 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4760 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4762 auto* lir = new (alloc()) LAddSlotAndCallAddPropHook(
4763 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()));
4764 add(lir, ins);
4765 assignSafepoint(lir, ins);
4768 void LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins) {
4769 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4771 if (ins->value()->type() == MIRType::Value) {
4772 LStoreFixedSlotV* lir = new (alloc())
4773 LStoreFixedSlotV(useRegister(ins->object()), useBox(ins->value()));
4774 add(lir, ins);
4775 } else {
4776 LStoreFixedSlotT* lir = new (alloc()) LStoreFixedSlotT(
4777 useRegister(ins->object()), useRegisterOrConstant(ins->value()));
4778 add(lir, ins);
4782 void LIRGenerator::visitGetNameCache(MGetNameCache* ins) {
4783 MOZ_ASSERT(ins->envObj()->type() == MIRType::Object);
4785 // Emit an overrecursed check: this is necessary because the cache can
4786 // attach a scripted getter stub that calls this script recursively.
4787 gen->setNeedsOverrecursedCheck();
4789 LGetNameCache* lir =
4790 new (alloc()) LGetNameCache(useRegister(ins->envObj()), temp());
4791 defineBox(lir, ins);
4792 assignSafepoint(lir, ins);
4795 void LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins) {
4796 LCallGetIntrinsicValue* lir = new (alloc()) LCallGetIntrinsicValue();
4797 defineReturn(lir, ins);
4798 assignSafepoint(lir, ins);
4801 void LIRGenerator::visitGetPropSuperCache(MGetPropSuperCache* ins) {
4802 MDefinition* obj = ins->object();
4803 MDefinition* receiver = ins->receiver();
4804 MDefinition* id = ins->idval();
4806 gen->setNeedsOverrecursedCheck();
4808 bool useConstId =
4809 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4811 auto* lir = new (alloc())
4812 LGetPropSuperCache(useRegister(obj), useBoxOrTyped(receiver),
4813 useBoxOrTypedOrConstant(id, useConstId));
4814 defineBox(lir, ins);
4815 assignSafepoint(lir, ins);
4818 void LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) {
4819 MDefinition* value = ins->value();
4820 MOZ_ASSERT(value->type() == MIRType::Object ||
4821 value->type() == MIRType::Value);
4823 MDefinition* id = ins->idval();
4824 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
4825 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
4827 // Emit an overrecursed check: this is necessary because the cache can
4828 // attach a scripted getter stub that calls this script recursively.
4829 gen->setNeedsOverrecursedCheck();
4831 // If this is a GetProp, the id is a constant string. Allow passing it as a
4832 // constant to reduce register allocation pressure.
4833 bool useConstId =
4834 id->type() == MIRType::String || id->type() == MIRType::Symbol;
4836 auto* lir = new (alloc()) LGetPropertyCache(
4837 useBoxOrTyped(value), useBoxOrTypedOrConstant(id, useConstId));
4838 defineBox(lir, ins);
4839 assignSafepoint(lir, ins);
4842 void LIRGenerator::visitBindNameCache(MBindNameCache* ins) {
4843 MOZ_ASSERT(ins->envChain()->type() == MIRType::Object);
4844 MOZ_ASSERT(ins->type() == MIRType::Object);
4846 LBindNameCache* lir =
4847 new (alloc()) LBindNameCache(useRegister(ins->envChain()), temp());
4848 define(lir, ins);
4849 assignSafepoint(lir, ins);
4852 void LIRGenerator::visitCallBindVar(MCallBindVar* ins) {
4853 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
4854 MOZ_ASSERT(ins->type() == MIRType::Object);
4856 LCallBindVar* lir =
4857 new (alloc()) LCallBindVar(useRegister(ins->environmentChain()));
4858 define(lir, ins);
4861 void LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins) {
4862 LGuardObjectIdentity* guard = new (alloc()) LGuardObjectIdentity(
4863 useRegister(ins->object()), useRegister(ins->expected()));
4864 assignSnapshot(guard, ins->bailoutKind());
4865 add(guard, ins);
4866 redefine(ins, ins->object());
4869 void LIRGenerator::visitGuardSpecificFunction(MGuardSpecificFunction* ins) {
4870 auto* guard = new (alloc()) LGuardSpecificFunction(
4871 useRegister(ins->function()), useRegister(ins->expected()));
4872 assignSnapshot(guard, ins->bailoutKind());
4873 add(guard, ins);
4874 redefine(ins, ins->function());
4877 void LIRGenerator::visitGuardSpecificAtom(MGuardSpecificAtom* ins) {
4878 auto* guard =
4879 new (alloc()) LGuardSpecificAtom(useRegister(ins->str()), temp());
4880 assignSnapshot(guard, ins->bailoutKind());
4881 add(guard, ins);
4882 redefine(ins, ins->str());
4883 assignSafepoint(guard, ins);
4886 void LIRGenerator::visitGuardSpecificSymbol(MGuardSpecificSymbol* ins) {
4887 auto* guard = new (alloc()) LGuardSpecificSymbol(useRegister(ins->symbol()));
4888 assignSnapshot(guard, ins->bailoutKind());
4889 add(guard, ins);
4890 redefine(ins, ins->symbol());
4893 void LIRGenerator::visitGuardSpecificInt32(MGuardSpecificInt32* ins) {
4894 auto* guard = new (alloc()) LGuardSpecificInt32(useRegister(ins->num()));
4895 assignSnapshot(guard, ins->bailoutKind());
4896 add(guard, ins);
4897 redefine(ins, ins->num());
4900 void LIRGenerator::visitGuardStringToIndex(MGuardStringToIndex* ins) {
4901 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4902 auto* guard = new (alloc()) LGuardStringToIndex(useRegister(ins->string()));
4903 assignSnapshot(guard, ins->bailoutKind());
4904 define(guard, ins);
4905 assignSafepoint(guard, ins);
4908 void LIRGenerator::visitGuardStringToInt32(MGuardStringToInt32* ins) {
4909 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4910 auto* guard =
4911 new (alloc()) LGuardStringToInt32(useRegister(ins->string()), temp());
4912 assignSnapshot(guard, ins->bailoutKind());
4913 define(guard, ins);
4914 assignSafepoint(guard, ins);
4917 void LIRGenerator::visitGuardStringToDouble(MGuardStringToDouble* ins) {
4918 MOZ_ASSERT(ins->string()->type() == MIRType::String);
4919 auto* guard = new (alloc())
4920 LGuardStringToDouble(useRegister(ins->string()), temp(), temp());
4921 assignSnapshot(guard, ins->bailoutKind());
4922 define(guard, ins);
4923 assignSafepoint(guard, ins);
4926 void LIRGenerator::visitGuardNoDenseElements(MGuardNoDenseElements* ins) {
4927 auto* guard =
4928 new (alloc()) LGuardNoDenseElements(useRegister(ins->object()), temp());
4929 assignSnapshot(guard, ins->bailoutKind());
4930 add(guard, ins);
4931 redefine(ins, ins->object());
4934 void LIRGenerator::visitGuardShape(MGuardShape* ins) {
4935 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4937 if (JitOptions.spectreObjectMitigations) {
4938 auto* lir =
4939 new (alloc()) LGuardShape(useRegisterAtStart(ins->object()), temp());
4940 assignSnapshot(lir, ins->bailoutKind());
4941 defineReuseInput(lir, ins, 0);
4942 } else {
4943 auto* lir = new (alloc())
4944 LGuardShape(useRegister(ins->object()), LDefinition::BogusTemp());
4945 assignSnapshot(lir, ins->bailoutKind());
4946 add(lir, ins);
4947 redefine(ins, ins->object());
4951 void LIRGenerator::visitGuardMultipleShapes(MGuardMultipleShapes* ins) {
4952 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4954 if (JitOptions.spectreObjectMitigations) {
4955 auto* lir = new (alloc()) LGuardMultipleShapes(
4956 useRegisterAtStart(ins->object()), useRegister(ins->shapeList()),
4957 temp(), temp(), temp(), temp());
4958 assignSnapshot(lir, ins->bailoutKind());
4959 defineReuseInput(lir, ins, 0);
4960 } else {
4961 auto* lir = new (alloc()) LGuardMultipleShapes(
4962 useRegister(ins->object()), useRegister(ins->shapeList()), temp(),
4963 temp(), temp(), LDefinition::BogusTemp());
4964 assignSnapshot(lir, ins->bailoutKind());
4965 add(lir, ins);
4966 redefine(ins, ins->object());
4970 void LIRGenerator::visitGuardProto(MGuardProto* ins) {
4971 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4972 MOZ_ASSERT(ins->expected()->type() == MIRType::Object);
4974 auto* lir = new (alloc()) LGuardProto(useRegister(ins->object()),
4975 useRegister(ins->expected()), temp());
4976 assignSnapshot(lir, ins->bailoutKind());
4977 add(lir, ins);
4978 redefine(ins, ins->object());
4981 void LIRGenerator::visitGuardNullProto(MGuardNullProto* ins) {
4982 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4984 auto* lir = new (alloc()) LGuardNullProto(useRegister(ins->object()), temp());
4985 assignSnapshot(lir, ins->bailoutKind());
4986 add(lir, ins);
4987 redefine(ins, ins->object());
4990 void LIRGenerator::visitGuardIsNativeObject(MGuardIsNativeObject* ins) {
4991 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4993 auto* lir =
4994 new (alloc()) LGuardIsNativeObject(useRegister(ins->object()), temp());
4995 assignSnapshot(lir, ins->bailoutKind());
4996 add(lir, ins);
4997 redefine(ins, ins->object());
5000 void LIRGenerator::visitGuardGlobalGeneration(MGuardGlobalGeneration* ins) {
5001 auto* lir = new (alloc()) LGuardGlobalGeneration(temp());
5002 assignSnapshot(lir, ins->bailoutKind());
5003 add(lir, ins);
5006 void LIRGenerator::visitGuardFuse(MGuardFuse* ins) {
5007 auto* lir = new (alloc()) LGuardFuse(temp());
5008 assignSnapshot(lir, ins->bailoutKind());
5009 add(lir, ins);
5012 void LIRGenerator::visitGuardIsProxy(MGuardIsProxy* ins) {
5013 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5015 auto* lir = new (alloc()) LGuardIsProxy(useRegister(ins->object()), temp());
5016 assignSnapshot(lir, ins->bailoutKind());
5017 add(lir, ins);
5018 redefine(ins, ins->object());
5021 void LIRGenerator::visitGuardIsNotProxy(MGuardIsNotProxy* ins) {
5022 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5024 auto* lir =
5025 new (alloc()) LGuardIsNotProxy(useRegister(ins->object()), temp());
5026 assignSnapshot(lir, ins->bailoutKind());
5027 add(lir, ins);
5028 redefine(ins, ins->object());
5031 void LIRGenerator::visitGuardIsNotDOMProxy(MGuardIsNotDOMProxy* ins) {
5032 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5034 auto* lir =
5035 new (alloc()) LGuardIsNotDOMProxy(useRegister(ins->proxy()), temp());
5036 assignSnapshot(lir, ins->bailoutKind());
5037 add(lir, ins);
5038 redefine(ins, ins->proxy());
5041 void LIRGenerator::visitProxyGet(MProxyGet* ins) {
5042 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5043 auto* lir = new (alloc())
5044 LProxyGet(useRegisterAtStart(ins->proxy()), tempFixed(CallTempReg0));
5045 defineReturn(lir, ins);
5046 assignSafepoint(lir, ins);
5049 void LIRGenerator::visitProxyGetByValue(MProxyGetByValue* ins) {
5050 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5051 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5052 auto* lir = new (alloc()) LProxyGetByValue(useRegisterAtStart(ins->proxy()),
5053 useBoxAtStart(ins->idVal()));
5054 defineReturn(lir, ins);
5055 assignSafepoint(lir, ins);
5058 void LIRGenerator::visitProxyHasProp(MProxyHasProp* ins) {
5059 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5060 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5061 auto* lir = new (alloc()) LProxyHasProp(useRegisterAtStart(ins->proxy()),
5062 useBoxAtStart(ins->idVal()));
5063 defineReturn(lir, ins);
5064 assignSafepoint(lir, ins);
5067 void LIRGenerator::visitProxySet(MProxySet* ins) {
5068 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5069 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5070 auto* lir = new (alloc())
5071 LProxySet(useRegisterAtStart(ins->proxy()), useBoxAtStart(ins->rhs()),
5072 tempFixed(CallTempReg0));
5073 add(lir, ins);
5074 assignSafepoint(lir, ins);
5077 void LIRGenerator::visitProxySetByValue(MProxySetByValue* ins) {
5078 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
5079 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5080 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5081 auto* lir = new (alloc())
5082 LProxySetByValue(useRegisterAtStart(ins->proxy()),
5083 useBoxAtStart(ins->idVal()), useBoxAtStart(ins->rhs()));
5084 add(lir, ins);
5085 assignSafepoint(lir, ins);
5088 void LIRGenerator::visitCallSetArrayLength(MCallSetArrayLength* ins) {
5089 MOZ_ASSERT(ins->obj()->type() == MIRType::Object);
5090 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5091 auto* lir = new (alloc()) LCallSetArrayLength(useRegisterAtStart(ins->obj()),
5092 useBoxAtStart(ins->rhs()));
5093 add(lir, ins);
5094 assignSafepoint(lir, ins);
5097 void LIRGenerator::visitMegamorphicLoadSlot(MMegamorphicLoadSlot* ins) {
5098 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5099 auto* lir = new (alloc())
5100 LMegamorphicLoadSlot(useRegisterAtStart(ins->object()),
5101 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5102 tempFixed(CallTempReg2), tempFixed(CallTempReg3));
5103 assignSnapshot(lir, ins->bailoutKind());
5104 defineReturn(lir, ins);
5107 void LIRGenerator::visitMegamorphicLoadSlotByValue(
5108 MMegamorphicLoadSlotByValue* ins) {
5109 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5110 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5111 auto* lir = new (alloc()) LMegamorphicLoadSlotByValue(
5112 useRegisterAtStart(ins->object()), useBoxAtStart(ins->idVal()),
5113 tempFixed(CallTempReg0), tempFixed(CallTempReg1),
5114 tempFixed(CallTempReg2));
5115 assignSnapshot(lir, ins->bailoutKind());
5116 defineReturn(lir, ins);
5119 void LIRGenerator::visitMegamorphicStoreSlot(MMegamorphicStoreSlot* ins) {
5120 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5121 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
5123 #ifdef JS_CODEGEN_X86
5124 auto* lir = new (alloc()) LMegamorphicStoreSlot(
5125 useFixedAtStart(ins->object(), CallTempReg0),
5126 useBoxFixedAtStart(ins->rhs(), CallTempReg1, CallTempReg2),
5127 tempFixed(CallTempReg5));
5128 #else
5129 auto* lir = new (alloc())
5130 LMegamorphicStoreSlot(useRegisterAtStart(ins->object()),
5131 useBoxAtStart(ins->rhs()), tempFixed(CallTempReg0),
5132 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5133 #endif
5135 add(lir, ins);
5136 assignSafepoint(lir, ins);
5139 void LIRGenerator::visitMegamorphicHasProp(MMegamorphicHasProp* ins) {
5140 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5141 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value);
5142 auto* lir = new (alloc())
5143 LMegamorphicHasProp(useRegisterAtStart(ins->object()),
5144 useBoxAtStart(ins->idVal()), tempFixed(CallTempReg0),
5145 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5146 assignSnapshot(lir, ins->bailoutKind());
5147 defineReturn(lir, ins);
5150 void LIRGenerator::visitGuardIsNotArrayBufferMaybeShared(
5151 MGuardIsNotArrayBufferMaybeShared* ins) {
5152 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5154 auto* lir = new (alloc())
5155 LGuardIsNotArrayBufferMaybeShared(useRegister(ins->object()), temp());
5156 assignSnapshot(lir, ins->bailoutKind());
5157 add(lir, ins);
5158 redefine(ins, ins->object());
5161 void LIRGenerator::visitGuardIsTypedArray(MGuardIsTypedArray* ins) {
5162 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5164 auto* lir =
5165 new (alloc()) LGuardIsTypedArray(useRegister(ins->object()), temp());
5166 assignSnapshot(lir, ins->bailoutKind());
5167 add(lir, ins);
5168 redefine(ins, ins->object());
5171 void LIRGenerator::visitGuardHasProxyHandler(MGuardHasProxyHandler* ins) {
5172 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5174 auto* lir = new (alloc()) LGuardHasProxyHandler(useRegister(ins->object()));
5175 assignSnapshot(lir, ins->bailoutKind());
5176 add(lir, ins);
5177 redefine(ins, ins->object());
5180 void LIRGenerator::visitNurseryObject(MNurseryObject* ins) {
5181 MOZ_ASSERT(ins->type() == MIRType::Object);
5183 auto* lir = new (alloc()) LNurseryObject();
5184 define(lir, ins);
5187 void LIRGenerator::visitGuardValue(MGuardValue* ins) {
5188 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5189 auto* lir = new (alloc()) LGuardValue(useBox(ins->value()));
5190 assignSnapshot(lir, ins->bailoutKind());
5191 add(lir, ins);
5192 redefine(ins, ins->value());
5195 void LIRGenerator::visitGuardNullOrUndefined(MGuardNullOrUndefined* ins) {
5196 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5197 auto* lir = new (alloc()) LGuardNullOrUndefined(useBox(ins->value()));
5198 assignSnapshot(lir, ins->bailoutKind());
5199 add(lir, ins);
5200 redefine(ins, ins->value());
5203 void LIRGenerator::visitGuardIsNotObject(MGuardIsNotObject* ins) {
5204 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5205 auto* lir = new (alloc()) LGuardIsNotObject(useBox(ins->value()));
5206 assignSnapshot(lir, ins->bailoutKind());
5207 add(lir, ins);
5208 redefine(ins, ins->value());
5211 void LIRGenerator::visitGuardFunctionFlags(MGuardFunctionFlags* ins) {
5212 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5214 auto* lir = new (alloc()) LGuardFunctionFlags(useRegister(ins->function()));
5215 assignSnapshot(lir, ins->bailoutKind());
5216 add(lir, ins);
5217 redefine(ins, ins->function());
5220 void LIRGenerator::visitGuardFunctionIsNonBuiltinCtor(
5221 MGuardFunctionIsNonBuiltinCtor* ins) {
5222 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5224 auto* lir = new (alloc())
5225 LGuardFunctionIsNonBuiltinCtor(useRegister(ins->function()), temp());
5226 assignSnapshot(lir, ins->bailoutKind());
5227 add(lir, ins);
5228 redefine(ins, ins->function());
5231 void LIRGenerator::visitGuardFunctionKind(MGuardFunctionKind* ins) {
5232 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5234 auto* lir =
5235 new (alloc()) LGuardFunctionKind(useRegister(ins->function()), temp());
5236 assignSnapshot(lir, ins->bailoutKind());
5237 add(lir, ins);
5238 redefine(ins, ins->function());
5241 void LIRGenerator::visitGuardFunctionScript(MGuardFunctionScript* ins) {
5242 MOZ_ASSERT(ins->function()->type() == MIRType::Object);
5244 auto* lir = new (alloc()) LGuardFunctionScript(useRegister(ins->function()));
5245 assignSnapshot(lir, ins->bailoutKind());
5246 add(lir, ins);
5247 redefine(ins, ins->function());
5250 void LIRGenerator::visitAssertRange(MAssertRange* ins) {
5251 MDefinition* input = ins->input();
5252 LInstruction* lir = nullptr;
5254 switch (input->type()) {
5255 case MIRType::Boolean:
5256 case MIRType::Int32:
5257 case MIRType::IntPtr:
5258 lir = new (alloc()) LAssertRangeI(useRegisterAtStart(input));
5259 break;
5261 case MIRType::Double:
5262 lir = new (alloc()) LAssertRangeD(useRegister(input), tempDouble());
5263 break;
5265 case MIRType::Float32:
5266 lir = new (alloc())
5267 LAssertRangeF(useRegister(input), tempDouble(), tempDouble());
5268 break;
5270 case MIRType::Value:
5271 lir = new (alloc()) LAssertRangeV(useBox(input), tempToUnbox(),
5272 tempDouble(), tempDouble());
5273 break;
5275 default:
5276 MOZ_CRASH("Unexpected Range for MIRType");
5277 break;
5280 lir->setMir(ins);
5281 add(lir);
5284 void LIRGenerator::visitAssertClass(MAssertClass* ins) {
5285 auto* lir =
5286 new (alloc()) LAssertClass(useRegisterAtStart(ins->input()), temp());
5287 add(lir, ins);
5290 void LIRGenerator::visitAssertShape(MAssertShape* ins) {
5291 auto* lir = new (alloc()) LAssertShape(useRegisterAtStart(ins->input()));
5292 add(lir, ins);
5295 void LIRGenerator::visitDeleteProperty(MDeleteProperty* ins) {
5296 LCallDeleteProperty* lir =
5297 new (alloc()) LCallDeleteProperty(useBoxAtStart(ins->value()));
5298 defineReturn(lir, ins);
5299 assignSafepoint(lir, ins);
5302 void LIRGenerator::visitDeleteElement(MDeleteElement* ins) {
5303 LCallDeleteElement* lir = new (alloc()) LCallDeleteElement(
5304 useBoxAtStart(ins->value()), useBoxAtStart(ins->index()));
5305 defineReturn(lir, ins);
5306 assignSafepoint(lir, ins);
5309 void LIRGenerator::visitObjectToIterator(MObjectToIterator* ins) {
5310 auto* lir = new (alloc())
5311 LObjectToIterator(useRegister(ins->object()), temp(), temp(), temp());
5312 define(lir, ins);
5313 assignSafepoint(lir, ins);
5316 void LIRGenerator::visitValueToIterator(MValueToIterator* ins) {
5317 auto* lir = new (alloc()) LValueToIterator(useBoxAtStart(ins->value()));
5318 defineReturn(lir, ins);
5319 assignSafepoint(lir, ins);
5322 void LIRGenerator::visitLoadSlotByIteratorIndex(MLoadSlotByIteratorIndex* ins) {
5323 auto* lir = new (alloc()) LLoadSlotByIteratorIndex(
5324 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->iterator()),
5325 temp(), temp());
5326 defineBox(lir, ins);
5329 void LIRGenerator::visitStoreSlotByIteratorIndex(
5330 MStoreSlotByIteratorIndex* ins) {
5331 auto* lir = new (alloc()) LStoreSlotByIteratorIndex(
5332 useRegister(ins->object()), useRegister(ins->iterator()),
5333 useBox(ins->value()), temp(), temp());
5334 add(lir, ins);
5337 void LIRGenerator::visitIteratorHasIndices(MIteratorHasIndices* ins) {
5338 MOZ_ASSERT(ins->hasOneUse());
5339 emitAtUses(ins);
5342 void LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) {
5343 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5345 MDefinition* id = ins->idval();
5346 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5347 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5349 // If this is a SetProp, the id is a constant string. Allow passing it as a
5350 // constant to reduce register allocation pressure.
5351 bool useConstId =
5352 id->type() == MIRType::String || id->type() == MIRType::Symbol;
5353 bool useConstValue = IsNonNurseryConstant(ins->value());
5355 // Emit an overrecursed check: this is necessary because the cache can
5356 // attach a scripted setter stub that calls this script recursively.
5357 gen->setNeedsOverrecursedCheck();
5359 // We need a double temp register for TypedArray stubs.
5360 LDefinition tempD = tempFixed(FloatReg0);
5362 LInstruction* lir = new (alloc()) LSetPropertyCache(
5363 useRegister(ins->object()), useBoxOrTypedOrConstant(id, useConstId),
5364 useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD);
5365 add(lir, ins);
5366 assignSafepoint(lir, ins);
5369 void LIRGenerator::visitMegamorphicSetElement(MMegamorphicSetElement* ins) {
5370 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5371 MOZ_ASSERT(ins->index()->type() == MIRType::Value);
5372 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5374 // See comment in LIROps.yaml (x86 is short on registers)
5375 #ifdef JS_CODEGEN_X86
5376 auto* lir = new (alloc()) LMegamorphicSetElement(
5377 useFixedAtStart(ins->object(), CallTempReg0),
5378 useBoxFixedAtStart(ins->index(), CallTempReg1, CallTempReg2),
5379 useBoxFixedAtStart(ins->value(), CallTempReg3, CallTempReg4),
5380 tempFixed(CallTempReg5));
5381 #else
5382 auto* lir = new (alloc()) LMegamorphicSetElement(
5383 useRegisterAtStart(ins->object()), useBoxAtStart(ins->index()),
5384 useBoxAtStart(ins->value()), tempFixed(CallTempReg0),
5385 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5386 #endif
5387 add(lir, ins);
5388 assignSafepoint(lir, ins);
5391 void LIRGenerator::visitGetIteratorCache(MGetIteratorCache* ins) {
5392 MDefinition* value = ins->value();
5393 MOZ_ASSERT(value->type() == MIRType::Object ||
5394 value->type() == MIRType::Value);
5396 LGetIteratorCache* lir =
5397 new (alloc()) LGetIteratorCache(useBoxOrTyped(value), temp(), temp());
5398 define(lir, ins);
5399 assignSafepoint(lir, ins);
5402 void LIRGenerator::visitOptimizeSpreadCallCache(MOptimizeSpreadCallCache* ins) {
5403 MDefinition* value = ins->value();
5404 MOZ_ASSERT(value->type() == MIRType::Value);
5406 auto* lir = new (alloc()) LOptimizeSpreadCallCache(useBox(value), temp());
5407 defineBox(lir, ins);
5408 assignSafepoint(lir, ins);
5411 void LIRGenerator::visitIteratorMore(MIteratorMore* ins) {
5412 LIteratorMore* lir =
5413 new (alloc()) LIteratorMore(useRegister(ins->iterator()), temp());
5414 defineBox(lir, ins);
5417 void LIRGenerator::visitIsNoIter(MIsNoIter* ins) {
5418 MOZ_ASSERT(ins->hasOneUse());
5419 emitAtUses(ins);
5422 void LIRGenerator::visitIteratorEnd(MIteratorEnd* ins) {
5423 LIteratorEnd* lir = new (alloc())
5424 LIteratorEnd(useRegister(ins->iterator()), temp(), temp(), temp());
5425 add(lir, ins);
5428 void LIRGenerator::visitCloseIterCache(MCloseIterCache* ins) {
5429 LCloseIterCache* lir =
5430 new (alloc()) LCloseIterCache(useRegister(ins->iter()), temp());
5431 add(lir, ins);
5432 assignSafepoint(lir, ins);
5435 void LIRGenerator::visitOptimizeGetIteratorCache(
5436 MOptimizeGetIteratorCache* ins) {
5437 MDefinition* value = ins->value();
5438 MOZ_ASSERT(value->type() == MIRType::Value);
5440 auto* lir = new (alloc()) LOptimizeGetIteratorCache(useBox(value), temp());
5441 define(lir, ins);
5442 assignSafepoint(lir, ins);
5445 void LIRGenerator::visitStringLength(MStringLength* ins) {
5446 MOZ_ASSERT(ins->string()->type() == MIRType::String);
5447 define(new (alloc()) LStringLength(useRegisterAtStart(ins->string())), ins);
5450 void LIRGenerator::visitArgumentsLength(MArgumentsLength* ins) {
5451 define(new (alloc()) LArgumentsLength(), ins);
5454 void LIRGenerator::visitGetFrameArgument(MGetFrameArgument* ins) {
5455 LGetFrameArgument* lir =
5456 new (alloc()) LGetFrameArgument(useRegisterOrConstant(ins->index()));
5457 defineBox(lir, ins);
5460 void LIRGenerator::visitGetFrameArgumentHole(MGetFrameArgumentHole* ins) {
5461 LDefinition spectreTemp =
5462 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
5464 auto* lir = new (alloc()) LGetFrameArgumentHole(
5465 useRegister(ins->index()), useRegister(ins->length()), spectreTemp);
5466 assignSnapshot(lir, ins->bailoutKind());
5467 defineBox(lir, ins);
5470 void LIRGenerator::visitNewTarget(MNewTarget* ins) {
5471 LNewTarget* lir = new (alloc()) LNewTarget();
5472 defineBox(lir, ins);
5475 void LIRGenerator::visitRest(MRest* ins) {
5476 MOZ_ASSERT(ins->numActuals()->type() == MIRType::Int32);
5478 LRest* lir = new (alloc())
5479 LRest(useRegisterAtStart(ins->numActuals()), tempFixed(CallTempReg0),
5480 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
5481 defineReturn(lir, ins);
5482 assignSafepoint(lir, ins);
5485 void LIRGenerator::visitThrow(MThrow* ins) {
5486 MDefinition* value = ins->value();
5487 MOZ_ASSERT(value->type() == MIRType::Value);
5489 LThrow* lir = new (alloc()) LThrow(useBoxAtStart(value));
5490 add(lir, ins);
5491 assignSafepoint(lir, ins);
5494 void LIRGenerator::visitThrowWithStack(MThrowWithStack* ins) {
5495 MDefinition* value = ins->value();
5496 MOZ_ASSERT(value->type() == MIRType::Value);
5498 MDefinition* stack = ins->stack();
5499 MOZ_ASSERT(stack->type() == MIRType::Value);
5501 auto* lir =
5502 new (alloc()) LThrowWithStack(useBoxAtStart(value), useBoxAtStart(stack));
5503 add(lir, ins);
5504 assignSafepoint(lir, ins);
5507 void LIRGenerator::visitInCache(MInCache* ins) {
5508 MDefinition* lhs = ins->lhs();
5509 MDefinition* rhs = ins->rhs();
5511 MOZ_ASSERT(lhs->type() == MIRType::String || lhs->type() == MIRType::Symbol ||
5512 lhs->type() == MIRType::Int32 || lhs->type() == MIRType::Value);
5513 MOZ_ASSERT(rhs->type() == MIRType::Object);
5515 LInCache* lir =
5516 new (alloc()) LInCache(useBoxOrTyped(lhs), useRegister(rhs), temp());
5517 define(lir, ins);
5518 assignSafepoint(lir, ins);
5521 void LIRGenerator::visitHasOwnCache(MHasOwnCache* ins) {
5522 MDefinition* value = ins->value();
5523 MOZ_ASSERT(value->type() == MIRType::Object ||
5524 value->type() == MIRType::Value);
5526 MDefinition* id = ins->idval();
5527 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5528 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5530 // Emit an overrecursed check: this is necessary because the cache can
5531 // attach a scripted getter stub that calls this script recursively.
5532 gen->setNeedsOverrecursedCheck();
5534 LHasOwnCache* lir =
5535 new (alloc()) LHasOwnCache(useBoxOrTyped(value), useBoxOrTyped(id));
5536 define(lir, ins);
5537 assignSafepoint(lir, ins);
5540 void LIRGenerator::visitCheckPrivateFieldCache(MCheckPrivateFieldCache* ins) {
5541 MDefinition* value = ins->value();
5542 MOZ_ASSERT(value->type() == MIRType::Object ||
5543 value->type() == MIRType::Value);
5545 MDefinition* id = ins->idval();
5546 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol ||
5547 id->type() == MIRType::Int32 || id->type() == MIRType::Value);
5549 LCheckPrivateFieldCache* lir = new (alloc())
5550 LCheckPrivateFieldCache(useBoxOrTyped(value), useBoxOrTyped(id));
5551 define(lir, ins);
5552 assignSafepoint(lir, ins);
5555 void LIRGenerator::visitNewPrivateName(MNewPrivateName* ins) {
5556 auto* lir = new (alloc()) LNewPrivateName();
5557 defineReturn(lir, ins);
5558 assignSafepoint(lir, ins);
5561 void LIRGenerator::visitInstanceOf(MInstanceOf* ins) {
5562 MDefinition* lhs = ins->lhs();
5563 MDefinition* rhs = ins->rhs();
5565 MOZ_ASSERT(lhs->type() == MIRType::Value || lhs->type() == MIRType::Object);
5566 MOZ_ASSERT(rhs->type() == MIRType::Object);
5568 if (lhs->type() == MIRType::Object) {
5569 auto* lir = new (alloc()) LInstanceOfO(useRegister(lhs), useRegister(rhs));
5570 define(lir, ins);
5571 assignSafepoint(lir, ins);
5572 } else {
5573 auto* lir = new (alloc()) LInstanceOfV(useBox(lhs), useRegister(rhs));
5574 define(lir, ins);
5575 assignSafepoint(lir, ins);
5579 void LIRGenerator::visitInstanceOfCache(MInstanceOfCache* ins) {
5580 MDefinition* lhs = ins->lhs();
5581 MDefinition* rhs = ins->rhs();
5583 MOZ_ASSERT(lhs->type() == MIRType::Value);
5584 MOZ_ASSERT(rhs->type() == MIRType::Object);
5586 LInstanceOfCache* lir =
5587 new (alloc()) LInstanceOfCache(useBox(lhs), useRegister(rhs));
5588 define(lir, ins);
5589 assignSafepoint(lir, ins);
5592 void LIRGenerator::visitIsArray(MIsArray* ins) {
5593 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5595 if (ins->value()->type() == MIRType::Object) {
5596 LIsArrayO* lir = new (alloc()) LIsArrayO(useRegister(ins->value()));
5597 define(lir, ins);
5598 assignSafepoint(lir, ins);
5599 } else {
5600 MOZ_ASSERT(ins->value()->type() == MIRType::Value);
5601 LIsArrayV* lir = new (alloc()) LIsArrayV(useBox(ins->value()), temp());
5602 define(lir, ins);
5603 assignSafepoint(lir, ins);
5607 void LIRGenerator::visitIsTypedArray(MIsTypedArray* ins) {
5608 MOZ_ASSERT(ins->value()->type() == MIRType::Object);
5609 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5611 auto* lir = new (alloc()) LIsTypedArray(useRegister(ins->value()));
5612 define(lir, ins);
5614 if (ins->isPossiblyWrapped()) {
5615 assignSafepoint(lir, ins);
5619 void LIRGenerator::visitIsCallable(MIsCallable* ins) {
5620 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5622 if (ins->object()->type() == MIRType::Object) {
5623 define(new (alloc()) LIsCallableO(useRegister(ins->object())), ins);
5624 } else {
5625 MOZ_ASSERT(ins->object()->type() == MIRType::Value);
5626 define(new (alloc()) LIsCallableV(useBox(ins->object()), temp()), ins);
5630 void LIRGenerator::visitIsConstructor(MIsConstructor* ins) {
5631 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5632 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5633 define(new (alloc()) LIsConstructor(useRegister(ins->object())), ins);
5636 void LIRGenerator::visitIsCrossRealmArrayConstructor(
5637 MIsCrossRealmArrayConstructor* ins) {
5638 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5639 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5640 define(new (alloc())
5641 LIsCrossRealmArrayConstructor(useRegister(ins->object())),
5642 ins);
5645 static bool CanEmitAtUseForSingleTest(MInstruction* ins) {
5646 if (!ins->canEmitAtUses()) {
5647 return false;
5650 MUseIterator iter(ins->usesBegin());
5651 if (iter == ins->usesEnd()) {
5652 return false;
5655 MNode* node = iter->consumer();
5656 if (!node->isDefinition()) {
5657 return false;
5660 if (!node->toDefinition()->isTest()) {
5661 return false;
5664 iter++;
5665 return iter == ins->usesEnd();
5668 void LIRGenerator::visitIsObject(MIsObject* ins) {
5669 if (CanEmitAtUseForSingleTest(ins)) {
5670 emitAtUses(ins);
5671 return;
5674 MDefinition* opd = ins->input();
5675 MOZ_ASSERT(opd->type() == MIRType::Value);
5676 LIsObject* lir = new (alloc()) LIsObject(useBoxAtStart(opd));
5677 define(lir, ins);
5680 void LIRGenerator::visitIsNullOrUndefined(MIsNullOrUndefined* ins) {
5681 if (CanEmitAtUseForSingleTest(ins)) {
5682 emitAtUses(ins);
5683 return;
5686 MDefinition* opd = ins->input();
5687 if (opd->type() == MIRType::Value) {
5688 auto* lir = new (alloc()) LIsNullOrUndefined(useBoxAtStart(opd));
5689 define(lir, ins);
5690 } else {
5691 define(new (alloc()) LInteger(IsNullOrUndefined(opd->type())), ins);
5695 void LIRGenerator::visitHasClass(MHasClass* ins) {
5696 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5697 MOZ_ASSERT(ins->type() == MIRType::Boolean);
5698 define(new (alloc()) LHasClass(useRegister(ins->object())), ins);
5701 void LIRGenerator::visitGuardToClass(MGuardToClass* ins) {
5702 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5703 MOZ_ASSERT(ins->type() == MIRType::Object);
5704 LGuardToClass* lir =
5705 new (alloc()) LGuardToClass(useRegisterAtStart(ins->object()), temp());
5706 assignSnapshot(lir, ins->bailoutKind());
5707 defineReuseInput(lir, ins, 0);
5710 void LIRGenerator::visitGuardToFunction(MGuardToFunction* ins) {
5711 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5712 MOZ_ASSERT(ins->type() == MIRType::Object);
5713 LGuardToFunction* lir =
5714 new (alloc()) LGuardToFunction(useRegisterAtStart(ins->object()), temp());
5715 assignSnapshot(lir, ins->bailoutKind());
5716 defineReuseInput(lir, ins, 0);
5719 void LIRGenerator::visitObjectClassToString(MObjectClassToString* ins) {
5720 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
5721 MOZ_ASSERT(ins->type() == MIRType::String);
5722 auto* lir = new (alloc()) LObjectClassToString(
5723 useRegisterAtStart(ins->object()), tempFixed(CallTempReg0));
5724 assignSnapshot(lir, ins->bailoutKind());
5725 defineReturn(lir, ins);
5728 void LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins) {
5729 MOZ_ASSERT(ins->offset());
5730 if (ins->base()->type() == MIRType::Int32) {
5731 MOZ_ASSERT(ins->type() == MIRType::Int32);
5732 MOZ_ASSERT(ins->offset() <= UINT32_MAX); // Because memory32
5733 define(new (alloc()) LWasmAddOffset(useRegisterAtStart(ins->base())), ins);
5734 } else {
5735 MOZ_ASSERT(ins->type() == MIRType::Int64);
5736 #ifdef JS_64BIT
5737 defineInt64(new (alloc())
5738 LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
5739 ins);
5740 #else
5741 // Avoid situation where the input is (a,b) and the output is (b,a).
5742 defineInt64ReuseInput(
5743 new (alloc()) LWasmAddOffset64(useInt64RegisterAtStart(ins->base())),
5744 ins, 0);
5745 #endif
5749 void LIRGenerator::visitWasmLoadInstance(MWasmLoadInstance* ins) {
5750 if (ins->type() == MIRType::Int64) {
5751 #ifdef JS_PUNBOX64
5752 LAllocation instance = useRegisterAtStart(ins->instance());
5753 #else
5754 // Avoid reusing instance for a 64-bit output pair as the load clobbers the
5755 // first half of that pair before loading the second half.
5756 LAllocation instance = useRegister(ins->instance());
5757 #endif
5758 auto* lir = new (alloc()) LWasmLoadInstance64(instance);
5759 defineInt64(lir, ins);
5760 } else {
5761 auto* lir =
5762 new (alloc()) LWasmLoadInstance(useRegisterAtStart(ins->instance()));
5763 define(lir, ins);
5767 void LIRGenerator::visitWasmStoreInstance(MWasmStoreInstance* ins) {
5768 MDefinition* value = ins->value();
5769 if (value->type() == MIRType::Int64) {
5770 #ifdef JS_PUNBOX64
5771 LAllocation instance = useRegisterAtStart(ins->instance());
5772 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5773 #else
5774 LAllocation instance = useRegister(ins->instance());
5775 LInt64Allocation valueAlloc = useInt64Register(value);
5776 #endif
5777 add(new (alloc()) LWasmStoreSlotI64(valueAlloc, instance, ins->offset(),
5778 mozilla::Nothing()),
5779 ins);
5780 } else {
5781 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5782 LAllocation instance = useRegisterAtStart(ins->instance());
5783 LAllocation valueAlloc = useRegisterAtStart(value);
5784 add(new (alloc())
5785 LWasmStoreSlot(valueAlloc, instance, ins->offset(), value->type(),
5786 MNarrowingOp::None, mozilla::Nothing()),
5787 ins);
5791 void LIRGenerator::visitWasmHeapReg(MWasmHeapReg* ins) {
5792 #ifdef WASM_HAS_HEAPREG
5793 auto* lir = new (alloc()) LWasmHeapReg();
5794 define(lir, ins);
5795 #else
5796 MOZ_CRASH();
5797 #endif
5800 void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) {
5801 MOZ_ASSERT(!ins->isRedundant());
5803 MDefinition* index = ins->index();
5804 MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
5806 MOZ_ASSERT(boundsCheckLimit->type() == index->type());
5808 if (index->type() == MIRType::Int64) {
5809 if (JitOptions.spectreIndexMasking) {
5810 auto* lir = new (alloc()) LWasmBoundsCheck64(
5811 useInt64RegisterAtStart(index), useInt64Register(boundsCheckLimit));
5812 defineInt64ReuseInput(lir, ins, 0);
5813 } else {
5814 auto* lir = new (alloc())
5815 LWasmBoundsCheck64(useInt64RegisterAtStart(index),
5816 useInt64RegisterAtStart(boundsCheckLimit));
5817 add(lir, ins);
5819 } else {
5820 MOZ_ASSERT(index->type() == MIRType::Int32);
5822 if (JitOptions.spectreIndexMasking) {
5823 auto* lir = new (alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
5824 useRegister(boundsCheckLimit));
5825 defineReuseInput(lir, ins, 0);
5826 } else {
5827 auto* lir = new (alloc()) LWasmBoundsCheck(
5828 useRegisterAtStart(index), useRegisterAtStart(boundsCheckLimit));
5829 add(lir, ins);
5834 void LIRGenerator::visitWasmBoundsCheckRange32(MWasmBoundsCheckRange32* ins) {
5835 MDefinition* index = ins->index();
5836 MDefinition* length = ins->length();
5837 MDefinition* limit = ins->limit();
5839 MOZ_ASSERT(index->type() == MIRType::Int32);
5840 MOZ_ASSERT(length->type() == MIRType::Int32);
5841 MOZ_ASSERT(limit->type() == MIRType::Int32);
5843 add(new (alloc()) LWasmBoundsCheckRange32(
5844 useRegister(index), useRegister(length), useRegister(limit), temp()),
5845 ins);
5848 void LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck* ins) {
5849 MDefinition* index = ins->index();
5850 if (index->type() == MIRType::Int64) {
5851 auto* lir =
5852 new (alloc()) LWasmAlignmentCheck64(useInt64RegisterAtStart(index));
5853 add(lir, ins);
5854 } else {
5855 auto* lir = new (alloc()) LWasmAlignmentCheck(useRegisterAtStart(index));
5856 add(lir, ins);
5860 void LIRGenerator::visitWasmLoadInstanceDataField(
5861 MWasmLoadInstanceDataField* ins) {
5862 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset());
5863 if (ins->type() == MIRType::Int64) {
5864 #ifdef JS_PUNBOX64
5865 LAllocation instance = useRegisterAtStart(ins->instance());
5866 #else
5867 // Avoid reusing instance for the output pair as the load clobbers the first
5868 // half of that pair before loading the second half.
5869 LAllocation instance = useRegister(ins->instance());
5870 #endif
5871 defineInt64(new (alloc())
5872 LWasmLoadSlotI64(instance, offs, mozilla::Nothing()),
5873 ins);
5874 } else {
5875 LAllocation instance = useRegisterAtStart(ins->instance());
5876 define(new (alloc()) LWasmLoadSlot(instance, offs, ins->type(),
5877 MWideningOp::None, mozilla::Nothing()),
5878 ins);
5882 void LIRGenerator::visitWasmLoadGlobalCell(MWasmLoadGlobalCell* ins) {
5883 if (ins->type() == MIRType::Int64) {
5884 #ifdef JS_PUNBOX64
5885 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5886 #else
5887 // Avoid reusing cellPtr for the output pair as the load clobbers the first
5888 // half of that pair before loading the second half.
5889 LAllocation cellPtr = useRegister(ins->cellPtr());
5890 #endif
5891 defineInt64(new (alloc())
5892 LWasmLoadSlotI64(cellPtr, /*offset=*/0, mozilla::Nothing()),
5893 ins);
5894 } else {
5895 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5896 define(new (alloc()) LWasmLoadSlot(cellPtr, /*offset=*/0, ins->type(),
5897 MWideningOp::None, mozilla::Nothing()),
5898 ins);
5902 void LIRGenerator::visitWasmLoadTableElement(MWasmLoadTableElement* ins) {
5903 LAllocation elements = useRegisterAtStart(ins->elements());
5904 LAllocation index = useRegisterAtStart(ins->index());
5905 define(new (alloc()) LWasmLoadTableElement(elements, index), ins);
5908 void LIRGenerator::visitWasmStoreInstanceDataField(
5909 MWasmStoreInstanceDataField* ins) {
5910 MDefinition* value = ins->value();
5911 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset());
5912 if (value->type() == MIRType::Int64) {
5913 #ifdef JS_PUNBOX64
5914 LAllocation instance = useRegisterAtStart(ins->instance());
5915 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5916 #else
5917 LAllocation instance = useRegister(ins->instance());
5918 LInt64Allocation valueAlloc = useInt64Register(value);
5919 #endif
5920 add(new (alloc())
5921 LWasmStoreSlotI64(valueAlloc, instance, offs, mozilla::Nothing()),
5922 ins);
5923 } else {
5924 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5925 LAllocation instance = useRegisterAtStart(ins->instance());
5926 LAllocation valueAlloc = useRegisterAtStart(value);
5927 add(new (alloc()) LWasmStoreSlot(valueAlloc, instance, offs, value->type(),
5928 MNarrowingOp::None, mozilla::Nothing()),
5929 ins);
5933 void LIRGenerator::visitWasmStoreGlobalCell(MWasmStoreGlobalCell* ins) {
5934 MDefinition* value = ins->value();
5935 size_t offs = 0;
5936 if (value->type() == MIRType::Int64) {
5937 #ifdef JS_PUNBOX64
5938 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5939 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
5940 #else
5941 LAllocation cellPtr = useRegister(ins->cellPtr());
5942 LInt64Allocation valueAlloc = useInt64Register(value);
5943 #endif
5944 add(new (alloc())
5945 LWasmStoreSlotI64(valueAlloc, cellPtr, offs, mozilla::Nothing()));
5946 } else {
5947 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5948 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr());
5949 LAllocation valueAlloc = useRegisterAtStart(value);
5950 add(new (alloc()) LWasmStoreSlot(valueAlloc, cellPtr, offs, value->type(),
5951 MNarrowingOp::None, mozilla::Nothing()));
5955 void LIRGenerator::visitWasmStoreStackResult(MWasmStoreStackResult* ins) {
5956 MDefinition* stackResultArea = ins->stackResultArea();
5957 MDefinition* value = ins->value();
5958 size_t offs = ins->offset();
5959 LInstruction* lir;
5960 if (value->type() == MIRType::Int64) {
5961 lir = new (alloc())
5962 LWasmStoreSlotI64(useInt64Register(value), useRegister(stackResultArea),
5963 offs, mozilla::Nothing());
5964 } else {
5965 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef);
5966 lir = new (alloc())
5967 LWasmStoreSlot(useRegister(value), useRegister(stackResultArea), offs,
5968 value->type(), MNarrowingOp::None, mozilla::Nothing());
5970 add(lir, ins);
5973 void LIRGenerator::visitWasmDerivedPointer(MWasmDerivedPointer* ins) {
5974 LAllocation base = useRegisterAtStart(ins->base());
5975 define(new (alloc()) LWasmDerivedPointer(base), ins);
5978 void LIRGenerator::visitWasmDerivedIndexPointer(MWasmDerivedIndexPointer* ins) {
5979 LAllocation base = useRegisterAtStart(ins->base());
5980 LAllocation index = useRegisterAtStart(ins->index());
5981 define(new (alloc()) LWasmDerivedIndexPointer(base, index), ins);
5984 void LIRGenerator::visitWasmStoreRef(MWasmStoreRef* ins) {
5985 LAllocation instance = useRegister(ins->instance());
5986 LAllocation valueBase = useFixed(ins->valueBase(), PreBarrierReg);
5987 LAllocation value = useRegister(ins->value());
5988 uint32_t valueOffset = ins->offset();
5989 add(new (alloc())
5990 LWasmStoreRef(instance, valueBase, value, temp(), valueOffset,
5991 mozilla::Nothing(), ins->preBarrierKind()),
5992 ins);
5995 void LIRGenerator::visitWasmPostWriteBarrier(MWasmPostWriteBarrier* ins) {
5996 LWasmPostWriteBarrier* lir = new (alloc()) LWasmPostWriteBarrier(
5997 useFixed(ins->instance(), InstanceReg), useRegister(ins->object()),
5998 useRegister(ins->valueBase()), useRegister(ins->value()), temp(),
5999 ins->valueOffset());
6000 add(lir, ins);
6001 assignWasmSafepoint(lir);
6004 void LIRGenerator::visitWasmParameter(MWasmParameter* ins) {
6005 ABIArg abi = ins->abi();
6006 if (ins->type() == MIRType::StackResults) {
6007 // Functions that return stack results receive an extra incoming parameter
6008 // with type MIRType::StackResults. This value is a pointer to fresh
6009 // memory. Here we treat it as if it were in fact MIRType::Pointer.
6010 auto* lir = new (alloc()) LWasmParameter;
6011 LDefinition def(LDefinition::TypeFrom(MIRType::Pointer),
6012 LDefinition::FIXED);
6013 def.setOutput(abi.argInRegister() ? LAllocation(abi.reg())
6014 : LArgument(abi.offsetFromArgBase()));
6015 define(lir, ins, def);
6016 return;
6018 if (abi.argInRegister()) {
6019 #if defined(JS_NUNBOX32)
6020 if (abi.isGeneralRegPair()) {
6021 defineInt64Fixed(
6022 new (alloc()) LWasmParameterI64, ins,
6023 LInt64Allocation(LAllocation(AnyRegister(abi.gpr64().high)),
6024 LAllocation(AnyRegister(abi.gpr64().low))));
6025 return;
6027 #endif
6028 defineFixed(new (alloc()) LWasmParameter, ins, LAllocation(abi.reg()));
6029 return;
6031 if (ins->type() == MIRType::Int64) {
6032 MOZ_ASSERT(!abi.argInRegister());
6033 defineInt64Fixed(
6034 new (alloc()) LWasmParameterI64, ins,
6035 #if defined(JS_NUNBOX32)
6036 LInt64Allocation(LArgument(abi.offsetFromArgBase() + INT64HIGH_OFFSET),
6037 LArgument(abi.offsetFromArgBase() + INT64LOW_OFFSET))
6038 #else
6039 LInt64Allocation(LArgument(abi.offsetFromArgBase()))
6040 #endif
6042 } else {
6043 MOZ_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType::WasmAnyRef
6044 #ifdef ENABLE_WASM_SIMD
6045 || ins->type() == MIRType::Simd128
6046 #endif
6048 defineFixed(new (alloc()) LWasmParameter, ins,
6049 LArgument(abi.offsetFromArgBase()));
6053 void LIRGenerator::visitWasmReturn(MWasmReturn* ins) {
6054 MDefinition* rval = ins->getOperand(0);
6055 MDefinition* instance = ins->getOperand(1);
6057 if (rval->type() == MIRType::Int64) {
6058 add(new (alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64),
6059 useFixed(instance, InstanceReg)));
6060 return;
6063 LAllocation returnReg;
6064 if (rval->type() == MIRType::Float32) {
6065 returnReg = useFixed(rval, ReturnFloat32Reg);
6066 } else if (rval->type() == MIRType::Double) {
6067 returnReg = useFixed(rval, ReturnDoubleReg);
6068 #ifdef ENABLE_WASM_SIMD
6069 } else if (rval->type() == MIRType::Simd128) {
6070 returnReg = useFixed(rval, ReturnSimd128Reg);
6071 #endif
6072 } else if (rval->type() == MIRType::Int32 ||
6073 rval->type() == MIRType::WasmAnyRef) {
6074 returnReg = useFixed(rval, ReturnReg);
6075 } else {
6076 MOZ_CRASH("Unexpected wasm return type");
6079 LWasmReturn* lir =
6080 new (alloc()) LWasmReturn(useFixed(instance, InstanceReg), returnReg);
6081 add(lir);
6084 void LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid* ins) {
6085 MDefinition* instance = ins->getOperand(0);
6086 LWasmReturnVoid* lir =
6087 new (alloc()) LWasmReturnVoid(useFixed(instance, InstanceReg));
6088 add(lir);
6091 void LIRGenerator::visitWasmStackArg(MWasmStackArg* ins) {
6092 if (ins->arg()->type() == MIRType::Int64) {
6093 add(new (alloc())
6094 LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins->arg())),
6095 ins);
6096 } else if (IsFloatingPointType(ins->arg()->type())) {
6097 MOZ_ASSERT(!ins->arg()->isEmittedAtUses());
6098 add(new (alloc()) LWasmStackArg(useRegisterAtStart(ins->arg())), ins);
6099 } else {
6100 add(new (alloc()) LWasmStackArg(useRegisterOrConstantAtStart(ins->arg())),
6101 ins);
6105 void LIRGenerator::visitWasmRegisterResult(MWasmRegisterResult* ins) {
6106 auto* lir = new (alloc()) LWasmRegisterResult();
6107 uint32_t vreg = getVirtualRegister();
6108 MOZ_ASSERT(ins->type() != MIRType::Int64);
6109 auto type = LDefinition::TypeFrom(ins->type());
6110 lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ins->loc())));
6111 ins->setVirtualRegister(vreg);
6112 add(lir, ins);
6115 void LIRGenerator::visitWasmFloatRegisterResult(MWasmFloatRegisterResult* ins) {
6116 auto* lir = new (alloc()) LWasmRegisterResult();
6117 uint32_t vreg = getVirtualRegister();
6118 auto type = LDefinition::TypeFrom(ins->type());
6119 lir->setDef(0, LDefinition(vreg, type, LFloatReg(ins->loc())));
6120 ins->setVirtualRegister(vreg);
6121 add(lir, ins);
6124 void LIRGenerator::visitWasmRegister64Result(MWasmRegister64Result* ins) {
6125 MOZ_ASSERT(ins->type() == MIRType::Int64);
6126 uint32_t vreg = getVirtualRegister();
6128 #if defined(JS_NUNBOX32)
6129 auto* lir = new (alloc()) LWasmRegisterPairResult();
6130 lir->setDef(INT64LOW_INDEX,
6131 LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL,
6132 LGeneralReg(ins->loc().low)));
6133 lir->setDef(INT64HIGH_INDEX,
6134 LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL,
6135 LGeneralReg(ins->loc().high)));
6136 getVirtualRegister();
6137 #elif defined(JS_PUNBOX64)
6138 auto* lir = new (alloc()) LWasmRegisterResult();
6139 lir->setDef(
6140 0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ins->loc().reg)));
6141 #else
6142 # error expected either JS_NUNBOX32 or JS_PUNBOX64
6143 #endif
6145 ins->setVirtualRegister(vreg);
6146 add(lir, ins);
6149 void LIRGenerator::visitWasmStackResultArea(MWasmStackResultArea* ins) {
6150 MOZ_ASSERT(ins->type() == MIRType::StackResults);
6151 auto* lir = new (alloc()) LWasmStackResultArea(temp());
6152 uint32_t vreg = getVirtualRegister();
6153 lir->setDef(0,
6154 LDefinition(vreg, LDefinition::STACKRESULTS, LDefinition::STACK));
6155 ins->setVirtualRegister(vreg);
6156 add(lir, ins);
6159 void LIRGenerator::visitWasmStackResult(MWasmStackResult* ins) {
6160 MWasmStackResultArea* area = ins->resultArea()->toWasmStackResultArea();
6161 LDefinition::Policy pol = LDefinition::STACK;
6163 if (ins->type() == MIRType::Int64) {
6164 auto* lir = new (alloc()) LWasmStackResult64;
6165 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
6166 uint32_t vreg = getVirtualRegister();
6167 LDefinition::Type typ = LDefinition::GENERAL;
6168 #if defined(JS_NUNBOX32)
6169 getVirtualRegister();
6170 lir->setDef(INT64LOW_INDEX, LDefinition(vreg + INT64LOW_INDEX, typ, pol));
6171 lir->setDef(INT64HIGH_INDEX, LDefinition(vreg + INT64HIGH_INDEX, typ, pol));
6172 #else
6173 lir->setDef(0, LDefinition(vreg, typ, pol));
6174 #endif
6175 ins->setVirtualRegister(vreg);
6176 add(lir, ins);
6177 return;
6180 auto* lir = new (alloc()) LWasmStackResult;
6181 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true)));
6182 uint32_t vreg = getVirtualRegister();
6183 LDefinition::Type typ = LDefinition::TypeFrom(ins->type());
6184 lir->setDef(0, LDefinition(vreg, typ, pol));
6185 ins->setVirtualRegister(vreg);
6186 add(lir, ins);
6189 template <class MWasmCallT>
6190 void LIRGenerator::visitWasmCall(MWasmCallT ins) {
6191 bool needsBoundsCheck = true;
6192 mozilla::Maybe<uint32_t> tableSize;
6194 if (ins->callee().isTable()) {
6195 MDefinition* index = ins->getOperand(ins->numArgs());
6197 if (ins->callee().which() == wasm::CalleeDesc::WasmTable) {
6198 uint32_t minLength = ins->callee().wasmTableMinLength();
6199 mozilla::Maybe<uint32_t> maxLength = ins->callee().wasmTableMaxLength();
6200 if (index->isConstant() &&
6201 uint32_t(index->toConstant()->toInt32()) < minLength) {
6202 needsBoundsCheck = false;
6204 if (maxLength.isSome() && *maxLength == minLength) {
6205 tableSize = maxLength;
6210 auto* lir = allocateVariadic<LWasmCall>(ins->numOperands(), needsBoundsCheck,
6211 tableSize);
6212 if (!lir) {
6213 abort(AbortReason::Alloc, "OOM: LIRGenerator::lowerWasmCall");
6214 return;
6217 for (unsigned i = 0; i < ins->numArgs(); i++) {
6218 lir->setOperand(
6219 i, useFixedAtStart(ins->getOperand(i), ins->registerForArg(i)));
6222 if (ins->callee().isTable()) {
6223 MDefinition* index = ins->getOperand(ins->numArgs());
6224 lir->setOperand(ins->numArgs(),
6225 useFixedAtStart(index, WasmTableCallIndexReg));
6227 if (ins->callee().isFuncRef()) {
6228 MDefinition* ref = ins->getOperand(ins->numArgs());
6229 lir->setOperand(ins->numArgs(), useFixedAtStart(ref, WasmCallRefReg));
6232 add(lir, ins);
6233 assignWasmSafepoint(lir);
6235 // WasmCall with WasmTable has two call instructions, and they both need a
6236 // safepoint associated with them. Create a second safepoint here; the node
6237 // otherwise does nothing, and codegen for it only marks the safepoint at the
6238 // node.
6239 if (ins->callee().which() == wasm::CalleeDesc::WasmTable &&
6240 !ins->isWasmReturnCall()) {
6241 auto* adjunctSafepoint = new (alloc()) LWasmCallIndirectAdjunctSafepoint();
6242 add(adjunctSafepoint);
6243 assignWasmSafepoint(adjunctSafepoint);
6244 lir->setAdjunctSafepoint(adjunctSafepoint);
6248 void LIRGenerator::visitWasmCallCatchable(MWasmCallCatchable* ins) {
6249 visitWasmCall(ins);
6252 void LIRGenerator::visitWasmCallUncatchable(MWasmCallUncatchable* ins) {
6253 visitWasmCall(ins);
6256 void LIRGenerator::visitWasmReturnCall(MWasmReturnCall* ins) {
6257 visitWasmCall(ins);
6260 void LIRGenerator::visitWasmCallLandingPrePad(MWasmCallLandingPrePad* ins) {
6261 add(new (alloc()) LWasmCallLandingPrePad, ins);
6264 void LIRGenerator::visitSetDOMProperty(MSetDOMProperty* ins) {
6265 MDefinition* val = ins->value();
6267 Register cxReg, objReg, privReg, valueReg;
6268 GetTempRegForIntArg(0, 0, &cxReg);
6269 GetTempRegForIntArg(1, 0, &objReg);
6270 GetTempRegForIntArg(2, 0, &privReg);
6271 GetTempRegForIntArg(3, 0, &valueReg);
6273 // Keep using GetTempRegForIntArg, since we want to make sure we
6274 // don't clobber registers we're already using.
6275 Register tempReg1, tempReg2;
6276 GetTempRegForIntArg(4, 0, &tempReg1);
6277 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2);
6278 MOZ_ASSERT(ok, "How can we not have six temp registers?");
6280 LSetDOMProperty* lir = new (alloc())
6281 LSetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
6282 useBoxFixedAtStart(val, tempReg1, tempReg2),
6283 tempFixed(privReg), tempFixed(valueReg));
6284 add(lir, ins);
6285 assignSafepoint(lir, ins);
6288 void LIRGenerator::visitGetDOMProperty(MGetDOMProperty* ins) {
6289 Register cxReg, objReg, privReg, valueReg;
6290 GetTempRegForIntArg(0, 0, &cxReg);
6291 GetTempRegForIntArg(1, 0, &objReg);
6292 GetTempRegForIntArg(2, 0, &privReg);
6293 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg);
6294 MOZ_ASSERT(ok, "How can we not have four temp registers?");
6295 LGetDOMProperty* lir = new (alloc())
6296 LGetDOMProperty(tempFixed(cxReg), useFixedAtStart(ins->object(), objReg),
6297 tempFixed(privReg), tempFixed(valueReg));
6299 defineReturn(lir, ins);
6300 assignSafepoint(lir, ins);
6303 void LIRGenerator::visitGetDOMMember(MGetDOMMember* ins) {
6304 MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
6305 // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
6306 // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
6307 // value can in fact change as a result of DOM setters and method calls.
6308 MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
6309 "Member gets had better not alias the world");
6311 MDefinition* obj = ins->object();
6312 MOZ_ASSERT(obj->type() == MIRType::Object);
6314 MIRType type = ins->type();
6316 if (type == MIRType::Value) {
6317 LGetDOMMemberV* lir = new (alloc()) LGetDOMMemberV(useRegisterAtStart(obj));
6318 defineBox(lir, ins);
6319 } else {
6320 LGetDOMMemberT* lir =
6321 new (alloc()) LGetDOMMemberT(useRegisterForTypedLoad(obj, type));
6322 define(lir, ins);
6326 void LIRGenerator::visitLoadDOMExpandoValue(MLoadDOMExpandoValue* ins) {
6327 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6328 auto* lir =
6329 new (alloc()) LLoadDOMExpandoValue(useRegisterAtStart(ins->proxy()));
6330 defineBox(lir, ins);
6333 void LIRGenerator::visitLoadDOMExpandoValueGuardGeneration(
6334 MLoadDOMExpandoValueGuardGeneration* ins) {
6335 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6336 auto* lir = new (alloc())
6337 LLoadDOMExpandoValueGuardGeneration(useRegisterAtStart(ins->proxy()));
6338 assignSnapshot(lir, ins->bailoutKind());
6339 defineBox(lir, ins);
6342 void LIRGenerator::visitLoadDOMExpandoValueIgnoreGeneration(
6343 MLoadDOMExpandoValueIgnoreGeneration* ins) {
6344 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object);
6345 auto* lir = new (alloc())
6346 LLoadDOMExpandoValueIgnoreGeneration(useRegisterAtStart(ins->proxy()));
6347 defineBox(lir, ins);
6350 void LIRGenerator::visitGuardDOMExpandoMissingOrGuardShape(
6351 MGuardDOMExpandoMissingOrGuardShape* ins) {
6352 MOZ_ASSERT(ins->expando()->type() == MIRType::Value);
6353 auto* lir = new (alloc())
6354 LGuardDOMExpandoMissingOrGuardShape(useBox(ins->expando()), temp());
6355 assignSnapshot(lir, ins->bailoutKind());
6356 add(lir, ins);
6357 redefine(ins, ins->expando());
6360 void LIRGenerator::visitIncrementWarmUpCounter(MIncrementWarmUpCounter* ins) {
6361 LIncrementWarmUpCounter* lir = new (alloc()) LIncrementWarmUpCounter(temp());
6362 add(lir, ins);
6365 void LIRGenerator::visitLexicalCheck(MLexicalCheck* ins) {
6366 MDefinition* input = ins->input();
6367 MOZ_ASSERT(input->type() == MIRType::Value);
6368 LLexicalCheck* lir = new (alloc()) LLexicalCheck(useBox(input));
6369 assignSnapshot(lir, ins->bailoutKind());
6370 add(lir, ins);
6371 redefine(ins, input);
6374 void LIRGenerator::visitThrowRuntimeLexicalError(
6375 MThrowRuntimeLexicalError* ins) {
6376 LThrowRuntimeLexicalError* lir = new (alloc()) LThrowRuntimeLexicalError();
6377 add(lir, ins);
6378 assignSafepoint(lir, ins);
6381 void LIRGenerator::visitThrowMsg(MThrowMsg* ins) {
6382 LThrowMsg* lir = new (alloc()) LThrowMsg();
6383 add(lir, ins);
6384 assignSafepoint(lir, ins);
6387 void LIRGenerator::visitGlobalDeclInstantiation(MGlobalDeclInstantiation* ins) {
6388 LGlobalDeclInstantiation* lir = new (alloc()) LGlobalDeclInstantiation();
6389 add(lir, ins);
6390 assignSafepoint(lir, ins);
6393 void LIRGenerator::visitDebugger(MDebugger* ins) {
6394 auto* lir = new (alloc()) LDebugger(tempFixed(CallTempReg0));
6395 assignSnapshot(lir, ins->bailoutKind());
6396 add(lir, ins);
6399 void LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins) {
6400 define(new (alloc()) LAtomicIsLockFree(useRegister(ins->input())), ins);
6403 void LIRGenerator::visitCheckReturn(MCheckReturn* ins) {
6404 MDefinition* retVal = ins->returnValue();
6405 MDefinition* thisVal = ins->thisValue();
6406 MOZ_ASSERT(retVal->type() == MIRType::Value);
6407 MOZ_ASSERT(thisVal->type() == MIRType::Value);
6409 auto* lir =
6410 new (alloc()) LCheckReturn(useBoxAtStart(retVal), useBoxAtStart(thisVal));
6411 defineBox(lir, ins);
6412 assignSafepoint(lir, ins);
6415 void LIRGenerator::visitCheckIsObj(MCheckIsObj* ins) {
6416 MDefinition* input = ins->input();
6417 MOZ_ASSERT(input->type() == MIRType::Value);
6419 LCheckIsObj* lir = new (alloc()) LCheckIsObj(useBox(input));
6420 define(lir, ins);
6421 assignSafepoint(lir, ins);
6424 #ifdef JS_PUNBOX64
6425 void LIRGenerator::visitCheckScriptedProxyGetResult(
6426 MCheckScriptedProxyGetResult* ins) {
6427 MDefinition* target = ins->target();
6428 MDefinition* id = ins->id();
6429 MDefinition* value = ins->value();
6431 LCheckScriptedProxyGetResult* lir =
6432 new (alloc()) LCheckScriptedProxyGetResult(useBox(target), useBox(id),
6433 useBox(value), temp(), temp());
6434 add(lir, ins);
6435 assignSafepoint(lir, ins);
6437 #endif
6439 void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) {
6440 MDefinition* checkVal = ins->checkValue();
6441 MOZ_ASSERT(checkVal->type() == MIRType::Value);
6443 auto* lir = new (alloc()) LCheckObjCoercible(useBoxAtStart(checkVal));
6444 redefine(ins, checkVal);
6445 add(lir, ins);
6446 assignSafepoint(lir, ins);
6449 void LIRGenerator::visitCheckClassHeritage(MCheckClassHeritage* ins) {
6450 MDefinition* heritage = ins->heritage();
6451 MOZ_ASSERT(heritage->type() == MIRType::Value);
6453 auto* lir =
6454 new (alloc()) LCheckClassHeritage(useBox(heritage), temp(), temp());
6455 redefine(ins, heritage);
6456 add(lir, ins);
6457 assignSafepoint(lir, ins);
6460 void LIRGenerator::visitCheckThis(MCheckThis* ins) {
6461 MDefinition* thisValue = ins->thisValue();
6462 MOZ_ASSERT(thisValue->type() == MIRType::Value);
6464 auto* lir = new (alloc()) LCheckThis(useBoxAtStart(thisValue));
6465 redefine(ins, thisValue);
6466 add(lir, ins);
6467 assignSafepoint(lir, ins);
6470 void LIRGenerator::visitCheckThisReinit(MCheckThisReinit* ins) {
6471 MDefinition* thisValue = ins->thisValue();
6472 MOZ_ASSERT(thisValue->type() == MIRType::Value);
6474 auto* lir = new (alloc()) LCheckThisReinit(useBoxAtStart(thisValue));
6475 redefine(ins, thisValue);
6476 add(lir, ins);
6477 assignSafepoint(lir, ins);
6480 void LIRGenerator::visitGenerator(MGenerator* ins) {
6481 auto* lir =
6482 new (alloc()) LGenerator(useRegisterAtStart(ins->callee()),
6483 useRegisterAtStart(ins->environmentChain()),
6484 useRegisterAtStart(ins->argsObject()));
6485 defineReturn(lir, ins);
6486 assignSafepoint(lir, ins);
6489 void LIRGenerator::visitAsyncResolve(MAsyncResolve* ins) {
6490 auto* lir = new (alloc()) LAsyncResolve(useRegisterAtStart(ins->generator()),
6491 useBoxAtStart(ins->valueOrReason()));
6492 defineReturn(lir, ins);
6493 assignSafepoint(lir, ins);
6496 void LIRGenerator::visitAsyncAwait(MAsyncAwait* ins) {
6497 MOZ_ASSERT(ins->generator()->type() == MIRType::Object);
6498 auto* lir = new (alloc()) LAsyncAwait(useBoxAtStart(ins->value()),
6499 useRegisterAtStart(ins->generator()));
6500 defineReturn(lir, ins);
6501 assignSafepoint(lir, ins);
6504 void LIRGenerator::visitCanSkipAwait(MCanSkipAwait* ins) {
6505 auto* lir = new (alloc()) LCanSkipAwait(useBoxAtStart(ins->value()));
6506 defineReturn(lir, ins);
6507 assignSafepoint(lir, ins);
6510 void LIRGenerator::visitMaybeExtractAwaitValue(MMaybeExtractAwaitValue* ins) {
6511 auto* lir = new (alloc()) LMaybeExtractAwaitValue(
6512 useBoxAtStart(ins->value()), useRegisterAtStart(ins->canSkip()));
6513 defineReturn(lir, ins);
6514 assignSafepoint(lir, ins);
6517 void LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins) {
6518 MDefinition* checkVal = ins->checkValue();
6519 MOZ_ASSERT(checkVal->type() == MIRType::Value);
6521 LDebugCheckSelfHosted* lir =
6522 new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal));
6523 redefine(ins, checkVal);
6524 add(lir, ins);
6525 assignSafepoint(lir, ins);
6528 void LIRGenerator::visitIsPackedArray(MIsPackedArray* ins) {
6529 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
6530 MOZ_ASSERT(ins->type() == MIRType::Boolean);
6532 auto lir = new (alloc()) LIsPackedArray(useRegister(ins->object()), temp());
6533 define(lir, ins);
6536 void LIRGenerator::visitGuardArrayIsPacked(MGuardArrayIsPacked* ins) {
6537 MOZ_ASSERT(ins->array()->type() == MIRType::Object);
6539 auto* lir = new (alloc())
6540 LGuardArrayIsPacked(useRegister(ins->array()), temp(), temp());
6541 assignSnapshot(lir, ins->bailoutKind());
6542 add(lir, ins);
6543 redefine(ins, ins->array());
6546 void LIRGenerator::visitGetPrototypeOf(MGetPrototypeOf* ins) {
6547 MOZ_ASSERT(ins->target()->type() == MIRType::Object);
6548 MOZ_ASSERT(ins->type() == MIRType::Value);
6550 auto lir = new (alloc()) LGetPrototypeOf(useRegister(ins->target()));
6551 defineBox(lir, ins);
6552 assignSafepoint(lir, ins);
6555 void LIRGenerator::visitObjectWithProto(MObjectWithProto* ins) {
6556 MOZ_ASSERT(ins->prototype()->type() == MIRType::Value);
6557 MOZ_ASSERT(ins->type() == MIRType::Object);
6559 auto* lir = new (alloc()) LObjectWithProto(useBoxAtStart(ins->prototype()));
6560 defineReturn(lir, ins);
6561 assignSafepoint(lir, ins);
6564 void LIRGenerator::visitObjectStaticProto(MObjectStaticProto* ins) {
6565 MOZ_ASSERT(ins->object()->type() == MIRType::Object);
6566 MOZ_ASSERT(ins->type() == MIRType::Object);
6568 auto* lir =
6569 new (alloc()) LObjectStaticProto(useRegisterAtStart(ins->object()));
6570 define(lir, ins);
6573 void LIRGenerator::visitBuiltinObject(MBuiltinObject* ins) {
6574 MOZ_ASSERT(ins->type() == MIRType::Object);
6576 auto* lir = new (alloc()) LBuiltinObject();
6577 defineReturn(lir, ins);
6578 assignSafepoint(lir, ins);
6581 void LIRGenerator::visitReturn(MReturn* ret) {
6582 return visitReturnImpl(ret->getOperand(0));
6585 void LIRGenerator::visitGeneratorReturn(MGeneratorReturn* ret) {
6586 return visitReturnImpl(ret->getOperand(0), true);
6589 void LIRGenerator::visitSuperFunction(MSuperFunction* ins) {
6590 MOZ_ASSERT(ins->callee()->type() == MIRType::Object);
6591 MOZ_ASSERT(ins->type() == MIRType::Value);
6593 auto* lir = new (alloc()) LSuperFunction(useRegister(ins->callee()), temp());
6594 defineBox(lir, ins);
6597 void LIRGenerator::visitInitHomeObject(MInitHomeObject* ins) {
6598 MDefinition* function = ins->function();
6599 MOZ_ASSERT(function->type() == MIRType::Object);
6601 MDefinition* homeObject = ins->homeObject();
6602 MOZ_ASSERT(homeObject->type() == MIRType::Value);
6604 MOZ_ASSERT(ins->type() == MIRType::Object);
6606 auto* lir = new (alloc())
6607 LInitHomeObject(useRegisterAtStart(function), useBoxAtStart(homeObject));
6608 redefine(ins, function);
6609 add(lir, ins);
6612 void LIRGenerator::visitIsTypedArrayConstructor(MIsTypedArrayConstructor* ins) {
6613 MDefinition* object = ins->object();
6614 MOZ_ASSERT(object->type() == MIRType::Object);
6616 auto* lir = new (alloc()) LIsTypedArrayConstructor(useRegister(object));
6617 define(lir, ins);
6620 void LIRGenerator::visitLoadValueTag(MLoadValueTag* ins) {
6621 MDefinition* value = ins->value();
6622 MOZ_ASSERT(value->type() == MIRType::Value);
6624 define(new (alloc()) LLoadValueTag(useBoxAtStart(value)), ins);
6627 void LIRGenerator::visitGuardTagNotEqual(MGuardTagNotEqual* ins) {
6628 MDefinition* lhs = ins->lhs();
6629 MOZ_ASSERT(lhs->type() == MIRType::Int32);
6631 MDefinition* rhs = ins->rhs();
6632 MOZ_ASSERT(rhs->type() == MIRType::Int32);
6634 auto* guard =
6635 new (alloc()) LGuardTagNotEqual(useRegister(lhs), useRegister(rhs));
6636 assignSnapshot(guard, ins->bailoutKind());
6637 add(guard, ins);
6640 void LIRGenerator::visitLoadWrapperTarget(MLoadWrapperTarget* ins) {
6641 MDefinition* object = ins->object();
6642 MOZ_ASSERT(object->type() == MIRType::Object);
6644 define(new (alloc()) LLoadWrapperTarget(useRegisterAtStart(object)), ins);
6647 void LIRGenerator::visitGuardHasGetterSetter(MGuardHasGetterSetter* ins) {
6648 MDefinition* object = ins->object();
6649 MOZ_ASSERT(object->type() == MIRType::Object);
6651 auto* guard = new (alloc())
6652 LGuardHasGetterSetter(useRegisterAtStart(object), tempFixed(CallTempReg0),
6653 tempFixed(CallTempReg1), tempFixed(CallTempReg2));
6654 assignSnapshot(guard, ins->bailoutKind());
6655 add(guard, ins);
6656 redefine(ins, object);
6659 void LIRGenerator::visitGuardIsExtensible(MGuardIsExtensible* ins) {
6660 MDefinition* object = ins->object();
6661 MOZ_ASSERT(object->type() == MIRType::Object);
6663 auto* guard = new (alloc()) LGuardIsExtensible(useRegister(object), temp());
6664 assignSnapshot(guard, ins->bailoutKind());
6665 add(guard, ins);
6666 redefine(ins, object);
6669 void LIRGenerator::visitGuardInt32IsNonNegative(MGuardInt32IsNonNegative* ins) {
6670 MDefinition* index = ins->index();
6671 MOZ_ASSERT(index->type() == MIRType::Int32);
6673 auto* guard = new (alloc()) LGuardInt32IsNonNegative(useRegister(index));
6674 assignSnapshot(guard, ins->bailoutKind());
6675 add(guard, ins);
6676 redefine(ins, index);
6679 void LIRGenerator::visitGuardInt32Range(MGuardInt32Range* ins) {
6680 MDefinition* input = ins->input();
6681 MOZ_ASSERT(input->type() == MIRType::Int32);
6683 auto* guard = new (alloc()) LGuardInt32Range(useRegister(input));
6684 assignSnapshot(guard, ins->bailoutKind());
6685 add(guard, ins);
6686 redefine(ins, input);
6689 void LIRGenerator::visitGuardIndexIsNotDenseElement(
6690 MGuardIndexIsNotDenseElement* ins) {
6691 MDefinition* object = ins->object();
6692 MOZ_ASSERT(object->type() == MIRType::Object);
6694 MDefinition* index = ins->index();
6695 MOZ_ASSERT(index->type() == MIRType::Int32);
6697 LDefinition spectreTemp =
6698 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6700 auto* guard = new (alloc()) LGuardIndexIsNotDenseElement(
6701 useRegister(object), useRegister(index), temp(), spectreTemp);
6702 assignSnapshot(guard, ins->bailoutKind());
6703 add(guard, ins);
6704 redefine(ins, index);
6707 void LIRGenerator::visitGuardIndexIsValidUpdateOrAdd(
6708 MGuardIndexIsValidUpdateOrAdd* ins) {
6709 MDefinition* object = ins->object();
6710 MOZ_ASSERT(object->type() == MIRType::Object);
6712 MDefinition* index = ins->index();
6713 MOZ_ASSERT(index->type() == MIRType::Int32);
6715 LDefinition spectreTemp =
6716 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp();
6718 auto* guard = new (alloc()) LGuardIndexIsValidUpdateOrAdd(
6719 useRegister(object), useRegister(index), temp(), spectreTemp);
6720 assignSnapshot(guard, ins->bailoutKind());
6721 add(guard, ins);
6722 redefine(ins, index);
6725 void LIRGenerator::visitCallAddOrUpdateSparseElement(
6726 MCallAddOrUpdateSparseElement* ins) {
6727 MDefinition* object = ins->object();
6728 MOZ_ASSERT(object->type() == MIRType::Object);
6730 MDefinition* index = ins->index();
6731 MOZ_ASSERT(index->type() == MIRType::Int32);
6733 MDefinition* value = ins->value();
6734 MOZ_ASSERT(value->type() == MIRType::Value);
6736 auto* lir = new (alloc()) LCallAddOrUpdateSparseElement(
6737 useRegisterAtStart(object), useRegisterAtStart(index),
6738 useBoxAtStart(value));
6739 add(lir, ins);
6740 assignSafepoint(lir, ins);
6743 void LIRGenerator::visitCallGetSparseElement(MCallGetSparseElement* ins) {
6744 MDefinition* object = ins->object();
6745 MOZ_ASSERT(object->type() == MIRType::Object);
6747 MDefinition* index = ins->index();
6748 MOZ_ASSERT(index->type() == MIRType::Int32);
6750 auto* lir = new (alloc()) LCallGetSparseElement(useRegisterAtStart(object),
6751 useRegisterAtStart(index));
6752 defineReturn(lir, ins);
6753 assignSafepoint(lir, ins);
6756 void LIRGenerator::visitCallNativeGetElement(MCallNativeGetElement* ins) {
6757 MDefinition* object = ins->object();
6758 MOZ_ASSERT(object->type() == MIRType::Object);
6760 MDefinition* index = ins->index();
6761 MOZ_ASSERT(index->type() == MIRType::Int32);
6763 auto* lir = new (alloc()) LCallNativeGetElement(useRegisterAtStart(object),
6764 useRegisterAtStart(index));
6765 defineReturn(lir, ins);
6766 assignSafepoint(lir, ins);
6769 void LIRGenerator::visitCallNativeGetElementSuper(
6770 MCallNativeGetElementSuper* ins) {
6771 MDefinition* object = ins->object();
6772 MOZ_ASSERT(object->type() == MIRType::Object);
6774 MDefinition* index = ins->index();
6775 MOZ_ASSERT(index->type() == MIRType::Int32);
6777 MDefinition* receiver = ins->receiver();
6779 auto* lir = new (alloc()) LCallNativeGetElementSuper(
6780 useRegisterAtStart(object), useRegisterAtStart(index),
6781 useBoxAtStart(receiver));
6782 defineReturn(lir, ins);
6783 assignSafepoint(lir, ins);
6786 void LIRGenerator::visitCallObjectHasSparseElement(
6787 MCallObjectHasSparseElement* ins) {
6788 MDefinition* object = ins->object();
6789 MOZ_ASSERT(object->type() == MIRType::Object);
6791 MDefinition* index = ins->index();
6792 MOZ_ASSERT(index->type() == MIRType::Int32);
6794 auto* lir = new (alloc()) LCallObjectHasSparseElement(
6795 useRegisterAtStart(object), useRegisterAtStart(index),
6796 tempFixed(CallTempReg0), tempFixed(CallTempReg1));
6797 assignSnapshot(lir, ins->bailoutKind());
6798 defineReturn(lir, ins);
6801 void LIRGenerator::visitBigIntAsIntN(MBigIntAsIntN* ins) {
6802 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
6803 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
6805 if (ins->bits()->isConstant()) {
6806 int32_t bits = ins->bits()->toConstant()->toInt32();
6807 if (bits == 64) {
6808 auto* lir = new (alloc())
6809 LBigIntAsIntN64(useRegister(ins->input()), temp(), tempInt64());
6810 define(lir, ins);
6811 assignSafepoint(lir, ins);
6812 return;
6814 if (bits == 32) {
6815 auto* lir = new (alloc())
6816 LBigIntAsIntN32(useRegister(ins->input()), temp(), tempInt64());
6817 define(lir, ins);
6818 assignSafepoint(lir, ins);
6819 return;
6823 auto* lir = new (alloc()) LBigIntAsIntN(useRegisterAtStart(ins->bits()),
6824 useRegisterAtStart(ins->input()));
6825 defineReturn(lir, ins);
6826 assignSafepoint(lir, ins);
6829 void LIRGenerator::visitBigIntAsUintN(MBigIntAsUintN* ins) {
6830 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32);
6831 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt);
6833 if (ins->bits()->isConstant()) {
6834 int32_t bits = ins->bits()->toConstant()->toInt32();
6835 if (bits == 64) {
6836 auto* lir = new (alloc())
6837 LBigIntAsUintN64(useRegister(ins->input()), temp(), tempInt64());
6838 define(lir, ins);
6839 assignSafepoint(lir, ins);
6840 return;
6842 if (bits == 32) {
6843 auto* lir = new (alloc())
6844 LBigIntAsUintN32(useRegister(ins->input()), temp(), tempInt64());
6845 define(lir, ins);
6846 assignSafepoint(lir, ins);
6847 return;
6851 auto* lir = new (alloc()) LBigIntAsUintN(useRegisterAtStart(ins->bits()),
6852 useRegisterAtStart(ins->input()));
6853 defineReturn(lir, ins);
6854 assignSafepoint(lir, ins);
6857 void LIRGenerator::visitGuardNonGCThing(MGuardNonGCThing* ins) {
6858 MDefinition* input = ins->input();
6860 auto* guard = new (alloc()) LGuardNonGCThing(useBox(input));
6861 assignSnapshot(guard, ins->bailoutKind());
6862 add(guard, ins);
6863 redefine(ins, input);
6866 void LIRGenerator::visitToHashableNonGCThing(MToHashableNonGCThing* ins) {
6867 auto* lir =
6868 new (alloc()) LToHashableNonGCThing(useBox(ins->input()), tempDouble());
6869 defineBox(lir, ins);
6872 void LIRGenerator::visitToHashableString(MToHashableString* ins) {
6873 auto* lir = new (alloc()) LToHashableString(useRegister(ins->input()));
6874 define(lir, ins);
6875 assignSafepoint(lir, ins);
6878 void LIRGenerator::visitToHashableValue(MToHashableValue* ins) {
6879 auto* lir =
6880 new (alloc()) LToHashableValue(useBox(ins->input()), tempDouble());
6881 defineBox(lir, ins);
6882 assignSafepoint(lir, ins);
6885 void LIRGenerator::visitHashNonGCThing(MHashNonGCThing* ins) {
6886 auto* lir = new (alloc()) LHashNonGCThing(useBox(ins->input()), temp());
6887 define(lir, ins);
6890 void LIRGenerator::visitHashString(MHashString* ins) {
6891 auto* lir = new (alloc()) LHashString(useRegister(ins->input()), temp());
6892 define(lir, ins);
6895 void LIRGenerator::visitHashSymbol(MHashSymbol* ins) {
6896 auto* lir = new (alloc()) LHashSymbol(useRegister(ins->input()));
6897 define(lir, ins);
6900 void LIRGenerator::visitHashBigInt(MHashBigInt* ins) {
6901 auto* lir = new (alloc())
6902 LHashBigInt(useRegister(ins->input()), temp(), temp(), temp());
6903 define(lir, ins);
6906 void LIRGenerator::visitHashObject(MHashObject* ins) {
6907 auto* lir =
6908 new (alloc()) LHashObject(useRegister(ins->set()), useBox(ins->input()),
6909 temp(), temp(), temp(), temp());
6910 define(lir, ins);
6913 void LIRGenerator::visitHashValue(MHashValue* ins) {
6914 auto* lir =
6915 new (alloc()) LHashValue(useRegister(ins->set()), useBox(ins->input()),
6916 temp(), temp(), temp(), temp());
6917 define(lir, ins);
6920 void LIRGenerator::visitSetObjectHasNonBigInt(MSetObjectHasNonBigInt* ins) {
6921 auto* lir = new (alloc())
6922 LSetObjectHasNonBigInt(useRegister(ins->set()), useBox(ins->value()),
6923 useRegister(ins->hash()), temp(), temp());
6924 define(lir, ins);
6927 void LIRGenerator::visitSetObjectHasBigInt(MSetObjectHasBigInt* ins) {
6928 auto* lir = new (alloc()) LSetObjectHasBigInt(
6929 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
6930 temp(), temp(), temp(), temp());
6931 define(lir, ins);
6934 void LIRGenerator::visitSetObjectHasValue(MSetObjectHasValue* ins) {
6935 auto* lir = new (alloc()) LSetObjectHasValue(
6936 useRegister(ins->set()), useBox(ins->value()), useRegister(ins->hash()),
6937 temp(), temp(), temp(), temp());
6938 define(lir, ins);
6941 void LIRGenerator::visitSetObjectHasValueVMCall(MSetObjectHasValueVMCall* ins) {
6942 auto* lir = new (alloc()) LSetObjectHasValueVMCall(
6943 useRegisterAtStart(ins->set()), useBoxAtStart(ins->value()));
6944 defineReturn(lir, ins);
6945 assignSafepoint(lir, ins);
6948 void LIRGenerator::visitSetObjectSize(MSetObjectSize* ins) {
6949 auto* lir = new (alloc()) LSetObjectSize(useRegisterAtStart(ins->set()));
6950 define(lir, ins);
6953 void LIRGenerator::visitMapObjectHasNonBigInt(MMapObjectHasNonBigInt* ins) {
6954 auto* lir = new (alloc())
6955 LMapObjectHasNonBigInt(useRegister(ins->map()), useBox(ins->value()),
6956 useRegister(ins->hash()), temp(), temp());
6957 define(lir, ins);
6960 void LIRGenerator::visitMapObjectHasBigInt(MMapObjectHasBigInt* ins) {
6961 auto* lir = new (alloc()) LMapObjectHasBigInt(
6962 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6963 temp(), temp(), temp(), temp());
6964 define(lir, ins);
6967 void LIRGenerator::visitMapObjectHasValue(MMapObjectHasValue* ins) {
6968 auto* lir = new (alloc()) LMapObjectHasValue(
6969 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6970 temp(), temp(), temp(), temp());
6971 define(lir, ins);
6974 void LIRGenerator::visitMapObjectHasValueVMCall(MMapObjectHasValueVMCall* ins) {
6975 auto* lir = new (alloc()) LMapObjectHasValueVMCall(
6976 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
6977 defineReturn(lir, ins);
6978 assignSafepoint(lir, ins);
6981 void LIRGenerator::visitMapObjectGetNonBigInt(MMapObjectGetNonBigInt* ins) {
6982 auto* lir = new (alloc())
6983 LMapObjectGetNonBigInt(useRegister(ins->map()), useBox(ins->value()),
6984 useRegister(ins->hash()), temp(), temp());
6985 defineBox(lir, ins);
6988 void LIRGenerator::visitMapObjectGetBigInt(MMapObjectGetBigInt* ins) {
6989 auto* lir = new (alloc()) LMapObjectGetBigInt(
6990 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6991 temp(), temp(), temp(), temp());
6992 defineBox(lir, ins);
6995 void LIRGenerator::visitMapObjectGetValue(MMapObjectGetValue* ins) {
6996 auto* lir = new (alloc()) LMapObjectGetValue(
6997 useRegister(ins->map()), useBox(ins->value()), useRegister(ins->hash()),
6998 temp(), temp(), temp(), temp());
6999 defineBox(lir, ins);
7002 void LIRGenerator::visitMapObjectGetValueVMCall(MMapObjectGetValueVMCall* ins) {
7003 auto* lir = new (alloc()) LMapObjectGetValueVMCall(
7004 useRegisterAtStart(ins->map()), useBoxAtStart(ins->value()));
7005 defineReturn(lir, ins);
7006 assignSafepoint(lir, ins);
7009 void LIRGenerator::visitMapObjectSize(MMapObjectSize* ins) {
7010 auto* lir = new (alloc()) LMapObjectSize(useRegisterAtStart(ins->map()));
7011 define(lir, ins);
7014 void LIRGenerator::visitConstant(MConstant* ins) {
7015 if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) {
7016 emitAtUses(ins);
7017 return;
7020 switch (ins->type()) {
7021 case MIRType::Double:
7022 define(new (alloc()) LDouble(ins->toDouble()), ins);
7023 break;
7024 case MIRType::Float32:
7025 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
7026 break;
7027 case MIRType::Boolean:
7028 define(new (alloc()) LInteger(ins->toBoolean()), ins);
7029 break;
7030 case MIRType::Int32:
7031 define(new (alloc()) LInteger(ins->toInt32()), ins);
7032 break;
7033 case MIRType::Int64:
7034 defineInt64(new (alloc()) LInteger64(ins->toInt64()), ins);
7035 break;
7036 case MIRType::IntPtr:
7037 #ifdef JS_64BIT
7038 defineInt64(new (alloc()) LInteger64(ins->toIntPtr()), ins);
7039 #else
7040 define(new (alloc()) LInteger(ins->toIntPtr()), ins);
7041 #endif
7042 break;
7043 case MIRType::String:
7044 define(new (alloc()) LPointer(ins->toString()), ins);
7045 break;
7046 case MIRType::Symbol:
7047 define(new (alloc()) LPointer(ins->toSymbol()), ins);
7048 break;
7049 case MIRType::BigInt:
7050 define(new (alloc()) LPointer(ins->toBigInt()), ins);
7051 break;
7052 case MIRType::Object:
7053 define(new (alloc()) LPointer(&ins->toObject()), ins);
7054 break;
7055 case MIRType::Shape:
7056 MOZ_ASSERT(ins->isEmittedAtUses());
7057 break;
7058 default:
7059 // Constants of special types (undefined, null) should never flow into
7060 // here directly. Operations blindly consuming them require a Box.
7061 MOZ_CRASH("unexpected constant type");
7065 void LIRGenerator::visitConstantProto(MConstantProto* ins) {
7066 JSObject* obj = &ins->protoObject()->toConstant()->toObject();
7067 define(new (alloc()) LPointer(obj), ins);
7070 void LIRGenerator::visitWasmNullConstant(MWasmNullConstant* ins) {
7071 define(new (alloc()) LWasmNullConstant(), ins);
7074 void LIRGenerator::visitWasmFloatConstant(MWasmFloatConstant* ins) {
7075 switch (ins->type()) {
7076 case MIRType::Double:
7077 define(new (alloc()) LDouble(ins->toDouble()), ins);
7078 break;
7079 case MIRType::Float32:
7080 define(new (alloc()) LFloat32(ins->toFloat32()), ins);
7081 break;
7082 #ifdef ENABLE_WASM_SIMD
7083 case MIRType::Simd128:
7084 define(new (alloc()) LSimd128(ins->toSimd128()), ins);
7085 break;
7086 #endif
7087 default:
7088 MOZ_CRASH("unexpected constant type");
7092 #ifdef JS_JITSPEW
7093 static void SpewResumePoint(MBasicBlock* block, MInstruction* ins,
7094 MResumePoint* resumePoint) {
7095 Fprinter& out = JitSpewPrinter();
7096 out.printf("Current resume point %p details:\n", (void*)resumePoint);
7097 out.printf(" frame count: %u\n", resumePoint->frameCount());
7099 if (ins) {
7100 out.printf(" taken after: ");
7101 ins->printName(out);
7102 } else {
7103 out.printf(" taken at block %u entry", block->id());
7105 out.printf("\n");
7107 out.printf(" pc: %p (script: %p, offset: %d)\n", (void*)resumePoint->pc(),
7108 (void*)resumePoint->block()->info().script(),
7109 int(resumePoint->block()->info().script()->pcToOffset(
7110 resumePoint->pc())));
7112 for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) {
7113 MDefinition* in = resumePoint->getOperand(i);
7114 out.printf(" slot%u: ", (unsigned)i);
7115 in->printName(out);
7116 out.printf("\n");
7119 #endif
7121 void LIRGenerator::visitInstructionDispatch(MInstruction* ins) {
7122 #ifdef JS_CODEGEN_NONE
7123 // Don't compile the switch-statement below so that we don't have to define
7124 // the platform-specific visit* methods for the none-backend.
7125 MOZ_CRASH();
7126 #else
7127 switch (ins->op()) {
7128 # define MIR_OP(op) \
7129 case MDefinition::Opcode::op: \
7130 visit##op(ins->to##op()); \
7131 break;
7132 MIR_OPCODE_LIST(MIR_OP)
7133 # undef MIR_OP
7134 default:
7135 MOZ_CRASH("Invalid instruction");
7137 #endif
7140 void LIRGeneratorShared::visitEmittedAtUses(MInstruction* ins) {
7141 static_cast<LIRGenerator*>(this)->visitInstructionDispatch(ins);
7144 bool LIRGenerator::visitInstruction(MInstruction* ins) {
7145 MOZ_ASSERT(!errored());
7147 if (ins->isRecoveredOnBailout()) {
7148 MOZ_ASSERT(!JitOptions.disableRecoverIns);
7149 return true;
7152 if (!gen->ensureBallast()) {
7153 return false;
7155 visitInstructionDispatch(ins);
7157 if (ins->resumePoint()) {
7158 updateResumeState(ins);
7161 #ifdef DEBUG
7162 ins->setInWorklistUnchecked();
7163 #endif
7165 // If no safepoint was created, there's no need for an OSI point.
7166 if (LOsiPoint* osiPoint = popOsiPoint()) {
7167 add(osiPoint);
7170 return !errored();
7173 bool LIRGenerator::definePhis() {
7174 size_t lirIndex = 0;
7175 MBasicBlock* block = current->mir();
7176 for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
7177 if (phi->type() == MIRType::Value) {
7178 defineUntypedPhi(*phi, lirIndex);
7179 lirIndex += BOX_PIECES;
7180 } else if (phi->type() == MIRType::Int64) {
7181 defineInt64Phi(*phi, lirIndex);
7182 lirIndex += INT64_PIECES;
7183 } else {
7184 defineTypedPhi(*phi, lirIndex);
7185 lirIndex += 1;
7188 return !errored();
7191 void LIRGenerator::updateResumeState(MInstruction* ins) {
7192 lastResumePoint_ = ins->resumePoint();
7193 #ifdef JS_JITSPEW
7194 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
7195 SpewResumePoint(nullptr, ins, lastResumePoint_);
7197 #endif
7200 void LIRGenerator::updateResumeState(MBasicBlock* block) {
7201 // Note: RangeAnalysis can flag blocks as unreachable, but they are only
7202 // removed iff GVN (including UCE) is enabled.
7203 MOZ_ASSERT_IF(!mir()->compilingWasm() && !block->unreachable(),
7204 block->entryResumePoint());
7205 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7206 lastResumePoint_ = block->entryResumePoint();
7207 #ifdef JS_JITSPEW
7208 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) {
7209 SpewResumePoint(block, nullptr, lastResumePoint_);
7211 #endif
7214 bool LIRGenerator::visitBlock(MBasicBlock* block) {
7215 current = block->lir();
7216 updateResumeState(block);
7218 if (!definePhis()) {
7219 return false;
7222 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled());
7223 for (MInstructionIterator iter = block->begin(); *iter != block->lastIns();
7224 iter++) {
7225 if (!visitInstruction(*iter)) {
7226 return false;
7230 if (block->successorWithPhis()) {
7231 // If we have a successor with phis, lower the phi input now that we
7232 // are approaching the join point.
7233 MBasicBlock* successor = block->successorWithPhis();
7234 uint32_t position = block->positionInPhiSuccessor();
7235 size_t lirIndex = 0;
7236 for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd();
7237 phi++) {
7238 if (!gen->ensureBallast()) {
7239 return false;
7242 MDefinition* opd = phi->getOperand(position);
7243 ensureDefined(opd);
7245 MOZ_ASSERT(opd->type() == phi->type());
7247 if (phi->type() == MIRType::Value) {
7248 lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex);
7249 lirIndex += BOX_PIECES;
7250 } else if (phi->type() == MIRType::Int64) {
7251 lowerInt64PhiInput(*phi, position, successor->lir(), lirIndex);
7252 lirIndex += INT64_PIECES;
7253 } else {
7254 lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex);
7255 lirIndex += 1;
7260 // Now emit the last instruction, which is some form of branch.
7261 if (!visitInstruction(block->lastIns())) {
7262 return false;
7265 return true;
7268 void LIRGenerator::visitNaNToZero(MNaNToZero* ins) {
7269 MDefinition* input = ins->input();
7271 if (ins->operandIsNeverNaN() && ins->operandIsNeverNegativeZero()) {
7272 redefine(ins, input);
7273 return;
7275 LNaNToZero* lir =
7276 new (alloc()) LNaNToZero(useRegisterAtStart(input), tempDouble());
7277 defineReuseInput(lir, ins, 0);
7280 bool LIRGenerator::generate() {
7281 // Create all blocks and prep all phis beforehand.
7282 for (ReversePostorderIterator block(graph.rpoBegin());
7283 block != graph.rpoEnd(); block++) {
7284 if (gen->shouldCancel("Lowering (preparation loop)")) {
7285 return false;
7288 if (!lirGraph_.initBlock(*block)) {
7289 return false;
7293 for (ReversePostorderIterator block(graph.rpoBegin());
7294 block != graph.rpoEnd(); block++) {
7295 if (gen->shouldCancel("Lowering (main loop)")) {
7296 return false;
7299 if (!visitBlock(*block)) {
7300 return false;
7304 lirGraph_.setArgumentSlotCount(maxargslots_);
7305 return true;
7308 void LIRGenerator::visitPhi(MPhi* phi) {
7309 // Phi nodes are not lowered because they are only meaningful for the register
7310 // allocator.
7311 MOZ_CRASH("Unexpected Phi node during Lowering.");
7314 void LIRGenerator::visitBeta(MBeta* beta) {
7315 // Beta nodes are supposed to be removed before because they are
7316 // only used to carry the range information for Range analysis
7317 MOZ_CRASH("Unexpected Beta node during Lowering.");
7320 void LIRGenerator::visitObjectState(MObjectState* objState) {
7321 // ObjectState nodes are always recovered on bailouts
7322 MOZ_CRASH("Unexpected ObjectState node during Lowering.");
7325 void LIRGenerator::visitArrayState(MArrayState* objState) {
7326 // ArrayState nodes are always recovered on bailouts
7327 MOZ_CRASH("Unexpected ArrayState node during Lowering.");
7330 void LIRGenerator::visitIonToWasmCall(MIonToWasmCall* ins) {
7331 // The instruction needs a temp register:
7332 // - that's not the FramePointer, since wasm is going to use it in the
7333 // function.
7334 // - that's not aliasing an input register.
7335 LDefinition scratch = tempFixed(ABINonArgReg0);
7337 // Note that since this is a LIR call instruction, regalloc will prevent
7338 // the use*AtStart below from reusing any of the temporaries.
7340 LInstruction* lir;
7341 if (ins->type() == MIRType::Value) {
7342 lir = allocateVariadic<LIonToWasmCallV>(ins->numOperands(), scratch);
7343 } else if (ins->type() == MIRType::Int64) {
7344 lir = allocateVariadic<LIonToWasmCallI64>(ins->numOperands(), scratch);
7345 } else {
7346 lir = allocateVariadic<LIonToWasmCall>(ins->numOperands(), scratch);
7348 if (!lir) {
7349 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitIonToWasmCall");
7350 return;
7353 ABIArgGenerator abi;
7354 for (unsigned i = 0; i < ins->numOperands(); i++) {
7355 MDefinition* argDef = ins->getOperand(i);
7356 ABIArg arg = abi.next(ToMIRType(argDef->type()));
7357 switch (arg.kind()) {
7358 case ABIArg::GPR:
7359 case ABIArg::FPU:
7360 lir->setOperand(i, useFixedAtStart(argDef, arg.reg()));
7361 break;
7362 case ABIArg::Stack:
7363 lir->setOperand(i, useAtStart(argDef));
7364 break;
7365 #ifdef JS_CODEGEN_REGISTER_PAIR
7366 case ABIArg::GPR_PAIR:
7367 MOZ_CRASH(
7368 "no way to pass i64, and wasm uses hardfp for function calls");
7369 #endif
7370 case ABIArg::Uninitialized:
7371 MOZ_CRASH("Uninitialized ABIArg kind");
7375 defineReturn(lir, ins);
7376 assignSafepoint(lir, ins);
7379 void LIRGenerator::visitWasmSelect(MWasmSelect* ins) {
7380 MDefinition* condExpr = ins->condExpr();
7382 // Pick off specific cases that we can do with LWasmCompareAndSelect to avoid
7383 // generating a boolean that we then have to test again.
7384 if (condExpr->isCompare() && condExpr->isEmittedAtUses()) {
7385 MCompare* comp = condExpr->toCompare();
7386 MCompare::CompareType compTy = comp->compareType();
7387 if (canSpecializeWasmCompareAndSelect(compTy, ins->type())) {
7388 JSOp jsop = comp->jsop();
7389 // We don't currently generate any other JSOPs for the comparison, and if
7390 // that changes, we want to know about it. Hence this assertion.
7391 MOZ_ASSERT(jsop == JSOp::Eq || jsop == JSOp::Ne || jsop == JSOp::Lt ||
7392 jsop == JSOp::Gt || jsop == JSOp::Le || jsop == JSOp::Ge);
7393 MDefinition* lhs = comp->lhs();
7394 MDefinition* rhs = comp->rhs();
7395 jsop = ReorderComparison(jsop, &lhs, &rhs);
7396 lowerWasmCompareAndSelect(ins, lhs, rhs, compTy, jsop);
7397 return;
7400 // Fall through to code that generates a boolean and selects on that.
7402 if (ins->type() == MIRType::Int64) {
7403 lowerWasmSelectI64(ins);
7404 return;
7407 lowerWasmSelectI(ins);
7410 void LIRGenerator::visitWasmFence(MWasmFence* ins) {
7411 add(new (alloc()) LWasmFence, ins);
7414 void LIRGenerator::visitWasmLoadField(MWasmLoadField* ins) {
7415 uint32_t offs = ins->offset();
7416 LAllocation obj = useRegister(ins->obj());
7417 MWideningOp wideningOp = ins->wideningOp();
7418 if (ins->type() == MIRType::Int64) {
7419 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7420 defineInt64(new (alloc()) LWasmLoadSlotI64(obj, offs, ins->maybeTrap()),
7421 ins);
7422 } else {
7423 define(new (alloc()) LWasmLoadSlot(obj, offs, ins->type(), wideningOp,
7424 ins->maybeTrap()),
7425 ins);
7429 void LIRGenerator::visitWasmLoadFieldKA(MWasmLoadFieldKA* ins) {
7430 uint32_t offs = ins->offset();
7431 LAllocation obj = useRegister(ins->obj());
7432 MWideningOp wideningOp = ins->wideningOp();
7433 if (ins->type() == MIRType::Int64) {
7434 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None);
7435 defineInt64(new (alloc()) LWasmLoadSlotI64(obj, offs, ins->maybeTrap()),
7436 ins);
7437 } else {
7438 define(new (alloc()) LWasmLoadSlot(obj, offs, ins->type(), wideningOp,
7439 ins->maybeTrap()),
7440 ins);
7442 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7445 void LIRGenerator::visitWasmStoreFieldKA(MWasmStoreFieldKA* ins) {
7446 MDefinition* value = ins->value();
7447 uint32_t offs = ins->offset();
7448 MNarrowingOp narrowingOp = ins->narrowingOp();
7449 LAllocation obj = useRegister(ins->obj());
7450 LInstruction* lir;
7451 if (value->type() == MIRType::Int64) {
7452 MOZ_RELEASE_ASSERT(narrowingOp == MNarrowingOp::None);
7453 lir = new (alloc())
7454 LWasmStoreSlotI64(useInt64Register(value), obj, offs, ins->maybeTrap());
7455 } else {
7456 lir = new (alloc())
7457 LWasmStoreSlot(useRegister(value), obj, offs, value->type(),
7458 narrowingOp, ins->maybeTrap());
7460 add(lir, ins);
7461 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7464 void LIRGenerator::visitWasmStoreFieldRefKA(MWasmStoreFieldRefKA* ins) {
7465 LAllocation instance = useRegister(ins->instance());
7466 LAllocation obj = useFixed(ins->obj(), PreBarrierReg);
7467 LAllocation value = useRegister(ins->value());
7468 uint32_t offset = ins->offset();
7469 add(new (alloc()) LWasmStoreRef(instance, obj, value, temp(), offset,
7470 ins->maybeTrap(), ins->preBarrierKind()),
7471 ins);
7472 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->ka())), ins);
7475 void LIRGenerator::visitWasmRefIsSubtypeOfAbstract(
7476 MWasmRefIsSubtypeOfAbstract* ins) {
7477 if (CanEmitAtUseForSingleTest(ins)) {
7478 emitAtUses(ins);
7479 return;
7482 LAllocation ref = useRegister(ins->ref());
7483 LDefinition scratch1 = LDefinition();
7484 if (ins->destType().isAnyHierarchy()) {
7485 // See comment on MacroAssembler::branchWasmRefIsSubtypeAny.
7486 // We know we do not need scratch2 and superSTV because we know
7487 // this is not a concrete type.
7488 MOZ_ASSERT(!MacroAssembler::needSuperSTVForBranchWasmRefIsSubtypeAny(
7489 ins->destType()));
7490 MOZ_ASSERT(!MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
7491 ins->destType()));
7493 scratch1 = MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
7494 ins->destType())
7495 ? temp()
7496 : LDefinition();
7497 } else if (ins->destType().isFuncHierarchy()) {
7498 // See comment on MacroAssembler::branchWasmRefIsSubtypeFunc.
7499 // We know we do not need any supertype vectors or scratch registers because
7500 // this is not a concrete cast.
7501 MOZ_ASSERT(
7502 !MacroAssembler::needSuperSTVAndScratch1ForBranchWasmRefIsSubtypeFunc(
7503 ins->destType()));
7504 MOZ_ASSERT(!MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
7505 ins->destType()));
7506 } else if (ins->destType().isExternHierarchy()) {
7507 // no scratch registers needed for casts in the extern hierarchy
7508 } else {
7509 MOZ_CRASH("unknown type hierarchy for abstract cast");
7512 define(new (alloc()) LWasmRefIsSubtypeOfAbstract(ref, scratch1), ins);
7515 void LIRGenerator::visitWasmRefIsSubtypeOfConcrete(
7516 MWasmRefIsSubtypeOfConcrete* ins) {
7517 if (CanEmitAtUseForSingleTest(ins)) {
7518 emitAtUses(ins);
7519 return;
7522 // This gets a bit wild because it needs to handle concrete casts in all
7523 // hierarchies. Supertype vectors are always required (that's what concrete
7524 // means) but the scratch registers can vary.
7526 LAllocation ref = useRegister(ins->ref());
7527 LAllocation superSTV = useRegister(ins->superSTV());
7528 LDefinition scratch1 = LDefinition();
7529 LDefinition scratch2 = LDefinition();
7530 if (ins->destType().isAnyHierarchy()) {
7531 // See comment on MacroAssembler::branchWasmRefIsSubtypeAny.
7532 // We know we need scratch1 because we know this is a concrete type.
7533 MOZ_ASSERT(MacroAssembler::needSuperSTVForBranchWasmRefIsSubtypeAny(
7534 ins->destType()));
7535 MOZ_ASSERT(MacroAssembler::needScratch1ForBranchWasmRefIsSubtypeAny(
7536 ins->destType()));
7537 scratch1 = temp();
7538 scratch2 = MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeAny(
7539 ins->destType())
7540 ? temp()
7541 : LDefinition();
7542 } else if (ins->destType().isFuncHierarchy()) {
7543 // See comment on MacroAssembler::branchWasmRefIsSubtypeFunc.
7544 // We know we need scratch1 because we know this is a concrete type.
7545 MOZ_ASSERT(
7546 MacroAssembler::needSuperSTVAndScratch1ForBranchWasmRefIsSubtypeFunc(
7547 ins->destType()));
7548 scratch1 = temp();
7549 scratch2 = MacroAssembler::needScratch2ForBranchWasmRefIsSubtypeFunc(
7550 ins->destType())
7551 ? temp()
7552 : LDefinition();
7553 } else if (ins->destType().isExternHierarchy()) {
7554 MOZ_CRASH("concrete casts are impossible in the extern hierarchy");
7555 } else {
7556 MOZ_CRASH("unknown type hierarchy for concrete cast");
7559 define(new (alloc())
7560 LWasmRefIsSubtypeOfConcrete(ref, superSTV, scratch1, scratch2),
7561 ins);
7564 void LIRGenerator::visitWasmNewStructObject(MWasmNewStructObject* ins) {
7565 LWasmNewStructObject* lir = new (alloc())
7566 LWasmNewStructObject(useFixed(ins->instance(), InstanceReg),
7567 useRegister(ins->typeDefData()), temp(), temp());
7568 define(lir, ins);
7569 assignWasmSafepoint(lir);
7572 #ifdef FUZZING_JS_FUZZILLI
7573 void LIRGenerator::visitFuzzilliHash(MFuzzilliHash* ins) {
7574 MDefinition* value = ins->getOperand(0);
7576 if (value->type() == MIRType::Undefined || value->type() == MIRType::Null) {
7577 define(new (alloc()) LFuzzilliHashT(LAllocation(), temp(), tempDouble()),
7578 ins);
7579 } else if (value->type() == MIRType::Int32 ||
7580 value->type() == MIRType::Double ||
7581 value->type() == MIRType::Float32 ||
7582 value->type() == MIRType::Boolean ||
7583 value->type() == MIRType::BigInt) {
7584 define(new (alloc())
7585 LFuzzilliHashT(useRegister(value), temp(), tempDouble()),
7586 ins);
7587 } else if (value->type() == MIRType::Object) {
7588 LFuzzilliHashT* lir =
7589 new (alloc()) LFuzzilliHashT(useRegister(value), temp(), tempDouble());
7590 define(lir, ins);
7591 assignSafepoint(lir, ins);
7592 } else if (value->type() == MIRType::Value) {
7593 LFuzzilliHashV* lir =
7594 new (alloc()) LFuzzilliHashV(useBox(value), temp(), tempDouble());
7595 define(lir, ins);
7596 assignSafepoint(lir, ins);
7597 } else {
7598 define(new (alloc()) LInteger(0), ins);
7602 void LIRGenerator::visitFuzzilliHashStore(MFuzzilliHashStore* ins) {
7603 MDefinition* value = ins->getOperand(0);
7604 MOZ_ASSERT(value->type() == MIRType::Int32);
7605 add(new (alloc()) LFuzzilliHashStore(useRegister(value), temp(), temp()),
7606 ins);
7608 #endif
7610 static_assert(!std::is_polymorphic_v<LIRGenerator>,
7611 "LIRGenerator should not have any virtual methods");
7613 #ifdef JS_CODEGEN_NONE
7614 void LIRGenerator::visitReturnImpl(MDefinition*, bool) { MOZ_CRASH(); }
7615 #endif