LIR-shared.h (37922B)
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 #ifndef jit_shared_LIR_shared_h 8 #define jit_shared_LIR_shared_h 9 10 #include "jit/AtomicOp.h" 11 #include "jit/shared/Assembler-shared.h" 12 #include "util/Memory.h" 13 14 // This file declares LIR instructions that are common to every platform. 15 16 namespace js { 17 namespace jit { 18 19 LIR_OPCODE_CLASS_GENERATED 20 21 template <size_t Temps, size_t ExtraUses = 0> 22 class LBinaryMath : public LInstructionHelper<1, 2 + ExtraUses, Temps> { 23 protected: 24 explicit LBinaryMath(LNode::Opcode opcode) 25 : LInstructionHelper<1, 2 + ExtraUses, Temps>(opcode) {} 26 27 public: 28 const LAllocation* lhs() { return this->getOperand(0); } 29 const LAllocation* rhs() { return this->getOperand(1); } 30 }; 31 32 // An LOsiPoint captures a snapshot after a call and ensures enough space to 33 // patch in a call to the invalidation mechanism. 34 // 35 // Note: LSafepoints are 1:1 with LOsiPoints, so it holds a reference to the 36 // corresponding LSafepoint to inform it of the LOsiPoint's masm offset when it 37 // gets GC'd. 38 class LOsiPoint : public LInstructionHelper<0, 0, 0> { 39 LSafepoint* safepoint_; 40 41 public: 42 LOsiPoint(LSafepoint* safepoint, LSnapshot* snapshot) 43 : LInstructionHelper(classOpcode), safepoint_(safepoint) { 44 MOZ_ASSERT(safepoint && snapshot); 45 assignSnapshot(snapshot); 46 } 47 48 LSafepoint* associatedSafepoint() { return safepoint_; } 49 50 LIR_HEADER(OsiPoint) 51 }; 52 53 class LMove { 54 LAllocation from_; 55 LAllocation to_; 56 LDefinition::Type type_; 57 58 public: 59 LMove(LAllocation from, LAllocation to, LDefinition::Type type) 60 : from_(from), to_(to), type_(type) {} 61 62 LAllocation from() const { return from_; } 63 LAllocation to() const { return to_; } 64 LDefinition::Type type() const { return type_; } 65 }; 66 67 class LMoveGroup : public LInstructionHelper<0, 0, 0> { 68 js::Vector<LMove, 2, JitAllocPolicy> moves_; 69 70 #ifdef JS_CODEGEN_X86 71 // Optional general register available for use when executing moves. 72 LAllocation scratchRegister_; 73 #endif 74 75 explicit LMoveGroup(TempAllocator& alloc) 76 : LInstructionHelper(classOpcode), moves_(alloc) {} 77 78 public: 79 LIR_HEADER(MoveGroup) 80 81 static LMoveGroup* New(TempAllocator& alloc) { 82 return new (alloc) LMoveGroup(alloc); 83 } 84 85 void printOperands(GenericPrinter& out); 86 87 // Add a move which takes place simultaneously with all others in the group. 88 bool add(LAllocation from, LAllocation to, LDefinition::Type type); 89 90 // Add a move which takes place after existing moves in the group. 91 bool addAfter(LAllocation from, LAllocation to, LDefinition::Type type); 92 93 size_t numMoves() const { return moves_.length(); } 94 const LMove& getMove(size_t i) const { return moves_[i]; } 95 96 #ifdef JS_CODEGEN_X86 97 void setScratchRegister(Register reg) { scratchRegister_ = LGeneralReg(reg); } 98 LAllocation maybeScratchRegister() { return scratchRegister_; } 99 #endif 100 101 bool uses(Register reg) { 102 for (size_t i = 0; i < numMoves(); i++) { 103 LMove move = getMove(i); 104 if (move.from() == LGeneralReg(reg) || move.to() == LGeneralReg(reg)) { 105 return true; 106 } 107 } 108 return false; 109 } 110 }; 111 112 // A constant Value. 113 class LValue : public LInstructionHelper<BOX_PIECES, 0, 0> { 114 Value v_; 115 116 public: 117 LIR_HEADER(Value) 118 119 explicit LValue(const Value& v) : LInstructionHelper(classOpcode), v_(v) {} 120 121 Value value() const { return v_; } 122 }; 123 124 // Allocate a new arguments object for an inlined frame. 125 class LCreateInlinedArgumentsObject : public LVariadicInstruction<1, 2> { 126 public: 127 LIR_HEADER(CreateInlinedArgumentsObject) 128 129 static const size_t CallObj = 0; 130 static const size_t Callee = 1; 131 static const size_t NumNonArgumentOperands = 2; 132 static size_t ArgIndex(size_t i) { 133 return NumNonArgumentOperands + BOX_PIECES * i; 134 } 135 136 LCreateInlinedArgumentsObject(uint32_t numOperands, const LDefinition& temp1, 137 const LDefinition& temp2) 138 : LVariadicInstruction(classOpcode, numOperands) { 139 setIsCall(); 140 setTemp(0, temp1); 141 setTemp(1, temp2); 142 } 143 144 const LAllocation* getCallObject() { return getOperand(CallObj); } 145 const LAllocation* getCallee() { return getOperand(Callee); } 146 147 const LDefinition* temp1() { return getTemp(0); } 148 const LDefinition* temp2() { return getTemp(1); } 149 150 MCreateInlinedArgumentsObject* mir() const { 151 return mir_->toCreateInlinedArgumentsObject(); 152 } 153 }; 154 155 class LGetInlinedArgument : public LVariadicInstruction<BOX_PIECES, 0> { 156 public: 157 LIR_HEADER(GetInlinedArgument) 158 159 static const size_t Index = 0; 160 static const size_t NumNonArgumentOperands = 1; 161 static size_t ArgIndex(size_t i) { 162 return NumNonArgumentOperands + BOX_PIECES * i; 163 } 164 165 explicit LGetInlinedArgument(uint32_t numOperands) 166 : LVariadicInstruction(classOpcode, numOperands) {} 167 168 const LAllocation* getIndex() { return getOperand(Index); } 169 170 MGetInlinedArgument* mir() const { return mir_->toGetInlinedArgument(); } 171 }; 172 173 class LGetInlinedArgumentHole : public LVariadicInstruction<BOX_PIECES, 0> { 174 public: 175 LIR_HEADER(GetInlinedArgumentHole) 176 177 static const size_t Index = 0; 178 static const size_t NumNonArgumentOperands = 1; 179 static size_t ArgIndex(size_t i) { 180 return NumNonArgumentOperands + BOX_PIECES * i; 181 } 182 183 explicit LGetInlinedArgumentHole(uint32_t numOperands) 184 : LVariadicInstruction(classOpcode, numOperands) {} 185 186 const LAllocation* getIndex() { return getOperand(Index); } 187 188 MGetInlinedArgumentHole* mir() const { 189 return mir_->toGetInlinedArgumentHole(); 190 } 191 }; 192 193 class LInlineArgumentsSlice : public LVariadicInstruction<1, 1> { 194 public: 195 LIR_HEADER(InlineArgumentsSlice) 196 197 static const size_t Begin = 0; 198 static const size_t Count = 1; 199 static const size_t NumNonArgumentOperands = 2; 200 static size_t ArgIndex(size_t i) { 201 return NumNonArgumentOperands + BOX_PIECES * i; 202 } 203 204 explicit LInlineArgumentsSlice(uint32_t numOperands, const LDefinition& temp) 205 : LVariadicInstruction(classOpcode, numOperands) { 206 setTemp(0, temp); 207 } 208 209 const LAllocation* begin() { return getOperand(Begin); } 210 const LAllocation* count() { return getOperand(Count); } 211 const LDefinition* temp() { return getTemp(0); } 212 213 MInlineArgumentsSlice* mir() const { return mir_->toInlineArgumentsSlice(); } 214 }; 215 216 // Common code for LIR descended from MCall. 217 template <size_t Defs, size_t Operands, size_t Temps> 218 class LJSCallInstructionHelper 219 : public LCallInstructionHelper<Defs, Operands, Temps> { 220 protected: 221 explicit LJSCallInstructionHelper(LNode::Opcode opcode) 222 : LCallInstructionHelper<Defs, Operands, Temps>(opcode) {} 223 224 public: 225 MCall* mir() const { return this->mir_->toCall(); } 226 227 bool hasSingleTarget() const { return getSingleTarget() != nullptr; } 228 WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); } 229 230 // Does not include |this|. 231 uint32_t numActualArgs() const { return mir()->numActualArgs(); } 232 233 bool isConstructing() const { return mir()->isConstructing(); } 234 bool ignoresReturnValue() const { return mir()->ignoresReturnValue(); } 235 }; 236 237 // Generates a polymorphic callsite, wherein the function being called is 238 // unknown and anticipated to vary. 239 class LCallGeneric : public LJSCallInstructionHelper<BOX_PIECES, 1, 1> { 240 public: 241 LIR_HEADER(CallGeneric) 242 243 LCallGeneric(const LAllocation& callee, const LDefinition& argc) 244 : LJSCallInstructionHelper(classOpcode) { 245 setOperand(0, callee); 246 setTemp(0, argc); 247 } 248 249 const LAllocation* getCallee() { return getOperand(0); } 250 const LDefinition* getArgc() { return getTemp(0); } 251 }; 252 253 // Generates a hardcoded callsite for a known, non-native target. 254 class LCallKnown : public LJSCallInstructionHelper<BOX_PIECES, 1, 1> { 255 public: 256 LIR_HEADER(CallKnown) 257 258 LCallKnown(const LAllocation& func, const LDefinition& tmpobjreg) 259 : LJSCallInstructionHelper(classOpcode) { 260 setOperand(0, func); 261 setTemp(0, tmpobjreg); 262 } 263 264 const LAllocation* getFunction() { return getOperand(0); } 265 const LDefinition* getTempObject() { return getTemp(0); } 266 }; 267 268 // Generates a hardcoded callsite for a known, native target. 269 class LCallNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4> { 270 public: 271 LIR_HEADER(CallNative) 272 273 LCallNative(const LDefinition& argContext, const LDefinition& argUintN, 274 const LDefinition& argVp, const LDefinition& tmpreg) 275 : LJSCallInstructionHelper(classOpcode) { 276 // Registers used for callWithABI(). 277 setTemp(0, argContext); 278 setTemp(1, argUintN); 279 setTemp(2, argVp); 280 281 // Temporary registers. 282 setTemp(3, tmpreg); 283 } 284 285 const LDefinition* getArgContextReg() { return getTemp(0); } 286 const LDefinition* getArgUintNReg() { return getTemp(1); } 287 const LDefinition* getArgVpReg() { return getTemp(2); } 288 const LDefinition* getTempReg() { return getTemp(3); } 289 }; 290 291 class LCallClassHook : public LCallInstructionHelper<BOX_PIECES, 1, 4> { 292 public: 293 LIR_HEADER(CallClassHook) 294 295 LCallClassHook(const LAllocation& callee, const LDefinition& argContext, 296 const LDefinition& argUintN, const LDefinition& argVp, 297 const LDefinition& tmpreg) 298 : LCallInstructionHelper(classOpcode) { 299 setOperand(0, callee); 300 301 // Registers used for callWithABI(). 302 setTemp(0, argContext); 303 setTemp(1, argUintN); 304 setTemp(2, argVp); 305 306 // Temporary registers. 307 setTemp(3, tmpreg); 308 } 309 310 MCallClassHook* mir() const { return mir_->toCallClassHook(); } 311 312 const LAllocation* getCallee() { return this->getOperand(0); } 313 314 const LDefinition* getArgContextReg() { return getTemp(0); } 315 const LDefinition* getArgUintNReg() { return getTemp(1); } 316 const LDefinition* getArgVpReg() { return getTemp(2); } 317 const LDefinition* getTempReg() { return getTemp(3); } 318 }; 319 320 // Generates a hardcoded callsite for a known, DOM-native target. 321 class LCallDOMNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4> { 322 public: 323 LIR_HEADER(CallDOMNative) 324 325 LCallDOMNative(const LDefinition& argJSContext, const LDefinition& argObj, 326 const LDefinition& argPrivate, const LDefinition& argArgs) 327 : LJSCallInstructionHelper(classOpcode) { 328 setTemp(0, argJSContext); 329 setTemp(1, argObj); 330 setTemp(2, argPrivate); 331 setTemp(3, argArgs); 332 } 333 334 const LDefinition* getArgJSContext() { return getTemp(0); } 335 const LDefinition* getArgObj() { return getTemp(1); } 336 const LDefinition* getArgPrivate() { return getTemp(2); } 337 const LDefinition* getArgArgs() { return getTemp(3); } 338 }; 339 340 // Generates a polymorphic callsite, wherein the function being called is 341 // unknown and anticipated to vary. 342 class LApplyArgsGeneric 343 : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2> { 344 public: 345 LIR_HEADER(ApplyArgsGeneric) 346 347 LApplyArgsGeneric(const LAllocation& func, const LAllocation& argc, 348 const LBoxAllocation& thisv, const LDefinition& tmpObjReg, 349 const LDefinition& tmpCopy) 350 : LCallInstructionHelper(classOpcode) { 351 setOperand(0, func); 352 setOperand(1, argc); 353 setBoxOperand(ThisIndex, thisv); 354 setTemp(0, tmpObjReg); 355 setTemp(1, tmpCopy); 356 } 357 358 MApplyArgs* mir() const { return mir_->toApplyArgs(); } 359 360 bool hasSingleTarget() const { return getSingleTarget() != nullptr; } 361 WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); } 362 363 uint32_t numExtraFormals() const { return mir()->numExtraFormals(); } 364 365 const LAllocation* getFunction() { return getOperand(0); } 366 const LAllocation* getArgc() { return getOperand(1); } 367 static const size_t ThisIndex = 2; 368 LBoxAllocation thisValue() const { return getBoxOperand(ThisIndex); } 369 370 const LDefinition* getTempObject() { return getTemp(0); } 371 const LDefinition* getTempForArgCopy() { return getTemp(1); } 372 }; 373 374 class LApplyArgsObj 375 : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2> { 376 public: 377 LIR_HEADER(ApplyArgsObj) 378 379 LApplyArgsObj(const LAllocation& func, const LAllocation& argsObj, 380 const LBoxAllocation& thisv, const LDefinition& tmpObjReg, 381 const LDefinition& tmpCopy) 382 : LCallInstructionHelper(classOpcode) { 383 setOperand(0, func); 384 setOperand(1, argsObj); 385 setBoxOperand(ThisIndex, thisv); 386 setTemp(0, tmpObjReg); 387 setTemp(1, tmpCopy); 388 } 389 390 MApplyArgsObj* mir() const { return mir_->toApplyArgsObj(); } 391 392 bool hasSingleTarget() const { return getSingleTarget() != nullptr; } 393 WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); } 394 395 const LAllocation* getFunction() { return getOperand(0); } 396 const LAllocation* getArgsObj() { return getOperand(1); } 397 // All registers are calltemps. argc is mapped to the same register as 398 // ArgsObj. argc becomes live as ArgsObj is dying. 399 const LAllocation* getArgc() { return getOperand(1); } 400 LBoxAllocation thisValue() const { return getBoxOperand(ThisIndex); } 401 static const size_t ThisIndex = 2; 402 403 const LDefinition* getTempObject() { return getTemp(0); } 404 const LDefinition* getTempForArgCopy() { return getTemp(1); } 405 }; 406 407 class LApplyArrayGeneric 408 : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 2, 2> { 409 public: 410 LIR_HEADER(ApplyArrayGeneric) 411 412 LApplyArrayGeneric(const LAllocation& func, const LAllocation& elements, 413 const LBoxAllocation& thisv, const LDefinition& tmpObjReg, 414 const LDefinition& tmpCopy) 415 : LCallInstructionHelper(classOpcode) { 416 setOperand(0, func); 417 setOperand(1, elements); 418 setBoxOperand(ThisIndex, thisv); 419 setTemp(0, tmpObjReg); 420 setTemp(1, tmpCopy); 421 } 422 423 MApplyArray* mir() const { return mir_->toApplyArray(); } 424 425 bool hasSingleTarget() const { return getSingleTarget() != nullptr; } 426 WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); } 427 428 const LAllocation* getFunction() { return getOperand(0); } 429 const LAllocation* getElements() { return getOperand(1); } 430 // argc is mapped to the same register as elements: argc becomes 431 // live as elements is dying, all registers are calltemps. 432 const LAllocation* getArgc() { return getOperand(1); } 433 LBoxAllocation thisValue() const { return getBoxOperand(ThisIndex); } 434 static const size_t ThisIndex = 2; 435 436 const LDefinition* getTempObject() { return getTemp(0); } 437 const LDefinition* getTempForArgCopy() { return getTemp(1); } 438 }; 439 440 class LConstructArgsGeneric 441 : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 3, 1> { 442 public: 443 LIR_HEADER(ConstructArgsGeneric) 444 445 LConstructArgsGeneric(const LAllocation& func, const LAllocation& argc, 446 const LAllocation& newTarget, 447 const LBoxAllocation& thisv, 448 const LDefinition& tmpObjReg) 449 : LCallInstructionHelper(classOpcode) { 450 setOperand(0, func); 451 setOperand(1, argc); 452 setOperand(2, newTarget); 453 setBoxOperand(ThisIndex, thisv); 454 setTemp(0, tmpObjReg); 455 } 456 457 MConstructArgs* mir() const { return mir_->toConstructArgs(); } 458 459 bool hasSingleTarget() const { return getSingleTarget() != nullptr; } 460 WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); } 461 462 uint32_t numExtraFormals() const { return mir()->numExtraFormals(); } 463 464 const LAllocation* getFunction() { return getOperand(0); } 465 const LAllocation* getArgc() { return getOperand(1); } 466 const LAllocation* getNewTarget() { return getOperand(2); } 467 LBoxAllocation thisValue() const { return getBoxOperand(ThisIndex); } 468 469 static const size_t ThisIndex = 3; 470 471 const LDefinition* getTempObject() { return getTemp(0); } 472 473 // tempForArgCopy is mapped to the same register as newTarget: 474 // tempForArgCopy becomes live as newTarget is dying, all registers are 475 // calltemps. 476 const LAllocation* getTempForArgCopy() { return getOperand(2); } 477 }; 478 479 class LConstructArrayGeneric 480 : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 3, 1> { 481 public: 482 LIR_HEADER(ConstructArrayGeneric) 483 484 LConstructArrayGeneric(const LAllocation& func, const LAllocation& elements, 485 const LAllocation& newTarget, 486 const LBoxAllocation& thisv, 487 const LDefinition& tmpObjReg) 488 : LCallInstructionHelper(classOpcode) { 489 setOperand(0, func); 490 setOperand(1, elements); 491 setOperand(2, newTarget); 492 setBoxOperand(ThisIndex, thisv); 493 setTemp(0, tmpObjReg); 494 } 495 496 MConstructArray* mir() const { return mir_->toConstructArray(); } 497 498 bool hasSingleTarget() const { return getSingleTarget() != nullptr; } 499 WrappedFunction* getSingleTarget() const { return mir()->getSingleTarget(); } 500 501 const LAllocation* getFunction() { return getOperand(0); } 502 const LAllocation* getElements() { return getOperand(1); } 503 const LAllocation* getNewTarget() { return getOperand(2); } 504 LBoxAllocation thisValue() const { return getBoxOperand(ThisIndex); } 505 506 static const size_t ThisIndex = 3; 507 508 const LDefinition* getTempObject() { return getTemp(0); } 509 510 // argc is mapped to the same register as elements: argc becomes 511 // live as elements is dying, all registers are calltemps. 512 const LAllocation* getArgc() { return getOperand(1); } 513 514 // tempForArgCopy is mapped to the same register as newTarget: 515 // tempForArgCopy becomes live as newTarget is dying, all registers are 516 // calltemps. 517 const LAllocation* getTempForArgCopy() { return getOperand(2); } 518 }; 519 520 class LApplyArgsNative 521 : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 1, 3> { 522 public: 523 LIR_HEADER(ApplyArgsNative) 524 525 LApplyArgsNative(const LAllocation& argc, const LBoxAllocation& thisv, 526 const LDefinition& tmpObjReg, const LDefinition& tmpCopy, 527 const LDefinition& tmpExtra) 528 : LCallInstructionHelper(classOpcode) { 529 setOperand(0, argc); 530 setBoxOperand(ThisIndex, thisv); 531 setTemp(0, tmpObjReg); 532 setTemp(1, tmpCopy); 533 setTemp(2, tmpExtra); 534 } 535 536 static constexpr bool isConstructing() { return false; } 537 538 MApplyArgs* mir() const { return mir_->toApplyArgs(); } 539 540 uint32_t numExtraFormals() const { return mir()->numExtraFormals(); } 541 542 const LAllocation* getArgc() { return getOperand(0); } 543 LBoxAllocation thisValue() const { return getBoxOperand(ThisIndex); } 544 545 static const size_t ThisIndex = 1; 546 547 const LDefinition* getTempObject() { return getTemp(0); } 548 const LDefinition* getTempForArgCopy() { return getTemp(1); } 549 const LDefinition* getTempExtra() { return getTemp(2); } 550 }; 551 552 class LApplyArgsObjNative 553 : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 1, 3> { 554 public: 555 LIR_HEADER(ApplyArgsObjNative) 556 557 LApplyArgsObjNative(const LAllocation& argsObj, const LBoxAllocation& thisv, 558 const LDefinition& tmpObjReg, const LDefinition& tmpCopy, 559 const LDefinition& tmpExtra) 560 : LCallInstructionHelper(classOpcode) { 561 setOperand(0, argsObj); 562 setBoxOperand(ThisIndex, thisv); 563 setTemp(0, tmpObjReg); 564 setTemp(1, tmpCopy); 565 setTemp(2, tmpExtra); 566 } 567 568 static constexpr bool isConstructing() { return false; } 569 570 MApplyArgsObj* mir() const { return mir_->toApplyArgsObj(); } 571 572 const LAllocation* getArgsObj() { return getOperand(0); } 573 LBoxAllocation thisValue() const { return getBoxOperand(ThisIndex); } 574 575 static const size_t ThisIndex = 1; 576 577 const LDefinition* getTempObject() { return getTemp(0); } 578 const LDefinition* getTempForArgCopy() { return getTemp(1); } 579 const LDefinition* getTempExtra() { return getTemp(2); } 580 581 // argc is mapped to the same register as argsObj: argc becomes live as 582 // argsObj is dying, all registers are calltemps. 583 const LAllocation* getArgc() { return getOperand(0); } 584 }; 585 586 class LApplyArrayNative 587 : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES + 1, 3> { 588 public: 589 LIR_HEADER(ApplyArrayNative) 590 591 LApplyArrayNative(const LAllocation& elements, const LBoxAllocation& thisv, 592 const LDefinition& tmpObjReg, const LDefinition& tmpCopy, 593 const LDefinition& tmpExtra) 594 : LCallInstructionHelper(classOpcode) { 595 setOperand(0, elements); 596 setBoxOperand(ThisIndex, thisv); 597 setTemp(0, tmpObjReg); 598 setTemp(1, tmpCopy); 599 setTemp(2, tmpExtra); 600 } 601 602 static constexpr bool isConstructing() { return false; } 603 604 MApplyArray* mir() const { return mir_->toApplyArray(); } 605 606 const LAllocation* getElements() { return getOperand(0); } 607 LBoxAllocation thisValue() const { return getBoxOperand(ThisIndex); } 608 609 static const size_t ThisIndex = 1; 610 611 const LDefinition* getTempObject() { return getTemp(0); } 612 const LDefinition* getTempForArgCopy() { return getTemp(1); } 613 const LDefinition* getTempExtra() { return getTemp(2); } 614 615 // argc is mapped to the same register as elements: argc becomes live as 616 // elements is dying, all registers are calltemps. 617 const LAllocation* getArgc() { return getOperand(0); } 618 }; 619 620 class LConstructArgsNative : public LCallInstructionHelper<BOX_PIECES, 2, 3> { 621 public: 622 LIR_HEADER(ConstructArgsNative) 623 624 LConstructArgsNative(const LAllocation& argc, const LAllocation& newTarget, 625 const LDefinition& tmpObjReg, const LDefinition& tmpCopy, 626 const LDefinition& tmpExtra) 627 : LCallInstructionHelper(classOpcode) { 628 setOperand(0, argc); 629 setOperand(1, newTarget); 630 setTemp(0, tmpObjReg); 631 setTemp(1, tmpCopy); 632 setTemp(2, tmpExtra); 633 } 634 635 static constexpr bool isConstructing() { return true; } 636 637 MConstructArgs* mir() const { return mir_->toConstructArgs(); } 638 639 uint32_t numExtraFormals() const { return mir()->numExtraFormals(); } 640 641 const LAllocation* getArgc() { return getOperand(0); } 642 const LAllocation* getNewTarget() { return getOperand(1); } 643 644 const LDefinition* getTempObject() { return getTemp(0); } 645 const LDefinition* getTempForArgCopy() { return getTemp(1); } 646 const LDefinition* getTempExtra() { return getTemp(2); } 647 }; 648 649 class LConstructArrayNative : public LCallInstructionHelper<BOX_PIECES, 2, 3> { 650 public: 651 LIR_HEADER(ConstructArrayNative) 652 653 LConstructArrayNative(const LAllocation& elements, 654 const LAllocation& newTarget, 655 const LDefinition& tmpObjReg, 656 const LDefinition& tmpCopy, const LDefinition& tmpExtra) 657 : LCallInstructionHelper(classOpcode) { 658 setOperand(0, elements); 659 setOperand(1, newTarget); 660 setTemp(0, tmpObjReg); 661 setTemp(1, tmpCopy); 662 setTemp(2, tmpExtra); 663 } 664 665 static constexpr bool isConstructing() { return true; } 666 667 MConstructArray* mir() const { return mir_->toConstructArray(); } 668 669 const LAllocation* getElements() { return getOperand(0); } 670 const LAllocation* getNewTarget() { return getOperand(1); } 671 672 const LDefinition* getTempObject() { return getTemp(0); } 673 const LDefinition* getTempForArgCopy() { return getTemp(1); } 674 const LDefinition* getTempExtra() { return getTemp(2); } 675 676 // argc is mapped to the same register as elements: argc becomes live as 677 // elements is dying, all registers are calltemps. 678 const LAllocation* getArgc() { return getOperand(0); } 679 }; 680 681 // Returns from the function being compiled (not used in inlined frames). The 682 // input must be a box. 683 class LReturn : public LInstructionHelper<0, BOX_PIECES, 0> { 684 bool isGenerator_; 685 686 public: 687 LIR_HEADER(Return) 688 689 explicit LReturn(bool isGenerator) 690 : LInstructionHelper(classOpcode), isGenerator_(isGenerator) {} 691 692 bool isGenerator() { return isGenerator_; } 693 }; 694 695 class LHypot : public LCallInstructionHelper<1, 4, 0> { 696 uint32_t numOperands_; 697 698 public: 699 LIR_HEADER(Hypot) 700 LHypot(const LAllocation& x, const LAllocation& y) 701 : LCallInstructionHelper(classOpcode), numOperands_(2) { 702 setOperand(0, x); 703 setOperand(1, y); 704 } 705 706 LHypot(const LAllocation& x, const LAllocation& y, const LAllocation& z) 707 : LCallInstructionHelper(classOpcode), numOperands_(3) { 708 setOperand(0, x); 709 setOperand(1, y); 710 setOperand(2, z); 711 } 712 713 LHypot(const LAllocation& x, const LAllocation& y, const LAllocation& z, 714 const LAllocation& w) 715 : LCallInstructionHelper(classOpcode), numOperands_(4) { 716 setOperand(0, x); 717 setOperand(1, y); 718 setOperand(2, z); 719 setOperand(3, w); 720 } 721 722 uint32_t numArgs() const { return numOperands_; } 723 724 const LAllocation* x() { return getOperand(0); } 725 726 const LAllocation* y() { return getOperand(1); } 727 }; 728 729 // Adds two integers, returning an integer value. 730 class LAddI : public LBinaryMath<0> { 731 bool recoversInput_; 732 733 public: 734 LIR_HEADER(AddI) 735 736 LAddI() : LBinaryMath(classOpcode), recoversInput_(false) {} 737 738 const char* extraName() const { 739 return snapshot() ? "OverflowCheck" : nullptr; 740 } 741 742 bool recoversInput() const { return recoversInput_; } 743 void setRecoversInput() { recoversInput_ = true; } 744 745 MAdd* mir() const { return mir_->toAdd(); } 746 }; 747 748 // Subtracts two integers, returning an integer value. 749 class LSubI : public LBinaryMath<0> { 750 bool recoversInput_; 751 752 public: 753 LIR_HEADER(SubI) 754 755 LSubI() : LBinaryMath(classOpcode), recoversInput_(false) {} 756 757 const char* extraName() const { 758 return snapshot() ? "OverflowCheck" : nullptr; 759 } 760 761 bool recoversInput() const { return recoversInput_; } 762 void setRecoversInput() { recoversInput_ = true; } 763 MSub* mir() const { return mir_->toSub(); } 764 }; 765 766 inline bool LNode::recoversInput() const { 767 switch (op()) { 768 case Opcode::AddI: 769 return toAddI()->recoversInput(); 770 case Opcode::SubI: 771 return toSubI()->recoversInput(); 772 default: 773 return false; 774 } 775 } 776 777 // Passed the BaselineFrame address in the OsrFrameReg via the IonOsrTempData 778 // populated by PrepareOsrTempData. 779 // 780 // Forwards this object to the LOsrValues for Value materialization. 781 class LOsrEntry : public LInstructionHelper<1, 0, 1> { 782 protected: 783 Label label_; 784 uint32_t frameDepth_; 785 786 public: 787 LIR_HEADER(OsrEntry) 788 789 explicit LOsrEntry(const LDefinition& temp) 790 : LInstructionHelper(classOpcode), frameDepth_(0) { 791 setTemp(0, temp); 792 } 793 794 void setFrameDepth(uint32_t depth) { frameDepth_ = depth; } 795 uint32_t getFrameDepth() { return frameDepth_; } 796 Label* label() { return &label_; } 797 const LDefinition* temp() { return getTemp(0); } 798 }; 799 800 // This is used only with LWasmCall. 801 class LWasmCallIndirectAdjunctSafepoint : public LInstructionHelper<0, 0, 0> { 802 CodeOffset offs_; 803 uint32_t framePushedAtStackMapBase_; 804 805 public: 806 LIR_HEADER(WasmCallIndirectAdjunctSafepoint); 807 808 LWasmCallIndirectAdjunctSafepoint() 809 : LInstructionHelper(classOpcode), 810 offs_(0), 811 framePushedAtStackMapBase_(0) { 812 // Ensure that the safepoint does not get live registers associated with it. 813 setIsCall(); 814 } 815 816 CodeOffset safepointLocation() const { 817 MOZ_ASSERT(offs_.offset() != 0); 818 return offs_; 819 } 820 uint32_t framePushedAtStackMapBase() const { 821 MOZ_ASSERT(offs_.offset() != 0); 822 return framePushedAtStackMapBase_; 823 } 824 void recordSafepointInfo(CodeOffset offs, uint32_t framePushed) { 825 offs_ = offs; 826 framePushedAtStackMapBase_ = framePushed; 827 } 828 }; 829 830 // LWasmCall may be generated into two function calls in the case of 831 // call_indirect, one for the fast path and one for the slow path. In that 832 // case, the node carries a pointer to a companion node, the "adjunct 833 // safepoint", representing the safepoint for the second of the two calls. The 834 // dual-call construction is only meaningful for wasm because wasm has no 835 // invalidation of code; this is not a pattern to be used generally. 836 class LWasmCall : public LVariadicInstruction<0, 0> { 837 LWasmCallIndirectAdjunctSafepoint* adjunctSafepoint_; 838 839 public: 840 LIR_HEADER(WasmCall); 841 842 explicit LWasmCall(uint32_t numOperands) 843 : LVariadicInstruction(classOpcode, numOperands), 844 adjunctSafepoint_(nullptr) { 845 this->setIsCall(); 846 } 847 848 MWasmCallBase* callBase() const { 849 if (isCatchable() && !isReturnCall()) { 850 return static_cast<MWasmCallBase*>(mirCatchable()); 851 } 852 if (isReturnCall()) { 853 return static_cast<MWasmReturnCall*>(mirReturnCall()); 854 } 855 return static_cast<MWasmCallBase*>(mirUncatchable()); 856 } 857 bool isCatchable() const { return mir_->isWasmCallCatchable(); } 858 bool isReturnCall() const { return mir_->isWasmReturnCall(); } 859 MWasmCallCatchable* mirCatchable() const { 860 return mir_->toWasmCallCatchable(); 861 } 862 MWasmCallUncatchable* mirUncatchable() const { 863 return mir_->toWasmCallUncatchable(); 864 } 865 MWasmReturnCall* mirReturnCall() const { return mir_->toWasmReturnCall(); } 866 867 static bool isCallPreserved(AnyRegister reg) { 868 // All MWasmCalls preserve the TLS register: 869 // - internal/indirect calls do by the internal wasm ABI 870 // - import calls do by explicitly saving/restoring at the callsite 871 // - builtin calls do because the TLS reg is non-volatile 872 // See also CodeGeneratorShared::emitWasmCall. 873 // 874 // All other registers are not preserved. This is is relied upon by 875 // MWasmCallCatchable which needs all live registers to be spilled before 876 // a call. 877 return !reg.isFloat() && reg.gpr() == InstanceReg; 878 } 879 880 LWasmCallIndirectAdjunctSafepoint* adjunctSafepoint() const { 881 MOZ_ASSERT(adjunctSafepoint_ != nullptr); 882 return adjunctSafepoint_; 883 } 884 void setAdjunctSafepoint(LWasmCallIndirectAdjunctSafepoint* asp) { 885 adjunctSafepoint_ = asp; 886 } 887 }; 888 889 class LWasmRegisterResult : public LInstructionHelper<1, 0, 0> { 890 public: 891 LIR_HEADER(WasmRegisterResult); 892 893 LWasmRegisterResult() : LInstructionHelper(classOpcode) {} 894 895 MWasmRegisterResult* mir() const { 896 if (!mir_->isWasmRegisterResult()) { 897 return nullptr; 898 } 899 return mir_->toWasmRegisterResult(); 900 } 901 }; 902 903 class LWasmRegisterPairResult : public LInstructionHelper<2, 0, 0> { 904 public: 905 LIR_HEADER(WasmRegisterPairResult); 906 907 LWasmRegisterPairResult() : LInstructionHelper(classOpcode) {} 908 909 MDefinition* mir() const { return mirRaw(); } 910 }; 911 912 class LWasmSystemFloatRegisterResult : public LInstructionHelper<1, 0, 0> { 913 public: 914 LIR_HEADER(WasmSystemFloatRegisterResult); 915 916 LWasmSystemFloatRegisterResult() : LInstructionHelper(classOpcode) {} 917 918 MWasmSystemFloatRegisterResult* mir() const { 919 return mir_->toWasmSystemFloatRegisterResult(); 920 } 921 }; 922 923 inline uint32_t LStackArea::base() const { 924 return ins()->toWasmStackResultArea()->mir()->base(); 925 } 926 inline void LStackArea::setBase(uint32_t base) { 927 ins()->toWasmStackResultArea()->mir()->setBase(base); 928 } 929 inline uint32_t LStackArea::size() const { 930 return ins()->toWasmStackResultArea()->mir()->byteSize(); 931 } 932 933 inline bool LStackArea::ResultIterator::done() const { 934 return idx_ == alloc_.ins()->toWasmStackResultArea()->mir()->resultCount(); 935 } 936 inline void LStackArea::ResultIterator::next() { 937 MOZ_ASSERT(!done()); 938 idx_++; 939 } 940 inline LAllocation LStackArea::ResultIterator::alloc() const { 941 MOZ_ASSERT(!done()); 942 MWasmStackResultArea* area = alloc_.ins()->toWasmStackResultArea()->mir(); 943 const auto& stackResult = area->result(idx_); 944 MIRType type = stackResult.type(); 945 auto width = 946 #ifndef JS_PUNBOX64 947 type == MIRType::Int64 ? LStackSlot::DoubleWord : 948 #endif 949 LStackSlot::width(LDefinition::TypeFrom(type)); 950 return LStackSlot(area->base() - stackResult.offset(), width); 951 } 952 inline bool LStackArea::ResultIterator::isWasmAnyRef() const { 953 MOZ_ASSERT(!done()); 954 MWasmStackResultArea* area = alloc_.ins()->toWasmStackResultArea()->mir(); 955 MIRType type = area->result(idx_).type(); 956 #ifndef JS_PUNBOX64 957 // LDefinition::TypeFrom isn't defined for MIRType::Int64 values on 958 // this platform, so here we have a special case. 959 if (type == MIRType::Int64) { 960 return false; 961 } 962 #endif 963 return LDefinition::TypeFrom(type) == LDefinition::WASM_ANYREF; 964 } 965 966 class LWasmStackResult : public LInstructionHelper<1, 1, 0> { 967 public: 968 LIR_HEADER(WasmStackResult); 969 970 LWasmStackResult() : LInstructionHelper(classOpcode) {} 971 972 MWasmStackResult* mir() const { return mir_->toWasmStackResult(); } 973 LStackSlot result(uint32_t base) const { 974 auto width = LStackSlot::width(LDefinition::TypeFrom(mir()->type())); 975 return LStackSlot(base - mir()->result().offset(), width); 976 } 977 }; 978 979 class LWasmStackResult64 : public LInstructionHelper<INT64_PIECES, 1, 0> { 980 public: 981 LIR_HEADER(WasmStackResult64); 982 983 LWasmStackResult64() : LInstructionHelper(classOpcode) {} 984 985 MWasmStackResult* mir() const { return mir_->toWasmStackResult(); } 986 LStackSlot result(uint32_t base, LDefinition* def) { 987 uint32_t offset = base - mir()->result().offset(); 988 #if defined(JS_NUNBOX32) 989 if (def == getDef(INT64LOW_INDEX)) { 990 offset -= INT64LOW_OFFSET; 991 } else { 992 MOZ_ASSERT(def == getDef(INT64HIGH_INDEX)); 993 offset -= INT64HIGH_OFFSET; 994 } 995 #else 996 MOZ_ASSERT(def == getDef(0)); 997 #endif 998 return LStackSlot(offset, LStackSlot::DoubleWord); 999 } 1000 }; 1001 1002 inline LStackSlot LStackArea::resultAlloc(LInstruction* lir, 1003 LDefinition* def) const { 1004 if (lir->isWasmStackResult64()) { 1005 return lir->toWasmStackResult64()->result(base(), def); 1006 } 1007 MOZ_ASSERT(def == lir->getDef(0)); 1008 return lir->toWasmStackResult()->result(base()); 1009 } 1010 1011 inline bool LNode::isCallPreserved(AnyRegister reg) const { 1012 return isWasmCall() && LWasmCall::isCallPreserved(reg); 1013 } 1014 1015 template <size_t NumDefs> 1016 class LIonToWasmCallBase : public LVariadicInstruction<NumDefs, 1> { 1017 using Base = LVariadicInstruction<NumDefs, 1>; 1018 1019 public: 1020 explicit LIonToWasmCallBase(LNode::Opcode classOpcode, uint32_t numOperands, 1021 const LDefinition& temp) 1022 : Base(classOpcode, numOperands) { 1023 this->setIsCall(); 1024 this->setTemp(0, temp); 1025 } 1026 MIonToWasmCall* mir() const { return this->mir_->toIonToWasmCall(); } 1027 const LDefinition* temp() { return this->getTemp(0); } 1028 }; 1029 1030 class LIonToWasmCall : public LIonToWasmCallBase<1> { 1031 public: 1032 LIR_HEADER(IonToWasmCall); 1033 LIonToWasmCall(uint32_t numOperands, const LDefinition& temp) 1034 : LIonToWasmCallBase<1>(classOpcode, numOperands, temp) {} 1035 }; 1036 1037 class LIonToWasmCallV : public LIonToWasmCallBase<BOX_PIECES> { 1038 public: 1039 LIR_HEADER(IonToWasmCallV); 1040 LIonToWasmCallV(uint32_t numOperands, const LDefinition& temp) 1041 : LIonToWasmCallBase<BOX_PIECES>(classOpcode, numOperands, temp) {} 1042 }; 1043 1044 class LIonToWasmCallI64 : public LIonToWasmCallBase<INT64_PIECES> { 1045 public: 1046 LIR_HEADER(IonToWasmCallI64); 1047 LIonToWasmCallI64(uint32_t numOperands, const LDefinition& temp) 1048 : LIonToWasmCallBase<INT64_PIECES>(classOpcode, numOperands, temp) {} 1049 }; 1050 1051 // Definitions for `extraName` methods of generated LIR instructions. 1052 1053 #ifdef JS_JITSPEW 1054 const char* LBox::extraName() const { return StringFromMIRType(type_); } 1055 1056 const char* LNewArray::extraName() const { 1057 return mir()->isVMCall() ? "VMCall" : nullptr; 1058 } 1059 1060 const char* LNewObject::extraName() const { 1061 return mir()->isVMCall() ? "VMCall" : nullptr; 1062 } 1063 1064 const char* LCompare::extraName() const { return CodeName(jsop_); } 1065 1066 const char* LCompareI64::extraName() const { return CodeName(jsop_); } 1067 1068 const char* LCompareI64AndBranch::extraName() const { return CodeName(jsop_); } 1069 1070 const char* LCompareAndBranch::extraName() const { return CodeName(jsop_); } 1071 1072 const char* LStrictConstantCompareInt32AndBranch::extraName() const { 1073 return CodeName(cmpMir()->jsop()); 1074 } 1075 1076 const char* LStrictConstantCompareBooleanAndBranch::extraName() const { 1077 return CodeName(cmpMir()->jsop()); 1078 } 1079 1080 const char* LMathFunctionD::extraName() const { 1081 return MMathFunction::FunctionName(mir()->function()); 1082 } 1083 1084 const char* LMathFunctionF::extraName() const { 1085 return MMathFunction::FunctionName(mir()->function()); 1086 } 1087 1088 const char* LStoreElementV::extraName() const { 1089 return mir()->needsHoleCheck() ? "HoleCheck" : nullptr; 1090 } 1091 1092 const char* LStoreElementT::extraName() const { 1093 return mir()->needsHoleCheck() ? "HoleCheck" : nullptr; 1094 } 1095 1096 const char* LArrayPopShift::extraName() const { 1097 return mir()->mode() == MArrayPopShift::Pop ? "Pop" : "Shift"; 1098 } 1099 1100 const char* LMinMaxI::extraName() const { 1101 return mir()->isMax() ? "Max" : "Min"; 1102 } 1103 1104 const char* LMinMaxIntPtr::extraName() const { 1105 return mir()->isMax() ? "Max" : "Min"; 1106 } 1107 1108 const char* LMinMaxD::extraName() const { 1109 return mir()->isMax() ? "Max" : "Min"; 1110 } 1111 1112 const char* LMinMaxF::extraName() const { 1113 return mir()->isMax() ? "Max" : "Min"; 1114 } 1115 1116 const char* LMulI::extraName() const { 1117 return (mir()->mode() == MMul::Integer) 1118 ? "Integer" 1119 : (mir()->canBeNegativeZero() ? "CanBeNegativeZero" : nullptr); 1120 } 1121 1122 const char* LDivI::extraName() const { 1123 if (mir()->isTruncated()) { 1124 if (mir()->canBeNegativeZero()) { 1125 return mir()->canBeNegativeOverflow() 1126 ? "Truncate_NegativeZero_NegativeOverflow" 1127 : "Truncate_NegativeZero"; 1128 } 1129 return mir()->canBeNegativeOverflow() ? "Truncate_NegativeOverflow" 1130 : "Truncate"; 1131 } 1132 if (mir()->canBeNegativeZero()) { 1133 return mir()->canBeNegativeOverflow() ? "NegativeZero_NegativeOverflow" 1134 : "NegativeZero"; 1135 } 1136 return mir()->canBeNegativeOverflow() ? "NegativeOverflow" : nullptr; 1137 } 1138 1139 const char* LModI::extraName() const { 1140 return mir()->isTruncated() ? "Truncated" : nullptr; 1141 } 1142 1143 const char* LBitOpI::extraName() const { 1144 if (bitop() == JSOp::Ursh && mir_->toUrsh()->bailoutsDisabled()) { 1145 return "ursh:BailoutsDisabled"; 1146 } 1147 return CodeName(bitop_); 1148 } 1149 1150 const char* LBitOpI64::extraName() const { return CodeName(bitop_); } 1151 1152 const char* LShiftI::extraName() const { return CodeName(bitop_); } 1153 1154 const char* LShiftIntPtr::extraName() const { return CodeName(bitop_); } 1155 1156 const char* LShiftI64::extraName() const { return CodeName(bitop_); } 1157 1158 const char* LMathD::extraName() const { return CodeName(jsop_); } 1159 1160 const char* LMathF::extraName() const { return CodeName(jsop_); } 1161 #endif 1162 1163 } // namespace jit 1164 } // namespace js 1165 1166 #endif /* jit_shared_LIR_shared_h */