Lowering.cpp (295216B)
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/. */ 6 7 #include "jit/Lowering.h" 8 9 #include "mozilla/DebugOnly.h" 10 #include "mozilla/EndianUtils.h" 11 #include "mozilla/FloatingPoint.h" 12 #include "mozilla/MathAlgorithms.h" 13 14 #include <type_traits> 15 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-wasm.h" 23 #include "jit/MIR.h" 24 #include "jit/MIRGraph.h" 25 #include "jit/SharedICRegisters.h" 26 #include "js/experimental/JitInfo.h" // JSJitInfo 27 #include "util/Memory.h" 28 #include "wasm/WasmCodegenTypes.h" 29 #include "wasm/WasmFeatures.h" // for wasm::ReportSimdAnalysis 30 #include "wasm/WasmInstanceData.h" 31 32 #include "jit/shared/Lowering-shared-inl.h" 33 #include "vm/BytecodeUtil-inl.h" 34 35 using namespace js; 36 using namespace jit; 37 38 using JS::GenericNaN; 39 using mozilla::DebugOnly; 40 41 LBoxAllocation LIRGenerator::useBoxFixedAtStart(MDefinition* mir, 42 ValueOperand op) { 43 #if defined(JS_NUNBOX32) 44 return useBoxFixed(mir, op.typeReg(), op.payloadReg(), true); 45 #elif defined(JS_PUNBOX64) 46 return useBoxFixed(mir, op.valueReg(), op.scratchReg(), true); 47 #endif 48 } 49 50 LBoxAllocation LIRGenerator::useBoxAtStart(MDefinition* mir, 51 LUse::Policy policy) { 52 return useBox(mir, policy, /* useAtStart = */ true); 53 } 54 55 void LIRGenerator::visitParameter(MParameter* param) { 56 ptrdiff_t offset; 57 if (param->index() == MParameter::THIS_SLOT) { 58 offset = THIS_FRAME_ARGSLOT; 59 } else { 60 offset = 1 + param->index(); 61 } 62 63 LParameter* ins = new (alloc()) LParameter; 64 defineBox(ins, param, LDefinition::FIXED); 65 66 offset *= sizeof(Value); 67 #if defined(JS_NUNBOX32) 68 # if MOZ_BIG_ENDIAN() 69 ins->getDef(0)->setOutput(LArgument(offset)); 70 ins->getDef(1)->setOutput(LArgument(offset + 4)); 71 # else 72 ins->getDef(0)->setOutput(LArgument(offset + 4)); 73 ins->getDef(1)->setOutput(LArgument(offset)); 74 # endif 75 #elif defined(JS_PUNBOX64) 76 ins->getDef(0)->setOutput(LArgument(offset)); 77 #endif 78 } 79 80 void LIRGenerator::visitCallee(MCallee* ins) { 81 define(new (alloc()) LCallee(), ins); 82 } 83 84 void LIRGenerator::visitIsConstructing(MIsConstructing* ins) { 85 define(new (alloc()) LIsConstructing(), ins); 86 } 87 88 void LIRGenerator::visitGoto(MGoto* ins) { 89 add(new (alloc()) LGoto(ins->target())); 90 } 91 92 void LIRGenerator::visitTableSwitch(MTableSwitch* tableswitch) { 93 MDefinition* opd = tableswitch->getOperand(0); 94 95 // There should be at least 1 successor. The default case! 96 MOZ_ASSERT(tableswitch->numSuccessors() > 0); 97 98 // If there are no cases, the default case is always taken. 99 if (tableswitch->numSuccessors() == 1) { 100 add(new (alloc()) LGoto(tableswitch->getDefault())); 101 return; 102 } 103 104 // If we don't know the type. 105 if (opd->type() == MIRType::Value) { 106 add(newLTableSwitchV(useBox(opd)), tableswitch); 107 return; 108 } 109 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; 115 } 116 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(); 127 } 128 add(newLTableSwitch(index, tempInt), tableswitch); 129 } 130 131 void LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed* ins) { 132 LCheckOverRecursed* lir = new (alloc()) LCheckOverRecursed(); 133 add(lir, ins); 134 assignSafepoint(lir, ins); 135 } 136 137 void LIRGenerator::visitNewArray(MNewArray* ins) { 138 LNewArray* lir = new (alloc()) LNewArray(temp()); 139 define(lir, ins); 140 assignSafepoint(lir, ins); 141 } 142 143 void LIRGenerator::visitNewArrayDynamicLength(MNewArrayDynamicLength* ins) { 144 MDefinition* length = ins->length(); 145 MOZ_ASSERT(length->type() == MIRType::Int32); 146 147 LNewArrayDynamicLength* lir = 148 new (alloc()) LNewArrayDynamicLength(useRegister(length), temp()); 149 define(lir, ins); 150 assignSafepoint(lir, ins); 151 } 152 153 void LIRGenerator::visitNewIterator(MNewIterator* ins) { 154 LNewIterator* lir = new (alloc()) LNewIterator(temp()); 155 define(lir, ins); 156 assignSafepoint(lir, ins); 157 } 158 159 void LIRGenerator::visitNewTypedArray(MNewTypedArray* ins) { 160 size_t nbytes = ins->templateObject()->byteLength(); 161 if (nbytes <= FixedLengthTypedArrayObject::INLINE_BUFFER_LIMIT) { 162 auto* lir = new (alloc()) LNewTypedArrayInline(temp()); 163 define(lir, ins); 164 assignSafepoint(lir, ins); 165 } else { 166 auto* lir = new (alloc()) 167 LNewTypedArray(tempFixed(CallTempReg0), tempFixed(CallTempReg1), 168 tempFixed(CallTempReg2), tempFixed(CallTempReg3)); 169 defineReturn(lir, ins); 170 assignSafepoint(lir, ins); 171 } 172 } 173 174 void LIRGenerator::visitNewTypedArrayDynamicLength( 175 MNewTypedArrayDynamicLength* ins) { 176 MDefinition* length = ins->length(); 177 MOZ_ASSERT(length->type() == MIRType::Int32); 178 179 auto* lir = new (alloc()) LNewTypedArrayDynamicLength( 180 useFixedAtStart(length, CallTempReg0), tempFixed(CallTempReg1), 181 tempFixed(CallTempReg2), tempFixed(CallTempReg3)); 182 defineReturn(lir, ins); 183 assignSafepoint(lir, ins); 184 } 185 186 void LIRGenerator::visitNewTypedArrayFromArray(MNewTypedArrayFromArray* ins) { 187 MDefinition* array = ins->array(); 188 MOZ_ASSERT(array->type() == MIRType::Object); 189 190 auto* lir = new (alloc()) LNewTypedArrayFromArray(useRegisterAtStart(array)); 191 defineReturn(lir, ins); 192 assignSafepoint(lir, ins); 193 } 194 195 void LIRGenerator::visitNewTypedArrayFromArrayBuffer( 196 MNewTypedArrayFromArrayBuffer* ins) { 197 MDefinition* arrayBuffer = ins->arrayBuffer(); 198 MDefinition* byteOffset = ins->byteOffset(); 199 MDefinition* length = ins->length(); 200 MOZ_ASSERT(arrayBuffer->type() == MIRType::Object); 201 MOZ_ASSERT(byteOffset->type() == MIRType::Value); 202 MOZ_ASSERT(length->type() == MIRType::Value); 203 204 auto* lir = new (alloc()) LNewTypedArrayFromArrayBuffer( 205 useRegisterAtStart(arrayBuffer), useBoxAtStart(byteOffset), 206 useBoxAtStart(length)); 207 defineReturn(lir, ins); 208 assignSafepoint(lir, ins); 209 } 210 211 void LIRGenerator::visitNewObject(MNewObject* ins) { 212 LNewObject* lir = new (alloc()) LNewObject(temp()); 213 define(lir, ins); 214 assignSafepoint(lir, ins); 215 } 216 217 void LIRGenerator::visitBindFunction(MBindFunction* ins) { 218 MDefinition* target = ins->target(); 219 MOZ_ASSERT(target->type() == MIRType::Object); 220 221 if (!lowerCallArguments(ins)) { 222 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitBindFunction"); 223 return; 224 } 225 226 auto* lir = new (alloc()) 227 LBindFunction(useFixedAtStart(target, CallTempReg0), 228 tempFixed(CallTempReg1), tempFixed(CallTempReg2)); 229 defineReturn(lir, ins); 230 assignSafepoint(lir, ins); 231 } 232 233 void LIRGenerator::visitNewBoundFunction(MNewBoundFunction* ins) { 234 auto* lir = new (alloc()) LNewBoundFunction(temp()); 235 define(lir, ins); 236 assignSafepoint(lir, ins); 237 } 238 239 void LIRGenerator::visitNewPlainObject(MNewPlainObject* ins) { 240 LNewPlainObject* lir = new (alloc()) LNewPlainObject(temp(), temp(), temp()); 241 define(lir, ins); 242 assignSafepoint(lir, ins); 243 } 244 245 void LIRGenerator::visitNewArrayObject(MNewArrayObject* ins) { 246 LNewArrayObject* lir = new (alloc()) LNewArrayObject(temp(), temp()); 247 define(lir, ins); 248 assignSafepoint(lir, ins); 249 } 250 251 void LIRGenerator::visitNewNamedLambdaObject(MNewNamedLambdaObject* ins) { 252 LNewNamedLambdaObject* lir = new (alloc()) LNewNamedLambdaObject(temp()); 253 define(lir, ins); 254 assignSafepoint(lir, ins); 255 } 256 257 void LIRGenerator::visitNewCallObject(MNewCallObject* ins) { 258 LNewCallObject* lir = new (alloc()) LNewCallObject(temp()); 259 define(lir, ins); 260 assignSafepoint(lir, ins); 261 } 262 263 void LIRGenerator::visitNewMapObject(MNewMapObject* ins) { 264 auto* lir = new (alloc()) LNewMapObject(temp()); 265 define(lir, ins); 266 assignSafepoint(lir, ins); 267 } 268 269 void LIRGenerator::visitNewSetObject(MNewSetObject* ins) { 270 auto* lir = new (alloc()) LNewSetObject(temp()); 271 define(lir, ins); 272 assignSafepoint(lir, ins); 273 } 274 275 void LIRGenerator::visitNewMapObjectFromIterable( 276 MNewMapObjectFromIterable* ins) { 277 MOZ_ASSERT(ins->iterable()->type() == MIRType::Value); 278 auto* lir = new (alloc()) LNewMapObjectFromIterable( 279 useBoxFixedAtStart(ins->iterable(), CallTempReg0, CallTempReg1), 280 tempFixed(CallTempReg2), tempFixed(CallTempReg3)); 281 defineReturn(lir, ins); 282 assignSafepoint(lir, ins); 283 } 284 285 void LIRGenerator::visitNewSetObjectFromIterable( 286 MNewSetObjectFromIterable* ins) { 287 MOZ_ASSERT(ins->iterable()->type() == MIRType::Value); 288 auto* lir = new (alloc()) LNewSetObjectFromIterable( 289 useBoxFixedAtStart(ins->iterable(), CallTempReg0, CallTempReg1), 290 tempFixed(CallTempReg2), tempFixed(CallTempReg3)); 291 defineReturn(lir, ins); 292 assignSafepoint(lir, ins); 293 } 294 295 void LIRGenerator::visitNewStringObject(MNewStringObject* ins) { 296 MOZ_ASSERT(ins->input()->type() == MIRType::String); 297 298 LNewStringObject* lir = 299 new (alloc()) LNewStringObject(useRegister(ins->input()), temp()); 300 define(lir, ins); 301 assignSafepoint(lir, ins); 302 } 303 304 void LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter* ins) { 305 LInitElemGetterSetter* lir = new (alloc()) LInitElemGetterSetter( 306 useRegisterAtStart(ins->object()), useBoxAtStart(ins->id()), 307 useRegisterAtStart(ins->value())); 308 add(lir, ins); 309 assignSafepoint(lir, ins); 310 } 311 312 void LIRGenerator::visitMutateProto(MMutateProto* ins) { 313 LMutateProto* lir = new (alloc()) LMutateProto( 314 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value())); 315 add(lir, ins); 316 assignSafepoint(lir, ins); 317 } 318 319 void LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter* ins) { 320 LInitPropGetterSetter* lir = new (alloc()) LInitPropGetterSetter( 321 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->value())); 322 add(lir, ins); 323 assignSafepoint(lir, ins); 324 } 325 326 void LIRGenerator::visitCreateThis(MCreateThis* ins) { 327 LCreateThis* lir = 328 new (alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->callee()), 329 useRegisterOrConstantAtStart(ins->newTarget())); 330 defineReturn(lir, ins); 331 assignSafepoint(lir, ins); 332 } 333 334 void LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject* ins) { 335 LAllocation callObj = useRegisterAtStart(ins->getCallObject()); 336 LCreateArgumentsObject* lir = new (alloc()) 337 LCreateArgumentsObject(callObj, tempFixed(CallTempReg0), 338 tempFixed(CallTempReg1), tempFixed(CallTempReg2)); 339 defineReturn(lir, ins); 340 assignSafepoint(lir, ins); 341 } 342 343 void LIRGenerator::visitCreateInlinedArgumentsObject( 344 MCreateInlinedArgumentsObject* ins) { 345 LAllocation callObj = useRegisterAtStart(ins->getCallObject()); 346 LAllocation callee = useRegisterAtStart(ins->getCallee()); 347 uint32_t numActuals = ins->numActuals(); 348 uint32_t numOperands = numActuals * BOX_PIECES + 349 LCreateInlinedArgumentsObject::NumNonArgumentOperands; 350 351 auto* lir = allocateVariadic<LCreateInlinedArgumentsObject>( 352 numOperands, tempFixed(CallTempReg0), tempFixed(CallTempReg1)); 353 if (!lir) { 354 abort(AbortReason::Alloc, 355 "OOM: LIRGenerator::visitCreateInlinedArgumentsObject"); 356 return; 357 } 358 359 lir->setOperand(LCreateInlinedArgumentsObject::CallObj, callObj); 360 lir->setOperand(LCreateInlinedArgumentsObject::Callee, callee); 361 for (uint32_t i = 0; i < numActuals; i++) { 362 MDefinition* arg = ins->getArg(i); 363 uint32_t index = LCreateInlinedArgumentsObject::ArgIndex(i); 364 lir->setBoxOperand(index, useBoxOrTypedOrConstant(arg, 365 /*useConstant = */ true, 366 /*useAtStart = */ true)); 367 } 368 369 defineReturn(lir, ins); 370 assignSafepoint(lir, ins); 371 } 372 373 void LIRGenerator::visitGetInlinedArgument(MGetInlinedArgument* ins) { 374 LAllocation index = useRegisterAtStart(ins->index()); 375 uint32_t numActuals = ins->numActuals(); 376 uint32_t numOperands = 377 numActuals * BOX_PIECES + LGetInlinedArgument::NumNonArgumentOperands; 378 379 auto* lir = allocateVariadic<LGetInlinedArgument>(numOperands); 380 if (!lir) { 381 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgument"); 382 return; 383 } 384 385 lir->setOperand(LGetInlinedArgument::Index, index); 386 for (uint32_t i = 0; i < numActuals; i++) { 387 MDefinition* arg = ins->getArg(i); 388 uint32_t index = LGetInlinedArgument::ArgIndex(i); 389 lir->setBoxOperand(index, useBoxOrTypedOrConstant(arg, 390 /*useConstant = */ true, 391 /*useAtStart = */ true)); 392 } 393 defineBox(lir, ins); 394 } 395 396 void LIRGenerator::visitGetInlinedArgumentHole(MGetInlinedArgumentHole* ins) { 397 LAllocation index = useRegisterAtStart(ins->index()); 398 uint32_t numActuals = ins->numActuals(); 399 uint32_t numOperands = 400 numActuals * BOX_PIECES + LGetInlinedArgumentHole::NumNonArgumentOperands; 401 402 auto* lir = allocateVariadic<LGetInlinedArgumentHole>(numOperands); 403 if (!lir) { 404 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitGetInlinedArgumentHole"); 405 return; 406 } 407 408 lir->setOperand(LGetInlinedArgumentHole::Index, index); 409 for (uint32_t i = 0; i < numActuals; i++) { 410 MDefinition* arg = ins->getArg(i); 411 uint32_t index = LGetInlinedArgumentHole::ArgIndex(i); 412 lir->setBoxOperand(index, useBoxOrTypedOrConstant(arg, 413 /*useConstant = */ true, 414 /*useAtStart = */ true)); 415 } 416 assignSnapshot(lir, ins->bailoutKind()); 417 defineBox(lir, ins); 418 } 419 420 void LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins) { 421 LAllocation argsObj = useRegister(ins->argsObject()); 422 LGetArgumentsObjectArg* lir = 423 new (alloc()) LGetArgumentsObjectArg(argsObj, temp()); 424 defineBox(lir, ins); 425 } 426 427 void LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins) { 428 LAllocation argsObj = useRegister(ins->argsObject()); 429 LSetArgumentsObjectArg* lir = new (alloc()) 430 LSetArgumentsObjectArg(argsObj, useBox(ins->value()), temp()); 431 add(lir, ins); 432 } 433 434 void LIRGenerator::visitLoadArgumentsObjectArg(MLoadArgumentsObjectArg* ins) { 435 MDefinition* argsObj = ins->argsObject(); 436 MOZ_ASSERT(argsObj->type() == MIRType::Object); 437 438 MDefinition* index = ins->index(); 439 MOZ_ASSERT(index->type() == MIRType::Int32); 440 441 auto* lir = new (alloc()) 442 LLoadArgumentsObjectArg(useRegister(argsObj), useRegister(index), temp()); 443 assignSnapshot(lir, ins->bailoutKind()); 444 defineBox(lir, ins); 445 } 446 447 void LIRGenerator::visitLoadArgumentsObjectArgHole( 448 MLoadArgumentsObjectArgHole* ins) { 449 MDefinition* argsObj = ins->argsObject(); 450 MOZ_ASSERT(argsObj->type() == MIRType::Object); 451 452 MDefinition* index = ins->index(); 453 MOZ_ASSERT(index->type() == MIRType::Int32); 454 455 auto* lir = new (alloc()) LLoadArgumentsObjectArgHole( 456 useRegister(argsObj), useRegister(index), temp()); 457 assignSnapshot(lir, ins->bailoutKind()); 458 defineBox(lir, ins); 459 } 460 461 void LIRGenerator::visitInArgumentsObjectArg(MInArgumentsObjectArg* ins) { 462 MDefinition* argsObj = ins->argsObject(); 463 MOZ_ASSERT(argsObj->type() == MIRType::Object); 464 465 MDefinition* index = ins->index(); 466 MOZ_ASSERT(index->type() == MIRType::Int32); 467 468 auto* lir = new (alloc()) 469 LInArgumentsObjectArg(useRegister(argsObj), useRegister(index), temp()); 470 assignSnapshot(lir, ins->bailoutKind()); 471 define(lir, ins); 472 } 473 474 void LIRGenerator::visitArgumentsObjectLength(MArgumentsObjectLength* ins) { 475 MDefinition* argsObj = ins->argsObject(); 476 MOZ_ASSERT(argsObj->type() == MIRType::Object); 477 478 auto* lir = new (alloc()) LArgumentsObjectLength(useRegister(argsObj)); 479 assignSnapshot(lir, ins->bailoutKind()); 480 define(lir, ins); 481 } 482 483 void LIRGenerator::visitArrayFromArgumentsObject( 484 MArrayFromArgumentsObject* ins) { 485 MDefinition* argsObj = ins->argsObject(); 486 MOZ_ASSERT(argsObj->type() == MIRType::Object); 487 488 auto* lir = 489 new (alloc()) LArrayFromArgumentsObject(useRegisterAtStart(argsObj)); 490 defineReturn(lir, ins); 491 assignSafepoint(lir, ins); 492 } 493 494 void LIRGenerator::visitGuardArgumentsObjectFlags( 495 MGuardArgumentsObjectFlags* ins) { 496 MDefinition* argsObj = ins->argsObject(); 497 MOZ_ASSERT(argsObj->type() == MIRType::Object); 498 499 auto* lir = 500 new (alloc()) LGuardArgumentsObjectFlags(useRegister(argsObj), temp()); 501 assignSnapshot(lir, ins->bailoutKind()); 502 add(lir, ins); 503 redefine(ins, argsObj); 504 } 505 506 void LIRGenerator::visitGuardObjectHasSameRealm(MGuardObjectHasSameRealm* ins) { 507 MDefinition* obj = ins->object(); 508 MOZ_ASSERT(obj->type() == MIRType::Object); 509 510 auto* lir = new (alloc()) LGuardObjectHasSameRealm(useRegister(obj), temp()); 511 assignSnapshot(lir, ins->bailoutKind()); 512 add(lir, ins); 513 redefine(ins, obj); 514 } 515 516 void LIRGenerator::visitBoundFunctionNumArgs(MBoundFunctionNumArgs* ins) { 517 MDefinition* obj = ins->object(); 518 MOZ_ASSERT(obj->type() == MIRType::Object); 519 520 auto* lir = new (alloc()) LBoundFunctionNumArgs(useRegisterAtStart(obj)); 521 define(lir, ins); 522 } 523 524 void LIRGenerator::visitGuardBoundFunctionIsConstructor( 525 MGuardBoundFunctionIsConstructor* ins) { 526 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 527 528 auto* lir = new (alloc()) 529 LGuardBoundFunctionIsConstructor(useRegister(ins->object())); 530 assignSnapshot(lir, ins->bailoutKind()); 531 add(lir, ins); 532 redefine(ins, ins->object()); 533 } 534 535 void LIRGenerator::visitReturnFromCtor(MReturnFromCtor* ins) { 536 LReturnFromCtor* lir = new (alloc()) 537 LReturnFromCtor(useBox(ins->value()), useRegister(ins->object())); 538 define(lir, ins); 539 } 540 541 void LIRGenerator::visitBoxNonStrictThis(MBoxNonStrictThis* ins) { 542 MOZ_ASSERT(ins->type() == MIRType::Object); 543 MOZ_ASSERT(ins->input()->type() == MIRType::Value); 544 545 auto* lir = new (alloc()) LBoxNonStrictThis(useBox(ins->input())); 546 define(lir, ins); 547 assignSafepoint(lir, ins); 548 } 549 550 void LIRGenerator::visitImplicitThis(MImplicitThis* ins) { 551 MDefinition* env = ins->env(); 552 MOZ_ASSERT(env->type() == MIRType::Object); 553 554 auto* lir = new (alloc()) LImplicitThis(useRegister(env)); 555 defineBox(lir, ins); 556 assignSafepoint(lir, ins); 557 } 558 559 template <typename T> 560 bool LIRGenerator::lowerCallArguments(T* call) { 561 uint32_t argc = call->numStackArgs(); 562 563 // Align the arguments of a call such that the callee would keep the same 564 // alignment as the caller. 565 uint32_t baseSlot = 0; 566 if (JitStackValueAlignment > 1) { 567 baseSlot = AlignBytes(argc, JitStackValueAlignment); 568 } else { 569 baseSlot = argc; 570 } 571 572 // Save the maximum number of argument, such that we can have one unique 573 // frame size. 574 if (baseSlot > maxargslots_) { 575 maxargslots_ = baseSlot; 576 } 577 578 for (size_t i = 0; i < argc; i++) { 579 MDefinition* arg = call->getArg(i); 580 uint32_t argslot = baseSlot - i; 581 582 // Values take a slow path. 583 if (arg->type() == MIRType::Value) { 584 LStackArgV* stack = new (alloc()) LStackArgV(useBox(arg), argslot); 585 add(stack); 586 } else { 587 // Known types can move constant types and/or payloads. 588 LStackArgT* stack = new (alloc()) 589 LStackArgT(useRegisterOrConstant(arg), argslot, arg->type()); 590 add(stack); 591 } 592 593 if (!alloc().ensureBallast()) { 594 return false; 595 } 596 } 597 return true; 598 } 599 600 void LIRGenerator::visitCall(MCall* call) { 601 MOZ_ASSERT(call->getCallee()->type() == MIRType::Object); 602 603 // In case of oom, skip the rest of the allocations. 604 if (!lowerCallArguments(call)) { 605 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitCall"); 606 return; 607 } 608 609 WrappedFunction* target = call->getSingleTarget(); 610 611 LInstruction* lir; 612 613 if (call->isCallDOMNative()) { 614 // Call DOM functions. 615 MOZ_ASSERT(target && target->isNativeWithoutJitEntry()); 616 Register cxReg, objReg, privReg, argsReg; 617 GetTempRegForIntArg(0, 0, &cxReg); 618 GetTempRegForIntArg(1, 0, &objReg); 619 GetTempRegForIntArg(2, 0, &privReg); 620 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &argsReg); 621 MOZ_ASSERT(ok, "How can we not have four temp registers?"); 622 lir = new (alloc()) LCallDOMNative(tempFixed(cxReg), tempFixed(objReg), 623 tempFixed(privReg), tempFixed(argsReg)); 624 } else if (target) { 625 // Call known functions. 626 if (target->isNativeWithoutJitEntry()) { 627 Register cxReg, numReg, vpReg, tmpReg; 628 GetTempRegForIntArg(0, 0, &cxReg); 629 GetTempRegForIntArg(1, 0, &numReg); 630 GetTempRegForIntArg(2, 0, &vpReg); 631 632 // Even though this is just a temp reg, use the same API to avoid 633 // register collisions. 634 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg); 635 MOZ_ASSERT(ok, "How can we not have four temp registers?"); 636 637 lir = new (alloc()) LCallNative(tempFixed(cxReg), tempFixed(numReg), 638 tempFixed(vpReg), tempFixed(tmpReg)); 639 } else { 640 lir = new (alloc()) LCallKnown(useRegisterAtStart(call->getCallee()), 641 tempFixed(CallTempReg0)); 642 } 643 } else { 644 // Call anything, using the most generic code. 645 lir = new (alloc()) LCallGeneric( 646 useFixedAtStart(call->getCallee(), IonGenericCallCalleeReg), 647 tempFixed(IonGenericCallArgcReg)); 648 } 649 defineReturn(lir, call); 650 assignSafepoint(lir, call); 651 } 652 653 void LIRGenerator::visitCallClassHook(MCallClassHook* call) { 654 MDefinition* callee = call->getCallee(); 655 MOZ_ASSERT(callee->type() == MIRType::Object); 656 657 // In case of oom, skip the rest of the allocations. 658 if (!lowerCallArguments(call)) { 659 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitCallClassHook"); 660 return; 661 } 662 663 Register cxReg, numReg, vpReg, tmpReg; 664 GetTempRegForIntArg(0, 0, &cxReg); 665 GetTempRegForIntArg(1, 0, &numReg); 666 GetTempRegForIntArg(2, 0, &vpReg); 667 668 // Even though this is just a temp reg, use the same API to avoid 669 // register collisions. 670 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg); 671 MOZ_ASSERT(ok, "How can we not have four temp registers?"); 672 673 auto* lir = new (alloc()) 674 LCallClassHook(useRegisterAtStart(callee), tempFixed(cxReg), 675 tempFixed(numReg), tempFixed(vpReg), tempFixed(tmpReg)); 676 defineReturn(lir, call); 677 assignSafepoint(lir, call); 678 } 679 680 void LIRGenerator::visitApplyArgs(MApplyArgs* apply) { 681 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object); 682 683 // Assert if the return value is already erased. 684 static_assert(CallTempReg2 != JSReturnReg_Type); 685 static_assert(CallTempReg2 != JSReturnReg_Data); 686 687 auto argc = useFixedAtStart(apply->getArgc(), CallTempReg0); 688 auto thisValue = 689 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5); 690 auto tempObj = tempFixed(CallTempReg1); // object register 691 auto tempCopy = tempFixed(CallTempReg2); // copy register 692 693 auto* target = apply->getSingleTarget(); 694 695 LInstruction* lir; 696 if (target && target->isNativeWithoutJitEntry()) { 697 auto temp = tempFixed(CallTempReg3); 698 699 lir = new (alloc()) 700 LApplyArgsNative(argc, thisValue, tempObj, tempCopy, temp); 701 } else { 702 auto function = useFixedAtStart(apply->getFunction(), CallTempReg3); 703 704 lir = new (alloc()) 705 LApplyArgsGeneric(function, argc, thisValue, tempObj, tempCopy); 706 lirGraph_.addExtraSafepointUses(1); 707 } 708 709 // Bailout is needed in the case of too many values in the arguments array. 710 assignSnapshot(lir, apply->bailoutKind()); 711 712 defineReturn(lir, apply); 713 assignSafepoint(lir, apply); 714 } 715 716 void LIRGenerator::visitApplyArgsObj(MApplyArgsObj* apply) { 717 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object); 718 719 // Assert if the return value is already erased. 720 static_assert(CallTempReg2 != JSReturnReg_Type); 721 static_assert(CallTempReg2 != JSReturnReg_Data); 722 723 auto argsObj = useFixedAtStart(apply->getArgsObj(), CallTempReg0); 724 auto thisValue = 725 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5); 726 auto tempObj = tempFixed(CallTempReg1); // object register 727 auto tempCopy = tempFixed(CallTempReg2); // copy register 728 729 auto* target = apply->getSingleTarget(); 730 731 LInstruction* lir; 732 if (target && target->isNativeWithoutJitEntry()) { 733 auto temp = tempFixed(CallTempReg3); 734 735 lir = new (alloc()) 736 LApplyArgsObjNative(argsObj, thisValue, tempObj, tempCopy, temp); 737 } else { 738 auto function = useFixedAtStart(apply->getFunction(), CallTempReg3); 739 740 lir = new (alloc()) 741 LApplyArgsObj(function, argsObj, thisValue, tempObj, tempCopy); 742 lirGraph_.addExtraSafepointUses(1); 743 } 744 745 // Bailout is needed in the case of too many values in the arguments array. 746 assignSnapshot(lir, apply->bailoutKind()); 747 748 defineReturn(lir, apply); 749 assignSafepoint(lir, apply); 750 } 751 752 void LIRGenerator::visitApplyArray(MApplyArray* apply) { 753 MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object); 754 755 // Assert if the return value is already erased. 756 static_assert(CallTempReg2 != JSReturnReg_Type); 757 static_assert(CallTempReg2 != JSReturnReg_Data); 758 759 auto elements = useFixedAtStart(apply->getElements(), CallTempReg0); 760 auto thisValue = 761 useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5); 762 auto tempObj = tempFixed(CallTempReg1); // object register 763 auto tempCopy = tempFixed(CallTempReg2); // copy register 764 765 auto* target = apply->getSingleTarget(); 766 767 LInstruction* lir; 768 if (target && target->isNativeWithoutJitEntry()) { 769 auto temp = tempFixed(CallTempReg3); 770 771 lir = new (alloc()) 772 LApplyArrayNative(elements, thisValue, tempObj, tempCopy, temp); 773 } else { 774 auto function = useFixedAtStart(apply->getFunction(), CallTempReg3); 775 776 lir = new (alloc()) 777 LApplyArrayGeneric(function, elements, thisValue, tempObj, tempCopy); 778 lirGraph_.addExtraSafepointUses(1); 779 } 780 781 // Bailout is needed in the case of too many values in the array, or empty 782 // space at the end of the array. 783 assignSnapshot(lir, apply->bailoutKind()); 784 785 defineReturn(lir, apply); 786 assignSafepoint(lir, apply); 787 } 788 789 void LIRGenerator::visitConstructArgs(MConstructArgs* mir) { 790 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object); 791 MOZ_ASSERT(mir->getArgc()->type() == MIRType::Int32); 792 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object); 793 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value); 794 795 // Assert if the return value is already erased. 796 static_assert(CallTempReg2 != JSReturnReg_Type); 797 static_assert(CallTempReg2 != JSReturnReg_Data); 798 799 auto argc = useFixedAtStart(mir->getArgc(), CallTempReg0); 800 auto newTarget = useFixedAtStart(mir->getNewTarget(), CallTempReg1); 801 auto temp = tempFixed(CallTempReg2); 802 803 auto* target = mir->getSingleTarget(); 804 805 LInstruction* lir; 806 if (target && target->isNativeWithoutJitEntry()) { 807 auto temp2 = tempFixed(CallTempReg3); 808 auto temp3 = tempFixed(CallTempReg4); 809 810 lir = 811 new (alloc()) LConstructArgsNative(argc, newTarget, temp, temp2, temp3); 812 } else { 813 auto function = useFixedAtStart(mir->getFunction(), CallTempReg3); 814 auto thisValue = 815 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5); 816 817 lir = new (alloc()) 818 LConstructArgsGeneric(function, argc, newTarget, thisValue, temp); 819 lirGraph_.addExtraSafepointUses(1); 820 } 821 822 // Bailout is needed in the case of too many values in the arguments array. 823 assignSnapshot(lir, mir->bailoutKind()); 824 825 defineReturn(lir, mir); 826 assignSafepoint(lir, mir); 827 } 828 829 void LIRGenerator::visitConstructArray(MConstructArray* mir) { 830 MOZ_ASSERT(mir->getFunction()->type() == MIRType::Object); 831 MOZ_ASSERT(mir->getElements()->type() == MIRType::Elements); 832 MOZ_ASSERT(mir->getNewTarget()->type() == MIRType::Object); 833 MOZ_ASSERT(mir->getThis()->type() == MIRType::Value); 834 835 // Assert if the return value is already erased. 836 static_assert(CallTempReg2 != JSReturnReg_Type); 837 static_assert(CallTempReg2 != JSReturnReg_Data); 838 839 auto elements = useFixedAtStart(mir->getElements(), CallTempReg0); 840 auto newTarget = useFixedAtStart(mir->getNewTarget(), CallTempReg1); 841 auto temp = tempFixed(CallTempReg2); 842 843 auto* target = mir->getSingleTarget(); 844 845 LInstruction* lir; 846 if (target && target->isNativeWithoutJitEntry()) { 847 auto temp2 = tempFixed(CallTempReg3); 848 auto temp3 = tempFixed(CallTempReg4); 849 850 lir = new (alloc()) 851 LConstructArrayNative(elements, newTarget, temp, temp2, temp3); 852 } else { 853 auto function = useFixedAtStart(mir->getFunction(), CallTempReg3); 854 auto thisValue = 855 useBoxFixedAtStart(mir->getThis(), CallTempReg4, CallTempReg5); 856 857 lir = new (alloc()) 858 LConstructArrayGeneric(function, elements, newTarget, thisValue, temp); 859 lirGraph_.addExtraSafepointUses(1); 860 } 861 862 // Bailout is needed in the case of too many values in the array, or empty 863 // space at the end of the array. 864 assignSnapshot(lir, mir->bailoutKind()); 865 866 defineReturn(lir, mir); 867 assignSafepoint(lir, mir); 868 } 869 870 void LIRGenerator::visitBail(MBail* bail) { 871 LBail* lir = new (alloc()) LBail(); 872 assignSnapshot(lir, bail->bailoutKind()); 873 add(lir, bail); 874 } 875 876 void LIRGenerator::visitUnreachable(MUnreachable* unreachable) { 877 LUnreachable* lir = new (alloc()) LUnreachable(); 878 add(lir, unreachable); 879 } 880 881 void LIRGenerator::visitEncodeSnapshot(MEncodeSnapshot* mir) { 882 LEncodeSnapshot* lir = new (alloc()) LEncodeSnapshot(); 883 assignSnapshot(lir, mir->bailoutKind()); 884 add(lir, mir); 885 } 886 887 void LIRGenerator::visitUnreachableResult(MUnreachableResult* mir) { 888 if (mir->type() == MIRType::Value) { 889 auto* lir = new (alloc()) LUnreachableResultV(); 890 defineBox(lir, mir); 891 } else { 892 auto* lir = new (alloc()) LUnreachableResultT(); 893 define(lir, mir); 894 } 895 } 896 897 void LIRGenerator::visitAssertFloat32(MAssertFloat32* assertion) { 898 MIRType type = assertion->input()->type(); 899 DebugOnly<bool> checkIsFloat32 = assertion->mustBeFloat32(); 900 901 if (type != MIRType::Value && !JitOptions.eagerIonCompilation()) { 902 MOZ_ASSERT_IF(checkIsFloat32, type == MIRType::Float32); 903 MOZ_ASSERT_IF(!checkIsFloat32, type != MIRType::Float32); 904 } 905 } 906 907 void LIRGenerator::visitAssertRecoveredOnBailout( 908 MAssertRecoveredOnBailout* assertion) { 909 MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts."); 910 } 911 912 [[nodiscard]] static JSOp ReorderComparison(JSOp op, MDefinition** lhsp, 913 MDefinition** rhsp) { 914 MDefinition* lhs = *lhsp; 915 MDefinition* rhs = *rhsp; 916 917 if (lhs->maybeConstantValue()) { 918 *rhsp = lhs; 919 *lhsp = rhs; 920 return ReverseCompareOp(op); 921 } 922 return op; 923 } 924 925 void LIRGenerator::visitTest(MTest* test) { 926 MDefinition* opd = test->getOperand(0); 927 MBasicBlock* ifTrue = test->ifTrue(); 928 MBasicBlock* ifFalse = test->ifFalse(); 929 930 // String is converted to length of string in the type analysis phase (see 931 // TestPolicy). 932 MOZ_ASSERT(opd->type() != MIRType::String); 933 934 // Testing a constant. 935 if (MConstant* constant = opd->maybeConstantValue()) { 936 bool b; 937 if (constant->valueToBoolean(&b)) { 938 add(new (alloc()) LGoto(b ? ifTrue : ifFalse)); 939 return; 940 } 941 } 942 943 if (opd->type() == MIRType::Value) { 944 auto* lir = new (alloc()) LTestVAndBranch( 945 ifTrue, ifFalse, useBox(opd), tempDouble(), tempToUnbox(), temp()); 946 add(lir, test); 947 return; 948 } 949 950 // Objects are truthy, except if it might emulate undefined. 951 if (opd->type() == MIRType::Object) { 952 add(new (alloc()) 953 LTestOAndBranch(ifTrue, ifFalse, useRegister(opd), temp()), 954 test); 955 return; 956 } 957 958 // These must be explicitly sniffed out since they are constants and have 959 // no payload. 960 if (opd->type() == MIRType::Undefined || opd->type() == MIRType::Null) { 961 add(new (alloc()) LGoto(ifFalse)); 962 return; 963 } 964 965 // All symbols are truthy. 966 if (opd->type() == MIRType::Symbol) { 967 add(new (alloc()) LGoto(ifTrue)); 968 return; 969 } 970 971 // Try to match the pattern 972 // test=MTest( 973 // comp=MCompare( 974 // {EQ,NE} for {Int,UInt}{32,64}, 975 // bitAnd={MBitAnd,MWasmBinaryBitwise(And{32,64})}(x, y), 976 // MConstant(0) 977 // ) 978 // ) 979 // and produce a single LBitAnd{,64}AndBranch node. This requires both `comp` 980 // and `bitAnd` to be marked emit-at-uses. 981 if (opd->isCompare() && opd->isEmittedAtUses()) { 982 MCompare* comp = opd->toCompare(); 983 Assembler::Condition compCond = 984 JSOpToCondition(comp->compareType(), comp->jsop()); 985 MDefinition* compL = comp->lhs(); 986 MDefinition* compR = comp->rhs(); 987 if ((comp->compareType() == MCompare::Compare_Int32 || 988 comp->compareType() == MCompare::Compare_UInt32 || 989 (comp->compareType() == MCompare::Compare_Int64) || 990 (comp->compareType() == MCompare::Compare_UInt64)) && 991 (compCond == Assembler::Equal || compCond == Assembler::NotEqual) && 992 compR->isConstant() && 993 (compR->toConstant()->isInt32(0) || 994 (compR->toConstant()->isInt64(0))) && 995 (compL->isBitAnd() || (compL->isWasmBinaryBitwise() && 996 compL->toWasmBinaryBitwise()->subOpcode() == 997 MWasmBinaryBitwise::SubOpcode::And))) { 998 // The MCompare is OK; now check its first operand (the and-ish node). 999 MDefinition* bitAnd = compL; 1000 MDefinition* bitAndL = bitAnd->getOperand(0); 1001 MDefinition* bitAndR = bitAnd->getOperand(1); 1002 MIRType bitAndLTy = bitAndL->type(); 1003 MIRType bitAndRTy = bitAndR->type(); 1004 if (bitAnd->isEmittedAtUses() && bitAndLTy == bitAndRTy && 1005 (bitAndLTy == MIRType::Int32 || (bitAndLTy == MIRType::Int64))) { 1006 // Pattern match succeeded. 1007 ReorderCommutative(&bitAndL, &bitAndR, test); 1008 if (compCond == Assembler::Equal) { 1009 compCond = Assembler::Zero; 1010 } else if (compCond == Assembler::NotEqual) { 1011 compCond = Assembler::NonZero; 1012 } else { 1013 MOZ_ASSERT_UNREACHABLE("inequality operators cannot be folded"); 1014 } 1015 1016 if (bitAndLTy == MIRType::Int64) { 1017 auto lhs = useInt64RegisterAtStart(bitAndL); 1018 auto rhs = useInt64RegisterOrConstantAtStart(bitAndR); 1019 auto* lir = new (alloc()) 1020 LBitAnd64AndBranch(ifTrue, ifFalse, lhs, rhs, compCond); 1021 add(lir, test); 1022 return; 1023 } 1024 1025 LAllocation lhs = useRegisterAtStart(bitAndL); 1026 LAllocation rhs = useRegisterOrConstantAtStart(bitAndR); 1027 auto* lir = 1028 new (alloc()) LBitAndAndBranch(ifTrue, ifFalse, lhs, rhs, compCond); 1029 add(lir, test); 1030 return; 1031 } 1032 } 1033 } 1034 1035 // Check if the operand for this test is a compare operation. If it is, we 1036 // want to emit an LCompare*AndBranch rather than an LTest*AndBranch, to fuse 1037 // the compare and jump instructions. 1038 if (opd->isCompare() && opd->isEmittedAtUses()) { 1039 MCompare* comp = opd->toCompare(); 1040 MDefinition* left = comp->lhs(); 1041 MDefinition* right = comp->rhs(); 1042 1043 // Try to fold the comparison so that we don't have to handle all cases. 1044 bool result; 1045 if (comp->tryFold(&result)) { 1046 add(new (alloc()) LGoto(result ? ifTrue : ifFalse)); 1047 return; 1048 } 1049 1050 // Emit LCompare*AndBranch. 1051 1052 // Compare and branch null/undefined. 1053 // The second operand has known null/undefined type, 1054 // so just test the first operand. 1055 if (comp->compareType() == MCompare::Compare_Null || 1056 comp->compareType() == MCompare::Compare_Undefined) { 1057 if (left->type() == MIRType::Object) { 1058 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchT( 1059 ifTrue, ifFalse, useRegister(left), temp(), comp); 1060 add(lir, test); 1061 return; 1062 } 1063 1064 if (IsLooseEqualityOp(comp->jsop())) { 1065 auto* lir = new (alloc()) LIsNullOrLikeUndefinedAndBranchV( 1066 ifTrue, ifFalse, useBox(left), temp(), tempToUnbox(), comp); 1067 add(lir, test); 1068 return; 1069 } 1070 1071 if (comp->compareType() == MCompare::Compare_Null) { 1072 auto* lir = 1073 new (alloc()) LIsNullAndBranch(ifTrue, ifFalse, useBox(left), comp); 1074 add(lir, test); 1075 return; 1076 } 1077 1078 auto* lir = new (alloc()) 1079 LIsUndefinedAndBranch(ifTrue, ifFalse, useBox(left), comp); 1080 add(lir, test); 1081 return; 1082 } 1083 1084 // Compare and branch Int32, Symbol, Object, or WasmAnyRef pointers. 1085 if (comp->isInt32Comparison() || 1086 comp->compareType() == MCompare::Compare_UInt32 || 1087 comp->compareType() == MCompare::Compare_IntPtr || 1088 comp->compareType() == MCompare::Compare_UIntPtr || 1089 comp->compareType() == MCompare::Compare_Object || 1090 comp->compareType() == MCompare::Compare_Symbol || 1091 comp->compareType() == MCompare::Compare_WasmAnyRef) { 1092 JSOp op = ReorderComparison(comp->jsop(), &left, &right); 1093 LAllocation lhs = useRegister(left); 1094 LAllocation rhs; 1095 if (comp->isInt32Comparison() || 1096 comp->compareType() == MCompare::Compare_UInt32 || 1097 comp->compareType() == MCompare::Compare_IntPtr || 1098 comp->compareType() == MCompare::Compare_UIntPtr) { 1099 rhs = useAnyOrInt32Constant(right); 1100 } else { 1101 rhs = useAny(right); 1102 } 1103 auto* lir = 1104 new (alloc()) LCompareAndBranch(ifTrue, ifFalse, lhs, rhs, comp, op); 1105 add(lir, test); 1106 return; 1107 } 1108 1109 // Compare and branch Int64. 1110 if (comp->compareType() == MCompare::Compare_Int64 || 1111 comp->compareType() == MCompare::Compare_UInt64) { 1112 JSOp op = ReorderComparison(comp->jsop(), &left, &right); 1113 LInt64Allocation lhs = useInt64Register(left); 1114 LInt64Allocation rhs = useInt64OrConstant(right); 1115 auto* lir = new (alloc()) 1116 LCompareI64AndBranch(ifTrue, ifFalse, lhs, rhs, comp, op); 1117 add(lir, test); 1118 return; 1119 } 1120 1121 // Compare and branch doubles. 1122 if (comp->isDoubleComparison()) { 1123 LAllocation lhs = useRegister(left); 1124 LAllocation rhs = useRegister(right); 1125 auto* lir = 1126 new (alloc()) LCompareDAndBranch(ifTrue, ifFalse, lhs, rhs, comp); 1127 add(lir, test); 1128 return; 1129 } 1130 1131 // Compare and branch floats. 1132 if (comp->isFloat32Comparison()) { 1133 LAllocation lhs = useRegister(left); 1134 LAllocation rhs = useRegister(right); 1135 auto* lir = 1136 new (alloc()) LCompareFAndBranch(ifTrue, ifFalse, lhs, rhs, comp); 1137 add(lir, test); 1138 return; 1139 } 1140 1141 // Compare and branch BigInt with Int32. 1142 if (comp->compareType() == MCompare::Compare_BigInt_Int32) { 1143 LAllocation lhs = useRegister(left); 1144 LAllocation rhs = useRegisterOrInt32Constant(right); 1145 LDefinition temp1 = temp(); 1146 LDefinition temp2 = !rhs.isConstant() ? temp() : LDefinition::BogusTemp(); 1147 auto* lir = new (alloc()) LCompareBigIntInt32AndBranch( 1148 ifTrue, ifFalse, lhs, rhs, temp1, temp2, comp); 1149 add(lir, test); 1150 return; 1151 } 1152 } 1153 1154 // Check if the operand for this test is a bitand operation. If it is, we want 1155 // to emit an LBitAndAndBranch rather than an LTest*AndBranch. 1156 if (opd->isBitAnd() && opd->isEmittedAtUses()) { 1157 MBitAnd* bitAnd = opd->toBitAnd(); 1158 MDefinition* left = bitAnd->lhs(); 1159 MDefinition* right = bitAnd->rhs(); 1160 if (left->type() == MIRType::Int32 && right->type() == MIRType::Int32) { 1161 ReorderCommutative(&left, &right, test); 1162 LAllocation lhs = useRegisterAtStart(left); 1163 LAllocation rhs = useRegisterOrConstantAtStart(right); 1164 auto* lir = new (alloc()) 1165 LBitAndAndBranch(ifTrue, ifFalse, lhs, rhs, Assembler::NonZero); 1166 add(lir, test); 1167 return; 1168 } 1169 } 1170 1171 #if defined(ENABLE_WASM_SIMD) && \ 1172 (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || \ 1173 defined(JS_CODEGEN_ARM64)) 1174 // Check if the operand for this test is an any_true/all_true SIMD operation. 1175 // If it is, we want to emit an LWasmReduceAndBranchSimd128 node to avoid 1176 // generating an intermediate boolean result. 1177 if (opd->isWasmReduceSimd128() && opd->isEmittedAtUses()) { 1178 MWasmReduceSimd128* node = opd->toWasmReduceSimd128(); 1179 if (canFoldReduceSimd128AndBranch(node->simdOp())) { 1180 # ifdef DEBUG 1181 js::wasm::ReportSimdAnalysis("simd128-to-scalar-and-branch -> folded"); 1182 # endif 1183 auto* lir = new (alloc()) LWasmReduceAndBranchSimd128( 1184 ifTrue, ifFalse, useRegister(node->input()), node->simdOp()); 1185 add(lir, test); 1186 return; 1187 } 1188 } 1189 #endif 1190 1191 if (opd->isIsObject() && opd->isEmittedAtUses()) { 1192 MDefinition* input = opd->toIsObject()->input(); 1193 MOZ_ASSERT(input->type() == MIRType::Value); 1194 1195 LIsObjectAndBranch* lir = 1196 new (alloc()) LIsObjectAndBranch(ifTrue, ifFalse, useBoxAtStart(input)); 1197 add(lir, test); 1198 return; 1199 } 1200 1201 if (opd->isWasmRefTestAbstract() && opd->isEmittedAtUses()) { 1202 MWasmRefTestAbstract* refTest = opd->toWasmRefTestAbstract(); 1203 1204 LAllocation ref = useRegister(refTest->ref()); 1205 WasmRefIsSubtypeDefs regs = 1206 useWasmRefIsSubtype(refTest->destType(), /*superSTV=*/nullptr); 1207 add(new (alloc()) LWasmRefTestAbstractAndBranch( 1208 ifTrue, ifFalse, ref, regs.scratch1, refTest->ref()->wasmRefType(), 1209 refTest->destType()), 1210 test); 1211 return; 1212 } 1213 1214 if (opd->isWasmRefTestConcrete() && opd->isEmittedAtUses()) { 1215 MWasmRefTestConcrete* refTest = opd->toWasmRefTestConcrete(); 1216 1217 LAllocation ref = useRegister(refTest->ref()); 1218 WasmRefIsSubtypeDefs regs = 1219 useWasmRefIsSubtype(refTest->destType(), refTest->superSTV()); 1220 add(new (alloc()) LWasmRefTestConcreteAndBranch( 1221 ifTrue, ifFalse, ref, regs.superSTV, regs.scratch1, regs.scratch2, 1222 refTest->ref()->wasmRefType(), refTest->destType()), 1223 test); 1224 return; 1225 } 1226 1227 if (opd->isIsNullOrUndefined() && opd->isEmittedAtUses()) { 1228 MIsNullOrUndefined* isNullOrUndefined = opd->toIsNullOrUndefined(); 1229 MDefinition* input = isNullOrUndefined->value(); 1230 1231 if (input->type() == MIRType::Value) { 1232 auto* lir = new (alloc()) 1233 LIsNullOrUndefinedAndBranch(ifTrue, ifFalse, useBoxAtStart(input)); 1234 add(lir, test); 1235 } else { 1236 auto* target = IsNullOrUndefined(input->type()) ? ifTrue : ifFalse; 1237 add(new (alloc()) LGoto(target)); 1238 } 1239 return; 1240 } 1241 1242 if (opd->isStrictConstantCompareInt32() && opd->isEmittedAtUses()) { 1243 auto* comp = opd->toStrictConstantCompareInt32(); 1244 auto* value = comp->value(); 1245 1246 auto* lir = new (alloc()) LStrictConstantCompareInt32AndBranch( 1247 ifTrue, ifFalse, useBoxAtStart(value), comp); 1248 add(lir, test); 1249 return; 1250 } 1251 1252 if (opd->isStrictConstantCompareBoolean() && opd->isEmittedAtUses()) { 1253 auto* comp = opd->toStrictConstantCompareBoolean(); 1254 auto* value = comp->value(); 1255 1256 auto* lir = new (alloc()) LStrictConstantCompareBooleanAndBranch( 1257 ifTrue, ifFalse, useBoxAtStart(value), comp); 1258 add(lir, test); 1259 return; 1260 } 1261 1262 if (opd->isIsNoIter()) { 1263 MOZ_ASSERT(opd->isEmittedAtUses()); 1264 1265 MDefinition* input = opd->toIsNoIter()->input(); 1266 MOZ_ASSERT(input->type() == MIRType::Value); 1267 1268 LIsNoIterAndBranch* lir = 1269 new (alloc()) LIsNoIterAndBranch(ifTrue, ifFalse, useBox(input)); 1270 add(lir, test); 1271 return; 1272 } 1273 1274 if (opd->isIteratorHasIndices()) { 1275 MOZ_ASSERT(opd->isEmittedAtUses()); 1276 1277 MDefinition* object = opd->toIteratorHasIndices()->object(); 1278 MDefinition* iterator = opd->toIteratorHasIndices()->iterator(); 1279 LIteratorHasIndicesAndBranch* lir = new (alloc()) 1280 LIteratorHasIndicesAndBranch(ifTrue, ifFalse, useRegister(object), 1281 useRegister(iterator), temp(), temp()); 1282 add(lir, test); 1283 return; 1284 } 1285 1286 if (opd->isIteratorsMatchAndHaveIndices()) { 1287 MOZ_ASSERT(opd->isEmittedAtUses()); 1288 1289 MDefinition* object = opd->toIteratorsMatchAndHaveIndices()->object(); 1290 MDefinition* iterator = opd->toIteratorsMatchAndHaveIndices()->iterator(); 1291 MDefinition* otherIterator = 1292 opd->toIteratorsMatchAndHaveIndices()->otherIterator(); 1293 LIteratorsMatchAndHaveIndicesAndBranch* lir = 1294 new (alloc()) LIteratorsMatchAndHaveIndicesAndBranch( 1295 ifTrue, ifFalse, useRegister(object), useRegister(iterator), 1296 useRegister(otherIterator), temp(), temp()); 1297 add(lir, test); 1298 return; 1299 } 1300 1301 switch (opd->type()) { 1302 case MIRType::Double: 1303 add(new (alloc()) LTestDAndBranch(ifTrue, ifFalse, useRegister(opd))); 1304 break; 1305 case MIRType::Float32: 1306 add(new (alloc()) LTestFAndBranch(ifTrue, ifFalse, useRegister(opd))); 1307 break; 1308 case MIRType::Int32: 1309 case MIRType::Boolean: 1310 add(new (alloc()) LTestIAndBranch(ifTrue, ifFalse, useRegister(opd))); 1311 break; 1312 case MIRType::IntPtr: 1313 add(new (alloc()) LTestIPtrAndBranch(ifTrue, ifFalse, useRegister(opd))); 1314 break; 1315 case MIRType::Int64: 1316 add(new (alloc()) 1317 LTestI64AndBranch(ifTrue, ifFalse, useInt64Register(opd))); 1318 break; 1319 case MIRType::BigInt: 1320 add(new (alloc()) LTestBIAndBranch(ifTrue, ifFalse, useRegister(opd))); 1321 break; 1322 default: 1323 MOZ_CRASH("Bad type"); 1324 } 1325 } 1326 1327 static inline bool CanEmitCompareAtUses(MInstruction* ins) { 1328 if (!ins->canEmitAtUses()) { 1329 return false; 1330 } 1331 1332 // If the result is never used, we can usefully defer emission to the use 1333 // point, since that will never happen. 1334 MUseIterator iter(ins->usesBegin()); 1335 if (iter == ins->usesEnd()) { 1336 return true; 1337 } 1338 1339 // If the first use isn't of the expected form, the answer is No. 1340 MNode* node = iter->consumer(); 1341 if (!node->isDefinition()) { 1342 return false; 1343 } 1344 1345 MDefinition* use = node->toDefinition(); 1346 if (!use->isTest() && !use->isWasmSelect()) { 1347 return false; 1348 } 1349 1350 // Emission can be deferred to the first use point, but only if there are no 1351 // other use points. 1352 iter++; 1353 return iter == ins->usesEnd(); 1354 } 1355 1356 void LIRGenerator::visitCompare(MCompare* comp) { 1357 MDefinition* left = comp->lhs(); 1358 MDefinition* right = comp->rhs(); 1359 1360 // Try to fold the comparison so that we don't have to handle all cases. 1361 bool result; 1362 if (comp->tryFold(&result)) { 1363 define(new (alloc()) LInteger(result), comp); 1364 return; 1365 } 1366 1367 // Move below the emitAtUses call if we ever implement 1368 // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't 1369 // make sense and avoids confusion. 1370 if (comp->compareType() == MCompare::Compare_String) { 1371 MConstant* constant = nullptr; 1372 MDefinition* input = nullptr; 1373 if (left->isConstant()) { 1374 constant = left->toConstant(); 1375 input = right; 1376 } else if (right->isConstant()) { 1377 constant = right->toConstant(); 1378 input = left; 1379 } 1380 1381 if (constant) { 1382 JSOffThreadAtom* str = constant->toString(); 1383 1384 if (IsEqualityOp(comp->jsop())) { 1385 if (MacroAssembler::canCompareStringCharsInline(str)) { 1386 auto* lir = new (alloc()) LCompareSInline(useRegister(input), str); 1387 define(lir, comp); 1388 assignSafepoint(lir, comp); 1389 return; 1390 } 1391 } else { 1392 MOZ_ASSERT(IsRelationalOp(comp->jsop())); 1393 1394 if (str->length() == 1) { 1395 // Move the constant value into the right-hand side operand. 1396 JSOp op = comp->jsop(); 1397 if (left == constant) { 1398 op = ReverseCompareOp(op); 1399 } 1400 1401 auto* lir = new (alloc()) 1402 LCompareSSingle(useRegister(input), temp(), op, str); 1403 define(lir, comp); 1404 return; 1405 } 1406 } 1407 } 1408 1409 LCompareS* lir = 1410 new (alloc()) LCompareS(useRegister(left), useRegister(right)); 1411 define(lir, comp); 1412 assignSafepoint(lir, comp); 1413 return; 1414 } 1415 1416 // Compare two BigInts. 1417 if (comp->compareType() == MCompare::Compare_BigInt) { 1418 auto* lir = new (alloc()) LCompareBigInt( 1419 useRegister(left), useRegister(right), temp(), temp(), temp()); 1420 define(lir, comp); 1421 return; 1422 } 1423 1424 // Compare BigInt with Double. 1425 if (comp->compareType() == MCompare::Compare_BigInt_Double) { 1426 auto* lir = new (alloc()) LCompareBigIntDouble(useRegisterAtStart(left), 1427 useRegisterAtStart(right)); 1428 defineReturn(lir, comp); 1429 return; 1430 } 1431 1432 // Compare BigInt with String. 1433 if (comp->compareType() == MCompare::Compare_BigInt_String) { 1434 auto* lir = new (alloc()) LCompareBigIntString(useRegisterAtStart(left), 1435 useRegisterAtStart(right)); 1436 defineReturn(lir, comp); 1437 assignSafepoint(lir, comp); 1438 return; 1439 } 1440 1441 // Sniff out if the output of this compare is used only for a branching. 1442 // If it is, then we will emit an LCompare*AndBranch instruction in place 1443 // of this compare and any test that uses this compare. Thus, we can 1444 // ignore this Compare. 1445 if (CanEmitCompareAtUses(comp)) { 1446 emitAtUses(comp); 1447 return; 1448 } 1449 1450 // Compare Null and Undefined. 1451 if (comp->compareType() == MCompare::Compare_Null || 1452 comp->compareType() == MCompare::Compare_Undefined) { 1453 if (left->type() == MIRType::Object) { 1454 define(new (alloc()) LIsNullOrLikeUndefinedT(useRegister(left)), comp); 1455 return; 1456 } 1457 1458 if (IsLooseEqualityOp(comp->jsop())) { 1459 auto* lir = 1460 new (alloc()) LIsNullOrLikeUndefinedV(useBox(left), tempToUnbox()); 1461 define(lir, comp); 1462 return; 1463 } 1464 1465 if (comp->compareType() == MCompare::Compare_Null) { 1466 auto* lir = new (alloc()) LIsNull(useBox(left)); 1467 define(lir, comp); 1468 return; 1469 } 1470 1471 auto* lir = new (alloc()) LIsUndefined(useBox(left)); 1472 define(lir, comp); 1473 return; 1474 } 1475 1476 // Compare Int32, Symbol, Object or Wasm pointers. 1477 if (comp->isInt32Comparison() || 1478 comp->compareType() == MCompare::Compare_UInt32 || 1479 comp->compareType() == MCompare::Compare_IntPtr || 1480 comp->compareType() == MCompare::Compare_UIntPtr || 1481 comp->compareType() == MCompare::Compare_Object || 1482 comp->compareType() == MCompare::Compare_Symbol || 1483 comp->compareType() == MCompare::Compare_WasmAnyRef) { 1484 JSOp op = ReorderComparison(comp->jsop(), &left, &right); 1485 LAllocation lhs = useRegister(left); 1486 LAllocation rhs; 1487 if (comp->isInt32Comparison() || 1488 comp->compareType() == MCompare::Compare_UInt32 || 1489 comp->compareType() == MCompare::Compare_IntPtr || 1490 comp->compareType() == MCompare::Compare_UIntPtr) { 1491 rhs = useAnyOrInt32Constant(right); 1492 } else { 1493 rhs = useAny(right); 1494 } 1495 define(new (alloc()) LCompare(lhs, rhs, op), comp); 1496 return; 1497 } 1498 1499 // Compare Int64. 1500 if (comp->compareType() == MCompare::Compare_Int64 || 1501 comp->compareType() == MCompare::Compare_UInt64) { 1502 JSOp op = ReorderComparison(comp->jsop(), &left, &right); 1503 define(new (alloc()) LCompareI64(useInt64Register(left), 1504 useInt64OrConstant(right), op), 1505 comp); 1506 return; 1507 } 1508 1509 // Compare doubles. 1510 if (comp->isDoubleComparison()) { 1511 define(new (alloc()) LCompareD(useRegister(left), useRegister(right)), 1512 comp); 1513 return; 1514 } 1515 1516 // Compare float32. 1517 if (comp->isFloat32Comparison()) { 1518 define(new (alloc()) LCompareF(useRegister(left), useRegister(right)), 1519 comp); 1520 return; 1521 } 1522 1523 // Compare BigInt with Int32. 1524 if (comp->compareType() == MCompare::Compare_BigInt_Int32) { 1525 LAllocation lhs = useRegister(left); 1526 LAllocation rhs = useRegisterOrInt32Constant(right); 1527 LDefinition temp1 = temp(); 1528 LDefinition temp2 = !rhs.isConstant() ? temp() : LDefinition::BogusTemp(); 1529 auto* lir = new (alloc()) LCompareBigIntInt32(lhs, rhs, temp1, temp2); 1530 define(lir, comp); 1531 return; 1532 } 1533 1534 MOZ_CRASH("Unrecognized compare type."); 1535 } 1536 1537 void LIRGenerator::visitStrictConstantCompareInt32( 1538 MStrictConstantCompareInt32* ins) { 1539 // Prefer to emit fused compare-and-branch if possible. 1540 if (CanEmitCompareAtUses(ins)) { 1541 emitAtUses(ins); 1542 return; 1543 } 1544 1545 MDefinition* value = ins->value(); 1546 1547 auto* lir = new (alloc()) LStrictConstantCompareInt32(useBox(value), temp()); 1548 define(lir, ins); 1549 } 1550 1551 void LIRGenerator::visitStrictConstantCompareBoolean( 1552 MStrictConstantCompareBoolean* ins) { 1553 // Prefer to emit fused compare-and-branch if possible. 1554 if (CanEmitCompareAtUses(ins)) { 1555 emitAtUses(ins); 1556 return; 1557 } 1558 1559 MDefinition* value = ins->value(); 1560 1561 auto* lir = new (alloc()) LStrictConstantCompareBoolean(useBox(value)); 1562 define(lir, ins); 1563 } 1564 1565 void LIRGenerator::visitSameValueDouble(MSameValueDouble* ins) { 1566 MDefinition* lhs = ins->lhs(); 1567 MDefinition* rhs = ins->rhs(); 1568 1569 MOZ_ASSERT(lhs->type() == MIRType::Double); 1570 MOZ_ASSERT(rhs->type() == MIRType::Double); 1571 1572 auto* lir = new (alloc()) 1573 LSameValueDouble(useRegister(lhs), useRegister(rhs), tempDouble()); 1574 define(lir, ins); 1575 } 1576 1577 void LIRGenerator::visitSameValue(MSameValue* ins) { 1578 MDefinition* lhs = ins->lhs(); 1579 MDefinition* rhs = ins->rhs(); 1580 1581 MOZ_ASSERT(lhs->type() == MIRType::Value); 1582 MOZ_ASSERT(rhs->type() == MIRType::Value); 1583 1584 auto* lir = new (alloc()) LSameValue(useBox(lhs), useBox(rhs)); 1585 define(lir, ins); 1586 assignSafepoint(lir, ins); 1587 } 1588 1589 void LIRGenerator::lowerBitOp(JSOp op, MBinaryInstruction* ins) { 1590 MDefinition* lhs = ins->getOperand(0); 1591 MDefinition* rhs = ins->getOperand(1); 1592 MOZ_ASSERT(IsIntType(ins->type())); 1593 1594 if (ins->type() == MIRType::Int32) { 1595 MOZ_ASSERT(lhs->type() == MIRType::Int32); 1596 MOZ_ASSERT(rhs->type() == MIRType::Int32); 1597 ReorderCommutative(&lhs, &rhs, ins); 1598 lowerForALU(new (alloc()) LBitOpI(op), ins, lhs, rhs); 1599 return; 1600 } 1601 1602 if (ins->type() == MIRType::Int64) { 1603 MOZ_ASSERT(lhs->type() == MIRType::Int64); 1604 MOZ_ASSERT(rhs->type() == MIRType::Int64); 1605 ReorderCommutative(&lhs, &rhs, ins); 1606 lowerForALUInt64(new (alloc()) LBitOpI64(op), ins, lhs, rhs); 1607 return; 1608 } 1609 1610 MOZ_CRASH("Unhandled integer specialization"); 1611 } 1612 1613 void LIRGenerator::visitTypeOf(MTypeOf* ins) { 1614 MDefinition* opd = ins->input(); 1615 1616 if (opd->type() == MIRType::Object) { 1617 auto* lir = new (alloc()) LTypeOfO(useRegister(opd)); 1618 define(lir, ins); 1619 return; 1620 } 1621 1622 MOZ_ASSERT(opd->type() == MIRType::Value); 1623 1624 LTypeOfV* lir = new (alloc()) LTypeOfV(useBox(opd), tempToUnbox()); 1625 define(lir, ins); 1626 } 1627 1628 void LIRGenerator::visitTypeOfName(MTypeOfName* ins) { 1629 MDefinition* input = ins->input(); 1630 MOZ_ASSERT(input->type() == MIRType::Int32); 1631 1632 auto* lir = new (alloc()) LTypeOfName(useRegister(input)); 1633 define(lir, ins); 1634 } 1635 1636 void LIRGenerator::visitTypeOfIs(MTypeOfIs* ins) { 1637 MDefinition* input = ins->input(); 1638 1639 MOZ_ASSERT(input->type() == MIRType::Object || 1640 input->type() == MIRType::Value); 1641 1642 switch (ins->jstype()) { 1643 case JSTYPE_UNDEFINED: 1644 case JSTYPE_OBJECT: 1645 case JSTYPE_FUNCTION: { 1646 if (input->type() == MIRType::Object) { 1647 auto* lir = new (alloc()) LTypeOfIsNonPrimitiveO(useRegister(input)); 1648 define(lir, ins); 1649 } else { 1650 auto* lir = 1651 new (alloc()) LTypeOfIsNonPrimitiveV(useBox(input), tempToUnbox()); 1652 define(lir, ins); 1653 } 1654 return; 1655 } 1656 1657 case JSTYPE_STRING: 1658 case JSTYPE_NUMBER: 1659 case JSTYPE_BOOLEAN: 1660 case JSTYPE_SYMBOL: 1661 case JSTYPE_BIGINT: { 1662 MOZ_ASSERT(input->type() == MIRType::Value); 1663 1664 auto* lir = new (alloc()) LTypeOfIsPrimitive(useBoxAtStart(input)); 1665 define(lir, ins); 1666 return; 1667 } 1668 1669 case JSTYPE_LIMIT: 1670 break; 1671 } 1672 MOZ_CRASH("Unhandled JSType"); 1673 } 1674 1675 void LIRGenerator::visitToAsyncIter(MToAsyncIter* ins) { 1676 LToAsyncIter* lir = new (alloc()) LToAsyncIter( 1677 useRegisterAtStart(ins->iterator()), useBoxAtStart(ins->nextMethod())); 1678 defineReturn(lir, ins); 1679 assignSafepoint(lir, ins); 1680 } 1681 1682 void LIRGenerator::visitToPropertyKeyCache(MToPropertyKeyCache* ins) { 1683 MDefinition* input = ins->getOperand(0); 1684 MOZ_ASSERT(ins->type() == MIRType::Value); 1685 1686 auto* lir = new (alloc()) LToPropertyKeyCache(useBox(input)); 1687 defineBox(lir, ins); 1688 assignSafepoint(lir, ins); 1689 } 1690 1691 void LIRGenerator::visitBitNot(MBitNot* ins) { 1692 MDefinition* input = ins->getOperand(0); 1693 1694 if (ins->type() == MIRType::Int32) { 1695 MOZ_ASSERT(input->type() == MIRType::Int32); 1696 lowerForALU(new (alloc()) LBitNotI(), ins, input); 1697 return; 1698 } 1699 1700 if (ins->type() == MIRType::Int64) { 1701 MOZ_ASSERT(input->type() == MIRType::Int64); 1702 lowerForALUInt64(new (alloc()) LBitNotI64(), ins, input); 1703 return; 1704 } 1705 1706 MOZ_CRASH("Unhandled integer specialization"); 1707 } 1708 1709 static bool CanEmitBitAndAtUses(MInstruction* ins) { 1710 if (!ins->canEmitAtUses()) { 1711 return false; 1712 } 1713 1714 MIRType tyL = ins->getOperand(0)->type(); 1715 MIRType tyR = ins->getOperand(1)->type(); 1716 if (tyL != tyR || (tyL != MIRType::Int32 && tyL != MIRType::Int64)) { 1717 return false; 1718 } 1719 1720 MUseIterator iter(ins->usesBegin()); 1721 if (iter == ins->usesEnd()) { 1722 return false; 1723 } 1724 1725 MNode* node = iter->consumer(); 1726 if (!node->isDefinition() || !node->toDefinition()->isInstruction()) { 1727 return false; 1728 } 1729 1730 MInstruction* use = node->toDefinition()->toInstruction(); 1731 if (!use->isTest() && !(use->isCompare() && CanEmitCompareAtUses(use))) { 1732 return false; 1733 } 1734 1735 iter++; 1736 return iter == ins->usesEnd(); 1737 } 1738 1739 void LIRGenerator::visitBitAnd(MBitAnd* ins) { 1740 // Sniff out if the output of this bitand is used only for a branching. 1741 // If it is, then we will emit an LBitAndAndBranch instruction in place 1742 // of this bitand and any test that uses this bitand. Thus, we can 1743 // ignore this BitAnd. 1744 if (CanEmitBitAndAtUses(ins)) { 1745 emitAtUses(ins); 1746 } else { 1747 lowerBitOp(JSOp::BitAnd, ins); 1748 } 1749 } 1750 1751 void LIRGenerator::visitBitOr(MBitOr* ins) { lowerBitOp(JSOp::BitOr, ins); } 1752 1753 void LIRGenerator::visitBitXor(MBitXor* ins) { lowerBitOp(JSOp::BitXor, ins); } 1754 1755 void LIRGenerator::visitWasmBinaryBitwise(MWasmBinaryBitwise* ins) { 1756 switch (ins->subOpcode()) { 1757 case MWasmBinaryBitwise::SubOpcode::And: 1758 if (CanEmitBitAndAtUses(ins)) { 1759 emitAtUses(ins); 1760 } else { 1761 lowerBitOp(JSOp::BitAnd, ins); 1762 } 1763 break; 1764 case MWasmBinaryBitwise::SubOpcode::Or: 1765 lowerBitOp(JSOp::BitOr, ins); 1766 break; 1767 case MWasmBinaryBitwise::SubOpcode::Xor: 1768 lowerBitOp(JSOp::BitXor, ins); 1769 break; 1770 default: 1771 MOZ_CRASH(); 1772 } 1773 } 1774 1775 void LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins) { 1776 MDefinition* lhs = ins->getOperand(0); 1777 MDefinition* rhs = ins->getOperand(1); 1778 1779 if (op == JSOp::Ursh && ins->type() == MIRType::Double) { 1780 MOZ_ASSERT(lhs->type() == MIRType::Int32); 1781 MOZ_ASSERT(rhs->type() == MIRType::Int32); 1782 lowerUrshD(ins->toUrsh()); 1783 return; 1784 } 1785 1786 MOZ_ASSERT(IsIntType(ins->type())); 1787 1788 if (ins->type() == MIRType::Int32) { 1789 MOZ_ASSERT(lhs->type() == MIRType::Int32); 1790 MOZ_ASSERT(rhs->type() == MIRType::Int32); 1791 1792 LShiftI* lir = new (alloc()) LShiftI(op); 1793 if (op == JSOp::Ursh) { 1794 if (ins->toUrsh()->fallible()) { 1795 assignSnapshot(lir, ins->bailoutKind()); 1796 } 1797 } 1798 lowerForShift(lir, ins, lhs, rhs); 1799 return; 1800 } 1801 1802 if (ins->type() == MIRType::Int64) { 1803 MOZ_ASSERT(lhs->type() == MIRType::Int64); 1804 MOZ_ASSERT(rhs->type() == MIRType::Int64); 1805 lowerForShiftInt64(new (alloc()) LShiftI64(op), ins, lhs, rhs); 1806 return; 1807 } 1808 1809 if (ins->type() == MIRType::IntPtr) { 1810 MOZ_ASSERT(lhs->type() == MIRType::IntPtr); 1811 MOZ_ASSERT(rhs->type() == MIRType::IntPtr); 1812 lowerForShift(new (alloc()) LShiftIntPtr(op), ins, lhs, rhs); 1813 return; 1814 } 1815 1816 MOZ_CRASH("Unhandled integer specialization"); 1817 } 1818 1819 void LIRGenerator::visitLsh(MLsh* ins) { lowerShiftOp(JSOp::Lsh, ins); } 1820 1821 void LIRGenerator::visitRsh(MRsh* ins) { lowerShiftOp(JSOp::Rsh, ins); } 1822 1823 void LIRGenerator::visitUrsh(MUrsh* ins) { lowerShiftOp(JSOp::Ursh, ins); } 1824 1825 void LIRGenerator::visitSignExtendInt32(MSignExtendInt32* ins) { 1826 LInstructionHelper<1, 1, 0>* lir; 1827 1828 if (ins->mode() == MSignExtendInt32::Byte) { 1829 lir = 1830 new (alloc()) LSignExtendInt32(useByteOpRegisterAtStart(ins->input())); 1831 } else { 1832 lir = new (alloc()) LSignExtendInt32(useRegisterAtStart(ins->input())); 1833 } 1834 1835 define(lir, ins); 1836 } 1837 1838 void LIRGenerator::visitSignExtendIntPtr(MSignExtendIntPtr* ins) { 1839 LInstructionHelper<1, 1, 0>* lir; 1840 1841 if (ins->mode() == MSignExtendIntPtr::Byte) { 1842 lir = 1843 new (alloc()) LSignExtendIntPtr(useByteOpRegisterAtStart(ins->input())); 1844 } else { 1845 lir = new (alloc()) LSignExtendIntPtr(useRegisterAtStart(ins->input())); 1846 } 1847 1848 define(lir, ins); 1849 } 1850 1851 void LIRGenerator::visitRotate(MRotate* ins) { 1852 MDefinition* input = ins->input(); 1853 MDefinition* count = ins->count(); 1854 1855 if (ins->type() == MIRType::Int32) { 1856 auto* lir = new (alloc()) LRotate(); 1857 lowerForShift(lir, ins, input, count); 1858 } else if (ins->type() == MIRType::Int64) { 1859 auto* lir = new (alloc()) LRotateI64(); 1860 lowerForShiftInt64(lir, ins, input, count); 1861 } else { 1862 MOZ_CRASH("unexpected type in visitRotate"); 1863 } 1864 } 1865 1866 void LIRGenerator::visitFloor(MFloor* ins) { 1867 MIRType type = ins->input()->type(); 1868 MOZ_ASSERT(IsFloatingPointType(type)); 1869 1870 LInstructionHelper<1, 1, 0>* lir; 1871 if (type == MIRType::Double) { 1872 lir = new (alloc()) LFloor(useRegister(ins->input())); 1873 } else { 1874 lir = new (alloc()) LFloorF(useRegister(ins->input())); 1875 } 1876 1877 assignSnapshot(lir, ins->bailoutKind()); 1878 define(lir, ins); 1879 } 1880 1881 void LIRGenerator::visitCeil(MCeil* ins) { 1882 MIRType type = ins->input()->type(); 1883 MOZ_ASSERT(IsFloatingPointType(type)); 1884 1885 LInstructionHelper<1, 1, 0>* lir; 1886 if (type == MIRType::Double) { 1887 lir = new (alloc()) LCeil(useRegister(ins->input())); 1888 } else { 1889 lir = new (alloc()) LCeilF(useRegister(ins->input())); 1890 } 1891 1892 assignSnapshot(lir, ins->bailoutKind()); 1893 define(lir, ins); 1894 } 1895 1896 void LIRGenerator::visitRound(MRound* ins) { 1897 MIRType type = ins->input()->type(); 1898 MOZ_ASSERT(IsFloatingPointType(type)); 1899 1900 LInstructionHelper<1, 1, 1>* lir; 1901 if (type == MIRType::Double) { 1902 lir = new (alloc()) LRound(useRegister(ins->input()), tempDouble()); 1903 } else { 1904 lir = new (alloc()) LRoundF(useRegister(ins->input()), tempFloat32()); 1905 } 1906 1907 assignSnapshot(lir, ins->bailoutKind()); 1908 define(lir, ins); 1909 } 1910 1911 void LIRGenerator::visitTrunc(MTrunc* ins) { 1912 MIRType type = ins->input()->type(); 1913 MOZ_ASSERT(IsFloatingPointType(type)); 1914 1915 LInstructionHelper<1, 1, 0>* lir; 1916 if (type == MIRType::Double) { 1917 lir = new (alloc()) LTrunc(useRegister(ins->input())); 1918 } else { 1919 lir = new (alloc()) LTruncF(useRegister(ins->input())); 1920 } 1921 1922 assignSnapshot(lir, ins->bailoutKind()); 1923 define(lir, ins); 1924 } 1925 1926 void LIRGenerator::visitNearbyInt(MNearbyInt* ins) { 1927 MIRType inputType = ins->input()->type(); 1928 MOZ_ASSERT(IsFloatingPointType(inputType)); 1929 MOZ_ASSERT(ins->type() == inputType); 1930 1931 LInstructionHelper<1, 1, 0>* lir; 1932 if (inputType == MIRType::Double) { 1933 lir = new (alloc()) LNearbyInt(useRegisterAtStart(ins->input())); 1934 } else { 1935 lir = new (alloc()) LNearbyIntF(useRegisterAtStart(ins->input())); 1936 } 1937 1938 define(lir, ins); 1939 } 1940 1941 void LIRGenerator::visitRoundToDouble(MRoundToDouble* ins) { 1942 MIRType inputType = ins->input()->type(); 1943 MOZ_ASSERT(IsFloatingPointType(inputType)); 1944 MOZ_ASSERT(ins->type() == inputType); 1945 1946 LInstructionHelper<1, 1, 0>* lir; 1947 if (inputType == MIRType::Double) { 1948 lir = new (alloc()) LRoundToDouble(useRegister(ins->input())); 1949 } else { 1950 lir = new (alloc()) LRoundToFloat32(useRegister(ins->input())); 1951 } 1952 1953 define(lir, ins); 1954 } 1955 1956 void LIRGenerator::visitMinMax(MMinMax* ins) { 1957 MDefinition* first = ins->getOperand(0); 1958 MDefinition* second = ins->getOperand(1); 1959 1960 ReorderCommutative(&first, &second, ins); 1961 1962 LInstructionHelper<1, 2, 0>* lir; 1963 switch (ins->type()) { 1964 case MIRType::Int32: 1965 lir = new (alloc()) 1966 LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second)); 1967 break; 1968 case MIRType::IntPtr: 1969 lir = new (alloc()) LMinMaxIntPtr(useRegisterAtStart(first), 1970 useRegisterOrConstant(second)); 1971 break; 1972 case MIRType::Float32: 1973 lir = new (alloc()) 1974 LMinMaxF(useRegisterAtStart(first), useRegister(second)); 1975 break; 1976 case MIRType::Double: 1977 lir = new (alloc()) 1978 LMinMaxD(useRegisterAtStart(first), useRegister(second)); 1979 break; 1980 default: 1981 MOZ_CRASH(); 1982 } 1983 1984 // Input reuse is OK (for now) even on ARM64: floating min/max are fairly 1985 // expensive due to SNaN -> QNaN conversion, and int min/max is for asm.js. 1986 defineReuseInput(lir, ins, 0); 1987 } 1988 1989 void LIRGenerator::visitMinMaxArray(MMinMaxArray* ins) { 1990 LInstructionHelper<1, 1, 3>* lir; 1991 if (ins->type() == MIRType::Int32) { 1992 lir = new (alloc()) 1993 LMinMaxArrayI(useRegisterAtStart(ins->array()), temp(), temp(), temp()); 1994 } else { 1995 MOZ_ASSERT(ins->type() == MIRType::Double); 1996 lir = new (alloc()) LMinMaxArrayD(useRegisterAtStart(ins->array()), 1997 tempDouble(), temp(), temp()); 1998 } 1999 assignSnapshot(lir, ins->bailoutKind()); 2000 define(lir, ins); 2001 } 2002 2003 void LIRGenerator::visitAbs(MAbs* ins) { 2004 MDefinition* num = ins->input(); 2005 MOZ_ASSERT(IsNumberType(num->type())); 2006 2007 switch (num->type()) { 2008 case MIRType::Int32: { 2009 auto* lir = new (alloc()) LAbsI; 2010 // needed to handle abs(INT32_MIN) 2011 if (ins->fallible()) { 2012 assignSnapshot(lir, ins->bailoutKind()); 2013 } 2014 lowerForALU(lir, ins, num); 2015 break; 2016 } 2017 case MIRType::Float32: 2018 lowerForFPU(new (alloc()) LAbsF, ins, num); 2019 break; 2020 case MIRType::Double: 2021 lowerForFPU(new (alloc()) LAbsD, ins, num); 2022 break; 2023 default: 2024 MOZ_CRASH(); 2025 } 2026 } 2027 2028 void LIRGenerator::visitClz(MClz* ins) { 2029 MDefinition* num = ins->num(); 2030 2031 MOZ_ASSERT(IsIntType(ins->type())); 2032 2033 if (ins->type() == MIRType::Int32) { 2034 LClzI* lir = new (alloc()) LClzI(useRegisterAtStart(num)); 2035 define(lir, ins); 2036 return; 2037 } 2038 2039 auto* lir = new (alloc()) LClzI64(useInt64RegisterAtStart(num)); 2040 defineInt64(lir, ins); 2041 } 2042 2043 void LIRGenerator::visitCtz(MCtz* ins) { 2044 MDefinition* num = ins->num(); 2045 2046 MOZ_ASSERT(IsIntType(ins->type())); 2047 2048 if (ins->type() == MIRType::Int32) { 2049 LCtzI* lir = new (alloc()) LCtzI(useRegisterAtStart(num)); 2050 define(lir, ins); 2051 return; 2052 } 2053 2054 auto* lir = new (alloc()) LCtzI64(useInt64RegisterAtStart(num)); 2055 defineInt64(lir, ins); 2056 } 2057 2058 void LIRGenerator::visitPopcnt(MPopcnt* ins) { 2059 MDefinition* num = ins->num(); 2060 2061 MOZ_ASSERT(IsIntType(ins->type())); 2062 2063 if (ins->type() == MIRType::Int32) { 2064 LPopcntI* lir = new (alloc()) LPopcntI(useRegisterAtStart(num), temp()); 2065 define(lir, ins); 2066 return; 2067 } 2068 2069 auto* lir = new (alloc()) LPopcntI64(useInt64RegisterAtStart(num), temp()); 2070 defineInt64(lir, ins); 2071 } 2072 2073 void LIRGenerator::visitSqrt(MSqrt* ins) { 2074 MDefinition* num = ins->input(); 2075 MOZ_ASSERT(IsFloatingPointType(num->type())); 2076 2077 LInstructionHelper<1, 1, 0>* lir; 2078 if (num->type() == MIRType::Double) { 2079 lir = new (alloc()) LSqrtD(useRegisterAtStart(num)); 2080 } else { 2081 lir = new (alloc()) LSqrtF(useRegisterAtStart(num)); 2082 } 2083 define(lir, ins); 2084 } 2085 2086 void LIRGenerator::visitAtan2(MAtan2* ins) { 2087 MDefinition* y = ins->y(); 2088 MOZ_ASSERT(y->type() == MIRType::Double); 2089 2090 MDefinition* x = ins->x(); 2091 MOZ_ASSERT(x->type() == MIRType::Double); 2092 2093 LAtan2D* lir = 2094 new (alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x)); 2095 defineReturn(lir, ins); 2096 } 2097 2098 void LIRGenerator::visitHypot(MHypot* ins) { 2099 LHypot* lir = nullptr; 2100 uint32_t length = ins->numOperands(); 2101 for (uint32_t i = 0; i < length; ++i) { 2102 MOZ_ASSERT(ins->getOperand(i)->type() == MIRType::Double); 2103 } 2104 2105 switch (length) { 2106 case 2: 2107 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)), 2108 useRegisterAtStart(ins->getOperand(1))); 2109 break; 2110 case 3: 2111 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)), 2112 useRegisterAtStart(ins->getOperand(1)), 2113 useRegisterAtStart(ins->getOperand(2))); 2114 break; 2115 case 4: 2116 lir = new (alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)), 2117 useRegisterAtStart(ins->getOperand(1)), 2118 useRegisterAtStart(ins->getOperand(2)), 2119 useRegisterAtStart(ins->getOperand(3))); 2120 break; 2121 default: 2122 MOZ_CRASH("Unexpected number of arguments to LHypot."); 2123 } 2124 2125 defineReturn(lir, ins); 2126 } 2127 2128 void LIRGenerator::visitPow(MPow* ins) { 2129 MDefinition* input = ins->input(); 2130 MDefinition* power = ins->power(); 2131 2132 if (ins->type() == MIRType::Int32) { 2133 MOZ_ASSERT(input->type() == MIRType::Int32); 2134 MOZ_ASSERT(power->type() == MIRType::Int32); 2135 2136 if (input->isConstant()) { 2137 // Restrict this optimization to |base <= 256| to avoid generating too 2138 // many consecutive shift instructions. 2139 int32_t base = input->toConstant()->toInt32(); 2140 if (2 <= base && base <= 256 && mozilla::IsPowerOfTwo(uint32_t(base))) { 2141 lowerPowOfTwoI(ins); 2142 return; 2143 } 2144 } 2145 2146 auto* lir = new (alloc()) 2147 LPowII(useRegister(input), useRegister(power), temp(), temp()); 2148 assignSnapshot(lir, ins->bailoutKind()); 2149 define(lir, ins); 2150 return; 2151 } 2152 2153 MOZ_ASSERT(ins->type() == MIRType::Double); 2154 MOZ_ASSERT(input->type() == MIRType::Double); 2155 MOZ_ASSERT(power->type() == MIRType::Int32 || 2156 power->type() == MIRType::Double); 2157 2158 LInstruction* lir; 2159 if (power->type() == MIRType::Int32) { 2160 lir = new (alloc()) 2161 LPowI(useRegisterAtStart(input), useRegisterAtStart(power)); 2162 } else { 2163 lir = new (alloc()) 2164 LPowD(useRegisterAtStart(input), useRegisterAtStart(power)); 2165 } 2166 defineReturn(lir, ins); 2167 } 2168 2169 void LIRGenerator::visitPowHalf(MPowHalf* ins) { 2170 MDefinition* input = ins->input(); 2171 MOZ_ASSERT(input->type() == MIRType::Double); 2172 auto* lir = new (alloc()) LPowHalfD(useRegisterAtStart(input)); 2173 define(lir, ins); 2174 } 2175 2176 void LIRGenerator::visitSign(MSign* ins) { 2177 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::Double); 2178 MOZ_ASSERT(ins->input()->type() == MIRType::Int32 || 2179 ins->input()->type() == MIRType::Double); 2180 2181 if (ins->type() == ins->input()->type()) { 2182 if (ins->type() == MIRType::Int32) { 2183 define(new (alloc()) LSignI(useRegister(ins->input())), ins); 2184 } else { 2185 define(new (alloc()) LSignD(useRegister(ins->input())), ins); 2186 } 2187 } else { 2188 if (ins->type() == MIRType::Int32) { 2189 auto* lir = 2190 new (alloc()) LSignDI(useRegister(ins->input()), tempDouble()); 2191 assignSnapshot(lir, ins->bailoutKind()); 2192 define(lir, ins); 2193 } else { 2194 define(new (alloc()) LSignID(useRegister(ins->input()), temp()), ins); 2195 } 2196 } 2197 } 2198 2199 void LIRGenerator::visitMathFunction(MMathFunction* ins) { 2200 MOZ_ASSERT(IsFloatingPointType(ins->type())); 2201 MOZ_ASSERT(ins->type() == ins->input()->type()); 2202 2203 LInstruction* lir; 2204 if (ins->type() == MIRType::Double) { 2205 lir = new (alloc()) LMathFunctionD(useRegisterAtStart(ins->input())); 2206 } else { 2207 lir = new (alloc()) LMathFunctionF(useRegisterAtStart(ins->input())); 2208 } 2209 defineReturn(lir, ins); 2210 } 2211 2212 void LIRGenerator::visitRandom(MRandom* ins) { 2213 auto* lir = new (alloc()) LRandom(temp(), tempInt64(), tempInt64()); 2214 define(lir, ins); 2215 } 2216 2217 // Try to mark an add or sub instruction as able to recover its input when 2218 // bailing out. 2219 template <typename S, typename T> 2220 static void MaybeSetRecoversInput(S* mir, T* lir) { 2221 MOZ_ASSERT(lir->mirRaw() == mir); 2222 if (!mir->fallible() || !lir->snapshot()) { 2223 return; 2224 } 2225 2226 if (lir->output()->policy() != LDefinition::MUST_REUSE_INPUT) { 2227 return; 2228 } 2229 2230 // The original operands to an add or sub can't be recovered if they both 2231 // use the same register. 2232 if (lir->lhs()->isUse() && lir->rhs()->isUse() && 2233 lir->lhs()->toUse()->virtualRegister() == 2234 lir->rhs()->toUse()->virtualRegister()) { 2235 return; 2236 } 2237 2238 // Add instructions that are on two different values can recover 2239 // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy 2240 // of that input does not need to be kept alive in the snapshot 2241 // for the instruction. 2242 2243 lir->setRecoversInput(); 2244 2245 const LUse* input = lir->getOperand(lir->output()->getReusedInput())->toUse(); 2246 lir->snapshot()->rewriteRecoveredInput(*input); 2247 } 2248 2249 void LIRGenerator::visitAdd(MAdd* ins) { 2250 MDefinition* lhs = ins->getOperand(0); 2251 MDefinition* rhs = ins->getOperand(1); 2252 2253 MOZ_ASSERT(lhs->type() == rhs->type()); 2254 MOZ_ASSERT(IsNumberType(ins->type())); 2255 2256 if (ins->type() == MIRType::Int32) { 2257 MOZ_ASSERT(lhs->type() == MIRType::Int32); 2258 ReorderCommutative(&lhs, &rhs, ins); 2259 LAddI* lir = new (alloc()) LAddI; 2260 2261 if (ins->fallible()) { 2262 assignSnapshot(lir, ins->bailoutKind()); 2263 } 2264 2265 lowerForALU(lir, ins, lhs, rhs); 2266 MaybeSetRecoversInput(ins, lir); 2267 return; 2268 } 2269 2270 if (ins->type() == MIRType::Int64) { 2271 MOZ_ASSERT(lhs->type() == MIRType::Int64); 2272 ReorderCommutative(&lhs, &rhs, ins); 2273 LAddI64* lir = new (alloc()) LAddI64; 2274 lowerForALUInt64(lir, ins, lhs, rhs); 2275 return; 2276 } 2277 2278 if (ins->type() == MIRType::IntPtr) { 2279 MOZ_ASSERT(lhs->type() == MIRType::IntPtr); 2280 ReorderCommutative(&lhs, &rhs, ins); 2281 2282 auto* lir = new (alloc()) LAddIntPtr; 2283 lowerForALU(lir, ins, lhs, rhs); 2284 return; 2285 } 2286 2287 if (ins->type() == MIRType::Double) { 2288 MOZ_ASSERT(lhs->type() == MIRType::Double); 2289 ReorderCommutative(&lhs, &rhs, ins); 2290 lowerForFPU(new (alloc()) LMathD(JSOp::Add), ins, lhs, rhs); 2291 return; 2292 } 2293 2294 if (ins->type() == MIRType::Float32) { 2295 MOZ_ASSERT(lhs->type() == MIRType::Float32); 2296 ReorderCommutative(&lhs, &rhs, ins); 2297 lowerForFPU(new (alloc()) LMathF(JSOp::Add), ins, lhs, rhs); 2298 return; 2299 } 2300 2301 MOZ_CRASH("Unhandled number specialization"); 2302 } 2303 2304 void LIRGenerator::visitSub(MSub* ins) { 2305 MDefinition* lhs = ins->lhs(); 2306 MDefinition* rhs = ins->rhs(); 2307 2308 MOZ_ASSERT(lhs->type() == rhs->type()); 2309 MOZ_ASSERT(IsNumberType(ins->type())); 2310 2311 if (ins->type() == MIRType::Int32) { 2312 MOZ_ASSERT(lhs->type() == MIRType::Int32); 2313 2314 // If our LHS is a constant 0 and we don't have to worry about results that 2315 // can't be represented as an int32, we can optimize to an LNegI. 2316 if (!ins->fallible() && lhs->isConstant() && 2317 lhs->toConstant()->toInt32() == 0) { 2318 lowerForALU(new (alloc()) LNegI, ins, rhs); 2319 return; 2320 } 2321 2322 LSubI* lir = new (alloc()) LSubI; 2323 if (ins->fallible()) { 2324 assignSnapshot(lir, ins->bailoutKind()); 2325 } 2326 2327 lowerForALU(lir, ins, lhs, rhs); 2328 MaybeSetRecoversInput(ins, lir); 2329 return; 2330 } 2331 2332 if (ins->type() == MIRType::Int64) { 2333 MOZ_ASSERT(lhs->type() == MIRType::Int64); 2334 2335 // If our LHS is a constant 0, we can optimize to an LNegI64. 2336 if (lhs->isConstant() && lhs->toConstant()->toInt64() == 0) { 2337 lowerForALUInt64(new (alloc()) LNegI64, ins, rhs); 2338 return; 2339 } 2340 2341 LSubI64* lir = new (alloc()) LSubI64; 2342 lowerForALUInt64(lir, ins, lhs, rhs); 2343 return; 2344 } 2345 2346 if (ins->type() == MIRType::IntPtr) { 2347 MOZ_ASSERT(lhs->type() == MIRType::IntPtr); 2348 2349 auto* lir = new (alloc()) LSubIntPtr; 2350 lowerForALU(lir, ins, lhs, rhs); 2351 return; 2352 } 2353 2354 if (ins->type() == MIRType::Double) { 2355 MOZ_ASSERT(lhs->type() == MIRType::Double); 2356 lowerForFPU(new (alloc()) LMathD(JSOp::Sub), ins, lhs, rhs); 2357 return; 2358 } 2359 2360 if (ins->type() == MIRType::Float32) { 2361 MOZ_ASSERT(lhs->type() == MIRType::Float32); 2362 lowerForFPU(new (alloc()) LMathF(JSOp::Sub), ins, lhs, rhs); 2363 return; 2364 } 2365 2366 MOZ_CRASH("Unhandled number specialization"); 2367 } 2368 2369 void LIRGenerator::visitMul(MMul* ins) { 2370 MDefinition* lhs = ins->lhs(); 2371 MDefinition* rhs = ins->rhs(); 2372 MOZ_ASSERT(lhs->type() == rhs->type()); 2373 MOZ_ASSERT(IsNumberType(ins->type())); 2374 2375 if (ins->type() == MIRType::Int32) { 2376 MOZ_ASSERT(lhs->type() == MIRType::Int32); 2377 ReorderCommutative(&lhs, &rhs, ins); 2378 2379 // If our RHS is a constant -1 and we don't have to worry about results that 2380 // can't be represented as an int32, we can optimize to an LNegI. 2381 if (!ins->fallible() && rhs->isConstant() && 2382 rhs->toConstant()->toInt32() == -1) { 2383 lowerForALU(new (alloc()) LNegI, ins, lhs); 2384 return; 2385 } 2386 2387 lowerMulI(ins, lhs, rhs); 2388 return; 2389 } 2390 2391 if (ins->type() == MIRType::Int64) { 2392 MOZ_ASSERT(lhs->type() == MIRType::Int64); 2393 ReorderCommutative(&lhs, &rhs, ins); 2394 2395 // If our RHS is a constant -1, we can optimize to an LNegI64. 2396 if (rhs->isConstant() && rhs->toConstant()->toInt64() == -1) { 2397 lowerForALUInt64(new (alloc()) LNegI64, ins, lhs); 2398 return; 2399 } 2400 2401 LMulI64* lir = new (alloc()) LMulI64; 2402 lowerForMulInt64(lir, ins, lhs, rhs); 2403 return; 2404 } 2405 2406 if (ins->type() == MIRType::IntPtr) { 2407 MOZ_ASSERT(lhs->type() == MIRType::IntPtr); 2408 ReorderCommutative(&lhs, &rhs, ins); 2409 2410 auto* lir = new (alloc()) LMulIntPtr; 2411 lowerForALU(lir, ins, lhs, rhs); 2412 return; 2413 } 2414 2415 if (ins->type() == MIRType::Double) { 2416 MOZ_ASSERT(lhs->type() == MIRType::Double); 2417 ReorderCommutative(&lhs, &rhs, ins); 2418 2419 // If our RHS is a constant -1.0, we can optimize to an LNegD. 2420 if (!ins->mustPreserveNaN() && rhs->isConstant() && 2421 rhs->toConstant()->toDouble() == -1.0) { 2422 lowerForFPU(new (alloc()) LNegD, ins, lhs); 2423 return; 2424 } 2425 2426 lowerForFPU(new (alloc()) LMathD(JSOp::Mul), ins, lhs, rhs); 2427 return; 2428 } 2429 2430 if (ins->type() == MIRType::Float32) { 2431 MOZ_ASSERT(lhs->type() == MIRType::Float32); 2432 ReorderCommutative(&lhs, &rhs, ins); 2433 2434 // We apply the same optimizations as for doubles 2435 if (!ins->mustPreserveNaN() && rhs->isConstant() && 2436 rhs->toConstant()->toFloat32() == -1.0f) { 2437 lowerForFPU(new (alloc()) LNegF, ins, lhs); 2438 return; 2439 } 2440 2441 lowerForFPU(new (alloc()) LMathF(JSOp::Mul), ins, lhs, rhs); 2442 return; 2443 } 2444 2445 MOZ_CRASH("Unhandled number specialization"); 2446 } 2447 2448 void LIRGenerator::visitWasmNeg(MWasmNeg* ins) { 2449 switch (ins->type()) { 2450 case MIRType::Int32: 2451 lowerForALU(new (alloc()) LNegI, ins, ins->input()); 2452 break; 2453 case MIRType::Float32: 2454 lowerForFPU(new (alloc()) LNegF, ins, ins->input()); 2455 break; 2456 case MIRType::Double: 2457 lowerForFPU(new (alloc()) LNegD, ins, ins->input()); 2458 break; 2459 default: 2460 MOZ_CRASH(); 2461 } 2462 } 2463 2464 void LIRGenerator::visitDiv(MDiv* ins) { 2465 MDefinition* lhs = ins->lhs(); 2466 MDefinition* rhs = ins->rhs(); 2467 MOZ_ASSERT(lhs->type() == rhs->type()); 2468 MOZ_ASSERT(IsNumberType(ins->type())); 2469 2470 if (ins->type() == MIRType::Int32) { 2471 MOZ_ASSERT(lhs->type() == MIRType::Int32); 2472 if (ins->isUnsigned()) { 2473 lowerUDiv(ins); 2474 } else { 2475 lowerDivI(ins); 2476 } 2477 return; 2478 } 2479 2480 if (ins->type() == MIRType::Int64) { 2481 MOZ_ASSERT(lhs->type() == MIRType::Int64); 2482 if (ins->isUnsigned()) { 2483 lowerUDivI64(ins); 2484 } else { 2485 lowerDivI64(ins); 2486 } 2487 return; 2488 } 2489 2490 if (ins->type() == MIRType::Double) { 2491 MOZ_ASSERT(lhs->type() == MIRType::Double); 2492 lowerForFPU(new (alloc()) LMathD(JSOp::Div), ins, lhs, rhs); 2493 return; 2494 } 2495 2496 if (ins->type() == MIRType::Float32) { 2497 MOZ_ASSERT(lhs->type() == MIRType::Float32); 2498 lowerForFPU(new (alloc()) LMathF(JSOp::Div), ins, lhs, rhs); 2499 return; 2500 } 2501 2502 MOZ_CRASH("Unhandled number specialization"); 2503 } 2504 2505 void LIRGenerator::visitWasmBuiltinDivI64(MWasmBuiltinDivI64* div) { 2506 lowerWasmBuiltinDivI64(div); 2507 } 2508 2509 void LIRGenerator::visitWasmBuiltinModI64(MWasmBuiltinModI64* mod) { 2510 lowerWasmBuiltinModI64(mod); 2511 } 2512 2513 void LIRGenerator::visitBuiltinInt64ToFloatingPoint( 2514 MBuiltinInt64ToFloatingPoint* ins) { 2515 lowerBuiltinInt64ToFloatingPoint(ins); 2516 } 2517 2518 void LIRGenerator::visitWasmBuiltinTruncateToInt64( 2519 MWasmBuiltinTruncateToInt64* ins) { 2520 lowerWasmBuiltinTruncateToInt64(ins); 2521 } 2522 2523 void LIRGenerator::visitWasmBuiltinModD(MWasmBuiltinModD* ins) { 2524 MOZ_ASSERT(gen->compilingWasm()); 2525 LWasmBuiltinModD* lir = new (alloc()) LWasmBuiltinModD( 2526 useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()), 2527 useFixedAtStart(ins->instance(), InstanceReg)); 2528 defineReturn(lir, ins); 2529 } 2530 2531 void LIRGenerator::visitMod(MMod* ins) { 2532 MOZ_ASSERT(ins->lhs()->type() == ins->rhs()->type()); 2533 MOZ_ASSERT(IsNumberType(ins->type())); 2534 2535 if (ins->type() == MIRType::Int32) { 2536 MOZ_ASSERT(ins->type() == MIRType::Int32); 2537 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int32); 2538 if (ins->isUnsigned()) { 2539 lowerUMod(ins); 2540 } else { 2541 lowerModI(ins); 2542 } 2543 return; 2544 } 2545 2546 if (ins->type() == MIRType::Int64) { 2547 MOZ_ASSERT(ins->type() == MIRType::Int64); 2548 MOZ_ASSERT(ins->lhs()->type() == MIRType::Int64); 2549 if (ins->isUnsigned()) { 2550 lowerUModI64(ins); 2551 } else { 2552 lowerModI64(ins); 2553 } 2554 return; 2555 } 2556 2557 if (ins->type() == MIRType::Double) { 2558 MOZ_ASSERT(ins->lhs()->type() == MIRType::Double); 2559 MOZ_ASSERT(ins->rhs()->type() == MIRType::Double); 2560 2561 MOZ_ASSERT(!gen->compilingWasm()); 2562 2563 if (Assembler::HasRoundInstruction(RoundingMode::TowardsZero)) { 2564 if (ins->rhs()->isConstant()) { 2565 double d = ins->rhs()->toConstant()->toDouble(); 2566 int32_t div; 2567 if (mozilla::NumberIsInt32(d, &div) && div > 0 && 2568 mozilla::IsPowerOfTwo(uint32_t(div))) { 2569 auto* lir = new (alloc()) LModPowTwoD(useRegister(ins->lhs()), div); 2570 define(lir, ins); 2571 return; 2572 } 2573 } 2574 } 2575 2576 LModD* lir = new (alloc()) 2577 LModD(useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs())); 2578 defineReturn(lir, ins); 2579 return; 2580 } 2581 2582 MOZ_CRASH("Unhandled number specialization"); 2583 } 2584 2585 void LIRGenerator::visitBigIntAdd(MBigIntAdd* ins) { 2586 auto* lir = new (alloc()) LBigIntAdd(useRegisterAtStart(ins->lhs()), 2587 useRegisterAtStart(ins->rhs())); 2588 defineReturn(lir, ins); 2589 assignSafepoint(lir, ins); 2590 } 2591 2592 void LIRGenerator::visitBigIntSub(MBigIntSub* ins) { 2593 auto* lir = new (alloc()) LBigIntSub(useRegisterAtStart(ins->lhs()), 2594 useRegisterAtStart(ins->rhs())); 2595 defineReturn(lir, ins); 2596 assignSafepoint(lir, ins); 2597 } 2598 2599 void LIRGenerator::visitBigIntMul(MBigIntMul* ins) { 2600 auto* lir = new (alloc()) LBigIntMul(useRegisterAtStart(ins->lhs()), 2601 useRegisterAtStart(ins->rhs())); 2602 defineReturn(lir, ins); 2603 assignSafepoint(lir, ins); 2604 } 2605 2606 void LIRGenerator::visitBigIntDiv(MBigIntDiv* ins) { 2607 auto* lir = new (alloc()) LBigIntDiv(useRegisterAtStart(ins->lhs()), 2608 useRegisterAtStart(ins->rhs())); 2609 defineReturn(lir, ins); 2610 assignSafepoint(lir, ins); 2611 } 2612 2613 void LIRGenerator::visitBigIntMod(MBigIntMod* ins) { 2614 auto* lir = new (alloc()) LBigIntMod(useRegisterAtStart(ins->lhs()), 2615 useRegisterAtStart(ins->rhs())); 2616 defineReturn(lir, ins); 2617 assignSafepoint(lir, ins); 2618 } 2619 2620 void LIRGenerator::visitBigIntPow(MBigIntPow* ins) { 2621 auto* lir = new (alloc()) LBigIntPow(useRegisterAtStart(ins->lhs()), 2622 useRegisterAtStart(ins->rhs())); 2623 defineReturn(lir, ins); 2624 assignSafepoint(lir, ins); 2625 } 2626 2627 void LIRGenerator::visitBigIntBitAnd(MBigIntBitAnd* ins) { 2628 auto* lir = new (alloc()) LBigIntBitAnd(useRegisterAtStart(ins->lhs()), 2629 useRegisterAtStart(ins->rhs())); 2630 defineReturn(lir, ins); 2631 assignSafepoint(lir, ins); 2632 } 2633 2634 void LIRGenerator::visitBigIntBitOr(MBigIntBitOr* ins) { 2635 auto* lir = new (alloc()) LBigIntBitOr(useRegisterAtStart(ins->lhs()), 2636 useRegisterAtStart(ins->rhs())); 2637 defineReturn(lir, ins); 2638 assignSafepoint(lir, ins); 2639 } 2640 2641 void LIRGenerator::visitBigIntBitXor(MBigIntBitXor* ins) { 2642 auto* lir = new (alloc()) LBigIntBitXor(useRegisterAtStart(ins->lhs()), 2643 useRegisterAtStart(ins->rhs())); 2644 defineReturn(lir, ins); 2645 assignSafepoint(lir, ins); 2646 } 2647 2648 void LIRGenerator::visitBigIntLsh(MBigIntLsh* ins) { 2649 auto* lir = new (alloc()) LBigIntLsh(useRegisterAtStart(ins->lhs()), 2650 useRegisterAtStart(ins->rhs())); 2651 defineReturn(lir, ins); 2652 assignSafepoint(lir, ins); 2653 } 2654 2655 void LIRGenerator::visitBigIntRsh(MBigIntRsh* ins) { 2656 auto* lir = new (alloc()) LBigIntRsh(useRegisterAtStart(ins->lhs()), 2657 useRegisterAtStart(ins->rhs())); 2658 defineReturn(lir, ins); 2659 assignSafepoint(lir, ins); 2660 } 2661 2662 void LIRGenerator::visitBigIntIncrement(MBigIntIncrement* ins) { 2663 auto* lir = new (alloc()) LBigIntIncrement(useRegisterAtStart(ins->input())); 2664 defineReturn(lir, ins); 2665 assignSafepoint(lir, ins); 2666 } 2667 2668 void LIRGenerator::visitBigIntDecrement(MBigIntDecrement* ins) { 2669 auto* lir = new (alloc()) LBigIntDecrement(useRegisterAtStart(ins->input())); 2670 defineReturn(lir, ins); 2671 assignSafepoint(lir, ins); 2672 } 2673 2674 void LIRGenerator::visitBigIntNegate(MBigIntNegate* ins) { 2675 auto* lir = new (alloc()) LBigIntNegate(useRegister(ins->input()), temp()); 2676 define(lir, ins); 2677 assignSafepoint(lir, ins); 2678 } 2679 2680 void LIRGenerator::visitBigIntBitNot(MBigIntBitNot* ins) { 2681 auto* lir = new (alloc()) LBigIntBitNot(useRegisterAtStart(ins->input())); 2682 defineReturn(lir, ins); 2683 assignSafepoint(lir, ins); 2684 } 2685 2686 void LIRGenerator::visitBigIntToIntPtr(MBigIntToIntPtr* ins) { 2687 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt); 2688 2689 auto* lir = new (alloc()) LBigIntToIntPtr(useRegister(ins->input())); 2690 assignSnapshot(lir, ins->bailoutKind()); 2691 define(lir, ins); 2692 } 2693 2694 void LIRGenerator::visitIntPtrToBigInt(MIntPtrToBigInt* ins) { 2695 MOZ_ASSERT(ins->input()->type() == MIRType::IntPtr); 2696 2697 auto* lir = new (alloc()) LIntPtrToBigInt(useRegister(ins->input()), temp()); 2698 define(lir, ins); 2699 assignSafepoint(lir, ins); 2700 } 2701 2702 void LIRGenerator::visitBigIntPtrAdd(MBigIntPtrAdd* ins) { 2703 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2704 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2705 2706 MDefinition* lhs = ins->lhs(); 2707 MDefinition* rhs = ins->rhs(); 2708 ReorderCommutative(&lhs, &rhs, ins); 2709 2710 auto* lir = 2711 new (alloc()) LBigIntPtrAdd(useRegister(lhs), useRegisterOrConstant(rhs)); 2712 assignSnapshot(lir, ins->bailoutKind()); 2713 define(lir, ins); 2714 } 2715 2716 void LIRGenerator::visitBigIntPtrSub(MBigIntPtrSub* ins) { 2717 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2718 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2719 2720 auto* lir = new (alloc()) 2721 LBigIntPtrSub(useRegister(ins->lhs()), useRegister(ins->rhs())); 2722 assignSnapshot(lir, ins->bailoutKind()); 2723 define(lir, ins); 2724 } 2725 2726 void LIRGenerator::visitBigIntPtrMul(MBigIntPtrMul* ins) { 2727 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2728 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2729 2730 MDefinition* lhs = ins->lhs(); 2731 MDefinition* rhs = ins->rhs(); 2732 ReorderCommutative(&lhs, &rhs, ins); 2733 2734 auto* lir = 2735 new (alloc()) LBigIntPtrMul(useRegister(lhs), useRegisterOrConstant(rhs)); 2736 assignSnapshot(lir, ins->bailoutKind()); 2737 define(lir, ins); 2738 } 2739 2740 void LIRGenerator::visitBigIntPtrDiv(MBigIntPtrDiv* ins) { 2741 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2742 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2743 2744 if (ins->rhs()->isConstant()) { 2745 intptr_t rhs = ins->rhs()->toConstant()->toIntPtr(); 2746 if (mozilla::IsPowerOfTwo(mozilla::Abs(rhs))) { 2747 int32_t shift = mozilla::FloorLog2(mozilla::Abs(rhs)); 2748 auto* lir = new (alloc()) 2749 LBigIntPtrDivPowTwo(useRegister(ins->lhs()), shift, rhs < 0); 2750 if (shift == 0 && rhs < 0) { 2751 assignSnapshot(lir, ins->bailoutKind()); 2752 } 2753 define(lir, ins); 2754 return; 2755 } 2756 } 2757 2758 lowerBigIntPtrDiv(ins); 2759 } 2760 2761 void LIRGenerator::visitBigIntPtrMod(MBigIntPtrMod* ins) { 2762 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2763 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2764 2765 if (ins->rhs()->isConstant()) { 2766 intptr_t rhs = ins->rhs()->toConstant()->toIntPtr(); 2767 if (mozilla::IsPowerOfTwo(mozilla::Abs(rhs))) { 2768 int32_t shift = mozilla::FloorLog2(mozilla::Abs(rhs)); 2769 auto* lir = new (alloc()) 2770 LBigIntPtrModPowTwo(useRegister(ins->lhs()), temp(), shift); 2771 define(lir, ins); 2772 return; 2773 } 2774 } 2775 2776 lowerBigIntPtrMod(ins); 2777 } 2778 2779 void LIRGenerator::visitBigIntPtrPow(MBigIntPtrPow* ins) { 2780 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2781 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2782 2783 auto* lir = new (alloc()) LBigIntPtrPow( 2784 useRegister(ins->lhs()), useRegister(ins->rhs()), temp(), temp()); 2785 assignSnapshot(lir, ins->bailoutKind()); 2786 define(lir, ins); 2787 } 2788 2789 void LIRGenerator::visitBigIntPtrBitAnd(MBigIntPtrBitAnd* ins) { 2790 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2791 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2792 2793 MDefinition* lhs = ins->lhs(); 2794 MDefinition* rhs = ins->rhs(); 2795 ReorderCommutative(&lhs, &rhs, ins); 2796 2797 auto* lir = new (alloc()) 2798 LBigIntPtrBitAnd(useRegister(lhs), useRegisterOrConstant(rhs)); 2799 define(lir, ins); 2800 } 2801 2802 void LIRGenerator::visitBigIntPtrBitOr(MBigIntPtrBitOr* ins) { 2803 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2804 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2805 2806 MDefinition* lhs = ins->lhs(); 2807 MDefinition* rhs = ins->rhs(); 2808 ReorderCommutative(&lhs, &rhs, ins); 2809 2810 auto* lir = new (alloc()) 2811 LBigIntPtrBitOr(useRegister(lhs), useRegisterOrConstant(rhs)); 2812 define(lir, ins); 2813 } 2814 2815 void LIRGenerator::visitBigIntPtrBitXor(MBigIntPtrBitXor* ins) { 2816 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2817 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2818 2819 MDefinition* lhs = ins->lhs(); 2820 MDefinition* rhs = ins->rhs(); 2821 ReorderCommutative(&lhs, &rhs, ins); 2822 2823 auto* lir = new (alloc()) 2824 LBigIntPtrBitXor(useRegister(lhs), useRegisterOrConstant(rhs)); 2825 define(lir, ins); 2826 } 2827 2828 void LIRGenerator::visitBigIntPtrLsh(MBigIntPtrLsh* ins) { 2829 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2830 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2831 2832 if (ins->rhs()->isConstant()) { 2833 // Need an additional temp when the operation is fallible. 2834 auto tmp = ins->fallible() ? temp() : LDefinition::BogusTemp(); 2835 2836 auto* lir = new (alloc()) LBigIntPtrLsh(useRegister(ins->lhs()), 2837 useRegisterOrConstant(ins->rhs()), 2838 tmp, LDefinition::BogusTemp()); 2839 if (ins->fallible()) { 2840 assignSnapshot(lir, ins->bailoutKind()); 2841 } 2842 define(lir, ins); 2843 return; 2844 } 2845 2846 lowerBigIntPtrLsh(ins); 2847 } 2848 2849 void LIRGenerator::visitBigIntPtrRsh(MBigIntPtrRsh* ins) { 2850 MOZ_ASSERT(ins->lhs()->type() == MIRType::IntPtr); 2851 MOZ_ASSERT(ins->rhs()->type() == MIRType::IntPtr); 2852 2853 if (ins->rhs()->isConstant()) { 2854 // Need an additional temp when the operation is fallible. 2855 auto tmp = ins->fallible() ? temp() : LDefinition::BogusTemp(); 2856 2857 auto* lir = new (alloc()) LBigIntPtrRsh(useRegister(ins->lhs()), 2858 useRegisterOrConstant(ins->rhs()), 2859 tmp, LDefinition::BogusTemp()); 2860 if (ins->fallible()) { 2861 assignSnapshot(lir, ins->bailoutKind()); 2862 } 2863 define(lir, ins); 2864 return; 2865 } 2866 2867 lowerBigIntPtrRsh(ins); 2868 } 2869 2870 void LIRGenerator::visitBigIntPtrBitNot(MBigIntPtrBitNot* ins) { 2871 MOZ_ASSERT(ins->input()->type() == MIRType::IntPtr); 2872 2873 auto* lir = new (alloc()) LBigIntPtrBitNot(useRegister(ins->input())); 2874 define(lir, ins); 2875 } 2876 2877 void LIRGenerator::visitInt32ToStringWithBase(MInt32ToStringWithBase* ins) { 2878 MOZ_ASSERT(ins->input()->type() == MIRType::Int32); 2879 MOZ_ASSERT(ins->base()->type() == MIRType::Int32); 2880 2881 int32_t baseInt = 2882 ins->base()->isConstant() ? ins->base()->toConstant()->toInt32() : 0; 2883 2884 LAllocation base; 2885 if (2 <= baseInt && baseInt <= 36) { 2886 base = useRegisterOrConstant(ins->base()); 2887 } else { 2888 base = useRegister(ins->base()); 2889 } 2890 2891 auto* lir = new (alloc()) 2892 LInt32ToStringWithBase(useRegister(ins->input()), base, temp(), temp()); 2893 define(lir, ins); 2894 assignSafepoint(lir, ins); 2895 } 2896 2897 void LIRGenerator::visitNumberParseInt(MNumberParseInt* ins) { 2898 MOZ_ASSERT(ins->string()->type() == MIRType::String); 2899 MOZ_ASSERT(ins->radix()->type() == MIRType::Int32); 2900 2901 auto* lir = new (alloc()) LNumberParseInt(useRegisterAtStart(ins->string()), 2902 useRegisterAtStart(ins->radix()), 2903 tempFixed(CallTempReg0)); 2904 defineReturn(lir, ins); 2905 assignSafepoint(lir, ins); 2906 } 2907 2908 void LIRGenerator::visitDoubleParseInt(MDoubleParseInt* ins) { 2909 MOZ_ASSERT(ins->number()->type() == MIRType::Double); 2910 2911 auto* lir = 2912 new (alloc()) LDoubleParseInt(useRegister(ins->number()), tempDouble()); 2913 assignSnapshot(lir, ins->bailoutKind()); 2914 define(lir, ins); 2915 } 2916 2917 void LIRGenerator::visitConcat(MConcat* ins) { 2918 MDefinition* lhs = ins->getOperand(0); 2919 MDefinition* rhs = ins->getOperand(1); 2920 2921 MOZ_ASSERT(lhs->type() == MIRType::String); 2922 MOZ_ASSERT(rhs->type() == MIRType::String); 2923 MOZ_ASSERT(ins->type() == MIRType::String); 2924 2925 LConcat* lir = new (alloc()) LConcat( 2926 useFixedAtStart(lhs, CallTempReg0), useFixedAtStart(rhs, CallTempReg1), 2927 tempFixed(CallTempReg0), tempFixed(CallTempReg1), tempFixed(CallTempReg2), 2928 tempFixed(CallTempReg3), tempFixed(CallTempReg4)); 2929 defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5))); 2930 assignSafepoint(lir, ins); 2931 } 2932 2933 void LIRGenerator::visitLinearizeString(MLinearizeString* ins) { 2934 MDefinition* str = ins->string(); 2935 MOZ_ASSERT(str->type() == MIRType::String); 2936 2937 auto* lir = new (alloc()) LLinearizeString(useRegister(str)); 2938 define(lir, ins); 2939 assignSafepoint(lir, ins); 2940 } 2941 2942 void LIRGenerator::visitLinearizeForCharAccess(MLinearizeForCharAccess* ins) { 2943 MDefinition* str = ins->string(); 2944 MDefinition* idx = ins->index(); 2945 2946 MOZ_ASSERT(str->type() == MIRType::String); 2947 MOZ_ASSERT(idx->type() == MIRType::Int32); 2948 2949 auto* lir = 2950 new (alloc()) LLinearizeForCharAccess(useRegister(str), useRegister(idx)); 2951 define(lir, ins); 2952 assignSafepoint(lir, ins); 2953 } 2954 2955 void LIRGenerator::visitLinearizeForCodePointAccess( 2956 MLinearizeForCodePointAccess* ins) { 2957 MDefinition* str = ins->string(); 2958 MDefinition* idx = ins->index(); 2959 2960 MOZ_ASSERT(str->type() == MIRType::String); 2961 MOZ_ASSERT(idx->type() == MIRType::Int32); 2962 2963 auto* lir = new (alloc()) 2964 LLinearizeForCodePointAccess(useRegister(str), useRegister(idx), temp()); 2965 define(lir, ins); 2966 assignSafepoint(lir, ins); 2967 } 2968 2969 void LIRGenerator::visitToRelativeStringIndex(MToRelativeStringIndex* ins) { 2970 MDefinition* index = ins->index(); 2971 MDefinition* length = ins->length(); 2972 2973 MOZ_ASSERT(index->type() == MIRType::Int32); 2974 MOZ_ASSERT(length->type() == MIRType::Int32); 2975 2976 auto* lir = new (alloc()) 2977 LToRelativeStringIndex(useRegister(index), useRegister(length)); 2978 define(lir, ins); 2979 } 2980 2981 void LIRGenerator::visitCharCodeAt(MCharCodeAt* ins) { 2982 MDefinition* str = ins->string(); 2983 MDefinition* idx = ins->index(); 2984 2985 MOZ_ASSERT(str->type() == MIRType::String); 2986 MOZ_ASSERT(idx->type() == MIRType::Int32); 2987 2988 auto* lir = new (alloc()) 2989 LCharCodeAt(useRegister(str), useRegisterOrZero(idx), temp(), temp()); 2990 define(lir, ins); 2991 assignSafepoint(lir, ins); 2992 } 2993 2994 void LIRGenerator::visitCharCodeAtOrNegative(MCharCodeAtOrNegative* ins) { 2995 MDefinition* str = ins->string(); 2996 MDefinition* idx = ins->index(); 2997 2998 MOZ_ASSERT(str->type() == MIRType::String); 2999 MOZ_ASSERT(idx->type() == MIRType::Int32); 3000 3001 auto* lir = new (alloc()) LCharCodeAtOrNegative( 3002 useRegister(str), useRegisterOrZero(idx), temp(), temp()); 3003 define(lir, ins); 3004 assignSafepoint(lir, ins); 3005 } 3006 3007 void LIRGenerator::visitCodePointAt(MCodePointAt* ins) { 3008 MDefinition* str = ins->string(); 3009 MDefinition* idx = ins->index(); 3010 3011 MOZ_ASSERT(str->type() == MIRType::String); 3012 MOZ_ASSERT(idx->type() == MIRType::Int32); 3013 3014 auto* lir = new (alloc()) 3015 LCodePointAt(useRegister(str), useRegister(idx), temp(), temp()); 3016 define(lir, ins); 3017 assignSafepoint(lir, ins); 3018 } 3019 3020 void LIRGenerator::visitCodePointAtOrNegative(MCodePointAtOrNegative* ins) { 3021 MDefinition* str = ins->string(); 3022 MDefinition* idx = ins->index(); 3023 3024 MOZ_ASSERT(str->type() == MIRType::String); 3025 MOZ_ASSERT(idx->type() == MIRType::Int32); 3026 3027 auto* lir = new (alloc()) LCodePointAtOrNegative( 3028 useRegister(str), useRegister(idx), temp(), temp()); 3029 define(lir, ins); 3030 assignSafepoint(lir, ins); 3031 } 3032 3033 void LIRGenerator::visitNegativeToNaN(MNegativeToNaN* ins) { 3034 MOZ_ASSERT(ins->input()->type() == MIRType::Int32); 3035 3036 auto* lir = new (alloc()) LNegativeToNaN(useRegister(ins->input())); 3037 defineBox(lir, ins); 3038 } 3039 3040 void LIRGenerator::visitNegativeToUndefined(MNegativeToUndefined* ins) { 3041 MOZ_ASSERT(ins->input()->type() == MIRType::Int32); 3042 3043 auto* lir = new (alloc()) LNegativeToUndefined(useRegister(ins->input())); 3044 defineBox(lir, ins); 3045 } 3046 3047 void LIRGenerator::visitFromCharCode(MFromCharCode* ins) { 3048 MDefinition* code = ins->code(); 3049 3050 MOZ_ASSERT(code->type() == MIRType::Int32); 3051 3052 LFromCharCode* lir = new (alloc()) LFromCharCode(useRegister(code)); 3053 define(lir, ins); 3054 assignSafepoint(lir, ins); 3055 } 3056 3057 void LIRGenerator::visitFromCharCodeEmptyIfNegative( 3058 MFromCharCodeEmptyIfNegative* ins) { 3059 MDefinition* code = ins->code(); 3060 3061 MOZ_ASSERT(code->type() == MIRType::Int32); 3062 3063 auto* lir = new (alloc()) LFromCharCodeEmptyIfNegative(useRegister(code)); 3064 define(lir, ins); 3065 assignSafepoint(lir, ins); 3066 } 3067 3068 void LIRGenerator::visitFromCharCodeUndefinedIfNegative( 3069 MFromCharCodeUndefinedIfNegative* ins) { 3070 MDefinition* code = ins->code(); 3071 3072 MOZ_ASSERT(code->type() == MIRType::Int32); 3073 3074 auto* lir = new (alloc()) LFromCharCodeUndefinedIfNegative(useRegister(code)); 3075 defineBox(lir, ins); 3076 assignSafepoint(lir, ins); 3077 } 3078 3079 void LIRGenerator::visitFromCodePoint(MFromCodePoint* ins) { 3080 MDefinition* codePoint = ins->codePoint(); 3081 3082 MOZ_ASSERT(codePoint->type() == MIRType::Int32); 3083 3084 LFromCodePoint* lir = 3085 new (alloc()) LFromCodePoint(useRegister(codePoint), temp(), temp()); 3086 assignSnapshot(lir, ins->bailoutKind()); 3087 define(lir, ins); 3088 assignSafepoint(lir, ins); 3089 } 3090 3091 void LIRGenerator::visitStringIncludes(MStringIncludes* ins) { 3092 auto* string = ins->string(); 3093 MOZ_ASSERT(string->type() == MIRType::String); 3094 3095 auto* searchStr = ins->searchString(); 3096 MOZ_ASSERT(searchStr->type() == MIRType::String); 3097 3098 if (searchStr->isConstant()) { 3099 JSOffThreadAtom* str = searchStr->toConstant()->toString(); 3100 size_t length = str->length(); 3101 if (length == 1 || length == 2) { 3102 LDefinition tempDef = LDefinition::BogusTemp(); 3103 if (length > 1) { 3104 tempDef = temp(); 3105 } 3106 3107 auto* lir = new (alloc()) LStringIncludesSIMD(useRegister(string), temp(), 3108 temp(), tempDef, str); 3109 define(lir, ins); 3110 assignSafepoint(lir, ins); 3111 return; 3112 } 3113 } 3114 3115 auto* lir = new (alloc()) LStringIncludes(useRegisterAtStart(string), 3116 useRegisterAtStart(searchStr)); 3117 defineReturn(lir, ins); 3118 assignSafepoint(lir, ins); 3119 } 3120 3121 void LIRGenerator::visitStringIndexOf(MStringIndexOf* ins) { 3122 auto* string = ins->string(); 3123 MOZ_ASSERT(string->type() == MIRType::String); 3124 3125 auto* searchStr = ins->searchString(); 3126 MOZ_ASSERT(searchStr->type() == MIRType::String); 3127 3128 if (searchStr->isConstant()) { 3129 JSOffThreadAtom* str = searchStr->toConstant()->toString(); 3130 size_t length = str->length(); 3131 if (length == 1 || length == 2) { 3132 LDefinition tempDef = LDefinition::BogusTemp(); 3133 if (length > 1) { 3134 tempDef = temp(); 3135 } 3136 3137 auto* lir = new (alloc()) 3138 LStringIndexOfSIMD(useRegister(string), temp(), temp(), tempDef, str); 3139 define(lir, ins); 3140 assignSafepoint(lir, ins); 3141 return; 3142 } 3143 } 3144 3145 auto* lir = new (alloc()) 3146 LStringIndexOf(useRegisterAtStart(string), useRegisterAtStart(searchStr)); 3147 defineReturn(lir, ins); 3148 assignSafepoint(lir, ins); 3149 } 3150 3151 void LIRGenerator::visitStringLastIndexOf(MStringLastIndexOf* ins) { 3152 auto* string = ins->string(); 3153 MOZ_ASSERT(string->type() == MIRType::String); 3154 3155 auto* searchStr = ins->searchString(); 3156 MOZ_ASSERT(searchStr->type() == MIRType::String); 3157 3158 auto* lir = new (alloc()) LStringLastIndexOf(useRegisterAtStart(string), 3159 useRegisterAtStart(searchStr)); 3160 defineReturn(lir, ins); 3161 assignSafepoint(lir, ins); 3162 } 3163 3164 void LIRGenerator::visitStringStartsWith(MStringStartsWith* ins) { 3165 auto* string = ins->string(); 3166 MOZ_ASSERT(string->type() == MIRType::String); 3167 3168 auto* searchStr = ins->searchString(); 3169 MOZ_ASSERT(searchStr->type() == MIRType::String); 3170 3171 if (searchStr->isConstant()) { 3172 JSOffThreadAtom* str = searchStr->toConstant()->toString(); 3173 3174 if (MacroAssembler::canCompareStringCharsInline(str)) { 3175 auto* lir = new (alloc()) 3176 LStringStartsWithInline(useRegister(string), temp(), str); 3177 define(lir, ins); 3178 assignSafepoint(lir, ins); 3179 return; 3180 } 3181 } 3182 3183 auto* lir = new (alloc()) LStringStartsWith(useRegisterAtStart(string), 3184 useRegisterAtStart(searchStr)); 3185 defineReturn(lir, ins); 3186 assignSafepoint(lir, ins); 3187 } 3188 3189 void LIRGenerator::visitStringEndsWith(MStringEndsWith* ins) { 3190 auto* string = ins->string(); 3191 MOZ_ASSERT(string->type() == MIRType::String); 3192 3193 auto* searchStr = ins->searchString(); 3194 MOZ_ASSERT(searchStr->type() == MIRType::String); 3195 3196 if (searchStr->isConstant()) { 3197 JSOffThreadAtom* str = searchStr->toConstant()->toString(); 3198 3199 if (MacroAssembler::canCompareStringCharsInline(str)) { 3200 auto* lir = 3201 new (alloc()) LStringEndsWithInline(useRegister(string), temp(), str); 3202 define(lir, ins); 3203 assignSafepoint(lir, ins); 3204 return; 3205 } 3206 } 3207 3208 auto* lir = new (alloc()) LStringEndsWith(useRegisterAtStart(string), 3209 useRegisterAtStart(searchStr)); 3210 defineReturn(lir, ins); 3211 assignSafepoint(lir, ins); 3212 } 3213 3214 void LIRGenerator::visitStringConvertCase(MStringConvertCase* ins) { 3215 MOZ_ASSERT(ins->string()->type() == MIRType::String); 3216 3217 if (ins->mode() == MStringConvertCase::LowerCase) { 3218 #ifdef JS_CODEGEN_X86 3219 // Due to lack of registers on x86, we reuse the string register as 3220 // temporary. As a result we only need four temporary registers and take a 3221 // bogus temporary as the fifth argument. 3222 LDefinition temp4 = LDefinition::BogusTemp(); 3223 #else 3224 LDefinition temp4 = temp(); 3225 #endif 3226 auto* lir = new (alloc()) 3227 LStringToLowerCase(useRegister(ins->string()), temp(), temp(), temp(), 3228 temp4, tempByteOpRegister()); 3229 define(lir, ins); 3230 assignSafepoint(lir, ins); 3231 } else { 3232 auto* lir = 3233 new (alloc()) LStringToUpperCase(useRegisterAtStart(ins->string())); 3234 defineReturn(lir, ins); 3235 assignSafepoint(lir, ins); 3236 } 3237 } 3238 3239 void LIRGenerator::visitCharCodeConvertCase(MCharCodeConvertCase* ins) { 3240 MOZ_ASSERT(ins->code()->type() == MIRType::Int32); 3241 3242 if (ins->mode() == MCharCodeConvertCase::LowerCase) { 3243 auto* lir = new (alloc()) 3244 LCharCodeToLowerCase(useRegister(ins->code()), tempByteOpRegister()); 3245 define(lir, ins); 3246 assignSafepoint(lir, ins); 3247 } else { 3248 auto* lir = new (alloc()) 3249 LCharCodeToUpperCase(useRegister(ins->code()), tempByteOpRegister()); 3250 define(lir, ins); 3251 assignSafepoint(lir, ins); 3252 } 3253 } 3254 3255 void LIRGenerator::visitStringTrimStartIndex(MStringTrimStartIndex* ins) { 3256 auto* string = ins->string(); 3257 MOZ_ASSERT(string->type() == MIRType::String); 3258 3259 auto* lir = new (alloc()) LStringTrimStartIndex(useRegister(string)); 3260 define(lir, ins); 3261 assignSafepoint(lir, ins); 3262 } 3263 3264 void LIRGenerator::visitStringTrimEndIndex(MStringTrimEndIndex* ins) { 3265 auto* string = ins->string(); 3266 MOZ_ASSERT(string->type() == MIRType::String); 3267 3268 auto* start = ins->start(); 3269 MOZ_ASSERT(start->type() == MIRType::Int32); 3270 3271 auto* lir = new (alloc()) 3272 LStringTrimEndIndex(useRegister(string), useRegister(start)); 3273 define(lir, ins); 3274 assignSafepoint(lir, ins); 3275 } 3276 3277 void LIRGenerator::visitStart(MStart* start) {} 3278 3279 void LIRGenerator::visitNop(MNop* nop) {} 3280 3281 void LIRGenerator::visitLimitedTruncate(MLimitedTruncate* nop) { 3282 redefine(nop, nop->input()); 3283 } 3284 3285 void LIRGenerator::visitIntPtrLimitedTruncate(MIntPtrLimitedTruncate* ins) { 3286 MOZ_ASSERT(ins->input()->type() == MIRType::IntPtr); 3287 3288 // This is a no-op. 3289 redefine(ins, ins->input()); 3290 } 3291 3292 void LIRGenerator::visitInt64LimitedTruncate(MInt64LimitedTruncate* ins) { 3293 MOZ_ASSERT(ins->input()->type() == MIRType::Int64); 3294 3295 // This is a no-op. 3296 redefine(ins, ins->input()); 3297 } 3298 3299 void LIRGenerator::visitOsrEntry(MOsrEntry* entry) { 3300 LOsrEntry* lir = new (alloc()) LOsrEntry(temp()); 3301 defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg))); 3302 } 3303 3304 void LIRGenerator::visitOsrValue(MOsrValue* value) { 3305 LOsrValue* lir = new (alloc()) LOsrValue(useRegister(value->entry())); 3306 defineBox(lir, value); 3307 } 3308 3309 void LIRGenerator::visitOsrReturnValue(MOsrReturnValue* value) { 3310 LOsrReturnValue* lir = 3311 new (alloc()) LOsrReturnValue(useRegister(value->entry())); 3312 defineBox(lir, value); 3313 } 3314 3315 void LIRGenerator::visitOsrEnvironmentChain(MOsrEnvironmentChain* object) { 3316 LOsrEnvironmentChain* lir = 3317 new (alloc()) LOsrEnvironmentChain(useRegister(object->entry())); 3318 define(lir, object); 3319 } 3320 3321 void LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject* object) { 3322 LOsrArgumentsObject* lir = 3323 new (alloc()) LOsrArgumentsObject(useRegister(object->entry())); 3324 define(lir, object); 3325 } 3326 3327 void LIRGenerator::visitToDouble(MToDouble* convert) { 3328 MDefinition* opd = convert->input(); 3329 3330 switch (opd->type()) { 3331 case MIRType::Value: { 3332 LValueToDouble* lir = new (alloc()) LValueToDouble(useBox(opd)); 3333 assignSnapshot(lir, convert->bailoutKind()); 3334 define(lir, convert); 3335 break; 3336 } 3337 3338 case MIRType::Null: 3339 lowerConstantDouble(0, convert); 3340 break; 3341 3342 case MIRType::Undefined: 3343 lowerConstantDouble(GenericNaN(), convert); 3344 break; 3345 3346 case MIRType::Boolean: 3347 case MIRType::Int32: { 3348 LInt32ToDouble* lir = 3349 new (alloc()) LInt32ToDouble(useRegisterAtStart(opd)); 3350 define(lir, convert); 3351 break; 3352 } 3353 3354 case MIRType::Float32: { 3355 LFloat32ToDouble* lir = 3356 new (alloc()) LFloat32ToDouble(useRegisterAtStart(opd)); 3357 define(lir, convert); 3358 break; 3359 } 3360 3361 case MIRType::Double: 3362 redefine(convert, opd); 3363 break; 3364 3365 default: 3366 // Objects might be effectful. Symbols will throw. 3367 // Strings are complicated - we don't handle them yet. 3368 MOZ_CRASH("unexpected type"); 3369 } 3370 } 3371 3372 void LIRGenerator::visitToFloat32(MToFloat32* convert) { 3373 MDefinition* opd = convert->input(); 3374 3375 switch (opd->type()) { 3376 case MIRType::Value: { 3377 LValueToFloat32* lir = new (alloc()) LValueToFloat32(useBox(opd)); 3378 assignSnapshot(lir, convert->bailoutKind()); 3379 define(lir, convert); 3380 break; 3381 } 3382 3383 case MIRType::Null: 3384 lowerConstantFloat32(0, convert); 3385 break; 3386 3387 case MIRType::Undefined: 3388 lowerConstantFloat32(GenericNaN(), convert); 3389 break; 3390 3391 case MIRType::Boolean: 3392 case MIRType::Int32: { 3393 LInt32ToFloat32* lir = 3394 new (alloc()) LInt32ToFloat32(useRegisterAtStart(opd)); 3395 define(lir, convert); 3396 break; 3397 } 3398 3399 case MIRType::Double: { 3400 LDoubleToFloat32* lir = 3401 new (alloc()) LDoubleToFloat32(useRegisterAtStart(opd)); 3402 define(lir, convert); 3403 break; 3404 } 3405 3406 case MIRType::Float32: 3407 redefine(convert, opd); 3408 break; 3409 3410 default: 3411 // Objects might be effectful. Symbols will throw. 3412 // Strings are complicated - we don't handle them yet. 3413 MOZ_CRASH("unexpected type"); 3414 } 3415 } 3416 3417 void LIRGenerator::visitToFloat16(MToFloat16* convert) { 3418 MDefinition* opd = convert->input(); 3419 3420 switch (opd->type()) { 3421 case MIRType::Value: { 3422 LDefinition tempDef = LDefinition::BogusTemp(); 3423 if (!MacroAssembler::SupportsFloat64To16()) { 3424 tempDef = temp(); 3425 } 3426 3427 auto* lir = new (alloc()) LValueToFloat16(useBox(opd), tempDef); 3428 assignSnapshot(lir, convert->bailoutKind()); 3429 define(lir, convert); 3430 3431 if (!MacroAssembler::SupportsFloat64To16()) { 3432 assignSafepoint(lir, convert); 3433 } 3434 break; 3435 } 3436 3437 case MIRType::Null: 3438 lowerConstantFloat32(0, convert); 3439 break; 3440 3441 case MIRType::Undefined: 3442 lowerConstantFloat32(GenericNaN(), convert); 3443 break; 3444 3445 case MIRType::Boolean: 3446 case MIRType::Int32: { 3447 LDefinition tempDef = LDefinition::BogusTemp(); 3448 if (!MacroAssembler::SupportsFloat32To16()) { 3449 tempDef = temp(); 3450 } 3451 3452 auto* lir = 3453 new (alloc()) LInt32ToFloat16(useRegisterAtStart(opd), tempDef); 3454 define(lir, convert); 3455 3456 if (!MacroAssembler::SupportsFloat32To16()) { 3457 assignSafepoint(lir, convert); 3458 } 3459 break; 3460 } 3461 3462 case MIRType::Double: { 3463 if (MacroAssembler::SupportsFloat64To16()) { 3464 auto* lir = new (alloc()) 3465 LDoubleToFloat16(useRegisterAtStart(opd), LDefinition::BogusTemp()); 3466 define(lir, convert); 3467 } else if (MacroAssembler::SupportsFloat32To16()) { 3468 auto* lir = new (alloc()) 3469 LDoubleToFloat32ToFloat16(useRegister(opd), temp(), temp()); 3470 define(lir, convert); 3471 } else { 3472 auto* lir = 3473 new (alloc()) LDoubleToFloat16(useRegisterAtStart(opd), temp()); 3474 define(lir, convert); 3475 assignSafepoint(lir, convert); 3476 } 3477 break; 3478 } 3479 3480 case MIRType::Float32: { 3481 LDefinition tempDef = LDefinition::BogusTemp(); 3482 if (!MacroAssembler::SupportsFloat32To16()) { 3483 tempDef = temp(); 3484 } 3485 3486 auto* lir = 3487 new (alloc()) LFloat32ToFloat16(useRegisterAtStart(opd), tempDef); 3488 define(lir, convert); 3489 3490 if (!MacroAssembler::SupportsFloat32To16()) { 3491 assignSafepoint(lir, convert); 3492 } 3493 break; 3494 } 3495 3496 default: 3497 // Objects might be effectful. Symbols will throw. 3498 // Strings are complicated - we don't handle them yet. 3499 MOZ_CRASH("unexpected type"); 3500 } 3501 } 3502 3503 void LIRGenerator::visitToNumberInt32(MToNumberInt32* convert) { 3504 MDefinition* opd = convert->input(); 3505 3506 switch (opd->type()) { 3507 case MIRType::Value: { 3508 auto* lir = new (alloc()) LValueToNumberInt32(useBox(opd), tempDouble()); 3509 assignSnapshot(lir, convert->bailoutKind()); 3510 define(lir, convert); 3511 break; 3512 } 3513 3514 case MIRType::Null: 3515 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any); 3516 define(new (alloc()) LInteger(0), convert); 3517 break; 3518 3519 case MIRType::Boolean: 3520 MOZ_ASSERT(convert->conversion() == IntConversionInputKind::Any); 3521 redefine(convert, opd); 3522 break; 3523 3524 case MIRType::Int32: 3525 redefine(convert, opd); 3526 break; 3527 3528 case MIRType::Float32: { 3529 LFloat32ToInt32* lir = new (alloc()) LFloat32ToInt32(useRegister(opd)); 3530 assignSnapshot(lir, convert->bailoutKind()); 3531 define(lir, convert); 3532 break; 3533 } 3534 3535 case MIRType::Double: { 3536 LDoubleToInt32* lir = new (alloc()) LDoubleToInt32(useRegister(opd)); 3537 assignSnapshot(lir, convert->bailoutKind()); 3538 define(lir, convert); 3539 break; 3540 } 3541 3542 case MIRType::String: 3543 case MIRType::Symbol: 3544 case MIRType::BigInt: 3545 case MIRType::Object: 3546 case MIRType::Undefined: 3547 // Objects might be effectful. Symbols and BigInts throw. Undefined 3548 // coerces to NaN, not int32. 3549 MOZ_CRASH("ToInt32 invalid input type"); 3550 3551 default: 3552 MOZ_CRASH("unexpected type"); 3553 } 3554 } 3555 3556 void LIRGenerator::visitBooleanToInt32(MBooleanToInt32* convert) { 3557 MDefinition* opd = convert->input(); 3558 MOZ_ASSERT(opd->type() == MIRType::Boolean); 3559 redefine(convert, opd); 3560 } 3561 3562 void LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate) { 3563 MDefinition* opd = truncate->input(); 3564 3565 switch (opd->type()) { 3566 case MIRType::Value: { 3567 auto* lir = new (alloc()) 3568 LValueTruncateToInt32(useBox(opd), tempDouble(), temp()); 3569 assignSnapshot(lir, truncate->bailoutKind()); 3570 define(lir, truncate); 3571 assignSafepoint(lir, truncate); 3572 break; 3573 } 3574 3575 case MIRType::Null: 3576 case MIRType::Undefined: 3577 define(new (alloc()) LInteger(0), truncate); 3578 break; 3579 3580 case MIRType::Int32: 3581 case MIRType::Boolean: 3582 redefine(truncate, opd); 3583 break; 3584 3585 case MIRType::Double: 3586 // May call into JS::ToInt32() on the slow OOL path. 3587 gen->setNeedsStaticStackAlignment(); 3588 lowerTruncateDToInt32(truncate); 3589 break; 3590 3591 case MIRType::Float32: 3592 // May call into JS::ToInt32() on the slow OOL path. 3593 gen->setNeedsStaticStackAlignment(); 3594 lowerTruncateFToInt32(truncate); 3595 break; 3596 3597 default: 3598 // Objects might be effectful. Symbols throw. 3599 // Strings are complicated - we don't handle them yet. 3600 MOZ_CRASH("unexpected type"); 3601 } 3602 } 3603 3604 void LIRGenerator::visitInt32ToIntPtr(MInt32ToIntPtr* ins) { 3605 MDefinition* input = ins->input(); 3606 MOZ_ASSERT(input->type() == MIRType::Int32); 3607 MOZ_ASSERT(ins->type() == MIRType::IntPtr); 3608 3609 #ifdef JS_64BIT 3610 // If the result is only used by instructions that expect a bounds-checked 3611 // index, we must have eliminated or hoisted a bounds check and we can assume 3612 // the index is non-negative. This lets us generate more efficient code. 3613 if (ins->canBeNegative()) { 3614 bool canBeNegative = false; 3615 for (MUseDefIterator iter(ins); iter; iter++) { 3616 if (iter.def()->isSpectreMaskIndex()) { 3617 continue; 3618 } 3619 if (iter.def()->isLoadUnboxedScalar() || 3620 iter.def()->isStoreUnboxedScalar() || 3621 iter.def()->isLoadDataViewElement() || 3622 iter.def()->isStoreDataViewElement()) { 3623 MOZ_ASSERT(iter.def()->indexOf(iter.use()) == 1, 3624 "unexpected non-index operand use"); 3625 continue; 3626 } 3627 3628 canBeNegative = true; 3629 break; 3630 } 3631 if (!canBeNegative) { 3632 ins->setCanNotBeNegative(); 3633 } 3634 } 3635 3636 if (ins->canBeNegative()) { 3637 auto* lir = new (alloc()) LInt32ToIntPtr(useAnyAtStart(input)); 3638 define(lir, ins); 3639 } else { 3640 redefine(ins, input); 3641 } 3642 #else 3643 // On 32-bit platforms this is a no-op. 3644 redefine(ins, input); 3645 #endif 3646 } 3647 3648 void LIRGenerator::visitNonNegativeIntPtrToInt32( 3649 MNonNegativeIntPtrToInt32* ins) { 3650 MDefinition* input = ins->input(); 3651 MOZ_ASSERT(input->type() == MIRType::IntPtr); 3652 MOZ_ASSERT(ins->type() == MIRType::Int32); 3653 3654 #ifdef JS_64BIT 3655 auto* lir = 3656 new (alloc()) LNonNegativeIntPtrToInt32(useRegisterAtStart(input)); 3657 assignSnapshot(lir, ins->bailoutKind()); 3658 defineReuseInput(lir, ins, 0); 3659 #else 3660 // On 32-bit platforms this is a no-op. 3661 redefine(ins, input); 3662 #endif 3663 } 3664 3665 void LIRGenerator::visitWasmExtendU32Index(MWasmExtendU32Index* ins) { 3666 #ifdef JS_64BIT 3667 // Technically this produces an Int64 register and I guess we could clean that 3668 // up, but it's a 64-bit only operation, so it doesn't actually matter. 3669 3670 MDefinition* input = ins->input(); 3671 MOZ_ASSERT(input->type() == MIRType::Int32); 3672 MOZ_ASSERT(ins->type() == MIRType::Int64); 3673 3674 // Input reuse is OK even on ARM64 because this node *must* reuse its input in 3675 // order not to generate any code at all, as is the intent. 3676 auto* lir = new (alloc()) LWasmExtendU32Index(useRegisterAtStart(input)); 3677 defineReuseInput(lir, ins, 0); 3678 #else 3679 MOZ_CRASH("64-bit only"); 3680 #endif 3681 } 3682 3683 void LIRGenerator::visitWasmWrapU32Index(MWasmWrapU32Index* ins) { 3684 MDefinition* input = ins->input(); 3685 MOZ_ASSERT(input->type() == MIRType::Int64); 3686 MOZ_ASSERT(ins->type() == MIRType::Int32); 3687 3688 // Tricky: On 64-bit, this just returns its input (except on MIPS64 there may 3689 // be a sign/zero extension). On 32-bit, it returns the low register of the 3690 // input, and should generate no code. 3691 3692 #ifdef JS_64BIT 3693 LAllocation index = useRegisterAtStart(input); 3694 #else 3695 LAllocation index = useLowWordRegisterAtStart(input); 3696 #endif 3697 3698 auto* lir = new (alloc()) LWasmWrapU32Index(index); 3699 defineReuseInput(lir, ins, 0); 3700 } 3701 3702 void LIRGenerator::visitWasmClampTable64Address(MWasmClampTable64Address* ins) { 3703 MDefinition* input = ins->address(); 3704 MOZ_ASSERT(input->type() == MIRType::Int64); 3705 MOZ_ASSERT(ins->type() == MIRType::Int32); 3706 3707 auto* lir = 3708 new (alloc()) LWasmClampTable64Address(useInt64RegisterAtStart(input)); 3709 define(lir, ins); 3710 } 3711 3712 void LIRGenerator::visitIntPtrToDouble(MIntPtrToDouble* ins) { 3713 MDefinition* input = ins->input(); 3714 MOZ_ASSERT(input->type() == MIRType::IntPtr); 3715 MOZ_ASSERT(ins->type() == MIRType::Double); 3716 3717 auto* lir = new (alloc()) LIntPtrToDouble(useRegister(input)); 3718 define(lir, ins); 3719 } 3720 3721 void LIRGenerator::visitAdjustDataViewLength(MAdjustDataViewLength* ins) { 3722 MDefinition* input = ins->input(); 3723 MOZ_ASSERT(input->type() == MIRType::IntPtr); 3724 3725 auto* lir = new (alloc()) LAdjustDataViewLength(useRegisterAtStart(input)); 3726 assignSnapshot(lir, ins->bailoutKind()); 3727 defineReuseInput(lir, ins, 0); 3728 } 3729 3730 void LIRGenerator::visitToBigInt(MToBigInt* ins) { 3731 MDefinition* opd = ins->input(); 3732 3733 switch (opd->type()) { 3734 case MIRType::Value: { 3735 auto* lir = new (alloc()) LValueToBigInt(useBox(opd)); 3736 assignSnapshot(lir, ins->bailoutKind()); 3737 define(lir, ins); 3738 assignSafepoint(lir, ins); 3739 break; 3740 } 3741 3742 case MIRType::BigInt: 3743 redefine(ins, opd); 3744 break; 3745 3746 default: 3747 MOZ_CRASH("unexpected type"); 3748 } 3749 } 3750 3751 void LIRGenerator::visitToInt64(MToInt64* ins) { 3752 MDefinition* opd = ins->input(); 3753 3754 switch (opd->type()) { 3755 case MIRType::Value: { 3756 auto* lir = new (alloc()) LValueToInt64(useBox(opd), temp()); 3757 assignSnapshot(lir, ins->bailoutKind()); 3758 defineInt64(lir, ins); 3759 assignSafepoint(lir, ins); 3760 break; 3761 } 3762 3763 case MIRType::Boolean: { 3764 auto* lir = new (alloc()) LBooleanToInt64(useRegisterAtStart(opd)); 3765 defineInt64(lir, ins); 3766 break; 3767 } 3768 3769 case MIRType::String: { 3770 auto* lir = new (alloc()) LStringToInt64(useRegister(opd)); 3771 defineInt64(lir, ins); 3772 assignSafepoint(lir, ins); 3773 break; 3774 } 3775 3776 // An Int64 may be passed here from a BigInt to Int64 conversion. 3777 case MIRType::Int64: { 3778 redefine(ins, opd); 3779 break; 3780 } 3781 3782 default: 3783 // Undefined, Null, Number, and Symbol throw. 3784 // Objects may be effectful. 3785 // BigInt operands are eliminated by the type policy. 3786 MOZ_CRASH("unexpected type"); 3787 } 3788 } 3789 3790 void LIRGenerator::visitTruncateBigIntToInt64(MTruncateBigIntToInt64* ins) { 3791 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt); 3792 auto* lir = new (alloc()) LTruncateBigIntToInt64(useRegister(ins->input())); 3793 defineInt64(lir, ins); 3794 } 3795 3796 void LIRGenerator::visitInt64ToBigInt(MInt64ToBigInt* ins) { 3797 MOZ_ASSERT(ins->input()->type() == MIRType::Int64); 3798 3799 if (ins->isSigned()) { 3800 auto* lir = new (alloc()) 3801 LInt64ToBigInt(useInt64Register(ins->input()), tempInt64()); 3802 define(lir, ins); 3803 assignSafepoint(lir, ins); 3804 } else { 3805 auto* lir = 3806 new (alloc()) LUint64ToBigInt(useInt64Register(ins->input()), temp()); 3807 define(lir, ins); 3808 assignSafepoint(lir, ins); 3809 } 3810 } 3811 3812 void LIRGenerator::visitInt64ToIntPtr(MInt64ToIntPtr* ins) { 3813 MOZ_ASSERT(ins->input()->type() == MIRType::Int64); 3814 3815 #ifdef JS_64BIT 3816 if (ins->isSigned()) { 3817 redefine(ins, ins->input()); 3818 return; 3819 } 3820 #endif 3821 3822 auto* lir = 3823 new (alloc()) LInt64ToIntPtr(useInt64RegisterAtStart(ins->input())); 3824 assignSnapshot(lir, ins->bailoutKind()); 3825 #ifdef JS_64BIT 3826 defineReuseInput(lir, ins, 0); 3827 #else 3828 define(lir, ins); 3829 #endif 3830 } 3831 3832 void LIRGenerator::visitIntPtrToInt64(MIntPtrToInt64* ins) { 3833 MOZ_ASSERT(ins->input()->type() == MIRType::IntPtr); 3834 3835 #ifdef JS_64BIT 3836 redefine(ins, ins->input()); 3837 #else 3838 auto* lir = new (alloc()) LIntPtrToInt64(useRegister(ins->input())); 3839 defineInt64(lir, ins); 3840 #endif 3841 } 3842 3843 void LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins) { 3844 MDefinition* input = ins->input(); 3845 switch (input->type()) { 3846 case MIRType::Double: 3847 case MIRType::Float32: { 3848 auto* lir = new (alloc()) LWasmTruncateToInt32(useRegisterAtStart(input)); 3849 define(lir, ins); 3850 break; 3851 } 3852 default: 3853 MOZ_CRASH("unexpected type in WasmTruncateToInt32"); 3854 } 3855 } 3856 3857 void LIRGenerator::visitWasmBuiltinTruncateToInt32( 3858 MWasmBuiltinTruncateToInt32* truncate) { 3859 mozilla::DebugOnly<MDefinition*> opd = truncate->input(); 3860 MOZ_ASSERT(opd->type() == MIRType::Double || opd->type() == MIRType::Float32); 3861 3862 // May call into JS::ToInt32() on the slow OOL path. 3863 gen->setNeedsStaticStackAlignment(); 3864 lowerWasmBuiltinTruncateToInt32(truncate); 3865 } 3866 3867 void LIRGenerator::visitWasmAnyRefFromJSValue(MWasmAnyRefFromJSValue* ins) { 3868 LWasmAnyRefFromJSValue* lir = 3869 new (alloc()) LWasmAnyRefFromJSValue(useBox(ins->input()), tempDouble()); 3870 define(lir, ins); 3871 assignSafepoint(lir, ins); 3872 } 3873 3874 void LIRGenerator::visitWasmAnyRefFromJSObject(MWasmAnyRefFromJSObject* ins) { 3875 LWasmAnyRefFromJSObject* lir = 3876 new (alloc()) LWasmAnyRefFromJSObject(useRegisterAtStart(ins->input())); 3877 define(lir, ins); 3878 } 3879 3880 void LIRGenerator::visitWasmAnyRefFromJSString(MWasmAnyRefFromJSString* ins) { 3881 LWasmAnyRefFromJSString* lir = 3882 new (alloc()) LWasmAnyRefFromJSString(useRegisterAtStart(ins->input())); 3883 define(lir, ins); 3884 } 3885 3886 void LIRGenerator::visitWasmAnyRefIsJSString(MWasmAnyRefIsJSString* ins) { 3887 LWasmAnyRefIsJSString* lir = new (alloc()) 3888 LWasmAnyRefIsJSString(useRegisterAtStart(ins->input()), temp()); 3889 define(lir, ins); 3890 } 3891 3892 void LIRGenerator::visitWasmTrapIfAnyRefIsNotJSString( 3893 MWasmTrapIfAnyRefIsNotJSString* ins) { 3894 LWasmTrapIfAnyRefIsNotJSString* lir = new (alloc()) 3895 LWasmTrapIfAnyRefIsNotJSString(useRegisterAtStart(ins->input()), temp()); 3896 add(lir, ins); 3897 } 3898 3899 void LIRGenerator::visitWasmAnyRefJSStringLength( 3900 MWasmAnyRefJSStringLength* ins) { 3901 LWasmAnyRefJSStringLength* lir = new (alloc()) 3902 LWasmAnyRefJSStringLength(useRegisterAtStart(ins->input()), temp()); 3903 define(lir, ins); 3904 } 3905 3906 void LIRGenerator::visitWasmNewI31Ref(MWasmNewI31Ref* ins) { 3907 // If it's a constant, it will be put directly into the register. 3908 LWasmNewI31Ref* lir = 3909 new (alloc()) LWasmNewI31Ref(useRegisterOrConstant(ins->input())); 3910 define(lir, ins); 3911 } 3912 3913 void LIRGenerator::visitWasmI31RefGet(MWasmI31RefGet* ins) { 3914 LWasmI31RefGet* lir = new (alloc()) LWasmI31RefGet(useRegister(ins->input())); 3915 define(lir, ins); 3916 } 3917 3918 void LIRGenerator::visitWrapInt64ToInt32(MWrapInt64ToInt32* ins) { 3919 define(new (alloc()) LWrapInt64ToInt32(useInt64AtStart(ins->input())), ins); 3920 } 3921 3922 void LIRGenerator::visitToString(MToString* ins) { 3923 MDefinition* opd = ins->input(); 3924 3925 switch (opd->type()) { 3926 case MIRType::Null: { 3927 const JSAtomState& names = gen->runtime->names(); 3928 LPointer* lir = new (alloc()) LPointer(names.null); 3929 define(lir, ins); 3930 break; 3931 } 3932 3933 case MIRType::Undefined: { 3934 const JSAtomState& names = gen->runtime->names(); 3935 LPointer* lir = new (alloc()) LPointer(names.undefined); 3936 define(lir, ins); 3937 break; 3938 } 3939 3940 case MIRType::Boolean: { 3941 LBooleanToString* lir = new (alloc()) LBooleanToString(useRegister(opd)); 3942 define(lir, ins); 3943 break; 3944 } 3945 3946 case MIRType::Double: { 3947 LDoubleToString* lir = 3948 new (alloc()) LDoubleToString(useRegister(opd), temp()); 3949 3950 define(lir, ins); 3951 assignSafepoint(lir, ins); 3952 break; 3953 } 3954 3955 case MIRType::Int32: { 3956 LIntToString* lir = new (alloc()) LIntToString(useRegister(opd)); 3957 3958 define(lir, ins); 3959 assignSafepoint(lir, ins); 3960 break; 3961 } 3962 3963 case MIRType::String: 3964 redefine(ins, ins->input()); 3965 break; 3966 3967 case MIRType::Value: { 3968 LValueToString* lir = 3969 new (alloc()) LValueToString(useBox(opd), tempToUnbox()); 3970 if (ins->needsSnapshot()) { 3971 assignSnapshot(lir, ins->bailoutKind()); 3972 } 3973 define(lir, ins); 3974 assignSafepoint(lir, ins); 3975 break; 3976 } 3977 3978 default: 3979 // Float32, symbols, bigint, and objects are not supported. 3980 MOZ_CRASH("unexpected type"); 3981 } 3982 } 3983 3984 void LIRGenerator::visitRegExp(MRegExp* ins) { 3985 LRegExp* lir = new (alloc()) LRegExp(temp()); 3986 define(lir, ins); 3987 assignSafepoint(lir, ins); 3988 } 3989 3990 void LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins) { 3991 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object); 3992 MOZ_ASSERT(ins->string()->type() == MIRType::String); 3993 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32); 3994 3995 LRegExpMatcher* lir = new (alloc()) LRegExpMatcher( 3996 useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg), 3997 useFixedAtStart(ins->string(), RegExpMatcherStringReg), 3998 useFixedAtStart(ins->lastIndex(), RegExpMatcherLastIndexReg)); 3999 defineReturn(lir, ins); 4000 assignSafepoint(lir, ins); 4001 } 4002 4003 void LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins) { 4004 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object); 4005 MOZ_ASSERT(ins->string()->type() == MIRType::String); 4006 MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32); 4007 4008 LRegExpSearcher* lir = new (alloc()) LRegExpSearcher( 4009 useFixedAtStart(ins->regexp(), RegExpSearcherRegExpReg), 4010 useFixedAtStart(ins->string(), RegExpSearcherStringReg), 4011 useFixedAtStart(ins->lastIndex(), RegExpSearcherLastIndexReg)); 4012 defineReturn(lir, ins); 4013 assignSafepoint(lir, ins); 4014 } 4015 4016 void LIRGenerator::visitRegExpSearcherLastLimit(MRegExpSearcherLastLimit* ins) { 4017 auto* lir = new (alloc()) LRegExpSearcherLastLimit(temp()); 4018 define(lir, ins); 4019 } 4020 4021 void LIRGenerator::visitRegExpExecMatch(MRegExpExecMatch* ins) { 4022 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object); 4023 MOZ_ASSERT(ins->string()->type() == MIRType::String); 4024 4025 auto* lir = new (alloc()) 4026 LRegExpExecMatch(useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg), 4027 useFixedAtStart(ins->string(), RegExpMatcherStringReg)); 4028 defineReturn(lir, ins); 4029 assignSafepoint(lir, ins); 4030 } 4031 4032 void LIRGenerator::visitRegExpExecTest(MRegExpExecTest* ins) { 4033 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object); 4034 MOZ_ASSERT(ins->string()->type() == MIRType::String); 4035 4036 auto* lir = new (alloc()) 4037 LRegExpExecTest(useFixedAtStart(ins->regexp(), RegExpExecTestRegExpReg), 4038 useFixedAtStart(ins->string(), RegExpExecTestStringReg)); 4039 defineReturn(lir, ins); 4040 assignSafepoint(lir, ins); 4041 } 4042 4043 void LIRGenerator::visitRegExpHasCaptureGroups(MRegExpHasCaptureGroups* ins) { 4044 MOZ_ASSERT(ins->regexp()->type() == MIRType::Object); 4045 MOZ_ASSERT(ins->input()->type() == MIRType::String); 4046 MOZ_ASSERT(ins->type() == MIRType::Boolean); 4047 4048 auto* lir = new (alloc()) LRegExpHasCaptureGroups(useRegister(ins->regexp()), 4049 useRegister(ins->input())); 4050 define(lir, ins); 4051 assignSafepoint(lir, ins); 4052 } 4053 4054 void LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex* ins) { 4055 MOZ_ASSERT(ins->str()->type() == MIRType::String); 4056 MOZ_ASSERT(ins->type() == MIRType::Int32); 4057 LGetFirstDollarIndex* lir = new (alloc()) 4058 LGetFirstDollarIndex(useRegister(ins->str()), temp(), temp(), temp()); 4059 define(lir, ins); 4060 assignSafepoint(lir, ins); 4061 } 4062 4063 void LIRGenerator::visitStringReplace(MStringReplace* ins) { 4064 MOZ_ASSERT(ins->pattern()->type() == MIRType::String); 4065 MOZ_ASSERT(ins->string()->type() == MIRType::String); 4066 MOZ_ASSERT(ins->replacement()->type() == MIRType::String); 4067 4068 LStringReplace* lir = new (alloc()) 4069 LStringReplace(useRegisterOrConstantAtStart(ins->string()), 4070 useRegisterAtStart(ins->pattern()), 4071 useRegisterOrConstantAtStart(ins->replacement())); 4072 defineReturn(lir, ins); 4073 assignSafepoint(lir, ins); 4074 } 4075 4076 void LIRGenerator::visitBinaryCache(MBinaryCache* ins) { 4077 MDefinition* lhs = ins->getOperand(0); 4078 MDefinition* rhs = ins->getOperand(1); 4079 4080 MOZ_ASSERT(ins->type() == MIRType::Value || ins->type() == MIRType::Boolean); 4081 LInstruction* lir; 4082 if (ins->type() == MIRType::Value) { 4083 LBinaryValueCache* valueLir = new (alloc()) LBinaryValueCache( 4084 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1)); 4085 defineBox(valueLir, ins); 4086 lir = valueLir; 4087 } else { 4088 MOZ_ASSERT(ins->type() == MIRType::Boolean); 4089 LBinaryBoolCache* boolLir = new (alloc()) LBinaryBoolCache( 4090 useBox(lhs), useBox(rhs), tempFixed(FloatReg0), tempFixed(FloatReg1)); 4091 define(boolLir, ins); 4092 lir = boolLir; 4093 } 4094 assignSafepoint(lir, ins); 4095 } 4096 4097 void LIRGenerator::visitUnaryCache(MUnaryCache* ins) { 4098 MDefinition* input = ins->getOperand(0); 4099 MOZ_ASSERT(ins->type() == MIRType::Value); 4100 4101 LUnaryCache* lir = new (alloc()) LUnaryCache(useBox(input)); 4102 defineBox(lir, ins); 4103 assignSafepoint(lir, ins); 4104 } 4105 4106 void LIRGenerator::visitModuleMetadata(MModuleMetadata* ins) { 4107 LModuleMetadata* lir = new (alloc()) LModuleMetadata(); 4108 defineReturn(lir, ins); 4109 assignSafepoint(lir, ins); 4110 } 4111 4112 void LIRGenerator::visitDynamicImport(MDynamicImport* ins) { 4113 LDynamicImport* lir = new (alloc()) LDynamicImport( 4114 useBoxAtStart(ins->specifier()), useBoxAtStart(ins->options())); 4115 defineReturn(lir, ins); 4116 assignSafepoint(lir, ins); 4117 } 4118 4119 void LIRGenerator::visitLambda(MLambda* ins) { 4120 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object); 4121 4122 auto* lir = 4123 new (alloc()) LLambda(useRegister(ins->environmentChain()), temp()); 4124 define(lir, ins); 4125 assignSafepoint(lir, ins); 4126 } 4127 4128 void LIRGenerator::visitFunctionWithProto(MFunctionWithProto* ins) { 4129 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object); 4130 MOZ_ASSERT(ins->prototype()->type() == MIRType::Object); 4131 4132 auto* lir = new (alloc()) 4133 LFunctionWithProto(useRegisterAtStart(ins->environmentChain()), 4134 useRegisterAtStart(ins->prototype())); 4135 defineReturn(lir, ins); 4136 assignSafepoint(lir, ins); 4137 } 4138 4139 void LIRGenerator::visitSetFunName(MSetFunName* ins) { 4140 MOZ_ASSERT(ins->fun()->type() == MIRType::Object); 4141 MOZ_ASSERT(ins->name()->type() == MIRType::Value); 4142 4143 LSetFunName* lir = new (alloc()) 4144 LSetFunName(useRegisterAtStart(ins->fun()), useBoxAtStart(ins->name())); 4145 add(lir, ins); 4146 assignSafepoint(lir, ins); 4147 } 4148 4149 void LIRGenerator::visitNewLexicalEnvironmentObject( 4150 MNewLexicalEnvironmentObject* ins) { 4151 auto* lir = new (alloc()) LNewLexicalEnvironmentObject(temp()); 4152 4153 define(lir, ins); 4154 assignSafepoint(lir, ins); 4155 } 4156 4157 void LIRGenerator::visitNewClassBodyEnvironmentObject( 4158 MNewClassBodyEnvironmentObject* ins) { 4159 auto* lir = new (alloc()) LNewClassBodyEnvironmentObject(temp()); 4160 4161 define(lir, ins); 4162 assignSafepoint(lir, ins); 4163 } 4164 4165 void LIRGenerator::visitNewVarEnvironmentObject(MNewVarEnvironmentObject* ins) { 4166 auto* lir = new (alloc()) LNewVarEnvironmentObject(temp()); 4167 4168 define(lir, ins); 4169 assignSafepoint(lir, ins); 4170 } 4171 4172 void LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins) { 4173 MDefinition* obj = ins->object(); 4174 MOZ_ASSERT(obj->type() == MIRType::Object); 4175 4176 add(new (alloc()) LKeepAliveObject(useKeepalive(obj)), ins); 4177 } 4178 4179 void LIRGenerator::visitDebugEnterGCUnsafeRegion( 4180 MDebugEnterGCUnsafeRegion* ins) { 4181 add(new (alloc()) LDebugEnterGCUnsafeRegion(temp()), ins); 4182 } 4183 4184 void LIRGenerator::visitDebugLeaveGCUnsafeRegion( 4185 MDebugLeaveGCUnsafeRegion* ins) { 4186 add(new (alloc()) LDebugLeaveGCUnsafeRegion(temp()), ins); 4187 } 4188 4189 void LIRGenerator::visitSlots(MSlots* ins) { 4190 define(new (alloc()) LSlots(useRegisterAtStart(ins->object())), ins); 4191 } 4192 4193 void LIRGenerator::visitElements(MElements* ins) { 4194 define(new (alloc()) LElements(useRegisterAtStart(ins->object())), ins); 4195 } 4196 4197 void LIRGenerator::visitLoadDynamicSlot(MLoadDynamicSlot* ins) { 4198 MOZ_ASSERT(ins->type() == MIRType::Value); 4199 if (ins->usedAsPropertyKey()) { 4200 auto* lir = new (alloc()) 4201 LLoadDynamicSlotAndAtomize(useRegister(ins->slots()), temp()); 4202 defineBox(lir, ins); 4203 assignSafepoint(lir, ins); 4204 } else { 4205 defineBox(new (alloc()) LLoadDynamicSlotV(useRegisterAtStart(ins->slots())), 4206 ins); 4207 } 4208 } 4209 4210 void LIRGenerator::visitLoadDynamicSlotFromOffset( 4211 MLoadDynamicSlotFromOffset* ins) { 4212 MOZ_ASSERT(ins->slots()->type() == MIRType::Slots); 4213 4214 auto* lir = new (alloc()) LLoadDynamicSlotFromOffset( 4215 useRegisterAtStart(ins->slots()), useRegisterAtStart(ins->offset())); 4216 defineBox(lir, ins); 4217 } 4218 4219 void LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment* ins) { 4220 define(new (alloc()) 4221 LFunctionEnvironment(useRegisterAtStart(ins->function())), 4222 ins); 4223 } 4224 4225 void LIRGenerator::visitHomeObject(MHomeObject* ins) { 4226 define(new (alloc()) LHomeObject(useRegisterAtStart(ins->function())), ins); 4227 } 4228 4229 void LIRGenerator::visitHomeObjectSuperBase(MHomeObjectSuperBase* ins) { 4230 MOZ_ASSERT(ins->homeObject()->type() == MIRType::Object); 4231 MOZ_ASSERT(ins->type() == MIRType::Value); 4232 4233 auto lir = 4234 new (alloc()) LHomeObjectSuperBase(useRegisterAtStart(ins->homeObject())); 4235 defineBox(lir, ins); 4236 } 4237 4238 void LIRGenerator::visitInterruptCheck(MInterruptCheck* ins) { 4239 auto* lir = new (alloc()) LInterruptCheck(); 4240 add(lir, ins); 4241 assignSafepoint(lir, ins); 4242 } 4243 4244 void LIRGenerator::visitWasmInterruptCheck(MWasmInterruptCheck* ins) { 4245 auto* lir = 4246 new (alloc()) LWasmInterruptCheck(useRegisterAtStart(ins->instance())); 4247 add(lir, ins); 4248 assignWasmSafepoint(lir); 4249 } 4250 4251 void LIRGenerator::visitWasmTrap(MWasmTrap* ins) { 4252 add(new (alloc()) LWasmTrap, ins); 4253 } 4254 4255 void LIRGenerator::visitWasmRefAsNonNull(MWasmRefAsNonNull* ins) { 4256 defineReuseInput( 4257 new (alloc()) LWasmRefAsNonNull(useRegisterAtStart(ins->ref())), ins, 0); 4258 } 4259 4260 void LIRGenerator::visitReinterpretCast(MReinterpretCast* ins) { 4261 if (ins->type() == MIRType::Int64) { 4262 defineInt64(new (alloc()) 4263 LReinterpretCastToI64(useRegisterAtStart(ins->input())), 4264 ins); 4265 } else if (ins->input()->type() == MIRType::Int64) { 4266 define(new (alloc()) 4267 LReinterpretCastFromI64(useInt64RegisterAtStart(ins->input())), 4268 ins); 4269 } else { 4270 define(new (alloc()) LReinterpretCast(useRegisterAtStart(ins->input())), 4271 ins); 4272 } 4273 } 4274 4275 void LIRGenerator::visitStoreDynamicSlot(MStoreDynamicSlot* ins) { 4276 switch (ins->value()->type()) { 4277 case MIRType::Value: 4278 add(new (alloc()) LStoreDynamicSlotV(useRegister(ins->slots()), 4279 useBox(ins->value())), 4280 ins); 4281 break; 4282 4283 case MIRType::Double: 4284 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()), 4285 useRegister(ins->value())), 4286 ins); 4287 break; 4288 4289 case MIRType::Float32: 4290 MOZ_CRASH("Float32 shouldn't be stored in a slot."); 4291 4292 default: 4293 add(new (alloc()) LStoreDynamicSlotT(useRegister(ins->slots()), 4294 useRegisterOrConstant(ins->value())), 4295 ins); 4296 break; 4297 } 4298 } 4299 4300 void LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins) { 4301 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4302 4303 // We need a barrier if the value might be allocated in the nursery. If the 4304 // value is a constant, it must be tenured because MIR can't contain nursery 4305 // pointers. 4306 MConstant* constValue = ins->value()->maybeConstantValue(); 4307 if (constValue) { 4308 MOZ_ASSERT(JS::GCPolicy<Value>::isTenured(constValue->toJSValue())); 4309 return; 4310 } 4311 4312 switch (ins->value()->type()) { 4313 case MIRType::Object: { 4314 LDefinition tmp = 4315 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); 4316 LPostWriteBarrierO* lir = new (alloc()) LPostWriteBarrierO( 4317 useRegisterOrConstant(ins->object()), useRegister(ins->value()), tmp); 4318 add(lir, ins); 4319 assignSafepoint(lir, ins); 4320 break; 4321 } 4322 case MIRType::String: { 4323 LDefinition tmp = 4324 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); 4325 LPostWriteBarrierS* lir = new (alloc()) LPostWriteBarrierS( 4326 useRegisterOrConstant(ins->object()), useRegister(ins->value()), tmp); 4327 add(lir, ins); 4328 assignSafepoint(lir, ins); 4329 break; 4330 } 4331 case MIRType::BigInt: { 4332 LDefinition tmp = 4333 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); 4334 auto* lir = new (alloc()) LPostWriteBarrierBI( 4335 useRegisterOrConstant(ins->object()), useRegister(ins->value()), tmp); 4336 add(lir, ins); 4337 assignSafepoint(lir, ins); 4338 break; 4339 } 4340 case MIRType::Value: { 4341 LDefinition tmp = 4342 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); 4343 LPostWriteBarrierV* lir = new (alloc()) LPostWriteBarrierV( 4344 useRegisterOrConstant(ins->object()), useBox(ins->value()), tmp); 4345 add(lir, ins); 4346 assignSafepoint(lir, ins); 4347 break; 4348 } 4349 default: 4350 // Currently, only objects, strings, and bigints can be in the nursery. 4351 // Other instruction types cannot hold nursery pointers. 4352 MOZ_ASSERT(!NeedsPostBarrier(ins->value()->type())); 4353 break; 4354 } 4355 } 4356 4357 void LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins) { 4358 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4359 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4360 4361 // We need a barrier if the value might be allocated in the nursery. If the 4362 // value is a constant, it must be tenured because MIR can't contain nursery 4363 // pointers. 4364 MConstant* constValue = ins->value()->maybeConstantValue(); 4365 if (constValue) { 4366 MOZ_ASSERT(JS::GCPolicy<Value>::isTenured(constValue->toJSValue())); 4367 return; 4368 } 4369 4370 switch (ins->value()->type()) { 4371 case MIRType::Object: { 4372 LDefinition tmp = 4373 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); 4374 LPostWriteElementBarrierO* lir = new (alloc()) LPostWriteElementBarrierO( 4375 useRegisterOrConstant(ins->object()), useRegister(ins->value()), 4376 useRegister(ins->index()), tmp); 4377 add(lir, ins); 4378 assignSafepoint(lir, ins); 4379 break; 4380 } 4381 case MIRType::String: { 4382 LDefinition tmp = 4383 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); 4384 LPostWriteElementBarrierS* lir = new (alloc()) LPostWriteElementBarrierS( 4385 useRegisterOrConstant(ins->object()), useRegister(ins->value()), 4386 useRegister(ins->index()), tmp); 4387 add(lir, ins); 4388 assignSafepoint(lir, ins); 4389 break; 4390 } 4391 case MIRType::BigInt: { 4392 LDefinition tmp = 4393 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); 4394 auto* lir = new (alloc()) LPostWriteElementBarrierBI( 4395 useRegisterOrConstant(ins->object()), useRegister(ins->value()), 4396 useRegister(ins->index()), tmp); 4397 add(lir, ins); 4398 assignSafepoint(lir, ins); 4399 break; 4400 } 4401 case MIRType::Value: { 4402 LDefinition tmp = 4403 needTempForPostBarrier() ? temp() : LDefinition::BogusTemp(); 4404 LPostWriteElementBarrierV* lir = new (alloc()) LPostWriteElementBarrierV( 4405 useRegisterOrConstant(ins->object()), useRegister(ins->index()), 4406 useBox(ins->value()), tmp); 4407 add(lir, ins); 4408 assignSafepoint(lir, ins); 4409 break; 4410 } 4411 default: 4412 // Currently, only objects, strings, and bigints can be in the nursery. 4413 // Other instruction types cannot hold nursery pointers. 4414 MOZ_ASSERT(!NeedsPostBarrier(ins->value()->type())); 4415 break; 4416 } 4417 } 4418 4419 void LIRGenerator::visitAssertCanElidePostWriteBarrier( 4420 MAssertCanElidePostWriteBarrier* ins) { 4421 auto* lir = new (alloc()) LAssertCanElidePostWriteBarrier( 4422 useRegister(ins->object()), useBox(ins->value()), temp()); 4423 add(lir, ins); 4424 } 4425 4426 void LIRGenerator::visitArrayLength(MArrayLength* ins) { 4427 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4428 auto* lir = new (alloc()) LArrayLength(useRegisterAtStart(ins->elements())); 4429 assignSnapshot(lir, ins->bailoutKind()); 4430 define(lir, ins); 4431 } 4432 4433 void LIRGenerator::visitSetArrayLength(MSetArrayLength* ins) { 4434 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4435 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4436 4437 MOZ_ASSERT(ins->index()->isConstant()); 4438 add(new (alloc()) LSetArrayLength(useRegister(ins->elements()), 4439 useRegisterOrConstant(ins->index())), 4440 ins); 4441 } 4442 4443 void LIRGenerator::visitFunctionLength(MFunctionLength* ins) { 4444 MOZ_ASSERT(ins->function()->type() == MIRType::Object); 4445 4446 auto* lir = new (alloc()) LFunctionLength(useRegister(ins->function())); 4447 assignSnapshot(lir, ins->bailoutKind()); 4448 define(lir, ins); 4449 } 4450 4451 void LIRGenerator::visitFunctionName(MFunctionName* ins) { 4452 MOZ_ASSERT(ins->function()->type() == MIRType::Object); 4453 4454 auto* lir = new (alloc()) LFunctionName(useRegister(ins->function())); 4455 assignSnapshot(lir, ins->bailoutKind()); 4456 define(lir, ins); 4457 } 4458 4459 void LIRGenerator::visitGetNextEntryForIterator(MGetNextEntryForIterator* ins) { 4460 MOZ_ASSERT(ins->iter()->type() == MIRType::Object); 4461 MOZ_ASSERT(ins->result()->type() == MIRType::Object); 4462 auto lir = new (alloc()) LGetNextEntryForIterator(useRegister(ins->iter()), 4463 useRegister(ins->result()), 4464 temp(), temp(), temp()); 4465 define(lir, ins); 4466 } 4467 4468 void LIRGenerator::visitArrayBufferByteLength(MArrayBufferByteLength* ins) { 4469 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4470 MOZ_ASSERT(ins->type() == MIRType::IntPtr); 4471 4472 auto* lir = 4473 new (alloc()) LArrayBufferByteLength(useRegisterAtStart(ins->object())); 4474 define(lir, ins); 4475 } 4476 4477 void LIRGenerator::visitArrayBufferViewLength(MArrayBufferViewLength* ins) { 4478 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4479 MOZ_ASSERT(ins->type() == MIRType::IntPtr); 4480 4481 auto* lir = 4482 new (alloc()) LArrayBufferViewLength(useRegisterAtStart(ins->object())); 4483 define(lir, ins); 4484 } 4485 4486 void LIRGenerator::visitArrayBufferViewByteOffset( 4487 MArrayBufferViewByteOffset* ins) { 4488 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4489 MOZ_ASSERT(ins->type() == MIRType::IntPtr); 4490 4491 auto* lir = new (alloc()) 4492 LArrayBufferViewByteOffset(useRegisterAtStart(ins->object())); 4493 define(lir, ins); 4494 } 4495 4496 void LIRGenerator::visitArrayBufferViewElements(MArrayBufferViewElements* ins) { 4497 MOZ_ASSERT(ins->type() == MIRType::Elements); 4498 define(new (alloc()) 4499 LArrayBufferViewElements(useRegisterAtStart(ins->object())), 4500 ins); 4501 } 4502 4503 void LIRGenerator::visitArrayBufferViewElementsWithOffset( 4504 MArrayBufferViewElementsWithOffset* ins) { 4505 MOZ_ASSERT(ins->offset()->type() == MIRType::IntPtr); 4506 MOZ_ASSERT(ins->type() == MIRType::Elements); 4507 4508 define(new (alloc()) LArrayBufferViewElementsWithOffset( 4509 useRegister(ins->object()), 4510 useRegisterOrIndexConstant(ins->offset(), ins->elementType())), 4511 ins); 4512 } 4513 4514 void LIRGenerator::visitTypedArrayElementSize(MTypedArrayElementSize* ins) { 4515 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4516 define(new (alloc()) 4517 LTypedArrayElementSize(useRegisterAtStart(ins->object())), 4518 ins); 4519 } 4520 4521 void LIRGenerator::visitResizableTypedArrayLength( 4522 MResizableTypedArrayLength* ins) { 4523 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4524 MOZ_ASSERT(ins->type() == MIRType::IntPtr); 4525 4526 auto* lir = new (alloc()) 4527 LResizableTypedArrayLength(useRegister(ins->object()), temp()); 4528 define(lir, ins); 4529 } 4530 4531 void LIRGenerator::visitResizableDataViewByteLength( 4532 MResizableDataViewByteLength* ins) { 4533 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4534 MOZ_ASSERT(ins->type() == MIRType::IntPtr); 4535 4536 auto* lir = new (alloc()) 4537 LResizableDataViewByteLength(useRegister(ins->object()), temp()); 4538 define(lir, ins); 4539 } 4540 4541 void LIRGenerator::visitGrowableSharedArrayBufferByteLength( 4542 MGrowableSharedArrayBufferByteLength* ins) { 4543 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4544 MOZ_ASSERT(ins->type() == MIRType::IntPtr); 4545 4546 auto* lir = new (alloc()) 4547 LGrowableSharedArrayBufferByteLength(useRegisterAtStart(ins->object())); 4548 define(lir, ins); 4549 } 4550 4551 void LIRGenerator::visitGuardResizableArrayBufferViewInBounds( 4552 MGuardResizableArrayBufferViewInBounds* ins) { 4553 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4554 4555 auto* lir = new (alloc()) LGuardResizableArrayBufferViewInBounds( 4556 useRegister(ins->object()), temp()); 4557 assignSnapshot(lir, ins->bailoutKind()); 4558 add(lir, ins); 4559 redefine(ins, ins->object()); 4560 } 4561 4562 void LIRGenerator::visitGuardResizableArrayBufferViewInBoundsOrDetached( 4563 MGuardResizableArrayBufferViewInBoundsOrDetached* ins) { 4564 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4565 4566 auto* lir = new (alloc()) LGuardResizableArrayBufferViewInBoundsOrDetached( 4567 useRegister(ins->object()), temp()); 4568 assignSnapshot(lir, ins->bailoutKind()); 4569 add(lir, ins); 4570 redefine(ins, ins->object()); 4571 } 4572 4573 void LIRGenerator::visitGuardHasAttachedArrayBuffer( 4574 MGuardHasAttachedArrayBuffer* ins) { 4575 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4576 4577 auto* lir = new (alloc()) 4578 LGuardHasAttachedArrayBuffer(useRegister(ins->object()), temp()); 4579 assignSnapshot(lir, ins->bailoutKind()); 4580 add(lir, ins); 4581 redefine(ins, ins->object()); 4582 } 4583 4584 void LIRGenerator::visitGuardTypedArraySetOffset( 4585 MGuardTypedArraySetOffset* ins) { 4586 auto* lir = new (alloc()) LGuardTypedArraySetOffset( 4587 useRegister(ins->offset()), useRegister(ins->targetLength()), 4588 useRegister(ins->sourceLength()), temp()); 4589 assignSnapshot(lir, ins->bailoutKind()); 4590 add(lir, ins); 4591 redefine(ins, ins->offset()); 4592 } 4593 4594 void LIRGenerator::visitTypedArrayFill(MTypedArrayFill* ins) { 4595 if (ins->isBigIntWrite()) { 4596 auto* lir = new (alloc()) LTypedArrayFill64( 4597 useRegisterAtStart(ins->object()), 4598 useInt64RegisterAtStart(ins->value()), useRegisterAtStart(ins->start()), 4599 useRegisterAtStart(ins->end())); 4600 add(lir, ins); 4601 } else { 4602 auto* lir = new (alloc()) LTypedArrayFill( 4603 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->value()), 4604 useRegisterAtStart(ins->start()), useRegisterAtStart(ins->end())); 4605 add(lir, ins); 4606 } 4607 } 4608 4609 void LIRGenerator::visitTypedArraySet(MTypedArraySet* ins) { 4610 auto* lir = new (alloc()) LTypedArraySet(useRegisterAtStart(ins->target()), 4611 useRegisterAtStart(ins->source()), 4612 useRegisterAtStart(ins->offset())); 4613 add(lir, ins); 4614 if (!ins->canUseBitwiseCopy()) { 4615 assignSafepoint(lir, ins); 4616 } 4617 } 4618 4619 void LIRGenerator::visitTypedArraySetFromSubarray( 4620 MTypedArraySetFromSubarray* ins) { 4621 auto* lir = new (alloc()) LTypedArraySetFromSubarray( 4622 useRegisterAtStart(ins->target()), useRegisterAtStart(ins->source()), 4623 useRegisterAtStart(ins->offset()), 4624 useRegisterAtStart(ins->sourceOffset()), 4625 useRegisterAtStart(ins->sourceLength())); 4626 add(lir, ins); 4627 if (!ins->canUseBitwiseCopy()) { 4628 assignSafepoint(lir, ins); 4629 } 4630 } 4631 4632 void LIRGenerator::visitTypedArraySubarray(MTypedArraySubarray* ins) { 4633 auto* lir = new (alloc()) LTypedArraySubarray( 4634 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->start()), 4635 useRegisterAtStart(ins->length())); 4636 defineReturn(lir, ins); 4637 assignSafepoint(lir, ins); 4638 } 4639 4640 void LIRGenerator::visitToIntegerIndex(MToIntegerIndex* ins) { 4641 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr); 4642 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr); 4643 4644 auto* lir = new (alloc()) 4645 LToIntegerIndex(useRegister(ins->index()), useRegister(ins->length())); 4646 define(lir, ins); 4647 } 4648 4649 void LIRGenerator::visitGuardNumberToIntPtrIndex( 4650 MGuardNumberToIntPtrIndex* ins) { 4651 MDefinition* input = ins->input(); 4652 MOZ_ASSERT(input->type() == MIRType::Double); 4653 4654 auto* lir = new (alloc()) LGuardNumberToIntPtrIndex(useRegister(input)); 4655 if (!ins->supportOOB()) { 4656 assignSnapshot(lir, ins->bailoutKind()); 4657 } 4658 define(lir, ins); 4659 } 4660 4661 void LIRGenerator::visitInitializedLength(MInitializedLength* ins) { 4662 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4663 define(new (alloc()) LInitializedLength(useRegisterAtStart(ins->elements())), 4664 ins); 4665 } 4666 4667 void LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins) { 4668 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4669 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4670 4671 MOZ_ASSERT(ins->index()->isConstant()); 4672 add(new (alloc()) LSetInitializedLength(useRegister(ins->elements()), 4673 useRegisterOrConstant(ins->index())), 4674 ins); 4675 } 4676 4677 void LIRGenerator::visitNot(MNot* ins) { 4678 MDefinition* op = ins->input(); 4679 4680 // String is converted to length of string in the type analysis phase (see 4681 // TestPolicy). 4682 MOZ_ASSERT(op->type() != MIRType::String); 4683 4684 // - boolean: x xor 1 4685 // - int32: LCompare(x, 0) 4686 // - double: LCompare(x, 0) 4687 // - null or undefined: true 4688 // - symbol: false 4689 // - bigint: LNotBI(x) 4690 // - object: false if it never emulates undefined, else LNotO(x) 4691 switch (op->type()) { 4692 case MIRType::Boolean: { 4693 MConstant* cons = MConstant::NewInt32(alloc(), 1); 4694 ins->block()->insertBefore(ins, cons); 4695 lowerForALU(new (alloc()) LBitOpI(JSOp::BitXor), ins, op, cons); 4696 break; 4697 } 4698 case MIRType::Int32: 4699 define(new (alloc()) LNotI(useRegisterAtStart(op)), ins); 4700 break; 4701 case MIRType::IntPtr: 4702 define(new (alloc()) LNotIPtr(useRegisterAtStart(op)), ins); 4703 break; 4704 case MIRType::Int64: 4705 define(new (alloc()) LNotI64(useInt64RegisterAtStart(op)), ins); 4706 break; 4707 case MIRType::Double: 4708 define(new (alloc()) LNotD(useRegister(op)), ins); 4709 break; 4710 case MIRType::Float32: 4711 define(new (alloc()) LNotF(useRegister(op)), ins); 4712 break; 4713 case MIRType::Undefined: 4714 case MIRType::Null: 4715 define(new (alloc()) LInteger(1), ins); 4716 break; 4717 case MIRType::Symbol: 4718 define(new (alloc()) LInteger(0), ins); 4719 break; 4720 case MIRType::BigInt: 4721 define(new (alloc()) LNotBI(useRegisterAtStart(op)), ins); 4722 break; 4723 case MIRType::Object: 4724 define(new (alloc()) LNotO(useRegister(op)), ins); 4725 break; 4726 case MIRType::Value: { 4727 auto* lir = new (alloc()) LNotV(useBox(op), tempDouble(), tempToUnbox()); 4728 define(lir, ins); 4729 break; 4730 } 4731 4732 default: 4733 MOZ_CRASH("Unexpected MIRType."); 4734 } 4735 } 4736 4737 void LIRGenerator::visitBoundsCheck(MBoundsCheck* ins) { 4738 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr); 4739 MOZ_ASSERT(ins->index()->type() == ins->type()); 4740 MOZ_ASSERT(ins->length()->type() == ins->type()); 4741 4742 if (!ins->fallible()) { 4743 return; 4744 } 4745 4746 if (ins->minimum() || ins->maximum()) { 4747 auto* check = new (alloc()) 4748 LBoundsCheckRange(useRegisterOrInt32Constant(ins->index()), 4749 useAny(ins->length()), temp()); 4750 assignSnapshot(check, ins->bailoutKind()); 4751 add(check, ins); 4752 } else { 4753 auto* check = 4754 new (alloc()) LBoundsCheck(useRegisterOrInt32Constant(ins->index()), 4755 useAnyOrInt32Constant(ins->length())); 4756 assignSnapshot(check, ins->bailoutKind()); 4757 add(check, ins); 4758 } 4759 } 4760 4761 void LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex* ins) { 4762 MOZ_ASSERT(ins->type() == MIRType::Int32 || ins->type() == MIRType::IntPtr); 4763 MOZ_ASSERT(ins->index()->type() == ins->type()); 4764 MOZ_ASSERT(ins->length()->type() == ins->type()); 4765 4766 auto* lir = new (alloc()) 4767 LSpectreMaskIndex(useRegister(ins->index()), useAny(ins->length())); 4768 define(lir, ins); 4769 } 4770 4771 void LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins) { 4772 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4773 4774 if (!ins->fallible()) { 4775 return; 4776 } 4777 4778 auto* check = new (alloc()) LBoundsCheckLower(useRegister(ins->index())); 4779 assignSnapshot(check, ins->bailoutKind()); 4780 add(check, ins); 4781 } 4782 4783 void LIRGenerator::visitInArray(MInArray* ins) { 4784 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4785 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4786 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32); 4787 MOZ_ASSERT(ins->type() == MIRType::Boolean); 4788 4789 auto* lir = new (alloc()) LInArray(useRegister(ins->elements()), 4790 useRegisterOrConstant(ins->index()), 4791 useRegister(ins->initLength())); 4792 if (ins->needsNegativeIntCheck()) { 4793 assignSnapshot(lir, ins->bailoutKind()); 4794 } 4795 define(lir, ins); 4796 } 4797 4798 void LIRGenerator::visitGuardElementNotHole(MGuardElementNotHole* ins) { 4799 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4800 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4801 4802 auto* guard = new (alloc()) 4803 LGuardElementNotHole(useRegisterAtStart(ins->elements()), 4804 useRegisterOrConstantAtStart(ins->index())); 4805 assignSnapshot(guard, ins->bailoutKind()); 4806 add(guard, ins); 4807 } 4808 4809 void LIRGenerator::visitLoadElement(MLoadElement* ins) { 4810 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4811 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4812 MOZ_ASSERT(ins->type() == MIRType::Value); 4813 4814 auto* lir = new (alloc()) LLoadElementV(useRegister(ins->elements()), 4815 useRegisterOrConstant(ins->index())); 4816 if (ins->needsHoleCheck()) { 4817 assignSnapshot(lir, ins->bailoutKind()); 4818 } 4819 defineBox(lir, ins); 4820 } 4821 4822 void LIRGenerator::visitLoadElementHole(MLoadElementHole* ins) { 4823 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4824 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4825 MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32); 4826 MOZ_ASSERT(ins->type() == MIRType::Value); 4827 4828 LLoadElementHole* lir = new (alloc()) 4829 LLoadElementHole(useRegister(ins->elements()), useRegister(ins->index()), 4830 useRegister(ins->initLength())); 4831 if (ins->needsNegativeIntCheck()) { 4832 assignSnapshot(lir, ins->bailoutKind()); 4833 } 4834 defineBox(lir, ins); 4835 } 4836 4837 void LIRGenerator::visitStoreElement(MStoreElement* ins) { 4838 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4839 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4840 4841 const LUse elements = useRegister(ins->elements()); 4842 const LAllocation index = useRegisterOrConstant(ins->index()); 4843 4844 switch (ins->value()->type()) { 4845 case MIRType::Value: { 4846 auto* lir = 4847 new (alloc()) LStoreElementV(elements, index, useBox(ins->value())); 4848 if (ins->fallible()) { 4849 assignSnapshot(lir, ins->bailoutKind()); 4850 } 4851 add(lir, ins); 4852 break; 4853 } 4854 4855 default: { 4856 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value()); 4857 auto* lir = new (alloc()) LStoreElementT(elements, index, value); 4858 if (ins->fallible()) { 4859 assignSnapshot(lir, ins->bailoutKind()); 4860 } 4861 add(lir, ins); 4862 break; 4863 } 4864 } 4865 } 4866 4867 void LIRGenerator::visitStoreHoleValueElement(MStoreHoleValueElement* ins) { 4868 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4869 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4870 4871 auto* lir = new (alloc()) LStoreHoleValueElement(useRegister(ins->elements()), 4872 useRegister(ins->index())); 4873 add(lir, ins); 4874 } 4875 4876 static bool BoundsCheckNeedsSpectreTemp() { 4877 // On x86, spectreBoundsCheck32 can emit better code if it has a scratch 4878 // register and index masking is enabled. 4879 #ifdef JS_CODEGEN_X86 4880 return JitOptions.spectreIndexMasking; 4881 #else 4882 return false; 4883 #endif 4884 } 4885 4886 void LIRGenerator::visitStoreElementHole(MStoreElementHole* ins) { 4887 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 4888 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 4889 4890 const LUse object = useRegister(ins->object()); 4891 const LUse elements = useRegister(ins->elements()); 4892 const LAllocation index = useRegister(ins->index()); 4893 4894 switch (ins->value()->type()) { 4895 case MIRType::Value: { 4896 auto* lir = new (alloc()) LStoreElementHoleV( 4897 object, elements, index, useBox(ins->value()), temp()); 4898 assignSnapshot(lir, ins->bailoutKind()); 4899 add(lir, ins); 4900 assignSafepoint(lir, ins); 4901 break; 4902 } 4903 default: { 4904 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value()); 4905 auto* lir = new (alloc()) 4906 LStoreElementHoleT(object, elements, index, value, temp()); 4907 assignSnapshot(lir, ins->bailoutKind()); 4908 add(lir, ins); 4909 assignSafepoint(lir, ins); 4910 break; 4911 } 4912 } 4913 } 4914 4915 void LIRGenerator::visitEffectiveAddress3(MEffectiveAddress3* ins) { 4916 define(new (alloc()) LEffectiveAddress3(useRegister(ins->base()), 4917 useRegister(ins->index())), 4918 ins); 4919 } 4920 4921 void LIRGenerator::visitEffectiveAddress2(MEffectiveAddress2* ins) { 4922 define(new (alloc()) LEffectiveAddress2(useRegister(ins->index())), ins); 4923 } 4924 4925 void LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) { 4926 MOZ_ASSERT(ins->type() == MIRType::Value); 4927 4928 auto* lir = 4929 new (alloc()) LArrayPopShift(useRegister(ins->object()), temp(), temp()); 4930 assignSnapshot(lir, ins->bailoutKind()); 4931 defineBox(lir, ins); 4932 4933 if (ins->mode() == MArrayPopShift::Shift) { 4934 assignSafepoint(lir, ins); 4935 } 4936 } 4937 4938 void LIRGenerator::visitArrayPush(MArrayPush* ins) { 4939 MOZ_ASSERT(ins->type() == MIRType::Int32); 4940 MOZ_ASSERT(ins->value()->type() == MIRType::Value); 4941 4942 LUse object = useRegister(ins->object()); 4943 4944 LDefinition spectreTemp = 4945 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp(); 4946 4947 auto* lir = new (alloc()) 4948 LArrayPush(object, useBox(ins->value()), temp(), spectreTemp); 4949 // We will bailout before pushing if the length would overflow INT32_MAX. 4950 assignSnapshot(lir, ins->bailoutKind()); 4951 define(lir, ins); 4952 assignSafepoint(lir, ins); 4953 } 4954 4955 void LIRGenerator::visitArraySlice(MArraySlice* ins) { 4956 MOZ_ASSERT(ins->type() == MIRType::Object); 4957 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4958 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32); 4959 MOZ_ASSERT(ins->end()->type() == MIRType::Int32); 4960 4961 LArraySlice* lir = new (alloc()) LArraySlice( 4962 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()), 4963 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0), 4964 tempFixed(CallTempReg1)); 4965 assignSnapshot(lir, ins->bailoutKind()); 4966 defineReturn(lir, ins); 4967 assignSafepoint(lir, ins); 4968 } 4969 4970 void LIRGenerator::visitArgumentsSlice(MArgumentsSlice* ins) { 4971 MOZ_ASSERT(ins->type() == MIRType::Object); 4972 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 4973 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32); 4974 MOZ_ASSERT(ins->end()->type() == MIRType::Int32); 4975 4976 auto* lir = new (alloc()) LArgumentsSlice( 4977 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->begin()), 4978 useRegisterAtStart(ins->end()), tempFixed(CallTempReg0), 4979 tempFixed(CallTempReg1)); 4980 defineReturn(lir, ins); 4981 assignSafepoint(lir, ins); 4982 } 4983 4984 void LIRGenerator::visitFrameArgumentsSlice(MFrameArgumentsSlice* ins) { 4985 MOZ_ASSERT(ins->type() == MIRType::Object); 4986 MOZ_ASSERT(ins->begin()->type() == MIRType::Int32); 4987 MOZ_ASSERT(ins->count()->type() == MIRType::Int32); 4988 4989 auto* lir = new (alloc()) LFrameArgumentsSlice( 4990 useRegister(ins->begin()), useRegister(ins->count()), temp()); 4991 define(lir, ins); 4992 assignSafepoint(lir, ins); 4993 } 4994 4995 void LIRGenerator::visitInlineArgumentsSlice(MInlineArgumentsSlice* ins) { 4996 LAllocation begin = useRegisterOrConstant(ins->begin()); 4997 LAllocation count = useRegisterOrConstant(ins->count()); 4998 uint32_t numActuals = ins->numActuals(); 4999 uint32_t numOperands = 5000 numActuals * BOX_PIECES + LInlineArgumentsSlice::NumNonArgumentOperands; 5001 5002 auto* lir = allocateVariadic<LInlineArgumentsSlice>(numOperands, temp()); 5003 if (!lir) { 5004 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitInlineArgumentsSlice"); 5005 return; 5006 } 5007 5008 lir->setOperand(LInlineArgumentsSlice::Begin, begin); 5009 lir->setOperand(LInlineArgumentsSlice::Count, count); 5010 for (uint32_t i = 0; i < numActuals; i++) { 5011 MDefinition* arg = ins->getArg(i); 5012 uint32_t index = LInlineArgumentsSlice::ArgIndex(i); 5013 lir->setBoxOperand(index, 5014 useBoxOrTypedOrConstant(arg, /*useConstant = */ true)); 5015 } 5016 define(lir, ins); 5017 assignSafepoint(lir, ins); 5018 } 5019 5020 void LIRGenerator::visitNormalizeSliceTerm(MNormalizeSliceTerm* ins) { 5021 MOZ_ASSERT(ins->type() == MIRType::Int32); 5022 MOZ_ASSERT(ins->value()->type() == MIRType::Int32); 5023 MOZ_ASSERT(ins->length()->type() == MIRType::Int32); 5024 5025 auto* lir = new (alloc()) LNormalizeSliceTerm(useRegister(ins->value()), 5026 useRegister(ins->length())); 5027 define(lir, ins); 5028 } 5029 5030 void LIRGenerator::visitArrayJoin(MArrayJoin* ins) { 5031 MOZ_ASSERT(ins->type() == MIRType::String); 5032 MOZ_ASSERT(ins->array()->type() == MIRType::Object); 5033 MOZ_ASSERT(ins->separator()->type() == MIRType::String); 5034 5035 auto* lir = new (alloc()) 5036 LArrayJoin(useRegisterAtStart(ins->array()), 5037 useRegisterAtStart(ins->separator()), tempFixed(CallTempReg0)); 5038 defineReturn(lir, ins); 5039 assignSafepoint(lir, ins); 5040 } 5041 5042 void LIRGenerator::visitObjectKeys(MObjectKeys* ins) { 5043 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5044 MOZ_ASSERT(ins->type() == MIRType::Object); 5045 5046 auto* lir = new (alloc()) LObjectKeys(useRegisterAtStart(ins->object())); 5047 defineReturn(lir, ins); 5048 assignSafepoint(lir, ins); 5049 } 5050 5051 void LIRGenerator::visitObjectKeysFromIterator(MObjectKeysFromIterator* ins) { 5052 MOZ_CRASH("ObjectKeysFromIterator is purely for recovery purposes."); 5053 } 5054 5055 void LIRGenerator::visitObjectKeysLength(MObjectKeysLength* ins) { 5056 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5057 MOZ_ASSERT(ins->type() == MIRType::Int32); 5058 5059 auto* lir = 5060 new (alloc()) LObjectKeysLength(useRegisterAtStart(ins->object())); 5061 defineReturn(lir, ins); 5062 assignSafepoint(lir, ins); 5063 } 5064 5065 void LIRGenerator::visitStringSplit(MStringSplit* ins) { 5066 MOZ_ASSERT(ins->type() == MIRType::Object); 5067 MOZ_ASSERT(ins->string()->type() == MIRType::String); 5068 MOZ_ASSERT(ins->separator()->type() == MIRType::String); 5069 5070 LStringSplit* lir = new (alloc()) LStringSplit( 5071 useRegisterAtStart(ins->string()), useRegisterAtStart(ins->separator())); 5072 defineReturn(lir, ins); 5073 assignSafepoint(lir, ins); 5074 } 5075 5076 void LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins) { 5077 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 5078 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr); 5079 MOZ_ASSERT(IsNumberType(ins->type())); 5080 5081 auto sync = SynchronizeLoad(ins->requiresMemoryBarrier()); 5082 5083 if (Scalar::isBigIntType(ins->storageType()) && !sync.isNone()) { 5084 lowerAtomicLoad64(ins); 5085 return; 5086 } 5087 5088 const LUse elements = useRegister(ins->elements()); 5089 const LAllocation index = 5090 useRegisterOrIndexConstant(ins->index(), ins->storageType()); 5091 5092 if (Scalar::isBigIntType(ins->storageType())) { 5093 MOZ_ASSERT(ins->type() == MIRType::Int64); 5094 5095 auto* lir = new (alloc()) LLoadUnboxedInt64(elements, index); 5096 defineInt64(lir, ins); 5097 return; 5098 } 5099 5100 // NOTE: the generated code must match the assembly code in gen_load in 5101 // GenerateAtomicOperations.py 5102 if (!sync.isNone()) { 5103 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore); 5104 add(fence, ins); 5105 } 5106 5107 // We need a temp register for Uint32Array with known double result and for 5108 // Float16Array. 5109 LDefinition temp1 = LDefinition::BogusTemp(); 5110 if ((ins->storageType() == Scalar::Uint32 && 5111 IsFloatingPointType(ins->type())) || 5112 ins->storageType() == Scalar::Float16) { 5113 temp1 = temp(); 5114 } 5115 5116 // Additional temp when Float16 to Float32 conversion requires a call. 5117 LDefinition temp2 = LDefinition::BogusTemp(); 5118 if (MacroAssembler::LoadRequiresCall(ins->storageType())) { 5119 temp2 = temp(); 5120 } 5121 5122 auto* lir = new (alloc()) LLoadUnboxedScalar(elements, index, temp1, temp2); 5123 if (ins->fallible()) { 5124 assignSnapshot(lir, ins->bailoutKind()); 5125 } 5126 define(lir, ins); 5127 5128 if (MacroAssembler::LoadRequiresCall(ins->storageType())) { 5129 assignSafepoint(lir, ins); 5130 } 5131 5132 if (!sync.isNone()) { 5133 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter); 5134 add(fence, ins); 5135 } 5136 } 5137 5138 void LIRGenerator::visitLoadDataViewElement(MLoadDataViewElement* ins) { 5139 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 5140 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr); 5141 5142 MOZ_ASSERT(IsNumberType(ins->type())); 5143 5144 LUse elements = useRegister(ins->elements()); 5145 LAllocation index = useRegisterOrIndexConstant(ins->index(), Scalar::Uint8); 5146 LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian()); 5147 5148 if (Scalar::isBigIntType(ins->storageType())) { 5149 auto* lir = 5150 new (alloc()) LLoadDataViewElement64(elements, index, littleEndian); 5151 defineInt64(lir, ins); 5152 return; 5153 } 5154 5155 // We need a temp register for: 5156 // - Uint32Array with known double result, 5157 // - Float16Array, 5158 // - Float32Array. 5159 LDefinition temp1 = LDefinition::BogusTemp(); 5160 if ((ins->storageType() == Scalar::Uint32 && 5161 IsFloatingPointType(ins->type())) || 5162 ins->storageType() == Scalar::Float16 || 5163 ins->storageType() == Scalar::Float32) { 5164 temp1 = temp(); 5165 } 5166 5167 // Additional temp when Float16 to Float64 conversion requires a call. 5168 LDefinition temp2 = LDefinition::BogusTemp(); 5169 if (MacroAssembler::LoadRequiresCall(ins->storageType())) { 5170 temp2 = temp(); 5171 } 5172 5173 // We also need a separate 64-bit temp register for Float64Array. 5174 LInt64Definition temp64 = LInt64Definition::BogusTemp(); 5175 if (ins->storageType() == Scalar::Float64) { 5176 temp64 = tempInt64(); 5177 } 5178 5179 auto* lir = new (alloc()) 5180 LLoadDataViewElement(elements, index, littleEndian, temp1, temp2, temp64); 5181 if (ins->fallible()) { 5182 assignSnapshot(lir, ins->bailoutKind()); 5183 } 5184 define(lir, ins); 5185 if (MacroAssembler::LoadRequiresCall(ins->storageType())) { 5186 assignSafepoint(lir, ins); 5187 } 5188 } 5189 5190 void LIRGenerator::visitClampToUint8(MClampToUint8* ins) { 5191 MDefinition* in = ins->input(); 5192 5193 switch (in->type()) { 5194 case MIRType::Int32: 5195 defineReuseInput(new (alloc()) LClampIToUint8(useRegisterAtStart(in)), 5196 ins, 0); 5197 break; 5198 5199 case MIRType::Double: 5200 // LClampDToUint8 clobbers its input register. Making it available as 5201 // a temp copy describes this behavior to the register allocator. 5202 define(new (alloc()) 5203 LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)), 5204 ins); 5205 break; 5206 5207 case MIRType::Value: { 5208 LClampVToUint8* lir = 5209 new (alloc()) LClampVToUint8(useBox(in), tempDouble()); 5210 assignSnapshot(lir, ins->bailoutKind()); 5211 define(lir, ins); 5212 assignSafepoint(lir, ins); 5213 break; 5214 } 5215 5216 default: 5217 MOZ_CRASH("unexpected type"); 5218 } 5219 } 5220 5221 void LIRGenerator::visitLoadTypedArrayElementHole( 5222 MLoadTypedArrayElementHole* ins) { 5223 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 5224 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr); 5225 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr); 5226 5227 MOZ_ASSERT(ins->type() == MIRType::Value); 5228 5229 const LUse elements = useRegister(ins->elements()); 5230 const LAllocation index = useRegister(ins->index()); 5231 const LAllocation length = useRegister(ins->length()); 5232 5233 if (!Scalar::isBigIntType(ins->arrayType())) { 5234 LDefinition tempDef = LDefinition::BogusTemp(); 5235 if (MacroAssembler::LoadRequiresCall(ins->arrayType())) { 5236 tempDef = temp(); 5237 } 5238 5239 auto* lir = new (alloc()) 5240 LLoadTypedArrayElementHole(elements, index, length, tempDef); 5241 if (ins->fallible()) { 5242 assignSnapshot(lir, ins->bailoutKind()); 5243 } 5244 defineBox(lir, ins); 5245 5246 if (MacroAssembler::LoadRequiresCall(ins->arrayType())) { 5247 assignSafepoint(lir, ins); 5248 } 5249 } else { 5250 #ifdef JS_CODEGEN_X86 5251 LInt64Definition temp64 = LInt64Definition::BogusTemp(); 5252 #else 5253 LInt64Definition temp64 = tempInt64(); 5254 #endif 5255 5256 auto* lir = new (alloc()) LLoadTypedArrayElementHoleBigInt( 5257 elements, index, length, temp(), temp64); 5258 defineBox(lir, ins); 5259 assignSafepoint(lir, ins); 5260 } 5261 } 5262 5263 void LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins) { 5264 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 5265 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr); 5266 5267 if (ins->isFloatWrite()) { 5268 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float16, 5269 ins->value()->type() == MIRType::Float32); 5270 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32, 5271 ins->value()->type() == MIRType::Float32); 5272 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64, 5273 ins->value()->type() == MIRType::Double); 5274 } else if (ins->isBigIntWrite()) { 5275 MOZ_ASSERT(ins->value()->type() == MIRType::Int64); 5276 } else { 5277 MOZ_ASSERT(ins->value()->type() == MIRType::Int32); 5278 } 5279 5280 auto sync = SynchronizeStore(ins->requiresMemoryBarrier()); 5281 5282 if (ins->isBigIntWrite() && !sync.isNone()) { 5283 lowerAtomicStore64(ins); 5284 return; 5285 } 5286 5287 LUse elements = useRegister(ins->elements()); 5288 LAllocation index = 5289 useRegisterOrIndexConstant(ins->index(), ins->writeType()); 5290 5291 if (ins->isBigIntWrite()) { 5292 LInt64Allocation value = useInt64RegisterOrConstant(ins->value()); 5293 add(new (alloc()) LStoreUnboxedInt64(elements, index, value), ins); 5294 return; 5295 } 5296 5297 // For byte arrays, the value has to be in a byte register on x86. 5298 LAllocation value; 5299 if (ins->isByteWrite()) { 5300 value = useByteOpRegisterOrNonDoubleConstant(ins->value()); 5301 } else { 5302 value = useRegisterOrNonDoubleConstant(ins->value()); 5303 } 5304 5305 // Optimization opportunity for atomics: on some platforms there 5306 // is a store instruction that incorporates the necessary 5307 // barriers, and we could use that instead of separate barrier and 5308 // store instructions. See bug #1077027. 5309 // 5310 // NOTE: the generated code must match the assembly code in gen_store in 5311 // GenerateAtomicOperations.py 5312 if (!sync.isNone()) { 5313 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierBefore); 5314 add(fence, ins); 5315 } 5316 5317 // We need a temp register for Float16Array. 5318 LDefinition tempDef = LDefinition::BogusTemp(); 5319 if (ins->writeType() == Scalar::Float16) { 5320 tempDef = temp(); 5321 } 5322 5323 auto* lir = 5324 new (alloc()) LStoreUnboxedScalar(elements, index, value, tempDef); 5325 add(lir, ins); 5326 5327 if (MacroAssembler::StoreRequiresCall(ins->writeType())) { 5328 assignSafepoint(lir, ins); 5329 } 5330 5331 if (!sync.isNone()) { 5332 LMemoryBarrier* fence = new (alloc()) LMemoryBarrier(sync.barrierAfter); 5333 add(fence, ins); 5334 } 5335 } 5336 5337 void LIRGenerator::visitStoreDataViewElement(MStoreDataViewElement* ins) { 5338 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 5339 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr); 5340 MOZ_ASSERT(ins->littleEndian()->type() == MIRType::Boolean); 5341 5342 if (ins->isFloatWrite()) { 5343 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float16, 5344 ins->value()->type() == MIRType::Float32); 5345 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32, 5346 ins->value()->type() == MIRType::Float32); 5347 MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64, 5348 ins->value()->type() == MIRType::Double); 5349 } else if (ins->isBigIntWrite()) { 5350 MOZ_ASSERT(ins->value()->type() == MIRType::Int64); 5351 } else { 5352 MOZ_ASSERT(ins->value()->type() == MIRType::Int32); 5353 } 5354 5355 LUse elements = useRegister(ins->elements()); 5356 LAllocation index = useRegisterOrIndexConstant(ins->index(), Scalar::Uint8); 5357 LAllocation littleEndian = useRegisterOrConstant(ins->littleEndian()); 5358 5359 if (ins->isBigIntWrite()) { 5360 #ifdef JS_CODEGEN_X86 5361 LInt64Allocation value = useInt64Register(ins->value()); 5362 LInt64Definition temp = LInt64Definition::BogusTemp(); 5363 if (littleEndian.isConstant()) { 5364 temp = tempInt64(); 5365 } 5366 #else 5367 LInt64Allocation value = useInt64RegisterOrConstant(ins->value()); 5368 LInt64Definition temp = tempInt64(); 5369 #endif 5370 5371 auto* lir = new (alloc()) 5372 LStoreDataViewElement64(elements, index, value, littleEndian, temp); 5373 add(lir, ins); 5374 return; 5375 } 5376 5377 LAllocation value = useRegisterOrNonDoubleConstant(ins->value()); 5378 5379 LDefinition tempDef = LDefinition::BogusTemp(); 5380 LInt64Definition temp64Def = LInt64Definition::BogusTemp(); 5381 if (ins->writeType() != Scalar::Float64) { 5382 tempDef = temp(); 5383 } else { 5384 temp64Def = tempInt64(); 5385 } 5386 5387 auto* lir = new (alloc()) LStoreDataViewElement( 5388 elements, index, value, littleEndian, tempDef, temp64Def); 5389 add(lir, ins); 5390 5391 if (MacroAssembler::StoreRequiresCall(ins->writeType())) { 5392 assignSafepoint(lir, ins); 5393 } 5394 } 5395 5396 void LIRGenerator::visitStoreTypedArrayElementHole( 5397 MStoreTypedArrayElementHole* ins) { 5398 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 5399 MOZ_ASSERT(ins->index()->type() == MIRType::IntPtr); 5400 MOZ_ASSERT(ins->length()->type() == MIRType::IntPtr); 5401 5402 if (ins->isFloatWrite()) { 5403 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float16, 5404 ins->value()->type() == MIRType::Float32); 5405 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32, 5406 ins->value()->type() == MIRType::Float32); 5407 MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64, 5408 ins->value()->type() == MIRType::Double); 5409 } else if (ins->isBigIntWrite()) { 5410 MOZ_ASSERT(ins->value()->type() == MIRType::Int64); 5411 } else { 5412 MOZ_ASSERT(ins->value()->type() == MIRType::Int32); 5413 } 5414 5415 LUse elements = useRegister(ins->elements()); 5416 LAllocation length = useAny(ins->length()); 5417 LAllocation index = useRegister(ins->index()); 5418 5419 if (ins->isBigIntWrite()) { 5420 LInt64Allocation value = useInt64RegisterOrConstant(ins->value()); 5421 LDefinition spectreTemp = 5422 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp(); 5423 5424 auto* lir = new (alloc()) LStoreTypedArrayElementHoleInt64( 5425 elements, length, index, value, spectreTemp); 5426 add(lir, ins); 5427 return; 5428 } 5429 5430 // For byte arrays, the value has to be in a byte register on x86. 5431 LAllocation value; 5432 if (ins->isByteWrite()) { 5433 value = useByteOpRegisterOrNonDoubleConstant(ins->value()); 5434 } else { 5435 value = useRegisterOrNonDoubleConstant(ins->value()); 5436 } 5437 5438 LDefinition tempDef = LDefinition::BogusTemp(); 5439 if (BoundsCheckNeedsSpectreTemp() || ins->arrayType() == Scalar::Float16) { 5440 tempDef = temp(); 5441 } 5442 5443 auto* lir = new (alloc()) 5444 LStoreTypedArrayElementHole(elements, length, index, value, tempDef); 5445 add(lir, ins); 5446 5447 if (MacroAssembler::StoreRequiresCall(ins->arrayType())) { 5448 assignSafepoint(lir, ins); 5449 } 5450 } 5451 5452 void LIRGenerator::visitLoadScriptedProxyHandler( 5453 MLoadScriptedProxyHandler* ins) { 5454 LLoadScriptedProxyHandler* lir = new (alloc()) 5455 LLoadScriptedProxyHandler(useRegisterAtStart(ins->object())); 5456 assignSnapshot(lir, ins->bailoutKind()); 5457 define(lir, ins); 5458 } 5459 5460 void LIRGenerator::visitIdToStringOrSymbol(MIdToStringOrSymbol* ins) { 5461 LIdToStringOrSymbol* lir = 5462 new (alloc()) LIdToStringOrSymbol(useBoxAtStart(ins->idVal()), temp()); 5463 assignSnapshot(lir, ins->bailoutKind()); 5464 defineBox(lir, ins); 5465 assignSafepoint(lir, ins); 5466 } 5467 5468 void LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins) { 5469 MDefinition* obj = ins->object(); 5470 MOZ_ASSERT(obj->type() == MIRType::Object); 5471 5472 MIRType type = ins->type(); 5473 5474 if (type == MIRType::Value) { 5475 if (ins->usedAsPropertyKey()) { 5476 LLoadFixedSlotAndAtomize* lir = 5477 new (alloc()) LLoadFixedSlotAndAtomize(useRegister(obj), temp()); 5478 defineBox(lir, ins); 5479 assignSafepoint(lir, ins); 5480 } else { 5481 LLoadFixedSlotV* lir = 5482 new (alloc()) LLoadFixedSlotV(useRegisterAtStart(obj)); 5483 defineBox(lir, ins); 5484 } 5485 } else { 5486 LLoadFixedSlotT* lir = 5487 new (alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj, type)); 5488 define(lir, ins); 5489 } 5490 } 5491 5492 void LIRGenerator::visitLoadFixedSlotFromOffset(MLoadFixedSlotFromOffset* ins) { 5493 MDefinition* obj = ins->object(); 5494 MOZ_ASSERT(obj->type() == MIRType::Object); 5495 MOZ_ASSERT(ins->type() == MIRType::Value); 5496 5497 auto* lir = new (alloc()) LLoadFixedSlotFromOffset( 5498 useRegisterAtStart(obj), useRegisterAtStart(ins->offset())); 5499 defineBox(lir, ins); 5500 } 5501 5502 void LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins) { 5503 MDefinition* obj = ins->object(); 5504 MOZ_ASSERT(obj->type() == MIRType::Object); 5505 5506 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) { 5507 LLoadFixedSlotUnboxAndAtomize* lir = 5508 new (alloc()) LLoadFixedSlotUnboxAndAtomize(useRegister(obj)); 5509 if (ins->fallible()) { 5510 assignSnapshot(lir, ins->bailoutKind()); 5511 } 5512 define(lir, ins); 5513 assignSafepoint(lir, ins); 5514 } else { 5515 LInt64Definition temp0 = ins->type() == MIRType::Double 5516 ? tempInt64() 5517 : LInt64Definition::BogusTemp(); 5518 5519 LLoadFixedSlotAndUnbox* lir = 5520 new (alloc()) LLoadFixedSlotAndUnbox(useRegisterAtStart(obj), temp0); 5521 if (ins->fallible()) { 5522 assignSnapshot(lir, ins->bailoutKind()); 5523 } 5524 define(lir, ins); 5525 } 5526 } 5527 5528 void LIRGenerator::visitLoadDynamicSlotAndUnbox(MLoadDynamicSlotAndUnbox* ins) { 5529 MDefinition* slots = ins->slots(); 5530 MOZ_ASSERT(slots->type() == MIRType::Slots); 5531 5532 if (ins->usedAsPropertyKey() && ins->type() == MIRType::String) { 5533 auto* lir = 5534 new (alloc()) LLoadDynamicSlotUnboxAndAtomize(useRegister(slots)); 5535 if (ins->fallible()) { 5536 assignSnapshot(lir, ins->bailoutKind()); 5537 } 5538 define(lir, ins); 5539 assignSafepoint(lir, ins); 5540 } else { 5541 LInt64Definition temp0 = ins->type() == MIRType::Double 5542 ? tempInt64() 5543 : LInt64Definition::BogusTemp(); 5544 auto* lir = new (alloc()) 5545 LLoadDynamicSlotAndUnbox(useRegisterAtStart(slots), temp0); 5546 if (ins->fallible()) { 5547 assignSnapshot(lir, ins->bailoutKind()); 5548 } 5549 define(lir, ins); 5550 } 5551 } 5552 5553 void LIRGenerator::visitLoadElementAndUnbox(MLoadElementAndUnbox* ins) { 5554 MDefinition* elements = ins->elements(); 5555 MDefinition* index = ins->index(); 5556 MOZ_ASSERT(elements->type() == MIRType::Elements); 5557 MOZ_ASSERT(index->type() == MIRType::Int32); 5558 5559 LInt64Definition temp0 = ins->type() == MIRType::Double 5560 ? tempInt64() 5561 : LInt64Definition::BogusTemp(); 5562 5563 auto* lir = new (alloc()) LLoadElementAndUnbox( 5564 useRegister(elements), useRegisterOrConstant(index), temp0); 5565 if (ins->fallible()) { 5566 assignSnapshot(lir, ins->bailoutKind()); 5567 } 5568 define(lir, ins); 5569 } 5570 5571 void LIRGenerator::visitAddAndStoreSlot(MAddAndStoreSlot* ins) { 5572 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5573 5574 if (ins->preserveWrapper()) { 5575 auto* lir = new (alloc()) LAddAndStoreSlotPreserveWrapper( 5576 useRegister(ins->object()), useBox(ins->value()), temp(), temp()); 5577 assignSnapshot(lir, ins->bailoutKind()); 5578 add(lir, ins); 5579 assignSafepoint(lir, ins); 5580 } else { 5581 LDefinition maybeTemp = LDefinition::BogusTemp(); 5582 if (ins->kind() != MAddAndStoreSlot::Kind::FixedSlot) { 5583 maybeTemp = temp(); 5584 } 5585 auto* lir = new (alloc()) LAddAndStoreSlot(useRegister(ins->object()), 5586 useBox(ins->value()), maybeTemp); 5587 add(lir, ins); 5588 } 5589 } 5590 5591 void LIRGenerator::visitAllocateAndStoreSlot(MAllocateAndStoreSlot* ins) { 5592 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5593 5594 auto* lir = new (alloc()) LAllocateAndStoreSlot( 5595 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value()), 5596 tempFixed(CallTempReg0), tempFixed(CallTempReg1)); 5597 assignSnapshot(lir, ins->bailoutKind()); 5598 add(lir, ins); 5599 } 5600 5601 void LIRGenerator::visitAddSlotAndCallAddPropHook( 5602 MAddSlotAndCallAddPropHook* ins) { 5603 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5604 MOZ_ASSERT(ins->value()->type() == MIRType::Value); 5605 5606 auto* lir = new (alloc()) LAddSlotAndCallAddPropHook( 5607 useRegisterAtStart(ins->object()), useBoxAtStart(ins->value())); 5608 add(lir, ins); 5609 assignSafepoint(lir, ins); 5610 } 5611 5612 void LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins) { 5613 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5614 5615 if (ins->value()->type() == MIRType::Value) { 5616 LStoreFixedSlotV* lir = new (alloc()) 5617 LStoreFixedSlotV(useRegister(ins->object()), useBox(ins->value())); 5618 add(lir, ins); 5619 } else { 5620 LStoreFixedSlotT* lir = new (alloc()) LStoreFixedSlotT( 5621 useRegister(ins->object()), useRegisterOrConstant(ins->value())); 5622 add(lir, ins); 5623 } 5624 } 5625 5626 void LIRGenerator::visitStoreFixedSlotFromOffset( 5627 MStoreFixedSlotFromOffset* ins) { 5628 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5629 5630 if (ins->value()->type() == MIRType::Value) { 5631 LStoreFixedSlotFromOffsetV* lir = new (alloc()) LStoreFixedSlotFromOffsetV( 5632 useRegister(ins->object()), useRegister(ins->offset()), 5633 useBox(ins->value()), temp()); 5634 add(lir, ins); 5635 } else { 5636 LStoreFixedSlotFromOffsetT* lir = new (alloc()) LStoreFixedSlotFromOffsetT( 5637 useRegister(ins->object()), useRegister(ins->offset()), 5638 useRegisterOrConstant(ins->value()), temp()); 5639 add(lir, ins); 5640 } 5641 } 5642 5643 void LIRGenerator::visitStoreDynamicSlotFromOffset( 5644 MStoreDynamicSlotFromOffset* ins) { 5645 MOZ_ASSERT(ins->slots()->type() == MIRType::Slots); 5646 5647 if (ins->value()->type() == MIRType::Value) { 5648 auto* lir = new (alloc()) LStoreDynamicSlotFromOffsetV( 5649 useRegister(ins->slots()), useRegister(ins->offset()), 5650 useBox(ins->value()), temp()); 5651 add(lir, ins); 5652 } else { 5653 auto* lir = new (alloc()) LStoreDynamicSlotFromOffsetT( 5654 useRegister(ins->slots()), useRegister(ins->offset()), 5655 useRegisterOrConstant(ins->value()), temp()); 5656 add(lir, ins); 5657 } 5658 } 5659 5660 void LIRGenerator::visitGetNameCache(MGetNameCache* ins) { 5661 MOZ_ASSERT(ins->envObj()->type() == MIRType::Object); 5662 5663 // Emit an overrecursed check: this is necessary because the cache can 5664 // attach a scripted getter stub that calls this script recursively. 5665 gen->setNeedsOverrecursedCheck(); 5666 5667 LGetNameCache* lir = 5668 new (alloc()) LGetNameCache(useRegister(ins->envObj()), temp()); 5669 defineBox(lir, ins); 5670 assignSafepoint(lir, ins); 5671 } 5672 5673 void LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins) { 5674 LCallGetIntrinsicValue* lir = new (alloc()) LCallGetIntrinsicValue(); 5675 defineReturn(lir, ins); 5676 assignSafepoint(lir, ins); 5677 } 5678 5679 void LIRGenerator::visitGetPropSuperCache(MGetPropSuperCache* ins) { 5680 MDefinition* obj = ins->object(); 5681 MDefinition* receiver = ins->receiver(); 5682 MDefinition* id = ins->idval(); 5683 5684 gen->setNeedsOverrecursedCheck(); 5685 5686 bool useConstId = 5687 id->type() == MIRType::String || id->type() == MIRType::Symbol; 5688 5689 auto* lir = new (alloc()) 5690 LGetPropSuperCache(useRegister(obj), useBoxOrTyped(receiver), 5691 useBoxOrTypedOrConstant(id, useConstId)); 5692 defineBox(lir, ins); 5693 assignSafepoint(lir, ins); 5694 } 5695 5696 void LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins) { 5697 MDefinition* value = ins->value(); 5698 MOZ_ASSERT(value->type() == MIRType::Object || 5699 value->type() == MIRType::Value); 5700 5701 MDefinition* id = ins->idval(); 5702 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol || 5703 id->type() == MIRType::Int32 || id->type() == MIRType::Value); 5704 5705 // Emit an overrecursed check: this is necessary because the cache can 5706 // attach a scripted getter stub that calls this script recursively. 5707 gen->setNeedsOverrecursedCheck(); 5708 5709 // If this is a GetProp, the id is a constant string. Allow passing it as a 5710 // constant to reduce register allocation pressure. 5711 bool useConstId = 5712 id->type() == MIRType::String || id->type() == MIRType::Symbol; 5713 5714 auto* lir = new (alloc()) LGetPropertyCache( 5715 useBoxOrTyped(value), useBoxOrTypedOrConstant(id, useConstId)); 5716 defineBox(lir, ins); 5717 assignSafepoint(lir, ins); 5718 } 5719 5720 void LIRGenerator::visitBindNameCache(MBindNameCache* ins) { 5721 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object); 5722 MOZ_ASSERT(ins->type() == MIRType::Object); 5723 5724 LBindNameCache* lir = new (alloc()) 5725 LBindNameCache(useRegister(ins->environmentChain()), temp()); 5726 define(lir, ins); 5727 assignSafepoint(lir, ins); 5728 } 5729 5730 void LIRGenerator::visitCallBindVar(MCallBindVar* ins) { 5731 MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object); 5732 MOZ_ASSERT(ins->type() == MIRType::Object); 5733 5734 LCallBindVar* lir = 5735 new (alloc()) LCallBindVar(useRegister(ins->environmentChain())); 5736 define(lir, ins); 5737 } 5738 5739 void LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins) { 5740 LGuardObjectIdentity* guard = new (alloc()) LGuardObjectIdentity( 5741 useRegister(ins->object()), useRegister(ins->expected())); 5742 assignSnapshot(guard, ins->bailoutKind()); 5743 add(guard, ins); 5744 redefine(ins, ins->object()); 5745 } 5746 5747 void LIRGenerator::visitGuardSpecificFunction(MGuardSpecificFunction* ins) { 5748 auto* guard = new (alloc()) LGuardSpecificFunction( 5749 useRegister(ins->function()), useRegister(ins->expected())); 5750 assignSnapshot(guard, ins->bailoutKind()); 5751 add(guard, ins); 5752 redefine(ins, ins->function()); 5753 } 5754 5755 void LIRGenerator::visitGuardSpecificAtom(MGuardSpecificAtom* ins) { 5756 auto* guard = 5757 new (alloc()) LGuardSpecificAtom(useRegister(ins->str()), temp()); 5758 assignSnapshot(guard, ins->bailoutKind()); 5759 add(guard, ins); 5760 redefine(ins, ins->str()); 5761 assignSafepoint(guard, ins); 5762 } 5763 5764 void LIRGenerator::visitGuardSpecificSymbol(MGuardSpecificSymbol* ins) { 5765 auto* guard = new (alloc()) LGuardSpecificSymbol(useRegister(ins->symbol())); 5766 assignSnapshot(guard, ins->bailoutKind()); 5767 add(guard, ins); 5768 redefine(ins, ins->symbol()); 5769 } 5770 5771 void LIRGenerator::visitGuardSpecificInt32(MGuardSpecificInt32* ins) { 5772 auto* guard = new (alloc()) LGuardSpecificInt32(useRegister(ins->num())); 5773 assignSnapshot(guard, ins->bailoutKind()); 5774 add(guard, ins); 5775 redefine(ins, ins->num()); 5776 } 5777 5778 void LIRGenerator::visitGuardStringToIndex(MGuardStringToIndex* ins) { 5779 MOZ_ASSERT(ins->string()->type() == MIRType::String); 5780 auto* guard = new (alloc()) LGuardStringToIndex(useRegister(ins->string())); 5781 assignSnapshot(guard, ins->bailoutKind()); 5782 define(guard, ins); 5783 assignSafepoint(guard, ins); 5784 } 5785 5786 void LIRGenerator::visitGuardStringToInt32(MGuardStringToInt32* ins) { 5787 MOZ_ASSERT(ins->string()->type() == MIRType::String); 5788 auto* guard = 5789 new (alloc()) LGuardStringToInt32(useRegister(ins->string()), temp()); 5790 assignSnapshot(guard, ins->bailoutKind()); 5791 define(guard, ins); 5792 assignSafepoint(guard, ins); 5793 } 5794 5795 void LIRGenerator::visitGuardStringToDouble(MGuardStringToDouble* ins) { 5796 MOZ_ASSERT(ins->string()->type() == MIRType::String); 5797 auto* guard = new (alloc()) 5798 LGuardStringToDouble(useRegister(ins->string()), temp(), temp()); 5799 assignSnapshot(guard, ins->bailoutKind()); 5800 define(guard, ins); 5801 assignSafepoint(guard, ins); 5802 } 5803 5804 void LIRGenerator::visitGuardNoDenseElements(MGuardNoDenseElements* ins) { 5805 auto* guard = 5806 new (alloc()) LGuardNoDenseElements(useRegister(ins->object()), temp()); 5807 assignSnapshot(guard, ins->bailoutKind()); 5808 add(guard, ins); 5809 redefine(ins, ins->object()); 5810 } 5811 5812 void LIRGenerator::visitGuardShape(MGuardShape* ins) { 5813 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5814 5815 if (JitOptions.spectreObjectMitigations) { 5816 auto* lir = 5817 new (alloc()) LGuardShape(useRegisterAtStart(ins->object()), temp()); 5818 assignSnapshot(lir, ins->bailoutKind()); 5819 defineReuseInput(lir, ins, 0); 5820 } else { 5821 auto* lir = new (alloc()) 5822 LGuardShape(useRegister(ins->object()), LDefinition::BogusTemp()); 5823 assignSnapshot(lir, ins->bailoutKind()); 5824 addUnchecked(lir, ins); 5825 redefine(ins, ins->object()); 5826 } 5827 } 5828 5829 void LIRGenerator::visitGuardMultipleShapes(MGuardMultipleShapes* ins) { 5830 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5831 5832 if (JitOptions.spectreObjectMitigations) { 5833 auto* lir = new (alloc()) LGuardMultipleShapes( 5834 useRegisterAtStart(ins->object()), useRegister(ins->shapeList()), 5835 temp(), temp(), temp(), temp()); 5836 assignSnapshot(lir, ins->bailoutKind()); 5837 defineReuseInput(lir, ins, 0); 5838 } else { 5839 auto* lir = new (alloc()) LGuardMultipleShapes( 5840 useRegister(ins->object()), useRegister(ins->shapeList()), temp(), 5841 temp(), temp(), LDefinition::BogusTemp()); 5842 assignSnapshot(lir, ins->bailoutKind()); 5843 addUnchecked(lir, ins); 5844 redefine(ins, ins->object()); 5845 } 5846 } 5847 5848 void LIRGenerator::visitGuardShapeList(MGuardShapeList* ins) { 5849 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5850 5851 if (JitOptions.spectreObjectMitigations) { 5852 auto* lir = new (alloc()) 5853 LGuardShapeList(useRegisterAtStart(ins->object()), temp(), temp()); 5854 assignSnapshot(lir, ins->bailoutKind()); 5855 defineReuseInput(lir, ins, 0); 5856 } else { 5857 auto* lir = new (alloc()) LGuardShapeList(useRegister(ins->object()), 5858 temp(), LDefinition::BogusTemp()); 5859 assignSnapshot(lir, ins->bailoutKind()); 5860 addUnchecked(lir, ins); 5861 redefine(ins, ins->object()); 5862 } 5863 } 5864 5865 void LIRGenerator::visitGuardShapeListToOffset(MGuardShapeListToOffset* ins) { 5866 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5867 5868 if (JitOptions.spectreObjectMitigations) { 5869 auto* lir = new (alloc()) 5870 LGuardShapeListToOffset(useRegister(ins->object()), temp(), temp()); 5871 assignSnapshot(lir, ins->bailoutKind()); 5872 define(lir, ins); 5873 } else { 5874 auto* lir = new (alloc()) LGuardShapeListToOffset( 5875 useRegister(ins->object()), temp(), LDefinition::BogusTemp()); 5876 assignSnapshot(lir, ins->bailoutKind()); 5877 define(lir, ins); 5878 } 5879 } 5880 5881 void LIRGenerator::visitGuardMultipleShapesToOffset( 5882 MGuardMultipleShapesToOffset* ins) { 5883 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5884 5885 auto* lir = new (alloc()) LGuardMultipleShapesToOffset( 5886 useRegister(ins->object()), useRegister(ins->shapeList()), temp(), temp(), 5887 temp()); 5888 assignSnapshot(lir, ins->bailoutKind()); 5889 define(lir, ins); 5890 } 5891 5892 void LIRGenerator::visitGuardProto(MGuardProto* ins) { 5893 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5894 MOZ_ASSERT(ins->expected()->type() == MIRType::Object); 5895 5896 auto* lir = new (alloc()) LGuardProto(useRegister(ins->object()), 5897 useRegister(ins->expected()), temp()); 5898 assignSnapshot(lir, ins->bailoutKind()); 5899 add(lir, ins); 5900 redefine(ins, ins->object()); 5901 } 5902 5903 void LIRGenerator::visitGuardNullProto(MGuardNullProto* ins) { 5904 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5905 5906 auto* lir = new (alloc()) LGuardNullProto(useRegister(ins->object()), temp()); 5907 assignSnapshot(lir, ins->bailoutKind()); 5908 add(lir, ins); 5909 redefine(ins, ins->object()); 5910 } 5911 5912 void LIRGenerator::visitGuardIsNativeObject(MGuardIsNativeObject* ins) { 5913 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5914 5915 auto* lir = 5916 new (alloc()) LGuardIsNativeObject(useRegister(ins->object()), temp()); 5917 assignSnapshot(lir, ins->bailoutKind()); 5918 add(lir, ins); 5919 redefine(ins, ins->object()); 5920 } 5921 5922 void LIRGenerator::visitGuardGlobalGeneration(MGuardGlobalGeneration* ins) { 5923 auto* lir = new (alloc()) LGuardGlobalGeneration(temp()); 5924 assignSnapshot(lir, ins->bailoutKind()); 5925 add(lir, ins); 5926 } 5927 5928 void LIRGenerator::visitGuardFuse(MGuardFuse* ins) { 5929 auto* lir = new (alloc()) LGuardFuse(); 5930 assignSnapshot(lir, ins->bailoutKind()); 5931 add(lir, ins); 5932 } 5933 5934 void LIRGenerator::visitGuardIsProxy(MGuardIsProxy* ins) { 5935 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5936 5937 auto* lir = new (alloc()) LGuardIsProxy(useRegister(ins->object()), temp()); 5938 assignSnapshot(lir, ins->bailoutKind()); 5939 add(lir, ins); 5940 redefine(ins, ins->object()); 5941 } 5942 5943 void LIRGenerator::visitGuardIsNotProxy(MGuardIsNotProxy* ins) { 5944 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 5945 5946 auto* lir = 5947 new (alloc()) LGuardIsNotProxy(useRegister(ins->object()), temp()); 5948 assignSnapshot(lir, ins->bailoutKind()); 5949 add(lir, ins); 5950 redefine(ins, ins->object()); 5951 } 5952 5953 void LIRGenerator::visitGuardIsNotDOMProxy(MGuardIsNotDOMProxy* ins) { 5954 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object); 5955 5956 auto* lir = 5957 new (alloc()) LGuardIsNotDOMProxy(useRegister(ins->proxy()), temp()); 5958 assignSnapshot(lir, ins->bailoutKind()); 5959 add(lir, ins); 5960 redefine(ins, ins->proxy()); 5961 } 5962 5963 void LIRGenerator::visitProxyGet(MProxyGet* ins) { 5964 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object); 5965 auto* lir = new (alloc()) 5966 LProxyGet(useRegisterAtStart(ins->proxy()), tempFixed(CallTempReg0)); 5967 defineReturn(lir, ins); 5968 assignSafepoint(lir, ins); 5969 } 5970 5971 void LIRGenerator::visitProxyGetByValue(MProxyGetByValue* ins) { 5972 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object); 5973 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value); 5974 auto* lir = new (alloc()) LProxyGetByValue(useRegisterAtStart(ins->proxy()), 5975 useBoxAtStart(ins->idVal())); 5976 defineReturn(lir, ins); 5977 assignSafepoint(lir, ins); 5978 } 5979 5980 void LIRGenerator::visitProxyHasProp(MProxyHasProp* ins) { 5981 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object); 5982 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value); 5983 auto* lir = new (alloc()) LProxyHasProp(useRegisterAtStart(ins->proxy()), 5984 useBoxAtStart(ins->idVal())); 5985 defineReturn(lir, ins); 5986 assignSafepoint(lir, ins); 5987 } 5988 5989 void LIRGenerator::visitProxySet(MProxySet* ins) { 5990 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object); 5991 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value); 5992 auto* lir = new (alloc()) 5993 LProxySet(useRegisterAtStart(ins->proxy()), useBoxAtStart(ins->rhs()), 5994 tempFixed(CallTempReg0)); 5995 add(lir, ins); 5996 assignSafepoint(lir, ins); 5997 } 5998 5999 void LIRGenerator::visitProxySetByValue(MProxySetByValue* ins) { 6000 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object); 6001 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value); 6002 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value); 6003 auto* lir = new (alloc()) 6004 LProxySetByValue(useRegisterAtStart(ins->proxy()), 6005 useBoxAtStart(ins->idVal()), useBoxAtStart(ins->rhs())); 6006 add(lir, ins); 6007 assignSafepoint(lir, ins); 6008 } 6009 6010 void LIRGenerator::visitCallSetArrayLength(MCallSetArrayLength* ins) { 6011 MOZ_ASSERT(ins->obj()->type() == MIRType::Object); 6012 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value); 6013 auto* lir = new (alloc()) LCallSetArrayLength(useRegisterAtStart(ins->obj()), 6014 useBoxAtStart(ins->rhs())); 6015 add(lir, ins); 6016 assignSafepoint(lir, ins); 6017 } 6018 6019 void LIRGenerator::visitMegamorphicLoadSlot(MMegamorphicLoadSlot* ins) { 6020 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6021 auto* lir = new (alloc()) 6022 LMegamorphicLoadSlot(useRegisterAtStart(ins->object()), 6023 tempFixed(CallTempReg0), tempFixed(CallTempReg1), 6024 tempFixed(CallTempReg2), tempFixed(CallTempReg3)); 6025 assignSnapshot(lir, ins->bailoutKind()); 6026 defineReturn(lir, ins); 6027 } 6028 6029 void LIRGenerator::visitMegamorphicLoadSlotPermissive( 6030 MMegamorphicLoadSlotPermissive* ins) { 6031 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6032 static_assert(IonGenericCallCalleeReg == CallTempReg1); 6033 static_assert(IonGenericCallArgcReg == CallTempReg2); 6034 6035 auto* lir = new (alloc()) LMegamorphicLoadSlotPermissive( 6036 useRegisterAtStart(ins->object()), tempFixed(CallTempReg0), 6037 tempFixed(IonGenericCallCalleeReg), tempFixed(IonGenericCallArgcReg), 6038 tempFixed(CallTempReg4)); 6039 defineReturn(lir, ins); 6040 assignSafepoint(lir, ins); 6041 lirGraph_.addExtraSafepointUses(1); 6042 } 6043 6044 void LIRGenerator::visitMegamorphicLoadSlotByValue( 6045 MMegamorphicLoadSlotByValue* ins) { 6046 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6047 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value); 6048 auto* lir = new (alloc()) LMegamorphicLoadSlotByValue( 6049 useRegisterAtStart(ins->object()), useBoxAtStart(ins->idVal()), 6050 tempFixed(CallTempReg0), tempFixed(CallTempReg1), 6051 tempFixed(CallTempReg2)); 6052 assignSnapshot(lir, ins->bailoutKind()); 6053 defineReturn(lir, ins); 6054 } 6055 6056 void LIRGenerator::visitMegamorphicLoadSlotByValuePermissive( 6057 MMegamorphicLoadSlotByValuePermissive* ins) { 6058 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6059 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value); 6060 #ifdef JS_CODEGEN_X86 6061 auto* lir = new (alloc()) LMegamorphicLoadSlotByValuePermissive( 6062 useRegisterAtStart(ins->object()), useBoxAtStart(ins->idVal()), 6063 tempFixed(CallTempReg0), tempFixed(IonGenericCallCalleeReg), 6064 tempFixed(IonGenericCallArgcReg)); 6065 defineReturn(lir, ins); 6066 assignSafepoint(lir, ins); 6067 #else 6068 static_assert(IonGenericCallCalleeReg == CallTempReg1); 6069 static_assert(IonGenericCallArgcReg == CallTempReg2); 6070 6071 auto* lir = new (alloc()) LMegamorphicLoadSlotByValuePermissive( 6072 useRegisterAtStart(ins->object()), useBoxAtStart(ins->idVal()), 6073 tempFixed(CallTempReg0), tempFixed(IonGenericCallCalleeReg), 6074 tempFixed(IonGenericCallArgcReg), tempFixed(CallTempReg4)); 6075 defineReturn(lir, ins); 6076 assignSafepoint(lir, ins); 6077 lirGraph_.addExtraSafepointUses(1); 6078 #endif 6079 } 6080 6081 void LIRGenerator::visitMegamorphicStoreSlot(MMegamorphicStoreSlot* ins) { 6082 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6083 MOZ_ASSERT(ins->rhs()->type() == MIRType::Value); 6084 6085 #ifdef JS_CODEGEN_X86 6086 auto* lir = new (alloc()) LMegamorphicStoreSlot( 6087 useFixedAtStart(ins->object(), CallTempReg0), 6088 useBoxFixedAtStart(ins->rhs(), CallTempReg1, CallTempReg2), 6089 tempFixed(CallTempReg5)); 6090 #else 6091 auto* lir = new (alloc()) 6092 LMegamorphicStoreSlot(useRegisterAtStart(ins->object()), 6093 useBoxAtStart(ins->rhs()), tempFixed(CallTempReg0), 6094 tempFixed(CallTempReg1), tempFixed(CallTempReg2)); 6095 #endif 6096 6097 add(lir, ins); 6098 assignSafepoint(lir, ins); 6099 } 6100 6101 void LIRGenerator::visitMegamorphicHasProp(MMegamorphicHasProp* ins) { 6102 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6103 MOZ_ASSERT(ins->idVal()->type() == MIRType::Value); 6104 auto* lir = new (alloc()) 6105 LMegamorphicHasProp(useRegisterAtStart(ins->object()), 6106 useBoxAtStart(ins->idVal()), tempFixed(CallTempReg0), 6107 tempFixed(CallTempReg1), tempFixed(CallTempReg2)); 6108 assignSnapshot(lir, ins->bailoutKind()); 6109 defineReturn(lir, ins); 6110 } 6111 6112 void LIRGenerator::visitSmallObjectVariableKeyHasProp( 6113 MSmallObjectVariableKeyHasProp* ins) { 6114 MOZ_ASSERT(ins->idStr()->type() == MIRType::String); 6115 auto* lir = new (alloc()) 6116 LSmallObjectVariableKeyHasProp(useRegisterAtStart(ins->idStr())); 6117 define(lir, ins); 6118 assignSafepoint(lir, ins); 6119 } 6120 6121 void LIRGenerator::visitGuardToArrayBuffer(MGuardToArrayBuffer* ins) { 6122 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6123 6124 auto* lir = new (alloc()) 6125 LGuardToArrayBuffer(useRegisterAtStart(ins->object()), temp()); 6126 assignSnapshot(lir, ins->bailoutKind()); 6127 defineReuseInput(lir, ins, 0); 6128 } 6129 6130 void LIRGenerator::visitGuardToSharedArrayBuffer( 6131 MGuardToSharedArrayBuffer* ins) { 6132 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6133 6134 auto* lir = new (alloc()) 6135 LGuardToSharedArrayBuffer(useRegisterAtStart(ins->object()), temp()); 6136 assignSnapshot(lir, ins->bailoutKind()); 6137 defineReuseInput(lir, ins, 0); 6138 } 6139 6140 void LIRGenerator::visitGuardIsNotArrayBufferMaybeShared( 6141 MGuardIsNotArrayBufferMaybeShared* ins) { 6142 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6143 6144 auto* lir = new (alloc()) 6145 LGuardIsNotArrayBufferMaybeShared(useRegister(ins->object()), temp()); 6146 assignSnapshot(lir, ins->bailoutKind()); 6147 add(lir, ins); 6148 redefine(ins, ins->object()); 6149 } 6150 6151 void LIRGenerator::visitGuardIsTypedArray(MGuardIsTypedArray* ins) { 6152 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6153 6154 auto* lir = 6155 new (alloc()) LGuardIsTypedArray(useRegister(ins->object()), temp()); 6156 assignSnapshot(lir, ins->bailoutKind()); 6157 add(lir, ins); 6158 redefine(ins, ins->object()); 6159 } 6160 6161 void LIRGenerator::visitGuardIsNonResizableTypedArray( 6162 MGuardIsNonResizableTypedArray* ins) { 6163 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6164 6165 auto* lir = new (alloc()) 6166 LGuardIsNonResizableTypedArray(useRegister(ins->object()), temp()); 6167 assignSnapshot(lir, ins->bailoutKind()); 6168 add(lir, ins); 6169 redefine(ins, ins->object()); 6170 } 6171 6172 void LIRGenerator::visitGuardIsResizableTypedArray( 6173 MGuardIsResizableTypedArray* ins) { 6174 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6175 6176 auto* lir = new (alloc()) 6177 LGuardIsResizableTypedArray(useRegister(ins->object()), temp()); 6178 assignSnapshot(lir, ins->bailoutKind()); 6179 add(lir, ins); 6180 redefine(ins, ins->object()); 6181 } 6182 6183 void LIRGenerator::visitGuardHasProxyHandler(MGuardHasProxyHandler* ins) { 6184 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6185 6186 auto* lir = new (alloc()) LGuardHasProxyHandler(useRegister(ins->object())); 6187 assignSnapshot(lir, ins->bailoutKind()); 6188 add(lir, ins); 6189 redefine(ins, ins->object()); 6190 } 6191 6192 void LIRGenerator::visitNurseryObject(MNurseryObject* ins) { 6193 MOZ_ASSERT(ins->type() == MIRType::Object); 6194 6195 auto* lir = new (alloc()) LNurseryObject(); 6196 define(lir, ins); 6197 } 6198 6199 void LIRGenerator::visitGuardValue(MGuardValue* ins) { 6200 MOZ_ASSERT(ins->value()->type() == MIRType::Value); 6201 LDefinition tempDef = LDefinition::BogusTemp(); 6202 if (!ins->expected().isValue() || ins->expected().toValue().isNaN()) { 6203 tempDef = temp(); 6204 } 6205 auto* lir = new (alloc()) LGuardValue(useBox(ins->value()), tempDef); 6206 assignSnapshot(lir, ins->bailoutKind()); 6207 add(lir, ins); 6208 redefine(ins, ins->value()); 6209 } 6210 6211 void LIRGenerator::visitGuardNullOrUndefined(MGuardNullOrUndefined* ins) { 6212 MOZ_ASSERT(ins->value()->type() == MIRType::Value); 6213 auto* lir = new (alloc()) LGuardNullOrUndefined(useBox(ins->value())); 6214 assignSnapshot(lir, ins->bailoutKind()); 6215 add(lir, ins); 6216 redefine(ins, ins->value()); 6217 } 6218 6219 void LIRGenerator::visitGuardIsNotObject(MGuardIsNotObject* ins) { 6220 MOZ_ASSERT(ins->value()->type() == MIRType::Value); 6221 auto* lir = new (alloc()) LGuardIsNotObject(useBox(ins->value())); 6222 assignSnapshot(lir, ins->bailoutKind()); 6223 add(lir, ins); 6224 redefine(ins, ins->value()); 6225 } 6226 6227 void LIRGenerator::visitGuardFunctionFlags(MGuardFunctionFlags* ins) { 6228 MOZ_ASSERT(ins->function()->type() == MIRType::Object); 6229 6230 auto* lir = new (alloc()) LGuardFunctionFlags(useRegister(ins->function())); 6231 assignSnapshot(lir, ins->bailoutKind()); 6232 add(lir, ins); 6233 redefine(ins, ins->function()); 6234 } 6235 6236 void LIRGenerator::visitGuardFunctionIsNonBuiltinCtor( 6237 MGuardFunctionIsNonBuiltinCtor* ins) { 6238 MOZ_ASSERT(ins->function()->type() == MIRType::Object); 6239 6240 auto* lir = new (alloc()) 6241 LGuardFunctionIsNonBuiltinCtor(useRegister(ins->function()), temp()); 6242 assignSnapshot(lir, ins->bailoutKind()); 6243 add(lir, ins); 6244 redefine(ins, ins->function()); 6245 } 6246 6247 void LIRGenerator::visitGuardFunctionKind(MGuardFunctionKind* ins) { 6248 MOZ_ASSERT(ins->function()->type() == MIRType::Object); 6249 6250 auto* lir = 6251 new (alloc()) LGuardFunctionKind(useRegister(ins->function()), temp()); 6252 assignSnapshot(lir, ins->bailoutKind()); 6253 add(lir, ins); 6254 redefine(ins, ins->function()); 6255 } 6256 6257 void LIRGenerator::visitGuardFunctionScript(MGuardFunctionScript* ins) { 6258 MOZ_ASSERT(ins->function()->type() == MIRType::Object); 6259 6260 auto* lir = new (alloc()) LGuardFunctionScript(useRegister(ins->function())); 6261 assignSnapshot(lir, ins->bailoutKind()); 6262 add(lir, ins); 6263 redefine(ins, ins->function()); 6264 } 6265 6266 void LIRGenerator::visitAssertRange(MAssertRange* ins) { 6267 MDefinition* input = ins->input(); 6268 switch (input->type()) { 6269 case MIRType::Boolean: 6270 case MIRType::Int32: 6271 case MIRType::IntPtr: 6272 add(new (alloc()) LAssertRangeI(useRegisterAtStart(input)), ins); 6273 break; 6274 6275 case MIRType::Double: 6276 add(new (alloc()) LAssertRangeD(useRegister(input), tempDouble()), ins); 6277 break; 6278 6279 case MIRType::Float32: 6280 add(new (alloc()) 6281 LAssertRangeF(useRegister(input), tempDouble(), tempDouble()), 6282 ins); 6283 break; 6284 6285 case MIRType::Value: 6286 add(new (alloc()) LAssertRangeV(useBox(input), tempToUnbox(), 6287 tempDouble(), tempDouble()), 6288 ins); 6289 break; 6290 6291 default: 6292 MOZ_CRASH("Unexpected Range for MIRType"); 6293 break; 6294 } 6295 } 6296 6297 void LIRGenerator::visitAssertClass(MAssertClass* ins) { 6298 auto* lir = 6299 new (alloc()) LAssertClass(useRegisterAtStart(ins->input()), temp()); 6300 add(lir, ins); 6301 } 6302 6303 void LIRGenerator::visitAssertShape(MAssertShape* ins) { 6304 auto* lir = new (alloc()) LAssertShape(useRegisterAtStart(ins->input())); 6305 add(lir, ins); 6306 } 6307 6308 void LIRGenerator::visitDeleteProperty(MDeleteProperty* ins) { 6309 LDeleteProperty* lir = 6310 new (alloc()) LDeleteProperty(useBoxAtStart(ins->value())); 6311 defineReturn(lir, ins); 6312 assignSafepoint(lir, ins); 6313 } 6314 6315 void LIRGenerator::visitDeleteElement(MDeleteElement* ins) { 6316 LDeleteElement* lir = new (alloc()) 6317 LDeleteElement(useBoxAtStart(ins->value()), useBoxAtStart(ins->index())); 6318 defineReturn(lir, ins); 6319 assignSafepoint(lir, ins); 6320 } 6321 6322 void LIRGenerator::visitObjectToIterator(MObjectToIterator* ins) { 6323 auto* lir = new (alloc()) 6324 LObjectToIterator(useRegister(ins->object()), temp(), temp(), temp()); 6325 define(lir, ins); 6326 assignSafepoint(lir, ins); 6327 } 6328 6329 void LIRGenerator::visitValueToIterator(MValueToIterator* ins) { 6330 auto* lir = new (alloc()) LValueToIterator(useBoxAtStart(ins->value())); 6331 defineReturn(lir, ins); 6332 assignSafepoint(lir, ins); 6333 } 6334 6335 void LIRGenerator::visitLoadSlotByIteratorIndex(MLoadSlotByIteratorIndex* ins) { 6336 auto* lir = new (alloc()) LLoadSlotByIteratorIndex( 6337 useRegisterAtStart(ins->object()), useRegisterAtStart(ins->iterator()), 6338 temp(), temp()); 6339 defineBox(lir, ins); 6340 } 6341 6342 void LIRGenerator::visitStoreSlotByIteratorIndex( 6343 MStoreSlotByIteratorIndex* ins) { 6344 auto* lir = new (alloc()) LStoreSlotByIteratorIndex( 6345 useRegister(ins->object()), useRegister(ins->iterator()), 6346 useBox(ins->value()), temp(), temp()); 6347 add(lir, ins); 6348 } 6349 6350 void LIRGenerator::visitLoadSlotByIteratorIndexIndexed( 6351 MLoadSlotByIteratorIndexIndexed* ins) { 6352 auto* lir = new (alloc()) LLoadSlotByIteratorIndexIndexed( 6353 useRegister(ins->object()), useRegister(ins->iterator()), 6354 useRegister(ins->index()), temp(), temp()); 6355 defineBox(lir, ins); 6356 } 6357 6358 void LIRGenerator::visitStoreSlotByIteratorIndexIndexed( 6359 MStoreSlotByIteratorIndexIndexed* ins) { 6360 auto* lir = new (alloc()) LStoreSlotByIteratorIndexIndexed( 6361 useRegister(ins->object()), useRegister(ins->iterator()), 6362 useRegister(ins->index()), useBox(ins->value()), temp(), temp()); 6363 add(lir, ins); 6364 } 6365 6366 void LIRGenerator::visitIteratorHasIndices(MIteratorHasIndices* ins) { 6367 MOZ_ASSERT(ins->hasOneUse()); 6368 emitAtUses(ins); 6369 } 6370 6371 void LIRGenerator::visitIteratorsMatchAndHaveIndices( 6372 MIteratorsMatchAndHaveIndices* ins) { 6373 MOZ_ASSERT(ins->hasOneUse()); 6374 emitAtUses(ins); 6375 } 6376 6377 void LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins) { 6378 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6379 6380 MDefinition* id = ins->idval(); 6381 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol || 6382 id->type() == MIRType::Int32 || id->type() == MIRType::Value); 6383 6384 // If this is a SetProp, the id is a constant string. Allow passing it as a 6385 // constant to reduce register allocation pressure. 6386 bool useConstId = 6387 id->type() == MIRType::String || id->type() == MIRType::Symbol; 6388 bool useConstValue = ins->value()->isConstant(); 6389 6390 // Emit an overrecursed check: this is necessary because the cache can 6391 // attach a scripted setter stub that calls this script recursively. 6392 gen->setNeedsOverrecursedCheck(); 6393 6394 // We need a double temp register for TypedArray stubs. 6395 LDefinition tempD = tempFixed(FloatReg0); 6396 6397 auto* lir = new (alloc()) LSetPropertyCache( 6398 useRegister(ins->object()), useBoxOrTypedOrConstant(id, useConstId), 6399 useBoxOrTypedOrConstant(ins->value(), useConstValue), temp(), tempD); 6400 add(lir, ins); 6401 assignSafepoint(lir, ins); 6402 } 6403 6404 void LIRGenerator::visitMegamorphicSetElement(MMegamorphicSetElement* ins) { 6405 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6406 MOZ_ASSERT(ins->index()->type() == MIRType::Value); 6407 MOZ_ASSERT(ins->value()->type() == MIRType::Value); 6408 6409 // See comment in LIROps.yaml (x86 is short on registers) 6410 #ifdef JS_CODEGEN_X86 6411 auto* lir = new (alloc()) LMegamorphicSetElement( 6412 useFixedAtStart(ins->object(), CallTempReg0), 6413 useBoxFixedAtStart(ins->index(), CallTempReg1, CallTempReg2), 6414 useBoxFixedAtStart(ins->value(), CallTempReg3, CallTempReg4), 6415 tempFixed(CallTempReg5)); 6416 #else 6417 auto* lir = new (alloc()) LMegamorphicSetElement( 6418 useRegisterAtStart(ins->object()), useBoxAtStart(ins->index()), 6419 useBoxAtStart(ins->value()), tempFixed(CallTempReg0), 6420 tempFixed(CallTempReg1), tempFixed(CallTempReg2)); 6421 #endif 6422 add(lir, ins); 6423 assignSafepoint(lir, ins); 6424 } 6425 6426 void LIRGenerator::visitGetIteratorCache(MGetIteratorCache* ins) { 6427 MDefinition* value = ins->value(); 6428 MOZ_ASSERT(value->type() == MIRType::Object || 6429 value->type() == MIRType::Value); 6430 6431 LGetIteratorCache* lir = 6432 new (alloc()) LGetIteratorCache(useBoxOrTyped(value), temp(), temp()); 6433 define(lir, ins); 6434 assignSafepoint(lir, ins); 6435 } 6436 6437 void LIRGenerator::visitOptimizeSpreadCallCache(MOptimizeSpreadCallCache* ins) { 6438 MDefinition* value = ins->value(); 6439 MOZ_ASSERT(value->type() == MIRType::Value); 6440 6441 auto* lir = new (alloc()) LOptimizeSpreadCallCache(useBox(value), temp()); 6442 defineBox(lir, ins); 6443 assignSafepoint(lir, ins); 6444 } 6445 6446 void LIRGenerator::visitIteratorMore(MIteratorMore* ins) { 6447 LIteratorMore* lir = 6448 new (alloc()) LIteratorMore(useRegister(ins->iterator()), temp()); 6449 defineBox(lir, ins); 6450 } 6451 6452 void LIRGenerator::visitIsNoIter(MIsNoIter* ins) { 6453 MOZ_ASSERT(ins->hasOneUse()); 6454 emitAtUses(ins); 6455 } 6456 6457 void LIRGenerator::visitIteratorEnd(MIteratorEnd* ins) { 6458 LIteratorEnd* lir = new (alloc()) 6459 LIteratorEnd(useRegister(ins->iterator()), temp(), temp(), temp()); 6460 add(lir, ins); 6461 } 6462 6463 void LIRGenerator::visitCloseIterCache(MCloseIterCache* ins) { 6464 LCloseIterCache* lir = 6465 new (alloc()) LCloseIterCache(useRegister(ins->iter()), temp()); 6466 add(lir, ins); 6467 assignSafepoint(lir, ins); 6468 } 6469 6470 void LIRGenerator::visitLoadIteratorElement(MLoadIteratorElement* ins) { 6471 MOZ_ASSERT(ins->iter()->type() == MIRType::Object); 6472 MOZ_ASSERT(ins->index()->type() == MIRType::Int32); 6473 MOZ_ASSERT(ins->type() == MIRType::String); 6474 6475 auto* lir = new (alloc()) LLoadIteratorElement( 6476 useRegister(ins->iter()), useRegisterOrConstant(ins->index())); 6477 define(lir, ins); 6478 } 6479 6480 void LIRGenerator::visitIteratorLength(MIteratorLength* ins) { 6481 MOZ_ASSERT(ins->iter()->type() == MIRType::Object); 6482 MOZ_ASSERT(ins->type() == MIRType::Int32); 6483 6484 auto* lir = new (alloc()) LIteratorLength(useRegister(ins->iter())); 6485 define(lir, ins); 6486 } 6487 6488 void LIRGenerator::visitOptimizeGetIteratorCache( 6489 MOptimizeGetIteratorCache* ins) { 6490 MDefinition* value = ins->value(); 6491 MOZ_ASSERT(value->type() == MIRType::Value); 6492 6493 auto* lir = new (alloc()) LOptimizeGetIteratorCache(useBox(value), temp()); 6494 define(lir, ins); 6495 assignSafepoint(lir, ins); 6496 } 6497 6498 void LIRGenerator::visitStringLength(MStringLength* ins) { 6499 MOZ_ASSERT(ins->string()->type() == MIRType::String); 6500 define(new (alloc()) LStringLength(useRegisterAtStart(ins->string())), ins); 6501 } 6502 6503 void LIRGenerator::visitArgumentsLength(MArgumentsLength* ins) { 6504 define(new (alloc()) LArgumentsLength(), ins); 6505 } 6506 6507 void LIRGenerator::visitGetFrameArgument(MGetFrameArgument* ins) { 6508 LGetFrameArgument* lir = 6509 new (alloc()) LGetFrameArgument(useRegisterOrConstant(ins->index())); 6510 defineBox(lir, ins); 6511 } 6512 6513 void LIRGenerator::visitGetFrameArgumentHole(MGetFrameArgumentHole* ins) { 6514 LDefinition spectreTemp = 6515 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp(); 6516 6517 auto* lir = new (alloc()) LGetFrameArgumentHole( 6518 useRegister(ins->index()), useRegister(ins->length()), spectreTemp); 6519 assignSnapshot(lir, ins->bailoutKind()); 6520 defineBox(lir, ins); 6521 } 6522 6523 void LIRGenerator::visitNewTarget(MNewTarget* ins) { 6524 LNewTarget* lir = new (alloc()) LNewTarget(); 6525 defineBox(lir, ins); 6526 } 6527 6528 void LIRGenerator::visitRest(MRest* ins) { 6529 MOZ_ASSERT(ins->numActuals()->type() == MIRType::Int32); 6530 6531 LRest* lir = 6532 new (alloc()) LRest(useRegisterAtStart(ins->numActuals()), 6533 tempFixed(CallTempReg0), tempFixed(CallTempReg1), 6534 tempFixed(CallTempReg2), tempFixed(CallTempReg3)); 6535 defineReturn(lir, ins); 6536 assignSafepoint(lir, ins); 6537 } 6538 6539 void LIRGenerator::visitThrow(MThrow* ins) { 6540 MDefinition* value = ins->value(); 6541 MOZ_ASSERT(value->type() == MIRType::Value); 6542 6543 LThrow* lir = new (alloc()) LThrow(useBoxAtStart(value)); 6544 add(lir, ins); 6545 assignSafepoint(lir, ins); 6546 } 6547 6548 void LIRGenerator::visitThrowWithStack(MThrowWithStack* ins) { 6549 MDefinition* value = ins->value(); 6550 MOZ_ASSERT(value->type() == MIRType::Value); 6551 6552 MDefinition* stack = ins->stack(); 6553 MOZ_ASSERT(stack->type() == MIRType::Value); 6554 6555 auto* lir = 6556 new (alloc()) LThrowWithStack(useBoxAtStart(value), useBoxAtStart(stack)); 6557 add(lir, ins); 6558 assignSafepoint(lir, ins); 6559 } 6560 6561 void LIRGenerator::visitInCache(MInCache* ins) { 6562 MDefinition* lhs = ins->lhs(); 6563 MDefinition* rhs = ins->rhs(); 6564 6565 MOZ_ASSERT(lhs->type() == MIRType::String || lhs->type() == MIRType::Symbol || 6566 lhs->type() == MIRType::Int32 || lhs->type() == MIRType::Value); 6567 MOZ_ASSERT(rhs->type() == MIRType::Object); 6568 6569 LInCache* lir = 6570 new (alloc()) LInCache(useBoxOrTyped(lhs), useRegister(rhs), temp()); 6571 define(lir, ins); 6572 assignSafepoint(lir, ins); 6573 } 6574 6575 void LIRGenerator::visitHasOwnCache(MHasOwnCache* ins) { 6576 MDefinition* value = ins->value(); 6577 MOZ_ASSERT(value->type() == MIRType::Object || 6578 value->type() == MIRType::Value); 6579 6580 MDefinition* id = ins->idval(); 6581 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol || 6582 id->type() == MIRType::Int32 || id->type() == MIRType::Value); 6583 6584 // Emit an overrecursed check: this is necessary because the cache can 6585 // attach a scripted getter stub that calls this script recursively. 6586 gen->setNeedsOverrecursedCheck(); 6587 6588 LHasOwnCache* lir = 6589 new (alloc()) LHasOwnCache(useBoxOrTyped(value), useBoxOrTyped(id)); 6590 define(lir, ins); 6591 assignSafepoint(lir, ins); 6592 } 6593 6594 void LIRGenerator::visitCheckPrivateFieldCache(MCheckPrivateFieldCache* ins) { 6595 MDefinition* value = ins->value(); 6596 MOZ_ASSERT(value->type() == MIRType::Object || 6597 value->type() == MIRType::Value); 6598 6599 MDefinition* id = ins->idval(); 6600 MOZ_ASSERT(id->type() == MIRType::String || id->type() == MIRType::Symbol || 6601 id->type() == MIRType::Int32 || id->type() == MIRType::Value); 6602 6603 LCheckPrivateFieldCache* lir = new (alloc()) 6604 LCheckPrivateFieldCache(useBoxOrTyped(value), useBoxOrTyped(id)); 6605 define(lir, ins); 6606 assignSafepoint(lir, ins); 6607 } 6608 6609 void LIRGenerator::visitNewPrivateName(MNewPrivateName* ins) { 6610 auto* lir = new (alloc()) LNewPrivateName(); 6611 defineReturn(lir, ins); 6612 assignSafepoint(lir, ins); 6613 } 6614 6615 void LIRGenerator::visitInstanceOf(MInstanceOf* ins) { 6616 MDefinition* lhs = ins->lhs(); 6617 MDefinition* rhs = ins->rhs(); 6618 6619 MOZ_ASSERT(lhs->type() == MIRType::Value || lhs->type() == MIRType::Object); 6620 MOZ_ASSERT(rhs->type() == MIRType::Object); 6621 6622 if (lhs->type() == MIRType::Object) { 6623 auto* lir = new (alloc()) LInstanceOfO(useRegister(lhs), useRegister(rhs)); 6624 define(lir, ins); 6625 assignSafepoint(lir, ins); 6626 } else { 6627 auto* lir = new (alloc()) LInstanceOfV(useBox(lhs), useRegister(rhs)); 6628 define(lir, ins); 6629 assignSafepoint(lir, ins); 6630 } 6631 } 6632 6633 void LIRGenerator::visitInstanceOfCache(MInstanceOfCache* ins) { 6634 MDefinition* lhs = ins->lhs(); 6635 MDefinition* rhs = ins->rhs(); 6636 6637 MOZ_ASSERT(lhs->type() == MIRType::Value); 6638 MOZ_ASSERT(rhs->type() == MIRType::Object); 6639 6640 LInstanceOfCache* lir = 6641 new (alloc()) LInstanceOfCache(useBox(lhs), useRegister(rhs)); 6642 define(lir, ins); 6643 assignSafepoint(lir, ins); 6644 } 6645 6646 void LIRGenerator::visitIsArray(MIsArray* ins) { 6647 MOZ_ASSERT(ins->type() == MIRType::Boolean); 6648 6649 if (ins->value()->type() == MIRType::Object) { 6650 LIsArrayO* lir = new (alloc()) LIsArrayO(useRegister(ins->value())); 6651 define(lir, ins); 6652 assignSafepoint(lir, ins); 6653 } else { 6654 MOZ_ASSERT(ins->value()->type() == MIRType::Value); 6655 LIsArrayV* lir = new (alloc()) LIsArrayV(useBox(ins->value()), temp()); 6656 define(lir, ins); 6657 assignSafepoint(lir, ins); 6658 } 6659 } 6660 6661 void LIRGenerator::visitIsTypedArray(MIsTypedArray* ins) { 6662 MOZ_ASSERT(ins->value()->type() == MIRType::Object); 6663 MOZ_ASSERT(ins->type() == MIRType::Boolean); 6664 6665 auto* lir = new (alloc()) LIsTypedArray(useRegister(ins->value())); 6666 define(lir, ins); 6667 6668 if (ins->isPossiblyWrapped()) { 6669 assignSafepoint(lir, ins); 6670 } 6671 } 6672 6673 void LIRGenerator::visitIsCallable(MIsCallable* ins) { 6674 MOZ_ASSERT(ins->type() == MIRType::Boolean); 6675 6676 if (ins->object()->type() == MIRType::Object) { 6677 define(new (alloc()) LIsCallableO(useRegister(ins->object())), ins); 6678 } else { 6679 MOZ_ASSERT(ins->object()->type() == MIRType::Value); 6680 define(new (alloc()) LIsCallableV(useBox(ins->object()), temp()), ins); 6681 } 6682 } 6683 6684 void LIRGenerator::visitIsConstructor(MIsConstructor* ins) { 6685 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6686 MOZ_ASSERT(ins->type() == MIRType::Boolean); 6687 define(new (alloc()) LIsConstructor(useRegister(ins->object())), ins); 6688 } 6689 6690 void LIRGenerator::visitIsCrossRealmArrayConstructor( 6691 MIsCrossRealmArrayConstructor* ins) { 6692 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6693 MOZ_ASSERT(ins->type() == MIRType::Boolean); 6694 define(new (alloc()) 6695 LIsCrossRealmArrayConstructor(useRegister(ins->object())), 6696 ins); 6697 } 6698 6699 static bool CanEmitAtUseForSingleTest(MInstruction* ins) { 6700 if (!ins->canEmitAtUses()) { 6701 return false; 6702 } 6703 6704 MUseIterator iter(ins->usesBegin()); 6705 if (iter == ins->usesEnd()) { 6706 return false; 6707 } 6708 6709 MNode* node = iter->consumer(); 6710 if (!node->isDefinition()) { 6711 return false; 6712 } 6713 6714 if (!node->toDefinition()->isTest()) { 6715 return false; 6716 } 6717 6718 iter++; 6719 return iter == ins->usesEnd(); 6720 } 6721 6722 void LIRGenerator::visitIsObject(MIsObject* ins) { 6723 if (CanEmitAtUseForSingleTest(ins)) { 6724 emitAtUses(ins); 6725 return; 6726 } 6727 6728 MDefinition* opd = ins->input(); 6729 MOZ_ASSERT(opd->type() == MIRType::Value); 6730 LIsObject* lir = new (alloc()) LIsObject(useBoxAtStart(opd)); 6731 define(lir, ins); 6732 } 6733 6734 void LIRGenerator::visitIsNullOrUndefined(MIsNullOrUndefined* ins) { 6735 if (CanEmitAtUseForSingleTest(ins)) { 6736 emitAtUses(ins); 6737 return; 6738 } 6739 6740 MDefinition* opd = ins->input(); 6741 if (opd->type() == MIRType::Value) { 6742 auto* lir = new (alloc()) LIsNullOrUndefined(useBoxAtStart(opd)); 6743 define(lir, ins); 6744 } else { 6745 define(new (alloc()) LInteger(IsNullOrUndefined(opd->type())), ins); 6746 } 6747 } 6748 6749 void LIRGenerator::visitHasClass(MHasClass* ins) { 6750 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6751 MOZ_ASSERT(ins->type() == MIRType::Boolean); 6752 define(new (alloc()) LHasClass(useRegister(ins->object())), ins); 6753 } 6754 6755 void LIRGenerator::visitHasShape(MHasShape* ins) { 6756 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6757 MOZ_ASSERT(ins->type() == MIRType::Boolean); 6758 define(new (alloc()) LHasShape(useRegister(ins->object())), ins); 6759 } 6760 6761 void LIRGenerator::visitGuardToClass(MGuardToClass* ins) { 6762 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6763 MOZ_ASSERT(ins->type() == MIRType::Object); 6764 LGuardToClass* lir = 6765 new (alloc()) LGuardToClass(useRegisterAtStart(ins->object()), temp()); 6766 assignSnapshot(lir, ins->bailoutKind()); 6767 defineReuseInput(lir, ins, 0); 6768 } 6769 6770 void LIRGenerator::visitGuardToFunction(MGuardToFunction* ins) { 6771 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6772 MOZ_ASSERT(ins->type() == MIRType::Object); 6773 LGuardToFunction* lir = 6774 new (alloc()) LGuardToFunction(useRegisterAtStart(ins->object()), temp()); 6775 assignSnapshot(lir, ins->bailoutKind()); 6776 defineReuseInput(lir, ins, 0); 6777 } 6778 6779 void LIRGenerator::visitObjectClassToString(MObjectClassToString* ins) { 6780 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 6781 MOZ_ASSERT(ins->type() == MIRType::String); 6782 auto* lir = new (alloc()) LObjectClassToString( 6783 useRegisterAtStart(ins->object()), tempFixed(CallTempReg0)); 6784 assignSnapshot(lir, ins->bailoutKind()); 6785 defineReturn(lir, ins); 6786 } 6787 6788 void LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins) { 6789 MOZ_ASSERT(ins->offset()); 6790 if (ins->base()->type() == MIRType::Int32) { 6791 MOZ_ASSERT(ins->type() == MIRType::Int32); 6792 MOZ_ASSERT(ins->offset() <= UINT32_MAX); // Because memory32 6793 define(new (alloc()) LWasmAddOffset(useRegisterAtStart(ins->base())), ins); 6794 } else { 6795 MOZ_ASSERT(ins->type() == MIRType::Int64); 6796 #ifdef JS_64BIT 6797 defineInt64(new (alloc()) 6798 LWasmAddOffset64(useInt64RegisterAtStart(ins->base())), 6799 ins); 6800 #else 6801 // Avoid situation where the input is (a,b) and the output is (b,a). 6802 defineInt64ReuseInput( 6803 new (alloc()) LWasmAddOffset64(useInt64RegisterAtStart(ins->base())), 6804 ins, 0); 6805 #endif 6806 } 6807 } 6808 6809 // When MWasmLoadInstance is used with MWasmBoundsCheck, it can be used as a 6810 // memory operand instead of being allocated to a register. 6811 static bool CanEmitWasmLoadInstanceAtUses(MWasmLoadInstance* ins) { 6812 if (!ins->canEmitAtUses()) { 6813 return false; 6814 } 6815 6816 if (!ins->hasOneUse()) { 6817 return false; 6818 } 6819 6820 MUseIterator iter(ins->usesBegin()); 6821 MNode* node = iter->consumer(); 6822 if (!node->isDefinition() || !node->toDefinition()->isInstruction()) { 6823 return false; 6824 } 6825 6826 MInstruction* use = node->toDefinition()->toInstruction(); 6827 return use->isWasmBoundsCheck(); 6828 } 6829 6830 void LIRGenerator::visitWasmLoadInstance(MWasmLoadInstance* ins) { 6831 if (CanEmitWasmLoadInstanceAtUses(ins)) { 6832 emitAtUses(ins); 6833 return; 6834 } 6835 6836 if (ins->type() == MIRType::Int64) { 6837 #ifdef JS_PUNBOX64 6838 LAllocation instance = useRegisterAtStart(ins->instance()); 6839 #else 6840 // Avoid reusing instance for a 64-bit output pair as the load clobbers the 6841 // first half of that pair before loading the second half. 6842 LAllocation instance = useRegister(ins->instance()); 6843 #endif 6844 auto* lir = new (alloc()) LWasmLoadInstance64(instance); 6845 defineInt64(lir, ins); 6846 } else { 6847 auto* lir = 6848 new (alloc()) LWasmLoadInstance(useRegisterAtStart(ins->instance())); 6849 define(lir, ins); 6850 } 6851 } 6852 6853 void LIRGenerator::visitWasmStoreInstance(MWasmStoreInstance* ins) { 6854 MDefinition* value = ins->value(); 6855 if (value->type() == MIRType::Int64) { 6856 #ifdef JS_PUNBOX64 6857 LAllocation instance = useRegisterAtStart(ins->instance()); 6858 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value); 6859 #else 6860 LAllocation instance = useRegister(ins->instance()); 6861 LInt64Allocation valueAlloc = useInt64Register(value); 6862 #endif 6863 add(new (alloc()) LWasmStoreSlotI64(valueAlloc, instance, ins->offset(), 6864 mozilla::Nothing()), 6865 ins); 6866 } else { 6867 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef); 6868 LAllocation instance = useRegisterAtStart(ins->instance()); 6869 LAllocation valueAlloc = useRegisterAtStart(value); 6870 add(new (alloc()) 6871 LWasmStoreSlot(valueAlloc, instance, ins->offset(), value->type(), 6872 MNarrowingOp::None, mozilla::Nothing()), 6873 ins); 6874 } 6875 } 6876 6877 void LIRGenerator::visitWasmHeapReg(MWasmHeapReg* ins) { 6878 #ifdef WASM_HAS_HEAPREG 6879 auto* lir = new (alloc()) LWasmHeapReg(); 6880 define(lir, ins); 6881 #else 6882 MOZ_CRASH(); 6883 #endif 6884 } 6885 6886 void LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) { 6887 MOZ_ASSERT(!ins->isRedundant()); 6888 6889 MDefinition* index = ins->index(); 6890 MDefinition* boundsCheckLimit = ins->boundsCheckLimit(); 6891 6892 MOZ_ASSERT(boundsCheckLimit->type() == index->type()); 6893 6894 // Fold the instance load into the bounds check as a memory operand, 6895 // if possible 6896 if (boundsCheckLimit->isWasmLoadInstance() && 6897 boundsCheckLimit->isEmittedAtUses()) { 6898 MWasmLoadInstance* lengthFromInstance = 6899 boundsCheckLimit->toWasmLoadInstance(); 6900 if (index->type() == MIRType::Int64) { 6901 if (JitOptions.spectreIndexMasking) { 6902 auto* lir = new (alloc()) LWasmBoundsCheckInstanceField64( 6903 useRegister(lengthFromInstance->instance()), 6904 useInt64RegisterAtStart(index), lengthFromInstance->offset()); 6905 defineInt64ReuseInput(lir, ins, 1); 6906 } else { 6907 auto* lir = new (alloc()) LWasmBoundsCheckInstanceField64( 6908 useRegisterAtStart(lengthFromInstance->instance()), 6909 useInt64RegisterAtStart(index), lengthFromInstance->offset()); 6910 addUnchecked(lir, ins); 6911 } 6912 } else { 6913 MOZ_ASSERT(index->type() == MIRType::Int32); 6914 6915 if (JitOptions.spectreIndexMasking) { 6916 auto* lir = new (alloc()) LWasmBoundsCheckInstanceField( 6917 useRegister(lengthFromInstance->instance()), 6918 useRegisterAtStart(index), lengthFromInstance->offset()); 6919 defineReuseInput(lir, ins, 1); 6920 } else { 6921 auto* lir = new (alloc()) LWasmBoundsCheckInstanceField( 6922 useRegisterAtStart(lengthFromInstance->instance()), 6923 useRegisterAtStart(index), lengthFromInstance->offset()); 6924 addUnchecked(lir, ins); 6925 } 6926 } 6927 6928 return; 6929 } 6930 6931 if (index->type() == MIRType::Int64) { 6932 if (JitOptions.spectreIndexMasking) { 6933 auto* lir = new (alloc()) 6934 LWasmBoundsCheck64(useInt64RegisterAtStart(index), 6935 useInt64RegisterOrConstant(boundsCheckLimit)); 6936 defineInt64ReuseInput(lir, ins, 0); 6937 } else { 6938 auto* lir = new (alloc()) LWasmBoundsCheck64( 6939 useInt64RegisterAtStart(index), 6940 useInt64RegisterOrConstantAtStart(boundsCheckLimit)); 6941 addUnchecked(lir, ins); 6942 } 6943 } else { 6944 MOZ_ASSERT(index->type() == MIRType::Int32); 6945 6946 if (JitOptions.spectreIndexMasking) { 6947 auto* lir = new (alloc()) LWasmBoundsCheck( 6948 useRegisterAtStart(index), useRegisterOrConstant(boundsCheckLimit)); 6949 defineReuseInput(lir, ins, 0); 6950 } else { 6951 auto* lir = new (alloc()) 6952 LWasmBoundsCheck(useRegisterAtStart(index), 6953 useRegisterOrConstantAtStart(boundsCheckLimit)); 6954 addUnchecked(lir, ins); 6955 } 6956 } 6957 } 6958 6959 void LIRGenerator::visitWasmBoundsCheckRange32(MWasmBoundsCheckRange32* ins) { 6960 MDefinition* index = ins->index(); 6961 MDefinition* length = ins->length(); 6962 MDefinition* limit = ins->limit(); 6963 6964 MOZ_ASSERT(index->type() == MIRType::Int32); 6965 MOZ_ASSERT(length->type() == MIRType::Int32); 6966 MOZ_ASSERT(limit->type() == MIRType::Int32); 6967 6968 add(new (alloc()) LWasmBoundsCheckRange32( 6969 useRegister(index), useRegister(length), useRegister(limit), temp()), 6970 ins); 6971 } 6972 6973 void LIRGenerator::visitWasmAlignmentCheck(MWasmAlignmentCheck* ins) { 6974 MDefinition* index = ins->index(); 6975 if (index->type() == MIRType::Int64) { 6976 auto* lir = 6977 new (alloc()) LWasmAlignmentCheck64(useInt64RegisterAtStart(index)); 6978 add(lir, ins); 6979 } else { 6980 auto* lir = new (alloc()) LWasmAlignmentCheck(useRegisterAtStart(index)); 6981 add(lir, ins); 6982 } 6983 } 6984 6985 void LIRGenerator::visitWasmLoadInstanceDataField( 6986 MWasmLoadInstanceDataField* ins) { 6987 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset()); 6988 if (ins->type() == MIRType::Int64) { 6989 #ifdef JS_PUNBOX64 6990 LAllocation instance = useRegisterAtStart(ins->instance()); 6991 #else 6992 // Avoid reusing instance for the output pair as the load clobbers the first 6993 // half of that pair before loading the second half. 6994 LAllocation instance = useRegister(ins->instance()); 6995 #endif 6996 defineInt64(new (alloc()) 6997 LWasmLoadSlotI64(instance, offs, mozilla::Nothing()), 6998 ins); 6999 } else { 7000 LAllocation instance = useRegisterAtStart(ins->instance()); 7001 define(new (alloc()) LWasmLoadSlot(instance, offs, ins->type(), 7002 MWideningOp::None, mozilla::Nothing()), 7003 ins); 7004 } 7005 } 7006 7007 void LIRGenerator::visitWasmLoadGlobalCell(MWasmLoadGlobalCell* ins) { 7008 if (ins->type() == MIRType::Int64) { 7009 #ifdef JS_PUNBOX64 7010 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr()); 7011 #else 7012 // Avoid reusing cellPtr for the output pair as the load clobbers the first 7013 // half of that pair before loading the second half. 7014 LAllocation cellPtr = useRegister(ins->cellPtr()); 7015 #endif 7016 defineInt64(new (alloc()) 7017 LWasmLoadSlotI64(cellPtr, /*offset=*/0, mozilla::Nothing()), 7018 ins); 7019 } else { 7020 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr()); 7021 define(new (alloc()) LWasmLoadSlot(cellPtr, /*offset=*/0, ins->type(), 7022 MWideningOp::None, mozilla::Nothing()), 7023 ins); 7024 } 7025 } 7026 7027 void LIRGenerator::visitWasmLoadTableElement(MWasmLoadTableElement* ins) { 7028 LAllocation elements = useRegisterAtStart(ins->elements()); 7029 LAllocation index = useRegisterAtStart(ins->index()); 7030 define(new (alloc()) LWasmLoadTableElement(elements, index), ins); 7031 } 7032 7033 void LIRGenerator::visitWasmStoreInstanceDataField( 7034 MWasmStoreInstanceDataField* ins) { 7035 MDefinition* value = ins->value(); 7036 size_t offs = wasm::Instance::offsetInData(ins->instanceDataOffset()); 7037 if (value->type() == MIRType::Int64) { 7038 #ifdef JS_PUNBOX64 7039 LAllocation instance = useRegisterAtStart(ins->instance()); 7040 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value); 7041 #else 7042 LAllocation instance = useRegister(ins->instance()); 7043 LInt64Allocation valueAlloc = useInt64Register(value); 7044 #endif 7045 add(new (alloc()) 7046 LWasmStoreSlotI64(valueAlloc, instance, offs, mozilla::Nothing()), 7047 ins); 7048 } else { 7049 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef); 7050 LAllocation instance = useRegisterAtStart(ins->instance()); 7051 LAllocation valueAlloc = useRegisterAtStart(value); 7052 add(new (alloc()) LWasmStoreSlot(valueAlloc, instance, offs, value->type(), 7053 MNarrowingOp::None, mozilla::Nothing()), 7054 ins); 7055 } 7056 } 7057 7058 void LIRGenerator::visitWasmStoreGlobalCell(MWasmStoreGlobalCell* ins) { 7059 MDefinition* value = ins->value(); 7060 size_t offs = 0; 7061 if (value->type() == MIRType::Int64) { 7062 #ifdef JS_PUNBOX64 7063 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr()); 7064 LInt64Allocation valueAlloc = useInt64RegisterAtStart(value); 7065 #else 7066 LAllocation cellPtr = useRegister(ins->cellPtr()); 7067 LInt64Allocation valueAlloc = useInt64Register(value); 7068 #endif 7069 add(new (alloc()) 7070 LWasmStoreSlotI64(valueAlloc, cellPtr, offs, mozilla::Nothing())); 7071 } else { 7072 MOZ_ASSERT(value->type() != MIRType::WasmAnyRef); 7073 LAllocation cellPtr = useRegisterAtStart(ins->cellPtr()); 7074 LAllocation valueAlloc = useRegisterAtStart(value); 7075 add(new (alloc()) LWasmStoreSlot(valueAlloc, cellPtr, offs, value->type(), 7076 MNarrowingOp::None, mozilla::Nothing())); 7077 } 7078 } 7079 7080 void LIRGenerator::visitWasmStoreStackResult(MWasmStoreStackResult* ins) { 7081 MDefinition* stackResultArea = ins->stackResultArea(); 7082 MDefinition* value = ins->value(); 7083 size_t offs = ins->offset(); 7084 if (value->type() == MIRType::Int64) { 7085 add(new (alloc()) LWasmStoreStackResultI64( 7086 useInt64Register(value), useRegister(stackResultArea), offs), 7087 ins); 7088 } else { 7089 add(new (alloc()) LWasmStoreStackResult(useRegister(value), 7090 useRegister(stackResultArea), offs, 7091 value->type()), 7092 ins); 7093 } 7094 } 7095 7096 void LIRGenerator::visitWasmDerivedPointer(MWasmDerivedPointer* ins) { 7097 LAllocation base = useRegisterAtStart(ins->base()); 7098 define(new (alloc()) LWasmDerivedPointer(base), ins); 7099 } 7100 7101 void LIRGenerator::visitWasmDerivedIndexPointer(MWasmDerivedIndexPointer* ins) { 7102 LAllocation base = useRegisterAtStart(ins->base()); 7103 LAllocation index = useRegisterAtStart(ins->index()); 7104 define(new (alloc()) LWasmDerivedIndexPointer(base, index), ins); 7105 } 7106 7107 void LIRGenerator::visitWasmStoreRef(MWasmStoreRef* ins) { 7108 LAllocation instance = useRegister(ins->instance()); 7109 LAllocation valueBase = useFixed(ins->valueBase(), PreBarrierReg); 7110 LAllocation value = useRegister(ins->value()); 7111 uint32_t valueOffset = ins->offset(); 7112 add(new (alloc()) 7113 LWasmStoreRef(instance, valueBase, value, temp(), valueOffset, 7114 mozilla::Nothing(), ins->preBarrierKind()), 7115 ins); 7116 } 7117 7118 void LIRGenerator::visitWasmPostWriteBarrierWholeCell( 7119 MWasmPostWriteBarrierWholeCell* ins) { 7120 LWasmPostWriteBarrierWholeCell* lir = new (alloc()) 7121 LWasmPostWriteBarrierWholeCell(useFixed(ins->instance(), InstanceReg), 7122 useRegister(ins->object()), 7123 useRegister(ins->value()), temp()); 7124 add(lir, ins); 7125 assignWasmSafepoint(lir); 7126 } 7127 7128 void LIRGenerator::visitWasmPostWriteBarrierEdgeAtIndex( 7129 MWasmPostWriteBarrierEdgeAtIndex* ins) { 7130 LWasmPostWriteBarrierEdgeAtIndex* lir = 7131 new (alloc()) LWasmPostWriteBarrierEdgeAtIndex( 7132 useFixed(ins->instance(), InstanceReg), useRegister(ins->object()), 7133 useRegister(ins->valueBase()), useRegister(ins->index()), 7134 useRegister(ins->value()), temp(), ins->elemSize()); 7135 add(lir, ins); 7136 assignWasmSafepoint(lir); 7137 } 7138 7139 void LIRGenerator::visitWasmParameter(MWasmParameter* ins) { 7140 ABIArg abi = ins->abi(); 7141 if (ins->type() == MIRType::StackResults) { 7142 // Functions that return stack results receive an extra incoming parameter 7143 // with type MIRType::StackResults. This value is a pointer to fresh 7144 // memory. Here we treat it as if it were in fact MIRType::Pointer. 7145 auto* lir = new (alloc()) LWasmParameter; 7146 LDefinition def(LDefinition::TypeFrom(MIRType::Pointer), 7147 LDefinition::FIXED); 7148 def.setOutput(abi.argInRegister() ? LAllocation(abi.reg()) 7149 : LArgument(abi.offsetFromArgBase())); 7150 define(lir, ins, def); 7151 return; 7152 } 7153 if (abi.argInRegister()) { 7154 #if defined(JS_NUNBOX32) 7155 if (abi.isGeneralRegPair()) { 7156 defineInt64Fixed( 7157 new (alloc()) LWasmParameterI64, ins, 7158 LInt64Allocation(LAllocation(AnyRegister(abi.gpr64().high)), 7159 LAllocation(AnyRegister(abi.gpr64().low)))); 7160 return; 7161 } 7162 #endif 7163 defineFixed(new (alloc()) LWasmParameter, ins, LAllocation(abi.reg())); 7164 return; 7165 } 7166 if (ins->type() == MIRType::Int64) { 7167 MOZ_ASSERT(!abi.argInRegister()); 7168 defineInt64Fixed( 7169 new (alloc()) LWasmParameterI64, ins, 7170 #if defined(JS_NUNBOX32) 7171 LInt64Allocation(LArgument(abi.offsetFromArgBase() + INT64HIGH_OFFSET), 7172 LArgument(abi.offsetFromArgBase() + INT64LOW_OFFSET)) 7173 #else 7174 LInt64Allocation(LArgument(abi.offsetFromArgBase())) 7175 #endif 7176 ); 7177 } else { 7178 MOZ_ASSERT(IsNumberType(ins->type()) || ins->type() == MIRType::WasmAnyRef 7179 #ifdef ENABLE_WASM_SIMD 7180 || ins->type() == MIRType::Simd128 7181 #endif 7182 ); 7183 defineFixed(new (alloc()) LWasmParameter, ins, 7184 LArgument(abi.offsetFromArgBase())); 7185 } 7186 } 7187 7188 void LIRGenerator::visitWasmReturn(MWasmReturn* ins) { 7189 MDefinition* rval = ins->getOperand(0); 7190 MDefinition* instance = ins->getOperand(1); 7191 7192 if (rval->type() == MIRType::Int64) { 7193 add(new (alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64), 7194 useFixed(instance, InstanceReg))); 7195 return; 7196 } 7197 7198 LAllocation returnReg; 7199 if (rval->type() == MIRType::Float32) { 7200 returnReg = useFixed(rval, ReturnFloat32Reg); 7201 } else if (rval->type() == MIRType::Double) { 7202 returnReg = useFixed(rval, ReturnDoubleReg); 7203 #ifdef ENABLE_WASM_SIMD 7204 } else if (rval->type() == MIRType::Simd128) { 7205 returnReg = useFixed(rval, ReturnSimd128Reg); 7206 #endif 7207 } else if (rval->type() == MIRType::Int32 || 7208 rval->type() == MIRType::WasmAnyRef) { 7209 returnReg = useFixed(rval, ReturnReg); 7210 } else { 7211 MOZ_CRASH("Unexpected wasm return type"); 7212 } 7213 7214 LWasmReturn* lir = 7215 new (alloc()) LWasmReturn(useFixed(instance, InstanceReg), returnReg); 7216 add(lir); 7217 } 7218 7219 void LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid* ins) { 7220 MDefinition* instance = ins->getOperand(0); 7221 LWasmReturnVoid* lir = 7222 new (alloc()) LWasmReturnVoid(useFixed(instance, InstanceReg)); 7223 add(lir); 7224 } 7225 7226 void LIRGenerator::visitWasmStackArg(MWasmStackArg* ins) { 7227 if (ins->arg()->type() == MIRType::Int64) { 7228 add(new (alloc()) 7229 LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins->arg())), 7230 ins); 7231 } else if (IsFloatingPointType(ins->arg()->type())) { 7232 MOZ_ASSERT(!ins->arg()->isEmittedAtUses()); 7233 add(new (alloc()) LWasmStackArg(useRegisterAtStart(ins->arg())), ins); 7234 } else { 7235 add(new (alloc()) LWasmStackArg(useRegisterOrConstantAtStart(ins->arg())), 7236 ins); 7237 } 7238 } 7239 7240 void LIRGenerator::visitWasmRegisterResult(MWasmRegisterResult* ins) { 7241 auto* lir = new (alloc()) LWasmRegisterResult(); 7242 uint32_t vreg = getVirtualRegister(); 7243 MOZ_ASSERT(ins->type() != MIRType::Int64); 7244 auto type = LDefinition::TypeFrom(ins->type()); 7245 lir->setDef(0, LDefinition(vreg, type, LGeneralReg(ins->loc()))); 7246 ins->setVirtualRegister(vreg); 7247 addUnchecked(lir, ins); 7248 } 7249 7250 void LIRGenerator::visitWasmFloatRegisterResult(MWasmFloatRegisterResult* ins) { 7251 auto* lir = new (alloc()) LWasmRegisterResult(); 7252 uint32_t vreg = getVirtualRegister(); 7253 auto type = LDefinition::TypeFrom(ins->type()); 7254 lir->setDef(0, LDefinition(vreg, type, LFloatReg(ins->loc()))); 7255 ins->setVirtualRegister(vreg); 7256 addUnchecked(lir, ins); 7257 } 7258 7259 void LIRGenerator::visitWasmSystemFloatRegisterResult( 7260 MWasmSystemFloatRegisterResult* ins) { 7261 auto* lir = new (alloc()) LWasmSystemFloatRegisterResult(); 7262 uint32_t vreg = getVirtualRegister(); 7263 auto type = LDefinition::TypeFrom(ins->type()); 7264 lir->setDef(0, LDefinition(vreg, type, LFloatReg(ins->loc()))); 7265 ins->setVirtualRegister(vreg); 7266 addUnchecked(lir, ins); 7267 } 7268 7269 void LIRGenerator::visitWasmRegister64Result(MWasmRegister64Result* ins) { 7270 MOZ_ASSERT(ins->type() == MIRType::Int64); 7271 uint32_t vreg = getVirtualRegister(); 7272 7273 #if defined(JS_NUNBOX32) 7274 auto* lir = new (alloc()) LWasmRegisterPairResult(); 7275 lir->setDef(INT64LOW_INDEX, 7276 LDefinition(vreg + INT64LOW_INDEX, LDefinition::GENERAL, 7277 LGeneralReg(ins->loc().low))); 7278 lir->setDef(INT64HIGH_INDEX, 7279 LDefinition(vreg + INT64HIGH_INDEX, LDefinition::GENERAL, 7280 LGeneralReg(ins->loc().high))); 7281 getVirtualRegister(); 7282 #elif defined(JS_PUNBOX64) 7283 auto* lir = new (alloc()) LWasmRegisterResult(); 7284 lir->setDef( 7285 0, LDefinition(vreg, LDefinition::GENERAL, LGeneralReg(ins->loc().reg))); 7286 #else 7287 # error expected either JS_NUNBOX32 or JS_PUNBOX64 7288 #endif 7289 7290 ins->setVirtualRegister(vreg); 7291 addUnchecked(lir, ins); 7292 } 7293 7294 void LIRGenerator::visitWasmStackResultArea(MWasmStackResultArea* ins) { 7295 MOZ_ASSERT(ins->type() == MIRType::StackResults); 7296 auto* lir = new (alloc()) LWasmStackResultArea(temp()); 7297 uint32_t vreg = getVirtualRegister(); 7298 lir->setDef(0, 7299 LDefinition(vreg, LDefinition::STACKRESULTS, LDefinition::STACK)); 7300 ins->setVirtualRegister(vreg); 7301 addUnchecked(lir, ins); 7302 } 7303 7304 void LIRGenerator::visitWasmStackResult(MWasmStackResult* ins) { 7305 MWasmStackResultArea* area = ins->resultArea()->toWasmStackResultArea(); 7306 LDefinition::Policy pol = LDefinition::STACK; 7307 7308 if (ins->type() == MIRType::Int64) { 7309 auto* lir = new (alloc()) LWasmStackResult64; 7310 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true))); 7311 uint32_t vreg = getVirtualRegister(); 7312 LDefinition::Type typ = LDefinition::GENERAL; 7313 #if defined(JS_NUNBOX32) 7314 getVirtualRegister(); 7315 lir->setDef(INT64LOW_INDEX, LDefinition(vreg + INT64LOW_INDEX, typ, pol)); 7316 lir->setDef(INT64HIGH_INDEX, LDefinition(vreg + INT64HIGH_INDEX, typ, pol)); 7317 #else 7318 lir->setDef(0, LDefinition(vreg, typ, pol)); 7319 #endif 7320 ins->setVirtualRegister(vreg); 7321 addUnchecked(lir, ins); 7322 return; 7323 } 7324 7325 auto* lir = new (alloc()) LWasmStackResult; 7326 lir->setOperand(0, use(area, LUse(LUse::STACK, /* usedAtStart = */ true))); 7327 uint32_t vreg = getVirtualRegister(); 7328 LDefinition::Type typ = LDefinition::TypeFrom(ins->type()); 7329 lir->setDef(0, LDefinition(vreg, typ, pol)); 7330 ins->setVirtualRegister(vreg); 7331 addUnchecked(lir, ins); 7332 } 7333 7334 void LIRGenerator::visitWasmStackSwitchToSuspendable( 7335 MWasmStackSwitchToSuspendable* ins) { 7336 #ifdef ENABLE_WASM_JSPI 7337 auto* lir = new (alloc()) LWasmStackSwitchToSuspendable( 7338 useFixedAtStart(ins->instance(), InstanceReg), 7339 useFixedAtStart(ins->suspender(), ABINonArgReg0), 7340 useFixedAtStart(ins->fn(), ABINonArgReg1), 7341 useFixedAtStart(ins->data(), ABINonArgReg2)); 7342 7343 add(lir, ins); 7344 assignWasmSafepoint(lir); 7345 #else 7346 MOZ_CRASH("NYI"); 7347 #endif 7348 } 7349 7350 void LIRGenerator::visitWasmStackSwitchToMain(MWasmStackSwitchToMain* ins) { 7351 #ifdef ENABLE_WASM_JSPI 7352 auto* lir = new (alloc()) 7353 LWasmStackSwitchToMain(useFixedAtStart(ins->instance(), InstanceReg), 7354 useFixedAtStart(ins->suspender(), ABINonArgReg0), 7355 useFixedAtStart(ins->fn(), ABINonArgReg1), 7356 useFixedAtStart(ins->data(), ABINonArgReg2)); 7357 7358 defineReturn(lir, ins); 7359 assignWasmSafepoint(lir); 7360 #else 7361 MOZ_CRASH("NYI"); 7362 #endif 7363 } 7364 7365 void LIRGenerator::visitWasmStackContinueOnSuspendable( 7366 MWasmStackContinueOnSuspendable* ins) { 7367 #ifdef ENABLE_WASM_JSPI 7368 auto* lir = new (alloc()) LWasmStackContinueOnSuspendable( 7369 useFixedAtStart(ins->instance(), InstanceReg), 7370 useRegisterAtStart(ins->suspender()), useRegisterAtStart(ins->result()), 7371 tempFixed(ABINonArgReturnReg0), tempFixed(ReturnReg)); 7372 7373 add(lir, ins); 7374 assignWasmSafepoint(lir); 7375 #else 7376 MOZ_CRASH("NYI"); 7377 #endif 7378 } 7379 7380 template <class MWasmCallT> 7381 void LIRGenerator::visitWasmCall(MWasmCallT ins) { 7382 auto* lir = allocateVariadic<LWasmCall>(ins->numOperands()); 7383 if (!lir) { 7384 abort(AbortReason::Alloc, "OOM: LIRGenerator::lowerWasmCall"); 7385 return; 7386 } 7387 7388 for (unsigned i = 0; i < ins->numArgs(); i++) { 7389 lir->setOperand( 7390 i, useFixedAtStart(ins->getOperand(i), ins->registerForArg(i))); 7391 } 7392 7393 if (ins->callee().isTable()) { 7394 MDefinition* index = ins->getOperand(ins->numArgs()); 7395 lir->setOperand(ins->numArgs(), 7396 useFixedAtStart(index, WasmTableCallIndexReg)); 7397 } 7398 if (ins->callee().isFuncRef()) { 7399 MDefinition* ref = ins->getOperand(ins->numArgs()); 7400 lir->setOperand(ins->numArgs(), useFixedAtStart(ref, WasmCallRefReg)); 7401 } 7402 7403 add(lir, ins); 7404 assignWasmSafepoint(lir); 7405 7406 // WasmCall with WasmTable has two call instructions, and they both need a 7407 // safepoint associated with them. Create a second safepoint here; the node 7408 // otherwise does nothing, and codegen for it only marks the safepoint at the 7409 // node. 7410 if ((ins->callee().which() == wasm::CalleeDesc::WasmTable || 7411 ins->callee().which() == wasm::CalleeDesc::FuncRef) && 7412 !ins->isWasmReturnCall()) { 7413 auto* adjunctSafepoint = new (alloc()) LWasmCallIndirectAdjunctSafepoint(); 7414 add(adjunctSafepoint); 7415 assignWasmSafepoint(adjunctSafepoint); 7416 lir->setAdjunctSafepoint(adjunctSafepoint); 7417 } 7418 } 7419 7420 void LIRGenerator::visitWasmCallCatchable(MWasmCallCatchable* ins) { 7421 visitWasmCall(ins); 7422 } 7423 7424 void LIRGenerator::visitWasmCallUncatchable(MWasmCallUncatchable* ins) { 7425 visitWasmCall(ins); 7426 } 7427 7428 void LIRGenerator::visitWasmReturnCall(MWasmReturnCall* ins) { 7429 visitWasmCall(ins); 7430 } 7431 7432 void LIRGenerator::visitWasmCallLandingPrePad(MWasmCallLandingPrePad* ins) { 7433 add(new (alloc()) LWasmCallLandingPrePad, ins); 7434 } 7435 7436 void LIRGenerator::visitSetDOMProperty(MSetDOMProperty* ins) { 7437 MDefinition* val = ins->value(); 7438 7439 Register cxReg, objReg, privReg, valueReg; 7440 GetTempRegForIntArg(0, 0, &cxReg); 7441 GetTempRegForIntArg(1, 0, &objReg); 7442 GetTempRegForIntArg(2, 0, &privReg); 7443 GetTempRegForIntArg(3, 0, &valueReg); 7444 7445 // Keep using GetTempRegForIntArg, since we want to make sure we 7446 // don't clobber registers we're already using. 7447 Register tempReg1, tempReg2; 7448 GetTempRegForIntArg(4, 0, &tempReg1); 7449 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2); 7450 MOZ_ASSERT(ok, "How can we not have six temp registers?"); 7451 7452 auto* lir = new (alloc()) LSetDOMProperty( 7453 useFixedAtStart(ins->object(), objReg), 7454 useBoxFixedAtStart(val, tempReg1, tempReg2), tempFixed(cxReg), 7455 tempFixed(privReg), tempFixed(valueReg)); 7456 add(lir, ins); 7457 assignSafepoint(lir, ins); 7458 } 7459 7460 void LIRGenerator::visitGetDOMProperty(MGetDOMProperty* ins) { 7461 Register cxReg, objReg, privReg, valueReg; 7462 GetTempRegForIntArg(0, 0, &cxReg); 7463 GetTempRegForIntArg(1, 0, &objReg); 7464 GetTempRegForIntArg(2, 0, &privReg); 7465 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg); 7466 MOZ_ASSERT(ok, "How can we not have four temp registers?"); 7467 auto* lir = new (alloc()) 7468 LGetDOMProperty(useFixedAtStart(ins->object(), objReg), tempFixed(cxReg), 7469 tempFixed(privReg), tempFixed(valueReg)); 7470 7471 defineReturn(lir, ins); 7472 assignSafepoint(lir, ins); 7473 } 7474 7475 void LIRGenerator::visitGetDOMMember(MGetDOMMember* ins) { 7476 MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable"); 7477 // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone, 7478 // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose 7479 // value can in fact change as a result of DOM setters and method calls. 7480 MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything, 7481 "Member gets had better not alias the world"); 7482 7483 MDefinition* obj = ins->object(); 7484 MOZ_ASSERT(obj->type() == MIRType::Object); 7485 7486 MIRType type = ins->type(); 7487 7488 if (type == MIRType::Value) { 7489 LGetDOMMemberV* lir = new (alloc()) LGetDOMMemberV(useRegisterAtStart(obj)); 7490 defineBox(lir, ins); 7491 } else { 7492 LGetDOMMemberT* lir = 7493 new (alloc()) LGetDOMMemberT(useRegisterForTypedLoad(obj, type)); 7494 define(lir, ins); 7495 } 7496 } 7497 7498 void LIRGenerator::visitLoadDOMExpandoValue(MLoadDOMExpandoValue* ins) { 7499 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object); 7500 auto* lir = 7501 new (alloc()) LLoadDOMExpandoValue(useRegisterAtStart(ins->proxy())); 7502 defineBox(lir, ins); 7503 } 7504 7505 void LIRGenerator::visitLoadDOMExpandoValueGuardGeneration( 7506 MLoadDOMExpandoValueGuardGeneration* ins) { 7507 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object); 7508 auto* lir = new (alloc()) 7509 LLoadDOMExpandoValueGuardGeneration(useRegisterAtStart(ins->proxy())); 7510 assignSnapshot(lir, ins->bailoutKind()); 7511 defineBox(lir, ins); 7512 } 7513 7514 void LIRGenerator::visitLoadDOMExpandoValueIgnoreGeneration( 7515 MLoadDOMExpandoValueIgnoreGeneration* ins) { 7516 MOZ_ASSERT(ins->proxy()->type() == MIRType::Object); 7517 auto* lir = new (alloc()) 7518 LLoadDOMExpandoValueIgnoreGeneration(useRegisterAtStart(ins->proxy())); 7519 defineBox(lir, ins); 7520 } 7521 7522 void LIRGenerator::visitGuardDOMExpandoMissingOrGuardShape( 7523 MGuardDOMExpandoMissingOrGuardShape* ins) { 7524 MOZ_ASSERT(ins->expando()->type() == MIRType::Value); 7525 auto* lir = new (alloc()) 7526 LGuardDOMExpandoMissingOrGuardShape(useBox(ins->expando()), temp()); 7527 assignSnapshot(lir, ins->bailoutKind()); 7528 add(lir, ins); 7529 redefine(ins, ins->expando()); 7530 } 7531 7532 void LIRGenerator::visitIncrementWarmUpCounter(MIncrementWarmUpCounter* ins) { 7533 LIncrementWarmUpCounter* lir = new (alloc()) LIncrementWarmUpCounter(temp()); 7534 add(lir, ins); 7535 } 7536 7537 void LIRGenerator::visitLexicalCheck(MLexicalCheck* ins) { 7538 MDefinition* input = ins->input(); 7539 MOZ_ASSERT(input->type() == MIRType::Value); 7540 LLexicalCheck* lir = new (alloc()) LLexicalCheck(useBox(input)); 7541 assignSnapshot(lir, ins->bailoutKind()); 7542 add(lir, ins); 7543 redefine(ins, input); 7544 } 7545 7546 void LIRGenerator::visitThrowRuntimeLexicalError( 7547 MThrowRuntimeLexicalError* ins) { 7548 LThrowRuntimeLexicalError* lir = new (alloc()) LThrowRuntimeLexicalError(); 7549 add(lir, ins); 7550 assignSafepoint(lir, ins); 7551 } 7552 7553 void LIRGenerator::visitThrowMsg(MThrowMsg* ins) { 7554 LThrowMsg* lir = new (alloc()) LThrowMsg(); 7555 add(lir, ins); 7556 assignSafepoint(lir, ins); 7557 } 7558 7559 void LIRGenerator::visitGlobalDeclInstantiation(MGlobalDeclInstantiation* ins) { 7560 LGlobalDeclInstantiation* lir = new (alloc()) LGlobalDeclInstantiation(); 7561 add(lir, ins); 7562 assignSafepoint(lir, ins); 7563 } 7564 7565 void LIRGenerator::visitDebugger(MDebugger* ins) { 7566 auto* lir = new (alloc()) LDebugger(tempFixed(CallTempReg0)); 7567 assignSnapshot(lir, ins->bailoutKind()); 7568 add(lir, ins); 7569 } 7570 7571 void LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins) { 7572 define(new (alloc()) LAtomicIsLockFree(useRegister(ins->input())), ins); 7573 } 7574 7575 void LIRGenerator::visitAtomicPause(MAtomicPause* ins) { 7576 add(new (alloc()) LAtomicPause()); 7577 } 7578 7579 void LIRGenerator::visitCheckReturn(MCheckReturn* ins) { 7580 MDefinition* retVal = ins->returnValue(); 7581 MDefinition* thisVal = ins->thisValue(); 7582 MOZ_ASSERT(retVal->type() == MIRType::Value); 7583 MOZ_ASSERT(thisVal->type() == MIRType::Value); 7584 7585 auto* lir = 7586 new (alloc()) LCheckReturn(useBoxAtStart(retVal), useBoxAtStart(thisVal)); 7587 defineBox(lir, ins); 7588 assignSafepoint(lir, ins); 7589 } 7590 7591 void LIRGenerator::visitCheckIsObj(MCheckIsObj* ins) { 7592 MDefinition* input = ins->input(); 7593 MOZ_ASSERT(input->type() == MIRType::Value); 7594 7595 LCheckIsObj* lir = new (alloc()) LCheckIsObj(useBox(input)); 7596 define(lir, ins); 7597 assignSafepoint(lir, ins); 7598 } 7599 7600 #ifdef JS_PUNBOX64 7601 void LIRGenerator::visitCheckScriptedProxyGetResult( 7602 MCheckScriptedProxyGetResult* ins) { 7603 MDefinition* target = ins->target(); 7604 MDefinition* id = ins->id(); 7605 MDefinition* value = ins->value(); 7606 7607 LCheckScriptedProxyGetResult* lir = 7608 new (alloc()) LCheckScriptedProxyGetResult(useBox(target), useBox(id), 7609 useBox(value), temp(), temp()); 7610 add(lir, ins); 7611 assignSafepoint(lir, ins); 7612 } 7613 #endif 7614 7615 void LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins) { 7616 MDefinition* checkVal = ins->checkValue(); 7617 MOZ_ASSERT(checkVal->type() == MIRType::Value); 7618 7619 auto* lir = new (alloc()) LCheckObjCoercible(useBoxAtStart(checkVal)); 7620 redefine(ins, checkVal); 7621 add(lir, ins); 7622 assignSafepoint(lir, ins); 7623 } 7624 7625 void LIRGenerator::visitCheckClassHeritage(MCheckClassHeritage* ins) { 7626 MDefinition* heritage = ins->heritage(); 7627 MOZ_ASSERT(heritage->type() == MIRType::Value); 7628 7629 auto* lir = 7630 new (alloc()) LCheckClassHeritage(useBox(heritage), temp(), temp()); 7631 redefine(ins, heritage); 7632 add(lir, ins); 7633 assignSafepoint(lir, ins); 7634 } 7635 7636 void LIRGenerator::visitCheckThis(MCheckThis* ins) { 7637 MDefinition* thisValue = ins->thisValue(); 7638 MOZ_ASSERT(thisValue->type() == MIRType::Value); 7639 7640 auto* lir = new (alloc()) LCheckThis(useBoxAtStart(thisValue)); 7641 redefine(ins, thisValue); 7642 add(lir, ins); 7643 assignSafepoint(lir, ins); 7644 } 7645 7646 void LIRGenerator::visitCheckThisReinit(MCheckThisReinit* ins) { 7647 MDefinition* thisValue = ins->thisValue(); 7648 MOZ_ASSERT(thisValue->type() == MIRType::Value); 7649 7650 auto* lir = new (alloc()) LCheckThisReinit(useBoxAtStart(thisValue)); 7651 redefine(ins, thisValue); 7652 add(lir, ins); 7653 assignSafepoint(lir, ins); 7654 } 7655 7656 void LIRGenerator::visitGenerator(MGenerator* ins) { 7657 auto* lir = 7658 new (alloc()) LGenerator(useRegisterAtStart(ins->callee()), 7659 useRegisterAtStart(ins->environmentChain()), 7660 useRegisterAtStart(ins->argsObject())); 7661 defineReturn(lir, ins); 7662 assignSafepoint(lir, ins); 7663 } 7664 7665 void LIRGenerator::visitAsyncResolve(MAsyncResolve* ins) { 7666 auto* lir = new (alloc()) LAsyncResolve(useRegisterAtStart(ins->generator()), 7667 useBoxAtStart(ins->value())); 7668 defineReturn(lir, ins); 7669 assignSafepoint(lir, ins); 7670 } 7671 7672 void LIRGenerator::visitAsyncReject(MAsyncReject* ins) { 7673 auto* lir = new (alloc()) 7674 LAsyncReject(useRegisterAtStart(ins->generator()), 7675 useBoxAtStart(ins->reason()), useBoxAtStart(ins->stack())); 7676 defineReturn(lir, ins); 7677 assignSafepoint(lir, ins); 7678 } 7679 7680 void LIRGenerator::visitAsyncAwait(MAsyncAwait* ins) { 7681 MOZ_ASSERT(ins->generator()->type() == MIRType::Object); 7682 auto* lir = new (alloc()) LAsyncAwait(useBoxAtStart(ins->value()), 7683 useRegisterAtStart(ins->generator())); 7684 defineReturn(lir, ins); 7685 assignSafepoint(lir, ins); 7686 } 7687 7688 void LIRGenerator::visitCanSkipAwait(MCanSkipAwait* ins) { 7689 auto* lir = new (alloc()) LCanSkipAwait(useBoxAtStart(ins->value())); 7690 defineReturn(lir, ins); 7691 assignSafepoint(lir, ins); 7692 } 7693 7694 void LIRGenerator::visitMaybeExtractAwaitValue(MMaybeExtractAwaitValue* ins) { 7695 auto* lir = new (alloc()) LMaybeExtractAwaitValue( 7696 useBoxAtStart(ins->value()), useRegisterAtStart(ins->canSkip())); 7697 defineReturn(lir, ins); 7698 assignSafepoint(lir, ins); 7699 } 7700 7701 void LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins) { 7702 MDefinition* checkVal = ins->checkValue(); 7703 MOZ_ASSERT(checkVal->type() == MIRType::Value); 7704 7705 LDebugCheckSelfHosted* lir = 7706 new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal)); 7707 redefine(ins, checkVal); 7708 add(lir, ins); 7709 assignSafepoint(lir, ins); 7710 } 7711 7712 void LIRGenerator::visitIsPackedArray(MIsPackedArray* ins) { 7713 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 7714 MOZ_ASSERT(ins->type() == MIRType::Boolean); 7715 7716 auto lir = new (alloc()) LIsPackedArray(useRegister(ins->object()), temp()); 7717 define(lir, ins); 7718 } 7719 7720 void LIRGenerator::visitGuardArrayIsPacked(MGuardArrayIsPacked* ins) { 7721 MOZ_ASSERT(ins->array()->type() == MIRType::Object); 7722 7723 auto* lir = new (alloc()) 7724 LGuardArrayIsPacked(useRegister(ins->array()), temp(), temp()); 7725 assignSnapshot(lir, ins->bailoutKind()); 7726 add(lir, ins); 7727 redefine(ins, ins->array()); 7728 } 7729 7730 void LIRGenerator::visitGuardElementsArePacked(MGuardElementsArePacked* ins) { 7731 MOZ_ASSERT(ins->elements()->type() == MIRType::Elements); 7732 7733 auto* lir = 7734 new (alloc()) LGuardElementsArePacked(useRegister(ins->elements())); 7735 assignSnapshot(lir, ins->bailoutKind()); 7736 add(lir, ins); 7737 } 7738 7739 void LIRGenerator::visitGetPrototypeOf(MGetPrototypeOf* ins) { 7740 MOZ_ASSERT(ins->target()->type() == MIRType::Object); 7741 MOZ_ASSERT(ins->type() == MIRType::Value); 7742 7743 auto lir = new (alloc()) LGetPrototypeOf(useRegister(ins->target())); 7744 defineBox(lir, ins); 7745 assignSafepoint(lir, ins); 7746 } 7747 7748 void LIRGenerator::visitObjectWithProto(MObjectWithProto* ins) { 7749 MOZ_ASSERT(ins->prototype()->type() == MIRType::Value); 7750 MOZ_ASSERT(ins->type() == MIRType::Object); 7751 7752 auto* lir = new (alloc()) LObjectWithProto(useBoxAtStart(ins->prototype())); 7753 defineReturn(lir, ins); 7754 assignSafepoint(lir, ins); 7755 } 7756 7757 void LIRGenerator::visitObjectStaticProto(MObjectStaticProto* ins) { 7758 MOZ_ASSERT(ins->object()->type() == MIRType::Object); 7759 MOZ_ASSERT(ins->type() == MIRType::Object); 7760 7761 auto* lir = 7762 new (alloc()) LObjectStaticProto(useRegisterAtStart(ins->object())); 7763 define(lir, ins); 7764 }; 7765 7766 void LIRGenerator::visitBuiltinObject(MBuiltinObject* ins) { 7767 MOZ_ASSERT(ins->type() == MIRType::Object); 7768 7769 auto* lir = new (alloc()) LBuiltinObject(); 7770 defineReturn(lir, ins); 7771 assignSafepoint(lir, ins); 7772 } 7773 7774 void LIRGenerator::visitReturn(MReturn* ret) { 7775 return visitReturnImpl(ret->getOperand(0)); 7776 } 7777 7778 void LIRGenerator::visitGeneratorReturn(MGeneratorReturn* ret) { 7779 return visitReturnImpl(ret->getOperand(0), true); 7780 } 7781 7782 void LIRGenerator::visitSuperFunction(MSuperFunction* ins) { 7783 MOZ_ASSERT(ins->callee()->type() == MIRType::Object); 7784 MOZ_ASSERT(ins->type() == MIRType::Value); 7785 7786 auto* lir = new (alloc()) LSuperFunction(useRegister(ins->callee())); 7787 defineBox(lir, ins); 7788 } 7789 7790 void LIRGenerator::visitSuperFunctionAndUnbox(MSuperFunctionAndUnbox* ins) { 7791 MOZ_ASSERT(ins->callee()->type() == MIRType::Object); 7792 MOZ_ASSERT(ins->type() == MIRType::Object); 7793 7794 auto* lir = new (alloc()) LSuperFunctionAndUnbox(useRegister(ins->callee())); 7795 assignSnapshot(lir, ins->bailoutKind()); 7796 define(lir, ins); 7797 } 7798 7799 void LIRGenerator::visitInitHomeObject(MInitHomeObject* ins) { 7800 MDefinition* function = ins->function(); 7801 MOZ_ASSERT(function->type() == MIRType::Object); 7802 7803 MDefinition* homeObject = ins->homeObject(); 7804 MOZ_ASSERT(homeObject->type() == MIRType::Value); 7805 7806 MOZ_ASSERT(ins->type() == MIRType::Object); 7807 7808 auto* lir = new (alloc()) 7809 LInitHomeObject(useRegisterAtStart(function), useBoxAtStart(homeObject)); 7810 redefine(ins, function); 7811 add(lir, ins); 7812 } 7813 7814 void LIRGenerator::visitIsTypedArrayConstructor(MIsTypedArrayConstructor* ins) { 7815 MDefinition* object = ins->object(); 7816 MOZ_ASSERT(object->type() == MIRType::Object); 7817 7818 auto* lir = new (alloc()) LIsTypedArrayConstructor(useRegister(object)); 7819 define(lir, ins); 7820 } 7821 7822 void LIRGenerator::visitLoadValueTag(MLoadValueTag* ins) { 7823 MDefinition* value = ins->value(); 7824 MOZ_ASSERT(value->type() == MIRType::Value); 7825 7826 define(new (alloc()) LLoadValueTag(useBoxAtStart(value)), ins); 7827 } 7828 7829 void LIRGenerator::visitGuardTagNotEqual(MGuardTagNotEqual* ins) { 7830 MDefinition* lhs = ins->lhs(); 7831 MOZ_ASSERT(lhs->type() == MIRType::Int32); 7832 7833 MDefinition* rhs = ins->rhs(); 7834 MOZ_ASSERT(rhs->type() == MIRType::Int32); 7835 7836 auto* guard = 7837 new (alloc()) LGuardTagNotEqual(useRegister(lhs), useRegister(rhs)); 7838 assignSnapshot(guard, ins->bailoutKind()); 7839 add(guard, ins); 7840 } 7841 7842 void LIRGenerator::visitLoadWrapperTarget(MLoadWrapperTarget* ins) { 7843 MDefinition* object = ins->object(); 7844 MOZ_ASSERT(object->type() == MIRType::Object); 7845 7846 auto* lir = new (alloc()) LLoadWrapperTarget(useRegisterAtStart(object)); 7847 if (ins->fallible()) { 7848 assignSnapshot(lir, ins->bailoutKind()); 7849 } 7850 define(lir, ins); 7851 } 7852 7853 void LIRGenerator::visitLoadGetterSetterFunction( 7854 MLoadGetterSetterFunction* ins) { 7855 MDefinition* getterSetter = ins->getterSetter(); 7856 7857 LDefinition classGuardTemp = 7858 ins->needsClassGuard() ? temp() : LDefinition::BogusTemp(); 7859 auto* lir = new (alloc()) 7860 LLoadGetterSetterFunction(useBoxAtStart(getterSetter), classGuardTemp); 7861 assignSnapshot(lir, ins->bailoutKind()); 7862 define(lir, ins); 7863 } 7864 7865 void LIRGenerator::visitGuardHasGetterSetter(MGuardHasGetterSetter* ins) { 7866 MDefinition* object = ins->object(); 7867 MOZ_ASSERT(object->type() == MIRType::Object); 7868 7869 auto* guard = new (alloc()) 7870 LGuardHasGetterSetter(useRegisterAtStart(object), tempFixed(CallTempReg0), 7871 tempFixed(CallTempReg1), tempFixed(CallTempReg2)); 7872 assignSnapshot(guard, ins->bailoutKind()); 7873 add(guard, ins); 7874 redefine(ins, object); 7875 } 7876 7877 void LIRGenerator::visitGuardIsExtensible(MGuardIsExtensible* ins) { 7878 MDefinition* object = ins->object(); 7879 MOZ_ASSERT(object->type() == MIRType::Object); 7880 7881 auto* guard = new (alloc()) LGuardIsExtensible(useRegister(object), temp()); 7882 assignSnapshot(guard, ins->bailoutKind()); 7883 add(guard, ins); 7884 redefine(ins, object); 7885 } 7886 7887 void LIRGenerator::visitGuardInt32IsNonNegative(MGuardInt32IsNonNegative* ins) { 7888 MDefinition* index = ins->index(); 7889 MOZ_ASSERT(index->type() == MIRType::Int32); 7890 7891 auto* guard = new (alloc()) LGuardInt32IsNonNegative(useRegister(index)); 7892 assignSnapshot(guard, ins->bailoutKind()); 7893 add(guard, ins); 7894 redefine(ins, index); 7895 } 7896 7897 void LIRGenerator::visitGuardIntPtrIsNonNegative( 7898 MGuardIntPtrIsNonNegative* ins) { 7899 MDefinition* index = ins->index(); 7900 MOZ_ASSERT(index->type() == MIRType::IntPtr); 7901 7902 auto* guard = new (alloc()) LGuardIntPtrIsNonNegative(useRegister(index)); 7903 assignSnapshot(guard, ins->bailoutKind()); 7904 add(guard, ins); 7905 redefine(ins, index); 7906 } 7907 7908 void LIRGenerator::visitGuardInt32Range(MGuardInt32Range* ins) { 7909 MDefinition* input = ins->input(); 7910 MOZ_ASSERT(input->type() == MIRType::Int32); 7911 7912 auto* guard = new (alloc()) LGuardInt32Range(useRegister(input)); 7913 assignSnapshot(guard, ins->bailoutKind()); 7914 add(guard, ins); 7915 redefine(ins, input); 7916 } 7917 7918 void LIRGenerator::visitGuardIndexIsNotDenseElement( 7919 MGuardIndexIsNotDenseElement* ins) { 7920 MDefinition* object = ins->object(); 7921 MOZ_ASSERT(object->type() == MIRType::Object); 7922 7923 MDefinition* index = ins->index(); 7924 MOZ_ASSERT(index->type() == MIRType::Int32); 7925 7926 LDefinition spectreTemp = 7927 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp(); 7928 7929 auto* guard = new (alloc()) LGuardIndexIsNotDenseElement( 7930 useRegister(object), useRegister(index), temp(), spectreTemp); 7931 assignSnapshot(guard, ins->bailoutKind()); 7932 add(guard, ins); 7933 redefine(ins, index); 7934 } 7935 7936 void LIRGenerator::visitGuardIndexIsValidUpdateOrAdd( 7937 MGuardIndexIsValidUpdateOrAdd* ins) { 7938 MDefinition* object = ins->object(); 7939 MOZ_ASSERT(object->type() == MIRType::Object); 7940 7941 MDefinition* index = ins->index(); 7942 MOZ_ASSERT(index->type() == MIRType::Int32); 7943 7944 LDefinition spectreTemp = 7945 BoundsCheckNeedsSpectreTemp() ? temp() : LDefinition::BogusTemp(); 7946 7947 auto* guard = new (alloc()) LGuardIndexIsValidUpdateOrAdd( 7948 useRegister(object), useRegister(index), temp(), spectreTemp); 7949 assignSnapshot(guard, ins->bailoutKind()); 7950 add(guard, ins); 7951 redefine(ins, index); 7952 } 7953 7954 void LIRGenerator::visitCallAddOrUpdateSparseElement( 7955 MCallAddOrUpdateSparseElement* ins) { 7956 MDefinition* object = ins->object(); 7957 MOZ_ASSERT(object->type() == MIRType::Object); 7958 7959 MDefinition* index = ins->index(); 7960 MOZ_ASSERT(index->type() == MIRType::Int32); 7961 7962 MDefinition* value = ins->value(); 7963 MOZ_ASSERT(value->type() == MIRType::Value); 7964 7965 auto* lir = new (alloc()) LCallAddOrUpdateSparseElement( 7966 useRegisterAtStart(object), useRegisterAtStart(index), 7967 useBoxAtStart(value)); 7968 add(lir, ins); 7969 assignSafepoint(lir, ins); 7970 } 7971 7972 void LIRGenerator::visitCallGetSparseElement(MCallGetSparseElement* ins) { 7973 MDefinition* object = ins->object(); 7974 MOZ_ASSERT(object->type() == MIRType::Object); 7975 7976 MDefinition* index = ins->index(); 7977 MOZ_ASSERT(index->type() == MIRType::Int32); 7978 7979 auto* lir = new (alloc()) LCallGetSparseElement(useRegisterAtStart(object), 7980 useRegisterAtStart(index)); 7981 defineReturn(lir, ins); 7982 assignSafepoint(lir, ins); 7983 } 7984 7985 void LIRGenerator::visitCallNativeGetElement(MCallNativeGetElement* ins) { 7986 MDefinition* object = ins->object(); 7987 MOZ_ASSERT(object->type() == MIRType::Object); 7988 7989 MDefinition* index = ins->index(); 7990 MOZ_ASSERT(index->type() == MIRType::Int32); 7991 7992 auto* lir = new (alloc()) LCallNativeGetElement(useRegisterAtStart(object), 7993 useRegisterAtStart(index)); 7994 defineReturn(lir, ins); 7995 assignSafepoint(lir, ins); 7996 } 7997 7998 void LIRGenerator::visitCallNativeGetElementSuper( 7999 MCallNativeGetElementSuper* ins) { 8000 MDefinition* object = ins->object(); 8001 MOZ_ASSERT(object->type() == MIRType::Object); 8002 8003 MDefinition* index = ins->index(); 8004 MOZ_ASSERT(index->type() == MIRType::Int32); 8005 8006 MDefinition* receiver = ins->receiver(); 8007 8008 auto* lir = new (alloc()) LCallNativeGetElementSuper( 8009 useRegisterAtStart(object), useRegisterAtStart(index), 8010 useBoxAtStart(receiver)); 8011 defineReturn(lir, ins); 8012 assignSafepoint(lir, ins); 8013 } 8014 8015 void LIRGenerator::visitCallObjectHasSparseElement( 8016 MCallObjectHasSparseElement* ins) { 8017 MDefinition* object = ins->object(); 8018 MOZ_ASSERT(object->type() == MIRType::Object); 8019 8020 MDefinition* index = ins->index(); 8021 MOZ_ASSERT(index->type() == MIRType::Int32); 8022 8023 auto* lir = new (alloc()) LCallObjectHasSparseElement( 8024 useRegisterAtStart(object), useRegisterAtStart(index), 8025 tempFixed(CallTempReg0), tempFixed(CallTempReg1)); 8026 assignSnapshot(lir, ins->bailoutKind()); 8027 defineReturn(lir, ins); 8028 } 8029 8030 void LIRGenerator::visitBigIntAsIntN(MBigIntAsIntN* ins) { 8031 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32); 8032 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt); 8033 8034 auto* lir = new (alloc()) LBigIntAsIntN(useRegisterAtStart(ins->bits()), 8035 useRegisterAtStart(ins->input())); 8036 defineReturn(lir, ins); 8037 assignSafepoint(lir, ins); 8038 } 8039 8040 void LIRGenerator::visitBigIntAsUintN(MBigIntAsUintN* ins) { 8041 MOZ_ASSERT(ins->bits()->type() == MIRType::Int32); 8042 MOZ_ASSERT(ins->input()->type() == MIRType::BigInt); 8043 8044 auto* lir = new (alloc()) LBigIntAsUintN(useRegisterAtStart(ins->bits()), 8045 useRegisterAtStart(ins->input())); 8046 defineReturn(lir, ins); 8047 assignSafepoint(lir, ins); 8048 } 8049 8050 void LIRGenerator::visitGuardNonGCThing(MGuardNonGCThing* ins) { 8051 MDefinition* input = ins->input(); 8052 8053 auto* guard = new (alloc()) LGuardNonGCThing(useBox(input)); 8054 assignSnapshot(guard, ins->bailoutKind()); 8055 add(guard, ins); 8056 redefine(ins, input); 8057 } 8058 8059 void LIRGenerator::visitToHashableNonGCThing(MToHashableNonGCThing* ins) { 8060 auto* lir = 8061 new (alloc()) LToHashableNonGCThing(useBox(ins->input()), tempDouble()); 8062 defineBox(lir, ins); 8063 } 8064 8065 void LIRGenerator::visitToHashableString(MToHashableString* ins) { 8066 auto* lir = new (alloc()) LToHashableString(useRegister(ins->input())); 8067 define(lir, ins); 8068 assignSafepoint(lir, ins); 8069 } 8070 8071 void LIRGenerator::visitToHashableValue(MToHashableValue* ins) { 8072 auto* lir = 8073 new (alloc()) LToHashableValue(useBox(ins->input()), tempDouble()); 8074 defineBox(lir, ins); 8075 assignSafepoint(lir, ins); 8076 } 8077 8078 void LIRGenerator::visitHashNonGCThing(MHashNonGCThing* ins) { 8079 auto* lir = new (alloc()) LHashNonGCThing(useBox(ins->input()), temp()); 8080 define(lir, ins); 8081 } 8082 8083 void LIRGenerator::visitHashString(MHashString* ins) { 8084 auto* lir = new (alloc()) LHashString(useRegister(ins->input()), temp()); 8085 define(lir, ins); 8086 } 8087 8088 void LIRGenerator::visitHashSymbol(MHashSymbol* ins) { 8089 auto* lir = new (alloc()) LHashSymbol(useRegister(ins->input())); 8090 define(lir, ins); 8091 } 8092 8093 void LIRGenerator::visitHashBigInt(MHashBigInt* ins) { 8094 auto* lir = new (alloc()) 8095 LHashBigInt(useRegister(ins->input()), temp(), temp(), temp()); 8096 define(lir, ins); 8097 } 8098 8099 void LIRGenerator::visitHashObject(MHashObject* ins) { 8100 auto* lir = new (alloc()) 8101 LHashObject(useRegister(ins->setObject()), useBox(ins->input()), temp(), 8102 temp(), temp(), temp()); 8103 define(lir, ins); 8104 } 8105 8106 void LIRGenerator::visitHashValue(MHashValue* ins) { 8107 auto* lir = new (alloc()) 8108 LHashValue(useRegister(ins->setObject()), useBox(ins->input()), temp(), 8109 temp(), temp(), temp()); 8110 define(lir, ins); 8111 } 8112 8113 void LIRGenerator::visitSetObjectHasNonBigInt(MSetObjectHasNonBigInt* ins) { 8114 auto* lir = new (alloc()) LSetObjectHasNonBigInt( 8115 useRegister(ins->setObject()), useBox(ins->value()), 8116 useRegister(ins->hash()), temp(), temp()); 8117 define(lir, ins); 8118 } 8119 8120 void LIRGenerator::visitSetObjectHasBigInt(MSetObjectHasBigInt* ins) { 8121 auto* lir = new (alloc()) LSetObjectHasBigInt( 8122 useRegister(ins->setObject()), useBox(ins->value()), 8123 useRegister(ins->hash()), temp(), temp(), temp(), temp()); 8124 define(lir, ins); 8125 } 8126 8127 void LIRGenerator::visitSetObjectHasValue(MSetObjectHasValue* ins) { 8128 auto* lir = new (alloc()) LSetObjectHasValue( 8129 useRegister(ins->setObject()), useBox(ins->value()), 8130 useRegister(ins->hash()), temp(), temp(), temp(), temp()); 8131 define(lir, ins); 8132 } 8133 8134 void LIRGenerator::visitSetObjectHasValueVMCall(MSetObjectHasValueVMCall* ins) { 8135 auto* lir = new (alloc()) LSetObjectHasValueVMCall( 8136 useRegisterAtStart(ins->setObject()), useBoxAtStart(ins->value())); 8137 defineReturn(lir, ins); 8138 assignSafepoint(lir, ins); 8139 } 8140 8141 void LIRGenerator::visitSetObjectDelete(MSetObjectDelete* ins) { 8142 auto* lir = new (alloc()) LSetObjectDelete( 8143 useRegisterAtStart(ins->setObject()), useBoxAtStart(ins->key())); 8144 defineReturn(lir, ins); 8145 assignSafepoint(lir, ins); 8146 } 8147 8148 void LIRGenerator::visitSetObjectAdd(MSetObjectAdd* ins) { 8149 auto* lir = new (alloc()) LSetObjectAdd(useRegisterAtStart(ins->setObject()), 8150 useBoxAtStart(ins->key())); 8151 add(lir, ins); 8152 assignSafepoint(lir, ins); 8153 } 8154 8155 void LIRGenerator::visitSetObjectSize(MSetObjectSize* ins) { 8156 auto* lir = 8157 new (alloc()) LSetObjectSize(useRegisterAtStart(ins->setObject())); 8158 define(lir, ins); 8159 } 8160 8161 void LIRGenerator::visitMapObjectHasNonBigInt(MMapObjectHasNonBigInt* ins) { 8162 auto* lir = new (alloc()) LMapObjectHasNonBigInt( 8163 useRegister(ins->mapObject()), useBox(ins->value()), 8164 useRegister(ins->hash()), temp(), temp()); 8165 define(lir, ins); 8166 } 8167 8168 void LIRGenerator::visitMapObjectHasBigInt(MMapObjectHasBigInt* ins) { 8169 auto* lir = new (alloc()) LMapObjectHasBigInt( 8170 useRegister(ins->mapObject()), useBox(ins->value()), 8171 useRegister(ins->hash()), temp(), temp(), temp(), temp()); 8172 define(lir, ins); 8173 } 8174 8175 void LIRGenerator::visitMapObjectHasValue(MMapObjectHasValue* ins) { 8176 auto* lir = new (alloc()) LMapObjectHasValue( 8177 useRegister(ins->mapObject()), useBox(ins->value()), 8178 useRegister(ins->hash()), temp(), temp(), temp(), temp()); 8179 define(lir, ins); 8180 } 8181 8182 void LIRGenerator::visitMapObjectHasValueVMCall(MMapObjectHasValueVMCall* ins) { 8183 auto* lir = new (alloc()) LMapObjectHasValueVMCall( 8184 useRegisterAtStart(ins->mapObject()), useBoxAtStart(ins->value())); 8185 defineReturn(lir, ins); 8186 assignSafepoint(lir, ins); 8187 } 8188 8189 void LIRGenerator::visitMapObjectGetNonBigInt(MMapObjectGetNonBigInt* ins) { 8190 auto* lir = new (alloc()) LMapObjectGetNonBigInt( 8191 useRegister(ins->mapObject()), useBox(ins->value()), 8192 useRegister(ins->hash()), temp(), temp()); 8193 defineBox(lir, ins); 8194 } 8195 8196 void LIRGenerator::visitMapObjectGetBigInt(MMapObjectGetBigInt* ins) { 8197 auto* lir = new (alloc()) LMapObjectGetBigInt( 8198 useRegister(ins->mapObject()), useBox(ins->value()), 8199 useRegister(ins->hash()), temp(), temp(), temp(), temp()); 8200 defineBox(lir, ins); 8201 } 8202 8203 void LIRGenerator::visitMapObjectGetValue(MMapObjectGetValue* ins) { 8204 auto* lir = new (alloc()) LMapObjectGetValue( 8205 useRegister(ins->mapObject()), useBox(ins->value()), 8206 useRegister(ins->hash()), temp(), temp(), temp(), temp()); 8207 defineBox(lir, ins); 8208 } 8209 8210 void LIRGenerator::visitMapObjectGetValueVMCall(MMapObjectGetValueVMCall* ins) { 8211 auto* lir = new (alloc()) LMapObjectGetValueVMCall( 8212 useRegisterAtStart(ins->mapObject()), useBoxAtStart(ins->value())); 8213 defineReturn(lir, ins); 8214 assignSafepoint(lir, ins); 8215 } 8216 8217 void LIRGenerator::visitMapObjectDelete(MMapObjectDelete* ins) { 8218 auto* lir = new (alloc()) LMapObjectDelete( 8219 useRegisterAtStart(ins->mapObject()), useBoxAtStart(ins->key())); 8220 defineReturn(lir, ins); 8221 assignSafepoint(lir, ins); 8222 } 8223 8224 void LIRGenerator::visitMapObjectSet(MMapObjectSet* ins) { 8225 auto* lir = new (alloc()) 8226 LMapObjectSet(useRegisterAtStart(ins->mapObject()), 8227 useBoxAtStart(ins->key()), useBoxAtStart(ins->value())); 8228 add(lir, ins); 8229 assignSafepoint(lir, ins); 8230 } 8231 8232 void LIRGenerator::visitMapObjectSize(MMapObjectSize* ins) { 8233 auto* lir = 8234 new (alloc()) LMapObjectSize(useRegisterAtStart(ins->mapObject())); 8235 define(lir, ins); 8236 } 8237 8238 void LIRGenerator::visitWeakMapGetObject(MWeakMapGetObject* ins) { 8239 #ifdef JS_CODEGEN_X86 8240 auto* lir = new (alloc()) LWeakMapGetObject( 8241 useFixedAtStart(ins->weakMap(), CallTempReg0), 8242 useFixedAtStart(ins->object(), CallTempReg1), tempFixed(CallTempReg2)); 8243 defineReturn(lir, ins); 8244 #else 8245 auto* lir = new (alloc()) LWeakMapGetObject( 8246 useRegisterAtStart(ins->weakMap()), useRegisterAtStart(ins->object()), 8247 temp(), temp(), temp(), temp(), temp(), temp(), temp()); 8248 defineBox(lir, ins); 8249 #endif 8250 } 8251 8252 void LIRGenerator::visitWeakMapHasObject(MWeakMapHasObject* ins) { 8253 #ifdef JS_CODEGEN_X86 8254 auto* lir = new (alloc()) LWeakMapHasObject( 8255 useRegisterAtStart(ins->weakMap()), useRegisterAtStart(ins->object())); 8256 defineReturn(lir, ins); 8257 #else 8258 auto* lir = new (alloc()) LWeakMapHasObject( 8259 useRegisterAtStart(ins->weakMap()), useRegisterAtStart(ins->object()), 8260 temp(), temp(), temp(), temp(), temp(), temp(), temp()); 8261 define(lir, ins); 8262 #endif 8263 } 8264 8265 void LIRGenerator::visitWeakSetHasObject(MWeakSetHasObject* ins) { 8266 auto* lir = new (alloc()) LWeakSetHasObject( 8267 useRegisterAtStart(ins->weakSet()), useRegisterAtStart(ins->object())); 8268 defineReturn(lir, ins); 8269 } 8270 8271 void LIRGenerator::visitDateFillLocalTimeSlots(MDateFillLocalTimeSlots* ins) { 8272 auto* lir = 8273 new (alloc()) LDateFillLocalTimeSlots(useRegister(ins->date()), temp()); 8274 add(lir, ins); 8275 assignSafepoint(lir, ins); 8276 } 8277 8278 void LIRGenerator::visitDateHoursFromSecondsIntoYear( 8279 MDateHoursFromSecondsIntoYear* ins) { 8280 auto* lir = new (alloc()) LDateHoursFromSecondsIntoYear( 8281 useBox(ins->secondsIntoYear()), temp(), temp()); 8282 defineBox(lir, ins); 8283 } 8284 8285 void LIRGenerator::visitDateMinutesFromSecondsIntoYear( 8286 MDateMinutesFromSecondsIntoYear* ins) { 8287 auto* lir = new (alloc()) LDateMinutesFromSecondsIntoYear( 8288 useBox(ins->secondsIntoYear()), temp(), temp()); 8289 defineBox(lir, ins); 8290 } 8291 8292 void LIRGenerator::visitDateSecondsFromSecondsIntoYear( 8293 MDateSecondsFromSecondsIntoYear* ins) { 8294 auto* lir = new (alloc()) LDateSecondsFromSecondsIntoYear( 8295 useBox(ins->secondsIntoYear()), temp(), temp()); 8296 defineBox(lir, ins); 8297 } 8298 8299 void LIRGenerator::visitPostIntPtrConversion(MPostIntPtrConversion* ins) { 8300 // This operation is a no-op. 8301 redefine(ins, ins->input()); 8302 } 8303 8304 void LIRGenerator::visitCanonicalizeNaN(MCanonicalizeNaN* ins) { 8305 MOZ_ASSERT(ins->type() == ins->input()->type()); 8306 8307 auto input = useRegisterAtStart(ins->input()); 8308 switch (ins->type()) { 8309 case MIRType::Double: 8310 defineReuseInput(new (alloc()) LCanonicalizeNaND(input), ins, 0); 8311 return; 8312 case MIRType::Float32: 8313 defineReuseInput(new (alloc()) LCanonicalizeNaNF(input), ins, 0); 8314 return; 8315 default: 8316 MOZ_CRASH("unexpected floating point type"); 8317 } 8318 } 8319 8320 void LIRGenerator::visitConstant(MConstant* ins) { 8321 if (!IsFloatingPointType(ins->type()) && ins->canEmitAtUses()) { 8322 emitAtUses(ins); 8323 return; 8324 } 8325 8326 switch (ins->type()) { 8327 case MIRType::Double: 8328 define(new (alloc()) LDouble(ins->toDouble()), ins); 8329 break; 8330 case MIRType::Float32: 8331 define(new (alloc()) LFloat32(ins->toFloat32()), ins); 8332 break; 8333 case MIRType::Boolean: 8334 define(new (alloc()) LInteger(ins->toBoolean()), ins); 8335 break; 8336 case MIRType::Int32: 8337 define(new (alloc()) LInteger(ins->toInt32()), ins); 8338 break; 8339 case MIRType::Int64: 8340 defineInt64(new (alloc()) LInteger64(ins->toInt64()), ins); 8341 break; 8342 case MIRType::IntPtr: 8343 #ifdef JS_64BIT 8344 defineInt64(new (alloc()) LInteger64(ins->toIntPtr()), ins); 8345 #else 8346 define(new (alloc()) LInteger(ins->toIntPtr()), ins); 8347 #endif 8348 break; 8349 case MIRType::String: 8350 define(new (alloc()) LPointer(ins->toString()->raw()), ins); 8351 break; 8352 case MIRType::Symbol: 8353 define(new (alloc()) LPointer(ins->toSymbol()), ins); 8354 break; 8355 case MIRType::BigInt: 8356 define(new (alloc()) LPointer(ins->toBigInt()), ins); 8357 break; 8358 case MIRType::Object: 8359 define(new (alloc()) LPointer(&ins->toObject()), ins); 8360 break; 8361 case MIRType::Shape: 8362 MOZ_ASSERT(ins->isEmittedAtUses()); 8363 break; 8364 default: 8365 // Constants of special types (undefined, null) should never flow into 8366 // here directly. Operations blindly consuming them require a Box. 8367 MOZ_CRASH("unexpected constant type"); 8368 } 8369 } 8370 8371 void LIRGenerator::visitConstantProto(MConstantProto* ins) { 8372 JSObject* obj = &ins->protoObject()->toConstant()->toObject(); 8373 define(new (alloc()) LPointer(obj), ins); 8374 } 8375 8376 void LIRGenerator::visitWasmNullConstant(MWasmNullConstant* ins) { 8377 define(new (alloc()) LWasmNullConstant(), ins); 8378 } 8379 8380 void LIRGenerator::visitWasmFloatConstant(MWasmFloatConstant* ins) { 8381 switch (ins->type()) { 8382 case MIRType::Double: 8383 define(new (alloc()) LDouble(ins->toDouble()), ins); 8384 break; 8385 case MIRType::Float32: 8386 define(new (alloc()) LFloat32(ins->toFloat32()), ins); 8387 break; 8388 #ifdef ENABLE_WASM_SIMD 8389 case MIRType::Simd128: 8390 define(new (alloc()) LSimd128(ins->toSimd128()), ins); 8391 break; 8392 #endif 8393 default: 8394 MOZ_CRASH("unexpected constant type"); 8395 } 8396 } 8397 8398 #ifdef JS_JITSPEW 8399 static void SpewResumePoint(MBasicBlock* block, MInstruction* ins, 8400 MResumePoint* resumePoint) { 8401 Fprinter& out = JitSpewPrinter(); 8402 out.printf("Current resume point %p details:\n", (void*)resumePoint); 8403 out.printf(" frame count: %u\n", resumePoint->frameCount()); 8404 8405 if (ins) { 8406 out.printf(" taken after: "); 8407 ins->printName(out); 8408 } else { 8409 out.printf(" taken at block %u entry", block->id()); 8410 } 8411 out.printf("\n"); 8412 8413 out.printf(" pc: %p (script: %p, offset: %d)\n", (void*)resumePoint->pc(), 8414 (void*)resumePoint->block()->info().script(), 8415 int(resumePoint->block()->info().script()->pcToOffset( 8416 resumePoint->pc()))); 8417 8418 for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) { 8419 MDefinition* in = resumePoint->getOperand(i); 8420 out.printf(" slot%u: ", (unsigned)i); 8421 in->printName(out); 8422 out.printf("\n"); 8423 } 8424 } 8425 #endif 8426 8427 void LIRGenerator::visitInstructionDispatch(MInstruction* ins) { 8428 #ifdef JS_CODEGEN_NONE 8429 // Don't compile the switch-statement below so that we don't have to define 8430 // the platform-specific visit* methods for the none-backend. 8431 MOZ_CRASH(); 8432 #else 8433 switch (ins->op()) { 8434 # define MIR_OP(op) \ 8435 case MDefinition::Opcode::op: \ 8436 visit##op(ins->to##op()); \ 8437 break; 8438 MIR_OPCODE_LIST(MIR_OP) 8439 # undef MIR_OP 8440 default: 8441 MOZ_CRASH("Invalid instruction"); 8442 } 8443 #endif 8444 } 8445 8446 void LIRGeneratorShared::visitEmittedAtUses(MInstruction* ins) { 8447 static_cast<LIRGenerator*>(this)->visitInstructionDispatch(ins); 8448 } 8449 8450 bool LIRGenerator::visitInstruction(MInstruction* ins) { 8451 MOZ_ASSERT(!errored()); 8452 8453 if (ins->isRecoveredOnBailout()) { 8454 MOZ_ASSERT(!JitOptions.disableRecoverIns); 8455 return true; 8456 } 8457 8458 if (!gen->ensureBallast()) { 8459 return false; 8460 } 8461 visitInstructionDispatch(ins); 8462 8463 if (ins->resumePoint()) { 8464 updateResumeState(ins); 8465 } 8466 8467 #ifdef DEBUG 8468 ins->setInWorklistUnchecked(); 8469 #endif 8470 8471 // If no safepoint was created, there's no need for an OSI point. 8472 if (LOsiPoint* osiPoint = popOsiPoint()) { 8473 add(osiPoint); 8474 } 8475 8476 return !errored(); 8477 } 8478 8479 bool LIRGenerator::definePhis() { 8480 size_t lirIndex = 0; 8481 MBasicBlock* block = current->mir(); 8482 for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) { 8483 if (phi->type() == MIRType::Value) { 8484 defineUntypedPhi(*phi, lirIndex); 8485 lirIndex += BOX_PIECES; 8486 } else if (phi->type() == MIRType::Int64) { 8487 defineInt64Phi(*phi, lirIndex); 8488 lirIndex += INT64_PIECES; 8489 } else { 8490 defineTypedPhi(*phi, lirIndex); 8491 lirIndex += 1; 8492 } 8493 } 8494 return !errored(); 8495 } 8496 8497 void LIRGenerator::updateResumeState(MInstruction* ins) { 8498 lastResumePoint_ = ins->resumePoint(); 8499 #ifdef JS_JITSPEW 8500 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) { 8501 SpewResumePoint(nullptr, ins, lastResumePoint_); 8502 } 8503 #endif 8504 } 8505 8506 void LIRGenerator::updateResumeState(MBasicBlock* block) { 8507 // Note: RangeAnalysis can flag blocks as unreachable, but they are only 8508 // removed iff GVN (including UCE) is enabled. 8509 MOZ_ASSERT_IF(!mir()->compilingWasm() && !block->unreachable(), 8510 block->entryResumePoint()); 8511 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled()); 8512 lastResumePoint_ = block->entryResumePoint(); 8513 #ifdef JS_JITSPEW 8514 if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) { 8515 SpewResumePoint(block, nullptr, lastResumePoint_); 8516 } 8517 #endif 8518 } 8519 8520 bool LIRGenerator::visitBlock(MBasicBlock* block) { 8521 current = block->lir(); 8522 updateResumeState(block); 8523 8524 if (!definePhis()) { 8525 return false; 8526 } 8527 8528 MOZ_ASSERT_IF(block->unreachable(), !mir()->optimizationInfo().gvnEnabled()); 8529 for (MInstructionIterator iter = block->begin(); *iter != block->lastIns(); 8530 iter++) { 8531 if (gen->shouldCancel("Lowering (instruction loop)")) { 8532 return false; 8533 } 8534 if (!visitInstruction(*iter)) { 8535 return false; 8536 } 8537 } 8538 8539 if (block->successorWithPhis()) { 8540 // If we have a successor with phis, lower the phi input now that we 8541 // are approaching the join point. 8542 MBasicBlock* successor = block->successorWithPhis(); 8543 uint32_t position = block->positionInPhiSuccessor(); 8544 size_t lirIndex = 0; 8545 for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd(); 8546 phi++) { 8547 if (!gen->ensureBallast()) { 8548 return false; 8549 } 8550 8551 MDefinition* opd = phi->getOperand(position); 8552 ensureDefined(opd); 8553 8554 MOZ_ASSERT(opd->type() == phi->type()); 8555 8556 if (phi->type() == MIRType::Value) { 8557 lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex); 8558 lirIndex += BOX_PIECES; 8559 } else if (phi->type() == MIRType::Int64) { 8560 lowerInt64PhiInput(*phi, position, successor->lir(), lirIndex); 8561 lirIndex += INT64_PIECES; 8562 } else { 8563 lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex); 8564 lirIndex += 1; 8565 } 8566 } 8567 } 8568 8569 // Now emit the last instruction, which is some form of branch. 8570 if (!visitInstruction(block->lastIns())) { 8571 return false; 8572 } 8573 8574 return true; 8575 } 8576 8577 void LIRGenerator::visitNaNToZero(MNaNToZero* ins) { 8578 MDefinition* input = ins->input(); 8579 8580 if (ins->operandIsNeverNaN() && ins->operandIsNeverNegativeZero()) { 8581 redefine(ins, input); 8582 return; 8583 } 8584 LNaNToZero* lir = 8585 new (alloc()) LNaNToZero(useRegisterAtStart(input), tempDouble()); 8586 defineReuseInput(lir, ins, 0); 8587 } 8588 8589 bool LIRGenerator::generate() { 8590 // Create all blocks and prep all phis beforehand. 8591 for (ReversePostorderIterator block(graph.rpoBegin()); 8592 block != graph.rpoEnd(); block++) { 8593 if (gen->shouldCancel("Lowering (preparation loop)")) { 8594 return false; 8595 } 8596 8597 if (!lirGraph_.initBlock(*block)) { 8598 return false; 8599 } 8600 } 8601 8602 for (ReversePostorderIterator block(graph.rpoBegin()); 8603 block != graph.rpoEnd(); block++) { 8604 if (gen->shouldCancel("Lowering (main loop)")) { 8605 return false; 8606 } 8607 8608 if (!visitBlock(*block)) { 8609 return false; 8610 } 8611 } 8612 8613 lirGraph_.setArgumentSlotCount(maxargslots_); 8614 return true; 8615 } 8616 8617 void LIRGenerator::visitPhi(MPhi* phi) { 8618 // Phi nodes are not lowered because they are only meaningful for the register 8619 // allocator. 8620 MOZ_CRASH("Unexpected Phi node during Lowering."); 8621 } 8622 8623 void LIRGenerator::visitBeta(MBeta* beta) { 8624 // Beta nodes are supposed to be removed before because they are 8625 // only used to carry the range information for Range analysis 8626 MOZ_CRASH("Unexpected Beta node during Lowering."); 8627 } 8628 8629 void LIRGenerator::visitObjectState(MObjectState* objState) { 8630 // ObjectState nodes are always recovered on bailouts 8631 MOZ_CRASH("Unexpected ObjectState node during Lowering."); 8632 } 8633 8634 void LIRGenerator::visitArrayState(MArrayState* objState) { 8635 // ArrayState nodes are always recovered on bailouts 8636 MOZ_CRASH("Unexpected ArrayState node during Lowering."); 8637 } 8638 8639 void LIRGenerator::visitIonToWasmCall(MIonToWasmCall* ins) { 8640 // The instruction needs a temp register: 8641 // - that's not the FramePointer, since wasm is going to use it in the 8642 // function. 8643 // - that's not aliasing an input register. 8644 LDefinition scratch = tempFixed(ABINonArgReg0); 8645 8646 // Note that since this is a LIR call instruction, regalloc will prevent 8647 // the use*AtStart below from reusing any of the temporaries. 8648 8649 LInstruction* lir; 8650 if (ins->type() == MIRType::Value) { 8651 lir = allocateVariadic<LIonToWasmCallV>(ins->numOperands(), scratch); 8652 } else if (ins->type() == MIRType::Int64) { 8653 lir = allocateVariadic<LIonToWasmCallI64>(ins->numOperands(), scratch); 8654 } else { 8655 lir = allocateVariadic<LIonToWasmCall>(ins->numOperands(), scratch); 8656 } 8657 if (!lir) { 8658 abort(AbortReason::Alloc, "OOM: LIRGenerator::visitIonToWasmCall"); 8659 return; 8660 } 8661 8662 ABIArgGenerator abi(ABIKind::Wasm); 8663 for (unsigned i = 0; i < ins->numOperands(); i++) { 8664 MDefinition* argDef = ins->getOperand(i); 8665 ABIArg arg = abi.next(ToMIRType(argDef->type())); 8666 switch (arg.kind()) { 8667 case ABIArg::GPR: 8668 case ABIArg::FPU: 8669 lir->setOperand(i, useFixedAtStart(argDef, arg.reg())); 8670 break; 8671 case ABIArg::Stack: 8672 lir->setOperand(i, useAtStart(argDef)); 8673 break; 8674 #ifdef JS_CODEGEN_REGISTER_PAIR 8675 case ABIArg::GPR_PAIR: 8676 MOZ_CRASH( 8677 "no way to pass i64, and wasm uses hardfp for function calls"); 8678 #endif 8679 case ABIArg::Uninitialized: 8680 MOZ_CRASH("Uninitialized ABIArg kind"); 8681 } 8682 } 8683 8684 defineReturn(lir, ins); 8685 assignSafepoint(lir, ins); 8686 } 8687 8688 void LIRGenerator::visitWasmSelect(MWasmSelect* ins) { 8689 MDefinition* condExpr = ins->condExpr(); 8690 8691 // Pick off specific cases that we can do with LWasmCompareAndSelect to avoid 8692 // generating a boolean that we then have to test again. 8693 if (condExpr->isCompare() && condExpr->isEmittedAtUses()) { 8694 MCompare* comp = condExpr->toCompare(); 8695 MCompare::CompareType compTy = comp->compareType(); 8696 if (canSpecializeWasmCompareAndSelect(compTy, ins->type())) { 8697 JSOp jsop = comp->jsop(); 8698 // We don't currently generate any other JSOPs for the comparison, and if 8699 // that changes, we want to know about it. Hence this assertion. 8700 MOZ_ASSERT(jsop == JSOp::Eq || jsop == JSOp::Ne || jsop == JSOp::Lt || 8701 jsop == JSOp::Gt || jsop == JSOp::Le || jsop == JSOp::Ge); 8702 MDefinition* lhs = comp->lhs(); 8703 MDefinition* rhs = comp->rhs(); 8704 jsop = ReorderComparison(jsop, &lhs, &rhs); 8705 lowerWasmCompareAndSelect(ins, lhs, rhs, compTy, jsop); 8706 return; 8707 } 8708 } 8709 // Fall through to code that generates a boolean and selects on that. 8710 8711 if (ins->type() == MIRType::Int64) { 8712 lowerWasmSelectI64(ins); 8713 return; 8714 } 8715 8716 lowerWasmSelectI(ins); 8717 } 8718 8719 void LIRGenerator::visitWasmFence(MWasmFence* ins) { 8720 add(new (alloc()) LWasmFence, ins); 8721 } 8722 8723 void LIRGenerator::visitWasmLoadField(MWasmLoadField* ins) { 8724 uint32_t offset = ins->offset(); 8725 LAllocation data = useRegisterAtStart(ins->base()); 8726 MWideningOp wideningOp = ins->wideningOp(); 8727 if (ins->type() == MIRType::Int64) { 8728 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None); 8729 defineInt64(new (alloc()) LWasmLoadSlotI64(data, offset, ins->maybeTrap()), 8730 ins); 8731 } else { 8732 define(new (alloc()) LWasmLoadSlot(data, offset, ins->type(), wideningOp, 8733 ins->maybeTrap()), 8734 ins); 8735 } 8736 if (ins->keepAlive() != ins->base()) { 8737 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->keepAlive())), ins); 8738 } 8739 } 8740 8741 void LIRGenerator::visitWasmLoadElement(MWasmLoadElement* ins) { 8742 LAllocation base = useRegister(ins->base()); 8743 LAllocation index = useRegister(ins->index()); 8744 MWideningOp wideningOp = ins->wideningOp(); 8745 Scale scale = ins->scale(); 8746 if (ins->type() == MIRType::Int64) { 8747 MOZ_RELEASE_ASSERT(wideningOp == MWideningOp::None); 8748 defineInt64( 8749 new (alloc()) LWasmLoadElementI64(base, index, ins->maybeTrap()), ins); 8750 } else { 8751 LDefinition tmp = 8752 ins->type() == MIRType::Simd128 ? temp() : LDefinition::BogusTemp(); 8753 define(new (alloc()) LWasmLoadElement(base, index, tmp, ins->type(), 8754 wideningOp, scale, ins->maybeTrap()), 8755 ins); 8756 } 8757 if (ins->keepAlive() != ins->base()) { 8758 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->keepAlive())), ins); 8759 } 8760 } 8761 8762 void LIRGenerator::visitWasmStoreField(MWasmStoreField* ins) { 8763 MDefinition* value = ins->value(); 8764 uint32_t offs = ins->offset(); 8765 MNarrowingOp narrowingOp = ins->narrowingOp(); 8766 LAllocation base = useRegister(ins->base()); 8767 if (value->type() == MIRType::Int64) { 8768 MOZ_RELEASE_ASSERT(narrowingOp == MNarrowingOp::None); 8769 add(new (alloc()) LWasmStoreSlotI64(useInt64Register(value), base, offs, 8770 ins->maybeTrap()), 8771 ins); 8772 } else { 8773 add(new (alloc()) 8774 LWasmStoreSlot(useRegister(value), base, offs, value->type(), 8775 narrowingOp, ins->maybeTrap()), 8776 ins); 8777 } 8778 if (ins->keepAlive() != ins->base()) { 8779 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->keepAlive())), ins); 8780 } 8781 } 8782 8783 void LIRGenerator::visitWasmStoreFieldRef(MWasmStoreFieldRef* ins) { 8784 LAllocation instance = useRegister(ins->instance()); 8785 LAllocation base = useFixed(ins->base(), PreBarrierReg); 8786 LAllocation value = useRegister(ins->value()); 8787 uint32_t offset = ins->offset(); 8788 add(new (alloc()) LWasmStoreRef(instance, base, value, temp(), offset, 8789 ins->maybeTrap(), ins->preBarrierKind()), 8790 ins); 8791 if (ins->keepAlive() != ins->base()) { 8792 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->keepAlive())), ins); 8793 } 8794 } 8795 8796 void LIRGenerator::visitWasmStoreElement(MWasmStoreElement* ins) { 8797 LAllocation base = useRegister(ins->base()); 8798 LAllocation index = useRegister(ins->index()); 8799 MDefinition* value = ins->value(); 8800 MNarrowingOp narrowingOp = ins->narrowingOp(); 8801 Scale scale = ins->scale(); 8802 if (value->type() == MIRType::Int64) { 8803 MOZ_RELEASE_ASSERT(narrowingOp == MNarrowingOp::None); 8804 add(new (alloc()) LWasmStoreElementI64(base, index, useInt64Register(value), 8805 ins->maybeTrap()), 8806 ins); 8807 } else { 8808 LDefinition tmp = 8809 value->type() == MIRType::Simd128 ? temp() : LDefinition::BogusTemp(); 8810 add(new (alloc()) LWasmStoreElement(base, index, useRegister(value), tmp, 8811 value->type(), narrowingOp, scale, 8812 ins->maybeTrap()), 8813 ins); 8814 } 8815 if (ins->keepAlive() != ins->base()) { 8816 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->keepAlive())), ins); 8817 } 8818 } 8819 8820 void LIRGenerator::visitWasmStoreElementRef(MWasmStoreElementRef* ins) { 8821 LAllocation instance = useRegister(ins->instance()); 8822 LAllocation base = useFixed(ins->base(), PreBarrierReg); 8823 LAllocation index = useRegister(ins->index()); 8824 LAllocation value = useRegister(ins->value()); 8825 bool needTemps = ins->preBarrierKind() == WasmPreBarrierKind::Normal; 8826 LDefinition temp0 = needTemps ? temp() : LDefinition::BogusTemp(); 8827 LDefinition temp1 = needTemps ? temp() : LDefinition::BogusTemp(); 8828 add(new (alloc()) 8829 LWasmStoreElementRef(instance, base, index, value, temp0, temp1, 8830 ins->maybeTrap(), ins->preBarrierKind()), 8831 ins); 8832 if (ins->keepAlive() != ins->base()) { 8833 add(new (alloc()) LKeepAliveObject(useKeepalive(ins->keepAlive())), ins); 8834 } 8835 } 8836 8837 WasmRefIsSubtypeDefs LIRGenerator::useWasmRefIsSubtype(wasm::RefType destType, 8838 MDefinition* superSTV) { 8839 BranchWasmRefIsSubtypeRegisters needs = 8840 MacroAssembler::regsForBranchWasmRefIsSubtype(destType); 8841 return WasmRefIsSubtypeDefs{ 8842 .superSTV = needs.needSuperSTV ? useRegister(superSTV) : LAllocation(), 8843 .scratch1 = needs.needScratch1 ? temp() : LDefinition(), 8844 .scratch2 = needs.needScratch2 ? temp() : LDefinition(), 8845 }; 8846 } 8847 8848 void LIRGenerator::visitWasmRefTestAbstract(MWasmRefTestAbstract* ins) { 8849 if (CanEmitAtUseForSingleTest(ins)) { 8850 emitAtUses(ins); 8851 return; 8852 } 8853 8854 LAllocation ref = useRegister(ins->ref()); 8855 WasmRefIsSubtypeDefs regs = 8856 useWasmRefIsSubtype(ins->destType(), /*superSTV=*/nullptr); 8857 define(new (alloc()) LWasmRefTestAbstract(ref, regs.scratch1), ins); 8858 } 8859 8860 void LIRGenerator::visitWasmRefTestConcrete(MWasmRefTestConcrete* ins) { 8861 if (CanEmitAtUseForSingleTest(ins)) { 8862 emitAtUses(ins); 8863 return; 8864 } 8865 8866 LAllocation ref = useRegister(ins->ref()); 8867 WasmRefIsSubtypeDefs regs = 8868 useWasmRefIsSubtype(ins->destType(), ins->superSTV()); 8869 define(new (alloc()) LWasmRefTestConcrete(ref, regs.superSTV, regs.scratch1, 8870 regs.scratch2), 8871 ins); 8872 } 8873 8874 void LIRGenerator::visitWasmRefCastAbstract(MWasmRefCastAbstract* ins) { 8875 LAllocation ref = useRegisterAtStart(ins->ref()); 8876 WasmRefIsSubtypeDefs regs = 8877 useWasmRefIsSubtype(ins->destType(), /*superSTV=*/nullptr); 8878 defineReuseInput(new (alloc()) LWasmRefCastAbstract(ref, regs.scratch1), ins, 8879 0); 8880 } 8881 8882 void LIRGenerator::visitWasmRefCastConcrete(MWasmRefCastConcrete* ins) { 8883 LAllocation ref = useRegisterAtStart(ins->ref()); 8884 WasmRefIsSubtypeDefs regs = 8885 useWasmRefIsSubtype(ins->destType(), ins->superSTV()); 8886 defineReuseInput(new (alloc()) LWasmRefCastConcrete( 8887 ref, regs.superSTV, regs.scratch1, regs.scratch2), 8888 ins, 0); 8889 } 8890 8891 void LIRGenerator::visitWasmRefConvertAnyExtern(MWasmRefConvertAnyExtern* ins) { 8892 // Because any and extern have the same representation, this is a no-op. 8893 return redefine(ins, ins->ref()); 8894 } 8895 8896 void LIRGenerator::visitWasmNewStructObject(MWasmNewStructObject* ins) { 8897 LWasmNewStructObject* lir = 8898 new (alloc()) LWasmNewStructObject(useFixed(ins->instance(), InstanceReg), 8899 useRegister(ins->allocSite()), temp()); 8900 define(lir, ins); 8901 assignWasmSafepoint(lir); 8902 } 8903 8904 void LIRGenerator::visitWasmNewArrayObject(MWasmNewArrayObject* ins) { 8905 LWasmNewArrayObject* lir = new (alloc()) 8906 LWasmNewArrayObject(useFixed(ins->instance(), InstanceReg), 8907 useRegisterOrConstant(ins->numElements()), 8908 useRegister(ins->allocSite()), temp(), temp()); 8909 define(lir, ins); 8910 assignWasmSafepoint(lir); 8911 } 8912 8913 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 8914 void LIRGenerator::visitAddDisposableResource(MAddDisposableResource* ins) { 8915 MDefinition* env = ins->environment(); 8916 8917 MOZ_ASSERT(env->type() == MIRType::Object); 8918 8919 MDefinition* resource = ins->resource(); 8920 MDefinition* method = ins->method(); 8921 MDefinition* needsClosure = ins->needsClosure(); 8922 8923 auto* lir = new (alloc()) LAddDisposableResource( 8924 useRegisterAtStart(env), useBoxAtStart(resource), useBoxAtStart(method), 8925 useRegisterAtStart(needsClosure)); 8926 add(lir, ins); 8927 assignSafepoint(lir, ins); 8928 } 8929 8930 void LIRGenerator::visitTakeDisposeCapability(MTakeDisposeCapability* ins) { 8931 MDefinition* env = ins->environment(); 8932 8933 LTakeDisposeCapability* lir = 8934 new (alloc()) LTakeDisposeCapability(useRegister(env)); 8935 defineBox(lir, ins); 8936 assignSafepoint(lir, ins); 8937 } 8938 8939 void LIRGenerator::visitCreateSuppressedError(MCreateSuppressedError* ins) { 8940 MDefinition* error = ins->error(); 8941 MDefinition* suppressed = ins->suppressed(); 8942 8943 LCreateSuppressedError* lir = new (alloc()) 8944 LCreateSuppressedError(useBoxAtStart(error), useBoxAtStart(suppressed)); 8945 define(lir, ins); 8946 assignSafepoint(lir, ins); 8947 } 8948 #endif 8949 8950 #ifdef FUZZING_JS_FUZZILLI 8951 void LIRGenerator::visitFuzzilliHash(MFuzzilliHash* ins) { 8952 MDefinition* value = ins->input(); 8953 8954 switch (value->type()) { 8955 case MIRType::Undefined: 8956 case MIRType::Null: { 8957 auto* lir = 8958 new (alloc()) LFuzzilliHashT(LAllocation(), temp(), tempDouble()); 8959 define(lir, ins); 8960 break; 8961 } 8962 8963 case MIRType::Int32: 8964 case MIRType::Double: 8965 case MIRType::Float32: 8966 case MIRType::Boolean: { 8967 auto* lir = new (alloc()) 8968 LFuzzilliHashT(useRegister(value), temp(), tempDouble()); 8969 define(lir, ins); 8970 break; 8971 } 8972 8973 case MIRType::BigInt: 8974 case MIRType::Object: { 8975 auto* lir = new (alloc()) 8976 LFuzzilliHashT(useRegister(value), LDefinition::BogusTemp(), 8977 LDefinition::BogusTemp()); 8978 define(lir, ins); 8979 assignSafepoint(lir, ins); 8980 break; 8981 } 8982 8983 case MIRType::Value: { 8984 auto* lir = 8985 new (alloc()) LFuzzilliHashV(useBox(value), temp(), tempDouble()); 8986 define(lir, ins); 8987 assignSafepoint(lir, ins); 8988 break; 8989 } 8990 8991 case MIRType::String: 8992 case MIRType::Symbol: { 8993 define(new (alloc()) LInteger(0), ins); 8994 break; 8995 } 8996 8997 default: 8998 MOZ_CRASH("Bad type"); 8999 } 9000 } 9001 9002 void LIRGenerator::visitFuzzilliHashStore(MFuzzilliHashStore* ins) { 9003 MDefinition* value = ins->input(); 9004 MOZ_ASSERT(value->type() == MIRType::Int32); 9005 add(new (alloc()) LFuzzilliHashStore(useRegister(value), temp(), temp()), 9006 ins); 9007 } 9008 #endif 9009 9010 static_assert(!std::is_polymorphic_v<LIRGenerator>, 9011 "LIRGenerator should not have any virtual methods"); 9012 9013 #ifdef JS_CODEGEN_NONE 9014 void LIRGenerator::visitReturnImpl(MDefinition*, bool) { MOZ_CRASH(); } 9015 #endif