WarpCacheIRTranspiler.cpp (232357B)
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/WarpCacheIRTranspiler.h" 8 9 #include "mozilla/Casting.h" 10 #include "mozilla/Maybe.h" 11 12 #include "jsmath.h" 13 14 #include "jit/AtomicOp.h" 15 #include "jit/CacheIR.h" 16 #include "jit/CacheIRCompiler.h" 17 #include "jit/CacheIROpsGenerated.h" 18 #include "jit/CacheIRReader.h" 19 #include "jit/LIR.h" 20 #include "jit/MIR-wasm.h" 21 #include "jit/MIR.h" 22 #include "jit/MIRGenerator.h" 23 #include "jit/MIRGraph.h" 24 #include "jit/WarpBuilder.h" 25 #include "jit/WarpBuilderShared.h" 26 #include "jit/WarpSnapshot.h" 27 #include "js/ScalarType.h" // js::Scalar::Type 28 #include "vm/BytecodeLocation.h" 29 #include "vm/ObjectFuse.h" 30 #include "vm/TypeofEqOperand.h" // TypeofEqOperand 31 #include "wasm/WasmCode.h" 32 33 #include "gc/ObjectKind-inl.h" 34 #include "vm/NativeObject-inl.h" 35 #include "wasm/WasmInstance-inl.h" 36 37 using namespace js; 38 using namespace js::jit; 39 40 // The CacheIR transpiler generates MIR from Baseline CacheIR. 41 class MOZ_RAII WarpCacheIRTranspiler : public WarpBuilderShared { 42 WarpBuilder* builder_; 43 BytecodeLocation loc_; 44 const WarpCacheIRBase* cacheIRSnapshot_; 45 const CacheIRStubInfo* stubInfo_; 46 const uint8_t* stubData_; 47 48 // Vector mapping OperandId to corresponding MDefinition. 49 using MDefinitionStackVector = Vector<MDefinition*, 8, SystemAllocPolicy>; 50 MDefinitionStackVector operands_; 51 52 CallInfo* callInfo_; 53 54 // Array mapping call arguments to OperandId. 55 using ArgumentKindArray = 56 mozilla::EnumeratedArray<ArgumentKind, OperandId, 57 size_t(ArgumentKind::NumKinds)>; 58 ArgumentKindArray argumentOperandIds_; 59 60 void setArgumentId(ArgumentKind kind, OperandId id) { 61 MOZ_ASSERT(kind != ArgumentKind::Callee); 62 MOZ_ASSERT(!argumentOperandIds_[kind].valid()); 63 argumentOperandIds_[kind] = id; 64 } 65 66 void updateArgumentsFromOperands(); 67 68 #ifdef DEBUG 69 // Used to assert that there is only one effectful instruction 70 // per stub. And that this instruction has a resume point. 71 MInstruction* effectful_ = nullptr; 72 bool pushedResult_ = false; 73 #endif 74 75 inline void addUnchecked(MInstruction* ins) { 76 current->add(ins); 77 78 // If we have not set a more specific bailout kind, mark this instruction 79 // as transpiled CacheIR. If one of these instructions bails out, we 80 // expect to hit the baseline fallback stub and invalidate the Warp script 81 // in tryAttach. 82 if (ins->bailoutKind() == BailoutKind::Unknown) { 83 ins->setBailoutKind(BailoutKind::TranspiledCacheIR); 84 } 85 } 86 87 inline void add(MInstruction* ins) { 88 MOZ_ASSERT(!ins->isEffectful()); 89 addUnchecked(ins); 90 } 91 92 inline void addEffectful(MInstruction* ins) { 93 MOZ_ASSERT(ins->isEffectful()); 94 MOZ_ASSERT(!effectful_, "Can only have one effectful instruction"); 95 addUnchecked(ins); 96 #ifdef DEBUG 97 effectful_ = ins; 98 #endif 99 } 100 101 // Bypasses all checks in addEffectful. Use with caution! 102 inline void addEffectfulUnsafe(MInstruction* ins) { 103 MOZ_ASSERT(ins->isEffectful()); 104 addUnchecked(ins); 105 } 106 107 [[nodiscard]] bool resumeAfterUnchecked(MInstruction* ins) { 108 return WarpBuilderShared::resumeAfter(ins, loc_); 109 } 110 [[nodiscard]] bool resumeAfter(MInstruction* ins) { 111 MOZ_ASSERT(effectful_ == ins); 112 return resumeAfterUnchecked(ins); 113 } 114 115 // CacheIR instructions writing to the IC's result register (the *Result 116 // instructions) must call this to push the result onto the virtual stack. 117 void pushResult(MDefinition* result) { 118 MOZ_ASSERT(!pushedResult_, "Can't have more than one result"); 119 current->push(result); 120 #ifdef DEBUG 121 pushedResult_ = true; 122 #endif 123 } 124 125 MDefinition* getOperand(OperandId id) const { return operands_[id.id()]; } 126 127 void setOperand(OperandId id, MDefinition* def) { operands_[id.id()] = def; } 128 129 [[nodiscard]] bool defineOperand(OperandId id, MDefinition* def) { 130 MOZ_ASSERT(id.id() == operands_.length()); 131 return operands_.append(def); 132 } 133 134 uintptr_t readStubWord(uint32_t offset) { 135 return stubInfo_->getStubRawWord(stubData_, offset); 136 } 137 138 Shape* shapeStubField(uint32_t offset) { 139 return reinterpret_cast<Shape*>(readStubWord(offset)); 140 } 141 GetterSetter* getterSetterStubField(uint32_t offset) { 142 return reinterpret_cast<GetterSetter*>(readStubWord(offset)); 143 } 144 const JSClass* classStubField(uint32_t offset) { 145 return reinterpret_cast<const JSClass*>(readStubWord(offset)); 146 } 147 JSString* stringStubField(uint32_t offset) { 148 return reinterpret_cast<JSString*>(readStubWord(offset)); 149 } 150 JS::Symbol* symbolStubField(uint32_t offset) { 151 return reinterpret_cast<JS::Symbol*>(readStubWord(offset)); 152 } 153 BaseScript* baseScriptStubField(uint32_t offset) { 154 return reinterpret_cast<BaseScript*>(readStubWord(offset)); 155 } 156 const JSJitInfo* jitInfoStubField(uint32_t offset) { 157 return reinterpret_cast<const JSJitInfo*>(readStubWord(offset)); 158 } 159 JSNative jsnativeStubField(uint32_t offset) { 160 return reinterpret_cast<JSNative>(readStubWord(offset)); 161 } 162 JS::ExpandoAndGeneration* expandoAndGenerationField(uint32_t offset) { 163 return reinterpret_cast<JS::ExpandoAndGeneration*>(readStubWord(offset)); 164 } 165 const wasm::FuncExport* wasmFuncExportField(uint32_t offset) { 166 return reinterpret_cast<const wasm::FuncExport*>(readStubWord(offset)); 167 } 168 NativeIteratorListHead* nativeIteratorListHeadStubField(uint32_t offset) { 169 return reinterpret_cast<NativeIteratorListHead*>(readStubWord(offset)); 170 } 171 size_t* fuseStubField(uint32_t offset) { 172 return reinterpret_cast<size_t*>(readStubWord(offset)); 173 } 174 ObjectFuse* objectFuseStubField(uint32_t offset) { 175 return reinterpret_cast<ObjectFuse*>(readStubWord(offset)); 176 } 177 gc::Heap allocSiteInitialHeapField(uint32_t offset) { 178 uintptr_t word = readStubWord(offset); 179 MOZ_ASSERT(word == uintptr_t(gc::Heap::Default) || 180 word == uintptr_t(gc::Heap::Tenured)); 181 return gc::Heap(word); 182 } 183 const void* rawPointerField(uint32_t offset) { 184 return reinterpret_cast<const void*>(readStubWord(offset)); 185 } 186 jsid idStubField(uint32_t offset) { 187 return jsid::fromRawBits(readStubWord(offset)); 188 } 189 int32_t int32StubField(uint32_t offset) { 190 return static_cast<int32_t>(readStubWord(offset)); 191 } 192 uint32_t uint32StubField(uint32_t offset) { 193 return static_cast<uint32_t>(readStubWord(offset)); 194 } 195 uint64_t uint64StubField(uint32_t offset) { 196 return static_cast<uint64_t>(stubInfo_->getStubRawInt64(stubData_, offset)); 197 } 198 ValueOrNurseryValueIndex valueStubField(uint32_t offset) { 199 uint64_t raw = 200 static_cast<uint64_t>(stubInfo_->getStubRawInt64(stubData_, offset)); 201 Value val = Value::fromRawBits(raw); 202 MOZ_ASSERT_IF(val.isGCThing(), val.toGCThing()->isTenured()); 203 return ValueOrNurseryValueIndex::fromValueOrNurseryIndex(val); 204 } 205 double doubleStubField(uint32_t offset) { 206 uint64_t raw = 207 static_cast<uint64_t>(stubInfo_->getStubRawInt64(stubData_, offset)); 208 return mozilla::BitwiseCast<double>(raw); 209 } 210 211 // This must only be called when the caller knows the object is tenured and 212 // not a nursery index. 213 JSObject* tenuredObjectStubField(uint32_t offset) { 214 WarpObjectField field = WarpObjectField::fromData(readStubWord(offset)); 215 return field.toObject(); 216 } 217 218 // Returns either MConstant or MNurseryIndex. See WarpObjectField. 219 MInstruction* objectStubField(uint32_t offset); 220 221 const JSClass* classForGuardClassKind(GuardClassKind kind); 222 223 [[nodiscard]] bool emitGuardTo(ValOperandId inputId, MIRType type); 224 225 [[nodiscard]] bool emitToString(OperandId inputId, StringOperandId resultId); 226 227 template <typename T> 228 [[nodiscard]] bool emitDoubleBinaryArithResult(NumberOperandId lhsId, 229 NumberOperandId rhsId); 230 231 template <typename T> 232 [[nodiscard]] bool emitInt32BinaryArithResult(Int32OperandId lhsId, 233 Int32OperandId rhsId); 234 235 template <typename T> 236 [[nodiscard]] bool emitBigIntBinaryArithResult(BigIntOperandId lhsId, 237 BigIntOperandId rhsId); 238 239 template <typename T> 240 [[nodiscard]] bool emitBigIntBinaryArithEffectfulResult( 241 BigIntOperandId lhsId, BigIntOperandId rhsId); 242 243 template <typename T> 244 [[nodiscard]] bool emitBigIntUnaryArithResult(BigIntOperandId inputId); 245 246 template <typename T> 247 [[nodiscard]] bool emitBigIntPtrBinaryArith(IntPtrOperandId lhsId, 248 IntPtrOperandId rhsId, 249 IntPtrOperandId resultId); 250 251 [[nodiscard]] bool emitCompareResult(JSOp op, OperandId lhsId, 252 OperandId rhsId, 253 MCompare::CompareType compareType); 254 255 [[nodiscard]] bool emitTruthyResult(OperandId inputId); 256 257 [[nodiscard]] bool emitNewIteratorResult(MNewIterator::Type type, 258 uint32_t templateObjectOffset); 259 260 MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length); 261 262 [[nodiscard]] MInstruction* convertToBoolean(MDefinition* input); 263 264 bool emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind kind, 265 ObjOperandId objId, uint32_t offsetOffset, 266 ValOperandId rhsId, uint32_t newShapeOffset, 267 bool preserveWrapper); 268 269 MInstruction* emitTypedArrayLength(ArrayBufferViewKind viewKind, 270 MDefinition* obj); 271 272 MInstruction* emitDataViewLength(ArrayBufferViewKind viewKind, 273 MDefinition* obj); 274 275 void addDataViewData(ArrayBufferViewKind viewKind, MDefinition* obj, 276 Scalar::Type type, MDefinition** offset, 277 MInstruction** elements); 278 279 [[nodiscard]] bool emitAtomicsBinaryOp( 280 ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId, 281 Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind, 282 AtomicOp op); 283 284 [[nodiscard]] bool emitLoadArgumentSlot(ValOperandId resultId, 285 uint32_t slotIndex); 286 287 // Calls are either Native (native function without a JitEntry), 288 // a DOM Native (native function with a JitInfo OpType::Method), 289 // or Scripted (scripted function or native function with a JitEntry). 290 enum class CallKind { Native, DOM, Scripted }; 291 292 [[nodiscard]] bool updateCallInfo(MDefinition* callee, CallFlags flags); 293 294 [[nodiscard]] bool emitCallFunction( 295 ObjOperandId calleeId, Int32OperandId argcId, 296 mozilla::Maybe<ObjOperandId> thisObjId, CallFlags flags, CallKind kind, 297 mozilla::Maybe<uint32_t> siteOffset = mozilla::Nothing()); 298 [[nodiscard]] bool emitFunApplyArgsObj(WrappedFunction* wrappedTarget, 299 CallFlags flags); 300 301 MDefinition* convertWasmArg(MDefinition* arg, wasm::ValType::Kind kind); 302 303 WrappedFunction* maybeWrappedFunction(MDefinition* callee, CallKind kind, 304 uint16_t nargs, FunctionFlags flags); 305 WrappedFunction* maybeCallTarget(MDefinition* callee, CallKind kind); 306 WrappedFunction* maybeGetterSetterTarget(MDefinition* callee, CallKind kind, 307 uint16_t nargs, FunctionFlags flags); 308 309 bool maybeCreateThis(MDefinition* callee, CallFlags flags, CallKind kind); 310 311 [[nodiscard]] bool emitCallGetterResult(CallKind kind, 312 ValOperandId receiverId, 313 MDefinition* getter, bool sameRealm, 314 uint32_t nargsAndFlagsOffset); 315 [[nodiscard]] bool emitCallSetter(CallKind kind, ObjOperandId receiverId, 316 MDefinition* setter, ValOperandId rhsId, 317 bool sameRealm, 318 uint32_t nargsAndFlagsOffset); 319 320 #ifndef JS_CODEGEN_X86 321 [[nodiscard]] bool emitCallScriptedProxyGetShared( 322 MDefinition* target, MDefinition* receiver, MDefinition* handler, 323 MDefinition* id, MDefinition* trapDef, WrappedFunction* trap); 324 #endif 325 326 CACHE_IR_TRANSPILER_GENERATED 327 328 public: 329 WarpCacheIRTranspiler(WarpBuilder* builder, BytecodeLocation loc, 330 CallInfo* callInfo, 331 const WarpCacheIRBase* cacheIRSnapshot) 332 : WarpBuilderShared(builder->snapshot(), builder->mirGen(), 333 builder->currentBlock()), 334 builder_(builder), 335 loc_(loc), 336 cacheIRSnapshot_(cacheIRSnapshot), 337 stubInfo_(cacheIRSnapshot->stubInfo()), 338 stubData_(cacheIRSnapshot->stubData()), 339 callInfo_(callInfo) {} 340 341 [[nodiscard]] bool transpile(std::initializer_list<MDefinition*> inputs); 342 }; 343 344 bool WarpCacheIRTranspiler::transpile( 345 std::initializer_list<MDefinition*> inputs) { 346 if (!operands_.append(inputs.begin(), inputs.end())) { 347 return false; 348 } 349 350 CacheIRReader reader(stubInfo_); 351 do { 352 CacheOp op = reader.readOp(); 353 switch (op) { 354 #define DEFINE_OP(op, ...) \ 355 case CacheOp::op: \ 356 if (!emit##op(reader)) { \ 357 return false; \ 358 } \ 359 break; 360 CACHE_IR_TRANSPILER_OPS(DEFINE_OP) 361 #undef DEFINE_OP 362 363 default: 364 MOZ_CRASH("Unsupported op"); 365 } 366 } while (reader.more()); 367 368 // Effectful instructions should have a resume point. We allow a limited 369 // number of exceptions: 370 // - MIonToWasmCall: Resumes after MInt64ToBigInt 371 // - MLoadUnboxedScalar: Resumes after MInt64ToBigInt 372 // - MAtomicTypedArrayElementBinop: Resumes after MInt64ToBigInt 373 // - MAtomicExchangeTypedArrayElement: Resumes after MInt64ToBigInt 374 // - MCompareExchangeTypedArrayElement: Resumes after MInt64ToBigInt 375 // - MResizableTypedArrayLength: Resumes after MPostIntPtrConversion 376 // - MResizableDataViewByteLength: Resumes after MPostIntPtrConversion 377 // - MGrowableSharedArrayBufferByteLength: Resumes after MPostIntPtrConversion 378 MOZ_ASSERT_IF(effectful_, 379 effectful_->resumePoint() || effectful_->isIonToWasmCall() || 380 effectful_->isLoadUnboxedScalar() || 381 effectful_->isAtomicTypedArrayElementBinop() || 382 effectful_->isAtomicExchangeTypedArrayElement() || 383 effectful_->isCompareExchangeTypedArrayElement() || 384 effectful_->isResizableTypedArrayLength() || 385 effectful_->isResizableDataViewByteLength() || 386 effectful_->isGrowableSharedArrayBufferByteLength()); 387 return true; 388 } 389 390 MInstruction* WarpCacheIRTranspiler::objectStubField(uint32_t offset) { 391 WarpObjectField field = WarpObjectField::fromData(readStubWord(offset)); 392 393 if (field.isNurseryIndex()) { 394 auto* ins = MNurseryObject::New(alloc(), field.toNurseryIndex()); 395 add(ins); 396 return ins; 397 } 398 399 auto* ins = MConstant::NewObject(alloc(), field.toObject()); 400 add(ins); 401 return ins; 402 } 403 404 bool WarpCacheIRTranspiler::emitGuardClass(ObjOperandId objId, 405 GuardClassKind kind) { 406 MDefinition* def = getOperand(objId); 407 408 MInstruction* ins; 409 if (kind == GuardClassKind::JSFunction) { 410 ins = MGuardToFunction::New(alloc(), def); 411 } else { 412 const JSClass* classp = classForGuardClassKind(kind); 413 ins = MGuardToClass::New(alloc(), def, classp); 414 } 415 416 add(ins); 417 418 setOperand(objId, ins); 419 return true; 420 } 421 422 const JSClass* WarpCacheIRTranspiler::classForGuardClassKind( 423 GuardClassKind kind) { 424 switch (kind) { 425 case GuardClassKind::Array: 426 case GuardClassKind::PlainObject: 427 case GuardClassKind::FixedLengthArrayBuffer: 428 case GuardClassKind::ImmutableArrayBuffer: 429 case GuardClassKind::ResizableArrayBuffer: 430 case GuardClassKind::FixedLengthSharedArrayBuffer: 431 case GuardClassKind::GrowableSharedArrayBuffer: 432 case GuardClassKind::FixedLengthDataView: 433 case GuardClassKind::ImmutableDataView: 434 case GuardClassKind::ResizableDataView: 435 case GuardClassKind::MappedArguments: 436 case GuardClassKind::UnmappedArguments: 437 case GuardClassKind::Set: 438 case GuardClassKind::Map: 439 case GuardClassKind::BoundFunction: 440 case GuardClassKind::Date: 441 case GuardClassKind::WeakMap: 442 case GuardClassKind::WeakSet: 443 return ClassFor(kind); 444 case GuardClassKind::WindowProxy: 445 return mirGen().runtime->maybeWindowProxyClass(); 446 case GuardClassKind::JSFunction: 447 break; 448 } 449 MOZ_CRASH("unexpected kind"); 450 } 451 452 bool WarpCacheIRTranspiler::emitGuardAnyClass(ObjOperandId objId, 453 uint32_t claspOffset) { 454 MDefinition* def = getOperand(objId); 455 const JSClass* classp = classStubField(claspOffset); 456 457 auto* ins = MGuardToClass::New(alloc(), def, classp); 458 add(ins); 459 460 setOperand(objId, ins); 461 return true; 462 } 463 464 bool WarpCacheIRTranspiler::emitGuardShape(ObjOperandId objId, 465 uint32_t shapeOffset) { 466 MDefinition* def = getOperand(objId); 467 468 // No read barrier is required because snapshot data is not weak and is traced 469 // as part of IonCompileTask. 470 Shape* shape = shapeStubField(shapeOffset); 471 472 auto* ins = MGuardShape::New(alloc(), def, shape); 473 add(ins); 474 475 setOperand(objId, ins); 476 return true; 477 } 478 479 bool WarpCacheIRTranspiler::emitGuardFuse(RealmFuses::FuseIndex fuseIndex) { 480 switch (fuseIndex) { 481 case RealmFuses::FuseIndex::OptimizeGetIteratorFuse: 482 case RealmFuses::FuseIndex::OptimizeArraySpeciesFuse: 483 case RealmFuses::FuseIndex::OptimizeTypedArraySpeciesFuse: 484 case RealmFuses::FuseIndex::OptimizeRegExpPrototypeFuse: 485 // This is a no-op because WarpOracle has added a compilation dependency. 486 MOZ_ASSERT(RealmFuses::isInvalidatingFuse(fuseIndex)); 487 return true; 488 default: 489 MOZ_ASSERT(!RealmFuses::isInvalidatingFuse(fuseIndex)); 490 auto* ins = MGuardFuse::New(alloc(), fuseIndex); 491 add(ins); 492 return true; 493 } 494 } 495 496 bool WarpCacheIRTranspiler::emitGuardRuntimeFuse( 497 RuntimeFuses::FuseIndex fuseIndex) { 498 // This is a no-op because WarpOracle has added a compilation dependency. 499 MOZ_ASSERT(RuntimeFuses::isInvalidatingFuse(fuseIndex)); 500 return true; 501 } 502 503 bool WarpCacheIRTranspiler::emitGuardObjectFuseProperty( 504 ObjOperandId objId, uint32_t objFuseOwnerOffset, uint32_t objFuseOffset, 505 uint32_t expectedGenerationOffset, uint32_t propIndexOffset, 506 uint32_t propMaskOffset, bool canUseFastPath) { 507 // A compilation dependency was added by WarpOracle. 508 return true; 509 } 510 511 bool WarpCacheIRTranspiler::emitGuardMultipleShapes(ObjOperandId objId, 512 uint32_t shapesOffset) { 513 MDefinition* def = getOperand(objId); 514 515 // Use MGuardShapeList if we snapshotted the list of shapes on the main 516 // thread. 517 MInstruction* ins; 518 if (cacheIRSnapshot_->is<WarpCacheIRWithShapeList>()) { 519 auto* shapes = cacheIRSnapshot_->as<WarpCacheIRWithShapeList>()->shapes(); 520 ins = MGuardShapeList::New(alloc(), def, shapes); 521 } else { 522 MInstruction* shapeList = objectStubField(shapesOffset); 523 ins = MGuardMultipleShapes::New(alloc(), def, shapeList); 524 ins->setBailoutKind(BailoutKind::StubFoldingGuardMultipleShapes); 525 } 526 add(ins); 527 528 setOperand(objId, ins); 529 return true; 530 } 531 532 bool WarpCacheIRTranspiler::emitGuardMultipleShapesToOffset( 533 ObjOperandId objId, uint32_t shapesOffset, Int32OperandId offsetId) { 534 MDefinition* obj = getOperand(objId); 535 536 // Use MGuardShapeListToOffset if we snapshotted the list of shapes on the 537 // main thread. 538 MInstruction* ins; 539 if (cacheIRSnapshot_->is<WarpCacheIRWithShapeListAndOffsets>()) { 540 auto* shapes = (ShapeListWithOffsetsSnapshot*)cacheIRSnapshot_ 541 ->as<WarpCacheIRWithShapeListAndOffsets>() 542 ->shapes(); 543 ins = MGuardShapeListToOffset::New(alloc(), obj, shapes); 544 } else { 545 MInstruction* shapeList = objectStubField(shapesOffset); 546 ins = MGuardMultipleShapesToOffset::New(alloc(), obj, shapeList); 547 ins->setBailoutKind(BailoutKind::StubFoldingGuardMultipleShapes); 548 } 549 add(ins); 550 551 return defineOperand(offsetId, ins); 552 } 553 554 bool WarpCacheIRTranspiler::emitGuardNullProto(ObjOperandId objId) { 555 MDefinition* def = getOperand(objId); 556 557 auto* ins = MGuardNullProto::New(alloc(), def); 558 add(ins); 559 560 setOperand(objId, ins); 561 return true; 562 } 563 564 bool WarpCacheIRTranspiler::emitGuardIsNativeObject(ObjOperandId objId) { 565 MDefinition* obj = getOperand(objId); 566 567 auto* ins = MGuardIsNativeObject::New(alloc(), obj); 568 add(ins); 569 570 setOperand(objId, ins); 571 return true; 572 } 573 574 bool WarpCacheIRTranspiler::emitGuardIsProxy(ObjOperandId objId) { 575 MDefinition* obj = getOperand(objId); 576 577 auto* ins = MGuardIsProxy::New(alloc(), obj); 578 add(ins); 579 580 setOperand(objId, ins); 581 return true; 582 } 583 584 bool WarpCacheIRTranspiler::emitGuardIsNotProxy(ObjOperandId objId) { 585 MDefinition* obj = getOperand(objId); 586 587 auto* ins = MGuardIsNotProxy::New(alloc(), obj); 588 add(ins); 589 590 setOperand(objId, ins); 591 return true; 592 } 593 594 bool WarpCacheIRTranspiler::emitGuardIsNotDOMProxy(ObjOperandId objId) { 595 MDefinition* obj = getOperand(objId); 596 597 auto* ins = MGuardIsNotDOMProxy::New(alloc(), obj); 598 add(ins); 599 600 setOperand(objId, ins); 601 return true; 602 } 603 604 bool WarpCacheIRTranspiler::emitLoadGetterSetterFunction( 605 ValOperandId getterSetterId, bool isGetter, bool needsClassGuard, 606 ObjOperandId resultId) { 607 MDefinition* getterSetter = getOperand(getterSetterId); 608 609 auto* ins = MLoadGetterSetterFunction::New(alloc(), getterSetter, isGetter, 610 needsClassGuard); 611 add(ins); 612 613 return defineOperand(resultId, ins); 614 } 615 616 bool WarpCacheIRTranspiler::emitGuardHasGetterSetter( 617 ObjOperandId objId, uint32_t idOffset, uint32_t getterSetterOffset) { 618 MDefinition* obj = getOperand(objId); 619 jsid id = idStubField(idOffset); 620 ValueOrNurseryValueIndex val = valueStubField(getterSetterOffset); 621 MOZ_ASSERT_IF(val.isValue(), val.toValue().toGCThing()->is<GetterSetter>()); 622 623 auto* ins = MGuardHasGetterSetter::New(alloc(), obj, id, val); 624 add(ins); 625 626 setOperand(objId, ins); 627 return true; 628 } 629 630 bool WarpCacheIRTranspiler::emitProxyGetResult(ObjOperandId objId, 631 uint32_t idOffset) { 632 MDefinition* obj = getOperand(objId); 633 jsid id = idStubField(idOffset); 634 635 auto* ins = MProxyGet::New(alloc(), obj, id); 636 addEffectful(ins); 637 638 pushResult(ins); 639 return resumeAfter(ins); 640 } 641 642 bool WarpCacheIRTranspiler::emitProxyGetByValueResult(ObjOperandId objId, 643 ValOperandId idId) { 644 MDefinition* obj = getOperand(objId); 645 MDefinition* id = getOperand(idId); 646 647 auto* ins = MProxyGetByValue::New(alloc(), obj, id); 648 addEffectful(ins); 649 650 pushResult(ins); 651 return resumeAfter(ins); 652 } 653 654 bool WarpCacheIRTranspiler::emitProxyHasPropResult(ObjOperandId objId, 655 ValOperandId idId, 656 bool hasOwn) { 657 MDefinition* obj = getOperand(objId); 658 MDefinition* id = getOperand(idId); 659 660 auto* ins = MProxyHasProp::New(alloc(), obj, id, hasOwn); 661 addEffectful(ins); 662 663 pushResult(ins); 664 return resumeAfter(ins); 665 } 666 667 bool WarpCacheIRTranspiler::emitProxySet(ObjOperandId objId, uint32_t idOffset, 668 ValOperandId rhsId, bool strict) { 669 MDefinition* obj = getOperand(objId); 670 jsid id = idStubField(idOffset); 671 MDefinition* rhs = getOperand(rhsId); 672 673 auto* ins = MProxySet::New(alloc(), obj, rhs, id, strict); 674 addEffectful(ins); 675 676 return resumeAfter(ins); 677 } 678 679 bool WarpCacheIRTranspiler::emitProxySetByValue(ObjOperandId objId, 680 ValOperandId idId, 681 ValOperandId rhsId, 682 bool strict) { 683 MDefinition* obj = getOperand(objId); 684 MDefinition* id = getOperand(idId); 685 MDefinition* rhs = getOperand(rhsId); 686 687 auto* ins = MProxySetByValue::New(alloc(), obj, id, rhs, strict); 688 addEffectful(ins); 689 690 return resumeAfter(ins); 691 } 692 693 bool WarpCacheIRTranspiler::emitCallSetArrayLength(ObjOperandId objId, 694 bool strict, 695 ValOperandId rhsId) { 696 MDefinition* obj = getOperand(objId); 697 MDefinition* rhs = getOperand(rhsId); 698 699 auto* ins = MCallSetArrayLength::New(alloc(), obj, rhs, strict); 700 addEffectful(ins); 701 702 return resumeAfter(ins); 703 } 704 705 bool WarpCacheIRTranspiler::emitCallDOMGetterResult(ObjOperandId objId, 706 uint32_t jitInfoOffset) { 707 MDefinition* obj = getOperand(objId); 708 const JSJitInfo* jitInfo = jitInfoStubField(jitInfoOffset); 709 710 MInstruction* ins; 711 if (jitInfo->isAlwaysInSlot) { 712 ins = MGetDOMMember::New(alloc(), jitInfo, obj, nullptr, nullptr); 713 } else { 714 // TODO(post-Warp): realms, guard operands (movable?). 715 ins = MGetDOMProperty::New(alloc(), jitInfo, DOMObjectKind::Native, 716 (JS::Realm*)mirGen().realm->realmPtr(), obj, 717 nullptr, nullptr); 718 } 719 720 if (!ins) { 721 return false; 722 } 723 724 if (ins->isEffectful()) { 725 addEffectful(ins); 726 pushResult(ins); 727 return resumeAfter(ins); 728 } 729 730 add(ins); 731 pushResult(ins); 732 return true; 733 } 734 735 bool WarpCacheIRTranspiler::emitCallDOMSetter(ObjOperandId objId, 736 uint32_t jitInfoOffset, 737 ValOperandId rhsId) { 738 MDefinition* obj = getOperand(objId); 739 const JSJitInfo* jitInfo = jitInfoStubField(jitInfoOffset); 740 MDefinition* value = getOperand(rhsId); 741 742 MOZ_ASSERT(jitInfo->type() == JSJitInfo::Setter); 743 auto* set = 744 MSetDOMProperty::New(alloc(), jitInfo->setter, DOMObjectKind::Native, 745 (JS::Realm*)mirGen().realm->realmPtr(), obj, value); 746 addEffectful(set); 747 return resumeAfter(set); 748 } 749 750 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValue(ObjOperandId objId, 751 ValOperandId resultId) { 752 MDefinition* proxy = getOperand(objId); 753 754 auto* ins = MLoadDOMExpandoValue::New(alloc(), proxy); 755 add(ins); 756 757 return defineOperand(resultId, ins); 758 } 759 760 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValueGuardGeneration( 761 ObjOperandId objId, uint32_t expandoAndGenerationOffset, 762 uint32_t generationOffset, ValOperandId resultId) { 763 MDefinition* proxy = getOperand(objId); 764 JS::ExpandoAndGeneration* expandoAndGeneration = 765 expandoAndGenerationField(expandoAndGenerationOffset); 766 uint64_t generation = uint64StubField(generationOffset); 767 768 auto* ins = MLoadDOMExpandoValueGuardGeneration::New( 769 alloc(), proxy, expandoAndGeneration, generation); 770 add(ins); 771 772 return defineOperand(resultId, ins); 773 } 774 775 bool WarpCacheIRTranspiler::emitLoadDOMExpandoValueIgnoreGeneration( 776 ObjOperandId objId, ValOperandId resultId) { 777 MDefinition* proxy = getOperand(objId); 778 779 auto* ins = MLoadDOMExpandoValueIgnoreGeneration::New(alloc(), proxy); 780 add(ins); 781 782 return defineOperand(resultId, ins); 783 } 784 785 bool WarpCacheIRTranspiler::emitGuardDOMExpandoMissingOrGuardShape( 786 ValOperandId expandoId, uint32_t shapeOffset) { 787 MDefinition* expando = getOperand(expandoId); 788 Shape* shape = shapeStubField(shapeOffset); 789 790 auto* ins = MGuardDOMExpandoMissingOrGuardShape::New(alloc(), expando, shape); 791 add(ins); 792 793 setOperand(expandoId, ins); 794 return true; 795 } 796 797 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotResult(ObjOperandId objId, 798 uint32_t nameOffset) { 799 MDefinition* obj = getOperand(objId); 800 PropertyName* name = stringStubField(nameOffset)->asAtom().asPropertyName(); 801 802 auto* ins = MMegamorphicLoadSlot::New(alloc(), obj, NameToId(name)); 803 804 add(ins); 805 pushResult(ins); 806 return true; 807 } 808 809 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotPermissiveResult( 810 ObjOperandId objId, uint32_t nameOffset) { 811 MDefinition* obj = getOperand(objId); 812 PropertyName* name = stringStubField(nameOffset)->asAtom().asPropertyName(); 813 814 auto* ins = MMegamorphicLoadSlotPermissive::New(alloc(), obj, NameToId(name)); 815 816 addEffectful(ins); 817 pushResult(ins); 818 return resumeAfter(ins); 819 } 820 821 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotByValueResult( 822 ObjOperandId objId, ValOperandId idId) { 823 MDefinition* obj = getOperand(objId); 824 MDefinition* id = getOperand(idId); 825 826 auto* ins = MMegamorphicLoadSlotByValue::New(alloc(), obj, id); 827 828 add(ins); 829 pushResult(ins); 830 return true; 831 } 832 833 bool WarpCacheIRTranspiler::emitMegamorphicLoadSlotByValuePermissiveResult( 834 ObjOperandId objId, ValOperandId idId) { 835 MDefinition* obj = getOperand(objId); 836 MDefinition* id = getOperand(idId); 837 838 auto* ins = MMegamorphicLoadSlotByValuePermissive::New(alloc(), obj, id); 839 840 addEffectful(ins); 841 pushResult(ins); 842 return resumeAfter(ins); 843 } 844 845 bool WarpCacheIRTranspiler::emitMegamorphicStoreSlot(ObjOperandId objId, 846 uint32_t idOffset, 847 ValOperandId rhsId, 848 bool strict) { 849 MDefinition* obj = getOperand(objId); 850 jsid id = idStubField(idOffset); 851 MDefinition* rhs = getOperand(rhsId); 852 853 auto* ins = MMegamorphicStoreSlot::New(alloc(), obj, rhs, id, strict); 854 addEffectful(ins); 855 856 return resumeAfter(ins); 857 } 858 859 bool WarpCacheIRTranspiler::emitMegamorphicHasPropResult(ObjOperandId objId, 860 ValOperandId idId, 861 bool hasOwn) { 862 MDefinition* obj = getOperand(objId); 863 MDefinition* id = getOperand(idId); 864 865 auto* ins = MMegamorphicHasProp::New(alloc(), obj, id, hasOwn); 866 add(ins); 867 868 pushResult(ins); 869 return true; 870 } 871 872 bool WarpCacheIRTranspiler::emitSmallObjectVariableKeyHasOwnResult( 873 StringOperandId idId, uint32_t propNamesOffset, uint32_t shapeOffset) { 874 MDefinition* id = getOperand(idId); 875 SharedShape* shape = &shapeStubField(shapeOffset)->asShared(); 876 877 auto* ins = MSmallObjectVariableKeyHasProp::New(alloc(), id, shape); 878 add(ins); 879 880 pushResult(ins); 881 return true; 882 } 883 884 bool WarpCacheIRTranspiler::emitMegamorphicSetElement(ObjOperandId objId, 885 ValOperandId idId, 886 ValOperandId rhsId, 887 bool strict) { 888 MDefinition* obj = getOperand(objId); 889 MDefinition* id = getOperand(idId); 890 MDefinition* rhs = getOperand(rhsId); 891 892 auto* ins = MMegamorphicSetElement::New(alloc(), obj, id, rhs, strict); 893 addEffectful(ins); 894 895 return resumeAfter(ins); 896 } 897 898 bool WarpCacheIRTranspiler::emitObjectToIteratorResult( 899 ObjOperandId objId, uint32_t enumeratorsAddrOffset) { 900 MDefinition* obj = getOperand(objId); 901 NativeIteratorListHead* enumeratorsAddr = 902 nativeIteratorListHeadStubField(enumeratorsAddrOffset); 903 904 auto* ins = MObjectToIterator::New(alloc(), obj, enumeratorsAddr); 905 addEffectful(ins); 906 pushResult(ins); 907 if (!resumeAfter(ins)) { 908 return false; 909 } 910 911 return true; 912 } 913 914 bool WarpCacheIRTranspiler::emitValueToIteratorResult(ValOperandId valId) { 915 MDefinition* val = getOperand(valId); 916 917 auto* ins = MValueToIterator::New(alloc(), val); 918 addEffectful(ins); 919 920 pushResult(ins); 921 return resumeAfter(ins); 922 } 923 924 bool WarpCacheIRTranspiler::emitGuardToArrayBuffer(ObjOperandId objId) { 925 MDefinition* obj = getOperand(objId); 926 927 auto* ins = MGuardToArrayBuffer::New(alloc(), obj); 928 add(ins); 929 930 setOperand(objId, ins); 931 return true; 932 } 933 934 bool WarpCacheIRTranspiler::emitGuardToSharedArrayBuffer(ObjOperandId objId) { 935 MDefinition* obj = getOperand(objId); 936 937 auto* ins = MGuardToSharedArrayBuffer::New(alloc(), obj); 938 add(ins); 939 940 setOperand(objId, ins); 941 return true; 942 } 943 944 bool WarpCacheIRTranspiler::emitGuardIsNotArrayBufferMaybeShared( 945 ObjOperandId objId) { 946 MDefinition* obj = getOperand(objId); 947 948 auto* ins = MGuardIsNotArrayBufferMaybeShared::New(alloc(), obj); 949 add(ins); 950 951 setOperand(objId, ins); 952 return true; 953 } 954 955 bool WarpCacheIRTranspiler::emitGuardIsTypedArray(ObjOperandId objId) { 956 MDefinition* obj = getOperand(objId); 957 958 auto* ins = MGuardIsTypedArray::New(alloc(), obj); 959 add(ins); 960 961 setOperand(objId, ins); 962 return true; 963 } 964 965 bool WarpCacheIRTranspiler::emitGuardIsNonResizableTypedArray( 966 ObjOperandId objId) { 967 MDefinition* obj = getOperand(objId); 968 969 auto* ins = MGuardIsNonResizableTypedArray::New(alloc(), obj); 970 add(ins); 971 972 setOperand(objId, ins); 973 return true; 974 } 975 976 bool WarpCacheIRTranspiler::emitGuardIsResizableTypedArray(ObjOperandId objId) { 977 MDefinition* obj = getOperand(objId); 978 979 auto* ins = MGuardIsResizableTypedArray::New(alloc(), obj); 980 add(ins); 981 982 setOperand(objId, ins); 983 return true; 984 } 985 986 bool WarpCacheIRTranspiler::emitGuardHasProxyHandler(ObjOperandId objId, 987 uint32_t handlerOffset) { 988 MDefinition* obj = getOperand(objId); 989 const void* handler = rawPointerField(handlerOffset); 990 991 auto* ins = MGuardHasProxyHandler::New(alloc(), obj, handler); 992 add(ins); 993 994 setOperand(objId, ins); 995 return true; 996 } 997 998 bool WarpCacheIRTranspiler::emitGuardProto(ObjOperandId objId, 999 uint32_t protoOffset) { 1000 MDefinition* def = getOperand(objId); 1001 MDefinition* proto = objectStubField(protoOffset); 1002 1003 auto* ins = MGuardProto::New(alloc(), def, proto); 1004 add(ins); 1005 1006 setOperand(objId, ins); 1007 return true; 1008 } 1009 1010 bool WarpCacheIRTranspiler::emitGuardDynamicSlotIsSpecificObject( 1011 ObjOperandId objId, ObjOperandId expectedId, uint32_t slotOffset) { 1012 size_t slotIndex = int32StubField(slotOffset); 1013 MDefinition* obj = getOperand(objId); 1014 MDefinition* expected = getOperand(expectedId); 1015 1016 auto* slots = MSlots::New(alloc(), obj); 1017 add(slots); 1018 1019 auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex); 1020 add(load); 1021 1022 auto* unbox = MUnbox::New(alloc(), load, MIRType::Object, MUnbox::Fallible); 1023 add(unbox); 1024 1025 auto* guard = MGuardObjectIdentity::New(alloc(), unbox, expected, 1026 /* bailOnEquality = */ false); 1027 add(guard); 1028 return true; 1029 } 1030 1031 bool WarpCacheIRTranspiler::emitLoadDynamicSlot(ValOperandId resultId, 1032 ObjOperandId objId, 1033 uint32_t slotOffset) { 1034 size_t slotIndex = int32StubField(slotOffset); 1035 MDefinition* obj = getOperand(objId); 1036 1037 auto* slots = MSlots::New(alloc(), obj); 1038 add(slots); 1039 1040 auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex); 1041 add(load); 1042 1043 return defineOperand(resultId, load); 1044 } 1045 1046 bool WarpCacheIRTranspiler::emitLoadDynamicSlotFromOffsetResult( 1047 ObjOperandId objId, Int32OperandId offsetId) { 1048 MDefinition* obj = getOperand(objId); 1049 MDefinition* offset = getOperand(offsetId); 1050 1051 auto* slots = MSlots::New(alloc(), obj); 1052 add(slots); 1053 1054 auto* load = MLoadDynamicSlotFromOffset::New(alloc(), slots, offset); 1055 add(load); 1056 1057 pushResult(load); 1058 return true; 1059 } 1060 1061 bool WarpCacheIRTranspiler::emitGuardDynamicSlotIsNotObject( 1062 ObjOperandId objId, uint32_t slotOffset) { 1063 size_t slotIndex = int32StubField(slotOffset); 1064 MDefinition* obj = getOperand(objId); 1065 1066 auto* slots = MSlots::New(alloc(), obj); 1067 add(slots); 1068 1069 auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex); 1070 add(load); 1071 1072 auto* guard = MGuardIsNotObject::New(alloc(), load); 1073 add(guard); 1074 return true; 1075 } 1076 1077 bool WarpCacheIRTranspiler::emitGuardFixedSlotValue(ObjOperandId objId, 1078 uint32_t offsetOffset, 1079 uint32_t valOffset) { 1080 MDefinition* obj = getOperand(objId); 1081 1082 size_t offset = int32StubField(offsetOffset); 1083 ValueOrNurseryValueIndex val = valueStubField(valOffset); 1084 1085 uint32_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset); 1086 1087 auto* load = MLoadFixedSlot::New(alloc(), obj, slotIndex); 1088 add(load); 1089 1090 auto* guard = MGuardValue::New(alloc(), load, val); 1091 add(guard); 1092 return true; 1093 } 1094 1095 bool WarpCacheIRTranspiler::emitGuardDynamicSlotValue(ObjOperandId objId, 1096 uint32_t offsetOffset, 1097 uint32_t valOffset) { 1098 MDefinition* obj = getOperand(objId); 1099 1100 size_t offset = int32StubField(offsetOffset); 1101 ValueOrNurseryValueIndex val = valueStubField(valOffset); 1102 1103 size_t slotIndex = NativeObject::getDynamicSlotIndexFromOffset(offset); 1104 1105 auto* slots = MSlots::New(alloc(), obj); 1106 add(slots); 1107 1108 auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex); 1109 add(load); 1110 1111 auto* guard = MGuardValue::New(alloc(), load, val); 1112 add(guard); 1113 return true; 1114 } 1115 1116 bool WarpCacheIRTranspiler::emitLoadScriptedProxyHandler(ObjOperandId resultId, 1117 ObjOperandId objId) { 1118 MDefinition* obj = getOperand(objId); 1119 1120 auto* load = MLoadScriptedProxyHandler::New(alloc(), obj); 1121 add(load); 1122 1123 return defineOperand(resultId, load); 1124 } 1125 1126 bool WarpCacheIRTranspiler::emitIdToStringOrSymbol(ValOperandId resultId, 1127 ValOperandId idId) { 1128 MDefinition* id = getOperand(idId); 1129 1130 auto* ins = MIdToStringOrSymbol::New(alloc(), id); 1131 add(ins); 1132 1133 return defineOperand(resultId, ins); 1134 } 1135 1136 bool WarpCacheIRTranspiler::emitGuardSpecificAtom(StringOperandId strId, 1137 uint32_t expectedOffset) { 1138 MDefinition* str = getOperand(strId); 1139 JSString* expected = stringStubField(expectedOffset); 1140 1141 auto* ins = 1142 MGuardSpecificAtom::New(alloc(), str, &expected->asOffThreadAtom()); 1143 add(ins); 1144 1145 setOperand(strId, ins); 1146 return true; 1147 } 1148 1149 bool WarpCacheIRTranspiler::emitGuardSpecificSymbol(SymbolOperandId symId, 1150 uint32_t expectedOffset) { 1151 MDefinition* symbol = getOperand(symId); 1152 JS::Symbol* expected = symbolStubField(expectedOffset); 1153 1154 auto* ins = MGuardSpecificSymbol::New(alloc(), symbol, expected); 1155 add(ins); 1156 1157 setOperand(symId, ins); 1158 return true; 1159 } 1160 1161 bool WarpCacheIRTranspiler::emitGuardSpecificInt32(Int32OperandId numId, 1162 int32_t expected) { 1163 MDefinition* num = getOperand(numId); 1164 1165 auto* ins = MGuardSpecificInt32::New(alloc(), num, expected); 1166 add(ins); 1167 1168 setOperand(numId, ins); 1169 return true; 1170 } 1171 1172 bool WarpCacheIRTranspiler::emitGuardSpecificValue(ValOperandId valId, 1173 uint32_t expectedOffset) { 1174 MDefinition* val = getOperand(valId); 1175 ValueOrNurseryValueIndex expected = valueStubField(expectedOffset); 1176 1177 auto* ins = MGuardValue::New(alloc(), val, expected); 1178 add(ins); 1179 1180 setOperand(valId, ins); 1181 return true; 1182 } 1183 1184 bool WarpCacheIRTranspiler::emitGuardSpecificObject(ObjOperandId objId, 1185 uint32_t expectedOffset) { 1186 MDefinition* obj = getOperand(objId); 1187 MDefinition* expected = objectStubField(expectedOffset); 1188 1189 auto* ins = MGuardObjectIdentity::New(alloc(), obj, expected, 1190 /* bailOnEquality = */ false); 1191 add(ins); 1192 1193 setOperand(objId, ins); 1194 return true; 1195 } 1196 1197 bool WarpCacheIRTranspiler::emitGuardSpecificFunction( 1198 ObjOperandId objId, uint32_t expectedOffset, uint32_t nargsAndFlagsOffset) { 1199 MDefinition* obj = getOperand(objId); 1200 MDefinition* expected = objectStubField(expectedOffset); 1201 uint32_t nargsAndFlags = uint32StubField(nargsAndFlagsOffset); 1202 1203 uint16_t nargs = nargsAndFlags >> 16; 1204 FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags)); 1205 1206 auto* ins = MGuardSpecificFunction::New(alloc(), obj, expected, nargs, flags); 1207 add(ins); 1208 1209 setOperand(objId, ins); 1210 return true; 1211 } 1212 1213 bool WarpCacheIRTranspiler::emitGuardFunctionScript( 1214 ObjOperandId funId, uint32_t expectedOffset, uint32_t nargsAndFlagsOffset) { 1215 MDefinition* fun = getOperand(funId); 1216 BaseScript* expected = baseScriptStubField(expectedOffset); 1217 uint32_t nargsAndFlags = uint32StubField(nargsAndFlagsOffset); 1218 1219 uint16_t nargs = nargsAndFlags >> 16; 1220 FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags)); 1221 1222 auto* ins = MGuardFunctionScript::New(alloc(), fun, expected, nargs, flags); 1223 add(ins); 1224 1225 setOperand(funId, ins); 1226 return true; 1227 } 1228 1229 bool WarpCacheIRTranspiler::emitGuardStringToIndex(StringOperandId strId, 1230 Int32OperandId resultId) { 1231 MDefinition* str = getOperand(strId); 1232 1233 auto* ins = MGuardStringToIndex::New(alloc(), str); 1234 add(ins); 1235 1236 return defineOperand(resultId, ins); 1237 } 1238 1239 bool WarpCacheIRTranspiler::emitGuardStringToInt32(StringOperandId strId, 1240 Int32OperandId resultId) { 1241 MDefinition* str = getOperand(strId); 1242 1243 auto* ins = MGuardStringToInt32::New(alloc(), str); 1244 add(ins); 1245 1246 return defineOperand(resultId, ins); 1247 } 1248 1249 bool WarpCacheIRTranspiler::emitGuardStringToNumber(StringOperandId strId, 1250 NumberOperandId resultId) { 1251 MDefinition* str = getOperand(strId); 1252 1253 auto* ins = MGuardStringToDouble::New(alloc(), str); 1254 add(ins); 1255 1256 return defineOperand(resultId, ins); 1257 } 1258 1259 bool WarpCacheIRTranspiler::emitGuardNoDenseElements(ObjOperandId objId) { 1260 MDefinition* obj = getOperand(objId); 1261 1262 auto* ins = MGuardNoDenseElements::New(alloc(), obj); 1263 add(ins); 1264 1265 setOperand(objId, ins); 1266 return true; 1267 } 1268 1269 bool WarpCacheIRTranspiler::emitGuardFunctionHasJitEntry(ObjOperandId funId) { 1270 MDefinition* fun = getOperand(funId); 1271 uint16_t expectedFlags = FunctionFlags::HasJitEntryFlags(); 1272 uint16_t unexpectedFlags = 0; 1273 1274 auto* ins = 1275 MGuardFunctionFlags::New(alloc(), fun, expectedFlags, unexpectedFlags); 1276 add(ins); 1277 1278 setOperand(funId, ins); 1279 return true; 1280 } 1281 1282 bool WarpCacheIRTranspiler::emitGuardFunctionHasNoJitEntry(ObjOperandId funId) { 1283 MDefinition* fun = getOperand(funId); 1284 uint16_t expectedFlags = 0; 1285 uint16_t unexpectedFlags = FunctionFlags::HasJitEntryFlags(); 1286 1287 auto* ins = 1288 MGuardFunctionFlags::New(alloc(), fun, expectedFlags, unexpectedFlags); 1289 add(ins); 1290 1291 setOperand(funId, ins); 1292 return true; 1293 } 1294 1295 bool WarpCacheIRTranspiler::emitGuardFunctionIsNonBuiltinCtor( 1296 ObjOperandId funId) { 1297 MDefinition* fun = getOperand(funId); 1298 1299 auto* ins = MGuardFunctionIsNonBuiltinCtor::New(alloc(), fun); 1300 add(ins); 1301 1302 setOperand(funId, ins); 1303 return true; 1304 } 1305 1306 bool WarpCacheIRTranspiler::emitGuardFunctionIsConstructor(ObjOperandId funId) { 1307 MDefinition* fun = getOperand(funId); 1308 uint16_t expectedFlags = FunctionFlags::CONSTRUCTOR; 1309 uint16_t unexpectedFlags = 0; 1310 1311 auto* ins = 1312 MGuardFunctionFlags::New(alloc(), fun, expectedFlags, unexpectedFlags); 1313 add(ins); 1314 1315 setOperand(funId, ins); 1316 return true; 1317 } 1318 1319 bool WarpCacheIRTranspiler::emitGuardNotClassConstructor(ObjOperandId funId) { 1320 MDefinition* fun = getOperand(funId); 1321 1322 auto* ins = 1323 MGuardFunctionKind::New(alloc(), fun, FunctionFlags::ClassConstructor, 1324 /*bailOnEquality=*/true); 1325 add(ins); 1326 1327 setOperand(funId, ins); 1328 return true; 1329 } 1330 1331 bool WarpCacheIRTranspiler::emitGuardArrayIsPacked(ObjOperandId arrayId) { 1332 MDefinition* array = getOperand(arrayId); 1333 1334 auto* ins = MGuardArrayIsPacked::New(alloc(), array); 1335 add(ins); 1336 1337 setOperand(arrayId, ins); 1338 return true; 1339 } 1340 1341 bool WarpCacheIRTranspiler::emitGuardArgumentsObjectFlags(ObjOperandId objId, 1342 uint8_t flags) { 1343 MDefinition* obj = getOperand(objId); 1344 1345 auto* ins = MGuardArgumentsObjectFlags::New(alloc(), obj, flags); 1346 add(ins); 1347 1348 setOperand(objId, ins); 1349 return true; 1350 } 1351 1352 bool WarpCacheIRTranspiler::emitGuardObjectHasSameRealm(ObjOperandId objId) { 1353 MDefinition* obj = getOperand(objId); 1354 1355 auto* ins = MGuardObjectHasSameRealm::New(alloc(), obj); 1356 add(ins); 1357 1358 setOperand(objId, ins); 1359 return true; 1360 } 1361 1362 bool WarpCacheIRTranspiler::emitGuardNonDoubleType(ValOperandId inputId, 1363 ValueType type) { 1364 switch (type) { 1365 case ValueType::String: 1366 case ValueType::Symbol: 1367 case ValueType::BigInt: 1368 case ValueType::Int32: 1369 case ValueType::Boolean: 1370 return emitGuardTo(inputId, MIRTypeFromValueType(JSValueType(type))); 1371 case ValueType::Undefined: 1372 return emitGuardIsUndefined(inputId); 1373 case ValueType::Null: 1374 return emitGuardIsNull(inputId); 1375 case ValueType::Double: 1376 case ValueType::Magic: 1377 case ValueType::PrivateGCThing: 1378 case ValueType::Object: 1379 break; 1380 } 1381 1382 MOZ_CRASH("unexpected type"); 1383 } 1384 1385 bool WarpCacheIRTranspiler::emitGuardTo(ValOperandId inputId, MIRType type) { 1386 MDefinition* def = getOperand(inputId); 1387 if (def->type() == type) { 1388 return true; 1389 } 1390 1391 auto* ins = MUnbox::New(alloc(), def, type, MUnbox::Fallible); 1392 add(ins); 1393 1394 setOperand(inputId, ins); 1395 return true; 1396 } 1397 1398 bool WarpCacheIRTranspiler::emitGuardToObject(ValOperandId inputId) { 1399 return emitGuardTo(inputId, MIRType::Object); 1400 } 1401 1402 bool WarpCacheIRTranspiler::emitGuardToString(ValOperandId inputId) { 1403 return emitGuardTo(inputId, MIRType::String); 1404 } 1405 1406 bool WarpCacheIRTranspiler::emitGuardToSymbol(ValOperandId inputId) { 1407 return emitGuardTo(inputId, MIRType::Symbol); 1408 } 1409 1410 bool WarpCacheIRTranspiler::emitGuardToBigInt(ValOperandId inputId) { 1411 return emitGuardTo(inputId, MIRType::BigInt); 1412 } 1413 1414 bool WarpCacheIRTranspiler::emitGuardToBoolean(ValOperandId inputId) { 1415 return emitGuardTo(inputId, MIRType::Boolean); 1416 } 1417 1418 bool WarpCacheIRTranspiler::emitGuardToInt32(ValOperandId inputId) { 1419 return emitGuardTo(inputId, MIRType::Int32); 1420 } 1421 1422 bool WarpCacheIRTranspiler::emitGuardBooleanToInt32(ValOperandId inputId, 1423 Int32OperandId resultId) { 1424 if (!emitGuardTo(inputId, MIRType::Boolean)) { 1425 return false; 1426 } 1427 1428 MDefinition* input = getOperand(inputId); 1429 MOZ_ASSERT(input->type() == MIRType::Boolean); 1430 1431 auto* ins = MBooleanToInt32::New(alloc(), input); 1432 add(ins); 1433 1434 return defineOperand(resultId, ins); 1435 } 1436 1437 bool WarpCacheIRTranspiler::emitGuardIsNumber(ValOperandId inputId) { 1438 MDefinition* def = getOperand(inputId); 1439 1440 // No guard needed when the input is already a number type. 1441 if (IsNumberType(def->type())) { 1442 return true; 1443 } 1444 1445 // MIRType::Double also implies int32 in Ion. 1446 return emitGuardTo(inputId, MIRType::Double); 1447 } 1448 1449 bool WarpCacheIRTranspiler::emitGuardIsNullOrUndefined(ValOperandId inputId) { 1450 MDefinition* input = getOperand(inputId); 1451 if (input->type() == MIRType::Null || input->type() == MIRType::Undefined) { 1452 return true; 1453 } 1454 1455 auto* ins = MGuardNullOrUndefined::New(alloc(), input); 1456 add(ins); 1457 1458 setOperand(inputId, ins); 1459 return true; 1460 } 1461 1462 bool WarpCacheIRTranspiler::emitGuardIsNull(ValOperandId inputId) { 1463 MDefinition* input = getOperand(inputId); 1464 if (input->type() == MIRType::Null) { 1465 return true; 1466 } 1467 1468 auto* ins = MGuardValue::New(alloc(), input, NullValue()); 1469 add(ins); 1470 setOperand(inputId, ins); 1471 return true; 1472 } 1473 1474 bool WarpCacheIRTranspiler::emitGuardIsUndefined(ValOperandId inputId) { 1475 MDefinition* input = getOperand(inputId); 1476 if (input->type() == MIRType::Undefined) { 1477 return true; 1478 } 1479 1480 auto* ins = MGuardValue::New(alloc(), input, UndefinedValue()); 1481 add(ins); 1482 setOperand(inputId, ins); 1483 return true; 1484 } 1485 1486 bool WarpCacheIRTranspiler::emitGuardIsExtensible(ObjOperandId objId) { 1487 MDefinition* obj = getOperand(objId); 1488 1489 auto* ins = MGuardIsExtensible::New(alloc(), obj); 1490 add(ins); 1491 setOperand(objId, ins); 1492 return true; 1493 } 1494 1495 bool WarpCacheIRTranspiler::emitGuardInt32IsNonNegative( 1496 Int32OperandId indexId) { 1497 MDefinition* index = getOperand(indexId); 1498 1499 auto* ins = MGuardInt32IsNonNegative::New(alloc(), index); 1500 add(ins); 1501 setOperand(indexId, ins); 1502 return true; 1503 } 1504 1505 bool WarpCacheIRTranspiler::emitGuardIntPtrIsNonNegative( 1506 IntPtrOperandId indexId) { 1507 MDefinition* index = getOperand(indexId); 1508 1509 auto* ins = MGuardIntPtrIsNonNegative::New(alloc(), index); 1510 add(ins); 1511 setOperand(indexId, ins); 1512 return true; 1513 } 1514 1515 bool WarpCacheIRTranspiler::emitGuardIndexIsNotDenseElement( 1516 ObjOperandId objId, Int32OperandId indexId) { 1517 MDefinition* obj = getOperand(objId); 1518 MDefinition* index = getOperand(indexId); 1519 1520 auto* ins = MGuardIndexIsNotDenseElement::New(alloc(), obj, index); 1521 add(ins); 1522 setOperand(indexId, ins); 1523 return true; 1524 } 1525 1526 bool WarpCacheIRTranspiler::emitGuardIndexIsValidUpdateOrAdd( 1527 ObjOperandId objId, Int32OperandId indexId) { 1528 MDefinition* obj = getOperand(objId); 1529 MDefinition* index = getOperand(indexId); 1530 1531 auto* ins = MGuardIndexIsValidUpdateOrAdd::New(alloc(), obj, index); 1532 add(ins); 1533 setOperand(indexId, ins); 1534 return true; 1535 } 1536 1537 bool WarpCacheIRTranspiler::emitCallAddOrUpdateSparseElementHelper( 1538 ObjOperandId objId, Int32OperandId idId, ValOperandId rhsId, bool strict) { 1539 MDefinition* obj = getOperand(objId); 1540 MDefinition* id = getOperand(idId); 1541 MDefinition* rhs = getOperand(rhsId); 1542 1543 auto* ins = MCallAddOrUpdateSparseElement::New(alloc(), obj, id, rhs, strict); 1544 addEffectful(ins); 1545 1546 return resumeAfter(ins); 1547 } 1548 1549 bool WarpCacheIRTranspiler::emitGuardTagNotEqual(ValueTagOperandId lhsId, 1550 ValueTagOperandId rhsId) { 1551 MDefinition* lhs = getOperand(lhsId); 1552 MDefinition* rhs = getOperand(rhsId); 1553 1554 auto* ins = MGuardTagNotEqual::New(alloc(), lhs, rhs); 1555 add(ins); 1556 1557 return true; 1558 } 1559 1560 bool WarpCacheIRTranspiler::emitGuardToInt32Index(ValOperandId inputId, 1561 Int32OperandId resultId) { 1562 MDefinition* input = getOperand(inputId); 1563 auto* ins = 1564 MToNumberInt32::New(alloc(), input, IntConversionInputKind::NumbersOnly); 1565 1566 // ToPropertyKey(-0) is "0", so we can silently convert -0 to 0 here. 1567 ins->setNeedsNegativeZeroCheck(false); 1568 add(ins); 1569 1570 return defineOperand(resultId, ins); 1571 } 1572 1573 bool WarpCacheIRTranspiler::emitTruncateDoubleToUInt32( 1574 NumberOperandId inputId, Int32OperandId resultId) { 1575 MDefinition* input = getOperand(inputId); 1576 auto* ins = MTruncateToInt32::New(alloc(), input); 1577 add(ins); 1578 1579 return defineOperand(resultId, ins); 1580 } 1581 1582 bool WarpCacheIRTranspiler::emitDoubleToUint8Clamped(NumberOperandId inputId, 1583 Int32OperandId resultId) { 1584 MDefinition* input = getOperand(inputId); 1585 auto* ins = MClampToUint8::New(alloc(), input); 1586 add(ins); 1587 1588 return defineOperand(resultId, ins); 1589 } 1590 1591 bool WarpCacheIRTranspiler::emitGuardToInt32ModUint32(ValOperandId valId, 1592 Int32OperandId resultId) { 1593 MDefinition* input = getOperand(valId); 1594 auto* ins = MTruncateToInt32::New(alloc(), input); 1595 add(ins); 1596 1597 return defineOperand(resultId, ins); 1598 } 1599 1600 bool WarpCacheIRTranspiler::emitGuardToUint8Clamped(ValOperandId valId, 1601 Int32OperandId resultId) { 1602 MDefinition* input = getOperand(valId); 1603 auto* ins = MClampToUint8::New(alloc(), input); 1604 add(ins); 1605 1606 return defineOperand(resultId, ins); 1607 } 1608 1609 bool WarpCacheIRTranspiler::emitToString(OperandId inputId, 1610 StringOperandId resultId) { 1611 MDefinition* input = getOperand(inputId); 1612 auto* ins = 1613 MToString::New(alloc(), input, MToString::SideEffectHandling::Bailout); 1614 add(ins); 1615 1616 return defineOperand(resultId, ins); 1617 } 1618 1619 bool WarpCacheIRTranspiler::emitInt32ToIntPtr(Int32OperandId inputId, 1620 IntPtrOperandId resultId) { 1621 MDefinition* input = getOperand(inputId); 1622 auto* ins = MInt32ToIntPtr::New(alloc(), input); 1623 add(ins); 1624 return defineOperand(resultId, ins); 1625 } 1626 1627 bool WarpCacheIRTranspiler::emitGuardNumberToIntPtrIndex( 1628 NumberOperandId inputId, bool supportOOB, IntPtrOperandId resultId) { 1629 MDefinition* input = getOperand(inputId); 1630 auto* ins = MGuardNumberToIntPtrIndex::New(alloc(), input, supportOOB); 1631 add(ins); 1632 return defineOperand(resultId, ins); 1633 } 1634 1635 bool WarpCacheIRTranspiler::emitCallInt32ToString(Int32OperandId inputId, 1636 StringOperandId resultId) { 1637 return emitToString(inputId, resultId); 1638 } 1639 1640 bool WarpCacheIRTranspiler::emitCallNumberToString(NumberOperandId inputId, 1641 StringOperandId resultId) { 1642 return emitToString(inputId, resultId); 1643 } 1644 1645 bool WarpCacheIRTranspiler::emitInt32ToStringWithBaseResult( 1646 Int32OperandId inputId, Int32OperandId baseId) { 1647 MDefinition* input = getOperand(inputId); 1648 MDefinition* base = getOperand(baseId); 1649 1650 auto* guardedBase = MGuardInt32Range::New(alloc(), base, 2, 36); 1651 add(guardedBase); 1652 1653 // Use lower-case characters by default. 1654 constexpr bool lower = true; 1655 1656 auto* ins = MInt32ToStringWithBase::New(alloc(), input, guardedBase, lower); 1657 add(ins); 1658 1659 pushResult(ins); 1660 return true; 1661 } 1662 1663 bool WarpCacheIRTranspiler::emitBooleanToString(BooleanOperandId inputId, 1664 StringOperandId resultId) { 1665 return emitToString(inputId, resultId); 1666 } 1667 1668 bool WarpCacheIRTranspiler::emitBooleanToNumber(BooleanOperandId inputId, 1669 NumberOperandId resultId) { 1670 MDefinition* input = getOperand(inputId); 1671 1672 auto* ins = MToDouble::New(alloc(), input); 1673 add(ins); 1674 1675 return defineOperand(resultId, ins); 1676 } 1677 1678 bool WarpCacheIRTranspiler::emitStringToAtom(StringOperandId strId) { 1679 MDefinition* str = getOperand(strId); 1680 1681 auto* ins = MToHashableString::New(alloc(), str); 1682 add(ins); 1683 1684 setOperand(strId, ins); 1685 return true; 1686 } 1687 1688 bool WarpCacheIRTranspiler::emitLoadInt32Result(Int32OperandId valId) { 1689 MDefinition* val = getOperand(valId); 1690 MOZ_ASSERT(val->type() == MIRType::Int32); 1691 pushResult(val); 1692 return true; 1693 } 1694 1695 bool WarpCacheIRTranspiler::emitLoadDoubleResult(NumberOperandId valId) { 1696 MDefinition* val = getOperand(valId); 1697 MOZ_ASSERT(IsNumberType(val->type())); 1698 1699 if (val->type() != MIRType::Double) { 1700 auto* ins = MToDouble::New(alloc(), val); 1701 add(ins); 1702 1703 val = ins; 1704 } 1705 1706 pushResult(val); 1707 return true; 1708 } 1709 1710 bool WarpCacheIRTranspiler::emitLoadBigIntResult(BigIntOperandId valId) { 1711 MDefinition* val = getOperand(valId); 1712 MOZ_ASSERT(val->type() == MIRType::BigInt); 1713 pushResult(val); 1714 return true; 1715 } 1716 1717 bool WarpCacheIRTranspiler::emitLoadObjectResult(ObjOperandId objId) { 1718 MDefinition* obj = getOperand(objId); 1719 MOZ_ASSERT(obj->type() == MIRType::Object); 1720 pushResult(obj); 1721 return true; 1722 } 1723 1724 bool WarpCacheIRTranspiler::emitLoadStringResult(StringOperandId strId) { 1725 MDefinition* str = getOperand(strId); 1726 MOZ_ASSERT(str->type() == MIRType::String); 1727 pushResult(str); 1728 return true; 1729 } 1730 1731 bool WarpCacheIRTranspiler::emitLoadSymbolResult(SymbolOperandId symId) { 1732 MDefinition* sym = getOperand(symId); 1733 MOZ_ASSERT(sym->type() == MIRType::Symbol); 1734 pushResult(sym); 1735 return true; 1736 } 1737 1738 bool WarpCacheIRTranspiler::emitLoadUndefinedResult() { 1739 pushResult(constant(UndefinedValue())); 1740 return true; 1741 } 1742 1743 bool WarpCacheIRTranspiler::emitLoadBooleanResult(bool val) { 1744 pushResult(constant(BooleanValue(val))); 1745 return true; 1746 } 1747 1748 bool WarpCacheIRTranspiler::emitLoadValueResult(uint32_t valOffset) { 1749 // This op is currently not used for nursery-allocated values. 1750 ValueOrNurseryValueIndex val = valueStubField(valOffset); 1751 MOZ_RELEASE_ASSERT(val.isValue(), "Unexpected nursery Value"); 1752 pushResult(constant(val.toValue())); 1753 return true; 1754 } 1755 1756 bool WarpCacheIRTranspiler::emitUncheckedLoadWeakValueResult( 1757 uint32_t valOffset) { 1758 // This op is currently not used for nursery-allocated values. 1759 ValueOrNurseryValueIndex val = valueStubField(valOffset); 1760 MOZ_RELEASE_ASSERT(val.isValue(), "Unexpected nursery Value"); 1761 pushResult(constant(val.toValue())); 1762 return true; 1763 } 1764 1765 bool WarpCacheIRTranspiler::emitUncheckedLoadWeakObjectResult( 1766 uint32_t objOffset) { 1767 MInstruction* ins = objectStubField(objOffset); 1768 pushResult(ins); 1769 return true; 1770 } 1771 1772 bool WarpCacheIRTranspiler::emitCheckWeakValueResultForFixedSlot( 1773 ObjOperandId objId, uint32_t offsetOffset, uint32_t valOffset) { 1774 // This is a no-op because we use strong references for weak BaselineIC stub 1775 // fields in Warp. 1776 return true; 1777 } 1778 1779 bool WarpCacheIRTranspiler::emitCheckWeakValueResultForDynamicSlot( 1780 ObjOperandId objId, uint32_t offsetOffset, uint32_t valOffset) { 1781 // This is a no-op because we use strong references for weak BaselineIC stub 1782 // fields in Warp. 1783 return true; 1784 } 1785 1786 bool WarpCacheIRTranspiler::emitLoadInt32Constant(uint32_t valOffset, 1787 Int32OperandId resultId) { 1788 int32_t val = int32StubField(valOffset); 1789 auto* valConst = constant(Int32Value(val)); 1790 return defineOperand(resultId, valConst); 1791 } 1792 1793 bool WarpCacheIRTranspiler::emitLoadInt32AsIntPtrConstant( 1794 uint32_t valOffset, IntPtrOperandId resultId) { 1795 int32_t val = int32StubField(valOffset); 1796 auto* valConst = MConstant::NewIntPtr(alloc(), intptr_t(val)); 1797 add(valConst); 1798 return defineOperand(resultId, valConst); 1799 } 1800 1801 bool WarpCacheIRTranspiler::emitLoadDoubleConstant(uint32_t valOffset, 1802 NumberOperandId resultId) { 1803 double val = doubleStubField(valOffset); 1804 auto* valConst = constant(DoubleValue(val)); 1805 return defineOperand(resultId, valConst); 1806 } 1807 1808 bool WarpCacheIRTranspiler::emitLoadBooleanConstant(bool val, 1809 BooleanOperandId resultId) { 1810 auto* valConst = constant(BooleanValue(val)); 1811 return defineOperand(resultId, valConst); 1812 } 1813 1814 bool WarpCacheIRTranspiler::emitLoadUndefined(ValOperandId resultId) { 1815 auto* valConst = constant(UndefinedValue()); 1816 return defineOperand(resultId, valConst); 1817 } 1818 1819 bool WarpCacheIRTranspiler::emitLoadConstantString(uint32_t strOffset, 1820 StringOperandId resultId) { 1821 JSString* val = stringStubField(strOffset); 1822 auto* valConst = constant(StringValue(val)); 1823 return defineOperand(resultId, valConst); 1824 } 1825 1826 bool WarpCacheIRTranspiler::emitLoadConstantStringResult(uint32_t strOffset) { 1827 JSString* val = stringStubField(strOffset); 1828 auto* valConst = constant(StringValue(val)); 1829 pushResult(valConst); 1830 return true; 1831 } 1832 1833 bool WarpCacheIRTranspiler::emitLoadTypeOfObjectResult(ObjOperandId objId) { 1834 MDefinition* obj = getOperand(objId); 1835 auto* typeOf = MTypeOf::New(alloc(), obj); 1836 add(typeOf); 1837 1838 auto* ins = MTypeOfName::New(alloc(), typeOf); 1839 add(ins); 1840 pushResult(ins); 1841 return true; 1842 } 1843 1844 bool WarpCacheIRTranspiler::emitLoadTypeOfEqObjectResult( 1845 ObjOperandId objId, TypeofEqOperand operand) { 1846 MDefinition* obj = getOperand(objId); 1847 auto* typeOf = MTypeOf::New(alloc(), obj); 1848 add(typeOf); 1849 1850 auto* typeInt = MConstant::NewInt32(alloc(), operand.type()); 1851 add(typeInt); 1852 1853 auto* ins = MCompare::New(alloc(), typeOf, typeInt, operand.compareOp(), 1854 MCompare::Compare_Int32); 1855 add(ins); 1856 pushResult(ins); 1857 return true; 1858 } 1859 1860 bool WarpCacheIRTranspiler::emitLoadEnclosingEnvironment( 1861 ObjOperandId objId, ObjOperandId resultId) { 1862 MDefinition* env = getOperand(objId); 1863 auto* ins = MEnclosingEnvironment::New(alloc(), env); 1864 add(ins); 1865 1866 return defineOperand(resultId, ins); 1867 } 1868 1869 bool WarpCacheIRTranspiler::emitLoadObject(ObjOperandId resultId, 1870 uint32_t objOffset) { 1871 MInstruction* ins = objectStubField(objOffset); 1872 1873 return defineOperand(resultId, ins); 1874 } 1875 1876 bool WarpCacheIRTranspiler::emitLoadProtoObject(ObjOperandId resultId, 1877 uint32_t objOffset, 1878 ObjOperandId receiverObjId) { 1879 MInstruction* ins = objectStubField(objOffset); 1880 if (ins->isConstant()) { 1881 MDefinition* receiverObj = getOperand(receiverObjId); 1882 1883 ins = MConstantProto::New(alloc(), ins, receiverObj->skipObjectGuards()); 1884 add(ins); 1885 } 1886 return defineOperand(resultId, ins); 1887 } 1888 1889 bool WarpCacheIRTranspiler::emitLoadProto(ObjOperandId objId, 1890 ObjOperandId resultId) { 1891 MDefinition* obj = getOperand(objId); 1892 1893 auto* ins = MObjectStaticProto::New(alloc(), obj); 1894 add(ins); 1895 1896 return defineOperand(resultId, ins); 1897 } 1898 1899 bool WarpCacheIRTranspiler::emitLoadInstanceOfObjectResult( 1900 ValOperandId lhsId, ObjOperandId protoId) { 1901 MDefinition* lhs = getOperand(lhsId); 1902 MDefinition* proto = getOperand(protoId); 1903 1904 auto* instanceOf = MInstanceOf::New(alloc(), lhs, proto); 1905 addEffectful(instanceOf); 1906 1907 pushResult(instanceOf); 1908 return resumeAfter(instanceOf); 1909 } 1910 1911 bool WarpCacheIRTranspiler::emitLoadValueTag(ValOperandId valId, 1912 ValueTagOperandId resultId) { 1913 MDefinition* val = getOperand(valId); 1914 1915 auto* ins = MLoadValueTag::New(alloc(), val); 1916 add(ins); 1917 1918 return defineOperand(resultId, ins); 1919 } 1920 1921 bool WarpCacheIRTranspiler::emitLoadDynamicSlotResult(ObjOperandId objId, 1922 uint32_t offsetOffset) { 1923 int32_t offset = int32StubField(offsetOffset); 1924 1925 MDefinition* obj = getOperand(objId); 1926 size_t slotIndex = NativeObject::getDynamicSlotIndexFromOffset(offset); 1927 1928 auto* slots = MSlots::New(alloc(), obj); 1929 add(slots); 1930 1931 auto* load = MLoadDynamicSlot::New(alloc(), slots, slotIndex); 1932 add(load); 1933 1934 pushResult(load); 1935 return true; 1936 } 1937 1938 bool WarpCacheIRTranspiler::emitLoadFixedSlot(ValOperandId resultId, 1939 ObjOperandId objId, 1940 uint32_t offsetOffset) { 1941 MDefinition* obj = getOperand(objId); 1942 1943 size_t offset = int32StubField(offsetOffset); 1944 uint32_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset); 1945 1946 auto* load = MLoadFixedSlot::New(alloc(), obj, slotIndex); 1947 add(load); 1948 1949 return defineOperand(resultId, load); 1950 } 1951 1952 bool WarpCacheIRTranspiler::emitLoadFixedSlotFromOffsetResult( 1953 ObjOperandId objId, Int32OperandId offsetId) { 1954 MDefinition* obj = getOperand(objId); 1955 MDefinition* offset = getOperand(offsetId); 1956 1957 auto* ins = MLoadFixedSlotFromOffset::New(alloc(), obj, offset); 1958 add(ins); 1959 1960 pushResult(ins); 1961 return true; 1962 } 1963 1964 bool WarpCacheIRTranspiler::emitStoreFixedSlotFromOffset( 1965 ObjOperandId objId, Int32OperandId offsetId, ValOperandId rhsId) { 1966 MDefinition* obj = getOperand(objId); 1967 MDefinition* offset = getOperand(offsetId); 1968 MDefinition* rhs = getOperand(rhsId); 1969 1970 auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs); 1971 add(barrier); 1972 1973 auto* store = 1974 MStoreFixedSlotFromOffset::NewBarriered(alloc(), obj, offset, rhs); 1975 addEffectful(store); 1976 1977 return resumeAfter(store); 1978 } 1979 1980 bool WarpCacheIRTranspiler::emitStoreDynamicSlotFromOffset( 1981 ObjOperandId objId, Int32OperandId offsetId, ValOperandId rhsId) { 1982 MDefinition* obj = getOperand(objId); 1983 MDefinition* offset = getOperand(offsetId); 1984 MDefinition* rhs = getOperand(rhsId); 1985 1986 auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs); 1987 add(barrier); 1988 1989 auto* slots = MSlots::New(alloc(), obj); 1990 add(slots); 1991 1992 auto* store = MStoreDynamicSlotFromOffset::New(alloc(), slots, offset, rhs); 1993 addEffectful(store); 1994 1995 return resumeAfter(store); 1996 } 1997 1998 bool WarpCacheIRTranspiler::emitLoadFixedSlotResult(ObjOperandId objId, 1999 uint32_t offsetOffset) { 2000 int32_t offset = int32StubField(offsetOffset); 2001 2002 MDefinition* obj = getOperand(objId); 2003 uint32_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset); 2004 2005 auto* load = MLoadFixedSlot::New(alloc(), obj, slotIndex); 2006 add(load); 2007 2008 pushResult(load); 2009 return true; 2010 } 2011 2012 bool WarpCacheIRTranspiler::emitLoadFixedSlotTypedResult(ObjOperandId objId, 2013 uint32_t offsetOffset, 2014 ValueType type) { 2015 int32_t offset = int32StubField(offsetOffset); 2016 2017 MDefinition* obj = getOperand(objId); 2018 uint32_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset); 2019 2020 auto* load = MLoadFixedSlot::New(alloc(), obj, slotIndex); 2021 load->setResultType(MIRTypeFromValueType(JSValueType(type))); 2022 add(load); 2023 2024 pushResult(load); 2025 return true; 2026 } 2027 2028 bool WarpCacheIRTranspiler::emitGuardIsNotUninitializedLexical( 2029 ValOperandId valId) { 2030 MDefinition* val = getOperand(valId); 2031 2032 auto* lexicalCheck = MLexicalCheck::New(alloc(), val); 2033 add(lexicalCheck); 2034 2035 if (snapshot().bailoutInfo().failedLexicalCheck()) { 2036 lexicalCheck->setNotMovable(); 2037 } 2038 2039 setOperand(valId, lexicalCheck); 2040 return true; 2041 } 2042 2043 bool WarpCacheIRTranspiler::emitLoadInt32ArrayLengthResult(ObjOperandId objId) { 2044 MDefinition* obj = getOperand(objId); 2045 2046 auto* elements = MElements::New(alloc(), obj); 2047 add(elements); 2048 2049 auto* length = MArrayLength::New(alloc(), elements); 2050 add(length); 2051 2052 pushResult(length); 2053 return true; 2054 } 2055 2056 bool WarpCacheIRTranspiler::emitLoadInt32ArrayLength(ObjOperandId objId, 2057 Int32OperandId resultId) { 2058 MDefinition* obj = getOperand(objId); 2059 2060 auto* elements = MElements::New(alloc(), obj); 2061 add(elements); 2062 2063 auto* length = MArrayLength::New(alloc(), elements); 2064 add(length); 2065 2066 return defineOperand(resultId, length); 2067 } 2068 2069 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgResult( 2070 ObjOperandId objId, Int32OperandId indexId) { 2071 MDefinition* obj = getOperand(objId); 2072 MDefinition* index = getOperand(indexId); 2073 2074 auto* load = MLoadArgumentsObjectArg::New(alloc(), obj, index); 2075 add(load); 2076 2077 pushResult(load); 2078 return true; 2079 } 2080 2081 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgHoleResult( 2082 ObjOperandId objId, Int32OperandId indexId) { 2083 MDefinition* obj = getOperand(objId); 2084 MDefinition* index = getOperand(indexId); 2085 2086 auto* load = MLoadArgumentsObjectArgHole::New(alloc(), obj, index); 2087 add(load); 2088 2089 pushResult(load); 2090 return true; 2091 } 2092 2093 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectArgExistsResult( 2094 ObjOperandId objId, Int32OperandId indexId) { 2095 MDefinition* obj = getOperand(objId); 2096 MDefinition* index = getOperand(indexId); 2097 2098 auto* ins = MInArgumentsObjectArg::New(alloc(), obj, index); 2099 add(ins); 2100 2101 pushResult(ins); 2102 return true; 2103 } 2104 2105 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectLengthResult( 2106 ObjOperandId objId) { 2107 MDefinition* obj = getOperand(objId); 2108 2109 auto* length = MArgumentsObjectLength::New(alloc(), obj); 2110 add(length); 2111 2112 pushResult(length); 2113 return true; 2114 } 2115 2116 bool WarpCacheIRTranspiler::emitLoadArgumentsObjectLength( 2117 ObjOperandId objId, Int32OperandId resultId) { 2118 MDefinition* obj = getOperand(objId); 2119 2120 auto* length = MArgumentsObjectLength::New(alloc(), obj); 2121 add(length); 2122 2123 return defineOperand(resultId, length); 2124 } 2125 2126 bool WarpCacheIRTranspiler::emitLoadBoundFunctionNumArgs( 2127 ObjOperandId objId, Int32OperandId resultId) { 2128 MDefinition* obj = getOperand(objId); 2129 2130 auto* numArgs = MBoundFunctionNumArgs::New(alloc(), obj); 2131 add(numArgs); 2132 2133 return defineOperand(resultId, numArgs); 2134 } 2135 2136 bool WarpCacheIRTranspiler::emitLoadBoundFunctionTarget(ObjOperandId objId, 2137 ObjOperandId resultId) { 2138 MDefinition* obj = getOperand(objId); 2139 2140 auto* target = MLoadFixedSlotAndUnbox::New( 2141 alloc(), obj, BoundFunctionObject::targetSlot(), MUnbox::Mode::Infallible, 2142 MIRType::Object); 2143 add(target); 2144 2145 return defineOperand(resultId, target); 2146 } 2147 2148 bool WarpCacheIRTranspiler::emitLoadBoundFunctionArgument( 2149 ObjOperandId objId, uint32_t index, ValOperandId resultId) { 2150 MDefinition* obj = getOperand(objId); 2151 2152 auto* boundArgs = MLoadFixedSlotAndUnbox::New( 2153 alloc(), obj, BoundFunctionObject::firstInlineBoundArgSlot(), 2154 MUnbox::Mode::Infallible, MIRType::Object); 2155 add(boundArgs); 2156 2157 auto* elements = MElements::New(alloc(), boundArgs); 2158 add(elements); 2159 2160 auto argIndex = constant(Int32Value(index)); 2161 auto* load = MLoadElement::New(alloc(), elements, argIndex, 2162 /* needsHoleCheck */ false); 2163 add(load); 2164 2165 return defineOperand(resultId, load); 2166 } 2167 2168 bool WarpCacheIRTranspiler::emitGuardBoundFunctionIsConstructor( 2169 ObjOperandId objId) { 2170 MDefinition* obj = getOperand(objId); 2171 2172 auto* guard = MGuardBoundFunctionIsConstructor::New(alloc(), obj); 2173 add(guard); 2174 2175 setOperand(objId, guard); 2176 return true; 2177 } 2178 2179 bool WarpCacheIRTranspiler::emitGuardObjectIdentity(ObjOperandId obj1Id, 2180 ObjOperandId obj2Id) { 2181 MDefinition* obj1 = getOperand(obj1Id); 2182 MDefinition* obj2 = getOperand(obj2Id); 2183 2184 auto* guard = MGuardObjectIdentity::New(alloc(), obj1, obj2, 2185 /* bailOnEquality = */ false); 2186 add(guard); 2187 return true; 2188 } 2189 2190 bool WarpCacheIRTranspiler::emitArrayFromArgumentsObjectResult( 2191 ObjOperandId objId, uint32_t shapeOffset) { 2192 MDefinition* obj = getOperand(objId); 2193 Shape* shape = shapeStubField(shapeOffset); 2194 MOZ_ASSERT(shape); 2195 2196 auto* array = MArrayFromArgumentsObject::New(alloc(), obj, shape); 2197 addEffectful(array); 2198 2199 pushResult(array); 2200 return resumeAfter(array); 2201 } 2202 2203 bool WarpCacheIRTranspiler::emitLoadFunctionLengthResult(ObjOperandId objId) { 2204 MDefinition* obj = getOperand(objId); 2205 2206 auto* length = MFunctionLength::New(alloc(), obj); 2207 add(length); 2208 2209 pushResult(length); 2210 return true; 2211 } 2212 2213 bool WarpCacheIRTranspiler::emitLoadFunctionNameResult(ObjOperandId objId) { 2214 MDefinition* obj = getOperand(objId); 2215 2216 auto* name = MFunctionName::New(alloc(), obj); 2217 add(name); 2218 2219 pushResult(name); 2220 return true; 2221 } 2222 2223 bool WarpCacheIRTranspiler::emitLoadArrayBufferByteLengthInt32Result( 2224 ObjOperandId objId) { 2225 MDefinition* obj = getOperand(objId); 2226 2227 auto* length = MArrayBufferByteLength::New(alloc(), obj); 2228 add(length); 2229 2230 auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length); 2231 add(lengthInt32); 2232 2233 pushResult(lengthInt32); 2234 return true; 2235 } 2236 2237 bool WarpCacheIRTranspiler::emitLoadArrayBufferByteLengthDoubleResult( 2238 ObjOperandId objId) { 2239 MDefinition* obj = getOperand(objId); 2240 2241 auto* length = MArrayBufferByteLength::New(alloc(), obj); 2242 add(length); 2243 2244 auto* lengthDouble = MIntPtrToDouble::New(alloc(), length); 2245 add(lengthDouble); 2246 2247 pushResult(lengthDouble); 2248 return true; 2249 } 2250 2251 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLengthInt32Result( 2252 ObjOperandId objId) { 2253 MDefinition* obj = getOperand(objId); 2254 2255 // Use a separate instruction for converting the length to Int32, so that we 2256 // can fold the MArrayBufferViewLength instruction with length instructions 2257 // added for bounds checks. 2258 2259 auto* length = MArrayBufferViewLength::New(alloc(), obj); 2260 add(length); 2261 2262 auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length); 2263 add(lengthInt32); 2264 2265 pushResult(lengthInt32); 2266 return true; 2267 } 2268 2269 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLengthDoubleResult( 2270 ObjOperandId objId) { 2271 MDefinition* obj = getOperand(objId); 2272 2273 auto* length = MArrayBufferViewLength::New(alloc(), obj); 2274 add(length); 2275 2276 auto* lengthDouble = MIntPtrToDouble::New(alloc(), length); 2277 add(lengthDouble); 2278 2279 pushResult(lengthDouble); 2280 return true; 2281 } 2282 2283 bool WarpCacheIRTranspiler::emitLoadArrayBufferViewLength( 2284 ObjOperandId objId, IntPtrOperandId resultId) { 2285 MDefinition* obj = getOperand(objId); 2286 2287 auto* length = MArrayBufferViewLength::New(alloc(), obj); 2288 add(length); 2289 2290 return defineOperand(resultId, length); 2291 } 2292 2293 bool WarpCacheIRTranspiler::emitLoadStringLengthResult(StringOperandId strId) { 2294 MDefinition* str = getOperand(strId); 2295 2296 auto* length = MStringLength::New(alloc(), str); 2297 add(length); 2298 2299 pushResult(length); 2300 return true; 2301 } 2302 2303 MInstruction* WarpCacheIRTranspiler::addBoundsCheck(MDefinition* index, 2304 MDefinition* length) { 2305 MInstruction* check = MBoundsCheck::New(alloc(), index, length); 2306 add(check); 2307 2308 if (snapshot().bailoutInfo().failedBoundsCheck()) { 2309 check->setNotMovable(); 2310 } 2311 2312 if (JitOptions.spectreIndexMasking) { 2313 // Use a separate MIR instruction for the index masking. Doing this as 2314 // part of MBoundsCheck would be unsound because bounds checks can be 2315 // optimized or eliminated completely. Consider this: 2316 // 2317 // for (var i = 0; i < x; i++) 2318 // res = arr[i]; 2319 // 2320 // If we can prove |x < arr.length|, we are able to eliminate the bounds 2321 // check, but we should not get rid of the index masking because the 2322 // |i < x| branch could still be mispredicted. 2323 // 2324 // Using a separate instruction lets us eliminate the bounds check 2325 // without affecting the index masking. 2326 check = MSpectreMaskIndex::New(alloc(), check, length); 2327 add(check); 2328 } 2329 2330 return check; 2331 } 2332 2333 bool WarpCacheIRTranspiler::emitLoadDenseElementResult( 2334 ObjOperandId objId, Int32OperandId indexId, bool expectPackedElements) { 2335 MDefinition* obj = getOperand(objId); 2336 MDefinition* index = getOperand(indexId); 2337 2338 auto* elements = MElements::New(alloc(), obj); 2339 add(elements); 2340 2341 auto* length = MInitializedLength::New(alloc(), elements); 2342 add(length); 2343 2344 index = addBoundsCheck(index, length); 2345 2346 if (expectPackedElements) { 2347 auto* guardPacked = MGuardElementsArePacked::New(alloc(), elements); 2348 add(guardPacked); 2349 } 2350 2351 bool needsHoleCheck = !expectPackedElements; 2352 auto* load = MLoadElement::New(alloc(), elements, index, needsHoleCheck); 2353 add(load); 2354 2355 pushResult(load); 2356 return true; 2357 } 2358 2359 bool WarpCacheIRTranspiler::emitLoadDenseElementHoleResult( 2360 ObjOperandId objId, Int32OperandId indexId) { 2361 MDefinition* obj = getOperand(objId); 2362 MDefinition* index = getOperand(indexId); 2363 2364 auto* elements = MElements::New(alloc(), obj); 2365 add(elements); 2366 2367 auto* length = MInitializedLength::New(alloc(), elements); 2368 add(length); 2369 2370 auto* load = MLoadElementHole::New(alloc(), elements, index, length); 2371 add(load); 2372 2373 pushResult(load); 2374 return true; 2375 } 2376 2377 bool WarpCacheIRTranspiler::emitCallGetSparseElementResult( 2378 ObjOperandId objId, Int32OperandId indexId) { 2379 MDefinition* obj = getOperand(objId); 2380 MDefinition* index = getOperand(indexId); 2381 2382 auto* call = MCallGetSparseElement::New(alloc(), obj, index); 2383 addEffectful(call); 2384 2385 pushResult(call); 2386 return resumeAfter(call); 2387 } 2388 2389 bool WarpCacheIRTranspiler::emitCallNativeGetElementResult( 2390 ObjOperandId objId, Int32OperandId indexId) { 2391 MDefinition* obj = getOperand(objId); 2392 MDefinition* index = getOperand(indexId); 2393 2394 auto* call = MCallNativeGetElement::New(alloc(), obj, index); 2395 addEffectful(call); 2396 2397 pushResult(call); 2398 return resumeAfter(call); 2399 } 2400 2401 bool WarpCacheIRTranspiler::emitCallNativeGetElementSuperResult( 2402 ObjOperandId objId, Int32OperandId indexId, ValOperandId receiverId) { 2403 MDefinition* obj = getOperand(objId); 2404 MDefinition* index = getOperand(indexId); 2405 MDefinition* receiver = getOperand(receiverId); 2406 2407 auto* call = MCallNativeGetElementSuper::New(alloc(), obj, index, receiver); 2408 addEffectful(call); 2409 2410 pushResult(call); 2411 return resumeAfter(call); 2412 } 2413 2414 bool WarpCacheIRTranspiler::emitLoadDenseElementExistsResult( 2415 ObjOperandId objId, Int32OperandId indexId) { 2416 MDefinition* obj = getOperand(objId); 2417 MDefinition* index = getOperand(indexId); 2418 2419 // Get the elements vector. 2420 auto* elements = MElements::New(alloc(), obj); 2421 add(elements); 2422 2423 auto* length = MInitializedLength::New(alloc(), elements); 2424 add(length); 2425 2426 // Check if id < initLength. 2427 index = addBoundsCheck(index, length); 2428 2429 // And check elem[id] is not a hole. 2430 auto* guard = MGuardElementNotHole::New(alloc(), elements, index); 2431 add(guard); 2432 2433 pushResult(constant(BooleanValue(true))); 2434 return true; 2435 } 2436 2437 bool WarpCacheIRTranspiler::emitLoadDenseElementHoleExistsResult( 2438 ObjOperandId objId, Int32OperandId indexId) { 2439 MDefinition* obj = getOperand(objId); 2440 MDefinition* index = getOperand(indexId); 2441 2442 // Get the elements vector. 2443 auto* elements = MElements::New(alloc(), obj); 2444 add(elements); 2445 2446 auto* length = MInitializedLength::New(alloc(), elements); 2447 add(length); 2448 2449 // Check if id < initLength and elem[id] not a hole. 2450 auto* ins = MInArray::New(alloc(), elements, index, length); 2451 add(ins); 2452 2453 pushResult(ins); 2454 return true; 2455 } 2456 2457 bool WarpCacheIRTranspiler::emitCallObjectHasSparseElementResult( 2458 ObjOperandId objId, Int32OperandId indexId) { 2459 MDefinition* obj = getOperand(objId); 2460 MDefinition* index = getOperand(indexId); 2461 2462 auto* ins = MCallObjectHasSparseElement::New(alloc(), obj, index); 2463 add(ins); 2464 2465 pushResult(ins); 2466 return true; 2467 } 2468 2469 MInstruction* WarpCacheIRTranspiler::emitTypedArrayLength( 2470 ArrayBufferViewKind viewKind, MDefinition* obj) { 2471 if (viewKind == ArrayBufferViewKind::FixedLength || 2472 viewKind == ArrayBufferViewKind::Immutable) { 2473 auto* length = MArrayBufferViewLength::New(alloc(), obj); 2474 add(length); 2475 2476 return length; 2477 } 2478 2479 // Bounds check doesn't require a memory barrier. See IsValidIntegerIndex 2480 // abstract operation which reads the underlying buffer byte length using 2481 // "unordered" memory order. 2482 auto barrier = MemoryBarrierRequirement::NotRequired; 2483 2484 // Movable and removable because no memory barrier is needed. 2485 auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier); 2486 length->setMovable(); 2487 length->setNotGuard(); 2488 add(length); 2489 2490 return length; 2491 } 2492 2493 bool WarpCacheIRTranspiler::emitLoadTypedArrayElementExistsResult( 2494 ObjOperandId objId, IntPtrOperandId indexId, ArrayBufferViewKind viewKind) { 2495 MDefinition* obj = getOperand(objId); 2496 MDefinition* index = getOperand(indexId); 2497 2498 auto* length = emitTypedArrayLength(viewKind, obj); 2499 2500 // Unsigned comparison to catch negative indices. 2501 auto* ins = MCompare::New(alloc(), index, length, JSOp::Lt, 2502 MCompare::Compare_UIntPtr); 2503 add(ins); 2504 2505 pushResult(ins); 2506 return true; 2507 } 2508 2509 static MIRType MIRTypeForArrayBufferViewRead(Scalar::Type arrayType, 2510 bool forceDoubleForUint32) { 2511 switch (arrayType) { 2512 case Scalar::Int8: 2513 case Scalar::Uint8: 2514 case Scalar::Uint8Clamped: 2515 case Scalar::Int16: 2516 case Scalar::Uint16: 2517 case Scalar::Int32: 2518 return MIRType::Int32; 2519 case Scalar::Uint32: 2520 return forceDoubleForUint32 ? MIRType::Double : MIRType::Int32; 2521 case Scalar::Float16: 2522 case Scalar::Float32: 2523 return MIRType::Float32; 2524 case Scalar::Float64: 2525 return MIRType::Double; 2526 case Scalar::BigInt64: 2527 case Scalar::BigUint64: 2528 return MIRType::Int64; 2529 default: 2530 break; 2531 } 2532 MOZ_CRASH("Unknown typed array type"); 2533 } 2534 2535 bool WarpCacheIRTranspiler::emitLoadTypedArrayElementResult( 2536 ObjOperandId objId, IntPtrOperandId indexId, Scalar::Type elementType, 2537 bool handleOOB, bool forceDoubleForUint32, ArrayBufferViewKind viewKind) { 2538 MDefinition* obj = getOperand(objId); 2539 MDefinition* index = getOperand(indexId); 2540 2541 auto* length = emitTypedArrayLength(viewKind, obj); 2542 2543 if (!handleOOB) { 2544 // MLoadTypedArrayElementHole does the bounds checking. 2545 index = addBoundsCheck(index, length); 2546 } 2547 2548 auto* elements = MArrayBufferViewElements::New(alloc(), obj); 2549 add(elements); 2550 2551 if (handleOOB) { 2552 auto* load = MLoadTypedArrayElementHole::New( 2553 alloc(), elements, index, length, elementType, forceDoubleForUint32); 2554 add(load); 2555 2556 pushResult(load); 2557 return true; 2558 } 2559 2560 auto* load = MLoadUnboxedScalar::New(alloc(), elements, index, elementType); 2561 load->setResultType( 2562 MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32)); 2563 add(load); 2564 2565 MInstruction* result = load; 2566 if (Scalar::isBigIntType(elementType)) { 2567 result = MInt64ToBigInt::New(alloc(), load, 2568 Scalar::isSignedIntType(elementType)); 2569 add(result); 2570 } 2571 2572 pushResult(result); 2573 return true; 2574 } 2575 2576 bool WarpCacheIRTranspiler::emitTypedArrayFillResult(ObjOperandId objId, 2577 uint32_t fillValueId, 2578 IntPtrOperandId startId, 2579 IntPtrOperandId endId, 2580 Scalar::Type elementType) { 2581 MDefinition* obj = getOperand(objId); 2582 MDefinition* fillValue = getOperand(ValOperandId(fillValueId)); 2583 MDefinition* start = getOperand(startId); 2584 MDefinition* end = getOperand(endId); 2585 2586 auto* ins = 2587 MTypedArrayFill::New(alloc(), obj, fillValue, start, end, elementType); 2588 addEffectful(ins); 2589 2590 pushResult(obj); 2591 return resumeAfter(ins); 2592 } 2593 2594 bool WarpCacheIRTranspiler::emitTypedArraySetResult(ObjOperandId targetId, 2595 ObjOperandId sourceId, 2596 IntPtrOperandId offsetId, 2597 bool canUseBitwiseCopy) { 2598 MDefinition* target = getOperand(targetId); 2599 MDefinition* source = getOperand(sourceId); 2600 MDefinition* offset = getOperand(offsetId); 2601 2602 auto* targetLength = MArrayBufferViewLength::New(alloc(), target); 2603 add(targetLength); 2604 2605 auto* sourceLength = MArrayBufferViewLength::New(alloc(), source); 2606 add(sourceLength); 2607 2608 auto* guardedOffset = MGuardTypedArraySetOffset::New( 2609 alloc(), offset, targetLength, sourceLength); 2610 add(guardedOffset); 2611 2612 auto* ins = MTypedArraySet::New(alloc(), target, source, guardedOffset, 2613 canUseBitwiseCopy); 2614 addEffectful(ins); 2615 2616 pushResult(constant(UndefinedValue())); 2617 return resumeAfter(ins); 2618 } 2619 2620 bool WarpCacheIRTranspiler::emitTypedArraySubarrayResult( 2621 uint32_t templateObjectOffset, ObjOperandId objId, IntPtrOperandId startId, 2622 IntPtrOperandId endId) { 2623 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 2624 MDefinition* obj = getOperand(objId); 2625 MDefinition* start = getOperand(startId); 2626 MDefinition* end = getOperand(endId); 2627 2628 auto* srcLength = MArrayBufferViewLength::New(alloc(), obj); 2629 add(srcLength); 2630 2631 auto* actualStart = MToIntegerIndex::New(alloc(), start, srcLength); 2632 add(actualStart); 2633 2634 auto* actualEnd = MToIntegerIndex::New(alloc(), end, srcLength); 2635 add(actualEnd); 2636 2637 auto* minStart = 2638 MMinMax::NewMin(alloc(), actualStart, actualEnd, MIRType::IntPtr); 2639 add(minStart); 2640 2641 auto* length = MSub::New(alloc(), actualEnd, minStart, MIRType::IntPtr); 2642 add(length); 2643 2644 // TODO: support pre-tenuring. 2645 gc::Heap heap = gc::Heap::Default; 2646 2647 auto* ins = MTypedArraySubarray::New(alloc(), obj, actualStart, length, 2648 templateObj, heap); 2649 addEffectful(ins); 2650 2651 pushResult(ins); 2652 return resumeAfter(ins); 2653 } 2654 2655 bool WarpCacheIRTranspiler::emitLinearizeForCharAccess( 2656 StringOperandId strId, Int32OperandId indexId, StringOperandId resultId) { 2657 MDefinition* str = getOperand(strId); 2658 MDefinition* index = getOperand(indexId); 2659 2660 auto* ins = MLinearizeForCharAccess::New(alloc(), str, index); 2661 add(ins); 2662 2663 return defineOperand(resultId, ins); 2664 } 2665 2666 bool WarpCacheIRTranspiler::emitLinearizeForCodePointAccess( 2667 StringOperandId strId, Int32OperandId indexId, StringOperandId resultId) { 2668 MDefinition* str = getOperand(strId); 2669 MDefinition* index = getOperand(indexId); 2670 2671 auto* ins = MLinearizeForCodePointAccess::New(alloc(), str, index); 2672 add(ins); 2673 2674 return defineOperand(resultId, ins); 2675 } 2676 2677 bool WarpCacheIRTranspiler::emitToRelativeStringIndex(Int32OperandId indexId, 2678 StringOperandId strId, 2679 Int32OperandId resultId) { 2680 MDefinition* str = getOperand(strId); 2681 MDefinition* index = getOperand(indexId); 2682 2683 auto* length = MStringLength::New(alloc(), str); 2684 add(length); 2685 2686 auto* ins = MToRelativeStringIndex::New(alloc(), index, length); 2687 add(ins); 2688 2689 return defineOperand(resultId, ins); 2690 } 2691 2692 bool WarpCacheIRTranspiler::emitLoadStringCharResult(StringOperandId strId, 2693 Int32OperandId indexId, 2694 bool handleOOB) { 2695 MDefinition* str = getOperand(strId); 2696 MDefinition* index = getOperand(indexId); 2697 2698 if (handleOOB) { 2699 auto* charCode = MCharCodeAtOrNegative::New(alloc(), str, index); 2700 add(charCode); 2701 2702 auto* fromCharCode = MFromCharCodeEmptyIfNegative::New(alloc(), charCode); 2703 add(fromCharCode); 2704 2705 pushResult(fromCharCode); 2706 return true; 2707 } 2708 2709 auto* length = MStringLength::New(alloc(), str); 2710 add(length); 2711 2712 index = addBoundsCheck(index, length); 2713 2714 auto* charCode = MCharCodeAt::New(alloc(), str, index); 2715 add(charCode); 2716 2717 auto* fromCharCode = MFromCharCode::New(alloc(), charCode); 2718 add(fromCharCode); 2719 2720 pushResult(fromCharCode); 2721 return true; 2722 } 2723 2724 bool WarpCacheIRTranspiler::emitLoadStringAtResult(StringOperandId strId, 2725 Int32OperandId indexId, 2726 bool handleOOB) { 2727 MDefinition* str = getOperand(strId); 2728 MDefinition* index = getOperand(indexId); 2729 2730 if (handleOOB) { 2731 auto* charCode = MCharCodeAtOrNegative::New(alloc(), str, index); 2732 add(charCode); 2733 2734 auto* fromCharCode = 2735 MFromCharCodeUndefinedIfNegative::New(alloc(), charCode); 2736 add(fromCharCode); 2737 2738 pushResult(fromCharCode); 2739 return true; 2740 } 2741 2742 auto* length = MStringLength::New(alloc(), str); 2743 add(length); 2744 2745 index = addBoundsCheck(index, length); 2746 2747 auto* charCode = MCharCodeAt::New(alloc(), str, index); 2748 add(charCode); 2749 2750 auto* fromCharCode = MFromCharCode::New(alloc(), charCode); 2751 add(fromCharCode); 2752 2753 pushResult(fromCharCode); 2754 return true; 2755 } 2756 2757 bool WarpCacheIRTranspiler::emitLoadStringCharCodeResult(StringOperandId strId, 2758 Int32OperandId indexId, 2759 bool handleOOB) { 2760 MDefinition* str = getOperand(strId); 2761 MDefinition* index = getOperand(indexId); 2762 2763 if (handleOOB) { 2764 auto* charCode = MCharCodeAtOrNegative::New(alloc(), str, index); 2765 add(charCode); 2766 2767 auto* ins = MNegativeToNaN::New(alloc(), charCode); 2768 add(ins); 2769 2770 pushResult(ins); 2771 return true; 2772 } 2773 2774 auto* length = MStringLength::New(alloc(), str); 2775 add(length); 2776 2777 index = addBoundsCheck(index, length); 2778 2779 auto* charCode = MCharCodeAt::New(alloc(), str, index); 2780 add(charCode); 2781 2782 pushResult(charCode); 2783 return true; 2784 } 2785 2786 bool WarpCacheIRTranspiler::emitLoadStringCodePointResult( 2787 StringOperandId strId, Int32OperandId indexId, bool handleOOB) { 2788 MDefinition* str = getOperand(strId); 2789 MDefinition* index = getOperand(indexId); 2790 2791 if (handleOOB) { 2792 auto* codePoint = MCodePointAtOrNegative::New(alloc(), str, index); 2793 add(codePoint); 2794 2795 auto* ins = MNegativeToUndefined::New(alloc(), codePoint); 2796 add(ins); 2797 2798 pushResult(ins); 2799 return true; 2800 } 2801 2802 auto* length = MStringLength::New(alloc(), str); 2803 add(length); 2804 2805 index = addBoundsCheck(index, length); 2806 2807 auto* codePoint = MCodePointAt::New(alloc(), str, index); 2808 add(codePoint); 2809 2810 pushResult(codePoint); 2811 return true; 2812 } 2813 2814 bool WarpCacheIRTranspiler::emitNewMapObjectResult( 2815 uint32_t templateObjectOffset) { 2816 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 2817 2818 auto* obj = MNewMapObject::New(alloc(), templateObj); 2819 addEffectful(obj); 2820 2821 pushResult(obj); 2822 return resumeAfter(obj); 2823 } 2824 2825 bool WarpCacheIRTranspiler::emitNewSetObjectResult( 2826 uint32_t templateObjectOffset) { 2827 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 2828 2829 auto* obj = MNewSetObject::New(alloc(), templateObj); 2830 addEffectful(obj); 2831 2832 pushResult(obj); 2833 return resumeAfter(obj); 2834 } 2835 2836 bool WarpCacheIRTranspiler::emitNewMapObjectFromIterableResult( 2837 uint32_t templateObjectOffset, ValOperandId iterableId) { 2838 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 2839 MDefinition* iterable = getOperand(iterableId); 2840 2841 auto* obj = MNewMapObjectFromIterable::New(alloc(), iterable, templateObj); 2842 addEffectful(obj); 2843 2844 pushResult(obj); 2845 return resumeAfter(obj); 2846 } 2847 2848 bool WarpCacheIRTranspiler::emitNewSetObjectFromIterableResult( 2849 uint32_t templateObjectOffset, ValOperandId iterableId) { 2850 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 2851 MDefinition* iterable = getOperand(iterableId); 2852 2853 auto* obj = MNewSetObjectFromIterable::New(alloc(), iterable, templateObj); 2854 addEffectful(obj); 2855 2856 pushResult(obj); 2857 return resumeAfter(obj); 2858 } 2859 2860 bool WarpCacheIRTranspiler::emitNewStringObjectResult( 2861 uint32_t templateObjectOffset, StringOperandId strId) { 2862 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 2863 MDefinition* string = getOperand(strId); 2864 2865 auto* obj = MNewStringObject::New(alloc(), string, templateObj); 2866 addEffectful(obj); 2867 2868 pushResult(obj); 2869 return resumeAfter(obj); 2870 } 2871 2872 bool WarpCacheIRTranspiler::emitStringFromCharCodeResult( 2873 Int32OperandId codeId) { 2874 MDefinition* code = getOperand(codeId); 2875 2876 auto* fromCharCode = MFromCharCode::New(alloc(), code); 2877 add(fromCharCode); 2878 2879 pushResult(fromCharCode); 2880 return true; 2881 } 2882 2883 bool WarpCacheIRTranspiler::emitStringFromCodePointResult( 2884 Int32OperandId codeId) { 2885 MDefinition* code = getOperand(codeId); 2886 2887 auto* fromCodePoint = MFromCodePoint::New(alloc(), code); 2888 add(fromCodePoint); 2889 2890 pushResult(fromCodePoint); 2891 return true; 2892 } 2893 2894 bool WarpCacheIRTranspiler::emitStringIncludesResult( 2895 StringOperandId strId, StringOperandId searchStrId) { 2896 MDefinition* str = getOperand(strId); 2897 MDefinition* searchStr = getOperand(searchStrId); 2898 2899 auto* includes = MStringIncludes::New(alloc(), str, searchStr); 2900 add(includes); 2901 2902 pushResult(includes); 2903 return true; 2904 } 2905 2906 bool WarpCacheIRTranspiler::emitStringIndexOfResult( 2907 StringOperandId strId, StringOperandId searchStrId) { 2908 MDefinition* str = getOperand(strId); 2909 MDefinition* searchStr = getOperand(searchStrId); 2910 2911 auto* indexOf = MStringIndexOf::New(alloc(), str, searchStr); 2912 add(indexOf); 2913 2914 pushResult(indexOf); 2915 return true; 2916 } 2917 2918 bool WarpCacheIRTranspiler::emitStringLastIndexOfResult( 2919 StringOperandId strId, StringOperandId searchStrId) { 2920 MDefinition* str = getOperand(strId); 2921 MDefinition* searchStr = getOperand(searchStrId); 2922 2923 auto* lastIndexOf = MStringLastIndexOf::New(alloc(), str, searchStr); 2924 add(lastIndexOf); 2925 2926 pushResult(lastIndexOf); 2927 return true; 2928 } 2929 2930 bool WarpCacheIRTranspiler::emitStringStartsWithResult( 2931 StringOperandId strId, StringOperandId searchStrId) { 2932 MDefinition* str = getOperand(strId); 2933 MDefinition* searchStr = getOperand(searchStrId); 2934 2935 auto* startsWith = MStringStartsWith::New(alloc(), str, searchStr); 2936 add(startsWith); 2937 2938 pushResult(startsWith); 2939 return true; 2940 } 2941 2942 bool WarpCacheIRTranspiler::emitStringEndsWithResult( 2943 StringOperandId strId, StringOperandId searchStrId) { 2944 MDefinition* str = getOperand(strId); 2945 MDefinition* searchStr = getOperand(searchStrId); 2946 2947 auto* endsWith = MStringEndsWith::New(alloc(), str, searchStr); 2948 add(endsWith); 2949 2950 pushResult(endsWith); 2951 return true; 2952 } 2953 2954 bool WarpCacheIRTranspiler::emitStringToLowerCaseResult(StringOperandId strId) { 2955 MDefinition* str = getOperand(strId); 2956 2957 auto* convert = 2958 MStringConvertCase::New(alloc(), str, MStringConvertCase::LowerCase); 2959 add(convert); 2960 2961 pushResult(convert); 2962 return true; 2963 } 2964 2965 bool WarpCacheIRTranspiler::emitStringToUpperCaseResult(StringOperandId strId) { 2966 MDefinition* str = getOperand(strId); 2967 2968 auto* convert = 2969 MStringConvertCase::New(alloc(), str, MStringConvertCase::UpperCase); 2970 add(convert); 2971 2972 pushResult(convert); 2973 return true; 2974 } 2975 2976 bool WarpCacheIRTranspiler::emitStringTrimResult(StringOperandId strId) { 2977 MDefinition* str = getOperand(strId); 2978 2979 auto* linear = MLinearizeString::New(alloc(), str); 2980 add(linear); 2981 2982 auto* start = MStringTrimStartIndex::New(alloc(), linear); 2983 add(start); 2984 2985 auto* end = MStringTrimEndIndex::New(alloc(), linear, start); 2986 add(end); 2987 2988 // Safe to truncate because both operands are positive and end >= start. 2989 auto* length = MSub::New(alloc(), end, start, MIRType::Int32); 2990 length->setTruncateKind(TruncateKind::Truncate); 2991 add(length); 2992 2993 auto* substr = MSubstr::New(alloc(), linear, start, length); 2994 add(substr); 2995 2996 pushResult(substr); 2997 return true; 2998 } 2999 3000 bool WarpCacheIRTranspiler::emitStringTrimStartResult(StringOperandId strId) { 3001 MDefinition* str = getOperand(strId); 3002 3003 auto* linear = MLinearizeString::New(alloc(), str); 3004 add(linear); 3005 3006 auto* start = MStringTrimStartIndex::New(alloc(), linear); 3007 add(start); 3008 3009 auto* end = MStringLength::New(alloc(), linear); 3010 add(end); 3011 3012 // Safe to truncate because both operands are positive and end >= start. 3013 auto* length = MSub::New(alloc(), end, start, MIRType::Int32); 3014 length->setTruncateKind(TruncateKind::Truncate); 3015 add(length); 3016 3017 auto* substr = MSubstr::New(alloc(), linear, start, length); 3018 add(substr); 3019 3020 pushResult(substr); 3021 return true; 3022 } 3023 3024 bool WarpCacheIRTranspiler::emitStringTrimEndResult(StringOperandId strId) { 3025 MDefinition* str = getOperand(strId); 3026 3027 auto* linear = MLinearizeString::New(alloc(), str); 3028 add(linear); 3029 3030 auto* start = constant(Int32Value(0)); 3031 3032 auto* length = MStringTrimEndIndex::New(alloc(), linear, start); 3033 add(length); 3034 3035 auto* substr = MSubstr::New(alloc(), linear, start, length); 3036 add(substr); 3037 3038 pushResult(substr); 3039 return true; 3040 } 3041 3042 bool WarpCacheIRTranspiler::emitStoreDynamicSlot(ObjOperandId objId, 3043 uint32_t offsetOffset, 3044 ValOperandId rhsId) { 3045 int32_t offset = int32StubField(offsetOffset); 3046 3047 MDefinition* obj = getOperand(objId); 3048 size_t slotIndex = NativeObject::getDynamicSlotIndexFromOffset(offset); 3049 MDefinition* rhs = getOperand(rhsId); 3050 3051 auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs); 3052 add(barrier); 3053 3054 auto* slots = MSlots::New(alloc(), obj); 3055 add(slots); 3056 3057 auto* store = MStoreDynamicSlot::NewBarriered(alloc(), slots, slotIndex, rhs); 3058 addEffectful(store); 3059 return resumeAfter(store); 3060 } 3061 3062 bool WarpCacheIRTranspiler::emitStoreFixedSlot(ObjOperandId objId, 3063 uint32_t offsetOffset, 3064 ValOperandId rhsId) { 3065 int32_t offset = int32StubField(offsetOffset); 3066 3067 MDefinition* obj = getOperand(objId); 3068 size_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset); 3069 MDefinition* rhs = getOperand(rhsId); 3070 3071 auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs); 3072 add(barrier); 3073 3074 auto* store = MStoreFixedSlot::NewBarriered(alloc(), obj, slotIndex, rhs); 3075 addEffectful(store); 3076 return resumeAfter(store); 3077 } 3078 3079 bool WarpCacheIRTranspiler::emitStoreFixedSlotUndefinedResult( 3080 ObjOperandId objId, uint32_t offsetOffset, ValOperandId rhsId) { 3081 int32_t offset = int32StubField(offsetOffset); 3082 3083 MDefinition* obj = getOperand(objId); 3084 size_t slotIndex = NativeObject::getFixedSlotIndexFromOffset(offset); 3085 MDefinition* rhs = getOperand(rhsId); 3086 3087 auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs); 3088 add(barrier); 3089 3090 auto* store = MStoreFixedSlot::NewBarriered(alloc(), obj, slotIndex, rhs); 3091 addEffectful(store); 3092 3093 auto* undef = constant(UndefinedValue()); 3094 pushResult(undef); 3095 3096 return resumeAfter(store); 3097 } 3098 3099 bool WarpCacheIRTranspiler::emitAddAndStoreSlotShared( 3100 MAddAndStoreSlot::Kind kind, ObjOperandId objId, uint32_t offsetOffset, 3101 ValOperandId rhsId, uint32_t newShapeOffset, bool preserveWrapper) { 3102 int32_t offset = int32StubField(offsetOffset); 3103 Shape* shape = shapeStubField(newShapeOffset); 3104 3105 MDefinition* obj = getOperand(objId); 3106 MDefinition* rhs = getOperand(rhsId); 3107 3108 auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs); 3109 add(barrier); 3110 3111 auto* addAndStore = MAddAndStoreSlot::New(alloc(), obj, rhs, kind, offset, 3112 shape, preserveWrapper); 3113 addEffectful(addAndStore); 3114 3115 return resumeAfter(addAndStore); 3116 } 3117 3118 bool WarpCacheIRTranspiler::emitAddAndStoreFixedSlot(ObjOperandId objId, 3119 uint32_t offsetOffset, 3120 ValOperandId rhsId, 3121 uint32_t newShapeOffset, 3122 bool preserveWrapper) { 3123 return emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind::FixedSlot, objId, 3124 offsetOffset, rhsId, newShapeOffset, 3125 preserveWrapper); 3126 } 3127 3128 bool WarpCacheIRTranspiler::emitAddAndStoreDynamicSlot(ObjOperandId objId, 3129 uint32_t offsetOffset, 3130 ValOperandId rhsId, 3131 uint32_t newShapeOffset, 3132 bool preserveWrapper) { 3133 return emitAddAndStoreSlotShared(MAddAndStoreSlot::Kind::DynamicSlot, objId, 3134 offsetOffset, rhsId, newShapeOffset, 3135 preserveWrapper); 3136 } 3137 3138 bool WarpCacheIRTranspiler::emitAllocateAndStoreDynamicSlot( 3139 ObjOperandId objId, uint32_t offsetOffset, ValOperandId rhsId, 3140 uint32_t newShapeOffset, uint32_t numNewSlotsOffset, bool preserveWrapper) { 3141 int32_t offset = int32StubField(offsetOffset); 3142 Shape* shape = shapeStubField(newShapeOffset); 3143 uint32_t numNewSlots = uint32StubField(numNewSlotsOffset); 3144 3145 MDefinition* obj = getOperand(objId); 3146 MDefinition* rhs = getOperand(rhsId); 3147 3148 auto* barrier = MPostWriteBarrier::New(alloc(), obj, rhs); 3149 add(barrier); 3150 3151 auto* allocateAndStore = MAllocateAndStoreSlot::New( 3152 alloc(), obj, rhs, offset, shape, numNewSlots, preserveWrapper); 3153 addEffectful(allocateAndStore); 3154 3155 return resumeAfter(allocateAndStore); 3156 } 3157 3158 bool WarpCacheIRTranspiler::emitAddSlotAndCallAddPropHook( 3159 ObjOperandId objId, ValOperandId rhsId, uint32_t newShapeOffset) { 3160 Shape* shape = shapeStubField(newShapeOffset); 3161 MDefinition* obj = getOperand(objId); 3162 MDefinition* rhs = getOperand(rhsId); 3163 3164 auto* addProp = MAddSlotAndCallAddPropHook::New(alloc(), obj, rhs, shape); 3165 addEffectful(addProp); 3166 3167 return resumeAfter(addProp); 3168 } 3169 3170 bool WarpCacheIRTranspiler::emitStoreDenseElement(ObjOperandId objId, 3171 Int32OperandId indexId, 3172 ValOperandId rhsId, 3173 bool expectPackedElements) { 3174 MDefinition* obj = getOperand(objId); 3175 MDefinition* index = getOperand(indexId); 3176 MDefinition* rhs = getOperand(rhsId); 3177 3178 auto* elements = MElements::New(alloc(), obj); 3179 add(elements); 3180 3181 auto* length = MInitializedLength::New(alloc(), elements); 3182 add(length); 3183 3184 index = addBoundsCheck(index, length); 3185 3186 if (expectPackedElements) { 3187 auto* guardPacked = MGuardElementsArePacked::New(alloc(), elements); 3188 add(guardPacked); 3189 } 3190 3191 auto* barrier = MPostWriteElementBarrier::New(alloc(), obj, rhs, index); 3192 add(barrier); 3193 3194 bool needsHoleCheck = !expectPackedElements; 3195 auto* store = MStoreElement::NewBarriered(alloc(), elements, index, rhs, 3196 needsHoleCheck); 3197 addEffectful(store); 3198 return resumeAfter(store); 3199 } 3200 3201 bool WarpCacheIRTranspiler::emitStoreDenseElementHole(ObjOperandId objId, 3202 Int32OperandId indexId, 3203 ValOperandId rhsId, 3204 bool handleAdd) { 3205 MDefinition* obj = getOperand(objId); 3206 MDefinition* index = getOperand(indexId); 3207 MDefinition* rhs = getOperand(rhsId); 3208 3209 auto* elements = MElements::New(alloc(), obj); 3210 add(elements); 3211 3212 MInstruction* store; 3213 if (handleAdd) { 3214 // TODO(post-Warp): Consider changing MStoreElementHole to match IC code. 3215 store = MStoreElementHole::New(alloc(), obj, elements, index, rhs); 3216 } else { 3217 auto* length = MInitializedLength::New(alloc(), elements); 3218 add(length); 3219 3220 index = addBoundsCheck(index, length); 3221 3222 auto* barrier = MPostWriteElementBarrier::New(alloc(), obj, rhs, index); 3223 add(barrier); 3224 3225 bool needsHoleCheck = false; 3226 store = MStoreElement::NewBarriered(alloc(), elements, index, rhs, 3227 needsHoleCheck); 3228 } 3229 addEffectful(store); 3230 3231 return resumeAfter(store); 3232 } 3233 3234 bool WarpCacheIRTranspiler::emitStoreTypedArrayElement( 3235 ObjOperandId objId, Scalar::Type elementType, IntPtrOperandId indexId, 3236 uint32_t rhsId, bool handleOOB, ArrayBufferViewKind viewKind) { 3237 MDefinition* obj = getOperand(objId); 3238 MDefinition* index = getOperand(indexId); 3239 MDefinition* rhs = getOperand(ValOperandId(rhsId)); 3240 3241 auto* length = emitTypedArrayLength(viewKind, obj); 3242 3243 if (!handleOOB) { 3244 // MStoreTypedArrayElementHole does the bounds checking. 3245 index = addBoundsCheck(index, length); 3246 } 3247 3248 auto* elements = MArrayBufferViewElements::New(alloc(), obj); 3249 add(elements); 3250 3251 MInstruction* store; 3252 if (handleOOB) { 3253 store = MStoreTypedArrayElementHole::New(alloc(), elements, length, index, 3254 rhs, elementType); 3255 } else { 3256 store = 3257 MStoreUnboxedScalar::New(alloc(), elements, index, rhs, elementType); 3258 } 3259 addEffectful(store); 3260 return resumeAfter(store); 3261 } 3262 3263 MInstruction* WarpCacheIRTranspiler::emitDataViewLength( 3264 ArrayBufferViewKind viewKind, MDefinition* obj) { 3265 if (viewKind == ArrayBufferViewKind::FixedLength || 3266 viewKind == ArrayBufferViewKind::Immutable) { 3267 auto* length = MArrayBufferViewLength::New(alloc(), obj); 3268 add(length); 3269 3270 return length; 3271 } 3272 3273 // Bounds check doesn't require a memory barrier. See GetViewValue and 3274 // SetViewValue abstract operations which read the underlying buffer byte 3275 // length using "unordered" memory order. 3276 auto barrier = MemoryBarrierRequirement::NotRequired; 3277 3278 // Movable and removable because no memory barrier is needed. 3279 auto* length = MResizableDataViewByteLength::New(alloc(), obj, barrier); 3280 length->setMovable(); 3281 length->setNotGuard(); 3282 add(length); 3283 3284 return length; 3285 } 3286 3287 void WarpCacheIRTranspiler::addDataViewData(ArrayBufferViewKind viewKind, 3288 MDefinition* obj, Scalar::Type type, 3289 MDefinition** offset, 3290 MInstruction** elements) { 3291 auto* length = emitDataViewLength(viewKind, obj); 3292 3293 // Adjust the length to account for accesses near the end of the dataview. 3294 if (size_t byteSize = Scalar::byteSize(type); byteSize > 1) { 3295 // To ensure |0 <= offset && offset + byteSize <= length|, first adjust the 3296 // length by subtracting |byteSize - 1| (bailing out if that becomes 3297 // negative). 3298 length = MAdjustDataViewLength::New(alloc(), length, byteSize); 3299 add(length); 3300 } 3301 3302 *offset = addBoundsCheck(*offset, length); 3303 3304 *elements = MArrayBufferViewElements::New(alloc(), obj); 3305 add(*elements); 3306 } 3307 3308 bool WarpCacheIRTranspiler::emitLoadDataViewValueResult( 3309 ObjOperandId objId, IntPtrOperandId offsetId, 3310 BooleanOperandId littleEndianId, Scalar::Type elementType, 3311 bool forceDoubleForUint32, ArrayBufferViewKind viewKind) { 3312 MDefinition* obj = getOperand(objId); 3313 MDefinition* offset = getOperand(offsetId); 3314 MDefinition* littleEndian = getOperand(littleEndianId); 3315 3316 // Add bounds check and get the DataViewObject's elements. 3317 MInstruction* elements; 3318 addDataViewData(viewKind, obj, elementType, &offset, &elements); 3319 3320 // Load the element. 3321 MInstruction* load; 3322 if (Scalar::byteSize(elementType) == 1) { 3323 load = MLoadUnboxedScalar::New(alloc(), elements, offset, elementType); 3324 } else { 3325 load = MLoadDataViewElement::New(alloc(), elements, offset, littleEndian, 3326 elementType); 3327 } 3328 add(load); 3329 3330 MIRType knownType = 3331 MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32); 3332 load->setResultType(knownType); 3333 3334 MInstruction* result = load; 3335 if (Scalar::isBigIntType(elementType)) { 3336 result = MInt64ToBigInt::New(alloc(), load, 3337 Scalar::isSignedIntType(elementType)); 3338 add(result); 3339 } 3340 3341 pushResult(result); 3342 return true; 3343 } 3344 3345 bool WarpCacheIRTranspiler::emitStoreDataViewValueResult( 3346 ObjOperandId objId, IntPtrOperandId offsetId, uint32_t valueId, 3347 BooleanOperandId littleEndianId, Scalar::Type elementType, 3348 ArrayBufferViewKind viewKind) { 3349 MDefinition* obj = getOperand(objId); 3350 MDefinition* offset = getOperand(offsetId); 3351 MDefinition* value = getOperand(ValOperandId(valueId)); 3352 MDefinition* littleEndian = getOperand(littleEndianId); 3353 3354 // Add bounds check and get the DataViewObject's elements. 3355 MInstruction* elements; 3356 addDataViewData(viewKind, obj, elementType, &offset, &elements); 3357 3358 // Store the element. 3359 MInstruction* store; 3360 if (Scalar::byteSize(elementType) == 1) { 3361 store = 3362 MStoreUnboxedScalar::New(alloc(), elements, offset, value, elementType); 3363 } else { 3364 store = MStoreDataViewElement::New(alloc(), elements, offset, value, 3365 littleEndian, elementType); 3366 } 3367 addEffectful(store); 3368 3369 pushResult(constant(UndefinedValue())); 3370 3371 return resumeAfter(store); 3372 } 3373 3374 bool WarpCacheIRTranspiler::emitInt32IncResult(Int32OperandId inputId) { 3375 MDefinition* input = getOperand(inputId); 3376 3377 auto* constOne = MConstant::NewInt32(alloc(), 1); 3378 add(constOne); 3379 3380 auto* ins = MAdd::New(alloc(), input, constOne, MIRType::Int32); 3381 add(ins); 3382 3383 pushResult(ins); 3384 return true; 3385 } 3386 3387 bool WarpCacheIRTranspiler::emitDoubleIncResult(NumberOperandId inputId) { 3388 MDefinition* input = getOperand(inputId); 3389 3390 auto* constOne = MConstant::NewDouble(alloc(), 1.0); 3391 add(constOne); 3392 3393 auto* ins = MAdd::New(alloc(), input, constOne, MIRType::Double); 3394 add(ins); 3395 3396 pushResult(ins); 3397 return true; 3398 } 3399 3400 bool WarpCacheIRTranspiler::emitInt32DecResult(Int32OperandId inputId) { 3401 MDefinition* input = getOperand(inputId); 3402 3403 auto* constOne = MConstant::NewInt32(alloc(), 1); 3404 add(constOne); 3405 3406 auto* ins = MSub::New(alloc(), input, constOne, MIRType::Int32); 3407 add(ins); 3408 3409 pushResult(ins); 3410 return true; 3411 } 3412 3413 bool WarpCacheIRTranspiler::emitDoubleDecResult(NumberOperandId inputId) { 3414 MDefinition* input = getOperand(inputId); 3415 3416 auto* constOne = MConstant::NewDouble(alloc(), 1.0); 3417 add(constOne); 3418 3419 auto* ins = MSub::New(alloc(), input, constOne, MIRType::Double); 3420 add(ins); 3421 3422 pushResult(ins); 3423 return true; 3424 } 3425 3426 bool WarpCacheIRTranspiler::emitInt32NegationResult(Int32OperandId inputId) { 3427 MDefinition* input = getOperand(inputId); 3428 3429 auto* constNegOne = MConstant::NewInt32(alloc(), -1); 3430 add(constNegOne); 3431 3432 auto* ins = MMul::New(alloc(), input, constNegOne, MIRType::Int32); 3433 add(ins); 3434 3435 pushResult(ins); 3436 return true; 3437 } 3438 3439 bool WarpCacheIRTranspiler::emitDoubleNegationResult(NumberOperandId inputId) { 3440 MDefinition* input = getOperand(inputId); 3441 3442 auto* constNegOne = MConstant::NewDouble(alloc(), -1.0); 3443 add(constNegOne); 3444 3445 auto* ins = MMul::New(alloc(), input, constNegOne, MIRType::Double); 3446 add(ins); 3447 3448 pushResult(ins); 3449 return true; 3450 } 3451 3452 bool WarpCacheIRTranspiler::emitInt32NotResult(Int32OperandId inputId) { 3453 MDefinition* input = getOperand(inputId); 3454 3455 auto* ins = MBitNot::New(alloc(), input, MIRType::Int32); 3456 add(ins); 3457 3458 pushResult(ins); 3459 return true; 3460 } 3461 3462 template <typename T> 3463 bool WarpCacheIRTranspiler::emitDoubleBinaryArithResult(NumberOperandId lhsId, 3464 NumberOperandId rhsId) { 3465 MDefinition* lhs = getOperand(lhsId); 3466 MDefinition* rhs = getOperand(rhsId); 3467 3468 auto* ins = T::New(alloc(), lhs, rhs, MIRType::Double); 3469 add(ins); 3470 3471 pushResult(ins); 3472 return true; 3473 } 3474 3475 bool WarpCacheIRTranspiler::emitDoubleAddResult(NumberOperandId lhsId, 3476 NumberOperandId rhsId) { 3477 return emitDoubleBinaryArithResult<MAdd>(lhsId, rhsId); 3478 } 3479 3480 bool WarpCacheIRTranspiler::emitDoubleSubResult(NumberOperandId lhsId, 3481 NumberOperandId rhsId) { 3482 return emitDoubleBinaryArithResult<MSub>(lhsId, rhsId); 3483 } 3484 3485 bool WarpCacheIRTranspiler::emitDoubleMulResult(NumberOperandId lhsId, 3486 NumberOperandId rhsId) { 3487 return emitDoubleBinaryArithResult<MMul>(lhsId, rhsId); 3488 } 3489 3490 bool WarpCacheIRTranspiler::emitDoubleDivResult(NumberOperandId lhsId, 3491 NumberOperandId rhsId) { 3492 return emitDoubleBinaryArithResult<MDiv>(lhsId, rhsId); 3493 } 3494 3495 bool WarpCacheIRTranspiler::emitDoubleModResult(NumberOperandId lhsId, 3496 NumberOperandId rhsId) { 3497 return emitDoubleBinaryArithResult<MMod>(lhsId, rhsId); 3498 } 3499 3500 bool WarpCacheIRTranspiler::emitDoublePowResult(NumberOperandId lhsId, 3501 NumberOperandId rhsId) { 3502 return emitDoubleBinaryArithResult<MPow>(lhsId, rhsId); 3503 } 3504 3505 template <typename T> 3506 bool WarpCacheIRTranspiler::emitInt32BinaryArithResult(Int32OperandId lhsId, 3507 Int32OperandId rhsId) { 3508 MDefinition* lhs = getOperand(lhsId); 3509 MDefinition* rhs = getOperand(rhsId); 3510 3511 auto* ins = T::New(alloc(), lhs, rhs, MIRType::Int32); 3512 add(ins); 3513 3514 pushResult(ins); 3515 return true; 3516 } 3517 3518 bool WarpCacheIRTranspiler::emitInt32AddResult(Int32OperandId lhsId, 3519 Int32OperandId rhsId) { 3520 return emitInt32BinaryArithResult<MAdd>(lhsId, rhsId); 3521 } 3522 3523 bool WarpCacheIRTranspiler::emitInt32SubResult(Int32OperandId lhsId, 3524 Int32OperandId rhsId) { 3525 return emitInt32BinaryArithResult<MSub>(lhsId, rhsId); 3526 } 3527 3528 bool WarpCacheIRTranspiler::emitInt32MulResult(Int32OperandId lhsId, 3529 Int32OperandId rhsId) { 3530 return emitInt32BinaryArithResult<MMul>(lhsId, rhsId); 3531 } 3532 3533 bool WarpCacheIRTranspiler::emitInt32DivResult(Int32OperandId lhsId, 3534 Int32OperandId rhsId) { 3535 return emitInt32BinaryArithResult<MDiv>(lhsId, rhsId); 3536 } 3537 3538 bool WarpCacheIRTranspiler::emitInt32ModResult(Int32OperandId lhsId, 3539 Int32OperandId rhsId) { 3540 return emitInt32BinaryArithResult<MMod>(lhsId, rhsId); 3541 } 3542 3543 bool WarpCacheIRTranspiler::emitInt32PowResult(Int32OperandId lhsId, 3544 Int32OperandId rhsId) { 3545 return emitInt32BinaryArithResult<MPow>(lhsId, rhsId); 3546 } 3547 3548 bool WarpCacheIRTranspiler::emitInt32BitOrResult(Int32OperandId lhsId, 3549 Int32OperandId rhsId) { 3550 return emitInt32BinaryArithResult<MBitOr>(lhsId, rhsId); 3551 } 3552 3553 bool WarpCacheIRTranspiler::emitInt32BitXorResult(Int32OperandId lhsId, 3554 Int32OperandId rhsId) { 3555 return emitInt32BinaryArithResult<MBitXor>(lhsId, rhsId); 3556 } 3557 3558 bool WarpCacheIRTranspiler::emitInt32BitAndResult(Int32OperandId lhsId, 3559 Int32OperandId rhsId) { 3560 return emitInt32BinaryArithResult<MBitAnd>(lhsId, rhsId); 3561 } 3562 3563 bool WarpCacheIRTranspiler::emitInt32LeftShiftResult(Int32OperandId lhsId, 3564 Int32OperandId rhsId) { 3565 return emitInt32BinaryArithResult<MLsh>(lhsId, rhsId); 3566 } 3567 3568 bool WarpCacheIRTranspiler::emitInt32RightShiftResult(Int32OperandId lhsId, 3569 Int32OperandId rhsId) { 3570 return emitInt32BinaryArithResult<MRsh>(lhsId, rhsId); 3571 } 3572 3573 bool WarpCacheIRTranspiler::emitInt32URightShiftResult(Int32OperandId lhsId, 3574 Int32OperandId rhsId, 3575 bool forceDouble) { 3576 MDefinition* lhs = getOperand(lhsId); 3577 MDefinition* rhs = getOperand(rhsId); 3578 3579 MIRType specialization = forceDouble ? MIRType::Double : MIRType::Int32; 3580 auto* ins = MUrsh::New(alloc(), lhs, rhs, specialization); 3581 add(ins); 3582 3583 pushResult(ins); 3584 return true; 3585 } 3586 3587 template <typename T> 3588 bool WarpCacheIRTranspiler::emitBigIntBinaryArithResult(BigIntOperandId lhsId, 3589 BigIntOperandId rhsId) { 3590 MDefinition* lhs = getOperand(lhsId); 3591 MDefinition* rhs = getOperand(rhsId); 3592 3593 auto* ins = T::New(alloc(), lhs, rhs); 3594 add(ins); 3595 3596 pushResult(ins); 3597 return true; 3598 } 3599 3600 bool WarpCacheIRTranspiler::emitBigIntAddResult(BigIntOperandId lhsId, 3601 BigIntOperandId rhsId) { 3602 return emitBigIntBinaryArithResult<MBigIntAdd>(lhsId, rhsId); 3603 } 3604 3605 bool WarpCacheIRTranspiler::emitBigIntSubResult(BigIntOperandId lhsId, 3606 BigIntOperandId rhsId) { 3607 return emitBigIntBinaryArithResult<MBigIntSub>(lhsId, rhsId); 3608 } 3609 3610 bool WarpCacheIRTranspiler::emitBigIntMulResult(BigIntOperandId lhsId, 3611 BigIntOperandId rhsId) { 3612 return emitBigIntBinaryArithResult<MBigIntMul>(lhsId, rhsId); 3613 } 3614 3615 template <typename T> 3616 bool WarpCacheIRTranspiler::emitBigIntBinaryArithEffectfulResult( 3617 BigIntOperandId lhsId, BigIntOperandId rhsId) { 3618 MDefinition* lhs = getOperand(lhsId); 3619 MDefinition* rhs = getOperand(rhsId); 3620 3621 auto* ins = T::New(alloc(), lhs, rhs); 3622 3623 if (ins->isEffectful()) { 3624 addEffectful(ins); 3625 3626 pushResult(ins); 3627 return resumeAfter(ins); 3628 } 3629 3630 add(ins); 3631 3632 pushResult(ins); 3633 return true; 3634 } 3635 3636 bool WarpCacheIRTranspiler::emitBigIntDivResult(BigIntOperandId lhsId, 3637 BigIntOperandId rhsId) { 3638 return emitBigIntBinaryArithEffectfulResult<MBigIntDiv>(lhsId, rhsId); 3639 } 3640 3641 bool WarpCacheIRTranspiler::emitBigIntModResult(BigIntOperandId lhsId, 3642 BigIntOperandId rhsId) { 3643 return emitBigIntBinaryArithEffectfulResult<MBigIntMod>(lhsId, rhsId); 3644 } 3645 3646 bool WarpCacheIRTranspiler::emitBigIntPowResult(BigIntOperandId lhsId, 3647 BigIntOperandId rhsId) { 3648 return emitBigIntBinaryArithEffectfulResult<MBigIntPow>(lhsId, rhsId); 3649 } 3650 3651 bool WarpCacheIRTranspiler::emitBigIntBitAndResult(BigIntOperandId lhsId, 3652 BigIntOperandId rhsId) { 3653 return emitBigIntBinaryArithResult<MBigIntBitAnd>(lhsId, rhsId); 3654 } 3655 3656 bool WarpCacheIRTranspiler::emitBigIntBitOrResult(BigIntOperandId lhsId, 3657 BigIntOperandId rhsId) { 3658 return emitBigIntBinaryArithResult<MBigIntBitOr>(lhsId, rhsId); 3659 } 3660 3661 bool WarpCacheIRTranspiler::emitBigIntBitXorResult(BigIntOperandId lhsId, 3662 BigIntOperandId rhsId) { 3663 return emitBigIntBinaryArithResult<MBigIntBitXor>(lhsId, rhsId); 3664 } 3665 3666 bool WarpCacheIRTranspiler::emitBigIntLeftShiftResult(BigIntOperandId lhsId, 3667 BigIntOperandId rhsId) { 3668 return emitBigIntBinaryArithResult<MBigIntLsh>(lhsId, rhsId); 3669 } 3670 3671 bool WarpCacheIRTranspiler::emitBigIntRightShiftResult(BigIntOperandId lhsId, 3672 BigIntOperandId rhsId) { 3673 return emitBigIntBinaryArithResult<MBigIntRsh>(lhsId, rhsId); 3674 } 3675 3676 template <typename T> 3677 bool WarpCacheIRTranspiler::emitBigIntUnaryArithResult( 3678 BigIntOperandId inputId) { 3679 MDefinition* input = getOperand(inputId); 3680 3681 auto* ins = T::New(alloc(), input); 3682 add(ins); 3683 3684 pushResult(ins); 3685 return true; 3686 } 3687 3688 bool WarpCacheIRTranspiler::emitBigIntIncResult(BigIntOperandId inputId) { 3689 return emitBigIntUnaryArithResult<MBigIntIncrement>(inputId); 3690 } 3691 3692 bool WarpCacheIRTranspiler::emitBigIntDecResult(BigIntOperandId inputId) { 3693 return emitBigIntUnaryArithResult<MBigIntDecrement>(inputId); 3694 } 3695 3696 bool WarpCacheIRTranspiler::emitBigIntNegationResult(BigIntOperandId inputId) { 3697 return emitBigIntUnaryArithResult<MBigIntNegate>(inputId); 3698 } 3699 3700 bool WarpCacheIRTranspiler::emitBigIntNotResult(BigIntOperandId inputId) { 3701 return emitBigIntUnaryArithResult<MBigIntBitNot>(inputId); 3702 } 3703 3704 bool WarpCacheIRTranspiler::emitBigIntToIntPtr(BigIntOperandId inputId, 3705 IntPtrOperandId resultId) { 3706 MDefinition* input = getOperand(inputId); 3707 3708 auto* ins = MBigIntToIntPtr::New(alloc(), input); 3709 add(ins); 3710 3711 return defineOperand(resultId, ins); 3712 } 3713 3714 bool WarpCacheIRTranspiler::emitIntPtrToBigIntResult(IntPtrOperandId inputId) { 3715 MDefinition* input = getOperand(inputId); 3716 3717 auto* ins = MIntPtrToBigInt::New(alloc(), input); 3718 add(ins); 3719 3720 pushResult(ins); 3721 return true; 3722 } 3723 3724 template <typename T> 3725 bool WarpCacheIRTranspiler::emitBigIntPtrBinaryArith(IntPtrOperandId lhsId, 3726 IntPtrOperandId rhsId, 3727 IntPtrOperandId resultId) { 3728 MDefinition* lhs = getOperand(lhsId); 3729 MDefinition* rhs = getOperand(rhsId); 3730 3731 auto* ins = T::New(alloc(), lhs, rhs); 3732 add(ins); 3733 3734 return defineOperand(resultId, ins); 3735 } 3736 3737 bool WarpCacheIRTranspiler::emitBigIntPtrAdd(IntPtrOperandId lhsId, 3738 IntPtrOperandId rhsId, 3739 IntPtrOperandId resultId) { 3740 return emitBigIntPtrBinaryArith<MBigIntPtrAdd>(lhsId, rhsId, resultId); 3741 } 3742 3743 bool WarpCacheIRTranspiler::emitBigIntPtrSub(IntPtrOperandId lhsId, 3744 IntPtrOperandId rhsId, 3745 IntPtrOperandId resultId) { 3746 return emitBigIntPtrBinaryArith<MBigIntPtrSub>(lhsId, rhsId, resultId); 3747 } 3748 3749 bool WarpCacheIRTranspiler::emitBigIntPtrMul(IntPtrOperandId lhsId, 3750 IntPtrOperandId rhsId, 3751 IntPtrOperandId resultId) { 3752 return emitBigIntPtrBinaryArith<MBigIntPtrMul>(lhsId, rhsId, resultId); 3753 } 3754 3755 bool WarpCacheIRTranspiler::emitBigIntPtrDiv(IntPtrOperandId lhsId, 3756 IntPtrOperandId rhsId, 3757 IntPtrOperandId resultId) { 3758 return emitBigIntPtrBinaryArith<MBigIntPtrDiv>(lhsId, rhsId, resultId); 3759 } 3760 3761 bool WarpCacheIRTranspiler::emitBigIntPtrMod(IntPtrOperandId lhsId, 3762 IntPtrOperandId rhsId, 3763 IntPtrOperandId resultId) { 3764 return emitBigIntPtrBinaryArith<MBigIntPtrMod>(lhsId, rhsId, resultId); 3765 } 3766 3767 bool WarpCacheIRTranspiler::emitBigIntPtrPow(IntPtrOperandId lhsId, 3768 IntPtrOperandId rhsId, 3769 IntPtrOperandId resultId) { 3770 return emitBigIntPtrBinaryArith<MBigIntPtrPow>(lhsId, rhsId, resultId); 3771 } 3772 3773 bool WarpCacheIRTranspiler::emitBigIntPtrBitOr(IntPtrOperandId lhsId, 3774 IntPtrOperandId rhsId, 3775 IntPtrOperandId resultId) { 3776 return emitBigIntPtrBinaryArith<MBigIntPtrBitOr>(lhsId, rhsId, resultId); 3777 } 3778 3779 bool WarpCacheIRTranspiler::emitBigIntPtrBitXor(IntPtrOperandId lhsId, 3780 IntPtrOperandId rhsId, 3781 IntPtrOperandId resultId) { 3782 return emitBigIntPtrBinaryArith<MBigIntPtrBitXor>(lhsId, rhsId, resultId); 3783 } 3784 3785 bool WarpCacheIRTranspiler::emitBigIntPtrBitAnd(IntPtrOperandId lhsId, 3786 IntPtrOperandId rhsId, 3787 IntPtrOperandId resultId) { 3788 return emitBigIntPtrBinaryArith<MBigIntPtrBitAnd>(lhsId, rhsId, resultId); 3789 } 3790 3791 bool WarpCacheIRTranspiler::emitBigIntPtrLeftShift(IntPtrOperandId lhsId, 3792 IntPtrOperandId rhsId, 3793 IntPtrOperandId resultId) { 3794 return emitBigIntPtrBinaryArith<MBigIntPtrLsh>(lhsId, rhsId, resultId); 3795 } 3796 3797 bool WarpCacheIRTranspiler::emitBigIntPtrRightShift(IntPtrOperandId lhsId, 3798 IntPtrOperandId rhsId, 3799 IntPtrOperandId resultId) { 3800 return emitBigIntPtrBinaryArith<MBigIntPtrRsh>(lhsId, rhsId, resultId); 3801 } 3802 3803 bool WarpCacheIRTranspiler::emitBigIntPtrInc(IntPtrOperandId inputId, 3804 IntPtrOperandId resultId) { 3805 MDefinition* input = getOperand(inputId); 3806 3807 auto* constOne = MConstant::NewIntPtr(alloc(), 1); 3808 add(constOne); 3809 3810 auto* ins = MBigIntPtrAdd::New(alloc(), input, constOne); 3811 add(ins); 3812 3813 return defineOperand(resultId, ins); 3814 } 3815 3816 bool WarpCacheIRTranspiler::emitBigIntPtrDec(IntPtrOperandId inputId, 3817 IntPtrOperandId resultId) { 3818 MDefinition* input = getOperand(inputId); 3819 3820 auto* constOne = MConstant::NewIntPtr(alloc(), 1); 3821 add(constOne); 3822 3823 auto* ins = MBigIntPtrSub::New(alloc(), input, constOne); 3824 add(ins); 3825 3826 return defineOperand(resultId, ins); 3827 } 3828 3829 bool WarpCacheIRTranspiler::emitBigIntPtrNegation(IntPtrOperandId inputId, 3830 IntPtrOperandId resultId) { 3831 MDefinition* input = getOperand(inputId); 3832 3833 auto* constNegOne = MConstant::NewIntPtr(alloc(), -1); 3834 add(constNegOne); 3835 3836 auto* ins = MBigIntPtrMul::New(alloc(), input, constNegOne); 3837 add(ins); 3838 3839 return defineOperand(resultId, ins); 3840 } 3841 3842 bool WarpCacheIRTranspiler::emitBigIntPtrNot(IntPtrOperandId inputId, 3843 IntPtrOperandId resultId) { 3844 MDefinition* input = getOperand(inputId); 3845 3846 auto* ins = MBigIntPtrBitNot::New(alloc(), input); 3847 add(ins); 3848 3849 return defineOperand(resultId, ins); 3850 } 3851 3852 bool WarpCacheIRTranspiler::emitConcatStringsResult(StringOperandId lhsId, 3853 StringOperandId rhsId, 3854 uint32_t stubOffset) { 3855 MDefinition* lhs = getOperand(lhsId); 3856 MDefinition* rhs = getOperand(rhsId); 3857 3858 auto* ins = MConcat::New(alloc(), lhs, rhs); 3859 add(ins); 3860 3861 pushResult(ins); 3862 return true; 3863 } 3864 3865 bool WarpCacheIRTranspiler::emitCompareResult( 3866 JSOp op, OperandId lhsId, OperandId rhsId, 3867 MCompare::CompareType compareType) { 3868 MDefinition* lhs = getOperand(lhsId); 3869 MDefinition* rhs = getOperand(rhsId); 3870 3871 auto* ins = MCompare::New(alloc(), lhs, rhs, op, compareType); 3872 add(ins); 3873 3874 pushResult(ins); 3875 return true; 3876 } 3877 3878 bool WarpCacheIRTranspiler::emitCompareInt32Result(JSOp op, 3879 Int32OperandId lhsId, 3880 Int32OperandId rhsId) { 3881 return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_Int32); 3882 } 3883 3884 bool WarpCacheIRTranspiler::emitCompareDoubleResult(JSOp op, 3885 NumberOperandId lhsId, 3886 NumberOperandId rhsId) { 3887 return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_Double); 3888 } 3889 3890 bool WarpCacheIRTranspiler::emitCompareObjectResult(JSOp op, ObjOperandId lhsId, 3891 ObjOperandId rhsId) { 3892 MOZ_ASSERT(IsEqualityOp(op)); 3893 return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_Object); 3894 } 3895 3896 bool WarpCacheIRTranspiler::emitCompareStringResult(JSOp op, 3897 StringOperandId lhsId, 3898 StringOperandId rhsId) { 3899 return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_String); 3900 } 3901 3902 bool WarpCacheIRTranspiler::emitCompareSymbolResult(JSOp op, 3903 SymbolOperandId lhsId, 3904 SymbolOperandId rhsId) { 3905 MOZ_ASSERT(IsEqualityOp(op)); 3906 return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_Symbol); 3907 } 3908 3909 bool WarpCacheIRTranspiler::emitCompareBigIntResult(JSOp op, 3910 BigIntOperandId lhsId, 3911 BigIntOperandId rhsId) { 3912 return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_BigInt); 3913 } 3914 3915 bool WarpCacheIRTranspiler::emitCompareBigIntInt32Result(JSOp op, 3916 BigIntOperandId lhsId, 3917 Int32OperandId rhsId) { 3918 return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_BigInt_Int32); 3919 } 3920 3921 bool WarpCacheIRTranspiler::emitCompareBigIntNumberResult( 3922 JSOp op, BigIntOperandId lhsId, NumberOperandId rhsId) { 3923 return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_BigInt_Double); 3924 } 3925 3926 bool WarpCacheIRTranspiler::emitCompareBigIntStringResult( 3927 JSOp op, BigIntOperandId lhsId, StringOperandId rhsId) { 3928 return emitCompareResult(op, lhsId, rhsId, MCompare::Compare_BigInt_String); 3929 } 3930 3931 bool WarpCacheIRTranspiler::emitCompareNullUndefinedResult( 3932 JSOp op, bool isUndefined, ValOperandId inputId) { 3933 MDefinition* input = getOperand(inputId); 3934 3935 MOZ_ASSERT(IsEqualityOp(op)); 3936 3937 // A previously emitted guard ensures that one side of the comparison 3938 // is null or undefined. 3939 MDefinition* cst = 3940 isUndefined ? constant(UndefinedValue()) : constant(NullValue()); 3941 auto compareType = 3942 isUndefined ? MCompare::Compare_Undefined : MCompare::Compare_Null; 3943 auto* ins = MCompare::New(alloc(), input, cst, op, compareType); 3944 add(ins); 3945 3946 pushResult(ins); 3947 return true; 3948 } 3949 3950 bool WarpCacheIRTranspiler::emitCompareDoubleSameValueResult( 3951 NumberOperandId lhsId, NumberOperandId rhsId) { 3952 MDefinition* lhs = getOperand(lhsId); 3953 MDefinition* rhs = getOperand(rhsId); 3954 3955 auto* sameValue = MSameValueDouble::New(alloc(), lhs, rhs); 3956 add(sameValue); 3957 3958 pushResult(sameValue); 3959 return true; 3960 } 3961 3962 bool WarpCacheIRTranspiler::emitSameValueResult(ValOperandId lhsId, 3963 ValOperandId rhsId) { 3964 MDefinition* lhs = getOperand(lhsId); 3965 MDefinition* rhs = getOperand(rhsId); 3966 3967 auto* sameValue = MSameValue::New(alloc(), lhs, rhs); 3968 add(sameValue); 3969 3970 pushResult(sameValue); 3971 return true; 3972 } 3973 3974 bool WarpCacheIRTranspiler::emitIndirectTruncateInt32Result( 3975 Int32OperandId valId) { 3976 MDefinition* val = getOperand(valId); 3977 MOZ_ASSERT(val->type() == MIRType::Int32); 3978 3979 auto* truncate = 3980 MLimitedTruncate::New(alloc(), val, TruncateKind::IndirectTruncate); 3981 add(truncate); 3982 3983 pushResult(truncate); 3984 return true; 3985 } 3986 3987 bool WarpCacheIRTranspiler::emitMathHypot2NumberResult( 3988 NumberOperandId firstId, NumberOperandId secondId) { 3989 MDefinitionVector vector(alloc()); 3990 if (!vector.reserve(2)) { 3991 return false; 3992 } 3993 3994 vector.infallibleAppend(getOperand(firstId)); 3995 vector.infallibleAppend(getOperand(secondId)); 3996 3997 auto* ins = MHypot::New(alloc(), vector); 3998 if (!ins) { 3999 return false; 4000 } 4001 add(ins); 4002 4003 pushResult(ins); 4004 return true; 4005 } 4006 4007 bool WarpCacheIRTranspiler::emitMathHypot3NumberResult( 4008 NumberOperandId firstId, NumberOperandId secondId, 4009 NumberOperandId thirdId) { 4010 MDefinitionVector vector(alloc()); 4011 if (!vector.reserve(3)) { 4012 return false; 4013 } 4014 4015 vector.infallibleAppend(getOperand(firstId)); 4016 vector.infallibleAppend(getOperand(secondId)); 4017 vector.infallibleAppend(getOperand(thirdId)); 4018 4019 auto* ins = MHypot::New(alloc(), vector); 4020 if (!ins) { 4021 return false; 4022 } 4023 add(ins); 4024 4025 pushResult(ins); 4026 return true; 4027 } 4028 4029 bool WarpCacheIRTranspiler::emitMathHypot4NumberResult( 4030 NumberOperandId firstId, NumberOperandId secondId, NumberOperandId thirdId, 4031 NumberOperandId fourthId) { 4032 MDefinitionVector vector(alloc()); 4033 if (!vector.reserve(4)) { 4034 return false; 4035 } 4036 4037 vector.infallibleAppend(getOperand(firstId)); 4038 vector.infallibleAppend(getOperand(secondId)); 4039 vector.infallibleAppend(getOperand(thirdId)); 4040 vector.infallibleAppend(getOperand(fourthId)); 4041 4042 auto* ins = MHypot::New(alloc(), vector); 4043 if (!ins) { 4044 return false; 4045 } 4046 add(ins); 4047 4048 pushResult(ins); 4049 return true; 4050 } 4051 4052 bool WarpCacheIRTranspiler::emitMathRandomResult(uint32_t rngOffset) { 4053 #ifdef DEBUG 4054 // CodeGenerator uses CompileRealm::addressOfRandomNumberGenerator. Assert it 4055 // matches the RNG pointer stored in the stub field. 4056 const void* rng = rawPointerField(rngOffset); 4057 MOZ_ASSERT(rng == mirGen().realm->addressOfRandomNumberGenerator()); 4058 #endif 4059 4060 auto* ins = MRandom::New(alloc()); 4061 addEffectful(ins); 4062 4063 pushResult(ins); 4064 return resumeAfter(ins); 4065 } 4066 4067 bool WarpCacheIRTranspiler::emitInt32MinMax(bool isMax, Int32OperandId firstId, 4068 Int32OperandId secondId, 4069 Int32OperandId resultId) { 4070 MDefinition* first = getOperand(firstId); 4071 MDefinition* second = getOperand(secondId); 4072 4073 auto* ins = MMinMax::New(alloc(), first, second, MIRType::Int32, isMax); 4074 add(ins); 4075 4076 return defineOperand(resultId, ins); 4077 } 4078 4079 bool WarpCacheIRTranspiler::emitNumberMinMax(bool isMax, 4080 NumberOperandId firstId, 4081 NumberOperandId secondId, 4082 NumberOperandId resultId) { 4083 MDefinition* first = getOperand(firstId); 4084 MDefinition* second = getOperand(secondId); 4085 4086 auto* ins = MMinMax::New(alloc(), first, second, MIRType::Double, isMax); 4087 add(ins); 4088 4089 return defineOperand(resultId, ins); 4090 } 4091 4092 bool WarpCacheIRTranspiler::emitInt32MinMaxArrayResult(ObjOperandId arrayId, 4093 bool isMax) { 4094 MDefinition* array = getOperand(arrayId); 4095 4096 auto* ins = MMinMaxArray::New(alloc(), array, MIRType::Int32, isMax); 4097 add(ins); 4098 4099 pushResult(ins); 4100 return true; 4101 } 4102 4103 bool WarpCacheIRTranspiler::emitNumberMinMaxArrayResult(ObjOperandId arrayId, 4104 bool isMax) { 4105 MDefinition* array = getOperand(arrayId); 4106 4107 auto* ins = MMinMaxArray::New(alloc(), array, MIRType::Double, isMax); 4108 add(ins); 4109 4110 pushResult(ins); 4111 return true; 4112 } 4113 4114 bool WarpCacheIRTranspiler::emitMathAbsInt32Result(Int32OperandId inputId) { 4115 MDefinition* input = getOperand(inputId); 4116 4117 auto* ins = MAbs::New(alloc(), input, MIRType::Int32); 4118 add(ins); 4119 4120 pushResult(ins); 4121 return true; 4122 } 4123 4124 bool WarpCacheIRTranspiler::emitMathAbsNumberResult(NumberOperandId inputId) { 4125 MDefinition* input = getOperand(inputId); 4126 4127 auto* ins = MAbs::New(alloc(), input, MIRType::Double); 4128 add(ins); 4129 4130 pushResult(ins); 4131 return true; 4132 } 4133 4134 bool WarpCacheIRTranspiler::emitMathClz32Result(Int32OperandId inputId) { 4135 MDefinition* input = getOperand(inputId); 4136 4137 auto* ins = MClz::New(alloc(), input, MIRType::Int32); 4138 add(ins); 4139 4140 pushResult(ins); 4141 return true; 4142 } 4143 4144 bool WarpCacheIRTranspiler::emitMathSignInt32Result(Int32OperandId inputId) { 4145 MDefinition* input = getOperand(inputId); 4146 4147 auto* ins = MSign::New(alloc(), input, MIRType::Int32); 4148 add(ins); 4149 4150 pushResult(ins); 4151 return true; 4152 } 4153 4154 bool WarpCacheIRTranspiler::emitMathSignNumberResult(NumberOperandId inputId) { 4155 MDefinition* input = getOperand(inputId); 4156 4157 auto* ins = MSign::New(alloc(), input, MIRType::Double); 4158 add(ins); 4159 4160 pushResult(ins); 4161 return true; 4162 } 4163 4164 bool WarpCacheIRTranspiler::emitMathSignNumberToInt32Result( 4165 NumberOperandId inputId) { 4166 MDefinition* input = getOperand(inputId); 4167 4168 auto* ins = MSign::New(alloc(), input, MIRType::Int32); 4169 add(ins); 4170 4171 pushResult(ins); 4172 return true; 4173 } 4174 4175 bool WarpCacheIRTranspiler::emitMathImulResult(Int32OperandId lhsId, 4176 Int32OperandId rhsId) { 4177 MDefinition* lhs = getOperand(lhsId); 4178 MDefinition* rhs = getOperand(rhsId); 4179 4180 auto* ins = MMul::New(alloc(), lhs, rhs, MIRType::Int32, MMul::Integer); 4181 add(ins); 4182 4183 pushResult(ins); 4184 return true; 4185 } 4186 4187 bool WarpCacheIRTranspiler::emitMathFloorToInt32Result( 4188 NumberOperandId inputId) { 4189 MDefinition* input = getOperand(inputId); 4190 4191 auto* ins = MFloor::New(alloc(), input); 4192 add(ins); 4193 4194 pushResult(ins); 4195 return true; 4196 } 4197 4198 bool WarpCacheIRTranspiler::emitMathCeilToInt32Result(NumberOperandId inputId) { 4199 MDefinition* input = getOperand(inputId); 4200 4201 auto* ins = MCeil::New(alloc(), input); 4202 add(ins); 4203 4204 pushResult(ins); 4205 return true; 4206 } 4207 4208 bool WarpCacheIRTranspiler::emitMathTruncToInt32Result( 4209 NumberOperandId inputId) { 4210 MDefinition* input = getOperand(inputId); 4211 4212 auto* ins = MTrunc::New(alloc(), input); 4213 add(ins); 4214 4215 pushResult(ins); 4216 return true; 4217 } 4218 4219 bool WarpCacheIRTranspiler::emitMathRoundToInt32Result( 4220 NumberOperandId inputId) { 4221 MDefinition* input = getOperand(inputId); 4222 4223 auto* ins = MRound::New(alloc(), input); 4224 add(ins); 4225 4226 pushResult(ins); 4227 return true; 4228 } 4229 4230 bool WarpCacheIRTranspiler::emitMathSqrtNumberResult(NumberOperandId inputId) { 4231 MDefinition* input = getOperand(inputId); 4232 4233 auto* ins = MSqrt::New(alloc(), input, MIRType::Double); 4234 add(ins); 4235 4236 pushResult(ins); 4237 return true; 4238 } 4239 4240 bool WarpCacheIRTranspiler::emitMathFRoundNumberResult( 4241 NumberOperandId inputId) { 4242 MDefinition* input = getOperand(inputId); 4243 4244 auto* ins = MToFloat32::New(alloc(), input); 4245 add(ins); 4246 4247 pushResult(ins); 4248 return true; 4249 } 4250 4251 bool WarpCacheIRTranspiler::emitMathF16RoundNumberResult( 4252 NumberOperandId inputId) { 4253 MDefinition* input = getOperand(inputId); 4254 4255 auto* ins = MToFloat16::New(alloc(), input); 4256 add(ins); 4257 4258 pushResult(ins); 4259 return true; 4260 } 4261 4262 bool WarpCacheIRTranspiler::emitMathAtan2NumberResult(NumberOperandId yId, 4263 NumberOperandId xId) { 4264 MDefinition* y = getOperand(yId); 4265 MDefinition* x = getOperand(xId); 4266 4267 auto* ins = MAtan2::New(alloc(), y, x); 4268 add(ins); 4269 4270 pushResult(ins); 4271 return true; 4272 } 4273 4274 bool WarpCacheIRTranspiler::emitMathFunctionNumberResult( 4275 NumberOperandId inputId, UnaryMathFunction fun) { 4276 MDefinition* input = getOperand(inputId); 4277 4278 auto* ins = MMathFunction::New(alloc(), input, fun); 4279 add(ins); 4280 4281 pushResult(ins); 4282 return true; 4283 } 4284 4285 bool WarpCacheIRTranspiler::emitMathFloorNumberResult(NumberOperandId inputId) { 4286 MDefinition* input = getOperand(inputId); 4287 4288 MInstruction* ins; 4289 if (MNearbyInt::HasAssemblerSupport(RoundingMode::Down)) { 4290 ins = MNearbyInt::New(alloc(), input, MIRType::Double, RoundingMode::Down); 4291 } else { 4292 ins = MMathFunction::New(alloc(), input, UnaryMathFunction::Floor); 4293 } 4294 add(ins); 4295 4296 pushResult(ins); 4297 return true; 4298 } 4299 4300 bool WarpCacheIRTranspiler::emitMathCeilNumberResult(NumberOperandId inputId) { 4301 MDefinition* input = getOperand(inputId); 4302 4303 MInstruction* ins; 4304 if (MNearbyInt::HasAssemblerSupport(RoundingMode::Up)) { 4305 ins = MNearbyInt::New(alloc(), input, MIRType::Double, RoundingMode::Up); 4306 } else { 4307 ins = MMathFunction::New(alloc(), input, UnaryMathFunction::Ceil); 4308 } 4309 add(ins); 4310 4311 pushResult(ins); 4312 return true; 4313 } 4314 4315 bool WarpCacheIRTranspiler::emitMathTruncNumberResult(NumberOperandId inputId) { 4316 MDefinition* input = getOperand(inputId); 4317 4318 MInstruction* ins; 4319 if (MNearbyInt::HasAssemblerSupport(RoundingMode::TowardsZero)) { 4320 ins = MNearbyInt::New(alloc(), input, MIRType::Double, 4321 RoundingMode::TowardsZero); 4322 } else { 4323 ins = MMathFunction::New(alloc(), input, UnaryMathFunction::Trunc); 4324 } 4325 add(ins); 4326 4327 pushResult(ins); 4328 return true; 4329 } 4330 4331 bool WarpCacheIRTranspiler::emitMathRoundNumberResult(NumberOperandId inputId) { 4332 MDefinition* input = getOperand(inputId); 4333 4334 MInstruction* ins; 4335 if (MRoundToDouble::HasAssemblerSupport()) { 4336 ins = MRoundToDouble::New(alloc(), input); 4337 } else { 4338 ins = MMathFunction::New(alloc(), input, UnaryMathFunction::Round); 4339 } 4340 add(ins); 4341 4342 pushResult(ins); 4343 return true; 4344 } 4345 4346 bool WarpCacheIRTranspiler::emitNumberParseIntResult(StringOperandId strId, 4347 Int32OperandId radixId) { 4348 MDefinition* str = getOperand(strId); 4349 MDefinition* radix = getOperand(radixId); 4350 4351 auto* ins = MNumberParseInt::New(alloc(), str, radix); 4352 add(ins); 4353 4354 pushResult(ins); 4355 return true; 4356 } 4357 4358 bool WarpCacheIRTranspiler::emitDoubleParseIntResult(NumberOperandId numId) { 4359 MDefinition* num = getOperand(numId); 4360 4361 auto* ins = MDoubleParseInt::New(alloc(), num); 4362 add(ins); 4363 4364 pushResult(ins); 4365 return true; 4366 } 4367 4368 bool WarpCacheIRTranspiler::emitObjectToStringResult(ObjOperandId objId) { 4369 MDefinition* obj = getOperand(objId); 4370 4371 auto* ins = MObjectClassToString::New(alloc(), obj); 4372 add(ins); 4373 4374 pushResult(ins); 4375 return true; 4376 } 4377 4378 bool WarpCacheIRTranspiler::emitReflectGetPrototypeOfResult( 4379 ObjOperandId objId) { 4380 MDefinition* obj = getOperand(objId); 4381 4382 auto* ins = MGetPrototypeOf::New(alloc(), obj); 4383 addEffectful(ins); 4384 pushResult(ins); 4385 4386 return resumeAfter(ins); 4387 } 4388 4389 bool WarpCacheIRTranspiler::emitArrayPush(ObjOperandId objId, 4390 ValOperandId rhsId) { 4391 MDefinition* obj = getOperand(objId); 4392 MDefinition* value = getOperand(rhsId); 4393 4394 auto* ins = MArrayPush::New(alloc(), obj, value); 4395 addEffectful(ins); 4396 pushResult(ins); 4397 4398 return resumeAfter(ins); 4399 } 4400 4401 bool WarpCacheIRTranspiler::emitArrayJoinResult(ObjOperandId objId, 4402 StringOperandId sepId) { 4403 MDefinition* obj = getOperand(objId); 4404 MDefinition* sep = getOperand(sepId); 4405 4406 auto* join = MArrayJoin::New(alloc(), obj, sep); 4407 addEffectful(join); 4408 4409 pushResult(join); 4410 return resumeAfter(join); 4411 } 4412 4413 bool WarpCacheIRTranspiler::emitObjectKeysResult(ObjOperandId objId, 4414 uint32_t resultShapeOffset) { 4415 MDefinition* obj = getOperand(objId); 4416 Shape* resultShape = shapeStubField(resultShapeOffset); 4417 4418 auto* join = MObjectKeys::New(alloc(), obj, resultShape); 4419 addEffectful(join); 4420 4421 pushResult(join); 4422 return resumeAfter(join); 4423 } 4424 4425 bool WarpCacheIRTranspiler::emitPackedArrayPopResult(ObjOperandId arrayId) { 4426 MDefinition* array = getOperand(arrayId); 4427 4428 auto* ins = MArrayPopShift::New(alloc(), array, MArrayPopShift::Pop); 4429 addEffectful(ins); 4430 4431 pushResult(ins); 4432 return resumeAfter(ins); 4433 } 4434 4435 bool WarpCacheIRTranspiler::emitPackedArrayShiftResult(ObjOperandId arrayId) { 4436 MDefinition* array = getOperand(arrayId); 4437 4438 auto* ins = MArrayPopShift::New(alloc(), array, MArrayPopShift::Shift); 4439 addEffectful(ins); 4440 4441 pushResult(ins); 4442 return resumeAfter(ins); 4443 } 4444 4445 bool WarpCacheIRTranspiler::emitPackedArraySliceResult( 4446 uint32_t templateObjectOffset, ObjOperandId arrayId, Int32OperandId beginId, 4447 Int32OperandId endId) { 4448 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 4449 4450 MDefinition* array = getOperand(arrayId); 4451 MDefinition* begin = getOperand(beginId); 4452 MDefinition* end = getOperand(endId); 4453 4454 // TODO: support pre-tenuring. 4455 gc::Heap heap = gc::Heap::Default; 4456 4457 auto* ins = MArraySlice::New(alloc(), array, begin, end, templateObj, heap); 4458 addEffectful(ins); 4459 4460 pushResult(ins); 4461 return resumeAfter(ins); 4462 } 4463 4464 bool WarpCacheIRTranspiler::emitArgumentsSliceResult( 4465 uint32_t templateObjectOffset, ObjOperandId argsId, Int32OperandId beginId, 4466 Int32OperandId endId) { 4467 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 4468 4469 MDefinition* args = getOperand(argsId); 4470 MDefinition* begin = getOperand(beginId); 4471 MDefinition* end = getOperand(endId); 4472 4473 // TODO: support pre-tenuring. 4474 gc::Heap heap = gc::Heap::Default; 4475 4476 auto* ins = 4477 MArgumentsSlice::New(alloc(), args, begin, end, templateObj, heap); 4478 addEffectful(ins); 4479 4480 pushResult(ins); 4481 return resumeAfter(ins); 4482 } 4483 4484 bool WarpCacheIRTranspiler::emitHasClassResult(ObjOperandId objId, 4485 uint32_t claspOffset) { 4486 MDefinition* obj = getOperand(objId); 4487 const JSClass* clasp = classStubField(claspOffset); 4488 4489 auto* hasClass = MHasClass::New(alloc(), obj, clasp); 4490 add(hasClass); 4491 4492 pushResult(hasClass); 4493 return true; 4494 } 4495 4496 bool WarpCacheIRTranspiler::emitHasShapeResult(ObjOperandId objId, 4497 uint32_t shapeOffset) { 4498 MDefinition* obj = getOperand(objId); 4499 Shape* shape = shapeStubField(shapeOffset); 4500 4501 auto* hasShape = MHasShape::New(alloc(), obj, shape); 4502 add(hasShape); 4503 4504 pushResult(hasShape); 4505 return true; 4506 } 4507 4508 bool WarpCacheIRTranspiler::emitCallRegExpMatcherResult( 4509 ObjOperandId regexpId, StringOperandId inputId, Int32OperandId lastIndexId, 4510 uint32_t stubOffset) { 4511 MDefinition* regexp = getOperand(regexpId); 4512 MDefinition* input = getOperand(inputId); 4513 MDefinition* lastIndex = getOperand(lastIndexId); 4514 4515 auto* matcher = MRegExpMatcher::New(alloc(), regexp, input, lastIndex); 4516 addEffectful(matcher); 4517 pushResult(matcher); 4518 4519 return resumeAfter(matcher); 4520 } 4521 4522 bool WarpCacheIRTranspiler::emitCallRegExpSearcherResult( 4523 ObjOperandId regexpId, StringOperandId inputId, Int32OperandId lastIndexId, 4524 uint32_t stubOffset) { 4525 MDefinition* regexp = getOperand(regexpId); 4526 MDefinition* input = getOperand(inputId); 4527 MDefinition* lastIndex = getOperand(lastIndexId); 4528 4529 auto* searcher = MRegExpSearcher::New(alloc(), regexp, input, lastIndex); 4530 addEffectful(searcher); 4531 pushResult(searcher); 4532 4533 return resumeAfter(searcher); 4534 } 4535 4536 bool WarpCacheIRTranspiler::emitRegExpSearcherLastLimitResult() { 4537 auto* limit = MRegExpSearcherLastLimit::New(alloc()); 4538 addEffectful(limit); 4539 pushResult(limit); 4540 4541 return resumeAfter(limit); 4542 } 4543 4544 bool WarpCacheIRTranspiler::emitRegExpBuiltinExecMatchResult( 4545 ObjOperandId regexpId, StringOperandId inputId, uint32_t stubOffset) { 4546 MDefinition* regexp = getOperand(regexpId); 4547 MDefinition* input = getOperand(inputId); 4548 4549 auto* ins = MRegExpExecMatch::New(alloc(), regexp, input); 4550 addEffectful(ins); 4551 pushResult(ins); 4552 4553 return resumeAfter(ins); 4554 } 4555 4556 bool WarpCacheIRTranspiler::emitRegExpBuiltinExecTestResult( 4557 ObjOperandId regexpId, StringOperandId inputId, uint32_t stubOffset) { 4558 MDefinition* regexp = getOperand(regexpId); 4559 MDefinition* input = getOperand(inputId); 4560 4561 auto* ins = MRegExpExecTest::New(alloc(), regexp, input); 4562 addEffectful(ins); 4563 pushResult(ins); 4564 4565 return resumeAfter(ins); 4566 } 4567 4568 bool WarpCacheIRTranspiler::emitRegExpHasCaptureGroupsResult( 4569 ObjOperandId regexpId, StringOperandId inputId) { 4570 MDefinition* regexp = getOperand(regexpId); 4571 MDefinition* input = getOperand(inputId); 4572 4573 auto* result = MRegExpHasCaptureGroups::New(alloc(), regexp, input); 4574 addEffectful(result); 4575 pushResult(result); 4576 4577 return resumeAfter(result); 4578 } 4579 4580 MInstruction* WarpCacheIRTranspiler::convertToBoolean(MDefinition* input) { 4581 // Convert to bool with the '!!' idiom. 4582 // 4583 // The FoldTests and GVN passes both specifically handle this pattern. If you 4584 // change this code, make sure to update FoldTests and GVN, too. 4585 4586 auto* resultInverted = MNot::New(alloc(), input); 4587 add(resultInverted); 4588 auto* result = MNot::New(alloc(), resultInverted); 4589 add(result); 4590 4591 return result; 4592 } 4593 4594 bool WarpCacheIRTranspiler::emitRegExpFlagResult(ObjOperandId regexpId, 4595 int32_t flagsMask) { 4596 MDefinition* regexp = getOperand(regexpId); 4597 4598 auto* flags = MLoadFixedSlot::New(alloc(), regexp, RegExpObject::flagsSlot()); 4599 flags->setResultType(MIRType::Int32); 4600 add(flags); 4601 4602 auto* mask = MConstant::NewInt32(alloc(), flagsMask); 4603 add(mask); 4604 4605 auto* maskedFlag = MBitAnd::New(alloc(), flags, mask, MIRType::Int32); 4606 add(maskedFlag); 4607 4608 auto* result = convertToBoolean(maskedFlag); 4609 4610 pushResult(result); 4611 return true; 4612 } 4613 4614 bool WarpCacheIRTranspiler::emitCallSubstringKernelResult( 4615 StringOperandId strId, Int32OperandId beginId, Int32OperandId lengthId) { 4616 MDefinition* str = getOperand(strId); 4617 MDefinition* begin = getOperand(beginId); 4618 MDefinition* length = getOperand(lengthId); 4619 4620 auto* substr = MSubstr::New(alloc(), str, begin, length); 4621 add(substr); 4622 4623 pushResult(substr); 4624 return true; 4625 } 4626 4627 bool WarpCacheIRTranspiler::emitStringReplaceStringResult( 4628 StringOperandId strId, StringOperandId patternId, 4629 StringOperandId replacementId) { 4630 MDefinition* str = getOperand(strId); 4631 MDefinition* pattern = getOperand(patternId); 4632 MDefinition* replacement = getOperand(replacementId); 4633 4634 auto* replace = MStringReplace::New(alloc(), str, pattern, replacement); 4635 add(replace); 4636 4637 pushResult(replace); 4638 return true; 4639 } 4640 4641 bool WarpCacheIRTranspiler::emitStringSplitStringResult( 4642 StringOperandId strId, StringOperandId separatorId) { 4643 MDefinition* str = getOperand(strId); 4644 MDefinition* separator = getOperand(separatorId); 4645 4646 auto* split = MStringSplit::New(alloc(), str, separator); 4647 add(split); 4648 4649 pushResult(split); 4650 return true; 4651 } 4652 4653 bool WarpCacheIRTranspiler::emitGetFirstDollarIndexResult( 4654 StringOperandId strId) { 4655 MDefinition* str = getOperand(strId); 4656 4657 auto* firstDollarIndex = MGetFirstDollarIndex::New(alloc(), str); 4658 add(firstDollarIndex); 4659 4660 pushResult(firstDollarIndex); 4661 return true; 4662 } 4663 4664 bool WarpCacheIRTranspiler::emitIsArrayResult(ValOperandId inputId) { 4665 MDefinition* value = getOperand(inputId); 4666 4667 auto* isArray = MIsArray::New(alloc(), value); 4668 addEffectful(isArray); 4669 pushResult(isArray); 4670 4671 return resumeAfter(isArray); 4672 } 4673 4674 bool WarpCacheIRTranspiler::emitIsObjectResult(ValOperandId inputId) { 4675 MDefinition* value = getOperand(inputId); 4676 4677 if (value->type() == MIRType::Object) { 4678 pushResult(constant(BooleanValue(true))); 4679 } else { 4680 auto* isObject = MIsObject::New(alloc(), value); 4681 add(isObject); 4682 pushResult(isObject); 4683 } 4684 4685 return true; 4686 } 4687 4688 bool WarpCacheIRTranspiler::emitIsPackedArrayResult(ObjOperandId objId) { 4689 MDefinition* obj = getOperand(objId); 4690 4691 auto* isPackedArray = MIsPackedArray::New(alloc(), obj); 4692 add(isPackedArray); 4693 4694 pushResult(isPackedArray); 4695 return true; 4696 } 4697 4698 bool WarpCacheIRTranspiler::emitIsCallableResult(ValOperandId inputId) { 4699 MDefinition* value = getOperand(inputId); 4700 4701 auto* isCallable = MIsCallable::New(alloc(), value); 4702 add(isCallable); 4703 4704 pushResult(isCallable); 4705 return true; 4706 } 4707 4708 bool WarpCacheIRTranspiler::emitIsConstructorResult(ObjOperandId objId) { 4709 MDefinition* obj = getOperand(objId); 4710 4711 auto* isConstructor = MIsConstructor::New(alloc(), obj); 4712 add(isConstructor); 4713 4714 pushResult(isConstructor); 4715 return true; 4716 } 4717 4718 bool WarpCacheIRTranspiler::emitIsCrossRealmArrayConstructorResult( 4719 ObjOperandId objId) { 4720 MDefinition* obj = getOperand(objId); 4721 4722 auto* ins = MIsCrossRealmArrayConstructor::New(alloc(), obj); 4723 add(ins); 4724 4725 pushResult(ins); 4726 return true; 4727 } 4728 4729 bool WarpCacheIRTranspiler::emitIsTypedArrayResult(ObjOperandId objId, 4730 bool isPossiblyWrapped) { 4731 MDefinition* obj = getOperand(objId); 4732 4733 auto* ins = MIsTypedArray::New(alloc(), obj, isPossiblyWrapped); 4734 if (isPossiblyWrapped) { 4735 addEffectful(ins); 4736 } else { 4737 add(ins); 4738 } 4739 4740 pushResult(ins); 4741 4742 if (isPossiblyWrapped) { 4743 if (!resumeAfter(ins)) { 4744 return false; 4745 } 4746 } 4747 4748 return true; 4749 } 4750 4751 bool WarpCacheIRTranspiler::emitArrayBufferViewByteOffsetInt32Result( 4752 ObjOperandId objId) { 4753 MDefinition* obj = getOperand(objId); 4754 4755 auto* byteOffset = MArrayBufferViewByteOffset::New(alloc(), obj); 4756 add(byteOffset); 4757 4758 auto* byteOffsetInt32 = MNonNegativeIntPtrToInt32::New(alloc(), byteOffset); 4759 add(byteOffsetInt32); 4760 4761 pushResult(byteOffsetInt32); 4762 return true; 4763 } 4764 4765 bool WarpCacheIRTranspiler::emitArrayBufferViewByteOffsetDoubleResult( 4766 ObjOperandId objId) { 4767 MDefinition* obj = getOperand(objId); 4768 4769 auto* byteOffset = MArrayBufferViewByteOffset::New(alloc(), obj); 4770 add(byteOffset); 4771 4772 auto* byteOffsetDouble = MIntPtrToDouble::New(alloc(), byteOffset); 4773 add(byteOffsetDouble); 4774 4775 pushResult(byteOffsetDouble); 4776 return true; 4777 } 4778 4779 bool WarpCacheIRTranspiler::emitResizableTypedArrayLengthInt32Result( 4780 ObjOperandId objId) { 4781 MDefinition* obj = getOperand(objId); 4782 4783 // Explicit |length| accesses are seq-consistent atomic loads. 4784 auto barrier = MemoryBarrierRequirement::Required; 4785 4786 auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier); 4787 addEffectful(length); 4788 4789 auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length); 4790 add(lengthInt32); 4791 4792 auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthInt32); 4793 add(postConversion); 4794 4795 pushResult(postConversion); 4796 return resumeAfterUnchecked(postConversion); 4797 } 4798 4799 bool WarpCacheIRTranspiler::emitResizableTypedArrayLengthDoubleResult( 4800 ObjOperandId objId) { 4801 MDefinition* obj = getOperand(objId); 4802 4803 // Explicit |length| accesses are seq-consistent atomic loads. 4804 auto barrier = MemoryBarrierRequirement::Required; 4805 4806 auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier); 4807 addEffectful(length); 4808 4809 auto* lengthDouble = MIntPtrToDouble::New(alloc(), length); 4810 add(lengthDouble); 4811 4812 auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthDouble); 4813 add(postConversion); 4814 4815 pushResult(postConversion); 4816 return resumeAfterUnchecked(postConversion); 4817 } 4818 4819 bool WarpCacheIRTranspiler::emitTypedArrayByteLengthInt32Result( 4820 ObjOperandId objId) { 4821 MDefinition* obj = getOperand(objId); 4822 4823 auto* length = MArrayBufferViewLength::New(alloc(), obj); 4824 add(length); 4825 4826 auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length); 4827 add(lengthInt32); 4828 4829 auto* size = MTypedArrayElementSize::New(alloc(), obj); 4830 add(size); 4831 4832 auto* mul = MMul::New(alloc(), lengthInt32, size, MIRType::Int32); 4833 mul->setCanBeNegativeZero(false); 4834 add(mul); 4835 4836 pushResult(mul); 4837 return true; 4838 } 4839 4840 bool WarpCacheIRTranspiler::emitTypedArrayByteLengthDoubleResult( 4841 ObjOperandId objId) { 4842 MDefinition* obj = getOperand(objId); 4843 4844 auto* length = MArrayBufferViewLength::New(alloc(), obj); 4845 add(length); 4846 4847 auto* lengthDouble = MIntPtrToDouble::New(alloc(), length); 4848 add(lengthDouble); 4849 4850 auto* size = MTypedArrayElementSize::New(alloc(), obj); 4851 add(size); 4852 4853 auto* sizeDouble = MToDouble::New(alloc(), size); 4854 add(sizeDouble); 4855 4856 auto* mul = MMul::New(alloc(), lengthDouble, sizeDouble, MIRType::Double); 4857 mul->setCanBeNegativeZero(false); 4858 add(mul); 4859 4860 pushResult(mul); 4861 return true; 4862 } 4863 4864 bool WarpCacheIRTranspiler::emitResizableTypedArrayByteLengthInt32Result( 4865 ObjOperandId objId) { 4866 MDefinition* obj = getOperand(objId); 4867 4868 // Explicit |byteLength| accesses are seq-consistent atomic loads. 4869 auto barrier = MemoryBarrierRequirement::Required; 4870 4871 auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier); 4872 addEffectful(length); 4873 4874 auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length); 4875 add(lengthInt32); 4876 4877 auto* size = MTypedArrayElementSize::New(alloc(), obj); 4878 add(size); 4879 4880 auto* mul = MMul::New(alloc(), lengthInt32, size, MIRType::Int32); 4881 mul->setCanBeNegativeZero(false); 4882 add(mul); 4883 4884 auto* postConversion = MPostIntPtrConversion::New(alloc(), mul); 4885 add(postConversion); 4886 4887 pushResult(postConversion); 4888 return resumeAfterUnchecked(postConversion); 4889 } 4890 4891 bool WarpCacheIRTranspiler::emitResizableTypedArrayByteLengthDoubleResult( 4892 ObjOperandId objId) { 4893 MDefinition* obj = getOperand(objId); 4894 4895 // Explicit |byteLength| accesses are seq-consistent atomic loads. 4896 auto barrier = MemoryBarrierRequirement::Required; 4897 4898 auto* length = MResizableTypedArrayLength::New(alloc(), obj, barrier); 4899 addEffectful(length); 4900 4901 auto* lengthDouble = MIntPtrToDouble::New(alloc(), length); 4902 add(lengthDouble); 4903 4904 auto* size = MTypedArrayElementSize::New(alloc(), obj); 4905 add(size); 4906 4907 auto* sizeDouble = MToDouble::New(alloc(), size); 4908 add(sizeDouble); 4909 4910 auto* mul = MMul::New(alloc(), lengthDouble, sizeDouble, MIRType::Double); 4911 mul->setCanBeNegativeZero(false); 4912 add(mul); 4913 4914 auto* postConversion = MPostIntPtrConversion::New(alloc(), mul); 4915 add(postConversion); 4916 4917 pushResult(postConversion); 4918 return resumeAfterUnchecked(postConversion); 4919 } 4920 4921 bool WarpCacheIRTranspiler::emitResizableDataViewByteLengthInt32Result( 4922 ObjOperandId objId) { 4923 MDefinition* obj = getOperand(objId); 4924 4925 // Explicit |byteLength| accesses are seq-consistent atomic loads. 4926 auto barrier = MemoryBarrierRequirement::Required; 4927 4928 auto* length = MResizableDataViewByteLength::New(alloc(), obj, barrier); 4929 addEffectful(length); 4930 4931 auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length); 4932 add(lengthInt32); 4933 4934 auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthInt32); 4935 add(postConversion); 4936 4937 pushResult(postConversion); 4938 return resumeAfterUnchecked(postConversion); 4939 } 4940 4941 bool WarpCacheIRTranspiler::emitResizableDataViewByteLengthDoubleResult( 4942 ObjOperandId objId) { 4943 MDefinition* obj = getOperand(objId); 4944 4945 // Explicit |byteLength| accesses are seq-consistent atomic loads. 4946 auto barrier = MemoryBarrierRequirement::Required; 4947 4948 auto* length = MResizableDataViewByteLength::New(alloc(), obj, barrier); 4949 addEffectful(length); 4950 4951 auto* lengthDouble = MIntPtrToDouble::New(alloc(), length); 4952 add(lengthDouble); 4953 4954 auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthDouble); 4955 add(postConversion); 4956 4957 pushResult(postConversion); 4958 return resumeAfterUnchecked(postConversion); 4959 } 4960 4961 bool WarpCacheIRTranspiler::emitGrowableSharedArrayBufferByteLengthInt32Result( 4962 ObjOperandId objId) { 4963 MDefinition* obj = getOperand(objId); 4964 4965 auto* length = MGrowableSharedArrayBufferByteLength::New(alloc(), obj); 4966 addEffectful(length); 4967 4968 auto* lengthInt32 = MNonNegativeIntPtrToInt32::New(alloc(), length); 4969 add(lengthInt32); 4970 4971 auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthInt32); 4972 add(postConversion); 4973 4974 pushResult(postConversion); 4975 return resumeAfterUnchecked(postConversion); 4976 } 4977 4978 bool WarpCacheIRTranspiler::emitGrowableSharedArrayBufferByteLengthDoubleResult( 4979 ObjOperandId objId) { 4980 MDefinition* obj = getOperand(objId); 4981 4982 auto* length = MGrowableSharedArrayBufferByteLength::New(alloc(), obj); 4983 addEffectful(length); 4984 4985 auto* lengthDouble = MIntPtrToDouble::New(alloc(), length); 4986 add(lengthDouble); 4987 4988 auto* postConversion = MPostIntPtrConversion::New(alloc(), lengthDouble); 4989 add(postConversion); 4990 4991 pushResult(postConversion); 4992 return resumeAfterUnchecked(postConversion); 4993 } 4994 4995 bool WarpCacheIRTranspiler::emitGuardHasAttachedArrayBuffer( 4996 ObjOperandId objId) { 4997 MDefinition* obj = getOperand(objId); 4998 4999 auto* ins = MGuardHasAttachedArrayBuffer::New(alloc(), obj); 5000 add(ins); 5001 5002 setOperand(objId, ins); 5003 return true; 5004 } 5005 5006 bool WarpCacheIRTranspiler::emitGuardResizableArrayBufferViewInBounds( 5007 ObjOperandId objId) { 5008 MDefinition* obj = getOperand(objId); 5009 5010 auto* ins = MGuardResizableArrayBufferViewInBounds::New(alloc(), obj); 5011 add(ins); 5012 5013 setOperand(objId, ins); 5014 return true; 5015 } 5016 5017 bool WarpCacheIRTranspiler::emitGuardResizableArrayBufferViewInBoundsOrDetached( 5018 ObjOperandId objId) { 5019 MDefinition* obj = getOperand(objId); 5020 5021 auto* ins = 5022 MGuardResizableArrayBufferViewInBoundsOrDetached::New(alloc(), obj); 5023 add(ins); 5024 5025 setOperand(objId, ins); 5026 return true; 5027 } 5028 5029 bool WarpCacheIRTranspiler::emitIsTypedArrayConstructorResult( 5030 ObjOperandId objId) { 5031 MDefinition* obj = getOperand(objId); 5032 5033 auto* ins = MIsTypedArrayConstructor::New(alloc(), obj); 5034 add(ins); 5035 5036 pushResult(ins); 5037 return true; 5038 } 5039 5040 bool WarpCacheIRTranspiler::emitGetNextMapSetEntryForIteratorResult( 5041 ObjOperandId iterId, ObjOperandId resultArrId, bool isMap) { 5042 MDefinition* iter = getOperand(iterId); 5043 MDefinition* resultArr = getOperand(resultArrId); 5044 5045 MGetNextEntryForIterator::Mode mode = 5046 isMap ? MGetNextEntryForIterator::Map : MGetNextEntryForIterator::Set; 5047 auto* ins = MGetNextEntryForIterator::New(alloc(), iter, resultArr, mode); 5048 addEffectful(ins); 5049 pushResult(ins); 5050 5051 return resumeAfter(ins); 5052 } 5053 5054 bool WarpCacheIRTranspiler::emitFrameIsConstructingResult() { 5055 if (const CallInfo* callInfo = builder_->inlineCallInfo()) { 5056 auto* ins = constant(BooleanValue(callInfo->constructing())); 5057 pushResult(ins); 5058 return true; 5059 } 5060 5061 auto* ins = MIsConstructing::New(alloc()); 5062 add(ins); 5063 pushResult(ins); 5064 return true; 5065 } 5066 5067 bool WarpCacheIRTranspiler::emitNewIteratorResult( 5068 MNewIterator::Type type, uint32_t templateObjectOffset) { 5069 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 5070 5071 auto* templateConst = constant(ObjectValue(*templateObj)); 5072 auto* iter = MNewIterator::New(alloc(), templateConst, type); 5073 add(iter); 5074 5075 pushResult(iter); 5076 return true; 5077 } 5078 5079 bool WarpCacheIRTranspiler::emitNewArrayIteratorResult( 5080 uint32_t templateObjectOffset) { 5081 return emitNewIteratorResult(MNewIterator::ArrayIterator, 5082 templateObjectOffset); 5083 } 5084 5085 bool WarpCacheIRTranspiler::emitNewStringIteratorResult( 5086 uint32_t templateObjectOffset) { 5087 return emitNewIteratorResult(MNewIterator::StringIterator, 5088 templateObjectOffset); 5089 } 5090 5091 bool WarpCacheIRTranspiler::emitNewRegExpStringIteratorResult( 5092 uint32_t templateObjectOffset) { 5093 return emitNewIteratorResult(MNewIterator::RegExpStringIterator, 5094 templateObjectOffset); 5095 } 5096 5097 bool WarpCacheIRTranspiler::emitObjectCreateResult( 5098 uint32_t templateObjectOffset) { 5099 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 5100 5101 auto* templateConst = constant(ObjectValue(*templateObj)); 5102 5103 // TODO: support pre-tenuring. 5104 gc::Heap heap = gc::Heap::Default; 5105 auto* obj = 5106 MNewObject::New(alloc(), templateConst, heap, MNewObject::ObjectCreate); 5107 addEffectful(obj); 5108 5109 pushResult(obj); 5110 return resumeAfter(obj); 5111 } 5112 5113 bool WarpCacheIRTranspiler::emitNewArrayFromLengthResult( 5114 uint32_t templateObjectOffset, Int32OperandId lengthId, 5115 uint32_t siteOffset) { 5116 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 5117 MDefinition* length = getOperand(lengthId); 5118 gc::Heap heap = allocSiteInitialHeapField(siteOffset); 5119 5120 if (length->isConstant()) { 5121 int32_t lenInt32 = length->toConstant()->toInt32(); 5122 if (lenInt32 >= 0 && 5123 uint32_t(lenInt32) == templateObj->as<ArrayObject>().length()) { 5124 uint32_t len = uint32_t(lenInt32); 5125 auto* templateConst = constant(ObjectValue(*templateObj)); 5126 5127 size_t inlineLength = 5128 gc::GetGCKindSlots(templateObj->asTenured().getAllocKind()) - 5129 ObjectElements::VALUES_PER_HEADER; 5130 5131 MNewArray* obj; 5132 if (len > inlineLength) { 5133 obj = MNewArray::NewVM(alloc(), len, templateConst, heap); 5134 } else { 5135 obj = MNewArray::New(alloc(), len, templateConst, heap); 5136 } 5137 add(obj); 5138 pushResult(obj); 5139 return true; 5140 } 5141 } 5142 5143 auto* obj = MNewArrayDynamicLength::New(alloc(), length, templateObj, heap); 5144 addEffectful(obj); 5145 pushResult(obj); 5146 return resumeAfter(obj); 5147 } 5148 5149 bool WarpCacheIRTranspiler::emitNewTypedArrayFromLengthResult( 5150 uint32_t templateObjectOffset, Int32OperandId lengthId) { 5151 auto* templateObj = &tenuredObjectStubField(templateObjectOffset) 5152 ->as<FixedLengthTypedArrayObject>(); 5153 MDefinition* length = getOperand(lengthId); 5154 5155 // TODO: support pre-tenuring. 5156 gc::Heap heap = gc::Heap::Default; 5157 5158 if (length->isConstant()) { 5159 int32_t len = length->toConstant()->toInt32(); 5160 if (len >= 0 && uint32_t(len) == templateObj->length()) { 5161 auto* templateConst = constant(ObjectValue(*templateObj)); 5162 auto* obj = MNewTypedArray::New(alloc(), templateConst, heap); 5163 add(obj); 5164 pushResult(obj); 5165 return true; 5166 } 5167 } 5168 5169 auto* obj = 5170 MNewTypedArrayDynamicLength::New(alloc(), length, templateObj, heap); 5171 addEffectful(obj); 5172 pushResult(obj); 5173 return resumeAfter(obj); 5174 } 5175 5176 bool WarpCacheIRTranspiler::emitNewTypedArrayFromArrayBufferResult( 5177 uint32_t templateObjectOffset, ObjOperandId bufferId, 5178 ValOperandId byteOffsetId, ValOperandId lengthId) { 5179 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 5180 MDefinition* buffer = getOperand(bufferId); 5181 MDefinition* byteOffset = getOperand(byteOffsetId); 5182 MDefinition* length = getOperand(lengthId); 5183 5184 // TODO: support pre-tenuring. 5185 gc::Heap heap = gc::Heap::Default; 5186 5187 auto* obj = MNewTypedArrayFromArrayBuffer::New(alloc(), buffer, byteOffset, 5188 length, templateObj, heap); 5189 addEffectful(obj); 5190 5191 pushResult(obj); 5192 return resumeAfter(obj); 5193 } 5194 5195 bool WarpCacheIRTranspiler::emitNewTypedArrayFromArrayResult( 5196 uint32_t templateObjectOffset, ObjOperandId arrayId) { 5197 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 5198 MDefinition* array = getOperand(arrayId); 5199 5200 // TODO: support pre-tenuring. 5201 gc::Heap heap = gc::Heap::Default; 5202 5203 auto* obj = MNewTypedArrayFromArray::New(alloc(), array, templateObj, heap); 5204 addEffectful(obj); 5205 5206 pushResult(obj); 5207 return resumeAfter(obj); 5208 } 5209 5210 bool WarpCacheIRTranspiler::emitAtomicsCompareExchangeResult( 5211 ObjOperandId objId, IntPtrOperandId indexId, uint32_t expectedId, 5212 uint32_t replacementId, Scalar::Type elementType, 5213 ArrayBufferViewKind viewKind) { 5214 MDefinition* obj = getOperand(objId); 5215 MDefinition* index = getOperand(indexId); 5216 MDefinition* expected = getOperand(ValOperandId(expectedId)); 5217 MDefinition* replacement = getOperand(ValOperandId(replacementId)); 5218 5219 auto* length = emitTypedArrayLength(viewKind, obj); 5220 5221 index = addBoundsCheck(index, length); 5222 5223 auto* elements = MArrayBufferViewElements::New(alloc(), obj); 5224 add(elements); 5225 5226 bool forceDoubleForUint32 = true; 5227 MIRType knownType = 5228 MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32); 5229 5230 auto* cas = MCompareExchangeTypedArrayElement::New( 5231 alloc(), elements, index, elementType, expected, replacement); 5232 cas->setResultType(knownType); 5233 addEffectful(cas); 5234 5235 MInstruction* result = cas; 5236 if (Scalar::isBigIntType(elementType)) { 5237 result = 5238 MInt64ToBigInt::New(alloc(), cas, Scalar::isSignedIntType(elementType)); 5239 5240 // Make non-movable so we can attach a resume point. 5241 result->setNotMovable(); 5242 5243 add(result); 5244 } 5245 5246 pushResult(result); 5247 return resumeAfterUnchecked(result); 5248 } 5249 5250 bool WarpCacheIRTranspiler::emitAtomicsExchangeResult( 5251 ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId, 5252 Scalar::Type elementType, ArrayBufferViewKind viewKind) { 5253 MDefinition* obj = getOperand(objId); 5254 MDefinition* index = getOperand(indexId); 5255 MDefinition* value = getOperand(ValOperandId(valueId)); 5256 5257 auto* length = emitTypedArrayLength(viewKind, obj); 5258 5259 index = addBoundsCheck(index, length); 5260 5261 auto* elements = MArrayBufferViewElements::New(alloc(), obj); 5262 add(elements); 5263 5264 bool forceDoubleForUint32 = true; 5265 MIRType knownType = 5266 MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32); 5267 5268 auto* exchange = MAtomicExchangeTypedArrayElement::New( 5269 alloc(), elements, index, value, elementType); 5270 exchange->setResultType(knownType); 5271 addEffectful(exchange); 5272 5273 MInstruction* result = exchange; 5274 if (Scalar::isBigIntType(elementType)) { 5275 result = MInt64ToBigInt::New(alloc(), exchange, 5276 Scalar::isSignedIntType(elementType)); 5277 5278 // Make non-movable so we can attach a resume point. 5279 result->setNotMovable(); 5280 5281 add(result); 5282 } 5283 5284 pushResult(result); 5285 return resumeAfterUnchecked(result); 5286 } 5287 5288 bool WarpCacheIRTranspiler::emitAtomicsBinaryOp( 5289 ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId, 5290 Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind, 5291 AtomicOp op) { 5292 MDefinition* obj = getOperand(objId); 5293 MDefinition* index = getOperand(indexId); 5294 MDefinition* value = getOperand(ValOperandId(valueId)); 5295 5296 auto* length = emitTypedArrayLength(viewKind, obj); 5297 5298 index = addBoundsCheck(index, length); 5299 5300 auto* elements = MArrayBufferViewElements::New(alloc(), obj); 5301 add(elements); 5302 5303 bool forceDoubleForUint32 = true; 5304 MIRType knownType = 5305 MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32); 5306 5307 auto* binop = MAtomicTypedArrayElementBinop::New( 5308 alloc(), op, elements, index, elementType, value, forEffect); 5309 if (!forEffect) { 5310 binop->setResultType(knownType); 5311 } 5312 addEffectful(binop); 5313 5314 if (forEffect) { 5315 pushResult(constant(UndefinedValue())); 5316 return resumeAfter(binop); 5317 } 5318 5319 MInstruction* result = binop; 5320 if (Scalar::isBigIntType(elementType)) { 5321 result = MInt64ToBigInt::New(alloc(), binop, 5322 Scalar::isSignedIntType(elementType)); 5323 5324 // Make non-movable so we can attach a resume point. 5325 result->setNotMovable(); 5326 5327 add(result); 5328 } 5329 5330 pushResult(result); 5331 return resumeAfterUnchecked(result); 5332 } 5333 5334 bool WarpCacheIRTranspiler::emitAtomicsAddResult( 5335 ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId, 5336 Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) { 5337 return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect, 5338 viewKind, AtomicOp::Add); 5339 } 5340 5341 bool WarpCacheIRTranspiler::emitAtomicsSubResult( 5342 ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId, 5343 Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) { 5344 return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect, 5345 viewKind, AtomicOp::Sub); 5346 } 5347 5348 bool WarpCacheIRTranspiler::emitAtomicsAndResult( 5349 ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId, 5350 Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) { 5351 return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect, 5352 viewKind, AtomicOp::And); 5353 } 5354 5355 bool WarpCacheIRTranspiler::emitAtomicsOrResult( 5356 ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId, 5357 Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) { 5358 return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect, 5359 viewKind, AtomicOp::Or); 5360 } 5361 5362 bool WarpCacheIRTranspiler::emitAtomicsXorResult( 5363 ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId, 5364 Scalar::Type elementType, bool forEffect, ArrayBufferViewKind viewKind) { 5365 return emitAtomicsBinaryOp(objId, indexId, valueId, elementType, forEffect, 5366 viewKind, AtomicOp::Xor); 5367 } 5368 5369 bool WarpCacheIRTranspiler::emitAtomicsLoadResult( 5370 ObjOperandId objId, IntPtrOperandId indexId, Scalar::Type elementType, 5371 ArrayBufferViewKind viewKind) { 5372 MDefinition* obj = getOperand(objId); 5373 MDefinition* index = getOperand(indexId); 5374 5375 auto* length = emitTypedArrayLength(viewKind, obj); 5376 5377 index = addBoundsCheck(index, length); 5378 5379 auto* elements = MArrayBufferViewElements::New(alloc(), obj); 5380 add(elements); 5381 5382 bool forceDoubleForUint32 = true; 5383 MIRType knownType = 5384 MIRTypeForArrayBufferViewRead(elementType, forceDoubleForUint32); 5385 5386 auto* load = MLoadUnboxedScalar::New(alloc(), elements, index, elementType, 5387 MemoryBarrierRequirement::Required); 5388 load->setResultType(knownType); 5389 addEffectful(load); 5390 5391 MInstruction* result = load; 5392 if (Scalar::isBigIntType(elementType)) { 5393 result = MInt64ToBigInt::New(alloc(), load, 5394 Scalar::isSignedIntType(elementType)); 5395 5396 // Make non-movable so we can attach a resume point. 5397 result->setNotMovable(); 5398 5399 add(result); 5400 } 5401 5402 pushResult(result); 5403 return resumeAfterUnchecked(result); 5404 } 5405 5406 bool WarpCacheIRTranspiler::emitAtomicsStoreResult( 5407 ObjOperandId objId, IntPtrOperandId indexId, uint32_t valueId, 5408 Scalar::Type elementType, ArrayBufferViewKind viewKind) { 5409 MDefinition* obj = getOperand(objId); 5410 MDefinition* index = getOperand(indexId); 5411 MDefinition* value = getOperand(ValOperandId(valueId)); 5412 5413 auto* length = emitTypedArrayLength(viewKind, obj); 5414 5415 index = addBoundsCheck(index, length); 5416 5417 auto* elements = MArrayBufferViewElements::New(alloc(), obj); 5418 add(elements); 5419 5420 auto* store = 5421 MStoreUnboxedScalar::New(alloc(), elements, index, value, elementType, 5422 MemoryBarrierRequirement::Required); 5423 addEffectful(store); 5424 5425 pushResult(value); 5426 return resumeAfter(store); 5427 } 5428 5429 bool WarpCacheIRTranspiler::emitAtomicsIsLockFreeResult( 5430 Int32OperandId valueId) { 5431 MDefinition* value = getOperand(valueId); 5432 5433 auto* ilf = MAtomicIsLockFree::New(alloc(), value); 5434 add(ilf); 5435 5436 pushResult(ilf); 5437 return true; 5438 } 5439 5440 bool WarpCacheIRTranspiler::emitAtomicsPauseResult() { 5441 auto* ins = MAtomicPause::New(alloc()); 5442 add(ins); 5443 5444 pushResult(constant(UndefinedValue())); 5445 return true; 5446 } 5447 5448 bool WarpCacheIRTranspiler::emitBigIntAsIntNResult(Int32OperandId bitsId, 5449 BigIntOperandId bigIntId) { 5450 MDefinition* bits = getOperand(bitsId); 5451 MDefinition* bigInt = getOperand(bigIntId); 5452 5453 auto* ins = MBigIntAsIntN::New(alloc(), bits, bigInt); 5454 add(ins); 5455 5456 pushResult(ins); 5457 return true; 5458 } 5459 5460 bool WarpCacheIRTranspiler::emitBigIntAsUintNResult(Int32OperandId bitsId, 5461 BigIntOperandId bigIntId) { 5462 MDefinition* bits = getOperand(bitsId); 5463 MDefinition* bigInt = getOperand(bigIntId); 5464 5465 auto* ins = MBigIntAsUintN::New(alloc(), bits, bigInt); 5466 add(ins); 5467 5468 pushResult(ins); 5469 return true; 5470 } 5471 5472 bool WarpCacheIRTranspiler::emitGuardToNonGCThing(ValOperandId inputId) { 5473 MDefinition* def = getOperand(inputId); 5474 if (IsNonGCThing(def->type())) { 5475 return true; 5476 } 5477 5478 auto* ins = MGuardNonGCThing::New(alloc(), def); 5479 add(ins); 5480 5481 setOperand(inputId, ins); 5482 return true; 5483 } 5484 5485 bool WarpCacheIRTranspiler::emitSetHasNonGCThingResult(ObjOperandId setId, 5486 ValOperandId valId) { 5487 MDefinition* set = getOperand(setId); 5488 MDefinition* val = getOperand(valId); 5489 5490 auto* hashValue = MToHashableNonGCThing::New(alloc(), val); 5491 add(hashValue); 5492 5493 auto* hash = MHashNonGCThing::New(alloc(), hashValue); 5494 add(hash); 5495 5496 auto* ins = MSetObjectHasNonBigInt::New(alloc(), set, hashValue, hash); 5497 add(ins); 5498 5499 pushResult(ins); 5500 return true; 5501 } 5502 5503 bool WarpCacheIRTranspiler::emitSetHasStringResult(ObjOperandId setId, 5504 StringOperandId strId) { 5505 MDefinition* set = getOperand(setId); 5506 MDefinition* str = getOperand(strId); 5507 5508 auto* hashValue = MToHashableString::New(alloc(), str); 5509 add(hashValue); 5510 5511 auto* hash = MHashString::New(alloc(), hashValue); 5512 add(hash); 5513 5514 auto* ins = MSetObjectHasNonBigInt::New(alloc(), set, hashValue, hash); 5515 add(ins); 5516 5517 pushResult(ins); 5518 return true; 5519 } 5520 5521 bool WarpCacheIRTranspiler::emitSetHasSymbolResult(ObjOperandId setId, 5522 SymbolOperandId symId) { 5523 MDefinition* set = getOperand(setId); 5524 MDefinition* sym = getOperand(symId); 5525 5526 auto* hash = MHashSymbol::New(alloc(), sym); 5527 add(hash); 5528 5529 auto* ins = MSetObjectHasNonBigInt::New(alloc(), set, sym, hash); 5530 add(ins); 5531 5532 pushResult(ins); 5533 return true; 5534 } 5535 5536 bool WarpCacheIRTranspiler::emitSetHasBigIntResult(ObjOperandId setId, 5537 BigIntOperandId bigIntId) { 5538 MDefinition* set = getOperand(setId); 5539 MDefinition* bigInt = getOperand(bigIntId); 5540 5541 auto* hash = MHashBigInt::New(alloc(), bigInt); 5542 add(hash); 5543 5544 auto* ins = MSetObjectHasBigInt::New(alloc(), set, bigInt, hash); 5545 add(ins); 5546 5547 pushResult(ins); 5548 return true; 5549 } 5550 5551 bool WarpCacheIRTranspiler::emitSetHasObjectResult(ObjOperandId setId, 5552 ObjOperandId objId) { 5553 MDefinition* set = getOperand(setId); 5554 MDefinition* obj = getOperand(objId); 5555 5556 auto* hash = MHashObject::New(alloc(), set, obj); 5557 add(hash); 5558 5559 auto* ins = MSetObjectHasNonBigInt::New(alloc(), set, obj, hash); 5560 add(ins); 5561 5562 pushResult(ins); 5563 return true; 5564 } 5565 5566 bool WarpCacheIRTranspiler::emitSetHasResult(ObjOperandId setId, 5567 ValOperandId valId) { 5568 MDefinition* set = getOperand(setId); 5569 MDefinition* val = getOperand(valId); 5570 5571 #ifdef JS_PUNBOX64 5572 auto* hashValue = MToHashableValue::New(alloc(), val); 5573 add(hashValue); 5574 5575 auto* hash = MHashValue::New(alloc(), set, hashValue); 5576 add(hash); 5577 5578 auto* ins = MSetObjectHasValue::New(alloc(), set, hashValue, hash); 5579 add(ins); 5580 #else 5581 auto* ins = MSetObjectHasValueVMCall::New(alloc(), set, val); 5582 add(ins); 5583 #endif 5584 5585 pushResult(ins); 5586 return true; 5587 } 5588 5589 bool WarpCacheIRTranspiler::emitSetDeleteResult(ObjOperandId setId, 5590 ValOperandId keyId) { 5591 MDefinition* set = getOperand(setId); 5592 MDefinition* key = getOperand(keyId); 5593 5594 auto* ins = MSetObjectDelete::New(alloc(), set, key); 5595 addEffectful(ins); 5596 5597 pushResult(ins); 5598 return resumeAfter(ins); 5599 } 5600 5601 bool WarpCacheIRTranspiler::emitSetAddResult(ObjOperandId setId, 5602 ValOperandId keyId) { 5603 MDefinition* set = getOperand(setId); 5604 MDefinition* key = getOperand(keyId); 5605 5606 auto* ins = MSetObjectAdd::New(alloc(), set, key); 5607 addEffectful(ins); 5608 5609 pushResult(set); 5610 return resumeAfter(ins); 5611 } 5612 5613 bool WarpCacheIRTranspiler::emitSetSizeResult(ObjOperandId setId) { 5614 MDefinition* set = getOperand(setId); 5615 5616 auto* ins = MSetObjectSize::New(alloc(), set); 5617 add(ins); 5618 5619 pushResult(ins); 5620 return true; 5621 } 5622 5623 bool WarpCacheIRTranspiler::emitMapHasNonGCThingResult(ObjOperandId mapId, 5624 ValOperandId valId) { 5625 MDefinition* map = getOperand(mapId); 5626 MDefinition* val = getOperand(valId); 5627 5628 auto* hashValue = MToHashableNonGCThing::New(alloc(), val); 5629 add(hashValue); 5630 5631 auto* hash = MHashNonGCThing::New(alloc(), hashValue); 5632 add(hash); 5633 5634 auto* ins = MMapObjectHasNonBigInt::New(alloc(), map, hashValue, hash); 5635 add(ins); 5636 5637 pushResult(ins); 5638 return true; 5639 } 5640 5641 bool WarpCacheIRTranspiler::emitMapHasStringResult(ObjOperandId mapId, 5642 StringOperandId strId) { 5643 MDefinition* map = getOperand(mapId); 5644 MDefinition* str = getOperand(strId); 5645 5646 auto* hashValue = MToHashableString::New(alloc(), str); 5647 add(hashValue); 5648 5649 auto* hash = MHashString::New(alloc(), hashValue); 5650 add(hash); 5651 5652 auto* ins = MMapObjectHasNonBigInt::New(alloc(), map, hashValue, hash); 5653 add(ins); 5654 5655 pushResult(ins); 5656 return true; 5657 } 5658 5659 bool WarpCacheIRTranspiler::emitMapHasSymbolResult(ObjOperandId mapId, 5660 SymbolOperandId symId) { 5661 MDefinition* map = getOperand(mapId); 5662 MDefinition* sym = getOperand(symId); 5663 5664 auto* hash = MHashSymbol::New(alloc(), sym); 5665 add(hash); 5666 5667 auto* ins = MMapObjectHasNonBigInt::New(alloc(), map, sym, hash); 5668 add(ins); 5669 5670 pushResult(ins); 5671 return true; 5672 } 5673 5674 bool WarpCacheIRTranspiler::emitMapHasBigIntResult(ObjOperandId mapId, 5675 BigIntOperandId bigIntId) { 5676 MDefinition* map = getOperand(mapId); 5677 MDefinition* bigInt = getOperand(bigIntId); 5678 5679 auto* hash = MHashBigInt::New(alloc(), bigInt); 5680 add(hash); 5681 5682 auto* ins = MMapObjectHasBigInt::New(alloc(), map, bigInt, hash); 5683 add(ins); 5684 5685 pushResult(ins); 5686 return true; 5687 } 5688 5689 bool WarpCacheIRTranspiler::emitMapHasObjectResult(ObjOperandId mapId, 5690 ObjOperandId objId) { 5691 MDefinition* map = getOperand(mapId); 5692 MDefinition* obj = getOperand(objId); 5693 5694 auto* hash = MHashObject::New(alloc(), map, obj); 5695 add(hash); 5696 5697 auto* ins = MMapObjectHasNonBigInt::New(alloc(), map, obj, hash); 5698 add(ins); 5699 5700 pushResult(ins); 5701 return true; 5702 } 5703 5704 bool WarpCacheIRTranspiler::emitMapHasResult(ObjOperandId mapId, 5705 ValOperandId valId) { 5706 MDefinition* map = getOperand(mapId); 5707 MDefinition* val = getOperand(valId); 5708 5709 #ifdef JS_PUNBOX64 5710 auto* hashValue = MToHashableValue::New(alloc(), val); 5711 add(hashValue); 5712 5713 auto* hash = MHashValue::New(alloc(), map, hashValue); 5714 add(hash); 5715 5716 auto* ins = MMapObjectHasValue::New(alloc(), map, hashValue, hash); 5717 add(ins); 5718 #else 5719 auto* ins = MMapObjectHasValueVMCall::New(alloc(), map, val); 5720 add(ins); 5721 #endif 5722 5723 pushResult(ins); 5724 return true; 5725 } 5726 5727 bool WarpCacheIRTranspiler::emitMapGetNonGCThingResult(ObjOperandId mapId, 5728 ValOperandId valId) { 5729 MDefinition* map = getOperand(mapId); 5730 MDefinition* val = getOperand(valId); 5731 5732 auto* hashValue = MToHashableNonGCThing::New(alloc(), val); 5733 add(hashValue); 5734 5735 auto* hash = MHashNonGCThing::New(alloc(), hashValue); 5736 add(hash); 5737 5738 auto* ins = MMapObjectGetNonBigInt::New(alloc(), map, hashValue, hash); 5739 add(ins); 5740 5741 pushResult(ins); 5742 return true; 5743 } 5744 5745 bool WarpCacheIRTranspiler::emitMapGetStringResult(ObjOperandId mapId, 5746 StringOperandId strId) { 5747 MDefinition* map = getOperand(mapId); 5748 MDefinition* str = getOperand(strId); 5749 5750 auto* hashValue = MToHashableString::New(alloc(), str); 5751 add(hashValue); 5752 5753 auto* hash = MHashString::New(alloc(), hashValue); 5754 add(hash); 5755 5756 auto* ins = MMapObjectGetNonBigInt::New(alloc(), map, hashValue, hash); 5757 add(ins); 5758 5759 pushResult(ins); 5760 return true; 5761 } 5762 5763 bool WarpCacheIRTranspiler::emitMapGetSymbolResult(ObjOperandId mapId, 5764 SymbolOperandId symId) { 5765 MDefinition* map = getOperand(mapId); 5766 MDefinition* sym = getOperand(symId); 5767 5768 auto* hash = MHashSymbol::New(alloc(), sym); 5769 add(hash); 5770 5771 auto* ins = MMapObjectGetNonBigInt::New(alloc(), map, sym, hash); 5772 add(ins); 5773 5774 pushResult(ins); 5775 return true; 5776 } 5777 5778 bool WarpCacheIRTranspiler::emitMapGetBigIntResult(ObjOperandId mapId, 5779 BigIntOperandId bigIntId) { 5780 MDefinition* map = getOperand(mapId); 5781 MDefinition* bigInt = getOperand(bigIntId); 5782 5783 auto* hash = MHashBigInt::New(alloc(), bigInt); 5784 add(hash); 5785 5786 auto* ins = MMapObjectGetBigInt::New(alloc(), map, bigInt, hash); 5787 add(ins); 5788 5789 pushResult(ins); 5790 return true; 5791 } 5792 5793 bool WarpCacheIRTranspiler::emitMapGetObjectResult(ObjOperandId mapId, 5794 ObjOperandId objId) { 5795 MDefinition* map = getOperand(mapId); 5796 MDefinition* obj = getOperand(objId); 5797 5798 auto* hash = MHashObject::New(alloc(), map, obj); 5799 add(hash); 5800 5801 auto* ins = MMapObjectGetNonBigInt::New(alloc(), map, obj, hash); 5802 add(ins); 5803 5804 pushResult(ins); 5805 return true; 5806 } 5807 5808 bool WarpCacheIRTranspiler::emitMapGetResult(ObjOperandId mapId, 5809 ValOperandId valId) { 5810 MDefinition* map = getOperand(mapId); 5811 MDefinition* val = getOperand(valId); 5812 5813 #ifdef JS_PUNBOX64 5814 auto* hashValue = MToHashableValue::New(alloc(), val); 5815 add(hashValue); 5816 5817 auto* hash = MHashValue::New(alloc(), map, hashValue); 5818 add(hash); 5819 5820 auto* ins = MMapObjectGetValue::New(alloc(), map, hashValue, hash); 5821 add(ins); 5822 #else 5823 auto* ins = MMapObjectGetValueVMCall::New(alloc(), map, val); 5824 add(ins); 5825 #endif 5826 5827 pushResult(ins); 5828 return true; 5829 } 5830 5831 bool WarpCacheIRTranspiler::emitMapDeleteResult(ObjOperandId mapId, 5832 ValOperandId keyId) { 5833 MDefinition* map = getOperand(mapId); 5834 MDefinition* key = getOperand(keyId); 5835 5836 auto* ins = MMapObjectDelete::New(alloc(), map, key); 5837 addEffectful(ins); 5838 5839 pushResult(ins); 5840 return resumeAfter(ins); 5841 } 5842 5843 bool WarpCacheIRTranspiler::emitMapSetResult(ObjOperandId mapId, 5844 ValOperandId keyId, 5845 ValOperandId valId) { 5846 MDefinition* map = getOperand(mapId); 5847 MDefinition* key = getOperand(keyId); 5848 MDefinition* val = getOperand(valId); 5849 5850 auto* ins = MMapObjectSet::New(alloc(), map, key, val); 5851 addEffectful(ins); 5852 5853 pushResult(map); 5854 return resumeAfter(ins); 5855 } 5856 5857 bool WarpCacheIRTranspiler::emitMapSizeResult(ObjOperandId mapId) { 5858 MDefinition* map = getOperand(mapId); 5859 5860 auto* ins = MMapObjectSize::New(alloc(), map); 5861 add(ins); 5862 5863 pushResult(ins); 5864 return true; 5865 } 5866 5867 bool WarpCacheIRTranspiler::emitWeakMapGetObjectResult(ObjOperandId weakMapId, 5868 ObjOperandId objId) { 5869 MDefinition* weakMap = getOperand(weakMapId); 5870 MDefinition* obj = getOperand(objId); 5871 5872 auto* ins = MWeakMapGetObject::New(alloc(), weakMap, obj); 5873 add(ins); 5874 5875 pushResult(ins); 5876 return true; 5877 } 5878 5879 bool WarpCacheIRTranspiler::emitWeakMapHasObjectResult(ObjOperandId weakMapId, 5880 ObjOperandId objId) { 5881 MDefinition* weakMap = getOperand(weakMapId); 5882 MDefinition* obj = getOperand(objId); 5883 5884 auto* ins = MWeakMapHasObject::New(alloc(), weakMap, obj); 5885 add(ins); 5886 5887 pushResult(ins); 5888 return true; 5889 } 5890 5891 bool WarpCacheIRTranspiler::emitWeakSetHasObjectResult(ObjOperandId weakSetId, 5892 ObjOperandId objId) { 5893 MDefinition* weakSet = getOperand(weakSetId); 5894 MDefinition* obj = getOperand(objId); 5895 5896 auto* ins = MWeakSetHasObject::New(alloc(), weakSet, obj); 5897 add(ins); 5898 5899 pushResult(ins); 5900 return true; 5901 } 5902 5903 bool WarpCacheIRTranspiler::emitDateFillLocalTimeSlots(ObjOperandId dateId) { 5904 MDefinition* date = getOperand(dateId); 5905 5906 // MDateFillLocalTimeSlots is effectful because it can store into fixed slots, 5907 // but it's safe to repeat this action after a bailout, therefore it's okay to 5908 // use |addEffectfulUnsafe|. 5909 auto* ins = MDateFillLocalTimeSlots::New(alloc(), date); 5910 addEffectfulUnsafe(ins); 5911 5912 return true; 5913 } 5914 5915 bool WarpCacheIRTranspiler::emitDateHoursFromSecondsIntoYearResult( 5916 ValOperandId secondsIntoYearId) { 5917 MDefinition* secondsIntoYear = getOperand(secondsIntoYearId); 5918 5919 auto* ins = MDateHoursFromSecondsIntoYear::New(alloc(), secondsIntoYear); 5920 add(ins); 5921 5922 pushResult(ins); 5923 return true; 5924 } 5925 5926 bool WarpCacheIRTranspiler::emitDateMinutesFromSecondsIntoYearResult( 5927 ValOperandId secondsIntoYearId) { 5928 MDefinition* secondsIntoYear = getOperand(secondsIntoYearId); 5929 5930 auto* ins = MDateMinutesFromSecondsIntoYear::New(alloc(), secondsIntoYear); 5931 add(ins); 5932 5933 pushResult(ins); 5934 return true; 5935 } 5936 5937 bool WarpCacheIRTranspiler::emitDateSecondsFromSecondsIntoYearResult( 5938 ValOperandId secondsIntoYearId) { 5939 MDefinition* secondsIntoYear = getOperand(secondsIntoYearId); 5940 5941 auto* ins = MDateSecondsFromSecondsIntoYear::New(alloc(), secondsIntoYear); 5942 add(ins); 5943 5944 pushResult(ins); 5945 return true; 5946 } 5947 5948 bool WarpCacheIRTranspiler::emitTruthyResult(OperandId inputId) { 5949 MDefinition* input = getOperand(inputId); 5950 5951 auto* result = convertToBoolean(input); 5952 5953 pushResult(result); 5954 return true; 5955 } 5956 5957 bool WarpCacheIRTranspiler::emitLoadInt32TruthyResult(ValOperandId inputId) { 5958 return emitTruthyResult(inputId); 5959 } 5960 5961 bool WarpCacheIRTranspiler::emitLoadDoubleTruthyResult( 5962 NumberOperandId inputId) { 5963 return emitTruthyResult(inputId); 5964 } 5965 5966 bool WarpCacheIRTranspiler::emitLoadStringTruthyResult( 5967 StringOperandId inputId) { 5968 return emitTruthyResult(inputId); 5969 } 5970 5971 bool WarpCacheIRTranspiler::emitLoadObjectTruthyResult(ObjOperandId inputId) { 5972 return emitTruthyResult(inputId); 5973 } 5974 5975 bool WarpCacheIRTranspiler::emitLoadBigIntTruthyResult( 5976 BigIntOperandId inputId) { 5977 return emitTruthyResult(inputId); 5978 } 5979 5980 bool WarpCacheIRTranspiler::emitLoadValueTruthyResult(ValOperandId inputId) { 5981 return emitTruthyResult(inputId); 5982 } 5983 5984 bool WarpCacheIRTranspiler::emitLoadOperandResult(ValOperandId inputId) { 5985 MDefinition* input = getOperand(inputId); 5986 pushResult(input); 5987 return true; 5988 } 5989 5990 bool WarpCacheIRTranspiler::emitLoadWrapperTarget(ObjOperandId objId, 5991 ObjOperandId resultId, 5992 bool fallible) { 5993 MDefinition* obj = getOperand(objId); 5994 5995 auto* ins = MLoadWrapperTarget::New(alloc(), obj, fallible); 5996 if (fallible) { 5997 ins->setGuard(); 5998 } 5999 add(ins); 6000 6001 return defineOperand(resultId, ins); 6002 } 6003 6004 // When we transpile a call, we may generate guards for some 6005 // arguments. To make sure the call instruction depends on those 6006 // guards, when the transpiler creates an operand for an argument, we 6007 // register the OperandId of that argument in argumentIds_. (See 6008 // emitLoadArgumentSlot.) Before generating the call, we update the 6009 // CallInfo to use the appropriate value from operands_. 6010 // Note: The callee is an explicit argument to the call op, and is 6011 // tracked separately. 6012 void WarpCacheIRTranspiler::updateArgumentsFromOperands() { 6013 for (uint32_t i = 0; i < uint32_t(ArgumentKind::NumKinds); i++) { 6014 ArgumentKind kind = ArgumentKind(i); 6015 OperandId id = argumentOperandIds_[kind]; 6016 if (id.valid()) { 6017 switch (kind) { 6018 case ArgumentKind::This: 6019 callInfo_->setThis(getOperand(id)); 6020 break; 6021 case ArgumentKind::NewTarget: 6022 callInfo_->setNewTarget(getOperand(id)); 6023 break; 6024 case ArgumentKind::Arg0: 6025 callInfo_->setArg(0, getOperand(id)); 6026 break; 6027 case ArgumentKind::Arg1: 6028 callInfo_->setArg(1, getOperand(id)); 6029 break; 6030 case ArgumentKind::Arg2: 6031 callInfo_->setArg(2, getOperand(id)); 6032 break; 6033 case ArgumentKind::Arg3: 6034 callInfo_->setArg(3, getOperand(id)); 6035 break; 6036 case ArgumentKind::Arg4: 6037 callInfo_->setArg(4, getOperand(id)); 6038 break; 6039 case ArgumentKind::Arg5: 6040 callInfo_->setArg(5, getOperand(id)); 6041 break; 6042 case ArgumentKind::Arg6: 6043 callInfo_->setArg(6, getOperand(id)); 6044 break; 6045 case ArgumentKind::Arg7: 6046 callInfo_->setArg(7, getOperand(id)); 6047 break; 6048 case ArgumentKind::Callee: 6049 case ArgumentKind::NumKinds: 6050 MOZ_CRASH("Unexpected argument kind"); 6051 } 6052 } 6053 } 6054 } 6055 6056 bool WarpCacheIRTranspiler::emitLoadArgumentSlot(ValOperandId resultId, 6057 uint32_t slotIndex) { 6058 // Reverse of GetIndexOfArgument. 6059 6060 // Layout: 6061 // NewTarget | Args.. (reversed) | ThisValue | Callee 6062 // 0 | ArgC .. Arg1 Arg0 (+1) | argc (+1) | argc + 1 (+ 1) 6063 // ^ (if constructing) 6064 6065 // NewTarget (optional) 6066 if (callInfo_->constructing()) { 6067 if (slotIndex == 0) { 6068 setArgumentId(ArgumentKind::NewTarget, resultId); 6069 return defineOperand(resultId, callInfo_->getNewTarget()); 6070 } 6071 6072 slotIndex -= 1; // Adjust slot index to match non-constructing calls. 6073 } 6074 6075 // Args.. 6076 if (slotIndex < callInfo_->argc()) { 6077 uint32_t arg = callInfo_->argc() - 1 - slotIndex; 6078 ArgumentKind kind = ArgumentKindForArgIndex(arg); 6079 MOZ_ASSERT(kind < ArgumentKind::NumKinds); 6080 setArgumentId(kind, resultId); 6081 return defineOperand(resultId, callInfo_->getArg(arg)); 6082 } 6083 6084 // ThisValue 6085 if (slotIndex == callInfo_->argc()) { 6086 setArgumentId(ArgumentKind::This, resultId); 6087 return defineOperand(resultId, callInfo_->thisArg()); 6088 } 6089 6090 // Callee 6091 MOZ_ASSERT(slotIndex == callInfo_->argc() + 1); 6092 return defineOperand(resultId, callInfo_->callee()); 6093 } 6094 6095 bool WarpCacheIRTranspiler::emitLoadArgumentFixedSlot(ValOperandId resultId, 6096 uint8_t slotIndex) { 6097 return emitLoadArgumentSlot(resultId, slotIndex); 6098 } 6099 6100 bool WarpCacheIRTranspiler::emitLoadArgumentDynamicSlot(ValOperandId resultId, 6101 Int32OperandId argcId, 6102 uint8_t slotIndex) { 6103 #ifdef DEBUG 6104 MDefinition* argc = getOperand(argcId); 6105 MOZ_ASSERT(argc->toConstant()->toInt32() == 6106 static_cast<int32_t>(callInfo_->argc())); 6107 #endif 6108 6109 return emitLoadArgumentSlot(resultId, callInfo_->argc() + slotIndex); 6110 } 6111 6112 WrappedFunction* WarpCacheIRTranspiler::maybeWrappedFunction( 6113 MDefinition* callee, CallKind kind, uint16_t nargs, FunctionFlags flags) { 6114 MOZ_ASSERT(callee->isConstant() || callee->isNurseryObject()); 6115 6116 // If this is a native without a JitEntry, WrappedFunction needs to know the 6117 // target JSFunction. 6118 // TODO: support nursery-allocated natives with WrappedFunction, maybe by 6119 // storing the JSNative in the Baseline stub like flags/nargs. 6120 bool isNative = flags.isNativeWithoutJitEntry(); 6121 if (isNative && !callee->isConstant()) { 6122 return nullptr; 6123 } 6124 6125 JSFunction* nativeTarget = nullptr; 6126 if (isNative) { 6127 nativeTarget = &callee->toConstant()->toObject().as<JSFunction>(); 6128 } 6129 6130 WrappedFunction* wrappedTarget = 6131 new (alloc()) WrappedFunction(nativeTarget, nargs, flags); 6132 MOZ_ASSERT_IF(kind == CallKind::Native || kind == CallKind::DOM, 6133 wrappedTarget->isNativeWithoutJitEntry()); 6134 MOZ_ASSERT_IF(kind == CallKind::Scripted, wrappedTarget->hasJitEntry()); 6135 return wrappedTarget; 6136 } 6137 6138 WrappedFunction* WarpCacheIRTranspiler::maybeCallTarget(MDefinition* callee, 6139 CallKind kind) { 6140 // CacheIR emits the following for specialized calls: 6141 // GuardSpecificFunction <callee> <func> .. 6142 // Call(Native|Scripted)Function <callee> .. 6143 // or: 6144 // GuardClass <callee> .. 6145 // GuardFunctionScript <callee> <script> .. 6146 // CallScriptedFunction <callee> .. 6147 // 6148 // We can use the <func> JSFunction or <script> BaseScript to specialize this 6149 // call. 6150 if (callee->isGuardSpecificFunction()) { 6151 auto* guard = callee->toGuardSpecificFunction(); 6152 return maybeWrappedFunction(guard->expected(), kind, guard->nargs(), 6153 guard->flags()); 6154 } 6155 if (callee->isGuardFunctionScript()) { 6156 MOZ_ASSERT(kind == CallKind::Scripted); 6157 auto* guard = callee->toGuardFunctionScript(); 6158 WrappedFunction* wrappedTarget = new (alloc()) WrappedFunction( 6159 /* nativeFun = */ nullptr, guard->nargs(), guard->flags()); 6160 MOZ_ASSERT(wrappedTarget->hasJitEntry()); 6161 return wrappedTarget; 6162 } 6163 return nullptr; 6164 } 6165 6166 WrappedFunction* WarpCacheIRTranspiler::maybeGetterSetterTarget( 6167 MDefinition* callee, CallKind kind, uint16_t nargs, FunctionFlags flags) { 6168 // CacheIR has two representations for the callee of a getter/setter: 6169 // 1. If it is always the same function, guard the GetterSetter pair, 6170 // then load a constant callee: 6171 // GuardDynamicSlotValue <holder> ... <GetterSetter> 6172 // LoadObject <callee> 6173 // CallScripted(Setter|GetterResult) <receiver> <callee> ... 6174 // 2. If it is different functions sharing a single script, load 6175 // the callee out of the GetterSetter pair, then guard that it 6176 // has the correct script: 6177 // Load(Fixed|Dynamic)Slot <GetterSetter> ... 6178 // LoadGetterSetterFunction <GetterSetter> <callee> 6179 // GuardFunctionScript <callee> <script> 6180 // CallScripted(Setter|GetterResult) <receiver> <callee> ... 6181 // 6182 // We can use <callee> from the first case, or <script> from the second. 6183 if (callee->isGuardFunctionScript()) { 6184 MOZ_ASSERT(kind == CallKind::Scripted); 6185 auto* guard = callee->toGuardFunctionScript(); 6186 WrappedFunction* wrappedTarget = new (alloc()) WrappedFunction( 6187 /* nativeFun = */ nullptr, guard->nargs(), guard->flags()); 6188 MOZ_ASSERT(wrappedTarget->hasJitEntry()); 6189 return wrappedTarget; 6190 } 6191 return maybeWrappedFunction(callee, kind, nargs, flags); 6192 } 6193 6194 // If it is possible to use MCall for this call, update callInfo_ to use 6195 // the correct arguments. Otherwise, update the ArgFormat of callInfo_. 6196 bool WarpCacheIRTranspiler::updateCallInfo(MDefinition* callee, 6197 CallFlags flags) { 6198 // The transpilation will add various guards to the callee. 6199 // We replace the callee referenced by the CallInfo, so that 6200 // the resulting call instruction depends on these guards. 6201 callInfo_->setCallee(callee); 6202 6203 // The transpilation may also add guards to other arguments. 6204 // We replace those arguments in the CallInfo here. 6205 updateArgumentsFromOperands(); 6206 6207 switch (flags.getArgFormat()) { 6208 case CallFlags::Standard: 6209 MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard); 6210 break; 6211 case CallFlags::Spread: 6212 MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Array); 6213 break; 6214 case CallFlags::FunCall: 6215 // Note: We already changed the callee to the target 6216 // function instead of the |call| function. 6217 MOZ_ASSERT(!callInfo_->constructing()); 6218 MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard); 6219 6220 if (callInfo_->argc() == 0) { 6221 // Special case for fun.call() with no arguments. 6222 auto* undef = constant(UndefinedValue()); 6223 callInfo_->setThis(undef); 6224 } else { 6225 // The first argument for |call| is the new this value. 6226 callInfo_->setThis(callInfo_->getArg(0)); 6227 6228 // Shift down all other arguments by removing the first. 6229 callInfo_->removeArg(0); 6230 } 6231 break; 6232 case CallFlags::FunApplyArgsObj: 6233 MOZ_ASSERT(!callInfo_->constructing()); 6234 MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard); 6235 6236 callInfo_->setArgFormat(CallInfo::ArgFormat::FunApplyArgsObj); 6237 break; 6238 case CallFlags::FunApplyArray: { 6239 MDefinition* argFunc = callInfo_->thisArg(); 6240 MDefinition* argThis = callInfo_->getArg(0); 6241 callInfo_->setCallee(argFunc); 6242 callInfo_->setThis(argThis); 6243 callInfo_->setArgFormat(CallInfo::ArgFormat::Array); 6244 break; 6245 } 6246 case CallFlags::FunApplyNullUndefined: 6247 // Note: We already changed the callee to the target 6248 // function instead of the |apply| function. 6249 MOZ_ASSERT(callInfo_->argc() == 2); 6250 MOZ_ASSERT(!callInfo_->constructing()); 6251 MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard); 6252 callInfo_->setThis(callInfo_->getArg(0)); 6253 callInfo_->getArg(1)->setImplicitlyUsedUnchecked(); 6254 callInfo_->removeArg(1); 6255 callInfo_->removeArg(0); 6256 break; 6257 default: 6258 MOZ_CRASH("Unsupported arg format"); 6259 } 6260 return true; 6261 } 6262 6263 // Returns true if we are generating a call to CreateThisFromIon and 6264 // must check its return value. 6265 bool WarpCacheIRTranspiler::maybeCreateThis(MDefinition* callee, 6266 CallFlags flags, CallKind kind) { 6267 MOZ_ASSERT(kind != CallKind::DOM, "DOM functions are not constructors"); 6268 MDefinition* thisArg = callInfo_->thisArg(); 6269 6270 if (kind == CallKind::Native) { 6271 // Native functions keep the is-constructing MagicValue as |this|. 6272 // If one of the arguments uses spread syntax this can be a loop phi with 6273 // MIRType::Value. 6274 MOZ_ASSERT(thisArg->type() == MIRType::MagicIsConstructing || 6275 thisArg->isPhi()); 6276 return false; 6277 } 6278 MOZ_ASSERT(kind == CallKind::Scripted); 6279 6280 if (thisArg->isNewPlainObject()) { 6281 // We have already updated |this| based on MetaScriptedThisShape. We do 6282 // not need to generate a check. 6283 return false; 6284 } 6285 if (flags.needsUninitializedThis()) { 6286 MConstant* uninit = constant(MagicValue(JS_UNINITIALIZED_LEXICAL)); 6287 thisArg->setImplicitlyUsedUnchecked(); 6288 callInfo_->setThis(uninit); 6289 return false; 6290 } 6291 // See the Native case above. 6292 MOZ_ASSERT(thisArg->type() == MIRType::MagicIsConstructing || 6293 thisArg->isPhi()); 6294 6295 auto* newTarget = unboxObjectInfallible(callInfo_->getNewTarget()); 6296 auto* createThis = MCreateThis::New(alloc(), callee, newTarget); 6297 add(createThis); 6298 6299 thisArg->setImplicitlyUsedUnchecked(); 6300 callInfo_->setThis(createThis); 6301 6302 return true; 6303 } 6304 6305 bool WarpCacheIRTranspiler::emitCallFunction( 6306 ObjOperandId calleeId, Int32OperandId argcId, 6307 mozilla::Maybe<ObjOperandId> thisObjId, CallFlags flags, CallKind kind, 6308 mozilla::Maybe<uint32_t> siteOffset) { 6309 MDefinition* callee = getOperand(calleeId); 6310 if (kind == CallKind::Scripted && callInfo_ && callInfo_->isInlined()) { 6311 // We are transpiling to generate the correct guards. We also 6312 // update the CallInfo to use the correct arguments. Code for the 6313 // inlined function itself will be generated in 6314 // WarpBuilder::buildInlinedCall. 6315 if (!updateCallInfo(callee, flags)) { 6316 return false; 6317 } 6318 if (callInfo_->constructing()) { 6319 MOZ_ASSERT(flags.isConstructing()); 6320 6321 // We call maybeCreateThis to update |this|, but inlined constructors 6322 // never need a VM call. CallIRGenerator::getThisForScripted ensures that 6323 // we don't attach a specialized stub unless we have a template object or 6324 // know that the constructor needs uninitialized this. 6325 MOZ_ALWAYS_FALSE(maybeCreateThis(callee, flags, CallKind::Scripted)); 6326 mozilla::DebugOnly<MDefinition*> thisArg = callInfo_->thisArg(); 6327 MOZ_ASSERT(thisArg->isNewPlainObject() || 6328 thisArg->type() == MIRType::MagicUninitializedLexical); 6329 } 6330 6331 if (flags.getArgFormat() == CallFlags::FunCall) { 6332 callInfo_->setInliningResumeMode(ResumeMode::InlinedFunCall); 6333 } else { 6334 MOZ_ASSERT(flags.getArgFormat() == CallFlags::Standard); 6335 callInfo_->setInliningResumeMode(ResumeMode::InlinedStandardCall); 6336 } 6337 6338 switch (callInfo_->argFormat()) { 6339 case CallInfo::ArgFormat::Standard: 6340 break; 6341 default: 6342 MOZ_CRASH("Unsupported arg format"); 6343 } 6344 return true; 6345 } 6346 6347 #ifdef DEBUG 6348 MDefinition* argc = getOperand(argcId); 6349 MOZ_ASSERT(argc->toConstant()->toInt32() == 6350 static_cast<int32_t>(callInfo_->argc())); 6351 #endif 6352 6353 if (!updateCallInfo(callee, flags)) { 6354 return false; 6355 } 6356 6357 if (kind == CallKind::DOM) { 6358 MOZ_ASSERT(flags.getArgFormat() == CallFlags::Standard); 6359 // For DOM calls |this| has a class guard. 6360 MDefinition* thisObj = getOperand(*thisObjId); 6361 callInfo_->setThis(thisObj); 6362 } 6363 6364 WrappedFunction* wrappedTarget = maybeCallTarget(callee, kind); 6365 6366 bool needsThisCheck = false; 6367 if (callInfo_->constructing()) { 6368 MOZ_ASSERT(flags.isConstructing()); 6369 needsThisCheck = maybeCreateThis(callee, flags, kind); 6370 if (needsThisCheck) { 6371 wrappedTarget = nullptr; 6372 } 6373 } 6374 6375 switch (callInfo_->argFormat()) { 6376 case CallInfo::ArgFormat::Standard: { 6377 gc::Heap initialHeap = gc::Heap::Default; 6378 if (siteOffset) { 6379 MOZ_ASSERT(kind == CallKind::DOM); 6380 MOZ_ASSERT(readStubWord(*siteOffset) <= (uintptr_t)(gc::Heap::Tenured)); 6381 initialHeap = static_cast<gc::Heap>(readStubWord(*siteOffset)); 6382 } 6383 MCall* call = makeCall(*callInfo_, needsThisCheck, wrappedTarget, 6384 kind == CallKind::DOM, initialHeap); 6385 if (!call) { 6386 return false; 6387 } 6388 6389 if (flags.isSameRealm()) { 6390 call->setNotCrossRealm(); 6391 } 6392 6393 if (call->isEffectful()) { 6394 addEffectful(call); 6395 pushResult(call); 6396 return resumeAfter(call); 6397 } 6398 6399 MOZ_ASSERT(kind == CallKind::DOM); 6400 add(call); 6401 pushResult(call); 6402 return true; 6403 } 6404 case CallInfo::ArgFormat::Array: { 6405 MInstruction* call = makeSpreadCall(*callInfo_, needsThisCheck, 6406 flags.isSameRealm(), wrappedTarget); 6407 if (!call) { 6408 return false; 6409 } 6410 addEffectful(call); 6411 pushResult(call); 6412 6413 return resumeAfter(call); 6414 } 6415 case CallInfo::ArgFormat::FunApplyArgsObj: { 6416 return emitFunApplyArgsObj(wrappedTarget, flags); 6417 } 6418 } 6419 MOZ_CRASH("unreachable"); 6420 } 6421 6422 bool WarpCacheIRTranspiler::emitFunApplyArgsObj(WrappedFunction* wrappedTarget, 6423 CallFlags flags) { 6424 MOZ_ASSERT(!callInfo_->constructing()); 6425 6426 MDefinition* callee = callInfo_->thisArg(); 6427 MDefinition* thisArg = callInfo_->getArg(0); 6428 MDefinition* argsObj = callInfo_->getArg(1); 6429 6430 MApplyArgsObj* apply = 6431 MApplyArgsObj::New(alloc(), wrappedTarget, callee, argsObj, thisArg); 6432 6433 if (flags.isSameRealm()) { 6434 apply->setNotCrossRealm(); 6435 } 6436 if (callInfo_->ignoresReturnValue()) { 6437 apply->setIgnoresReturnValue(); 6438 } 6439 6440 addEffectful(apply); 6441 pushResult(apply); 6442 6443 return resumeAfter(apply); 6444 } 6445 6446 #ifndef JS_SIMULATOR 6447 bool WarpCacheIRTranspiler::emitCallNativeFunction(ObjOperandId calleeId, 6448 Int32OperandId argcId, 6449 CallFlags flags, 6450 uint32_t argcFixed, 6451 bool ignoresReturnValue) { 6452 // Instead of ignoresReturnValue we use CallInfo::ignoresReturnValue. 6453 return emitCallFunction(calleeId, argcId, mozilla::Nothing(), flags, 6454 CallKind::Native); 6455 } 6456 6457 bool WarpCacheIRTranspiler::emitCallDOMFunction(ObjOperandId calleeId, 6458 Int32OperandId argcId, 6459 ObjOperandId thisObjId, 6460 CallFlags flags, 6461 uint32_t argcFixed) { 6462 return emitCallFunction(calleeId, argcId, mozilla::Some(thisObjId), flags, 6463 CallKind::DOM); 6464 } 6465 6466 bool WarpCacheIRTranspiler::emitCallDOMFunctionWithAllocSite( 6467 ObjOperandId calleeId, Int32OperandId argcId, ObjOperandId thisObjId, 6468 CallFlags flags, uint32_t argcFixed, uint32_t siteOffset) { 6469 return emitCallFunction(calleeId, argcId, mozilla::Some(thisObjId), flags, 6470 CallKind::DOM, mozilla::Some(siteOffset)); 6471 } 6472 #else 6473 bool WarpCacheIRTranspiler::emitCallNativeFunction(ObjOperandId calleeId, 6474 Int32OperandId argcId, 6475 CallFlags flags, 6476 uint32_t argcFixed, 6477 uint32_t targetOffset) { 6478 return emitCallFunction(calleeId, argcId, mozilla::Nothing(), flags, 6479 CallKind::Native); 6480 } 6481 6482 bool WarpCacheIRTranspiler::emitCallDOMFunction( 6483 ObjOperandId calleeId, Int32OperandId argcId, ObjOperandId thisObjId, 6484 CallFlags flags, uint32_t argcFixed, uint32_t targetOffset) { 6485 return emitCallFunction(calleeId, argcId, mozilla::Some(thisObjId), flags, 6486 CallKind::DOM); 6487 } 6488 6489 bool WarpCacheIRTranspiler::emitCallDOMFunctionWithAllocSite( 6490 ObjOperandId calleeId, Int32OperandId argcId, ObjOperandId thisObjId, 6491 CallFlags flags, uint32_t argcFixed, uint32_t siteOffset, 6492 uint32_t targetOffset) { 6493 return emitCallFunction(calleeId, argcId, mozilla::Some(thisObjId), flags, 6494 CallKind::DOM, mozilla::Some(siteOffset)); 6495 } 6496 #endif 6497 6498 bool WarpCacheIRTranspiler::emitCallScriptedFunction(ObjOperandId calleeId, 6499 Int32OperandId argcId, 6500 CallFlags flags, 6501 uint32_t argcFixed) { 6502 return emitCallFunction(calleeId, argcId, mozilla::Nothing(), flags, 6503 CallKind::Scripted); 6504 } 6505 6506 bool WarpCacheIRTranspiler::emitCallInlinedFunction(ObjOperandId calleeId, 6507 Int32OperandId argcId, 6508 uint32_t icScriptOffset, 6509 CallFlags flags, 6510 uint32_t argcFixed) { 6511 return emitCallFunction(calleeId, argcId, mozilla::Nothing(), flags, 6512 CallKind::Scripted); 6513 } 6514 6515 #ifdef JS_PUNBOX64 6516 bool WarpCacheIRTranspiler::emitCallScriptedProxyGetShared( 6517 MDefinition* target, MDefinition* receiver, MDefinition* handler, 6518 MDefinition* id, MDefinition* trapDef, WrappedFunction* trap) { 6519 CallInfo callInfo(alloc(), /* constructing = */ false, 6520 /* ignoresRval = */ false); 6521 callInfo.initForProxyGet(trapDef, handler, target, id, receiver); 6522 6523 MCall* call = makeCall(callInfo, /* needsThisCheck = */ false, trap); 6524 if (!call) { 6525 return false; 6526 } 6527 6528 addEffectful(call); 6529 6530 if (!current->ensureHasSlots(3)) { 6531 return false; 6532 } 6533 current->push(call); 6534 current->push(id); 6535 current->push(target); 6536 6537 MResumePoint* resumePoint = 6538 MResumePoint::New(alloc(), current, loc_.toRawBytecode(), 6539 ResumeMode::ResumeAfterCheckProxyGetResult); 6540 if (!resumePoint) { 6541 return false; 6542 } 6543 call->setResumePoint(resumePoint); 6544 6545 current->pop(); 6546 current->pop(); 6547 6548 MCheckScriptedProxyGetResult* check = 6549 MCheckScriptedProxyGetResult::New(alloc(), target, id, call); 6550 addEffectfulUnsafe(check); 6551 6552 return resumeAfterUnchecked(check); 6553 } 6554 6555 bool WarpCacheIRTranspiler::emitCallScriptedProxyGetResult( 6556 ValOperandId targetId, ObjOperandId receiverId, ObjOperandId handlerId, 6557 ObjOperandId trapId, uint32_t idOffset, uint32_t nargsAndFlags) { 6558 MDefinition* target = getOperand(targetId); 6559 MDefinition* receiver = getOperand(receiverId); 6560 MDefinition* handler = getOperand(handlerId); 6561 MDefinition* trap = getOperand(trapId); 6562 jsid id = idStubField(idOffset); 6563 MDefinition* idDef = constant(StringValue(id.toAtom())); 6564 WrappedFunction* wrappedTarget = maybeCallTarget(trap, CallKind::Scripted); 6565 MOZ_RELEASE_ASSERT(wrappedTarget); 6566 return emitCallScriptedProxyGetShared(target, receiver, handler, idDef, trap, 6567 wrappedTarget); 6568 } 6569 6570 bool WarpCacheIRTranspiler::emitCallScriptedProxyGetByValueResult( 6571 ValOperandId targetId, ObjOperandId receiverId, ObjOperandId handlerId, 6572 ValOperandId idId, ObjOperandId trapId, uint32_t nargsAndFlags) { 6573 MDefinition* target = getOperand(targetId); 6574 MDefinition* receiver = getOperand(receiverId); 6575 MDefinition* handler = getOperand(handlerId); 6576 MDefinition* trap = getOperand(trapId); 6577 MDefinition* idDef = getOperand(idId); 6578 WrappedFunction* wrappedTarget = maybeCallTarget(trap, CallKind::Scripted); 6579 MOZ_RELEASE_ASSERT(wrappedTarget); 6580 return emitCallScriptedProxyGetShared(target, receiver, handler, idDef, trap, 6581 wrappedTarget); 6582 } 6583 #endif 6584 6585 bool WarpCacheIRTranspiler::emitCallClassHook(ObjOperandId calleeId, 6586 Int32OperandId argcId, 6587 CallFlags flags, 6588 uint32_t argcFixed, 6589 uint32_t targetOffset) { 6590 MDefinition* callee = getOperand(calleeId); 6591 JSNative target = jsnativeStubField(targetOffset); 6592 6593 #ifdef DEBUG 6594 MDefinition* argc = getOperand(argcId); 6595 MOZ_ASSERT(argc->toConstant()->toInt32() == 6596 static_cast<int32_t>(callInfo_->argc())); 6597 #endif 6598 6599 if (!updateCallInfo(callee, flags)) { 6600 return false; 6601 } 6602 6603 MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard); 6604 MOZ_ASSERT(flags.getArgFormat() == CallFlags::ArgFormat::Standard); 6605 6606 // Callees can be from any realm. If this changes, we should update 6607 // MCallClassHook::maybeCrossRealm. 6608 MOZ_ASSERT(!flags.isSameRealm()); 6609 6610 auto* call = MCallClassHook::New(alloc(), target, callInfo_->argc(), 6611 callInfo_->constructing()); 6612 if (!call) { 6613 return false; 6614 } 6615 6616 if (callInfo_->ignoresReturnValue()) { 6617 call->setIgnoresReturnValue(); 6618 } 6619 6620 call->initCallee(callInfo_->callee()); 6621 call->addArg(0, callInfo_->thisArg()); 6622 6623 for (uint32_t i = 0; i < callInfo_->argc(); i++) { 6624 call->addArg(i + 1, callInfo_->getArg(i)); 6625 } 6626 6627 if (callInfo_->constructing()) { 6628 call->addArg(1 + callInfo_->argc(), callInfo_->getNewTarget()); 6629 } 6630 6631 addEffectful(call); 6632 pushResult(call); 6633 6634 return resumeAfter(call); 6635 } 6636 6637 bool WarpCacheIRTranspiler::emitCallBoundScriptedFunction( 6638 ObjOperandId calleeId, ObjOperandId targetId, Int32OperandId argcId, 6639 CallFlags flags, uint32_t numBoundArgs) { 6640 MDefinition* callee = getOperand(calleeId); 6641 MDefinition* target = getOperand(targetId); 6642 6643 MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard); 6644 MOZ_ASSERT(callInfo_->constructing() == flags.isConstructing()); 6645 6646 callInfo_->setCallee(target); 6647 updateArgumentsFromOperands(); 6648 6649 WrappedFunction* wrappedTarget = maybeCallTarget(target, CallKind::Scripted); 6650 6651 bool needsThisCheck = false; 6652 if (callInfo_->constructing()) { 6653 callInfo_->setNewTarget(target); 6654 needsThisCheck = maybeCreateThis(target, flags, CallKind::Scripted); 6655 if (needsThisCheck) { 6656 wrappedTarget = nullptr; 6657 } 6658 } else { 6659 auto* thisv = MLoadFixedSlot::New(alloc(), callee, 6660 BoundFunctionObject::boundThisSlot()); 6661 add(thisv); 6662 callInfo_->thisArg()->setImplicitlyUsedUnchecked(); 6663 callInfo_->setThis(thisv); 6664 } 6665 6666 bool usingInlineBoundArgs = 6667 numBoundArgs <= BoundFunctionObject::MaxInlineBoundArgs; 6668 6669 MElements* elements = nullptr; 6670 if (!usingInlineBoundArgs) { 6671 auto* boundArgs = MLoadFixedSlot::New( 6672 alloc(), callee, BoundFunctionObject::firstInlineBoundArgSlot()); 6673 add(boundArgs); 6674 auto* boundArgsObj = unboxObjectInfallible(boundArgs, IsMovable::Yes); 6675 elements = MElements::New(alloc(), boundArgsObj); 6676 add(elements); 6677 } 6678 6679 auto loadBoundArg = [&](size_t index) { 6680 MInstruction* arg; 6681 if (usingInlineBoundArgs) { 6682 size_t slot = BoundFunctionObject::firstInlineBoundArgSlot() + index; 6683 arg = MLoadFixedSlot::New(alloc(), callee, slot); 6684 } else { 6685 arg = MLoadElement::New(alloc(), elements, constant(Int32Value(index)), 6686 /*needsHoleCheck*/ false); 6687 } 6688 add(arg); 6689 return arg; 6690 }; 6691 if (!callInfo_->prependArgs(numBoundArgs, loadBoundArg)) { 6692 return false; 6693 } 6694 6695 MCall* call = makeCall(*callInfo_, needsThisCheck, wrappedTarget); 6696 if (!call) { 6697 return false; 6698 } 6699 6700 if (flags.isSameRealm()) { 6701 call->setNotCrossRealm(); 6702 } 6703 6704 addEffectful(call); 6705 pushResult(call); 6706 return resumeAfter(call); 6707 } 6708 6709 bool WarpCacheIRTranspiler::emitBindFunctionResult( 6710 ObjOperandId targetId, uint32_t argc, uint32_t templateObjectOffset) { 6711 MDefinition* target = getOperand(targetId); 6712 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 6713 6714 // callInfo_ can be null when `bind` is inlined through a getter access, but 6715 // in that case `argc` is guaranteed to be zero. 6716 MOZ_ASSERT_IF(callInfo_, callInfo_->argc() == argc); 6717 MOZ_ASSERT_IF(!callInfo_, argc == 0); 6718 6719 auto* bound = MBindFunction::New(alloc(), target, argc, templateObj); 6720 if (!bound) { 6721 return false; 6722 } 6723 addEffectful(bound); 6724 6725 for (uint32_t i = 0; i < argc; i++) { 6726 bound->initArg(i, callInfo_->getArg(i)); 6727 } 6728 6729 pushResult(bound); 6730 return resumeAfter(bound); 6731 } 6732 6733 bool WarpCacheIRTranspiler::emitSpecializedBindFunctionResult( 6734 ObjOperandId targetId, uint32_t argc, uint32_t templateObjectOffset) { 6735 MDefinition* target = getOperand(targetId); 6736 JSObject* templateObj = tenuredObjectStubField(templateObjectOffset); 6737 6738 // callInfo_ can be null when `bind` is inlined through a getter access, but 6739 // in that case `argc` is guaranteed to be zero. 6740 MOZ_ASSERT_IF(callInfo_, callInfo_->argc() == argc); 6741 MOZ_ASSERT_IF(!callInfo_, argc == 0); 6742 6743 auto* bound = MNewBoundFunction::New(alloc(), templateObj); 6744 add(bound); 6745 6746 size_t numBoundArgs = argc > 0 ? argc - 1 : 0; 6747 MOZ_ASSERT(numBoundArgs <= BoundFunctionObject::MaxInlineBoundArgs); 6748 6749 auto initSlot = [&](size_t slot, MDefinition* value) { 6750 #ifdef DEBUG 6751 // Assert we can elide the post write barrier. See also the comment in 6752 // WarpBuilder::buildNamedLambdaEnv. 6753 add(MAssertCanElidePostWriteBarrier::New(alloc(), bound, value)); 6754 #endif 6755 addUnchecked(MStoreFixedSlot::NewUnbarriered(alloc(), bound, slot, value)); 6756 }; 6757 6758 initSlot(BoundFunctionObject::targetSlot(), target); 6759 if (argc > 0) { 6760 initSlot(BoundFunctionObject::boundThisSlot(), callInfo_->getArg(0)); 6761 } 6762 for (size_t i = 0; i < numBoundArgs; i++) { 6763 size_t slot = BoundFunctionObject::firstInlineBoundArgSlot() + i; 6764 initSlot(slot, callInfo_->getArg(1 + i)); 6765 } 6766 6767 pushResult(bound); 6768 return true; 6769 } 6770 6771 bool WarpCacheIRTranspiler::emitCallWasmFunction( 6772 ObjOperandId calleeId, Int32OperandId argcId, CallFlags flags, 6773 uint32_t argcFixed, uint32_t funcExportOffset, uint32_t instanceOffset) { 6774 MDefinition* callee = getOperand(calleeId); 6775 #ifdef DEBUG 6776 MDefinition* argc = getOperand(argcId); 6777 MOZ_ASSERT(argc->toConstant()->toInt32() == 6778 static_cast<int32_t>(callInfo_->argc())); 6779 #endif 6780 JSObject* instanceObject = tenuredObjectStubField(instanceOffset); 6781 auto* wasmInstanceObj = &instanceObject->as<WasmInstanceObject>(); 6782 const wasm::FuncExport* funcExport = wasmFuncExportField(funcExportOffset); 6783 const wasm::FuncType& sig = 6784 wasmInstanceObj->instance().code().codeMeta().getFuncType( 6785 funcExport->funcIndex()); 6786 6787 if (!updateCallInfo(callee, flags)) { 6788 return false; 6789 } 6790 6791 static_assert(wasm::MaxArgsForJitInlineCall <= MaxNumLInstructionOperands, 6792 "arguments must fit in LIR operands"); 6793 MOZ_ASSERT(sig.args().length() <= wasm::MaxArgsForJitInlineCall); 6794 6795 MOZ_ASSERT(callInfo_->argFormat() == CallInfo::ArgFormat::Standard); 6796 6797 auto* call = MIonToWasmCall::New(alloc(), wasmInstanceObj, *funcExport); 6798 if (!call) { 6799 return false; 6800 } 6801 6802 mozilla::Maybe<MDefinition*> undefined; 6803 for (size_t i = 0; i < sig.args().length(); i++) { 6804 if (!alloc().ensureBallast()) { 6805 return false; 6806 } 6807 6808 MDefinition* arg; 6809 if (i < callInfo_->argc()) { 6810 arg = callInfo_->getArg(i); 6811 } else { 6812 if (!undefined) { 6813 undefined.emplace(constant(UndefinedValue())); 6814 } 6815 arg = convertWasmArg(*undefined, sig.args()[i].kind()); 6816 } 6817 call->initArg(i, arg); 6818 } 6819 6820 addEffectful(call); 6821 6822 // Add any post-function call conversions that are necessary. 6823 MInstruction* postConversion = call; 6824 const wasm::ValTypeVector& results = sig.results(); 6825 MOZ_ASSERT(results.length() <= 1, "Multi-value returns not supported."); 6826 if (results.length() == 0) { 6827 // No results to convert. 6828 } else { 6829 switch (results[0].kind()) { 6830 case wasm::ValType::I64: 6831 // JS expects a BigInt from I64 types. 6832 postConversion = 6833 MInt64ToBigInt::New(alloc(), call, /* isSigned = */ true); 6834 6835 // Make non-movable so we can attach a resume point. 6836 postConversion->setNotMovable(); 6837 6838 add(postConversion); 6839 break; 6840 default: 6841 // No spectre.index_masking of i32 results required, as the generated 6842 // stub takes care of that. 6843 break; 6844 } 6845 } 6846 6847 // The resume point has to be attached to the post-conversion instruction 6848 // (if present) instead of to the call. This way, if the call triggers an 6849 // invalidation bailout, we will have the BigInt value on the Baseline stack. 6850 // Potential alternative solution: attach the resume point to the call and 6851 // have bailouts turn the Int64 value into a BigInt, maybe with a recover 6852 // instruction. 6853 pushResult(postConversion); 6854 return resumeAfterUnchecked(postConversion); 6855 } 6856 6857 MDefinition* WarpCacheIRTranspiler::convertWasmArg(MDefinition* arg, 6858 wasm::ValType::Kind kind) { 6859 // An invariant in this code is that any type conversion operation that has 6860 // externally visible effects, such as invoking valueOf on an object argument, 6861 // must bailout so that we don't have to worry about replaying effects during 6862 // argument conversion. 6863 MInstruction* conversion = nullptr; 6864 switch (kind) { 6865 case wasm::ValType::I32: 6866 conversion = MTruncateToInt32::New(alloc(), arg); 6867 break; 6868 case wasm::ValType::I64: 6869 conversion = MToInt64::New(alloc(), arg); 6870 break; 6871 case wasm::ValType::F32: 6872 conversion = MToFloat32::New(alloc(), arg); 6873 break; 6874 case wasm::ValType::F64: 6875 conversion = MToDouble::New(alloc(), arg); 6876 break; 6877 case wasm::ValType::V128: 6878 MOZ_CRASH("Unexpected type for Wasm JitEntry"); 6879 case wasm::ValType::Ref: 6880 // Transform the JS representation into an AnyRef representation. 6881 // The resulting type is MIRType::WasmAnyRef. These cases are all 6882 // effect-free. 6883 switch (arg->type()) { 6884 case MIRType::Object: 6885 conversion = MWasmAnyRefFromJSObject::New(alloc(), arg); 6886 break; 6887 case MIRType::String: 6888 conversion = MWasmAnyRefFromJSString::New(alloc(), arg); 6889 break; 6890 case MIRType::Null: 6891 arg->setImplicitlyUsedUnchecked(); 6892 conversion = MWasmNullConstant::New(alloc(), wasm::MaybeRefType()); 6893 break; 6894 default: 6895 conversion = MWasmAnyRefFromJSValue::New(alloc(), arg); 6896 break; 6897 } 6898 break; 6899 } 6900 6901 add(conversion); 6902 return conversion; 6903 } 6904 6905 bool WarpCacheIRTranspiler::emitGuardWasmArg(ValOperandId argId, 6906 wasm::ValType::Kind kind) { 6907 MDefinition* arg = getOperand(argId); 6908 MDefinition* conversion = convertWasmArg(arg, kind); 6909 6910 setOperand(argId, conversion); 6911 return true; 6912 } 6913 6914 bool WarpCacheIRTranspiler::emitCallGetterResult(CallKind kind, 6915 ValOperandId receiverId, 6916 MDefinition* getter, 6917 bool sameRealm, 6918 uint32_t nargsAndFlagsOffset) { 6919 MDefinition* receiver = getOperand(receiverId); 6920 if (kind == CallKind::Scripted && callInfo_ && callInfo_->isInlined()) { 6921 // We are transpiling to generate the correct guards. We also update the 6922 // CallInfo to use the correct arguments. Code for the inlined getter 6923 // itself will be generated in WarpBuilder::buildInlinedCall. 6924 callInfo_->initForGetterCall(getter, receiver); 6925 callInfo_->setInliningResumeMode(ResumeMode::InlinedAccessor); 6926 6927 // Make sure there's enough room to push the arguments on the stack. 6928 if (!current->ensureHasSlots(2)) { 6929 return false; 6930 } 6931 6932 return true; 6933 } 6934 6935 uint32_t nargsAndFlags = uint32StubField(nargsAndFlagsOffset); 6936 uint16_t nargs = nargsAndFlags >> 16; 6937 FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags)); 6938 WrappedFunction* wrappedTarget = 6939 maybeGetterSetterTarget(getter, kind, nargs, flags); 6940 6941 bool ignoresRval = loc_.resultIsPopped(); 6942 CallInfo callInfo(alloc(), /* constructing = */ false, ignoresRval); 6943 callInfo.initForGetterCall(getter, receiver); 6944 6945 MCall* call = makeCall(callInfo, /* needsThisCheck = */ false, wrappedTarget); 6946 if (!call) { 6947 return false; 6948 } 6949 6950 if (sameRealm) { 6951 call->setNotCrossRealm(); 6952 } 6953 6954 addEffectful(call); 6955 pushResult(call); 6956 6957 return resumeAfter(call); 6958 } 6959 6960 bool WarpCacheIRTranspiler::emitCallScriptedGetterResult( 6961 ValOperandId receiverId, ObjOperandId calleeId, bool sameRealm, 6962 uint32_t nargsAndFlagsOffset) { 6963 MDefinition* getter = getOperand(calleeId); 6964 return emitCallGetterResult(CallKind::Scripted, receiverId, getter, sameRealm, 6965 nargsAndFlagsOffset); 6966 } 6967 6968 bool WarpCacheIRTranspiler::emitCallInlinedGetterResult( 6969 ValOperandId receiverId, ObjOperandId calleeId, uint32_t icScriptOffset, 6970 bool sameRealm, uint32_t nargsAndFlagsOffset) { 6971 MDefinition* getter = getOperand(calleeId); 6972 return emitCallGetterResult(CallKind::Scripted, receiverId, getter, sameRealm, 6973 nargsAndFlagsOffset); 6974 } 6975 6976 bool WarpCacheIRTranspiler::emitCallNativeGetterResult( 6977 ValOperandId receiverId, uint32_t getterOffset, bool sameRealm, 6978 uint32_t nargsAndFlagsOffset) { 6979 MDefinition* getter = objectStubField(getterOffset); 6980 return emitCallGetterResult(CallKind::Native, receiverId, getter, sameRealm, 6981 nargsAndFlagsOffset); 6982 } 6983 6984 bool WarpCacheIRTranspiler::emitCallSetter(CallKind kind, 6985 ObjOperandId receiverId, 6986 MDefinition* setter, 6987 ValOperandId rhsId, bool sameRealm, 6988 uint32_t nargsAndFlagsOffset) { 6989 MDefinition* receiver = getOperand(receiverId); 6990 MDefinition* rhs = getOperand(rhsId); 6991 if (kind == CallKind::Scripted && callInfo_ && callInfo_->isInlined()) { 6992 // We are transpiling to generate the correct guards. We also update the 6993 // CallInfo to use the correct arguments. Code for the inlined setter 6994 // itself will be generated in WarpBuilder::buildInlinedCall. 6995 callInfo_->initForSetterCall(setter, receiver, rhs); 6996 callInfo_->setInliningResumeMode(ResumeMode::InlinedAccessor); 6997 6998 // Make sure there's enough room to push the arguments on the stack. 6999 if (!current->ensureHasSlots(3)) { 7000 return false; 7001 } 7002 7003 return true; 7004 } 7005 7006 uint32_t nargsAndFlags = uint32StubField(nargsAndFlagsOffset); 7007 uint16_t nargs = nargsAndFlags >> 16; 7008 FunctionFlags flags = FunctionFlags(uint16_t(nargsAndFlags)); 7009 WrappedFunction* wrappedTarget = 7010 maybeGetterSetterTarget(setter, kind, nargs, flags); 7011 7012 CallInfo callInfo(alloc(), /* constructing = */ false, 7013 /* ignoresReturnValue = */ true); 7014 callInfo.initForSetterCall(setter, receiver, rhs); 7015 7016 MCall* call = makeCall(callInfo, /* needsThisCheck = */ false, wrappedTarget); 7017 if (!call) { 7018 return false; 7019 } 7020 7021 if (sameRealm) { 7022 call->setNotCrossRealm(); 7023 } 7024 7025 addEffectful(call); 7026 return resumeAfter(call); 7027 } 7028 7029 bool WarpCacheIRTranspiler::emitCallScriptedSetter( 7030 ObjOperandId receiverId, ObjOperandId calleeId, ValOperandId rhsId, 7031 bool sameRealm, uint32_t nargsAndFlagsOffset) { 7032 MDefinition* setter = getOperand(calleeId); 7033 return emitCallSetter(CallKind::Scripted, receiverId, setter, rhsId, 7034 sameRealm, nargsAndFlagsOffset); 7035 } 7036 7037 bool WarpCacheIRTranspiler::emitCallInlinedSetter( 7038 ObjOperandId receiverId, ObjOperandId calleeId, ValOperandId rhsId, 7039 uint32_t icScriptOffset, bool sameRealm, uint32_t nargsAndFlagsOffset) { 7040 MDefinition* setter = getOperand(calleeId); 7041 return emitCallSetter(CallKind::Scripted, receiverId, setter, rhsId, 7042 sameRealm, nargsAndFlagsOffset); 7043 } 7044 7045 bool WarpCacheIRTranspiler::emitCallNativeSetter(ObjOperandId receiverId, 7046 uint32_t setterOffset, 7047 ValOperandId rhsId, 7048 bool sameRealm, 7049 uint32_t nargsAndFlagsOffset) { 7050 MDefinition* setter = objectStubField(setterOffset); 7051 return emitCallSetter(CallKind::Native, receiverId, setter, rhsId, sameRealm, 7052 nargsAndFlagsOffset); 7053 } 7054 7055 bool WarpCacheIRTranspiler::emitMetaScriptedThisShape( 7056 uint32_t thisShapeOffset) { 7057 SharedShape* shape = &shapeStubField(thisShapeOffset)->asShared(); 7058 MOZ_ASSERT(shape->getObjectClass() == &PlainObject::class_); 7059 7060 MConstant* shapeConst = MConstant::NewShape(alloc(), shape); 7061 add(shapeConst); 7062 7063 // TODO: support pre-tenuring. 7064 gc::Heap heap = gc::Heap::Default; 7065 7066 uint32_t numFixedSlots = shape->numFixedSlots(); 7067 uint32_t numDynamicSlots = NativeObject::calculateDynamicSlots(shape); 7068 gc::AllocKind kind = gc::GetGCObjectKind(numFixedSlots); 7069 MOZ_ASSERT(gc::GetObjectFinalizeKind(&PlainObject::class_) == 7070 gc::FinalizeKind::None); 7071 MOZ_ASSERT(!IsFinalizedKind(kind)); 7072 7073 auto* createThis = MNewPlainObject::New(alloc(), shapeConst, numFixedSlots, 7074 numDynamicSlots, kind, heap); 7075 add(createThis); 7076 7077 callInfo_->thisArg()->setImplicitlyUsedUnchecked(); 7078 callInfo_->setThis(createThis); 7079 return true; 7080 } 7081 7082 bool WarpCacheIRTranspiler::emitReturnFromIC() { return true; } 7083 7084 bool WarpCacheIRTranspiler::emitBailout() { 7085 auto* bail = MBail::New(alloc()); 7086 add(bail); 7087 7088 return true; 7089 } 7090 7091 bool WarpCacheIRTranspiler::emitAssertPropertyLookup(ObjOperandId objId, 7092 uint32_t idOffset, 7093 uint32_t slotOffset) { 7094 // We currently only emit checks in baseline. 7095 return true; 7096 } 7097 7098 bool WarpCacheIRTranspiler::emitAssertFloat32Result(ValOperandId valId, 7099 bool mustBeFloat32) { 7100 MDefinition* val = getOperand(valId); 7101 7102 auto* assert = MAssertFloat32::New(alloc(), val, mustBeFloat32); 7103 addEffectful(assert); 7104 7105 pushResult(constant(UndefinedValue())); 7106 return resumeAfter(assert); 7107 } 7108 7109 bool WarpCacheIRTranspiler::emitAssertRecoveredOnBailoutResult( 7110 ValOperandId valId, bool mustBeRecovered) { 7111 MDefinition* val = getOperand(valId); 7112 7113 // Don't assert for recovered instructions when recovering is disabled. 7114 if (JitOptions.disableRecoverIns) { 7115 pushResult(constant(UndefinedValue())); 7116 return true; 7117 } 7118 7119 if (JitOptions.checkRangeAnalysis) { 7120 // If we are checking the range of all instructions, then the guards 7121 // inserted by Range Analysis prevent the use of recover instruction. Thus, 7122 // we just disable these checks. 7123 pushResult(constant(UndefinedValue())); 7124 return true; 7125 } 7126 7127 auto* assert = MAssertRecoveredOnBailout::New(alloc(), val, mustBeRecovered); 7128 addEffectfulUnsafe(assert); 7129 current->push(assert); 7130 7131 // Create an instruction sequence which implies that the argument of the 7132 // assertRecoveredOnBailout function would be encoded at least in one 7133 // Snapshot. 7134 auto* nop = MNop::New(alloc()); 7135 add(nop); 7136 7137 auto* resumePoint = MResumePoint::New( 7138 alloc(), nop->block(), loc_.toRawBytecode(), ResumeMode::ResumeAfter); 7139 if (!resumePoint) { 7140 return false; 7141 } 7142 nop->setResumePoint(resumePoint); 7143 7144 auto* encode = MEncodeSnapshot::New(alloc()); 7145 addEffectfulUnsafe(encode); 7146 7147 current->pop(); 7148 7149 pushResult(constant(UndefinedValue())); 7150 return true; 7151 } 7152 7153 bool WarpCacheIRTranspiler::emitGuardNoAllocationMetadataBuilder( 7154 uint32_t builderAddrOffset) { 7155 // This is a no-op because we discard all JIT code when set an allocation 7156 // metadata callback. 7157 return true; 7158 } 7159 7160 bool WarpCacheIRTranspiler::emitNewPlainObjectResult(uint32_t numFixedSlots, 7161 uint32_t numDynamicSlots, 7162 gc::AllocKind allocKind, 7163 uint32_t shapeOffset, 7164 uint32_t siteOffset) { 7165 Shape* shape = shapeStubField(shapeOffset); 7166 gc::Heap heap = allocSiteInitialHeapField(siteOffset); 7167 7168 auto* shapeConstant = MConstant::NewShape(alloc(), shape); 7169 add(shapeConstant); 7170 7171 auto* obj = MNewPlainObject::New(alloc(), shapeConstant, numFixedSlots, 7172 numDynamicSlots, allocKind, heap); 7173 add(obj); 7174 7175 pushResult(obj); 7176 return true; 7177 } 7178 7179 bool WarpCacheIRTranspiler::emitNewArrayObjectResult(uint32_t length, 7180 uint32_t shapeOffset, 7181 uint32_t siteOffset) { 7182 Shape* shape = shapeStubField(shapeOffset); 7183 gc::Heap heap = allocSiteInitialHeapField(siteOffset); 7184 7185 auto* shapeConstant = MConstant::NewShape(alloc(), shape); 7186 add(shapeConstant); 7187 7188 auto* obj = MNewArrayObject::New(alloc(), shapeConstant, length, heap); 7189 add(obj); 7190 7191 pushResult(obj); 7192 return true; 7193 } 7194 7195 bool WarpCacheIRTranspiler::emitNewFunctionCloneResult(uint32_t canonicalOffset, 7196 gc::AllocKind allocKind, 7197 uint32_t siteOffset) { 7198 JSObject* fun = tenuredObjectStubField(canonicalOffset); 7199 MOZ_ASSERT(fun->is<JSFunction>()); 7200 7201 gc::Heap heap = allocSiteInitialHeapField(siteOffset); 7202 7203 MDefinition* env = currentBlock()->environmentChain(); 7204 7205 // The environment chain must be an object, but the MIR type can be Value when 7206 // phis are involved. 7207 if (env->type() != MIRType::Object) { 7208 MOZ_ASSERT(env->type() == MIRType::Value); 7209 auto* unbox = 7210 MUnbox::New(alloc(), env, MIRType::Object, MUnbox::Infallible); 7211 current->add(unbox); 7212 env = unbox; 7213 } 7214 7215 MConstant* funConst = constant(ObjectValue(*fun)); 7216 7217 auto* ins = MLambda::New(alloc(), env, funConst, heap); 7218 addEffectful(ins); 7219 pushResult(ins); 7220 return resumeAfter(ins); 7221 } 7222 7223 bool WarpCacheIRTranspiler::emitCloseIterScriptedResult(ObjOperandId iterId, 7224 ObjOperandId calleeId, 7225 uint32_t calleeNargs) { 7226 MDefinition* iter = getOperand(iterId); 7227 MDefinition* callee = getOperand(calleeId); 7228 7229 WrappedFunction* wrappedTarget = maybeCallTarget(callee, CallKind::Scripted); 7230 MOZ_ASSERT(wrappedTarget); 7231 MOZ_ASSERT(wrappedTarget->nargs() == calleeNargs); 7232 MOZ_ASSERT(wrappedTarget->hasJitEntry()); 7233 7234 bool constructing = false; 7235 bool ignoresRval = false; 7236 bool needsThisCheck = false; 7237 CallInfo callInfo(alloc(), constructing, ignoresRval); 7238 callInfo.initForCloseIter(iter, callee); 7239 MCall* call = makeCall(callInfo, needsThisCheck, wrappedTarget); 7240 if (!call) { 7241 return false; 7242 } 7243 addEffectful(call); 7244 7245 // If we bail out here, after the call but before the CheckIsObj, we 7246 // can't simply resume in the baseline interpreter. If we resume 7247 // after the CloseIter, we won't check the return value. If we 7248 // resume at the CloseIter, we will call the |return| method twice. 7249 // Instead, we use a special resume mode that captures the 7250 // intermediate value, and then checks that it's an object while 7251 // bailing out. 7252 current->push(call); 7253 MResumePoint* resumePoint = 7254 MResumePoint::New(alloc(), current, loc_.toRawBytecode(), 7255 ResumeMode::ResumeAfterCheckIsObject); 7256 if (!resumePoint) { 7257 return false; 7258 } 7259 call->setResumePoint(resumePoint); 7260 current->pop(); 7261 7262 MCheckIsObj* check = MCheckIsObj::New( 7263 alloc(), call, uint8_t(CheckIsObjectKind::IteratorReturn)); 7264 addEffectfulUnsafe(check); 7265 7266 return resumeAfterUnchecked(check); 7267 } 7268 7269 bool WarpCacheIRTranspiler::emitGuardGlobalGeneration( 7270 uint32_t expectedOffset, uint32_t generationAddrOffset) { 7271 uint32_t expected = uint32StubField(expectedOffset); 7272 const void* generationAddr = rawPointerField(generationAddrOffset); 7273 7274 auto guard = MGuardGlobalGeneration::New(alloc(), expected, generationAddr); 7275 add(guard); 7276 7277 return true; 7278 } 7279 7280 #ifdef FUZZING_JS_FUZZILLI 7281 bool WarpCacheIRTranspiler::emitFuzzilliHashResult(ValOperandId valId) { 7282 MDefinition* input = getOperand(valId); 7283 7284 auto* hash = MFuzzilliHash::New(alloc(), input); 7285 add(hash); 7286 7287 auto* store = MFuzzilliHashStore::New(alloc(), hash); 7288 addEffectful(store); 7289 pushResult(constant(UndefinedValue())); 7290 7291 return resumeAfter(store); 7292 } 7293 #endif 7294 7295 static void MaybeSetImplicitlyUsed(uint32_t numInstructionIdsBefore, 7296 MDefinition* input) { 7297 // When building MIR from bytecode, for each MDefinition that's an operand to 7298 // a bytecode instruction, we must either add an SSA use or set the 7299 // ImplicitlyUsed flag on that definition. The ImplicitlyUsed flag prevents 7300 // the backend from optimizing-out values that will be used by Baseline after 7301 // a bailout. 7302 // 7303 // WarpBuilder uses WarpPoppedValueUseChecker to assert this invariant in 7304 // debug builds. 7305 // 7306 // This function is responsible for setting the ImplicitlyUsed flag for an 7307 // input when using the transpiler. It looks at the input's most recent use 7308 // and if that's an instruction that was added while transpiling this JSOp 7309 // (based on the MIR instruction id) we don't set the ImplicitlyUsed flag. 7310 7311 if (input->isImplicitlyUsed()) { 7312 // Nothing to do. 7313 return; 7314 } 7315 7316 // If the most recent use of 'input' is an instruction we just added, there is 7317 // nothing to do. 7318 MDefinition* inputUse = input->maybeMostRecentlyAddedDefUse(); 7319 if (inputUse && inputUse->id() >= numInstructionIdsBefore) { 7320 return; 7321 } 7322 7323 // The transpiler didn't add a use for 'input'. 7324 input->setImplicitlyUsed(); 7325 } 7326 7327 bool jit::TranspileCacheIRToMIR(WarpBuilder* builder, BytecodeLocation loc, 7328 const WarpCacheIRBase* cacheIRSnapshot, 7329 std::initializer_list<MDefinition*> inputs, 7330 CallInfo* maybeCallInfo) { 7331 uint32_t numInstructionIdsBefore = 7332 builder->mirGen().graph().getNumInstructionIds(); 7333 7334 WarpCacheIRTranspiler transpiler(builder, loc, maybeCallInfo, 7335 cacheIRSnapshot); 7336 if (!transpiler.transpile(inputs)) { 7337 return false; 7338 } 7339 7340 for (MDefinition* input : inputs) { 7341 MaybeSetImplicitlyUsed(numInstructionIdsBefore, input); 7342 } 7343 7344 if (maybeCallInfo) { 7345 auto maybeSetFlag = [numInstructionIdsBefore](MDefinition* def) { 7346 MaybeSetImplicitlyUsed(numInstructionIdsBefore, def); 7347 }; 7348 maybeCallInfo->forEachCallOperand(maybeSetFlag); 7349 } 7350 7351 return true; 7352 }