| File: | var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h |
| Warning: | line 9474, column 17 Value stored to 'what' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | /* |
| 8 | * Everything needed to build actual MIR instructions: the actual opcodes and |
| 9 | * instructions, the instruction interface, and use chains. |
| 10 | */ |
| 11 | |
| 12 | #ifndef jit_MIR_h |
| 13 | #define jit_MIR_h |
| 14 | |
| 15 | #include "mozilla/Array.h" |
| 16 | #include "mozilla/HashFunctions.h" |
| 17 | #ifdef JS_JITSPEW1 |
| 18 | # include "mozilla/Attributes.h" // MOZ_STACK_CLASS |
| 19 | #endif |
| 20 | #include "mozilla/MacroForEach.h" |
| 21 | #ifdef JS_JITSPEW1 |
| 22 | # include "mozilla/Sprintf.h" |
| 23 | # include "mozilla/Vector.h" |
| 24 | #endif |
| 25 | |
| 26 | #include <algorithm> |
| 27 | #include <initializer_list> |
| 28 | |
| 29 | #include "NamespaceImports.h" |
| 30 | |
| 31 | #include "jit/AtomicOp.h" |
| 32 | #include "jit/FixedList.h" |
| 33 | #include "jit/InlineList.h" |
| 34 | #include "jit/JitAllocPolicy.h" |
| 35 | #include "jit/MacroAssembler.h" |
| 36 | #include "jit/MIROpsGenerated.h" |
| 37 | #include "jit/ShuffleAnalysis.h" |
| 38 | #include "jit/TypeData.h" |
| 39 | #include "jit/TypePolicy.h" |
| 40 | #include "js/experimental/JitInfo.h" // JSJit{Getter,Setter}Op, JSJitInfo |
| 41 | #include "js/HeapAPI.h" |
| 42 | #include "js/ScalarType.h" // js::Scalar::Type |
| 43 | #include "js/Value.h" |
| 44 | #include "js/Vector.h" |
| 45 | #include "util/DifferentialTesting.h" |
| 46 | #include "vm/BigIntType.h" |
| 47 | #include "vm/EnvironmentObject.h" |
| 48 | #include "vm/FunctionFlags.h" // js::FunctionFlags |
| 49 | #include "vm/JSContext.h" |
| 50 | #include "vm/RegExpObject.h" |
| 51 | #include "vm/TypedArrayObject.h" |
| 52 | #include "wasm/WasmJS.h" // for WasmInstanceObject |
| 53 | |
| 54 | namespace JS { |
| 55 | struct ExpandoAndGeneration; |
| 56 | } |
| 57 | |
| 58 | namespace js { |
| 59 | |
| 60 | namespace wasm { |
| 61 | class FuncExport; |
| 62 | extern uint32_t MIRTypeToABIResultSize(jit::MIRType); |
| 63 | } // namespace wasm |
| 64 | |
| 65 | class JS_PUBLIC_API GenericPrinter; |
| 66 | class NativeIteratorListHead; |
| 67 | class StringObject; |
| 68 | |
| 69 | enum class UnaryMathFunction : uint8_t; |
| 70 | |
| 71 | bool CurrentThreadIsIonCompiling(); |
| 72 | |
| 73 | namespace jit { |
| 74 | |
| 75 | class CallInfo; |
| 76 | |
| 77 | #ifdef JS_JITSPEW1 |
| 78 | // Helper for debug printing. Avoids creating a MIR.h <--> MIRGraph.h cycle. |
| 79 | // Implementation of this needs to see inside `MBasicBlock`; that is possible |
| 80 | // in MIR.cpp since it also includes MIRGraph.h, whereas this file does not. |
| 81 | class MBasicBlock; |
| 82 | uint32_t GetMBasicBlockId(const MBasicBlock* block); |
| 83 | |
| 84 | // Helper class for debug printing. This class allows `::getExtras` methods |
| 85 | // to add strings to be printed, on a per-MIR-node basis. The strings are |
| 86 | // copied into storage owned by this class when `::add` is called, so the |
| 87 | // `::getExtras` methods do not need to be concerned about storage management. |
| 88 | class MOZ_STACK_CLASS ExtrasCollector { |
| 89 | mozilla::Vector<UniqueChars, 4> strings_; |
| 90 | |
| 91 | public: |
| 92 | // Add `str` to the collection. A copy, owned by this object, is made. In |
| 93 | // case of OOM the call has no effect. |
| 94 | void add(const char* str) { |
| 95 | UniqueChars dup = DuplicateString(str); |
| 96 | if (dup) { |
| 97 | (void)strings_.append(std::move(dup)); |
| 98 | } |
| 99 | } |
| 100 | size_t count() const { return strings_.length(); } |
| 101 | UniqueChars get(size_t ix) { return std::move(strings_[ix]); } |
| 102 | }; |
| 103 | #endif |
| 104 | |
| 105 | // Forward declarations of MIR types. |
| 106 | #define FORWARD_DECLARE(op) class M##op; |
| 107 | MIR_OPCODE_LIST(FORWARD_DECLARE)FORWARD_DECLARE(Start)FORWARD_DECLARE(OsrEntry)FORWARD_DECLARE (Nop)FORWARD_DECLARE(LimitedTruncate)FORWARD_DECLARE(Constant )FORWARD_DECLARE(WasmNullConstant)FORWARD_DECLARE(WasmFloatConstant )FORWARD_DECLARE(Parameter)FORWARD_DECLARE(Callee)FORWARD_DECLARE (IsConstructing)FORWARD_DECLARE(TableSwitch)FORWARD_DECLARE(Goto )FORWARD_DECLARE(Test)FORWARD_DECLARE(Return)FORWARD_DECLARE( Throw)FORWARD_DECLARE(ThrowWithStack)FORWARD_DECLARE(NewArray )FORWARD_DECLARE(NewArrayDynamicLength)FORWARD_DECLARE(NewTypedArray )FORWARD_DECLARE(NewTypedArrayDynamicLength)FORWARD_DECLARE(NewTypedArrayFromArray )FORWARD_DECLARE(NewTypedArrayFromArrayBuffer)FORWARD_DECLARE (NewObject)FORWARD_DECLARE(NewPlainObject)FORWARD_DECLARE(NewArrayObject )FORWARD_DECLARE(NewIterator)FORWARD_DECLARE(ObjectState)FORWARD_DECLARE (ArrayState)FORWARD_DECLARE(BindFunction)FORWARD_DECLARE(NewBoundFunction )FORWARD_DECLARE(BoundFunctionNumArgs)FORWARD_DECLARE(GuardBoundFunctionIsConstructor )FORWARD_DECLARE(MutateProto)FORWARD_DECLARE(InitPropGetterSetter )FORWARD_DECLARE(InitElemGetterSetter)FORWARD_DECLARE(Call)FORWARD_DECLARE (CallClassHook)FORWARD_DECLARE(ApplyArgs)FORWARD_DECLARE(ApplyArgsObj )FORWARD_DECLARE(ApplyArray)FORWARD_DECLARE(ConstructArgs)FORWARD_DECLARE (ConstructArray)FORWARD_DECLARE(Bail)FORWARD_DECLARE(Unreachable )FORWARD_DECLARE(EncodeSnapshot)FORWARD_DECLARE(AssertRecoveredOnBailout )FORWARD_DECLARE(AssertFloat32)FORWARD_DECLARE(Compare)FORWARD_DECLARE (SameValueDouble)FORWARD_DECLARE(SameValue)FORWARD_DECLARE(Box )FORWARD_DECLARE(Unbox)FORWARD_DECLARE(AssertRange)FORWARD_DECLARE (AssertClass)FORWARD_DECLARE(AssertShape)FORWARD_DECLARE(CreateThis )FORWARD_DECLARE(CreateArgumentsObject)FORWARD_DECLARE(CreateInlinedArgumentsObject )FORWARD_DECLARE(GetInlinedArgument)FORWARD_DECLARE(GetInlinedArgumentHole )FORWARD_DECLARE(GetArgumentsObjectArg)FORWARD_DECLARE(SetArgumentsObjectArg )FORWARD_DECLARE(LoadArgumentsObjectArg)FORWARD_DECLARE(LoadArgumentsObjectArgHole )FORWARD_DECLARE(InArgumentsObjectArg)FORWARD_DECLARE(ArgumentsObjectLength )FORWARD_DECLARE(ArrayFromArgumentsObject)FORWARD_DECLARE(GuardArgumentsObjectFlags )FORWARD_DECLARE(LoadScriptedProxyHandler)FORWARD_DECLARE(CheckScriptedProxyGetResult )FORWARD_DECLARE(IdToStringOrSymbol)FORWARD_DECLARE(ReturnFromCtor )FORWARD_DECLARE(ToDouble)FORWARD_DECLARE(ToFloat32)FORWARD_DECLARE (WasmUnsignedToDouble)FORWARD_DECLARE(WasmUnsignedToFloat32)FORWARD_DECLARE (WrapInt64ToInt32)FORWARD_DECLARE(ExtendInt32ToInt64)FORWARD_DECLARE (WasmBuiltinTruncateToInt64)FORWARD_DECLARE(WasmTruncateToInt64 )FORWARD_DECLARE(WasmTruncateToInt32)FORWARD_DECLARE(WasmAnyRefFromJSValue )FORWARD_DECLARE(WasmAnyRefFromJSObject)FORWARD_DECLARE(WasmAnyRefFromJSString )FORWARD_DECLARE(WasmNewI31Ref)FORWARD_DECLARE(WasmI31RefGet) FORWARD_DECLARE(Int32ToIntPtr)FORWARD_DECLARE(NonNegativeIntPtrToInt32 )FORWARD_DECLARE(IntPtrToDouble)FORWARD_DECLARE(AdjustDataViewLength )FORWARD_DECLARE(Int64ToFloatingPoint)FORWARD_DECLARE(BuiltinInt64ToFloatingPoint )FORWARD_DECLARE(ToNumberInt32)FORWARD_DECLARE(BooleanToInt32 )FORWARD_DECLARE(TruncateToInt32)FORWARD_DECLARE(WasmBuiltinTruncateToInt32 )FORWARD_DECLARE(ToBigInt)FORWARD_DECLARE(ToInt64)FORWARD_DECLARE (TruncateBigIntToInt64)FORWARD_DECLARE(Int64ToBigInt)FORWARD_DECLARE (ToString)FORWARD_DECLARE(BitNot)FORWARD_DECLARE(TypeOf)FORWARD_DECLARE (TypeOfName)FORWARD_DECLARE(TypeOfIs)FORWARD_DECLARE(ToAsyncIter )FORWARD_DECLARE(ToPropertyKeyCache)FORWARD_DECLARE(BitAnd)FORWARD_DECLARE (BitOr)FORWARD_DECLARE(BitXor)FORWARD_DECLARE(Lsh)FORWARD_DECLARE (Rsh)FORWARD_DECLARE(Ursh)FORWARD_DECLARE(SignExtendInt32)FORWARD_DECLARE (SignExtendInt64)FORWARD_DECLARE(MinMax)FORWARD_DECLARE(MinMaxArray )FORWARD_DECLARE(Abs)FORWARD_DECLARE(Clz)FORWARD_DECLARE(Ctz) FORWARD_DECLARE(Popcnt)FORWARD_DECLARE(Sqrt)FORWARD_DECLARE(CopySign )FORWARD_DECLARE(Atan2)FORWARD_DECLARE(Hypot)FORWARD_DECLARE( Pow)FORWARD_DECLARE(PowHalf)FORWARD_DECLARE(Random)FORWARD_DECLARE (Sign)FORWARD_DECLARE(MathFunction)FORWARD_DECLARE(Add)FORWARD_DECLARE (Sub)FORWARD_DECLARE(Mul)FORWARD_DECLARE(Div)FORWARD_DECLARE( WasmBuiltinDivI64)FORWARD_DECLARE(Mod)FORWARD_DECLARE(WasmBuiltinModD )FORWARD_DECLARE(WasmBuiltinModI64)FORWARD_DECLARE(BigIntAdd) FORWARD_DECLARE(BigIntSub)FORWARD_DECLARE(BigIntMul)FORWARD_DECLARE (BigIntDiv)FORWARD_DECLARE(BigIntMod)FORWARD_DECLARE(BigIntPow )FORWARD_DECLARE(BigIntBitAnd)FORWARD_DECLARE(BigIntBitOr)FORWARD_DECLARE (BigIntBitXor)FORWARD_DECLARE(BigIntLsh)FORWARD_DECLARE(BigIntRsh )FORWARD_DECLARE(BigIntIncrement)FORWARD_DECLARE(BigIntDecrement )FORWARD_DECLARE(BigIntNegate)FORWARD_DECLARE(BigIntBitNot)FORWARD_DECLARE (Int32ToStringWithBase)FORWARD_DECLARE(NumberParseInt)FORWARD_DECLARE (DoubleParseInt)FORWARD_DECLARE(Concat)FORWARD_DECLARE(LinearizeString )FORWARD_DECLARE(LinearizeForCharAccess)FORWARD_DECLARE(LinearizeForCodePointAccess )FORWARD_DECLARE(ToRelativeStringIndex)FORWARD_DECLARE(CharCodeAt )FORWARD_DECLARE(CharCodeAtOrNegative)FORWARD_DECLARE(CodePointAt )FORWARD_DECLARE(CodePointAtOrNegative)FORWARD_DECLARE(NegativeToNaN )FORWARD_DECLARE(NegativeToUndefined)FORWARD_DECLARE(FromCharCode )FORWARD_DECLARE(FromCharCodeEmptyIfNegative)FORWARD_DECLARE( FromCharCodeUndefinedIfNegative)FORWARD_DECLARE(FromCodePoint )FORWARD_DECLARE(StringIncludes)FORWARD_DECLARE(StringIndexOf )FORWARD_DECLARE(StringLastIndexOf)FORWARD_DECLARE(StringStartsWith )FORWARD_DECLARE(StringEndsWith)FORWARD_DECLARE(StringConvertCase )FORWARD_DECLARE(CharCodeConvertCase)FORWARD_DECLARE(StringTrimStartIndex )FORWARD_DECLARE(StringTrimEndIndex)FORWARD_DECLARE(StringSplit )FORWARD_DECLARE(BoxNonStrictThis)FORWARD_DECLARE(ImplicitThis )FORWARD_DECLARE(Phi)FORWARD_DECLARE(Beta)FORWARD_DECLARE(NaNToZero )FORWARD_DECLARE(OsrValue)FORWARD_DECLARE(OsrEnvironmentChain )FORWARD_DECLARE(OsrArgumentsObject)FORWARD_DECLARE(OsrReturnValue )FORWARD_DECLARE(BinaryCache)FORWARD_DECLARE(UnaryCache)FORWARD_DECLARE (CheckOverRecursed)FORWARD_DECLARE(InterruptCheck)FORWARD_DECLARE (WasmInterruptCheck)FORWARD_DECLARE(WasmTrap)FORWARD_DECLARE( WasmTrapIfNull)FORWARD_DECLARE(LexicalCheck)FORWARD_DECLARE(ThrowRuntimeLexicalError )FORWARD_DECLARE(ThrowMsg)FORWARD_DECLARE(GlobalDeclInstantiation )FORWARD_DECLARE(RegExp)FORWARD_DECLARE(RegExpMatcher)FORWARD_DECLARE (RegExpSearcher)FORWARD_DECLARE(RegExpSearcherLastLimit)FORWARD_DECLARE (RegExpExecMatch)FORWARD_DECLARE(RegExpExecTest)FORWARD_DECLARE (RegExpHasCaptureGroups)FORWARD_DECLARE(RegExpPrototypeOptimizable )FORWARD_DECLARE(RegExpInstanceOptimizable)FORWARD_DECLARE(GetFirstDollarIndex )FORWARD_DECLARE(StringReplace)FORWARD_DECLARE(Substr)FORWARD_DECLARE (ModuleMetadata)FORWARD_DECLARE(DynamicImport)FORWARD_DECLARE (Lambda)FORWARD_DECLARE(FunctionWithProto)FORWARD_DECLARE(SetFunName )FORWARD_DECLARE(Slots)FORWARD_DECLARE(Elements)FORWARD_DECLARE (InitializedLength)FORWARD_DECLARE(SetInitializedLength)FORWARD_DECLARE (ArrayLength)FORWARD_DECLARE(SetArrayLength)FORWARD_DECLARE(FunctionLength )FORWARD_DECLARE(FunctionName)FORWARD_DECLARE(GetNextEntryForIterator )FORWARD_DECLARE(ArrayBufferByteLength)FORWARD_DECLARE(ArrayBufferViewLength )FORWARD_DECLARE(ArrayBufferViewByteOffset)FORWARD_DECLARE(ArrayBufferViewElements )FORWARD_DECLARE(ResizableTypedArrayByteOffsetMaybeOutOfBounds )FORWARD_DECLARE(ResizableTypedArrayLength)FORWARD_DECLARE(ResizableDataViewByteLength )FORWARD_DECLARE(GrowableSharedArrayBufferByteLength)FORWARD_DECLARE (TypedArrayElementSize)FORWARD_DECLARE(GuardHasAttachedArrayBuffer )FORWARD_DECLARE(GuardResizableArrayBufferViewInBounds)FORWARD_DECLARE (GuardResizableArrayBufferViewInBoundsOrDetached)FORWARD_DECLARE (GuardNumberToIntPtrIndex)FORWARD_DECLARE(KeepAliveObject)FORWARD_DECLARE (DebugEnterGCUnsafeRegion)FORWARD_DECLARE(DebugLeaveGCUnsafeRegion )FORWARD_DECLARE(Not)FORWARD_DECLARE(BoundsCheck)FORWARD_DECLARE (BoundsCheckLower)FORWARD_DECLARE(SpectreMaskIndex)FORWARD_DECLARE (LoadElement)FORWARD_DECLARE(LoadElementAndUnbox)FORWARD_DECLARE (LoadElementHole)FORWARD_DECLARE(StoreElement)FORWARD_DECLARE (StoreHoleValueElement)FORWARD_DECLARE(StoreElementHole)FORWARD_DECLARE (ArrayPopShift)FORWARD_DECLARE(ArrayPush)FORWARD_DECLARE(ArraySlice )FORWARD_DECLARE(ArgumentsSlice)FORWARD_DECLARE(FrameArgumentsSlice )FORWARD_DECLARE(InlineArgumentsSlice)FORWARD_DECLARE(NormalizeSliceTerm )FORWARD_DECLARE(ArrayJoin)FORWARD_DECLARE(ObjectKeys)FORWARD_DECLARE (ObjectKeysLength)FORWARD_DECLARE(LoadUnboxedScalar)FORWARD_DECLARE (LoadDataViewElement)FORWARD_DECLARE(LoadTypedArrayElementHole )FORWARD_DECLARE(StoreUnboxedScalar)FORWARD_DECLARE(StoreDataViewElement )FORWARD_DECLARE(StoreTypedArrayElementHole)FORWARD_DECLARE(EffectiveAddress )FORWARD_DECLARE(ClampToUint8)FORWARD_DECLARE(LoadFixedSlot)FORWARD_DECLARE (LoadFixedSlotAndUnbox)FORWARD_DECLARE(LoadDynamicSlotAndUnbox )FORWARD_DECLARE(StoreFixedSlot)FORWARD_DECLARE(GetPropertyCache )FORWARD_DECLARE(HomeObjectSuperBase)FORWARD_DECLARE(GetPropSuperCache )FORWARD_DECLARE(BindNameCache)FORWARD_DECLARE(CallBindVar)FORWARD_DECLARE (GuardShape)FORWARD_DECLARE(GuardFuse)FORWARD_DECLARE(GuardMultipleShapes )FORWARD_DECLARE(GuardProto)FORWARD_DECLARE(GuardNullProto)FORWARD_DECLARE (GuardIsNativeObject)FORWARD_DECLARE(GuardGlobalGeneration)FORWARD_DECLARE (GuardIsProxy)FORWARD_DECLARE(GuardIsNotDOMProxy)FORWARD_DECLARE (GuardIsNotProxy)FORWARD_DECLARE(ProxyGet)FORWARD_DECLARE(ProxyGetByValue )FORWARD_DECLARE(ProxyHasProp)FORWARD_DECLARE(ProxySet)FORWARD_DECLARE (ProxySetByValue)FORWARD_DECLARE(CallSetArrayLength)FORWARD_DECLARE (MegamorphicLoadSlot)FORWARD_DECLARE(MegamorphicLoadSlotByValue )FORWARD_DECLARE(MegamorphicStoreSlot)FORWARD_DECLARE(MegamorphicHasProp )FORWARD_DECLARE(SmallObjectVariableKeyHasProp)FORWARD_DECLARE (GuardIsNotArrayBufferMaybeShared)FORWARD_DECLARE(GuardIsTypedArray )FORWARD_DECLARE(GuardIsFixedLengthTypedArray)FORWARD_DECLARE (GuardIsResizableTypedArray)FORWARD_DECLARE(GuardHasProxyHandler )FORWARD_DECLARE(NurseryObject)FORWARD_DECLARE(GuardValue)FORWARD_DECLARE (GuardNullOrUndefined)FORWARD_DECLARE(GuardIsNotObject)FORWARD_DECLARE (GuardFunctionFlags)FORWARD_DECLARE(GuardFunctionIsNonBuiltinCtor )FORWARD_DECLARE(GuardFunctionKind)FORWARD_DECLARE(GuardFunctionScript )FORWARD_DECLARE(GuardObjectIdentity)FORWARD_DECLARE(GuardSpecificFunction )FORWARD_DECLARE(GuardSpecificAtom)FORWARD_DECLARE(GuardSpecificSymbol )FORWARD_DECLARE(GuardSpecificInt32)FORWARD_DECLARE(GuardStringToIndex )FORWARD_DECLARE(GuardStringToInt32)FORWARD_DECLARE(GuardStringToDouble )FORWARD_DECLARE(GuardNoDenseElements)FORWARD_DECLARE(GuardTagNotEqual )FORWARD_DECLARE(LoadDynamicSlot)FORWARD_DECLARE(FunctionEnvironment )FORWARD_DECLARE(NewLexicalEnvironmentObject)FORWARD_DECLARE( NewClassBodyEnvironmentObject)FORWARD_DECLARE(NewVarEnvironmentObject )FORWARD_DECLARE(HomeObject)FORWARD_DECLARE(AddAndStoreSlot)FORWARD_DECLARE (AllocateAndStoreSlot)FORWARD_DECLARE(AddSlotAndCallAddPropHook )FORWARD_DECLARE(StoreDynamicSlot)FORWARD_DECLARE(GetNameCache )FORWARD_DECLARE(CallGetIntrinsicValue)FORWARD_DECLARE(DeleteProperty )FORWARD_DECLARE(DeleteElement)FORWARD_DECLARE(SetPropertyCache )FORWARD_DECLARE(MegamorphicSetElement)FORWARD_DECLARE(SetDOMProperty )FORWARD_DECLARE(GetDOMProperty)FORWARD_DECLARE(GetDOMMember) FORWARD_DECLARE(ObjectToIterator)FORWARD_DECLARE(ValueToIterator )FORWARD_DECLARE(IteratorHasIndices)FORWARD_DECLARE(LoadSlotByIteratorIndex )FORWARD_DECLARE(StoreSlotByIteratorIndex)FORWARD_DECLARE(LoadDOMExpandoValue )FORWARD_DECLARE(LoadDOMExpandoValueGuardGeneration)FORWARD_DECLARE (LoadDOMExpandoValueIgnoreGeneration)FORWARD_DECLARE(GuardDOMExpandoMissingOrGuardShape )FORWARD_DECLARE(StringLength)FORWARD_DECLARE(Floor)FORWARD_DECLARE (Ceil)FORWARD_DECLARE(Round)FORWARD_DECLARE(Trunc)FORWARD_DECLARE (NearbyInt)FORWARD_DECLARE(GetIteratorCache)FORWARD_DECLARE(OptimizeSpreadCallCache )FORWARD_DECLARE(IteratorMore)FORWARD_DECLARE(IsNoIter)FORWARD_DECLARE (IteratorEnd)FORWARD_DECLARE(CloseIterCache)FORWARD_DECLARE(OptimizeGetIteratorCache )FORWARD_DECLARE(InCache)FORWARD_DECLARE(InArray)FORWARD_DECLARE (GuardElementNotHole)FORWARD_DECLARE(NewPrivateName)FORWARD_DECLARE (CheckPrivateFieldCache)FORWARD_DECLARE(HasOwnCache)FORWARD_DECLARE (InstanceOf)FORWARD_DECLARE(InstanceOfCache)FORWARD_DECLARE(ArgumentsLength )FORWARD_DECLARE(GetFrameArgument)FORWARD_DECLARE(GetFrameArgumentHole )FORWARD_DECLARE(NewTarget)FORWARD_DECLARE(Rest)FORWARD_DECLARE (PostWriteBarrier)FORWARD_DECLARE(PostWriteElementBarrier)FORWARD_DECLARE (AssertCanElidePostWriteBarrier)FORWARD_DECLARE(NewNamedLambdaObject )FORWARD_DECLARE(NewCallObject)FORWARD_DECLARE(NewStringObject )FORWARD_DECLARE(IsCallable)FORWARD_DECLARE(IsConstructor)FORWARD_DECLARE (IsCrossRealmArrayConstructor)FORWARD_DECLARE(IsObject)FORWARD_DECLARE (IsNullOrUndefined)FORWARD_DECLARE(HasClass)FORWARD_DECLARE(GuardToClass )FORWARD_DECLARE(GuardToEitherClass)FORWARD_DECLARE(GuardToFunction )FORWARD_DECLARE(IsArray)FORWARD_DECLARE(IsTypedArray)FORWARD_DECLARE (ObjectClassToString)FORWARD_DECLARE(CheckReturn)FORWARD_DECLARE (CheckThis)FORWARD_DECLARE(AsyncResolve)FORWARD_DECLARE(AsyncReject )FORWARD_DECLARE(GeneratorReturn)FORWARD_DECLARE(AsyncAwait)FORWARD_DECLARE (CheckThisReinit)FORWARD_DECLARE(Generator)FORWARD_DECLARE(CanSkipAwait )FORWARD_DECLARE(MaybeExtractAwaitValue)FORWARD_DECLARE(IncrementWarmUpCounter )FORWARD_DECLARE(AtomicIsLockFree)FORWARD_DECLARE(CompareExchangeTypedArrayElement )FORWARD_DECLARE(AtomicExchangeTypedArrayElement)FORWARD_DECLARE (AtomicTypedArrayElementBinop)FORWARD_DECLARE(Debugger)FORWARD_DECLARE (CheckIsObj)FORWARD_DECLARE(CheckObjCoercible)FORWARD_DECLARE (CheckClassHeritage)FORWARD_DECLARE(DebugCheckSelfHosted)FORWARD_DECLARE (IsPackedArray)FORWARD_DECLARE(GuardArrayIsPacked)FORWARD_DECLARE (GetPrototypeOf)FORWARD_DECLARE(ObjectWithProto)FORWARD_DECLARE (ObjectStaticProto)FORWARD_DECLARE(ConstantProto)FORWARD_DECLARE (BuiltinObject)FORWARD_DECLARE(SuperFunction)FORWARD_DECLARE( InitHomeObject)FORWARD_DECLARE(IsTypedArrayConstructor)FORWARD_DECLARE (LoadValueTag)FORWARD_DECLARE(LoadWrapperTarget)FORWARD_DECLARE (GuardHasGetterSetter)FORWARD_DECLARE(GuardIsExtensible)FORWARD_DECLARE (GuardInt32IsNonNegative)FORWARD_DECLARE(GuardInt32Range)FORWARD_DECLARE (GuardIndexIsNotDenseElement)FORWARD_DECLARE(GuardIndexIsValidUpdateOrAdd )FORWARD_DECLARE(CallAddOrUpdateSparseElement)FORWARD_DECLARE (CallGetSparseElement)FORWARD_DECLARE(CallNativeGetElement)FORWARD_DECLARE (CallNativeGetElementSuper)FORWARD_DECLARE(CallObjectHasSparseElement )FORWARD_DECLARE(BigIntAsIntN)FORWARD_DECLARE(BigIntAsUintN)FORWARD_DECLARE (GuardNonGCThing)FORWARD_DECLARE(ToHashableNonGCThing)FORWARD_DECLARE (ToHashableString)FORWARD_DECLARE(ToHashableValue)FORWARD_DECLARE (HashNonGCThing)FORWARD_DECLARE(HashString)FORWARD_DECLARE(HashSymbol )FORWARD_DECLARE(HashBigInt)FORWARD_DECLARE(HashObject)FORWARD_DECLARE (HashValue)FORWARD_DECLARE(SetObjectHasNonBigInt)FORWARD_DECLARE (SetObjectHasBigInt)FORWARD_DECLARE(SetObjectHasValue)FORWARD_DECLARE (SetObjectHasValueVMCall)FORWARD_DECLARE(SetObjectSize)FORWARD_DECLARE (MapObjectHasNonBigInt)FORWARD_DECLARE(MapObjectHasBigInt)FORWARD_DECLARE (MapObjectHasValue)FORWARD_DECLARE(MapObjectHasValueVMCall)FORWARD_DECLARE (MapObjectGetNonBigInt)FORWARD_DECLARE(MapObjectGetBigInt)FORWARD_DECLARE (MapObjectGetValue)FORWARD_DECLARE(MapObjectGetValueVMCall)FORWARD_DECLARE (MapObjectSize)FORWARD_DECLARE(PostIntPtrConversion)FORWARD_DECLARE (WasmNeg)FORWARD_DECLARE(WasmBinaryBitwise)FORWARD_DECLARE(WasmLoadInstance )FORWARD_DECLARE(WasmStoreInstance)FORWARD_DECLARE(WasmHeapReg )FORWARD_DECLARE(WasmBoundsCheck)FORWARD_DECLARE(WasmBoundsCheckRange32 )FORWARD_DECLARE(WasmExtendU32Index)FORWARD_DECLARE(WasmWrapU32Index )FORWARD_DECLARE(WasmAddOffset)FORWARD_DECLARE(WasmAlignmentCheck )FORWARD_DECLARE(WasmLoad)FORWARD_DECLARE(WasmStore)FORWARD_DECLARE (AsmJSLoadHeap)FORWARD_DECLARE(AsmJSStoreHeap)FORWARD_DECLARE (WasmFence)FORWARD_DECLARE(WasmCompareExchangeHeap)FORWARD_DECLARE (WasmAtomicExchangeHeap)FORWARD_DECLARE(WasmAtomicBinopHeap)FORWARD_DECLARE (WasmLoadInstanceDataField)FORWARD_DECLARE(WasmLoadGlobalCell )FORWARD_DECLARE(WasmLoadTableElement)FORWARD_DECLARE(WasmStoreInstanceDataField )FORWARD_DECLARE(WasmStoreGlobalCell)FORWARD_DECLARE(WasmStoreStackResult )FORWARD_DECLARE(WasmDerivedPointer)FORWARD_DECLARE(WasmDerivedIndexPointer )FORWARD_DECLARE(WasmStoreRef)FORWARD_DECLARE(WasmPostWriteBarrierImmediate )FORWARD_DECLARE(WasmPostWriteBarrierIndex)FORWARD_DECLARE(WasmParameter )FORWARD_DECLARE(WasmReturn)FORWARD_DECLARE(WasmReturnVoid)FORWARD_DECLARE (WasmStackArg)FORWARD_DECLARE(WasmRegisterResult)FORWARD_DECLARE (WasmFloatRegisterResult)FORWARD_DECLARE(WasmRegister64Result )FORWARD_DECLARE(WasmStackResultArea)FORWARD_DECLARE(WasmStackResult )FORWARD_DECLARE(WasmCallCatchable)FORWARD_DECLARE(WasmCallUncatchable )FORWARD_DECLARE(WasmCallLandingPrePad)FORWARD_DECLARE(WasmReturnCall )FORWARD_DECLARE(WasmSelect)FORWARD_DECLARE(WasmReinterpret)FORWARD_DECLARE (Rotate)FORWARD_DECLARE(WasmStackSwitchToMain)FORWARD_DECLARE (WasmStackSwitchToSuspendable)FORWARD_DECLARE(WasmStackContinueOnSuspendable )FORWARD_DECLARE(WasmBinarySimd128)FORWARD_DECLARE(WasmBinarySimd128WithConstant )FORWARD_DECLARE(WasmShiftSimd128)FORWARD_DECLARE(WasmShuffleSimd128 )FORWARD_DECLARE(WasmReplaceLaneSimd128)FORWARD_DECLARE(WasmUnarySimd128 )FORWARD_DECLARE(WasmTernarySimd128)FORWARD_DECLARE(WasmScalarToSimd128 )FORWARD_DECLARE(WasmReduceSimd128)FORWARD_DECLARE(WasmLoadLaneSimd128 )FORWARD_DECLARE(WasmStoreLaneSimd128)FORWARD_DECLARE(UnreachableResult )FORWARD_DECLARE(IonToWasmCall)FORWARD_DECLARE(WasmLoadField) FORWARD_DECLARE(WasmLoadFieldKA)FORWARD_DECLARE(WasmLoadElementKA )FORWARD_DECLARE(WasmStoreFieldKA)FORWARD_DECLARE(WasmStoreFieldRefKA )FORWARD_DECLARE(WasmStoreElementKA)FORWARD_DECLARE(WasmStoreElementRefKA )FORWARD_DECLARE(WasmRefIsSubtypeOfConcrete)FORWARD_DECLARE(WasmRefIsSubtypeOfAbstract )FORWARD_DECLARE(WasmNewStructObject)FORWARD_DECLARE(WasmNewArrayObject ) |
| 108 | #undef FORWARD_DECLARE |
| 109 | |
| 110 | // MDefinition visitor which ignores non-overloaded visit functions. |
| 111 | class MDefinitionVisitorDefaultNoop { |
| 112 | public: |
| 113 | #define VISIT_INS(op) \ |
| 114 | void visit##op(M##op*) {} |
| 115 | MIR_OPCODE_LIST(VISIT_INS)VISIT_INS(Start)VISIT_INS(OsrEntry)VISIT_INS(Nop)VISIT_INS(LimitedTruncate )VISIT_INS(Constant)VISIT_INS(WasmNullConstant)VISIT_INS(WasmFloatConstant )VISIT_INS(Parameter)VISIT_INS(Callee)VISIT_INS(IsConstructing )VISIT_INS(TableSwitch)VISIT_INS(Goto)VISIT_INS(Test)VISIT_INS (Return)VISIT_INS(Throw)VISIT_INS(ThrowWithStack)VISIT_INS(NewArray )VISIT_INS(NewArrayDynamicLength)VISIT_INS(NewTypedArray)VISIT_INS (NewTypedArrayDynamicLength)VISIT_INS(NewTypedArrayFromArray) VISIT_INS(NewTypedArrayFromArrayBuffer)VISIT_INS(NewObject)VISIT_INS (NewPlainObject)VISIT_INS(NewArrayObject)VISIT_INS(NewIterator )VISIT_INS(ObjectState)VISIT_INS(ArrayState)VISIT_INS(BindFunction )VISIT_INS(NewBoundFunction)VISIT_INS(BoundFunctionNumArgs)VISIT_INS (GuardBoundFunctionIsConstructor)VISIT_INS(MutateProto)VISIT_INS (InitPropGetterSetter)VISIT_INS(InitElemGetterSetter)VISIT_INS (Call)VISIT_INS(CallClassHook)VISIT_INS(ApplyArgs)VISIT_INS(ApplyArgsObj )VISIT_INS(ApplyArray)VISIT_INS(ConstructArgs)VISIT_INS(ConstructArray )VISIT_INS(Bail)VISIT_INS(Unreachable)VISIT_INS(EncodeSnapshot )VISIT_INS(AssertRecoveredOnBailout)VISIT_INS(AssertFloat32)VISIT_INS (Compare)VISIT_INS(SameValueDouble)VISIT_INS(SameValue)VISIT_INS (Box)VISIT_INS(Unbox)VISIT_INS(AssertRange)VISIT_INS(AssertClass )VISIT_INS(AssertShape)VISIT_INS(CreateThis)VISIT_INS(CreateArgumentsObject )VISIT_INS(CreateInlinedArgumentsObject)VISIT_INS(GetInlinedArgument )VISIT_INS(GetInlinedArgumentHole)VISIT_INS(GetArgumentsObjectArg )VISIT_INS(SetArgumentsObjectArg)VISIT_INS(LoadArgumentsObjectArg )VISIT_INS(LoadArgumentsObjectArgHole)VISIT_INS(InArgumentsObjectArg )VISIT_INS(ArgumentsObjectLength)VISIT_INS(ArrayFromArgumentsObject )VISIT_INS(GuardArgumentsObjectFlags)VISIT_INS(LoadScriptedProxyHandler )VISIT_INS(CheckScriptedProxyGetResult)VISIT_INS(IdToStringOrSymbol )VISIT_INS(ReturnFromCtor)VISIT_INS(ToDouble)VISIT_INS(ToFloat32 )VISIT_INS(WasmUnsignedToDouble)VISIT_INS(WasmUnsignedToFloat32 )VISIT_INS(WrapInt64ToInt32)VISIT_INS(ExtendInt32ToInt64)VISIT_INS (WasmBuiltinTruncateToInt64)VISIT_INS(WasmTruncateToInt64)VISIT_INS (WasmTruncateToInt32)VISIT_INS(WasmAnyRefFromJSValue)VISIT_INS (WasmAnyRefFromJSObject)VISIT_INS(WasmAnyRefFromJSString)VISIT_INS (WasmNewI31Ref)VISIT_INS(WasmI31RefGet)VISIT_INS(Int32ToIntPtr )VISIT_INS(NonNegativeIntPtrToInt32)VISIT_INS(IntPtrToDouble) VISIT_INS(AdjustDataViewLength)VISIT_INS(Int64ToFloatingPoint )VISIT_INS(BuiltinInt64ToFloatingPoint)VISIT_INS(ToNumberInt32 )VISIT_INS(BooleanToInt32)VISIT_INS(TruncateToInt32)VISIT_INS (WasmBuiltinTruncateToInt32)VISIT_INS(ToBigInt)VISIT_INS(ToInt64 )VISIT_INS(TruncateBigIntToInt64)VISIT_INS(Int64ToBigInt)VISIT_INS (ToString)VISIT_INS(BitNot)VISIT_INS(TypeOf)VISIT_INS(TypeOfName )VISIT_INS(TypeOfIs)VISIT_INS(ToAsyncIter)VISIT_INS(ToPropertyKeyCache )VISIT_INS(BitAnd)VISIT_INS(BitOr)VISIT_INS(BitXor)VISIT_INS( Lsh)VISIT_INS(Rsh)VISIT_INS(Ursh)VISIT_INS(SignExtendInt32)VISIT_INS (SignExtendInt64)VISIT_INS(MinMax)VISIT_INS(MinMaxArray)VISIT_INS (Abs)VISIT_INS(Clz)VISIT_INS(Ctz)VISIT_INS(Popcnt)VISIT_INS(Sqrt )VISIT_INS(CopySign)VISIT_INS(Atan2)VISIT_INS(Hypot)VISIT_INS (Pow)VISIT_INS(PowHalf)VISIT_INS(Random)VISIT_INS(Sign)VISIT_INS (MathFunction)VISIT_INS(Add)VISIT_INS(Sub)VISIT_INS(Mul)VISIT_INS (Div)VISIT_INS(WasmBuiltinDivI64)VISIT_INS(Mod)VISIT_INS(WasmBuiltinModD )VISIT_INS(WasmBuiltinModI64)VISIT_INS(BigIntAdd)VISIT_INS(BigIntSub )VISIT_INS(BigIntMul)VISIT_INS(BigIntDiv)VISIT_INS(BigIntMod) VISIT_INS(BigIntPow)VISIT_INS(BigIntBitAnd)VISIT_INS(BigIntBitOr )VISIT_INS(BigIntBitXor)VISIT_INS(BigIntLsh)VISIT_INS(BigIntRsh )VISIT_INS(BigIntIncrement)VISIT_INS(BigIntDecrement)VISIT_INS (BigIntNegate)VISIT_INS(BigIntBitNot)VISIT_INS(Int32ToStringWithBase )VISIT_INS(NumberParseInt)VISIT_INS(DoubleParseInt)VISIT_INS( Concat)VISIT_INS(LinearizeString)VISIT_INS(LinearizeForCharAccess )VISIT_INS(LinearizeForCodePointAccess)VISIT_INS(ToRelativeStringIndex )VISIT_INS(CharCodeAt)VISIT_INS(CharCodeAtOrNegative)VISIT_INS (CodePointAt)VISIT_INS(CodePointAtOrNegative)VISIT_INS(NegativeToNaN )VISIT_INS(NegativeToUndefined)VISIT_INS(FromCharCode)VISIT_INS (FromCharCodeEmptyIfNegative)VISIT_INS(FromCharCodeUndefinedIfNegative )VISIT_INS(FromCodePoint)VISIT_INS(StringIncludes)VISIT_INS(StringIndexOf )VISIT_INS(StringLastIndexOf)VISIT_INS(StringStartsWith)VISIT_INS (StringEndsWith)VISIT_INS(StringConvertCase)VISIT_INS(CharCodeConvertCase )VISIT_INS(StringTrimStartIndex)VISIT_INS(StringTrimEndIndex) VISIT_INS(StringSplit)VISIT_INS(BoxNonStrictThis)VISIT_INS(ImplicitThis )VISIT_INS(Phi)VISIT_INS(Beta)VISIT_INS(NaNToZero)VISIT_INS(OsrValue )VISIT_INS(OsrEnvironmentChain)VISIT_INS(OsrArgumentsObject)VISIT_INS (OsrReturnValue)VISIT_INS(BinaryCache)VISIT_INS(UnaryCache)VISIT_INS (CheckOverRecursed)VISIT_INS(InterruptCheck)VISIT_INS(WasmInterruptCheck )VISIT_INS(WasmTrap)VISIT_INS(WasmTrapIfNull)VISIT_INS(LexicalCheck )VISIT_INS(ThrowRuntimeLexicalError)VISIT_INS(ThrowMsg)VISIT_INS (GlobalDeclInstantiation)VISIT_INS(RegExp)VISIT_INS(RegExpMatcher )VISIT_INS(RegExpSearcher)VISIT_INS(RegExpSearcherLastLimit)VISIT_INS (RegExpExecMatch)VISIT_INS(RegExpExecTest)VISIT_INS(RegExpHasCaptureGroups )VISIT_INS(RegExpPrototypeOptimizable)VISIT_INS(RegExpInstanceOptimizable )VISIT_INS(GetFirstDollarIndex)VISIT_INS(StringReplace)VISIT_INS (Substr)VISIT_INS(ModuleMetadata)VISIT_INS(DynamicImport)VISIT_INS (Lambda)VISIT_INS(FunctionWithProto)VISIT_INS(SetFunName)VISIT_INS (Slots)VISIT_INS(Elements)VISIT_INS(InitializedLength)VISIT_INS (SetInitializedLength)VISIT_INS(ArrayLength)VISIT_INS(SetArrayLength )VISIT_INS(FunctionLength)VISIT_INS(FunctionName)VISIT_INS(GetNextEntryForIterator )VISIT_INS(ArrayBufferByteLength)VISIT_INS(ArrayBufferViewLength )VISIT_INS(ArrayBufferViewByteOffset)VISIT_INS(ArrayBufferViewElements )VISIT_INS(ResizableTypedArrayByteOffsetMaybeOutOfBounds)VISIT_INS (ResizableTypedArrayLength)VISIT_INS(ResizableDataViewByteLength )VISIT_INS(GrowableSharedArrayBufferByteLength)VISIT_INS(TypedArrayElementSize )VISIT_INS(GuardHasAttachedArrayBuffer)VISIT_INS(GuardResizableArrayBufferViewInBounds )VISIT_INS(GuardResizableArrayBufferViewInBoundsOrDetached)VISIT_INS (GuardNumberToIntPtrIndex)VISIT_INS(KeepAliveObject)VISIT_INS (DebugEnterGCUnsafeRegion)VISIT_INS(DebugLeaveGCUnsafeRegion) VISIT_INS(Not)VISIT_INS(BoundsCheck)VISIT_INS(BoundsCheckLower )VISIT_INS(SpectreMaskIndex)VISIT_INS(LoadElement)VISIT_INS(LoadElementAndUnbox )VISIT_INS(LoadElementHole)VISIT_INS(StoreElement)VISIT_INS(StoreHoleValueElement )VISIT_INS(StoreElementHole)VISIT_INS(ArrayPopShift)VISIT_INS (ArrayPush)VISIT_INS(ArraySlice)VISIT_INS(ArgumentsSlice)VISIT_INS (FrameArgumentsSlice)VISIT_INS(InlineArgumentsSlice)VISIT_INS (NormalizeSliceTerm)VISIT_INS(ArrayJoin)VISIT_INS(ObjectKeys) VISIT_INS(ObjectKeysLength)VISIT_INS(LoadUnboxedScalar)VISIT_INS (LoadDataViewElement)VISIT_INS(LoadTypedArrayElementHole)VISIT_INS (StoreUnboxedScalar)VISIT_INS(StoreDataViewElement)VISIT_INS( StoreTypedArrayElementHole)VISIT_INS(EffectiveAddress)VISIT_INS (ClampToUint8)VISIT_INS(LoadFixedSlot)VISIT_INS(LoadFixedSlotAndUnbox )VISIT_INS(LoadDynamicSlotAndUnbox)VISIT_INS(StoreFixedSlot)VISIT_INS (GetPropertyCache)VISIT_INS(HomeObjectSuperBase)VISIT_INS(GetPropSuperCache )VISIT_INS(BindNameCache)VISIT_INS(CallBindVar)VISIT_INS(GuardShape )VISIT_INS(GuardFuse)VISIT_INS(GuardMultipleShapes)VISIT_INS( GuardProto)VISIT_INS(GuardNullProto)VISIT_INS(GuardIsNativeObject )VISIT_INS(GuardGlobalGeneration)VISIT_INS(GuardIsProxy)VISIT_INS (GuardIsNotDOMProxy)VISIT_INS(GuardIsNotProxy)VISIT_INS(ProxyGet )VISIT_INS(ProxyGetByValue)VISIT_INS(ProxyHasProp)VISIT_INS(ProxySet )VISIT_INS(ProxySetByValue)VISIT_INS(CallSetArrayLength)VISIT_INS (MegamorphicLoadSlot)VISIT_INS(MegamorphicLoadSlotByValue)VISIT_INS (MegamorphicStoreSlot)VISIT_INS(MegamorphicHasProp)VISIT_INS( SmallObjectVariableKeyHasProp)VISIT_INS(GuardIsNotArrayBufferMaybeShared )VISIT_INS(GuardIsTypedArray)VISIT_INS(GuardIsFixedLengthTypedArray )VISIT_INS(GuardIsResizableTypedArray)VISIT_INS(GuardHasProxyHandler )VISIT_INS(NurseryObject)VISIT_INS(GuardValue)VISIT_INS(GuardNullOrUndefined )VISIT_INS(GuardIsNotObject)VISIT_INS(GuardFunctionFlags)VISIT_INS (GuardFunctionIsNonBuiltinCtor)VISIT_INS(GuardFunctionKind)VISIT_INS (GuardFunctionScript)VISIT_INS(GuardObjectIdentity)VISIT_INS( GuardSpecificFunction)VISIT_INS(GuardSpecificAtom)VISIT_INS(GuardSpecificSymbol )VISIT_INS(GuardSpecificInt32)VISIT_INS(GuardStringToIndex)VISIT_INS (GuardStringToInt32)VISIT_INS(GuardStringToDouble)VISIT_INS(GuardNoDenseElements )VISIT_INS(GuardTagNotEqual)VISIT_INS(LoadDynamicSlot)VISIT_INS (FunctionEnvironment)VISIT_INS(NewLexicalEnvironmentObject)VISIT_INS (NewClassBodyEnvironmentObject)VISIT_INS(NewVarEnvironmentObject )VISIT_INS(HomeObject)VISIT_INS(AddAndStoreSlot)VISIT_INS(AllocateAndStoreSlot )VISIT_INS(AddSlotAndCallAddPropHook)VISIT_INS(StoreDynamicSlot )VISIT_INS(GetNameCache)VISIT_INS(CallGetIntrinsicValue)VISIT_INS (DeleteProperty)VISIT_INS(DeleteElement)VISIT_INS(SetPropertyCache )VISIT_INS(MegamorphicSetElement)VISIT_INS(SetDOMProperty)VISIT_INS (GetDOMProperty)VISIT_INS(GetDOMMember)VISIT_INS(ObjectToIterator )VISIT_INS(ValueToIterator)VISIT_INS(IteratorHasIndices)VISIT_INS (LoadSlotByIteratorIndex)VISIT_INS(StoreSlotByIteratorIndex)VISIT_INS (LoadDOMExpandoValue)VISIT_INS(LoadDOMExpandoValueGuardGeneration )VISIT_INS(LoadDOMExpandoValueIgnoreGeneration)VISIT_INS(GuardDOMExpandoMissingOrGuardShape )VISIT_INS(StringLength)VISIT_INS(Floor)VISIT_INS(Ceil)VISIT_INS (Round)VISIT_INS(Trunc)VISIT_INS(NearbyInt)VISIT_INS(GetIteratorCache )VISIT_INS(OptimizeSpreadCallCache)VISIT_INS(IteratorMore)VISIT_INS (IsNoIter)VISIT_INS(IteratorEnd)VISIT_INS(CloseIterCache)VISIT_INS (OptimizeGetIteratorCache)VISIT_INS(InCache)VISIT_INS(InArray )VISIT_INS(GuardElementNotHole)VISIT_INS(NewPrivateName)VISIT_INS (CheckPrivateFieldCache)VISIT_INS(HasOwnCache)VISIT_INS(InstanceOf )VISIT_INS(InstanceOfCache)VISIT_INS(ArgumentsLength)VISIT_INS (GetFrameArgument)VISIT_INS(GetFrameArgumentHole)VISIT_INS(NewTarget )VISIT_INS(Rest)VISIT_INS(PostWriteBarrier)VISIT_INS(PostWriteElementBarrier )VISIT_INS(AssertCanElidePostWriteBarrier)VISIT_INS(NewNamedLambdaObject )VISIT_INS(NewCallObject)VISIT_INS(NewStringObject)VISIT_INS( IsCallable)VISIT_INS(IsConstructor)VISIT_INS(IsCrossRealmArrayConstructor )VISIT_INS(IsObject)VISIT_INS(IsNullOrUndefined)VISIT_INS(HasClass )VISIT_INS(GuardToClass)VISIT_INS(GuardToEitherClass)VISIT_INS (GuardToFunction)VISIT_INS(IsArray)VISIT_INS(IsTypedArray)VISIT_INS (ObjectClassToString)VISIT_INS(CheckReturn)VISIT_INS(CheckThis )VISIT_INS(AsyncResolve)VISIT_INS(AsyncReject)VISIT_INS(GeneratorReturn )VISIT_INS(AsyncAwait)VISIT_INS(CheckThisReinit)VISIT_INS(Generator )VISIT_INS(CanSkipAwait)VISIT_INS(MaybeExtractAwaitValue)VISIT_INS (IncrementWarmUpCounter)VISIT_INS(AtomicIsLockFree)VISIT_INS( CompareExchangeTypedArrayElement)VISIT_INS(AtomicExchangeTypedArrayElement )VISIT_INS(AtomicTypedArrayElementBinop)VISIT_INS(Debugger)VISIT_INS (CheckIsObj)VISIT_INS(CheckObjCoercible)VISIT_INS(CheckClassHeritage )VISIT_INS(DebugCheckSelfHosted)VISIT_INS(IsPackedArray)VISIT_INS (GuardArrayIsPacked)VISIT_INS(GetPrototypeOf)VISIT_INS(ObjectWithProto )VISIT_INS(ObjectStaticProto)VISIT_INS(ConstantProto)VISIT_INS (BuiltinObject)VISIT_INS(SuperFunction)VISIT_INS(InitHomeObject )VISIT_INS(IsTypedArrayConstructor)VISIT_INS(LoadValueTag)VISIT_INS (LoadWrapperTarget)VISIT_INS(GuardHasGetterSetter)VISIT_INS(GuardIsExtensible )VISIT_INS(GuardInt32IsNonNegative)VISIT_INS(GuardInt32Range) VISIT_INS(GuardIndexIsNotDenseElement)VISIT_INS(GuardIndexIsValidUpdateOrAdd )VISIT_INS(CallAddOrUpdateSparseElement)VISIT_INS(CallGetSparseElement )VISIT_INS(CallNativeGetElement)VISIT_INS(CallNativeGetElementSuper )VISIT_INS(CallObjectHasSparseElement)VISIT_INS(BigIntAsIntN) VISIT_INS(BigIntAsUintN)VISIT_INS(GuardNonGCThing)VISIT_INS(ToHashableNonGCThing )VISIT_INS(ToHashableString)VISIT_INS(ToHashableValue)VISIT_INS (HashNonGCThing)VISIT_INS(HashString)VISIT_INS(HashSymbol)VISIT_INS (HashBigInt)VISIT_INS(HashObject)VISIT_INS(HashValue)VISIT_INS (SetObjectHasNonBigInt)VISIT_INS(SetObjectHasBigInt)VISIT_INS (SetObjectHasValue)VISIT_INS(SetObjectHasValueVMCall)VISIT_INS (SetObjectSize)VISIT_INS(MapObjectHasNonBigInt)VISIT_INS(MapObjectHasBigInt )VISIT_INS(MapObjectHasValue)VISIT_INS(MapObjectHasValueVMCall )VISIT_INS(MapObjectGetNonBigInt)VISIT_INS(MapObjectGetBigInt )VISIT_INS(MapObjectGetValue)VISIT_INS(MapObjectGetValueVMCall )VISIT_INS(MapObjectSize)VISIT_INS(PostIntPtrConversion)VISIT_INS (WasmNeg)VISIT_INS(WasmBinaryBitwise)VISIT_INS(WasmLoadInstance )VISIT_INS(WasmStoreInstance)VISIT_INS(WasmHeapReg)VISIT_INS( WasmBoundsCheck)VISIT_INS(WasmBoundsCheckRange32)VISIT_INS(WasmExtendU32Index )VISIT_INS(WasmWrapU32Index)VISIT_INS(WasmAddOffset)VISIT_INS (WasmAlignmentCheck)VISIT_INS(WasmLoad)VISIT_INS(WasmStore)VISIT_INS (AsmJSLoadHeap)VISIT_INS(AsmJSStoreHeap)VISIT_INS(WasmFence)VISIT_INS (WasmCompareExchangeHeap)VISIT_INS(WasmAtomicExchangeHeap)VISIT_INS (WasmAtomicBinopHeap)VISIT_INS(WasmLoadInstanceDataField)VISIT_INS (WasmLoadGlobalCell)VISIT_INS(WasmLoadTableElement)VISIT_INS( WasmStoreInstanceDataField)VISIT_INS(WasmStoreGlobalCell)VISIT_INS (WasmStoreStackResult)VISIT_INS(WasmDerivedPointer)VISIT_INS( WasmDerivedIndexPointer)VISIT_INS(WasmStoreRef)VISIT_INS(WasmPostWriteBarrierImmediate )VISIT_INS(WasmPostWriteBarrierIndex)VISIT_INS(WasmParameter) VISIT_INS(WasmReturn)VISIT_INS(WasmReturnVoid)VISIT_INS(WasmStackArg )VISIT_INS(WasmRegisterResult)VISIT_INS(WasmFloatRegisterResult )VISIT_INS(WasmRegister64Result)VISIT_INS(WasmStackResultArea )VISIT_INS(WasmStackResult)VISIT_INS(WasmCallCatchable)VISIT_INS (WasmCallUncatchable)VISIT_INS(WasmCallLandingPrePad)VISIT_INS (WasmReturnCall)VISIT_INS(WasmSelect)VISIT_INS(WasmReinterpret )VISIT_INS(Rotate)VISIT_INS(WasmStackSwitchToMain)VISIT_INS(WasmStackSwitchToSuspendable )VISIT_INS(WasmStackContinueOnSuspendable)VISIT_INS(WasmBinarySimd128 )VISIT_INS(WasmBinarySimd128WithConstant)VISIT_INS(WasmShiftSimd128 )VISIT_INS(WasmShuffleSimd128)VISIT_INS(WasmReplaceLaneSimd128 )VISIT_INS(WasmUnarySimd128)VISIT_INS(WasmTernarySimd128)VISIT_INS (WasmScalarToSimd128)VISIT_INS(WasmReduceSimd128)VISIT_INS(WasmLoadLaneSimd128 )VISIT_INS(WasmStoreLaneSimd128)VISIT_INS(UnreachableResult)VISIT_INS (IonToWasmCall)VISIT_INS(WasmLoadField)VISIT_INS(WasmLoadFieldKA )VISIT_INS(WasmLoadElementKA)VISIT_INS(WasmStoreFieldKA)VISIT_INS (WasmStoreFieldRefKA)VISIT_INS(WasmStoreElementKA)VISIT_INS(WasmStoreElementRefKA )VISIT_INS(WasmRefIsSubtypeOfConcrete)VISIT_INS(WasmRefIsSubtypeOfAbstract )VISIT_INS(WasmNewStructObject)VISIT_INS(WasmNewArrayObject) |
| 116 | #undef VISIT_INS |
| 117 | }; |
| 118 | |
| 119 | class BytecodeSite; |
| 120 | class CompactBufferWriter; |
| 121 | class Range; |
| 122 | |
| 123 | #define MIR_FLAG_LIST(_)_(InWorklist) _(EmittedAtUses) _(Commutative) _(Movable) _(Lowered ) _(Guard) _(GuardRangeBailouts) _(ImplicitlyUsed) _(Unused) _ (RecoveredOnBailout) _(IncompleteObject) _(CallResultCapture) _(Discarded) \ |
| 124 | _(InWorklist) \ |
| 125 | _(EmittedAtUses) \ |
| 126 | _(Commutative) \ |
| 127 | _(Movable) /* Allow passes like LICM to move this instruction */ \ |
| 128 | _(Lowered) /* (Debug only) has a virtual register */ \ |
| 129 | _(Guard) /* Not removable if uses == 0 */ \ |
| 130 | \ |
| 131 | /* Flag an instruction to be considered as a Guard if the instructions \ |
| 132 | * bails out on some inputs. \ |
| 133 | * \ |
| 134 | * Some optimizations can replace an instruction, and leave its operands \ |
| 135 | * unused. When the type information of the operand got used as a \ |
| 136 | * predicate of the transformation, then we have to flag the operands as \ |
| 137 | * GuardRangeBailouts. \ |
| 138 | * \ |
| 139 | * This flag prevents further optimization of instructions, which \ |
| 140 | * might remove the run-time checks (bailout conditions) used as a \ |
| 141 | * predicate of the previous transformation. \ |
| 142 | */ \ |
| 143 | _(GuardRangeBailouts) \ |
| 144 | \ |
| 145 | /* Some instructions have uses that aren't directly represented in the \ |
| 146 | * graph, and need to be handled specially. As an example, this is used to \ |
| 147 | * keep the flagged instruction in resume points, not substituting with an \ |
| 148 | * UndefinedValue. This can be used by call inlining when a function \ |
| 149 | * argument is not used by the inlined instructions. It is also used \ |
| 150 | * to annotate instructions which were used in removed branches. \ |
| 151 | */ \ |
| 152 | _(ImplicitlyUsed) \ |
| 153 | \ |
| 154 | /* The instruction has been marked dead for lazy removal from resume \ |
| 155 | * points. \ |
| 156 | */ \ |
| 157 | _(Unused) \ |
| 158 | \ |
| 159 | /* Marks if the current instruction should go to the bailout paths instead \ |
| 160 | * of producing code as part of the control flow. This flag can only be set \ |
| 161 | * on instructions which are only used by ResumePoint or by other flagged \ |
| 162 | * instructions. \ |
| 163 | */ \ |
| 164 | _(RecoveredOnBailout) \ |
| 165 | \ |
| 166 | /* Some instructions might represent an object, but the memory of these \ |
| 167 | * objects might be incomplete if we have not recovered all the stores which \ |
| 168 | * were supposed to happen before. This flag is used to annotate \ |
| 169 | * instructions which might return a pointer to a memory area which is not \ |
| 170 | * yet fully initialized. This flag is used to ensure that stores are \ |
| 171 | * executed before returning the value. \ |
| 172 | */ \ |
| 173 | _(IncompleteObject) \ |
| 174 | \ |
| 175 | /* For WebAssembly, there are functions with multiple results. Instead of \ |
| 176 | * having the results defined by one call instruction, they are instead \ |
| 177 | * captured in subsequent result capture instructions, because modelling \ |
| 178 | * multi-value results in Ion is too complicated. However since they \ |
| 179 | * capture ambient live registers, it would be an error to move an unrelated \ |
| 180 | * instruction between the call and the result capture. This flag is used \ |
| 181 | * to prevent code motion from moving instructions in invalid ways. \ |
| 182 | */ \ |
| 183 | _(CallResultCapture) \ |
| 184 | \ |
| 185 | /* The current instruction got discarded from the MIR Graph. This is useful \ |
| 186 | * when we want to iterate over resume points and instructions, while \ |
| 187 | * handling instructions which are discarded without reporting to the \ |
| 188 | * iterator. \ |
| 189 | */ \ |
| 190 | _(Discarded) |
| 191 | |
| 192 | class MDefinition; |
| 193 | class MInstruction; |
| 194 | class MBasicBlock; |
| 195 | class MNode; |
| 196 | class MUse; |
| 197 | class MPhi; |
| 198 | class MIRGraph; |
| 199 | class MResumePoint; |
| 200 | class MControlInstruction; |
| 201 | |
| 202 | // Represents a use of a node. |
| 203 | class MUse : public TempObject, public InlineListNode<MUse> { |
| 204 | // Grant access to setProducerUnchecked. |
| 205 | friend class MDefinition; |
| 206 | friend class MPhi; |
| 207 | |
| 208 | MDefinition* producer_; // MDefinition that is being used. |
| 209 | MNode* consumer_; // The node that is using this operand. |
| 210 | |
| 211 | // Low-level unchecked edit method for replaceAllUsesWith and |
| 212 | // MPhi::removeOperand. This doesn't update use lists! |
| 213 | // replaceAllUsesWith and MPhi::removeOperand do that manually. |
| 214 | void setProducerUnchecked(MDefinition* producer) { |
| 215 | MOZ_ASSERT(consumer_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(consumer_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(consumer_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("consumer_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "consumer_" ")" ); do { *((volatile int*)__null) = 215; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 216 | MOZ_ASSERT(producer_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(producer_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(producer_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("producer_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 216); AnnotateMozCrashReason("MOZ_ASSERT" "(" "producer_" ")" ); do { *((volatile int*)__null) = 216; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 217 | MOZ_ASSERT(producer)do { static_assert( mozilla::detail::AssertionConditionType< decltype(producer)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(producer))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("producer", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 217); AnnotateMozCrashReason("MOZ_ASSERT" "(" "producer" ")" ); do { *((volatile int*)__null) = 217; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 218 | producer_ = producer; |
| 219 | } |
| 220 | |
| 221 | public: |
| 222 | // Default constructor for use in vectors. |
| 223 | MUse() : producer_(nullptr), consumer_(nullptr) {} |
| 224 | |
| 225 | // Move constructor for use in vectors. When an MUse is moved, it stays |
| 226 | // in its containing use list. |
| 227 | MUse(MUse&& other) |
| 228 | : InlineListNode<MUse>(std::move(other)), |
| 229 | producer_(other.producer_), |
| 230 | consumer_(other.consumer_) {} |
| 231 | |
| 232 | // Construct an MUse initialized with |producer| and |consumer|. |
| 233 | MUse(MDefinition* producer, MNode* consumer) { |
| 234 | initUnchecked(producer, consumer); |
| 235 | } |
| 236 | |
| 237 | // Set this use, which was previously clear. |
| 238 | inline void init(MDefinition* producer, MNode* consumer); |
| 239 | // Like init, but works even when the use contains uninitialized data. |
| 240 | inline void initUnchecked(MDefinition* producer, MNode* consumer); |
| 241 | // Like initUnchecked, but set the producer to nullptr. |
| 242 | inline void initUncheckedWithoutProducer(MNode* consumer); |
| 243 | // Set this use, which was not previously clear. |
| 244 | inline void replaceProducer(MDefinition* producer); |
| 245 | // Clear this use. |
| 246 | inline void releaseProducer(); |
| 247 | |
| 248 | MDefinition* producer() const { |
| 249 | MOZ_ASSERT(producer_ != nullptr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(producer_ != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(producer_ != nullptr))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("producer_ != nullptr" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "producer_ != nullptr" ")"); do { *((volatile int*)__null) = 249; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 250 | return producer_; |
| 251 | } |
| 252 | bool hasProducer() const { return producer_ != nullptr; } |
| 253 | MNode* consumer() const { |
| 254 | MOZ_ASSERT(consumer_ != nullptr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(consumer_ != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(consumer_ != nullptr))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("consumer_ != nullptr" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 254); AnnotateMozCrashReason("MOZ_ASSERT" "(" "consumer_ != nullptr" ")"); do { *((volatile int*)__null) = 254; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 255 | return consumer_; |
| 256 | } |
| 257 | |
| 258 | #ifdef DEBUG1 |
| 259 | // Return the operand index of this MUse in its consumer. This is DEBUG-only |
| 260 | // as normal code should instead call indexOf on the cast consumer directly, |
| 261 | // to allow it to be devirtualized and inlined. |
| 262 | size_t index() const; |
| 263 | #endif |
| 264 | }; |
| 265 | |
| 266 | using MUseIterator = InlineList<MUse>::iterator; |
| 267 | |
| 268 | // A node is an entry in the MIR graph. It has two kinds: |
| 269 | // MInstruction: an instruction which appears in the IR stream. |
| 270 | // MResumePoint: a list of instructions that correspond to the state of the |
| 271 | // interpreter/Baseline stack. |
| 272 | // |
| 273 | // Nodes can hold references to MDefinitions. Each MDefinition has a list of |
| 274 | // nodes holding such a reference (its use chain). |
| 275 | class MNode : public TempObject { |
| 276 | protected: |
| 277 | enum class Kind { Definition = 0, ResumePoint }; |
| 278 | |
| 279 | private: |
| 280 | static const uintptr_t KindMask = 0x1; |
| 281 | uintptr_t blockAndKind_; |
| 282 | |
| 283 | Kind kind() const { return Kind(blockAndKind_ & KindMask); } |
| 284 | |
| 285 | protected: |
| 286 | explicit MNode(const MNode& other) : blockAndKind_(other.blockAndKind_) {} |
| 287 | |
| 288 | MNode(MBasicBlock* block, Kind kind) { setBlockAndKind(block, kind); } |
| 289 | |
| 290 | void setBlockAndKind(MBasicBlock* block, Kind kind) { |
| 291 | blockAndKind_ = uintptr_t(block) | uintptr_t(kind); |
| 292 | MOZ_ASSERT(this->block() == block)do { static_assert( mozilla::detail::AssertionConditionType< decltype(this->block() == block)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(this->block() == block))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("this->block() == block" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this->block() == block" ")"); do { *((volatile int*)__null) = 292; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 293 | } |
| 294 | |
| 295 | MBasicBlock* definitionBlock() const { |
| 296 | MOZ_ASSERT(isDefinition())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isDefinition())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isDefinition()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isDefinition()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isDefinition()" ")"); do { *((volatile int*)__null) = 296; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 297 | static_assert(unsigned(Kind::Definition) == 0, |
| 298 | "Code below relies on low bit being 0"); |
| 299 | return reinterpret_cast<MBasicBlock*>(blockAndKind_); |
| 300 | } |
| 301 | MBasicBlock* resumePointBlock() const { |
| 302 | MOZ_ASSERT(isResumePoint())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isResumePoint())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isResumePoint()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isResumePoint()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isResumePoint()" ")"); do { *((volatile int*)__null) = 302; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 303 | static_assert(unsigned(Kind::ResumePoint) == 1, |
| 304 | "Code below relies on low bit being 1"); |
| 305 | // Use a subtraction: if the caller does block()->foo, the compiler |
| 306 | // will be able to fold it with the load. |
| 307 | return reinterpret_cast<MBasicBlock*>(blockAndKind_ - 1); |
| 308 | } |
| 309 | |
| 310 | public: |
| 311 | // Returns the definition at a given operand. |
| 312 | virtual MDefinition* getOperand(size_t index) const = 0; |
| 313 | virtual size_t numOperands() const = 0; |
| 314 | virtual size_t indexOf(const MUse* u) const = 0; |
| 315 | |
| 316 | bool isDefinition() const { return kind() == Kind::Definition; } |
| 317 | bool isResumePoint() const { return kind() == Kind::ResumePoint; } |
| 318 | MBasicBlock* block() const { |
| 319 | return reinterpret_cast<MBasicBlock*>(blockAndKind_ & ~KindMask); |
| 320 | } |
| 321 | MBasicBlock* caller() const; |
| 322 | |
| 323 | // Sets an already set operand, updating use information. If you're looking |
| 324 | // for setOperand, this is probably what you want. |
| 325 | virtual void replaceOperand(size_t index, MDefinition* operand) = 0; |
| 326 | |
| 327 | // Resets the operand to an uninitialized state, breaking the link |
| 328 | // with the previous operand's producer. |
| 329 | void releaseOperand(size_t index) { getUseFor(index)->releaseProducer(); } |
| 330 | bool hasOperand(size_t index) const { |
| 331 | return getUseFor(index)->hasProducer(); |
| 332 | } |
| 333 | |
| 334 | inline MDefinition* toDefinition(); |
| 335 | inline MResumePoint* toResumePoint(); |
| 336 | |
| 337 | [[nodiscard]] virtual bool writeRecoverData( |
| 338 | CompactBufferWriter& writer) const; |
| 339 | |
| 340 | #ifdef JS_JITSPEW1 |
| 341 | virtual void dump(GenericPrinter& out) const = 0; |
| 342 | virtual void dump() const = 0; |
| 343 | #endif |
| 344 | |
| 345 | protected: |
| 346 | // Need visibility on getUseFor to avoid O(n^2) complexity. |
| 347 | friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force); |
| 348 | |
| 349 | // Gets the MUse corresponding to given operand. |
| 350 | virtual MUse* getUseFor(size_t index) = 0; |
| 351 | virtual const MUse* getUseFor(size_t index) const = 0; |
| 352 | }; |
| 353 | |
| 354 | class AliasSet { |
| 355 | private: |
| 356 | uint32_t flags_; |
| 357 | |
| 358 | public: |
| 359 | enum Flag { |
| 360 | None_ = 0, |
| 361 | ObjectFields = 1 << 0, // shape, class, slots, length etc. |
| 362 | Element = 1 << 1, // A Value member of obj->elements or |
| 363 | // a typed object. |
| 364 | UnboxedElement = 1 << 2, // An unboxed scalar or reference member of |
| 365 | // typed object. |
| 366 | DynamicSlot = 1 << 3, // A Value member of obj->slots. |
| 367 | FixedSlot = 1 << 4, // A Value member of obj->fixedSlots(). |
| 368 | DOMProperty = 1 << 5, // A DOM property |
| 369 | WasmInstanceData = 1 << 6, // An asm.js/wasm private global var |
| 370 | WasmHeap = 1 << 7, // An asm.js/wasm heap load |
| 371 | WasmHeapMeta = 1 << 8, // The asm.js/wasm heap base pointer and |
| 372 | // bounds check limit, in Instance. |
| 373 | ArrayBufferViewLengthOrOffset = |
| 374 | 1 << 9, // An array buffer view's length or byteOffset |
| 375 | WasmGlobalCell = 1 << 10, // A wasm global cell |
| 376 | WasmTableElement = 1 << 11, // An element of a wasm table |
| 377 | WasmTableMeta = 1 << 12, // A wasm table elements pointer and |
| 378 | // length field, in instance data. |
| 379 | WasmStackResult = 1 << 13, // A stack result from the current function |
| 380 | |
| 381 | // JSContext's exception state. This is used on instructions like MThrow |
| 382 | // or MNewArrayDynamicLength that throw exceptions (other than OOM) but have |
| 383 | // no other side effect, to ensure that they get their own up-to-date resume |
| 384 | // point. (This resume point will be used when constructing the Baseline |
| 385 | // frame during exception bailouts.) |
| 386 | ExceptionState = 1 << 14, |
| 387 | |
| 388 | // Used for instructions that load the privateSlot of DOM proxies and |
| 389 | // the ExpandoAndGeneration. |
| 390 | DOMProxyExpando = 1 << 15, |
| 391 | |
| 392 | // Hash table of a Map or Set object. |
| 393 | MapOrSetHashTable = 1 << 16, |
| 394 | |
| 395 | // Internal state of the random number generator |
| 396 | RNG = 1 << 17, |
| 397 | |
| 398 | // The pendingException slot on the wasm instance object. |
| 399 | WasmPendingException = 1 << 18, |
| 400 | |
| 401 | // The fuzzilliHash slot |
| 402 | FuzzilliHash = 1 << 19, |
| 403 | |
| 404 | // The WasmStructObject::inlineData_[..] storage area |
| 405 | WasmStructInlineDataArea = 1 << 20, |
| 406 | |
| 407 | // The WasmStructObject::outlineData_ pointer only |
| 408 | WasmStructOutlineDataPointer = 1 << 21, |
| 409 | |
| 410 | // The malloc'd block that WasmStructObject::outlineData_ points at |
| 411 | WasmStructOutlineDataArea = 1 << 22, |
| 412 | |
| 413 | // The WasmArrayObject::numElements_ field |
| 414 | WasmArrayNumElements = 1 << 23, |
| 415 | |
| 416 | // The WasmArrayObject::data_ pointer only |
| 417 | WasmArrayDataPointer = 1 << 24, |
| 418 | |
| 419 | // The malloc'd block that WasmArrayObject::data_ points at |
| 420 | WasmArrayDataArea = 1 << 25, |
| 421 | |
| 422 | // The generation counter associated with the global object |
| 423 | GlobalGenerationCounter = 1 << 26, |
| 424 | |
| 425 | // The SharedArrayRawBuffer::length field. |
| 426 | SharedArrayRawBufferLength = 1 << 27, |
| 427 | |
| 428 | Last = SharedArrayRawBufferLength, |
| 429 | |
| 430 | Any = Last | (Last - 1), |
| 431 | NumCategories = 28, |
| 432 | |
| 433 | // Indicates load or store. |
| 434 | Store_ = 1 << 31 |
| 435 | }; |
| 436 | |
| 437 | static_assert((1 << NumCategories) - 1 == Any, |
| 438 | "NumCategories must include all flags present in Any"); |
| 439 | |
| 440 | explicit AliasSet(uint32_t flags) : flags_(flags) {} |
| 441 | |
| 442 | public: |
| 443 | inline bool isNone() const { return flags_ == None_; } |
| 444 | uint32_t flags() const { return flags_ & Any; } |
| 445 | inline bool isStore() const { return !!(flags_ & Store_); } |
| 446 | inline bool isLoad() const { return !isStore() && !isNone(); } |
| 447 | inline AliasSet operator|(const AliasSet& other) const { |
| 448 | return AliasSet(flags_ | other.flags_); |
| 449 | } |
| 450 | inline AliasSet operator&(const AliasSet& other) const { |
| 451 | return AliasSet(flags_ & other.flags_); |
| 452 | } |
| 453 | inline AliasSet operator~() const { return AliasSet(~flags_); } |
| 454 | static AliasSet None() { return AliasSet(None_); } |
| 455 | static AliasSet Load(uint32_t flags) { |
| 456 | MOZ_ASSERT(flags && !(flags & Store_))do { static_assert( mozilla::detail::AssertionConditionType< decltype(flags && !(flags & Store_))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(flags && !(flags & Store_)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("flags && !(flags & Store_)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 456); AnnotateMozCrashReason("MOZ_ASSERT" "(" "flags && !(flags & Store_)" ")"); do { *((volatile int*)__null) = 456; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 457 | return AliasSet(flags); |
| 458 | } |
| 459 | static AliasSet Store(uint32_t flags) { |
| 460 | MOZ_ASSERT(flags && !(flags & Store_))do { static_assert( mozilla::detail::AssertionConditionType< decltype(flags && !(flags & Store_))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(flags && !(flags & Store_)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("flags && !(flags & Store_)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 460); AnnotateMozCrashReason("MOZ_ASSERT" "(" "flags && !(flags & Store_)" ")"); do { *((volatile int*)__null) = 460; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 461 | return AliasSet(flags | Store_); |
| 462 | } |
| 463 | }; |
| 464 | |
| 465 | typedef Vector<MDefinition*, 6, JitAllocPolicy> MDefinitionVector; |
| 466 | typedef Vector<MInstruction*, 6, JitAllocPolicy> MInstructionVector; |
| 467 | |
| 468 | // When a floating-point value is used by nodes which would prefer to |
| 469 | // receive integer inputs, we may be able to help by computing our result |
| 470 | // into an integer directly. |
| 471 | // |
| 472 | // A value can be truncated in 4 differents ways: |
| 473 | // 1. Ignore Infinities (x / 0 --> 0). |
| 474 | // 2. Ignore overflow (INT_MIN / -1 == (INT_MAX + 1) --> INT_MIN) |
| 475 | // 3. Ignore negative zeros. (-0 --> 0) |
| 476 | // 4. Ignore remainder. (3 / 4 --> 0) |
| 477 | // |
| 478 | // Indirect truncation is used to represent that we are interested in the |
| 479 | // truncated result, but only if it can safely flow into operations which |
| 480 | // are computed modulo 2^32, such as (2) and (3). Infinities are not safe, |
| 481 | // as they would have absorbed other math operations. Remainders are not |
| 482 | // safe, as fractions can be scaled up by multiplication. |
| 483 | // |
| 484 | // Division is a particularly interesting node here because it covers all 4 |
| 485 | // cases even when its own operands are integers. |
| 486 | // |
| 487 | // Note that these enum values are ordered from least value-modifying to |
| 488 | // most value-modifying, and code relies on this ordering. |
| 489 | enum class TruncateKind { |
| 490 | // No correction. |
| 491 | NoTruncate = 0, |
| 492 | // An integer is desired, but we can't skip bailout checks. |
| 493 | TruncateAfterBailouts = 1, |
| 494 | // The value will be truncated after some arithmetic (see above). |
| 495 | IndirectTruncate = 2, |
| 496 | // Direct and infallible truncation to int32. |
| 497 | Truncate = 3 |
| 498 | }; |
| 499 | |
| 500 | // An MDefinition is an SSA name. |
| 501 | class MDefinition : public MNode { |
| 502 | friend class MBasicBlock; |
| 503 | |
| 504 | public: |
| 505 | enum class Opcode : uint16_t { |
| 506 | #define DEFINE_OPCODES(op) op, |
| 507 | MIR_OPCODE_LIST(DEFINE_OPCODES)DEFINE_OPCODES(Start)DEFINE_OPCODES(OsrEntry)DEFINE_OPCODES(Nop )DEFINE_OPCODES(LimitedTruncate)DEFINE_OPCODES(Constant)DEFINE_OPCODES (WasmNullConstant)DEFINE_OPCODES(WasmFloatConstant)DEFINE_OPCODES (Parameter)DEFINE_OPCODES(Callee)DEFINE_OPCODES(IsConstructing )DEFINE_OPCODES(TableSwitch)DEFINE_OPCODES(Goto)DEFINE_OPCODES (Test)DEFINE_OPCODES(Return)DEFINE_OPCODES(Throw)DEFINE_OPCODES (ThrowWithStack)DEFINE_OPCODES(NewArray)DEFINE_OPCODES(NewArrayDynamicLength )DEFINE_OPCODES(NewTypedArray)DEFINE_OPCODES(NewTypedArrayDynamicLength )DEFINE_OPCODES(NewTypedArrayFromArray)DEFINE_OPCODES(NewTypedArrayFromArrayBuffer )DEFINE_OPCODES(NewObject)DEFINE_OPCODES(NewPlainObject)DEFINE_OPCODES (NewArrayObject)DEFINE_OPCODES(NewIterator)DEFINE_OPCODES(ObjectState )DEFINE_OPCODES(ArrayState)DEFINE_OPCODES(BindFunction)DEFINE_OPCODES (NewBoundFunction)DEFINE_OPCODES(BoundFunctionNumArgs)DEFINE_OPCODES (GuardBoundFunctionIsConstructor)DEFINE_OPCODES(MutateProto)DEFINE_OPCODES (InitPropGetterSetter)DEFINE_OPCODES(InitElemGetterSetter)DEFINE_OPCODES (Call)DEFINE_OPCODES(CallClassHook)DEFINE_OPCODES(ApplyArgs)DEFINE_OPCODES (ApplyArgsObj)DEFINE_OPCODES(ApplyArray)DEFINE_OPCODES(ConstructArgs )DEFINE_OPCODES(ConstructArray)DEFINE_OPCODES(Bail)DEFINE_OPCODES (Unreachable)DEFINE_OPCODES(EncodeSnapshot)DEFINE_OPCODES(AssertRecoveredOnBailout )DEFINE_OPCODES(AssertFloat32)DEFINE_OPCODES(Compare)DEFINE_OPCODES (SameValueDouble)DEFINE_OPCODES(SameValue)DEFINE_OPCODES(Box) DEFINE_OPCODES(Unbox)DEFINE_OPCODES(AssertRange)DEFINE_OPCODES (AssertClass)DEFINE_OPCODES(AssertShape)DEFINE_OPCODES(CreateThis )DEFINE_OPCODES(CreateArgumentsObject)DEFINE_OPCODES(CreateInlinedArgumentsObject )DEFINE_OPCODES(GetInlinedArgument)DEFINE_OPCODES(GetInlinedArgumentHole )DEFINE_OPCODES(GetArgumentsObjectArg)DEFINE_OPCODES(SetArgumentsObjectArg )DEFINE_OPCODES(LoadArgumentsObjectArg)DEFINE_OPCODES(LoadArgumentsObjectArgHole )DEFINE_OPCODES(InArgumentsObjectArg)DEFINE_OPCODES(ArgumentsObjectLength )DEFINE_OPCODES(ArrayFromArgumentsObject)DEFINE_OPCODES(GuardArgumentsObjectFlags )DEFINE_OPCODES(LoadScriptedProxyHandler)DEFINE_OPCODES(CheckScriptedProxyGetResult )DEFINE_OPCODES(IdToStringOrSymbol)DEFINE_OPCODES(ReturnFromCtor )DEFINE_OPCODES(ToDouble)DEFINE_OPCODES(ToFloat32)DEFINE_OPCODES (WasmUnsignedToDouble)DEFINE_OPCODES(WasmUnsignedToFloat32)DEFINE_OPCODES (WrapInt64ToInt32)DEFINE_OPCODES(ExtendInt32ToInt64)DEFINE_OPCODES (WasmBuiltinTruncateToInt64)DEFINE_OPCODES(WasmTruncateToInt64 )DEFINE_OPCODES(WasmTruncateToInt32)DEFINE_OPCODES(WasmAnyRefFromJSValue )DEFINE_OPCODES(WasmAnyRefFromJSObject)DEFINE_OPCODES(WasmAnyRefFromJSString )DEFINE_OPCODES(WasmNewI31Ref)DEFINE_OPCODES(WasmI31RefGet)DEFINE_OPCODES (Int32ToIntPtr)DEFINE_OPCODES(NonNegativeIntPtrToInt32)DEFINE_OPCODES (IntPtrToDouble)DEFINE_OPCODES(AdjustDataViewLength)DEFINE_OPCODES (Int64ToFloatingPoint)DEFINE_OPCODES(BuiltinInt64ToFloatingPoint )DEFINE_OPCODES(ToNumberInt32)DEFINE_OPCODES(BooleanToInt32)DEFINE_OPCODES (TruncateToInt32)DEFINE_OPCODES(WasmBuiltinTruncateToInt32)DEFINE_OPCODES (ToBigInt)DEFINE_OPCODES(ToInt64)DEFINE_OPCODES(TruncateBigIntToInt64 )DEFINE_OPCODES(Int64ToBigInt)DEFINE_OPCODES(ToString)DEFINE_OPCODES (BitNot)DEFINE_OPCODES(TypeOf)DEFINE_OPCODES(TypeOfName)DEFINE_OPCODES (TypeOfIs)DEFINE_OPCODES(ToAsyncIter)DEFINE_OPCODES(ToPropertyKeyCache )DEFINE_OPCODES(BitAnd)DEFINE_OPCODES(BitOr)DEFINE_OPCODES(BitXor )DEFINE_OPCODES(Lsh)DEFINE_OPCODES(Rsh)DEFINE_OPCODES(Ursh)DEFINE_OPCODES (SignExtendInt32)DEFINE_OPCODES(SignExtendInt64)DEFINE_OPCODES (MinMax)DEFINE_OPCODES(MinMaxArray)DEFINE_OPCODES(Abs)DEFINE_OPCODES (Clz)DEFINE_OPCODES(Ctz)DEFINE_OPCODES(Popcnt)DEFINE_OPCODES( Sqrt)DEFINE_OPCODES(CopySign)DEFINE_OPCODES(Atan2)DEFINE_OPCODES (Hypot)DEFINE_OPCODES(Pow)DEFINE_OPCODES(PowHalf)DEFINE_OPCODES (Random)DEFINE_OPCODES(Sign)DEFINE_OPCODES(MathFunction)DEFINE_OPCODES (Add)DEFINE_OPCODES(Sub)DEFINE_OPCODES(Mul)DEFINE_OPCODES(Div )DEFINE_OPCODES(WasmBuiltinDivI64)DEFINE_OPCODES(Mod)DEFINE_OPCODES (WasmBuiltinModD)DEFINE_OPCODES(WasmBuiltinModI64)DEFINE_OPCODES (BigIntAdd)DEFINE_OPCODES(BigIntSub)DEFINE_OPCODES(BigIntMul) DEFINE_OPCODES(BigIntDiv)DEFINE_OPCODES(BigIntMod)DEFINE_OPCODES (BigIntPow)DEFINE_OPCODES(BigIntBitAnd)DEFINE_OPCODES(BigIntBitOr )DEFINE_OPCODES(BigIntBitXor)DEFINE_OPCODES(BigIntLsh)DEFINE_OPCODES (BigIntRsh)DEFINE_OPCODES(BigIntIncrement)DEFINE_OPCODES(BigIntDecrement )DEFINE_OPCODES(BigIntNegate)DEFINE_OPCODES(BigIntBitNot)DEFINE_OPCODES (Int32ToStringWithBase)DEFINE_OPCODES(NumberParseInt)DEFINE_OPCODES (DoubleParseInt)DEFINE_OPCODES(Concat)DEFINE_OPCODES(LinearizeString )DEFINE_OPCODES(LinearizeForCharAccess)DEFINE_OPCODES(LinearizeForCodePointAccess )DEFINE_OPCODES(ToRelativeStringIndex)DEFINE_OPCODES(CharCodeAt )DEFINE_OPCODES(CharCodeAtOrNegative)DEFINE_OPCODES(CodePointAt )DEFINE_OPCODES(CodePointAtOrNegative)DEFINE_OPCODES(NegativeToNaN )DEFINE_OPCODES(NegativeToUndefined)DEFINE_OPCODES(FromCharCode )DEFINE_OPCODES(FromCharCodeEmptyIfNegative)DEFINE_OPCODES(FromCharCodeUndefinedIfNegative )DEFINE_OPCODES(FromCodePoint)DEFINE_OPCODES(StringIncludes)DEFINE_OPCODES (StringIndexOf)DEFINE_OPCODES(StringLastIndexOf)DEFINE_OPCODES (StringStartsWith)DEFINE_OPCODES(StringEndsWith)DEFINE_OPCODES (StringConvertCase)DEFINE_OPCODES(CharCodeConvertCase)DEFINE_OPCODES (StringTrimStartIndex)DEFINE_OPCODES(StringTrimEndIndex)DEFINE_OPCODES (StringSplit)DEFINE_OPCODES(BoxNonStrictThis)DEFINE_OPCODES(ImplicitThis )DEFINE_OPCODES(Phi)DEFINE_OPCODES(Beta)DEFINE_OPCODES(NaNToZero )DEFINE_OPCODES(OsrValue)DEFINE_OPCODES(OsrEnvironmentChain)DEFINE_OPCODES (OsrArgumentsObject)DEFINE_OPCODES(OsrReturnValue)DEFINE_OPCODES (BinaryCache)DEFINE_OPCODES(UnaryCache)DEFINE_OPCODES(CheckOverRecursed )DEFINE_OPCODES(InterruptCheck)DEFINE_OPCODES(WasmInterruptCheck )DEFINE_OPCODES(WasmTrap)DEFINE_OPCODES(WasmTrapIfNull)DEFINE_OPCODES (LexicalCheck)DEFINE_OPCODES(ThrowRuntimeLexicalError)DEFINE_OPCODES (ThrowMsg)DEFINE_OPCODES(GlobalDeclInstantiation)DEFINE_OPCODES (RegExp)DEFINE_OPCODES(RegExpMatcher)DEFINE_OPCODES(RegExpSearcher )DEFINE_OPCODES(RegExpSearcherLastLimit)DEFINE_OPCODES(RegExpExecMatch )DEFINE_OPCODES(RegExpExecTest)DEFINE_OPCODES(RegExpHasCaptureGroups )DEFINE_OPCODES(RegExpPrototypeOptimizable)DEFINE_OPCODES(RegExpInstanceOptimizable )DEFINE_OPCODES(GetFirstDollarIndex)DEFINE_OPCODES(StringReplace )DEFINE_OPCODES(Substr)DEFINE_OPCODES(ModuleMetadata)DEFINE_OPCODES (DynamicImport)DEFINE_OPCODES(Lambda)DEFINE_OPCODES(FunctionWithProto )DEFINE_OPCODES(SetFunName)DEFINE_OPCODES(Slots)DEFINE_OPCODES (Elements)DEFINE_OPCODES(InitializedLength)DEFINE_OPCODES(SetInitializedLength )DEFINE_OPCODES(ArrayLength)DEFINE_OPCODES(SetArrayLength)DEFINE_OPCODES (FunctionLength)DEFINE_OPCODES(FunctionName)DEFINE_OPCODES(GetNextEntryForIterator )DEFINE_OPCODES(ArrayBufferByteLength)DEFINE_OPCODES(ArrayBufferViewLength )DEFINE_OPCODES(ArrayBufferViewByteOffset)DEFINE_OPCODES(ArrayBufferViewElements )DEFINE_OPCODES(ResizableTypedArrayByteOffsetMaybeOutOfBounds )DEFINE_OPCODES(ResizableTypedArrayLength)DEFINE_OPCODES(ResizableDataViewByteLength )DEFINE_OPCODES(GrowableSharedArrayBufferByteLength)DEFINE_OPCODES (TypedArrayElementSize)DEFINE_OPCODES(GuardHasAttachedArrayBuffer )DEFINE_OPCODES(GuardResizableArrayBufferViewInBounds)DEFINE_OPCODES (GuardResizableArrayBufferViewInBoundsOrDetached)DEFINE_OPCODES (GuardNumberToIntPtrIndex)DEFINE_OPCODES(KeepAliveObject)DEFINE_OPCODES (DebugEnterGCUnsafeRegion)DEFINE_OPCODES(DebugLeaveGCUnsafeRegion )DEFINE_OPCODES(Not)DEFINE_OPCODES(BoundsCheck)DEFINE_OPCODES (BoundsCheckLower)DEFINE_OPCODES(SpectreMaskIndex)DEFINE_OPCODES (LoadElement)DEFINE_OPCODES(LoadElementAndUnbox)DEFINE_OPCODES (LoadElementHole)DEFINE_OPCODES(StoreElement)DEFINE_OPCODES(StoreHoleValueElement )DEFINE_OPCODES(StoreElementHole)DEFINE_OPCODES(ArrayPopShift )DEFINE_OPCODES(ArrayPush)DEFINE_OPCODES(ArraySlice)DEFINE_OPCODES (ArgumentsSlice)DEFINE_OPCODES(FrameArgumentsSlice)DEFINE_OPCODES (InlineArgumentsSlice)DEFINE_OPCODES(NormalizeSliceTerm)DEFINE_OPCODES (ArrayJoin)DEFINE_OPCODES(ObjectKeys)DEFINE_OPCODES(ObjectKeysLength )DEFINE_OPCODES(LoadUnboxedScalar)DEFINE_OPCODES(LoadDataViewElement )DEFINE_OPCODES(LoadTypedArrayElementHole)DEFINE_OPCODES(StoreUnboxedScalar )DEFINE_OPCODES(StoreDataViewElement)DEFINE_OPCODES(StoreTypedArrayElementHole )DEFINE_OPCODES(EffectiveAddress)DEFINE_OPCODES(ClampToUint8) DEFINE_OPCODES(LoadFixedSlot)DEFINE_OPCODES(LoadFixedSlotAndUnbox )DEFINE_OPCODES(LoadDynamicSlotAndUnbox)DEFINE_OPCODES(StoreFixedSlot )DEFINE_OPCODES(GetPropertyCache)DEFINE_OPCODES(HomeObjectSuperBase )DEFINE_OPCODES(GetPropSuperCache)DEFINE_OPCODES(BindNameCache )DEFINE_OPCODES(CallBindVar)DEFINE_OPCODES(GuardShape)DEFINE_OPCODES (GuardFuse)DEFINE_OPCODES(GuardMultipleShapes)DEFINE_OPCODES( GuardProto)DEFINE_OPCODES(GuardNullProto)DEFINE_OPCODES(GuardIsNativeObject )DEFINE_OPCODES(GuardGlobalGeneration)DEFINE_OPCODES(GuardIsProxy )DEFINE_OPCODES(GuardIsNotDOMProxy)DEFINE_OPCODES(GuardIsNotProxy )DEFINE_OPCODES(ProxyGet)DEFINE_OPCODES(ProxyGetByValue)DEFINE_OPCODES (ProxyHasProp)DEFINE_OPCODES(ProxySet)DEFINE_OPCODES(ProxySetByValue )DEFINE_OPCODES(CallSetArrayLength)DEFINE_OPCODES(MegamorphicLoadSlot )DEFINE_OPCODES(MegamorphicLoadSlotByValue)DEFINE_OPCODES(MegamorphicStoreSlot )DEFINE_OPCODES(MegamorphicHasProp)DEFINE_OPCODES(SmallObjectVariableKeyHasProp )DEFINE_OPCODES(GuardIsNotArrayBufferMaybeShared)DEFINE_OPCODES (GuardIsTypedArray)DEFINE_OPCODES(GuardIsFixedLengthTypedArray )DEFINE_OPCODES(GuardIsResizableTypedArray)DEFINE_OPCODES(GuardHasProxyHandler )DEFINE_OPCODES(NurseryObject)DEFINE_OPCODES(GuardValue)DEFINE_OPCODES (GuardNullOrUndefined)DEFINE_OPCODES(GuardIsNotObject)DEFINE_OPCODES (GuardFunctionFlags)DEFINE_OPCODES(GuardFunctionIsNonBuiltinCtor )DEFINE_OPCODES(GuardFunctionKind)DEFINE_OPCODES(GuardFunctionScript )DEFINE_OPCODES(GuardObjectIdentity)DEFINE_OPCODES(GuardSpecificFunction )DEFINE_OPCODES(GuardSpecificAtom)DEFINE_OPCODES(GuardSpecificSymbol )DEFINE_OPCODES(GuardSpecificInt32)DEFINE_OPCODES(GuardStringToIndex )DEFINE_OPCODES(GuardStringToInt32)DEFINE_OPCODES(GuardStringToDouble )DEFINE_OPCODES(GuardNoDenseElements)DEFINE_OPCODES(GuardTagNotEqual )DEFINE_OPCODES(LoadDynamicSlot)DEFINE_OPCODES(FunctionEnvironment )DEFINE_OPCODES(NewLexicalEnvironmentObject)DEFINE_OPCODES(NewClassBodyEnvironmentObject )DEFINE_OPCODES(NewVarEnvironmentObject)DEFINE_OPCODES(HomeObject )DEFINE_OPCODES(AddAndStoreSlot)DEFINE_OPCODES(AllocateAndStoreSlot )DEFINE_OPCODES(AddSlotAndCallAddPropHook)DEFINE_OPCODES(StoreDynamicSlot )DEFINE_OPCODES(GetNameCache)DEFINE_OPCODES(CallGetIntrinsicValue )DEFINE_OPCODES(DeleteProperty)DEFINE_OPCODES(DeleteElement)DEFINE_OPCODES (SetPropertyCache)DEFINE_OPCODES(MegamorphicSetElement)DEFINE_OPCODES (SetDOMProperty)DEFINE_OPCODES(GetDOMProperty)DEFINE_OPCODES( GetDOMMember)DEFINE_OPCODES(ObjectToIterator)DEFINE_OPCODES(ValueToIterator )DEFINE_OPCODES(IteratorHasIndices)DEFINE_OPCODES(LoadSlotByIteratorIndex )DEFINE_OPCODES(StoreSlotByIteratorIndex)DEFINE_OPCODES(LoadDOMExpandoValue )DEFINE_OPCODES(LoadDOMExpandoValueGuardGeneration)DEFINE_OPCODES (LoadDOMExpandoValueIgnoreGeneration)DEFINE_OPCODES(GuardDOMExpandoMissingOrGuardShape )DEFINE_OPCODES(StringLength)DEFINE_OPCODES(Floor)DEFINE_OPCODES (Ceil)DEFINE_OPCODES(Round)DEFINE_OPCODES(Trunc)DEFINE_OPCODES (NearbyInt)DEFINE_OPCODES(GetIteratorCache)DEFINE_OPCODES(OptimizeSpreadCallCache )DEFINE_OPCODES(IteratorMore)DEFINE_OPCODES(IsNoIter)DEFINE_OPCODES (IteratorEnd)DEFINE_OPCODES(CloseIterCache)DEFINE_OPCODES(OptimizeGetIteratorCache )DEFINE_OPCODES(InCache)DEFINE_OPCODES(InArray)DEFINE_OPCODES (GuardElementNotHole)DEFINE_OPCODES(NewPrivateName)DEFINE_OPCODES (CheckPrivateFieldCache)DEFINE_OPCODES(HasOwnCache)DEFINE_OPCODES (InstanceOf)DEFINE_OPCODES(InstanceOfCache)DEFINE_OPCODES(ArgumentsLength )DEFINE_OPCODES(GetFrameArgument)DEFINE_OPCODES(GetFrameArgumentHole )DEFINE_OPCODES(NewTarget)DEFINE_OPCODES(Rest)DEFINE_OPCODES( PostWriteBarrier)DEFINE_OPCODES(PostWriteElementBarrier)DEFINE_OPCODES (AssertCanElidePostWriteBarrier)DEFINE_OPCODES(NewNamedLambdaObject )DEFINE_OPCODES(NewCallObject)DEFINE_OPCODES(NewStringObject) DEFINE_OPCODES(IsCallable)DEFINE_OPCODES(IsConstructor)DEFINE_OPCODES (IsCrossRealmArrayConstructor)DEFINE_OPCODES(IsObject)DEFINE_OPCODES (IsNullOrUndefined)DEFINE_OPCODES(HasClass)DEFINE_OPCODES(GuardToClass )DEFINE_OPCODES(GuardToEitherClass)DEFINE_OPCODES(GuardToFunction )DEFINE_OPCODES(IsArray)DEFINE_OPCODES(IsTypedArray)DEFINE_OPCODES (ObjectClassToString)DEFINE_OPCODES(CheckReturn)DEFINE_OPCODES (CheckThis)DEFINE_OPCODES(AsyncResolve)DEFINE_OPCODES(AsyncReject )DEFINE_OPCODES(GeneratorReturn)DEFINE_OPCODES(AsyncAwait)DEFINE_OPCODES (CheckThisReinit)DEFINE_OPCODES(Generator)DEFINE_OPCODES(CanSkipAwait )DEFINE_OPCODES(MaybeExtractAwaitValue)DEFINE_OPCODES(IncrementWarmUpCounter )DEFINE_OPCODES(AtomicIsLockFree)DEFINE_OPCODES(CompareExchangeTypedArrayElement )DEFINE_OPCODES(AtomicExchangeTypedArrayElement)DEFINE_OPCODES (AtomicTypedArrayElementBinop)DEFINE_OPCODES(Debugger)DEFINE_OPCODES (CheckIsObj)DEFINE_OPCODES(CheckObjCoercible)DEFINE_OPCODES(CheckClassHeritage )DEFINE_OPCODES(DebugCheckSelfHosted)DEFINE_OPCODES(IsPackedArray )DEFINE_OPCODES(GuardArrayIsPacked)DEFINE_OPCODES(GetPrototypeOf )DEFINE_OPCODES(ObjectWithProto)DEFINE_OPCODES(ObjectStaticProto )DEFINE_OPCODES(ConstantProto)DEFINE_OPCODES(BuiltinObject)DEFINE_OPCODES (SuperFunction)DEFINE_OPCODES(InitHomeObject)DEFINE_OPCODES(IsTypedArrayConstructor )DEFINE_OPCODES(LoadValueTag)DEFINE_OPCODES(LoadWrapperTarget )DEFINE_OPCODES(GuardHasGetterSetter)DEFINE_OPCODES(GuardIsExtensible )DEFINE_OPCODES(GuardInt32IsNonNegative)DEFINE_OPCODES(GuardInt32Range )DEFINE_OPCODES(GuardIndexIsNotDenseElement)DEFINE_OPCODES(GuardIndexIsValidUpdateOrAdd )DEFINE_OPCODES(CallAddOrUpdateSparseElement)DEFINE_OPCODES(CallGetSparseElement )DEFINE_OPCODES(CallNativeGetElement)DEFINE_OPCODES(CallNativeGetElementSuper )DEFINE_OPCODES(CallObjectHasSparseElement)DEFINE_OPCODES(BigIntAsIntN )DEFINE_OPCODES(BigIntAsUintN)DEFINE_OPCODES(GuardNonGCThing) DEFINE_OPCODES(ToHashableNonGCThing)DEFINE_OPCODES(ToHashableString )DEFINE_OPCODES(ToHashableValue)DEFINE_OPCODES(HashNonGCThing )DEFINE_OPCODES(HashString)DEFINE_OPCODES(HashSymbol)DEFINE_OPCODES (HashBigInt)DEFINE_OPCODES(HashObject)DEFINE_OPCODES(HashValue )DEFINE_OPCODES(SetObjectHasNonBigInt)DEFINE_OPCODES(SetObjectHasBigInt )DEFINE_OPCODES(SetObjectHasValue)DEFINE_OPCODES(SetObjectHasValueVMCall )DEFINE_OPCODES(SetObjectSize)DEFINE_OPCODES(MapObjectHasNonBigInt )DEFINE_OPCODES(MapObjectHasBigInt)DEFINE_OPCODES(MapObjectHasValue )DEFINE_OPCODES(MapObjectHasValueVMCall)DEFINE_OPCODES(MapObjectGetNonBigInt )DEFINE_OPCODES(MapObjectGetBigInt)DEFINE_OPCODES(MapObjectGetValue )DEFINE_OPCODES(MapObjectGetValueVMCall)DEFINE_OPCODES(MapObjectSize )DEFINE_OPCODES(PostIntPtrConversion)DEFINE_OPCODES(WasmNeg)DEFINE_OPCODES (WasmBinaryBitwise)DEFINE_OPCODES(WasmLoadInstance)DEFINE_OPCODES (WasmStoreInstance)DEFINE_OPCODES(WasmHeapReg)DEFINE_OPCODES( WasmBoundsCheck)DEFINE_OPCODES(WasmBoundsCheckRange32)DEFINE_OPCODES (WasmExtendU32Index)DEFINE_OPCODES(WasmWrapU32Index)DEFINE_OPCODES (WasmAddOffset)DEFINE_OPCODES(WasmAlignmentCheck)DEFINE_OPCODES (WasmLoad)DEFINE_OPCODES(WasmStore)DEFINE_OPCODES(AsmJSLoadHeap )DEFINE_OPCODES(AsmJSStoreHeap)DEFINE_OPCODES(WasmFence)DEFINE_OPCODES (WasmCompareExchangeHeap)DEFINE_OPCODES(WasmAtomicExchangeHeap )DEFINE_OPCODES(WasmAtomicBinopHeap)DEFINE_OPCODES(WasmLoadInstanceDataField )DEFINE_OPCODES(WasmLoadGlobalCell)DEFINE_OPCODES(WasmLoadTableElement )DEFINE_OPCODES(WasmStoreInstanceDataField)DEFINE_OPCODES(WasmStoreGlobalCell )DEFINE_OPCODES(WasmStoreStackResult)DEFINE_OPCODES(WasmDerivedPointer )DEFINE_OPCODES(WasmDerivedIndexPointer)DEFINE_OPCODES(WasmStoreRef )DEFINE_OPCODES(WasmPostWriteBarrierImmediate)DEFINE_OPCODES( WasmPostWriteBarrierIndex)DEFINE_OPCODES(WasmParameter)DEFINE_OPCODES (WasmReturn)DEFINE_OPCODES(WasmReturnVoid)DEFINE_OPCODES(WasmStackArg )DEFINE_OPCODES(WasmRegisterResult)DEFINE_OPCODES(WasmFloatRegisterResult )DEFINE_OPCODES(WasmRegister64Result)DEFINE_OPCODES(WasmStackResultArea )DEFINE_OPCODES(WasmStackResult)DEFINE_OPCODES(WasmCallCatchable )DEFINE_OPCODES(WasmCallUncatchable)DEFINE_OPCODES(WasmCallLandingPrePad )DEFINE_OPCODES(WasmReturnCall)DEFINE_OPCODES(WasmSelect)DEFINE_OPCODES (WasmReinterpret)DEFINE_OPCODES(Rotate)DEFINE_OPCODES(WasmStackSwitchToMain )DEFINE_OPCODES(WasmStackSwitchToSuspendable)DEFINE_OPCODES(WasmStackContinueOnSuspendable )DEFINE_OPCODES(WasmBinarySimd128)DEFINE_OPCODES(WasmBinarySimd128WithConstant )DEFINE_OPCODES(WasmShiftSimd128)DEFINE_OPCODES(WasmShuffleSimd128 )DEFINE_OPCODES(WasmReplaceLaneSimd128)DEFINE_OPCODES(WasmUnarySimd128 )DEFINE_OPCODES(WasmTernarySimd128)DEFINE_OPCODES(WasmScalarToSimd128 )DEFINE_OPCODES(WasmReduceSimd128)DEFINE_OPCODES(WasmLoadLaneSimd128 )DEFINE_OPCODES(WasmStoreLaneSimd128)DEFINE_OPCODES(UnreachableResult )DEFINE_OPCODES(IonToWasmCall)DEFINE_OPCODES(WasmLoadField)DEFINE_OPCODES (WasmLoadFieldKA)DEFINE_OPCODES(WasmLoadElementKA)DEFINE_OPCODES (WasmStoreFieldKA)DEFINE_OPCODES(WasmStoreFieldRefKA)DEFINE_OPCODES (WasmStoreElementKA)DEFINE_OPCODES(WasmStoreElementRefKA)DEFINE_OPCODES (WasmRefIsSubtypeOfConcrete)DEFINE_OPCODES(WasmRefIsSubtypeOfAbstract )DEFINE_OPCODES(WasmNewStructObject)DEFINE_OPCODES(WasmNewArrayObject ) |
| 508 | #undef DEFINE_OPCODES |
| 509 | }; |
| 510 | |
| 511 | private: |
| 512 | InlineList<MUse> uses_; // Use chain. |
| 513 | uint32_t id_; // Instruction ID, which after block re-ordering |
| 514 | // is sorted within a basic block. |
| 515 | Opcode op_; // Opcode. |
| 516 | uint16_t flags_; // Bit flags. |
| 517 | Range* range_; // Any computed range for this def. |
| 518 | union { |
| 519 | MDefinition* |
| 520 | loadDependency_; // Implicit dependency (store, call, etc.) of this |
| 521 | // instruction. Used by alias analysis, GVN and LICM. |
| 522 | uint32_t virtualRegister_; // Used by lowering to map definitions to |
| 523 | // virtual registers. |
| 524 | }; |
| 525 | |
| 526 | // Track bailouts by storing the current pc in MIR instruction. Also used |
| 527 | // for profiling and keeping track of what the last known pc was. |
| 528 | const BytecodeSite* trackedSite_; |
| 529 | |
| 530 | // If we generate a bailout path for this instruction, this is the |
| 531 | // bailout kind that will be encoded in the snapshot. When we bail out, |
| 532 | // FinishBailoutToBaseline may take action based on the bailout kind to |
| 533 | // prevent bailout loops. (For example, if an instruction bails out after |
| 534 | // being hoisted by LICM, we will disable LICM when recompiling the script.) |
| 535 | BailoutKind bailoutKind_; |
| 536 | |
| 537 | MIRType resultType_; // Representation of result type. |
| 538 | |
| 539 | private: |
| 540 | enum Flag { |
| 541 | None = 0, |
| 542 | #define DEFINE_FLAG(flag) flag, |
| 543 | MIR_FLAG_LIST(DEFINE_FLAG)DEFINE_FLAG(InWorklist) DEFINE_FLAG(EmittedAtUses) DEFINE_FLAG (Commutative) DEFINE_FLAG(Movable) DEFINE_FLAG(Lowered) DEFINE_FLAG (Guard) DEFINE_FLAG(GuardRangeBailouts) DEFINE_FLAG(ImplicitlyUsed ) DEFINE_FLAG(Unused) DEFINE_FLAG(RecoveredOnBailout) DEFINE_FLAG (IncompleteObject) DEFINE_FLAG(CallResultCapture) DEFINE_FLAG (Discarded) |
| 544 | #undef DEFINE_FLAG |
| 545 | Total |
| 546 | }; |
| 547 | |
| 548 | bool hasFlags(uint32_t flags) const { return (flags_ & flags) == flags; } |
| 549 | void removeFlags(uint32_t flags) { flags_ &= ~flags; } |
| 550 | void setFlags(uint32_t flags) { flags_ |= flags; } |
| 551 | |
| 552 | // Calling isDefinition or isResumePoint on MDefinition is unnecessary. |
| 553 | bool isDefinition() const = delete; |
| 554 | bool isResumePoint() const = delete; |
| 555 | |
| 556 | protected: |
| 557 | void setInstructionBlock(MBasicBlock* block, const BytecodeSite* site) { |
| 558 | MOZ_ASSERT(isInstruction())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isInstruction())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isInstruction()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isInstruction()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isInstruction()" ")"); do { *((volatile int*)__null) = 558; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 559 | setBlockAndKind(block, Kind::Definition); |
| 560 | setTrackedSite(site); |
| 561 | } |
| 562 | |
| 563 | void setPhiBlock(MBasicBlock* block) { |
| 564 | MOZ_ASSERT(isPhi())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isPhi())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isPhi()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isPhi()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 564); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isPhi()" ")" ); do { *((volatile int*)__null) = 564; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 565 | setBlockAndKind(block, Kind::Definition); |
| 566 | } |
| 567 | |
| 568 | static HashNumber addU32ToHash(HashNumber hash, uint32_t data) { |
| 569 | return data + (hash << 6) + (hash << 16) - hash; |
| 570 | } |
| 571 | |
| 572 | static HashNumber addU64ToHash(HashNumber hash, uint64_t data) { |
| 573 | hash = addU32ToHash(hash, uint32_t(data)); |
| 574 | hash = addU32ToHash(hash, uint32_t(data >> 32)); |
| 575 | return hash; |
| 576 | } |
| 577 | |
| 578 | public: |
| 579 | explicit MDefinition(Opcode op) |
| 580 | : MNode(nullptr, Kind::Definition), |
| 581 | id_(0), |
| 582 | op_(op), |
| 583 | flags_(0), |
| 584 | range_(nullptr), |
| 585 | loadDependency_(nullptr), |
| 586 | trackedSite_(nullptr), |
| 587 | bailoutKind_(BailoutKind::Unknown), |
| 588 | resultType_(MIRType::None) {} |
| 589 | |
| 590 | // Copying a definition leaves the list of uses empty. |
| 591 | explicit MDefinition(const MDefinition& other) |
| 592 | : MNode(other), |
| 593 | id_(0), |
| 594 | op_(other.op_), |
| 595 | flags_(other.flags_), |
| 596 | range_(other.range_), |
| 597 | loadDependency_(other.loadDependency_), |
| 598 | trackedSite_(other.trackedSite_), |
| 599 | bailoutKind_(other.bailoutKind_), |
| 600 | resultType_(other.resultType_) {} |
| 601 | |
| 602 | Opcode op() const { return op_; } |
| 603 | |
| 604 | #ifdef JS_JITSPEW1 |
| 605 | const char* opName() const; |
| 606 | void printName(GenericPrinter& out) const; |
| 607 | static void PrintOpcodeName(GenericPrinter& out, Opcode op); |
| 608 | virtual void printOpcode(GenericPrinter& out) const; |
| 609 | void dump(GenericPrinter& out) const override; |
| 610 | void dump() const override; |
| 611 | void dumpLocation(GenericPrinter& out) const; |
| 612 | void dumpLocation() const; |
| 613 | // Dump any other stuff the node wants to have printed in `extras`. The |
| 614 | // added strings are copied, with the `ExtrasCollector` taking ownership of |
| 615 | // the copies. |
| 616 | virtual void getExtras(ExtrasCollector* extras) {} |
| 617 | #endif |
| 618 | |
| 619 | // Also for LICM. Test whether this definition is likely to be a call, which |
| 620 | // would clobber all or many of the floating-point registers, such that |
| 621 | // hoisting floating-point constants out of containing loops isn't likely to |
| 622 | // be worthwhile. |
| 623 | virtual bool possiblyCalls() const { return false; } |
| 624 | |
| 625 | MBasicBlock* block() const { return definitionBlock(); } |
| 626 | |
| 627 | private: |
| 628 | void setTrackedSite(const BytecodeSite* site) { |
| 629 | MOZ_ASSERT(site)do { static_assert( mozilla::detail::AssertionConditionType< decltype(site)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(site))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("site", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 629); AnnotateMozCrashReason("MOZ_ASSERT" "(" "site" ")"); do { *((volatile int*)__null) = 629; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 630 | trackedSite_ = site; |
| 631 | } |
| 632 | |
| 633 | public: |
| 634 | const BytecodeSite* trackedSite() const { |
| 635 | MOZ_ASSERT(trackedSite_,do { static_assert( mozilla::detail::AssertionConditionType< decltype(trackedSite_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(trackedSite_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("trackedSite_" " (" "missing tracked bytecode site; node not assigned to a block?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 636); AnnotateMozCrashReason("MOZ_ASSERT" "(" "trackedSite_" ") (" "missing tracked bytecode site; node not assigned to a block?" ")"); do { *((volatile int*)__null) = 636; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 636 | "missing tracked bytecode site; node not assigned to a block?")do { static_assert( mozilla::detail::AssertionConditionType< decltype(trackedSite_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(trackedSite_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("trackedSite_" " (" "missing tracked bytecode site; node not assigned to a block?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 636); AnnotateMozCrashReason("MOZ_ASSERT" "(" "trackedSite_" ") (" "missing tracked bytecode site; node not assigned to a block?" ")"); do { *((volatile int*)__null) = 636; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 637 | return trackedSite_; |
| 638 | } |
| 639 | |
| 640 | BailoutKind bailoutKind() const { return bailoutKind_; } |
| 641 | void setBailoutKind(BailoutKind kind) { bailoutKind_ = kind; } |
| 642 | |
| 643 | // Return the range of this value, *before* any bailout checks. Contrast |
| 644 | // this with the type() method, and the Range constructor which takes an |
| 645 | // MDefinition*, which describe the value *after* any bailout checks. |
| 646 | // |
| 647 | // Warning: Range analysis is removing the bit-operations such as '| 0' at |
| 648 | // the end of the transformations. Using this function to analyse any |
| 649 | // operands after the truncate phase of the range analysis will lead to |
| 650 | // errors. Instead, one should define the collectRangeInfoPreTrunc() to set |
| 651 | // the right set of flags which are dependent on the range of the inputs. |
| 652 | Range* range() const { |
| 653 | MOZ_ASSERT(type() != MIRType::None)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() != MIRType::None)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() != MIRType::None))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("type() != MIRType::None" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 653); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() != MIRType::None" ")"); do { *((volatile int*)__null) = 653; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 654 | return range_; |
| 655 | } |
| 656 | void setRange(Range* range) { |
| 657 | MOZ_ASSERT(type() != MIRType::None)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() != MIRType::None)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() != MIRType::None))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("type() != MIRType::None" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() != MIRType::None" ")"); do { *((volatile int*)__null) = 657; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 658 | range_ = range; |
| 659 | } |
| 660 | |
| 661 | virtual HashNumber valueHash() const; |
| 662 | virtual bool congruentTo(const MDefinition* ins) const { return false; } |
| 663 | const MDefinition* skipObjectGuards() const; |
| 664 | |
| 665 | // Note that, for a call `congruentIfOperandsEqual(ins)` inside some class |
| 666 | // MFoo, if `true` is returned then we are ensured that `ins` is also an |
| 667 | // MFoo, so it is safe to do `ins->toMFoo()` without first checking whether |
| 668 | // `ins->isMFoo()`. |
| 669 | bool congruentIfOperandsEqual(const MDefinition* ins) const; |
| 670 | |
| 671 | virtual MDefinition* foldsTo(TempAllocator& alloc); |
| 672 | virtual void analyzeEdgeCasesForward(); |
| 673 | virtual void analyzeEdgeCasesBackward(); |
| 674 | |
| 675 | // |canTruncate| reports if this instruction supports truncation. If |
| 676 | // |canTruncate| function returns true, then the |truncate| function is |
| 677 | // called on the same instruction to mutate the instruction, such as updating |
| 678 | // the return type, the range and the specialization of the instruction. |
| 679 | virtual bool canTruncate() const; |
| 680 | virtual void truncate(TruncateKind kind); |
| 681 | |
| 682 | // Determine what kind of truncate this node prefers for the operand at the |
| 683 | // given index. |
| 684 | virtual TruncateKind operandTruncateKind(size_t index) const; |
| 685 | |
| 686 | // Compute an absolute or symbolic range for the value of this node. |
| 687 | virtual void computeRange(TempAllocator& alloc) {} |
| 688 | |
| 689 | // Collect information from the pre-truncated ranges. |
| 690 | virtual void collectRangeInfoPreTrunc() {} |
| 691 | |
| 692 | uint32_t id() const { |
| 693 | MOZ_ASSERT(block())do { static_assert( mozilla::detail::AssertionConditionType< decltype(block())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(block()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("block()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 693); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()" ")" ); do { *((volatile int*)__null) = 693; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 694 | return id_; |
| 695 | } |
| 696 | void setId(uint32_t id) { id_ = id; } |
| 697 | |
| 698 | #define FLAG_ACCESSOR(flag) \ |
| 699 | bool is##flag() const { \ |
| 700 | static_assert(Flag::Total <= sizeof(flags_) * 8, \ |
| 701 | "Flags should fit in flags_ field"); \ |
| 702 | return hasFlags(1 << flag); \ |
| 703 | } \ |
| 704 | void set##flag() { \ |
| 705 | MOZ_ASSERT(!hasFlags(1 << flag))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!hasFlags(1 << flag))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!hasFlags(1 << flag))) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!hasFlags(1 << flag)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 705); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!hasFlags(1 << flag)" ")"); do { *((volatile int*)__null) = 705; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); \ |
| 706 | setFlags(1 << flag); \ |
| 707 | } \ |
| 708 | void setNot##flag() { \ |
| 709 | MOZ_ASSERT(hasFlags(1 << flag))do { static_assert( mozilla::detail::AssertionConditionType< decltype(hasFlags(1 << flag))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hasFlags(1 << flag)))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("hasFlags(1 << flag)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 709); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hasFlags(1 << flag)" ")"); do { *((volatile int*)__null) = 709; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); \ |
| 710 | removeFlags(1 << flag); \ |
| 711 | } \ |
| 712 | void set##flag##Unchecked() { setFlags(1 << flag); } \ |
| 713 | void setNot##flag##Unchecked() { removeFlags(1 << flag); } |
| 714 | |
| 715 | MIR_FLAG_LIST(FLAG_ACCESSOR)FLAG_ACCESSOR(InWorklist) FLAG_ACCESSOR(EmittedAtUses) FLAG_ACCESSOR (Commutative) FLAG_ACCESSOR(Movable) FLAG_ACCESSOR(Lowered) FLAG_ACCESSOR (Guard) FLAG_ACCESSOR(GuardRangeBailouts) FLAG_ACCESSOR(ImplicitlyUsed ) FLAG_ACCESSOR(Unused) FLAG_ACCESSOR(RecoveredOnBailout) FLAG_ACCESSOR (IncompleteObject) FLAG_ACCESSOR(CallResultCapture) FLAG_ACCESSOR (Discarded) |
| 716 | #undef FLAG_ACCESSOR |
| 717 | |
| 718 | // Return the type of this value. This may be speculative, and enforced |
| 719 | // dynamically with the use of bailout checks. If all the bailout checks |
| 720 | // pass, the value will have this type. |
| 721 | // |
| 722 | // Unless this is an MUrsh that has bailouts disabled, which, as a special |
| 723 | // case, may return a value in (INT32_MAX,UINT32_MAX] even when its type() |
| 724 | // is MIRType::Int32. |
| 725 | MIRType type() const { return resultType_; } |
| 726 | |
| 727 | bool mightBeType(MIRType type) const { |
| 728 | MOZ_ASSERT(type != MIRType::Value)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type != MIRType::Value)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type != MIRType::Value))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("type != MIRType::Value" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 728); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type != MIRType::Value" ")"); do { *((volatile int*)__null) = 728; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 729 | |
| 730 | if (type == this->type()) { |
| 731 | return true; |
| 732 | } |
| 733 | |
| 734 | if (this->type() == MIRType::Value) { |
| 735 | return true; |
| 736 | } |
| 737 | |
| 738 | return false; |
| 739 | } |
| 740 | |
| 741 | bool mightBeMagicType() const; |
| 742 | |
| 743 | // Return true if the result-set types are a subset of the given types. |
| 744 | bool definitelyType(std::initializer_list<MIRType> types) const; |
| 745 | |
| 746 | // Float32 specialization operations (see big comment in IonAnalysis before |
| 747 | // the Float32 specialization algorithm). |
| 748 | virtual bool isFloat32Commutative() const { return false; } |
| 749 | virtual bool canProduceFloat32() const { return false; } |
| 750 | virtual bool canConsumeFloat32(MUse* use) const { return false; } |
| 751 | virtual void trySpecializeFloat32(TempAllocator& alloc) {} |
| 752 | #ifdef DEBUG1 |
| 753 | // Used during the pass that checks that Float32 flow into valid MDefinitions |
| 754 | virtual bool isConsistentFloat32Use(MUse* use) const { |
| 755 | return type() == MIRType::Float32 || canConsumeFloat32(use); |
| 756 | } |
| 757 | #endif |
| 758 | |
| 759 | // Returns the beginning of this definition's use chain. |
| 760 | MUseIterator usesBegin() const { return uses_.begin(); } |
| 761 | |
| 762 | // Returns the end of this definition's use chain. |
| 763 | MUseIterator usesEnd() const { return uses_.end(); } |
| 764 | |
| 765 | bool canEmitAtUses() const { return !isEmittedAtUses(); } |
| 766 | |
| 767 | // Removes a use at the given position |
| 768 | void removeUse(MUse* use) { uses_.remove(use); } |
| 769 | |
| 770 | #if defined(DEBUG1) || defined(JS_JITSPEW1) |
| 771 | // Number of uses of this instruction. This function is only available |
| 772 | // in DEBUG mode since it requires traversing the list. Most users should |
| 773 | // use hasUses() or hasOneUse() instead. |
| 774 | size_t useCount() const; |
| 775 | |
| 776 | // Number of uses of this instruction (only counting MDefinitions, ignoring |
| 777 | // MResumePoints). This function is only available in DEBUG mode since it |
| 778 | // requires traversing the list. Most users should use hasUses() or |
| 779 | // hasOneUse() instead. |
| 780 | size_t defUseCount() const; |
| 781 | #endif |
| 782 | |
| 783 | // Test whether this MDefinition has exactly one use. |
| 784 | bool hasOneUse() const; |
| 785 | |
| 786 | // Test whether this MDefinition has exactly one use. |
| 787 | // (only counting MDefinitions, ignoring MResumePoints) |
| 788 | bool hasOneDefUse() const; |
| 789 | |
| 790 | // Test whether this MDefinition has exactly one live use. (only counting |
| 791 | // MDefinitions which are not recovered on bailout and ignoring MResumePoints) |
| 792 | bool hasOneLiveDefUse() const; |
| 793 | |
| 794 | // Test whether this MDefinition has at least one use. |
| 795 | // (only counting MDefinitions, ignoring MResumePoints) |
| 796 | bool hasDefUses() const; |
| 797 | |
| 798 | // Test whether this MDefinition has at least one non-recovered use. |
| 799 | // (only counting MDefinitions, ignoring MResumePoints) |
| 800 | bool hasLiveDefUses() const; |
| 801 | |
| 802 | bool hasUses() const { return !uses_.empty(); } |
| 803 | |
| 804 | // If this MDefinition has a single use (ignoring MResumePoints), returns that |
| 805 | // use's definition. Else returns nullptr. |
| 806 | MDefinition* maybeSingleDefUse() const; |
| 807 | |
| 808 | // Returns the most recently added use (ignoring MResumePoints) for this |
| 809 | // MDefinition. Returns nullptr if there are no uses. Note that this relies on |
| 810 | // addUse adding new uses to the front of the list, and should only be called |
| 811 | // during MIR building (before optimization passes make changes to the uses). |
| 812 | MDefinition* maybeMostRecentlyAddedDefUse() const; |
| 813 | |
| 814 | void addUse(MUse* use) { |
| 815 | MOZ_ASSERT(use->producer() == this)do { static_assert( mozilla::detail::AssertionConditionType< decltype(use->producer() == this)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(use->producer() == this)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("use->producer() == this" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 815); AnnotateMozCrashReason("MOZ_ASSERT" "(" "use->producer() == this" ")"); do { *((volatile int*)__null) = 815; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 816 | uses_.pushFront(use); |
| 817 | } |
| 818 | void addUseUnchecked(MUse* use) { |
| 819 | MOZ_ASSERT(use->producer() == this)do { static_assert( mozilla::detail::AssertionConditionType< decltype(use->producer() == this)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(use->producer() == this)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("use->producer() == this" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 819); AnnotateMozCrashReason("MOZ_ASSERT" "(" "use->producer() == this" ")"); do { *((volatile int*)__null) = 819; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 820 | uses_.pushFrontUnchecked(use); |
| 821 | } |
| 822 | void replaceUse(MUse* old, MUse* now) { |
| 823 | MOZ_ASSERT(now->producer() == this)do { static_assert( mozilla::detail::AssertionConditionType< decltype(now->producer() == this)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(now->producer() == this)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("now->producer() == this" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 823); AnnotateMozCrashReason("MOZ_ASSERT" "(" "now->producer() == this" ")"); do { *((volatile int*)__null) = 823; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 824 | uses_.replace(old, now); |
| 825 | } |
| 826 | |
| 827 | // Replace the current instruction by a dominating instruction |dom| in all |
| 828 | // uses of the current instruction. |
| 829 | void replaceAllUsesWith(MDefinition* dom); |
| 830 | |
| 831 | // Like replaceAllUsesWith, but doesn't set ImplicitlyUsed on |this|'s |
| 832 | // operands. |
| 833 | void justReplaceAllUsesWith(MDefinition* dom); |
| 834 | |
| 835 | // Replace the current instruction by an optimized-out constant in all uses |
| 836 | // of the current instruction. Note, that optimized-out constant should not |
| 837 | // be observed, and thus they should not flow in any computation. |
| 838 | [[nodiscard]] bool optimizeOutAllUses(TempAllocator& alloc); |
| 839 | |
| 840 | // Replace the current instruction by a dominating instruction |dom| in all |
| 841 | // instruction, but keep the current instruction for resume point and |
| 842 | // instruction which are recovered on bailouts. |
| 843 | void replaceAllLiveUsesWith(MDefinition* dom); |
| 844 | |
| 845 | void setVirtualRegister(uint32_t vreg) { |
| 846 | virtualRegister_ = vreg; |
| 847 | setLoweredUnchecked(); |
| 848 | } |
| 849 | uint32_t virtualRegister() const { |
| 850 | MOZ_ASSERT(isLowered())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isLowered())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isLowered()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isLowered()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 850); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isLowered()" ")"); do { *((volatile int*)__null) = 850; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 851 | return virtualRegister_; |
| 852 | } |
| 853 | |
| 854 | public: |
| 855 | // Opcode testing and casts. |
| 856 | template <typename MIRType> |
| 857 | bool is() const { |
| 858 | return op() == MIRType::classOpcode; |
| 859 | } |
| 860 | template <typename MIRType> |
| 861 | MIRType* to() { |
| 862 | MOZ_ASSERT(this->is<MIRType>())do { static_assert( mozilla::detail::AssertionConditionType< decltype(this->is<MIRType>())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(this->is<MIRType>() ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "this->is<MIRType>()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this->is<MIRType>()" ")"); do { *((volatile int*)__null) = 862; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 863 | return static_cast<MIRType*>(this); |
| 864 | } |
| 865 | template <typename MIRType> |
| 866 | const MIRType* to() const { |
| 867 | MOZ_ASSERT(this->is<MIRType>())do { static_assert( mozilla::detail::AssertionConditionType< decltype(this->is<MIRType>())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(this->is<MIRType>() ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "this->is<MIRType>()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 867); AnnotateMozCrashReason("MOZ_ASSERT" "(" "this->is<MIRType>()" ")"); do { *((volatile int*)__null) = 867; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 868 | return static_cast<const MIRType*>(this); |
| 869 | } |
| 870 | #define OPCODE_CASTS(opcode) \ |
| 871 | bool is##opcode() const { return this->is<M##opcode>(); } \ |
| 872 | M##opcode* to##opcode() { return this->to<M##opcode>(); } \ |
| 873 | const M##opcode* to##opcode() const { return this->to<M##opcode>(); } |
| 874 | MIR_OPCODE_LIST(OPCODE_CASTS)OPCODE_CASTS(Start)OPCODE_CASTS(OsrEntry)OPCODE_CASTS(Nop)OPCODE_CASTS (LimitedTruncate)OPCODE_CASTS(Constant)OPCODE_CASTS(WasmNullConstant )OPCODE_CASTS(WasmFloatConstant)OPCODE_CASTS(Parameter)OPCODE_CASTS (Callee)OPCODE_CASTS(IsConstructing)OPCODE_CASTS(TableSwitch) OPCODE_CASTS(Goto)OPCODE_CASTS(Test)OPCODE_CASTS(Return)OPCODE_CASTS (Throw)OPCODE_CASTS(ThrowWithStack)OPCODE_CASTS(NewArray)OPCODE_CASTS (NewArrayDynamicLength)OPCODE_CASTS(NewTypedArray)OPCODE_CASTS (NewTypedArrayDynamicLength)OPCODE_CASTS(NewTypedArrayFromArray )OPCODE_CASTS(NewTypedArrayFromArrayBuffer)OPCODE_CASTS(NewObject )OPCODE_CASTS(NewPlainObject)OPCODE_CASTS(NewArrayObject)OPCODE_CASTS (NewIterator)OPCODE_CASTS(ObjectState)OPCODE_CASTS(ArrayState )OPCODE_CASTS(BindFunction)OPCODE_CASTS(NewBoundFunction)OPCODE_CASTS (BoundFunctionNumArgs)OPCODE_CASTS(GuardBoundFunctionIsConstructor )OPCODE_CASTS(MutateProto)OPCODE_CASTS(InitPropGetterSetter)OPCODE_CASTS (InitElemGetterSetter)OPCODE_CASTS(Call)OPCODE_CASTS(CallClassHook )OPCODE_CASTS(ApplyArgs)OPCODE_CASTS(ApplyArgsObj)OPCODE_CASTS (ApplyArray)OPCODE_CASTS(ConstructArgs)OPCODE_CASTS(ConstructArray )OPCODE_CASTS(Bail)OPCODE_CASTS(Unreachable)OPCODE_CASTS(EncodeSnapshot )OPCODE_CASTS(AssertRecoveredOnBailout)OPCODE_CASTS(AssertFloat32 )OPCODE_CASTS(Compare)OPCODE_CASTS(SameValueDouble)OPCODE_CASTS (SameValue)OPCODE_CASTS(Box)OPCODE_CASTS(Unbox)OPCODE_CASTS(AssertRange )OPCODE_CASTS(AssertClass)OPCODE_CASTS(AssertShape)OPCODE_CASTS (CreateThis)OPCODE_CASTS(CreateArgumentsObject)OPCODE_CASTS(CreateInlinedArgumentsObject )OPCODE_CASTS(GetInlinedArgument)OPCODE_CASTS(GetInlinedArgumentHole )OPCODE_CASTS(GetArgumentsObjectArg)OPCODE_CASTS(SetArgumentsObjectArg )OPCODE_CASTS(LoadArgumentsObjectArg)OPCODE_CASTS(LoadArgumentsObjectArgHole )OPCODE_CASTS(InArgumentsObjectArg)OPCODE_CASTS(ArgumentsObjectLength )OPCODE_CASTS(ArrayFromArgumentsObject)OPCODE_CASTS(GuardArgumentsObjectFlags )OPCODE_CASTS(LoadScriptedProxyHandler)OPCODE_CASTS(CheckScriptedProxyGetResult )OPCODE_CASTS(IdToStringOrSymbol)OPCODE_CASTS(ReturnFromCtor) OPCODE_CASTS(ToDouble)OPCODE_CASTS(ToFloat32)OPCODE_CASTS(WasmUnsignedToDouble )OPCODE_CASTS(WasmUnsignedToFloat32)OPCODE_CASTS(WrapInt64ToInt32 )OPCODE_CASTS(ExtendInt32ToInt64)OPCODE_CASTS(WasmBuiltinTruncateToInt64 )OPCODE_CASTS(WasmTruncateToInt64)OPCODE_CASTS(WasmTruncateToInt32 )OPCODE_CASTS(WasmAnyRefFromJSValue)OPCODE_CASTS(WasmAnyRefFromJSObject )OPCODE_CASTS(WasmAnyRefFromJSString)OPCODE_CASTS(WasmNewI31Ref )OPCODE_CASTS(WasmI31RefGet)OPCODE_CASTS(Int32ToIntPtr)OPCODE_CASTS (NonNegativeIntPtrToInt32)OPCODE_CASTS(IntPtrToDouble)OPCODE_CASTS (AdjustDataViewLength)OPCODE_CASTS(Int64ToFloatingPoint)OPCODE_CASTS (BuiltinInt64ToFloatingPoint)OPCODE_CASTS(ToNumberInt32)OPCODE_CASTS (BooleanToInt32)OPCODE_CASTS(TruncateToInt32)OPCODE_CASTS(WasmBuiltinTruncateToInt32 )OPCODE_CASTS(ToBigInt)OPCODE_CASTS(ToInt64)OPCODE_CASTS(TruncateBigIntToInt64 )OPCODE_CASTS(Int64ToBigInt)OPCODE_CASTS(ToString)OPCODE_CASTS (BitNot)OPCODE_CASTS(TypeOf)OPCODE_CASTS(TypeOfName)OPCODE_CASTS (TypeOfIs)OPCODE_CASTS(ToAsyncIter)OPCODE_CASTS(ToPropertyKeyCache )OPCODE_CASTS(BitAnd)OPCODE_CASTS(BitOr)OPCODE_CASTS(BitXor)OPCODE_CASTS (Lsh)OPCODE_CASTS(Rsh)OPCODE_CASTS(Ursh)OPCODE_CASTS(SignExtendInt32 )OPCODE_CASTS(SignExtendInt64)OPCODE_CASTS(MinMax)OPCODE_CASTS (MinMaxArray)OPCODE_CASTS(Abs)OPCODE_CASTS(Clz)OPCODE_CASTS(Ctz )OPCODE_CASTS(Popcnt)OPCODE_CASTS(Sqrt)OPCODE_CASTS(CopySign) OPCODE_CASTS(Atan2)OPCODE_CASTS(Hypot)OPCODE_CASTS(Pow)OPCODE_CASTS (PowHalf)OPCODE_CASTS(Random)OPCODE_CASTS(Sign)OPCODE_CASTS(MathFunction )OPCODE_CASTS(Add)OPCODE_CASTS(Sub)OPCODE_CASTS(Mul)OPCODE_CASTS (Div)OPCODE_CASTS(WasmBuiltinDivI64)OPCODE_CASTS(Mod)OPCODE_CASTS (WasmBuiltinModD)OPCODE_CASTS(WasmBuiltinModI64)OPCODE_CASTS( BigIntAdd)OPCODE_CASTS(BigIntSub)OPCODE_CASTS(BigIntMul)OPCODE_CASTS (BigIntDiv)OPCODE_CASTS(BigIntMod)OPCODE_CASTS(BigIntPow)OPCODE_CASTS (BigIntBitAnd)OPCODE_CASTS(BigIntBitOr)OPCODE_CASTS(BigIntBitXor )OPCODE_CASTS(BigIntLsh)OPCODE_CASTS(BigIntRsh)OPCODE_CASTS(BigIntIncrement )OPCODE_CASTS(BigIntDecrement)OPCODE_CASTS(BigIntNegate)OPCODE_CASTS (BigIntBitNot)OPCODE_CASTS(Int32ToStringWithBase)OPCODE_CASTS (NumberParseInt)OPCODE_CASTS(DoubleParseInt)OPCODE_CASTS(Concat )OPCODE_CASTS(LinearizeString)OPCODE_CASTS(LinearizeForCharAccess )OPCODE_CASTS(LinearizeForCodePointAccess)OPCODE_CASTS(ToRelativeStringIndex )OPCODE_CASTS(CharCodeAt)OPCODE_CASTS(CharCodeAtOrNegative)OPCODE_CASTS (CodePointAt)OPCODE_CASTS(CodePointAtOrNegative)OPCODE_CASTS( NegativeToNaN)OPCODE_CASTS(NegativeToUndefined)OPCODE_CASTS(FromCharCode )OPCODE_CASTS(FromCharCodeEmptyIfNegative)OPCODE_CASTS(FromCharCodeUndefinedIfNegative )OPCODE_CASTS(FromCodePoint)OPCODE_CASTS(StringIncludes)OPCODE_CASTS (StringIndexOf)OPCODE_CASTS(StringLastIndexOf)OPCODE_CASTS(StringStartsWith )OPCODE_CASTS(StringEndsWith)OPCODE_CASTS(StringConvertCase)OPCODE_CASTS (CharCodeConvertCase)OPCODE_CASTS(StringTrimStartIndex)OPCODE_CASTS (StringTrimEndIndex)OPCODE_CASTS(StringSplit)OPCODE_CASTS(BoxNonStrictThis )OPCODE_CASTS(ImplicitThis)OPCODE_CASTS(Phi)OPCODE_CASTS(Beta )OPCODE_CASTS(NaNToZero)OPCODE_CASTS(OsrValue)OPCODE_CASTS(OsrEnvironmentChain )OPCODE_CASTS(OsrArgumentsObject)OPCODE_CASTS(OsrReturnValue) OPCODE_CASTS(BinaryCache)OPCODE_CASTS(UnaryCache)OPCODE_CASTS (CheckOverRecursed)OPCODE_CASTS(InterruptCheck)OPCODE_CASTS(WasmInterruptCheck )OPCODE_CASTS(WasmTrap)OPCODE_CASTS(WasmTrapIfNull)OPCODE_CASTS (LexicalCheck)OPCODE_CASTS(ThrowRuntimeLexicalError)OPCODE_CASTS (ThrowMsg)OPCODE_CASTS(GlobalDeclInstantiation)OPCODE_CASTS(RegExp )OPCODE_CASTS(RegExpMatcher)OPCODE_CASTS(RegExpSearcher)OPCODE_CASTS (RegExpSearcherLastLimit)OPCODE_CASTS(RegExpExecMatch)OPCODE_CASTS (RegExpExecTest)OPCODE_CASTS(RegExpHasCaptureGroups)OPCODE_CASTS (RegExpPrototypeOptimizable)OPCODE_CASTS(RegExpInstanceOptimizable )OPCODE_CASTS(GetFirstDollarIndex)OPCODE_CASTS(StringReplace) OPCODE_CASTS(Substr)OPCODE_CASTS(ModuleMetadata)OPCODE_CASTS( DynamicImport)OPCODE_CASTS(Lambda)OPCODE_CASTS(FunctionWithProto )OPCODE_CASTS(SetFunName)OPCODE_CASTS(Slots)OPCODE_CASTS(Elements )OPCODE_CASTS(InitializedLength)OPCODE_CASTS(SetInitializedLength )OPCODE_CASTS(ArrayLength)OPCODE_CASTS(SetArrayLength)OPCODE_CASTS (FunctionLength)OPCODE_CASTS(FunctionName)OPCODE_CASTS(GetNextEntryForIterator )OPCODE_CASTS(ArrayBufferByteLength)OPCODE_CASTS(ArrayBufferViewLength )OPCODE_CASTS(ArrayBufferViewByteOffset)OPCODE_CASTS(ArrayBufferViewElements )OPCODE_CASTS(ResizableTypedArrayByteOffsetMaybeOutOfBounds)OPCODE_CASTS (ResizableTypedArrayLength)OPCODE_CASTS(ResizableDataViewByteLength )OPCODE_CASTS(GrowableSharedArrayBufferByteLength)OPCODE_CASTS (TypedArrayElementSize)OPCODE_CASTS(GuardHasAttachedArrayBuffer )OPCODE_CASTS(GuardResizableArrayBufferViewInBounds)OPCODE_CASTS (GuardResizableArrayBufferViewInBoundsOrDetached)OPCODE_CASTS (GuardNumberToIntPtrIndex)OPCODE_CASTS(KeepAliveObject)OPCODE_CASTS (DebugEnterGCUnsafeRegion)OPCODE_CASTS(DebugLeaveGCUnsafeRegion )OPCODE_CASTS(Not)OPCODE_CASTS(BoundsCheck)OPCODE_CASTS(BoundsCheckLower )OPCODE_CASTS(SpectreMaskIndex)OPCODE_CASTS(LoadElement)OPCODE_CASTS (LoadElementAndUnbox)OPCODE_CASTS(LoadElementHole)OPCODE_CASTS (StoreElement)OPCODE_CASTS(StoreHoleValueElement)OPCODE_CASTS (StoreElementHole)OPCODE_CASTS(ArrayPopShift)OPCODE_CASTS(ArrayPush )OPCODE_CASTS(ArraySlice)OPCODE_CASTS(ArgumentsSlice)OPCODE_CASTS (FrameArgumentsSlice)OPCODE_CASTS(InlineArgumentsSlice)OPCODE_CASTS (NormalizeSliceTerm)OPCODE_CASTS(ArrayJoin)OPCODE_CASTS(ObjectKeys )OPCODE_CASTS(ObjectKeysLength)OPCODE_CASTS(LoadUnboxedScalar )OPCODE_CASTS(LoadDataViewElement)OPCODE_CASTS(LoadTypedArrayElementHole )OPCODE_CASTS(StoreUnboxedScalar)OPCODE_CASTS(StoreDataViewElement )OPCODE_CASTS(StoreTypedArrayElementHole)OPCODE_CASTS(EffectiveAddress )OPCODE_CASTS(ClampToUint8)OPCODE_CASTS(LoadFixedSlot)OPCODE_CASTS (LoadFixedSlotAndUnbox)OPCODE_CASTS(LoadDynamicSlotAndUnbox)OPCODE_CASTS (StoreFixedSlot)OPCODE_CASTS(GetPropertyCache)OPCODE_CASTS(HomeObjectSuperBase )OPCODE_CASTS(GetPropSuperCache)OPCODE_CASTS(BindNameCache)OPCODE_CASTS (CallBindVar)OPCODE_CASTS(GuardShape)OPCODE_CASTS(GuardFuse)OPCODE_CASTS (GuardMultipleShapes)OPCODE_CASTS(GuardProto)OPCODE_CASTS(GuardNullProto )OPCODE_CASTS(GuardIsNativeObject)OPCODE_CASTS(GuardGlobalGeneration )OPCODE_CASTS(GuardIsProxy)OPCODE_CASTS(GuardIsNotDOMProxy)OPCODE_CASTS (GuardIsNotProxy)OPCODE_CASTS(ProxyGet)OPCODE_CASTS(ProxyGetByValue )OPCODE_CASTS(ProxyHasProp)OPCODE_CASTS(ProxySet)OPCODE_CASTS (ProxySetByValue)OPCODE_CASTS(CallSetArrayLength)OPCODE_CASTS (MegamorphicLoadSlot)OPCODE_CASTS(MegamorphicLoadSlotByValue) OPCODE_CASTS(MegamorphicStoreSlot)OPCODE_CASTS(MegamorphicHasProp )OPCODE_CASTS(SmallObjectVariableKeyHasProp)OPCODE_CASTS(GuardIsNotArrayBufferMaybeShared )OPCODE_CASTS(GuardIsTypedArray)OPCODE_CASTS(GuardIsFixedLengthTypedArray )OPCODE_CASTS(GuardIsResizableTypedArray)OPCODE_CASTS(GuardHasProxyHandler )OPCODE_CASTS(NurseryObject)OPCODE_CASTS(GuardValue)OPCODE_CASTS (GuardNullOrUndefined)OPCODE_CASTS(GuardIsNotObject)OPCODE_CASTS (GuardFunctionFlags)OPCODE_CASTS(GuardFunctionIsNonBuiltinCtor )OPCODE_CASTS(GuardFunctionKind)OPCODE_CASTS(GuardFunctionScript )OPCODE_CASTS(GuardObjectIdentity)OPCODE_CASTS(GuardSpecificFunction )OPCODE_CASTS(GuardSpecificAtom)OPCODE_CASTS(GuardSpecificSymbol )OPCODE_CASTS(GuardSpecificInt32)OPCODE_CASTS(GuardStringToIndex )OPCODE_CASTS(GuardStringToInt32)OPCODE_CASTS(GuardStringToDouble )OPCODE_CASTS(GuardNoDenseElements)OPCODE_CASTS(GuardTagNotEqual )OPCODE_CASTS(LoadDynamicSlot)OPCODE_CASTS(FunctionEnvironment )OPCODE_CASTS(NewLexicalEnvironmentObject)OPCODE_CASTS(NewClassBodyEnvironmentObject )OPCODE_CASTS(NewVarEnvironmentObject)OPCODE_CASTS(HomeObject )OPCODE_CASTS(AddAndStoreSlot)OPCODE_CASTS(AllocateAndStoreSlot )OPCODE_CASTS(AddSlotAndCallAddPropHook)OPCODE_CASTS(StoreDynamicSlot )OPCODE_CASTS(GetNameCache)OPCODE_CASTS(CallGetIntrinsicValue )OPCODE_CASTS(DeleteProperty)OPCODE_CASTS(DeleteElement)OPCODE_CASTS (SetPropertyCache)OPCODE_CASTS(MegamorphicSetElement)OPCODE_CASTS (SetDOMProperty)OPCODE_CASTS(GetDOMProperty)OPCODE_CASTS(GetDOMMember )OPCODE_CASTS(ObjectToIterator)OPCODE_CASTS(ValueToIterator)OPCODE_CASTS (IteratorHasIndices)OPCODE_CASTS(LoadSlotByIteratorIndex)OPCODE_CASTS (StoreSlotByIteratorIndex)OPCODE_CASTS(LoadDOMExpandoValue)OPCODE_CASTS (LoadDOMExpandoValueGuardGeneration)OPCODE_CASTS(LoadDOMExpandoValueIgnoreGeneration )OPCODE_CASTS(GuardDOMExpandoMissingOrGuardShape)OPCODE_CASTS (StringLength)OPCODE_CASTS(Floor)OPCODE_CASTS(Ceil)OPCODE_CASTS (Round)OPCODE_CASTS(Trunc)OPCODE_CASTS(NearbyInt)OPCODE_CASTS (GetIteratorCache)OPCODE_CASTS(OptimizeSpreadCallCache)OPCODE_CASTS (IteratorMore)OPCODE_CASTS(IsNoIter)OPCODE_CASTS(IteratorEnd) OPCODE_CASTS(CloseIterCache)OPCODE_CASTS(OptimizeGetIteratorCache )OPCODE_CASTS(InCache)OPCODE_CASTS(InArray)OPCODE_CASTS(GuardElementNotHole )OPCODE_CASTS(NewPrivateName)OPCODE_CASTS(CheckPrivateFieldCache )OPCODE_CASTS(HasOwnCache)OPCODE_CASTS(InstanceOf)OPCODE_CASTS (InstanceOfCache)OPCODE_CASTS(ArgumentsLength)OPCODE_CASTS(GetFrameArgument )OPCODE_CASTS(GetFrameArgumentHole)OPCODE_CASTS(NewTarget)OPCODE_CASTS (Rest)OPCODE_CASTS(PostWriteBarrier)OPCODE_CASTS(PostWriteElementBarrier )OPCODE_CASTS(AssertCanElidePostWriteBarrier)OPCODE_CASTS(NewNamedLambdaObject )OPCODE_CASTS(NewCallObject)OPCODE_CASTS(NewStringObject)OPCODE_CASTS (IsCallable)OPCODE_CASTS(IsConstructor)OPCODE_CASTS(IsCrossRealmArrayConstructor )OPCODE_CASTS(IsObject)OPCODE_CASTS(IsNullOrUndefined)OPCODE_CASTS (HasClass)OPCODE_CASTS(GuardToClass)OPCODE_CASTS(GuardToEitherClass )OPCODE_CASTS(GuardToFunction)OPCODE_CASTS(IsArray)OPCODE_CASTS (IsTypedArray)OPCODE_CASTS(ObjectClassToString)OPCODE_CASTS(CheckReturn )OPCODE_CASTS(CheckThis)OPCODE_CASTS(AsyncResolve)OPCODE_CASTS (AsyncReject)OPCODE_CASTS(GeneratorReturn)OPCODE_CASTS(AsyncAwait )OPCODE_CASTS(CheckThisReinit)OPCODE_CASTS(Generator)OPCODE_CASTS (CanSkipAwait)OPCODE_CASTS(MaybeExtractAwaitValue)OPCODE_CASTS (IncrementWarmUpCounter)OPCODE_CASTS(AtomicIsLockFree)OPCODE_CASTS (CompareExchangeTypedArrayElement)OPCODE_CASTS(AtomicExchangeTypedArrayElement )OPCODE_CASTS(AtomicTypedArrayElementBinop)OPCODE_CASTS(Debugger )OPCODE_CASTS(CheckIsObj)OPCODE_CASTS(CheckObjCoercible)OPCODE_CASTS (CheckClassHeritage)OPCODE_CASTS(DebugCheckSelfHosted)OPCODE_CASTS (IsPackedArray)OPCODE_CASTS(GuardArrayIsPacked)OPCODE_CASTS(GetPrototypeOf )OPCODE_CASTS(ObjectWithProto)OPCODE_CASTS(ObjectStaticProto) OPCODE_CASTS(ConstantProto)OPCODE_CASTS(BuiltinObject)OPCODE_CASTS (SuperFunction)OPCODE_CASTS(InitHomeObject)OPCODE_CASTS(IsTypedArrayConstructor )OPCODE_CASTS(LoadValueTag)OPCODE_CASTS(LoadWrapperTarget)OPCODE_CASTS (GuardHasGetterSetter)OPCODE_CASTS(GuardIsExtensible)OPCODE_CASTS (GuardInt32IsNonNegative)OPCODE_CASTS(GuardInt32Range)OPCODE_CASTS (GuardIndexIsNotDenseElement)OPCODE_CASTS(GuardIndexIsValidUpdateOrAdd )OPCODE_CASTS(CallAddOrUpdateSparseElement)OPCODE_CASTS(CallGetSparseElement )OPCODE_CASTS(CallNativeGetElement)OPCODE_CASTS(CallNativeGetElementSuper )OPCODE_CASTS(CallObjectHasSparseElement)OPCODE_CASTS(BigIntAsIntN )OPCODE_CASTS(BigIntAsUintN)OPCODE_CASTS(GuardNonGCThing)OPCODE_CASTS (ToHashableNonGCThing)OPCODE_CASTS(ToHashableString)OPCODE_CASTS (ToHashableValue)OPCODE_CASTS(HashNonGCThing)OPCODE_CASTS(HashString )OPCODE_CASTS(HashSymbol)OPCODE_CASTS(HashBigInt)OPCODE_CASTS (HashObject)OPCODE_CASTS(HashValue)OPCODE_CASTS(SetObjectHasNonBigInt )OPCODE_CASTS(SetObjectHasBigInt)OPCODE_CASTS(SetObjectHasValue )OPCODE_CASTS(SetObjectHasValueVMCall)OPCODE_CASTS(SetObjectSize )OPCODE_CASTS(MapObjectHasNonBigInt)OPCODE_CASTS(MapObjectHasBigInt )OPCODE_CASTS(MapObjectHasValue)OPCODE_CASTS(MapObjectHasValueVMCall )OPCODE_CASTS(MapObjectGetNonBigInt)OPCODE_CASTS(MapObjectGetBigInt )OPCODE_CASTS(MapObjectGetValue)OPCODE_CASTS(MapObjectGetValueVMCall )OPCODE_CASTS(MapObjectSize)OPCODE_CASTS(PostIntPtrConversion )OPCODE_CASTS(WasmNeg)OPCODE_CASTS(WasmBinaryBitwise)OPCODE_CASTS (WasmLoadInstance)OPCODE_CASTS(WasmStoreInstance)OPCODE_CASTS (WasmHeapReg)OPCODE_CASTS(WasmBoundsCheck)OPCODE_CASTS(WasmBoundsCheckRange32 )OPCODE_CASTS(WasmExtendU32Index)OPCODE_CASTS(WasmWrapU32Index )OPCODE_CASTS(WasmAddOffset)OPCODE_CASTS(WasmAlignmentCheck)OPCODE_CASTS (WasmLoad)OPCODE_CASTS(WasmStore)OPCODE_CASTS(AsmJSLoadHeap)OPCODE_CASTS (AsmJSStoreHeap)OPCODE_CASTS(WasmFence)OPCODE_CASTS(WasmCompareExchangeHeap )OPCODE_CASTS(WasmAtomicExchangeHeap)OPCODE_CASTS(WasmAtomicBinopHeap )OPCODE_CASTS(WasmLoadInstanceDataField)OPCODE_CASTS(WasmLoadGlobalCell )OPCODE_CASTS(WasmLoadTableElement)OPCODE_CASTS(WasmStoreInstanceDataField )OPCODE_CASTS(WasmStoreGlobalCell)OPCODE_CASTS(WasmStoreStackResult )OPCODE_CASTS(WasmDerivedPointer)OPCODE_CASTS(WasmDerivedIndexPointer )OPCODE_CASTS(WasmStoreRef)OPCODE_CASTS(WasmPostWriteBarrierImmediate )OPCODE_CASTS(WasmPostWriteBarrierIndex)OPCODE_CASTS(WasmParameter )OPCODE_CASTS(WasmReturn)OPCODE_CASTS(WasmReturnVoid)OPCODE_CASTS (WasmStackArg)OPCODE_CASTS(WasmRegisterResult)OPCODE_CASTS(WasmFloatRegisterResult )OPCODE_CASTS(WasmRegister64Result)OPCODE_CASTS(WasmStackResultArea )OPCODE_CASTS(WasmStackResult)OPCODE_CASTS(WasmCallCatchable) OPCODE_CASTS(WasmCallUncatchable)OPCODE_CASTS(WasmCallLandingPrePad )OPCODE_CASTS(WasmReturnCall)OPCODE_CASTS(WasmSelect)OPCODE_CASTS (WasmReinterpret)OPCODE_CASTS(Rotate)OPCODE_CASTS(WasmStackSwitchToMain )OPCODE_CASTS(WasmStackSwitchToSuspendable)OPCODE_CASTS(WasmStackContinueOnSuspendable )OPCODE_CASTS(WasmBinarySimd128)OPCODE_CASTS(WasmBinarySimd128WithConstant )OPCODE_CASTS(WasmShiftSimd128)OPCODE_CASTS(WasmShuffleSimd128 )OPCODE_CASTS(WasmReplaceLaneSimd128)OPCODE_CASTS(WasmUnarySimd128 )OPCODE_CASTS(WasmTernarySimd128)OPCODE_CASTS(WasmScalarToSimd128 )OPCODE_CASTS(WasmReduceSimd128)OPCODE_CASTS(WasmLoadLaneSimd128 )OPCODE_CASTS(WasmStoreLaneSimd128)OPCODE_CASTS(UnreachableResult )OPCODE_CASTS(IonToWasmCall)OPCODE_CASTS(WasmLoadField)OPCODE_CASTS (WasmLoadFieldKA)OPCODE_CASTS(WasmLoadElementKA)OPCODE_CASTS( WasmStoreFieldKA)OPCODE_CASTS(WasmStoreFieldRefKA)OPCODE_CASTS (WasmStoreElementKA)OPCODE_CASTS(WasmStoreElementRefKA)OPCODE_CASTS (WasmRefIsSubtypeOfConcrete)OPCODE_CASTS(WasmRefIsSubtypeOfAbstract )OPCODE_CASTS(WasmNewStructObject)OPCODE_CASTS(WasmNewArrayObject ) |
| 875 | #undef OPCODE_CASTS |
| 876 | |
| 877 | inline MConstant* maybeConstantValue(); |
| 878 | |
| 879 | inline MInstruction* toInstruction(); |
| 880 | inline const MInstruction* toInstruction() const; |
| 881 | bool isInstruction() const { return !isPhi(); } |
| 882 | |
| 883 | virtual bool isControlInstruction() const { return false; } |
| 884 | inline MControlInstruction* toControlInstruction(); |
| 885 | |
| 886 | void setResultType(MIRType type) { resultType_ = type; } |
| 887 | virtual AliasSet getAliasSet() const { |
| 888 | // Instructions are effectful by default. |
| 889 | return AliasSet::Store(AliasSet::Any); |
| 890 | } |
| 891 | |
| 892 | #ifdef DEBUG1 |
| 893 | bool hasDefaultAliasSet() const { |
| 894 | AliasSet set = getAliasSet(); |
| 895 | return set.isStore() && set.flags() == AliasSet::Flag::Any; |
| 896 | } |
| 897 | #endif |
| 898 | |
| 899 | MDefinition* dependency() const { |
| 900 | if (getAliasSet().isStore()) { |
| 901 | return nullptr; |
| 902 | } |
| 903 | return loadDependency_; |
| 904 | } |
| 905 | void setDependency(MDefinition* dependency) { |
| 906 | MOZ_ASSERT(!getAliasSet().isStore())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!getAliasSet().isStore())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!getAliasSet().isStore()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!getAliasSet().isStore()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 906); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!getAliasSet().isStore()" ")"); do { *((volatile int*)__null) = 906; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 907 | loadDependency_ = dependency; |
| 908 | } |
| 909 | bool isEffectful() const { return getAliasSet().isStore(); } |
| 910 | |
| 911 | #ifdef DEBUG1 |
| 912 | bool needsResumePoint() const { |
| 913 | // Return whether this instruction should have its own resume point. |
| 914 | return isEffectful(); |
| 915 | } |
| 916 | #endif |
| 917 | |
| 918 | enum class AliasType : uint32_t { NoAlias = 0, MayAlias = 1, MustAlias = 2 }; |
| 919 | virtual AliasType mightAlias(const MDefinition* store) const { |
| 920 | // Return whether this load may depend on the specified store, given |
| 921 | // that the alias sets intersect. This may be refined to exclude |
| 922 | // possible aliasing in cases where alias set flags are too imprecise. |
| 923 | if (!(getAliasSet().flags() & store->getAliasSet().flags())) { |
| 924 | return AliasType::NoAlias; |
| 925 | } |
| 926 | MOZ_ASSERT(!isEffectful() && store->isEffectful())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!isEffectful() && store->isEffectful())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!isEffectful() && store->isEffectful()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("!isEffectful() && store->isEffectful()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 926); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isEffectful() && store->isEffectful()" ")"); do { *((volatile int*)__null) = 926; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 927 | return AliasType::MayAlias; |
| 928 | } |
| 929 | |
| 930 | virtual bool canRecoverOnBailout() const { return false; } |
| 931 | }; |
| 932 | |
| 933 | // An MUseDefIterator walks over uses in a definition, skipping any use that is |
| 934 | // not a definition. Items from the use list must not be deleted during |
| 935 | // iteration. |
| 936 | class MUseDefIterator { |
| 937 | const MDefinition* def_; |
| 938 | MUseIterator current_; |
| 939 | |
| 940 | MUseIterator search(MUseIterator start) { |
| 941 | MUseIterator i(start); |
| 942 | for (; i != def_->usesEnd(); i++) { |
| 943 | if (i->consumer()->isDefinition()) { |
| 944 | return i; |
| 945 | } |
| 946 | } |
| 947 | return def_->usesEnd(); |
| 948 | } |
| 949 | |
| 950 | public: |
| 951 | explicit MUseDefIterator(const MDefinition* def) |
| 952 | : def_(def), current_(search(def->usesBegin())) {} |
| 953 | |
| 954 | explicit operator bool() const { return current_ != def_->usesEnd(); } |
| 955 | MUseDefIterator operator++() { |
| 956 | MOZ_ASSERT(current_ != def_->usesEnd())do { static_assert( mozilla::detail::AssertionConditionType< decltype(current_ != def_->usesEnd())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(current_ != def_->usesEnd ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("current_ != def_->usesEnd()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 956); AnnotateMozCrashReason("MOZ_ASSERT" "(" "current_ != def_->usesEnd()" ")"); do { *((volatile int*)__null) = 956; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 957 | ++current_; |
| 958 | current_ = search(current_); |
| 959 | return *this; |
| 960 | } |
| 961 | MUseDefIterator operator++(int) { |
| 962 | MUseDefIterator old(*this); |
| 963 | operator++(); |
| 964 | return old; |
| 965 | } |
| 966 | MUse* use() const { return *current_; } |
| 967 | MDefinition* def() const { return current_->consumer()->toDefinition(); } |
| 968 | }; |
| 969 | |
| 970 | // Helper class to check that GC pointers embedded in MIR instructions are not |
| 971 | // in the nursery. Off-thread compilation and nursery GCs can happen in |
| 972 | // parallel. Nursery pointers are handled with MNurseryObject and the |
| 973 | // nurseryObjects lists in WarpSnapshot and IonScript. |
| 974 | // |
| 975 | // These GC things are rooted through the WarpSnapshot. Compacting GCs cancel |
| 976 | // off-thread compilations. |
| 977 | template <typename T> |
| 978 | class CompilerGCPointer { |
| 979 | js::gc::Cell* ptr_; |
| 980 | |
| 981 | public: |
| 982 | explicit CompilerGCPointer(T ptr) : ptr_(ptr) { |
| 983 | MOZ_ASSERT_IF(ptr, !IsInsideNursery(ptr))do { if (ptr) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(!IsInsideNursery(ptr))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsInsideNursery(ptr)))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("!IsInsideNursery(ptr)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 983); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(ptr)" ")"); do { *((volatile int*)__null) = 983; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
| 984 | MOZ_ASSERT_IF(!CurrentThreadIsIonCompiling(), TlsContext.get()->suppressGC)do { if (!CurrentThreadIsIonCompiling()) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(TlsContext .get()->suppressGC)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(TlsContext.get()->suppressGC ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "TlsContext.get()->suppressGC", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "TlsContext.get()->suppressGC" ")"); do { *((volatile int*)__null) = 984; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
| 985 | } |
| 986 | |
| 987 | operator T() const { return static_cast<T>(ptr_); } |
| 988 | T operator->() const { return static_cast<T>(ptr_); } |
| 989 | |
| 990 | private: |
| 991 | CompilerGCPointer() = delete; |
| 992 | CompilerGCPointer(const CompilerGCPointer<T>&) = delete; |
| 993 | CompilerGCPointer<T>& operator=(const CompilerGCPointer<T>&) = delete; |
| 994 | }; |
| 995 | |
| 996 | using CompilerObject = CompilerGCPointer<JSObject*>; |
| 997 | using CompilerNativeObject = CompilerGCPointer<NativeObject*>; |
| 998 | using CompilerFunction = CompilerGCPointer<JSFunction*>; |
| 999 | using CompilerBaseScript = CompilerGCPointer<BaseScript*>; |
| 1000 | using CompilerPropertyName = CompilerGCPointer<PropertyName*>; |
| 1001 | using CompilerShape = CompilerGCPointer<Shape*>; |
| 1002 | using CompilerGetterSetter = CompilerGCPointer<GetterSetter*>; |
| 1003 | |
| 1004 | // An instruction is an SSA name that is inserted into a basic block's IR |
| 1005 | // stream. |
| 1006 | class MInstruction : public MDefinition, public InlineListNode<MInstruction> { |
| 1007 | MResumePoint* resumePoint_; |
| 1008 | |
| 1009 | protected: |
| 1010 | // All MInstructions are using the "MFoo::New(alloc)" notation instead of |
| 1011 | // the TempObject new operator. This code redefines the new operator as |
| 1012 | // protected, and delegates to the TempObject new operator. Thus, the |
| 1013 | // following code prevents calls to "new(alloc) MFoo" outside the MFoo |
| 1014 | // members. |
| 1015 | inline void* operator new(size_t nbytes, |
| 1016 | TempAllocator::Fallible view) noexcept(true) { |
| 1017 | return TempObject::operator new(nbytes, view); |
| 1018 | } |
| 1019 | inline void* operator new(size_t nbytes, TempAllocator& alloc) { |
| 1020 | return TempObject::operator new(nbytes, alloc); |
| 1021 | } |
| 1022 | template <class T> |
| 1023 | inline void* operator new(size_t nbytes, T* pos) { |
| 1024 | return TempObject::operator new(nbytes, pos); |
| 1025 | } |
| 1026 | |
| 1027 | public: |
| 1028 | explicit MInstruction(Opcode op) : MDefinition(op), resumePoint_(nullptr) {} |
| 1029 | |
| 1030 | // Copying an instruction leaves the resume point as empty. |
| 1031 | explicit MInstruction(const MInstruction& other) |
| 1032 | : MDefinition(other), resumePoint_(nullptr) {} |
| 1033 | |
| 1034 | // Convenient function used for replacing a load by the value of the store |
| 1035 | // if the types are match, and boxing the value if they do not match. |
| 1036 | MDefinition* foldsToStore(TempAllocator& alloc); |
| 1037 | |
| 1038 | void setResumePoint(MResumePoint* resumePoint); |
| 1039 | void stealResumePoint(MInstruction* other); |
| 1040 | |
| 1041 | void moveResumePointAsEntry(); |
| 1042 | void clearResumePoint(); |
| 1043 | MResumePoint* resumePoint() const { return resumePoint_; } |
| 1044 | |
| 1045 | // For instructions which can be cloned with new inputs, with all other |
| 1046 | // information being the same. clone() implementations do not need to worry |
| 1047 | // about cloning generic MInstruction/MDefinition state like flags and |
| 1048 | // resume points. |
| 1049 | virtual bool canClone() const { return false; } |
| 1050 | virtual MInstruction* clone(TempAllocator& alloc, |
| 1051 | const MDefinitionVector& inputs) const { |
| 1052 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1052); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 1052; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
| 1053 | } |
| 1054 | |
| 1055 | // Instructions needing to hook into type analysis should return a |
| 1056 | // TypePolicy. |
| 1057 | virtual const TypePolicy* typePolicy() = 0; |
| 1058 | virtual MIRType typePolicySpecialization() = 0; |
| 1059 | }; |
| 1060 | |
| 1061 | // Note: GenerateOpcodeFiles.py generates MOpcodesGenerated.h based on the |
| 1062 | // INSTRUCTION_HEADER* macros. |
| 1063 | #define INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)static const Opcode classOpcode = Opcode::opcode; using MThisOpcode = Mopcode; \ |
| 1064 | static const Opcode classOpcode = Opcode::opcode; \ |
| 1065 | using MThisOpcode = M##opcode; |
| 1066 | |
| 1067 | #define INSTRUCTION_HEADER(opcode) \ |
| 1068 | INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(opcode)static const Opcode classOpcode = Opcode::opcode; using MThisOpcode = Mopcode; \ |
| 1069 | virtual const TypePolicy* typePolicy() override; \ |
| 1070 | virtual MIRType typePolicySpecialization() override; |
| 1071 | |
| 1072 | #define ALLOW_CLONE(typename)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) typename (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } \ |
| 1073 | bool canClone() const override { return true; } \ |
| 1074 | MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) \ |
| 1075 | const override { \ |
| 1076 | MInstruction* res = new (alloc) typename(*this); \ |
| 1077 | for (size_t i = 0; i < numOperands(); i++) \ |
| 1078 | res->replaceOperand(i, inputs[i]); \ |
| 1079 | return res; \ |
| 1080 | } |
| 1081 | |
| 1082 | // Adds MFoo::New functions which are mirroring the arguments of the |
| 1083 | // constructors. Opcodes which are using this macro can be called with a |
| 1084 | // TempAllocator, or the fallible version of the TempAllocator. |
| 1085 | #define TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } \ |
| 1086 | template <typename... Args> \ |
| 1087 | static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { \ |
| 1088 | return new (alloc) MThisOpcode(std::forward<Args>(args)...); \ |
| 1089 | } \ |
| 1090 | template <typename... Args> \ |
| 1091 | static MThisOpcode* New(TempAllocator::Fallible alloc, Args&&... args) { \ |
| 1092 | return new (alloc) MThisOpcode(std::forward<Args>(args)...); \ |
| 1093 | } |
| 1094 | |
| 1095 | // These macros are used as a syntactic sugar for writting getOperand |
| 1096 | // accessors. They are meant to be used in the body of MIR Instructions as |
| 1097 | // follows: |
| 1098 | // |
| 1099 | // public: |
| 1100 | // INSTRUCTION_HEADER(Foo) |
| 1101 | // NAMED_OPERANDS((0, lhs), (1, rhs)) |
| 1102 | // |
| 1103 | // The above example defines 2 accessors, one named "lhs" accessing the first |
| 1104 | // operand, and a one named "rhs" accessing the second operand. |
| 1105 | #define NAMED_OPERAND_ACCESSOR(Index, Name)MDefinition* Name() const { return getOperand(Index); } \ |
| 1106 | MDefinition* Name() const { return getOperand(Index); } |
| 1107 | #define NAMED_OPERAND_ACCESSOR_APPLY(Args)NAMED_OPERAND_ACCESSOR Args NAMED_OPERAND_ACCESSOR Args |
| 1108 | #define NAMED_OPERANDS(...)NAMED_OPERAND_ACCESSOR ... \ |
| 1109 | MOZ_FOR_EACH(NAMED_OPERAND_ACCESSOR_APPLY, (), (__VA_ARGS__))NAMED_OPERAND_ACCESSOR __VA_ARGS__ |
| 1110 | |
| 1111 | template <size_t Arity> |
| 1112 | class MAryInstruction : public MInstruction { |
| 1113 | mozilla::Array<MUse, Arity> operands_; |
| 1114 | |
| 1115 | protected: |
| 1116 | MUse* getUseFor(size_t index) final { return &operands_[index]; } |
| 1117 | const MUse* getUseFor(size_t index) const final { return &operands_[index]; } |
| 1118 | void initOperand(size_t index, MDefinition* operand) { |
| 1119 | operands_[index].init(operand, this); |
| 1120 | } |
| 1121 | |
| 1122 | public: |
| 1123 | MDefinition* getOperand(size_t index) const final { |
| 1124 | return operands_[index].producer(); |
| 1125 | } |
| 1126 | size_t numOperands() const final { return Arity; } |
| 1127 | #ifdef DEBUG1 |
| 1128 | static const size_t staticNumOperands = Arity; |
| 1129 | #endif |
| 1130 | size_t indexOf(const MUse* u) const final { |
| 1131 | MOZ_ASSERT(u >= &operands_[0])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u >= &operands_[0])>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(u >= &operands_[0]))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("u >= &operands_[0]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u >= &operands_[0]" ")"); do { *((volatile int*)__null) = 1131; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1132 | MOZ_ASSERT(u <= &operands_[numOperands() - 1])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u <= &operands_[numOperands() - 1])>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(u <= &operands_[numOperands() - 1]))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("u <= &operands_[numOperands() - 1]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u <= &operands_[numOperands() - 1]" ")"); do { *((volatile int*)__null) = 1132; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1133 | return u - &operands_[0]; |
| 1134 | } |
| 1135 | void replaceOperand(size_t index, MDefinition* operand) final { |
| 1136 | operands_[index].replaceProducer(operand); |
| 1137 | } |
| 1138 | |
| 1139 | explicit MAryInstruction(Opcode op) : MInstruction(op) {} |
| 1140 | |
| 1141 | explicit MAryInstruction(const MAryInstruction<Arity>& other) |
| 1142 | : MInstruction(other) { |
| 1143 | for (int i = 0; i < (int)Arity; |
| 1144 | i++) { // N.B. use |int| to avoid warnings when Arity == 0 |
| 1145 | operands_[i].init(other.operands_[i].producer(), this); |
| 1146 | } |
| 1147 | } |
| 1148 | }; |
| 1149 | |
| 1150 | class MNullaryInstruction : public MAryInstruction<0>, |
| 1151 | public NoTypePolicy::Data { |
| 1152 | protected: |
| 1153 | explicit MNullaryInstruction(Opcode op) : MAryInstruction(op) {} |
| 1154 | |
| 1155 | HashNumber valueHash() const override; |
| 1156 | }; |
| 1157 | |
| 1158 | class MUnaryInstruction : public MAryInstruction<1> { |
| 1159 | protected: |
| 1160 | MUnaryInstruction(Opcode op, MDefinition* ins) : MAryInstruction(op) { |
| 1161 | initOperand(0, ins); |
| 1162 | } |
| 1163 | |
| 1164 | HashNumber valueHash() const override; |
| 1165 | |
| 1166 | public: |
| 1167 | NAMED_OPERANDS((0, input))MDefinition* input() const { return getOperand(0); } |
| 1168 | }; |
| 1169 | |
| 1170 | class MBinaryInstruction : public MAryInstruction<2> { |
| 1171 | protected: |
| 1172 | MBinaryInstruction(Opcode op, MDefinition* left, MDefinition* right) |
| 1173 | : MAryInstruction(op) { |
| 1174 | initOperand(0, left); |
| 1175 | initOperand(1, right); |
| 1176 | } |
| 1177 | |
| 1178 | public: |
| 1179 | NAMED_OPERANDS((0, lhs), (1, rhs))MDefinition* lhs() const { return getOperand(0); } MDefinition * rhs() const { return getOperand(1); } |
| 1180 | |
| 1181 | protected: |
| 1182 | HashNumber valueHash() const override; |
| 1183 | |
| 1184 | bool binaryCongruentTo(const MDefinition* ins) const { |
| 1185 | if (op() != ins->op()) { |
| 1186 | return false; |
| 1187 | } |
| 1188 | |
| 1189 | if (type() != ins->type()) { |
| 1190 | return false; |
| 1191 | } |
| 1192 | |
| 1193 | if (isEffectful() || ins->isEffectful()) { |
| 1194 | return false; |
| 1195 | } |
| 1196 | |
| 1197 | const MDefinition* left = getOperand(0); |
| 1198 | const MDefinition* right = getOperand(1); |
| 1199 | if (isCommutative() && left->id() > right->id()) { |
| 1200 | std::swap(left, right); |
| 1201 | } |
| 1202 | |
| 1203 | const MBinaryInstruction* bi = static_cast<const MBinaryInstruction*>(ins); |
| 1204 | const MDefinition* insLeft = bi->getOperand(0); |
| 1205 | const MDefinition* insRight = bi->getOperand(1); |
| 1206 | if (bi->isCommutative() && insLeft->id() > insRight->id()) { |
| 1207 | std::swap(insLeft, insRight); |
| 1208 | } |
| 1209 | |
| 1210 | return left == insLeft && right == insRight; |
| 1211 | } |
| 1212 | |
| 1213 | public: |
| 1214 | // Return if the operands to this instruction are both unsigned. |
| 1215 | static bool unsignedOperands(MDefinition* left, MDefinition* right); |
| 1216 | bool unsignedOperands(); |
| 1217 | |
| 1218 | // Replace any wrapping operands with the underlying int32 operands |
| 1219 | // in case of unsigned operands. |
| 1220 | void replaceWithUnsignedOperands(); |
| 1221 | }; |
| 1222 | |
| 1223 | class MTernaryInstruction : public MAryInstruction<3> { |
| 1224 | protected: |
| 1225 | MTernaryInstruction(Opcode op, MDefinition* first, MDefinition* second, |
| 1226 | MDefinition* third) |
| 1227 | : MAryInstruction(op) { |
| 1228 | initOperand(0, first); |
| 1229 | initOperand(1, second); |
| 1230 | initOperand(2, third); |
| 1231 | } |
| 1232 | |
| 1233 | HashNumber valueHash() const override; |
| 1234 | }; |
| 1235 | |
| 1236 | class MQuaternaryInstruction : public MAryInstruction<4> { |
| 1237 | protected: |
| 1238 | MQuaternaryInstruction(Opcode op, MDefinition* first, MDefinition* second, |
| 1239 | MDefinition* third, MDefinition* fourth) |
| 1240 | : MAryInstruction(op) { |
| 1241 | initOperand(0, first); |
| 1242 | initOperand(1, second); |
| 1243 | initOperand(2, third); |
| 1244 | initOperand(3, fourth); |
| 1245 | } |
| 1246 | |
| 1247 | HashNumber valueHash() const override; |
| 1248 | }; |
| 1249 | |
| 1250 | template <class T> |
| 1251 | class MVariadicT : public T { |
| 1252 | FixedList<MUse> operands_; |
| 1253 | |
| 1254 | protected: |
| 1255 | explicit MVariadicT(typename T::Opcode op) : T(op) {} |
| 1256 | [[nodiscard]] bool init(TempAllocator& alloc, size_t length) { |
| 1257 | return operands_.init(alloc, length); |
| 1258 | } |
| 1259 | void initOperand(size_t index, MDefinition* operand) { |
| 1260 | // FixedList doesn't initialize its elements, so do an unchecked init. |
| 1261 | operands_[index].initUnchecked(operand, this); |
| 1262 | } |
| 1263 | MUse* getUseFor(size_t index) final { return &operands_[index]; } |
| 1264 | const MUse* getUseFor(size_t index) const final { return &operands_[index]; } |
| 1265 | |
| 1266 | // The MWasmCallBase mixin performs initialization for it's subclasses. |
| 1267 | friend class MWasmCallBase; |
| 1268 | |
| 1269 | public: |
| 1270 | // Will assert if called before initialization. |
| 1271 | MDefinition* getOperand(size_t index) const final { |
| 1272 | return operands_[index].producer(); |
| 1273 | } |
| 1274 | size_t numOperands() const final { return operands_.length(); } |
| 1275 | size_t indexOf(const MUse* u) const final { |
| 1276 | MOZ_ASSERT(u >= &operands_[0])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u >= &operands_[0])>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(u >= &operands_[0]))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("u >= &operands_[0]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1276); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u >= &operands_[0]" ")"); do { *((volatile int*)__null) = 1276; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1277 | MOZ_ASSERT(u <= &operands_[numOperands() - 1])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u <= &operands_[numOperands() - 1])>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(u <= &operands_[numOperands() - 1]))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("u <= &operands_[numOperands() - 1]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u <= &operands_[numOperands() - 1]" ")"); do { *((volatile int*)__null) = 1277; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1278 | return u - &operands_[0]; |
| 1279 | } |
| 1280 | void replaceOperand(size_t index, MDefinition* operand) final { |
| 1281 | operands_[index].replaceProducer(operand); |
| 1282 | } |
| 1283 | }; |
| 1284 | |
| 1285 | // An instruction with a variable number of operands. Note that the |
| 1286 | // MFoo::New constructor for variadic instructions fallibly |
| 1287 | // initializes the operands_ array and must be checked for OOM. |
| 1288 | using MVariadicInstruction = MVariadicT<MInstruction>; |
| 1289 | |
| 1290 | // All barriered operations: |
| 1291 | // - MCompareExchangeTypedArrayElement |
| 1292 | // - MExchangeTypedArrayElement |
| 1293 | // - MAtomicTypedArrayElementBinop |
| 1294 | // - MGrowableSharedArrayBufferByteLength |
| 1295 | // |
| 1296 | // And operations which are optionally barriered: |
| 1297 | // - MLoadUnboxedScalar |
| 1298 | // - MStoreUnboxedScalar |
| 1299 | // - MResizableTypedArrayLength |
| 1300 | // - MResizableDataViewByteLength |
| 1301 | // |
| 1302 | // Must have the following attributes: |
| 1303 | // |
| 1304 | // - Not movable |
| 1305 | // - Not removable |
| 1306 | // - Not congruent with any other instruction |
| 1307 | // - Effectful (they alias every TypedArray store) |
| 1308 | // |
| 1309 | // The intended effect of those constraints is to prevent all loads and stores |
| 1310 | // preceding the barriered operation from being moved to after the barriered |
| 1311 | // operation, and vice versa, and to prevent the barriered operation from being |
| 1312 | // removed or hoisted. |
| 1313 | |
| 1314 | enum class MemoryBarrierRequirement : bool { |
| 1315 | NotRequired, |
| 1316 | Required, |
| 1317 | }; |
| 1318 | |
| 1319 | MIR_OPCODE_CLASS_GENERATEDclass MStart : public MNullaryInstruction { explicit MStart() : MNullaryInstruction(classOpcode) { } public: INSTRUCTION_HEADER (Start) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); }};class MOsrEntry : public MNullaryInstruction { explicit MOsrEntry() : MNullaryInstruction (classOpcode) { setResultType(MIRType::Pointer); } public: INSTRUCTION_HEADER (OsrEntry) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); }};class MNop : public MNullaryInstruction { explicit MNop() : MNullaryInstruction (classOpcode) { } public: INSTRUCTION_HEADER(Nop) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc , const MDefinitionVector& inputs) const override { MInstruction * res = new (alloc) MNop(*this); for (size_t i = 0; i < numOperands (); i++) res->replaceOperand(i, inputs[i]); return res; }} ;class MCallee : public MNullaryInstruction { explicit MCallee () : MNullaryInstruction(classOpcode) { setMovable(); setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(Callee) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MIsConstructing : public MNullaryInstruction { explicit MIsConstructing() : MNullaryInstruction(classOpcode ) { setMovable(); setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (IsConstructing) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } AliasSet getAliasSet () const override { return AliasSet::None(); } bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MThrow : public MUnaryInstruction, public BoxPolicy <0>::Data { explicit MThrow(MDefinition* value) : MUnaryInstruction (classOpcode, value) { } public: INSTRUCTION_HEADER(Throw) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* value() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool possiblyCalls() const override { return true; }};class MThrowWithStack : public MBinaryInstruction, public MixPolicy <BoxPolicy<0>, BoxPolicy<1>>::Data { explicit MThrowWithStack(MDefinition* value, MDefinition* stack) : MBinaryInstruction (classOpcode, value, stack) { } public: INSTRUCTION_HEADER(ThrowWithStack ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* value() const { return getOperand(0); } MDefinition* stack() const { return getOperand(1); } AliasSet getAliasSet() const override; bool possiblyCalls() const override { return true; }};class MNewArrayDynamicLength : public MUnaryInstruction, public UnboxedInt32Policy<0> ::Data { CompilerGCPointer<JSObject*> templateObject_; gc ::Heap initialHeap_; explicit MNewArrayDynamicLength(MDefinition * length, JSObject* templateObject, gc::Heap initialHeap) : MUnaryInstruction (classOpcode, length), templateObject_(templateObject), initialHeap_ (initialHeap) { setGuard(); setResultType(MIRType::Object); } public: JSObject* templateObject() const { return templateObject_ ; } gc::Heap initialHeap() const { return initialHeap_; } INSTRUCTION_HEADER (NewArrayDynamicLength) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* length() const { return getOperand(0); } AliasSet getAliasSet() const override;};class MNewTypedArrayDynamicLength : public MUnaryInstruction, public UnboxedInt32Policy<0> ::Data { CompilerGCPointer<JSObject*> templateObject_; gc ::Heap initialHeap_; explicit MNewTypedArrayDynamicLength(MDefinition * length, JSObject* templateObject, gc::Heap initialHeap) : MUnaryInstruction (classOpcode, length), templateObject_(templateObject), initialHeap_ (initialHeap) { setGuard(); setResultType(MIRType::Object); } public: JSObject* templateObject() const { return templateObject_ ; } gc::Heap initialHeap() const { return initialHeap_; } INSTRUCTION_HEADER (NewTypedArrayDynamicLength) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* length() const { return getOperand(0); } AliasSet getAliasSet() const override;};class MNewTypedArrayFromArray : public MUnaryInstruction, public ObjectPolicy<0>::Data { CompilerGCPointer<JSObject*> templateObject_; gc::Heap initialHeap_; explicit MNewTypedArrayFromArray(MDefinition* array , JSObject* templateObject, gc::Heap initialHeap) : MUnaryInstruction (classOpcode, array), templateObject_(templateObject), initialHeap_ (initialHeap) { setGuard(); setResultType(MIRType::Object); } public: JSObject* templateObject() const { return templateObject_ ; } gc::Heap initialHeap() const { return initialHeap_; } INSTRUCTION_HEADER (NewTypedArrayFromArray) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* array() const { return getOperand(0); } bool possiblyCalls() const override { return true; }};class MNewTypedArrayFromArrayBuffer : public MTernaryInstruction, public MixPolicy<ObjectPolicy <0>, BoxPolicy<1>, BoxPolicy<2>>::Data { CompilerGCPointer<JSObject*> templateObject_; gc::Heap initialHeap_; explicit MNewTypedArrayFromArrayBuffer(MDefinition * arrayBuffer, MDefinition* byteOffset, MDefinition* length, JSObject * templateObject, gc::Heap initialHeap) : MTernaryInstruction (classOpcode, arrayBuffer, byteOffset, length), templateObject_ (templateObject), initialHeap_(initialHeap) { setGuard(); setResultType (MIRType::Object); } public: JSObject* templateObject() const { return templateObject_; } gc::Heap initialHeap() const { return initialHeap_; } INSTRUCTION_HEADER(NewTypedArrayFromArrayBuffer ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* arrayBuffer() const { return getOperand(0); } MDefinition* byteOffset() const { return getOperand(1); } MDefinition* length() const { return getOperand(2); } bool possiblyCalls() const override { return true; }};class MNewBoundFunction : public MNullaryInstruction { CompilerGCPointer<JSObject*> templateObj_; explicit MNewBoundFunction (JSObject* templateObj) : MNullaryInstruction(classOpcode), templateObj_ (templateObj) { setResultType(MIRType::Object); } public: JSObject * templateObj() const { return templateObj_; } INSTRUCTION_HEADER (NewBoundFunction) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } AliasSet getAliasSet () const override { return AliasSet::None(); }};class MBoundFunctionNumArgs : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MBoundFunctionNumArgs(MDefinition* object) : MUnaryInstruction (classOpcode, object) { setMovable(); setResultType(MIRType:: Int32); } public: INSTRUCTION_HEADER(BoundFunctionNumArgs) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardBoundFunctionIsConstructor : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MGuardBoundFunctionIsConstructor (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setGuard(); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(GuardBoundFunctionIsConstructor ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MMutateProto : public MBinaryInstruction, public MixPolicy <ObjectPolicy<0>, BoxPolicy<1>>::Data { explicit MMutateProto(MDefinition* object, MDefinition* value) : MBinaryInstruction (classOpcode, object, value) { setResultType(MIRType::None); } public: INSTRUCTION_HEADER(MutateProto) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } bool possiblyCalls() const override { return true; }}; class MInitPropGetterSetter : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>> ::Data { CompilerGCPointer<PropertyName*> name_; explicit MInitPropGetterSetter(MDefinition* object, MDefinition* value , PropertyName* name) : MBinaryInstruction(classOpcode, object , value), name_(name) { } public: PropertyName* name() const { return name_; } INSTRUCTION_HEADER(InitPropGetterSetter) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* value() const { return getOperand(1); }};class MInitElemGetterSetter : public MTernaryInstruction , public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> , ObjectPolicy<2>>::Data { explicit MInitElemGetterSetter (MDefinition* object, MDefinition* id, MDefinition* value) : MTernaryInstruction (classOpcode, object, id, value) { } public: INSTRUCTION_HEADER (InitElemGetterSetter) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } MDefinition* id() const { return getOperand(1); } MDefinition * value() const { return getOperand(2); }};class MEncodeSnapshot : public MNullaryInstruction { explicit MEncodeSnapshot() : MNullaryInstruction (classOpcode) { setGuard(); } public: INSTRUCTION_HEADER(EncodeSnapshot ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); }};class MSameValueDouble : public MBinaryInstruction, public MixPolicy<DoublePolicy<0> , DoublePolicy<1>>::Data { explicit MSameValueDouble (MDefinition* left, MDefinition* right) : MBinaryInstruction( classOpcode, left, right) { setMovable(); setResultType(MIRType ::Boolean); } public: INSTRUCTION_HEADER(SameValueDouble) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* left() const { return getOperand(0); } MDefinition* right() const { return getOperand (1); } AliasSet getAliasSet() const override { return AliasSet ::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MSameValueDouble(*this); for (size_t i = 0; i < numOperands(); i++) res->replaceOperand (i, inputs[i]); return res; }};class MSameValue : public MBinaryInstruction , public MixPolicy<BoxPolicy<0>, BoxPolicy<1>> ::Data { explicit MSameValue(MDefinition* left, MDefinition* right ) : MBinaryInstruction(classOpcode, left, right) { setMovable (); setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (SameValue) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * left() const { return getOperand(0); } MDefinition* right() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MSameValue (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MCreateThis : public MBinaryInstruction, public MixPolicy<ObjectPolicy <0>, ObjectPolicy<1>>::Data { explicit MCreateThis (MDefinition* callee, MDefinition* newTarget) : MBinaryInstruction (classOpcode, callee, newTarget) { setResultType(MIRType::Value ); } public: INSTRUCTION_HEADER(CreateThis) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* callee() const { return getOperand(0); } MDefinition* newTarget() const { return getOperand (1); } AliasSet getAliasSet() const override; bool possiblyCalls () const override { return true; }};class MGetArgumentsObjectArg : public MUnaryInstruction, public ObjectPolicy<0>::Data { size_t argno_; explicit MGetArgumentsObjectArg(MDefinition * argsObject, size_t argno) : MUnaryInstruction(classOpcode, argsObject ), argno_(argno) { setResultType(MIRType::Value); } public: size_t argno() const { return argno_; } INSTRUCTION_HEADER(GetArgumentsObjectArg ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* argsObject() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override;};class MSetArgumentsObjectArg : public MBinaryInstruction, public MixPolicy <ObjectPolicy<0>, BoxPolicy<1>>::Data { size_t argno_; explicit MSetArgumentsObjectArg(MDefinition* argsObject , MDefinition* value, size_t argno) : MBinaryInstruction(classOpcode , argsObject, value), argno_(argno) { } public: size_t argno( ) const { return argno_; } INSTRUCTION_HEADER(SetArgumentsObjectArg ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* argsObject() const { return getOperand(0); } MDefinition* value() const { return getOperand(1); } AliasSet getAliasSet() const override;};class MLoadArgumentsObjectArg : public MBinaryInstruction, public MixPolicy <ObjectPolicy<0>, UnboxedInt32Policy<1>>::Data { explicit MLoadArgumentsObjectArg(MDefinition* argsObject, MDefinition * index) : MBinaryInstruction(classOpcode, argsObject, index) { setGuard(); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (LoadArgumentsObjectArg) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* argsObject() const { return getOperand( 0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MLoadArgumentsObjectArgHole : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy <1>>::Data { explicit MLoadArgumentsObjectArgHole(MDefinition * argsObject, MDefinition* index) : MBinaryInstruction(classOpcode , argsObject, index) { setGuard(); setResultType(MIRType::Value ); } public: INSTRUCTION_HEADER(LoadArgumentsObjectArgHole) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* argsObject() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MInArgumentsObjectArg : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy <1>>::Data { explicit MInArgumentsObjectArg(MDefinition * argsObject, MDefinition* index) : MBinaryInstruction(classOpcode , argsObject, index) { setGuard(); setResultType(MIRType::Boolean ); } public: INSTRUCTION_HEADER(InArgumentsObjectArg) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* argsObject() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MArgumentsObjectLength : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MArgumentsObjectLength (MDefinition* argsObject) : MUnaryInstruction(classOpcode, argsObject ) { setGuard(); setMovable(); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER(ArgumentsObjectLength) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* argsObject() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MArrayFromArgumentsObject : public MUnaryInstruction, public ObjectPolicy<0>::Data { CompilerGCPointer<Shape*> shape_; explicit MArrayFromArgumentsObject (MDefinition* argsObject, Shape* shape) : MUnaryInstruction(classOpcode , argsObject), shape_(shape) { setResultType(MIRType::Object) ; } public: Shape* shape() const { return shape_; } INSTRUCTION_HEADER (ArrayFromArgumentsObject) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* argsObject() const { return getOperand( 0); } bool possiblyCalls() const override { return true; }};class MGuardArgumentsObjectFlags : public MUnaryInstruction, public ObjectPolicy<0>::Data { uint32_t flags_; explicit MGuardArgumentsObjectFlags (MDefinition* argsObject, uint32_t flags) : MUnaryInstruction (classOpcode, argsObject), flags_(flags) { setGuard(); setMovable (); setResultType(MIRType::Object); } public: uint32_t flags( ) const { return flags_; } INSTRUCTION_HEADER(GuardArgumentsObjectFlags ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* argsObject() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override;};class MLoadScriptedProxyHandler : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MLoadScriptedProxyHandler (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setGuard(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER (LoadScriptedProxyHandler) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MCheckScriptedProxyGetResult : public MTernaryInstruction, public MixPolicy<BoxPolicy< 0>, BoxPolicy<1>, BoxPolicy<2>>::Data { explicit MCheckScriptedProxyGetResult(MDefinition* target, MDefinition * id, MDefinition* value) : MTernaryInstruction(classOpcode, target , id, value) { setGuard(); } public: INSTRUCTION_HEADER(CheckScriptedProxyGetResult ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* target() const { return getOperand(0); } MDefinition* id() const { return getOperand (1); } MDefinition* value() const { return getOperand(2); } AliasSet getAliasSet() const override;};class MIdToStringOrSymbol : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MIdToStringOrSymbol(MDefinition* idVal) : MUnaryInstruction( classOpcode, idVal) { setResultType(MIRType::Value); } public : INSTRUCTION_HEADER(IdToStringOrSymbol) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* idVal() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator& alloc ) override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MReturnFromCtor : public MBinaryInstruction, public MixPolicy<BoxPolicy< 0>, ObjectPolicy<1>>::Data { explicit MReturnFromCtor (MDefinition* value, MDefinition* object) : MBinaryInstruction (classOpcode, value, object) { setResultType(MIRType::Object) ; } public: INSTRUCTION_HEADER(ReturnFromCtor) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* value() const { return getOperand(0); } MDefinition* object() const { return getOperand (1); } AliasSet getAliasSet() const override { return AliasSet ::None(); } MDefinition* foldsTo(TempAllocator& alloc) override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MWasmUnsignedToDouble : public MUnaryInstruction, public NoTypePolicy::Data { explicit MWasmUnsignedToDouble(MDefinition* def) : MUnaryInstruction( classOpcode, def) { setMovable(); setResultType(MIRType::Double ); } public: INSTRUCTION_HEADER(WasmUnsignedToDouble) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* def() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); }};class MWasmAnyRefFromJSValue : public MUnaryInstruction, public BoxPolicy <0>::Data { explicit MWasmAnyRefFromJSValue(MDefinition * def) : MUnaryInstruction(classOpcode, def) { setResultType( MIRType::WasmAnyRef); } public: INSTRUCTION_HEADER(WasmAnyRefFromJSValue ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* def() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MWasmAnyRefFromJSObject : public MUnaryInstruction, public NoTypePolicy::Data { explicit MWasmAnyRefFromJSObject (MDefinition* def) : MUnaryInstruction(classOpcode, def) { setResultType (MIRType::WasmAnyRef); } public: INSTRUCTION_HEADER(WasmAnyRefFromJSObject ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* def() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MWasmAnyRefFromJSString : public MUnaryInstruction, public NoTypePolicy::Data { explicit MWasmAnyRefFromJSString (MDefinition* def) : MUnaryInstruction(classOpcode, def) { setResultType (MIRType::WasmAnyRef); } public: INSTRUCTION_HEADER(WasmAnyRefFromJSString ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* def() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MWasmNewI31Ref : public MUnaryInstruction, public NoTypePolicy ::Data { explicit MWasmNewI31Ref(MDefinition* input) : MUnaryInstruction (classOpcode, input) { setMovable(); setResultType(MIRType::WasmAnyRef ); } public: INSTRUCTION_HEADER(WasmNewI31Ref) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MWasmI31RefGet : public MUnaryInstruction, public NoTypePolicy ::Data { wasm::FieldWideningOp wideningOp_; explicit MWasmI31RefGet (MDefinition* input, wasm::FieldWideningOp wideningOp) : MUnaryInstruction (classOpcode, input), wideningOp_(wideningOp) { setMovable(); setResultType(MIRType::Int32); } public: wasm::FieldWideningOp wideningOp() const { return wideningOp_; } INSTRUCTION_HEADER (WasmI31RefGet) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * input() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MBooleanToInt32 : public MUnaryInstruction, public BooleanPolicy<0>::Data { explicit MBooleanToInt32(MDefinition * input) : MUnaryInstruction(classOpcode, input) { setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (BooleanToInt32) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * input() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } MDefinition* foldsTo (TempAllocator& alloc) override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); } void computeRange(TempAllocator& alloc) override;};class MTypeOfName : public MUnaryInstruction, public UnboxedInt32Policy <0>::Data { explicit MTypeOfName(MDefinition* input) : MUnaryInstruction (classOpcode, input) { setMovable(); setResultType(MIRType::String ); } public: INSTRUCTION_HEADER(TypeOfName) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator& alloc ) override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } [[nodiscard]] bool writeRecoverData( CompactBufferWriter& writer) const override ; bool canRecoverOnBailout() const override { return true; }} ;class MToAsyncIter : public MBinaryInstruction, public MixPolicy <ObjectPolicy<0>, BoxPolicy<1>>::Data { explicit MToAsyncIter(MDefinition* iterator, MDefinition* nextMethod) : MBinaryInstruction(classOpcode, iterator, nextMethod) { setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(ToAsyncIter) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* iterator() const { return getOperand(0); } MDefinition* nextMethod() const { return getOperand(1); }};class MToPropertyKeyCache : public MUnaryInstruction , public BoxPolicy<0>::Data { explicit MToPropertyKeyCache (MDefinition* input) : MUnaryInstruction(classOpcode, input) { setResultType(MIRType::Value); } public: INSTRUCTION_HEADER( ToPropertyKeyCache) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * input() const { return getOperand(0); }};class MAtan2 : public MBinaryInstruction, public MixPolicy<DoublePolicy<0> , DoublePolicy<1>>::Data { explicit MAtan2(MDefinition * y, MDefinition* x) : MBinaryInstruction(classOpcode, y, x) { setMovable(); setResultType(MIRType::Double); } public: INSTRUCTION_HEADER (Atan2) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * y() const { return getOperand(0); } MDefinition* x() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); } bool possiblyCalls() const override { return true; } [[nodiscard ]] bool writeRecoverData( CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; } bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MAtan2 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MRandom : public MNullaryInstruction { explicit MRandom() : MNullaryInstruction (classOpcode) { setResultType(MIRType::Double); } public: INSTRUCTION_HEADER (Random) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } AliasSet getAliasSet () const override; bool possiblyCalls() const override { return true; } void computeRange(TempAllocator& alloc) override ; [[nodiscard]] bool writeRecoverData( CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override ; bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MRandom (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MInt32ToStringWithBase : public MBinaryInstruction, public MixPolicy<UnboxedInt32Policy <0>, UnboxedInt32Policy<1>>::Data { bool lowerCase_ ; explicit MInt32ToStringWithBase(MDefinition* input, MDefinition * base, bool lowerCase) : MBinaryInstruction(classOpcode, input , base), lowerCase_(lowerCase) { setMovable(); setResultType( MIRType::String); } public: bool lowerCase() const { return lowerCase_ ; } INSTRUCTION_HEADER(Int32ToStringWithBase) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* input() const { return getOperand(0); } MDefinition* base() const { return getOperand (1); } AliasSet getAliasSet() const override { return AliasSet ::None(); } bool congruentTo(const MDefinition* ins) const override ;};class MNumberParseInt : public MBinaryInstruction, public MixPolicy <StringPolicy<0>, UnboxedInt32Policy<1>>::Data { explicit MNumberParseInt(MDefinition* string, MDefinition* radix) : MBinaryInstruction(classOpcode, string, radix) { setMovable (); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (NumberParseInt) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * string() const { return getOperand(0); } MDefinition* radix () const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool possiblyCalls() const override { return true; } };class MDoubleParseInt : public MUnaryInstruction, public DoublePolicy <0>::Data { explicit MDoubleParseInt(MDefinition* number ) : MUnaryInstruction(classOpcode, number) { setMovable(); setResultType (MIRType::Int32); } public: INSTRUCTION_HEADER(DoubleParseInt ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* number() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MLinearizeString : public MUnaryInstruction, public StringPolicy<0>::Data { explicit MLinearizeString(MDefinition * string) : MUnaryInstruction(classOpcode, string) { setMovable (); setResultType(MIRType::String); } public: INSTRUCTION_HEADER (LinearizeString) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * string() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MLinearizeForCharAccess : public MBinaryInstruction , public MixPolicy<StringPolicy<0>, UnboxedInt32Policy <1>>::Data { explicit MLinearizeForCharAccess(MDefinition * string, MDefinition* index) : MBinaryInstruction(classOpcode , string, index) { setMovable(); setResultType(MIRType::String ); } public: INSTRUCTION_HEADER(LinearizeForCharAccess) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* string() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MLinearizeForCodePointAccess : public MBinaryInstruction, public MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>> ::Data { explicit MLinearizeForCodePointAccess(MDefinition* string , MDefinition* index) : MBinaryInstruction(classOpcode, string , index) { setMovable(); setResultType(MIRType::String); } public : INSTRUCTION_HEADER(LinearizeForCodePointAccess) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* string() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MToRelativeStringIndex : public MBinaryInstruction, public MixPolicy <UnboxedInt32Policy<0>, UnboxedInt32Policy<1>> ::Data { explicit MToRelativeStringIndex(MDefinition* index, MDefinition * length) : MBinaryInstruction(classOpcode, index, length) { setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (ToRelativeStringIndex) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* index() const { return getOperand(0); } MDefinition* length() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition * foldsTo(TempAllocator& alloc) override; bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MCharCodeAt : public MBinaryInstruction, public MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>> ::Data { explicit MCharCodeAt(MDefinition* string, MDefinition * index) : MBinaryInstruction(classOpcode, string, index) { setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (CharCodeAt) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * string() const { return getOperand(0); } MDefinition* index () const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); } void computeRange(TempAllocator& alloc) override; [[nodiscard ]] bool writeRecoverData( CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; } bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MCharCodeAt (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MCharCodeAtOrNegative : public MBinaryInstruction, public MixPolicy<StringPolicy <0>, UnboxedInt32Policy<1>>::Data { explicit MCharCodeAtOrNegative (MDefinition* string, MDefinition* index) : MBinaryInstruction (classOpcode, string, index) { setMovable(); setResultType(MIRType ::Int32); } public: INSTRUCTION_HEADER(CharCodeAtOrNegative) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* string() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MCodePointAt : public MBinaryInstruction, public MixPolicy< StringPolicy<0>, UnboxedInt32Policy<1>>::Data { explicit MCodePointAt(MDefinition* string, MDefinition* index ) : MBinaryInstruction(classOpcode, string, index) { setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (CodePointAt) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * string() const { return getOperand(0); } MDefinition* index () const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); } void computeRange(TempAllocator& alloc) override; bool canClone () const override { return true; } MInstruction* clone(TempAllocator & alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MCodePointAt(*this); for ( size_t i = 0; i < numOperands(); i++) res->replaceOperand (i, inputs[i]); return res; }};class MCodePointAtOrNegative : public MBinaryInstruction, public MixPolicy<StringPolicy< 0>, UnboxedInt32Policy<1>>::Data { explicit MCodePointAtOrNegative (MDefinition* string, MDefinition* index) : MBinaryInstruction (classOpcode, string, index) { setMovable(); setResultType(MIRType ::Int32); } public: INSTRUCTION_HEADER(CodePointAtOrNegative) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* string() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MNegativeToNaN : public MUnaryInstruction, public UnboxedInt32Policy <0>::Data { explicit MNegativeToNaN(MDefinition* input) : MUnaryInstruction(classOpcode, input) { setMovable(); setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(NegativeToNaN) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MNegativeToUndefined : public MUnaryInstruction, public UnboxedInt32Policy<0>::Data { explicit MNegativeToUndefined (MDefinition* input) : MUnaryInstruction(classOpcode, input) { setMovable(); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (NegativeToUndefined) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MFromCharCode : public MUnaryInstruction, public UnboxedInt32Policy<0> ::Data { explicit MFromCharCode(MDefinition* code) : MUnaryInstruction (classOpcode, code) { setMovable(); setResultType(MIRType::String ); } public: INSTRUCTION_HEADER(FromCharCode) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* code() const { return getOperand (0); } AliasSet getAliasSet() const override { return AliasSet ::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } [[nodiscard]] bool writeRecoverData( CompactBufferWriter& writer) const override ; bool canRecoverOnBailout() const override { return true; } bool canClone() const override { return true; } MInstruction* clone (TempAllocator& alloc, const MDefinitionVector& inputs ) const override { MInstruction* res = new (alloc) MFromCharCode (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MFromCharCodeEmptyIfNegative : public MUnaryInstruction, public UnboxedInt32Policy<0> ::Data { explicit MFromCharCodeEmptyIfNegative(MDefinition* code ) : MUnaryInstruction(classOpcode, code) { setMovable(); setResultType (MIRType::String); } public: INSTRUCTION_HEADER(FromCharCodeEmptyIfNegative ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* code() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); } [[nodiscard]] bool writeRecoverData( CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; } bool canClone() const override { return true ; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector & inputs) const override { MInstruction* res = new (alloc ) MFromCharCodeEmptyIfNegative(*this); for (size_t i = 0; i < numOperands(); i++) res->replaceOperand(i, inputs[i]); return res; }};class MFromCharCodeUndefinedIfNegative : public MUnaryInstruction , public UnboxedInt32Policy<0>::Data { explicit MFromCharCodeUndefinedIfNegative (MDefinition* code) : MUnaryInstruction(classOpcode, code) { setMovable (); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (FromCharCodeUndefinedIfNegative) template <typename... Args > static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* code() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MFromCodePoint : public MUnaryInstruction, public UnboxedInt32Policy<0>::Data { explicit MFromCodePoint( MDefinition* codePoint) : MUnaryInstruction(classOpcode, codePoint ) { setGuard(); setMovable(); setResultType(MIRType::String); } public: INSTRUCTION_HEADER(FromCodePoint) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* codePoint() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } bool canClone() const override { return true; } MInstruction* clone (TempAllocator& alloc, const MDefinitionVector& inputs ) const override { MInstruction* res = new (alloc) MFromCodePoint (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MStringIncludes : public MBinaryInstruction, public MixPolicy<StringPolicy <0>, StringPolicy<1>>::Data { explicit MStringIncludes (MDefinition* string, MDefinition* searchString) : MBinaryInstruction (classOpcode, string, searchString) { setMovable(); setResultType (MIRType::Boolean); } public: INSTRUCTION_HEADER(StringIncludes ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* string() const { return getOperand(0); } MDefinition* searchString() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); } bool possiblyCalls() const override { return true; }};class MStringIndexOf : public MBinaryInstruction, public MixPolicy <StringPolicy<0>, StringPolicy<1>>::Data { explicit MStringIndexOf(MDefinition* string, MDefinition* searchString ) : MBinaryInstruction(classOpcode, string, searchString) { setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (StringIndexOf) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * string() const { return getOperand(0); } MDefinition* searchString () const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool possiblyCalls() const override { return true; } };class MStringLastIndexOf : public MBinaryInstruction, public MixPolicy<StringPolicy<0>, StringPolicy<1>> ::Data { explicit MStringLastIndexOf(MDefinition* string, MDefinition * searchString) : MBinaryInstruction(classOpcode, string, searchString ) { setMovable(); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (StringLastIndexOf) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * string() const { return getOperand(0); } MDefinition* searchString () const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool possiblyCalls() const override { return true; } };class MStringStartsWith : public MBinaryInstruction, public MixPolicy<StringPolicy<0>, StringPolicy<1>> ::Data { explicit MStringStartsWith(MDefinition* string, MDefinition * searchString) : MBinaryInstruction(classOpcode, string, searchString ) { setMovable(); setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (StringStartsWith) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * string() const { return getOperand(0); } MDefinition* searchString () const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool possiblyCalls() const override { return true; } };class MStringEndsWith : public MBinaryInstruction, public MixPolicy <StringPolicy<0>, StringPolicy<1>>::Data { explicit MStringEndsWith(MDefinition* string, MDefinition* searchString ) : MBinaryInstruction(classOpcode, string, searchString) { setMovable (); setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (StringEndsWith) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * string() const { return getOperand(0); } MDefinition* searchString () const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool possiblyCalls() const override { return true; } };class MStringTrimStartIndex : public MUnaryInstruction, public StringPolicy<0>::Data { explicit MStringTrimStartIndex (MDefinition* string) : MUnaryInstruction(classOpcode, string ) { setMovable(); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (StringTrimStartIndex) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* string() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MStringTrimEndIndex : public MBinaryInstruction, public MixPolicy<StringPolicy <0>, UnboxedInt32Policy<1>>::Data { explicit MStringTrimEndIndex (MDefinition* string, MDefinition* start) : MBinaryInstruction (classOpcode, string, start) { setMovable(); setResultType(MIRType ::Int32); } public: INSTRUCTION_HEADER(StringTrimEndIndex) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* string() const { return getOperand(0); } MDefinition* start() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MStringSplit : public MBinaryInstruction, public MixPolicy< StringPolicy<0>, StringPolicy<1>>::Data { explicit MStringSplit(MDefinition* string, MDefinition* separator) : MBinaryInstruction (classOpcode, string, separator) { setResultType(MIRType::Object ); } public: INSTRUCTION_HEADER(StringSplit) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* string() const { return getOperand(0); } MDefinition* separator() const { return getOperand (1); } AliasSet getAliasSet() const override { return AliasSet ::None(); } bool possiblyCalls() const override { return true ; } [[nodiscard]] bool writeRecoverData( CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; }};class MBoxNonStrictThis : public MUnaryInstruction , public BoxPolicy<0>::Data { CompilerGCPointer<JSObject *> globalThis_; explicit MBoxNonStrictThis(MDefinition* def , JSObject* globalThis) : MUnaryInstruction(classOpcode, def) , globalThis_(globalThis) { setResultType(MIRType::Object); } public: JSObject* globalThis() const { return globalThis_; } INSTRUCTION_HEADER(BoxNonStrictThis) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } MDefinition* def() const { return getOperand (0); } AliasSet getAliasSet() const override { return AliasSet ::None(); } MDefinition* foldsTo(TempAllocator& alloc) override ; bool possiblyCalls() const override { return true; }};class MImplicitThis : public MUnaryInstruction, public ObjectPolicy <0>::Data { CompilerGCPointer<PropertyName*> name_ ; explicit MImplicitThis(MDefinition* envChain, PropertyName* name) : MUnaryInstruction(classOpcode, envChain), name_(name ) { setResultType(MIRType::Value); } public: PropertyName* name () const { return name_; } INSTRUCTION_HEADER(ImplicitThis) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* envChain() const { return getOperand(0); } bool possiblyCalls() const override { return true; }};class MUnaryCache : public MUnaryInstruction , public BoxPolicy<0>::Data { explicit MUnaryCache(MDefinition * input) : MUnaryInstruction(classOpcode, input) { setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(UnaryCache) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* input() const { return getOperand(0); }};class MCheckOverRecursed : public MNullaryInstruction { explicit MCheckOverRecursed() : MNullaryInstruction (classOpcode) { setGuard(); } public: INSTRUCTION_HEADER(CheckOverRecursed ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MInterruptCheck : public MNullaryInstruction { explicit MInterruptCheck() : MNullaryInstruction (classOpcode) { setGuard(); } public: INSTRUCTION_HEADER(InterruptCheck ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MWasmTrapIfNull : public MUnaryInstruction, public NoTypePolicy::Data { wasm ::Trap trap_; wasm::BytecodeOffset bytecodeOffset_; explicit MWasmTrapIfNull (MDefinition* ref, wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset ) : MUnaryInstruction(classOpcode, ref), trap_(trap), bytecodeOffset_ (bytecodeOffset) { setGuard(); setResultType(MIRType::None); } public: wasm::Trap trap() const { return trap_; } wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } INSTRUCTION_HEADER (WasmTrapIfNull) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * ref() const { return getOperand(0); }};class MThrowRuntimeLexicalError : public MNullaryInstruction { unsigned errorNumber_; explicit MThrowRuntimeLexicalError(unsigned errorNumber) : MNullaryInstruction (classOpcode), errorNumber_(errorNumber) { setGuard(); setResultType (MIRType::None); } public: unsigned errorNumber() const { return errorNumber_; } INSTRUCTION_HEADER(ThrowRuntimeLexicalError) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } AliasSet getAliasSet() const override;};class MGlobalDeclInstantiation : public MNullaryInstruction { explicit MGlobalDeclInstantiation() : MNullaryInstruction( classOpcode) { setGuard(); } public: INSTRUCTION_HEADER(GlobalDeclInstantiation ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); }};class MRegExp : public MNullaryInstruction { CompilerGCPointer<RegExpObject*> source_; bool hasShared_ ; explicit MRegExp(RegExpObject* source, bool hasShared) : MNullaryInstruction (classOpcode), source_(source), hasShared_(hasShared) { setResultType (MIRType::Object); } public: RegExpObject* source() const { return source_; } bool hasShared() const { return hasShared_; } INSTRUCTION_HEADER (RegExp) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } AliasSet getAliasSet () const override { return AliasSet::None(); } bool possiblyCalls () const override { return true; }};class MRegExpMatcher : public MTernaryInstruction, public MixPolicy<ObjectPolicy<0> , StringPolicy<1>, UnboxedInt32Policy<2>>::Data { explicit MRegExpMatcher(MDefinition* regexp, MDefinition* string , MDefinition* lastIndex) : MTernaryInstruction(classOpcode, regexp , string, lastIndex) { setResultType(MIRType::Value); } public : INSTRUCTION_HEADER(RegExpMatcher) template <typename... Args > static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* regexp() const { return getOperand(0); } MDefinition* string() const { return getOperand(1); } MDefinition * lastIndex() const { return getOperand(2); } bool possiblyCalls () const override { return true; } [[nodiscard]] bool writeRecoverData ( CompactBufferWriter& writer) const override; bool canRecoverOnBailout () const override { return true; }};class MRegExpSearcher : public MTernaryInstruction, public MixPolicy<ObjectPolicy<0> , StringPolicy<1>, UnboxedInt32Policy<2>>::Data { explicit MRegExpSearcher(MDefinition* regexp, MDefinition* string, MDefinition* lastIndex) : MTernaryInstruction(classOpcode , regexp, string, lastIndex) { setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER(RegExpSearcher) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* regexp() const { return getOperand(0); } MDefinition* string() const { return getOperand (1); } MDefinition* lastIndex() const { return getOperand(2); } bool possiblyCalls() const override { return true; }};class MRegExpSearcherLastLimit : public MNullaryInstruction { explicit MRegExpSearcherLastLimit() : MNullaryInstruction(classOpcode ) { setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (RegExpSearcherLastLimit) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); }};class MRegExpExecMatch : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0>, StringPolicy<1 >>::Data { explicit MRegExpExecMatch(MDefinition* regexp , MDefinition* string) : MBinaryInstruction(classOpcode, regexp , string) { setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (RegExpExecMatch) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * regexp() const { return getOperand(0); } MDefinition* string () const { return getOperand(1); } bool possiblyCalls() const override { return true; }};class MRegExpExecTest : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, StringPolicy< 1>>::Data { explicit MRegExpExecTest(MDefinition* regexp , MDefinition* string) : MBinaryInstruction(classOpcode, regexp , string) { setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (RegExpExecTest) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * regexp() const { return getOperand(0); } MDefinition* string () const { return getOperand(1); } bool possiblyCalls() const override { return true; }};class MRegExpHasCaptureGroups : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0> , StringPolicy<1>>::Data { explicit MRegExpHasCaptureGroups (MDefinition* regexp, MDefinition* input) : MBinaryInstruction (classOpcode, regexp, input) { setResultType(MIRType::Boolean ); } public: INSTRUCTION_HEADER(RegExpHasCaptureGroups) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* regexp() const { return getOperand(0); } MDefinition* input() const { return getOperand(1); } bool possiblyCalls() const override { return true; }};class MRegExpPrototypeOptimizable : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MRegExpPrototypeOptimizable (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (RegExpPrototypeOptimizable) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); }};class MRegExpInstanceOptimizable : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, ObjectPolicy< 1>>::Data { explicit MRegExpInstanceOptimizable(MDefinition * object, MDefinition* proto) : MBinaryInstruction(classOpcode , object, proto) { setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER(RegExpInstanceOptimizable) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* proto() const { return getOperand (1); } AliasSet getAliasSet() const override { return AliasSet ::None(); }};class MSubstr : public MTernaryInstruction, public MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1> , UnboxedInt32Policy<2>>::Data { explicit MSubstr(MDefinition * string, MDefinition* begin, MDefinition* length) : MTernaryInstruction (classOpcode, string, begin, length) { setResultType(MIRType:: String); } public: INSTRUCTION_HEADER(Substr) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* string() const { return getOperand(0); } MDefinition* begin() const { return getOperand (1); } MDefinition* length() const { return getOperand(2); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition * foldsTo(TempAllocator& alloc) override; bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } [[nodiscard]] bool writeRecoverData( CompactBufferWriter & writer) const override; bool canRecoverOnBailout() const override { return true; }};class MModuleMetadata : public MNullaryInstruction { CompilerGCPointer<JSObject*> module_; explicit MModuleMetadata (JSObject* module) : MNullaryInstruction(classOpcode), module_ (module) { setResultType(MIRType::Object); } public: JSObject * module() const { return module_; } INSTRUCTION_HEADER(ModuleMetadata ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); }};class MDynamicImport : public MBinaryInstruction, public MixPolicy<BoxPolicy<0>, BoxPolicy <1>>::Data { explicit MDynamicImport(MDefinition* specifier , MDefinition* options) : MBinaryInstruction(classOpcode, specifier , options) { setResultType(MIRType::Object); } public: INSTRUCTION_HEADER (DynamicImport) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * specifier() const { return getOperand(0); } MDefinition* options () const { return getOperand(1); }};class MSetFunName : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0> , BoxPolicy<1>>::Data { uint8_t prefixKind_; explicit MSetFunName(MDefinition* fun, MDefinition* name, uint8_t prefixKind ) : MBinaryInstruction(classOpcode, fun, name), prefixKind_(prefixKind ) { setResultType(MIRType::None); } public: uint8_t prefixKind () const { return prefixKind_; } INSTRUCTION_HEADER(SetFunName ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* fun() const { return getOperand(0); } MDefinition* name() const { return getOperand (1); } bool possiblyCalls() const override { return true; }}; class MSlots : public MUnaryInstruction, public ObjectPolicy< 0>::Data { explicit MSlots(MDefinition* object) : MUnaryInstruction (classOpcode, object) { setMovable(); setResultType(MIRType:: Slots); } public: INSTRUCTION_HEADER(Slots) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; AliasType mightAlias(const MDefinition* store) const override; bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MSlots (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MElements : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MElements(MDefinition* object) : MUnaryInstruction (classOpcode, object) { setMovable(); setResultType(MIRType:: Elements); } public: INSTRUCTION_HEADER(Elements) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc , const MDefinitionVector& inputs) const override { MInstruction * res = new (alloc) MElements(*this); for (size_t i = 0; i < numOperands(); i++) res->replaceOperand(i, inputs[i]); return res; }};class MInitializedLength : public MUnaryInstruction, public NoTypePolicy::Data { explicit MInitializedLength(MDefinition * elements) : MUnaryInstruction(classOpcode, elements) { setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (InitializedLength) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * elements() const { return getOperand(0); } AliasSet getAliasSet () const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } void computeRange (TempAllocator& alloc) override; bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc , const MDefinitionVector& inputs) const override { MInstruction * res = new (alloc) MInitializedLength(*this); for (size_t i = 0; i < numOperands(); i++) res->replaceOperand(i, inputs [i]); return res; }};class MSetInitializedLength : public MBinaryInstruction , public NoTypePolicy::Data { explicit MSetInitializedLength( MDefinition* elements, MDefinition* index) : MBinaryInstruction (classOpcode, elements, index) { } public: INSTRUCTION_HEADER (SetInitializedLength) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* elements() const { return getOperand(0) ; } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override; bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc , const MDefinitionVector& inputs) const override { MInstruction * res = new (alloc) MSetInitializedLength(*this); for (size_t i = 0; i < numOperands(); i++) res->replaceOperand(i, inputs [i]); return res; }};class MArrayLength : public MUnaryInstruction , public NoTypePolicy::Data { explicit MArrayLength(MDefinition * elements) : MUnaryInstruction(classOpcode, elements) { setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (ArrayLength) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * elements() const { return getOperand(0); } AliasSet getAliasSet () const override; MDefinition* foldsTo(TempAllocator& alloc ) override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } void computeRange( TempAllocator& alloc) override; bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc , const MDefinitionVector& inputs) const override { MInstruction * res = new (alloc) MArrayLength(*this); for (size_t i = 0; i < numOperands(); i++) res->replaceOperand(i, inputs[i] ); return res; }};class MSetArrayLength : public MBinaryInstruction , public NoTypePolicy::Data { explicit MSetArrayLength(MDefinition * elements, MDefinition* index) : MBinaryInstruction(classOpcode , elements, index) { } public: INSTRUCTION_HEADER(SetArrayLength ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* elements() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override;};class MFunctionLength : public MUnaryInstruction, public ObjectPolicy <0>::Data { explicit MFunctionLength(MDefinition* function ) : MUnaryInstruction(classOpcode, function) { setGuard(); setResultType (MIRType::Int32); } public: INSTRUCTION_HEADER(FunctionLength ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* function() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MFunctionName : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MFunctionName(MDefinition* function) : MUnaryInstruction(classOpcode , function) { setGuard(); setResultType(MIRType::String); } public : INSTRUCTION_HEADER(FunctionName) template <typename... Args > static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* function() const { return getOperand(0) ; } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MArrayBufferByteLength : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MArrayBufferByteLength (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setMovable(); setResultType(MIRType::IntPtr); } public: INSTRUCTION_HEADER (ArrayBufferByteLength) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MArrayBufferViewLength : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MArrayBufferViewLength (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setMovable(); setResultType(MIRType::IntPtr); } public: INSTRUCTION_HEADER (ArrayBufferViewLength) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } void computeRange(TempAllocator& alloc) override ;};class MArrayBufferViewByteOffset : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MArrayBufferViewByteOffset (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setMovable(); setResultType(MIRType::IntPtr); } public: INSTRUCTION_HEADER (ArrayBufferViewByteOffset) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } void computeRange(TempAllocator& alloc) override ;};class MArrayBufferViewElements : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MArrayBufferViewElements (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setMovable(); setResultType(MIRType::Elements); } public: INSTRUCTION_HEADER(ArrayBufferViewElements) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MArrayBufferViewElements (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MResizableTypedArrayByteOffsetMaybeOutOfBounds : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MResizableTypedArrayByteOffsetMaybeOutOfBounds(MDefinition * object) : MUnaryInstruction(classOpcode, object) { setMovable (); setResultType(MIRType::IntPtr); } public: INSTRUCTION_HEADER (ResizableTypedArrayByteOffsetMaybeOutOfBounds) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } void computeRange(TempAllocator & alloc) override;};class MResizableTypedArrayLength : public MUnaryInstruction, public ObjectPolicy<0>::Data { MemoryBarrierRequirement requiresMemoryBarrier_; explicit MResizableTypedArrayLength( MDefinition* object, MemoryBarrierRequirement requiresMemoryBarrier ) : MUnaryInstruction(classOpcode, object), requiresMemoryBarrier_ (requiresMemoryBarrier) { setGuard(); setResultType(MIRType:: IntPtr); } public: MemoryBarrierRequirement requiresMemoryBarrier () const { return requiresMemoryBarrier_; } INSTRUCTION_HEADER (ResizableTypedArrayLength) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override; void computeRange(TempAllocator & alloc) override;};class MResizableDataViewByteLength : public MUnaryInstruction, public ObjectPolicy<0>::Data { MemoryBarrierRequirement requiresMemoryBarrier_; explicit MResizableDataViewByteLength (MDefinition* object, MemoryBarrierRequirement requiresMemoryBarrier ) : MUnaryInstruction(classOpcode, object), requiresMemoryBarrier_ (requiresMemoryBarrier) { setGuard(); setResultType(MIRType:: IntPtr); } public: MemoryBarrierRequirement requiresMemoryBarrier () const { return requiresMemoryBarrier_; } INSTRUCTION_HEADER (ResizableDataViewByteLength) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override; void computeRange(TempAllocator & alloc) override;};class MGrowableSharedArrayBufferByteLength : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGrowableSharedArrayBufferByteLength(MDefinition* object) : MUnaryInstruction(classOpcode, object) { setGuard( ); setResultType(MIRType::IntPtr); } public: INSTRUCTION_HEADER (GrowableSharedArrayBufferByteLength) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } MDefinition* object() const { return getOperand (0); } AliasSet getAliasSet() const override;};class MTypedArrayElementSize : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MTypedArrayElementSize(MDefinition* object) : MUnaryInstruction (classOpcode, object) { setMovable(); setResultType(MIRType:: Int32); } public: INSTRUCTION_HEADER(TypedArrayElementSize) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); } void computeRange(TempAllocator& alloc) override;};class MGuardHasAttachedArrayBuffer : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGuardHasAttachedArrayBuffer (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setGuard(); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(GuardHasAttachedArrayBuffer) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardResizableArrayBufferViewInBounds : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGuardResizableArrayBufferViewInBounds(MDefinition * object) : MUnaryInstruction(classOpcode, object) { setGuard (); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER (GuardResizableArrayBufferViewInBounds) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MGuardResizableArrayBufferViewInBoundsOrDetached : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGuardResizableArrayBufferViewInBoundsOrDetached( MDefinition* object) : MUnaryInstruction(classOpcode, object) { setGuard(); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(GuardResizableArrayBufferViewInBoundsOrDetached ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MKeepAliveObject : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MKeepAliveObject(MDefinition* object) : MUnaryInstruction(classOpcode , object) { setGuard(); setResultType(MIRType::None); } public : INSTRUCTION_HEADER(KeepAliveObject) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } MDefinition* object() const { return getOperand (0); }};class MDebugEnterGCUnsafeRegion : public MNullaryInstruction { explicit MDebugEnterGCUnsafeRegion() : MNullaryInstruction (classOpcode) { setGuard(); setResultType(MIRType::None); } public : INSTRUCTION_HEADER(DebugEnterGCUnsafeRegion) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MDebugLeaveGCUnsafeRegion : public MNullaryInstruction { explicit MDebugLeaveGCUnsafeRegion () : MNullaryInstruction(classOpcode) { setGuard(); setResultType (MIRType::None); } public: INSTRUCTION_HEADER(DebugLeaveGCUnsafeRegion ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MArrayPush : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0> , BoxPolicy<1>>::Data { explicit MArrayPush(MDefinition * object, MDefinition* value) : MBinaryInstruction(classOpcode , object, value) { setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (ArrayPush) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * object() const { return getOperand(0); } MDefinition* value () const { return getOperand(1); } AliasSet getAliasSet() const override; void computeRange(TempAllocator& alloc) override ; bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MArrayPush (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MArraySlice : public MTernaryInstruction, public MixPolicy<ObjectPolicy <0>, UnboxedInt32Policy<1>, UnboxedInt32Policy< 2>>::Data { CompilerGCPointer<JSObject*> templateObj_ ; gc::Heap initialHeap_; explicit MArraySlice(MDefinition* object , MDefinition* begin, MDefinition* end, JSObject* templateObj , gc::Heap initialHeap) : MTernaryInstruction(classOpcode, object , begin, end), templateObj_(templateObj), initialHeap_(initialHeap ) { setResultType(MIRType::Object); } public: JSObject* templateObj () const { return templateObj_; } gc::Heap initialHeap() const { return initialHeap_; } INSTRUCTION_HEADER(ArraySlice) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* begin() const { return getOperand(1); } MDefinition* end() const { return getOperand (2); } bool possiblyCalls() const override { return true; }}; class MArgumentsSlice : public MTernaryInstruction, public MixPolicy <ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy <2>>::Data { CompilerGCPointer<JSObject*> templateObj_ ; gc::Heap initialHeap_; explicit MArgumentsSlice(MDefinition * object, MDefinition* begin, MDefinition* end, JSObject* templateObj , gc::Heap initialHeap) : MTernaryInstruction(classOpcode, object , begin, end), templateObj_(templateObj), initialHeap_(initialHeap ) { setResultType(MIRType::Object); } public: JSObject* templateObj () const { return templateObj_; } gc::Heap initialHeap() const { return initialHeap_; } INSTRUCTION_HEADER(ArgumentsSlice) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* begin() const { return getOperand(1); } MDefinition* end() const { return getOperand (2); } bool possiblyCalls() const override { return true; }}; class MFrameArgumentsSlice : public MBinaryInstruction, public MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy <1>>::Data { CompilerGCPointer<JSObject*> templateObj_ ; gc::Heap initialHeap_; explicit MFrameArgumentsSlice(MDefinition * begin, MDefinition* count, JSObject* templateObj, gc::Heap initialHeap ) : MBinaryInstruction(classOpcode, begin, count), templateObj_ (templateObj), initialHeap_(initialHeap) { setResultType(MIRType ::Object); } public: JSObject* templateObj() const { return templateObj_ ; } gc::Heap initialHeap() const { return initialHeap_; } INSTRUCTION_HEADER (FrameArgumentsSlice) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* begin() const { return getOperand(0); } MDefinition* count() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool possiblyCalls() const override { return true; }};class MNormalizeSliceTerm : public MBinaryInstruction, public MixPolicy<UnboxedInt32Policy <0>, UnboxedInt32Policy<1>>::Data { explicit MNormalizeSliceTerm (MDefinition* value, MDefinition* length) : MBinaryInstruction (classOpcode, value, length) { setMovable(); setResultType(MIRType ::Int32); } public: INSTRUCTION_HEADER(NormalizeSliceTerm) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* value() const { return getOperand(0); } MDefinition* length() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator& alloc ) override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MArrayJoin : public MBinaryInstruction, public MixPolicy<ObjectPolicy< 0>, StringPolicy<1>>::Data { explicit MArrayJoin( MDefinition* array, MDefinition* sep) : MBinaryInstruction(classOpcode , array, sep) { setResultType(MIRType::String); } public: INSTRUCTION_HEADER (ArrayJoin) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * array() const { return getOperand(0); } MDefinition* sep() const { return getOperand(1); } MDefinition* foldsTo(TempAllocator & alloc) override; bool possiblyCalls() const override { return true; }};class MObjectKeys : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MObjectKeys(MDefinition * object) : MUnaryInstruction(classOpcode, object) { setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(ObjectKeys) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } [[nodiscard]] bool writeRecoverData ( CompactBufferWriter& writer) const override; bool canRecoverOnBailout () const override;};class MObjectKeysLength : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MObjectKeysLength (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (ObjectKeysLength) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * object() const { return getOperand(0); } AliasSet getAliasSet () const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } bool canClone () const override { return true; } MInstruction* clone(TempAllocator & alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MObjectKeysLength(*this); for (size_t i = 0; i < numOperands(); i++) res->replaceOperand (i, inputs[i]); return res; }};class MHomeObjectSuperBase : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MHomeObjectSuperBase(MDefinition* homeObject) : MUnaryInstruction (classOpcode, homeObject) { setMovable(); setResultType(MIRType ::Value); } public: INSTRUCTION_HEADER(HomeObjectSuperBase) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* homeObject() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MBindNameCache : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MBindNameCache(MDefinition* envChain) : MUnaryInstruction(classOpcode , envChain) { setResultType(MIRType::Object); } public: INSTRUCTION_HEADER (BindNameCache) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * envChain() const { return getOperand(0); }};class MCallBindVar : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MCallBindVar(MDefinition* environmentChain) : MUnaryInstruction (classOpcode, environmentChain) { setMovable(); setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(CallBindVar) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* environmentChain () const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override;};class MGuardShape : public MUnaryInstruction, public ObjectPolicy<0>::Data { CompilerGCPointer <Shape*> shape_; explicit MGuardShape(MDefinition* object , Shape* shape) : MUnaryInstruction(classOpcode, object), shape_ (shape) { setGuard(); setMovable(); setResultType(MIRType::Object ); } public: Shape* shape() const { return shape_; } INSTRUCTION_HEADER (GuardShape) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * object() const { return getOperand(0); } AliasSet getAliasSet () const override; AliasType mightAlias(const MDefinition* store ) const override; bool congruentTo(const MDefinition* ins) const override;};class MGuardFuse : public MNullaryInstruction { RealmFuses ::FuseIndex fuseIndex_; explicit MGuardFuse(RealmFuses::FuseIndex fuseIndex) : MNullaryInstruction(classOpcode), fuseIndex_(fuseIndex ) { setGuard(); setMovable(); setResultType(MIRType::None); } public: RealmFuses::FuseIndex fuseIndex() const { return fuseIndex_ ; } INSTRUCTION_HEADER(GuardFuse) template <typename... Args > static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } AliasSet getAliasSet() const override; bool congruentTo (const MDefinition* ins) const override;};class MGuardMultipleShapes : public MBinaryInstruction, public MixPolicy<ObjectPolicy <0>, ObjectPolicy<1>>::Data { explicit MGuardMultipleShapes (MDefinition* object, MDefinition* shapeList) : MBinaryInstruction (classOpcode, object, shapeList) { setGuard(); setMovable(); setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(GuardMultipleShapes ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* shapeList() const { return getOperand(1); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MGuardIsNativeObject : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MGuardIsNativeObject (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setGuard(); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(GuardIsNativeObject) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardGlobalGeneration : public MNullaryInstruction { uint32_t expected_; const void* generationAddr_; explicit MGuardGlobalGeneration (uint32_t expected, const void* generationAddr) : MNullaryInstruction (classOpcode), expected_(expected), generationAddr_(generationAddr ) { setGuard(); setMovable(); setResultType(MIRType::None); } public: uint32_t expected() const { return expected_; } const void* generationAddr() const { return generationAddr_; } INSTRUCTION_HEADER (GuardGlobalGeneration) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } AliasSet getAliasSet() const override; bool congruentTo (const MDefinition* ins) const override;};class MGuardIsProxy : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGuardIsProxy(MDefinition* object) : MUnaryInstruction (classOpcode, object) { setGuard(); setMovable(); setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(GuardIsProxy) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardIsNotDOMProxy : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGuardIsNotDOMProxy(MDefinition * proxy) : MUnaryInstruction(classOpcode, proxy) { setGuard() ; setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER (GuardIsNotDOMProxy) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* proxy() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardIsNotProxy : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGuardIsNotProxy(MDefinition* object) : MUnaryInstruction (classOpcode, object) { setGuard(); setMovable(); setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(GuardIsNotProxy ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); }};class MProxyGet : public MUnaryInstruction, public ObjectPolicy< 0>::Data { jsid id_; explicit MProxyGet(MDefinition* proxy , jsid id) : MUnaryInstruction(classOpcode, proxy), id_(id) { setResultType(MIRType::Value); } public: jsid id() const { return id_; } INSTRUCTION_HEADER(ProxyGet) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } MDefinition* proxy() const { return getOperand (0); } bool possiblyCalls() const override { return true; }}; class MProxyGetByValue : public MBinaryInstruction, public MixPolicy <ObjectPolicy<0>, BoxPolicy<1>>::Data { explicit MProxyGetByValue(MDefinition* proxy, MDefinition* idVal) : MBinaryInstruction (classOpcode, proxy, idVal) { setResultType(MIRType::Value); } public: INSTRUCTION_HEADER(ProxyGetByValue) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* proxy() const { return getOperand(0); } MDefinition* idVal() const { return getOperand (1); } bool possiblyCalls() const override { return true; }}; class MProxyHasProp : public MBinaryInstruction, public MixPolicy <ObjectPolicy<0>, BoxPolicy<1>>::Data { bool hasOwn_; explicit MProxyHasProp(MDefinition* proxy, MDefinition * idVal, bool hasOwn) : MBinaryInstruction(classOpcode, proxy , idVal), hasOwn_(hasOwn) { setResultType(MIRType::Boolean); } public: bool hasOwn() const { return hasOwn_; } INSTRUCTION_HEADER (ProxyHasProp) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * proxy() const { return getOperand(0); } MDefinition* idVal( ) const { return getOperand(1); } bool possiblyCalls() const override { return true; }};class MProxySet : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>> ::Data { jsid id_; bool strict_; explicit MProxySet(MDefinition * proxy, MDefinition* rhs, jsid id, bool strict) : MBinaryInstruction (classOpcode, proxy, rhs), id_(id), strict_(strict) { } public : jsid id() const { return id_; } bool strict() const { return strict_; } INSTRUCTION_HEADER(ProxySet) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* proxy() const { return getOperand(0); } MDefinition* rhs() const { return getOperand (1); } bool possiblyCalls() const override { return true; }}; class MProxySetByValue : public MTernaryInstruction, public MixPolicy <ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2 >>::Data { bool strict_; explicit MProxySetByValue(MDefinition * proxy, MDefinition* idVal, MDefinition* rhs, bool strict) : MTernaryInstruction(classOpcode, proxy, idVal, rhs), strict_ (strict) { } public: bool strict() const { return strict_; } INSTRUCTION_HEADER (ProxySetByValue) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * proxy() const { return getOperand(0); } MDefinition* idVal( ) const { return getOperand(1); } MDefinition* rhs() const { return getOperand(2); } bool possiblyCalls() const override { return true; }};class MCallSetArrayLength : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>> ::Data { bool strict_; explicit MCallSetArrayLength(MDefinition * obj, MDefinition* rhs, bool strict) : MBinaryInstruction(classOpcode , obj, rhs), strict_(strict) { } public: bool strict() const { return strict_; } INSTRUCTION_HEADER(CallSetArrayLength) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* obj() const { return getOperand(0); } MDefinition* rhs() const { return getOperand (1); } bool possiblyCalls() const override { return true; }}; class MMegamorphicLoadSlot : public MUnaryInstruction, public ObjectPolicy<0>::Data { PropertyKey name_; explicit MMegamorphicLoadSlot (MDefinition* object, PropertyKey name) : MUnaryInstruction(classOpcode , object), name_(name) { setGuard(); setResultType(MIRType::Value ); } public: PropertyKey name() const { return name_; } INSTRUCTION_HEADER (MegamorphicLoadSlot) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override; bool possiblyCalls() const override { return true; }};class MMegamorphicLoadSlotByValue : public MBinaryInstruction, public MixPolicy<ObjectPolicy <0>, BoxPolicy<1>>::Data { explicit MMegamorphicLoadSlotByValue (MDefinition* object, MDefinition* idVal) : MBinaryInstruction (classOpcode, object, idVal) { setGuard(); setResultType(MIRType ::Value); } public: INSTRUCTION_HEADER(MegamorphicLoadSlotByValue ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* idVal() const { return getOperand(1); } AliasSet getAliasSet() const override; MDefinition * foldsTo(TempAllocator& alloc) override; bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool possiblyCalls() const override { return true; } };class MMegamorphicStoreSlot : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>:: Data { PropertyKey name_; bool strict_; explicit MMegamorphicStoreSlot (MDefinition* object, MDefinition* rhs, PropertyKey name, bool strict) : MBinaryInstruction(classOpcode, object, rhs), name_ (name), strict_(strict) { } public: PropertyKey name() const { return name_; } bool strict() const { return strict_; } INSTRUCTION_HEADER (MegamorphicStoreSlot) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } MDefinition* rhs() const { return getOperand(1); } bool possiblyCalls () const override { return true; }};class MMegamorphicHasProp : public MBinaryInstruction, public MixPolicy<ObjectPolicy <0>, BoxPolicy<1>>::Data { bool hasOwn_; explicit MMegamorphicHasProp(MDefinition* object, MDefinition* idVal, bool hasOwn) : MBinaryInstruction(classOpcode, object, idVal ), hasOwn_(hasOwn) { setGuard(); setResultType(MIRType::Boolean ); } public: bool hasOwn() const { return hasOwn_; } INSTRUCTION_HEADER (MegamorphicHasProp) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } MDefinition* idVal() const { return getOperand(1); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override; bool possiblyCalls() const override { return true; }};class MSmallObjectVariableKeyHasProp : public MUnaryInstruction , public StringPolicy<0>::Data { CompilerGCPointer<Shape *> shape_; explicit MSmallObjectVariableKeyHasProp(MDefinition * idStr, Shape* shape) : MUnaryInstruction(classOpcode, idStr ), shape_(shape) { setResultType(MIRType::Boolean); } public: Shape* shape() const { return shape_; } INSTRUCTION_HEADER(SmallObjectVariableKeyHasProp ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* idStr() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override;};class MGuardIsNotArrayBufferMaybeShared : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MGuardIsNotArrayBufferMaybeShared (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setGuard(); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(GuardIsNotArrayBufferMaybeShared ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); }};class MGuardIsTypedArray : public MUnaryInstruction, public ObjectPolicy <0>::Data { explicit MGuardIsTypedArray(MDefinition* object ) : MUnaryInstruction(classOpcode, object) { setGuard(); setMovable (); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER (GuardIsTypedArray) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * object() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MGuardIsFixedLengthTypedArray : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MGuardIsFixedLengthTypedArray (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setGuard(); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(GuardIsFixedLengthTypedArray) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardIsResizableTypedArray : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MGuardIsResizableTypedArray (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setGuard(); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(GuardIsResizableTypedArray) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardHasProxyHandler : public MUnaryInstruction, public ObjectPolicy<0>::Data { const void* handler_; explicit MGuardHasProxyHandler(MDefinition* object, const void* handler ) : MUnaryInstruction(classOpcode, object), handler_(handler) { setGuard(); setMovable(); setResultType(MIRType::Object); } public: const void* handler() const { return handler_; } INSTRUCTION_HEADER (GuardHasProxyHandler) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MNurseryObject : public MNullaryInstruction { uint32_t nurseryIndex_; explicit MNurseryObject(uint32_t nurseryIndex) : MNullaryInstruction( classOpcode), nurseryIndex_(nurseryIndex) { setMovable(); setResultType (MIRType::Object); } public: uint32_t nurseryIndex() const { return nurseryIndex_; } INSTRUCTION_HEADER(NurseryObject) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override;};class MGuardNullOrUndefined : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MGuardNullOrUndefined(MDefinition* value) : MUnaryInstruction (classOpcode, value) { setGuard(); setMovable(); setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(GuardNullOrUndefined ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* value() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); }};class MGuardIsNotObject : public MUnaryInstruction, public BoxPolicy <0>::Data { explicit MGuardIsNotObject(MDefinition* value ) : MUnaryInstruction(classOpcode, value) { setGuard(); setMovable (); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (GuardIsNotObject) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * value() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } MDefinition* foldsTo (TempAllocator& alloc) override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardFunctionIsNonBuiltinCtor : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MGuardFunctionIsNonBuiltinCtor (MDefinition* function) : MUnaryInstruction(classOpcode, function ) { setGuard(); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(GuardFunctionIsNonBuiltinCtor) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* function() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardFunctionKind : public MUnaryInstruction, public ObjectPolicy<0>::Data { FunctionFlags::FunctionKind expected_; bool bailOnEquality_ ; explicit MGuardFunctionKind(MDefinition* function, FunctionFlags ::FunctionKind expected, bool bailOnEquality) : MUnaryInstruction (classOpcode, function), expected_(expected), bailOnEquality_ (bailOnEquality) { setGuard(); setMovable(); setResultType(MIRType ::Object); } public: FunctionFlags::FunctionKind expected() const { return expected_; } bool bailOnEquality() const { return bailOnEquality_ ; } INSTRUCTION_HEADER(GuardFunctionKind) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* function() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override;};class MGuardFunctionScript : public MUnaryInstruction, public ObjectPolicy<0>::Data { CompilerGCPointer<BaseScript*> expected_; uint16_t nargs_ ; FunctionFlags flags_; explicit MGuardFunctionScript(MDefinition * function, BaseScript* expected, uint16_t nargs, FunctionFlags flags) : MUnaryInstruction(classOpcode, function), expected_ (expected), nargs_(nargs), flags_(flags) { setGuard(); setMovable (); setResultType(MIRType::Object); } public: BaseScript* expected () const { return expected_; } uint16_t nargs() const { return nargs_; } FunctionFlags flags() const { return flags_; } INSTRUCTION_HEADER (GuardFunctionScript) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* function() const { return getOperand(0) ; } AliasSet getAliasSet() const override; MDefinition* foldsTo (TempAllocator& alloc) override; bool congruentTo(const MDefinition * ins) const override;};class MGuardSpecificAtom : public MUnaryInstruction , public StringPolicy<0>::Data { CompilerGCPointer<JSAtom *> atom_; explicit MGuardSpecificAtom(MDefinition* str, JSAtom * atom) : MUnaryInstruction(classOpcode, str), atom_(atom) { setGuard (); setMovable(); setResultType(MIRType::String); } public: JSAtom * atom() const { return atom_; } INSTRUCTION_HEADER(GuardSpecificAtom ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* str() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override;};class MGuardSpecificInt32 : public MUnaryInstruction , public UnboxedInt32Policy<0>::Data { int32_t expected_ ; explicit MGuardSpecificInt32(MDefinition* num, int32_t expected ) : MUnaryInstruction(classOpcode, num), expected_(expected) { setGuard(); setMovable(); setResultType(MIRType::Int32); } public : int32_t expected() const { return expected_; } INSTRUCTION_HEADER (GuardSpecificInt32) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* num() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition * foldsTo(TempAllocator& alloc) override;};class MGuardStringToIndex : public MUnaryInstruction, public StringPolicy<0>::Data { explicit MGuardStringToIndex(MDefinition* string) : MUnaryInstruction (classOpcode, string) { setGuard(); setMovable(); setResultType (MIRType::Int32); } public: INSTRUCTION_HEADER(GuardStringToIndex ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* string() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); }};class MGuardStringToInt32 : public MUnaryInstruction, public StringPolicy <0>::Data { explicit MGuardStringToInt32(MDefinition* string ) : MUnaryInstruction(classOpcode, string) { setGuard(); setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (GuardStringToInt32) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* string() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } MDefinition* foldsTo(TempAllocator& alloc) override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardStringToDouble : public MUnaryInstruction, public StringPolicy<0>::Data { explicit MGuardStringToDouble(MDefinition* string) : MUnaryInstruction (classOpcode, string) { setGuard(); setMovable(); setResultType (MIRType::Double); } public: INSTRUCTION_HEADER(GuardStringToDouble ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* string() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); }};class MGuardNoDenseElements : public MUnaryInstruction, public ObjectPolicy <0>::Data { explicit MGuardNoDenseElements(MDefinition* object) : MUnaryInstruction(classOpcode, object) { setGuard( ); setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER (GuardNoDenseElements) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override;};class MFunctionEnvironment : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MFunctionEnvironment(MDefinition* function) : MUnaryInstruction (classOpcode, function) { setMovable(); setResultType(MIRType ::Object); } public: INSTRUCTION_HEADER(FunctionEnvironment) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* function() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override;};class MNewLexicalEnvironmentObject : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MNewLexicalEnvironmentObject(MDefinition* templateObj) : MUnaryInstruction (classOpcode, templateObj) { setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(NewLexicalEnvironmentObject) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* templateObj() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MNewClassBodyEnvironmentObject : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MNewClassBodyEnvironmentObject(MDefinition* templateObj ) : MUnaryInstruction(classOpcode, templateObj) { setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(NewClassBodyEnvironmentObject ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* templateObj() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MNewVarEnvironmentObject : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MNewVarEnvironmentObject(MDefinition* templateObj ) : MUnaryInstruction(classOpcode, templateObj) { setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(NewVarEnvironmentObject ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* templateObj() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MHomeObject : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MHomeObject(MDefinition* function) : MUnaryInstruction(classOpcode , function) { setMovable(); setResultType(MIRType::Object); } public: INSTRUCTION_HEADER(HomeObject) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* function() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MAllocateAndStoreSlot : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>> ::Data { uint32_t slotOffset_; CompilerGCPointer<Shape*> shape_; uint32_t numNewSlots_; explicit MAllocateAndStoreSlot (MDefinition* object, MDefinition* value, uint32_t slotOffset , Shape* shape, uint32_t numNewSlots) : MBinaryInstruction(classOpcode , object, value), slotOffset_(slotOffset), shape_(shape), numNewSlots_ (numNewSlots) { } public: uint32_t slotOffset() const { return slotOffset_; } Shape* shape() const { return shape_; } uint32_t numNewSlots() const { return numNewSlots_; } INSTRUCTION_HEADER (AllocateAndStoreSlot) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } MDefinition* value() const { return getOperand(1); } AliasSet getAliasSet() const override; bool possiblyCalls() const override { return true; }};class MAddSlotAndCallAddPropHook : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>> ::Data { CompilerGCPointer<Shape*> shape_; explicit MAddSlotAndCallAddPropHook (MDefinition* object, MDefinition* value, Shape* shape) : MBinaryInstruction (classOpcode, object, value), shape_(shape) { } public: Shape * shape() const { return shape_; } INSTRUCTION_HEADER(AddSlotAndCallAddPropHook ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* value() const { return getOperand(1); } bool possiblyCalls() const override { return true; }};class MGetNameCache : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGetNameCache(MDefinition * envObj) : MUnaryInstruction(classOpcode, envObj) { setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(GetNameCache) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* envObj() const { return getOperand(0); }};class MCallGetIntrinsicValue : public MNullaryInstruction { CompilerGCPointer<PropertyName*> name_; explicit MCallGetIntrinsicValue(PropertyName* name) : MNullaryInstruction(classOpcode), name_(name) { setResultType (MIRType::Value); } public: PropertyName* name() const { return name_; } INSTRUCTION_HEADER(CallGetIntrinsicValue) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } bool possiblyCalls() const override { return true; }};class MDeleteProperty : public MUnaryInstruction , public BoxPolicy<0>::Data { CompilerGCPointer<PropertyName *> name_; bool strict_; explicit MDeleteProperty(MDefinition * value, PropertyName* name, bool strict) : MUnaryInstruction (classOpcode, value), name_(name), strict_(strict) { setResultType (MIRType::Boolean); } public: PropertyName* name() const { return name_; } bool strict() const { return strict_; } INSTRUCTION_HEADER (DeleteProperty) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * value() const { return getOperand(0); }};class MDeleteElement : public MBinaryInstruction, public MixPolicy<BoxPolicy< 0>, BoxPolicy<1>>::Data { bool strict_; explicit MDeleteElement (MDefinition* value, MDefinition* index, bool strict) : MBinaryInstruction (classOpcode, value, index), strict_(strict) { setResultType( MIRType::Boolean); } public: bool strict() const { return strict_ ; } INSTRUCTION_HEADER(DeleteElement) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } MDefinition* value() const { return getOperand (0); } MDefinition* index() const { return getOperand(1); }}; class MValueToIterator : public MUnaryInstruction, public BoxPolicy <0>::Data { explicit MValueToIterator(MDefinition* value ) : MUnaryInstruction(classOpcode, value) { setResultType(MIRType ::Object); } public: INSTRUCTION_HEADER(ValueToIterator) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* value() const { return getOperand(0); }};class MIteratorHasIndices : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0> , ObjectPolicy<1>>::Data { explicit MIteratorHasIndices (MDefinition* object, MDefinition* iterator) : MBinaryInstruction (classOpcode, object, iterator) { setResultType(MIRType::Boolean ); } public: INSTRUCTION_HEADER(IteratorHasIndices) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* iterator() const { return getOperand(1); } AliasSet getAliasSet() const override;};class MLoadSlotByIteratorIndex : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>> ::Data { explicit MLoadSlotByIteratorIndex(MDefinition* object , MDefinition* iterator) : MBinaryInstruction(classOpcode, object , iterator) { setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (LoadSlotByIteratorIndex) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } MDefinition* iterator() const { return getOperand(1); } AliasSet getAliasSet() const override;};class MStoreSlotByIteratorIndex : public MTernaryInstruction, public MixPolicy<ObjectPolicy <0>, ObjectPolicy<1>, BoxPolicy<2>>::Data { explicit MStoreSlotByIteratorIndex(MDefinition* object, MDefinition * iterator, MDefinition* value) : MTernaryInstruction(classOpcode , object, iterator, value) { } public: INSTRUCTION_HEADER(StoreSlotByIteratorIndex ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* iterator() const { return getOperand(1); } MDefinition* value() const { return getOperand (2); } AliasSet getAliasSet() const override;};class MLoadDOMExpandoValue : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MLoadDOMExpandoValue(MDefinition* proxy) : MUnaryInstruction (classOpcode, proxy) { setMovable(); setResultType(MIRType::Value ); } public: INSTRUCTION_HEADER(LoadDOMExpandoValue) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* proxy() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MLoadDOMExpandoValueIgnoreGeneration : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MLoadDOMExpandoValueIgnoreGeneration(MDefinition* proxy) : MUnaryInstruction(classOpcode, proxy) { setMovable( ); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (LoadDOMExpandoValueIgnoreGeneration) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } MDefinition* proxy() const { return getOperand (0); } AliasSet getAliasSet() const override; bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MGuardDOMExpandoMissingOrGuardShape : public MUnaryInstruction , public BoxPolicy<0>::Data { CompilerGCPointer<Shape *> shape_; explicit MGuardDOMExpandoMissingOrGuardShape(MDefinition * expando, Shape* shape) : MUnaryInstruction(classOpcode, expando ), shape_(shape) { setGuard(); setMovable(); setResultType(MIRType ::Value); } public: Shape* shape() const { return shape_; } INSTRUCTION_HEADER (GuardDOMExpandoMissingOrGuardShape) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } MDefinition* expando() const { return getOperand (0); } AliasSet getAliasSet() const override; bool congruentTo (const MDefinition* ins) const override;};class MStringLength : public MUnaryInstruction, public StringPolicy<0>::Data { explicit MStringLength(MDefinition* string) : MUnaryInstruction (classOpcode, string) { setMovable(); setResultType(MIRType:: Int32); } public: INSTRUCTION_HEADER(StringLength) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* string() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); } void computeRange(TempAllocator& alloc) override; [[nodiscard ]] bool writeRecoverData( CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; } bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MStringLength (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MOptimizeSpreadCallCache : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MOptimizeSpreadCallCache(MDefinition* value) : MUnaryInstruction (classOpcode, value) { setResultType(MIRType::Value); } public : INSTRUCTION_HEADER(OptimizeSpreadCallCache) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* value() const { return getOperand(0); }};class MIteratorMore : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MIteratorMore (MDefinition* iterator) : MUnaryInstruction(classOpcode, iterator ) { setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (IteratorMore) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * iterator() const { return getOperand(0); }};class MIsNoIter : public MUnaryInstruction, public NoTypePolicy::Data { explicit MIsNoIter(MDefinition* def) : MUnaryInstruction(classOpcode, def) { setMovable(); setResultType(MIRType::Boolean); } public : INSTRUCTION_HEADER(IsNoIter) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* def() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MIteratorEnd : public MUnaryInstruction, public ObjectPolicy <0>::Data { explicit MIteratorEnd(MDefinition* iterator ) : MUnaryInstruction(classOpcode, iterator) { } public: INSTRUCTION_HEADER (IteratorEnd) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * iterator() const { return getOperand(0); }};class MCloseIterCache : public MUnaryInstruction, public ObjectPolicy<0>::Data { uint8_t completionKind_; explicit MCloseIterCache(MDefinition * iter, uint8_t completionKind) : MUnaryInstruction(classOpcode , iter), completionKind_(completionKind) { } public: uint8_t completionKind () const { return completionKind_; } INSTRUCTION_HEADER(CloseIterCache ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* iter() const { return getOperand(0); } bool possiblyCalls() const override { return true; }};class MOptimizeGetIteratorCache : public MUnaryInstruction , public BoxPolicy<0>::Data { explicit MOptimizeGetIteratorCache (MDefinition* value) : MUnaryInstruction(classOpcode, value) { setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (OptimizeGetIteratorCache) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* value() const { return getOperand(0); } };class MNewPrivateName : public MNullaryInstruction { CompilerGCPointer <JSAtom*> name_; explicit MNewPrivateName(JSAtom* name) : MNullaryInstruction(classOpcode), name_(name) { setResultType (MIRType::Symbol); } public: JSAtom* name() const { return name_ ; } INSTRUCTION_HEADER(NewPrivateName) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } bool possiblyCalls() const override { return true; }};class MInstanceOfCache : public MBinaryInstruction, public MixPolicy<BoxPolicy<0>, ObjectPolicy<1>> ::Data { explicit MInstanceOfCache(MDefinition* obj, MDefinition * proto) : MBinaryInstruction(classOpcode, obj, proto) { setResultType (MIRType::Boolean); } public: INSTRUCTION_HEADER(InstanceOfCache ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* obj() const { return getOperand(0); } MDefinition* proto() const { return getOperand (1); }};class MArgumentsLength : public MNullaryInstruction { explicit MArgumentsLength() : MNullaryInstruction(classOpcode ) { setMovable(); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (ArgumentsLength) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } AliasSet getAliasSet () const override { return AliasSet::None(); } bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } void computeRange(TempAllocator& alloc) override ; [[nodiscard]] bool writeRecoverData( CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; }};class MGetFrameArgument : public MUnaryInstruction , public UnboxedInt32Policy<0>::Data { explicit MGetFrameArgument (MDefinition* index) : MUnaryInstruction(classOpcode, index) { setMovable(); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (GetFrameArgument) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * index() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MGetFrameArgumentHole : public MBinaryInstruction , public MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy <1>>::Data { explicit MGetFrameArgumentHole(MDefinition * index, MDefinition* length) : MBinaryInstruction(classOpcode , index, length) { setGuard(); setMovable(); setResultType(MIRType ::Value); } public: INSTRUCTION_HEADER(GetFrameArgumentHole) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* index() const { return getOperand(0); } MDefinition* length() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MNewTarget : public MNullaryInstruction { explicit MNewTarget () : MNullaryInstruction(classOpcode) { setMovable(); setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(NewTarget) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MRest : public MUnaryInstruction, public UnboxedInt32Policy <0>::Data { unsigned numFormals_; CompilerGCPointer< Shape*> shape_; explicit MRest(MDefinition* numActuals, unsigned numFormals, Shape* shape) : MUnaryInstruction(classOpcode, numActuals ), numFormals_(numFormals), shape_(shape) { setResultType(MIRType ::Object); } public: unsigned numFormals() const { return numFormals_ ; } Shape* shape() const { return shape_; } INSTRUCTION_HEADER (Rest) template <typename... Args> static MThisOpcode* New (TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * numActuals() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } bool possiblyCalls () const override { return true; } [[nodiscard]] bool writeRecoverData ( CompactBufferWriter& writer) const override; bool canRecoverOnBailout () const override { return true; }};class MAssertCanElidePostWriteBarrier : public MBinaryInstruction, public MixPolicy<ObjectPolicy <0>, BoxPolicy<1>>::Data { explicit MAssertCanElidePostWriteBarrier (MDefinition* object, MDefinition* value) : MBinaryInstruction (classOpcode, object, value) { setGuard(); setResultType(MIRType ::None); } public: INSTRUCTION_HEADER(AssertCanElidePostWriteBarrier ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* value() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MNewNamedLambdaObject : public MNullaryInstruction { CompilerGCPointer<NamedLambdaObject*> templateObj_; explicit MNewNamedLambdaObject(NamedLambdaObject* templateObj) : MNullaryInstruction (classOpcode), templateObj_(templateObj) { setResultType(MIRType ::Object); } public: NamedLambdaObject* templateObj() const { return templateObj_; } INSTRUCTION_HEADER(NewNamedLambdaObject ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MIsConstructor : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MIsConstructor(MDefinition* object) : MUnaryInstruction (classOpcode, object) { setMovable(); setResultType(MIRType:: Boolean); } public: INSTRUCTION_HEADER(IsConstructor) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MIsCrossRealmArrayConstructor : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MIsCrossRealmArrayConstructor (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setMovable(); setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (IsCrossRealmArrayConstructor) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MIsObject : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MIsObject(MDefinition* object) : MUnaryInstruction(classOpcode , object) { setMovable(); setResultType(MIRType::Boolean); } public : INSTRUCTION_HEADER(IsObject) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } MDefinition* foldsTo(TempAllocator& alloc) override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MIsNullOrUndefined : public MUnaryInstruction, public NoTypePolicy::Data { explicit MIsNullOrUndefined(MDefinition* value) : MUnaryInstruction(classOpcode , value) { setMovable(); setResultType(MIRType::Boolean); } public : INSTRUCTION_HEADER(IsNullOrUndefined) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* value() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator& alloc ) override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } bool canConsumeFloat32 (MUse* use) const override { return true; }};class MObjectClassToString : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MObjectClassToString(MDefinition* object) : MUnaryInstruction (classOpcode, object) { setGuard(); setMovable(); setResultType (MIRType::String); } public: INSTRUCTION_HEADER(ObjectClassToString ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } bool possiblyCalls() const override { return true; }};class MCheckReturn : public MBinaryInstruction , public MixPolicy<BoxPolicy<0>, BoxPolicy<1>> ::Data { explicit MCheckReturn(MDefinition* returnValue, MDefinition * thisValue) : MBinaryInstruction(classOpcode, returnValue, thisValue ) { setGuard(); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (CheckReturn) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * returnValue() const { return getOperand(0); } MDefinition* thisValue () const { return getOperand(1); } AliasSet getAliasSet() const override; MDefinition* foldsTo(TempAllocator& alloc) override ;};class MCheckThis : public MUnaryInstruction, public BoxPolicy <0>::Data { explicit MCheckThis(MDefinition* thisValue) : MUnaryInstruction(classOpcode, thisValue) { setGuard(); setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(CheckThis) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* thisValue() const { return getOperand(0); } AliasSet getAliasSet() const override ; MDefinition* foldsTo(TempAllocator& alloc) override;};class MAsyncResolve : public MBinaryInstruction, public MixPolicy< ObjectPolicy<0>, BoxPolicy<1>>::Data { explicit MAsyncResolve(MDefinition* generator, MDefinition* value) : MBinaryInstruction (classOpcode, generator, value) { setResultType(MIRType::Object ); } public: INSTRUCTION_HEADER(AsyncResolve) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* generator() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); }};class MAsyncReject : public MTernaryInstruction, public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy <2>>::Data { explicit MAsyncReject(MDefinition* generator , MDefinition* reason, MDefinition* stack) : MTernaryInstruction (classOpcode, generator, reason, stack) { setResultType(MIRType ::Object); } public: INSTRUCTION_HEADER(AsyncReject) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* generator() const { return getOperand(0); } MDefinition* reason() const { return getOperand(1); } MDefinition* stack() const { return getOperand (2); }};class MGeneratorReturn : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MGeneratorReturn(MDefinition * input) : MUnaryInstruction(classOpcode, input) { setGuard() ; } public: INSTRUCTION_HEADER(GeneratorReturn) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MAsyncAwait : public MBinaryInstruction , public MixPolicy<BoxPolicy<0>, ObjectPolicy<1>> ::Data { explicit MAsyncAwait(MDefinition* value, MDefinition * generator) : MBinaryInstruction(classOpcode, value, generator ) { setResultType(MIRType::Object); } public: INSTRUCTION_HEADER (AsyncAwait) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * value() const { return getOperand(0); } MDefinition* generator () const { return getOperand(1); }};class MCheckThisReinit : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MCheckThisReinit(MDefinition* thisValue) : MUnaryInstruction (classOpcode, thisValue) { setGuard(); setResultType(MIRType:: Value); } public: INSTRUCTION_HEADER(CheckThisReinit) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* thisValue() const { return getOperand(0); } AliasSet getAliasSet() const override ; MDefinition* foldsTo(TempAllocator& alloc) override;};class MCanSkipAwait : public MUnaryInstruction, public BoxPolicy< 0>::Data { explicit MCanSkipAwait(MDefinition* value) : MUnaryInstruction (classOpcode, value) { setResultType(MIRType::Boolean); } public : INSTRUCTION_HEADER(CanSkipAwait) template <typename... Args > static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* value() const { return getOperand(0); } };class MIncrementWarmUpCounter : public MNullaryInstruction { CompilerGCPointer<JSScript*> script_; explicit MIncrementWarmUpCounter (JSScript* script) : MNullaryInstruction(classOpcode), script_ (script) { } public: JSScript* script() const { return script_ ; } INSTRUCTION_HEADER(IncrementWarmUpCounter) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MCheckIsObj : public MUnaryInstruction , public BoxPolicy<0>::Data { uint8_t checkKind_; explicit MCheckIsObj(MDefinition* value, uint8_t checkKind) : MUnaryInstruction (classOpcode, value), checkKind_(checkKind) { setGuard(); setResultType (MIRType::Object); } public: uint8_t checkKind() const { return checkKind_; } INSTRUCTION_HEADER(CheckIsObj) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* value() const { return getOperand(0); } AliasSet getAliasSet() const override; MDefinition * foldsTo(TempAllocator& alloc) override;};class MCheckObjCoercible : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MCheckObjCoercible(MDefinition* checkValue) : MUnaryInstruction (classOpcode, checkValue) { setGuard(); setResultType(MIRType ::Value); } public: INSTRUCTION_HEADER(CheckObjCoercible) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* checkValue() const { return getOperand(0); } AliasSet getAliasSet() const override ; MDefinition* foldsTo(TempAllocator& alloc) override;};class MCheckClassHeritage : public MUnaryInstruction, public BoxPolicy <0>::Data { explicit MCheckClassHeritage(MDefinition* heritage ) : MUnaryInstruction(classOpcode, heritage) { setGuard(); setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(CheckClassHeritage ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* heritage() const { return getOperand(0); }};class MDebugCheckSelfHosted : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MDebugCheckSelfHosted(MDefinition* checkValue) : MUnaryInstruction (classOpcode, checkValue) { setGuard(); setResultType(MIRType ::Value); } public: INSTRUCTION_HEADER(DebugCheckSelfHosted) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* checkValue() const { return getOperand(0); }};class MIsPackedArray : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MIsPackedArray (MDefinition* object) : MUnaryInstruction(classOpcode, object ) { setMovable(); setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (IsPackedArray) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * object() const { return getOperand(0); } AliasSet getAliasSet () const override;};class MGuardArrayIsPacked : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MGuardArrayIsPacked (MDefinition* array) : MUnaryInstruction(classOpcode, array) { setGuard(); setMovable(); setResultType(MIRType::Object); } public : INSTRUCTION_HEADER(GuardArrayIsPacked) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* array() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MGetPrototypeOf : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGetPrototypeOf(MDefinition * target) : MUnaryInstruction(classOpcode, target) { setGuard (); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (GetPrototypeOf) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * target() const { return getOperand(0); }};class MObjectWithProto : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MObjectWithProto(MDefinition* prototype) : MUnaryInstruction (classOpcode, prototype) { setGuard(); setResultType(MIRType:: Object); } public: INSTRUCTION_HEADER(ObjectWithProto) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* prototype() const { return getOperand(0); } bool possiblyCalls() const override { return true; }};class MBuiltinObject : public MNullaryInstruction { BuiltinObjectKind builtinObjectKind_; explicit MBuiltinObject (BuiltinObjectKind builtinObjectKind) : MNullaryInstruction(classOpcode ), builtinObjectKind_(builtinObjectKind) { setResultType(MIRType ::Object); } public: BuiltinObjectKind builtinObjectKind() const { return builtinObjectKind_; } INSTRUCTION_HEADER(BuiltinObject ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } bool possiblyCalls() const override { return true; }};class MSuperFunction : public MUnaryInstruction , public ObjectPolicy<0>::Data { explicit MSuperFunction (MDefinition* callee) : MUnaryInstruction(classOpcode, callee ) { setMovable(); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (SuperFunction) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * callee() const { return getOperand(0); } AliasSet getAliasSet () const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MInitHomeObject : public MBinaryInstruction, public MixPolicy<ObjectPolicy <0>, BoxPolicy<1>>::Data { explicit MInitHomeObject (MDefinition* function, MDefinition* homeObject) : MBinaryInstruction (classOpcode, function, homeObject) { setResultType(MIRType:: Object); } public: INSTRUCTION_HEADER(InitHomeObject) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* function() const { return getOperand(0); } MDefinition* homeObject() const { return getOperand(1); } AliasSet getAliasSet() const override;};class MIsTypedArrayConstructor : public MUnaryInstruction, public ObjectPolicy <0>::Data { explicit MIsTypedArrayConstructor(MDefinition * object) : MUnaryInstruction(classOpcode, object) { setResultType (MIRType::Boolean); } public: INSTRUCTION_HEADER(IsTypedArrayConstructor ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MLoadValueTag : public MUnaryInstruction , public BoxPolicy<0>::Data { explicit MLoadValueTag(MDefinition * value) : MUnaryInstruction(classOpcode, value) { setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (LoadValueTag) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * value() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } bool congruentTo (const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MLoadWrapperTarget : public MUnaryInstruction , public ObjectPolicy<0>::Data { bool fallible_; explicit MLoadWrapperTarget(MDefinition* object, bool fallible) : MUnaryInstruction (classOpcode, object), fallible_(fallible) { setMovable(); setResultType (MIRType::Object); } public: bool fallible() const { return fallible_ ; } INSTRUCTION_HEADER(LoadWrapperTarget) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override;};class MGuardHasGetterSetter : public MUnaryInstruction, public ObjectPolicy<0>::Data { jsid propId_; CompilerGCPointer<GetterSetter*> getterSetter_ ; explicit MGuardHasGetterSetter(MDefinition* object, jsid propId , GetterSetter* getterSetter) : MUnaryInstruction(classOpcode , object), propId_(propId), getterSetter_(getterSetter) { setGuard (); setMovable(); setResultType(MIRType::Object); } public: jsid propId() const { return propId_; } GetterSetter* getterSetter () const { return getterSetter_; } INSTRUCTION_HEADER(GuardHasGetterSetter ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override; bool possiblyCalls() const override { return true; }};class MGuardIsExtensible : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MGuardIsExtensible(MDefinition* object) : MUnaryInstruction (classOpcode, object) { setGuard(); setMovable(); setResultType (MIRType::Object); } public: INSTRUCTION_HEADER(GuardIsExtensible ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } AliasSet getAliasSet() const override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardInt32IsNonNegative : public MUnaryInstruction, public UnboxedInt32Policy<0> ::Data { explicit MGuardInt32IsNonNegative(MDefinition* index ) : MUnaryInstruction(classOpcode, index) { setGuard(); setMovable (); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (GuardInt32IsNonNegative) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* index() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } MDefinition* foldsTo(TempAllocator& alloc) override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MGuardInt32Range : public MUnaryInstruction, public UnboxedInt32Policy<0>::Data { int32_t minimum_; int32_t maximum_; explicit MGuardInt32Range (MDefinition* input, int32_t minimum, int32_t maximum) : MUnaryInstruction (classOpcode, input), minimum_(minimum), maximum_(maximum) { setGuard (); setMovable(); setResultType(MIRType::Int32); } public: int32_t minimum() const { return minimum_; } int32_t maximum() const { return maximum_; } INSTRUCTION_HEADER(GuardInt32Range) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } MDefinition* foldsTo(TempAllocator & alloc) override; bool congruentTo(const MDefinition* ins ) const override { return congruentIfOperandsEqual(ins); }};class MGuardIndexIsNotDenseElement : public MBinaryInstruction, public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>> ::Data { explicit MGuardIndexIsNotDenseElement(MDefinition* object , MDefinition* index) : MBinaryInstruction(classOpcode, object , index) { setGuard(); setMovable(); setResultType(MIRType::Int32 ); } public: INSTRUCTION_HEADER(GuardIndexIsNotDenseElement) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MGuardIndexIsValidUpdateOrAdd : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy <1>>::Data { explicit MGuardIndexIsValidUpdateOrAdd( MDefinition* object, MDefinition* index) : MBinaryInstruction (classOpcode, object, index) { setGuard(); setMovable(); setResultType (MIRType::Int32); } public: INSTRUCTION_HEADER(GuardIndexIsValidUpdateOrAdd ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MCallAddOrUpdateSparseElement : public MTernaryInstruction , public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy <1>, BoxPolicy<2>>::Data { bool strict_; explicit MCallAddOrUpdateSparseElement(MDefinition* object, MDefinition * index, MDefinition* value, bool strict) : MTernaryInstruction (classOpcode, object, index, value), strict_(strict) { } public : bool strict() const { return strict_; } INSTRUCTION_HEADER( CallAddOrUpdateSparseElement) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } MDefinition * value() const { return getOperand(2); } bool possiblyCalls( ) const override { return true; }};class MCallGetSparseElement : public MBinaryInstruction, public MixPolicy<ObjectPolicy <0>, UnboxedInt32Policy<1>>::Data { explicit MCallGetSparseElement (MDefinition* object, MDefinition* index) : MBinaryInstruction (classOpcode, object, index) { setResultType(MIRType::Value); } public: INSTRUCTION_HEADER(CallGetSparseElement) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } bool possiblyCalls() const override { return true; }};class MCallNativeGetElement : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy <1>>::Data { explicit MCallNativeGetElement(MDefinition * object, MDefinition* index) : MBinaryInstruction(classOpcode , object, index) { setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (CallNativeGetElement) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* object() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } bool possiblyCalls () const override { return true; }};class MCallNativeGetElementSuper : public MTernaryInstruction, public MixPolicy<ObjectPolicy <0>, UnboxedInt32Policy<1>, BoxPolicy<2>> ::Data { explicit MCallNativeGetElementSuper(MDefinition* object , MDefinition* index, MDefinition* receiver) : MTernaryInstruction (classOpcode, object, index, receiver) { setResultType(MIRType ::Value); } public: INSTRUCTION_HEADER(CallNativeGetElementSuper ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } MDefinition* receiver() const { return getOperand (2); } bool possiblyCalls() const override { return true; }}; class MCallObjectHasSparseElement : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy <1>>::Data { explicit MCallObjectHasSparseElement(MDefinition * object, MDefinition* index) : MBinaryInstruction(classOpcode , object, index) { setGuard(); setResultType(MIRType::Boolean ); } public: INSTRUCTION_HEADER(CallObjectHasSparseElement) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* object() const { return getOperand(0); } MDefinition* index() const { return getOperand(1); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool possiblyCalls() const override { return true; } };class MBigIntAsIntN : public MBinaryInstruction, public MixPolicy <UnboxedInt32Policy<0>, BigIntPolicy<1>>::Data { explicit MBigIntAsIntN(MDefinition* bits, MDefinition* input ) : MBinaryInstruction(classOpcode, bits, input) { setMovable (); setResultType(MIRType::BigInt); } public: INSTRUCTION_HEADER (BigIntAsIntN) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * bits() const { return getOperand(0); } MDefinition* input() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool possiblyCalls() const override { return true; } [[nodiscard]] bool writeRecoverData( CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; } bool canClone() const override { return true ; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector & inputs) const override { MInstruction* res = new (alloc ) MBigIntAsIntN(*this); for (size_t i = 0; i < numOperands (); i++) res->replaceOperand(i, inputs[i]); return res; }} ;class MBigIntAsUintN : public MBinaryInstruction, public MixPolicy <UnboxedInt32Policy<0>, BigIntPolicy<1>>::Data { explicit MBigIntAsUintN(MDefinition* bits, MDefinition* input ) : MBinaryInstruction(classOpcode, bits, input) { setMovable (); setResultType(MIRType::BigInt); } public: INSTRUCTION_HEADER (BigIntAsUintN) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * bits() const { return getOperand(0); } MDefinition* input() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); } bool possiblyCalls() const override { return true; } [[nodiscard]] bool writeRecoverData( CompactBufferWriter& writer) const override; bool canRecoverOnBailout() const override { return true; } bool canClone() const override { return true ; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector & inputs) const override { MInstruction* res = new (alloc ) MBigIntAsUintN(*this); for (size_t i = 0; i < numOperands (); i++) res->replaceOperand(i, inputs[i]); return res; }} ;class MGuardNonGCThing : public MUnaryInstruction, public BoxPolicy <0>::Data { explicit MGuardNonGCThing(MDefinition* input ) : MUnaryInstruction(classOpcode, input) { setGuard(); setMovable (); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (GuardNonGCThing) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * input() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } MDefinition* foldsTo (TempAllocator& alloc) override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MToHashableNonGCThing : public MUnaryInstruction, public BoxPolicy<0>::Data { explicit MToHashableNonGCThing(MDefinition * input) : MUnaryInstruction(classOpcode, input) { setMovable (); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (ToHashableNonGCThing) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MToHashableString : public MUnaryInstruction, public StringPolicy<0>::Data { explicit MToHashableString(MDefinition* input) : MUnaryInstruction (classOpcode, input) { setMovable(); setResultType(MIRType::String ); } public: INSTRUCTION_HEADER(ToHashableString) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); } bool possiblyCalls() const override { return true; }};class MToHashableValue : public MUnaryInstruction, public BoxPolicy <0>::Data { explicit MToHashableValue(MDefinition* input ) : MUnaryInstruction(classOpcode, input) { setMovable(); setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(ToHashableValue ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); } bool possiblyCalls() const override { return true; }};class MHashNonGCThing : public MUnaryInstruction, public BoxPolicy <0>::Data { explicit MHashNonGCThing(MDefinition* input ) : MUnaryInstruction(classOpcode, input) { setMovable(); setResultType (MIRType::Int32); } public: INSTRUCTION_HEADER(HashNonGCThing ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MHashString : public MUnaryInstruction, public StringPolicy <0>::Data { explicit MHashString(MDefinition* input) : MUnaryInstruction (classOpcode, input) { setMovable(); setResultType(MIRType::Int32 ); } public: INSTRUCTION_HEADER(HashString) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MHashSymbol : public MUnaryInstruction, public SymbolPolicy< 0>::Data { explicit MHashSymbol(MDefinition* input) : MUnaryInstruction (classOpcode, input) { setMovable(); setResultType(MIRType::Int32 ); } public: INSTRUCTION_HEADER(HashSymbol) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MHashBigInt : public MUnaryInstruction, public BigIntPolicy< 0>::Data { explicit MHashBigInt(MDefinition* input) : MUnaryInstruction (classOpcode, input) { setMovable(); setResultType(MIRType::Int32 ); } public: INSTRUCTION_HEADER(HashBigInt) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MHashObject : public MBinaryInstruction, public MixPolicy< ObjectPolicy<0>, BoxPolicy<1>>::Data { explicit MHashObject(MDefinition* set, MDefinition* input) : MBinaryInstruction (classOpcode, set, input) { setResultType(MIRType::Int32); } public : INSTRUCTION_HEADER(HashObject) template <typename... Args > static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* set() const { return getOperand(0); } MDefinition * input() const { return getOperand(1); } AliasSet getAliasSet () const override { return AliasSet::None(); }};class MHashValue : public MBinaryInstruction, public MixPolicy<ObjectPolicy <0>, BoxPolicy<1>>::Data { explicit MHashValue (MDefinition* set, MDefinition* input) : MBinaryInstruction(classOpcode , set, input) { setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (HashValue) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * set() const { return getOperand(0); } MDefinition* input() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); }};class MSetObjectHasNonBigInt : public MTernaryInstruction, public MixPolicy<ObjectPolicy <0>, BoxPolicy<1>, UnboxedInt32Policy<2>> ::Data { explicit MSetObjectHasNonBigInt(MDefinition* set, MDefinition * value, MDefinition* hash) : MTernaryInstruction(classOpcode , set, value, hash) { setMovable(); setResultType(MIRType::Boolean ); } public: INSTRUCTION_HEADER(SetObjectHasNonBigInt) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* set() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } MDefinition* hash() const { return getOperand(2); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MSetObjectHasBigInt : public MTernaryInstruction, public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy <2>>::Data { explicit MSetObjectHasBigInt(MDefinition * set, MDefinition* value, MDefinition* hash) : MTernaryInstruction (classOpcode, set, value, hash) { setMovable(); setResultType (MIRType::Boolean); } public: INSTRUCTION_HEADER(SetObjectHasBigInt ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* set() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } MDefinition* hash() const { return getOperand(2); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MSetObjectHasValue : public MTernaryInstruction, public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy <2>>::Data { explicit MSetObjectHasValue(MDefinition * set, MDefinition* value, MDefinition* hash) : MTernaryInstruction (classOpcode, set, value, hash) { setMovable(); setResultType (MIRType::Boolean); } public: INSTRUCTION_HEADER(SetObjectHasValue ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* set() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } MDefinition* hash() const { return getOperand(2); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MSetObjectHasValueVMCall : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>> ::Data { explicit MSetObjectHasValueVMCall(MDefinition* set, MDefinition * value) : MBinaryInstruction(classOpcode, set, value) { setMovable (); setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (SetObjectHasValueVMCall) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* set() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } AliasSet getAliasSet () const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } bool possiblyCalls () const override { return true; }};class MSetObjectSize : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MSetObjectSize(MDefinition* set) : MUnaryInstruction(classOpcode , set) { setMovable(); setResultType(MIRType::Int32); } public : INSTRUCTION_HEADER(SetObjectSize) template <typename... Args > static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* set() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MMapObjectHasNonBigInt : public MTernaryInstruction , public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> , UnboxedInt32Policy<2>>::Data { explicit MMapObjectHasNonBigInt (MDefinition* map, MDefinition* value, MDefinition* hash) : MTernaryInstruction (classOpcode, map, value, hash) { setMovable(); setResultType (MIRType::Boolean); } public: INSTRUCTION_HEADER(MapObjectHasNonBigInt ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* map() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } MDefinition* hash() const { return getOperand(2); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MMapObjectHasBigInt : public MTernaryInstruction, public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy <2>>::Data { explicit MMapObjectHasBigInt(MDefinition * map, MDefinition* value, MDefinition* hash) : MTernaryInstruction (classOpcode, map, value, hash) { setMovable(); setResultType (MIRType::Boolean); } public: INSTRUCTION_HEADER(MapObjectHasBigInt ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* map() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } MDefinition* hash() const { return getOperand(2); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MMapObjectHasValue : public MTernaryInstruction, public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy <2>>::Data { explicit MMapObjectHasValue(MDefinition * map, MDefinition* value, MDefinition* hash) : MTernaryInstruction (classOpcode, map, value, hash) { setMovable(); setResultType (MIRType::Boolean); } public: INSTRUCTION_HEADER(MapObjectHasValue ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* map() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } MDefinition* hash() const { return getOperand(2); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MMapObjectHasValueVMCall : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>> ::Data { explicit MMapObjectHasValueVMCall(MDefinition* map, MDefinition * value) : MBinaryInstruction(classOpcode, map, value) { setMovable (); setResultType(MIRType::Boolean); } public: INSTRUCTION_HEADER (MapObjectHasValueVMCall) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* map() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } AliasSet getAliasSet () const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } bool possiblyCalls () const override { return true; }};class MMapObjectGetNonBigInt : public MTernaryInstruction, public MixPolicy<ObjectPolicy <0>, BoxPolicy<1>, UnboxedInt32Policy<2>> ::Data { explicit MMapObjectGetNonBigInt(MDefinition* map, MDefinition * value, MDefinition* hash) : MTernaryInstruction(classOpcode , map, value, hash) { setMovable(); setResultType(MIRType::Value ); } public: INSTRUCTION_HEADER(MapObjectGetNonBigInt) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* map() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } MDefinition* hash() const { return getOperand(2); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MMapObjectGetBigInt : public MTernaryInstruction, public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy <2>>::Data { explicit MMapObjectGetBigInt(MDefinition * map, MDefinition* value, MDefinition* hash) : MTernaryInstruction (classOpcode, map, value, hash) { setMovable(); setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(MapObjectGetBigInt ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* map() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } MDefinition* hash() const { return getOperand(2); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MMapObjectGetValue : public MTernaryInstruction, public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy <2>>::Data { explicit MMapObjectGetValue(MDefinition * map, MDefinition* value, MDefinition* hash) : MTernaryInstruction (classOpcode, map, value, hash) { setMovable(); setResultType (MIRType::Value); } public: INSTRUCTION_HEADER(MapObjectGetValue ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* map() const { return getOperand(0); } MDefinition* value() const { return getOperand (1); } MDefinition* hash() const { return getOperand(2); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MMapObjectGetValueVMCall : public MBinaryInstruction , public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>> ::Data { explicit MMapObjectGetValueVMCall(MDefinition* map, MDefinition * value) : MBinaryInstruction(classOpcode, map, value) { setMovable (); setResultType(MIRType::Value); } public: INSTRUCTION_HEADER (MapObjectGetValueVMCall) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* map() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } AliasSet getAliasSet () const override; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); } bool possiblyCalls () const override { return true; }};class MMapObjectSize : public MUnaryInstruction, public ObjectPolicy<0>::Data { explicit MMapObjectSize(MDefinition* map) : MUnaryInstruction(classOpcode , map) { setMovable(); setResultType(MIRType::Int32); } public : INSTRUCTION_HEADER(MapObjectSize) template <typename... Args > static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* map() const { return getOperand(0); } AliasSet getAliasSet() const override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MWasmBoundsCheckRange32 : public MTernaryInstruction , public NoTypePolicy::Data { wasm::BytecodeOffset bytecodeOffset_ ; explicit MWasmBoundsCheckRange32(MDefinition* index, MDefinition * length, MDefinition* limit, wasm::BytecodeOffset bytecodeOffset ) : MTernaryInstruction(classOpcode, index, length, limit), bytecodeOffset_ (bytecodeOffset) { setResultType(MIRType::Int32); } public: wasm ::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_ ; } INSTRUCTION_HEADER(WasmBoundsCheckRange32) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* index() const { return getOperand(0); } MDefinition* length() const { return getOperand (1); } MDefinition* limit() const { return getOperand(2); } bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual (ins); }};class MWasmExtendU32Index : public MUnaryInstruction , public NoTypePolicy::Data { explicit MWasmExtendU32Index(MDefinition * input) : MUnaryInstruction(classOpcode, input) { setMovable (); setResultType(MIRType::Int64); } public: INSTRUCTION_HEADER (WasmExtendU32Index) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args> (args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } MDefinition* input() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None (); } MDefinition* foldsTo(TempAllocator& alloc) override ; bool congruentTo(const MDefinition* ins) const override { return congruentIfOperandsEqual(ins); }};class MWasmWrapU32Index : public MUnaryInstruction, public NoTypePolicy::Data { explicit MWasmWrapU32Index (MDefinition* input) : MUnaryInstruction(classOpcode, input) { setMovable(); setResultType(MIRType::Int32); } public: INSTRUCTION_HEADER (WasmWrapU32Index) template <typename... Args> static MThisOpcode * New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator ::Fallible alloc, Args&&... args) { return new (alloc ) MThisOpcode(std::forward<Args>(args)...); } MDefinition * input() const { return getOperand(0); } AliasSet getAliasSet () const override { return AliasSet::None(); } MDefinition* foldsTo (TempAllocator& alloc) override; bool congruentTo(const MDefinition * ins) const override { return congruentIfOperandsEqual(ins); }};class MWasmFence : public MNullaryInstruction { explicit MWasmFence () : MNullaryInstruction(classOpcode) { setGuard(); } public: INSTRUCTION_HEADER(WasmFence) template <typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&& ... args) { return new (alloc) MThisOpcode(std::forward<Args >(args)...); } template <typename... Args> static MThisOpcode * New(TempAllocator::Fallible alloc, Args&&... args) { return new (alloc) MThisOpcode(std::forward<Args>(args )...); } AliasSet getAliasSet() const override { return AliasSet ::None(); } bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmFence (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MWasmStackSwitchToMain : public MTernaryInstruction, public NoTypePolicy::Data { explicit MWasmStackSwitchToMain(MDefinition* suspender, MDefinition* fn , MDefinition* data) : MTernaryInstruction(classOpcode, suspender , fn, data) { } public: INSTRUCTION_HEADER(WasmStackSwitchToMain ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* suspender() const { return getOperand(0); } MDefinition* fn() const { return getOperand (1); } MDefinition* data() const { return getOperand(2); }};class MWasmStackSwitchToSuspendable : public MTernaryInstruction, public NoTypePolicy::Data { explicit MWasmStackSwitchToSuspendable( MDefinition* suspender, MDefinition* fn, MDefinition* data) : MTernaryInstruction(classOpcode, suspender, fn, data) { } public : INSTRUCTION_HEADER(WasmStackSwitchToSuspendable) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* suspender() const { return getOperand(0); } MDefinition* fn() const { return getOperand (1); } MDefinition* data() const { return getOperand(2); }};class MWasmStackContinueOnSuspendable : public MUnaryInstruction, public NoTypePolicy::Data { explicit MWasmStackContinueOnSuspendable (MDefinition* suspender) : MUnaryInstruction(classOpcode, suspender ) { } public: INSTRUCTION_HEADER(WasmStackContinueOnSuspendable ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* suspender() const { return getOperand(0); }};class MWasmShiftSimd128 : public MBinaryInstruction , public NoTypePolicy::Data { wasm::SimdOp simdOp_; explicit MWasmShiftSimd128 (MDefinition* lhs, MDefinition* rhs, wasm::SimdOp simdOp) : MBinaryInstruction (classOpcode, lhs, rhs), simdOp_(simdOp) { setMovable(); setResultType (MIRType::Simd128); } public: wasm::SimdOp simdOp() const { return simdOp_; } INSTRUCTION_HEADER(WasmShiftSimd128) template < typename... Args> static MThisOpcode* New(TempAllocator& alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* lhs() const { return getOperand(0); } MDefinition* rhs() const { return getOperand (1); } AliasSet getAliasSet() const override { return AliasSet ::None(); } bool congruentTo(const MDefinition* ins) const override ; bool canClone() const override { return true; } MInstruction * clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmShiftSimd128 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }};class MWasmShuffleSimd128 : public MBinaryInstruction, public NoTypePolicy::Data { SimdShuffle shuffle_; explicit MWasmShuffleSimd128(MDefinition* lhs, MDefinition * rhs, SimdShuffle shuffle) : MBinaryInstruction(classOpcode, lhs, rhs), shuffle_(shuffle) { setMovable(); setResultType(MIRType ::Simd128); } public: SimdShuffle shuffle() const { return shuffle_ ; } INSTRUCTION_HEADER(WasmShuffleSimd128) template <typename ... Args> static MThisOpcode* New(TempAllocator& alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } template <typename... Args > static MThisOpcode* New(TempAllocator::Fallible alloc, Args &&... args) { return new (alloc) MThisOpcode(std::forward <Args>(args)...); } MDefinition* lhs() const { return getOperand (0); } MDefinition* rhs() const { return getOperand(1); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override; bool canClone () const override { return true; } MInstruction* clone(TempAllocator & alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmShuffleSimd128(*this) ; for (size_t i = 0; i < numOperands(); i++) res->replaceOperand (i, inputs[i]); return res; }};class MWasmUnarySimd128 : public MUnaryInstruction, public NoTypePolicy::Data { wasm::SimdOp simdOp_ ; explicit MWasmUnarySimd128(MDefinition* src, wasm::SimdOp simdOp ) : MUnaryInstruction(classOpcode, src), simdOp_(simdOp) { setMovable (); setResultType(MIRType::Simd128); } public: wasm::SimdOp simdOp () const { return simdOp_; } INSTRUCTION_HEADER(WasmUnarySimd128 ) template <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } MDefinition* src() const { return getOperand(0); } AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition * ins) const override; bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector & inputs) const override { MInstruction* res = new (alloc ) MWasmUnarySimd128(*this); for (size_t i = 0; i < numOperands (); i++) res->replaceOperand(i, inputs[i]); return res; }} ; |
| 1320 | |
| 1321 | // Truncation barrier. This is intended for protecting its input against |
| 1322 | // follow-up truncation optimizations. |
| 1323 | class MLimitedTruncate : public MUnaryInstruction, |
| 1324 | public ConvertToInt32Policy<0>::Data { |
| 1325 | TruncateKind truncate_; |
| 1326 | TruncateKind truncateLimit_; |
| 1327 | |
| 1328 | MLimitedTruncate(MDefinition* input, TruncateKind limit) |
| 1329 | : MUnaryInstruction(classOpcode, input), |
| 1330 | truncate_(TruncateKind::NoTruncate), |
| 1331 | truncateLimit_(limit) { |
| 1332 | setResultType(MIRType::Int32); |
| 1333 | setMovable(); |
| 1334 | } |
| 1335 | |
| 1336 | public: |
| 1337 | INSTRUCTION_HEADER(LimitedTruncate) |
| 1338 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 1339 | |
| 1340 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1341 | |
| 1342 | void computeRange(TempAllocator& alloc) override; |
| 1343 | bool canTruncate() const override; |
| 1344 | void truncate(TruncateKind kind) override; |
| 1345 | TruncateKind operandTruncateKind(size_t index) const override; |
| 1346 | TruncateKind truncateKind() const { return truncate_; } |
| 1347 | void setTruncateKind(TruncateKind kind) { truncate_ = kind; } |
| 1348 | }; |
| 1349 | |
| 1350 | // A constant js::Value. |
| 1351 | class MConstant : public MNullaryInstruction { |
| 1352 | struct Payload { |
| 1353 | union { |
| 1354 | bool b; |
| 1355 | int32_t i32; |
| 1356 | int64_t i64; |
| 1357 | intptr_t iptr; |
| 1358 | float f; |
| 1359 | double d; |
| 1360 | JSString* str; |
| 1361 | JS::Symbol* sym; |
| 1362 | BigInt* bi; |
| 1363 | JSObject* obj; |
| 1364 | Shape* shape; |
| 1365 | uint64_t asBits; |
| 1366 | }; |
| 1367 | Payload() : asBits(0) {} |
| 1368 | }; |
| 1369 | |
| 1370 | Payload payload_; |
| 1371 | |
| 1372 | static_assert(sizeof(Payload) == sizeof(uint64_t), |
| 1373 | "asBits must be big enough for all payload bits"); |
| 1374 | |
| 1375 | #ifdef DEBUG1 |
| 1376 | void assertInitializedPayload() const; |
| 1377 | #else |
| 1378 | void assertInitializedPayload() const {} |
| 1379 | #endif |
| 1380 | |
| 1381 | MConstant(TempAllocator& alloc, const Value& v); |
| 1382 | explicit MConstant(JSObject* obj); |
| 1383 | explicit MConstant(Shape* shape); |
| 1384 | explicit MConstant(float f); |
| 1385 | explicit MConstant(MIRType type, int64_t i); |
| 1386 | |
| 1387 | public: |
| 1388 | INSTRUCTION_HEADER(Constant) |
| 1389 | static MConstant* New(TempAllocator& alloc, const Value& v); |
| 1390 | static MConstant* New(TempAllocator::Fallible alloc, const Value& v); |
| 1391 | static MConstant* New(TempAllocator& alloc, const Value& v, MIRType type); |
| 1392 | static MConstant* NewFloat32(TempAllocator& alloc, double d); |
| 1393 | static MConstant* NewInt64(TempAllocator& alloc, int64_t i); |
| 1394 | static MConstant* NewIntPtr(TempAllocator& alloc, intptr_t i); |
| 1395 | static MConstant* NewObject(TempAllocator& alloc, JSObject* v); |
| 1396 | static MConstant* NewShape(TempAllocator& alloc, Shape* s); |
| 1397 | static MConstant* Copy(TempAllocator& alloc, MConstant* src) { |
| 1398 | return new (alloc) MConstant(*src); |
| 1399 | } |
| 1400 | |
| 1401 | // Try to convert this constant to boolean, similar to js::ToBoolean. |
| 1402 | // Returns false if the type is MIRType::Magic* or MIRType::Object. |
| 1403 | [[nodiscard]] bool valueToBoolean(bool* res) const; |
| 1404 | |
| 1405 | #ifdef JS_JITSPEW1 |
| 1406 | void printOpcode(GenericPrinter& out) const override; |
| 1407 | #endif |
| 1408 | |
| 1409 | HashNumber valueHash() const override; |
| 1410 | bool congruentTo(const MDefinition* ins) const override; |
| 1411 | |
| 1412 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1413 | |
| 1414 | void computeRange(TempAllocator& alloc) override; |
| 1415 | bool canTruncate() const override; |
| 1416 | void truncate(TruncateKind kind) override; |
| 1417 | |
| 1418 | bool canProduceFloat32() const override; |
| 1419 | |
| 1420 | ALLOW_CLONE(MConstant)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MConstant (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 1421 | |
| 1422 | bool equals(const MConstant* other) const { |
| 1423 | assertInitializedPayload(); |
| 1424 | return type() == other->type() && payload_.asBits == other->payload_.asBits; |
| 1425 | } |
| 1426 | |
| 1427 | bool toBoolean() const { |
| 1428 | MOZ_ASSERT(type() == MIRType::Boolean)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Boolean)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Boolean)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Boolean" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1428); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Boolean" ")"); do { *((volatile int*)__null) = 1428; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1429 | return payload_.b; |
| 1430 | } |
| 1431 | int32_t toInt32() const { |
| 1432 | MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1432); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 1432; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1433 | return payload_.i32; |
| 1434 | } |
| 1435 | int64_t toInt64() const { |
| 1436 | MOZ_ASSERT(type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Int64)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int64" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1436); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 1436; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1437 | return payload_.i64; |
| 1438 | } |
| 1439 | intptr_t toIntPtr() const { |
| 1440 | MOZ_ASSERT(type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::IntPtr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::IntPtr" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1440); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 1440; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1441 | return payload_.iptr; |
| 1442 | } |
| 1443 | bool isInt32(int32_t i) const { |
| 1444 | return type() == MIRType::Int32 && payload_.i32 == i; |
| 1445 | } |
| 1446 | bool isInt64(int64_t i) const { |
| 1447 | return type() == MIRType::Int64 && payload_.i64 == i; |
| 1448 | } |
| 1449 | const double& toDouble() const { |
| 1450 | MOZ_ASSERT(type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Double)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Double))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Double" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1450); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 1450; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1451 | return payload_.d; |
| 1452 | } |
| 1453 | const float& toFloat32() const { |
| 1454 | MOZ_ASSERT(type() == MIRType::Float32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Float32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Float32)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Float32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1454); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Float32" ")"); do { *((volatile int*)__null) = 1454; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1455 | return payload_.f; |
| 1456 | } |
| 1457 | JSString* toString() const { |
| 1458 | MOZ_ASSERT(type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::String))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1458); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::String" ")"); do { *((volatile int*)__null) = 1458; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1459 | return payload_.str; |
| 1460 | } |
| 1461 | JS::Symbol* toSymbol() const { |
| 1462 | MOZ_ASSERT(type() == MIRType::Symbol)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Symbol)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Symbol))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Symbol" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1462); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Symbol" ")"); do { *((volatile int*)__null) = 1462; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1463 | return payload_.sym; |
| 1464 | } |
| 1465 | BigInt* toBigInt() const { |
| 1466 | MOZ_ASSERT(type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::BigInt))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::BigInt" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 1466; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1467 | return payload_.bi; |
| 1468 | } |
| 1469 | JSObject& toObject() const { |
| 1470 | MOZ_ASSERT(type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Object)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Object))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Object" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1470); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 1470; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1471 | return *payload_.obj; |
| 1472 | } |
| 1473 | JSObject* toObjectOrNull() const { |
| 1474 | if (type() == MIRType::Object) { |
| 1475 | return payload_.obj; |
| 1476 | } |
| 1477 | MOZ_ASSERT(type() == MIRType::Null)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Null)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Null))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Null" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1477); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Null" ")"); do { *((volatile int*)__null) = 1477; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1478 | return nullptr; |
| 1479 | } |
| 1480 | Shape* toShape() const { |
| 1481 | MOZ_ASSERT(type() == MIRType::Shape)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Shape)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Shape))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Shape" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1481); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Shape" ")"); do { *((volatile int*)__null) = 1481; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1482 | return payload_.shape; |
| 1483 | } |
| 1484 | |
| 1485 | bool isTypeRepresentableAsDouble() const { |
| 1486 | return IsTypeRepresentableAsDouble(type()); |
| 1487 | } |
| 1488 | double numberToDouble() const { |
| 1489 | MOZ_ASSERT(isTypeRepresentableAsDouble())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isTypeRepresentableAsDouble())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isTypeRepresentableAsDouble( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("isTypeRepresentableAsDouble()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1489); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isTypeRepresentableAsDouble()" ")"); do { *((volatile int*)__null) = 1489; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1490 | if (type() == MIRType::Int32) { |
| 1491 | return toInt32(); |
| 1492 | } |
| 1493 | if (type() == MIRType::Double) { |
| 1494 | return toDouble(); |
| 1495 | } |
| 1496 | return toFloat32(); |
| 1497 | } |
| 1498 | |
| 1499 | // Convert this constant to a js::Value. Float32 constants will be stored |
| 1500 | // as DoubleValue and NaNs are canonicalized. Callers must be careful: not |
| 1501 | // all constants can be represented by js::Value (wasm supports int64). |
| 1502 | Value toJSValue() const; |
| 1503 | }; |
| 1504 | |
| 1505 | class MWasmNullConstant : public MNullaryInstruction { |
| 1506 | explicit MWasmNullConstant() : MNullaryInstruction(classOpcode) { |
| 1507 | setResultType(MIRType::WasmAnyRef); |
| 1508 | setMovable(); |
| 1509 | } |
| 1510 | |
| 1511 | public: |
| 1512 | INSTRUCTION_HEADER(WasmNullConstant) |
| 1513 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 1514 | |
| 1515 | HashNumber valueHash() const override; |
| 1516 | bool congruentTo(const MDefinition* ins) const override { |
| 1517 | return ins->isWasmNullConstant(); |
| 1518 | } |
| 1519 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1520 | |
| 1521 | ALLOW_CLONE(MWasmNullConstant)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmNullConstant (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 1522 | }; |
| 1523 | |
| 1524 | // Floating-point value as created by wasm. Just a constant value, used to |
| 1525 | // effectively inhibit all the MIR optimizations. This uses the same LIR nodes |
| 1526 | // as a MConstant of the same type would. |
| 1527 | class MWasmFloatConstant : public MNullaryInstruction { |
| 1528 | union { |
| 1529 | float f32_; |
| 1530 | double f64_; |
| 1531 | #ifdef ENABLE_WASM_SIMD1 |
| 1532 | int8_t s128_[16]; |
| 1533 | uint64_t bits_[2]; |
| 1534 | #else |
| 1535 | uint64_t bits_[1]; |
| 1536 | #endif |
| 1537 | } u; |
| 1538 | |
| 1539 | explicit MWasmFloatConstant(MIRType type) : MNullaryInstruction(classOpcode) { |
| 1540 | u.bits_[0] = 0; |
| 1541 | #ifdef ENABLE_WASM_SIMD1 |
| 1542 | u.bits_[1] = 0; |
| 1543 | #endif |
| 1544 | setResultType(type); |
| 1545 | } |
| 1546 | |
| 1547 | public: |
| 1548 | INSTRUCTION_HEADER(WasmFloatConstant) |
| 1549 | |
| 1550 | static MWasmFloatConstant* NewDouble(TempAllocator& alloc, double d) { |
| 1551 | auto* ret = new (alloc) MWasmFloatConstant(MIRType::Double); |
| 1552 | ret->u.f64_ = d; |
| 1553 | return ret; |
| 1554 | } |
| 1555 | |
| 1556 | static MWasmFloatConstant* NewFloat32(TempAllocator& alloc, float f) { |
| 1557 | auto* ret = new (alloc) MWasmFloatConstant(MIRType::Float32); |
| 1558 | ret->u.f32_ = f; |
| 1559 | return ret; |
| 1560 | } |
| 1561 | |
| 1562 | #ifdef ENABLE_WASM_SIMD1 |
| 1563 | static MWasmFloatConstant* NewSimd128(TempAllocator& alloc, |
| 1564 | const SimdConstant& s) { |
| 1565 | auto* ret = new (alloc) MWasmFloatConstant(MIRType::Simd128); |
| 1566 | memcpy(ret->u.s128_, s.bytes(), 16); |
| 1567 | return ret; |
| 1568 | } |
| 1569 | #endif |
| 1570 | |
| 1571 | HashNumber valueHash() const override; |
| 1572 | bool congruentTo(const MDefinition* ins) const override; |
| 1573 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1574 | |
| 1575 | const double& toDouble() const { |
| 1576 | MOZ_ASSERT(type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Double)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Double))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Double" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1576); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 1576; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1577 | return u.f64_; |
| 1578 | } |
| 1579 | const float& toFloat32() const { |
| 1580 | MOZ_ASSERT(type() == MIRType::Float32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Float32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Float32)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Float32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1580); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Float32" ")"); do { *((volatile int*)__null) = 1580; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1581 | return u.f32_; |
| 1582 | } |
| 1583 | #ifdef ENABLE_WASM_SIMD1 |
| 1584 | const SimdConstant toSimd128() const { |
| 1585 | MOZ_ASSERT(type() == MIRType::Simd128)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Simd128)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Simd128)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Simd128" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1585); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Simd128" ")"); do { *((volatile int*)__null) = 1585; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1586 | return SimdConstant::CreateX16(u.s128_); |
| 1587 | } |
| 1588 | #endif |
| 1589 | #ifdef JS_JITSPEW1 |
| 1590 | void getExtras(ExtrasCollector* extras) override { |
| 1591 | char buf[64]; |
| 1592 | switch (type()) { |
| 1593 | case MIRType::Float32: |
| 1594 | SprintfLiteral(buf, "f32{%e}", (double)u.f32_); |
| 1595 | break; |
| 1596 | case MIRType::Double: |
| 1597 | SprintfLiteral(buf, "f64{%e}", u.f64_); |
| 1598 | break; |
| 1599 | # ifdef ENABLE_WASM_SIMD1 |
| 1600 | case MIRType::Simd128: |
| 1601 | SprintfLiteral(buf, "v128{[1]=%016llx:[0]=%016llx}", |
| 1602 | (unsigned long long int)u.bits_[1], |
| 1603 | (unsigned long long int)u.bits_[0]); |
| 1604 | break; |
| 1605 | # endif |
| 1606 | default: |
| 1607 | SprintfLiteral(buf, "!!getExtras: missing case!!"); |
| 1608 | break; |
| 1609 | } |
| 1610 | extras->add(buf); |
| 1611 | } |
| 1612 | #endif |
| 1613 | }; |
| 1614 | |
| 1615 | class MParameter : public MNullaryInstruction { |
| 1616 | int32_t index_; |
| 1617 | |
| 1618 | explicit MParameter(int32_t index) |
| 1619 | : MNullaryInstruction(classOpcode), index_(index) { |
| 1620 | setResultType(MIRType::Value); |
| 1621 | } |
| 1622 | |
| 1623 | public: |
| 1624 | INSTRUCTION_HEADER(Parameter) |
| 1625 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 1626 | |
| 1627 | static const int32_t THIS_SLOT = -1; |
| 1628 | int32_t index() const { return index_; } |
| 1629 | #ifdef JS_JITSPEW1 |
| 1630 | void printOpcode(GenericPrinter& out) const override; |
| 1631 | #endif |
| 1632 | HashNumber valueHash() const override; |
| 1633 | bool congruentTo(const MDefinition* ins) const override; |
| 1634 | }; |
| 1635 | |
| 1636 | class MControlInstruction : public MInstruction { |
| 1637 | protected: |
| 1638 | explicit MControlInstruction(Opcode op) : MInstruction(op) {} |
| 1639 | |
| 1640 | public: |
| 1641 | virtual size_t numSuccessors() const = 0; |
| 1642 | virtual MBasicBlock* getSuccessor(size_t i) const = 0; |
| 1643 | virtual void replaceSuccessor(size_t i, MBasicBlock* successor) = 0; |
| 1644 | |
| 1645 | void initSuccessor(size_t i, MBasicBlock* successor) { |
| 1646 | MOZ_ASSERT(!getSuccessor(i))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!getSuccessor(i))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!getSuccessor(i)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!getSuccessor(i)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1646); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!getSuccessor(i)" ")"); do { *((volatile int*)__null) = 1646; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1647 | replaceSuccessor(i, successor); |
| 1648 | } |
| 1649 | |
| 1650 | bool isControlInstruction() const override { return true; } |
| 1651 | |
| 1652 | #ifdef JS_JITSPEW1 |
| 1653 | void printOpcode(GenericPrinter& out) const override; |
| 1654 | #endif |
| 1655 | }; |
| 1656 | |
| 1657 | class MTableSwitch final : public MControlInstruction, |
| 1658 | public NoFloatPolicy<0>::Data { |
| 1659 | // The successors of the tableswitch |
| 1660 | // - First successor = the default case |
| 1661 | // - Successors 2 and higher = the cases |
| 1662 | Vector<MBasicBlock*, 0, JitAllocPolicy> successors_; |
| 1663 | // Index into successors_ sorted on case index |
| 1664 | Vector<size_t, 0, JitAllocPolicy> cases_; |
| 1665 | |
| 1666 | MUse operand_; |
| 1667 | int32_t low_; |
| 1668 | int32_t high_; |
| 1669 | |
| 1670 | void initOperand(size_t index, MDefinition* operand) { |
| 1671 | MOZ_ASSERT(index == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index == 0" ")"); do { *((volatile int*)__null) = 1671; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1672 | operand_.init(operand, this); |
| 1673 | } |
| 1674 | |
| 1675 | MTableSwitch(TempAllocator& alloc, MDefinition* ins, int32_t low, |
| 1676 | int32_t high) |
| 1677 | : MControlInstruction(classOpcode), |
| 1678 | successors_(alloc), |
| 1679 | cases_(alloc), |
| 1680 | low_(low), |
| 1681 | high_(high) { |
| 1682 | initOperand(0, ins); |
| 1683 | } |
| 1684 | |
| 1685 | protected: |
| 1686 | MUse* getUseFor(size_t index) override { |
| 1687 | MOZ_ASSERT(index == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1687); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index == 0" ")"); do { *((volatile int*)__null) = 1687; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1688 | return &operand_; |
| 1689 | } |
| 1690 | |
| 1691 | const MUse* getUseFor(size_t index) const override { |
| 1692 | MOZ_ASSERT(index == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1692); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index == 0" ")"); do { *((volatile int*)__null) = 1692; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1693 | return &operand_; |
| 1694 | } |
| 1695 | |
| 1696 | public: |
| 1697 | INSTRUCTION_HEADER(TableSwitch) |
| 1698 | |
| 1699 | static MTableSwitch* New(TempAllocator& alloc, MDefinition* ins, int32_t low, |
| 1700 | int32_t high) { |
| 1701 | return new (alloc) MTableSwitch(alloc, ins, low, high); |
| 1702 | } |
| 1703 | |
| 1704 | size_t numSuccessors() const override { return successors_.length(); } |
| 1705 | |
| 1706 | [[nodiscard]] bool addSuccessor(MBasicBlock* successor, size_t* index) { |
| 1707 | MOZ_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2))do { static_assert( mozilla::detail::AssertionConditionType< decltype(successors_.length() < (size_t)(high_ - low_ + 2) )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(successors_.length() < (size_t)(high_ - low_ + 2) ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "successors_.length() < (size_t)(high_ - low_ + 2)", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1707); AnnotateMozCrashReason("MOZ_ASSERT" "(" "successors_.length() < (size_t)(high_ - low_ + 2)" ")"); do { *((volatile int*)__null) = 1707; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1708 | MOZ_ASSERT(!successors_.empty())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!successors_.empty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!successors_.empty()))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("!successors_.empty()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1708); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!successors_.empty()" ")"); do { *((volatile int*)__null) = 1708; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1709 | *index = successors_.length(); |
| 1710 | return successors_.append(successor); |
| 1711 | } |
| 1712 | |
| 1713 | MBasicBlock* getSuccessor(size_t i) const override { |
| 1714 | MOZ_ASSERT(i < numSuccessors())do { static_assert( mozilla::detail::AssertionConditionType< decltype(i < numSuccessors())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(i < numSuccessors()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("i < numSuccessors()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "i < numSuccessors()" ")"); do { *((volatile int*)__null) = 1714; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1715 | return successors_[i]; |
| 1716 | } |
| 1717 | |
| 1718 | void replaceSuccessor(size_t i, MBasicBlock* successor) override { |
| 1719 | MOZ_ASSERT(i < numSuccessors())do { static_assert( mozilla::detail::AssertionConditionType< decltype(i < numSuccessors())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(i < numSuccessors()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("i < numSuccessors()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1719); AnnotateMozCrashReason("MOZ_ASSERT" "(" "i < numSuccessors()" ")"); do { *((volatile int*)__null) = 1719; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1720 | successors_[i] = successor; |
| 1721 | } |
| 1722 | |
| 1723 | int32_t low() const { return low_; } |
| 1724 | |
| 1725 | int32_t high() const { return high_; } |
| 1726 | |
| 1727 | MBasicBlock* getDefault() const { return getSuccessor(0); } |
| 1728 | |
| 1729 | MBasicBlock* getCase(size_t i) const { return getSuccessor(cases_[i]); } |
| 1730 | |
| 1731 | [[nodiscard]] bool addDefault(MBasicBlock* block, size_t* index = nullptr) { |
| 1732 | MOZ_ASSERT(successors_.empty())do { static_assert( mozilla::detail::AssertionConditionType< decltype(successors_.empty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(successors_.empty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("successors_.empty()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1732); AnnotateMozCrashReason("MOZ_ASSERT" "(" "successors_.empty()" ")"); do { *((volatile int*)__null) = 1732; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1733 | if (index) { |
| 1734 | *index = 0; |
| 1735 | } |
| 1736 | return successors_.append(block); |
| 1737 | } |
| 1738 | |
| 1739 | [[nodiscard]] bool addCase(size_t successorIndex) { |
| 1740 | return cases_.append(successorIndex); |
| 1741 | } |
| 1742 | |
| 1743 | size_t numCases() const { return high() - low() + 1; } |
| 1744 | |
| 1745 | MDefinition* getOperand(size_t index) const override { |
| 1746 | MOZ_ASSERT(index == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index == 0" ")"); do { *((volatile int*)__null) = 1746; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1747 | return operand_.producer(); |
| 1748 | } |
| 1749 | |
| 1750 | size_t numOperands() const override { return 1; } |
| 1751 | |
| 1752 | size_t indexOf(const MUse* u) const final { |
| 1753 | MOZ_ASSERT(u == getUseFor(0))do { static_assert( mozilla::detail::AssertionConditionType< decltype(u == getUseFor(0))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(u == getUseFor(0)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("u == getUseFor(0)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1753); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u == getUseFor(0)" ")"); do { *((volatile int*)__null) = 1753; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1754 | return 0; |
| 1755 | } |
| 1756 | |
| 1757 | void replaceOperand(size_t index, MDefinition* operand) final { |
| 1758 | MOZ_ASSERT(index == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1758); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index == 0" ")"); do { *((volatile int*)__null) = 1758; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1759 | operand_.replaceProducer(operand); |
| 1760 | } |
| 1761 | |
| 1762 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 1763 | |
| 1764 | // It does read memory in that it must read an entry from the jump table, |
| 1765 | // but that's effectively data that is private to this MIR. And it should |
| 1766 | // certainly never be modified by any other MIR. Hence it is effect-free |
| 1767 | // from an alias-analysis standpoint. |
| 1768 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1769 | }; |
| 1770 | |
| 1771 | template <size_t Arity, size_t Successors> |
| 1772 | class MAryControlInstruction : public MControlInstruction { |
| 1773 | mozilla::Array<MUse, Arity> operands_; |
| 1774 | mozilla::Array<MBasicBlock*, Successors> successors_; |
| 1775 | |
| 1776 | protected: |
| 1777 | explicit MAryControlInstruction(Opcode op) : MControlInstruction(op) {} |
| 1778 | void setSuccessor(size_t index, MBasicBlock* successor) { |
| 1779 | successors_[index] = successor; |
| 1780 | } |
| 1781 | |
| 1782 | MUse* getUseFor(size_t index) final { return &operands_[index]; } |
| 1783 | const MUse* getUseFor(size_t index) const final { return &operands_[index]; } |
| 1784 | void initOperand(size_t index, MDefinition* operand) { |
| 1785 | operands_[index].init(operand, this); |
| 1786 | } |
| 1787 | |
| 1788 | public: |
| 1789 | MDefinition* getOperand(size_t index) const final { |
| 1790 | return operands_[index].producer(); |
| 1791 | } |
| 1792 | size_t numOperands() const final { return Arity; } |
| 1793 | size_t indexOf(const MUse* u) const final { |
| 1794 | MOZ_ASSERT(u >= &operands_[0])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u >= &operands_[0])>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(u >= &operands_[0]))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("u >= &operands_[0]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1794); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u >= &operands_[0]" ")"); do { *((volatile int*)__null) = 1794; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1795 | MOZ_ASSERT(u <= &operands_[numOperands() - 1])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u <= &operands_[numOperands() - 1])>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(u <= &operands_[numOperands() - 1]))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("u <= &operands_[numOperands() - 1]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 1795); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u <= &operands_[numOperands() - 1]" ")"); do { *((volatile int*)__null) = 1795; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1796 | return u - &operands_[0]; |
| 1797 | } |
| 1798 | void replaceOperand(size_t index, MDefinition* operand) final { |
| 1799 | operands_[index].replaceProducer(operand); |
| 1800 | } |
| 1801 | size_t numSuccessors() const final { return Successors; } |
| 1802 | MBasicBlock* getSuccessor(size_t i) const final { return successors_[i]; } |
| 1803 | void replaceSuccessor(size_t i, MBasicBlock* succ) final { |
| 1804 | successors_[i] = succ; |
| 1805 | } |
| 1806 | }; |
| 1807 | |
| 1808 | template <size_t Successors> |
| 1809 | class MVariadicControlInstruction : public MVariadicT<MControlInstruction> { |
| 1810 | mozilla::Array<MBasicBlock*, Successors> successors_; |
| 1811 | |
| 1812 | protected: |
| 1813 | explicit MVariadicControlInstruction(Opcode op) |
| 1814 | : MVariadicT<MControlInstruction>(op) {} |
| 1815 | void setSuccessor(size_t index, MBasicBlock* successor) { |
| 1816 | successors_[index] = successor; |
| 1817 | } |
| 1818 | |
| 1819 | public: |
| 1820 | size_t numSuccessors() const final { return Successors; } |
| 1821 | MBasicBlock* getSuccessor(size_t i) const final { return successors_[i]; } |
| 1822 | void replaceSuccessor(size_t i, MBasicBlock* succ) final { |
| 1823 | successors_[i] = succ; |
| 1824 | } |
| 1825 | }; |
| 1826 | |
| 1827 | // Jump to the start of another basic block. |
| 1828 | class MGoto : public MAryControlInstruction<0, 1>, public NoTypePolicy::Data { |
| 1829 | explicit MGoto(MBasicBlock* target) : MAryControlInstruction(classOpcode) { |
| 1830 | setSuccessor(TargetIndex, target); |
| 1831 | } |
| 1832 | |
| 1833 | public: |
| 1834 | INSTRUCTION_HEADER(Goto) |
| 1835 | static MGoto* New(TempAllocator& alloc, MBasicBlock* target); |
| 1836 | static MGoto* New(TempAllocator::Fallible alloc, MBasicBlock* target); |
| 1837 | |
| 1838 | // Variant that may patch the target later. |
| 1839 | static MGoto* New(TempAllocator& alloc); |
| 1840 | |
| 1841 | static constexpr size_t TargetIndex = 0; |
| 1842 | |
| 1843 | MBasicBlock* target() { return getSuccessor(TargetIndex); } |
| 1844 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1845 | |
| 1846 | #ifdef JS_JITSPEW1 |
| 1847 | void getExtras(ExtrasCollector* extras) override { |
| 1848 | char buf[64]; |
| 1849 | SprintfLiteral(buf, "Block%u", GetMBasicBlockId(target())); |
| 1850 | extras->add(buf); |
| 1851 | } |
| 1852 | #endif |
| 1853 | }; |
| 1854 | |
| 1855 | // Tests if the input instruction evaluates to true or false, and jumps to the |
| 1856 | // start of a corresponding basic block. |
| 1857 | class MTest : public MAryControlInstruction<1, 2>, public TestPolicy::Data { |
| 1858 | // It is allowable to specify `trueBranch` or `falseBranch` as nullptr and |
| 1859 | // patch it in later. |
| 1860 | MTest(MDefinition* ins, MBasicBlock* trueBranch, MBasicBlock* falseBranch) |
| 1861 | : MAryControlInstruction(classOpcode) { |
| 1862 | initOperand(0, ins); |
| 1863 | setSuccessor(TrueBranchIndex, trueBranch); |
| 1864 | setSuccessor(FalseBranchIndex, falseBranch); |
| 1865 | } |
| 1866 | |
| 1867 | TypeDataList observedTypes_; |
| 1868 | |
| 1869 | public: |
| 1870 | INSTRUCTION_HEADER(Test) |
| 1871 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 1872 | NAMED_OPERANDS((0, input))MDefinition* input() const { return getOperand(0); } |
| 1873 | |
| 1874 | const TypeDataList& observedTypes() const { return observedTypes_; } |
| 1875 | void setObservedTypes(const TypeDataList& observed) { |
| 1876 | observedTypes_ = observed; |
| 1877 | } |
| 1878 | |
| 1879 | static constexpr size_t TrueBranchIndex = 0; |
| 1880 | static constexpr size_t FalseBranchIndex = 1; |
| 1881 | |
| 1882 | MBasicBlock* ifTrue() const { return getSuccessor(TrueBranchIndex); } |
| 1883 | MBasicBlock* ifFalse() const { return getSuccessor(FalseBranchIndex); } |
| 1884 | MBasicBlock* branchSuccessor(BranchDirection dir) const { |
| 1885 | return (dir == TRUE_BRANCH) ? ifTrue() : ifFalse(); |
| 1886 | } |
| 1887 | |
| 1888 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1889 | |
| 1890 | MDefinition* foldsDoubleNegation(TempAllocator& alloc); |
| 1891 | MDefinition* foldsConstant(TempAllocator& alloc); |
| 1892 | MDefinition* foldsTypes(TempAllocator& alloc); |
| 1893 | MDefinition* foldsNeedlessControlFlow(TempAllocator& alloc); |
| 1894 | MDefinition* foldsRedundantTest(TempAllocator& alloc); |
| 1895 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 1896 | |
| 1897 | #ifdef DEBUG1 |
| 1898 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 1899 | #endif |
| 1900 | |
| 1901 | #ifdef JS_JITSPEW1 |
| 1902 | void getExtras(ExtrasCollector* extras) override { |
| 1903 | char buf[64]; |
| 1904 | SprintfLiteral(buf, "true->Block%u false->Block%u", |
| 1905 | GetMBasicBlockId(ifTrue()), GetMBasicBlockId(ifFalse())); |
| 1906 | extras->add(buf); |
| 1907 | } |
| 1908 | #endif |
| 1909 | }; |
| 1910 | |
| 1911 | // Returns from this function to the previous caller. |
| 1912 | class MReturn : public MAryControlInstruction<1, 0>, |
| 1913 | public BoxInputsPolicy::Data { |
| 1914 | explicit MReturn(MDefinition* ins) : MAryControlInstruction(classOpcode) { |
| 1915 | initOperand(0, ins); |
| 1916 | } |
| 1917 | |
| 1918 | public: |
| 1919 | INSTRUCTION_HEADER(Return) |
| 1920 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 1921 | NAMED_OPERANDS((0, input))MDefinition* input() const { return getOperand(0); } |
| 1922 | |
| 1923 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1924 | }; |
| 1925 | |
| 1926 | class MNewArray : public MUnaryInstruction, public NoTypePolicy::Data { |
| 1927 | private: |
| 1928 | // Number of elements to allocate for the array. |
| 1929 | uint32_t length_; |
| 1930 | |
| 1931 | // Heap where the array should be allocated. |
| 1932 | gc::Heap initialHeap_; |
| 1933 | |
| 1934 | bool vmCall_; |
| 1935 | |
| 1936 | MNewArray(uint32_t length, MConstant* templateConst, gc::Heap initialHeap, |
| 1937 | bool vmCall = false); |
| 1938 | |
| 1939 | public: |
| 1940 | INSTRUCTION_HEADER(NewArray) |
| 1941 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 1942 | |
| 1943 | static MNewArray* NewVM(TempAllocator& alloc, uint32_t length, |
| 1944 | MConstant* templateConst, gc::Heap initialHeap) { |
| 1945 | return new (alloc) MNewArray(length, templateConst, initialHeap, true); |
| 1946 | } |
| 1947 | |
| 1948 | uint32_t length() const { return length_; } |
| 1949 | |
| 1950 | JSObject* templateObject() const { |
| 1951 | return getOperand(0)->toConstant()->toObjectOrNull(); |
| 1952 | } |
| 1953 | |
| 1954 | gc::Heap initialHeap() const { return initialHeap_; } |
| 1955 | |
| 1956 | bool isVMCall() const { return vmCall_; } |
| 1957 | |
| 1958 | // NewArray is marked as non-effectful because all our allocations are |
| 1959 | // either lazy when we are using "new Array(length)" or bounded by the |
| 1960 | // script or the stack size when we are using "new Array(...)" or "[...]" |
| 1961 | // notations. So we might have to allocate the array twice if we bail |
| 1962 | // during the computation of the first element of the square braket |
| 1963 | // notation. |
| 1964 | virtual AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1965 | |
| 1966 | [[nodiscard]] bool writeRecoverData( |
| 1967 | CompactBufferWriter& writer) const override; |
| 1968 | bool canRecoverOnBailout() const override { |
| 1969 | // The template object can safely be used in the recover instruction |
| 1970 | // because it can never be mutated by any other function execution. |
| 1971 | return templateObject() != nullptr; |
| 1972 | } |
| 1973 | }; |
| 1974 | |
| 1975 | class MNewTypedArray : public MUnaryInstruction, public NoTypePolicy::Data { |
| 1976 | gc::Heap initialHeap_; |
| 1977 | |
| 1978 | MNewTypedArray(MConstant* templateConst, gc::Heap initialHeap) |
| 1979 | : MUnaryInstruction(classOpcode, templateConst), |
| 1980 | initialHeap_(initialHeap) { |
| 1981 | setResultType(MIRType::Object); |
| 1982 | } |
| 1983 | |
| 1984 | public: |
| 1985 | INSTRUCTION_HEADER(NewTypedArray) |
| 1986 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 1987 | |
| 1988 | TypedArrayObject* templateObject() const { |
| 1989 | return &getOperand(0)->toConstant()->toObject().as<TypedArrayObject>(); |
| 1990 | } |
| 1991 | |
| 1992 | gc::Heap initialHeap() const { return initialHeap_; } |
| 1993 | |
| 1994 | virtual AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 1995 | |
| 1996 | [[nodiscard]] bool writeRecoverData( |
| 1997 | CompactBufferWriter& writer) const override; |
| 1998 | bool canRecoverOnBailout() const override { return true; } |
| 1999 | }; |
| 2000 | |
| 2001 | class MNewObject : public MUnaryInstruction, public NoTypePolicy::Data { |
| 2002 | public: |
| 2003 | enum Mode { ObjectLiteral, ObjectCreate }; |
| 2004 | |
| 2005 | private: |
| 2006 | gc::Heap initialHeap_; |
| 2007 | Mode mode_; |
| 2008 | bool vmCall_; |
| 2009 | |
| 2010 | MNewObject(MConstant* templateConst, gc::Heap initialHeap, Mode mode, |
| 2011 | bool vmCall = false) |
| 2012 | : MUnaryInstruction(classOpcode, templateConst), |
| 2013 | initialHeap_(initialHeap), |
| 2014 | mode_(mode), |
| 2015 | vmCall_(vmCall) { |
| 2016 | if (mode == ObjectLiteral) { |
| 2017 | MOZ_ASSERT(!templateObject())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!templateObject())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!templateObject()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!templateObject()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2017); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!templateObject()" ")"); do { *((volatile int*)__null) = 2017; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2018 | } else { |
| 2019 | MOZ_ASSERT(templateObject())do { static_assert( mozilla::detail::AssertionConditionType< decltype(templateObject())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(templateObject()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("templateObject()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject()" ")"); do { *((volatile int*)__null) = 2019; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2020 | } |
| 2021 | setResultType(MIRType::Object); |
| 2022 | |
| 2023 | // The constant is kept separated in a MConstant, this way we can safely |
| 2024 | // mark it during GC if we recover the object allocation. Otherwise, by |
| 2025 | // making it emittedAtUses, we do not produce register allocations for |
| 2026 | // it and inline its content inside the code produced by the |
| 2027 | // CodeGenerator. |
| 2028 | if (templateConst->toConstant()->type() == MIRType::Object) { |
| 2029 | templateConst->setEmittedAtUses(); |
| 2030 | } |
| 2031 | } |
| 2032 | |
| 2033 | public: |
| 2034 | INSTRUCTION_HEADER(NewObject) |
| 2035 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2036 | |
| 2037 | static MNewObject* NewVM(TempAllocator& alloc, MConstant* templateConst, |
| 2038 | gc::Heap initialHeap, Mode mode) { |
| 2039 | return new (alloc) MNewObject(templateConst, initialHeap, mode, true); |
| 2040 | } |
| 2041 | |
| 2042 | Mode mode() const { return mode_; } |
| 2043 | |
| 2044 | JSObject* templateObject() const { |
| 2045 | return getOperand(0)->toConstant()->toObjectOrNull(); |
| 2046 | } |
| 2047 | |
| 2048 | gc::Heap initialHeap() const { return initialHeap_; } |
| 2049 | |
| 2050 | bool isVMCall() const { return vmCall_; } |
| 2051 | |
| 2052 | [[nodiscard]] bool writeRecoverData( |
| 2053 | CompactBufferWriter& writer) const override; |
| 2054 | bool canRecoverOnBailout() const override { |
| 2055 | // The template object can safely be used in the recover instruction |
| 2056 | // because it can never be mutated by any other function execution. |
| 2057 | return templateObject() != nullptr; |
| 2058 | } |
| 2059 | }; |
| 2060 | |
| 2061 | class MNewPlainObject : public MUnaryInstruction, public NoTypePolicy::Data { |
| 2062 | private: |
| 2063 | uint32_t numFixedSlots_; |
| 2064 | uint32_t numDynamicSlots_; |
| 2065 | gc::AllocKind allocKind_; |
| 2066 | gc::Heap initialHeap_; |
| 2067 | |
| 2068 | MNewPlainObject(MConstant* shapeConst, uint32_t numFixedSlots, |
| 2069 | uint32_t numDynamicSlots, gc::AllocKind allocKind, |
| 2070 | gc::Heap initialHeap) |
| 2071 | : MUnaryInstruction(classOpcode, shapeConst), |
| 2072 | numFixedSlots_(numFixedSlots), |
| 2073 | numDynamicSlots_(numDynamicSlots), |
| 2074 | allocKind_(allocKind), |
| 2075 | initialHeap_(initialHeap) { |
| 2076 | setResultType(MIRType::Object); |
| 2077 | |
| 2078 | // The shape constant is kept separated in a MConstant. This way we can |
| 2079 | // safely mark it during GC if we recover the object allocation. Otherwise, |
| 2080 | // by making it emittedAtUses, we do not produce register allocations for it |
| 2081 | // and inline its content inside the code produced by the CodeGenerator. |
| 2082 | MOZ_ASSERT(shapeConst->toConstant()->type() == MIRType::Shape)do { static_assert( mozilla::detail::AssertionConditionType< decltype(shapeConst->toConstant()->type() == MIRType::Shape )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(shapeConst->toConstant()->type() == MIRType::Shape ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "shapeConst->toConstant()->type() == MIRType::Shape", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "shapeConst->toConstant()->type() == MIRType::Shape" ")"); do { *((volatile int*)__null) = 2082; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2083 | shapeConst->setEmittedAtUses(); |
| 2084 | } |
| 2085 | |
| 2086 | public: |
| 2087 | INSTRUCTION_HEADER(NewPlainObject) |
| 2088 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2089 | |
| 2090 | const Shape* shape() const { return getOperand(0)->toConstant()->toShape(); } |
| 2091 | |
| 2092 | uint32_t numFixedSlots() const { return numFixedSlots_; } |
| 2093 | uint32_t numDynamicSlots() const { return numDynamicSlots_; } |
| 2094 | gc::AllocKind allocKind() const { return allocKind_; } |
| 2095 | gc::Heap initialHeap() const { return initialHeap_; } |
| 2096 | |
| 2097 | [[nodiscard]] bool writeRecoverData( |
| 2098 | CompactBufferWriter& writer) const override; |
| 2099 | bool canRecoverOnBailout() const override { return true; } |
| 2100 | |
| 2101 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 2102 | }; |
| 2103 | |
| 2104 | class MNewArrayObject : public MUnaryInstruction, public NoTypePolicy::Data { |
| 2105 | private: |
| 2106 | uint32_t length_; |
| 2107 | gc::Heap initialHeap_; |
| 2108 | |
| 2109 | MNewArrayObject(TempAllocator& alloc, MConstant* shapeConst, uint32_t length, |
| 2110 | gc::Heap initialHeap) |
| 2111 | : MUnaryInstruction(classOpcode, shapeConst), |
| 2112 | length_(length), |
| 2113 | initialHeap_(initialHeap) { |
| 2114 | setResultType(MIRType::Object); |
| 2115 | MOZ_ASSERT(shapeConst->toConstant()->type() == MIRType::Shape)do { static_assert( mozilla::detail::AssertionConditionType< decltype(shapeConst->toConstant()->type() == MIRType::Shape )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(shapeConst->toConstant()->type() == MIRType::Shape ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "shapeConst->toConstant()->type() == MIRType::Shape", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2115); AnnotateMozCrashReason("MOZ_ASSERT" "(" "shapeConst->toConstant()->type() == MIRType::Shape" ")"); do { *((volatile int*)__null) = 2115; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2116 | shapeConst->setEmittedAtUses(); |
| 2117 | } |
| 2118 | |
| 2119 | public: |
| 2120 | INSTRUCTION_HEADER(NewArrayObject) |
| 2121 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2122 | |
| 2123 | static MNewArrayObject* New(TempAllocator& alloc, MConstant* shapeConst, |
| 2124 | uint32_t length, gc::Heap initialHeap) { |
| 2125 | return new (alloc) MNewArrayObject(alloc, shapeConst, length, initialHeap); |
| 2126 | } |
| 2127 | |
| 2128 | const Shape* shape() const { return getOperand(0)->toConstant()->toShape(); } |
| 2129 | |
| 2130 | // See MNewArray::getAliasSet comment. |
| 2131 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 2132 | |
| 2133 | uint32_t length() const { return length_; } |
| 2134 | gc::Heap initialHeap() const { return initialHeap_; } |
| 2135 | |
| 2136 | [[nodiscard]] bool writeRecoverData( |
| 2137 | CompactBufferWriter& writer) const override; |
| 2138 | bool canRecoverOnBailout() const override { return true; } |
| 2139 | }; |
| 2140 | |
| 2141 | class MNewIterator : public MUnaryInstruction, public NoTypePolicy::Data { |
| 2142 | public: |
| 2143 | enum Type { |
| 2144 | ArrayIterator, |
| 2145 | StringIterator, |
| 2146 | RegExpStringIterator, |
| 2147 | }; |
| 2148 | |
| 2149 | private: |
| 2150 | Type type_; |
| 2151 | |
| 2152 | MNewIterator(MConstant* templateConst, Type type) |
| 2153 | : MUnaryInstruction(classOpcode, templateConst), type_(type) { |
| 2154 | setResultType(MIRType::Object); |
| 2155 | templateConst->setEmittedAtUses(); |
| 2156 | } |
| 2157 | |
| 2158 | public: |
| 2159 | INSTRUCTION_HEADER(NewIterator) |
| 2160 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2161 | |
| 2162 | Type type() const { return type_; } |
| 2163 | |
| 2164 | JSObject* templateObject() { |
| 2165 | return getOperand(0)->toConstant()->toObjectOrNull(); |
| 2166 | } |
| 2167 | |
| 2168 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 2169 | |
| 2170 | [[nodiscard]] bool writeRecoverData( |
| 2171 | CompactBufferWriter& writer) const override; |
| 2172 | bool canRecoverOnBailout() const override { return true; } |
| 2173 | }; |
| 2174 | |
| 2175 | // Represent the content of all slots of an object. This instruction is not |
| 2176 | // lowered and is not used to generate code. |
| 2177 | class MObjectState : public MVariadicInstruction, |
| 2178 | public NoFloatPolicyAfter<1>::Data { |
| 2179 | private: |
| 2180 | uint32_t numSlots_; |
| 2181 | uint32_t numFixedSlots_; |
| 2182 | |
| 2183 | explicit MObjectState(JSObject* templateObject); |
| 2184 | explicit MObjectState(const Shape* shape); |
| 2185 | explicit MObjectState(MObjectState* state); |
| 2186 | |
| 2187 | [[nodiscard]] bool init(TempAllocator& alloc, MDefinition* obj); |
| 2188 | |
| 2189 | void initSlot(uint32_t slot, MDefinition* def) { initOperand(slot + 1, def); } |
| 2190 | |
| 2191 | public: |
| 2192 | INSTRUCTION_HEADER(ObjectState) |
| 2193 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 2194 | |
| 2195 | // Return the template object of any object creation which can be recovered |
| 2196 | // on bailout. |
| 2197 | static JSObject* templateObjectOf(MDefinition* obj); |
| 2198 | |
| 2199 | static MObjectState* New(TempAllocator& alloc, MDefinition* obj); |
| 2200 | static MObjectState* Copy(TempAllocator& alloc, MObjectState* state); |
| 2201 | |
| 2202 | // As we might do read of uninitialized properties, we have to copy the |
| 2203 | // initial values from the template object. |
| 2204 | void initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal); |
| 2205 | |
| 2206 | size_t numFixedSlots() const { return numFixedSlots_; } |
| 2207 | size_t numSlots() const { return numSlots_; } |
| 2208 | |
| 2209 | MDefinition* getSlot(uint32_t slot) const { return getOperand(slot + 1); } |
| 2210 | void setSlot(uint32_t slot, MDefinition* def) { |
| 2211 | replaceOperand(slot + 1, def); |
| 2212 | } |
| 2213 | |
| 2214 | bool hasFixedSlot(uint32_t slot) const { |
| 2215 | return slot < numSlots() && slot < numFixedSlots(); |
| 2216 | } |
| 2217 | MDefinition* getFixedSlot(uint32_t slot) const { |
| 2218 | MOZ_ASSERT(slot < numFixedSlots())do { static_assert( mozilla::detail::AssertionConditionType< decltype(slot < numFixedSlots())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(slot < numFixedSlots()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("slot < numFixedSlots()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "slot < numFixedSlots()" ")"); do { *((volatile int*)__null) = 2218; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2219 | return getSlot(slot); |
| 2220 | } |
| 2221 | void setFixedSlot(uint32_t slot, MDefinition* def) { |
| 2222 | MOZ_ASSERT(slot < numFixedSlots())do { static_assert( mozilla::detail::AssertionConditionType< decltype(slot < numFixedSlots())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(slot < numFixedSlots()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("slot < numFixedSlots()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2222); AnnotateMozCrashReason("MOZ_ASSERT" "(" "slot < numFixedSlots()" ")"); do { *((volatile int*)__null) = 2222; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2223 | setSlot(slot, def); |
| 2224 | } |
| 2225 | |
| 2226 | bool hasDynamicSlot(uint32_t slot) const { |
| 2227 | return numFixedSlots() < numSlots() && slot < numSlots() - numFixedSlots(); |
| 2228 | } |
| 2229 | MDefinition* getDynamicSlot(uint32_t slot) const { |
| 2230 | return getSlot(slot + numFixedSlots()); |
| 2231 | } |
| 2232 | void setDynamicSlot(uint32_t slot, MDefinition* def) { |
| 2233 | setSlot(slot + numFixedSlots(), def); |
| 2234 | } |
| 2235 | |
| 2236 | [[nodiscard]] bool writeRecoverData( |
| 2237 | CompactBufferWriter& writer) const override; |
| 2238 | bool canRecoverOnBailout() const override { return true; } |
| 2239 | }; |
| 2240 | |
| 2241 | // Represent the contents of all elements of an array. This instruction is not |
| 2242 | // lowered and is not used to generate code. |
| 2243 | class MArrayState : public MVariadicInstruction, |
| 2244 | public NoFloatPolicyAfter<2>::Data { |
| 2245 | private: |
| 2246 | uint32_t numElements_; |
| 2247 | |
| 2248 | explicit MArrayState(MDefinition* arr); |
| 2249 | |
| 2250 | [[nodiscard]] bool init(TempAllocator& alloc, MDefinition* obj, |
| 2251 | MDefinition* len); |
| 2252 | |
| 2253 | void initElement(uint32_t index, MDefinition* def) { |
| 2254 | initOperand(index + 2, def); |
| 2255 | } |
| 2256 | |
| 2257 | public: |
| 2258 | INSTRUCTION_HEADER(ArrayState) |
| 2259 | NAMED_OPERANDS((0, array), (1, initializedLength))MDefinition* array() const { return getOperand(0); } MDefinition * initializedLength() const { return getOperand(1); } |
| 2260 | |
| 2261 | static MArrayState* New(TempAllocator& alloc, MDefinition* arr, |
| 2262 | MDefinition* initLength); |
| 2263 | static MArrayState* Copy(TempAllocator& alloc, MArrayState* state); |
| 2264 | |
| 2265 | void initFromTemplateObject(TempAllocator& alloc, MDefinition* undefinedVal); |
| 2266 | |
| 2267 | void setInitializedLength(MDefinition* def) { replaceOperand(1, def); } |
| 2268 | |
| 2269 | size_t numElements() const { return numElements_; } |
| 2270 | |
| 2271 | MDefinition* getElement(uint32_t index) const { |
| 2272 | return getOperand(index + 2); |
| 2273 | } |
| 2274 | void setElement(uint32_t index, MDefinition* def) { |
| 2275 | replaceOperand(index + 2, def); |
| 2276 | } |
| 2277 | |
| 2278 | [[nodiscard]] bool writeRecoverData( |
| 2279 | CompactBufferWriter& writer) const override; |
| 2280 | bool canRecoverOnBailout() const override { return true; } |
| 2281 | }; |
| 2282 | |
| 2283 | // WrappedFunction stores information about a function that can safely be used |
| 2284 | // off-thread. In particular, a function's flags can be modified on the main |
| 2285 | // thread as functions are relazified and delazified, so we must be careful not |
| 2286 | // to access these flags off-thread. |
| 2287 | class WrappedFunction : public TempObject { |
| 2288 | // If this is a native function without a JitEntry, the JSFunction*. |
| 2289 | CompilerFunction nativeFun_; |
| 2290 | uint16_t nargs_; |
| 2291 | js::FunctionFlags flags_; |
| 2292 | |
| 2293 | public: |
| 2294 | WrappedFunction(JSFunction* nativeFun, uint16_t nargs, FunctionFlags flags); |
| 2295 | |
| 2296 | // Note: When adding new accessors be sure to add consistency asserts |
| 2297 | // to the constructor. |
| 2298 | |
| 2299 | size_t nargs() const { return nargs_; } |
| 2300 | |
| 2301 | bool isNativeWithoutJitEntry() const { |
| 2302 | return flags_.isNativeWithoutJitEntry(); |
| 2303 | } |
| 2304 | bool hasJitEntry() const { return flags_.hasJitEntry(); } |
| 2305 | bool isConstructor() const { return flags_.isConstructor(); } |
| 2306 | bool isClassConstructor() const { return flags_.isClassConstructor(); } |
| 2307 | |
| 2308 | // These fields never change, they can be accessed off-main thread. |
| 2309 | JSNative native() const { |
| 2310 | MOZ_ASSERT(isNativeWithoutJitEntry())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isNativeWithoutJitEntry())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isNativeWithoutJitEntry()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("isNativeWithoutJitEntry()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2310); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNativeWithoutJitEntry()" ")"); do { *((volatile int*)__null) = 2310; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2311 | return nativeFun_->nativeUnchecked(); |
| 2312 | } |
| 2313 | bool hasJitInfo() const { |
| 2314 | return flags_.canHaveJitInfo() && nativeFun_->jitInfoUnchecked(); |
| 2315 | } |
| 2316 | const JSJitInfo* jitInfo() const { |
| 2317 | MOZ_ASSERT(hasJitInfo())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hasJitInfo())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hasJitInfo()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("hasJitInfo()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2317); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hasJitInfo()" ")"); do { *((volatile int*)__null) = 2317; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2318 | return nativeFun_->jitInfoUnchecked(); |
| 2319 | } |
| 2320 | |
| 2321 | JSFunction* rawNativeJSFunction() const { return nativeFun_; } |
| 2322 | }; |
| 2323 | |
| 2324 | enum class DOMObjectKind : uint8_t { Proxy, Native }; |
| 2325 | |
| 2326 | class MCallBase : public MVariadicInstruction, public CallPolicy::Data { |
| 2327 | protected: |
| 2328 | // The callee, this, and the actual arguments are all operands of MCall. |
| 2329 | static const size_t CalleeOperandIndex = 0; |
| 2330 | static const size_t NumNonArgumentOperands = 1; |
| 2331 | |
| 2332 | explicit MCallBase(Opcode op) : MVariadicInstruction(op) {} |
| 2333 | |
| 2334 | public: |
| 2335 | void initCallee(MDefinition* func) { initOperand(CalleeOperandIndex, func); } |
| 2336 | MDefinition* getCallee() const { return getOperand(CalleeOperandIndex); } |
| 2337 | |
| 2338 | void replaceCallee(MInstruction* newfunc) { |
| 2339 | replaceOperand(CalleeOperandIndex, newfunc); |
| 2340 | } |
| 2341 | |
| 2342 | void addArg(size_t argnum, MDefinition* arg); |
| 2343 | |
| 2344 | MDefinition* getArg(uint32_t index) const { |
| 2345 | return getOperand(NumNonArgumentOperands + index); |
| 2346 | } |
| 2347 | |
| 2348 | // The number of stack arguments is the max between the number of formal |
| 2349 | // arguments and the number of actual arguments. The number of stack |
| 2350 | // argument includes the |undefined| padding added in case of underflow. |
| 2351 | // Includes |this|. |
| 2352 | uint32_t numStackArgs() const { |
| 2353 | return numOperands() - NumNonArgumentOperands; |
| 2354 | } |
| 2355 | uint32_t paddedNumStackArgs() const { |
| 2356 | if (JitStackValueAlignment > 1) { |
| 2357 | return AlignBytes(numStackArgs(), JitStackValueAlignment); |
| 2358 | } |
| 2359 | return numStackArgs(); |
| 2360 | } |
| 2361 | |
| 2362 | static size_t IndexOfThis() { return NumNonArgumentOperands; } |
| 2363 | static size_t IndexOfArgument(size_t index) { |
| 2364 | return NumNonArgumentOperands + index + 1; // +1 to skip |this|. |
| 2365 | } |
| 2366 | static size_t IndexOfStackArg(size_t index) { |
| 2367 | return NumNonArgumentOperands + index; |
| 2368 | } |
| 2369 | }; |
| 2370 | |
| 2371 | class MCall : public MCallBase { |
| 2372 | protected: |
| 2373 | // Monomorphic cache for MCalls with a single JSFunction target. |
| 2374 | WrappedFunction* target_; |
| 2375 | |
| 2376 | // Original value of argc from the bytecode. |
| 2377 | uint32_t numActualArgs_; |
| 2378 | |
| 2379 | // True if the call is for JSOp::New or JSOp::SuperCall. |
| 2380 | bool construct_ : 1; |
| 2381 | |
| 2382 | // True if the caller does not use the return value. |
| 2383 | bool ignoresReturnValue_ : 1; |
| 2384 | |
| 2385 | bool needsClassCheck_ : 1; |
| 2386 | bool maybeCrossRealm_ : 1; |
| 2387 | bool needsThisCheck_ : 1; |
| 2388 | |
| 2389 | MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct, |
| 2390 | bool ignoresReturnValue) |
| 2391 | : MCallBase(classOpcode), |
| 2392 | target_(target), |
| 2393 | numActualArgs_(numActualArgs), |
| 2394 | construct_(construct), |
| 2395 | ignoresReturnValue_(ignoresReturnValue), |
| 2396 | needsClassCheck_(true), |
| 2397 | maybeCrossRealm_(true), |
| 2398 | needsThisCheck_(false) { |
| 2399 | setResultType(MIRType::Value); |
| 2400 | } |
| 2401 | |
| 2402 | public: |
| 2403 | INSTRUCTION_HEADER(Call) |
| 2404 | static MCall* New(TempAllocator& alloc, WrappedFunction* target, |
| 2405 | size_t maxArgc, size_t numActualArgs, bool construct, |
| 2406 | bool ignoresReturnValue, bool isDOMCall, |
| 2407 | mozilla::Maybe<DOMObjectKind> objectKind); |
| 2408 | |
| 2409 | bool needsClassCheck() const { return needsClassCheck_; } |
| 2410 | void disableClassCheck() { needsClassCheck_ = false; } |
| 2411 | |
| 2412 | bool maybeCrossRealm() const { return maybeCrossRealm_; } |
| 2413 | void setNotCrossRealm() { maybeCrossRealm_ = false; } |
| 2414 | |
| 2415 | bool needsThisCheck() const { return needsThisCheck_; } |
| 2416 | void setNeedsThisCheck() { |
| 2417 | MOZ_ASSERT(construct_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(construct_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(construct_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("construct_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2417); AnnotateMozCrashReason("MOZ_ASSERT" "(" "construct_" ")"); do { *((volatile int*)__null) = 2417; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2418 | needsThisCheck_ = true; |
| 2419 | } |
| 2420 | |
| 2421 | // For monomorphic callsites. |
| 2422 | WrappedFunction* getSingleTarget() const { return target_; } |
| 2423 | |
| 2424 | bool isConstructing() const { return construct_; } |
| 2425 | |
| 2426 | bool ignoresReturnValue() const { return ignoresReturnValue_; } |
| 2427 | |
| 2428 | // Does not include |this|. |
| 2429 | uint32_t numActualArgs() const { return numActualArgs_; } |
| 2430 | |
| 2431 | bool possiblyCalls() const override { return true; } |
| 2432 | |
| 2433 | virtual bool isCallDOMNative() const { return false; } |
| 2434 | |
| 2435 | // A method that can be called to tell the MCall to figure out whether it's |
| 2436 | // movable or not. This can't be done in the constructor, because it |
| 2437 | // depends on the arguments to the call, and those aren't passed to the |
| 2438 | // constructor but are set up later via addArg. |
| 2439 | virtual void computeMovable() {} |
| 2440 | }; |
| 2441 | |
| 2442 | class MCallDOMNative : public MCall { |
| 2443 | // A helper class for MCalls for DOM natives. Note that this is NOT |
| 2444 | // actually a separate MIR op from MCall, because all sorts of places use |
| 2445 | // isCall() to check for calls and all we really want is to overload a few |
| 2446 | // virtual things from MCall. |
| 2447 | |
| 2448 | DOMObjectKind objectKind_; |
| 2449 | |
| 2450 | MCallDOMNative(WrappedFunction* target, uint32_t numActualArgs, |
| 2451 | DOMObjectKind objectKind) |
| 2452 | : MCall(target, numActualArgs, false, false), objectKind_(objectKind) { |
| 2453 | MOZ_ASSERT(getJitInfo()->type() != JSJitInfo::InlinableNative)do { static_assert( mozilla::detail::AssertionConditionType< decltype(getJitInfo()->type() != JSJitInfo::InlinableNative )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(getJitInfo()->type() != JSJitInfo::InlinableNative ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "getJitInfo()->type() != JSJitInfo::InlinableNative", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2453); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getJitInfo()->type() != JSJitInfo::InlinableNative" ")"); do { *((volatile int*)__null) = 2453; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2454 | |
| 2455 | // If our jitinfo is not marked eliminatable, that means that our C++ |
| 2456 | // implementation is fallible or that it never wants to be eliminated or |
| 2457 | // that we have no hope of ever doing the sort of argument analysis that |
| 2458 | // would allow us to detemine that we're side-effect-free. In the |
| 2459 | // latter case we wouldn't get DCEd no matter what, but for the former |
| 2460 | // two cases we have to explicitly say that we can't be DCEd. |
| 2461 | if (!getJitInfo()->isEliminatable) { |
| 2462 | setGuard(); |
| 2463 | } |
| 2464 | } |
| 2465 | |
| 2466 | friend MCall* MCall::New(TempAllocator& alloc, WrappedFunction* target, |
| 2467 | size_t maxArgc, size_t numActualArgs, bool construct, |
| 2468 | bool ignoresReturnValue, bool isDOMCall, |
| 2469 | mozilla::Maybe<DOMObjectKind> objectKind); |
| 2470 | |
| 2471 | const JSJitInfo* getJitInfo() const; |
| 2472 | |
| 2473 | public: |
| 2474 | DOMObjectKind objectKind() const { return objectKind_; } |
| 2475 | |
| 2476 | virtual AliasSet getAliasSet() const override; |
| 2477 | |
| 2478 | virtual bool congruentTo(const MDefinition* ins) const override; |
| 2479 | |
| 2480 | virtual bool isCallDOMNative() const override { return true; } |
| 2481 | |
| 2482 | virtual void computeMovable() override; |
| 2483 | }; |
| 2484 | |
| 2485 | // Used to invoke a JSClass call/construct hook. |
| 2486 | class MCallClassHook : public MCallBase { |
| 2487 | const JSNative target_; |
| 2488 | bool constructing_ : 1; |
| 2489 | bool ignoresReturnValue_ : 1; |
| 2490 | |
| 2491 | MCallClassHook(JSNative target, bool constructing) |
| 2492 | : MCallBase(classOpcode), |
| 2493 | target_(target), |
| 2494 | constructing_(constructing), |
| 2495 | ignoresReturnValue_(false) { |
| 2496 | setResultType(MIRType::Value); |
| 2497 | } |
| 2498 | |
| 2499 | public: |
| 2500 | INSTRUCTION_HEADER(CallClassHook) |
| 2501 | static MCallClassHook* New(TempAllocator& alloc, JSNative target, |
| 2502 | uint32_t argc, bool constructing); |
| 2503 | |
| 2504 | JSNative target() const { return target_; } |
| 2505 | bool isConstructing() const { return constructing_; } |
| 2506 | |
| 2507 | uint32_t numActualArgs() const { |
| 2508 | uint32_t thisAndNewTarget = 1 + constructing_; |
| 2509 | MOZ_ASSERT(numStackArgs() >= thisAndNewTarget)do { static_assert( mozilla::detail::AssertionConditionType< decltype(numStackArgs() >= thisAndNewTarget)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(numStackArgs() >= thisAndNewTarget))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("numStackArgs() >= thisAndNewTarget" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2509); AnnotateMozCrashReason("MOZ_ASSERT" "(" "numStackArgs() >= thisAndNewTarget" ")"); do { *((volatile int*)__null) = 2509; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2510 | return numStackArgs() - thisAndNewTarget; |
| 2511 | } |
| 2512 | |
| 2513 | bool maybeCrossRealm() const { return true; } |
| 2514 | |
| 2515 | bool ignoresReturnValue() const { return ignoresReturnValue_; } |
| 2516 | void setIgnoresReturnValue() { ignoresReturnValue_ = true; } |
| 2517 | |
| 2518 | bool possiblyCalls() const override { return true; } |
| 2519 | }; |
| 2520 | |
| 2521 | // fun.apply(self, arguments) |
| 2522 | class MApplyArgs : public MTernaryInstruction, |
| 2523 | public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, |
| 2524 | BoxPolicy<2>>::Data { |
| 2525 | // Single target from CacheIR, or nullptr |
| 2526 | WrappedFunction* target_; |
| 2527 | // Number of extra initial formals to skip. |
| 2528 | uint32_t numExtraFormals_; |
| 2529 | bool maybeCrossRealm_ = true; |
| 2530 | bool ignoresReturnValue_ = false; |
| 2531 | |
| 2532 | MApplyArgs(WrappedFunction* target, MDefinition* fun, MDefinition* argc, |
| 2533 | MDefinition* self, uint32_t numExtraFormals = 0) |
| 2534 | : MTernaryInstruction(classOpcode, fun, argc, self), |
| 2535 | target_(target), |
| 2536 | numExtraFormals_(numExtraFormals) { |
| 2537 | MOZ_ASSERT(argc->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(argc->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(argc->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("argc->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2537); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2537; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2538 | setResultType(MIRType::Value); |
| 2539 | } |
| 2540 | |
| 2541 | public: |
| 2542 | INSTRUCTION_HEADER(ApplyArgs) |
| 2543 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2544 | NAMED_OPERANDS((0, getFunction), (1, getArgc), (2, getThis))MDefinition* getFunction() const { return getOperand(0); } MDefinition * getArgc() const { return getOperand(1); } MDefinition* getThis () const { return getOperand(2); } |
| 2545 | |
| 2546 | WrappedFunction* getSingleTarget() const { return target_; } |
| 2547 | |
| 2548 | uint32_t numExtraFormals() const { return numExtraFormals_; } |
| 2549 | |
| 2550 | bool maybeCrossRealm() const { return maybeCrossRealm_; } |
| 2551 | void setNotCrossRealm() { maybeCrossRealm_ = false; } |
| 2552 | |
| 2553 | bool ignoresReturnValue() const { return ignoresReturnValue_; } |
| 2554 | void setIgnoresReturnValue() { ignoresReturnValue_ = true; } |
| 2555 | |
| 2556 | bool isConstructing() const { return false; } |
| 2557 | |
| 2558 | bool possiblyCalls() const override { return true; } |
| 2559 | }; |
| 2560 | |
| 2561 | class MApplyArgsObj |
| 2562 | : public MTernaryInstruction, |
| 2563 | public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2>>::Data { |
| 2564 | WrappedFunction* target_; |
| 2565 | bool maybeCrossRealm_ = true; |
| 2566 | bool ignoresReturnValue_ = false; |
| 2567 | |
| 2568 | MApplyArgsObj(WrappedFunction* target, MDefinition* fun, MDefinition* argsObj, |
| 2569 | MDefinition* thisArg) |
| 2570 | : MTernaryInstruction(classOpcode, fun, argsObj, thisArg), |
| 2571 | target_(target) { |
| 2572 | MOZ_ASSERT(argsObj->type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(argsObj->type() == MIRType::Object)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(argsObj->type() == MIRType::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("argsObj->type() == MIRType::Object" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2572); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argsObj->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 2572; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2573 | setResultType(MIRType::Value); |
| 2574 | } |
| 2575 | |
| 2576 | public: |
| 2577 | INSTRUCTION_HEADER(ApplyArgsObj) |
| 2578 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2579 | NAMED_OPERANDS((0, getFunction), (1, getArgsObj), (2, getThis))MDefinition* getFunction() const { return getOperand(0); } MDefinition * getArgsObj() const { return getOperand(1); } MDefinition* getThis () const { return getOperand(2); } |
| 2580 | |
| 2581 | WrappedFunction* getSingleTarget() const { return target_; } |
| 2582 | |
| 2583 | bool maybeCrossRealm() const { return maybeCrossRealm_; } |
| 2584 | void setNotCrossRealm() { maybeCrossRealm_ = false; } |
| 2585 | |
| 2586 | bool ignoresReturnValue() const { return ignoresReturnValue_; } |
| 2587 | void setIgnoresReturnValue() { ignoresReturnValue_ = true; } |
| 2588 | |
| 2589 | bool isConstructing() const { return false; } |
| 2590 | |
| 2591 | bool possiblyCalls() const override { return true; } |
| 2592 | }; |
| 2593 | |
| 2594 | // fun.apply(fn, array) |
| 2595 | class MApplyArray : public MTernaryInstruction, |
| 2596 | public MixPolicy<ObjectPolicy<0>, BoxPolicy<2>>::Data { |
| 2597 | // Single target from CacheIR, or nullptr |
| 2598 | WrappedFunction* target_; |
| 2599 | bool maybeCrossRealm_ = true; |
| 2600 | bool ignoresReturnValue_ = false; |
| 2601 | |
| 2602 | MApplyArray(WrappedFunction* target, MDefinition* fun, MDefinition* elements, |
| 2603 | MDefinition* self) |
| 2604 | : MTernaryInstruction(classOpcode, fun, elements, self), target_(target) { |
| 2605 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2605); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 2605; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2606 | setResultType(MIRType::Value); |
| 2607 | } |
| 2608 | |
| 2609 | public: |
| 2610 | INSTRUCTION_HEADER(ApplyArray) |
| 2611 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2612 | NAMED_OPERANDS((0, getFunction), (1, getElements), (2, getThis))MDefinition* getFunction() const { return getOperand(0); } MDefinition * getElements() const { return getOperand(1); } MDefinition* getThis () const { return getOperand(2); } |
| 2613 | |
| 2614 | WrappedFunction* getSingleTarget() const { return target_; } |
| 2615 | |
| 2616 | bool maybeCrossRealm() const { return maybeCrossRealm_; } |
| 2617 | void setNotCrossRealm() { maybeCrossRealm_ = false; } |
| 2618 | |
| 2619 | bool ignoresReturnValue() const { return ignoresReturnValue_; } |
| 2620 | void setIgnoresReturnValue() { ignoresReturnValue_ = true; } |
| 2621 | |
| 2622 | bool isConstructing() const { return false; } |
| 2623 | |
| 2624 | bool possiblyCalls() const override { return true; } |
| 2625 | }; |
| 2626 | |
| 2627 | // |new F(...arguments)| and |super(...arguments)|. |
| 2628 | class MConstructArgs : public MQuaternaryInstruction, |
| 2629 | public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, |
| 2630 | BoxPolicy<2>, ObjectPolicy<3>>::Data { |
| 2631 | // Single target from CacheIR, or nullptr |
| 2632 | WrappedFunction* target_; |
| 2633 | // Number of extra initial formals to skip. |
| 2634 | uint32_t numExtraFormals_; |
| 2635 | bool maybeCrossRealm_ = true; |
| 2636 | |
| 2637 | MConstructArgs(WrappedFunction* target, MDefinition* fun, MDefinition* argc, |
| 2638 | MDefinition* thisValue, MDefinition* newTarget, |
| 2639 | uint32_t numExtraFormals = 0) |
| 2640 | : MQuaternaryInstruction(classOpcode, fun, argc, thisValue, newTarget), |
| 2641 | target_(target), |
| 2642 | numExtraFormals_(numExtraFormals) { |
| 2643 | MOZ_ASSERT(argc->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(argc->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(argc->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("argc->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2643); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2643; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2644 | setResultType(MIRType::Value); |
| 2645 | } |
| 2646 | |
| 2647 | public: |
| 2648 | INSTRUCTION_HEADER(ConstructArgs) |
| 2649 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2650 | NAMED_OPERANDS((0, getFunction), (1, getArgc), (2, getThis),MDefinition* getFunction() const { return getOperand(0); } MDefinition * getArgc() const { return getOperand(1); } MDefinition* getThis () const { return getOperand(2); } MDefinition* getNewTarget( ) const { return getOperand(3); } |
| 2651 | (3, getNewTarget))MDefinition* getFunction() const { return getOperand(0); } MDefinition * getArgc() const { return getOperand(1); } MDefinition* getThis () const { return getOperand(2); } MDefinition* getNewTarget( ) const { return getOperand(3); } |
| 2652 | |
| 2653 | WrappedFunction* getSingleTarget() const { return target_; } |
| 2654 | |
| 2655 | uint32_t numExtraFormals() const { return numExtraFormals_; } |
| 2656 | |
| 2657 | bool maybeCrossRealm() const { return maybeCrossRealm_; } |
| 2658 | void setNotCrossRealm() { maybeCrossRealm_ = false; } |
| 2659 | |
| 2660 | bool ignoresReturnValue() const { return false; } |
| 2661 | bool isConstructing() const { return true; } |
| 2662 | |
| 2663 | bool possiblyCalls() const override { return true; } |
| 2664 | }; |
| 2665 | |
| 2666 | // |new F(...args)| and |super(...args)|. |
| 2667 | class MConstructArray |
| 2668 | : public MQuaternaryInstruction, |
| 2669 | public MixPolicy<ObjectPolicy<0>, BoxPolicy<2>, ObjectPolicy<3>>::Data { |
| 2670 | // Single target from CacheIR, or nullptr |
| 2671 | WrappedFunction* target_; |
| 2672 | bool maybeCrossRealm_ = true; |
| 2673 | bool needsThisCheck_ = false; |
| 2674 | |
| 2675 | MConstructArray(WrappedFunction* target, MDefinition* fun, |
| 2676 | MDefinition* elements, MDefinition* thisValue, |
| 2677 | MDefinition* newTarget) |
| 2678 | : MQuaternaryInstruction(classOpcode, fun, elements, thisValue, |
| 2679 | newTarget), |
| 2680 | target_(target) { |
| 2681 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2681); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 2681; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2682 | setResultType(MIRType::Value); |
| 2683 | } |
| 2684 | |
| 2685 | public: |
| 2686 | INSTRUCTION_HEADER(ConstructArray) |
| 2687 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2688 | NAMED_OPERANDS((0, getFunction), (1, getElements), (2, getThis),MDefinition* getFunction() const { return getOperand(0); } MDefinition * getElements() const { return getOperand(1); } MDefinition* getThis () const { return getOperand(2); } MDefinition* getNewTarget( ) const { return getOperand(3); } |
| 2689 | (3, getNewTarget))MDefinition* getFunction() const { return getOperand(0); } MDefinition * getElements() const { return getOperand(1); } MDefinition* getThis () const { return getOperand(2); } MDefinition* getNewTarget( ) const { return getOperand(3); } |
| 2690 | |
| 2691 | WrappedFunction* getSingleTarget() const { return target_; } |
| 2692 | |
| 2693 | bool maybeCrossRealm() const { return maybeCrossRealm_; } |
| 2694 | void setNotCrossRealm() { maybeCrossRealm_ = false; } |
| 2695 | |
| 2696 | bool needsThisCheck() const { return needsThisCheck_; } |
| 2697 | void setNeedsThisCheck() { needsThisCheck_ = true; } |
| 2698 | |
| 2699 | bool ignoresReturnValue() const { return false; } |
| 2700 | bool isConstructing() const { return true; } |
| 2701 | |
| 2702 | bool possiblyCalls() const override { return true; } |
| 2703 | }; |
| 2704 | |
| 2705 | class MBail : public MNullaryInstruction { |
| 2706 | explicit MBail(BailoutKind kind) : MNullaryInstruction(classOpcode) { |
| 2707 | setBailoutKind(kind); |
| 2708 | setGuard(); |
| 2709 | } |
| 2710 | |
| 2711 | public: |
| 2712 | INSTRUCTION_HEADER(Bail) |
| 2713 | |
| 2714 | static MBail* New(TempAllocator& alloc, BailoutKind kind) { |
| 2715 | return new (alloc) MBail(kind); |
| 2716 | } |
| 2717 | static MBail* New(TempAllocator& alloc) { |
| 2718 | return new (alloc) MBail(BailoutKind::Inevitable); |
| 2719 | } |
| 2720 | |
| 2721 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 2722 | }; |
| 2723 | |
| 2724 | class MUnreachable : public MAryControlInstruction<0, 0>, |
| 2725 | public NoTypePolicy::Data { |
| 2726 | MUnreachable() : MAryControlInstruction(classOpcode) {} |
| 2727 | |
| 2728 | public: |
| 2729 | INSTRUCTION_HEADER(Unreachable) |
| 2730 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2731 | |
| 2732 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 2733 | }; |
| 2734 | |
| 2735 | class MAssertRecoveredOnBailout : public MUnaryInstruction, |
| 2736 | public NoTypePolicy::Data { |
| 2737 | bool mustBeRecovered_; |
| 2738 | |
| 2739 | MAssertRecoveredOnBailout(MDefinition* ins, bool mustBeRecovered) |
| 2740 | : MUnaryInstruction(classOpcode, ins), mustBeRecovered_(mustBeRecovered) { |
| 2741 | setResultType(MIRType::Value); |
| 2742 | setRecoveredOnBailout(); |
| 2743 | setGuard(); |
| 2744 | } |
| 2745 | |
| 2746 | public: |
| 2747 | INSTRUCTION_HEADER(AssertRecoveredOnBailout) |
| 2748 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2749 | |
| 2750 | // Needed to assert that float32 instructions are correctly recovered. |
| 2751 | bool canConsumeFloat32(MUse* use) const override { return true; } |
| 2752 | |
| 2753 | [[nodiscard]] bool writeRecoverData( |
| 2754 | CompactBufferWriter& writer) const override; |
| 2755 | bool canRecoverOnBailout() const override { return true; } |
| 2756 | }; |
| 2757 | |
| 2758 | class MAssertFloat32 : public MUnaryInstruction, public NoTypePolicy::Data { |
| 2759 | bool mustBeFloat32_; |
| 2760 | |
| 2761 | MAssertFloat32(MDefinition* value, bool mustBeFloat32) |
| 2762 | : MUnaryInstruction(classOpcode, value), mustBeFloat32_(mustBeFloat32) {} |
| 2763 | |
| 2764 | public: |
| 2765 | INSTRUCTION_HEADER(AssertFloat32) |
| 2766 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2767 | |
| 2768 | bool canConsumeFloat32(MUse* use) const override { return true; } |
| 2769 | |
| 2770 | bool mustBeFloat32() const { return mustBeFloat32_; } |
| 2771 | }; |
| 2772 | |
| 2773 | class MCompare : public MBinaryInstruction, public ComparePolicy::Data { |
| 2774 | public: |
| 2775 | enum CompareType { |
| 2776 | |
| 2777 | // Anything compared to Undefined |
| 2778 | Compare_Undefined, |
| 2779 | |
| 2780 | // Anything compared to Null |
| 2781 | Compare_Null, |
| 2782 | |
| 2783 | // Int32 compared to Int32 |
| 2784 | // Boolean compared to Boolean |
| 2785 | Compare_Int32, |
| 2786 | |
| 2787 | // Int32 compared as unsigneds |
| 2788 | Compare_UInt32, |
| 2789 | |
| 2790 | // Int64 compared to Int64. |
| 2791 | Compare_Int64, |
| 2792 | |
| 2793 | // Int64 compared as unsigneds. |
| 2794 | Compare_UInt64, |
| 2795 | |
| 2796 | // IntPtr compared as unsigneds. |
| 2797 | Compare_UIntPtr, |
| 2798 | |
| 2799 | // Double compared to Double |
| 2800 | Compare_Double, |
| 2801 | |
| 2802 | // Float compared to Float |
| 2803 | Compare_Float32, |
| 2804 | |
| 2805 | // String compared to String |
| 2806 | Compare_String, |
| 2807 | |
| 2808 | // Symbol compared to Symbol |
| 2809 | Compare_Symbol, |
| 2810 | |
| 2811 | // Object compared to Object |
| 2812 | Compare_Object, |
| 2813 | |
| 2814 | // BigInt compared to BigInt |
| 2815 | Compare_BigInt, |
| 2816 | |
| 2817 | // BigInt compared to Int32 |
| 2818 | Compare_BigInt_Int32, |
| 2819 | |
| 2820 | // BigInt compared to Double |
| 2821 | Compare_BigInt_Double, |
| 2822 | |
| 2823 | // BigInt compared to String |
| 2824 | Compare_BigInt_String, |
| 2825 | |
| 2826 | // Wasm Ref/AnyRef/NullRef compared to Ref/AnyRef/NullRef |
| 2827 | Compare_WasmAnyRef, |
| 2828 | }; |
| 2829 | |
| 2830 | private: |
| 2831 | CompareType compareType_; |
| 2832 | JSOp jsop_; |
| 2833 | bool operandsAreNeverNaN_; |
| 2834 | |
| 2835 | // When a floating-point comparison is converted to an integer comparison |
| 2836 | // (when range analysis proves it safe), we need to convert the operands |
| 2837 | // to integer as well. |
| 2838 | bool truncateOperands_; |
| 2839 | |
| 2840 | MCompare(MDefinition* left, MDefinition* right, JSOp jsop, |
| 2841 | CompareType compareType) |
| 2842 | : MBinaryInstruction(classOpcode, left, right), |
| 2843 | compareType_(compareType), |
| 2844 | jsop_(jsop), |
| 2845 | operandsAreNeverNaN_(false), |
| 2846 | truncateOperands_(false) { |
| 2847 | setResultType(MIRType::Boolean); |
| 2848 | setMovable(); |
| 2849 | } |
| 2850 | |
| 2851 | public: |
| 2852 | INSTRUCTION_HEADER(Compare) |
| 2853 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 2854 | |
| 2855 | static MCompare* NewWasm(TempAllocator& alloc, MDefinition* left, |
| 2856 | MDefinition* right, JSOp jsop, |
| 2857 | CompareType compareType) { |
| 2858 | MOZ_ASSERT(compareType == Compare_Int32 || compareType == Compare_UInt32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" ")"); do { *((volatile int*)__null) = 2862; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 2859 | compareType == Compare_Int64 || compareType == Compare_UInt64 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" ")"); do { *((volatile int*)__null) = 2862; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 2860 | compareType == Compare_Double ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" ")"); do { *((volatile int*)__null) = 2862; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 2861 | compareType == Compare_Float32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" ")"); do { *((volatile int*)__null) = 2862; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 2862 | compareType == Compare_WasmAnyRef)do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType == Compare_Int32 || compareType == Compare_UInt32 || compareType == Compare_Int64 || compareType == Compare_UInt64 || compareType == Compare_Double || compareType == Compare_Float32 || compareType == Compare_WasmAnyRef" ")"); do { *((volatile int*)__null) = 2862; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2863 | auto* ins = MCompare::New(alloc, left, right, jsop, compareType); |
| 2864 | ins->setResultType(MIRType::Int32); |
| 2865 | return ins; |
| 2866 | } |
| 2867 | |
| 2868 | [[nodiscard]] bool tryFold(bool* result); |
| 2869 | [[nodiscard]] bool evaluateConstantOperands(TempAllocator& alloc, |
| 2870 | bool* result); |
| 2871 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 2872 | |
| 2873 | CompareType compareType() const { return compareType_; } |
| 2874 | bool isInt32Comparison() const { return compareType() == Compare_Int32; } |
| 2875 | bool isDoubleComparison() const { return compareType() == Compare_Double; } |
| 2876 | bool isFloat32Comparison() const { return compareType() == Compare_Float32; } |
| 2877 | bool isNumericComparison() const { |
| 2878 | return isInt32Comparison() || isDoubleComparison() || isFloat32Comparison(); |
| 2879 | } |
| 2880 | MIRType inputType(); |
| 2881 | |
| 2882 | JSOp jsop() const { return jsop_; } |
| 2883 | bool operandsAreNeverNaN() const { return operandsAreNeverNaN_; } |
| 2884 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 2885 | |
| 2886 | #ifdef JS_JITSPEW1 |
| 2887 | void printOpcode(GenericPrinter& out) const override; |
| 2888 | #endif |
| 2889 | void collectRangeInfoPreTrunc() override; |
| 2890 | |
| 2891 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 2892 | bool isFloat32Commutative() const override { return true; } |
| 2893 | bool canTruncate() const override; |
| 2894 | void truncate(TruncateKind kind) override; |
| 2895 | TruncateKind operandTruncateKind(size_t index) const override; |
| 2896 | |
| 2897 | #ifdef DEBUG1 |
| 2898 | bool isConsistentFloat32Use(MUse* use) const override { |
| 2899 | // Both sides of the compare can be Float32 |
| 2900 | return compareType_ == Compare_Float32; |
| 2901 | } |
| 2902 | #endif |
| 2903 | |
| 2904 | ALLOW_CLONE(MCompare)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MCompare (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 2905 | |
| 2906 | private: |
| 2907 | [[nodiscard]] bool tryFoldEqualOperands(bool* result); |
| 2908 | [[nodiscard]] bool tryFoldTypeOf(bool* result); |
| 2909 | [[nodiscard]] MDefinition* tryFoldTypeOf(TempAllocator& alloc); |
| 2910 | [[nodiscard]] MDefinition* tryFoldCharCompare(TempAllocator& alloc); |
| 2911 | [[nodiscard]] MDefinition* tryFoldStringCompare(TempAllocator& alloc); |
| 2912 | [[nodiscard]] MDefinition* tryFoldStringSubstring(TempAllocator& alloc); |
| 2913 | [[nodiscard]] MDefinition* tryFoldStringIndexOf(TempAllocator& alloc); |
| 2914 | |
| 2915 | public: |
| 2916 | bool congruentTo(const MDefinition* ins) const override { |
| 2917 | if (!binaryCongruentTo(ins)) { |
| 2918 | return false; |
| 2919 | } |
| 2920 | return compareType() == ins->toCompare()->compareType() && |
| 2921 | jsop() == ins->toCompare()->jsop(); |
| 2922 | } |
| 2923 | |
| 2924 | [[nodiscard]] bool writeRecoverData( |
| 2925 | CompactBufferWriter& writer) const override; |
| 2926 | bool canRecoverOnBailout() const override { |
| 2927 | switch (compareType_) { |
| 2928 | case Compare_Undefined: |
| 2929 | case Compare_Null: |
| 2930 | case Compare_Int32: |
| 2931 | case Compare_UInt32: |
| 2932 | case Compare_Double: |
| 2933 | case Compare_Float32: |
| 2934 | case Compare_String: |
| 2935 | case Compare_Symbol: |
| 2936 | case Compare_Object: |
| 2937 | case Compare_BigInt: |
| 2938 | case Compare_BigInt_Int32: |
| 2939 | case Compare_BigInt_Double: |
| 2940 | case Compare_BigInt_String: |
| 2941 | return true; |
| 2942 | |
| 2943 | case Compare_Int64: |
| 2944 | case Compare_UInt64: |
| 2945 | case Compare_UIntPtr: |
| 2946 | case Compare_WasmAnyRef: |
| 2947 | return false; |
| 2948 | } |
| 2949 | MOZ_CRASH("unexpected compare type")do { do { } while (false); MOZ_ReportCrash("" "unexpected compare type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 2949); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected compare type" ")"); do { *((volatile int*)__null) = 2949; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
| 2950 | } |
| 2951 | |
| 2952 | #ifdef JS_JITSPEW1 |
| 2953 | void getExtras(ExtrasCollector* extras) override { |
| 2954 | const char* ty = nullptr; |
| 2955 | switch (compareType_) { |
| 2956 | case Compare_Undefined: |
| 2957 | ty = "Undefined"; |
| 2958 | break; |
| 2959 | case Compare_Null: |
| 2960 | ty = "Null"; |
| 2961 | break; |
| 2962 | case Compare_Int32: |
| 2963 | ty = "Int32"; |
| 2964 | break; |
| 2965 | case Compare_UInt32: |
| 2966 | ty = "UInt32"; |
| 2967 | break; |
| 2968 | case Compare_Int64: |
| 2969 | ty = "Int64"; |
| 2970 | break; |
| 2971 | case Compare_UInt64: |
| 2972 | ty = "UInt64"; |
| 2973 | break; |
| 2974 | case Compare_UIntPtr: |
| 2975 | ty = "UIntPtr"; |
| 2976 | break; |
| 2977 | case Compare_Double: |
| 2978 | ty = "Double"; |
| 2979 | break; |
| 2980 | case Compare_Float32: |
| 2981 | ty = "Float32"; |
| 2982 | break; |
| 2983 | case Compare_String: |
| 2984 | ty = "String"; |
| 2985 | break; |
| 2986 | case Compare_Symbol: |
| 2987 | ty = "Symbol"; |
| 2988 | break; |
| 2989 | case Compare_Object: |
| 2990 | ty = "Object"; |
| 2991 | break; |
| 2992 | case Compare_BigInt: |
| 2993 | ty = "BigInt"; |
| 2994 | break; |
| 2995 | case Compare_BigInt_Int32: |
| 2996 | ty = "BigInt_Int32"; |
| 2997 | break; |
| 2998 | case Compare_BigInt_Double: |
| 2999 | ty = "BigInt_Double"; |
| 3000 | break; |
| 3001 | case Compare_BigInt_String: |
| 3002 | ty = "BigInt_String"; |
| 3003 | break; |
| 3004 | case Compare_WasmAnyRef: |
| 3005 | ty = "WasmAnyRef"; |
| 3006 | break; |
| 3007 | default: |
| 3008 | ty = "!!unknown!!"; |
| 3009 | break; |
| 3010 | }; |
| 3011 | char buf[64]; |
| 3012 | SprintfLiteral(buf, "ty=%s jsop=%s", ty, CodeName(jsop())); |
| 3013 | extras->add(buf); |
| 3014 | } |
| 3015 | #endif |
| 3016 | }; |
| 3017 | |
| 3018 | // Takes a typed value and returns an untyped value. |
| 3019 | class MBox : public MUnaryInstruction, public NoTypePolicy::Data { |
| 3020 | explicit MBox(MDefinition* ins) : MUnaryInstruction(classOpcode, ins) { |
| 3021 | // Cannot box a box. |
| 3022 | MOZ_ASSERT(ins->type() != MIRType::Value)do { static_assert( mozilla::detail::AssertionConditionType< decltype(ins->type() != MIRType::Value)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(ins->type() != MIRType::Value ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "ins->type() != MIRType::Value", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3022); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() != MIRType::Value" ")"); do { *((volatile int*)__null) = 3022; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3023 | |
| 3024 | setResultType(MIRType::Value); |
| 3025 | setMovable(); |
| 3026 | } |
| 3027 | |
| 3028 | public: |
| 3029 | INSTRUCTION_HEADER(Box) |
| 3030 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3031 | |
| 3032 | bool congruentTo(const MDefinition* ins) const override { |
| 3033 | return congruentIfOperandsEqual(ins); |
| 3034 | } |
| 3035 | |
| 3036 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3037 | |
| 3038 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3039 | |
| 3040 | ALLOW_CLONE(MBox)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBox (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 3041 | }; |
| 3042 | |
| 3043 | // Note: the op may have been inverted during lowering (to put constants in a |
| 3044 | // position where they can be immediates), so it is important to use the |
| 3045 | // lir->jsop() instead of the mir->jsop() when it is present. |
| 3046 | static inline Assembler::Condition JSOpToCondition( |
| 3047 | MCompare::CompareType compareType, JSOp op) { |
| 3048 | bool isSigned = (compareType != MCompare::Compare_UInt32 && |
| 3049 | compareType != MCompare::Compare_UInt64 && |
| 3050 | compareType != MCompare::Compare_UIntPtr); |
| 3051 | return JSOpToCondition(op, isSigned); |
| 3052 | } |
| 3053 | |
| 3054 | // Takes a typed value and checks if it is a certain type. If so, the payload |
| 3055 | // is unpacked and returned as that type. Otherwise, it is considered a |
| 3056 | // deoptimization. |
| 3057 | class MUnbox final : public MUnaryInstruction, public BoxInputsPolicy::Data { |
| 3058 | public: |
| 3059 | enum Mode { |
| 3060 | Fallible, // Check the type, and deoptimize if unexpected. |
| 3061 | Infallible, // Type guard is not necessary. |
| 3062 | }; |
| 3063 | |
| 3064 | private: |
| 3065 | Mode mode_; |
| 3066 | |
| 3067 | MUnbox(MDefinition* ins, MIRType type, Mode mode) |
| 3068 | : MUnaryInstruction(classOpcode, ins), mode_(mode) { |
| 3069 | // Only allow unboxing a non MIRType::Value when input and output types |
| 3070 | // don't match. This is often used to force a bailout. Boxing happens |
| 3071 | // during type analysis. |
| 3072 | MOZ_ASSERT_IF(ins->type() != MIRType::Value, type != ins->type())do { if (ins->type() != MIRType::Value) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(type != ins->type())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(type != ins->type()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("type != ins->type()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3072); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type != ins->type()" ")"); do { *((volatile int*)__null) = 3072; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
| 3073 | |
| 3074 | MOZ_ASSERT(type == MIRType::Boolean || type == MIRType::Int32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType ::Object)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(type == MIRType::Boolean || type == MIRType ::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3077); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object" ")"); do { *((volatile int*)__null) = 3077; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 3075 | type == MIRType::Double || type == MIRType::String ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType ::Object)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(type == MIRType::Boolean || type == MIRType ::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3077); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object" ")"); do { *((volatile int*)__null) = 3077; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 3076 | type == MIRType::Symbol || type == MIRType::BigInt ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType ::Object)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(type == MIRType::Boolean || type == MIRType ::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3077); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object" ")"); do { *((volatile int*)__null) = 3077; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 3077 | type == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType ::Object)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(type == MIRType::Boolean || type == MIRType ::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3077); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Boolean || type == MIRType::Int32 || type == MIRType::Double || type == MIRType::String || type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object" ")"); do { *((volatile int*)__null) = 3077; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3078 | |
| 3079 | setResultType(type); |
| 3080 | setMovable(); |
| 3081 | |
| 3082 | if (mode_ == Fallible) { |
| 3083 | setGuard(); |
| 3084 | } |
| 3085 | } |
| 3086 | |
| 3087 | public: |
| 3088 | INSTRUCTION_HEADER(Unbox) |
| 3089 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3090 | |
| 3091 | Mode mode() const { return mode_; } |
| 3092 | bool fallible() const { return mode() != Infallible; } |
| 3093 | bool congruentTo(const MDefinition* ins) const override { |
| 3094 | if (!ins->isUnbox() || ins->toUnbox()->mode() != mode()) { |
| 3095 | return false; |
| 3096 | } |
| 3097 | return congruentIfOperandsEqual(ins); |
| 3098 | } |
| 3099 | |
| 3100 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3101 | |
| 3102 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3103 | #ifdef JS_JITSPEW1 |
| 3104 | void printOpcode(GenericPrinter& out) const override; |
| 3105 | #endif |
| 3106 | |
| 3107 | ALLOW_CLONE(MUnbox)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MUnbox (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 3108 | }; |
| 3109 | |
| 3110 | class MAssertRange : public MUnaryInstruction, public NoTypePolicy::Data { |
| 3111 | // This is the range checked by the assertion. Don't confuse this with the |
| 3112 | // range_ member or the range() accessor. Since MAssertRange doesn't return |
| 3113 | // a value, it doesn't use those. |
| 3114 | const Range* assertedRange_; |
| 3115 | |
| 3116 | MAssertRange(MDefinition* ins, const Range* assertedRange) |
| 3117 | : MUnaryInstruction(classOpcode, ins), assertedRange_(assertedRange) { |
| 3118 | setGuard(); |
| 3119 | setResultType(MIRType::None); |
| 3120 | } |
| 3121 | |
| 3122 | public: |
| 3123 | INSTRUCTION_HEADER(AssertRange) |
| 3124 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3125 | |
| 3126 | const Range* assertedRange() const { return assertedRange_; } |
| 3127 | |
| 3128 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3129 | |
| 3130 | #ifdef JS_JITSPEW1 |
| 3131 | void printOpcode(GenericPrinter& out) const override; |
| 3132 | #endif |
| 3133 | }; |
| 3134 | |
| 3135 | class MAssertClass : public MUnaryInstruction, public NoTypePolicy::Data { |
| 3136 | const JSClass* class_; |
| 3137 | |
| 3138 | MAssertClass(MDefinition* obj, const JSClass* clasp) |
| 3139 | : MUnaryInstruction(classOpcode, obj), class_(clasp) { |
| 3140 | MOZ_ASSERT(obj->type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(obj->type() == MIRType::Object)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(obj->type() == MIRType::Object ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "obj->type() == MIRType::Object", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "obj->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 3140; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3141 | |
| 3142 | setGuard(); |
| 3143 | setResultType(MIRType::None); |
| 3144 | } |
| 3145 | |
| 3146 | public: |
| 3147 | INSTRUCTION_HEADER(AssertClass) |
| 3148 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3149 | |
| 3150 | const JSClass* getClass() const { return class_; } |
| 3151 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3152 | }; |
| 3153 | |
| 3154 | class MAssertShape : public MUnaryInstruction, public NoTypePolicy::Data { |
| 3155 | CompilerShape shape_; |
| 3156 | |
| 3157 | MAssertShape(MDefinition* obj, Shape* shape) |
| 3158 | : MUnaryInstruction(classOpcode, obj), shape_(shape) { |
| 3159 | MOZ_ASSERT(obj->type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(obj->type() == MIRType::Object)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(obj->type() == MIRType::Object ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "obj->type() == MIRType::Object", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3159); AnnotateMozCrashReason("MOZ_ASSERT" "(" "obj->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 3159; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3160 | |
| 3161 | setGuard(); |
| 3162 | setResultType(MIRType::None); |
| 3163 | } |
| 3164 | |
| 3165 | public: |
| 3166 | INSTRUCTION_HEADER(AssertShape) |
| 3167 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3168 | |
| 3169 | const Shape* shape() const { return shape_; } |
| 3170 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3171 | }; |
| 3172 | |
| 3173 | // Eager initialization of arguments object. |
| 3174 | class MCreateArgumentsObject : public MUnaryInstruction, |
| 3175 | public ObjectPolicy<0>::Data { |
| 3176 | CompilerGCPointer<ArgumentsObject*> templateObj_; |
| 3177 | |
| 3178 | MCreateArgumentsObject(MDefinition* callObj, ArgumentsObject* templateObj) |
| 3179 | : MUnaryInstruction(classOpcode, callObj), templateObj_(templateObj) { |
| 3180 | setResultType(MIRType::Object); |
| 3181 | } |
| 3182 | |
| 3183 | public: |
| 3184 | INSTRUCTION_HEADER(CreateArgumentsObject) |
| 3185 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3186 | NAMED_OPERANDS((0, getCallObject))MDefinition* getCallObject() const { return getOperand(0); } |
| 3187 | |
| 3188 | ArgumentsObject* templateObject() const { return templateObj_; } |
| 3189 | |
| 3190 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3191 | |
| 3192 | bool possiblyCalls() const override { return true; } |
| 3193 | |
| 3194 | [[nodiscard]] bool writeRecoverData( |
| 3195 | CompactBufferWriter& writer) const override; |
| 3196 | bool canRecoverOnBailout() const override { return true; } |
| 3197 | }; |
| 3198 | |
| 3199 | // Eager initialization of arguments object for inlined function |
| 3200 | class MCreateInlinedArgumentsObject : public MVariadicInstruction, |
| 3201 | public NoFloatPolicyAfter<0>::Data { |
| 3202 | CompilerGCPointer<ArgumentsObject*> templateObj_; |
| 3203 | |
| 3204 | explicit MCreateInlinedArgumentsObject(ArgumentsObject* templateObj) |
| 3205 | : MVariadicInstruction(classOpcode), templateObj_(templateObj) { |
| 3206 | setResultType(MIRType::Object); |
| 3207 | } |
| 3208 | |
| 3209 | static const size_t NumNonArgumentOperands = 2; |
| 3210 | |
| 3211 | public: |
| 3212 | INSTRUCTION_HEADER(CreateInlinedArgumentsObject) |
| 3213 | static MCreateInlinedArgumentsObject* New(TempAllocator& alloc, |
| 3214 | MDefinition* callObj, |
| 3215 | MDefinition* callee, |
| 3216 | MDefinitionVector& args, |
| 3217 | ArgumentsObject* templateObj); |
| 3218 | NAMED_OPERANDS((0, getCallObject), (1, getCallee))MDefinition* getCallObject() const { return getOperand(0); } MDefinition * getCallee() const { return getOperand(1); } |
| 3219 | |
| 3220 | ArgumentsObject* templateObject() const { return templateObj_; } |
| 3221 | |
| 3222 | MDefinition* getArg(uint32_t idx) const { |
| 3223 | return getOperand(idx + NumNonArgumentOperands); |
| 3224 | } |
| 3225 | uint32_t numActuals() const { return numOperands() - NumNonArgumentOperands; } |
| 3226 | |
| 3227 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3228 | |
| 3229 | bool possiblyCalls() const override { return true; } |
| 3230 | |
| 3231 | [[nodiscard]] bool writeRecoverData( |
| 3232 | CompactBufferWriter& writer) const override; |
| 3233 | bool canRecoverOnBailout() const override { return true; } |
| 3234 | }; |
| 3235 | |
| 3236 | class MGetInlinedArgument |
| 3237 | : public MVariadicInstruction, |
| 3238 | public MixPolicy<UnboxedInt32Policy<0>, NoFloatPolicyAfter<1>>::Data { |
| 3239 | MGetInlinedArgument() : MVariadicInstruction(classOpcode) { |
| 3240 | setResultType(MIRType::Value); |
| 3241 | } |
| 3242 | |
| 3243 | static const size_t NumNonArgumentOperands = 1; |
| 3244 | |
| 3245 | public: |
| 3246 | INSTRUCTION_HEADER(GetInlinedArgument) |
| 3247 | static MGetInlinedArgument* New(TempAllocator& alloc, MDefinition* index, |
| 3248 | MCreateInlinedArgumentsObject* args); |
| 3249 | static MGetInlinedArgument* New(TempAllocator& alloc, MDefinition* index, |
| 3250 | const CallInfo& callInfo); |
| 3251 | NAMED_OPERANDS((0, index))MDefinition* index() const { return getOperand(0); } |
| 3252 | |
| 3253 | MDefinition* getArg(uint32_t idx) const { |
| 3254 | return getOperand(idx + NumNonArgumentOperands); |
| 3255 | } |
| 3256 | uint32_t numActuals() const { return numOperands() - NumNonArgumentOperands; } |
| 3257 | |
| 3258 | bool congruentTo(const MDefinition* ins) const override { |
| 3259 | return congruentIfOperandsEqual(ins); |
| 3260 | } |
| 3261 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3262 | |
| 3263 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3264 | }; |
| 3265 | |
| 3266 | class MGetInlinedArgumentHole |
| 3267 | : public MVariadicInstruction, |
| 3268 | public MixPolicy<UnboxedInt32Policy<0>, NoFloatPolicyAfter<1>>::Data { |
| 3269 | MGetInlinedArgumentHole() : MVariadicInstruction(classOpcode) { |
| 3270 | setGuard(); |
| 3271 | setResultType(MIRType::Value); |
| 3272 | } |
| 3273 | |
| 3274 | static const size_t NumNonArgumentOperands = 1; |
| 3275 | |
| 3276 | public: |
| 3277 | INSTRUCTION_HEADER(GetInlinedArgumentHole) |
| 3278 | static MGetInlinedArgumentHole* New(TempAllocator& alloc, MDefinition* index, |
| 3279 | MCreateInlinedArgumentsObject* args); |
| 3280 | NAMED_OPERANDS((0, index))MDefinition* index() const { return getOperand(0); } |
| 3281 | |
| 3282 | MDefinition* getArg(uint32_t idx) const { |
| 3283 | return getOperand(idx + NumNonArgumentOperands); |
| 3284 | } |
| 3285 | uint32_t numActuals() const { return numOperands() - NumNonArgumentOperands; } |
| 3286 | |
| 3287 | bool congruentTo(const MDefinition* ins) const override { |
| 3288 | return congruentIfOperandsEqual(ins); |
| 3289 | } |
| 3290 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3291 | |
| 3292 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3293 | }; |
| 3294 | |
| 3295 | class MInlineArgumentsSlice |
| 3296 | : public MVariadicInstruction, |
| 3297 | public MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>, |
| 3298 | NoFloatPolicyAfter<2>>::Data { |
| 3299 | JSObject* templateObj_; |
| 3300 | gc::Heap initialHeap_; |
| 3301 | |
| 3302 | MInlineArgumentsSlice(JSObject* templateObj, gc::Heap initialHeap) |
| 3303 | : MVariadicInstruction(classOpcode), |
| 3304 | templateObj_(templateObj), |
| 3305 | initialHeap_(initialHeap) { |
| 3306 | setResultType(MIRType::Object); |
| 3307 | } |
| 3308 | |
| 3309 | static const size_t NumNonArgumentOperands = 2; |
| 3310 | |
| 3311 | public: |
| 3312 | INSTRUCTION_HEADER(InlineArgumentsSlice) |
| 3313 | static MInlineArgumentsSlice* New(TempAllocator& alloc, MDefinition* begin, |
| 3314 | MDefinition* count, |
| 3315 | MCreateInlinedArgumentsObject* args, |
| 3316 | JSObject* templateObj, |
| 3317 | gc::Heap initialHeap); |
| 3318 | NAMED_OPERANDS((0, begin), (1, count))MDefinition* begin() const { return getOperand(0); } MDefinition * count() const { return getOperand(1); } |
| 3319 | |
| 3320 | JSObject* templateObj() const { return templateObj_; } |
| 3321 | gc::Heap initialHeap() const { return initialHeap_; } |
| 3322 | |
| 3323 | MDefinition* getArg(uint32_t idx) const { |
| 3324 | return getOperand(idx + NumNonArgumentOperands); |
| 3325 | } |
| 3326 | uint32_t numActuals() const { return numOperands() - NumNonArgumentOperands; } |
| 3327 | |
| 3328 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3329 | |
| 3330 | bool possiblyCalls() const override { return true; } |
| 3331 | }; |
| 3332 | |
| 3333 | // Allocates a new BoundFunctionObject and calls |
| 3334 | // BoundFunctionObject::functionBindImpl. This instruction can have arbitrary |
| 3335 | // side-effects because the GetProperty calls for length/name can call into JS. |
| 3336 | class MBindFunction |
| 3337 | : public MVariadicInstruction, |
| 3338 | public MixPolicy<ObjectPolicy<0>, NoFloatPolicyAfter<1>>::Data { |
| 3339 | CompilerGCPointer<JSObject*> templateObj_; |
| 3340 | |
| 3341 | explicit MBindFunction(JSObject* templateObj) |
| 3342 | : MVariadicInstruction(classOpcode), templateObj_(templateObj) { |
| 3343 | setResultType(MIRType::Object); |
| 3344 | } |
| 3345 | |
| 3346 | // The target object is operand 0. |
| 3347 | static const size_t NumNonArgumentOperands = 1; |
| 3348 | |
| 3349 | public: |
| 3350 | INSTRUCTION_HEADER(BindFunction) |
| 3351 | static MBindFunction* New(TempAllocator& alloc, MDefinition* target, |
| 3352 | uint32_t argc, JSObject* templateObj); |
| 3353 | NAMED_OPERANDS((0, target))MDefinition* target() const { return getOperand(0); } |
| 3354 | |
| 3355 | JSObject* templateObject() const { return templateObj_; } |
| 3356 | |
| 3357 | MDefinition* getArg(uint32_t idx) const { |
| 3358 | return getOperand(idx + NumNonArgumentOperands); |
| 3359 | } |
| 3360 | void initArg(size_t i, MDefinition* arg) { |
| 3361 | initOperand(NumNonArgumentOperands + i, arg); |
| 3362 | } |
| 3363 | uint32_t numStackArgs() const { |
| 3364 | return numOperands() - NumNonArgumentOperands; |
| 3365 | } |
| 3366 | |
| 3367 | bool possiblyCalls() const override { return true; } |
| 3368 | }; |
| 3369 | |
| 3370 | class MToFPInstruction : public MUnaryInstruction, public ToDoublePolicy::Data { |
| 3371 | public: |
| 3372 | // Types of values which can be converted. |
| 3373 | enum ConversionKind { NonStringPrimitives, NumbersOnly }; |
| 3374 | |
| 3375 | private: |
| 3376 | ConversionKind conversion_; |
| 3377 | |
| 3378 | protected: |
| 3379 | MToFPInstruction(Opcode op, MDefinition* def, |
| 3380 | ConversionKind conversion = NonStringPrimitives) |
| 3381 | : MUnaryInstruction(op, def), conversion_(conversion) {} |
| 3382 | |
| 3383 | public: |
| 3384 | ConversionKind conversion() const { return conversion_; } |
| 3385 | }; |
| 3386 | |
| 3387 | // Converts a primitive (either typed or untyped) to a double. If the input is |
| 3388 | // not primitive at runtime, a bailout occurs. |
| 3389 | class MToDouble : public MToFPInstruction { |
| 3390 | private: |
| 3391 | TruncateKind implicitTruncate_; |
| 3392 | |
| 3393 | explicit MToDouble(MDefinition* def, |
| 3394 | ConversionKind conversion = NonStringPrimitives) |
| 3395 | : MToFPInstruction(classOpcode, def, conversion), |
| 3396 | implicitTruncate_(TruncateKind::NoTruncate) { |
| 3397 | setResultType(MIRType::Double); |
| 3398 | setMovable(); |
| 3399 | |
| 3400 | // Guard unless the conversion is known to be non-effectful & non-throwing. |
| 3401 | if (!def->definitelyType({MIRType::Undefined, MIRType::Null, |
| 3402 | MIRType::Boolean, MIRType::Int32, MIRType::Double, |
| 3403 | MIRType::Float32, MIRType::String})) { |
| 3404 | setGuard(); |
| 3405 | } |
| 3406 | } |
| 3407 | |
| 3408 | public: |
| 3409 | INSTRUCTION_HEADER(ToDouble) |
| 3410 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3411 | |
| 3412 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3413 | bool congruentTo(const MDefinition* ins) const override { |
| 3414 | if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion()) { |
| 3415 | return false; |
| 3416 | } |
| 3417 | return congruentIfOperandsEqual(ins); |
| 3418 | } |
| 3419 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3420 | |
| 3421 | void computeRange(TempAllocator& alloc) override; |
| 3422 | bool canTruncate() const override; |
| 3423 | void truncate(TruncateKind kind) override; |
| 3424 | TruncateKind operandTruncateKind(size_t index) const override; |
| 3425 | |
| 3426 | #ifdef DEBUG1 |
| 3427 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 3428 | #endif |
| 3429 | |
| 3430 | TruncateKind truncateKind() const { return implicitTruncate_; } |
| 3431 | void setTruncateKind(TruncateKind kind) { |
| 3432 | implicitTruncate_ = std::max(implicitTruncate_, kind); |
| 3433 | } |
| 3434 | |
| 3435 | [[nodiscard]] bool writeRecoverData( |
| 3436 | CompactBufferWriter& writer) const override; |
| 3437 | bool canRecoverOnBailout() const override { |
| 3438 | if (input()->type() == MIRType::Value) { |
| 3439 | return false; |
| 3440 | } |
| 3441 | if (input()->type() == MIRType::Symbol) { |
| 3442 | return false; |
| 3443 | } |
| 3444 | if (input()->type() == MIRType::BigInt) { |
| 3445 | return false; |
| 3446 | } |
| 3447 | |
| 3448 | return true; |
| 3449 | } |
| 3450 | |
| 3451 | ALLOW_CLONE(MToDouble)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MToDouble (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 3452 | }; |
| 3453 | |
| 3454 | // Converts a primitive (either typed or untyped) to a float32. If the input is |
| 3455 | // not primitive at runtime, a bailout occurs. |
| 3456 | class MToFloat32 : public MToFPInstruction { |
| 3457 | bool mustPreserveNaN_; |
| 3458 | |
| 3459 | explicit MToFloat32(MDefinition* def, |
| 3460 | ConversionKind conversion = NonStringPrimitives) |
| 3461 | : MToFPInstruction(classOpcode, def, conversion), |
| 3462 | mustPreserveNaN_(false) { |
| 3463 | setResultType(MIRType::Float32); |
| 3464 | setMovable(); |
| 3465 | |
| 3466 | // Guard unless the conversion is known to be non-effectful & non-throwing. |
| 3467 | if (!def->definitelyType({MIRType::Undefined, MIRType::Null, |
| 3468 | MIRType::Boolean, MIRType::Int32, MIRType::Double, |
| 3469 | MIRType::Float32, MIRType::String})) { |
| 3470 | setGuard(); |
| 3471 | } |
| 3472 | } |
| 3473 | |
| 3474 | explicit MToFloat32(MDefinition* def, bool mustPreserveNaN) |
| 3475 | : MToFloat32(def) { |
| 3476 | mustPreserveNaN_ = mustPreserveNaN; |
| 3477 | } |
| 3478 | |
| 3479 | public: |
| 3480 | INSTRUCTION_HEADER(ToFloat32) |
| 3481 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3482 | |
| 3483 | virtual MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3484 | bool congruentTo(const MDefinition* ins) const override { |
| 3485 | if (!congruentIfOperandsEqual(ins)) { |
| 3486 | return false; |
| 3487 | } |
| 3488 | auto* other = ins->toToFloat32(); |
| 3489 | return other->conversion() == conversion() && |
| 3490 | other->mustPreserveNaN_ == mustPreserveNaN_; |
| 3491 | } |
| 3492 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3493 | |
| 3494 | void computeRange(TempAllocator& alloc) override; |
| 3495 | |
| 3496 | bool canConsumeFloat32(MUse* use) const override { return true; } |
| 3497 | bool canProduceFloat32() const override { return true; } |
| 3498 | |
| 3499 | [[nodiscard]] bool writeRecoverData( |
| 3500 | CompactBufferWriter& writer) const override; |
| 3501 | bool canRecoverOnBailout() const override { return true; } |
| 3502 | |
| 3503 | ALLOW_CLONE(MToFloat32)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MToFloat32 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 3504 | }; |
| 3505 | |
| 3506 | // Converts a uint32 to a float32 (coming from wasm). |
| 3507 | class MWasmUnsignedToFloat32 : public MUnaryInstruction, |
| 3508 | public NoTypePolicy::Data { |
| 3509 | explicit MWasmUnsignedToFloat32(MDefinition* def) |
| 3510 | : MUnaryInstruction(classOpcode, def) { |
| 3511 | setResultType(MIRType::Float32); |
| 3512 | setMovable(); |
| 3513 | } |
| 3514 | |
| 3515 | public: |
| 3516 | INSTRUCTION_HEADER(WasmUnsignedToFloat32) |
| 3517 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3518 | |
| 3519 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3520 | bool congruentTo(const MDefinition* ins) const override { |
| 3521 | return congruentIfOperandsEqual(ins); |
| 3522 | } |
| 3523 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3524 | |
| 3525 | bool canProduceFloat32() const override { return true; } |
| 3526 | }; |
| 3527 | |
| 3528 | class MWrapInt64ToInt32 : public MUnaryInstruction, public NoTypePolicy::Data { |
| 3529 | bool bottomHalf_; |
| 3530 | |
| 3531 | explicit MWrapInt64ToInt32(MDefinition* def, bool bottomHalf = true) |
| 3532 | : MUnaryInstruction(classOpcode, def), bottomHalf_(bottomHalf) { |
| 3533 | setResultType(MIRType::Int32); |
| 3534 | setMovable(); |
| 3535 | } |
| 3536 | |
| 3537 | public: |
| 3538 | INSTRUCTION_HEADER(WrapInt64ToInt32) |
| 3539 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3540 | |
| 3541 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3542 | bool congruentTo(const MDefinition* ins) const override { |
| 3543 | if (!ins->isWrapInt64ToInt32()) { |
| 3544 | return false; |
| 3545 | } |
| 3546 | if (ins->toWrapInt64ToInt32()->bottomHalf() != bottomHalf()) { |
| 3547 | return false; |
| 3548 | } |
| 3549 | return congruentIfOperandsEqual(ins); |
| 3550 | } |
| 3551 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3552 | |
| 3553 | bool bottomHalf() const { return bottomHalf_; } |
| 3554 | }; |
| 3555 | |
| 3556 | class MExtendInt32ToInt64 : public MUnaryInstruction, |
| 3557 | public NoTypePolicy::Data { |
| 3558 | bool isUnsigned_; |
| 3559 | |
| 3560 | MExtendInt32ToInt64(MDefinition* def, bool isUnsigned) |
| 3561 | : MUnaryInstruction(classOpcode, def), isUnsigned_(isUnsigned) { |
| 3562 | setResultType(MIRType::Int64); |
| 3563 | setMovable(); |
| 3564 | } |
| 3565 | |
| 3566 | public: |
| 3567 | INSTRUCTION_HEADER(ExtendInt32ToInt64) |
| 3568 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3569 | |
| 3570 | bool isUnsigned() const { return isUnsigned_; } |
| 3571 | |
| 3572 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3573 | bool congruentTo(const MDefinition* ins) const override { |
| 3574 | if (!ins->isExtendInt32ToInt64()) { |
| 3575 | return false; |
| 3576 | } |
| 3577 | if (ins->toExtendInt32ToInt64()->isUnsigned_ != isUnsigned_) { |
| 3578 | return false; |
| 3579 | } |
| 3580 | return congruentIfOperandsEqual(ins); |
| 3581 | } |
| 3582 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3583 | }; |
| 3584 | |
| 3585 | // The same as MWasmTruncateToInt64 but with the Instance dependency. |
| 3586 | // It used only for arm now because on arm we need to call builtin to truncate |
| 3587 | // to i64. |
| 3588 | class MWasmBuiltinTruncateToInt64 : public MAryInstruction<2>, |
| 3589 | public NoTypePolicy::Data { |
| 3590 | TruncFlags flags_; |
| 3591 | wasm::BytecodeOffset bytecodeOffset_; |
| 3592 | |
| 3593 | MWasmBuiltinTruncateToInt64(MDefinition* def, MDefinition* instance, |
| 3594 | TruncFlags flags, |
| 3595 | wasm::BytecodeOffset bytecodeOffset) |
| 3596 | : MAryInstruction(classOpcode), |
| 3597 | flags_(flags), |
| 3598 | bytecodeOffset_(bytecodeOffset) { |
| 3599 | initOperand(0, def); |
| 3600 | initOperand(1, instance); |
| 3601 | |
| 3602 | setResultType(MIRType::Int64); |
| 3603 | setGuard(); // neither removable nor movable because of possible |
| 3604 | // side-effects. |
| 3605 | } |
| 3606 | |
| 3607 | public: |
| 3608 | INSTRUCTION_HEADER(WasmBuiltinTruncateToInt64) |
| 3609 | NAMED_OPERANDS((0, input), (1, instance))MDefinition* input() const { return getOperand(0); } MDefinition * instance() const { return getOperand(1); }; |
| 3610 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3611 | |
| 3612 | bool isUnsigned() const { return flags_ & TRUNC_UNSIGNED; } |
| 3613 | bool isSaturating() const { return flags_ & TRUNC_SATURATING; } |
| 3614 | TruncFlags flags() const { return flags_; } |
| 3615 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 3616 | |
| 3617 | bool congruentTo(const MDefinition* ins) const override { |
| 3618 | return congruentIfOperandsEqual(ins) && |
| 3619 | ins->toWasmBuiltinTruncateToInt64()->flags() == flags_; |
| 3620 | } |
| 3621 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3622 | }; |
| 3623 | |
| 3624 | class MWasmTruncateToInt64 : public MUnaryInstruction, |
| 3625 | public NoTypePolicy::Data { |
| 3626 | TruncFlags flags_; |
| 3627 | wasm::BytecodeOffset bytecodeOffset_; |
| 3628 | |
| 3629 | MWasmTruncateToInt64(MDefinition* def, TruncFlags flags, |
| 3630 | wasm::BytecodeOffset bytecodeOffset) |
| 3631 | : MUnaryInstruction(classOpcode, def), |
| 3632 | flags_(flags), |
| 3633 | bytecodeOffset_(bytecodeOffset) { |
| 3634 | setResultType(MIRType::Int64); |
| 3635 | setGuard(); // neither removable nor movable because of possible |
| 3636 | // side-effects. |
| 3637 | } |
| 3638 | |
| 3639 | public: |
| 3640 | INSTRUCTION_HEADER(WasmTruncateToInt64) |
| 3641 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3642 | |
| 3643 | bool isUnsigned() const { return flags_ & TRUNC_UNSIGNED; } |
| 3644 | bool isSaturating() const { return flags_ & TRUNC_SATURATING; } |
| 3645 | TruncFlags flags() const { return flags_; } |
| 3646 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 3647 | |
| 3648 | bool congruentTo(const MDefinition* ins) const override { |
| 3649 | return congruentIfOperandsEqual(ins) && |
| 3650 | ins->toWasmTruncateToInt64()->flags() == flags_; |
| 3651 | } |
| 3652 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3653 | }; |
| 3654 | |
| 3655 | // Truncate a value to an int32, with wasm semantics: this will trap when the |
| 3656 | // value is out of range. |
| 3657 | class MWasmTruncateToInt32 : public MUnaryInstruction, |
| 3658 | public NoTypePolicy::Data { |
| 3659 | TruncFlags flags_; |
| 3660 | wasm::BytecodeOffset bytecodeOffset_; |
| 3661 | |
| 3662 | explicit MWasmTruncateToInt32(MDefinition* def, TruncFlags flags, |
| 3663 | wasm::BytecodeOffset bytecodeOffset) |
| 3664 | : MUnaryInstruction(classOpcode, def), |
| 3665 | flags_(flags), |
| 3666 | bytecodeOffset_(bytecodeOffset) { |
| 3667 | setResultType(MIRType::Int32); |
| 3668 | setGuard(); // neither removable nor movable because of possible |
| 3669 | // side-effects. |
| 3670 | } |
| 3671 | |
| 3672 | public: |
| 3673 | INSTRUCTION_HEADER(WasmTruncateToInt32) |
| 3674 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3675 | |
| 3676 | bool isUnsigned() const { return flags_ & TRUNC_UNSIGNED; } |
| 3677 | bool isSaturating() const { return flags_ & TRUNC_SATURATING; } |
| 3678 | TruncFlags flags() const { return flags_; } |
| 3679 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 3680 | |
| 3681 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3682 | |
| 3683 | bool congruentTo(const MDefinition* ins) const override { |
| 3684 | return congruentIfOperandsEqual(ins) && |
| 3685 | ins->toWasmTruncateToInt32()->flags() == flags_; |
| 3686 | } |
| 3687 | |
| 3688 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3689 | }; |
| 3690 | |
| 3691 | // Converts an int32 value to intptr by sign-extending it. |
| 3692 | class MInt32ToIntPtr : public MUnaryInstruction, |
| 3693 | public UnboxedInt32Policy<0>::Data { |
| 3694 | bool canBeNegative_ = true; |
| 3695 | |
| 3696 | explicit MInt32ToIntPtr(MDefinition* def) |
| 3697 | : MUnaryInstruction(classOpcode, def) { |
| 3698 | setResultType(MIRType::IntPtr); |
| 3699 | setMovable(); |
| 3700 | } |
| 3701 | |
| 3702 | public: |
| 3703 | INSTRUCTION_HEADER(Int32ToIntPtr) |
| 3704 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3705 | |
| 3706 | bool canBeNegative() const { return canBeNegative_; } |
| 3707 | void setCanNotBeNegative() { canBeNegative_ = false; } |
| 3708 | |
| 3709 | void computeRange(TempAllocator& alloc) override; |
| 3710 | void collectRangeInfoPreTrunc() override; |
| 3711 | |
| 3712 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3713 | |
| 3714 | bool congruentTo(const MDefinition* ins) const override { |
| 3715 | return congruentIfOperandsEqual(ins); |
| 3716 | } |
| 3717 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3718 | }; |
| 3719 | |
| 3720 | // Converts an IntPtr value >= 0 to Int32. Bails out if the value > INT32_MAX. |
| 3721 | class MNonNegativeIntPtrToInt32 : public MUnaryInstruction, |
| 3722 | public NoTypePolicy::Data { |
| 3723 | explicit MNonNegativeIntPtrToInt32(MDefinition* def) |
| 3724 | : MUnaryInstruction(classOpcode, def) { |
| 3725 | MOZ_ASSERT(def->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(def->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(def->type() == MIRType::IntPtr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "def->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3725); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 3725; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3726 | setResultType(MIRType::Int32); |
| 3727 | setMovable(); |
| 3728 | } |
| 3729 | |
| 3730 | public: |
| 3731 | INSTRUCTION_HEADER(NonNegativeIntPtrToInt32) |
| 3732 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3733 | |
| 3734 | void computeRange(TempAllocator& alloc) override; |
| 3735 | |
| 3736 | bool congruentTo(const MDefinition* ins) const override { |
| 3737 | return congruentIfOperandsEqual(ins); |
| 3738 | } |
| 3739 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3740 | }; |
| 3741 | |
| 3742 | // Converts an IntPtr value to Double. |
| 3743 | class MIntPtrToDouble : public MUnaryInstruction, public NoTypePolicy::Data { |
| 3744 | explicit MIntPtrToDouble(MDefinition* def) |
| 3745 | : MUnaryInstruction(classOpcode, def) { |
| 3746 | MOZ_ASSERT(def->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(def->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(def->type() == MIRType::IntPtr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "def->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 3746; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3747 | setResultType(MIRType::Double); |
| 3748 | setMovable(); |
| 3749 | } |
| 3750 | |
| 3751 | public: |
| 3752 | INSTRUCTION_HEADER(IntPtrToDouble) |
| 3753 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3754 | |
| 3755 | bool congruentTo(const MDefinition* ins) const override { |
| 3756 | return congruentIfOperandsEqual(ins); |
| 3757 | } |
| 3758 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3759 | }; |
| 3760 | |
| 3761 | // Subtracts (byteSize - 1) from the input value. Bails out if the result is |
| 3762 | // negative. This is used to implement bounds checks for DataView accesses. |
| 3763 | class MAdjustDataViewLength : public MUnaryInstruction, |
| 3764 | public NoTypePolicy::Data { |
| 3765 | const uint32_t byteSize_; |
| 3766 | |
| 3767 | MAdjustDataViewLength(MDefinition* input, uint32_t byteSize) |
| 3768 | : MUnaryInstruction(classOpcode, input), byteSize_(byteSize) { |
| 3769 | MOZ_ASSERT(input->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(input->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(input->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("input->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3769); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 3769; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3770 | MOZ_ASSERT(byteSize > 1)do { static_assert( mozilla::detail::AssertionConditionType< decltype(byteSize > 1)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(byteSize > 1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("byteSize > 1" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3770); AnnotateMozCrashReason("MOZ_ASSERT" "(" "byteSize > 1" ")"); do { *((volatile int*)__null) = 3770; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3771 | setResultType(MIRType::IntPtr); |
| 3772 | setMovable(); |
| 3773 | setGuard(); |
| 3774 | } |
| 3775 | |
| 3776 | public: |
| 3777 | INSTRUCTION_HEADER(AdjustDataViewLength) |
| 3778 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3779 | |
| 3780 | uint32_t byteSize() const { return byteSize_; } |
| 3781 | |
| 3782 | bool congruentTo(const MDefinition* ins) const override { |
| 3783 | if (!ins->isAdjustDataViewLength()) { |
| 3784 | return false; |
| 3785 | } |
| 3786 | if (ins->toAdjustDataViewLength()->byteSize() != byteSize()) { |
| 3787 | return false; |
| 3788 | } |
| 3789 | return congruentIfOperandsEqual(ins); |
| 3790 | } |
| 3791 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3792 | }; |
| 3793 | |
| 3794 | class MInt64ToFloatingPoint : public MUnaryInstruction, |
| 3795 | public NoTypePolicy::Data { |
| 3796 | bool isUnsigned_; |
| 3797 | wasm::BytecodeOffset bytecodeOffset_; |
| 3798 | |
| 3799 | MInt64ToFloatingPoint(MDefinition* def, MIRType type, |
| 3800 | wasm::BytecodeOffset bytecodeOffset, bool isUnsigned) |
| 3801 | : MUnaryInstruction(classOpcode, def), |
| 3802 | isUnsigned_(isUnsigned), |
| 3803 | bytecodeOffset_(bytecodeOffset) { |
| 3804 | MOZ_ASSERT(IsFloatingPointType(type))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsFloatingPointType(type))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsFloatingPointType(type)))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsFloatingPointType(type)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3804); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(type)" ")"); do { *((volatile int*)__null) = 3804; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3805 | setResultType(type); |
| 3806 | setMovable(); |
| 3807 | } |
| 3808 | |
| 3809 | public: |
| 3810 | INSTRUCTION_HEADER(Int64ToFloatingPoint) |
| 3811 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3812 | |
| 3813 | bool isUnsigned() const { return isUnsigned_; } |
| 3814 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 3815 | |
| 3816 | bool congruentTo(const MDefinition* ins) const override { |
| 3817 | if (!ins->isInt64ToFloatingPoint()) { |
| 3818 | return false; |
| 3819 | } |
| 3820 | if (ins->toInt64ToFloatingPoint()->isUnsigned_ != isUnsigned_) { |
| 3821 | return false; |
| 3822 | } |
| 3823 | return congruentIfOperandsEqual(ins); |
| 3824 | } |
| 3825 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3826 | }; |
| 3827 | |
| 3828 | // It used only for arm now because on arm we need to call builtin to convert |
| 3829 | // i64 to float. |
| 3830 | class MBuiltinInt64ToFloatingPoint : public MAryInstruction<2>, |
| 3831 | public NoTypePolicy::Data { |
| 3832 | bool isUnsigned_; |
| 3833 | wasm::BytecodeOffset bytecodeOffset_; |
| 3834 | |
| 3835 | MBuiltinInt64ToFloatingPoint(MDefinition* def, MDefinition* instance, |
| 3836 | MIRType type, |
| 3837 | wasm::BytecodeOffset bytecodeOffset, |
| 3838 | bool isUnsigned) |
| 3839 | : MAryInstruction(classOpcode), |
| 3840 | isUnsigned_(isUnsigned), |
| 3841 | bytecodeOffset_(bytecodeOffset) { |
| 3842 | MOZ_ASSERT(IsFloatingPointType(type))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsFloatingPointType(type))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsFloatingPointType(type)))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsFloatingPointType(type)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 3842); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(type)" ")"); do { *((volatile int*)__null) = 3842; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3843 | initOperand(0, def); |
| 3844 | initOperand(1, instance); |
| 3845 | setResultType(type); |
| 3846 | setMovable(); |
| 3847 | } |
| 3848 | |
| 3849 | public: |
| 3850 | INSTRUCTION_HEADER(BuiltinInt64ToFloatingPoint) |
| 3851 | NAMED_OPERANDS((0, input), (1, instance))MDefinition* input() const { return getOperand(0); } MDefinition * instance() const { return getOperand(1); }; |
| 3852 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3853 | |
| 3854 | bool isUnsigned() const { return isUnsigned_; } |
| 3855 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 3856 | |
| 3857 | bool congruentTo(const MDefinition* ins) const override { |
| 3858 | if (!ins->isBuiltinInt64ToFloatingPoint()) { |
| 3859 | return false; |
| 3860 | } |
| 3861 | if (ins->toBuiltinInt64ToFloatingPoint()->isUnsigned_ != isUnsigned_) { |
| 3862 | return false; |
| 3863 | } |
| 3864 | return congruentIfOperandsEqual(ins); |
| 3865 | } |
| 3866 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3867 | }; |
| 3868 | |
| 3869 | // Applies ECMA's ToNumber on a primitive (either typed or untyped) and expects |
| 3870 | // the result to be precisely representable as an Int32, otherwise bails. |
| 3871 | // |
| 3872 | // If the input is not primitive at runtime, a bailout occurs. If the input |
| 3873 | // cannot be converted to an int32 without loss (i.e. 5.5 or undefined) then a |
| 3874 | // bailout occurs. |
| 3875 | class MToNumberInt32 : public MUnaryInstruction, public ToInt32Policy::Data { |
| 3876 | bool needsNegativeZeroCheck_; |
| 3877 | IntConversionInputKind conversion_; |
| 3878 | |
| 3879 | explicit MToNumberInt32(MDefinition* def, IntConversionInputKind conversion = |
| 3880 | IntConversionInputKind::Any) |
| 3881 | : MUnaryInstruction(classOpcode, def), |
| 3882 | needsNegativeZeroCheck_(true), |
| 3883 | conversion_(conversion) { |
| 3884 | setResultType(MIRType::Int32); |
| 3885 | setMovable(); |
| 3886 | |
| 3887 | // Guard unless the conversion is known to be non-effectful & non-throwing. |
| 3888 | if (!def->definitelyType({MIRType::Undefined, MIRType::Null, |
| 3889 | MIRType::Boolean, MIRType::Int32, MIRType::Double, |
| 3890 | MIRType::Float32, MIRType::String})) { |
| 3891 | setGuard(); |
| 3892 | } |
| 3893 | } |
| 3894 | |
| 3895 | public: |
| 3896 | INSTRUCTION_HEADER(ToNumberInt32) |
| 3897 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3898 | |
| 3899 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3900 | |
| 3901 | // this only has backwards information flow. |
| 3902 | void analyzeEdgeCasesBackward() override; |
| 3903 | |
| 3904 | bool needsNegativeZeroCheck() const { return needsNegativeZeroCheck_; } |
| 3905 | void setNeedsNegativeZeroCheck(bool needsCheck) { |
| 3906 | needsNegativeZeroCheck_ = needsCheck; |
| 3907 | } |
| 3908 | |
| 3909 | IntConversionInputKind conversion() const { return conversion_; } |
| 3910 | |
| 3911 | bool congruentTo(const MDefinition* ins) const override { |
| 3912 | if (!ins->isToNumberInt32() || |
| 3913 | ins->toToNumberInt32()->conversion() != conversion()) { |
| 3914 | return false; |
| 3915 | } |
| 3916 | return congruentIfOperandsEqual(ins); |
| 3917 | } |
| 3918 | |
| 3919 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3920 | void computeRange(TempAllocator& alloc) override; |
| 3921 | void collectRangeInfoPreTrunc() override; |
| 3922 | |
| 3923 | #ifdef DEBUG1 |
| 3924 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 3925 | #endif |
| 3926 | |
| 3927 | ALLOW_CLONE(MToNumberInt32)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MToNumberInt32 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 3928 | }; |
| 3929 | |
| 3930 | // Converts a value or typed input to a truncated int32, for use with bitwise |
| 3931 | // operations. This is an infallible ValueToECMAInt32. |
| 3932 | class MTruncateToInt32 : public MUnaryInstruction, public ToInt32Policy::Data { |
| 3933 | wasm::BytecodeOffset bytecodeOffset_; |
| 3934 | |
| 3935 | explicit MTruncateToInt32( |
| 3936 | MDefinition* def, |
| 3937 | wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset()) |
| 3938 | : MUnaryInstruction(classOpcode, def), bytecodeOffset_(bytecodeOffset) { |
| 3939 | setResultType(MIRType::Int32); |
| 3940 | setMovable(); |
| 3941 | |
| 3942 | // Guard unless the conversion is known to be non-effectful & non-throwing. |
| 3943 | if (mightHaveSideEffects(def)) { |
| 3944 | setGuard(); |
| 3945 | } |
| 3946 | } |
| 3947 | |
| 3948 | public: |
| 3949 | INSTRUCTION_HEADER(TruncateToInt32) |
| 3950 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 3951 | |
| 3952 | static bool mightHaveSideEffects(MDefinition* def) { |
| 3953 | return !def->definitelyType( |
| 3954 | {MIRType::Undefined, MIRType::Null, MIRType::Boolean, MIRType::Int32, |
| 3955 | MIRType::Double, MIRType::Float32, MIRType::String}); |
| 3956 | } |
| 3957 | |
| 3958 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 3959 | |
| 3960 | bool congruentTo(const MDefinition* ins) const override { |
| 3961 | return congruentIfOperandsEqual(ins); |
| 3962 | } |
| 3963 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 3964 | |
| 3965 | void computeRange(TempAllocator& alloc) override; |
| 3966 | TruncateKind operandTruncateKind(size_t index) const override; |
| 3967 | #ifdef DEBUG1 |
| 3968 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 3969 | #endif |
| 3970 | |
| 3971 | [[nodiscard]] bool writeRecoverData( |
| 3972 | CompactBufferWriter& writer) const override; |
| 3973 | bool canRecoverOnBailout() const override { |
| 3974 | return input()->type() < MIRType::Symbol; |
| 3975 | } |
| 3976 | |
| 3977 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 3978 | |
| 3979 | ALLOW_CLONE(MTruncateToInt32)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MTruncateToInt32 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 3980 | }; |
| 3981 | |
| 3982 | // It is like MTruncateToInt32 but with instance dependency. |
| 3983 | class MWasmBuiltinTruncateToInt32 : public MAryInstruction<2>, |
| 3984 | public ToInt32Policy::Data { |
| 3985 | wasm::BytecodeOffset bytecodeOffset_; |
| 3986 | |
| 3987 | MWasmBuiltinTruncateToInt32( |
| 3988 | MDefinition* def, MDefinition* instance, |
| 3989 | wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset()) |
| 3990 | : MAryInstruction(classOpcode), bytecodeOffset_(bytecodeOffset) { |
| 3991 | initOperand(0, def); |
| 3992 | initOperand(1, instance); |
| 3993 | setResultType(MIRType::Int32); |
| 3994 | setMovable(); |
| 3995 | |
| 3996 | // Guard unless the conversion is known to be non-effectful & non-throwing. |
| 3997 | if (MTruncateToInt32::mightHaveSideEffects(def)) { |
| 3998 | setGuard(); |
| 3999 | } |
| 4000 | } |
| 4001 | |
| 4002 | public: |
| 4003 | INSTRUCTION_HEADER(WasmBuiltinTruncateToInt32) |
| 4004 | NAMED_OPERANDS((0, input), (1, instance))MDefinition* input() const { return getOperand(0); } MDefinition * instance() const { return getOperand(1); } |
| 4005 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4006 | |
| 4007 | bool congruentTo(const MDefinition* ins) const override { |
| 4008 | return congruentIfOperandsEqual(ins); |
| 4009 | } |
| 4010 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4011 | |
| 4012 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 4013 | |
| 4014 | ALLOW_CLONE(MWasmBuiltinTruncateToInt32)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmBuiltinTruncateToInt32 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4015 | }; |
| 4016 | |
| 4017 | // Converts a primitive (either typed or untyped) to a BigInt. If the input is |
| 4018 | // not primitive at runtime, a bailout occurs. |
| 4019 | class MToBigInt : public MUnaryInstruction, public ToBigIntPolicy::Data { |
| 4020 | private: |
| 4021 | explicit MToBigInt(MDefinition* def) : MUnaryInstruction(classOpcode, def) { |
| 4022 | setResultType(MIRType::BigInt); |
| 4023 | setMovable(); |
| 4024 | |
| 4025 | // Guard unless the conversion is known to be non-effectful & non-throwing. |
| 4026 | if (!def->definitelyType({MIRType::Boolean, MIRType::BigInt})) { |
| 4027 | setGuard(); |
| 4028 | } |
| 4029 | } |
| 4030 | |
| 4031 | public: |
| 4032 | INSTRUCTION_HEADER(ToBigInt) |
| 4033 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4034 | |
| 4035 | bool congruentTo(const MDefinition* ins) const override { |
| 4036 | return congruentIfOperandsEqual(ins); |
| 4037 | } |
| 4038 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4039 | |
| 4040 | ALLOW_CLONE(MToBigInt)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MToBigInt (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4041 | }; |
| 4042 | |
| 4043 | // Takes a Value or typed input and returns a suitable Int64 using the |
| 4044 | // ToBigInt algorithm, possibly calling out to the VM for string, etc inputs. |
| 4045 | class MToInt64 : public MUnaryInstruction, public ToInt64Policy::Data { |
| 4046 | explicit MToInt64(MDefinition* def) : MUnaryInstruction(classOpcode, def) { |
| 4047 | setResultType(MIRType::Int64); |
| 4048 | setMovable(); |
| 4049 | |
| 4050 | // Guard unless the conversion is known to be non-effectful & non-throwing. |
| 4051 | if (!def->definitelyType( |
| 4052 | {MIRType::Boolean, MIRType::BigInt, MIRType::Int64})) { |
| 4053 | setGuard(); |
| 4054 | } |
| 4055 | } |
| 4056 | |
| 4057 | public: |
| 4058 | INSTRUCTION_HEADER(ToInt64) |
| 4059 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4060 | |
| 4061 | bool congruentTo(const MDefinition* ins) const override { |
| 4062 | return congruentIfOperandsEqual(ins); |
| 4063 | } |
| 4064 | |
| 4065 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4066 | |
| 4067 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4068 | |
| 4069 | ALLOW_CLONE(MToInt64)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MToInt64 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4070 | }; |
| 4071 | |
| 4072 | // Takes a BigInt pointer and returns its toInt64 value. |
| 4073 | class MTruncateBigIntToInt64 : public MUnaryInstruction, |
| 4074 | public NoTypePolicy::Data { |
| 4075 | explicit MTruncateBigIntToInt64(MDefinition* def) |
| 4076 | : MUnaryInstruction(classOpcode, def) { |
| 4077 | MOZ_ASSERT(def->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(def->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(def->type() == MIRType::BigInt ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "def->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4077); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 4077; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4078 | setResultType(MIRType::Int64); |
| 4079 | setMovable(); |
| 4080 | } |
| 4081 | |
| 4082 | public: |
| 4083 | INSTRUCTION_HEADER(TruncateBigIntToInt64) |
| 4084 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4085 | |
| 4086 | bool congruentTo(const MDefinition* ins) const override { |
| 4087 | return congruentIfOperandsEqual(ins); |
| 4088 | } |
| 4089 | |
| 4090 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4091 | |
| 4092 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4093 | |
| 4094 | ALLOW_CLONE(MTruncateBigIntToInt64)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MTruncateBigIntToInt64 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4095 | }; |
| 4096 | |
| 4097 | // Takes an Int64 and returns a fresh BigInt pointer. |
| 4098 | class MInt64ToBigInt : public MUnaryInstruction, public NoTypePolicy::Data { |
| 4099 | explicit MInt64ToBigInt(MDefinition* def) |
| 4100 | : MUnaryInstruction(classOpcode, def) { |
| 4101 | MOZ_ASSERT(def->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(def->type() == MIRType::Int64)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(def->type() == MIRType::Int64 ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "def->type() == MIRType::Int64", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4101); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 4101; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4102 | setResultType(MIRType::BigInt); |
| 4103 | setMovable(); |
| 4104 | } |
| 4105 | |
| 4106 | public: |
| 4107 | INSTRUCTION_HEADER(Int64ToBigInt) |
| 4108 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4109 | |
| 4110 | bool congruentTo(const MDefinition* ins) const override { |
| 4111 | return congruentIfOperandsEqual(ins); |
| 4112 | } |
| 4113 | |
| 4114 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4115 | |
| 4116 | ALLOW_CLONE(MInt64ToBigInt)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MInt64ToBigInt (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4117 | }; |
| 4118 | |
| 4119 | // Converts any type to a string |
| 4120 | class MToString : public MUnaryInstruction, public ToStringPolicy::Data { |
| 4121 | public: |
| 4122 | // MToString has two modes for handling of object/symbol arguments: if the |
| 4123 | // to-string conversion happens as part of another opcode, we have to bail out |
| 4124 | // to Baseline. If the conversion is for a stand-alone JSOp we can support |
| 4125 | // side-effects. |
| 4126 | enum class SideEffectHandling { Bailout, Supported }; |
| 4127 | |
| 4128 | private: |
| 4129 | SideEffectHandling sideEffects_; |
| 4130 | bool mightHaveSideEffects_ = false; |
| 4131 | |
| 4132 | MToString(MDefinition* def, SideEffectHandling sideEffects) |
| 4133 | : MUnaryInstruction(classOpcode, def), sideEffects_(sideEffects) { |
| 4134 | setResultType(MIRType::String); |
| 4135 | |
| 4136 | if (!def->definitelyType({MIRType::Undefined, MIRType::Null, |
| 4137 | MIRType::Boolean, MIRType::Int32, MIRType::Double, |
| 4138 | MIRType::Float32, MIRType::String, |
| 4139 | MIRType::BigInt})) { |
| 4140 | mightHaveSideEffects_ = true; |
| 4141 | } |
| 4142 | |
| 4143 | // If this instruction is not effectful, mark it as movable and set the |
| 4144 | // Guard flag if needed. If the operation is effectful it won't be |
| 4145 | // optimized anyway so there's no need to set any flags. |
| 4146 | if (!isEffectful()) { |
| 4147 | setMovable(); |
| 4148 | // Objects might override toString; Symbol throws. We bailout in those |
| 4149 | // cases and run side-effects in baseline instead. |
| 4150 | if (mightHaveSideEffects_) { |
| 4151 | setGuard(); |
| 4152 | } |
| 4153 | } |
| 4154 | } |
| 4155 | |
| 4156 | public: |
| 4157 | INSTRUCTION_HEADER(ToString) |
| 4158 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4159 | |
| 4160 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4161 | |
| 4162 | bool congruentTo(const MDefinition* ins) const override { |
| 4163 | if (!ins->isToString()) { |
| 4164 | return false; |
| 4165 | } |
| 4166 | if (sideEffects_ != ins->toToString()->sideEffects_) { |
| 4167 | return false; |
| 4168 | } |
| 4169 | return congruentIfOperandsEqual(ins); |
| 4170 | } |
| 4171 | |
| 4172 | AliasSet getAliasSet() const override { |
| 4173 | if (supportSideEffects() && mightHaveSideEffects_) { |
| 4174 | return AliasSet::Store(AliasSet::Any); |
| 4175 | } |
| 4176 | return AliasSet::None(); |
| 4177 | } |
| 4178 | |
| 4179 | bool mightHaveSideEffects() const { return mightHaveSideEffects_; } |
| 4180 | |
| 4181 | bool supportSideEffects() const { |
| 4182 | return sideEffects_ == SideEffectHandling::Supported; |
| 4183 | } |
| 4184 | |
| 4185 | bool needsSnapshot() const { |
| 4186 | return sideEffects_ == SideEffectHandling::Bailout && mightHaveSideEffects_; |
| 4187 | } |
| 4188 | |
| 4189 | ALLOW_CLONE(MToString)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MToString (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4190 | }; |
| 4191 | |
| 4192 | class MBitNot : public MUnaryInstruction, public BitwisePolicy::Data { |
| 4193 | explicit MBitNot(MDefinition* input) : MUnaryInstruction(classOpcode, input) { |
| 4194 | setResultType(MIRType::Int32); |
| 4195 | if (input->type() == MIRType::Int64) { |
| 4196 | setResultType(MIRType::Int64); |
| 4197 | } |
| 4198 | setMovable(); |
| 4199 | } |
| 4200 | |
| 4201 | public: |
| 4202 | INSTRUCTION_HEADER(BitNot) |
| 4203 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4204 | |
| 4205 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4206 | |
| 4207 | bool congruentTo(const MDefinition* ins) const override { |
| 4208 | return congruentIfOperandsEqual(ins); |
| 4209 | } |
| 4210 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4211 | void computeRange(TempAllocator& alloc) override; |
| 4212 | |
| 4213 | [[nodiscard]] bool writeRecoverData( |
| 4214 | CompactBufferWriter& writer) const override; |
| 4215 | bool canRecoverOnBailout() const override { return true; } |
| 4216 | |
| 4217 | ALLOW_CLONE(MBitNot)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBitNot (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4218 | }; |
| 4219 | |
| 4220 | class MTypeOf : public MUnaryInstruction, |
| 4221 | public BoxExceptPolicy<0, MIRType::Object>::Data { |
| 4222 | explicit MTypeOf(MDefinition* def) : MUnaryInstruction(classOpcode, def) { |
| 4223 | setResultType(MIRType::Int32); |
| 4224 | setMovable(); |
| 4225 | } |
| 4226 | TypeDataList observed_; |
| 4227 | |
| 4228 | public: |
| 4229 | INSTRUCTION_HEADER(TypeOf) |
| 4230 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4231 | |
| 4232 | void setObservedTypes(const TypeDataList& observed) { observed_ = observed; } |
| 4233 | bool hasObservedTypes() const { return observed_.count() > 0; } |
| 4234 | const TypeDataList& observedTypes() const { return observed_; } |
| 4235 | |
| 4236 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4237 | |
| 4238 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4239 | |
| 4240 | bool congruentTo(const MDefinition* ins) const override { |
| 4241 | return congruentIfOperandsEqual(ins); |
| 4242 | } |
| 4243 | |
| 4244 | [[nodiscard]] bool writeRecoverData( |
| 4245 | CompactBufferWriter& writer) const override; |
| 4246 | bool canRecoverOnBailout() const override { return true; } |
| 4247 | }; |
| 4248 | |
| 4249 | class MTypeOfIs : public MUnaryInstruction, public NoTypePolicy::Data { |
| 4250 | JSOp jsop_; |
| 4251 | JSType jstype_; |
| 4252 | |
| 4253 | MTypeOfIs(MDefinition* def, JSOp jsop, JSType jstype) |
| 4254 | : MUnaryInstruction(classOpcode, def), jsop_(jsop), jstype_(jstype) { |
| 4255 | MOZ_ASSERT(def->type() == MIRType::Object || def->type() == MIRType::Value)do { static_assert( mozilla::detail::AssertionConditionType< decltype(def->type() == MIRType::Object || def->type() == MIRType::Value)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(def->type() == MIRType::Object || def->type() == MIRType::Value))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("def->type() == MIRType::Object || def->type() == MIRType::Value" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4255); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::Object || def->type() == MIRType::Value" ")"); do { *((volatile int*)__null) = 4255; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4256 | |
| 4257 | setResultType(MIRType::Boolean); |
| 4258 | setMovable(); |
| 4259 | } |
| 4260 | |
| 4261 | public: |
| 4262 | INSTRUCTION_HEADER(TypeOfIs) |
| 4263 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4264 | |
| 4265 | JSOp jsop() const { return jsop_; } |
| 4266 | JSType jstype() const { return jstype_; } |
| 4267 | |
| 4268 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4269 | |
| 4270 | bool congruentTo(const MDefinition* ins) const override { |
| 4271 | if (!congruentIfOperandsEqual(ins)) { |
| 4272 | return false; |
| 4273 | } |
| 4274 | return jsop() == ins->toTypeOfIs()->jsop() && |
| 4275 | jstype() == ins->toTypeOfIs()->jstype(); |
| 4276 | } |
| 4277 | |
| 4278 | #ifdef JS_JITSPEW1 |
| 4279 | void printOpcode(GenericPrinter& out) const override; |
| 4280 | #endif |
| 4281 | }; |
| 4282 | |
| 4283 | class MBinaryBitwiseInstruction : public MBinaryInstruction, |
| 4284 | public BitwisePolicy::Data { |
| 4285 | protected: |
| 4286 | MBinaryBitwiseInstruction(Opcode op, MDefinition* left, MDefinition* right, |
| 4287 | MIRType type) |
| 4288 | : MBinaryInstruction(op, left, right), |
| 4289 | maskMatchesLeftRange(false), |
| 4290 | maskMatchesRightRange(false) { |
| 4291 | MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Int32 || type == MIRType::Int64 || ( isUrsh() && type == MIRType::Double))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type == MIRType::Int32 || type == MIRType::Int64 || (isUrsh() && type == MIRType::Double )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("type == MIRType::Int32 || type == MIRType::Int64 || (isUrsh() && type == MIRType::Double)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int32 || type == MIRType::Int64 || (isUrsh() && type == MIRType::Double)" ")"); do { *((volatile int*)__null) = 4292; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 4292 | (isUrsh() && type == MIRType::Double))do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Int32 || type == MIRType::Int64 || ( isUrsh() && type == MIRType::Double))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type == MIRType::Int32 || type == MIRType::Int64 || (isUrsh() && type == MIRType::Double )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("type == MIRType::Int32 || type == MIRType::Int64 || (isUrsh() && type == MIRType::Double)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int32 || type == MIRType::Int64 || (isUrsh() && type == MIRType::Double)" ")"); do { *((volatile int*)__null) = 4292; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4293 | setResultType(type); |
| 4294 | setMovable(); |
| 4295 | } |
| 4296 | |
| 4297 | bool maskMatchesLeftRange; |
| 4298 | bool maskMatchesRightRange; |
| 4299 | |
| 4300 | public: |
| 4301 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4302 | MDefinition* foldUnnecessaryBitop(); |
| 4303 | virtual MDefinition* foldIfZero(size_t operand) = 0; |
| 4304 | virtual MDefinition* foldIfNegOne(size_t operand) = 0; |
| 4305 | virtual MDefinition* foldIfEqual() = 0; |
| 4306 | virtual MDefinition* foldIfAllBitsSet(size_t operand) = 0; |
| 4307 | void collectRangeInfoPreTrunc() override; |
| 4308 | |
| 4309 | bool congruentTo(const MDefinition* ins) const override { |
| 4310 | return binaryCongruentTo(ins); |
| 4311 | } |
| 4312 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4313 | |
| 4314 | TruncateKind operandTruncateKind(size_t index) const override; |
| 4315 | }; |
| 4316 | |
| 4317 | class MBitAnd : public MBinaryBitwiseInstruction { |
| 4318 | MBitAnd(MDefinition* left, MDefinition* right, MIRType type) |
| 4319 | : MBinaryBitwiseInstruction(classOpcode, left, right, type) { |
| 4320 | setCommutative(); |
| 4321 | } |
| 4322 | |
| 4323 | public: |
| 4324 | INSTRUCTION_HEADER(BitAnd) |
| 4325 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4326 | |
| 4327 | MDefinition* foldIfZero(size_t operand) override { |
| 4328 | return getOperand(operand); // 0 & x => 0; |
| 4329 | } |
| 4330 | MDefinition* foldIfNegOne(size_t operand) override { |
| 4331 | return getOperand(1 - operand); // x & -1 => x |
| 4332 | } |
| 4333 | MDefinition* foldIfEqual() override { |
| 4334 | return getOperand(0); // x & x => x; |
| 4335 | } |
| 4336 | MDefinition* foldIfAllBitsSet(size_t operand) override { |
| 4337 | // e.g. for uint16: x & 0xffff => x; |
| 4338 | return getOperand(1 - operand); |
| 4339 | } |
| 4340 | void computeRange(TempAllocator& alloc) override; |
| 4341 | |
| 4342 | [[nodiscard]] bool writeRecoverData( |
| 4343 | CompactBufferWriter& writer) const override; |
| 4344 | bool canRecoverOnBailout() const override { return true; } |
| 4345 | |
| 4346 | ALLOW_CLONE(MBitAnd)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBitAnd (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4347 | }; |
| 4348 | |
| 4349 | class MBitOr : public MBinaryBitwiseInstruction { |
| 4350 | MBitOr(MDefinition* left, MDefinition* right, MIRType type) |
| 4351 | : MBinaryBitwiseInstruction(classOpcode, left, right, type) { |
| 4352 | setCommutative(); |
| 4353 | } |
| 4354 | |
| 4355 | public: |
| 4356 | INSTRUCTION_HEADER(BitOr) |
| 4357 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4358 | |
| 4359 | MDefinition* foldIfZero(size_t operand) override { |
| 4360 | return getOperand(1 - |
| 4361 | operand); // 0 | x => x, so if ith is 0, return (1-i)th |
| 4362 | } |
| 4363 | MDefinition* foldIfNegOne(size_t operand) override { |
| 4364 | return getOperand(operand); // x | -1 => -1 |
| 4365 | } |
| 4366 | MDefinition* foldIfEqual() override { |
| 4367 | return getOperand(0); // x | x => x |
| 4368 | } |
| 4369 | MDefinition* foldIfAllBitsSet(size_t operand) override { return this; } |
| 4370 | void computeRange(TempAllocator& alloc) override; |
| 4371 | [[nodiscard]] bool writeRecoverData( |
| 4372 | CompactBufferWriter& writer) const override; |
| 4373 | bool canRecoverOnBailout() const override { return true; } |
| 4374 | |
| 4375 | ALLOW_CLONE(MBitOr)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBitOr (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4376 | }; |
| 4377 | |
| 4378 | class MBitXor : public MBinaryBitwiseInstruction { |
| 4379 | MBitXor(MDefinition* left, MDefinition* right, MIRType type) |
| 4380 | : MBinaryBitwiseInstruction(classOpcode, left, right, type) { |
| 4381 | setCommutative(); |
| 4382 | } |
| 4383 | |
| 4384 | public: |
| 4385 | INSTRUCTION_HEADER(BitXor) |
| 4386 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4387 | |
| 4388 | MDefinition* foldIfZero(size_t operand) override { |
| 4389 | return getOperand(1 - operand); // 0 ^ x => x |
| 4390 | } |
| 4391 | MDefinition* foldIfNegOne(size_t operand) override { return this; } |
| 4392 | MDefinition* foldIfEqual() override { return this; } |
| 4393 | MDefinition* foldIfAllBitsSet(size_t operand) override { return this; } |
| 4394 | void computeRange(TempAllocator& alloc) override; |
| 4395 | |
| 4396 | [[nodiscard]] bool writeRecoverData( |
| 4397 | CompactBufferWriter& writer) const override; |
| 4398 | bool canRecoverOnBailout() const override { return true; } |
| 4399 | |
| 4400 | ALLOW_CLONE(MBitXor)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBitXor (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4401 | }; |
| 4402 | |
| 4403 | class MShiftInstruction : public MBinaryBitwiseInstruction { |
| 4404 | protected: |
| 4405 | MShiftInstruction(Opcode op, MDefinition* left, MDefinition* right, |
| 4406 | MIRType type) |
| 4407 | : MBinaryBitwiseInstruction(op, left, right, type) {} |
| 4408 | |
| 4409 | public: |
| 4410 | MDefinition* foldIfNegOne(size_t operand) override { return this; } |
| 4411 | MDefinition* foldIfEqual() override { return this; } |
| 4412 | MDefinition* foldIfAllBitsSet(size_t operand) override { return this; } |
| 4413 | }; |
| 4414 | |
| 4415 | class MLsh : public MShiftInstruction { |
| 4416 | MLsh(MDefinition* left, MDefinition* right, MIRType type) |
| 4417 | : MShiftInstruction(classOpcode, left, right, type) {} |
| 4418 | |
| 4419 | public: |
| 4420 | INSTRUCTION_HEADER(Lsh) |
| 4421 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4422 | |
| 4423 | MDefinition* foldIfZero(size_t operand) override { |
| 4424 | // 0 << x => 0 |
| 4425 | // x << 0 => x |
| 4426 | return getOperand(0); |
| 4427 | } |
| 4428 | |
| 4429 | void computeRange(TempAllocator& alloc) override; |
| 4430 | [[nodiscard]] bool writeRecoverData( |
| 4431 | CompactBufferWriter& writer) const override; |
| 4432 | bool canRecoverOnBailout() const override { return true; } |
| 4433 | |
| 4434 | ALLOW_CLONE(MLsh)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLsh (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4435 | }; |
| 4436 | |
| 4437 | class MRsh : public MShiftInstruction { |
| 4438 | MRsh(MDefinition* left, MDefinition* right, MIRType type) |
| 4439 | : MShiftInstruction(classOpcode, left, right, type) {} |
| 4440 | |
| 4441 | public: |
| 4442 | INSTRUCTION_HEADER(Rsh) |
| 4443 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4444 | |
| 4445 | MDefinition* foldIfZero(size_t operand) override { |
| 4446 | // 0 >> x => 0 |
| 4447 | // x >> 0 => x |
| 4448 | return getOperand(0); |
| 4449 | } |
| 4450 | void computeRange(TempAllocator& alloc) override; |
| 4451 | |
| 4452 | [[nodiscard]] bool writeRecoverData( |
| 4453 | CompactBufferWriter& writer) const override; |
| 4454 | bool canRecoverOnBailout() const override { return true; } |
| 4455 | |
| 4456 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4457 | |
| 4458 | ALLOW_CLONE(MRsh)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MRsh (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4459 | }; |
| 4460 | |
| 4461 | class MUrsh : public MShiftInstruction { |
| 4462 | bool bailoutsDisabled_; |
| 4463 | |
| 4464 | MUrsh(MDefinition* left, MDefinition* right, MIRType type) |
| 4465 | : MShiftInstruction(classOpcode, left, right, type), |
| 4466 | bailoutsDisabled_(false) {} |
| 4467 | |
| 4468 | public: |
| 4469 | INSTRUCTION_HEADER(Ursh) |
| 4470 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4471 | |
| 4472 | static MUrsh* NewWasm(TempAllocator& alloc, MDefinition* left, |
| 4473 | MDefinition* right, MIRType type); |
| 4474 | |
| 4475 | MDefinition* foldIfZero(size_t operand) override { |
| 4476 | // 0 >>> x => 0 |
| 4477 | if (operand == 0) { |
| 4478 | return getOperand(0); |
| 4479 | } |
| 4480 | |
| 4481 | return this; |
| 4482 | } |
| 4483 | |
| 4484 | bool bailoutsDisabled() const { return bailoutsDisabled_; } |
| 4485 | |
| 4486 | bool fallible() const; |
| 4487 | |
| 4488 | void computeRange(TempAllocator& alloc) override; |
| 4489 | void collectRangeInfoPreTrunc() override; |
| 4490 | |
| 4491 | [[nodiscard]] bool writeRecoverData( |
| 4492 | CompactBufferWriter& writer) const override; |
| 4493 | bool canRecoverOnBailout() const override { return true; } |
| 4494 | |
| 4495 | ALLOW_CLONE(MUrsh)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MUrsh (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4496 | }; |
| 4497 | |
| 4498 | class MSignExtendInt32 : public MUnaryInstruction, public NoTypePolicy::Data { |
| 4499 | public: |
| 4500 | enum Mode { Byte, Half }; |
| 4501 | |
| 4502 | private: |
| 4503 | Mode mode_; |
| 4504 | |
| 4505 | MSignExtendInt32(MDefinition* op, Mode mode) |
| 4506 | : MUnaryInstruction(classOpcode, op), mode_(mode) { |
| 4507 | setResultType(MIRType::Int32); |
| 4508 | setMovable(); |
| 4509 | } |
| 4510 | |
| 4511 | public: |
| 4512 | INSTRUCTION_HEADER(SignExtendInt32) |
| 4513 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4514 | |
| 4515 | Mode mode() const { return mode_; } |
| 4516 | |
| 4517 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4518 | bool congruentTo(const MDefinition* ins) const override { |
| 4519 | if (!congruentIfOperandsEqual(ins)) { |
| 4520 | return false; |
| 4521 | } |
| 4522 | return ins->isSignExtendInt32() && ins->toSignExtendInt32()->mode_ == mode_; |
| 4523 | } |
| 4524 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4525 | |
| 4526 | [[nodiscard]] bool writeRecoverData( |
| 4527 | CompactBufferWriter& writer) const override; |
| 4528 | bool canRecoverOnBailout() const override { return true; } |
| 4529 | |
| 4530 | ALLOW_CLONE(MSignExtendInt32)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MSignExtendInt32 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4531 | }; |
| 4532 | |
| 4533 | class MSignExtendInt64 : public MUnaryInstruction, public NoTypePolicy::Data { |
| 4534 | public: |
| 4535 | enum Mode { Byte, Half, Word }; |
| 4536 | |
| 4537 | private: |
| 4538 | Mode mode_; |
| 4539 | |
| 4540 | MSignExtendInt64(MDefinition* op, Mode mode) |
| 4541 | : MUnaryInstruction(classOpcode, op), mode_(mode) { |
| 4542 | setResultType(MIRType::Int64); |
| 4543 | setMovable(); |
| 4544 | } |
| 4545 | |
| 4546 | public: |
| 4547 | INSTRUCTION_HEADER(SignExtendInt64) |
| 4548 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4549 | |
| 4550 | Mode mode() const { return mode_; } |
| 4551 | |
| 4552 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4553 | bool congruentTo(const MDefinition* ins) const override { |
| 4554 | if (!congruentIfOperandsEqual(ins)) { |
| 4555 | return false; |
| 4556 | } |
| 4557 | return ins->isSignExtendInt64() && ins->toSignExtendInt64()->mode_ == mode_; |
| 4558 | } |
| 4559 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4560 | |
| 4561 | ALLOW_CLONE(MSignExtendInt64)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MSignExtendInt64 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4562 | }; |
| 4563 | |
| 4564 | class MBinaryArithInstruction : public MBinaryInstruction, |
| 4565 | public ArithPolicy::Data { |
| 4566 | // Implicit truncate flag is set by the truncate backward range analysis |
| 4567 | // optimization phase, and by wasm pre-processing. It is used in |
| 4568 | // NeedNegativeZeroCheck to check if the result of a multiplication needs to |
| 4569 | // produce -0 double value, and for avoiding overflow checks. |
| 4570 | |
| 4571 | // This optimization happens when the multiplication cannot be truncated |
| 4572 | // even if all uses are truncating its result, such as when the range |
| 4573 | // analysis detect a precision loss in the multiplication. |
| 4574 | TruncateKind implicitTruncate_; |
| 4575 | |
| 4576 | // Whether we must preserve NaN semantics, and in particular not fold |
| 4577 | // (x op id) or (id op x) to x, or replace a division by a multiply of the |
| 4578 | // exact reciprocal. |
| 4579 | bool mustPreserveNaN_; |
| 4580 | |
| 4581 | protected: |
| 4582 | MBinaryArithInstruction(Opcode op, MDefinition* left, MDefinition* right, |
| 4583 | MIRType type) |
| 4584 | : MBinaryInstruction(op, left, right), |
| 4585 | implicitTruncate_(TruncateKind::NoTruncate), |
| 4586 | mustPreserveNaN_(false) { |
| 4587 | MOZ_ASSERT(IsNumberType(type))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(type))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsNumberType(type)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4587); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type)" ")"); do { *((volatile int*)__null) = 4587; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4588 | setResultType(type); |
| 4589 | setMovable(); |
| 4590 | } |
| 4591 | |
| 4592 | public: |
| 4593 | void setMustPreserveNaN(bool b) { mustPreserveNaN_ = b; } |
| 4594 | bool mustPreserveNaN() const { return mustPreserveNaN_; } |
| 4595 | |
| 4596 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4597 | #ifdef JS_JITSPEW1 |
| 4598 | void printOpcode(GenericPrinter& out) const override; |
| 4599 | #endif |
| 4600 | |
| 4601 | virtual double getIdentity() = 0; |
| 4602 | |
| 4603 | void setSpecialization(MIRType type) { |
| 4604 | MOZ_ASSERT(IsNumberType(type))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(type))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsNumberType(type)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4604); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type)" ")"); do { *((volatile int*)__null) = 4604; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4605 | setResultType(type); |
| 4606 | } |
| 4607 | |
| 4608 | virtual void trySpecializeFloat32(TempAllocator& alloc) override; |
| 4609 | |
| 4610 | bool congruentTo(const MDefinition* ins) const override { |
| 4611 | if (!binaryCongruentTo(ins)) { |
| 4612 | return false; |
| 4613 | } |
| 4614 | const auto* other = static_cast<const MBinaryArithInstruction*>(ins); |
| 4615 | return other->mustPreserveNaN_ == mustPreserveNaN_; |
| 4616 | } |
| 4617 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4618 | |
| 4619 | bool isTruncated() const { |
| 4620 | return implicitTruncate_ == TruncateKind::Truncate; |
| 4621 | } |
| 4622 | TruncateKind truncateKind() const { return implicitTruncate_; } |
| 4623 | void setTruncateKind(TruncateKind kind) { |
| 4624 | implicitTruncate_ = std::max(implicitTruncate_, kind); |
| 4625 | } |
| 4626 | }; |
| 4627 | |
| 4628 | class MMinMax : public MBinaryInstruction, public ArithPolicy::Data { |
| 4629 | bool isMax_; |
| 4630 | |
| 4631 | MMinMax(MDefinition* left, MDefinition* right, MIRType type, bool isMax) |
| 4632 | : MBinaryInstruction(classOpcode, left, right), isMax_(isMax) { |
| 4633 | MOZ_ASSERT(IsNumberType(type))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(type))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsNumberType(type)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4633); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type)" ")"); do { *((volatile int*)__null) = 4633; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4634 | setResultType(type); |
| 4635 | setMovable(); |
| 4636 | } |
| 4637 | |
| 4638 | public: |
| 4639 | INSTRUCTION_HEADER(MinMax) |
| 4640 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4641 | |
| 4642 | static MMinMax* NewWasm(TempAllocator& alloc, MDefinition* left, |
| 4643 | MDefinition* right, MIRType type, bool isMax) { |
| 4644 | return New(alloc, left, right, type, isMax); |
| 4645 | } |
| 4646 | |
| 4647 | bool isMax() const { return isMax_; } |
| 4648 | |
| 4649 | bool congruentTo(const MDefinition* ins) const override { |
| 4650 | if (!congruentIfOperandsEqual(ins)) { |
| 4651 | return false; |
| 4652 | } |
| 4653 | const MMinMax* other = ins->toMinMax(); |
| 4654 | return other->isMax() == isMax(); |
| 4655 | } |
| 4656 | |
| 4657 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4658 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4659 | void computeRange(TempAllocator& alloc) override; |
| 4660 | [[nodiscard]] bool writeRecoverData( |
| 4661 | CompactBufferWriter& writer) const override; |
| 4662 | bool canRecoverOnBailout() const override { return true; } |
| 4663 | |
| 4664 | bool isFloat32Commutative() const override { return true; } |
| 4665 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 4666 | |
| 4667 | #ifdef JS_JITSPEW1 |
| 4668 | void printOpcode(GenericPrinter& out) const override; |
| 4669 | #endif |
| 4670 | |
| 4671 | ALLOW_CLONE(MMinMax)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MMinMax (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4672 | }; |
| 4673 | |
| 4674 | class MMinMaxArray : public MUnaryInstruction, public SingleObjectPolicy::Data { |
| 4675 | bool isMax_; |
| 4676 | |
| 4677 | MMinMaxArray(MDefinition* array, MIRType type, bool isMax) |
| 4678 | : MUnaryInstruction(classOpcode, array), isMax_(isMax) { |
| 4679 | MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Int32 || type == MIRType::Double)> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == MIRType::Int32 || type == MIRType::Double))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Int32 || type == MIRType::Double" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4679); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int32 || type == MIRType::Double" ")"); do { *((volatile int*)__null) = 4679; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4680 | setResultType(type); |
| 4681 | |
| 4682 | // We can't DCE this, even if the result is unused, in case one of the |
| 4683 | // elements of the array is an object with a `valueOf` function that |
| 4684 | // must be called. |
| 4685 | setGuard(); |
| 4686 | } |
| 4687 | |
| 4688 | public: |
| 4689 | INSTRUCTION_HEADER(MinMaxArray) |
| 4690 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4691 | NAMED_OPERANDS((0, array))MDefinition* array() const { return getOperand(0); } |
| 4692 | |
| 4693 | bool isMax() const { return isMax_; } |
| 4694 | |
| 4695 | bool congruentTo(const MDefinition* ins) const override { |
| 4696 | if (!ins->isMinMaxArray() || ins->toMinMaxArray()->isMax() != isMax()) { |
| 4697 | return false; |
| 4698 | } |
| 4699 | return congruentIfOperandsEqual(ins); |
| 4700 | } |
| 4701 | |
| 4702 | AliasSet getAliasSet() const override { |
| 4703 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::Element); |
| 4704 | } |
| 4705 | |
| 4706 | #ifdef JS_JITSPEW1 |
| 4707 | void printOpcode(GenericPrinter& out) const override; |
| 4708 | #endif |
| 4709 | }; |
| 4710 | |
| 4711 | class MAbs : public MUnaryInstruction, public ArithPolicy::Data { |
| 4712 | bool implicitTruncate_; |
| 4713 | |
| 4714 | MAbs(MDefinition* num, MIRType type) |
| 4715 | : MUnaryInstruction(classOpcode, num), implicitTruncate_(false) { |
| 4716 | MOZ_ASSERT(IsNumberType(type))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(type))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsNumberType(type)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4716); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type)" ")"); do { *((volatile int*)__null) = 4716; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4717 | setResultType(type); |
| 4718 | setMovable(); |
| 4719 | } |
| 4720 | |
| 4721 | public: |
| 4722 | INSTRUCTION_HEADER(Abs) |
| 4723 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4724 | |
| 4725 | static MAbs* NewWasm(TempAllocator& alloc, MDefinition* num, MIRType type) { |
| 4726 | auto* ins = new (alloc) MAbs(num, type); |
| 4727 | if (type == MIRType::Int32) { |
| 4728 | ins->implicitTruncate_ = true; |
| 4729 | } |
| 4730 | return ins; |
| 4731 | } |
| 4732 | |
| 4733 | bool congruentTo(const MDefinition* ins) const override { |
| 4734 | return congruentIfOperandsEqual(ins); |
| 4735 | } |
| 4736 | bool fallible() const; |
| 4737 | |
| 4738 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4739 | void computeRange(TempAllocator& alloc) override; |
| 4740 | bool isFloat32Commutative() const override { return true; } |
| 4741 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 4742 | |
| 4743 | [[nodiscard]] bool writeRecoverData( |
| 4744 | CompactBufferWriter& writer) const override; |
| 4745 | bool canRecoverOnBailout() const override { return true; } |
| 4746 | |
| 4747 | ALLOW_CLONE(MAbs)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MAbs (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4748 | }; |
| 4749 | |
| 4750 | class MClz : public MUnaryInstruction, public BitwisePolicy::Data { |
| 4751 | bool operandIsNeverZero_; |
| 4752 | |
| 4753 | explicit MClz(MDefinition* num, MIRType type) |
| 4754 | : MUnaryInstruction(classOpcode, num), operandIsNeverZero_(false) { |
| 4755 | MOZ_ASSERT(IsIntType(type))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsIntType(type))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsIntType(type)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsIntType(type)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4755); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsIntType(type)" ")"); do { *((volatile int*)__null) = 4755; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4756 | MOZ_ASSERT(IsNumberType(num->type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(num->type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsNumberType(num->type()) ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "IsNumberType(num->type())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4756); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(num->type())" ")"); do { *((volatile int*)__null) = 4756; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4757 | setResultType(type); |
| 4758 | setMovable(); |
| 4759 | } |
| 4760 | |
| 4761 | public: |
| 4762 | INSTRUCTION_HEADER(Clz) |
| 4763 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4764 | NAMED_OPERANDS((0, num))MDefinition* num() const { return getOperand(0); } |
| 4765 | |
| 4766 | bool congruentTo(const MDefinition* ins) const override { |
| 4767 | return congruentIfOperandsEqual(ins); |
| 4768 | } |
| 4769 | |
| 4770 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4771 | |
| 4772 | bool operandIsNeverZero() const { return operandIsNeverZero_; } |
| 4773 | |
| 4774 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4775 | void computeRange(TempAllocator& alloc) override; |
| 4776 | void collectRangeInfoPreTrunc() override; |
| 4777 | }; |
| 4778 | |
| 4779 | class MCtz : public MUnaryInstruction, public BitwisePolicy::Data { |
| 4780 | bool operandIsNeverZero_; |
| 4781 | |
| 4782 | explicit MCtz(MDefinition* num, MIRType type) |
| 4783 | : MUnaryInstruction(classOpcode, num), operandIsNeverZero_(false) { |
| 4784 | MOZ_ASSERT(IsIntType(type))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsIntType(type))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsIntType(type)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsIntType(type)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4784); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsIntType(type)" ")"); do { *((volatile int*)__null) = 4784; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4785 | MOZ_ASSERT(IsNumberType(num->type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(num->type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsNumberType(num->type()) ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "IsNumberType(num->type())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4785); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(num->type())" ")"); do { *((volatile int*)__null) = 4785; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4786 | setResultType(type); |
| 4787 | setMovable(); |
| 4788 | } |
| 4789 | |
| 4790 | public: |
| 4791 | INSTRUCTION_HEADER(Ctz) |
| 4792 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4793 | NAMED_OPERANDS((0, num))MDefinition* num() const { return getOperand(0); } |
| 4794 | |
| 4795 | bool congruentTo(const MDefinition* ins) const override { |
| 4796 | return congruentIfOperandsEqual(ins); |
| 4797 | } |
| 4798 | |
| 4799 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4800 | |
| 4801 | bool operandIsNeverZero() const { return operandIsNeverZero_; } |
| 4802 | |
| 4803 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4804 | void computeRange(TempAllocator& alloc) override; |
| 4805 | void collectRangeInfoPreTrunc() override; |
| 4806 | }; |
| 4807 | |
| 4808 | class MPopcnt : public MUnaryInstruction, public BitwisePolicy::Data { |
| 4809 | explicit MPopcnt(MDefinition* num, MIRType type) |
| 4810 | : MUnaryInstruction(classOpcode, num) { |
| 4811 | MOZ_ASSERT(IsNumberType(num->type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(num->type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsNumberType(num->type()) ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "IsNumberType(num->type())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4811); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(num->type())" ")"); do { *((volatile int*)__null) = 4811; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4812 | MOZ_ASSERT(IsIntType(type))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsIntType(type))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsIntType(type)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsIntType(type)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4812); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsIntType(type)" ")"); do { *((volatile int*)__null) = 4812; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4813 | setResultType(type); |
| 4814 | setMovable(); |
| 4815 | } |
| 4816 | |
| 4817 | public: |
| 4818 | INSTRUCTION_HEADER(Popcnt) |
| 4819 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4820 | NAMED_OPERANDS((0, num))MDefinition* num() const { return getOperand(0); } |
| 4821 | |
| 4822 | bool congruentTo(const MDefinition* ins) const override { |
| 4823 | return congruentIfOperandsEqual(ins); |
| 4824 | } |
| 4825 | |
| 4826 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4827 | |
| 4828 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4829 | void computeRange(TempAllocator& alloc) override; |
| 4830 | }; |
| 4831 | |
| 4832 | // Inline implementation of Math.sqrt(). |
| 4833 | class MSqrt : public MUnaryInstruction, public FloatingPointPolicy<0>::Data { |
| 4834 | MSqrt(MDefinition* num, MIRType type) : MUnaryInstruction(classOpcode, num) { |
| 4835 | setResultType(type); |
| 4836 | specialization_ = type; |
| 4837 | setMovable(); |
| 4838 | } |
| 4839 | |
| 4840 | public: |
| 4841 | INSTRUCTION_HEADER(Sqrt) |
| 4842 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4843 | |
| 4844 | bool congruentTo(const MDefinition* ins) const override { |
| 4845 | return congruentIfOperandsEqual(ins); |
| 4846 | } |
| 4847 | |
| 4848 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4849 | void computeRange(TempAllocator& alloc) override; |
| 4850 | |
| 4851 | bool isFloat32Commutative() const override { return true; } |
| 4852 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 4853 | |
| 4854 | [[nodiscard]] bool writeRecoverData( |
| 4855 | CompactBufferWriter& writer) const override; |
| 4856 | bool canRecoverOnBailout() const override { return true; } |
| 4857 | |
| 4858 | ALLOW_CLONE(MSqrt)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MSqrt (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4859 | }; |
| 4860 | |
| 4861 | class MCopySign : public MBinaryInstruction, public NoTypePolicy::Data { |
| 4862 | MCopySign(MDefinition* lhs, MDefinition* rhs, MIRType type) |
| 4863 | : MBinaryInstruction(classOpcode, lhs, rhs) { |
| 4864 | setResultType(type); |
| 4865 | setMovable(); |
| 4866 | } |
| 4867 | |
| 4868 | public: |
| 4869 | INSTRUCTION_HEADER(CopySign) |
| 4870 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4871 | |
| 4872 | bool congruentTo(const MDefinition* ins) const override { |
| 4873 | return congruentIfOperandsEqual(ins); |
| 4874 | } |
| 4875 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4876 | |
| 4877 | ALLOW_CLONE(MCopySign)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MCopySign (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4878 | }; |
| 4879 | |
| 4880 | // Inline implementation of Math.hypot(). |
| 4881 | class MHypot : public MVariadicInstruction, public AllDoublePolicy::Data { |
| 4882 | MHypot() : MVariadicInstruction(classOpcode) { |
| 4883 | setResultType(MIRType::Double); |
| 4884 | setMovable(); |
| 4885 | } |
| 4886 | |
| 4887 | public: |
| 4888 | INSTRUCTION_HEADER(Hypot) |
| 4889 | static MHypot* New(TempAllocator& alloc, const MDefinitionVector& vector); |
| 4890 | |
| 4891 | bool congruentTo(const MDefinition* ins) const override { |
| 4892 | return congruentIfOperandsEqual(ins); |
| 4893 | } |
| 4894 | |
| 4895 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4896 | |
| 4897 | bool possiblyCalls() const override { return true; } |
| 4898 | |
| 4899 | [[nodiscard]] bool writeRecoverData( |
| 4900 | CompactBufferWriter& writer) const override; |
| 4901 | bool canRecoverOnBailout() const override { return true; } |
| 4902 | |
| 4903 | bool canClone() const override { return true; } |
| 4904 | |
| 4905 | MInstruction* clone(TempAllocator& alloc, |
| 4906 | const MDefinitionVector& inputs) const override { |
| 4907 | return MHypot::New(alloc, inputs); |
| 4908 | } |
| 4909 | }; |
| 4910 | |
| 4911 | // Inline implementation of Math.pow(). |
| 4912 | // |
| 4913 | // Supports the following three specializations: |
| 4914 | // |
| 4915 | // 1. MPow(FloatingPoint, FloatingPoint) -> Double |
| 4916 | // - The most general mode, calls js::ecmaPow. |
| 4917 | // - Never performs a bailout. |
| 4918 | // 2. MPow(FloatingPoint, Int32) -> Double |
| 4919 | // - Optimization to call js::powi instead of js::ecmaPow. |
| 4920 | // - Never performs a bailout. |
| 4921 | // 3. MPow(Int32, Int32) -> Int32 |
| 4922 | // - Performs the complete exponentiation operation in assembly code. |
| 4923 | // - Bails out if the result doesn't fit in Int32. |
| 4924 | class MPow : public MBinaryInstruction, public PowPolicy::Data { |
| 4925 | // If true, the result is guaranteed to never be negative zero, as long as the |
| 4926 | // power is a positive number. |
| 4927 | bool canBeNegativeZero_; |
| 4928 | |
| 4929 | MPow(MDefinition* input, MDefinition* power, MIRType specialization) |
| 4930 | : MBinaryInstruction(classOpcode, input, power) { |
| 4931 | MOZ_ASSERT(specialization == MIRType::Int32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(specialization == MIRType::Int32 || specialization == MIRType::Double)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(specialization == MIRType::Int32 || specialization == MIRType::Double))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("specialization == MIRType::Int32 || specialization == MIRType::Double" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "specialization == MIRType::Int32 || specialization == MIRType::Double" ")"); do { *((volatile int*)__null) = 4932; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 4932 | specialization == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType< decltype(specialization == MIRType::Int32 || specialization == MIRType::Double)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(specialization == MIRType::Int32 || specialization == MIRType::Double))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("specialization == MIRType::Int32 || specialization == MIRType::Double" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 4932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "specialization == MIRType::Int32 || specialization == MIRType::Double" ")"); do { *((volatile int*)__null) = 4932; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4933 | setResultType(specialization); |
| 4934 | setMovable(); |
| 4935 | |
| 4936 | // The result can't be negative zero if the base is an Int32 value. |
| 4937 | canBeNegativeZero_ = input->type() != MIRType::Int32; |
| 4938 | } |
| 4939 | |
| 4940 | // Helpers for `foldsTo` |
| 4941 | MDefinition* foldsConstant(TempAllocator& alloc); |
| 4942 | MDefinition* foldsConstantPower(TempAllocator& alloc); |
| 4943 | |
| 4944 | bool canBeNegativeZero() const { return canBeNegativeZero_; } |
| 4945 | |
| 4946 | public: |
| 4947 | INSTRUCTION_HEADER(Pow) |
| 4948 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4949 | |
| 4950 | MDefinition* input() const { return lhs(); } |
| 4951 | MDefinition* power() const { return rhs(); } |
| 4952 | |
| 4953 | bool congruentTo(const MDefinition* ins) const override { |
| 4954 | return congruentIfOperandsEqual(ins); |
| 4955 | } |
| 4956 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4957 | bool possiblyCalls() const override { return type() != MIRType::Int32; } |
| 4958 | [[nodiscard]] bool writeRecoverData( |
| 4959 | CompactBufferWriter& writer) const override; |
| 4960 | bool canRecoverOnBailout() const override { return true; } |
| 4961 | |
| 4962 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 4963 | |
| 4964 | ALLOW_CLONE(MPow)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MPow (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 4965 | }; |
| 4966 | |
| 4967 | // Inline implementation of Math.pow(x, 0.5), which subtly differs from |
| 4968 | // Math.sqrt(x). |
| 4969 | class MPowHalf : public MUnaryInstruction, public DoublePolicy<0>::Data { |
| 4970 | bool operandIsNeverNegativeInfinity_; |
| 4971 | bool operandIsNeverNegativeZero_; |
| 4972 | bool operandIsNeverNaN_; |
| 4973 | |
| 4974 | explicit MPowHalf(MDefinition* input) |
| 4975 | : MUnaryInstruction(classOpcode, input), |
| 4976 | operandIsNeverNegativeInfinity_(false), |
| 4977 | operandIsNeverNegativeZero_(false), |
| 4978 | operandIsNeverNaN_(false) { |
| 4979 | setResultType(MIRType::Double); |
| 4980 | setMovable(); |
| 4981 | } |
| 4982 | |
| 4983 | public: |
| 4984 | INSTRUCTION_HEADER(PowHalf) |
| 4985 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 4986 | |
| 4987 | bool congruentTo(const MDefinition* ins) const override { |
| 4988 | return congruentIfOperandsEqual(ins); |
| 4989 | } |
| 4990 | bool operandIsNeverNegativeInfinity() const { |
| 4991 | return operandIsNeverNegativeInfinity_; |
| 4992 | } |
| 4993 | bool operandIsNeverNegativeZero() const { |
| 4994 | return operandIsNeverNegativeZero_; |
| 4995 | } |
| 4996 | bool operandIsNeverNaN() const { return operandIsNeverNaN_; } |
| 4997 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 4998 | void collectRangeInfoPreTrunc() override; |
| 4999 | [[nodiscard]] bool writeRecoverData( |
| 5000 | CompactBufferWriter& writer) const override; |
| 5001 | bool canRecoverOnBailout() const override { return true; } |
| 5002 | |
| 5003 | ALLOW_CLONE(MPowHalf)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MPowHalf (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5004 | }; |
| 5005 | |
| 5006 | class MSign : public MUnaryInstruction, public SignPolicy::Data { |
| 5007 | private: |
| 5008 | MSign(MDefinition* input, MIRType resultType) |
| 5009 | : MUnaryInstruction(classOpcode, input) { |
| 5010 | MOZ_ASSERT(IsNumberType(input->type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(input->type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsNumberType(input->type( ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsNumberType(input->type())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(input->type())" ")"); do { *((volatile int*)__null) = 5010; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5011 | MOZ_ASSERT(resultType == MIRType::Int32 || resultType == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType< decltype(resultType == MIRType::Int32 || resultType == MIRType ::Double)>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(resultType == MIRType::Int32 || resultType == MIRType::Double))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("resultType == MIRType::Int32 || resultType == MIRType::Double" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5011); AnnotateMozCrashReason("MOZ_ASSERT" "(" "resultType == MIRType::Int32 || resultType == MIRType::Double" ")"); do { *((volatile int*)__null) = 5011; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5012 | specialization_ = input->type(); |
| 5013 | setResultType(resultType); |
| 5014 | setMovable(); |
| 5015 | } |
| 5016 | |
| 5017 | public: |
| 5018 | INSTRUCTION_HEADER(Sign) |
| 5019 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5020 | |
| 5021 | bool congruentTo(const MDefinition* ins) const override { |
| 5022 | return congruentIfOperandsEqual(ins); |
| 5023 | } |
| 5024 | |
| 5025 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 5026 | |
| 5027 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 5028 | |
| 5029 | void computeRange(TempAllocator& alloc) override; |
| 5030 | [[nodiscard]] bool writeRecoverData( |
| 5031 | CompactBufferWriter& writer) const override; |
| 5032 | bool canRecoverOnBailout() const override { return true; } |
| 5033 | |
| 5034 | ALLOW_CLONE(MSign)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MSign (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5035 | }; |
| 5036 | |
| 5037 | class MMathFunction : public MUnaryInstruction, |
| 5038 | public FloatingPointPolicy<0>::Data { |
| 5039 | UnaryMathFunction function_; |
| 5040 | |
| 5041 | // A nullptr cache means this function will neither access nor update the |
| 5042 | // cache. |
| 5043 | MMathFunction(MDefinition* input, UnaryMathFunction function) |
| 5044 | : MUnaryInstruction(classOpcode, input), function_(function) { |
| 5045 | setResultType(MIRType::Double); |
| 5046 | specialization_ = MIRType::Double; |
| 5047 | setMovable(); |
| 5048 | } |
| 5049 | |
| 5050 | public: |
| 5051 | INSTRUCTION_HEADER(MathFunction) |
| 5052 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5053 | |
| 5054 | UnaryMathFunction function() const { return function_; } |
| 5055 | |
| 5056 | bool congruentTo(const MDefinition* ins) const override { |
| 5057 | if (!ins->isMathFunction()) { |
| 5058 | return false; |
| 5059 | } |
| 5060 | if (ins->toMathFunction()->function() != function()) { |
| 5061 | return false; |
| 5062 | } |
| 5063 | return congruentIfOperandsEqual(ins); |
| 5064 | } |
| 5065 | |
| 5066 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 5067 | |
| 5068 | bool possiblyCalls() const override { return true; } |
| 5069 | |
| 5070 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 5071 | |
| 5072 | #ifdef JS_JITSPEW1 |
| 5073 | void printOpcode(GenericPrinter& out) const override; |
| 5074 | #endif |
| 5075 | |
| 5076 | static const char* FunctionName(UnaryMathFunction function); |
| 5077 | |
| 5078 | bool isFloat32Commutative() const override; |
| 5079 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 5080 | |
| 5081 | void computeRange(TempAllocator& alloc) override; |
| 5082 | |
| 5083 | [[nodiscard]] bool writeRecoverData( |
| 5084 | CompactBufferWriter& writer) const override; |
| 5085 | bool canRecoverOnBailout() const override { return true; } |
| 5086 | |
| 5087 | ALLOW_CLONE(MMathFunction)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MMathFunction (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5088 | }; |
| 5089 | |
| 5090 | class MAdd : public MBinaryArithInstruction { |
| 5091 | MAdd(MDefinition* left, MDefinition* right, MIRType type) |
| 5092 | : MBinaryArithInstruction(classOpcode, left, right, type) { |
| 5093 | setCommutative(); |
| 5094 | } |
| 5095 | |
| 5096 | MAdd(MDefinition* left, MDefinition* right, TruncateKind truncateKind) |
| 5097 | : MAdd(left, right, MIRType::Int32) { |
| 5098 | setTruncateKind(truncateKind); |
| 5099 | } |
| 5100 | |
| 5101 | public: |
| 5102 | INSTRUCTION_HEADER(Add) |
| 5103 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5104 | |
| 5105 | static MAdd* NewWasm(TempAllocator& alloc, MDefinition* left, |
| 5106 | MDefinition* right, MIRType type) { |
| 5107 | auto* ret = new (alloc) MAdd(left, right, type); |
| 5108 | if (type == MIRType::Int32) { |
| 5109 | ret->setTruncateKind(TruncateKind::Truncate); |
| 5110 | } |
| 5111 | return ret; |
| 5112 | } |
| 5113 | |
| 5114 | bool isFloat32Commutative() const override { return true; } |
| 5115 | |
| 5116 | double getIdentity() override { return 0; } |
| 5117 | |
| 5118 | bool fallible() const; |
| 5119 | void computeRange(TempAllocator& alloc) override; |
| 5120 | bool canTruncate() const override; |
| 5121 | void truncate(TruncateKind kind) override; |
| 5122 | TruncateKind operandTruncateKind(size_t index) const override; |
| 5123 | |
| 5124 | [[nodiscard]] bool writeRecoverData( |
| 5125 | CompactBufferWriter& writer) const override; |
| 5126 | bool canRecoverOnBailout() const override { return true; } |
| 5127 | |
| 5128 | ALLOW_CLONE(MAdd)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MAdd (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5129 | }; |
| 5130 | |
| 5131 | class MSub : public MBinaryArithInstruction { |
| 5132 | MSub(MDefinition* left, MDefinition* right, MIRType type) |
| 5133 | : MBinaryArithInstruction(classOpcode, left, right, type) {} |
| 5134 | |
| 5135 | public: |
| 5136 | INSTRUCTION_HEADER(Sub) |
| 5137 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5138 | |
| 5139 | static MSub* NewWasm(TempAllocator& alloc, MDefinition* left, |
| 5140 | MDefinition* right, MIRType type, bool mustPreserveNaN) { |
| 5141 | auto* ret = new (alloc) MSub(left, right, type); |
| 5142 | ret->setMustPreserveNaN(mustPreserveNaN); |
| 5143 | if (type == MIRType::Int32) { |
| 5144 | ret->setTruncateKind(TruncateKind::Truncate); |
| 5145 | } |
| 5146 | return ret; |
| 5147 | } |
| 5148 | |
| 5149 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 5150 | |
| 5151 | double getIdentity() override { return 0; } |
| 5152 | |
| 5153 | bool isFloat32Commutative() const override { return true; } |
| 5154 | |
| 5155 | bool fallible() const; |
| 5156 | void computeRange(TempAllocator& alloc) override; |
| 5157 | bool canTruncate() const override; |
| 5158 | void truncate(TruncateKind kind) override; |
| 5159 | TruncateKind operandTruncateKind(size_t index) const override; |
| 5160 | |
| 5161 | [[nodiscard]] bool writeRecoverData( |
| 5162 | CompactBufferWriter& writer) const override; |
| 5163 | bool canRecoverOnBailout() const override { return true; } |
| 5164 | |
| 5165 | ALLOW_CLONE(MSub)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MSub (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5166 | }; |
| 5167 | |
| 5168 | class MMul : public MBinaryArithInstruction { |
| 5169 | public: |
| 5170 | enum Mode { Normal, Integer }; |
| 5171 | |
| 5172 | private: |
| 5173 | // Annotation the result could be a negative zero |
| 5174 | // and we need to guard this during execution. |
| 5175 | bool canBeNegativeZero_; |
| 5176 | |
| 5177 | Mode mode_; |
| 5178 | |
| 5179 | MMul(MDefinition* left, MDefinition* right, MIRType type, Mode mode) |
| 5180 | : MBinaryArithInstruction(classOpcode, left, right, type), |
| 5181 | canBeNegativeZero_(true), |
| 5182 | mode_(mode) { |
| 5183 | setCommutative(); |
| 5184 | if (mode == Integer) { |
| 5185 | // This implements the required behavior for Math.imul, which |
| 5186 | // can never fail and always truncates its output to int32. |
| 5187 | canBeNegativeZero_ = false; |
| 5188 | setTruncateKind(TruncateKind::Truncate); |
| 5189 | } |
| 5190 | MOZ_ASSERT_IF(mode != Integer, mode == Normal)do { if (mode != Integer) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(mode == Normal)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(mode == Normal))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("mode == Normal", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mode == Normal" ")"); do { *((volatile int*)__null) = 5190; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
| 5191 | } |
| 5192 | |
| 5193 | public: |
| 5194 | INSTRUCTION_HEADER(Mul) |
| 5195 | |
| 5196 | static MMul* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, |
| 5197 | MIRType type, Mode mode = Normal) { |
| 5198 | return new (alloc) MMul(left, right, type, mode); |
| 5199 | } |
| 5200 | static MMul* NewWasm(TempAllocator& alloc, MDefinition* left, |
| 5201 | MDefinition* right, MIRType type, Mode mode, |
| 5202 | bool mustPreserveNaN) { |
| 5203 | auto* ret = new (alloc) MMul(left, right, type, mode); |
| 5204 | ret->setMustPreserveNaN(mustPreserveNaN); |
| 5205 | return ret; |
| 5206 | } |
| 5207 | |
| 5208 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 5209 | void analyzeEdgeCasesForward() override; |
| 5210 | void analyzeEdgeCasesBackward() override; |
| 5211 | void collectRangeInfoPreTrunc() override; |
| 5212 | |
| 5213 | double getIdentity() override { return 1; } |
| 5214 | |
| 5215 | bool congruentTo(const MDefinition* ins) const override { |
| 5216 | if (!ins->isMul()) { |
| 5217 | return false; |
| 5218 | } |
| 5219 | |
| 5220 | const MMul* mul = ins->toMul(); |
| 5221 | if (canBeNegativeZero_ != mul->canBeNegativeZero()) { |
| 5222 | return false; |
| 5223 | } |
| 5224 | |
| 5225 | if (mode_ != mul->mode()) { |
| 5226 | return false; |
| 5227 | } |
| 5228 | |
| 5229 | if (mustPreserveNaN() != mul->mustPreserveNaN()) { |
| 5230 | return false; |
| 5231 | } |
| 5232 | |
| 5233 | return binaryCongruentTo(ins); |
| 5234 | } |
| 5235 | |
| 5236 | bool canOverflow() const; |
| 5237 | |
| 5238 | bool canBeNegativeZero() const { return canBeNegativeZero_; } |
| 5239 | void setCanBeNegativeZero(bool negativeZero) { |
| 5240 | canBeNegativeZero_ = negativeZero; |
| 5241 | } |
| 5242 | |
| 5243 | bool fallible() const { return canBeNegativeZero_ || canOverflow(); } |
| 5244 | |
| 5245 | bool isFloat32Commutative() const override { return true; } |
| 5246 | |
| 5247 | void computeRange(TempAllocator& alloc) override; |
| 5248 | bool canTruncate() const override; |
| 5249 | void truncate(TruncateKind kind) override; |
| 5250 | TruncateKind operandTruncateKind(size_t index) const override; |
| 5251 | |
| 5252 | Mode mode() const { return mode_; } |
| 5253 | |
| 5254 | [[nodiscard]] bool writeRecoverData( |
| 5255 | CompactBufferWriter& writer) const override; |
| 5256 | bool canRecoverOnBailout() const override { return true; } |
| 5257 | |
| 5258 | ALLOW_CLONE(MMul)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MMul (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5259 | }; |
| 5260 | |
| 5261 | class MDiv : public MBinaryArithInstruction { |
| 5262 | bool canBeNegativeZero_; |
| 5263 | bool canBeNegativeOverflow_; |
| 5264 | bool canBeDivideByZero_; |
| 5265 | bool canBeNegativeDividend_; |
| 5266 | bool unsigned_; // If false, signedness will be derived from operands |
| 5267 | bool trapOnError_; |
| 5268 | wasm::BytecodeOffset bytecodeOffset_; |
| 5269 | |
| 5270 | MDiv(MDefinition* left, MDefinition* right, MIRType type) |
| 5271 | : MBinaryArithInstruction(classOpcode, left, right, type), |
| 5272 | canBeNegativeZero_(true), |
| 5273 | canBeNegativeOverflow_(true), |
| 5274 | canBeDivideByZero_(true), |
| 5275 | canBeNegativeDividend_(true), |
| 5276 | unsigned_(false), |
| 5277 | trapOnError_(false) {} |
| 5278 | |
| 5279 | public: |
| 5280 | INSTRUCTION_HEADER(Div) |
| 5281 | |
| 5282 | static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, |
| 5283 | MIRType type) { |
| 5284 | return new (alloc) MDiv(left, right, type); |
| 5285 | } |
| 5286 | static MDiv* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, |
| 5287 | MIRType type, bool unsignd, bool trapOnError = false, |
| 5288 | wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset(), |
| 5289 | bool mustPreserveNaN = false) { |
| 5290 | auto* div = new (alloc) MDiv(left, right, type); |
| 5291 | div->unsigned_ = unsignd; |
| 5292 | div->trapOnError_ = trapOnError; |
| 5293 | div->bytecodeOffset_ = bytecodeOffset; |
| 5294 | if (trapOnError) { |
| 5295 | div->setGuard(); // not removable because of possible side-effects. |
| 5296 | div->setNotMovable(); |
| 5297 | } |
| 5298 | div->setMustPreserveNaN(mustPreserveNaN); |
| 5299 | if (type == MIRType::Int32) { |
| 5300 | div->setTruncateKind(TruncateKind::Truncate); |
| 5301 | } |
| 5302 | return div; |
| 5303 | } |
| 5304 | |
| 5305 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 5306 | void analyzeEdgeCasesForward() override; |
| 5307 | void analyzeEdgeCasesBackward() override; |
| 5308 | |
| 5309 | double getIdentity() override { MOZ_CRASH("not used")do { do { } while (false); MOZ_ReportCrash("" "not used", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5309); AnnotateMozCrashReason("MOZ_CRASH(" "not used" ")"); do { *((volatile int*)__null) = 5309; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } |
| 5310 | |
| 5311 | bool canBeNegativeZero() const { return canBeNegativeZero_; } |
| 5312 | void setCanBeNegativeZero(bool negativeZero) { |
| 5313 | canBeNegativeZero_ = negativeZero; |
| 5314 | } |
| 5315 | |
| 5316 | bool canBeNegativeOverflow() const { return canBeNegativeOverflow_; } |
| 5317 | |
| 5318 | bool canBeDivideByZero() const { return canBeDivideByZero_; } |
| 5319 | |
| 5320 | bool canBeNegativeDividend() const { |
| 5321 | // "Dividend" is an ambiguous concept for unsigned truncated |
| 5322 | // division, because of the truncation procedure: |
| 5323 | // ((x>>>0)/2)|0, for example, gets transformed in |
| 5324 | // MDiv::truncate into a node with lhs representing x (not |
| 5325 | // x>>>0) and rhs representing the constant 2; in other words, |
| 5326 | // the MIR node corresponds to "cast operands to unsigned and |
| 5327 | // divide" operation. In this case, is the dividend x or is it |
| 5328 | // x>>>0? In order to resolve such ambiguities, we disallow |
| 5329 | // the usage of this method for unsigned division. |
| 5330 | MOZ_ASSERT(!unsigned_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!unsigned_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!unsigned_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!unsigned_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5330); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!unsigned_" ")"); do { *((volatile int*)__null) = 5330; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5331 | return canBeNegativeDividend_; |
| 5332 | } |
| 5333 | |
| 5334 | bool isUnsigned() const { return unsigned_; } |
| 5335 | |
| 5336 | bool isTruncatedIndirectly() const { |
| 5337 | return truncateKind() >= TruncateKind::IndirectTruncate; |
| 5338 | } |
| 5339 | |
| 5340 | bool canTruncateInfinities() const { return isTruncated(); } |
| 5341 | bool canTruncateRemainder() const { return isTruncated(); } |
| 5342 | bool canTruncateOverflow() const { |
| 5343 | return isTruncated() || isTruncatedIndirectly(); |
| 5344 | } |
| 5345 | bool canTruncateNegativeZero() const { |
| 5346 | return isTruncated() || isTruncatedIndirectly(); |
| 5347 | } |
| 5348 | |
| 5349 | bool trapOnError() const { return trapOnError_; } |
| 5350 | wasm::BytecodeOffset bytecodeOffset() const { |
| 5351 | MOZ_ASSERT(bytecodeOffset_.isValid())do { static_assert( mozilla::detail::AssertionConditionType< decltype(bytecodeOffset_.isValid())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(bytecodeOffset_.isValid()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("bytecodeOffset_.isValid()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5351); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bytecodeOffset_.isValid()" ")"); do { *((volatile int*)__null) = 5351; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5352 | return bytecodeOffset_; |
| 5353 | } |
| 5354 | |
| 5355 | bool isFloat32Commutative() const override { return true; } |
| 5356 | |
| 5357 | void computeRange(TempAllocator& alloc) override; |
| 5358 | bool fallible() const; |
| 5359 | bool canTruncate() const override; |
| 5360 | void truncate(TruncateKind kind) override; |
| 5361 | void collectRangeInfoPreTrunc() override; |
| 5362 | TruncateKind operandTruncateKind(size_t index) const override; |
| 5363 | |
| 5364 | [[nodiscard]] bool writeRecoverData( |
| 5365 | CompactBufferWriter& writer) const override; |
| 5366 | bool canRecoverOnBailout() const override { return true; } |
| 5367 | |
| 5368 | bool congruentTo(const MDefinition* ins) const override { |
| 5369 | if (!MBinaryArithInstruction::congruentTo(ins)) { |
| 5370 | return false; |
| 5371 | } |
| 5372 | const MDiv* other = ins->toDiv(); |
| 5373 | MOZ_ASSERT(other->trapOnError() == trapOnError_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(other->trapOnError() == trapOnError_)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(other->trapOnError() == trapOnError_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("other->trapOnError() == trapOnError_" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5373); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->trapOnError() == trapOnError_" ")"); do { *((volatile int*)__null) = 5373; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5374 | return unsigned_ == other->isUnsigned(); |
| 5375 | } |
| 5376 | |
| 5377 | ALLOW_CLONE(MDiv)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MDiv (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5378 | }; |
| 5379 | |
| 5380 | class MWasmBuiltinDivI64 : public MAryInstruction<3>, public ArithPolicy::Data { |
| 5381 | bool canBeNegativeZero_; |
| 5382 | bool canBeNegativeOverflow_; |
| 5383 | bool canBeDivideByZero_; |
| 5384 | bool canBeNegativeDividend_; |
| 5385 | bool unsigned_; // If false, signedness will be derived from operands |
| 5386 | bool trapOnError_; |
| 5387 | wasm::BytecodeOffset bytecodeOffset_; |
| 5388 | |
| 5389 | MWasmBuiltinDivI64(MDefinition* left, MDefinition* right, |
| 5390 | MDefinition* instance) |
| 5391 | : MAryInstruction(classOpcode), |
| 5392 | canBeNegativeZero_(true), |
| 5393 | canBeNegativeOverflow_(true), |
| 5394 | canBeDivideByZero_(true), |
| 5395 | canBeNegativeDividend_(true), |
| 5396 | unsigned_(false), |
| 5397 | trapOnError_(false) { |
| 5398 | initOperand(0, left); |
| 5399 | initOperand(1, right); |
| 5400 | initOperand(2, instance); |
| 5401 | |
| 5402 | setResultType(MIRType::Int64); |
| 5403 | setMovable(); |
| 5404 | } |
| 5405 | |
| 5406 | public: |
| 5407 | INSTRUCTION_HEADER(WasmBuiltinDivI64) |
| 5408 | |
| 5409 | NAMED_OPERANDS((0, lhs), (1, rhs), (2, instance))MDefinition* lhs() const { return getOperand(0); } MDefinition * rhs() const { return getOperand(1); } MDefinition* instance () const { return getOperand(2); } |
| 5410 | |
| 5411 | static MWasmBuiltinDivI64* New( |
| 5412 | TempAllocator& alloc, MDefinition* left, MDefinition* right, |
| 5413 | MDefinition* instance, bool unsignd, bool trapOnError = false, |
| 5414 | wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset()) { |
| 5415 | auto* wasm64Div = new (alloc) MWasmBuiltinDivI64(left, right, instance); |
| 5416 | wasm64Div->unsigned_ = unsignd; |
| 5417 | wasm64Div->trapOnError_ = trapOnError; |
| 5418 | wasm64Div->bytecodeOffset_ = bytecodeOffset; |
| 5419 | if (trapOnError) { |
| 5420 | wasm64Div->setGuard(); // not removable because of possible side-effects. |
| 5421 | wasm64Div->setNotMovable(); |
| 5422 | } |
| 5423 | return wasm64Div; |
| 5424 | } |
| 5425 | |
| 5426 | bool canBeNegativeZero() const { return canBeNegativeZero_; } |
| 5427 | void setCanBeNegativeZero(bool negativeZero) { |
| 5428 | canBeNegativeZero_ = negativeZero; |
| 5429 | } |
| 5430 | |
| 5431 | bool canBeNegativeOverflow() const { return canBeNegativeOverflow_; } |
| 5432 | |
| 5433 | bool canBeDivideByZero() const { return canBeDivideByZero_; } |
| 5434 | |
| 5435 | bool canBeNegativeDividend() const { |
| 5436 | // "Dividend" is an ambiguous concept for unsigned truncated |
| 5437 | // division, because of the truncation procedure: |
| 5438 | // ((x>>>0)/2)|0, for example, gets transformed in |
| 5439 | // MWasmDiv::truncate into a node with lhs representing x (not |
| 5440 | // x>>>0) and rhs representing the constant 2; in other words, |
| 5441 | // the MIR node corresponds to "cast operands to unsigned and |
| 5442 | // divide" operation. In this case, is the dividend x or is it |
| 5443 | // x>>>0? In order to resolve such ambiguities, we disallow |
| 5444 | // the usage of this method for unsigned division. |
| 5445 | MOZ_ASSERT(!unsigned_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!unsigned_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!unsigned_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!unsigned_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!unsigned_" ")"); do { *((volatile int*)__null) = 5445; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5446 | return canBeNegativeDividend_; |
| 5447 | } |
| 5448 | |
| 5449 | bool isUnsigned() const { return unsigned_; } |
| 5450 | |
| 5451 | bool trapOnError() const { return trapOnError_; } |
| 5452 | wasm::BytecodeOffset bytecodeOffset() const { |
| 5453 | MOZ_ASSERT(bytecodeOffset_.isValid())do { static_assert( mozilla::detail::AssertionConditionType< decltype(bytecodeOffset_.isValid())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(bytecodeOffset_.isValid()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("bytecodeOffset_.isValid()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5453); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bytecodeOffset_.isValid()" ")"); do { *((volatile int*)__null) = 5453; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5454 | return bytecodeOffset_; |
| 5455 | } |
| 5456 | |
| 5457 | ALLOW_CLONE(MWasmBuiltinDivI64)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmBuiltinDivI64 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5458 | }; |
| 5459 | |
| 5460 | class MMod : public MBinaryArithInstruction { |
| 5461 | bool unsigned_; // If false, signedness will be derived from operands |
| 5462 | bool canBeNegativeDividend_; |
| 5463 | bool canBePowerOfTwoDivisor_; |
| 5464 | bool canBeDivideByZero_; |
| 5465 | bool trapOnError_; |
| 5466 | wasm::BytecodeOffset bytecodeOffset_; |
| 5467 | |
| 5468 | MMod(MDefinition* left, MDefinition* right, MIRType type) |
| 5469 | : MBinaryArithInstruction(classOpcode, left, right, type), |
| 5470 | unsigned_(false), |
| 5471 | canBeNegativeDividend_(true), |
| 5472 | canBePowerOfTwoDivisor_(true), |
| 5473 | canBeDivideByZero_(true), |
| 5474 | trapOnError_(false) {} |
| 5475 | |
| 5476 | public: |
| 5477 | INSTRUCTION_HEADER(Mod) |
| 5478 | |
| 5479 | static MMod* New(TempAllocator& alloc, MDefinition* left, MDefinition* right, |
| 5480 | MIRType type) { |
| 5481 | return new (alloc) MMod(left, right, type); |
| 5482 | } |
| 5483 | static MMod* New( |
| 5484 | TempAllocator& alloc, MDefinition* left, MDefinition* right, MIRType type, |
| 5485 | bool unsignd, bool trapOnError = false, |
| 5486 | wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset()) { |
| 5487 | auto* mod = new (alloc) MMod(left, right, type); |
| 5488 | mod->unsigned_ = unsignd; |
| 5489 | mod->trapOnError_ = trapOnError; |
| 5490 | mod->bytecodeOffset_ = bytecodeOffset; |
| 5491 | if (trapOnError) { |
| 5492 | mod->setGuard(); // not removable because of possible side-effects. |
| 5493 | mod->setNotMovable(); |
| 5494 | } |
| 5495 | if (type == MIRType::Int32) { |
| 5496 | mod->setTruncateKind(TruncateKind::Truncate); |
| 5497 | } |
| 5498 | return mod; |
| 5499 | } |
| 5500 | |
| 5501 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 5502 | |
| 5503 | double getIdentity() override { MOZ_CRASH("not used")do { do { } while (false); MOZ_ReportCrash("" "not used", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5503); AnnotateMozCrashReason("MOZ_CRASH(" "not used" ")"); do { *((volatile int*)__null) = 5503; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } |
| 5504 | |
| 5505 | bool canBeNegativeDividend() const { |
| 5506 | MOZ_ASSERT(type() == MIRType::Int32 || type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Int32 || type() == MIRType::Int64 )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type() == MIRType::Int32 || type() == MIRType::Int64 ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "type() == MIRType::Int32 || type() == MIRType::Int64", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5506); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32 || type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 5506; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5507 | MOZ_ASSERT(!unsigned_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!unsigned_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!unsigned_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!unsigned_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5507); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!unsigned_" ")"); do { *((volatile int*)__null) = 5507; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5508 | return canBeNegativeDividend_; |
| 5509 | } |
| 5510 | |
| 5511 | bool canBeDivideByZero() const { |
| 5512 | MOZ_ASSERT(type() == MIRType::Int32 || type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Int32 || type() == MIRType::Int64 )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type() == MIRType::Int32 || type() == MIRType::Int64 ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "type() == MIRType::Int32 || type() == MIRType::Int64", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5512); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32 || type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 5512; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5513 | return canBeDivideByZero_; |
| 5514 | } |
| 5515 | |
| 5516 | bool canBePowerOfTwoDivisor() const { |
| 5517 | MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5517); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 5517; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5518 | return canBePowerOfTwoDivisor_; |
| 5519 | } |
| 5520 | |
| 5521 | void analyzeEdgeCasesForward() override; |
| 5522 | |
| 5523 | bool isUnsigned() const { return unsigned_; } |
| 5524 | |
| 5525 | bool trapOnError() const { return trapOnError_; } |
| 5526 | wasm::BytecodeOffset bytecodeOffset() const { |
| 5527 | MOZ_ASSERT(bytecodeOffset_.isValid())do { static_assert( mozilla::detail::AssertionConditionType< decltype(bytecodeOffset_.isValid())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(bytecodeOffset_.isValid()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("bytecodeOffset_.isValid()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5527); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bytecodeOffset_.isValid()" ")"); do { *((volatile int*)__null) = 5527; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5528 | return bytecodeOffset_; |
| 5529 | } |
| 5530 | |
| 5531 | [[nodiscard]] bool writeRecoverData( |
| 5532 | CompactBufferWriter& writer) const override; |
| 5533 | bool canRecoverOnBailout() const override { return true; } |
| 5534 | |
| 5535 | bool fallible() const; |
| 5536 | |
| 5537 | void computeRange(TempAllocator& alloc) override; |
| 5538 | bool canTruncate() const override; |
| 5539 | void truncate(TruncateKind kind) override; |
| 5540 | void collectRangeInfoPreTrunc() override; |
| 5541 | TruncateKind operandTruncateKind(size_t index) const override; |
| 5542 | |
| 5543 | bool congruentTo(const MDefinition* ins) const override { |
| 5544 | return MBinaryArithInstruction::congruentTo(ins) && |
| 5545 | unsigned_ == ins->toMod()->isUnsigned(); |
| 5546 | } |
| 5547 | |
| 5548 | bool possiblyCalls() const override { return type() == MIRType::Double; } |
| 5549 | |
| 5550 | ALLOW_CLONE(MMod)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MMod (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5551 | }; |
| 5552 | |
| 5553 | class MWasmBuiltinModD : public MAryInstruction<3>, public ArithPolicy::Data { |
| 5554 | wasm::BytecodeOffset bytecodeOffset_; |
| 5555 | |
| 5556 | MWasmBuiltinModD(MDefinition* left, MDefinition* right, MDefinition* instance, |
| 5557 | MIRType type) |
| 5558 | : MAryInstruction(classOpcode) { |
| 5559 | initOperand(0, left); |
| 5560 | initOperand(1, right); |
| 5561 | initOperand(2, instance); |
| 5562 | |
| 5563 | setResultType(type); |
| 5564 | setMovable(); |
| 5565 | } |
| 5566 | |
| 5567 | public: |
| 5568 | INSTRUCTION_HEADER(WasmBuiltinModD) |
| 5569 | NAMED_OPERANDS((0, lhs), (1, rhs), (2, instance))MDefinition* lhs() const { return getOperand(0); } MDefinition * rhs() const { return getOperand(1); } MDefinition* instance () const { return getOperand(2); } |
| 5570 | |
| 5571 | static MWasmBuiltinModD* New( |
| 5572 | TempAllocator& alloc, MDefinition* left, MDefinition* right, |
| 5573 | MDefinition* instance, MIRType type, |
| 5574 | wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset()) { |
| 5575 | auto* wasmBuiltinModD = |
| 5576 | new (alloc) MWasmBuiltinModD(left, right, instance, type); |
| 5577 | wasmBuiltinModD->bytecodeOffset_ = bytecodeOffset; |
| 5578 | return wasmBuiltinModD; |
| 5579 | } |
| 5580 | |
| 5581 | wasm::BytecodeOffset bytecodeOffset() const { |
| 5582 | MOZ_ASSERT(bytecodeOffset_.isValid())do { static_assert( mozilla::detail::AssertionConditionType< decltype(bytecodeOffset_.isValid())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(bytecodeOffset_.isValid()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("bytecodeOffset_.isValid()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5582); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bytecodeOffset_.isValid()" ")"); do { *((volatile int*)__null) = 5582; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5583 | return bytecodeOffset_; |
| 5584 | } |
| 5585 | |
| 5586 | ALLOW_CLONE(MWasmBuiltinModD)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmBuiltinModD (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5587 | }; |
| 5588 | |
| 5589 | class MWasmBuiltinModI64 : public MAryInstruction<3>, public ArithPolicy::Data { |
| 5590 | bool unsigned_; // If false, signedness will be derived from operands |
| 5591 | bool canBeNegativeDividend_; |
| 5592 | bool canBeDivideByZero_; |
| 5593 | bool trapOnError_; |
| 5594 | wasm::BytecodeOffset bytecodeOffset_; |
| 5595 | |
| 5596 | MWasmBuiltinModI64(MDefinition* left, MDefinition* right, |
| 5597 | MDefinition* instance) |
| 5598 | : MAryInstruction(classOpcode), |
| 5599 | unsigned_(false), |
| 5600 | canBeNegativeDividend_(true), |
| 5601 | canBeDivideByZero_(true), |
| 5602 | trapOnError_(false) { |
| 5603 | initOperand(0, left); |
| 5604 | initOperand(1, right); |
| 5605 | initOperand(2, instance); |
| 5606 | |
| 5607 | setResultType(MIRType::Int64); |
| 5608 | setMovable(); |
| 5609 | } |
| 5610 | |
| 5611 | public: |
| 5612 | INSTRUCTION_HEADER(WasmBuiltinModI64) |
| 5613 | |
| 5614 | NAMED_OPERANDS((0, lhs), (1, rhs), (2, instance))MDefinition* lhs() const { return getOperand(0); } MDefinition * rhs() const { return getOperand(1); } MDefinition* instance () const { return getOperand(2); } |
| 5615 | |
| 5616 | static MWasmBuiltinModI64* New( |
| 5617 | TempAllocator& alloc, MDefinition* left, MDefinition* right, |
| 5618 | MDefinition* instance, bool unsignd, bool trapOnError = false, |
| 5619 | wasm::BytecodeOffset bytecodeOffset = wasm::BytecodeOffset()) { |
| 5620 | auto* mod = new (alloc) MWasmBuiltinModI64(left, right, instance); |
| 5621 | mod->unsigned_ = unsignd; |
| 5622 | mod->trapOnError_ = trapOnError; |
| 5623 | mod->bytecodeOffset_ = bytecodeOffset; |
| 5624 | if (trapOnError) { |
| 5625 | mod->setGuard(); // not removable because of possible side-effects. |
| 5626 | mod->setNotMovable(); |
| 5627 | } |
| 5628 | return mod; |
| 5629 | } |
| 5630 | |
| 5631 | bool canBeNegativeDividend() const { |
| 5632 | MOZ_ASSERT(!unsigned_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!unsigned_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!unsigned_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!unsigned_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5632); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!unsigned_" ")"); do { *((volatile int*)__null) = 5632; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5633 | return canBeNegativeDividend_; |
| 5634 | } |
| 5635 | |
| 5636 | bool canBeDivideByZero() const { return canBeDivideByZero_; } |
| 5637 | |
| 5638 | bool isUnsigned() const { return unsigned_; } |
| 5639 | |
| 5640 | bool trapOnError() const { return trapOnError_; } |
| 5641 | wasm::BytecodeOffset bytecodeOffset() const { |
| 5642 | MOZ_ASSERT(bytecodeOffset_.isValid())do { static_assert( mozilla::detail::AssertionConditionType< decltype(bytecodeOffset_.isValid())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(bytecodeOffset_.isValid()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("bytecodeOffset_.isValid()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5642); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bytecodeOffset_.isValid()" ")"); do { *((volatile int*)__null) = 5642; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5643 | return bytecodeOffset_; |
| 5644 | } |
| 5645 | |
| 5646 | ALLOW_CLONE(MWasmBuiltinModI64)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmBuiltinModI64 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5647 | }; |
| 5648 | |
| 5649 | class MBigIntBinaryArithInstruction : public MBinaryInstruction, |
| 5650 | public BigIntArithPolicy::Data { |
| 5651 | protected: |
| 5652 | MBigIntBinaryArithInstruction(Opcode op, MDefinition* left, |
| 5653 | MDefinition* right) |
| 5654 | : MBinaryInstruction(op, left, right) { |
| 5655 | setResultType(MIRType::BigInt); |
| 5656 | setMovable(); |
| 5657 | } |
| 5658 | |
| 5659 | public: |
| 5660 | bool congruentTo(const MDefinition* ins) const override { |
| 5661 | return binaryCongruentTo(ins); |
| 5662 | } |
| 5663 | |
| 5664 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 5665 | }; |
| 5666 | |
| 5667 | class MBigIntAdd : public MBigIntBinaryArithInstruction { |
| 5668 | MBigIntAdd(MDefinition* left, MDefinition* right) |
| 5669 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5670 | setCommutative(); |
| 5671 | |
| 5672 | // Don't guard this instruction even though adding two BigInts can throw |
| 5673 | // JSMSG_BIGINT_TOO_LARGE. This matches the behavior when adding too large |
| 5674 | // strings in MConcat. |
| 5675 | } |
| 5676 | |
| 5677 | public: |
| 5678 | INSTRUCTION_HEADER(BigIntAdd) |
| 5679 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5680 | |
| 5681 | [[nodiscard]] bool writeRecoverData( |
| 5682 | CompactBufferWriter& writer) const override; |
| 5683 | bool canRecoverOnBailout() const override { return true; } |
| 5684 | |
| 5685 | ALLOW_CLONE(MBigIntAdd)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntAdd (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5686 | }; |
| 5687 | |
| 5688 | class MBigIntSub : public MBigIntBinaryArithInstruction { |
| 5689 | MBigIntSub(MDefinition* left, MDefinition* right) |
| 5690 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5691 | // See MBigIntAdd for why we don't guard this instruction. |
| 5692 | } |
| 5693 | |
| 5694 | public: |
| 5695 | INSTRUCTION_HEADER(BigIntSub) |
| 5696 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5697 | |
| 5698 | [[nodiscard]] bool writeRecoverData( |
| 5699 | CompactBufferWriter& writer) const override; |
| 5700 | bool canRecoverOnBailout() const override { return true; } |
| 5701 | |
| 5702 | ALLOW_CLONE(MBigIntSub)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntSub (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5703 | }; |
| 5704 | |
| 5705 | class MBigIntMul : public MBigIntBinaryArithInstruction { |
| 5706 | MBigIntMul(MDefinition* left, MDefinition* right) |
| 5707 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5708 | setCommutative(); |
| 5709 | |
| 5710 | // See MBigIntAdd for why we don't guard this instruction. |
| 5711 | } |
| 5712 | |
| 5713 | public: |
| 5714 | INSTRUCTION_HEADER(BigIntMul) |
| 5715 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5716 | |
| 5717 | [[nodiscard]] bool writeRecoverData( |
| 5718 | CompactBufferWriter& writer) const override; |
| 5719 | bool canRecoverOnBailout() const override { return true; } |
| 5720 | |
| 5721 | ALLOW_CLONE(MBigIntMul)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntMul (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5722 | }; |
| 5723 | |
| 5724 | class MBigIntDiv : public MBigIntBinaryArithInstruction { |
| 5725 | bool canBeDivideByZero_; |
| 5726 | |
| 5727 | MBigIntDiv(MDefinition* left, MDefinition* right) |
| 5728 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5729 | MOZ_ASSERT(right->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5729); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5729; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5730 | canBeDivideByZero_ = |
| 5731 | !right->isConstant() || right->toConstant()->toBigInt()->isZero(); |
| 5732 | |
| 5733 | // Throws when the divisor is zero. |
| 5734 | if (canBeDivideByZero_) { |
| 5735 | setGuard(); |
| 5736 | setNotMovable(); |
| 5737 | } |
| 5738 | } |
| 5739 | |
| 5740 | public: |
| 5741 | INSTRUCTION_HEADER(BigIntDiv) |
| 5742 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5743 | |
| 5744 | bool canBeDivideByZero() const { return canBeDivideByZero_; } |
| 5745 | |
| 5746 | AliasSet getAliasSet() const override { |
| 5747 | if (canBeDivideByZero()) { |
| 5748 | return AliasSet::Store(AliasSet::ExceptionState); |
| 5749 | } |
| 5750 | return AliasSet::None(); |
| 5751 | } |
| 5752 | |
| 5753 | [[nodiscard]] bool writeRecoverData( |
| 5754 | CompactBufferWriter& writer) const override; |
| 5755 | bool canRecoverOnBailout() const override { return !canBeDivideByZero(); } |
| 5756 | |
| 5757 | ALLOW_CLONE(MBigIntDiv)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntDiv (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5758 | }; |
| 5759 | |
| 5760 | class MBigIntMod : public MBigIntBinaryArithInstruction { |
| 5761 | bool canBeDivideByZero_; |
| 5762 | |
| 5763 | MBigIntMod(MDefinition* left, MDefinition* right) |
| 5764 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5765 | MOZ_ASSERT(right->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5765); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5765; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5766 | canBeDivideByZero_ = |
| 5767 | !right->isConstant() || right->toConstant()->toBigInt()->isZero(); |
| 5768 | |
| 5769 | // Throws when the divisor is zero. |
| 5770 | if (canBeDivideByZero_) { |
| 5771 | setGuard(); |
| 5772 | setNotMovable(); |
| 5773 | } |
| 5774 | } |
| 5775 | |
| 5776 | public: |
| 5777 | INSTRUCTION_HEADER(BigIntMod) |
| 5778 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5779 | |
| 5780 | bool canBeDivideByZero() const { return canBeDivideByZero_; } |
| 5781 | |
| 5782 | AliasSet getAliasSet() const override { |
| 5783 | if (canBeDivideByZero()) { |
| 5784 | return AliasSet::Store(AliasSet::ExceptionState); |
| 5785 | } |
| 5786 | return AliasSet::None(); |
| 5787 | } |
| 5788 | |
| 5789 | [[nodiscard]] bool writeRecoverData( |
| 5790 | CompactBufferWriter& writer) const override; |
| 5791 | bool canRecoverOnBailout() const override { return !canBeDivideByZero(); } |
| 5792 | |
| 5793 | ALLOW_CLONE(MBigIntMod)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntMod (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5794 | }; |
| 5795 | |
| 5796 | class MBigIntPow : public MBigIntBinaryArithInstruction { |
| 5797 | bool canBeNegativeExponent_; |
| 5798 | |
| 5799 | MBigIntPow(MDefinition* left, MDefinition* right) |
| 5800 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5801 | MOZ_ASSERT(right->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 5801); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5801; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5802 | canBeNegativeExponent_ = |
| 5803 | !right->isConstant() || right->toConstant()->toBigInt()->isNegative(); |
| 5804 | |
| 5805 | // Throws when the exponent is negative. |
| 5806 | if (canBeNegativeExponent_) { |
| 5807 | setGuard(); |
| 5808 | setNotMovable(); |
| 5809 | } |
| 5810 | } |
| 5811 | |
| 5812 | public: |
| 5813 | INSTRUCTION_HEADER(BigIntPow) |
| 5814 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5815 | |
| 5816 | bool canBeNegativeExponent() const { return canBeNegativeExponent_; } |
| 5817 | |
| 5818 | AliasSet getAliasSet() const override { |
| 5819 | if (canBeNegativeExponent()) { |
| 5820 | return AliasSet::Store(AliasSet::ExceptionState); |
| 5821 | } |
| 5822 | return AliasSet::None(); |
| 5823 | } |
| 5824 | |
| 5825 | [[nodiscard]] bool writeRecoverData( |
| 5826 | CompactBufferWriter& writer) const override; |
| 5827 | bool canRecoverOnBailout() const override { return !canBeNegativeExponent(); } |
| 5828 | |
| 5829 | ALLOW_CLONE(MBigIntPow)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntPow (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5830 | }; |
| 5831 | |
| 5832 | class MBigIntBitAnd : public MBigIntBinaryArithInstruction { |
| 5833 | MBigIntBitAnd(MDefinition* left, MDefinition* right) |
| 5834 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5835 | setCommutative(); |
| 5836 | |
| 5837 | // We don't need to guard this instruction because it can only fail on OOM. |
| 5838 | } |
| 5839 | |
| 5840 | public: |
| 5841 | INSTRUCTION_HEADER(BigIntBitAnd) |
| 5842 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5843 | |
| 5844 | [[nodiscard]] bool writeRecoverData( |
| 5845 | CompactBufferWriter& writer) const override; |
| 5846 | bool canRecoverOnBailout() const override { return true; } |
| 5847 | |
| 5848 | ALLOW_CLONE(MBigIntBitAnd)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntBitAnd (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5849 | }; |
| 5850 | |
| 5851 | class MBigIntBitOr : public MBigIntBinaryArithInstruction { |
| 5852 | MBigIntBitOr(MDefinition* left, MDefinition* right) |
| 5853 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5854 | setCommutative(); |
| 5855 | |
| 5856 | // We don't need to guard this instruction because it can only fail on OOM. |
| 5857 | } |
| 5858 | |
| 5859 | public: |
| 5860 | INSTRUCTION_HEADER(BigIntBitOr) |
| 5861 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5862 | |
| 5863 | [[nodiscard]] bool writeRecoverData( |
| 5864 | CompactBufferWriter& writer) const override; |
| 5865 | bool canRecoverOnBailout() const override { return true; } |
| 5866 | |
| 5867 | ALLOW_CLONE(MBigIntBitOr)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntBitOr (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5868 | }; |
| 5869 | |
| 5870 | class MBigIntBitXor : public MBigIntBinaryArithInstruction { |
| 5871 | MBigIntBitXor(MDefinition* left, MDefinition* right) |
| 5872 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5873 | setCommutative(); |
| 5874 | |
| 5875 | // We don't need to guard this instruction because it can only fail on OOM. |
| 5876 | } |
| 5877 | |
| 5878 | public: |
| 5879 | INSTRUCTION_HEADER(BigIntBitXor) |
| 5880 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5881 | |
| 5882 | [[nodiscard]] bool writeRecoverData( |
| 5883 | CompactBufferWriter& writer) const override; |
| 5884 | bool canRecoverOnBailout() const override { return true; } |
| 5885 | |
| 5886 | ALLOW_CLONE(MBigIntBitXor)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntBitXor (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5887 | }; |
| 5888 | |
| 5889 | class MBigIntLsh : public MBigIntBinaryArithInstruction { |
| 5890 | MBigIntLsh(MDefinition* left, MDefinition* right) |
| 5891 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5892 | // See MBigIntAdd for why we don't guard this instruction. |
| 5893 | } |
| 5894 | |
| 5895 | public: |
| 5896 | INSTRUCTION_HEADER(BigIntLsh) |
| 5897 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5898 | |
| 5899 | [[nodiscard]] bool writeRecoverData( |
| 5900 | CompactBufferWriter& writer) const override; |
| 5901 | bool canRecoverOnBailout() const override { return true; } |
| 5902 | |
| 5903 | ALLOW_CLONE(MBigIntLsh)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntLsh (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5904 | }; |
| 5905 | |
| 5906 | class MBigIntRsh : public MBigIntBinaryArithInstruction { |
| 5907 | MBigIntRsh(MDefinition* left, MDefinition* right) |
| 5908 | : MBigIntBinaryArithInstruction(classOpcode, left, right) { |
| 5909 | // See MBigIntAdd for why we don't guard this instruction. |
| 5910 | } |
| 5911 | |
| 5912 | public: |
| 5913 | INSTRUCTION_HEADER(BigIntRsh) |
| 5914 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5915 | |
| 5916 | [[nodiscard]] bool writeRecoverData( |
| 5917 | CompactBufferWriter& writer) const override; |
| 5918 | bool canRecoverOnBailout() const override { return true; } |
| 5919 | |
| 5920 | ALLOW_CLONE(MBigIntRsh)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntRsh (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5921 | }; |
| 5922 | |
| 5923 | class MBigIntUnaryArithInstruction : public MUnaryInstruction, |
| 5924 | public BigIntArithPolicy::Data { |
| 5925 | protected: |
| 5926 | MBigIntUnaryArithInstruction(Opcode op, MDefinition* input) |
| 5927 | : MUnaryInstruction(op, input) { |
| 5928 | setResultType(MIRType::BigInt); |
| 5929 | setMovable(); |
| 5930 | } |
| 5931 | |
| 5932 | public: |
| 5933 | bool congruentTo(const MDefinition* ins) const override { |
| 5934 | return congruentIfOperandsEqual(ins); |
| 5935 | } |
| 5936 | |
| 5937 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 5938 | }; |
| 5939 | |
| 5940 | class MBigIntIncrement : public MBigIntUnaryArithInstruction { |
| 5941 | explicit MBigIntIncrement(MDefinition* input) |
| 5942 | : MBigIntUnaryArithInstruction(classOpcode, input) { |
| 5943 | // See MBigIntAdd for why we don't guard this instruction. |
| 5944 | } |
| 5945 | |
| 5946 | public: |
| 5947 | INSTRUCTION_HEADER(BigIntIncrement) |
| 5948 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5949 | |
| 5950 | [[nodiscard]] bool writeRecoverData( |
| 5951 | CompactBufferWriter& writer) const override; |
| 5952 | bool canRecoverOnBailout() const override { return true; } |
| 5953 | |
| 5954 | ALLOW_CLONE(MBigIntIncrement)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntIncrement (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5955 | }; |
| 5956 | |
| 5957 | class MBigIntDecrement : public MBigIntUnaryArithInstruction { |
| 5958 | explicit MBigIntDecrement(MDefinition* input) |
| 5959 | : MBigIntUnaryArithInstruction(classOpcode, input) { |
| 5960 | // See MBigIntAdd for why we don't guard this instruction. |
| 5961 | } |
| 5962 | |
| 5963 | public: |
| 5964 | INSTRUCTION_HEADER(BigIntDecrement) |
| 5965 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5966 | |
| 5967 | [[nodiscard]] bool writeRecoverData( |
| 5968 | CompactBufferWriter& writer) const override; |
| 5969 | bool canRecoverOnBailout() const override { return true; } |
| 5970 | |
| 5971 | ALLOW_CLONE(MBigIntDecrement)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntDecrement (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5972 | }; |
| 5973 | |
| 5974 | class MBigIntNegate : public MBigIntUnaryArithInstruction { |
| 5975 | explicit MBigIntNegate(MDefinition* input) |
| 5976 | : MBigIntUnaryArithInstruction(classOpcode, input) { |
| 5977 | // We don't need to guard this instruction because it can only fail on OOM. |
| 5978 | } |
| 5979 | |
| 5980 | public: |
| 5981 | INSTRUCTION_HEADER(BigIntNegate) |
| 5982 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 5983 | |
| 5984 | [[nodiscard]] bool writeRecoverData( |
| 5985 | CompactBufferWriter& writer) const override; |
| 5986 | bool canRecoverOnBailout() const override { return true; } |
| 5987 | |
| 5988 | ALLOW_CLONE(MBigIntNegate)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntNegate (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 5989 | }; |
| 5990 | |
| 5991 | class MBigIntBitNot : public MBigIntUnaryArithInstruction { |
| 5992 | explicit MBigIntBitNot(MDefinition* input) |
| 5993 | : MBigIntUnaryArithInstruction(classOpcode, input) { |
| 5994 | // See MBigIntAdd for why we don't guard this instruction. |
| 5995 | } |
| 5996 | |
| 5997 | public: |
| 5998 | INSTRUCTION_HEADER(BigIntBitNot) |
| 5999 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6000 | |
| 6001 | [[nodiscard]] bool writeRecoverData( |
| 6002 | CompactBufferWriter& writer) const override; |
| 6003 | bool canRecoverOnBailout() const override { return true; } |
| 6004 | |
| 6005 | ALLOW_CLONE(MBigIntBitNot)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBigIntBitNot (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 6006 | }; |
| 6007 | |
| 6008 | class MConcat : public MBinaryInstruction, |
| 6009 | public MixPolicy<ConvertToStringPolicy<0>, |
| 6010 | ConvertToStringPolicy<1>>::Data { |
| 6011 | MConcat(MDefinition* left, MDefinition* right) |
| 6012 | : MBinaryInstruction(classOpcode, left, right) { |
| 6013 | // At least one input should be definitely string |
| 6014 | MOZ_ASSERT(left->type() == MIRType::String ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::String || right->type () == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: String || right->type() == MIRType::String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("left->type() == MIRType::String || right->type() == MIRType::String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String || right->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 6015; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 6015 | right->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::String || right->type () == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: String || right->type() == MIRType::String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("left->type() == MIRType::String || right->type() == MIRType::String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String || right->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 6015; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6016 | |
| 6017 | setMovable(); |
| 6018 | setResultType(MIRType::String); |
| 6019 | } |
| 6020 | |
| 6021 | public: |
| 6022 | INSTRUCTION_HEADER(Concat) |
| 6023 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6024 | |
| 6025 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 6026 | bool congruentTo(const MDefinition* ins) const override { |
| 6027 | return congruentIfOperandsEqual(ins); |
| 6028 | } |
| 6029 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6030 | |
| 6031 | [[nodiscard]] bool writeRecoverData( |
| 6032 | CompactBufferWriter& writer) const override; |
| 6033 | bool canRecoverOnBailout() const override { return true; } |
| 6034 | |
| 6035 | ALLOW_CLONE(MConcat)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MConcat (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 6036 | }; |
| 6037 | |
| 6038 | class MStringConvertCase : public MUnaryInstruction, |
| 6039 | public StringPolicy<0>::Data { |
| 6040 | public: |
| 6041 | enum Mode { LowerCase, UpperCase }; |
| 6042 | |
| 6043 | private: |
| 6044 | Mode mode_; |
| 6045 | |
| 6046 | MStringConvertCase(MDefinition* string, Mode mode) |
| 6047 | : MUnaryInstruction(classOpcode, string), mode_(mode) { |
| 6048 | setResultType(MIRType::String); |
| 6049 | setMovable(); |
| 6050 | } |
| 6051 | |
| 6052 | public: |
| 6053 | INSTRUCTION_HEADER(StringConvertCase) |
| 6054 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6055 | NAMED_OPERANDS((0, string))MDefinition* string() const { return getOperand(0); } |
| 6056 | |
| 6057 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 6058 | bool congruentTo(const MDefinition* ins) const override { |
| 6059 | return congruentIfOperandsEqual(ins) && |
| 6060 | ins->toStringConvertCase()->mode() == mode(); |
| 6061 | } |
| 6062 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6063 | bool possiblyCalls() const override { return true; } |
| 6064 | Mode mode() const { return mode_; } |
| 6065 | }; |
| 6066 | |
| 6067 | class MCharCodeConvertCase : public MUnaryInstruction, |
| 6068 | public UnboxedInt32Policy<0>::Data { |
| 6069 | public: |
| 6070 | enum Mode { LowerCase, UpperCase }; |
| 6071 | |
| 6072 | private: |
| 6073 | Mode mode_; |
| 6074 | |
| 6075 | MCharCodeConvertCase(MDefinition* code, Mode mode) |
| 6076 | : MUnaryInstruction(classOpcode, code), mode_(mode) { |
| 6077 | setResultType(MIRType::String); |
| 6078 | setMovable(); |
| 6079 | } |
| 6080 | |
| 6081 | public: |
| 6082 | INSTRUCTION_HEADER(CharCodeConvertCase) |
| 6083 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6084 | NAMED_OPERANDS((0, code))MDefinition* code() const { return getOperand(0); } |
| 6085 | |
| 6086 | bool congruentTo(const MDefinition* ins) const override { |
| 6087 | return congruentIfOperandsEqual(ins) && |
| 6088 | ins->toCharCodeConvertCase()->mode() == mode(); |
| 6089 | } |
| 6090 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6091 | Mode mode() const { return mode_; } |
| 6092 | }; |
| 6093 | |
| 6094 | // This is a 3 state flag used by FlagPhiInputsAsImplicitlyUsed to record and |
| 6095 | // propagate the information about the consumers of a Phi instruction. This is |
| 6096 | // then used to set ImplicitlyUsed flags on the inputs of such Phi instructions. |
| 6097 | enum class PhiUsage : uint8_t { Unknown, Unused, Used }; |
| 6098 | |
| 6099 | using PhiVector = Vector<MPhi*, 4, JitAllocPolicy>; |
| 6100 | |
| 6101 | class MPhi final : public MDefinition, |
| 6102 | public InlineListNode<MPhi>, |
| 6103 | public NoTypePolicy::Data { |
| 6104 | using InputVector = js::Vector<MUse, 2, JitAllocPolicy>; |
| 6105 | InputVector inputs_; |
| 6106 | |
| 6107 | TruncateKind truncateKind_; |
| 6108 | bool triedToSpecialize_; |
| 6109 | bool isIterator_; |
| 6110 | bool canProduceFloat32_; |
| 6111 | bool canConsumeFloat32_; |
| 6112 | // Record the state of the data flow before any mutation made to the control |
| 6113 | // flow, such that removing branches is properly accounted for. |
| 6114 | PhiUsage usageAnalysis_; |
| 6115 | |
| 6116 | protected: |
| 6117 | MUse* getUseFor(size_t index) override { |
| 6118 | MOZ_ASSERT(index < numOperands())do { static_assert( mozilla::detail::AssertionConditionType< decltype(index < numOperands())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index < numOperands()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index < numOperands()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6118); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index < numOperands()" ")"); do { *((volatile int*)__null) = 6118; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6119 | return &inputs_[index]; |
| 6120 | } |
| 6121 | const MUse* getUseFor(size_t index) const override { return &inputs_[index]; } |
| 6122 | |
| 6123 | public: |
| 6124 | INSTRUCTION_HEADER_WITHOUT_TYPEPOLICY(Phi)static const Opcode classOpcode = Opcode::Phi; using MThisOpcode = MPhi; |
| 6125 | virtual const TypePolicy* typePolicy(); |
| 6126 | virtual MIRType typePolicySpecialization(); |
| 6127 | |
| 6128 | MPhi(TempAllocator& alloc, MIRType resultType) |
| 6129 | : MDefinition(classOpcode), |
| 6130 | inputs_(alloc), |
| 6131 | truncateKind_(TruncateKind::NoTruncate), |
| 6132 | triedToSpecialize_(false), |
| 6133 | isIterator_(false), |
| 6134 | canProduceFloat32_(false), |
| 6135 | canConsumeFloat32_(false), |
| 6136 | usageAnalysis_(PhiUsage::Unknown) { |
| 6137 | setResultType(resultType); |
| 6138 | } |
| 6139 | |
| 6140 | static MPhi* New(TempAllocator& alloc, MIRType resultType = MIRType::Value) { |
| 6141 | return new (alloc) MPhi(alloc, resultType); |
| 6142 | } |
| 6143 | static MPhi* New(TempAllocator::Fallible alloc, |
| 6144 | MIRType resultType = MIRType::Value) { |
| 6145 | return new (alloc) MPhi(alloc.alloc, resultType); |
| 6146 | } |
| 6147 | |
| 6148 | void removeOperand(size_t index); |
| 6149 | void removeAllOperands(); |
| 6150 | |
| 6151 | MDefinition* getOperand(size_t index) const override { |
| 6152 | return inputs_[index].producer(); |
| 6153 | } |
| 6154 | size_t numOperands() const override { return inputs_.length(); } |
| 6155 | size_t indexOf(const MUse* u) const final { |
| 6156 | MOZ_ASSERT(u >= &inputs_[0])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u >= &inputs_[0])>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(u >= &inputs_[0]))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("u >= &inputs_[0]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6156); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u >= &inputs_[0]" ")"); do { *((volatile int*)__null) = 6156; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6157 | MOZ_ASSERT(u <= &inputs_[numOperands() - 1])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u <= &inputs_[numOperands() - 1])>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(u <= &inputs_[numOperands() - 1]))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("u <= &inputs_[numOperands() - 1]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6157); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u <= &inputs_[numOperands() - 1]" ")"); do { *((volatile int*)__null) = 6157; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6158 | return u - &inputs_[0]; |
| 6159 | } |
| 6160 | void replaceOperand(size_t index, MDefinition* operand) final { |
| 6161 | inputs_[index].replaceProducer(operand); |
| 6162 | } |
| 6163 | bool triedToSpecialize() const { return triedToSpecialize_; } |
| 6164 | void specialize(MIRType type) { |
| 6165 | triedToSpecialize_ = true; |
| 6166 | setResultType(type); |
| 6167 | } |
| 6168 | |
| 6169 | #ifdef DEBUG1 |
| 6170 | // Assert that this is a phi in a loop header with a unique predecessor and |
| 6171 | // a unique backedge. |
| 6172 | void assertLoopPhi() const; |
| 6173 | #else |
| 6174 | void assertLoopPhi() const {} |
| 6175 | #endif |
| 6176 | |
| 6177 | // Assuming this phi is in a loop header with a unique loop entry, return |
| 6178 | // the phi operand along the loop entry. |
| 6179 | MDefinition* getLoopPredecessorOperand() const; |
| 6180 | |
| 6181 | // Assuming this phi is in a loop header with a unique loop entry, return |
| 6182 | // the phi operand along the loop backedge. |
| 6183 | MDefinition* getLoopBackedgeOperand() const; |
| 6184 | |
| 6185 | // Whether this phi's type already includes information for def. |
| 6186 | bool typeIncludes(MDefinition* def); |
| 6187 | |
| 6188 | // Mark all phis in |iterators|, and the phis they flow into, as having |
| 6189 | // implicit uses. |
| 6190 | [[nodiscard]] static bool markIteratorPhis(const PhiVector& iterators); |
| 6191 | |
| 6192 | // Initializes the operands vector to the given capacity, |
| 6193 | // permitting use of addInput() instead of addInputSlow(). |
| 6194 | [[nodiscard]] bool reserveLength(size_t length) { |
| 6195 | return inputs_.reserve(length); |
| 6196 | } |
| 6197 | |
| 6198 | // Use only if capacity has been reserved by reserveLength |
| 6199 | void addInput(MDefinition* ins) { |
| 6200 | MOZ_ASSERT_IF(type() != MIRType::Value, ins->type() == type())do { if (type() != MIRType::Value) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(ins->type() == type())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(ins->type() == type()))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("ins->type() == type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6200); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == type()" ")"); do { *((volatile int*)__null) = 6200; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
| 6201 | inputs_.infallibleEmplaceBack(ins, this); |
| 6202 | } |
| 6203 | |
| 6204 | // Appends a new input to the input vector. May perform reallocation. |
| 6205 | // Prefer reserveLength() and addInput() instead, where possible. |
| 6206 | [[nodiscard]] bool addInputSlow(MDefinition* ins) { |
| 6207 | MOZ_ASSERT_IF(type() != MIRType::Value, ins->type() == type())do { if (type() != MIRType::Value) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(ins->type() == type())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(ins->type() == type()))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("ins->type() == type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == type()" ")"); do { *((volatile int*)__null) = 6207; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
| 6208 | return inputs_.emplaceBack(ins, this); |
| 6209 | } |
| 6210 | |
| 6211 | // Appends a new input to the input vector. Infallible because |
| 6212 | // we know the inputs fits in the vector's inline storage. |
| 6213 | void addInlineInput(MDefinition* ins) { |
| 6214 | MOZ_ASSERT(inputs_.length() < InputVector::InlineLength)do { static_assert( mozilla::detail::AssertionConditionType< decltype(inputs_.length() < InputVector::InlineLength)> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(inputs_.length() < InputVector::InlineLength))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("inputs_.length() < InputVector::InlineLength" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputs_.length() < InputVector::InlineLength" ")"); do { *((volatile int*)__null) = 6214; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6215 | MOZ_ALWAYS_TRUE(addInputSlow(ins))do { if ((__builtin_expect(!!(addInputSlow(ins)), 1))) { } else { do { static_assert( mozilla::detail::AssertionConditionType <decltype(false)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("false" " (" "addInputSlow(ins)" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6215); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false" ") (" "addInputSlow(ins)" ")"); do { *((volatile int*)__null ) = 6215; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); } } while (false); |
| 6216 | } |
| 6217 | |
| 6218 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 6219 | MDefinition* foldsTernary(TempAllocator& alloc); |
| 6220 | |
| 6221 | bool congruentTo(const MDefinition* ins) const override; |
| 6222 | |
| 6223 | // Mark this phi-node as having replaced all uses of |other|, as during GVN. |
| 6224 | // For use when GVN eliminates phis which are not equivalent to one another. |
| 6225 | void updateForReplacement(MPhi* other); |
| 6226 | |
| 6227 | bool isIterator() const { return isIterator_; } |
| 6228 | void setIterator() { isIterator_ = true; } |
| 6229 | |
| 6230 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6231 | void computeRange(TempAllocator& alloc) override; |
| 6232 | |
| 6233 | MDefinition* operandIfRedundant(); |
| 6234 | |
| 6235 | bool canProduceFloat32() const override { return canProduceFloat32_; } |
| 6236 | |
| 6237 | void setCanProduceFloat32(bool can) { canProduceFloat32_ = can; } |
| 6238 | |
| 6239 | bool canConsumeFloat32(MUse* use) const override { |
| 6240 | return canConsumeFloat32_; |
| 6241 | } |
| 6242 | |
| 6243 | void setCanConsumeFloat32(bool can) { canConsumeFloat32_ = can; } |
| 6244 | |
| 6245 | TruncateKind operandTruncateKind(size_t index) const override; |
| 6246 | bool canTruncate() const override; |
| 6247 | void truncate(TruncateKind kind) override; |
| 6248 | |
| 6249 | PhiUsage getUsageAnalysis() const { return usageAnalysis_; } |
| 6250 | void setUsageAnalysis(PhiUsage pu) { |
| 6251 | MOZ_ASSERT(usageAnalysis_ == PhiUsage::Unknown)do { static_assert( mozilla::detail::AssertionConditionType< decltype(usageAnalysis_ == PhiUsage::Unknown)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(usageAnalysis_ == PhiUsage:: Unknown))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("usageAnalysis_ == PhiUsage::Unknown", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6251); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unknown" ")"); do { *((volatile int*)__null) = 6251; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6252 | usageAnalysis_ = pu; |
| 6253 | MOZ_ASSERT(usageAnalysis_ != PhiUsage::Unknown)do { static_assert( mozilla::detail::AssertionConditionType< decltype(usageAnalysis_ != PhiUsage::Unknown)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(usageAnalysis_ != PhiUsage:: Unknown))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("usageAnalysis_ != PhiUsage::Unknown", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6253); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ != PhiUsage::Unknown" ")"); do { *((volatile int*)__null) = 6253; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6254 | } |
| 6255 | }; |
| 6256 | |
| 6257 | // The goal of a Beta node is to split a def at a conditionally taken |
| 6258 | // branch, so that uses dominated by it have a different name. |
| 6259 | class MBeta : public MUnaryInstruction, public NoTypePolicy::Data { |
| 6260 | private: |
| 6261 | // This is the range induced by a comparison and branch in a preceding |
| 6262 | // block. Note that this does not reflect any range constraints from |
| 6263 | // the input value itself, so this value may differ from the range() |
| 6264 | // range after it is computed. |
| 6265 | const Range* comparison_; |
| 6266 | |
| 6267 | MBeta(MDefinition* val, const Range* comp) |
| 6268 | : MUnaryInstruction(classOpcode, val), comparison_(comp) { |
| 6269 | setResultType(val->type()); |
| 6270 | } |
| 6271 | |
| 6272 | public: |
| 6273 | INSTRUCTION_HEADER(Beta) |
| 6274 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6275 | |
| 6276 | #ifdef JS_JITSPEW1 |
| 6277 | void printOpcode(GenericPrinter& out) const override; |
| 6278 | #endif |
| 6279 | |
| 6280 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6281 | |
| 6282 | void computeRange(TempAllocator& alloc) override; |
| 6283 | }; |
| 6284 | |
| 6285 | // If input evaluates to false (i.e. it's NaN, 0 or -0), 0 is returned, else the |
| 6286 | // input is returned |
| 6287 | class MNaNToZero : public MUnaryInstruction, public DoublePolicy<0>::Data { |
| 6288 | bool operandIsNeverNaN_; |
| 6289 | bool operandIsNeverNegativeZero_; |
| 6290 | |
| 6291 | explicit MNaNToZero(MDefinition* input) |
| 6292 | : MUnaryInstruction(classOpcode, input), |
| 6293 | operandIsNeverNaN_(false), |
| 6294 | operandIsNeverNegativeZero_(false) { |
| 6295 | setResultType(MIRType::Double); |
| 6296 | setMovable(); |
| 6297 | } |
| 6298 | |
| 6299 | public: |
| 6300 | INSTRUCTION_HEADER(NaNToZero) |
| 6301 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6302 | |
| 6303 | bool operandIsNeverNaN() const { return operandIsNeverNaN_; } |
| 6304 | |
| 6305 | bool operandIsNeverNegativeZero() const { |
| 6306 | return operandIsNeverNegativeZero_; |
| 6307 | } |
| 6308 | |
| 6309 | void collectRangeInfoPreTrunc() override; |
| 6310 | |
| 6311 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6312 | |
| 6313 | void computeRange(TempAllocator& alloc) override; |
| 6314 | |
| 6315 | bool writeRecoverData(CompactBufferWriter& writer) const override; |
| 6316 | bool canRecoverOnBailout() const override { return true; } |
| 6317 | |
| 6318 | ALLOW_CLONE(MNaNToZero)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MNaNToZero (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 6319 | }; |
| 6320 | |
| 6321 | // MIR representation of a Value on the OSR BaselineFrame. |
| 6322 | // The Value is indexed off of OsrFrameReg. |
| 6323 | class MOsrValue : public MUnaryInstruction, public NoTypePolicy::Data { |
| 6324 | private: |
| 6325 | ptrdiff_t frameOffset_; |
| 6326 | |
| 6327 | MOsrValue(MOsrEntry* entry, ptrdiff_t frameOffset) |
| 6328 | : MUnaryInstruction(classOpcode, entry), frameOffset_(frameOffset) { |
| 6329 | setResultType(MIRType::Value); |
| 6330 | } |
| 6331 | |
| 6332 | public: |
| 6333 | INSTRUCTION_HEADER(OsrValue) |
| 6334 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6335 | |
| 6336 | ptrdiff_t frameOffset() const { return frameOffset_; } |
| 6337 | |
| 6338 | MOsrEntry* entry() { return getOperand(0)->toOsrEntry(); } |
| 6339 | |
| 6340 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6341 | }; |
| 6342 | |
| 6343 | // MIR representation of a JSObject scope chain pointer on the OSR |
| 6344 | // BaselineFrame. The pointer is indexed off of OsrFrameReg. |
| 6345 | class MOsrEnvironmentChain : public MUnaryInstruction, |
| 6346 | public NoTypePolicy::Data { |
| 6347 | private: |
| 6348 | explicit MOsrEnvironmentChain(MOsrEntry* entry) |
| 6349 | : MUnaryInstruction(classOpcode, entry) { |
| 6350 | setResultType(MIRType::Object); |
| 6351 | } |
| 6352 | |
| 6353 | public: |
| 6354 | INSTRUCTION_HEADER(OsrEnvironmentChain) |
| 6355 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6356 | |
| 6357 | MOsrEntry* entry() { return getOperand(0)->toOsrEntry(); } |
| 6358 | }; |
| 6359 | |
| 6360 | // MIR representation of a JSObject ArgumentsObject pointer on the OSR |
| 6361 | // BaselineFrame. The pointer is indexed off of OsrFrameReg. |
| 6362 | class MOsrArgumentsObject : public MUnaryInstruction, |
| 6363 | public NoTypePolicy::Data { |
| 6364 | private: |
| 6365 | explicit MOsrArgumentsObject(MOsrEntry* entry) |
| 6366 | : MUnaryInstruction(classOpcode, entry) { |
| 6367 | setResultType(MIRType::Object); |
| 6368 | } |
| 6369 | |
| 6370 | public: |
| 6371 | INSTRUCTION_HEADER(OsrArgumentsObject) |
| 6372 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6373 | |
| 6374 | MOsrEntry* entry() { return getOperand(0)->toOsrEntry(); } |
| 6375 | }; |
| 6376 | |
| 6377 | // MIR representation of the return value on the OSR BaselineFrame. |
| 6378 | // The Value is indexed off of OsrFrameReg. |
| 6379 | class MOsrReturnValue : public MUnaryInstruction, public NoTypePolicy::Data { |
| 6380 | private: |
| 6381 | explicit MOsrReturnValue(MOsrEntry* entry) |
| 6382 | : MUnaryInstruction(classOpcode, entry) { |
| 6383 | setResultType(MIRType::Value); |
| 6384 | } |
| 6385 | |
| 6386 | public: |
| 6387 | INSTRUCTION_HEADER(OsrReturnValue) |
| 6388 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6389 | |
| 6390 | MOsrEntry* entry() { return getOperand(0)->toOsrEntry(); } |
| 6391 | }; |
| 6392 | |
| 6393 | class MBinaryCache : public MBinaryInstruction, |
| 6394 | public MixPolicy<BoxPolicy<0>, BoxPolicy<1>>::Data { |
| 6395 | explicit MBinaryCache(MDefinition* left, MDefinition* right, MIRType resType) |
| 6396 | : MBinaryInstruction(classOpcode, left, right) { |
| 6397 | setResultType(resType); |
| 6398 | } |
| 6399 | |
| 6400 | public: |
| 6401 | INSTRUCTION_HEADER(BinaryCache) |
| 6402 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6403 | }; |
| 6404 | |
| 6405 | // Check whether we need to fire the interrupt handler (in wasm code). |
| 6406 | class MWasmInterruptCheck : public MUnaryInstruction, |
| 6407 | public NoTypePolicy::Data { |
| 6408 | wasm::BytecodeOffset bytecodeOffset_; |
| 6409 | |
| 6410 | MWasmInterruptCheck(MDefinition* instance, |
| 6411 | wasm::BytecodeOffset bytecodeOffset) |
| 6412 | : MUnaryInstruction(classOpcode, instance), |
| 6413 | bytecodeOffset_(bytecodeOffset) { |
| 6414 | setGuard(); |
| 6415 | } |
| 6416 | |
| 6417 | public: |
| 6418 | INSTRUCTION_HEADER(WasmInterruptCheck) |
| 6419 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6420 | NAMED_OPERANDS((0, instance))MDefinition* instance() const { return getOperand(0); } |
| 6421 | |
| 6422 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6423 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 6424 | }; |
| 6425 | |
| 6426 | // Directly jumps to the indicated trap, leaving Wasm code and reporting a |
| 6427 | // runtime error. |
| 6428 | |
| 6429 | class MWasmTrap : public MAryControlInstruction<0, 0>, |
| 6430 | public NoTypePolicy::Data { |
| 6431 | wasm::Trap trap_; |
| 6432 | wasm::BytecodeOffset bytecodeOffset_; |
| 6433 | |
| 6434 | explicit MWasmTrap(wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset) |
| 6435 | : MAryControlInstruction(classOpcode), |
| 6436 | trap_(trap), |
| 6437 | bytecodeOffset_(bytecodeOffset) {} |
| 6438 | |
| 6439 | public: |
| 6440 | INSTRUCTION_HEADER(WasmTrap) |
| 6441 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6442 | |
| 6443 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6444 | |
| 6445 | wasm::Trap trap() const { return trap_; } |
| 6446 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 6447 | }; |
| 6448 | |
| 6449 | // Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving |
| 6450 | // it to baseline to throw at the correct pc. |
| 6451 | class MLexicalCheck : public MUnaryInstruction, public BoxPolicy<0>::Data { |
| 6452 | explicit MLexicalCheck(MDefinition* input) |
| 6453 | : MUnaryInstruction(classOpcode, input) { |
| 6454 | setResultType(MIRType::Value); |
| 6455 | setMovable(); |
| 6456 | setGuard(); |
| 6457 | |
| 6458 | // If this instruction bails out, we will set a flag to prevent |
| 6459 | // lexical checks in this script from being moved. |
| 6460 | setBailoutKind(BailoutKind::UninitializedLexical); |
| 6461 | } |
| 6462 | |
| 6463 | public: |
| 6464 | INSTRUCTION_HEADER(LexicalCheck) |
| 6465 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6466 | |
| 6467 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6468 | |
| 6469 | bool congruentTo(const MDefinition* ins) const override { |
| 6470 | return congruentIfOperandsEqual(ins); |
| 6471 | } |
| 6472 | }; |
| 6473 | |
| 6474 | // Unconditionally throw a known error number. |
| 6475 | class MThrowMsg : public MNullaryInstruction { |
| 6476 | const ThrowMsgKind throwMsgKind_; |
| 6477 | |
| 6478 | explicit MThrowMsg(ThrowMsgKind throwMsgKind) |
| 6479 | : MNullaryInstruction(classOpcode), throwMsgKind_(throwMsgKind) { |
| 6480 | setGuard(); |
| 6481 | setResultType(MIRType::None); |
| 6482 | } |
| 6483 | |
| 6484 | public: |
| 6485 | INSTRUCTION_HEADER(ThrowMsg) |
| 6486 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6487 | |
| 6488 | ThrowMsgKind throwMsgKind() const { return throwMsgKind_; } |
| 6489 | |
| 6490 | AliasSet getAliasSet() const override { |
| 6491 | return AliasSet::Store(AliasSet::ExceptionState); |
| 6492 | } |
| 6493 | }; |
| 6494 | |
| 6495 | class MGetFirstDollarIndex : public MUnaryInstruction, |
| 6496 | public StringPolicy<0>::Data { |
| 6497 | explicit MGetFirstDollarIndex(MDefinition* str) |
| 6498 | : MUnaryInstruction(classOpcode, str) { |
| 6499 | setResultType(MIRType::Int32); |
| 6500 | |
| 6501 | // Codegen assumes string length > 0. Don't allow LICM to move this |
| 6502 | // before the .length > 1 check in RegExpReplace in RegExp.js. |
| 6503 | MOZ_ASSERT(!isMovable())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!isMovable())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!isMovable()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!isMovable()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6503); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isMovable()" ")"); do { *((volatile int*)__null) = 6503; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6504 | } |
| 6505 | |
| 6506 | public: |
| 6507 | INSTRUCTION_HEADER(GetFirstDollarIndex) |
| 6508 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6509 | NAMED_OPERANDS((0, str))MDefinition* str() const { return getOperand(0); } |
| 6510 | |
| 6511 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6512 | |
| 6513 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 6514 | }; |
| 6515 | |
| 6516 | class MStringReplace : public MTernaryInstruction, |
| 6517 | public MixPolicy<StringPolicy<0>, StringPolicy<1>, |
| 6518 | StringPolicy<2>>::Data { |
| 6519 | private: |
| 6520 | bool isFlatReplacement_; |
| 6521 | |
| 6522 | MStringReplace(MDefinition* string, MDefinition* pattern, |
| 6523 | MDefinition* replacement) |
| 6524 | : MTernaryInstruction(classOpcode, string, pattern, replacement), |
| 6525 | isFlatReplacement_(false) { |
| 6526 | setMovable(); |
| 6527 | setResultType(MIRType::String); |
| 6528 | } |
| 6529 | |
| 6530 | public: |
| 6531 | INSTRUCTION_HEADER(StringReplace) |
| 6532 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6533 | NAMED_OPERANDS((0, string), (1, pattern), (2, replacement))MDefinition* string() const { return getOperand(0); } MDefinition * pattern() const { return getOperand(1); } MDefinition* replacement () const { return getOperand(2); } |
| 6534 | |
| 6535 | void setFlatReplacement() { |
| 6536 | MOZ_ASSERT(!isFlatReplacement_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!isFlatReplacement_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!isFlatReplacement_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!isFlatReplacement_" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6536); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isFlatReplacement_" ")"); do { *((volatile int*)__null) = 6536; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6537 | isFlatReplacement_ = true; |
| 6538 | } |
| 6539 | |
| 6540 | bool isFlatReplacement() const { return isFlatReplacement_; } |
| 6541 | |
| 6542 | bool congruentTo(const MDefinition* ins) const override { |
| 6543 | if (!ins->isStringReplace()) { |
| 6544 | return false; |
| 6545 | } |
| 6546 | if (isFlatReplacement_ != ins->toStringReplace()->isFlatReplacement()) { |
| 6547 | return false; |
| 6548 | } |
| 6549 | return congruentIfOperandsEqual(ins); |
| 6550 | } |
| 6551 | |
| 6552 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6553 | |
| 6554 | [[nodiscard]] bool writeRecoverData( |
| 6555 | CompactBufferWriter& writer) const override; |
| 6556 | bool canRecoverOnBailout() const override { |
| 6557 | if (isFlatReplacement_) { |
| 6558 | MOZ_ASSERT(!pattern()->isRegExp())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!pattern()->isRegExp())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!pattern()->isRegExp()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("!pattern()->isRegExp()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6558); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!pattern()->isRegExp()" ")"); do { *((volatile int*)__null) = 6558; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6559 | return true; |
| 6560 | } |
| 6561 | return false; |
| 6562 | } |
| 6563 | |
| 6564 | bool possiblyCalls() const override { return true; } |
| 6565 | }; |
| 6566 | |
| 6567 | class MLambda : public MBinaryInstruction, public SingleObjectPolicy::Data { |
| 6568 | MLambda(MDefinition* envChain, MConstant* cst) |
| 6569 | : MBinaryInstruction(classOpcode, envChain, cst) { |
| 6570 | setResultType(MIRType::Object); |
| 6571 | } |
| 6572 | |
| 6573 | public: |
| 6574 | INSTRUCTION_HEADER(Lambda) |
| 6575 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6576 | NAMED_OPERANDS((0, environmentChain))MDefinition* environmentChain() const { return getOperand(0); } |
| 6577 | |
| 6578 | MConstant* functionOperand() const { return getOperand(1)->toConstant(); } |
| 6579 | JSFunction* templateFunction() const { |
| 6580 | return &functionOperand()->toObject().as<JSFunction>(); |
| 6581 | } |
| 6582 | |
| 6583 | [[nodiscard]] bool writeRecoverData( |
| 6584 | CompactBufferWriter& writer) const override; |
| 6585 | bool canRecoverOnBailout() const override { return true; } |
| 6586 | }; |
| 6587 | |
| 6588 | class MFunctionWithProto : public MTernaryInstruction, |
| 6589 | public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, |
| 6590 | ObjectPolicy<2>>::Data { |
| 6591 | CompilerFunction fun_; |
| 6592 | |
| 6593 | MFunctionWithProto(MDefinition* envChain, MDefinition* prototype, |
| 6594 | MConstant* cst) |
| 6595 | : MTernaryInstruction(classOpcode, envChain, prototype, cst), |
| 6596 | fun_(&cst->toObject().as<JSFunction>()) { |
| 6597 | setResultType(MIRType::Object); |
| 6598 | } |
| 6599 | |
| 6600 | public: |
| 6601 | INSTRUCTION_HEADER(FunctionWithProto) |
| 6602 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6603 | NAMED_OPERANDS((0, environmentChain), (1, prototype))MDefinition* environmentChain() const { return getOperand(0); } MDefinition* prototype() const { return getOperand(1); } |
| 6604 | |
| 6605 | MConstant* functionOperand() const { return getOperand(2)->toConstant(); } |
| 6606 | JSFunction* function() const { return fun_; } |
| 6607 | [[nodiscard]] bool writeRecoverData( |
| 6608 | CompactBufferWriter& writer) const override; |
| 6609 | bool canRecoverOnBailout() const override { return true; } |
| 6610 | |
| 6611 | bool possiblyCalls() const override { return true; } |
| 6612 | }; |
| 6613 | |
| 6614 | class MGetNextEntryForIterator |
| 6615 | : public MBinaryInstruction, |
| 6616 | public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>>::Data { |
| 6617 | public: |
| 6618 | enum Mode { Map, Set }; |
| 6619 | |
| 6620 | private: |
| 6621 | Mode mode_; |
| 6622 | |
| 6623 | explicit MGetNextEntryForIterator(MDefinition* iter, MDefinition* result, |
| 6624 | Mode mode) |
| 6625 | : MBinaryInstruction(classOpcode, iter, result), mode_(mode) { |
| 6626 | setResultType(MIRType::Boolean); |
| 6627 | } |
| 6628 | |
| 6629 | public: |
| 6630 | INSTRUCTION_HEADER(GetNextEntryForIterator) |
| 6631 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6632 | NAMED_OPERANDS((0, iter), (1, result))MDefinition* iter() const { return getOperand(0); } MDefinition * result() const { return getOperand(1); } |
| 6633 | |
| 6634 | Mode mode() const { return mode_; } |
| 6635 | }; |
| 6636 | |
| 6637 | // Convert a Double into an IntPtr value for accessing a TypedArray or DataView |
| 6638 | // element. If the input is non-finite, not an integer, negative, or outside the |
| 6639 | // IntPtr range, either bails out or produces a value which is known to trigger |
| 6640 | // an out-of-bounds access (this depends on the supportOOB flag). |
| 6641 | class MGuardNumberToIntPtrIndex : public MUnaryInstruction, |
| 6642 | public DoublePolicy<0>::Data { |
| 6643 | // If true, produce an out-of-bounds index for non-IntPtr doubles instead of |
| 6644 | // bailing out. |
| 6645 | const bool supportOOB_; |
| 6646 | |
| 6647 | MGuardNumberToIntPtrIndex(MDefinition* def, bool supportOOB) |
| 6648 | : MUnaryInstruction(classOpcode, def), supportOOB_(supportOOB) { |
| 6649 | MOZ_ASSERT(def->type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType< decltype(def->type() == MIRType::Double)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(def->type() == MIRType::Double ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "def->type() == MIRType::Double", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 6649; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6650 | setResultType(MIRType::IntPtr); |
| 6651 | setMovable(); |
| 6652 | if (!supportOOB) { |
| 6653 | setGuard(); |
| 6654 | } |
| 6655 | } |
| 6656 | |
| 6657 | public: |
| 6658 | INSTRUCTION_HEADER(GuardNumberToIntPtrIndex) |
| 6659 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6660 | |
| 6661 | bool supportOOB() const { return supportOOB_; } |
| 6662 | |
| 6663 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 6664 | |
| 6665 | bool congruentTo(const MDefinition* ins) const override { |
| 6666 | if (!ins->isGuardNumberToIntPtrIndex()) { |
| 6667 | return false; |
| 6668 | } |
| 6669 | if (ins->toGuardNumberToIntPtrIndex()->supportOOB() != supportOOB()) { |
| 6670 | return false; |
| 6671 | } |
| 6672 | return congruentIfOperandsEqual(ins); |
| 6673 | } |
| 6674 | |
| 6675 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6676 | |
| 6677 | ALLOW_CLONE(MGuardNumberToIntPtrIndex)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MGuardNumberToIntPtrIndex (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 6678 | }; |
| 6679 | |
| 6680 | // Perform !-operation |
| 6681 | class MNot : public MUnaryInstruction, public TestPolicy::Data { |
| 6682 | bool operandIsNeverNaN_; |
| 6683 | TypeDataList observedTypes_; |
| 6684 | |
| 6685 | explicit MNot(MDefinition* input) |
| 6686 | : MUnaryInstruction(classOpcode, input), operandIsNeverNaN_(false) { |
| 6687 | setResultType(MIRType::Boolean); |
| 6688 | setMovable(); |
| 6689 | } |
| 6690 | |
| 6691 | public: |
| 6692 | static MNot* NewInt32(TempAllocator& alloc, MDefinition* input) { |
| 6693 | MOZ_ASSERT(input->type() == MIRType::Int32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(input->type() == MIRType::Int32 || input->type () == MIRType::Int64)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(input->type() == MIRType:: Int32 || input->type() == MIRType::Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("input->type() == MIRType::Int32 || input->type() == MIRType::Int64" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6694); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Int32 || input->type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 6694; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 6694 | input->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(input->type() == MIRType::Int32 || input->type () == MIRType::Int64)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(input->type() == MIRType:: Int32 || input->type() == MIRType::Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("input->type() == MIRType::Int32 || input->type() == MIRType::Int64" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6694); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Int32 || input->type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 6694; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6695 | auto* ins = new (alloc) MNot(input); |
| 6696 | ins->setResultType(MIRType::Int32); |
| 6697 | return ins; |
| 6698 | } |
| 6699 | |
| 6700 | INSTRUCTION_HEADER(Not) |
| 6701 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6702 | |
| 6703 | void setObservedTypes(const TypeDataList& observed) { |
| 6704 | observedTypes_ = observed; |
| 6705 | } |
| 6706 | const TypeDataList& observedTypes() const { return observedTypes_; } |
| 6707 | |
| 6708 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 6709 | |
| 6710 | bool operandIsNeverNaN() const { return operandIsNeverNaN_; } |
| 6711 | |
| 6712 | virtual AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6713 | void collectRangeInfoPreTrunc() override; |
| 6714 | |
| 6715 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 6716 | bool isFloat32Commutative() const override { return true; } |
| 6717 | #ifdef DEBUG1 |
| 6718 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 6719 | #endif |
| 6720 | bool congruentTo(const MDefinition* ins) const override { |
| 6721 | return congruentIfOperandsEqual(ins); |
| 6722 | } |
| 6723 | [[nodiscard]] bool writeRecoverData( |
| 6724 | CompactBufferWriter& writer) const override; |
| 6725 | bool canRecoverOnBailout() const override { return true; } |
| 6726 | }; |
| 6727 | |
| 6728 | // Bailout if index + minimum < 0 or index + maximum >= length. The length used |
| 6729 | // in a bounds check must not be negative, or the wrong result may be computed |
| 6730 | // (unsigned comparisons may be used). |
| 6731 | class MBoundsCheck |
| 6732 | : public MBinaryInstruction, |
| 6733 | public MixPolicy<Int32OrIntPtrPolicy<0>, Int32OrIntPtrPolicy<1>>::Data { |
| 6734 | // Range over which to perform the bounds check, may be modified by GVN. |
| 6735 | int32_t minimum_; |
| 6736 | int32_t maximum_; |
| 6737 | bool fallible_; |
| 6738 | |
| 6739 | MBoundsCheck(MDefinition* index, MDefinition* length) |
| 6740 | : MBinaryInstruction(classOpcode, index, length), |
| 6741 | minimum_(0), |
| 6742 | maximum_(0), |
| 6743 | fallible_(true) { |
| 6744 | setGuard(); |
| 6745 | setMovable(); |
| 6746 | MOZ_ASSERT(index->type() == MIRType::Int32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32 || index->type () == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32 || index->type() == MIRType::IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index->type() == MIRType::Int32 || index->type() == MIRType::IntPtr" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6747); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32 || index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 6747; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 6747 | index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32 || index->type () == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32 || index->type() == MIRType::IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index->type() == MIRType::Int32 || index->type() == MIRType::IntPtr" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6747); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32 || index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 6747; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6748 | MOZ_ASSERT(index->type() == length->type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == length->type())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(index->type() == length->type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index->type() == length->type()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6748); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == length->type()" ")"); do { *((volatile int*)__null) = 6748; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6749 | |
| 6750 | // Returns the checked index. |
| 6751 | setResultType(index->type()); |
| 6752 | } |
| 6753 | |
| 6754 | public: |
| 6755 | INSTRUCTION_HEADER(BoundsCheck) |
| 6756 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6757 | NAMED_OPERANDS((0, index), (1, length))MDefinition* index() const { return getOperand(0); } MDefinition * length() const { return getOperand(1); } |
| 6758 | |
| 6759 | int32_t minimum() const { return minimum_; } |
| 6760 | void setMinimum(int32_t n) { |
| 6761 | MOZ_ASSERT(fallible_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(fallible_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(fallible_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("fallible_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6761); AnnotateMozCrashReason("MOZ_ASSERT" "(" "fallible_" ")" ); do { *((volatile int*)__null) = 6761; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6762 | minimum_ = n; |
| 6763 | } |
| 6764 | int32_t maximum() const { return maximum_; } |
| 6765 | void setMaximum(int32_t n) { |
| 6766 | MOZ_ASSERT(fallible_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(fallible_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(fallible_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("fallible_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6766); AnnotateMozCrashReason("MOZ_ASSERT" "(" "fallible_" ")" ); do { *((volatile int*)__null) = 6766; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6767 | maximum_ = n; |
| 6768 | } |
| 6769 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 6770 | bool congruentTo(const MDefinition* ins) const override { |
| 6771 | if (!ins->isBoundsCheck()) { |
| 6772 | return false; |
| 6773 | } |
| 6774 | const MBoundsCheck* other = ins->toBoundsCheck(); |
| 6775 | if (minimum() != other->minimum() || maximum() != other->maximum()) { |
| 6776 | return false; |
| 6777 | } |
| 6778 | if (fallible() != other->fallible()) { |
| 6779 | return false; |
| 6780 | } |
| 6781 | return congruentIfOperandsEqual(other); |
| 6782 | } |
| 6783 | virtual AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6784 | void computeRange(TempAllocator& alloc) override; |
| 6785 | bool fallible() const { return fallible_; } |
| 6786 | void collectRangeInfoPreTrunc() override; |
| 6787 | |
| 6788 | ALLOW_CLONE(MBoundsCheck)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MBoundsCheck (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 6789 | }; |
| 6790 | |
| 6791 | // Bailout if index < minimum. |
| 6792 | class MBoundsCheckLower : public MUnaryInstruction, |
| 6793 | public UnboxedInt32Policy<0>::Data { |
| 6794 | int32_t minimum_; |
| 6795 | bool fallible_; |
| 6796 | |
| 6797 | explicit MBoundsCheckLower(MDefinition* index) |
| 6798 | : MUnaryInstruction(classOpcode, index), minimum_(0), fallible_(true) { |
| 6799 | setGuard(); |
| 6800 | setMovable(); |
| 6801 | MOZ_ASSERT(index->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6801); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 6801; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6802 | } |
| 6803 | |
| 6804 | public: |
| 6805 | INSTRUCTION_HEADER(BoundsCheckLower) |
| 6806 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6807 | NAMED_OPERANDS((0, index))MDefinition* index() const { return getOperand(0); } |
| 6808 | |
| 6809 | int32_t minimum() const { return minimum_; } |
| 6810 | void setMinimum(int32_t n) { minimum_ = n; } |
| 6811 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6812 | bool fallible() const { return fallible_; } |
| 6813 | void collectRangeInfoPreTrunc() override; |
| 6814 | }; |
| 6815 | |
| 6816 | class MSpectreMaskIndex |
| 6817 | : public MBinaryInstruction, |
| 6818 | public MixPolicy<Int32OrIntPtrPolicy<0>, Int32OrIntPtrPolicy<1>>::Data { |
| 6819 | MSpectreMaskIndex(MDefinition* index, MDefinition* length) |
| 6820 | : MBinaryInstruction(classOpcode, index, length) { |
| 6821 | // Note: this instruction does not need setGuard(): if there are no uses |
| 6822 | // it's fine for DCE to eliminate this instruction. |
| 6823 | setMovable(); |
| 6824 | MOZ_ASSERT(index->type() == MIRType::Int32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32 || index->type () == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32 || index->type() == MIRType::IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index->type() == MIRType::Int32 || index->type() == MIRType::IntPtr" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32 || index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 6825; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 6825 | index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32 || index->type () == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32 || index->type() == MIRType::IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index->type() == MIRType::Int32 || index->type() == MIRType::IntPtr" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32 || index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 6825; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6826 | MOZ_ASSERT(index->type() == length->type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == length->type())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(index->type() == length->type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("index->type() == length->type()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6826); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == length->type()" ")"); do { *((volatile int*)__null) = 6826; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6827 | |
| 6828 | // Returns the masked index. |
| 6829 | setResultType(index->type()); |
| 6830 | } |
| 6831 | |
| 6832 | public: |
| 6833 | INSTRUCTION_HEADER(SpectreMaskIndex) |
| 6834 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6835 | NAMED_OPERANDS((0, index), (1, length))MDefinition* index() const { return getOperand(0); } MDefinition * length() const { return getOperand(1); } |
| 6836 | |
| 6837 | bool congruentTo(const MDefinition* ins) const override { |
| 6838 | return congruentIfOperandsEqual(ins); |
| 6839 | } |
| 6840 | virtual AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 6841 | void computeRange(TempAllocator& alloc) override; |
| 6842 | |
| 6843 | ALLOW_CLONE(MSpectreMaskIndex)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MSpectreMaskIndex (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 6844 | }; |
| 6845 | |
| 6846 | // Load a value from a dense array's element vector. Bails out if the element is |
| 6847 | // a hole. |
| 6848 | class MLoadElement : public MBinaryInstruction, public NoTypePolicy::Data { |
| 6849 | MLoadElement(MDefinition* elements, MDefinition* index) |
| 6850 | : MBinaryInstruction(classOpcode, elements, index) { |
| 6851 | // Uses may be optimized away based on this instruction's result |
| 6852 | // type. This means it's invalid to DCE this instruction, as we |
| 6853 | // have to invalidate when we read a hole. |
| 6854 | setGuard(); |
| 6855 | setResultType(MIRType::Value); |
| 6856 | setMovable(); |
| 6857 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6857); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 6857; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6858 | MOZ_ASSERT(index->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6858); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 6858; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6859 | } |
| 6860 | |
| 6861 | public: |
| 6862 | INSTRUCTION_HEADER(LoadElement) |
| 6863 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6864 | NAMED_OPERANDS((0, elements), (1, index))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } |
| 6865 | |
| 6866 | bool congruentTo(const MDefinition* ins) const override { |
| 6867 | return congruentIfOperandsEqual(ins); |
| 6868 | } |
| 6869 | AliasType mightAlias(const MDefinition* store) const override; |
| 6870 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 6871 | AliasSet getAliasSet() const override { |
| 6872 | return AliasSet::Load(AliasSet::Element); |
| 6873 | } |
| 6874 | |
| 6875 | ALLOW_CLONE(MLoadElement)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadElement (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 6876 | }; |
| 6877 | |
| 6878 | class MLoadElementAndUnbox : public MBinaryInstruction, |
| 6879 | public NoTypePolicy::Data { |
| 6880 | MUnbox::Mode mode_; |
| 6881 | |
| 6882 | MLoadElementAndUnbox(MDefinition* elements, MDefinition* index, |
| 6883 | MUnbox::Mode mode, MIRType type) |
| 6884 | : MBinaryInstruction(classOpcode, elements, index), mode_(mode) { |
| 6885 | setResultType(type); |
| 6886 | setMovable(); |
| 6887 | if (mode_ == MUnbox::Fallible) { |
| 6888 | setGuard(); |
| 6889 | } |
| 6890 | } |
| 6891 | |
| 6892 | public: |
| 6893 | INSTRUCTION_HEADER(LoadElementAndUnbox) |
| 6894 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6895 | NAMED_OPERANDS((0, elements), (1, index))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } |
| 6896 | |
| 6897 | MUnbox::Mode mode() const { return mode_; } |
| 6898 | bool fallible() const { return mode_ != MUnbox::Infallible; } |
| 6899 | |
| 6900 | bool congruentTo(const MDefinition* ins) const override { |
| 6901 | if (!ins->isLoadElementAndUnbox() || |
| 6902 | mode() != ins->toLoadElementAndUnbox()->mode()) { |
| 6903 | return false; |
| 6904 | } |
| 6905 | return congruentIfOperandsEqual(ins); |
| 6906 | } |
| 6907 | |
| 6908 | AliasSet getAliasSet() const override { |
| 6909 | return AliasSet::Load(AliasSet::Element); |
| 6910 | } |
| 6911 | |
| 6912 | ALLOW_CLONE(MLoadElementAndUnbox)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadElementAndUnbox (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }; |
| 6913 | }; |
| 6914 | |
| 6915 | // Load a value from the elements vector of a native object. If the index is |
| 6916 | // out-of-bounds, or the indexed slot has a hole, undefined is returned instead. |
| 6917 | class MLoadElementHole : public MTernaryInstruction, public NoTypePolicy::Data { |
| 6918 | bool needsNegativeIntCheck_ = true; |
| 6919 | |
| 6920 | MLoadElementHole(MDefinition* elements, MDefinition* index, |
| 6921 | MDefinition* initLength) |
| 6922 | : MTernaryInstruction(classOpcode, elements, index, initLength) { |
| 6923 | setResultType(MIRType::Value); |
| 6924 | setMovable(); |
| 6925 | |
| 6926 | // Set the guard flag to make sure we bail when we see a negative |
| 6927 | // index. We can clear this flag (and needsNegativeIntCheck_) in |
| 6928 | // collectRangeInfoPreTrunc. |
| 6929 | setGuard(); |
| 6930 | |
| 6931 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6931); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 6931; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6932 | MOZ_ASSERT(index->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 6932; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6933 | MOZ_ASSERT(initLength->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(initLength->type() == MIRType::Int32)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(initLength->type() == MIRType::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("initLength->type() == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6933); AnnotateMozCrashReason("MOZ_ASSERT" "(" "initLength->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 6933; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6934 | } |
| 6935 | |
| 6936 | public: |
| 6937 | INSTRUCTION_HEADER(LoadElementHole) |
| 6938 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6939 | NAMED_OPERANDS((0, elements), (1, index), (2, initLength))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* initLength () const { return getOperand(2); } |
| 6940 | |
| 6941 | bool needsNegativeIntCheck() const { return needsNegativeIntCheck_; } |
| 6942 | bool congruentTo(const MDefinition* ins) const override { |
| 6943 | if (!ins->isLoadElementHole()) { |
| 6944 | return false; |
| 6945 | } |
| 6946 | const MLoadElementHole* other = ins->toLoadElementHole(); |
| 6947 | if (needsNegativeIntCheck() != other->needsNegativeIntCheck()) { |
| 6948 | return false; |
| 6949 | } |
| 6950 | return congruentIfOperandsEqual(other); |
| 6951 | } |
| 6952 | AliasSet getAliasSet() const override { |
| 6953 | return AliasSet::Load(AliasSet::Element); |
| 6954 | } |
| 6955 | void collectRangeInfoPreTrunc() override; |
| 6956 | |
| 6957 | ALLOW_CLONE(MLoadElementHole)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadElementHole (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 6958 | }; |
| 6959 | |
| 6960 | // Store a value to a dense array slots vector. |
| 6961 | class MStoreElement : public MTernaryInstruction, |
| 6962 | public NoFloatPolicy<2>::Data { |
| 6963 | bool needsHoleCheck_; |
| 6964 | bool needsBarrier_; |
| 6965 | |
| 6966 | MStoreElement(MDefinition* elements, MDefinition* index, MDefinition* value, |
| 6967 | bool needsHoleCheck, bool needsBarrier) |
| 6968 | : MTernaryInstruction(classOpcode, elements, index, value) { |
| 6969 | needsHoleCheck_ = needsHoleCheck; |
| 6970 | needsBarrier_ = needsBarrier; |
| 6971 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6971); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 6971; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6972 | MOZ_ASSERT(index->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6972); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 6972; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6973 | MOZ_ASSERT(value->type() != MIRType::MagicHole)do { static_assert( mozilla::detail::AssertionConditionType< decltype(value->type() != MIRType::MagicHole)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(value->type() != MIRType::MagicHole))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("value->type() != MIRType::MagicHole" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 6973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() != MIRType::MagicHole" ")"); do { *((volatile int*)__null) = 6973; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6974 | } |
| 6975 | |
| 6976 | public: |
| 6977 | INSTRUCTION_HEADER(StoreElement) |
| 6978 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 6979 | NAMED_OPERANDS((0, elements), (1, index), (2, value))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* value( ) const { return getOperand(2); } |
| 6980 | |
| 6981 | static MStoreElement* NewUnbarriered(TempAllocator& alloc, |
| 6982 | MDefinition* elements, |
| 6983 | MDefinition* index, MDefinition* value, |
| 6984 | bool needsHoleCheck) { |
| 6985 | return new (alloc) |
| 6986 | MStoreElement(elements, index, value, needsHoleCheck, false); |
| 6987 | } |
| 6988 | |
| 6989 | static MStoreElement* NewBarriered(TempAllocator& alloc, |
| 6990 | MDefinition* elements, MDefinition* index, |
| 6991 | MDefinition* value, bool needsHoleCheck) { |
| 6992 | return new (alloc) |
| 6993 | MStoreElement(elements, index, value, needsHoleCheck, true); |
| 6994 | } |
| 6995 | |
| 6996 | AliasSet getAliasSet() const override { |
| 6997 | return AliasSet::Store(AliasSet::Element); |
| 6998 | } |
| 6999 | bool needsBarrier() const { return needsBarrier_; } |
| 7000 | bool needsHoleCheck() const { return needsHoleCheck_; } |
| 7001 | bool fallible() const { return needsHoleCheck(); } |
| 7002 | |
| 7003 | ALLOW_CLONE(MStoreElement)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MStoreElement (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7004 | }; |
| 7005 | |
| 7006 | // Stores MagicValue(JS_ELEMENTS_HOLE) and marks the elements as non-packed. |
| 7007 | class MStoreHoleValueElement : public MBinaryInstruction, |
| 7008 | public NoTypePolicy::Data { |
| 7009 | MStoreHoleValueElement(MDefinition* elements, MDefinition* index) |
| 7010 | : MBinaryInstruction(classOpcode, elements, index) { |
| 7011 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7011); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 7011; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7012 | MOZ_ASSERT(index->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 7012; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7013 | } |
| 7014 | |
| 7015 | public: |
| 7016 | INSTRUCTION_HEADER(StoreHoleValueElement) |
| 7017 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7018 | NAMED_OPERANDS((0, elements), (1, index))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } |
| 7019 | |
| 7020 | AliasSet getAliasSet() const override { |
| 7021 | return AliasSet::Store(AliasSet::Element | AliasSet::ObjectFields); |
| 7022 | } |
| 7023 | |
| 7024 | ALLOW_CLONE(MStoreHoleValueElement)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MStoreHoleValueElement (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7025 | }; |
| 7026 | |
| 7027 | // Like MStoreElement, but also supports index == initialized length. The |
| 7028 | // downside is that we cannot hoist the elements vector and bounds check, since |
| 7029 | // this instruction may update the (initialized) length and reallocate the |
| 7030 | // elements vector. |
| 7031 | class MStoreElementHole |
| 7032 | : public MQuaternaryInstruction, |
| 7033 | public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3>>::Data { |
| 7034 | MStoreElementHole(MDefinition* object, MDefinition* elements, |
| 7035 | MDefinition* index, MDefinition* value) |
| 7036 | : MQuaternaryInstruction(classOpcode, object, elements, index, value) { |
| 7037 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 7037; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7038 | MOZ_ASSERT(index->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7038); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 7038; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7039 | MOZ_ASSERT(value->type() != MIRType::MagicHole)do { static_assert( mozilla::detail::AssertionConditionType< decltype(value->type() != MIRType::MagicHole)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(value->type() != MIRType::MagicHole))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("value->type() != MIRType::MagicHole" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7039); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() != MIRType::MagicHole" ")"); do { *((volatile int*)__null) = 7039; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7040 | } |
| 7041 | |
| 7042 | public: |
| 7043 | INSTRUCTION_HEADER(StoreElementHole) |
| 7044 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7045 | NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))MDefinition* object() const { return getOperand(0); } MDefinition * elements() const { return getOperand(1); } MDefinition* index () const { return getOperand(2); } MDefinition* value() const { return getOperand(3); } |
| 7046 | |
| 7047 | AliasSet getAliasSet() const override { |
| 7048 | // StoreElementHole can update the initialized length, the array length |
| 7049 | // or reallocate obj->elements. |
| 7050 | return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); |
| 7051 | } |
| 7052 | |
| 7053 | ALLOW_CLONE(MStoreElementHole)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MStoreElementHole (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7054 | }; |
| 7055 | |
| 7056 | // Array.prototype.pop or Array.prototype.shift on a dense array. |
| 7057 | class MArrayPopShift : public MUnaryInstruction, |
| 7058 | public SingleObjectPolicy::Data { |
| 7059 | public: |
| 7060 | enum Mode { Pop, Shift }; |
| 7061 | |
| 7062 | private: |
| 7063 | Mode mode_; |
| 7064 | |
| 7065 | MArrayPopShift(MDefinition* object, Mode mode) |
| 7066 | : MUnaryInstruction(classOpcode, object), mode_(mode) { |
| 7067 | setResultType(MIRType::Value); |
| 7068 | } |
| 7069 | |
| 7070 | public: |
| 7071 | INSTRUCTION_HEADER(ArrayPopShift) |
| 7072 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7073 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 7074 | |
| 7075 | bool mode() const { return mode_; } |
| 7076 | AliasSet getAliasSet() const override { |
| 7077 | return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); |
| 7078 | } |
| 7079 | |
| 7080 | ALLOW_CLONE(MArrayPopShift)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MArrayPopShift (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7081 | }; |
| 7082 | |
| 7083 | // Load an unboxed scalar value from an array buffer view or other object. |
| 7084 | class MLoadUnboxedScalar : public MBinaryInstruction, |
| 7085 | public NoTypePolicy::Data { |
| 7086 | int32_t offsetAdjustment_ = 0; |
| 7087 | Scalar::Type storageType_; |
| 7088 | MemoryBarrierRequirement requiresBarrier_; |
| 7089 | |
| 7090 | MLoadUnboxedScalar(MDefinition* elements, MDefinition* index, |
| 7091 | Scalar::Type storageType, |
| 7092 | MemoryBarrierRequirement requiresBarrier = |
| 7093 | MemoryBarrierRequirement::NotRequired) |
| 7094 | : MBinaryInstruction(classOpcode, elements, index), |
| 7095 | storageType_(storageType), |
| 7096 | requiresBarrier_(requiresBarrier) { |
| 7097 | setResultType(MIRType::Value); |
| 7098 | if (requiresBarrier_ == MemoryBarrierRequirement::Required) { |
| 7099 | setGuard(); // Not removable or movable |
| 7100 | } else { |
| 7101 | setMovable(); |
| 7102 | } |
| 7103 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 7103; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7104 | MOZ_ASSERT(index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 7104; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7105 | MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType)do { static_assert( mozilla::detail::AssertionConditionType< decltype(storageType >= 0 && storageType < Scalar ::MaxTypedArrayViewType)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType" ")"); do { *((volatile int*)__null) = 7105; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7106 | } |
| 7107 | |
| 7108 | public: |
| 7109 | INSTRUCTION_HEADER(LoadUnboxedScalar) |
| 7110 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7111 | NAMED_OPERANDS((0, elements), (1, index))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } |
| 7112 | |
| 7113 | Scalar::Type storageType() const { return storageType_; } |
| 7114 | bool fallible() const { |
| 7115 | // Bailout if the result does not fit in an int32. |
| 7116 | return storageType_ == Scalar::Uint32 && type() == MIRType::Int32; |
| 7117 | } |
| 7118 | auto requiresMemoryBarrier() const { return requiresBarrier_; } |
| 7119 | int32_t offsetAdjustment() const { return offsetAdjustment_; } |
| 7120 | void setOffsetAdjustment(int32_t offsetAdjustment) { |
| 7121 | offsetAdjustment_ = offsetAdjustment; |
| 7122 | } |
| 7123 | AliasSet getAliasSet() const override { |
| 7124 | // When a barrier is needed make the instruction effectful by |
| 7125 | // giving it a "store" effect. |
| 7126 | if (requiresBarrier_ == MemoryBarrierRequirement::Required) { |
| 7127 | return AliasSet::Store(AliasSet::UnboxedElement); |
| 7128 | } |
| 7129 | return AliasSet::Load(AliasSet::UnboxedElement); |
| 7130 | } |
| 7131 | |
| 7132 | bool congruentTo(const MDefinition* ins) const override { |
| 7133 | if (requiresBarrier_ == MemoryBarrierRequirement::Required) { |
| 7134 | return false; |
| 7135 | } |
| 7136 | if (!ins->isLoadUnboxedScalar()) { |
| 7137 | return false; |
| 7138 | } |
| 7139 | const MLoadUnboxedScalar* other = ins->toLoadUnboxedScalar(); |
| 7140 | if (storageType_ != other->storageType_) { |
| 7141 | return false; |
| 7142 | } |
| 7143 | if (offsetAdjustment() != other->offsetAdjustment()) { |
| 7144 | return false; |
| 7145 | } |
| 7146 | return congruentIfOperandsEqual(other); |
| 7147 | } |
| 7148 | |
| 7149 | #ifdef JS_JITSPEW1 |
| 7150 | void printOpcode(GenericPrinter& out) const override; |
| 7151 | #endif |
| 7152 | |
| 7153 | void computeRange(TempAllocator& alloc) override; |
| 7154 | |
| 7155 | bool canProduceFloat32() const override { |
| 7156 | return storageType_ == Scalar::Float32; |
| 7157 | } |
| 7158 | |
| 7159 | ALLOW_CLONE(MLoadUnboxedScalar)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadUnboxedScalar (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7160 | }; |
| 7161 | |
| 7162 | // Load an unboxed scalar value from a dataview object. |
| 7163 | class MLoadDataViewElement : public MTernaryInstruction, |
| 7164 | public NoTypePolicy::Data { |
| 7165 | Scalar::Type storageType_; |
| 7166 | |
| 7167 | MLoadDataViewElement(MDefinition* elements, MDefinition* index, |
| 7168 | MDefinition* littleEndian, Scalar::Type storageType) |
| 7169 | : MTernaryInstruction(classOpcode, elements, index, littleEndian), |
| 7170 | storageType_(storageType) { |
| 7171 | setResultType(MIRType::Value); |
| 7172 | setMovable(); |
| 7173 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 7173; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7174 | MOZ_ASSERT(index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7174); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 7174; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7175 | MOZ_ASSERT(littleEndian->type() == MIRType::Boolean)do { static_assert( mozilla::detail::AssertionConditionType< decltype(littleEndian->type() == MIRType::Boolean)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(littleEndian->type() == MIRType::Boolean))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("littleEndian->type() == MIRType::Boolean" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "littleEndian->type() == MIRType::Boolean" ")"); do { *((volatile int*)__null) = 7175; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7176 | MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType)do { static_assert( mozilla::detail::AssertionConditionType< decltype(storageType >= 0 && storageType < Scalar ::MaxTypedArrayViewType)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7176); AnnotateMozCrashReason("MOZ_ASSERT" "(" "storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType" ")"); do { *((volatile int*)__null) = 7176; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7177 | MOZ_ASSERT(Scalar::byteSize(storageType) > 1)do { static_assert( mozilla::detail::AssertionConditionType< decltype(Scalar::byteSize(storageType) > 1)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(Scalar::byteSize(storageType ) > 1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("Scalar::byteSize(storageType) > 1", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7177); AnnotateMozCrashReason("MOZ_ASSERT" "(" "Scalar::byteSize(storageType) > 1" ")"); do { *((volatile int*)__null) = 7177; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7178 | } |
| 7179 | |
| 7180 | public: |
| 7181 | INSTRUCTION_HEADER(LoadDataViewElement) |
| 7182 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7183 | NAMED_OPERANDS((0, elements), (1, index), (2, littleEndian))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* littleEndian () const { return getOperand(2); } |
| 7184 | |
| 7185 | Scalar::Type storageType() const { return storageType_; } |
| 7186 | bool fallible() const { |
| 7187 | // Bailout if the result does not fit in an int32. |
| 7188 | return storageType_ == Scalar::Uint32 && type() == MIRType::Int32; |
| 7189 | } |
| 7190 | AliasSet getAliasSet() const override { |
| 7191 | return AliasSet::Load(AliasSet::UnboxedElement); |
| 7192 | } |
| 7193 | |
| 7194 | bool congruentTo(const MDefinition* ins) const override { |
| 7195 | if (!ins->isLoadDataViewElement()) { |
| 7196 | return false; |
| 7197 | } |
| 7198 | const MLoadDataViewElement* other = ins->toLoadDataViewElement(); |
| 7199 | if (storageType_ != other->storageType_) { |
| 7200 | return false; |
| 7201 | } |
| 7202 | return congruentIfOperandsEqual(other); |
| 7203 | } |
| 7204 | |
| 7205 | #ifdef JS_JITSPEW1 |
| 7206 | void printOpcode(GenericPrinter& out) const override; |
| 7207 | #endif |
| 7208 | |
| 7209 | void computeRange(TempAllocator& alloc) override; |
| 7210 | |
| 7211 | bool canProduceFloat32() const override { |
| 7212 | return storageType_ == Scalar::Float32; |
| 7213 | } |
| 7214 | |
| 7215 | ALLOW_CLONE(MLoadDataViewElement)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadDataViewElement (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7216 | }; |
| 7217 | |
| 7218 | // Load a value from a typed array. Out-of-bounds accesses are handled in-line. |
| 7219 | class MLoadTypedArrayElementHole : public MTernaryInstruction, |
| 7220 | public NoTypePolicy::Data { |
| 7221 | Scalar::Type arrayType_; |
| 7222 | bool forceDouble_; |
| 7223 | |
| 7224 | MLoadTypedArrayElementHole(MDefinition* elements, MDefinition* index, |
| 7225 | MDefinition* length, Scalar::Type arrayType, |
| 7226 | bool forceDouble) |
| 7227 | : MTernaryInstruction(classOpcode, elements, index, length), |
| 7228 | arrayType_(arrayType), |
| 7229 | forceDouble_(forceDouble) { |
| 7230 | setResultType(MIRType::Value); |
| 7231 | setMovable(); |
| 7232 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7232); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 7232; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7233 | MOZ_ASSERT(index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7233); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 7233; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7234 | MOZ_ASSERT(length->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(length->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(length->type() == MIRType ::IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("length->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7234); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 7234; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7235 | MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType)do { static_assert( mozilla::detail::AssertionConditionType< decltype(arrayType >= 0 && arrayType < Scalar:: MaxTypedArrayViewType)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7235); AnnotateMozCrashReason("MOZ_ASSERT" "(" "arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType" ")"); do { *((volatile int*)__null) = 7235; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7236 | } |
| 7237 | |
| 7238 | public: |
| 7239 | INSTRUCTION_HEADER(LoadTypedArrayElementHole) |
| 7240 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7241 | NAMED_OPERANDS((0, elements), (1, index), (2, length))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* length () const { return getOperand(2); } |
| 7242 | |
| 7243 | Scalar::Type arrayType() const { return arrayType_; } |
| 7244 | bool forceDouble() const { return forceDouble_; } |
| 7245 | bool fallible() const { |
| 7246 | return arrayType_ == Scalar::Uint32 && !forceDouble_; |
| 7247 | } |
| 7248 | bool congruentTo(const MDefinition* ins) const override { |
| 7249 | if (!ins->isLoadTypedArrayElementHole()) { |
| 7250 | return false; |
| 7251 | } |
| 7252 | const MLoadTypedArrayElementHole* other = |
| 7253 | ins->toLoadTypedArrayElementHole(); |
| 7254 | if (arrayType() != other->arrayType()) { |
| 7255 | return false; |
| 7256 | } |
| 7257 | if (forceDouble() != other->forceDouble()) { |
| 7258 | return false; |
| 7259 | } |
| 7260 | return congruentIfOperandsEqual(other); |
| 7261 | } |
| 7262 | AliasSet getAliasSet() const override { |
| 7263 | return AliasSet::Load(AliasSet::UnboxedElement); |
| 7264 | } |
| 7265 | bool canProduceFloat32() const override { |
| 7266 | return arrayType_ == Scalar::Float32; |
| 7267 | } |
| 7268 | |
| 7269 | ALLOW_CLONE(MLoadTypedArrayElementHole)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadTypedArrayElementHole (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7270 | }; |
| 7271 | |
| 7272 | // Base class for MIR ops that write unboxed scalar values. |
| 7273 | class StoreUnboxedScalarBase { |
| 7274 | Scalar::Type writeType_; |
| 7275 | |
| 7276 | protected: |
| 7277 | explicit StoreUnboxedScalarBase(Scalar::Type writeType) |
| 7278 | : writeType_(writeType) { |
| 7279 | MOZ_ASSERT(isIntegerWrite() || isFloatWrite() || isBigIntWrite())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isIntegerWrite() || isFloatWrite() || isBigIntWrite( ))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(isIntegerWrite() || isFloatWrite() || isBigIntWrite( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("isIntegerWrite() || isFloatWrite() || isBigIntWrite()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7279); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isIntegerWrite() || isFloatWrite() || isBigIntWrite()" ")"); do { *((volatile int*)__null) = 7279; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7280 | } |
| 7281 | |
| 7282 | public: |
| 7283 | Scalar::Type writeType() const { return writeType_; } |
| 7284 | bool isByteWrite() const { |
| 7285 | return writeType_ == Scalar::Int8 || writeType_ == Scalar::Uint8 || |
| 7286 | writeType_ == Scalar::Uint8Clamped; |
| 7287 | } |
| 7288 | bool isIntegerWrite() const { |
| 7289 | return isByteWrite() || writeType_ == Scalar::Int16 || |
| 7290 | writeType_ == Scalar::Uint16 || writeType_ == Scalar::Int32 || |
| 7291 | writeType_ == Scalar::Uint32; |
| 7292 | } |
| 7293 | bool isFloatWrite() const { |
| 7294 | return writeType_ == Scalar::Float32 || writeType_ == Scalar::Float64; |
| 7295 | } |
| 7296 | bool isBigIntWrite() const { return Scalar::isBigIntType(writeType_); } |
| 7297 | }; |
| 7298 | |
| 7299 | // Store an unboxed scalar value to an array buffer view or other object. |
| 7300 | class MStoreUnboxedScalar : public MTernaryInstruction, |
| 7301 | public StoreUnboxedScalarBase, |
| 7302 | public StoreUnboxedScalarPolicy::Data { |
| 7303 | MemoryBarrierRequirement requiresBarrier_; |
| 7304 | |
| 7305 | MStoreUnboxedScalar(MDefinition* elements, MDefinition* index, |
| 7306 | MDefinition* value, Scalar::Type storageType, |
| 7307 | MemoryBarrierRequirement requiresBarrier = |
| 7308 | MemoryBarrierRequirement::NotRequired) |
| 7309 | : MTernaryInstruction(classOpcode, elements, index, value), |
| 7310 | StoreUnboxedScalarBase(storageType), |
| 7311 | requiresBarrier_(requiresBarrier) { |
| 7312 | if (requiresBarrier_ == MemoryBarrierRequirement::Required) { |
| 7313 | setGuard(); // Not removable or movable |
| 7314 | } |
| 7315 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7315); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 7315; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7316 | MOZ_ASSERT(index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7316); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 7316; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7317 | MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType)do { static_assert( mozilla::detail::AssertionConditionType< decltype(storageType >= 0 && storageType < Scalar ::MaxTypedArrayViewType)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7317); AnnotateMozCrashReason("MOZ_ASSERT" "(" "storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType" ")"); do { *((volatile int*)__null) = 7317; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7318 | } |
| 7319 | |
| 7320 | public: |
| 7321 | INSTRUCTION_HEADER(StoreUnboxedScalar) |
| 7322 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7323 | NAMED_OPERANDS((0, elements), (1, index), (2, value))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* value( ) const { return getOperand(2); } |
| 7324 | |
| 7325 | AliasSet getAliasSet() const override { |
| 7326 | return AliasSet::Store(AliasSet::UnboxedElement); |
| 7327 | } |
| 7328 | auto requiresMemoryBarrier() const { return requiresBarrier_; } |
| 7329 | TruncateKind operandTruncateKind(size_t index) const override; |
| 7330 | |
| 7331 | bool canConsumeFloat32(MUse* use) const override { |
| 7332 | return use == getUseFor(2) && writeType() == Scalar::Float32; |
| 7333 | } |
| 7334 | |
| 7335 | ALLOW_CLONE(MStoreUnboxedScalar)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MStoreUnboxedScalar (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7336 | }; |
| 7337 | |
| 7338 | // Store an unboxed scalar value to a dataview object. |
| 7339 | class MStoreDataViewElement : public MQuaternaryInstruction, |
| 7340 | public StoreUnboxedScalarBase, |
| 7341 | public StoreDataViewElementPolicy::Data { |
| 7342 | MStoreDataViewElement(MDefinition* elements, MDefinition* index, |
| 7343 | MDefinition* value, MDefinition* littleEndian, |
| 7344 | Scalar::Type storageType) |
| 7345 | : MQuaternaryInstruction(classOpcode, elements, index, value, |
| 7346 | littleEndian), |
| 7347 | StoreUnboxedScalarBase(storageType) { |
| 7348 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7348); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 7348; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7349 | MOZ_ASSERT(index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7349); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 7349; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7350 | MOZ_ASSERT(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType)do { static_assert( mozilla::detail::AssertionConditionType< decltype(storageType >= 0 && storageType < Scalar ::MaxTypedArrayViewType)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7350); AnnotateMozCrashReason("MOZ_ASSERT" "(" "storageType >= 0 && storageType < Scalar::MaxTypedArrayViewType" ")"); do { *((volatile int*)__null) = 7350; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7351 | MOZ_ASSERT(Scalar::byteSize(storageType) > 1)do { static_assert( mozilla::detail::AssertionConditionType< decltype(Scalar::byteSize(storageType) > 1)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(Scalar::byteSize(storageType ) > 1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("Scalar::byteSize(storageType) > 1", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7351); AnnotateMozCrashReason("MOZ_ASSERT" "(" "Scalar::byteSize(storageType) > 1" ")"); do { *((volatile int*)__null) = 7351; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7352 | } |
| 7353 | |
| 7354 | public: |
| 7355 | INSTRUCTION_HEADER(StoreDataViewElement) |
| 7356 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7357 | NAMED_OPERANDS((0, elements), (1, index), (2, value), (3, littleEndian))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* value( ) const { return getOperand(2); } MDefinition* littleEndian() const { return getOperand(3); } |
| 7358 | |
| 7359 | AliasSet getAliasSet() const override { |
| 7360 | return AliasSet::Store(AliasSet::UnboxedElement); |
| 7361 | } |
| 7362 | TruncateKind operandTruncateKind(size_t index) const override; |
| 7363 | |
| 7364 | bool canConsumeFloat32(MUse* use) const override { |
| 7365 | return use == getUseFor(2) && writeType() == Scalar::Float32; |
| 7366 | } |
| 7367 | |
| 7368 | ALLOW_CLONE(MStoreDataViewElement)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MStoreDataViewElement (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7369 | }; |
| 7370 | |
| 7371 | class MStoreTypedArrayElementHole : public MQuaternaryInstruction, |
| 7372 | public StoreUnboxedScalarBase, |
| 7373 | public StoreTypedArrayHolePolicy::Data { |
| 7374 | MStoreTypedArrayElementHole(MDefinition* elements, MDefinition* length, |
| 7375 | MDefinition* index, MDefinition* value, |
| 7376 | Scalar::Type arrayType) |
| 7377 | : MQuaternaryInstruction(classOpcode, elements, length, index, value), |
| 7378 | StoreUnboxedScalarBase(arrayType) { |
| 7379 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 7379; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7380 | MOZ_ASSERT(length->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(length->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(length->type() == MIRType ::IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("length->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7380); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 7380; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7381 | MOZ_ASSERT(index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 7381; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7382 | MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType)do { static_assert( mozilla::detail::AssertionConditionType< decltype(arrayType >= 0 && arrayType < Scalar:: MaxTypedArrayViewType)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7382); AnnotateMozCrashReason("MOZ_ASSERT" "(" "arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType" ")"); do { *((volatile int*)__null) = 7382; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7383 | } |
| 7384 | |
| 7385 | public: |
| 7386 | INSTRUCTION_HEADER(StoreTypedArrayElementHole) |
| 7387 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7388 | NAMED_OPERANDS((0, elements), (1, length), (2, index), (3, value))MDefinition* elements() const { return getOperand(0); } MDefinition * length() const { return getOperand(1); } MDefinition* index () const { return getOperand(2); } MDefinition* value() const { return getOperand(3); } |
| 7389 | |
| 7390 | Scalar::Type arrayType() const { return writeType(); } |
| 7391 | AliasSet getAliasSet() const override { |
| 7392 | return AliasSet::Store(AliasSet::UnboxedElement); |
| 7393 | } |
| 7394 | TruncateKind operandTruncateKind(size_t index) const override; |
| 7395 | |
| 7396 | bool canConsumeFloat32(MUse* use) const override { |
| 7397 | return use == getUseFor(3) && arrayType() == Scalar::Float32; |
| 7398 | } |
| 7399 | |
| 7400 | ALLOW_CLONE(MStoreTypedArrayElementHole)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MStoreTypedArrayElementHole (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7401 | }; |
| 7402 | |
| 7403 | // Compute an "effective address", i.e., a compound computation of the form: |
| 7404 | // base + index * scale + displacement |
| 7405 | class MEffectiveAddress : public MBinaryInstruction, public NoTypePolicy::Data { |
| 7406 | MEffectiveAddress(MDefinition* base, MDefinition* index, Scale scale, |
| 7407 | int32_t displacement) |
| 7408 | : MBinaryInstruction(classOpcode, base, index), |
| 7409 | scale_(scale), |
| 7410 | displacement_(displacement) { |
| 7411 | MOZ_ASSERT(base->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(base->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("base->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7411); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 7411; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7412 | MOZ_ASSERT(index->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7412); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 7412; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7413 | setMovable(); |
| 7414 | setResultType(MIRType::Int32); |
| 7415 | } |
| 7416 | |
| 7417 | Scale scale_; |
| 7418 | int32_t displacement_; |
| 7419 | |
| 7420 | public: |
| 7421 | INSTRUCTION_HEADER(EffectiveAddress) |
| 7422 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7423 | |
| 7424 | MDefinition* base() const { return lhs(); } |
| 7425 | MDefinition* index() const { return rhs(); } |
| 7426 | Scale scale() const { return scale_; } |
| 7427 | int32_t displacement() const { return displacement_; } |
| 7428 | |
| 7429 | ALLOW_CLONE(MEffectiveAddress)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MEffectiveAddress (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7430 | }; |
| 7431 | |
| 7432 | // Clamp input to range [0, 255] for Uint8ClampedArray. |
| 7433 | class MClampToUint8 : public MUnaryInstruction, public ClampPolicy::Data { |
| 7434 | explicit MClampToUint8(MDefinition* input) |
| 7435 | : MUnaryInstruction(classOpcode, input) { |
| 7436 | setResultType(MIRType::Int32); |
| 7437 | setMovable(); |
| 7438 | } |
| 7439 | |
| 7440 | public: |
| 7441 | INSTRUCTION_HEADER(ClampToUint8) |
| 7442 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7443 | |
| 7444 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 7445 | |
| 7446 | bool congruentTo(const MDefinition* ins) const override { |
| 7447 | return congruentIfOperandsEqual(ins); |
| 7448 | } |
| 7449 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 7450 | void computeRange(TempAllocator& alloc) override; |
| 7451 | |
| 7452 | ALLOW_CLONE(MClampToUint8)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MClampToUint8 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7453 | }; |
| 7454 | |
| 7455 | class MLoadFixedSlot : public MUnaryInstruction, |
| 7456 | public SingleObjectPolicy::Data { |
| 7457 | size_t slot_; |
| 7458 | bool usedAsPropertyKey_ = false; |
| 7459 | |
| 7460 | protected: |
| 7461 | MLoadFixedSlot(MDefinition* obj, size_t slot) |
| 7462 | : MUnaryInstruction(classOpcode, obj), slot_(slot) { |
| 7463 | setResultType(MIRType::Value); |
| 7464 | setMovable(); |
| 7465 | } |
| 7466 | |
| 7467 | public: |
| 7468 | INSTRUCTION_HEADER(LoadFixedSlot) |
| 7469 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7470 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 7471 | |
| 7472 | size_t slot() const { return slot_; } |
| 7473 | bool congruentTo(const MDefinition* ins) const override { |
| 7474 | if (!ins->isLoadFixedSlot()) { |
| 7475 | return false; |
| 7476 | } |
| 7477 | if (slot() != ins->toLoadFixedSlot()->slot()) { |
| 7478 | return false; |
| 7479 | } |
| 7480 | return congruentIfOperandsEqual(ins); |
| 7481 | } |
| 7482 | |
| 7483 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 7484 | |
| 7485 | AliasSet getAliasSet() const override { |
| 7486 | return AliasSet::Load(AliasSet::FixedSlot); |
| 7487 | } |
| 7488 | |
| 7489 | AliasType mightAlias(const MDefinition* store) const override; |
| 7490 | |
| 7491 | #ifdef JS_JITSPEW1 |
| 7492 | void printOpcode(GenericPrinter& out) const override; |
| 7493 | #endif |
| 7494 | |
| 7495 | void setUsedAsPropertyKey() { usedAsPropertyKey_ = true; } |
| 7496 | bool usedAsPropertyKey() const { return usedAsPropertyKey_; } |
| 7497 | |
| 7498 | ALLOW_CLONE(MLoadFixedSlot)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadFixedSlot (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7499 | }; |
| 7500 | |
| 7501 | class MLoadFixedSlotAndUnbox : public MUnaryInstruction, |
| 7502 | public SingleObjectPolicy::Data { |
| 7503 | size_t slot_; |
| 7504 | MUnbox::Mode mode_; |
| 7505 | bool usedAsPropertyKey_; |
| 7506 | |
| 7507 | MLoadFixedSlotAndUnbox(MDefinition* obj, size_t slot, MUnbox::Mode mode, |
| 7508 | MIRType type, bool usedAsPropertyKey = false) |
| 7509 | : MUnaryInstruction(classOpcode, obj), |
| 7510 | slot_(slot), |
| 7511 | mode_(mode), |
| 7512 | usedAsPropertyKey_(usedAsPropertyKey) { |
| 7513 | setResultType(type); |
| 7514 | setMovable(); |
| 7515 | if (mode_ == MUnbox::Fallible) { |
| 7516 | setGuard(); |
| 7517 | } |
| 7518 | } |
| 7519 | |
| 7520 | public: |
| 7521 | INSTRUCTION_HEADER(LoadFixedSlotAndUnbox) |
| 7522 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7523 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 7524 | |
| 7525 | size_t slot() const { return slot_; } |
| 7526 | MUnbox::Mode mode() const { return mode_; } |
| 7527 | bool fallible() const { return mode_ != MUnbox::Infallible; } |
| 7528 | bool congruentTo(const MDefinition* ins) const override { |
| 7529 | if (!ins->isLoadFixedSlotAndUnbox() || |
| 7530 | slot() != ins->toLoadFixedSlotAndUnbox()->slot() || |
| 7531 | mode() != ins->toLoadFixedSlotAndUnbox()->mode()) { |
| 7532 | return false; |
| 7533 | } |
| 7534 | return congruentIfOperandsEqual(ins); |
| 7535 | } |
| 7536 | |
| 7537 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 7538 | |
| 7539 | AliasSet getAliasSet() const override { |
| 7540 | return AliasSet::Load(AliasSet::FixedSlot); |
| 7541 | } |
| 7542 | |
| 7543 | AliasType mightAlias(const MDefinition* store) const override; |
| 7544 | |
| 7545 | #ifdef JS_JITSPEW1 |
| 7546 | void printOpcode(GenericPrinter& out) const override; |
| 7547 | #endif |
| 7548 | |
| 7549 | bool usedAsPropertyKey() const { return usedAsPropertyKey_; } |
| 7550 | |
| 7551 | ALLOW_CLONE(MLoadFixedSlotAndUnbox)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadFixedSlotAndUnbox (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }; |
| 7552 | }; |
| 7553 | |
| 7554 | class MLoadDynamicSlotAndUnbox : public MUnaryInstruction, |
| 7555 | public NoTypePolicy::Data { |
| 7556 | size_t slot_; |
| 7557 | MUnbox::Mode mode_; |
| 7558 | bool usedAsPropertyKey_ = false; |
| 7559 | |
| 7560 | MLoadDynamicSlotAndUnbox(MDefinition* slots, size_t slot, MUnbox::Mode mode, |
| 7561 | MIRType type, bool usedAsPropertyKey = false) |
| 7562 | : MUnaryInstruction(classOpcode, slots), |
| 7563 | slot_(slot), |
| 7564 | mode_(mode), |
| 7565 | usedAsPropertyKey_(usedAsPropertyKey) { |
| 7566 | setResultType(type); |
| 7567 | setMovable(); |
| 7568 | if (mode_ == MUnbox::Fallible) { |
| 7569 | setGuard(); |
| 7570 | } |
| 7571 | } |
| 7572 | |
| 7573 | public: |
| 7574 | INSTRUCTION_HEADER(LoadDynamicSlotAndUnbox) |
| 7575 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7576 | NAMED_OPERANDS((0, slots))MDefinition* slots() const { return getOperand(0); } |
| 7577 | |
| 7578 | size_t slot() const { return slot_; } |
| 7579 | MUnbox::Mode mode() const { return mode_; } |
| 7580 | bool fallible() const { return mode_ != MUnbox::Infallible; } |
| 7581 | |
| 7582 | bool congruentTo(const MDefinition* ins) const override { |
| 7583 | if (!ins->isLoadDynamicSlotAndUnbox() || |
| 7584 | slot() != ins->toLoadDynamicSlotAndUnbox()->slot() || |
| 7585 | mode() != ins->toLoadDynamicSlotAndUnbox()->mode()) { |
| 7586 | return false; |
| 7587 | } |
| 7588 | return congruentIfOperandsEqual(ins); |
| 7589 | } |
| 7590 | |
| 7591 | AliasSet getAliasSet() const override { |
| 7592 | return AliasSet::Load(AliasSet::DynamicSlot); |
| 7593 | } |
| 7594 | |
| 7595 | #ifdef JS_JITSPEW1 |
| 7596 | void printOpcode(GenericPrinter& out) const override; |
| 7597 | #endif |
| 7598 | |
| 7599 | bool usedAsPropertyKey() const { return usedAsPropertyKey_; } |
| 7600 | |
| 7601 | ALLOW_CLONE(MLoadDynamicSlotAndUnbox)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadDynamicSlotAndUnbox (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; }; |
| 7602 | }; |
| 7603 | |
| 7604 | class MStoreFixedSlot |
| 7605 | : public MBinaryInstruction, |
| 7606 | public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1>>::Data { |
| 7607 | bool needsBarrier_; |
| 7608 | size_t slot_; |
| 7609 | |
| 7610 | MStoreFixedSlot(MDefinition* obj, MDefinition* rval, size_t slot, |
| 7611 | bool barrier) |
| 7612 | : MBinaryInstruction(classOpcode, obj, rval), |
| 7613 | needsBarrier_(barrier), |
| 7614 | slot_(slot) {} |
| 7615 | |
| 7616 | public: |
| 7617 | INSTRUCTION_HEADER(StoreFixedSlot) |
| 7618 | NAMED_OPERANDS((0, object), (1, value))MDefinition* object() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } |
| 7619 | |
| 7620 | static MStoreFixedSlot* NewUnbarriered(TempAllocator& alloc, MDefinition* obj, |
| 7621 | size_t slot, MDefinition* rval) { |
| 7622 | return new (alloc) MStoreFixedSlot(obj, rval, slot, false); |
| 7623 | } |
| 7624 | static MStoreFixedSlot* NewBarriered(TempAllocator& alloc, MDefinition* obj, |
| 7625 | size_t slot, MDefinition* rval) { |
| 7626 | return new (alloc) MStoreFixedSlot(obj, rval, slot, true); |
| 7627 | } |
| 7628 | |
| 7629 | size_t slot() const { return slot_; } |
| 7630 | |
| 7631 | AliasSet getAliasSet() const override { |
| 7632 | return AliasSet::Store(AliasSet::FixedSlot); |
| 7633 | } |
| 7634 | bool needsBarrier() const { return needsBarrier_; } |
| 7635 | void setNeedsBarrier(bool needsBarrier = true) { |
| 7636 | needsBarrier_ = needsBarrier; |
| 7637 | } |
| 7638 | |
| 7639 | #ifdef JS_JITSPEW1 |
| 7640 | void printOpcode(GenericPrinter& out) const override; |
| 7641 | #endif |
| 7642 | |
| 7643 | ALLOW_CLONE(MStoreFixedSlot)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MStoreFixedSlot (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7644 | }; |
| 7645 | |
| 7646 | class MGetPropertyCache : public MBinaryInstruction, |
| 7647 | public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, |
| 7648 | CacheIdPolicy<1>>::Data { |
| 7649 | MGetPropertyCache(MDefinition* obj, MDefinition* id) |
| 7650 | : MBinaryInstruction(classOpcode, obj, id) { |
| 7651 | setResultType(MIRType::Value); |
| 7652 | } |
| 7653 | |
| 7654 | public: |
| 7655 | INSTRUCTION_HEADER(GetPropertyCache) |
| 7656 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7657 | NAMED_OPERANDS((0, value), (1, idval))MDefinition* value() const { return getOperand(0); } MDefinition * idval() const { return getOperand(1); } |
| 7658 | }; |
| 7659 | |
| 7660 | class MGetPropSuperCache |
| 7661 | : public MTernaryInstruction, |
| 7662 | public MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, |
| 7663 | CacheIdPolicy<2>>::Data { |
| 7664 | MGetPropSuperCache(MDefinition* obj, MDefinition* receiver, MDefinition* id) |
| 7665 | : MTernaryInstruction(classOpcode, obj, receiver, id) { |
| 7666 | setResultType(MIRType::Value); |
| 7667 | setGuard(); |
| 7668 | } |
| 7669 | |
| 7670 | public: |
| 7671 | INSTRUCTION_HEADER(GetPropSuperCache) |
| 7672 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7673 | NAMED_OPERANDS((0, object), (1, receiver), (2, idval))MDefinition* object() const { return getOperand(0); } MDefinition * receiver() const { return getOperand(1); } MDefinition* idval () const { return getOperand(2); } |
| 7674 | }; |
| 7675 | |
| 7676 | // Guard the object's proto is |expected|. |
| 7677 | class MGuardProto : public MBinaryInstruction, public SingleObjectPolicy::Data { |
| 7678 | MGuardProto(MDefinition* obj, MDefinition* expected) |
| 7679 | : MBinaryInstruction(classOpcode, obj, expected) { |
| 7680 | MOZ_ASSERT(expected->isConstant() || expected->isNurseryObject())do { static_assert( mozilla::detail::AssertionConditionType< decltype(expected->isConstant() || expected->isNurseryObject ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(expected->isConstant() || expected->isNurseryObject ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("expected->isConstant() || expected->isNurseryObject()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7680); AnnotateMozCrashReason("MOZ_ASSERT" "(" "expected->isConstant() || expected->isNurseryObject()" ")"); do { *((volatile int*)__null) = 7680; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7681 | setGuard(); |
| 7682 | setMovable(); |
| 7683 | setResultType(MIRType::Object); |
| 7684 | } |
| 7685 | |
| 7686 | public: |
| 7687 | INSTRUCTION_HEADER(GuardProto) |
| 7688 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7689 | NAMED_OPERANDS((0, object), (1, expected))MDefinition* object() const { return getOperand(0); } MDefinition * expected() const { return getOperand(1); } |
| 7690 | |
| 7691 | bool congruentTo(const MDefinition* ins) const override { |
| 7692 | return congruentIfOperandsEqual(ins); |
| 7693 | } |
| 7694 | |
| 7695 | AliasSet getAliasSet() const override { |
| 7696 | return AliasSet::Load(AliasSet::ObjectFields); |
| 7697 | } |
| 7698 | AliasType mightAlias(const MDefinition* def) const override { |
| 7699 | // These instructions never modify the [[Prototype]]. |
| 7700 | if (def->isAddAndStoreSlot() || def->isAllocateAndStoreSlot()) { |
| 7701 | return AliasType::NoAlias; |
| 7702 | } |
| 7703 | return AliasType::MayAlias; |
| 7704 | } |
| 7705 | }; |
| 7706 | |
| 7707 | // Guard the object has no proto. |
| 7708 | class MGuardNullProto : public MUnaryInstruction, |
| 7709 | public SingleObjectPolicy::Data { |
| 7710 | explicit MGuardNullProto(MDefinition* obj) |
| 7711 | : MUnaryInstruction(classOpcode, obj) { |
| 7712 | setGuard(); |
| 7713 | setMovable(); |
| 7714 | setResultType(MIRType::Object); |
| 7715 | } |
| 7716 | |
| 7717 | public: |
| 7718 | INSTRUCTION_HEADER(GuardNullProto) |
| 7719 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7720 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 7721 | |
| 7722 | bool congruentTo(const MDefinition* ins) const override { |
| 7723 | return congruentIfOperandsEqual(ins); |
| 7724 | } |
| 7725 | AliasSet getAliasSet() const override { |
| 7726 | return AliasSet::Load(AliasSet::ObjectFields); |
| 7727 | } |
| 7728 | AliasType mightAlias(const MDefinition* def) const override { |
| 7729 | // These instructions never modify the [[Prototype]]. |
| 7730 | if (def->isAddAndStoreSlot() || def->isAllocateAndStoreSlot()) { |
| 7731 | return AliasType::NoAlias; |
| 7732 | } |
| 7733 | return AliasType::MayAlias; |
| 7734 | } |
| 7735 | }; |
| 7736 | |
| 7737 | // Guard on a specific Value. |
| 7738 | class MGuardValue : public MUnaryInstruction, public BoxInputsPolicy::Data { |
| 7739 | Value expected_; |
| 7740 | |
| 7741 | MGuardValue(MDefinition* val, const Value& expected) |
| 7742 | : MUnaryInstruction(classOpcode, val), expected_(expected) { |
| 7743 | setGuard(); |
| 7744 | setMovable(); |
| 7745 | setResultType(MIRType::Value); |
| 7746 | } |
| 7747 | |
| 7748 | public: |
| 7749 | INSTRUCTION_HEADER(GuardValue) |
| 7750 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7751 | NAMED_OPERANDS((0, value))MDefinition* value() const { return getOperand(0); } |
| 7752 | |
| 7753 | Value expected() const { return expected_; } |
| 7754 | |
| 7755 | bool congruentTo(const MDefinition* ins) const override { |
| 7756 | if (!ins->isGuardValue()) { |
| 7757 | return false; |
| 7758 | } |
| 7759 | if (expected() != ins->toGuardValue()->expected()) { |
| 7760 | return false; |
| 7761 | } |
| 7762 | return congruentIfOperandsEqual(ins); |
| 7763 | } |
| 7764 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 7765 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 7766 | }; |
| 7767 | |
| 7768 | // Guard on function flags |
| 7769 | class MGuardFunctionFlags : public MUnaryInstruction, |
| 7770 | public SingleObjectPolicy::Data { |
| 7771 | // At least one of the expected flags must be set, but not necessarily all |
| 7772 | // expected flags. |
| 7773 | uint16_t expectedFlags_; |
| 7774 | |
| 7775 | // None of the unexpected flags must be set. |
| 7776 | uint16_t unexpectedFlags_; |
| 7777 | |
| 7778 | explicit MGuardFunctionFlags(MDefinition* fun, uint16_t expectedFlags, |
| 7779 | uint16_t unexpectedFlags) |
| 7780 | : MUnaryInstruction(classOpcode, fun), |
| 7781 | expectedFlags_(expectedFlags), |
| 7782 | unexpectedFlags_(unexpectedFlags) { |
| 7783 | MOZ_ASSERT((expectedFlags & unexpectedFlags) == 0,do { static_assert( mozilla::detail::AssertionConditionType< decltype((expectedFlags & unexpectedFlags) == 0)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!((expectedFlags & unexpectedFlags) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("(expectedFlags & unexpectedFlags) == 0" " (" "Can't guard inconsistent flags" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7784); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(expectedFlags & unexpectedFlags) == 0" ") (" "Can't guard inconsistent flags" ")"); do { *((volatile int*)__null) = 7784; __attribute__((nomerge)) ::abort(); } while (false); } } while (false) |
| 7784 | "Can't guard inconsistent flags")do { static_assert( mozilla::detail::AssertionConditionType< decltype((expectedFlags & unexpectedFlags) == 0)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!((expectedFlags & unexpectedFlags) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("(expectedFlags & unexpectedFlags) == 0" " (" "Can't guard inconsistent flags" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7784); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(expectedFlags & unexpectedFlags) == 0" ") (" "Can't guard inconsistent flags" ")"); do { *((volatile int*)__null) = 7784; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 7785 | MOZ_ASSERT((expectedFlags | unexpectedFlags) != 0,do { static_assert( mozilla::detail::AssertionConditionType< decltype((expectedFlags | unexpectedFlags) != 0)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!((expectedFlags | unexpectedFlags) != 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("(expectedFlags | unexpectedFlags) != 0" " (" "Can't guard zero flags" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(expectedFlags | unexpectedFlags) != 0" ") (" "Can't guard zero flags" ")"); do { *((volatile int*)__null ) = 7786; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false) |
| 7786 | "Can't guard zero flags")do { static_assert( mozilla::detail::AssertionConditionType< decltype((expectedFlags | unexpectedFlags) != 0)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!((expectedFlags | unexpectedFlags) != 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("(expectedFlags | unexpectedFlags) != 0" " (" "Can't guard zero flags" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7786); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(expectedFlags | unexpectedFlags) != 0" ") (" "Can't guard zero flags" ")"); do { *((volatile int*)__null ) = 7786; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); |
| 7787 | setGuard(); |
| 7788 | setMovable(); |
| 7789 | setResultType(MIRType::Object); |
| 7790 | } |
| 7791 | |
| 7792 | public: |
| 7793 | INSTRUCTION_HEADER(GuardFunctionFlags) |
| 7794 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7795 | NAMED_OPERANDS((0, function))MDefinition* function() const { return getOperand(0); } |
| 7796 | |
| 7797 | uint16_t expectedFlags() const { return expectedFlags_; }; |
| 7798 | uint16_t unexpectedFlags() const { return unexpectedFlags_; }; |
| 7799 | |
| 7800 | bool congruentTo(const MDefinition* ins) const override { |
| 7801 | if (!ins->isGuardFunctionFlags()) { |
| 7802 | return false; |
| 7803 | } |
| 7804 | if (expectedFlags() != ins->toGuardFunctionFlags()->expectedFlags()) { |
| 7805 | return false; |
| 7806 | } |
| 7807 | if (unexpectedFlags() != ins->toGuardFunctionFlags()->unexpectedFlags()) { |
| 7808 | return false; |
| 7809 | } |
| 7810 | return congruentIfOperandsEqual(ins); |
| 7811 | } |
| 7812 | AliasSet getAliasSet() const override { |
| 7813 | return AliasSet::Load(AliasSet::ObjectFields); |
| 7814 | } |
| 7815 | }; |
| 7816 | |
| 7817 | // Guard on an object's identity, inclusively or exclusively. |
| 7818 | class MGuardObjectIdentity : public MBinaryInstruction, |
| 7819 | public SingleObjectPolicy::Data { |
| 7820 | bool bailOnEquality_; |
| 7821 | |
| 7822 | MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, |
| 7823 | bool bailOnEquality) |
| 7824 | : MBinaryInstruction(classOpcode, obj, expected), |
| 7825 | bailOnEquality_(bailOnEquality) { |
| 7826 | setGuard(); |
| 7827 | setMovable(); |
| 7828 | setResultType(MIRType::Object); |
| 7829 | } |
| 7830 | |
| 7831 | public: |
| 7832 | INSTRUCTION_HEADER(GuardObjectIdentity) |
| 7833 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7834 | NAMED_OPERANDS((0, object), (1, expected))MDefinition* object() const { return getOperand(0); } MDefinition * expected() const { return getOperand(1); } |
| 7835 | |
| 7836 | bool bailOnEquality() const { return bailOnEquality_; } |
| 7837 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 7838 | bool congruentTo(const MDefinition* ins) const override { |
| 7839 | if (!ins->isGuardObjectIdentity()) { |
| 7840 | return false; |
| 7841 | } |
| 7842 | if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality()) { |
| 7843 | return false; |
| 7844 | } |
| 7845 | return congruentIfOperandsEqual(ins); |
| 7846 | } |
| 7847 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 7848 | }; |
| 7849 | |
| 7850 | // Guard on a specific JSFunction. Used instead of MGuardObjectIdentity, |
| 7851 | // so we can store some metadata related to the expected function. |
| 7852 | class MGuardSpecificFunction : public MBinaryInstruction, |
| 7853 | public SingleObjectPolicy::Data { |
| 7854 | uint16_t nargs_; |
| 7855 | FunctionFlags flags_; |
| 7856 | |
| 7857 | MGuardSpecificFunction(MDefinition* obj, MDefinition* expected, |
| 7858 | uint16_t nargs, FunctionFlags flags) |
| 7859 | : MBinaryInstruction(classOpcode, obj, expected), |
| 7860 | nargs_(nargs), |
| 7861 | flags_(flags) { |
| 7862 | MOZ_ASSERT(expected->isConstant() || expected->isNurseryObject())do { static_assert( mozilla::detail::AssertionConditionType< decltype(expected->isConstant() || expected->isNurseryObject ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(expected->isConstant() || expected->isNurseryObject ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("expected->isConstant() || expected->isNurseryObject()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "expected->isConstant() || expected->isNurseryObject()" ")"); do { *((volatile int*)__null) = 7862; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7863 | setGuard(); |
| 7864 | setMovable(); |
| 7865 | setResultType(MIRType::Object); |
| 7866 | } |
| 7867 | |
| 7868 | public: |
| 7869 | INSTRUCTION_HEADER(GuardSpecificFunction) |
| 7870 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7871 | NAMED_OPERANDS((0, function), (1, expected))MDefinition* function() const { return getOperand(0); } MDefinition * expected() const { return getOperand(1); } |
| 7872 | |
| 7873 | uint16_t nargs() const { return nargs_; } |
| 7874 | FunctionFlags flags() const { return flags_; } |
| 7875 | |
| 7876 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 7877 | bool congruentTo(const MDefinition* ins) const override { |
| 7878 | if (!ins->isGuardSpecificFunction()) { |
| 7879 | return false; |
| 7880 | } |
| 7881 | |
| 7882 | auto* other = ins->toGuardSpecificFunction(); |
| 7883 | if (nargs() != other->nargs() || |
| 7884 | flags().toRaw() != other->flags().toRaw()) { |
| 7885 | return false; |
| 7886 | } |
| 7887 | return congruentIfOperandsEqual(other); |
| 7888 | } |
| 7889 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 7890 | }; |
| 7891 | |
| 7892 | class MGuardSpecificSymbol : public MUnaryInstruction, |
| 7893 | public SymbolPolicy<0>::Data { |
| 7894 | CompilerGCPointer<JS::Symbol*> expected_; |
| 7895 | |
| 7896 | MGuardSpecificSymbol(MDefinition* symbol, JS::Symbol* expected) |
| 7897 | : MUnaryInstruction(classOpcode, symbol), expected_(expected) { |
| 7898 | setGuard(); |
| 7899 | setMovable(); |
| 7900 | setResultType(MIRType::Symbol); |
| 7901 | } |
| 7902 | |
| 7903 | public: |
| 7904 | INSTRUCTION_HEADER(GuardSpecificSymbol) |
| 7905 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7906 | NAMED_OPERANDS((0, symbol))MDefinition* symbol() const { return getOperand(0); } |
| 7907 | |
| 7908 | JS::Symbol* expected() const { return expected_; } |
| 7909 | |
| 7910 | bool congruentTo(const MDefinition* ins) const override { |
| 7911 | if (!ins->isGuardSpecificSymbol()) { |
| 7912 | return false; |
| 7913 | } |
| 7914 | if (expected() != ins->toGuardSpecificSymbol()->expected()) { |
| 7915 | return false; |
| 7916 | } |
| 7917 | return congruentIfOperandsEqual(ins); |
| 7918 | } |
| 7919 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 7920 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 7921 | }; |
| 7922 | |
| 7923 | class MGuardTagNotEqual |
| 7924 | : public MBinaryInstruction, |
| 7925 | public MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>>::Data { |
| 7926 | MGuardTagNotEqual(MDefinition* left, MDefinition* right) |
| 7927 | : MBinaryInstruction(classOpcode, left, right) { |
| 7928 | setGuard(); |
| 7929 | setMovable(); |
| 7930 | setCommutative(); |
| 7931 | } |
| 7932 | |
| 7933 | public: |
| 7934 | INSTRUCTION_HEADER(GuardTagNotEqual) |
| 7935 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7936 | |
| 7937 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 7938 | |
| 7939 | bool congruentTo(const MDefinition* ins) const override { |
| 7940 | return binaryCongruentTo(ins); |
| 7941 | } |
| 7942 | }; |
| 7943 | |
| 7944 | // Load from vp[slot] (slots that are not inline in an object). |
| 7945 | class MLoadDynamicSlot : public MUnaryInstruction, public NoTypePolicy::Data { |
| 7946 | uint32_t slot_; |
| 7947 | bool usedAsPropertyKey_ = false; |
| 7948 | |
| 7949 | MLoadDynamicSlot(MDefinition* slots, uint32_t slot) |
| 7950 | : MUnaryInstruction(classOpcode, slots), slot_(slot) { |
| 7951 | setResultType(MIRType::Value); |
| 7952 | setMovable(); |
| 7953 | MOZ_ASSERT(slots->type() == MIRType::Slots)do { static_assert( mozilla::detail::AssertionConditionType< decltype(slots->type() == MIRType::Slots)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(slots->type() == MIRType:: Slots))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("slots->type() == MIRType::Slots", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7953); AnnotateMozCrashReason("MOZ_ASSERT" "(" "slots->type() == MIRType::Slots" ")"); do { *((volatile int*)__null) = 7953; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7954 | } |
| 7955 | |
| 7956 | public: |
| 7957 | INSTRUCTION_HEADER(LoadDynamicSlot) |
| 7958 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 7959 | NAMED_OPERANDS((0, slots))MDefinition* slots() const { return getOperand(0); } |
| 7960 | |
| 7961 | uint32_t slot() const { return slot_; } |
| 7962 | |
| 7963 | HashNumber valueHash() const override; |
| 7964 | bool congruentTo(const MDefinition* ins) const override { |
| 7965 | if (!ins->isLoadDynamicSlot()) { |
| 7966 | return false; |
| 7967 | } |
| 7968 | if (slot() != ins->toLoadDynamicSlot()->slot()) { |
| 7969 | return false; |
| 7970 | } |
| 7971 | return congruentIfOperandsEqual(ins); |
| 7972 | } |
| 7973 | |
| 7974 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 7975 | |
| 7976 | AliasSet getAliasSet() const override { |
| 7977 | MOZ_ASSERT(slots()->type() == MIRType::Slots)do { static_assert( mozilla::detail::AssertionConditionType< decltype(slots()->type() == MIRType::Slots)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(slots()->type() == MIRType ::Slots))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("slots()->type() == MIRType::Slots", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 7977); AnnotateMozCrashReason("MOZ_ASSERT" "(" "slots()->type() == MIRType::Slots" ")"); do { *((volatile int*)__null) = 7977; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7978 | return AliasSet::Load(AliasSet::DynamicSlot); |
| 7979 | } |
| 7980 | AliasType mightAlias(const MDefinition* store) const override; |
| 7981 | |
| 7982 | #ifdef JS_JITSPEW1 |
| 7983 | void printOpcode(GenericPrinter& out) const override; |
| 7984 | #endif |
| 7985 | |
| 7986 | void setUsedAsPropertyKey() { usedAsPropertyKey_ = true; } |
| 7987 | bool usedAsPropertyKey() const { return usedAsPropertyKey_; } |
| 7988 | |
| 7989 | ALLOW_CLONE(MLoadDynamicSlot)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MLoadDynamicSlot (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 7990 | }; |
| 7991 | |
| 7992 | class MAddAndStoreSlot |
| 7993 | : public MBinaryInstruction, |
| 7994 | public MixPolicy<SingleObjectPolicy, BoxPolicy<1>>::Data { |
| 7995 | public: |
| 7996 | enum class Kind { |
| 7997 | FixedSlot, |
| 7998 | DynamicSlot, |
| 7999 | }; |
| 8000 | |
| 8001 | private: |
| 8002 | Kind kind_; |
| 8003 | uint32_t slotOffset_; |
| 8004 | CompilerShape shape_; |
| 8005 | |
| 8006 | MAddAndStoreSlot(MDefinition* obj, MDefinition* value, Kind kind, |
| 8007 | uint32_t slotOffset, Shape* shape) |
| 8008 | : MBinaryInstruction(classOpcode, obj, value), |
| 8009 | kind_(kind), |
| 8010 | slotOffset_(slotOffset), |
| 8011 | shape_(shape) {} |
| 8012 | |
| 8013 | public: |
| 8014 | INSTRUCTION_HEADER(AddAndStoreSlot) |
| 8015 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8016 | NAMED_OPERANDS((0, object), (1, value))MDefinition* object() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } |
| 8017 | |
| 8018 | Kind kind() const { return kind_; } |
| 8019 | uint32_t slotOffset() const { return slotOffset_; } |
| 8020 | Shape* shape() const { return shape_; } |
| 8021 | |
| 8022 | AliasSet getAliasSet() const override { |
| 8023 | return AliasSet::Store(AliasSet::ObjectFields | |
| 8024 | (kind() == Kind::FixedSlot ? AliasSet::FixedSlot |
| 8025 | : AliasSet::DynamicSlot)); |
| 8026 | } |
| 8027 | }; |
| 8028 | |
| 8029 | // Store to vp[slot] (slots that are not inline in an object). |
| 8030 | class MStoreDynamicSlot : public MBinaryInstruction, |
| 8031 | public NoFloatPolicy<1>::Data { |
| 8032 | uint32_t slot_; |
| 8033 | bool needsBarrier_; |
| 8034 | |
| 8035 | MStoreDynamicSlot(MDefinition* slots, uint32_t slot, MDefinition* value, |
| 8036 | bool barrier) |
| 8037 | : MBinaryInstruction(classOpcode, slots, value), |
| 8038 | slot_(slot), |
| 8039 | needsBarrier_(barrier) { |
| 8040 | MOZ_ASSERT(slots->type() == MIRType::Slots)do { static_assert( mozilla::detail::AssertionConditionType< decltype(slots->type() == MIRType::Slots)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(slots->type() == MIRType:: Slots))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("slots->type() == MIRType::Slots", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8040); AnnotateMozCrashReason("MOZ_ASSERT" "(" "slots->type() == MIRType::Slots" ")"); do { *((volatile int*)__null) = 8040; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8041 | } |
| 8042 | |
| 8043 | public: |
| 8044 | INSTRUCTION_HEADER(StoreDynamicSlot) |
| 8045 | NAMED_OPERANDS((0, slots), (1, value))MDefinition* slots() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } |
| 8046 | |
| 8047 | static MStoreDynamicSlot* NewUnbarriered(TempAllocator& alloc, |
| 8048 | MDefinition* slots, uint32_t slot, |
| 8049 | MDefinition* value) { |
| 8050 | return new (alloc) MStoreDynamicSlot(slots, slot, value, false); |
| 8051 | } |
| 8052 | static MStoreDynamicSlot* NewBarriered(TempAllocator& alloc, |
| 8053 | MDefinition* slots, uint32_t slot, |
| 8054 | MDefinition* value) { |
| 8055 | return new (alloc) MStoreDynamicSlot(slots, slot, value, true); |
| 8056 | } |
| 8057 | |
| 8058 | uint32_t slot() const { return slot_; } |
| 8059 | bool needsBarrier() const { return needsBarrier_; } |
| 8060 | AliasSet getAliasSet() const override { |
| 8061 | return AliasSet::Store(AliasSet::DynamicSlot); |
| 8062 | } |
| 8063 | |
| 8064 | #ifdef JS_JITSPEW1 |
| 8065 | void printOpcode(GenericPrinter& out) const override; |
| 8066 | #endif |
| 8067 | |
| 8068 | ALLOW_CLONE(MStoreDynamicSlot)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MStoreDynamicSlot (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 8069 | }; |
| 8070 | |
| 8071 | class MSetPropertyCache : public MTernaryInstruction, |
| 8072 | public MixPolicy<SingleObjectPolicy, CacheIdPolicy<1>, |
| 8073 | NoFloatPolicy<2>>::Data { |
| 8074 | bool strict_ : 1; |
| 8075 | |
| 8076 | MSetPropertyCache(MDefinition* obj, MDefinition* id, MDefinition* value, |
| 8077 | bool strict) |
| 8078 | : MTernaryInstruction(classOpcode, obj, id, value), strict_(strict) {} |
| 8079 | |
| 8080 | public: |
| 8081 | INSTRUCTION_HEADER(SetPropertyCache) |
| 8082 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8083 | NAMED_OPERANDS((0, object), (1, idval), (2, value))MDefinition* object() const { return getOperand(0); } MDefinition * idval() const { return getOperand(1); } MDefinition* value( ) const { return getOperand(2); } |
| 8084 | |
| 8085 | bool strict() const { return strict_; } |
| 8086 | }; |
| 8087 | |
| 8088 | class MMegamorphicSetElement : public MTernaryInstruction, |
| 8089 | public MegamorphicSetElementPolicy::Data { |
| 8090 | bool strict_; |
| 8091 | |
| 8092 | MMegamorphicSetElement(MDefinition* object, MDefinition* index, |
| 8093 | MDefinition* value, bool strict) |
| 8094 | : MTernaryInstruction(classOpcode, object, index, value), |
| 8095 | strict_(strict) {} |
| 8096 | |
| 8097 | public: |
| 8098 | INSTRUCTION_HEADER(MegamorphicSetElement) |
| 8099 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8100 | NAMED_OPERANDS((0, object), (1, index), (2, value))MDefinition* object() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* value( ) const { return getOperand(2); } |
| 8101 | |
| 8102 | bool strict() const { return strict_; } |
| 8103 | |
| 8104 | bool possiblyCalls() const override { return true; } |
| 8105 | }; |
| 8106 | |
| 8107 | class MSetDOMProperty : public MBinaryInstruction, |
| 8108 | public MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>::Data { |
| 8109 | const JSJitSetterOp func_; |
| 8110 | Realm* setterRealm_; |
| 8111 | DOMObjectKind objectKind_; |
| 8112 | |
| 8113 | MSetDOMProperty(const JSJitSetterOp func, DOMObjectKind objectKind, |
| 8114 | Realm* setterRealm, MDefinition* obj, MDefinition* val) |
| 8115 | : MBinaryInstruction(classOpcode, obj, val), |
| 8116 | func_(func), |
| 8117 | setterRealm_(setterRealm), |
| 8118 | objectKind_(objectKind) {} |
| 8119 | |
| 8120 | public: |
| 8121 | INSTRUCTION_HEADER(SetDOMProperty) |
| 8122 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8123 | NAMED_OPERANDS((0, object), (1, value))MDefinition* object() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } |
| 8124 | |
| 8125 | JSJitSetterOp fun() const { return func_; } |
| 8126 | Realm* setterRealm() const { return setterRealm_; } |
| 8127 | DOMObjectKind objectKind() const { return objectKind_; } |
| 8128 | |
| 8129 | bool possiblyCalls() const override { return true; } |
| 8130 | }; |
| 8131 | |
| 8132 | class MGetDOMPropertyBase : public MVariadicInstruction, |
| 8133 | public ObjectPolicy<0>::Data { |
| 8134 | const JSJitInfo* info_; |
| 8135 | |
| 8136 | protected: |
| 8137 | MGetDOMPropertyBase(Opcode op, const JSJitInfo* jitinfo) |
| 8138 | : MVariadicInstruction(op), info_(jitinfo) { |
| 8139 | MOZ_ASSERT(jitinfo)do { static_assert( mozilla::detail::AssertionConditionType< decltype(jitinfo)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(jitinfo))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("jitinfo", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8139); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitinfo" ")" ); do { *((volatile int*)__null) = 8139; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8140 | MOZ_ASSERT(jitinfo->type() == JSJitInfo::Getter)do { static_assert( mozilla::detail::AssertionConditionType< decltype(jitinfo->type() == JSJitInfo::Getter)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(jitinfo->type() == JSJitInfo::Getter))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("jitinfo->type() == JSJitInfo::Getter" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitinfo->type() == JSJitInfo::Getter" ")"); do { *((volatile int*)__null) = 8140; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8141 | |
| 8142 | // We are movable iff the jitinfo says we can be. |
| 8143 | if (isDomMovable()) { |
| 8144 | MOZ_ASSERT(jitinfo->aliasSet() != JSJitInfo::AliasEverything)do { static_assert( mozilla::detail::AssertionConditionType< decltype(jitinfo->aliasSet() != JSJitInfo::AliasEverything )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(jitinfo->aliasSet() != JSJitInfo::AliasEverything ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "jitinfo->aliasSet() != JSJitInfo::AliasEverything", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitinfo->aliasSet() != JSJitInfo::AliasEverything" ")"); do { *((volatile int*)__null) = 8144; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8145 | setMovable(); |
| 8146 | } else { |
| 8147 | // If we're not movable, that means we shouldn't be DCEd either, |
| 8148 | // because we might throw an exception when called, and getting rid |
| 8149 | // of that is observable. |
| 8150 | setGuard(); |
| 8151 | } |
| 8152 | |
| 8153 | setResultType(MIRType::Value); |
| 8154 | } |
| 8155 | |
| 8156 | const JSJitInfo* info() const { return info_; } |
| 8157 | |
| 8158 | [[nodiscard]] bool init(TempAllocator& alloc, MDefinition* obj, |
| 8159 | MDefinition* guard, MDefinition* globalGuard) { |
| 8160 | MOZ_ASSERT(obj)do { static_assert( mozilla::detail::AssertionConditionType< decltype(obj)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(obj))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("obj", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8160); AnnotateMozCrashReason("MOZ_ASSERT" "(" "obj" ")"); do { *((volatile int*)__null) = 8160; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 8161 | // guard can be null. |
| 8162 | // globalGuard can be null. |
| 8163 | size_t operandCount = 1; |
| 8164 | if (guard) { |
| 8165 | ++operandCount; |
| 8166 | } |
| 8167 | if (globalGuard) { |
| 8168 | ++operandCount; |
| 8169 | } |
| 8170 | if (!MVariadicInstruction::init(alloc, operandCount)) { |
| 8171 | return false; |
| 8172 | } |
| 8173 | initOperand(0, obj); |
| 8174 | |
| 8175 | size_t operandIndex = 1; |
| 8176 | // Pin the guard, if we have one as an operand if we want to hoist later. |
| 8177 | if (guard) { |
| 8178 | initOperand(operandIndex++, guard); |
| 8179 | } |
| 8180 | |
| 8181 | // And the same for the global guard, if we have one. |
| 8182 | if (globalGuard) { |
| 8183 | initOperand(operandIndex, globalGuard); |
| 8184 | } |
| 8185 | |
| 8186 | return true; |
| 8187 | } |
| 8188 | |
| 8189 | public: |
| 8190 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 8191 | |
| 8192 | JSJitGetterOp fun() const { return info_->getter; } |
| 8193 | bool isInfallible() const { return info_->isInfallible; } |
| 8194 | bool isDomMovable() const { return info_->isMovable; } |
| 8195 | JSJitInfo::AliasSet domAliasSet() const { return info_->aliasSet(); } |
| 8196 | size_t domMemberSlotIndex() const { |
| 8197 | MOZ_ASSERT(info_->isAlwaysInSlot || info_->isLazilyCachedInSlot)do { static_assert( mozilla::detail::AssertionConditionType< decltype(info_->isAlwaysInSlot || info_->isLazilyCachedInSlot )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(info_->isAlwaysInSlot || info_->isLazilyCachedInSlot ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "info_->isAlwaysInSlot || info_->isLazilyCachedInSlot", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8197); AnnotateMozCrashReason("MOZ_ASSERT" "(" "info_->isAlwaysInSlot || info_->isLazilyCachedInSlot" ")"); do { *((volatile int*)__null) = 8197; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8198 | return info_->slotIndex; |
| 8199 | } |
| 8200 | bool valueMayBeInSlot() const { return info_->isLazilyCachedInSlot; } |
| 8201 | |
| 8202 | bool baseCongruentTo(const MGetDOMPropertyBase* ins) const { |
| 8203 | if (!isDomMovable()) { |
| 8204 | return false; |
| 8205 | } |
| 8206 | |
| 8207 | // Checking the jitinfo is the same as checking the constant function |
| 8208 | if (!(info() == ins->info())) { |
| 8209 | return false; |
| 8210 | } |
| 8211 | |
| 8212 | return congruentIfOperandsEqual(ins); |
| 8213 | } |
| 8214 | |
| 8215 | AliasSet getAliasSet() const override { |
| 8216 | JSJitInfo::AliasSet aliasSet = domAliasSet(); |
| 8217 | if (aliasSet == JSJitInfo::AliasNone) { |
| 8218 | return AliasSet::None(); |
| 8219 | } |
| 8220 | if (aliasSet == JSJitInfo::AliasDOMSets) { |
| 8221 | return AliasSet::Load(AliasSet::DOMProperty); |
| 8222 | } |
| 8223 | MOZ_ASSERT(aliasSet == JSJitInfo::AliasEverything)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliasSet == JSJitInfo::AliasEverything)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(aliasSet == JSJitInfo::AliasEverything))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aliasSet == JSJitInfo::AliasEverything" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliasSet == JSJitInfo::AliasEverything" ")"); do { *((volatile int*)__null) = 8223; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8224 | return AliasSet::Store(AliasSet::Any); |
| 8225 | } |
| 8226 | }; |
| 8227 | |
| 8228 | class MGetDOMProperty : public MGetDOMPropertyBase { |
| 8229 | Realm* getterRealm_; |
| 8230 | DOMObjectKind objectKind_; |
| 8231 | |
| 8232 | MGetDOMProperty(const JSJitInfo* jitinfo, DOMObjectKind objectKind, |
| 8233 | Realm* getterRealm) |
| 8234 | : MGetDOMPropertyBase(classOpcode, jitinfo), |
| 8235 | getterRealm_(getterRealm), |
| 8236 | objectKind_(objectKind) {} |
| 8237 | |
| 8238 | public: |
| 8239 | INSTRUCTION_HEADER(GetDOMProperty) |
| 8240 | |
| 8241 | static MGetDOMProperty* New(TempAllocator& alloc, const JSJitInfo* info, |
| 8242 | DOMObjectKind objectKind, Realm* getterRealm, |
| 8243 | MDefinition* obj, MDefinition* guard, |
| 8244 | MDefinition* globalGuard) { |
| 8245 | auto* res = new (alloc) MGetDOMProperty(info, objectKind, getterRealm); |
| 8246 | if (!res || !res->init(alloc, obj, guard, globalGuard)) { |
| 8247 | return nullptr; |
| 8248 | } |
| 8249 | return res; |
| 8250 | } |
| 8251 | |
| 8252 | Realm* getterRealm() const { return getterRealm_; } |
| 8253 | DOMObjectKind objectKind() const { return objectKind_; } |
| 8254 | |
| 8255 | bool congruentTo(const MDefinition* ins) const override { |
| 8256 | if (!ins->isGetDOMProperty()) { |
| 8257 | return false; |
| 8258 | } |
| 8259 | |
| 8260 | if (ins->toGetDOMProperty()->getterRealm() != getterRealm()) { |
| 8261 | return false; |
| 8262 | } |
| 8263 | |
| 8264 | return baseCongruentTo(ins->toGetDOMProperty()); |
| 8265 | } |
| 8266 | |
| 8267 | bool possiblyCalls() const override { return true; } |
| 8268 | }; |
| 8269 | |
| 8270 | class MGetDOMMember : public MGetDOMPropertyBase { |
| 8271 | explicit MGetDOMMember(const JSJitInfo* jitinfo) |
| 8272 | : MGetDOMPropertyBase(classOpcode, jitinfo) { |
| 8273 | setResultType(MIRTypeFromValueType(jitinfo->returnType())); |
| 8274 | } |
| 8275 | |
| 8276 | public: |
| 8277 | INSTRUCTION_HEADER(GetDOMMember) |
| 8278 | |
| 8279 | static MGetDOMMember* New(TempAllocator& alloc, const JSJitInfo* info, |
| 8280 | MDefinition* obj, MDefinition* guard, |
| 8281 | MDefinition* globalGuard) { |
| 8282 | auto* res = new (alloc) MGetDOMMember(info); |
| 8283 | if (!res || !res->init(alloc, obj, guard, globalGuard)) { |
| 8284 | return nullptr; |
| 8285 | } |
| 8286 | return res; |
| 8287 | } |
| 8288 | |
| 8289 | bool possiblyCalls() const override { return false; } |
| 8290 | |
| 8291 | bool congruentTo(const MDefinition* ins) const override { |
| 8292 | if (!ins->isGetDOMMember()) { |
| 8293 | return false; |
| 8294 | } |
| 8295 | |
| 8296 | return baseCongruentTo(ins->toGetDOMMember()); |
| 8297 | } |
| 8298 | }; |
| 8299 | |
| 8300 | class MLoadDOMExpandoValueGuardGeneration : public MUnaryInstruction, |
| 8301 | public SingleObjectPolicy::Data { |
| 8302 | JS::ExpandoAndGeneration* expandoAndGeneration_; |
| 8303 | uint64_t generation_; |
| 8304 | |
| 8305 | MLoadDOMExpandoValueGuardGeneration( |
| 8306 | MDefinition* proxy, JS::ExpandoAndGeneration* expandoAndGeneration, |
| 8307 | uint64_t generation) |
| 8308 | : MUnaryInstruction(classOpcode, proxy), |
| 8309 | expandoAndGeneration_(expandoAndGeneration), |
| 8310 | generation_(generation) { |
| 8311 | setGuard(); |
| 8312 | setMovable(); |
| 8313 | setResultType(MIRType::Value); |
| 8314 | } |
| 8315 | |
| 8316 | public: |
| 8317 | INSTRUCTION_HEADER(LoadDOMExpandoValueGuardGeneration) |
| 8318 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8319 | NAMED_OPERANDS((0, proxy))MDefinition* proxy() const { return getOperand(0); } |
| 8320 | |
| 8321 | JS::ExpandoAndGeneration* expandoAndGeneration() const { |
| 8322 | return expandoAndGeneration_; |
| 8323 | } |
| 8324 | uint64_t generation() const { return generation_; } |
| 8325 | |
| 8326 | bool congruentTo(const MDefinition* ins) const override { |
| 8327 | if (!ins->isLoadDOMExpandoValueGuardGeneration()) { |
| 8328 | return false; |
| 8329 | } |
| 8330 | const auto* other = ins->toLoadDOMExpandoValueGuardGeneration(); |
| 8331 | if (expandoAndGeneration() != other->expandoAndGeneration() || |
| 8332 | generation() != other->generation()) { |
| 8333 | return false; |
| 8334 | } |
| 8335 | return congruentIfOperandsEqual(ins); |
| 8336 | } |
| 8337 | AliasSet getAliasSet() const override { |
| 8338 | return AliasSet::Load(AliasSet::DOMProxyExpando); |
| 8339 | } |
| 8340 | }; |
| 8341 | |
| 8342 | // Inlined assembly for Math.floor(double | float32) -> int32. |
| 8343 | class MFloor : public MUnaryInstruction, public FloatingPointPolicy<0>::Data { |
| 8344 | explicit MFloor(MDefinition* num) : MUnaryInstruction(classOpcode, num) { |
| 8345 | setResultType(MIRType::Int32); |
| 8346 | specialization_ = MIRType::Double; |
| 8347 | setMovable(); |
| 8348 | } |
| 8349 | |
| 8350 | public: |
| 8351 | INSTRUCTION_HEADER(Floor) |
| 8352 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8353 | |
| 8354 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8355 | bool isFloat32Commutative() const override { return true; } |
| 8356 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 8357 | #ifdef DEBUG1 |
| 8358 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 8359 | #endif |
| 8360 | bool congruentTo(const MDefinition* ins) const override { |
| 8361 | return congruentIfOperandsEqual(ins); |
| 8362 | } |
| 8363 | void computeRange(TempAllocator& alloc) override; |
| 8364 | [[nodiscard]] bool writeRecoverData( |
| 8365 | CompactBufferWriter& writer) const override; |
| 8366 | bool canRecoverOnBailout() const override { return true; } |
| 8367 | |
| 8368 | ALLOW_CLONE(MFloor)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MFloor (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 8369 | }; |
| 8370 | |
| 8371 | // Inlined assembly version for Math.ceil(double | float32) -> int32. |
| 8372 | class MCeil : public MUnaryInstruction, public FloatingPointPolicy<0>::Data { |
| 8373 | explicit MCeil(MDefinition* num) : MUnaryInstruction(classOpcode, num) { |
| 8374 | setResultType(MIRType::Int32); |
| 8375 | specialization_ = MIRType::Double; |
| 8376 | setMovable(); |
| 8377 | } |
| 8378 | |
| 8379 | public: |
| 8380 | INSTRUCTION_HEADER(Ceil) |
| 8381 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8382 | |
| 8383 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8384 | bool isFloat32Commutative() const override { return true; } |
| 8385 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 8386 | #ifdef DEBUG1 |
| 8387 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 8388 | #endif |
| 8389 | bool congruentTo(const MDefinition* ins) const override { |
| 8390 | return congruentIfOperandsEqual(ins); |
| 8391 | } |
| 8392 | void computeRange(TempAllocator& alloc) override; |
| 8393 | [[nodiscard]] bool writeRecoverData( |
| 8394 | CompactBufferWriter& writer) const override; |
| 8395 | bool canRecoverOnBailout() const override { return true; } |
| 8396 | |
| 8397 | ALLOW_CLONE(MCeil)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MCeil (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 8398 | }; |
| 8399 | |
| 8400 | // Inlined version of Math.round(double | float32) -> int32. |
| 8401 | class MRound : public MUnaryInstruction, public FloatingPointPolicy<0>::Data { |
| 8402 | explicit MRound(MDefinition* num) : MUnaryInstruction(classOpcode, num) { |
| 8403 | setResultType(MIRType::Int32); |
| 8404 | specialization_ = MIRType::Double; |
| 8405 | setMovable(); |
| 8406 | } |
| 8407 | |
| 8408 | public: |
| 8409 | INSTRUCTION_HEADER(Round) |
| 8410 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8411 | |
| 8412 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8413 | |
| 8414 | bool isFloat32Commutative() const override { return true; } |
| 8415 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 8416 | #ifdef DEBUG1 |
| 8417 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 8418 | #endif |
| 8419 | bool congruentTo(const MDefinition* ins) const override { |
| 8420 | return congruentIfOperandsEqual(ins); |
| 8421 | } |
| 8422 | |
| 8423 | [[nodiscard]] bool writeRecoverData( |
| 8424 | CompactBufferWriter& writer) const override; |
| 8425 | bool canRecoverOnBailout() const override { return true; } |
| 8426 | |
| 8427 | ALLOW_CLONE(MRound)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MRound (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 8428 | }; |
| 8429 | |
| 8430 | // Inlined version of Math.trunc(double | float32) -> int32. |
| 8431 | class MTrunc : public MUnaryInstruction, public FloatingPointPolicy<0>::Data { |
| 8432 | explicit MTrunc(MDefinition* num) : MUnaryInstruction(classOpcode, num) { |
| 8433 | setResultType(MIRType::Int32); |
| 8434 | specialization_ = MIRType::Double; |
| 8435 | setMovable(); |
| 8436 | } |
| 8437 | |
| 8438 | public: |
| 8439 | INSTRUCTION_HEADER(Trunc) |
| 8440 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8441 | |
| 8442 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8443 | |
| 8444 | bool isFloat32Commutative() const override { return true; } |
| 8445 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 8446 | #ifdef DEBUG1 |
| 8447 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 8448 | #endif |
| 8449 | bool congruentTo(const MDefinition* ins) const override { |
| 8450 | return congruentIfOperandsEqual(ins); |
| 8451 | } |
| 8452 | |
| 8453 | [[nodiscard]] bool writeRecoverData( |
| 8454 | CompactBufferWriter& writer) const override; |
| 8455 | bool canRecoverOnBailout() const override { return true; } |
| 8456 | |
| 8457 | ALLOW_CLONE(MTrunc)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MTrunc (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 8458 | }; |
| 8459 | |
| 8460 | // NearbyInt rounds the floating-point input to the nearest integer, according |
| 8461 | // to the RoundingMode. |
| 8462 | class MNearbyInt : public MUnaryInstruction, |
| 8463 | public FloatingPointPolicy<0>::Data { |
| 8464 | RoundingMode roundingMode_; |
| 8465 | |
| 8466 | explicit MNearbyInt(MDefinition* num, MIRType resultType, |
| 8467 | RoundingMode roundingMode) |
| 8468 | : MUnaryInstruction(classOpcode, num), roundingMode_(roundingMode) { |
| 8469 | MOZ_ASSERT(HasAssemblerSupport(roundingMode))do { static_assert( mozilla::detail::AssertionConditionType< decltype(HasAssemblerSupport(roundingMode))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(HasAssemblerSupport(roundingMode )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("HasAssemblerSupport(roundingMode)", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8469); AnnotateMozCrashReason("MOZ_ASSERT" "(" "HasAssemblerSupport(roundingMode)" ")"); do { *((volatile int*)__null) = 8469; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8470 | |
| 8471 | MOZ_ASSERT(IsFloatingPointType(resultType))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsFloatingPointType(resultType))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsFloatingPointType(resultType )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("IsFloatingPointType(resultType)", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(resultType)" ")"); do { *((volatile int*)__null) = 8471; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8472 | setResultType(resultType); |
| 8473 | specialization_ = resultType; |
| 8474 | |
| 8475 | setMovable(); |
| 8476 | } |
| 8477 | |
| 8478 | public: |
| 8479 | INSTRUCTION_HEADER(NearbyInt) |
| 8480 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8481 | |
| 8482 | static bool HasAssemblerSupport(RoundingMode mode) { |
| 8483 | return Assembler::HasRoundInstruction(mode); |
| 8484 | } |
| 8485 | |
| 8486 | RoundingMode roundingMode() const { return roundingMode_; } |
| 8487 | |
| 8488 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8489 | |
| 8490 | bool isFloat32Commutative() const override { return true; } |
| 8491 | void trySpecializeFloat32(TempAllocator& alloc) override; |
| 8492 | #ifdef DEBUG1 |
| 8493 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 8494 | #endif |
| 8495 | |
| 8496 | bool congruentTo(const MDefinition* ins) const override { |
| 8497 | return congruentIfOperandsEqual(ins) && |
| 8498 | ins->toNearbyInt()->roundingMode() == roundingMode_; |
| 8499 | } |
| 8500 | |
| 8501 | #ifdef JS_JITSPEW1 |
| 8502 | void printOpcode(GenericPrinter& out) const override; |
| 8503 | #endif |
| 8504 | |
| 8505 | [[nodiscard]] bool writeRecoverData( |
| 8506 | CompactBufferWriter& writer) const override; |
| 8507 | |
| 8508 | bool canRecoverOnBailout() const override { |
| 8509 | switch (roundingMode_) { |
| 8510 | case RoundingMode::Up: |
| 8511 | case RoundingMode::Down: |
| 8512 | case RoundingMode::TowardsZero: |
| 8513 | return true; |
| 8514 | default: |
| 8515 | return false; |
| 8516 | } |
| 8517 | } |
| 8518 | |
| 8519 | ALLOW_CLONE(MNearbyInt)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MNearbyInt (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 8520 | }; |
| 8521 | |
| 8522 | class MGetIteratorCache : public MUnaryInstruction, |
| 8523 | public BoxExceptPolicy<0, MIRType::Object>::Data { |
| 8524 | explicit MGetIteratorCache(MDefinition* val) |
| 8525 | : MUnaryInstruction(classOpcode, val) { |
| 8526 | setResultType(MIRType::Object); |
| 8527 | } |
| 8528 | |
| 8529 | public: |
| 8530 | INSTRUCTION_HEADER(GetIteratorCache) |
| 8531 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8532 | NAMED_OPERANDS((0, value))MDefinition* value() const { return getOperand(0); } |
| 8533 | }; |
| 8534 | |
| 8535 | // Implementation for 'in' operator using instruction cache |
| 8536 | class MInCache : public MBinaryInstruction, |
| 8537 | public MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1>>::Data { |
| 8538 | MInCache(MDefinition* key, MDefinition* obj) |
| 8539 | : MBinaryInstruction(classOpcode, key, obj) { |
| 8540 | setResultType(MIRType::Boolean); |
| 8541 | } |
| 8542 | |
| 8543 | public: |
| 8544 | INSTRUCTION_HEADER(InCache) |
| 8545 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8546 | NAMED_OPERANDS((0, key), (1, object))MDefinition* key() const { return getOperand(0); } MDefinition * object() const { return getOperand(1); } |
| 8547 | }; |
| 8548 | |
| 8549 | // Test whether the index is in the array bounds or a hole. |
| 8550 | class MInArray : public MTernaryInstruction, public NoTypePolicy::Data { |
| 8551 | bool needsNegativeIntCheck_ = true; |
| 8552 | |
| 8553 | MInArray(MDefinition* elements, MDefinition* index, MDefinition* initLength) |
| 8554 | : MTernaryInstruction(classOpcode, elements, index, initLength) { |
| 8555 | setResultType(MIRType::Boolean); |
| 8556 | setMovable(); |
| 8557 | |
| 8558 | // Set the guard flag to make sure we bail when we see a negative index. |
| 8559 | // We can clear this flag (and needsNegativeIntCheck_) in |
| 8560 | // collectRangeInfoPreTrunc. |
| 8561 | setGuard(); |
| 8562 | |
| 8563 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8563); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 8563; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8564 | MOZ_ASSERT(index->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8564); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 8564; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8565 | MOZ_ASSERT(initLength->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(initLength->type() == MIRType::Int32)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(initLength->type() == MIRType::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("initLength->type() == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8565); AnnotateMozCrashReason("MOZ_ASSERT" "(" "initLength->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 8565; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8566 | } |
| 8567 | |
| 8568 | public: |
| 8569 | INSTRUCTION_HEADER(InArray) |
| 8570 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8571 | NAMED_OPERANDS((0, elements), (1, index), (2, initLength))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* initLength () const { return getOperand(2); } |
| 8572 | |
| 8573 | bool needsNegativeIntCheck() const { return needsNegativeIntCheck_; } |
| 8574 | void collectRangeInfoPreTrunc() override; |
| 8575 | AliasSet getAliasSet() const override { |
| 8576 | return AliasSet::Load(AliasSet::Element); |
| 8577 | } |
| 8578 | bool congruentTo(const MDefinition* ins) const override { |
| 8579 | if (!ins->isInArray()) { |
| 8580 | return false; |
| 8581 | } |
| 8582 | const MInArray* other = ins->toInArray(); |
| 8583 | if (needsNegativeIntCheck() != other->needsNegativeIntCheck()) { |
| 8584 | return false; |
| 8585 | } |
| 8586 | return congruentIfOperandsEqual(other); |
| 8587 | } |
| 8588 | }; |
| 8589 | |
| 8590 | // Bail when the element is a hole. |
| 8591 | class MGuardElementNotHole : public MBinaryInstruction, |
| 8592 | public NoTypePolicy::Data { |
| 8593 | MGuardElementNotHole(MDefinition* elements, MDefinition* index) |
| 8594 | : MBinaryInstruction(classOpcode, elements, index) { |
| 8595 | setMovable(); |
| 8596 | setGuard(); |
| 8597 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8597); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 8597; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8598 | MOZ_ASSERT(index->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8598); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 8598; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8599 | } |
| 8600 | |
| 8601 | public: |
| 8602 | INSTRUCTION_HEADER(GuardElementNotHole) |
| 8603 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8604 | NAMED_OPERANDS((0, elements), (1, index))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } |
| 8605 | |
| 8606 | AliasSet getAliasSet() const override { |
| 8607 | return AliasSet::Load(AliasSet::Element); |
| 8608 | } |
| 8609 | bool congruentTo(const MDefinition* ins) const override { |
| 8610 | return congruentIfOperandsEqual(ins); |
| 8611 | } |
| 8612 | }; |
| 8613 | |
| 8614 | class MCheckPrivateFieldCache |
| 8615 | : public MBinaryInstruction, |
| 8616 | public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, |
| 8617 | CacheIdPolicy<1>>::Data { |
| 8618 | MCheckPrivateFieldCache(MDefinition* obj, MDefinition* id) |
| 8619 | : MBinaryInstruction(classOpcode, obj, id) { |
| 8620 | setResultType(MIRType::Boolean); |
| 8621 | } |
| 8622 | |
| 8623 | public: |
| 8624 | INSTRUCTION_HEADER(CheckPrivateFieldCache) |
| 8625 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8626 | NAMED_OPERANDS((0, value), (1, idval))MDefinition* value() const { return getOperand(0); } MDefinition * idval() const { return getOperand(1); } |
| 8627 | }; |
| 8628 | |
| 8629 | class MHasOwnCache : public MBinaryInstruction, |
| 8630 | public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, |
| 8631 | CacheIdPolicy<1>>::Data { |
| 8632 | MHasOwnCache(MDefinition* obj, MDefinition* id) |
| 8633 | : MBinaryInstruction(classOpcode, obj, id) { |
| 8634 | setResultType(MIRType::Boolean); |
| 8635 | } |
| 8636 | |
| 8637 | public: |
| 8638 | INSTRUCTION_HEADER(HasOwnCache) |
| 8639 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8640 | NAMED_OPERANDS((0, value), (1, idval))MDefinition* value() const { return getOperand(0); } MDefinition * idval() const { return getOperand(1); } |
| 8641 | }; |
| 8642 | |
| 8643 | // Implementation for instanceof operator with specific rhs. |
| 8644 | class MInstanceOf : public MBinaryInstruction, |
| 8645 | public MixPolicy<BoxExceptPolicy<0, MIRType::Object>, |
| 8646 | ObjectPolicy<1>>::Data { |
| 8647 | MInstanceOf(MDefinition* obj, MDefinition* proto) |
| 8648 | : MBinaryInstruction(classOpcode, obj, proto) { |
| 8649 | setResultType(MIRType::Boolean); |
| 8650 | } |
| 8651 | |
| 8652 | public: |
| 8653 | INSTRUCTION_HEADER(InstanceOf) |
| 8654 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8655 | }; |
| 8656 | |
| 8657 | // Given a value being written to another object, update the generational store |
| 8658 | // buffer if the value is in the nursery and object is in the tenured heap. |
| 8659 | class MPostWriteBarrier : public MBinaryInstruction, |
| 8660 | public ObjectPolicy<0>::Data { |
| 8661 | MPostWriteBarrier(MDefinition* obj, MDefinition* value) |
| 8662 | : MBinaryInstruction(classOpcode, obj, value) { |
| 8663 | setGuard(); |
| 8664 | } |
| 8665 | |
| 8666 | public: |
| 8667 | INSTRUCTION_HEADER(PostWriteBarrier) |
| 8668 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8669 | NAMED_OPERANDS((0, object), (1, value))MDefinition* object() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } |
| 8670 | |
| 8671 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8672 | |
| 8673 | #ifdef DEBUG1 |
| 8674 | bool isConsistentFloat32Use(MUse* use) const override { |
| 8675 | // During lowering, values that neither have object nor value MIR type |
| 8676 | // are ignored, thus Float32 can show up at this point without any issue. |
| 8677 | return use == getUseFor(1); |
| 8678 | } |
| 8679 | #endif |
| 8680 | |
| 8681 | ALLOW_CLONE(MPostWriteBarrier)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MPostWriteBarrier (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 8682 | }; |
| 8683 | |
| 8684 | // Given a value being written to another object's elements at the specified |
| 8685 | // index, update the generational store buffer if the value is in the nursery |
| 8686 | // and object is in the tenured heap. |
| 8687 | class MPostWriteElementBarrier |
| 8688 | : public MTernaryInstruction, |
| 8689 | public MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<2>>::Data { |
| 8690 | MPostWriteElementBarrier(MDefinition* obj, MDefinition* value, |
| 8691 | MDefinition* index) |
| 8692 | : MTernaryInstruction(classOpcode, obj, value, index) { |
| 8693 | setGuard(); |
| 8694 | } |
| 8695 | |
| 8696 | public: |
| 8697 | INSTRUCTION_HEADER(PostWriteElementBarrier) |
| 8698 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8699 | NAMED_OPERANDS((0, object), (1, value), (2, index))MDefinition* object() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } MDefinition* index( ) const { return getOperand(2); } |
| 8700 | |
| 8701 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8702 | |
| 8703 | #ifdef DEBUG1 |
| 8704 | bool isConsistentFloat32Use(MUse* use) const override { |
| 8705 | // During lowering, values that neither have object nor value MIR type |
| 8706 | // are ignored, thus Float32 can show up at this point without any issue. |
| 8707 | return use == getUseFor(1); |
| 8708 | } |
| 8709 | #endif |
| 8710 | |
| 8711 | ALLOW_CLONE(MPostWriteElementBarrier)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MPostWriteElementBarrier (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 8712 | }; |
| 8713 | |
| 8714 | class MNewCallObject : public MUnaryInstruction, |
| 8715 | public SingleObjectPolicy::Data { |
| 8716 | public: |
| 8717 | INSTRUCTION_HEADER(NewCallObject) |
| 8718 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8719 | |
| 8720 | explicit MNewCallObject(MConstant* templateObj) |
| 8721 | : MUnaryInstruction(classOpcode, templateObj) { |
| 8722 | setResultType(MIRType::Object); |
| 8723 | } |
| 8724 | |
| 8725 | CallObject* templateObject() const { |
| 8726 | return &getOperand(0)->toConstant()->toObject().as<CallObject>(); |
| 8727 | } |
| 8728 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8729 | |
| 8730 | [[nodiscard]] bool writeRecoverData( |
| 8731 | CompactBufferWriter& writer) const override; |
| 8732 | bool canRecoverOnBailout() const override { return true; } |
| 8733 | }; |
| 8734 | |
| 8735 | class MNewStringObject : public MUnaryInstruction, |
| 8736 | public ConvertToStringPolicy<0>::Data { |
| 8737 | CompilerObject templateObj_; |
| 8738 | |
| 8739 | MNewStringObject(MDefinition* input, JSObject* templateObj) |
| 8740 | : MUnaryInstruction(classOpcode, input), templateObj_(templateObj) { |
| 8741 | setResultType(MIRType::Object); |
| 8742 | } |
| 8743 | |
| 8744 | public: |
| 8745 | INSTRUCTION_HEADER(NewStringObject) |
| 8746 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8747 | |
| 8748 | StringObject* templateObj() const; |
| 8749 | }; |
| 8750 | |
| 8751 | // This is an alias for MLoadFixedSlot. |
| 8752 | class MEnclosingEnvironment : public MLoadFixedSlot { |
| 8753 | explicit MEnclosingEnvironment(MDefinition* obj) |
| 8754 | : MLoadFixedSlot(obj, EnvironmentObject::enclosingEnvironmentSlot()) { |
| 8755 | setResultType(MIRType::Object); |
| 8756 | } |
| 8757 | |
| 8758 | public: |
| 8759 | static MEnclosingEnvironment* New(TempAllocator& alloc, MDefinition* obj) { |
| 8760 | return new (alloc) MEnclosingEnvironment(obj); |
| 8761 | } |
| 8762 | |
| 8763 | AliasSet getAliasSet() const override { |
| 8764 | // EnvironmentObject reserved slots are immutable. |
| 8765 | return AliasSet::None(); |
| 8766 | } |
| 8767 | }; |
| 8768 | |
| 8769 | // This is an element of a spaghetti stack which is used to represent the memory |
| 8770 | // context which has to be restored in case of a bailout. |
| 8771 | struct MStoreToRecover : public TempObject, |
| 8772 | public InlineSpaghettiStackNode<MStoreToRecover> { |
| 8773 | MDefinition* operand; |
| 8774 | |
| 8775 | explicit MStoreToRecover(MDefinition* operand) : operand(operand) {} |
| 8776 | }; |
| 8777 | |
| 8778 | using MStoresToRecoverList = InlineSpaghettiStack<MStoreToRecover>; |
| 8779 | |
| 8780 | // A resume point contains the information needed to reconstruct the Baseline |
| 8781 | // Interpreter state from a position in Warp JIT code. A resume point is a |
| 8782 | // mapping of stack slots to MDefinitions. |
| 8783 | // |
| 8784 | // We capture stack state at critical points: |
| 8785 | // * (1) At the beginning of every basic block. |
| 8786 | // * (2) After every effectful operation. |
| 8787 | // |
| 8788 | // As long as these two properties are maintained, instructions can be moved, |
| 8789 | // hoisted, or, eliminated without problems, and ops without side effects do not |
| 8790 | // need to worry about capturing state at precisely the right point in time. |
| 8791 | // |
| 8792 | // Effectful instructions, of course, need to capture state after completion, |
| 8793 | // where the interpreter will not attempt to repeat the operation. For this, |
| 8794 | // ResumeAfter must be used. The state is attached directly to the effectful |
| 8795 | // instruction to ensure that no intermediate instructions could be injected |
| 8796 | // in between by a future analysis pass. |
| 8797 | // |
| 8798 | // During LIR construction, if an instruction can bail back to the interpreter, |
| 8799 | // we create an LSnapshot, which uses the last known resume point to request |
| 8800 | // register/stack assignments for every live value. |
| 8801 | class MResumePoint final : public MNode |
| 8802 | #ifdef DEBUG1 |
| 8803 | , |
| 8804 | public InlineForwardListNode<MResumePoint> |
| 8805 | #endif |
| 8806 | { |
| 8807 | private: |
| 8808 | friend class MBasicBlock; |
| 8809 | friend void AssertBasicGraphCoherency(MIRGraph& graph, bool force); |
| 8810 | |
| 8811 | // List of stack slots needed to reconstruct the BaselineFrame. |
| 8812 | FixedList<MUse> operands_; |
| 8813 | |
| 8814 | // List of stores needed to reconstruct the content of objects which are |
| 8815 | // emulated by EmulateStateOf variants. |
| 8816 | MStoresToRecoverList stores_; |
| 8817 | |
| 8818 | jsbytecode* pc_; |
| 8819 | MInstruction* instruction_; |
| 8820 | ResumeMode mode_; |
| 8821 | bool isDiscarded_ = false; |
| 8822 | |
| 8823 | MResumePoint(MBasicBlock* block, jsbytecode* pc, ResumeMode mode); |
| 8824 | void inherit(MBasicBlock* state); |
| 8825 | |
| 8826 | // Calling isDefinition or isResumePoint on MResumePoint is unnecessary. |
| 8827 | bool isDefinition() const = delete; |
| 8828 | bool isResumePoint() const = delete; |
| 8829 | |
| 8830 | void setBlock(MBasicBlock* block) { |
| 8831 | setBlockAndKind(block, Kind::ResumePoint); |
| 8832 | } |
| 8833 | |
| 8834 | protected: |
| 8835 | // Initializes operands_ to an empty array of a fixed length. |
| 8836 | // The array may then be filled in by inherit(). |
| 8837 | [[nodiscard]] bool init(TempAllocator& alloc); |
| 8838 | |
| 8839 | void clearOperand(size_t index) { |
| 8840 | // FixedList doesn't initialize its elements, so do an unchecked init. |
| 8841 | operands_[index].initUncheckedWithoutProducer(this); |
| 8842 | } |
| 8843 | |
| 8844 | MUse* getUseFor(size_t index) override { return &operands_[index]; } |
| 8845 | const MUse* getUseFor(size_t index) const override { |
| 8846 | return &operands_[index]; |
| 8847 | } |
| 8848 | |
| 8849 | public: |
| 8850 | static MResumePoint* New(TempAllocator& alloc, MBasicBlock* block, |
| 8851 | jsbytecode* pc, ResumeMode mode); |
| 8852 | |
| 8853 | MBasicBlock* block() const { return resumePointBlock(); } |
| 8854 | |
| 8855 | size_t numAllocatedOperands() const { return operands_.length(); } |
| 8856 | uint32_t stackDepth() const { return numAllocatedOperands(); } |
| 8857 | size_t numOperands() const override { return numAllocatedOperands(); } |
| 8858 | size_t indexOf(const MUse* u) const final { |
| 8859 | MOZ_ASSERT(u >= &operands_[0])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u >= &operands_[0])>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(u >= &operands_[0]))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("u >= &operands_[0]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u >= &operands_[0]" ")"); do { *((volatile int*)__null) = 8859; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8860 | MOZ_ASSERT(u <= &operands_[numOperands() - 1])do { static_assert( mozilla::detail::AssertionConditionType< decltype(u <= &operands_[numOperands() - 1])>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(u <= &operands_[numOperands() - 1]))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("u <= &operands_[numOperands() - 1]" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "u <= &operands_[numOperands() - 1]" ")"); do { *((volatile int*)__null) = 8860; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8861 | return u - &operands_[0]; |
| 8862 | } |
| 8863 | void initOperand(size_t index, MDefinition* operand) { |
| 8864 | // FixedList doesn't initialize its elements, so do an unchecked init. |
| 8865 | operands_[index].initUnchecked(operand, this); |
| 8866 | } |
| 8867 | void replaceOperand(size_t index, MDefinition* operand) final { |
| 8868 | operands_[index].replaceProducer(operand); |
| 8869 | } |
| 8870 | |
| 8871 | bool isObservableOperand(MUse* u) const; |
| 8872 | bool isObservableOperand(size_t index) const; |
| 8873 | bool isRecoverableOperand(MUse* u) const; |
| 8874 | |
| 8875 | MDefinition* getOperand(size_t index) const override { |
| 8876 | return operands_[index].producer(); |
| 8877 | } |
| 8878 | jsbytecode* pc() const { return pc_; } |
| 8879 | MResumePoint* caller() const; |
| 8880 | uint32_t frameCount() const { |
| 8881 | uint32_t count = 1; |
| 8882 | for (MResumePoint* it = caller(); it; it = it->caller()) { |
| 8883 | count++; |
| 8884 | } |
| 8885 | return count; |
| 8886 | } |
| 8887 | MInstruction* instruction() { return instruction_; } |
| 8888 | void setInstruction(MInstruction* ins) { |
| 8889 | MOZ_ASSERT(!instruction_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!instruction_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!instruction_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!instruction_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8889); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!instruction_" ")"); do { *((volatile int*)__null) = 8889; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8890 | instruction_ = ins; |
| 8891 | } |
| 8892 | void resetInstruction() { |
| 8893 | MOZ_ASSERT(instruction_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(instruction_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(instruction_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("instruction_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8893); AnnotateMozCrashReason("MOZ_ASSERT" "(" "instruction_" ")"); do { *((volatile int*)__null) = 8893; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8894 | instruction_ = nullptr; |
| 8895 | } |
| 8896 | ResumeMode mode() const { return mode_; } |
| 8897 | |
| 8898 | void releaseUses() { |
| 8899 | for (size_t i = 0, e = numOperands(); i < e; i++) { |
| 8900 | if (operands_[i].hasProducer()) { |
| 8901 | operands_[i].releaseProducer(); |
| 8902 | } |
| 8903 | } |
| 8904 | } |
| 8905 | |
| 8906 | [[nodiscard]] bool writeRecoverData( |
| 8907 | CompactBufferWriter& writer) const override; |
| 8908 | |
| 8909 | // Register a store instruction on the current resume point. This |
| 8910 | // instruction would be recovered when we are bailing out. The |cache| |
| 8911 | // argument can be any resume point, it is used to share memory if we are |
| 8912 | // doing the same modification. |
| 8913 | void addStore(TempAllocator& alloc, MDefinition* store, |
| 8914 | const MResumePoint* cache = nullptr); |
| 8915 | |
| 8916 | MStoresToRecoverList::iterator storesBegin() const { return stores_.begin(); } |
| 8917 | MStoresToRecoverList::iterator storesEnd() const { return stores_.end(); } |
| 8918 | bool storesEmpty() const { return stores_.empty(); } |
| 8919 | |
| 8920 | void setDiscarded() { isDiscarded_ = true; } |
| 8921 | bool isDiscarded() const { return isDiscarded_; } |
| 8922 | |
| 8923 | #ifdef JS_JITSPEW1 |
| 8924 | virtual void dump(GenericPrinter& out) const override; |
| 8925 | virtual void dump() const override; |
| 8926 | #endif |
| 8927 | }; |
| 8928 | |
| 8929 | class MIsCallable : public MUnaryInstruction, |
| 8930 | public BoxExceptPolicy<0, MIRType::Object>::Data { |
| 8931 | explicit MIsCallable(MDefinition* object) |
| 8932 | : MUnaryInstruction(classOpcode, object) { |
| 8933 | setResultType(MIRType::Boolean); |
| 8934 | setMovable(); |
| 8935 | } |
| 8936 | |
| 8937 | public: |
| 8938 | INSTRUCTION_HEADER(IsCallable) |
| 8939 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8940 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 8941 | |
| 8942 | bool congruentTo(const MDefinition* ins) const override { |
| 8943 | return congruentIfOperandsEqual(ins); |
| 8944 | } |
| 8945 | |
| 8946 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 8947 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8948 | }; |
| 8949 | |
| 8950 | class MHasClass : public MUnaryInstruction, public SingleObjectPolicy::Data { |
| 8951 | const JSClass* class_; |
| 8952 | |
| 8953 | MHasClass(MDefinition* object, const JSClass* clasp) |
| 8954 | : MUnaryInstruction(classOpcode, object), class_(clasp) { |
| 8955 | MOZ_ASSERT(object->type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(object->type() == MIRType::Object)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(object->type() == MIRType ::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("object->type() == MIRType::Object", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 8955; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8956 | setResultType(MIRType::Boolean); |
| 8957 | setMovable(); |
| 8958 | } |
| 8959 | |
| 8960 | public: |
| 8961 | INSTRUCTION_HEADER(HasClass) |
| 8962 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8963 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 8964 | |
| 8965 | const JSClass* getClass() const { return class_; } |
| 8966 | |
| 8967 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 8968 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 8969 | bool congruentTo(const MDefinition* ins) const override { |
| 8970 | if (!ins->isHasClass()) { |
| 8971 | return false; |
| 8972 | } |
| 8973 | if (getClass() != ins->toHasClass()->getClass()) { |
| 8974 | return false; |
| 8975 | } |
| 8976 | return congruentIfOperandsEqual(ins); |
| 8977 | } |
| 8978 | }; |
| 8979 | |
| 8980 | class MGuardToClass : public MUnaryInstruction, |
| 8981 | public SingleObjectPolicy::Data { |
| 8982 | const JSClass* class_; |
| 8983 | |
| 8984 | MGuardToClass(MDefinition* object, const JSClass* clasp) |
| 8985 | : MUnaryInstruction(classOpcode, object), class_(clasp) { |
| 8986 | MOZ_ASSERT(object->type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(object->type() == MIRType::Object)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(object->type() == MIRType ::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("object->type() == MIRType::Object", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8986); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 8986; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 8987 | MOZ_ASSERT(!clasp->isJSFunction(), "Use MGuardToFunction instead")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!clasp->isJSFunction())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!clasp->isJSFunction()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("!clasp->isJSFunction()" " (" "Use MGuardToFunction instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 8987); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!clasp->isJSFunction()" ") (" "Use MGuardToFunction instead" ")"); do { *((volatile int *)__null) = 8987; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 8988 | setResultType(MIRType::Object); |
| 8989 | setMovable(); |
| 8990 | |
| 8991 | // We will bail out if the class type is incorrect, so we need to ensure we |
| 8992 | // don't eliminate this instruction |
| 8993 | setGuard(); |
| 8994 | } |
| 8995 | |
| 8996 | public: |
| 8997 | INSTRUCTION_HEADER(GuardToClass) |
| 8998 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 8999 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 9000 | |
| 9001 | const JSClass* getClass() const { return class_; } |
| 9002 | bool isArgumentsObjectClass() const { |
| 9003 | return class_ == &MappedArgumentsObject::class_ || |
| 9004 | class_ == &UnmappedArgumentsObject::class_; |
| 9005 | } |
| 9006 | |
| 9007 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 9008 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9009 | bool congruentTo(const MDefinition* ins) const override { |
| 9010 | if (!ins->isGuardToClass()) { |
| 9011 | return false; |
| 9012 | } |
| 9013 | if (getClass() != ins->toGuardToClass()->getClass()) { |
| 9014 | return false; |
| 9015 | } |
| 9016 | return congruentIfOperandsEqual(ins); |
| 9017 | } |
| 9018 | }; |
| 9019 | |
| 9020 | class MGuardToEitherClass : public MUnaryInstruction, |
| 9021 | public SingleObjectPolicy::Data { |
| 9022 | const JSClass* class1_; |
| 9023 | const JSClass* class2_; |
| 9024 | |
| 9025 | MGuardToEitherClass(MDefinition* object, const JSClass* clasp1, |
| 9026 | const JSClass* clasp2) |
| 9027 | : MUnaryInstruction(classOpcode, object), |
| 9028 | class1_(clasp1), |
| 9029 | class2_(clasp2) { |
| 9030 | MOZ_ASSERT(object->type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(object->type() == MIRType::Object)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(object->type() == MIRType ::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("object->type() == MIRType::Object", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9030); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 9030; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9031 | MOZ_ASSERT(clasp1 != clasp2, "Use MGuardToClass instead")do { static_assert( mozilla::detail::AssertionConditionType< decltype(clasp1 != clasp2)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(clasp1 != clasp2))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("clasp1 != clasp2" " (" "Use MGuardToClass instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9031); AnnotateMozCrashReason("MOZ_ASSERT" "(" "clasp1 != clasp2" ") (" "Use MGuardToClass instead" ")"); do { *((volatile int *)__null) = 9031; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 9032 | MOZ_ASSERT(!clasp1->isJSFunction(), "Use MGuardToFunction instead")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!clasp1->isJSFunction())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!clasp1->isJSFunction())) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!clasp1->isJSFunction()" " (" "Use MGuardToFunction instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!clasp1->isJSFunction()" ") (" "Use MGuardToFunction instead" ")"); do { *((volatile int *)__null) = 9032; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 9033 | MOZ_ASSERT(!clasp2->isJSFunction(), "Use MGuardToFunction instead")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!clasp2->isJSFunction())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!clasp2->isJSFunction())) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!clasp2->isJSFunction()" " (" "Use MGuardToFunction instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9033); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!clasp2->isJSFunction()" ") (" "Use MGuardToFunction instead" ")"); do { *((volatile int *)__null) = 9033; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 9034 | setResultType(MIRType::Object); |
| 9035 | setMovable(); |
| 9036 | |
| 9037 | // We will bail out if the class type is incorrect, so we need to ensure we |
| 9038 | // don't eliminate this instruction |
| 9039 | setGuard(); |
| 9040 | } |
| 9041 | |
| 9042 | public: |
| 9043 | INSTRUCTION_HEADER(GuardToEitherClass) |
| 9044 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9045 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 9046 | |
| 9047 | const JSClass* getClass1() const { return class1_; } |
| 9048 | const JSClass* getClass2() const { return class2_; } |
| 9049 | |
| 9050 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 9051 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9052 | bool congruentTo(const MDefinition* ins) const override { |
| 9053 | if (!ins->isGuardToEitherClass()) { |
| 9054 | return false; |
| 9055 | } |
| 9056 | const auto* other = ins->toGuardToEitherClass(); |
| 9057 | if (getClass1() != other->getClass1() && |
| 9058 | getClass1() != other->getClass2()) { |
| 9059 | return false; |
| 9060 | } |
| 9061 | if (getClass2() != other->getClass1() && |
| 9062 | getClass2() != other->getClass2()) { |
| 9063 | return false; |
| 9064 | } |
| 9065 | return congruentIfOperandsEqual(ins); |
| 9066 | } |
| 9067 | }; |
| 9068 | |
| 9069 | class MGuardToFunction : public MUnaryInstruction, |
| 9070 | public SingleObjectPolicy::Data { |
| 9071 | explicit MGuardToFunction(MDefinition* object) |
| 9072 | : MUnaryInstruction(classOpcode, object) { |
| 9073 | MOZ_ASSERT(object->type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(object->type() == MIRType::Object)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(object->type() == MIRType ::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("object->type() == MIRType::Object", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9073); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 9073; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9074 | setResultType(MIRType::Object); |
| 9075 | setMovable(); |
| 9076 | |
| 9077 | // We will bail out if the class type is incorrect, so we need to ensure we |
| 9078 | // don't eliminate this instruction |
| 9079 | setGuard(); |
| 9080 | } |
| 9081 | |
| 9082 | public: |
| 9083 | INSTRUCTION_HEADER(GuardToFunction) |
| 9084 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9085 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 9086 | |
| 9087 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 9088 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9089 | bool congruentTo(const MDefinition* ins) const override { |
| 9090 | if (!ins->isGuardToFunction()) { |
| 9091 | return false; |
| 9092 | } |
| 9093 | return congruentIfOperandsEqual(ins); |
| 9094 | } |
| 9095 | }; |
| 9096 | |
| 9097 | // Note: we might call a proxy trap, so this instruction is effectful. |
| 9098 | class MIsArray : public MUnaryInstruction, |
| 9099 | public BoxExceptPolicy<0, MIRType::Object>::Data { |
| 9100 | explicit MIsArray(MDefinition* value) |
| 9101 | : MUnaryInstruction(classOpcode, value) { |
| 9102 | setResultType(MIRType::Boolean); |
| 9103 | } |
| 9104 | |
| 9105 | public: |
| 9106 | INSTRUCTION_HEADER(IsArray) |
| 9107 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9108 | NAMED_OPERANDS((0, value))MDefinition* value() const { return getOperand(0); } |
| 9109 | |
| 9110 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 9111 | }; |
| 9112 | |
| 9113 | class MIsTypedArray : public MUnaryInstruction, |
| 9114 | public SingleObjectPolicy::Data { |
| 9115 | bool possiblyWrapped_; |
| 9116 | |
| 9117 | explicit MIsTypedArray(MDefinition* value, bool possiblyWrapped) |
| 9118 | : MUnaryInstruction(classOpcode, value), |
| 9119 | possiblyWrapped_(possiblyWrapped) { |
| 9120 | setResultType(MIRType::Boolean); |
| 9121 | |
| 9122 | if (possiblyWrapped) { |
| 9123 | // Proxy checks may throw, so we're neither removable nor movable. |
| 9124 | setGuard(); |
| 9125 | } else { |
| 9126 | setMovable(); |
| 9127 | } |
| 9128 | } |
| 9129 | |
| 9130 | public: |
| 9131 | INSTRUCTION_HEADER(IsTypedArray) |
| 9132 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9133 | NAMED_OPERANDS((0, value))MDefinition* value() const { return getOperand(0); } |
| 9134 | |
| 9135 | bool isPossiblyWrapped() const { return possiblyWrapped_; } |
| 9136 | AliasSet getAliasSet() const override { |
| 9137 | if (isPossiblyWrapped()) { |
| 9138 | return AliasSet::Store(AliasSet::Any); |
| 9139 | } |
| 9140 | return AliasSet::None(); |
| 9141 | } |
| 9142 | }; |
| 9143 | |
| 9144 | // Allocate the generator object for a frame. |
| 9145 | class MGenerator : public MTernaryInstruction, |
| 9146 | public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>>::Data { |
| 9147 | explicit MGenerator(MDefinition* callee, MDefinition* environmentChain, |
| 9148 | MDefinition* argsObject) |
| 9149 | : MTernaryInstruction(classOpcode, callee, environmentChain, argsObject) { |
| 9150 | setResultType(MIRType::Object); |
| 9151 | }; |
| 9152 | |
| 9153 | public: |
| 9154 | INSTRUCTION_HEADER(Generator) |
| 9155 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9156 | NAMED_OPERANDS((0, callee), (1, environmentChain), (2, argsObject))MDefinition* callee() const { return getOperand(0); } MDefinition * environmentChain() const { return getOperand(1); } MDefinition * argsObject() const { return getOperand(2); } |
| 9157 | }; |
| 9158 | |
| 9159 | class MMaybeExtractAwaitValue : public MBinaryInstruction, |
| 9160 | public BoxPolicy<0>::Data { |
| 9161 | explicit MMaybeExtractAwaitValue(MDefinition* value, MDefinition* canSkip) |
| 9162 | : MBinaryInstruction(classOpcode, value, canSkip) { |
| 9163 | setResultType(MIRType::Value); |
| 9164 | } |
| 9165 | |
| 9166 | public: |
| 9167 | INSTRUCTION_HEADER(MaybeExtractAwaitValue) |
| 9168 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9169 | NAMED_OPERANDS((0, value), (1, canSkip))MDefinition* value() const { return getOperand(0); } MDefinition * canSkip() const { return getOperand(1); } |
| 9170 | }; |
| 9171 | |
| 9172 | class MAtomicIsLockFree : public MUnaryInstruction, |
| 9173 | public ConvertToInt32Policy<0>::Data { |
| 9174 | explicit MAtomicIsLockFree(MDefinition* value) |
| 9175 | : MUnaryInstruction(classOpcode, value) { |
| 9176 | setResultType(MIRType::Boolean); |
| 9177 | setMovable(); |
| 9178 | } |
| 9179 | |
| 9180 | public: |
| 9181 | INSTRUCTION_HEADER(AtomicIsLockFree) |
| 9182 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9183 | |
| 9184 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 9185 | |
| 9186 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9187 | |
| 9188 | bool congruentTo(const MDefinition* ins) const override { |
| 9189 | return congruentIfOperandsEqual(ins); |
| 9190 | } |
| 9191 | |
| 9192 | [[nodiscard]] bool writeRecoverData( |
| 9193 | CompactBufferWriter& writer) const override; |
| 9194 | bool canRecoverOnBailout() const override { return true; } |
| 9195 | |
| 9196 | ALLOW_CLONE(MAtomicIsLockFree)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MAtomicIsLockFree (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 9197 | }; |
| 9198 | |
| 9199 | class MCompareExchangeTypedArrayElement |
| 9200 | : public MQuaternaryInstruction, |
| 9201 | public MixPolicy<TruncateToInt32OrToBigIntPolicy<2>, |
| 9202 | TruncateToInt32OrToBigIntPolicy<3>>::Data { |
| 9203 | Scalar::Type arrayType_; |
| 9204 | |
| 9205 | explicit MCompareExchangeTypedArrayElement(MDefinition* elements, |
| 9206 | MDefinition* index, |
| 9207 | Scalar::Type arrayType, |
| 9208 | MDefinition* oldval, |
| 9209 | MDefinition* newval) |
| 9210 | : MQuaternaryInstruction(classOpcode, elements, index, oldval, newval), |
| 9211 | arrayType_(arrayType) { |
| 9212 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 9212; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9213 | MOZ_ASSERT(index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9213); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 9213; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9214 | setGuard(); // Not removable |
| 9215 | } |
| 9216 | |
| 9217 | public: |
| 9218 | INSTRUCTION_HEADER(CompareExchangeTypedArrayElement) |
| 9219 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9220 | NAMED_OPERANDS((0, elements), (1, index), (2, oldval), (3, newval))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* oldval () const { return getOperand(2); } MDefinition* newval() const { return getOperand(3); } |
| 9221 | |
| 9222 | bool isByteArray() const { |
| 9223 | return (arrayType_ == Scalar::Int8 || arrayType_ == Scalar::Uint8); |
| 9224 | } |
| 9225 | Scalar::Type arrayType() const { return arrayType_; } |
| 9226 | AliasSet getAliasSet() const override { |
| 9227 | return AliasSet::Store(AliasSet::UnboxedElement); |
| 9228 | } |
| 9229 | }; |
| 9230 | |
| 9231 | class MAtomicExchangeTypedArrayElement |
| 9232 | : public MTernaryInstruction, |
| 9233 | public TruncateToInt32OrToBigIntPolicy<2>::Data { |
| 9234 | Scalar::Type arrayType_; |
| 9235 | |
| 9236 | MAtomicExchangeTypedArrayElement(MDefinition* elements, MDefinition* index, |
| 9237 | MDefinition* value, Scalar::Type arrayType) |
| 9238 | : MTernaryInstruction(classOpcode, elements, index, value), |
| 9239 | arrayType_(arrayType) { |
| 9240 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9240); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 9240; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9241 | MOZ_ASSERT(index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9241); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 9241; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9242 | MOZ_ASSERT(arrayType <= Scalar::Uint32 || Scalar::isBigIntType(arrayType))do { static_assert( mozilla::detail::AssertionConditionType< decltype(arrayType <= Scalar::Uint32 || Scalar::isBigIntType (arrayType))>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(arrayType <= Scalar::Uint32 || Scalar::isBigIntType(arrayType)))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("arrayType <= Scalar::Uint32 || Scalar::isBigIntType(arrayType)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9242); AnnotateMozCrashReason("MOZ_ASSERT" "(" "arrayType <= Scalar::Uint32 || Scalar::isBigIntType(arrayType)" ")"); do { *((volatile int*)__null) = 9242; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9243 | setGuard(); // Not removable |
| 9244 | } |
| 9245 | |
| 9246 | public: |
| 9247 | INSTRUCTION_HEADER(AtomicExchangeTypedArrayElement) |
| 9248 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9249 | NAMED_OPERANDS((0, elements), (1, index), (2, value))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* value( ) const { return getOperand(2); } |
| 9250 | |
| 9251 | bool isByteArray() const { |
| 9252 | return (arrayType_ == Scalar::Int8 || arrayType_ == Scalar::Uint8); |
| 9253 | } |
| 9254 | Scalar::Type arrayType() const { return arrayType_; } |
| 9255 | AliasSet getAliasSet() const override { |
| 9256 | return AliasSet::Store(AliasSet::UnboxedElement); |
| 9257 | } |
| 9258 | }; |
| 9259 | |
| 9260 | class MAtomicTypedArrayElementBinop |
| 9261 | : public MTernaryInstruction, |
| 9262 | public TruncateToInt32OrToBigIntPolicy<2>::Data { |
| 9263 | private: |
| 9264 | AtomicOp op_; |
| 9265 | Scalar::Type arrayType_; |
| 9266 | bool forEffect_; |
| 9267 | |
| 9268 | explicit MAtomicTypedArrayElementBinop(AtomicOp op, MDefinition* elements, |
| 9269 | MDefinition* index, |
| 9270 | Scalar::Type arrayType, |
| 9271 | MDefinition* value, bool forEffect) |
| 9272 | : MTernaryInstruction(classOpcode, elements, index, value), |
| 9273 | op_(op), |
| 9274 | arrayType_(arrayType), |
| 9275 | forEffect_(forEffect) { |
| 9276 | MOZ_ASSERT(elements->type() == MIRType::Elements)do { static_assert( mozilla::detail::AssertionConditionType< decltype(elements->type() == MIRType::Elements)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(elements->type() == MIRType::Elements))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("elements->type() == MIRType::Elements" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9276); AnnotateMozCrashReason("MOZ_ASSERT" "(" "elements->type() == MIRType::Elements" ")"); do { *((volatile int*)__null) = 9276; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9277 | MOZ_ASSERT(index->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index->type() == MIRType:: IntPtr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("index->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 9277; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9278 | MOZ_ASSERT(arrayType <= Scalar::Uint32 || Scalar::isBigIntType(arrayType))do { static_assert( mozilla::detail::AssertionConditionType< decltype(arrayType <= Scalar::Uint32 || Scalar::isBigIntType (arrayType))>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(arrayType <= Scalar::Uint32 || Scalar::isBigIntType(arrayType)))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("arrayType <= Scalar::Uint32 || Scalar::isBigIntType(arrayType)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9278); AnnotateMozCrashReason("MOZ_ASSERT" "(" "arrayType <= Scalar::Uint32 || Scalar::isBigIntType(arrayType)" ")"); do { *((volatile int*)__null) = 9278; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9279 | setGuard(); // Not removable |
| 9280 | } |
| 9281 | |
| 9282 | public: |
| 9283 | INSTRUCTION_HEADER(AtomicTypedArrayElementBinop) |
| 9284 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9285 | NAMED_OPERANDS((0, elements), (1, index), (2, value))MDefinition* elements() const { return getOperand(0); } MDefinition * index() const { return getOperand(1); } MDefinition* value( ) const { return getOperand(2); } |
| 9286 | |
| 9287 | bool isByteArray() const { |
| 9288 | return (arrayType_ == Scalar::Int8 || arrayType_ == Scalar::Uint8); |
| 9289 | } |
| 9290 | AtomicOp operation() const { return op_; } |
| 9291 | Scalar::Type arrayType() const { return arrayType_; } |
| 9292 | bool isForEffect() const { return forEffect_; } |
| 9293 | AliasSet getAliasSet() const override { |
| 9294 | return AliasSet::Store(AliasSet::UnboxedElement); |
| 9295 | } |
| 9296 | }; |
| 9297 | |
| 9298 | class MDebugger : public MNullaryInstruction { |
| 9299 | MDebugger() : MNullaryInstruction(classOpcode) { |
| 9300 | setBailoutKind(BailoutKind::Debugger); |
| 9301 | } |
| 9302 | |
| 9303 | public: |
| 9304 | INSTRUCTION_HEADER(Debugger) |
| 9305 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9306 | }; |
| 9307 | |
| 9308 | // Used to load the prototype of an object known to have |
| 9309 | // a static prototype. |
| 9310 | class MObjectStaticProto : public MUnaryInstruction, |
| 9311 | public SingleObjectPolicy::Data { |
| 9312 | explicit MObjectStaticProto(MDefinition* object) |
| 9313 | : MUnaryInstruction(classOpcode, object) { |
| 9314 | setResultType(MIRType::Object); |
| 9315 | setMovable(); |
| 9316 | } |
| 9317 | |
| 9318 | public: |
| 9319 | INSTRUCTION_HEADER(ObjectStaticProto) |
| 9320 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9321 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 9322 | |
| 9323 | bool congruentTo(const MDefinition* ins) const override { |
| 9324 | return congruentIfOperandsEqual(ins); |
| 9325 | } |
| 9326 | |
| 9327 | AliasSet getAliasSet() const override { |
| 9328 | return AliasSet::Load(AliasSet::ObjectFields); |
| 9329 | } |
| 9330 | AliasType mightAlias(const MDefinition* def) const override { |
| 9331 | // These instructions never modify the [[Prototype]]. |
| 9332 | if (def->isAddAndStoreSlot() || def->isAllocateAndStoreSlot() || |
| 9333 | def->isStoreElementHole() || def->isArrayPush()) { |
| 9334 | return AliasType::NoAlias; |
| 9335 | } |
| 9336 | return AliasType::MayAlias; |
| 9337 | } |
| 9338 | }; |
| 9339 | |
| 9340 | class MConstantProto : public MUnaryInstruction, |
| 9341 | public SingleObjectPolicy::Data { |
| 9342 | // NOTE: we're not going to actually use the underlying receiver object for |
| 9343 | // anything. This is just here for giving extra information to MGuardShape |
| 9344 | // to MGuardShape::mightAlias. Accordingly, we don't take it as an operand, |
| 9345 | // but instead just keep a pointer to it. This means we need to ensure it's |
| 9346 | // not discarded before we try to access it. If this is discarded, we |
| 9347 | // basically just become an MConstant for the object's proto, which is fine. |
| 9348 | const MDefinition* receiverObject_; |
| 9349 | |
| 9350 | explicit MConstantProto(MDefinition* protoObject, |
| 9351 | const MDefinition* receiverObject) |
| 9352 | : MUnaryInstruction(classOpcode, protoObject), |
| 9353 | receiverObject_(receiverObject) { |
| 9354 | MOZ_ASSERT(protoObject->isConstant())do { static_assert( mozilla::detail::AssertionConditionType< decltype(protoObject->isConstant())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(protoObject->isConstant() ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "protoObject->isConstant()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "protoObject->isConstant()" ")"); do { *((volatile int*)__null) = 9354; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9355 | setResultType(MIRType::Object); |
| 9356 | setMovable(); |
| 9357 | } |
| 9358 | |
| 9359 | ALLOW_CLONE(MConstantProto)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MConstantProto (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 9360 | |
| 9361 | public: |
| 9362 | INSTRUCTION_HEADER(ConstantProto) |
| 9363 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9364 | NAMED_OPERANDS((0, protoObject))MDefinition* protoObject() const { return getOperand(0); } |
| 9365 | |
| 9366 | HashNumber valueHash() const override; |
| 9367 | |
| 9368 | bool congruentTo(const MDefinition* ins) const override { |
| 9369 | if (this == ins) { |
| 9370 | return true; |
| 9371 | } |
| 9372 | const MDefinition* receiverObject = getReceiverObject(); |
| 9373 | return congruentIfOperandsEqual(ins) && receiverObject && |
| 9374 | receiverObject == ins->toConstantProto()->getReceiverObject(); |
| 9375 | } |
| 9376 | |
| 9377 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9378 | |
| 9379 | const MDefinition* getReceiverObject() const { |
| 9380 | if (receiverObject_->isDiscarded()) { |
| 9381 | return nullptr; |
| 9382 | } |
| 9383 | return receiverObject_; |
| 9384 | } |
| 9385 | }; |
| 9386 | |
| 9387 | class MObjectToIterator : public MUnaryInstruction, |
| 9388 | public ObjectPolicy<0>::Data { |
| 9389 | NativeIteratorListHead* enumeratorsAddr_; |
| 9390 | bool wantsIndices_ = false; |
| 9391 | |
| 9392 | explicit MObjectToIterator(MDefinition* object, |
| 9393 | NativeIteratorListHead* enumeratorsAddr) |
| 9394 | : MUnaryInstruction(classOpcode, object), |
| 9395 | enumeratorsAddr_(enumeratorsAddr) { |
| 9396 | setResultType(MIRType::Object); |
| 9397 | } |
| 9398 | |
| 9399 | public: |
| 9400 | NativeIteratorListHead* enumeratorsAddr() const { return enumeratorsAddr_; } |
| 9401 | INSTRUCTION_HEADER(ObjectToIterator) |
| 9402 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9403 | NAMED_OPERANDS((0, object))MDefinition* object() const { return getOperand(0); } |
| 9404 | |
| 9405 | bool wantsIndices() const { return wantsIndices_; } |
| 9406 | void setWantsIndices(bool value) { wantsIndices_ = value; } |
| 9407 | }; |
| 9408 | |
| 9409 | class MPostIntPtrConversion : public MUnaryInstruction, |
| 9410 | public NoTypePolicy::Data { |
| 9411 | explicit MPostIntPtrConversion(MDefinition* input) |
| 9412 | : MUnaryInstruction(classOpcode, input) { |
| 9413 | // Passes through the input. |
| 9414 | setResultType(input->type()); |
| 9415 | |
| 9416 | // Note: Must be non-movable so we can attach a resume point. |
| 9417 | } |
| 9418 | |
| 9419 | public: |
| 9420 | INSTRUCTION_HEADER(PostIntPtrConversion) |
| 9421 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9422 | |
| 9423 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9424 | }; |
| 9425 | |
| 9426 | // Flips the input's sign bit, independently of the rest of the number's |
| 9427 | // payload. Note this is different from multiplying by minus-one, which has |
| 9428 | // side-effects for e.g. NaNs. |
| 9429 | class MWasmNeg : public MUnaryInstruction, public NoTypePolicy::Data { |
| 9430 | MWasmNeg(MDefinition* op, MIRType type) : MUnaryInstruction(classOpcode, op) { |
| 9431 | setResultType(type); |
| 9432 | setMovable(); |
| 9433 | } |
| 9434 | |
| 9435 | public: |
| 9436 | INSTRUCTION_HEADER(WasmNeg) |
| 9437 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9438 | }; |
| 9439 | |
| 9440 | // Machine-level bitwise AND/OR/XOR, avoiding all JS-level complexity embodied |
| 9441 | // in MBinaryBitwiseInstruction. |
| 9442 | class MWasmBinaryBitwise : public MBinaryInstruction, |
| 9443 | public NoTypePolicy::Data { |
| 9444 | public: |
| 9445 | enum class SubOpcode { And, Or, Xor }; |
| 9446 | |
| 9447 | protected: |
| 9448 | MWasmBinaryBitwise(MDefinition* left, MDefinition* right, MIRType type, |
| 9449 | SubOpcode subOpcode) |
| 9450 | : MBinaryInstruction(classOpcode, left, right), subOpcode_(subOpcode) { |
| 9451 | MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Int32 || type == MIRType::Int64)> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == MIRType::Int32 || type == MIRType::Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Int32 || type == MIRType::Int64" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9451); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int32 || type == MIRType::Int64" ")"); do { *((volatile int*)__null) = 9451; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9452 | setResultType(type); |
| 9453 | setMovable(); |
| 9454 | setCommutative(); |
| 9455 | } |
| 9456 | |
| 9457 | public: |
| 9458 | INSTRUCTION_HEADER(WasmBinaryBitwise) |
| 9459 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9460 | |
| 9461 | SubOpcode subOpcode() const { return subOpcode_; } |
| 9462 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 9463 | |
| 9464 | bool congruentTo(const MDefinition* ins) const override { |
| 9465 | return ins->isWasmBinaryBitwise() && |
| 9466 | ins->toWasmBinaryBitwise()->subOpcode() == subOpcode() && |
| 9467 | binaryCongruentTo(ins); |
| 9468 | } |
| 9469 | |
| 9470 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9471 | |
| 9472 | #ifdef JS_JITSPEW1 |
| 9473 | void getExtras(ExtrasCollector* extras) override { |
| 9474 | const char* what = "!!unknown!!"; |
Value stored to 'what' during its initialization is never read | |
| 9475 | switch (subOpcode()) { |
| 9476 | case SubOpcode::And: |
| 9477 | what = "And"; |
| 9478 | break; |
| 9479 | case SubOpcode::Or: |
| 9480 | what = "Or"; |
| 9481 | break; |
| 9482 | case SubOpcode::Xor: |
| 9483 | what = "Xor"; |
| 9484 | break; |
| 9485 | } |
| 9486 | extras->add(what); |
| 9487 | } |
| 9488 | #endif |
| 9489 | |
| 9490 | private: |
| 9491 | SubOpcode subOpcode_; |
| 9492 | |
| 9493 | ALLOW_CLONE(MWasmBinaryBitwise)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmBinaryBitwise (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 9494 | }; |
| 9495 | |
| 9496 | class MWasmLoadInstance : public MUnaryInstruction, public NoTypePolicy::Data { |
| 9497 | uint32_t offset_; |
| 9498 | AliasSet aliases_; |
| 9499 | |
| 9500 | explicit MWasmLoadInstance(MDefinition* instance, uint32_t offset, |
| 9501 | MIRType type, AliasSet aliases) |
| 9502 | : MUnaryInstruction(classOpcode, instance), |
| 9503 | offset_(offset), |
| 9504 | aliases_(aliases) { |
| 9505 | // Different instance data have different alias classes and only those |
| 9506 | // classes are allowed. |
| 9507 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9512); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" ")"); do { *((volatile int*)__null) = 9512; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 9508 | aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9512); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" ")"); do { *((volatile int*)__null) = 9512; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 9509 | aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9512); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" ")"); do { *((volatile int*)__null) = 9512; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 9510 | aliases_.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9512); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" ")"); do { *((volatile int*)__null) = 9512; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 9511 | AliasSet::Load(AliasSet::WasmPendingException).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9512); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" ")"); do { *((volatile int*)__null) = 9512; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 9512 | aliases_.flags() == AliasSet::None().flags())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta ).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException ).flags() || aliases_.flags() == AliasSet::None().flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9512); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases_.flags() == AliasSet::Load(AliasSet::WasmHeapMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmTableMeta).flags() || aliases_.flags() == AliasSet::Load(AliasSet::WasmPendingException).flags() || aliases_.flags() == AliasSet::None().flags()" ")"); do { *((volatile int*)__null) = 9512; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9513 | |
| 9514 | // The only types supported at the moment. |
| 9515 | MOZ_ASSERT(type == MIRType::Pointer || type == MIRType::Int32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9516); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 9516; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 9516 | type == MIRType::Int64 || type == MIRType::WasmAnyRef)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9516); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 9516; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9517 | |
| 9518 | setMovable(); |
| 9519 | setResultType(type); |
| 9520 | } |
| 9521 | |
| 9522 | public: |
| 9523 | INSTRUCTION_HEADER(WasmLoadInstance) |
| 9524 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9525 | NAMED_OPERANDS((0, instance))MDefinition* instance() const { return getOperand(0); } |
| 9526 | |
| 9527 | uint32_t offset() const { return offset_; } |
| 9528 | |
| 9529 | bool congruentTo(const MDefinition* ins) const override { |
| 9530 | return op() == ins->op() && |
| 9531 | offset() == ins->toWasmLoadInstance()->offset() && |
| 9532 | type() == ins->type(); |
| 9533 | } |
| 9534 | |
| 9535 | HashNumber valueHash() const override { |
| 9536 | return addU32ToHash(HashNumber(op()), offset()); |
| 9537 | } |
| 9538 | |
| 9539 | AliasSet getAliasSet() const override { return aliases_; } |
| 9540 | }; |
| 9541 | |
| 9542 | class MWasmStoreInstance : public MBinaryInstruction, |
| 9543 | public NoTypePolicy::Data { |
| 9544 | uint32_t offset_; |
| 9545 | AliasSet aliases_; |
| 9546 | |
| 9547 | explicit MWasmStoreInstance(MDefinition* instance, MDefinition* value, |
| 9548 | uint32_t offset, MIRType type, AliasSet aliases) |
| 9549 | : MBinaryInstruction(classOpcode, instance, value), |
| 9550 | offset_(offset), |
| 9551 | aliases_(aliases) { |
| 9552 | // Different instance data have different alias classes and only those |
| 9553 | // classes are allowed. |
| 9554 | MOZ_ASSERT(aliases_.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases_.flags() == AliasSet::Store(AliasSet::WasmPendingException ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases_.flags() == AliasSet::Store (AliasSet::WasmPendingException).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aliases_.flags() == AliasSet::Store(AliasSet::WasmPendingException).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9555); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases_.flags() == AliasSet::Store(AliasSet::WasmPendingException).flags()" ")"); do { *((volatile int*)__null) = 9555; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 9555 | AliasSet::Store(AliasSet::WasmPendingException).flags())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases_.flags() == AliasSet::Store(AliasSet::WasmPendingException ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases_.flags() == AliasSet::Store (AliasSet::WasmPendingException).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aliases_.flags() == AliasSet::Store(AliasSet::WasmPendingException).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9555); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases_.flags() == AliasSet::Store(AliasSet::WasmPendingException).flags()" ")"); do { *((volatile int*)__null) = 9555; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9556 | |
| 9557 | // The only types supported at the moment. |
| 9558 | MOZ_ASSERT(type == MIRType::Pointer || type == MIRType::Int32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9559); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 9559; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 9559 | type == MIRType::Int64 || type == MIRType::WasmAnyRef)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9559); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Pointer || type == MIRType::Int32 || type == MIRType::Int64 || type == MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 9559; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9560 | } |
| 9561 | |
| 9562 | public: |
| 9563 | INSTRUCTION_HEADER(WasmStoreInstance) |
| 9564 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9565 | NAMED_OPERANDS((0, instance), (1, value))MDefinition* instance() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } |
| 9566 | |
| 9567 | uint32_t offset() const { return offset_; } |
| 9568 | |
| 9569 | AliasSet getAliasSet() const override { return aliases_; } |
| 9570 | }; |
| 9571 | |
| 9572 | class MWasmHeapReg : public MNullaryInstruction { |
| 9573 | AliasSet aliases_; |
| 9574 | |
| 9575 | explicit MWasmHeapReg(AliasSet aliases) |
| 9576 | : MNullaryInstruction(classOpcode), aliases_(aliases) { |
| 9577 | setMovable(); |
| 9578 | setResultType(MIRType::Pointer); |
| 9579 | } |
| 9580 | |
| 9581 | public: |
| 9582 | INSTRUCTION_HEADER(WasmHeapReg) |
| 9583 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9584 | |
| 9585 | bool congruentTo(const MDefinition* ins) const override { |
| 9586 | return ins->isWasmHeapReg(); |
| 9587 | } |
| 9588 | |
| 9589 | AliasSet getAliasSet() const override { return aliases_; } |
| 9590 | }; |
| 9591 | |
| 9592 | // For memory32, bounds check nodes are of type Int32 on 32-bit systems for both |
| 9593 | // wasm and asm.js code, as well as on 64-bit systems for asm.js code and for |
| 9594 | // wasm code that is known to have a bounds check limit that fits into 32 bits. |
| 9595 | // They are of type Int64 only on 64-bit systems for wasm code with 4GB heaps. |
| 9596 | // There is no way for nodes of both types to be present in the same function. |
| 9597 | // Should this change, then BCE must be updated to take type into account. |
| 9598 | // |
| 9599 | // For memory64, bounds check nodes are always of type Int64. |
| 9600 | |
| 9601 | class MWasmBoundsCheck : public MBinaryInstruction, public NoTypePolicy::Data { |
| 9602 | public: |
| 9603 | enum Target { |
| 9604 | // Linear memory at index zero, which is the only memory allowed so far. |
| 9605 | Memory0, |
| 9606 | // Everything else. Currently comprises tables, and arrays in the GC |
| 9607 | // proposal. |
| 9608 | Unknown |
| 9609 | }; |
| 9610 | |
| 9611 | private: |
| 9612 | wasm::BytecodeOffset bytecodeOffset_; |
| 9613 | Target target_; |
| 9614 | |
| 9615 | explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit, |
| 9616 | wasm::BytecodeOffset bytecodeOffset, Target target) |
| 9617 | : MBinaryInstruction(classOpcode, index, boundsCheckLimit), |
| 9618 | bytecodeOffset_(bytecodeOffset), |
| 9619 | target_(target) { |
| 9620 | MOZ_ASSERT(index->type() == boundsCheckLimit->type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(index->type() == boundsCheckLimit->type())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(index->type() == boundsCheckLimit->type()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("index->type() == boundsCheckLimit->type()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9620); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index->type() == boundsCheckLimit->type()" ")"); do { *((volatile int*)__null) = 9620; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9621 | |
| 9622 | // Bounds check is effectful: it throws for OOB. |
| 9623 | setGuard(); |
| 9624 | |
| 9625 | if (JitOptions.spectreIndexMasking) { |
| 9626 | setResultType(index->type()); |
| 9627 | } |
| 9628 | } |
| 9629 | |
| 9630 | public: |
| 9631 | INSTRUCTION_HEADER(WasmBoundsCheck) |
| 9632 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9633 | NAMED_OPERANDS((0, index), (1, boundsCheckLimit))MDefinition* index() const { return getOperand(0); } MDefinition * boundsCheckLimit() const { return getOperand(1); } |
| 9634 | |
| 9635 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9636 | |
| 9637 | bool isMemory0() const { return target_ == MWasmBoundsCheck::Memory0; } |
| 9638 | |
| 9639 | bool isRedundant() const { return !isGuard(); } |
| 9640 | |
| 9641 | void setRedundant() { setNotGuard(); } |
| 9642 | |
| 9643 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 9644 | }; |
| 9645 | |
| 9646 | class MWasmAddOffset : public MUnaryInstruction, public NoTypePolicy::Data { |
| 9647 | uint64_t offset_; |
| 9648 | wasm::BytecodeOffset bytecodeOffset_; |
| 9649 | |
| 9650 | MWasmAddOffset(MDefinition* base, uint64_t offset, |
| 9651 | wasm::BytecodeOffset bytecodeOffset) |
| 9652 | : MUnaryInstruction(classOpcode, base), |
| 9653 | offset_(offset), |
| 9654 | bytecodeOffset_(bytecodeOffset) { |
| 9655 | setGuard(); |
| 9656 | MOZ_ASSERT(base->type() == MIRType::Int32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::Int32 || base->type() == MIRType::Int64)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(base->type() == MIRType:: Int32 || base->type() == MIRType::Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("base->type() == MIRType::Int32 || base->type() == MIRType::Int64" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::Int32 || base->type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 9657; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 9657 | base->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::Int32 || base->type() == MIRType::Int64)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(base->type() == MIRType:: Int32 || base->type() == MIRType::Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("base->type() == MIRType::Int32 || base->type() == MIRType::Int64" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::Int32 || base->type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 9657; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9658 | setResultType(base->type()); |
| 9659 | } |
| 9660 | |
| 9661 | public: |
| 9662 | INSTRUCTION_HEADER(WasmAddOffset) |
| 9663 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9664 | NAMED_OPERANDS((0, base))MDefinition* base() const { return getOperand(0); } |
| 9665 | |
| 9666 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 9667 | |
| 9668 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9669 | |
| 9670 | uint64_t offset() const { return offset_; } |
| 9671 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 9672 | }; |
| 9673 | |
| 9674 | class MWasmAlignmentCheck : public MUnaryInstruction, |
| 9675 | public NoTypePolicy::Data { |
| 9676 | uint32_t byteSize_; |
| 9677 | wasm::BytecodeOffset bytecodeOffset_; |
| 9678 | |
| 9679 | explicit MWasmAlignmentCheck(MDefinition* index, uint32_t byteSize, |
| 9680 | wasm::BytecodeOffset bytecodeOffset) |
| 9681 | : MUnaryInstruction(classOpcode, index), |
| 9682 | byteSize_(byteSize), |
| 9683 | bytecodeOffset_(bytecodeOffset) { |
| 9684 | MOZ_ASSERT(mozilla::IsPowerOfTwo(byteSize))do { static_assert( mozilla::detail::AssertionConditionType< decltype(mozilla::IsPowerOfTwo(byteSize))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mozilla::IsPowerOfTwo(byteSize )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("mozilla::IsPowerOfTwo(byteSize)", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mozilla::IsPowerOfTwo(byteSize)" ")"); do { *((volatile int*)__null) = 9684; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9685 | // Alignment check is effectful: it throws for unaligned. |
| 9686 | setGuard(); |
| 9687 | } |
| 9688 | |
| 9689 | public: |
| 9690 | INSTRUCTION_HEADER(WasmAlignmentCheck) |
| 9691 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 9692 | NAMED_OPERANDS((0, index))MDefinition* index() const { return getOperand(0); } |
| 9693 | |
| 9694 | bool congruentTo(const MDefinition* ins) const override; |
| 9695 | |
| 9696 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 9697 | |
| 9698 | uint32_t byteSize() const { return byteSize_; } |
| 9699 | |
| 9700 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 9701 | }; |
| 9702 | |
| 9703 | class MWasmLoad |
| 9704 | : public MVariadicInstruction, // memoryBase is nullptr on some platforms |
| 9705 | public NoTypePolicy::Data { |
| 9706 | wasm::MemoryAccessDesc access_; |
| 9707 | |
| 9708 | explicit MWasmLoad(const wasm::MemoryAccessDesc& access, MIRType resultType) |
| 9709 | : MVariadicInstruction(classOpcode), access_(access) { |
| 9710 | setGuard(); |
| 9711 | setResultType(resultType); |
| 9712 | } |
| 9713 | |
| 9714 | public: |
| 9715 | INSTRUCTION_HEADER(WasmLoad) |
| 9716 | NAMED_OPERANDS((0, base), (1, memoryBase))MDefinition* base() const { return getOperand(0); } MDefinition * memoryBase() const { return getOperand(1); }; |
| 9717 | |
| 9718 | static MWasmLoad* New(TempAllocator& alloc, MDefinition* memoryBase, |
| 9719 | MDefinition* base, const wasm::MemoryAccessDesc& access, |
| 9720 | MIRType resultType) { |
| 9721 | MWasmLoad* load = new (alloc) MWasmLoad(access, resultType); |
| 9722 | if (!load->init(alloc, 1 + !!memoryBase)) { |
| 9723 | return nullptr; |
| 9724 | } |
| 9725 | |
| 9726 | load->initOperand(0, base); |
| 9727 | if (memoryBase) { |
| 9728 | load->initOperand(1, memoryBase); |
| 9729 | } |
| 9730 | |
| 9731 | return load; |
| 9732 | } |
| 9733 | |
| 9734 | const wasm::MemoryAccessDesc& access() const { return access_; } |
| 9735 | |
| 9736 | AliasSet getAliasSet() const override { |
| 9737 | // When a barrier is needed, make the instruction effectful by giving |
| 9738 | // it a "store" effect. |
| 9739 | if (access_.isAtomic()) { |
| 9740 | return AliasSet::Store(AliasSet::WasmHeap); |
| 9741 | } |
| 9742 | return AliasSet::Load(AliasSet::WasmHeap); |
| 9743 | } |
| 9744 | |
| 9745 | bool hasMemoryBase() const { return numOperands() > 1; } |
| 9746 | |
| 9747 | #ifdef JS_JITSPEW1 |
| 9748 | void getExtras(ExtrasCollector* extras) override { |
| 9749 | char buf[64]; |
| 9750 | SprintfLiteral(buf, "(offs=%lld)", (long long int)access().offset64()); |
| 9751 | extras->add(buf); |
| 9752 | } |
| 9753 | #endif |
| 9754 | }; |
| 9755 | |
| 9756 | class MWasmStore : public MVariadicInstruction, public NoTypePolicy::Data { |
| 9757 | wasm::MemoryAccessDesc access_; |
| 9758 | |
| 9759 | explicit MWasmStore(const wasm::MemoryAccessDesc& access) |
| 9760 | : MVariadicInstruction(classOpcode), access_(access) { |
| 9761 | setGuard(); |
| 9762 | } |
| 9763 | |
| 9764 | public: |
| 9765 | INSTRUCTION_HEADER(WasmStore) |
| 9766 | NAMED_OPERANDS((0, base), (1, value), (2, memoryBase))MDefinition* base() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } MDefinition* memoryBase () const { return getOperand(2); } |
| 9767 | |
| 9768 | static MWasmStore* New(TempAllocator& alloc, MDefinition* memoryBase, |
| 9769 | MDefinition* base, |
| 9770 | const wasm::MemoryAccessDesc& access, |
| 9771 | MDefinition* value) { |
| 9772 | MWasmStore* store = new (alloc) MWasmStore(access); |
| 9773 | if (!store->init(alloc, 2 + !!memoryBase)) { |
| 9774 | return nullptr; |
| 9775 | } |
| 9776 | |
| 9777 | store->initOperand(0, base); |
| 9778 | store->initOperand(1, value); |
| 9779 | if (memoryBase) { |
| 9780 | store->initOperand(2, memoryBase); |
| 9781 | } |
| 9782 | |
| 9783 | return store; |
| 9784 | } |
| 9785 | |
| 9786 | const wasm::MemoryAccessDesc& access() const { return access_; } |
| 9787 | |
| 9788 | AliasSet getAliasSet() const override { |
| 9789 | return AliasSet::Store(AliasSet::WasmHeap); |
| 9790 | } |
| 9791 | |
| 9792 | bool hasMemoryBase() const { return numOperands() > 2; } |
| 9793 | |
| 9794 | #ifdef JS_JITSPEW1 |
| 9795 | void getExtras(ExtrasCollector* extras) override { |
| 9796 | char buf[64]; |
| 9797 | SprintfLiteral(buf, "(offs=%lld)", (long long int)access().offset64()); |
| 9798 | extras->add(buf); |
| 9799 | } |
| 9800 | #endif |
| 9801 | }; |
| 9802 | |
| 9803 | class MAsmJSMemoryAccess { |
| 9804 | Scalar::Type accessType_; |
| 9805 | bool needsBoundsCheck_; |
| 9806 | |
| 9807 | public: |
| 9808 | explicit MAsmJSMemoryAccess(Scalar::Type accessType) |
| 9809 | : accessType_(accessType), needsBoundsCheck_(true) { |
| 9810 | MOZ_ASSERT(accessType != Scalar::Uint8Clamped)do { static_assert( mozilla::detail::AssertionConditionType< decltype(accessType != Scalar::Uint8Clamped)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(accessType != Scalar::Uint8Clamped ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "accessType != Scalar::Uint8Clamped", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "accessType != Scalar::Uint8Clamped" ")"); do { *((volatile int*)__null) = 9810; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9811 | } |
| 9812 | |
| 9813 | Scalar::Type accessType() const { return accessType_; } |
| 9814 | unsigned byteSize() const { return TypedArrayElemSize(accessType()); } |
| 9815 | bool needsBoundsCheck() const { return needsBoundsCheck_; } |
| 9816 | |
| 9817 | wasm::MemoryAccessDesc access() const { |
| 9818 | return wasm::MemoryAccessDesc(0, accessType_, Scalar::byteSize(accessType_), |
| 9819 | 0, wasm::BytecodeOffset(), false); |
| 9820 | } |
| 9821 | |
| 9822 | void removeBoundsCheck() { needsBoundsCheck_ = false; } |
| 9823 | }; |
| 9824 | |
| 9825 | class MAsmJSLoadHeap |
| 9826 | : public MVariadicInstruction, // 1 plus optional memoryBase and |
| 9827 | // boundsCheckLimit |
| 9828 | public MAsmJSMemoryAccess, |
| 9829 | public NoTypePolicy::Data { |
| 9830 | uint32_t memoryBaseIndex_; |
| 9831 | |
| 9832 | explicit MAsmJSLoadHeap(uint32_t memoryBaseIndex, Scalar::Type accessType) |
| 9833 | : MVariadicInstruction(classOpcode), |
| 9834 | MAsmJSMemoryAccess(accessType), |
| 9835 | memoryBaseIndex_(memoryBaseIndex) { |
| 9836 | setResultType(ScalarTypeToMIRType(accessType)); |
| 9837 | } |
| 9838 | |
| 9839 | public: |
| 9840 | INSTRUCTION_HEADER(AsmJSLoadHeap) |
| 9841 | NAMED_OPERANDS((0, base), (1, boundsCheckLimit))MDefinition* base() const { return getOperand(0); } MDefinition * boundsCheckLimit() const { return getOperand(1); } |
| 9842 | |
| 9843 | static MAsmJSLoadHeap* New(TempAllocator& alloc, MDefinition* memoryBase, |
| 9844 | MDefinition* base, MDefinition* boundsCheckLimit, |
| 9845 | Scalar::Type accessType) { |
| 9846 | uint32_t nextIndex = 2; |
| 9847 | uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX(4294967295U); |
| 9848 | |
| 9849 | MAsmJSLoadHeap* load = |
| 9850 | new (alloc) MAsmJSLoadHeap(memoryBaseIndex, accessType); |
| 9851 | if (!load->init(alloc, nextIndex)) { |
| 9852 | return nullptr; |
| 9853 | } |
| 9854 | |
| 9855 | load->initOperand(0, base); |
| 9856 | load->initOperand(1, boundsCheckLimit); |
| 9857 | if (memoryBase) { |
| 9858 | load->initOperand(memoryBaseIndex, memoryBase); |
| 9859 | } |
| 9860 | |
| 9861 | return load; |
| 9862 | } |
| 9863 | |
| 9864 | bool hasMemoryBase() const { return memoryBaseIndex_ != UINT32_MAX(4294967295U); } |
| 9865 | MDefinition* memoryBase() const { |
| 9866 | MOZ_ASSERT(hasMemoryBase())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hasMemoryBase())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hasMemoryBase()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("hasMemoryBase()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9866); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hasMemoryBase()" ")"); do { *((volatile int*)__null) = 9866; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9867 | return getOperand(memoryBaseIndex_); |
| 9868 | } |
| 9869 | |
| 9870 | bool congruentTo(const MDefinition* ins) const override; |
| 9871 | AliasSet getAliasSet() const override { |
| 9872 | return AliasSet::Load(AliasSet::WasmHeap); |
| 9873 | } |
| 9874 | AliasType mightAlias(const MDefinition* def) const override; |
| 9875 | }; |
| 9876 | |
| 9877 | class MAsmJSStoreHeap |
| 9878 | : public MVariadicInstruction, // 2 plus optional memoryBase and |
| 9879 | // boundsCheckLimit |
| 9880 | public MAsmJSMemoryAccess, |
| 9881 | public NoTypePolicy::Data { |
| 9882 | uint32_t memoryBaseIndex_; |
| 9883 | |
| 9884 | explicit MAsmJSStoreHeap(uint32_t memoryBaseIndex, Scalar::Type accessType) |
| 9885 | : MVariadicInstruction(classOpcode), |
| 9886 | MAsmJSMemoryAccess(accessType), |
| 9887 | memoryBaseIndex_(memoryBaseIndex) {} |
| 9888 | |
| 9889 | public: |
| 9890 | INSTRUCTION_HEADER(AsmJSStoreHeap) |
| 9891 | NAMED_OPERANDS((0, base), (1, value), (2, boundsCheckLimit))MDefinition* base() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } MDefinition* boundsCheckLimit () const { return getOperand(2); } |
| 9892 | |
| 9893 | static MAsmJSStoreHeap* New(TempAllocator& alloc, MDefinition* memoryBase, |
| 9894 | MDefinition* base, MDefinition* boundsCheckLimit, |
| 9895 | Scalar::Type accessType, MDefinition* v) { |
| 9896 | uint32_t nextIndex = 3; |
| 9897 | uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX(4294967295U); |
| 9898 | |
| 9899 | MAsmJSStoreHeap* store = |
| 9900 | new (alloc) MAsmJSStoreHeap(memoryBaseIndex, accessType); |
| 9901 | if (!store->init(alloc, nextIndex)) { |
| 9902 | return nullptr; |
| 9903 | } |
| 9904 | |
| 9905 | store->initOperand(0, base); |
| 9906 | store->initOperand(1, v); |
| 9907 | store->initOperand(2, boundsCheckLimit); |
| 9908 | if (memoryBase) { |
| 9909 | store->initOperand(memoryBaseIndex, memoryBase); |
| 9910 | } |
| 9911 | |
| 9912 | return store; |
| 9913 | } |
| 9914 | |
| 9915 | bool hasMemoryBase() const { return memoryBaseIndex_ != UINT32_MAX(4294967295U); } |
| 9916 | MDefinition* memoryBase() const { |
| 9917 | MOZ_ASSERT(hasMemoryBase())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hasMemoryBase())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hasMemoryBase()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("hasMemoryBase()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 9917); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hasMemoryBase()" ")"); do { *((volatile int*)__null) = 9917; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 9918 | return getOperand(memoryBaseIndex_); |
| 9919 | } |
| 9920 | |
| 9921 | AliasSet getAliasSet() const override { |
| 9922 | return AliasSet::Store(AliasSet::WasmHeap); |
| 9923 | } |
| 9924 | }; |
| 9925 | |
| 9926 | class MWasmCompareExchangeHeap : public MVariadicInstruction, |
| 9927 | public NoTypePolicy::Data { |
| 9928 | wasm::MemoryAccessDesc access_; |
| 9929 | wasm::BytecodeOffset bytecodeOffset_; |
| 9930 | |
| 9931 | explicit MWasmCompareExchangeHeap(const wasm::MemoryAccessDesc& access, |
| 9932 | wasm::BytecodeOffset bytecodeOffset) |
| 9933 | : MVariadicInstruction(classOpcode), |
| 9934 | access_(access), |
| 9935 | bytecodeOffset_(bytecodeOffset) { |
| 9936 | setGuard(); // Not removable |
| 9937 | setResultType(ScalarTypeToMIRType(access.type())); |
| 9938 | } |
| 9939 | |
| 9940 | public: |
| 9941 | INSTRUCTION_HEADER(WasmCompareExchangeHeap) |
| 9942 | NAMED_OPERANDS((0, base), (1, oldValue), (2, newValue), (3, instance),MDefinition* base() const { return getOperand(0); } MDefinition * oldValue() const { return getOperand(1); } MDefinition* newValue () const { return getOperand(2); } MDefinition* instance() const { return getOperand(3); } MDefinition* memoryBase() const { return getOperand(4); } |
| 9943 | (4, memoryBase))MDefinition* base() const { return getOperand(0); } MDefinition * oldValue() const { return getOperand(1); } MDefinition* newValue () const { return getOperand(2); } MDefinition* instance() const { return getOperand(3); } MDefinition* memoryBase() const { return getOperand(4); } |
| 9944 | |
| 9945 | static MWasmCompareExchangeHeap* New(TempAllocator& alloc, |
| 9946 | wasm::BytecodeOffset bytecodeOffset, |
| 9947 | MDefinition* memoryBase, |
| 9948 | MDefinition* base, |
| 9949 | const wasm::MemoryAccessDesc& access, |
| 9950 | MDefinition* oldv, MDefinition* newv, |
| 9951 | MDefinition* instance) { |
| 9952 | MWasmCompareExchangeHeap* cas = |
| 9953 | new (alloc) MWasmCompareExchangeHeap(access, bytecodeOffset); |
| 9954 | if (!cas->init(alloc, 4 + !!memoryBase)) { |
| 9955 | return nullptr; |
| 9956 | } |
| 9957 | cas->initOperand(0, base); |
| 9958 | cas->initOperand(1, oldv); |
| 9959 | cas->initOperand(2, newv); |
| 9960 | cas->initOperand(3, instance); |
| 9961 | if (memoryBase) { |
| 9962 | cas->initOperand(4, memoryBase); |
| 9963 | } |
| 9964 | return cas; |
| 9965 | } |
| 9966 | |
| 9967 | const wasm::MemoryAccessDesc& access() const { return access_; } |
| 9968 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 9969 | |
| 9970 | AliasSet getAliasSet() const override { |
| 9971 | return AliasSet::Store(AliasSet::WasmHeap); |
| 9972 | } |
| 9973 | |
| 9974 | bool hasMemoryBase() const { return numOperands() > 4; } |
| 9975 | }; |
| 9976 | |
| 9977 | class MWasmAtomicExchangeHeap : public MVariadicInstruction, |
| 9978 | public NoTypePolicy::Data { |
| 9979 | wasm::MemoryAccessDesc access_; |
| 9980 | wasm::BytecodeOffset bytecodeOffset_; |
| 9981 | |
| 9982 | explicit MWasmAtomicExchangeHeap(const wasm::MemoryAccessDesc& access, |
| 9983 | wasm::BytecodeOffset bytecodeOffset) |
| 9984 | : MVariadicInstruction(classOpcode), |
| 9985 | access_(access), |
| 9986 | bytecodeOffset_(bytecodeOffset) { |
| 9987 | setGuard(); // Not removable |
| 9988 | setResultType(ScalarTypeToMIRType(access.type())); |
| 9989 | } |
| 9990 | |
| 9991 | public: |
| 9992 | INSTRUCTION_HEADER(WasmAtomicExchangeHeap) |
| 9993 | NAMED_OPERANDS((0, base), (1, value), (2, instance), (3, memoryBase))MDefinition* base() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } MDefinition* instance () const { return getOperand(2); } MDefinition* memoryBase() const { return getOperand(3); } |
| 9994 | |
| 9995 | static MWasmAtomicExchangeHeap* New(TempAllocator& alloc, |
| 9996 | wasm::BytecodeOffset bytecodeOffset, |
| 9997 | MDefinition* memoryBase, |
| 9998 | MDefinition* base, |
| 9999 | const wasm::MemoryAccessDesc& access, |
| 10000 | MDefinition* value, |
| 10001 | MDefinition* instance) { |
| 10002 | MWasmAtomicExchangeHeap* xchg = |
| 10003 | new (alloc) MWasmAtomicExchangeHeap(access, bytecodeOffset); |
| 10004 | if (!xchg->init(alloc, 3 + !!memoryBase)) { |
| 10005 | return nullptr; |
| 10006 | } |
| 10007 | |
| 10008 | xchg->initOperand(0, base); |
| 10009 | xchg->initOperand(1, value); |
| 10010 | xchg->initOperand(2, instance); |
| 10011 | if (memoryBase) { |
| 10012 | xchg->initOperand(3, memoryBase); |
| 10013 | } |
| 10014 | |
| 10015 | return xchg; |
| 10016 | } |
| 10017 | |
| 10018 | const wasm::MemoryAccessDesc& access() const { return access_; } |
| 10019 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 10020 | |
| 10021 | AliasSet getAliasSet() const override { |
| 10022 | return AliasSet::Store(AliasSet::WasmHeap); |
| 10023 | } |
| 10024 | |
| 10025 | bool hasMemoryBase() const { return numOperands() > 3; } |
| 10026 | }; |
| 10027 | |
| 10028 | class MWasmAtomicBinopHeap : public MVariadicInstruction, |
| 10029 | public NoTypePolicy::Data { |
| 10030 | AtomicOp op_; |
| 10031 | wasm::MemoryAccessDesc access_; |
| 10032 | wasm::BytecodeOffset bytecodeOffset_; |
| 10033 | |
| 10034 | explicit MWasmAtomicBinopHeap(AtomicOp op, |
| 10035 | const wasm::MemoryAccessDesc& access, |
| 10036 | wasm::BytecodeOffset bytecodeOffset) |
| 10037 | : MVariadicInstruction(classOpcode), |
| 10038 | op_(op), |
| 10039 | access_(access), |
| 10040 | bytecodeOffset_(bytecodeOffset) { |
| 10041 | setGuard(); // Not removable |
| 10042 | setResultType(ScalarTypeToMIRType(access.type())); |
| 10043 | } |
| 10044 | |
| 10045 | public: |
| 10046 | INSTRUCTION_HEADER(WasmAtomicBinopHeap) |
| 10047 | NAMED_OPERANDS((0, base), (1, value), (2, instance), (3, memoryBase))MDefinition* base() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } MDefinition* instance () const { return getOperand(2); } MDefinition* memoryBase() const { return getOperand(3); } |
| 10048 | |
| 10049 | static MWasmAtomicBinopHeap* New(TempAllocator& alloc, |
| 10050 | wasm::BytecodeOffset bytecodeOffset, |
| 10051 | AtomicOp op, MDefinition* memoryBase, |
| 10052 | MDefinition* base, |
| 10053 | const wasm::MemoryAccessDesc& access, |
| 10054 | MDefinition* v, MDefinition* instance) { |
| 10055 | MWasmAtomicBinopHeap* binop = |
| 10056 | new (alloc) MWasmAtomicBinopHeap(op, access, bytecodeOffset); |
| 10057 | if (!binop->init(alloc, 3 + !!memoryBase)) { |
| 10058 | return nullptr; |
| 10059 | } |
| 10060 | |
| 10061 | binop->initOperand(0, base); |
| 10062 | binop->initOperand(1, v); |
| 10063 | binop->initOperand(2, instance); |
| 10064 | if (memoryBase) { |
| 10065 | binop->initOperand(3, memoryBase); |
| 10066 | } |
| 10067 | |
| 10068 | return binop; |
| 10069 | } |
| 10070 | |
| 10071 | AtomicOp operation() const { return op_; } |
| 10072 | const wasm::MemoryAccessDesc& access() const { return access_; } |
| 10073 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 10074 | |
| 10075 | AliasSet getAliasSet() const override { |
| 10076 | return AliasSet::Store(AliasSet::WasmHeap); |
| 10077 | } |
| 10078 | |
| 10079 | bool hasMemoryBase() const { return numOperands() > 3; } |
| 10080 | }; |
| 10081 | |
| 10082 | class MWasmLoadInstanceDataField : public MUnaryInstruction, |
| 10083 | public NoTypePolicy::Data { |
| 10084 | MWasmLoadInstanceDataField(MIRType type, unsigned instanceDataOffset, |
| 10085 | bool isConstant, MDefinition* instance) |
| 10086 | : MUnaryInstruction(classOpcode, instance), |
| 10087 | instanceDataOffset_(instanceDataOffset), |
| 10088 | isConstant_(isConstant) { |
| 10089 | MOZ_ASSERT(IsNumberType(type) || type == MIRType::Simd128 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(type) || type == MIRType::Simd128 || type == MIRType::Pointer || type == MIRType::WasmAnyRef)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(IsNumberType(type) || type == MIRType::Simd128 || type == MIRType ::Pointer || type == MIRType::WasmAnyRef))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type) || type == MIRType::Simd128 || type == MIRType::Pointer || type == MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type) || type == MIRType::Simd128 || type == MIRType::Pointer || type == MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 10090; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 10090 | type == MIRType::Pointer || type == MIRType::WasmAnyRef)do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNumberType(type) || type == MIRType::Simd128 || type == MIRType::Pointer || type == MIRType::WasmAnyRef)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(IsNumberType(type) || type == MIRType::Simd128 || type == MIRType ::Pointer || type == MIRType::WasmAnyRef))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type) || type == MIRType::Simd128 || type == MIRType::Pointer || type == MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type) || type == MIRType::Simd128 || type == MIRType::Pointer || type == MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 10090; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10091 | setResultType(type); |
| 10092 | setMovable(); |
| 10093 | } |
| 10094 | |
| 10095 | unsigned instanceDataOffset_; |
| 10096 | bool isConstant_; |
| 10097 | |
| 10098 | public: |
| 10099 | INSTRUCTION_HEADER(WasmLoadInstanceDataField) |
| 10100 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10101 | NAMED_OPERANDS((0, instance))MDefinition* instance() const { return getOperand(0); } |
| 10102 | |
| 10103 | unsigned instanceDataOffset() const { return instanceDataOffset_; } |
| 10104 | |
| 10105 | HashNumber valueHash() const override; |
| 10106 | bool congruentTo(const MDefinition* ins) const override; |
| 10107 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 10108 | |
| 10109 | AliasSet getAliasSet() const override { |
| 10110 | return isConstant_ ? AliasSet::None() |
| 10111 | : AliasSet::Load(AliasSet::WasmInstanceData); |
| 10112 | } |
| 10113 | |
| 10114 | AliasType mightAlias(const MDefinition* def) const override; |
| 10115 | |
| 10116 | #ifdef JS_JITSPEW1 |
| 10117 | void getExtras(ExtrasCollector* extras) override { |
| 10118 | char buf[96]; |
| 10119 | SprintfLiteral(buf, "(offs=%lld, isConst=%s)", |
| 10120 | (long long int)instanceDataOffset_, |
| 10121 | isConstant_ ? "true" : "false"); |
| 10122 | extras->add(buf); |
| 10123 | } |
| 10124 | #endif |
| 10125 | }; |
| 10126 | |
| 10127 | class MWasmLoadGlobalCell : public MUnaryInstruction, |
| 10128 | public NoTypePolicy::Data { |
| 10129 | MWasmLoadGlobalCell(MIRType type, MDefinition* cellPtr) |
| 10130 | : MUnaryInstruction(classOpcode, cellPtr) { |
| 10131 | setResultType(type); |
| 10132 | setMovable(); |
| 10133 | } |
| 10134 | |
| 10135 | public: |
| 10136 | INSTRUCTION_HEADER(WasmLoadGlobalCell) |
| 10137 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10138 | NAMED_OPERANDS((0, cellPtr))MDefinition* cellPtr() const { return getOperand(0); } |
| 10139 | |
| 10140 | // The default valueHash is good enough, because there are no non-operand |
| 10141 | // fields. |
| 10142 | bool congruentTo(const MDefinition* ins) const override; |
| 10143 | |
| 10144 | AliasSet getAliasSet() const override { |
| 10145 | return AliasSet::Load(AliasSet::WasmGlobalCell); |
| 10146 | } |
| 10147 | |
| 10148 | AliasType mightAlias(const MDefinition* def) const override; |
| 10149 | }; |
| 10150 | |
| 10151 | class MWasmLoadTableElement : public MBinaryInstruction, |
| 10152 | public NoTypePolicy::Data { |
| 10153 | MWasmLoadTableElement(MDefinition* elements, MDefinition* index) |
| 10154 | : MBinaryInstruction(classOpcode, elements, index) { |
| 10155 | setResultType(MIRType::WasmAnyRef); |
| 10156 | setMovable(); |
| 10157 | } |
| 10158 | |
| 10159 | public: |
| 10160 | INSTRUCTION_HEADER(WasmLoadTableElement) |
| 10161 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10162 | NAMED_OPERANDS((0, elements))MDefinition* elements() const { return getOperand(0); } |
| 10163 | NAMED_OPERANDS((1, index))MDefinition* index() const { return getOperand(1); } |
| 10164 | |
| 10165 | AliasSet getAliasSet() const override { |
| 10166 | return AliasSet::Load(AliasSet::WasmTableElement); |
| 10167 | } |
| 10168 | }; |
| 10169 | |
| 10170 | class MWasmStoreInstanceDataField : public MBinaryInstruction, |
| 10171 | public NoTypePolicy::Data { |
| 10172 | MWasmStoreInstanceDataField(unsigned instanceDataOffset, MDefinition* value, |
| 10173 | MDefinition* instance) |
| 10174 | : MBinaryInstruction(classOpcode, value, instance), |
| 10175 | instanceDataOffset_(instanceDataOffset) {} |
| 10176 | |
| 10177 | unsigned instanceDataOffset_; |
| 10178 | |
| 10179 | public: |
| 10180 | INSTRUCTION_HEADER(WasmStoreInstanceDataField) |
| 10181 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10182 | NAMED_OPERANDS((0, value), (1, instance))MDefinition* value() const { return getOperand(0); } MDefinition * instance() const { return getOperand(1); } |
| 10183 | |
| 10184 | unsigned instanceDataOffset() const { return instanceDataOffset_; } |
| 10185 | |
| 10186 | AliasSet getAliasSet() const override { |
| 10187 | return AliasSet::Store(AliasSet::WasmInstanceData); |
| 10188 | } |
| 10189 | }; |
| 10190 | |
| 10191 | class MWasmStoreGlobalCell : public MBinaryInstruction, |
| 10192 | public NoTypePolicy::Data { |
| 10193 | MWasmStoreGlobalCell(MDefinition* value, MDefinition* cellPtr) |
| 10194 | : MBinaryInstruction(classOpcode, value, cellPtr) {} |
| 10195 | |
| 10196 | public: |
| 10197 | INSTRUCTION_HEADER(WasmStoreGlobalCell) |
| 10198 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10199 | NAMED_OPERANDS((0, value), (1, cellPtr))MDefinition* value() const { return getOperand(0); } MDefinition * cellPtr() const { return getOperand(1); } |
| 10200 | |
| 10201 | AliasSet getAliasSet() const override { |
| 10202 | return AliasSet::Store(AliasSet::WasmGlobalCell); |
| 10203 | } |
| 10204 | }; |
| 10205 | |
| 10206 | class MWasmStoreStackResult : public MBinaryInstruction, |
| 10207 | public NoTypePolicy::Data { |
| 10208 | MWasmStoreStackResult(MDefinition* stackResultArea, uint32_t offset, |
| 10209 | MDefinition* value) |
| 10210 | : MBinaryInstruction(classOpcode, stackResultArea, value), |
| 10211 | offset_(offset) {} |
| 10212 | |
| 10213 | uint32_t offset_; |
| 10214 | |
| 10215 | public: |
| 10216 | INSTRUCTION_HEADER(WasmStoreStackResult) |
| 10217 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10218 | NAMED_OPERANDS((0, stackResultArea), (1, value))MDefinition* stackResultArea() const { return getOperand(0); } MDefinition* value() const { return getOperand(1); } |
| 10219 | |
| 10220 | uint32_t offset() const { return offset_; } |
| 10221 | |
| 10222 | AliasSet getAliasSet() const override { |
| 10223 | return AliasSet::Store(AliasSet::WasmStackResult); |
| 10224 | } |
| 10225 | }; |
| 10226 | |
| 10227 | // Represents a known-good derived pointer into an object or memory region (in |
| 10228 | // the most general sense) that will not move while the derived pointer is live. |
| 10229 | // The `offset` *must* be a valid offset into the object represented by `base`; |
| 10230 | // hence overflow in the address calculation will never be an issue. `offset` |
| 10231 | // must be representable as a 31-bit unsigned integer. |
| 10232 | // |
| 10233 | // DO NOT use this with a base value of any JS-heap-resident object type. |
| 10234 | // Such a value would need to be adjusted during GC, yet we have no mechanism |
| 10235 | // to do that. See bug 1810090. |
| 10236 | |
| 10237 | class MWasmDerivedPointer : public MUnaryInstruction, |
| 10238 | public NoTypePolicy::Data { |
| 10239 | MWasmDerivedPointer(MDefinition* base, size_t offset) |
| 10240 | : MUnaryInstruction(classOpcode, base), offset_(uint32_t(offset)) { |
| 10241 | MOZ_ASSERT(offset <= INT32_MAX)do { static_assert( mozilla::detail::AssertionConditionType< decltype(offset <= (2147483647))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(offset <= (2147483647)))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("offset <= (2147483647)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10241); AnnotateMozCrashReason("MOZ_ASSERT" "(" "offset <= (2147483647)" ")"); do { *((volatile int*)__null) = 10241; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10242 | // Do not change this to allow `base` to be a GC-heap allocated type. |
| 10243 | MOZ_ASSERT(base->type() == MIRType::Pointer ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::Pointer || base->type () == TargetWordMIRType())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(base->type() == MIRType:: Pointer || base->type() == TargetWordMIRType()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("base->type() == MIRType::Pointer || base->type() == TargetWordMIRType()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::Pointer || base->type() == TargetWordMIRType()" ")"); do { *((volatile int*)__null) = 10244; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 10244 | base->type() == TargetWordMIRType())do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::Pointer || base->type () == TargetWordMIRType())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(base->type() == MIRType:: Pointer || base->type() == TargetWordMIRType()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("base->type() == MIRType::Pointer || base->type() == TargetWordMIRType()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::Pointer || base->type() == TargetWordMIRType()" ")"); do { *((volatile int*)__null) = 10244; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10245 | setResultType(MIRType::Pointer); |
| 10246 | setMovable(); |
| 10247 | } |
| 10248 | |
| 10249 | uint32_t offset_; |
| 10250 | |
| 10251 | public: |
| 10252 | INSTRUCTION_HEADER(WasmDerivedPointer) |
| 10253 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10254 | NAMED_OPERANDS((0, base))MDefinition* base() const { return getOperand(0); } |
| 10255 | |
| 10256 | uint32_t offset() const { return offset_; } |
| 10257 | |
| 10258 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10259 | |
| 10260 | bool congruentTo(const MDefinition* ins) const override { |
| 10261 | return congruentIfOperandsEqual(ins) && |
| 10262 | ins->toWasmDerivedPointer()->offset() == offset(); |
| 10263 | } |
| 10264 | |
| 10265 | #ifdef JS_JITSPEW1 |
| 10266 | void getExtras(ExtrasCollector* extras) override { |
| 10267 | char buf[64]; |
| 10268 | SprintfLiteral(buf, "(offs=%lld)", (long long int)offset_); |
| 10269 | extras->add(buf); |
| 10270 | } |
| 10271 | #endif |
| 10272 | |
| 10273 | ALLOW_CLONE(MWasmDerivedPointer)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmDerivedPointer (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 10274 | }; |
| 10275 | |
| 10276 | // As with MWasmDerivedPointer, DO NOT use this with a base value of any |
| 10277 | // JS-heap-resident object type. |
| 10278 | class MWasmDerivedIndexPointer : public MBinaryInstruction, |
| 10279 | public NoTypePolicy::Data { |
| 10280 | MWasmDerivedIndexPointer(MDefinition* base, MDefinition* index, Scale scale) |
| 10281 | : MBinaryInstruction(classOpcode, base, index), scale_(scale) { |
| 10282 | // Do not change this to allow `base` to be a GC-heap allocated type. |
| 10283 | MOZ_ASSERT(base->type() == MIRType::Pointer)do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::Pointer)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(base->type() == MIRType:: Pointer))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("base->type() == MIRType::Pointer", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10283); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::Pointer" ")"); do { *((volatile int*)__null) = 10283; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10284 | setResultType(MIRType::Pointer); |
| 10285 | setMovable(); |
| 10286 | } |
| 10287 | |
| 10288 | Scale scale_; |
| 10289 | |
| 10290 | public: |
| 10291 | INSTRUCTION_HEADER(WasmDerivedIndexPointer) |
| 10292 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10293 | NAMED_OPERANDS((0, base))MDefinition* base() const { return getOperand(0); } |
| 10294 | NAMED_OPERANDS((1, index))MDefinition* index() const { return getOperand(1); } |
| 10295 | |
| 10296 | Scale scale() const { return scale_; } |
| 10297 | |
| 10298 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10299 | |
| 10300 | bool congruentTo(const MDefinition* ins) const override { |
| 10301 | return congruentIfOperandsEqual(ins) && |
| 10302 | ins->toWasmDerivedIndexPointer()->scale() == scale(); |
| 10303 | } |
| 10304 | |
| 10305 | ALLOW_CLONE(MWasmDerivedIndexPointer)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmDerivedIndexPointer (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 10306 | }; |
| 10307 | |
| 10308 | // Whether to perform a pre-write barrier for a wasm store reference. |
| 10309 | enum class WasmPreBarrierKind : uint8_t { None, Normal }; |
| 10310 | |
| 10311 | // Stores a reference to an address. This performs a pre-barrier on the address, |
| 10312 | // but not a post-barrier. A post-barrier must be performed separately, if it's |
| 10313 | // required. The accessed location is `valueBase + valueOffset`. The latter |
| 10314 | // must be be representable as a 31-bit unsigned integer. |
| 10315 | |
| 10316 | class MWasmStoreRef : public MAryInstruction<3>, public NoTypePolicy::Data { |
| 10317 | uint32_t offset_; |
| 10318 | AliasSet::Flag aliasSet_; |
| 10319 | WasmPreBarrierKind preBarrierKind_; |
| 10320 | |
| 10321 | MWasmStoreRef(MDefinition* instance, MDefinition* valueBase, |
| 10322 | size_t valueOffset, MDefinition* value, AliasSet::Flag aliasSet, |
| 10323 | WasmPreBarrierKind preBarrierKind) |
| 10324 | : MAryInstruction<3>(classOpcode), |
| 10325 | offset_(uint32_t(valueOffset)), |
| 10326 | aliasSet_(aliasSet), |
| 10327 | preBarrierKind_(preBarrierKind) { |
| 10328 | MOZ_ASSERT(valueOffset <= INT32_MAX)do { static_assert( mozilla::detail::AssertionConditionType< decltype(valueOffset <= (2147483647))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(valueOffset <= (2147483647 )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("valueOffset <= (2147483647)", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10328); AnnotateMozCrashReason("MOZ_ASSERT" "(" "valueOffset <= (2147483647)" ")"); do { *((volatile int*)__null) = 10328; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10329 | MOZ_ASSERT(valueBase->type() == MIRType::Pointer ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(valueBase->type() == MIRType::Pointer || valueBase ->type() == MIRType::StackResults)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(valueBase->type() == MIRType ::Pointer || valueBase->type() == MIRType::StackResults))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("valueBase->type() == MIRType::Pointer || valueBase->type() == MIRType::StackResults" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10330); AnnotateMozCrashReason("MOZ_ASSERT" "(" "valueBase->type() == MIRType::Pointer || valueBase->type() == MIRType::StackResults" ")"); do { *((volatile int*)__null) = 10330; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 10330 | valueBase->type() == MIRType::StackResults)do { static_assert( mozilla::detail::AssertionConditionType< decltype(valueBase->type() == MIRType::Pointer || valueBase ->type() == MIRType::StackResults)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(valueBase->type() == MIRType ::Pointer || valueBase->type() == MIRType::StackResults))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("valueBase->type() == MIRType::Pointer || valueBase->type() == MIRType::StackResults" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10330); AnnotateMozCrashReason("MOZ_ASSERT" "(" "valueBase->type() == MIRType::Pointer || valueBase->type() == MIRType::StackResults" ")"); do { *((volatile int*)__null) = 10330; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10331 | MOZ_ASSERT(value->type() == MIRType::WasmAnyRef)do { static_assert( mozilla::detail::AssertionConditionType< decltype(value->type() == MIRType::WasmAnyRef)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(value->type() == MIRType::WasmAnyRef))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("value->type() == MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10331); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() == MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 10331; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10332 | initOperand(0, instance); |
| 10333 | initOperand(1, valueBase); |
| 10334 | initOperand(2, value); |
| 10335 | } |
| 10336 | |
| 10337 | public: |
| 10338 | INSTRUCTION_HEADER(WasmStoreRef) |
| 10339 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10340 | NAMED_OPERANDS((0, instance), (1, valueBase), (2, value))MDefinition* instance() const { return getOperand(0); } MDefinition * valueBase() const { return getOperand(1); } MDefinition* value () const { return getOperand(2); } |
| 10341 | |
| 10342 | uint32_t offset() const { return offset_; } |
| 10343 | AliasSet getAliasSet() const override { return AliasSet::Store(aliasSet_); } |
| 10344 | WasmPreBarrierKind preBarrierKind() const { return preBarrierKind_; } |
| 10345 | |
| 10346 | #ifdef JS_JITSPEW1 |
| 10347 | void getExtras(ExtrasCollector* extras) override { |
| 10348 | char buf[64]; |
| 10349 | SprintfLiteral(buf, "(offs=%lld)", (long long int)offset_); |
| 10350 | extras->add(buf); |
| 10351 | } |
| 10352 | #endif |
| 10353 | }; |
| 10354 | |
| 10355 | // Given a value being written to another object, update the generational store |
| 10356 | // buffer if the value is in the nursery and object is in the tenured heap. |
| 10357 | class MWasmPostWriteBarrierImmediate : public MQuaternaryInstruction, |
| 10358 | public NoTypePolicy::Data { |
| 10359 | uint32_t valueOffset_; |
| 10360 | |
| 10361 | MWasmPostWriteBarrierImmediate(MDefinition* instance, MDefinition* object, |
| 10362 | MDefinition* valueBase, uint32_t valueOffset, |
| 10363 | MDefinition* value) |
| 10364 | : MQuaternaryInstruction(classOpcode, instance, object, valueBase, value), |
| 10365 | valueOffset_(valueOffset) { |
| 10366 | setGuard(); |
| 10367 | } |
| 10368 | |
| 10369 | public: |
| 10370 | INSTRUCTION_HEADER(WasmPostWriteBarrierImmediate) |
| 10371 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10372 | NAMED_OPERANDS((0, instance), (1, object), (2, valueBase), (3, value))MDefinition* instance() const { return getOperand(0); } MDefinition * object() const { return getOperand(1); } MDefinition* valueBase () const { return getOperand(2); } MDefinition* value() const { return getOperand(3); } |
| 10373 | |
| 10374 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10375 | uint32_t valueOffset() const { return valueOffset_; } |
| 10376 | |
| 10377 | ALLOW_CLONE(MWasmPostWriteBarrierImmediate)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmPostWriteBarrierImmediate (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 10378 | }; |
| 10379 | |
| 10380 | // Given a value being written to another object, update the generational store |
| 10381 | // buffer if the value is in the nursery and object is in the tenured heap. |
| 10382 | class MWasmPostWriteBarrierIndex : public MAryInstruction<5>, |
| 10383 | public NoTypePolicy::Data { |
| 10384 | uint32_t elemSize_; |
| 10385 | |
| 10386 | MWasmPostWriteBarrierIndex(MDefinition* instance, MDefinition* object, |
| 10387 | MDefinition* valueBase, MDefinition* index, |
| 10388 | uint32_t scale, MDefinition* value) |
| 10389 | : MAryInstruction<5>(classOpcode), elemSize_(scale) { |
| 10390 | initOperand(0, instance); |
| 10391 | initOperand(1, object); |
| 10392 | initOperand(2, valueBase); |
| 10393 | initOperand(3, index); |
| 10394 | initOperand(4, value); |
| 10395 | setGuard(); |
| 10396 | } |
| 10397 | |
| 10398 | public: |
| 10399 | INSTRUCTION_HEADER(WasmPostWriteBarrierIndex) |
| 10400 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10401 | NAMED_OPERANDS((0, instance), (1, object), (2, valueBase), (3, index),MDefinition* instance() const { return getOperand(0); } MDefinition * object() const { return getOperand(1); } MDefinition* valueBase () const { return getOperand(2); } MDefinition* index() const { return getOperand(3); } MDefinition* value() const { return getOperand(4); } |
| 10402 | (4, value))MDefinition* instance() const { return getOperand(0); } MDefinition * object() const { return getOperand(1); } MDefinition* valueBase () const { return getOperand(2); } MDefinition* index() const { return getOperand(3); } MDefinition* value() const { return getOperand(4); } |
| 10403 | |
| 10404 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10405 | uint32_t elemSize() const { return elemSize_; } |
| 10406 | |
| 10407 | ALLOW_CLONE(MWasmPostWriteBarrierIndex)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmPostWriteBarrierIndex (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 10408 | }; |
| 10409 | |
| 10410 | class MWasmParameter : public MNullaryInstruction { |
| 10411 | ABIArg abi_; |
| 10412 | |
| 10413 | MWasmParameter(ABIArg abi, MIRType mirType) |
| 10414 | : MNullaryInstruction(classOpcode), abi_(abi) { |
| 10415 | setResultType(mirType); |
| 10416 | } |
| 10417 | |
| 10418 | public: |
| 10419 | INSTRUCTION_HEADER(WasmParameter) |
| 10420 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10421 | |
| 10422 | ABIArg abi() const { return abi_; } |
| 10423 | }; |
| 10424 | |
| 10425 | class MWasmReturn : public MAryControlInstruction<2, 0>, |
| 10426 | public NoTypePolicy::Data { |
| 10427 | MWasmReturn(MDefinition* ins, MDefinition* instance) |
| 10428 | : MAryControlInstruction(classOpcode) { |
| 10429 | initOperand(0, ins); |
| 10430 | initOperand(1, instance); |
| 10431 | } |
| 10432 | |
| 10433 | public: |
| 10434 | INSTRUCTION_HEADER(WasmReturn) |
| 10435 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10436 | |
| 10437 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10438 | }; |
| 10439 | |
| 10440 | class MWasmReturnVoid : public MAryControlInstruction<1, 0>, |
| 10441 | public NoTypePolicy::Data { |
| 10442 | explicit MWasmReturnVoid(MDefinition* instance) |
| 10443 | : MAryControlInstruction(classOpcode) { |
| 10444 | initOperand(0, instance); |
| 10445 | } |
| 10446 | |
| 10447 | public: |
| 10448 | INSTRUCTION_HEADER(WasmReturnVoid) |
| 10449 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10450 | |
| 10451 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10452 | }; |
| 10453 | |
| 10454 | class MWasmStackArg : public MUnaryInstruction, public NoTypePolicy::Data { |
| 10455 | MWasmStackArg(uint32_t spOffset, MDefinition* ins) |
| 10456 | : MUnaryInstruction(classOpcode, ins), spOffset_(spOffset) {} |
| 10457 | |
| 10458 | uint32_t spOffset_; |
| 10459 | |
| 10460 | public: |
| 10461 | INSTRUCTION_HEADER(WasmStackArg) |
| 10462 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10463 | NAMED_OPERANDS((0, arg))MDefinition* arg() const { return getOperand(0); } |
| 10464 | |
| 10465 | uint32_t spOffset() const { return spOffset_; } |
| 10466 | void incrementOffset(uint32_t inc) { spOffset_ += inc; } |
| 10467 | }; |
| 10468 | |
| 10469 | template <typename Location> |
| 10470 | class MWasmResultBase : public MNullaryInstruction { |
| 10471 | Location loc_; |
| 10472 | |
| 10473 | protected: |
| 10474 | MWasmResultBase(Opcode op, MIRType type, Location loc) |
| 10475 | : MNullaryInstruction(op), loc_(loc) { |
| 10476 | setResultType(type); |
| 10477 | setCallResultCapture(); |
| 10478 | } |
| 10479 | |
| 10480 | public: |
| 10481 | Location loc() { return loc_; } |
| 10482 | }; |
| 10483 | |
| 10484 | class MWasmRegisterResult : public MWasmResultBase<Register> { |
| 10485 | MWasmRegisterResult(MIRType type, Register reg) |
| 10486 | : MWasmResultBase(classOpcode, type, reg) {} |
| 10487 | |
| 10488 | public: |
| 10489 | INSTRUCTION_HEADER(WasmRegisterResult) |
| 10490 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10491 | }; |
| 10492 | |
| 10493 | class MWasmFloatRegisterResult : public MWasmResultBase<FloatRegister> { |
| 10494 | MWasmFloatRegisterResult(MIRType type, FloatRegister reg) |
| 10495 | : MWasmResultBase(classOpcode, type, reg) {} |
| 10496 | |
| 10497 | public: |
| 10498 | INSTRUCTION_HEADER(WasmFloatRegisterResult) |
| 10499 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10500 | }; |
| 10501 | |
| 10502 | class MWasmRegister64Result : public MWasmResultBase<Register64> { |
| 10503 | explicit MWasmRegister64Result(Register64 reg) |
| 10504 | : MWasmResultBase(classOpcode, MIRType::Int64, reg) {} |
| 10505 | |
| 10506 | public: |
| 10507 | INSTRUCTION_HEADER(WasmRegister64Result) |
| 10508 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10509 | }; |
| 10510 | |
| 10511 | class MWasmStackResultArea : public MNullaryInstruction { |
| 10512 | public: |
| 10513 | class StackResult { |
| 10514 | // Offset in bytes from lowest address of stack result area. |
| 10515 | uint32_t offset_; |
| 10516 | MIRType type_; |
| 10517 | |
| 10518 | public: |
| 10519 | StackResult() : type_(MIRType::Undefined) {} |
| 10520 | StackResult(uint32_t offset, MIRType type) : offset_(offset), type_(type) {} |
| 10521 | |
| 10522 | bool initialized() const { return type_ != MIRType::Undefined; } |
| 10523 | uint32_t offset() const { |
| 10524 | MOZ_ASSERT(initialized())do { static_assert( mozilla::detail::AssertionConditionType< decltype(initialized())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(initialized()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("initialized()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10524); AnnotateMozCrashReason("MOZ_ASSERT" "(" "initialized()" ")"); do { *((volatile int*)__null) = 10524; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10525 | return offset_; |
| 10526 | } |
| 10527 | MIRType type() const { |
| 10528 | MOZ_ASSERT(initialized())do { static_assert( mozilla::detail::AssertionConditionType< decltype(initialized())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(initialized()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("initialized()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10528); AnnotateMozCrashReason("MOZ_ASSERT" "(" "initialized()" ")"); do { *((volatile int*)__null) = 10528; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10529 | return type_; |
| 10530 | } |
| 10531 | uint32_t endOffset() const { |
| 10532 | return offset() + wasm::MIRTypeToABIResultSize(type()); |
| 10533 | } |
| 10534 | }; |
| 10535 | |
| 10536 | private: |
| 10537 | FixedList<StackResult> results_; |
| 10538 | uint32_t base_; |
| 10539 | |
| 10540 | explicit MWasmStackResultArea() |
| 10541 | : MNullaryInstruction(classOpcode), base_(UINT32_MAX(4294967295U)) { |
| 10542 | setResultType(MIRType::StackResults); |
| 10543 | } |
| 10544 | |
| 10545 | void assertInitialized() const { |
| 10546 | MOZ_ASSERT(results_.length() != 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(results_.length() != 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(results_.length() != 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("results_.length() != 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10546); AnnotateMozCrashReason("MOZ_ASSERT" "(" "results_.length() != 0" ")"); do { *((volatile int*)__null) = 10546; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10547 | #ifdef DEBUG1 |
| 10548 | for (size_t i = 0; i < results_.length(); i++) { |
| 10549 | MOZ_ASSERT(results_[i].initialized())do { static_assert( mozilla::detail::AssertionConditionType< decltype(results_[i].initialized())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(results_[i].initialized()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("results_[i].initialized()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10549); AnnotateMozCrashReason("MOZ_ASSERT" "(" "results_[i].initialized()" ")"); do { *((volatile int*)__null) = 10549; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10550 | } |
| 10551 | #endif |
| 10552 | } |
| 10553 | |
| 10554 | bool baseInitialized() const { return base_ != UINT32_MAX(4294967295U); } |
| 10555 | |
| 10556 | public: |
| 10557 | INSTRUCTION_HEADER(WasmStackResultArea) |
| 10558 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10559 | |
| 10560 | [[nodiscard]] bool init(TempAllocator& alloc, size_t stackResultCount) { |
| 10561 | MOZ_ASSERT(results_.length() == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(results_.length() == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(results_.length() == 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("results_.length() == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10561); AnnotateMozCrashReason("MOZ_ASSERT" "(" "results_.length() == 0" ")"); do { *((volatile int*)__null) = 10561; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10562 | MOZ_ASSERT(stackResultCount > 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(stackResultCount > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(stackResultCount > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("stackResultCount > 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10562); AnnotateMozCrashReason("MOZ_ASSERT" "(" "stackResultCount > 0" ")"); do { *((volatile int*)__null) = 10562; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10563 | if (!results_.init(alloc, stackResultCount)) { |
| 10564 | return false; |
| 10565 | } |
| 10566 | for (size_t n = 0; n < stackResultCount; n++) { |
| 10567 | results_[n] = StackResult(); |
| 10568 | } |
| 10569 | return true; |
| 10570 | } |
| 10571 | |
| 10572 | size_t resultCount() const { return results_.length(); } |
| 10573 | const StackResult& result(size_t n) const { |
| 10574 | MOZ_ASSERT(results_[n].initialized())do { static_assert( mozilla::detail::AssertionConditionType< decltype(results_[n].initialized())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(results_[n].initialized()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("results_[n].initialized()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10574); AnnotateMozCrashReason("MOZ_ASSERT" "(" "results_[n].initialized()" ")"); do { *((volatile int*)__null) = 10574; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10575 | return results_[n]; |
| 10576 | } |
| 10577 | void initResult(size_t n, const StackResult& loc) { |
| 10578 | MOZ_ASSERT(!results_[n].initialized())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!results_[n].initialized())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!results_[n].initialized())) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!results_[n].initialized()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10578); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!results_[n].initialized()" ")"); do { *((volatile int*)__null) = 10578; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10579 | MOZ_ASSERT((n == 0) == (loc.offset() == 0))do { static_assert( mozilla::detail::AssertionConditionType< decltype((n == 0) == (loc.offset() == 0))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!((n == 0) == (loc.offset() == 0)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("(n == 0) == (loc.offset() == 0)", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10579); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(n == 0) == (loc.offset() == 0)" ")"); do { *((volatile int*)__null) = 10579; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10580 | MOZ_ASSERT_IF(n > 0, loc.offset() >= result(n - 1).endOffset())do { if (n > 0) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(loc.offset() >= result(n - 1).endOffset())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(loc.offset() >= result(n - 1).endOffset()))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("loc.offset() >= result(n - 1).endOffset()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10580); AnnotateMozCrashReason("MOZ_ASSERT" "(" "loc.offset() >= result(n - 1).endOffset()" ")"); do { *((volatile int*)__null) = 10580; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); } } while (false); |
| 10581 | results_[n] = loc; |
| 10582 | } |
| 10583 | |
| 10584 | uint32_t byteSize() const { |
| 10585 | assertInitialized(); |
| 10586 | return result(resultCount() - 1).endOffset(); |
| 10587 | } |
| 10588 | |
| 10589 | // Stack index indicating base of stack area. |
| 10590 | uint32_t base() const { |
| 10591 | MOZ_ASSERT(baseInitialized())do { static_assert( mozilla::detail::AssertionConditionType< decltype(baseInitialized())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(baseInitialized()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("baseInitialized()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10591); AnnotateMozCrashReason("MOZ_ASSERT" "(" "baseInitialized()" ")"); do { *((volatile int*)__null) = 10591; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10592 | return base_; |
| 10593 | } |
| 10594 | void setBase(uint32_t base) { |
| 10595 | MOZ_ASSERT(!baseInitialized())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!baseInitialized())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!baseInitialized()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!baseInitialized()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!baseInitialized()" ")"); do { *((volatile int*)__null) = 10595; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10596 | base_ = base; |
| 10597 | MOZ_ASSERT(baseInitialized())do { static_assert( mozilla::detail::AssertionConditionType< decltype(baseInitialized())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(baseInitialized()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("baseInitialized()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10597); AnnotateMozCrashReason("MOZ_ASSERT" "(" "baseInitialized()" ")"); do { *((volatile int*)__null) = 10597; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10598 | } |
| 10599 | }; |
| 10600 | |
| 10601 | class MWasmStackResult : public MUnaryInstruction, public NoTypePolicy::Data { |
| 10602 | uint32_t resultIdx_; |
| 10603 | |
| 10604 | MWasmStackResult(MWasmStackResultArea* resultArea, size_t idx) |
| 10605 | : MUnaryInstruction(classOpcode, resultArea), resultIdx_(idx) { |
| 10606 | setResultType(result().type()); |
| 10607 | setCallResultCapture(); |
| 10608 | } |
| 10609 | |
| 10610 | public: |
| 10611 | INSTRUCTION_HEADER(WasmStackResult) |
| 10612 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10613 | NAMED_OPERANDS((0, resultArea))MDefinition* resultArea() const { return getOperand(0); } |
| 10614 | |
| 10615 | const MWasmStackResultArea::StackResult& result() const { |
| 10616 | return resultArea()->toWasmStackResultArea()->result(resultIdx_); |
| 10617 | } |
| 10618 | }; |
| 10619 | |
| 10620 | // Arguments for constructing a catchable wasm call inside of a try block. |
| 10621 | struct MWasmCallTryDesc { |
| 10622 | bool inTry; |
| 10623 | uint32_t relativeTryDepth; |
| 10624 | size_t tryNoteIndex; |
| 10625 | MBasicBlock* fallthroughBlock; |
| 10626 | MBasicBlock* prePadBlock; |
| 10627 | |
| 10628 | MWasmCallTryDesc() |
| 10629 | : inTry(false), |
| 10630 | relativeTryDepth(0), |
| 10631 | tryNoteIndex(0), |
| 10632 | fallthroughBlock(nullptr), |
| 10633 | prePadBlock(nullptr) {} |
| 10634 | }; |
| 10635 | |
| 10636 | // Mixin class for wasm calls that may or may not be catchable. |
| 10637 | class MWasmCallBase { |
| 10638 | public: |
| 10639 | struct Arg { |
| 10640 | AnyRegister reg; |
| 10641 | MDefinition* def; |
| 10642 | Arg(AnyRegister reg, MDefinition* def) : reg(reg), def(def) {} |
| 10643 | }; |
| 10644 | typedef Vector<Arg, 8, SystemAllocPolicy> Args; |
| 10645 | |
| 10646 | protected: |
| 10647 | wasm::CallSiteDesc desc_; |
| 10648 | wasm::CalleeDesc callee_; |
| 10649 | wasm::FailureMode builtinMethodFailureMode_; |
| 10650 | FixedList<AnyRegister> argRegs_; |
| 10651 | uint32_t stackArgAreaSizeUnaligned_; |
| 10652 | ABIArg instanceArg_; |
| 10653 | bool inTry_; |
| 10654 | size_t tryNoteIndex_; |
| 10655 | |
| 10656 | MWasmCallBase(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee, |
| 10657 | uint32_t stackArgAreaSizeUnaligned, bool inTry, |
| 10658 | size_t tryNoteIndex) |
| 10659 | : desc_(desc), |
| 10660 | callee_(callee), |
| 10661 | builtinMethodFailureMode_(wasm::FailureMode::Infallible), |
| 10662 | stackArgAreaSizeUnaligned_(stackArgAreaSizeUnaligned), |
| 10663 | inTry_(inTry), |
| 10664 | tryNoteIndex_(tryNoteIndex) {} |
| 10665 | |
| 10666 | template <class MVariadicT> |
| 10667 | [[nodiscard]] bool initWithArgs(TempAllocator& alloc, MVariadicT* ins, |
| 10668 | const Args& args, |
| 10669 | MDefinition* tableIndexOrRef) { |
| 10670 | if (!argRegs_.init(alloc, args.length())) { |
| 10671 | return false; |
| 10672 | } |
| 10673 | for (size_t i = 0; i < argRegs_.length(); i++) { |
| 10674 | argRegs_[i] = args[i].reg; |
| 10675 | } |
| 10676 | |
| 10677 | if (!ins->init(alloc, argRegs_.length() + (tableIndexOrRef ? 1 : 0))) { |
| 10678 | return false; |
| 10679 | } |
| 10680 | // FixedList doesn't initialize its elements, so do an unchecked init. |
| 10681 | for (size_t i = 0; i < argRegs_.length(); i++) { |
| 10682 | ins->initOperand(i, args[i].def); |
| 10683 | } |
| 10684 | if (tableIndexOrRef) { |
| 10685 | ins->initOperand(argRegs_.length(), tableIndexOrRef); |
| 10686 | } |
| 10687 | return true; |
| 10688 | } |
| 10689 | |
| 10690 | public: |
| 10691 | static bool IsWasmCall(MDefinition* def) { |
| 10692 | return def->isWasmCallCatchable() || def->isWasmCallUncatchable() || |
| 10693 | def->isWasmReturnCall(); |
| 10694 | } |
| 10695 | |
| 10696 | size_t numArgs() const { return argRegs_.length(); } |
| 10697 | AnyRegister registerForArg(size_t index) const { |
| 10698 | MOZ_ASSERT(index < numArgs())do { static_assert( mozilla::detail::AssertionConditionType< decltype(index < numArgs())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(index < numArgs()))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("index < numArgs()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index < numArgs()" ")"); do { *((volatile int*)__null) = 10698; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10699 | return argRegs_[index]; |
| 10700 | } |
| 10701 | const wasm::CallSiteDesc& desc() const { return desc_; } |
| 10702 | const wasm::CalleeDesc& callee() const { return callee_; } |
| 10703 | wasm::FailureMode builtinMethodFailureMode() const { |
| 10704 | MOZ_ASSERT(callee_.which() == wasm::CalleeDesc::BuiltinInstanceMethod)do { static_assert( mozilla::detail::AssertionConditionType< decltype(callee_.which() == wasm::CalleeDesc::BuiltinInstanceMethod )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(callee_.which() == wasm::CalleeDesc::BuiltinInstanceMethod ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "callee_.which() == wasm::CalleeDesc::BuiltinInstanceMethod", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10704); AnnotateMozCrashReason("MOZ_ASSERT" "(" "callee_.which() == wasm::CalleeDesc::BuiltinInstanceMethod" ")"); do { *((volatile int*)__null) = 10704; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10705 | return builtinMethodFailureMode_; |
| 10706 | } |
| 10707 | uint32_t stackArgAreaSizeUnaligned() const { |
| 10708 | return stackArgAreaSizeUnaligned_; |
| 10709 | } |
| 10710 | |
| 10711 | const ABIArg& instanceArg() const { return instanceArg_; } |
| 10712 | |
| 10713 | bool inTry() const { return inTry_; } |
| 10714 | size_t tryNoteIndex() const { return tryNoteIndex_; } |
| 10715 | |
| 10716 | static AliasSet wasmCallAliasSet() { |
| 10717 | // This is ok because: |
| 10718 | // - numElements is immutable |
| 10719 | // - the GC will rewrite any array data pointers on move |
| 10720 | AliasSet exclude = AliasSet(AliasSet::WasmArrayNumElements) | |
| 10721 | AliasSet(AliasSet::WasmArrayDataPointer); |
| 10722 | return AliasSet::Store(AliasSet::Any) & ~exclude; |
| 10723 | } |
| 10724 | }; |
| 10725 | |
| 10726 | // A wasm call that is catchable. This instruction is a control instruction, |
| 10727 | // and terminates the block it is on. A normal return will proceed in a the |
| 10728 | // fallthrough block. An exceptional return will unwind into the landing pad |
| 10729 | // block for this call. The landing pad block must begin with an |
| 10730 | // MWasmCallLandingPrePad. |
| 10731 | class MWasmCallCatchable final : public MVariadicControlInstruction<2>, |
| 10732 | public MWasmCallBase, |
| 10733 | public NoTypePolicy::Data { |
| 10734 | MWasmCallCatchable(const wasm::CallSiteDesc& desc, |
| 10735 | const wasm::CalleeDesc& callee, |
| 10736 | uint32_t stackArgAreaSizeUnaligned, size_t tryNoteIndex) |
| 10737 | : MVariadicControlInstruction(classOpcode), |
| 10738 | MWasmCallBase(desc, callee, stackArgAreaSizeUnaligned, true, |
| 10739 | tryNoteIndex) {} |
| 10740 | |
| 10741 | public: |
| 10742 | INSTRUCTION_HEADER(WasmCallCatchable) |
| 10743 | |
| 10744 | static MWasmCallCatchable* New(TempAllocator& alloc, |
| 10745 | const wasm::CallSiteDesc& desc, |
| 10746 | const wasm::CalleeDesc& callee, |
| 10747 | const Args& args, |
| 10748 | uint32_t stackArgAreaSizeUnaligned, |
| 10749 | const MWasmCallTryDesc& tryDesc, |
| 10750 | MDefinition* tableIndexOrRef = nullptr); |
| 10751 | |
| 10752 | static MWasmCallCatchable* NewBuiltinInstanceMethodCall( |
| 10753 | TempAllocator& alloc, const wasm::CallSiteDesc& desc, |
| 10754 | const wasm::SymbolicAddress builtin, wasm::FailureMode failureMode, |
| 10755 | const ABIArg& instanceArg, const Args& args, |
| 10756 | uint32_t stackArgAreaSizeUnaligned, const MWasmCallTryDesc& tryDesc); |
| 10757 | |
| 10758 | bool possiblyCalls() const override { return true; } |
| 10759 | AliasSet getAliasSet() const override { return wasmCallAliasSet(); } |
| 10760 | |
| 10761 | static const size_t FallthroughBranchIndex = 0; |
| 10762 | static const size_t PrePadBranchIndex = 1; |
| 10763 | }; |
| 10764 | |
| 10765 | // A wasm call that is not catchable. This instruction is not a control |
| 10766 | // instruction, and therefore is not a block terminator. |
| 10767 | class MWasmCallUncatchable final : public MVariadicInstruction, |
| 10768 | public MWasmCallBase, |
| 10769 | public NoTypePolicy::Data { |
| 10770 | MWasmCallUncatchable(const wasm::CallSiteDesc& desc, |
| 10771 | const wasm::CalleeDesc& callee, |
| 10772 | uint32_t stackArgAreaSizeUnaligned) |
| 10773 | : MVariadicInstruction(classOpcode), |
| 10774 | MWasmCallBase(desc, callee, stackArgAreaSizeUnaligned, false, 0) {} |
| 10775 | |
| 10776 | public: |
| 10777 | INSTRUCTION_HEADER(WasmCallUncatchable) |
| 10778 | |
| 10779 | static MWasmCallUncatchable* New(TempAllocator& alloc, |
| 10780 | const wasm::CallSiteDesc& desc, |
| 10781 | const wasm::CalleeDesc& callee, |
| 10782 | const Args& args, |
| 10783 | uint32_t stackArgAreaSizeUnaligned, |
| 10784 | MDefinition* tableIndexOrRef = nullptr); |
| 10785 | |
| 10786 | static MWasmCallUncatchable* NewBuiltinInstanceMethodCall( |
| 10787 | TempAllocator& alloc, const wasm::CallSiteDesc& desc, |
| 10788 | const wasm::SymbolicAddress builtin, wasm::FailureMode failureMode, |
| 10789 | const ABIArg& instanceArg, const Args& args, |
| 10790 | uint32_t stackArgAreaSizeUnaligned); |
| 10791 | |
| 10792 | bool possiblyCalls() const override { return true; } |
| 10793 | AliasSet getAliasSet() const override { return wasmCallAliasSet(); } |
| 10794 | }; |
| 10795 | |
| 10796 | class MWasmReturnCall final : public MVariadicControlInstruction<0>, |
| 10797 | public MWasmCallBase, |
| 10798 | public NoTypePolicy::Data { |
| 10799 | MWasmReturnCall(const wasm::CallSiteDesc& desc, |
| 10800 | const wasm::CalleeDesc& callee, |
| 10801 | uint32_t stackArgAreaSizeUnaligned) |
| 10802 | : MVariadicControlInstruction(classOpcode), |
| 10803 | MWasmCallBase(desc, callee, stackArgAreaSizeUnaligned, false, 0) {} |
| 10804 | |
| 10805 | public: |
| 10806 | INSTRUCTION_HEADER(WasmReturnCall) |
| 10807 | |
| 10808 | static MWasmReturnCall* New(TempAllocator& alloc, |
| 10809 | const wasm::CallSiteDesc& desc, |
| 10810 | const wasm::CalleeDesc& callee, const Args& args, |
| 10811 | uint32_t stackArgAreaSizeUnaligned, |
| 10812 | MDefinition* tableIndexOrRef = nullptr); |
| 10813 | |
| 10814 | bool possiblyCalls() const override { return true; } |
| 10815 | }; |
| 10816 | |
| 10817 | // A marker instruction for a block which is the landing pad for a catchable |
| 10818 | // wasm call. This instruction does not emit any code, only filling in |
| 10819 | // metadata. This instruction must be the first instruction added to the |
| 10820 | // landing pad block. |
| 10821 | class MWasmCallLandingPrePad : public MNullaryInstruction { |
| 10822 | // The block of the call that may unwind to this landing pad. |
| 10823 | MBasicBlock* callBlock_; |
| 10824 | // The index of the try note to initialize a landing pad for. |
| 10825 | size_t tryNoteIndex_; |
| 10826 | |
| 10827 | explicit MWasmCallLandingPrePad(MBasicBlock* callBlock, size_t tryNoteIndex) |
| 10828 | : MNullaryInstruction(classOpcode), |
| 10829 | callBlock_(callBlock), |
| 10830 | tryNoteIndex_(tryNoteIndex) { |
| 10831 | setGuard(); |
| 10832 | } |
| 10833 | |
| 10834 | public: |
| 10835 | INSTRUCTION_HEADER(WasmCallLandingPrePad) |
| 10836 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10837 | |
| 10838 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10839 | |
| 10840 | size_t tryNoteIndex() { return tryNoteIndex_; } |
| 10841 | MBasicBlock* callBlock() { return callBlock_; } |
| 10842 | }; |
| 10843 | |
| 10844 | class MWasmSelect : public MTernaryInstruction, public NoTypePolicy::Data { |
| 10845 | MWasmSelect(MDefinition* trueExpr, MDefinition* falseExpr, |
| 10846 | MDefinition* condExpr) |
| 10847 | : MTernaryInstruction(classOpcode, trueExpr, falseExpr, condExpr) { |
| 10848 | MOZ_ASSERT(condExpr->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(condExpr->type() == MIRType::Int32)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(condExpr->type() == MIRType::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("condExpr->type() == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10848); AnnotateMozCrashReason("MOZ_ASSERT" "(" "condExpr->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 10848; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10849 | MOZ_ASSERT(trueExpr->type() == falseExpr->type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(trueExpr->type() == falseExpr->type())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(trueExpr->type() == falseExpr->type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("trueExpr->type() == falseExpr->type()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "trueExpr->type() == falseExpr->type()" ")"); do { *((volatile int*)__null) = 10849; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10850 | setResultType(trueExpr->type()); |
| 10851 | setMovable(); |
| 10852 | } |
| 10853 | |
| 10854 | public: |
| 10855 | INSTRUCTION_HEADER(WasmSelect) |
| 10856 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10857 | NAMED_OPERANDS((0, trueExpr), (1, falseExpr), (2, condExpr))MDefinition* trueExpr() const { return getOperand(0); } MDefinition * falseExpr() const { return getOperand(1); } MDefinition* condExpr () const { return getOperand(2); } |
| 10858 | |
| 10859 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10860 | |
| 10861 | bool congruentTo(const MDefinition* ins) const override { |
| 10862 | return congruentIfOperandsEqual(ins); |
| 10863 | } |
| 10864 | |
| 10865 | ALLOW_CLONE(MWasmSelect)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmSelect (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 10866 | }; |
| 10867 | |
| 10868 | class MWasmReinterpret : public MUnaryInstruction, public NoTypePolicy::Data { |
| 10869 | MWasmReinterpret(MDefinition* val, MIRType toType) |
| 10870 | : MUnaryInstruction(classOpcode, val) { |
| 10871 | switch (val->type()) { |
| 10872 | case MIRType::Int32: |
| 10873 | MOZ_ASSERT(toType == MIRType::Float32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(toType == MIRType::Float32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(toType == MIRType::Float32)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("toType == MIRType::Float32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10873); AnnotateMozCrashReason("MOZ_ASSERT" "(" "toType == MIRType::Float32" ")"); do { *((volatile int*)__null) = 10873; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10874 | break; |
| 10875 | case MIRType::Float32: |
| 10876 | MOZ_ASSERT(toType == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(toType == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(toType == MIRType::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("toType == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10876); AnnotateMozCrashReason("MOZ_ASSERT" "(" "toType == MIRType::Int32" ")"); do { *((volatile int*)__null) = 10876; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10877 | break; |
| 10878 | case MIRType::Double: |
| 10879 | MOZ_ASSERT(toType == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(toType == MIRType::Int64)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(toType == MIRType::Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("toType == MIRType::Int64" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "toType == MIRType::Int64" ")"); do { *((volatile int*)__null) = 10879; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10880 | break; |
| 10881 | case MIRType::Int64: |
| 10882 | MOZ_ASSERT(toType == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType< decltype(toType == MIRType::Double)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(toType == MIRType::Double))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("toType == MIRType::Double" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10882); AnnotateMozCrashReason("MOZ_ASSERT" "(" "toType == MIRType::Double" ")"); do { *((volatile int*)__null) = 10882; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 10883 | break; |
| 10884 | default: |
| 10885 | MOZ_CRASH("unexpected reinterpret conversion")do { do { } while (false); MOZ_ReportCrash("" "unexpected reinterpret conversion" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 10885); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected reinterpret conversion" ")"); do { *((volatile int*)__null) = 10885; __attribute__(( nomerge)) ::abort(); } while (false); } while (false); |
| 10886 | } |
| 10887 | setMovable(); |
| 10888 | setResultType(toType); |
| 10889 | } |
| 10890 | |
| 10891 | public: |
| 10892 | INSTRUCTION_HEADER(WasmReinterpret) |
| 10893 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10894 | |
| 10895 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10896 | bool congruentTo(const MDefinition* ins) const override { |
| 10897 | // No need to check type() here, because congruentIfOperandsEqual will |
| 10898 | // check it. |
| 10899 | return congruentIfOperandsEqual(ins); |
| 10900 | } |
| 10901 | |
| 10902 | ALLOW_CLONE(MWasmReinterpret)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmReinterpret (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 10903 | }; |
| 10904 | |
| 10905 | class MRotate : public MBinaryInstruction, public NoTypePolicy::Data { |
| 10906 | bool isLeftRotate_; |
| 10907 | |
| 10908 | MRotate(MDefinition* input, MDefinition* count, MIRType type, |
| 10909 | bool isLeftRotate) |
| 10910 | : MBinaryInstruction(classOpcode, input, count), |
| 10911 | isLeftRotate_(isLeftRotate) { |
| 10912 | setMovable(); |
| 10913 | setResultType(type); |
| 10914 | // Prevent reordering. Although there's no problem eliding call result |
| 10915 | // definitions, there's also no need, as they cause no codegen. |
| 10916 | setGuard(); |
| 10917 | } |
| 10918 | |
| 10919 | public: |
| 10920 | INSTRUCTION_HEADER(Rotate) |
| 10921 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10922 | NAMED_OPERANDS((0, input), (1, count))MDefinition* input() const { return getOperand(0); } MDefinition * count() const { return getOperand(1); } |
| 10923 | |
| 10924 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10925 | bool congruentTo(const MDefinition* ins) const override { |
| 10926 | return congruentIfOperandsEqual(ins) && |
| 10927 | ins->toRotate()->isLeftRotate() == isLeftRotate_; |
| 10928 | } |
| 10929 | |
| 10930 | bool isLeftRotate() const { return isLeftRotate_; } |
| 10931 | |
| 10932 | ALLOW_CLONE(MRotate)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MRotate (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 10933 | }; |
| 10934 | |
| 10935 | // Wasm SIMD. |
| 10936 | // |
| 10937 | // See comment in WasmIonCompile.cpp for a justification for these nodes. |
| 10938 | |
| 10939 | // (v128, v128, v128) -> v128 effect-free operation. |
| 10940 | class MWasmTernarySimd128 : public MTernaryInstruction, |
| 10941 | public NoTypePolicy::Data { |
| 10942 | wasm::SimdOp simdOp_; |
| 10943 | |
| 10944 | MWasmTernarySimd128(MDefinition* v0, MDefinition* v1, MDefinition* v2, |
| 10945 | wasm::SimdOp simdOp) |
| 10946 | : MTernaryInstruction(classOpcode, v0, v1, v2), simdOp_(simdOp) { |
| 10947 | setMovable(); |
| 10948 | setResultType(MIRType::Simd128); |
| 10949 | } |
| 10950 | |
| 10951 | public: |
| 10952 | INSTRUCTION_HEADER(WasmTernarySimd128) |
| 10953 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10954 | NAMED_OPERANDS((0, v0), (1, v1), (2, v2))MDefinition* v0() const { return getOperand(0); } MDefinition * v1() const { return getOperand(1); } MDefinition* v2() const { return getOperand(2); } |
| 10955 | |
| 10956 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10957 | bool congruentTo(const MDefinition* ins) const override { |
| 10958 | return congruentIfOperandsEqual(ins) && |
| 10959 | simdOp() == ins->toWasmTernarySimd128()->simdOp(); |
| 10960 | } |
| 10961 | #ifdef ENABLE_WASM_SIMD1 |
| 10962 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 10963 | |
| 10964 | // If the control mask of a bitselect allows the operation to be specialized |
| 10965 | // as a shuffle and it is profitable to specialize it on this platform, return |
| 10966 | // true and the appropriate shuffle mask. |
| 10967 | bool specializeBitselectConstantMaskAsShuffle(int8_t shuffle[16]); |
| 10968 | // Checks if more relaxed version of lane select can be used. It returns true |
| 10969 | // if a bit mask input expected to be all 0s or 1s for entire 8-bit lanes, |
| 10970 | // false otherwise. |
| 10971 | bool canRelaxBitselect(); |
| 10972 | #endif |
| 10973 | |
| 10974 | wasm::SimdOp simdOp() const { return simdOp_; } |
| 10975 | |
| 10976 | ALLOW_CLONE(MWasmTernarySimd128)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmTernarySimd128 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 10977 | }; |
| 10978 | |
| 10979 | // (v128, v128) -> v128 effect-free operations. |
| 10980 | class MWasmBinarySimd128 : public MBinaryInstruction, |
| 10981 | public NoTypePolicy::Data { |
| 10982 | wasm::SimdOp simdOp_; |
| 10983 | |
| 10984 | MWasmBinarySimd128(MDefinition* lhs, MDefinition* rhs, bool commutative, |
| 10985 | wasm::SimdOp simdOp) |
| 10986 | : MBinaryInstruction(classOpcode, lhs, rhs), simdOp_(simdOp) { |
| 10987 | setMovable(); |
| 10988 | setResultType(MIRType::Simd128); |
| 10989 | if (commutative) { |
| 10990 | setCommutative(); |
| 10991 | } |
| 10992 | } |
| 10993 | |
| 10994 | public: |
| 10995 | INSTRUCTION_HEADER(WasmBinarySimd128) |
| 10996 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 10997 | |
| 10998 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 10999 | bool congruentTo(const MDefinition* ins) const override { |
| 11000 | return congruentIfOperandsEqual(ins) && |
| 11001 | ins->toWasmBinarySimd128()->simdOp() == simdOp_; |
| 11002 | } |
| 11003 | #ifdef ENABLE_WASM_SIMD1 |
| 11004 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 11005 | |
| 11006 | // Checks if pmaddubsw operation is supported. |
| 11007 | bool canPmaddubsw(); |
| 11008 | #endif |
| 11009 | |
| 11010 | wasm::SimdOp simdOp() const { return simdOp_; } |
| 11011 | |
| 11012 | // Platform-dependent specialization. |
| 11013 | bool specializeForConstantRhs(); |
| 11014 | |
| 11015 | ALLOW_CLONE(MWasmBinarySimd128)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmBinarySimd128 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 11016 | }; |
| 11017 | |
| 11018 | // (v128, const) -> v128 effect-free operations. |
| 11019 | class MWasmBinarySimd128WithConstant : public MUnaryInstruction, |
| 11020 | public NoTypePolicy::Data { |
| 11021 | SimdConstant rhs_; |
| 11022 | wasm::SimdOp simdOp_; |
| 11023 | |
| 11024 | MWasmBinarySimd128WithConstant(MDefinition* lhs, const SimdConstant& rhs, |
| 11025 | wasm::SimdOp simdOp) |
| 11026 | : MUnaryInstruction(classOpcode, lhs), rhs_(rhs), simdOp_(simdOp) { |
| 11027 | setMovable(); |
| 11028 | setResultType(MIRType::Simd128); |
| 11029 | } |
| 11030 | |
| 11031 | public: |
| 11032 | INSTRUCTION_HEADER(WasmBinarySimd128WithConstant) |
| 11033 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11034 | |
| 11035 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 11036 | bool congruentTo(const MDefinition* ins) const override { |
| 11037 | return congruentIfOperandsEqual(ins) && |
| 11038 | ins->toWasmBinarySimd128WithConstant()->simdOp() == simdOp_ && |
| 11039 | rhs_.bitwiseEqual(ins->toWasmBinarySimd128WithConstant()->rhs()); |
| 11040 | } |
| 11041 | |
| 11042 | wasm::SimdOp simdOp() const { return simdOp_; } |
| 11043 | MDefinition* lhs() const { return input(); } |
| 11044 | const SimdConstant& rhs() const { return rhs_; } |
| 11045 | |
| 11046 | ALLOW_CLONE(MWasmBinarySimd128WithConstant)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmBinarySimd128WithConstant (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 11047 | }; |
| 11048 | |
| 11049 | // (v128, scalar, imm) -> v128 effect-free operations. |
| 11050 | class MWasmReplaceLaneSimd128 : public MBinaryInstruction, |
| 11051 | public NoTypePolicy::Data { |
| 11052 | uint32_t laneIndex_; |
| 11053 | wasm::SimdOp simdOp_; |
| 11054 | |
| 11055 | MWasmReplaceLaneSimd128(MDefinition* lhs, MDefinition* rhs, |
| 11056 | uint32_t laneIndex, wasm::SimdOp simdOp) |
| 11057 | : MBinaryInstruction(classOpcode, lhs, rhs), |
| 11058 | laneIndex_(laneIndex), |
| 11059 | simdOp_(simdOp) { |
| 11060 | setMovable(); |
| 11061 | setResultType(MIRType::Simd128); |
| 11062 | } |
| 11063 | |
| 11064 | public: |
| 11065 | INSTRUCTION_HEADER(WasmReplaceLaneSimd128) |
| 11066 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11067 | |
| 11068 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 11069 | bool congruentTo(const MDefinition* ins) const override { |
| 11070 | return congruentIfOperandsEqual(ins) && |
| 11071 | ins->toWasmReplaceLaneSimd128()->simdOp() == simdOp_ && |
| 11072 | ins->toWasmReplaceLaneSimd128()->laneIndex() == laneIndex_; |
| 11073 | } |
| 11074 | |
| 11075 | uint32_t laneIndex() const { return laneIndex_; } |
| 11076 | wasm::SimdOp simdOp() const { return simdOp_; } |
| 11077 | |
| 11078 | ALLOW_CLONE(MWasmReplaceLaneSimd128)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmReplaceLaneSimd128 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 11079 | }; |
| 11080 | |
| 11081 | // (scalar) -> v128 effect-free operations. |
| 11082 | class MWasmScalarToSimd128 : public MUnaryInstruction, |
| 11083 | public NoTypePolicy::Data { |
| 11084 | wasm::SimdOp simdOp_; |
| 11085 | |
| 11086 | MWasmScalarToSimd128(MDefinition* src, wasm::SimdOp simdOp) |
| 11087 | : MUnaryInstruction(classOpcode, src), simdOp_(simdOp) { |
| 11088 | setMovable(); |
| 11089 | setResultType(MIRType::Simd128); |
| 11090 | } |
| 11091 | |
| 11092 | public: |
| 11093 | INSTRUCTION_HEADER(WasmScalarToSimd128) |
| 11094 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11095 | |
| 11096 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 11097 | bool congruentTo(const MDefinition* ins) const override { |
| 11098 | return congruentIfOperandsEqual(ins) && |
| 11099 | ins->toWasmScalarToSimd128()->simdOp() == simdOp_; |
| 11100 | } |
| 11101 | #ifdef ENABLE_WASM_SIMD1 |
| 11102 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 11103 | #endif |
| 11104 | |
| 11105 | wasm::SimdOp simdOp() const { return simdOp_; } |
| 11106 | |
| 11107 | ALLOW_CLONE(MWasmScalarToSimd128)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmScalarToSimd128 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 11108 | }; |
| 11109 | |
| 11110 | // (v128, imm) -> scalar effect-free operations. |
| 11111 | class MWasmReduceSimd128 : public MUnaryInstruction, public NoTypePolicy::Data { |
| 11112 | wasm::SimdOp simdOp_; |
| 11113 | uint32_t imm_; |
| 11114 | |
| 11115 | MWasmReduceSimd128(MDefinition* src, wasm::SimdOp simdOp, MIRType outType, |
| 11116 | uint32_t imm) |
| 11117 | : MUnaryInstruction(classOpcode, src), simdOp_(simdOp), imm_(imm) { |
| 11118 | setMovable(); |
| 11119 | setResultType(outType); |
| 11120 | } |
| 11121 | |
| 11122 | public: |
| 11123 | INSTRUCTION_HEADER(WasmReduceSimd128) |
| 11124 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11125 | |
| 11126 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 11127 | bool congruentTo(const MDefinition* ins) const override { |
| 11128 | return congruentIfOperandsEqual(ins) && |
| 11129 | ins->toWasmReduceSimd128()->simdOp() == simdOp_ && |
| 11130 | ins->toWasmReduceSimd128()->imm() == imm_; |
| 11131 | } |
| 11132 | #ifdef ENABLE_WASM_SIMD1 |
| 11133 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 11134 | #endif |
| 11135 | |
| 11136 | uint32_t imm() const { return imm_; } |
| 11137 | wasm::SimdOp simdOp() const { return simdOp_; } |
| 11138 | |
| 11139 | ALLOW_CLONE(MWasmReduceSimd128)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MWasmReduceSimd128 (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 11140 | }; |
| 11141 | |
| 11142 | class MWasmLoadLaneSimd128 |
| 11143 | : public MVariadicInstruction, // memoryBase is nullptr on some platforms |
| 11144 | public NoTypePolicy::Data { |
| 11145 | wasm::MemoryAccessDesc access_; |
| 11146 | uint32_t laneSize_; |
| 11147 | uint32_t laneIndex_; |
| 11148 | uint32_t memoryBaseIndex_; |
| 11149 | |
| 11150 | MWasmLoadLaneSimd128(const wasm::MemoryAccessDesc& access, uint32_t laneSize, |
| 11151 | uint32_t laneIndex, uint32_t memoryBaseIndex) |
| 11152 | : MVariadicInstruction(classOpcode), |
| 11153 | access_(access), |
| 11154 | laneSize_(laneSize), |
| 11155 | laneIndex_(laneIndex), |
| 11156 | memoryBaseIndex_(memoryBaseIndex) { |
| 11157 | MOZ_ASSERT(!access_.isAtomic())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!access_.isAtomic())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!access_.isAtomic()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!access_.isAtomic()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11157); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!access_.isAtomic()" ")"); do { *((volatile int*)__null) = 11157; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11158 | setGuard(); |
| 11159 | setResultType(MIRType::Simd128); |
| 11160 | } |
| 11161 | |
| 11162 | public: |
| 11163 | INSTRUCTION_HEADER(WasmLoadLaneSimd128) |
| 11164 | NAMED_OPERANDS((0, base), (1, value))MDefinition* base() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); }; |
| 11165 | |
| 11166 | static MWasmLoadLaneSimd128* New(TempAllocator& alloc, |
| 11167 | MDefinition* memoryBase, MDefinition* base, |
| 11168 | const wasm::MemoryAccessDesc& access, |
| 11169 | uint32_t laneSize, uint32_t laneIndex, |
| 11170 | MDefinition* value) { |
| 11171 | uint32_t nextIndex = 2; |
| 11172 | uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX(4294967295U); |
| 11173 | |
| 11174 | MWasmLoadLaneSimd128* load = new (alloc) |
| 11175 | MWasmLoadLaneSimd128(access, laneSize, laneIndex, memoryBaseIndex); |
| 11176 | if (!load->init(alloc, nextIndex)) { |
| 11177 | return nullptr; |
| 11178 | } |
| 11179 | |
| 11180 | load->initOperand(0, base); |
| 11181 | load->initOperand(1, value); |
| 11182 | if (memoryBase) { |
| 11183 | load->initOperand(memoryBaseIndex, memoryBase); |
| 11184 | } |
| 11185 | |
| 11186 | return load; |
| 11187 | } |
| 11188 | |
| 11189 | const wasm::MemoryAccessDesc& access() const { return access_; } |
| 11190 | uint32_t laneSize() const { return laneSize_; } |
| 11191 | uint32_t laneIndex() const { return laneIndex_; } |
| 11192 | bool hasMemoryBase() const { return memoryBaseIndex_ != UINT32_MAX(4294967295U); } |
| 11193 | MDefinition* memoryBase() const { |
| 11194 | MOZ_ASSERT(hasMemoryBase())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hasMemoryBase())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hasMemoryBase()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("hasMemoryBase()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11194); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hasMemoryBase()" ")"); do { *((volatile int*)__null) = 11194; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11195 | return getOperand(memoryBaseIndex_); |
| 11196 | } |
| 11197 | |
| 11198 | AliasSet getAliasSet() const override { |
| 11199 | return AliasSet::Load(AliasSet::WasmHeap); |
| 11200 | } |
| 11201 | }; |
| 11202 | |
| 11203 | class MWasmStoreLaneSimd128 : public MVariadicInstruction, |
| 11204 | public NoTypePolicy::Data { |
| 11205 | wasm::MemoryAccessDesc access_; |
| 11206 | uint32_t laneSize_; |
| 11207 | uint32_t laneIndex_; |
| 11208 | uint32_t memoryBaseIndex_; |
| 11209 | |
| 11210 | explicit MWasmStoreLaneSimd128(const wasm::MemoryAccessDesc& access, |
| 11211 | uint32_t laneSize, uint32_t laneIndex, |
| 11212 | uint32_t memoryBaseIndex) |
| 11213 | : MVariadicInstruction(classOpcode), |
| 11214 | access_(access), |
| 11215 | laneSize_(laneSize), |
| 11216 | laneIndex_(laneIndex), |
| 11217 | memoryBaseIndex_(memoryBaseIndex) { |
| 11218 | MOZ_ASSERT(!access_.isAtomic())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!access_.isAtomic())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!access_.isAtomic()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!access_.isAtomic()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!access_.isAtomic()" ")"); do { *((volatile int*)__null) = 11218; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11219 | setGuard(); |
| 11220 | setResultType(MIRType::Simd128); |
| 11221 | } |
| 11222 | |
| 11223 | public: |
| 11224 | INSTRUCTION_HEADER(WasmStoreLaneSimd128) |
| 11225 | NAMED_OPERANDS((0, base), (1, value))MDefinition* base() const { return getOperand(0); } MDefinition * value() const { return getOperand(1); } |
| 11226 | |
| 11227 | static MWasmStoreLaneSimd128* New(TempAllocator& alloc, |
| 11228 | MDefinition* memoryBase, MDefinition* base, |
| 11229 | const wasm::MemoryAccessDesc& access, |
| 11230 | uint32_t laneSize, uint32_t laneIndex, |
| 11231 | MDefinition* value) { |
| 11232 | uint32_t nextIndex = 2; |
| 11233 | uint32_t memoryBaseIndex = memoryBase ? nextIndex++ : UINT32_MAX(4294967295U); |
| 11234 | |
| 11235 | MWasmStoreLaneSimd128* store = new (alloc) |
| 11236 | MWasmStoreLaneSimd128(access, laneSize, laneIndex, memoryBaseIndex); |
| 11237 | if (!store->init(alloc, nextIndex)) { |
| 11238 | return nullptr; |
| 11239 | } |
| 11240 | |
| 11241 | store->initOperand(0, base); |
| 11242 | store->initOperand(1, value); |
| 11243 | if (memoryBase) { |
| 11244 | store->initOperand(memoryBaseIndex, memoryBase); |
| 11245 | } |
| 11246 | |
| 11247 | return store; |
| 11248 | } |
| 11249 | |
| 11250 | const wasm::MemoryAccessDesc& access() const { return access_; } |
| 11251 | uint32_t laneSize() const { return laneSize_; } |
| 11252 | uint32_t laneIndex() const { return laneIndex_; } |
| 11253 | bool hasMemoryBase() const { return memoryBaseIndex_ != UINT32_MAX(4294967295U); } |
| 11254 | MDefinition* memoryBase() const { |
| 11255 | MOZ_ASSERT(hasMemoryBase())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hasMemoryBase())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hasMemoryBase()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("hasMemoryBase()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11255); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hasMemoryBase()" ")"); do { *((volatile int*)__null) = 11255; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11256 | return getOperand(memoryBaseIndex_); |
| 11257 | } |
| 11258 | |
| 11259 | AliasSet getAliasSet() const override { |
| 11260 | return AliasSet::Store(AliasSet::WasmHeap); |
| 11261 | } |
| 11262 | }; |
| 11263 | |
| 11264 | // End Wasm SIMD |
| 11265 | |
| 11266 | // Used by MIR building to represent the bytecode result of an operation for |
| 11267 | // which an MBail was generated, to balance the basic block's MDefinition stack. |
| 11268 | class MUnreachableResult : public MNullaryInstruction { |
| 11269 | explicit MUnreachableResult(MIRType type) : MNullaryInstruction(classOpcode) { |
| 11270 | MOZ_ASSERT(type != MIRType::None)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type != MIRType::None)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type != MIRType::None))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("type != MIRType::None" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11270); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type != MIRType::None" ")"); do { *((volatile int*)__null) = 11270; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11271 | setResultType(type); |
| 11272 | } |
| 11273 | |
| 11274 | public: |
| 11275 | INSTRUCTION_HEADER(UnreachableResult) |
| 11276 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11277 | |
| 11278 | bool congruentTo(const MDefinition* ins) const override { |
| 11279 | return congruentIfOperandsEqual(ins); |
| 11280 | } |
| 11281 | AliasSet getAliasSet() const override { return AliasSet::None(); } |
| 11282 | }; |
| 11283 | |
| 11284 | class MIonToWasmCall final : public MVariadicInstruction, |
| 11285 | public NoTypePolicy::Data { |
| 11286 | CompilerGCPointer<WasmInstanceObject*> instanceObj_; |
| 11287 | const wasm::FuncExport& funcExport_; |
| 11288 | |
| 11289 | MIonToWasmCall(WasmInstanceObject* instanceObj, MIRType resultType, |
| 11290 | const wasm::FuncExport& funcExport) |
| 11291 | : MVariadicInstruction(classOpcode), |
| 11292 | instanceObj_(instanceObj), |
| 11293 | funcExport_(funcExport) { |
| 11294 | setResultType(resultType); |
| 11295 | } |
| 11296 | |
| 11297 | public: |
| 11298 | INSTRUCTION_HEADER(IonToWasmCall); |
| 11299 | |
| 11300 | static MIonToWasmCall* New(TempAllocator& alloc, |
| 11301 | WasmInstanceObject* instanceObj, |
| 11302 | const wasm::FuncExport& funcExport); |
| 11303 | |
| 11304 | void initArg(size_t i, MDefinition* arg) { initOperand(i, arg); } |
| 11305 | |
| 11306 | WasmInstanceObject* instanceObject() const { return instanceObj_; } |
| 11307 | wasm::Instance* instance() const { return &instanceObj_->instance(); } |
| 11308 | const wasm::FuncExport& funcExport() const { return funcExport_; } |
| 11309 | bool possiblyCalls() const override { return true; } |
| 11310 | #ifdef DEBUG1 |
| 11311 | bool isConsistentFloat32Use(MUse* use) const override; |
| 11312 | #endif |
| 11313 | }; |
| 11314 | |
| 11315 | // For accesses to wasm object fields, we need to be able to describe 8- and |
| 11316 | // 16-bit accesses. But MIRType can't represent those. Hence these two |
| 11317 | // supplemental enums, used for reading and writing fields respectively. |
| 11318 | |
| 11319 | // Indicates how to widen an 8- or 16-bit value (when it is read from memory). |
| 11320 | enum class MWideningOp : uint8_t { None, FromU16, FromS16, FromU8, FromS8 }; |
| 11321 | |
| 11322 | #ifdef JS_JITSPEW1 |
| 11323 | static inline const char* StringFromMWideningOp(MWideningOp op) { |
| 11324 | switch (op) { |
| 11325 | case MWideningOp::None: |
| 11326 | return "None"; |
| 11327 | case MWideningOp::FromU16: |
| 11328 | return "FromU16"; |
| 11329 | case MWideningOp::FromS16: |
| 11330 | return "FromS16"; |
| 11331 | case MWideningOp::FromU8: |
| 11332 | return "FromU8"; |
| 11333 | case MWideningOp::FromS8: |
| 11334 | return "FromS8"; |
| 11335 | default: |
| 11336 | break; |
| 11337 | } |
| 11338 | MOZ_CRASH("Unknown MWideningOp")do { do { } while (false); MOZ_ReportCrash("" "Unknown MWideningOp" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11338); AnnotateMozCrashReason("MOZ_CRASH(" "Unknown MWideningOp" ")"); do { *((volatile int*)__null) = 11338; __attribute__(( nomerge)) ::abort(); } while (false); } while (false); |
| 11339 | } |
| 11340 | #endif |
| 11341 | |
| 11342 | // Indicates how to narrow a 32-bit value (when it is written to memory). The |
| 11343 | // operation is a simple truncate. |
| 11344 | enum class MNarrowingOp : uint8_t { None, To16, To8 }; |
| 11345 | |
| 11346 | #ifdef JS_JITSPEW1 |
| 11347 | static inline const char* StringFromMNarrowingOp(MNarrowingOp op) { |
| 11348 | switch (op) { |
| 11349 | case MNarrowingOp::None: |
| 11350 | return "None"; |
| 11351 | case MNarrowingOp::To16: |
| 11352 | return "To16"; |
| 11353 | case MNarrowingOp::To8: |
| 11354 | return "To8"; |
| 11355 | default: |
| 11356 | break; |
| 11357 | } |
| 11358 | MOZ_CRASH("Unknown MNarrowingOp")do { do { } while (false); MOZ_ReportCrash("" "Unknown MNarrowingOp" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11358); AnnotateMozCrashReason("MOZ_CRASH(" "Unknown MNarrowingOp" ")"); do { *((volatile int*)__null) = 11358; __attribute__(( nomerge)) ::abort(); } while (false); } while (false); |
| 11359 | } |
| 11360 | #endif |
| 11361 | |
| 11362 | // Provide information about potential trap at the instruction machine code, |
| 11363 | // e.g. null pointer dereference. |
| 11364 | struct TrapSiteInfo { |
| 11365 | wasm::BytecodeOffset offset; |
| 11366 | explicit TrapSiteInfo(wasm::BytecodeOffset offset_) : offset(offset_) {} |
| 11367 | }; |
| 11368 | |
| 11369 | typedef mozilla::Maybe<TrapSiteInfo> MaybeTrapSiteInfo; |
| 11370 | |
| 11371 | // Load an object field stored at a fixed offset from a base pointer. This |
| 11372 | // field may be any value type, including references. No barriers are |
| 11373 | // performed. The offset must be representable as a 31-bit unsigned integer. |
| 11374 | class MWasmLoadField : public MUnaryInstruction, public NoTypePolicy::Data { |
| 11375 | uint32_t offset_; |
| 11376 | MWideningOp wideningOp_; |
| 11377 | AliasSet aliases_; |
| 11378 | MaybeTrapSiteInfo maybeTrap_; |
| 11379 | |
| 11380 | MWasmLoadField(MDefinition* obj, uint32_t offset, MIRType type, |
| 11381 | MWideningOp wideningOp, AliasSet aliases, |
| 11382 | MaybeTrapSiteInfo maybeTrap = mozilla::Nothing()) |
| 11383 | : MUnaryInstruction(classOpcode, obj), |
| 11384 | offset_(uint32_t(offset)), |
| 11385 | wideningOp_(wideningOp), |
| 11386 | aliases_(aliases), |
| 11387 | maybeTrap_(maybeTrap) { |
| 11388 | MOZ_ASSERT(offset <= INT32_MAX)do { static_assert( mozilla::detail::AssertionConditionType< decltype(offset <= (2147483647))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(offset <= (2147483647)))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("offset <= (2147483647)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11388); AnnotateMozCrashReason("MOZ_ASSERT" "(" "offset <= (2147483647)" ")"); do { *((volatile int*)__null) = 11388; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11389 | // "if you want to widen the value when it is loaded, the destination type |
| 11390 | // must be Int32". |
| 11391 | MOZ_ASSERT_IF(wideningOp != MWideningOp::None, type == MIRType::Int32)do { if (wideningOp != MWideningOp::None) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(type == MIRType::Int32)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(type == MIRType::Int32))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11391); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int32" ")"); do { *((volatile int*)__null) = 11391; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); } } while (false); |
| 11392 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11399; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11393 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11399; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11394 | AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11399; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11395 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11399; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11396 | AliasSet::Load(AliasSet::WasmArrayNumElements).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11399; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11397 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11399; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11398 | AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11399; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11399 | aliases.flags() == AliasSet::Load(AliasSet::Any).flags())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11399); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayNumElements).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataPointer).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11399; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11400 | setResultType(type); |
| 11401 | if (maybeTrap_) { |
| 11402 | setGuard(); |
| 11403 | } |
| 11404 | } |
| 11405 | |
| 11406 | public: |
| 11407 | INSTRUCTION_HEADER(WasmLoadField) |
| 11408 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11409 | NAMED_OPERANDS((0, obj))MDefinition* obj() const { return getOperand(0); } |
| 11410 | |
| 11411 | uint32_t offset() const { return offset_; } |
| 11412 | MWideningOp wideningOp() const { return wideningOp_; } |
| 11413 | AliasSet getAliasSet() const override { return aliases_; } |
| 11414 | MaybeTrapSiteInfo maybeTrap() const { return maybeTrap_; } |
| 11415 | |
| 11416 | bool congruentTo(const MDefinition* ins) const override { |
| 11417 | // In the limited case where this insn is used to read |
| 11418 | // WasmStructObject::outlineData_ (the field itself, not what it points |
| 11419 | // at), we allow commoning up to happen. This is OK because |
| 11420 | // WasmStructObject::outlineData_ is readonly for the life of the |
| 11421 | // WasmStructObject. |
| 11422 | if (!ins->isWasmLoadField()) { |
| 11423 | return false; |
| 11424 | } |
| 11425 | const MWasmLoadField* other = ins->toWasmLoadField(); |
| 11426 | return ins->isWasmLoadField() && congruentIfOperandsEqual(ins) && |
| 11427 | offset() == other->offset() && wideningOp() == other->wideningOp() && |
| 11428 | getAliasSet().flags() == other->getAliasSet().flags(); |
| 11429 | } |
| 11430 | |
| 11431 | #ifdef JS_JITSPEW1 |
| 11432 | void getExtras(ExtrasCollector* extras) override { |
| 11433 | char buf[96]; |
| 11434 | SprintfLiteral(buf, "(offs=%lld, wideningOp=%s)", (long long int)offset_, |
| 11435 | StringFromMWideningOp(wideningOp_)); |
| 11436 | extras->add(buf); |
| 11437 | } |
| 11438 | #endif |
| 11439 | }; |
| 11440 | |
| 11441 | // Loads a value from a location, denoted as a fixed offset from a base |
| 11442 | // pointer, which (it is assumed) is within a wasm object. This field may be |
| 11443 | // any value type, including references. No barriers are performed. |
| 11444 | // |
| 11445 | // This instruction takes a pointer to a second object `ka`, which it is |
| 11446 | // necessary to keep alive. It is expected that `ka` holds a reference to |
| 11447 | // `obj`, but this is not enforced and no code is generated to access `ka`. |
| 11448 | // This instruction extends the lifetime of `ka` so that it, and hence `obj`, |
| 11449 | // cannot be collected while `obj` is live. This is necessary if `obj` does |
| 11450 | // not point to a GC-managed object. `offset` must be representable as a |
| 11451 | // 31-bit unsigned integer. |
| 11452 | class MWasmLoadFieldKA : public MBinaryInstruction, public NoTypePolicy::Data { |
| 11453 | uint32_t offset_; |
| 11454 | MWideningOp wideningOp_; |
| 11455 | AliasSet aliases_; |
| 11456 | MaybeTrapSiteInfo maybeTrap_; |
| 11457 | |
| 11458 | MWasmLoadFieldKA(MDefinition* ka, MDefinition* obj, size_t offset, |
| 11459 | MIRType type, MWideningOp wideningOp, AliasSet aliases, |
| 11460 | MaybeTrapSiteInfo maybeTrap = mozilla::Nothing()) |
| 11461 | : MBinaryInstruction(classOpcode, ka, obj), |
| 11462 | offset_(uint32_t(offset)), |
| 11463 | wideningOp_(wideningOp), |
| 11464 | aliases_(aliases), |
| 11465 | maybeTrap_(maybeTrap) { |
| 11466 | MOZ_ASSERT(offset <= INT32_MAX)do { static_assert( mozilla::detail::AssertionConditionType< decltype(offset <= (2147483647))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(offset <= (2147483647)))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("offset <= (2147483647)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "offset <= (2147483647)" ")"); do { *((volatile int*)__null) = 11466; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11467 | MOZ_ASSERT_IF(wideningOp != MWideningOp::None, type == MIRType::Int32)do { if (wideningOp != MWideningOp::None) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(type == MIRType::Int32)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(type == MIRType::Int32))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11467); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int32" ")"); do { *((volatile int*)__null) = 11467; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); } } while (false); |
| 11468 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet ::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11475; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11469 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet ::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11475; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11470 | AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet ::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11475; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11471 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet ::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11475; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11472 | AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet ::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11475; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11473 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet ::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11475; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11474 | AliasSet::Load(AliasSet::WasmArrayDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet ::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11475; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11475 | aliases.flags() == AliasSet::Load(AliasSet::Any).flags())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet ::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases .flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags () || aliases.flags() == AliasSet::Load(AliasSet::Any).flags( )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11475); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11475; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11476 | setResultType(type); |
| 11477 | if (maybeTrap_) { |
| 11478 | setGuard(); |
| 11479 | } |
| 11480 | } |
| 11481 | |
| 11482 | public: |
| 11483 | INSTRUCTION_HEADER(WasmLoadFieldKA) |
| 11484 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11485 | NAMED_OPERANDS((0, ka), (1, obj))MDefinition* ka() const { return getOperand(0); } MDefinition * obj() const { return getOperand(1); } |
| 11486 | |
| 11487 | uint32_t offset() const { return offset_; } |
| 11488 | MWideningOp wideningOp() const { return wideningOp_; } |
| 11489 | AliasSet getAliasSet() const override { return aliases_; } |
| 11490 | MaybeTrapSiteInfo maybeTrap() const { return maybeTrap_; } |
| 11491 | |
| 11492 | #ifdef JS_JITSPEW1 |
| 11493 | void getExtras(ExtrasCollector* extras) override { |
| 11494 | char buf[96]; |
| 11495 | SprintfLiteral(buf, "(offs=%lld, wideningOp=%s)", (long long int)offset_, |
| 11496 | StringFromMWideningOp(wideningOp_)); |
| 11497 | extras->add(buf); |
| 11498 | } |
| 11499 | #endif |
| 11500 | }; |
| 11501 | |
| 11502 | // Loads a value from base pointer, given an index and element size. This field |
| 11503 | // may be any value type, including references. No barriers are performed. |
| 11504 | // |
| 11505 | // The element size is implicitly defined by MIRType and MWideningOp. For |
| 11506 | // example, MIRType::Float32 indicates an element size of 32 bits, and |
| 11507 | // MIRType::Int32 and MWideningOp::FromU16 together indicate an element size of |
| 11508 | // 16 bits. |
| 11509 | // |
| 11510 | // This instruction takes a second object `ka` that must be kept alive, as |
| 11511 | // described for MWasmLoadFieldKA above. |
| 11512 | class MWasmLoadElementKA : public MTernaryInstruction, |
| 11513 | public NoTypePolicy::Data { |
| 11514 | MWideningOp wideningOp_; |
| 11515 | Scale scale_; |
| 11516 | AliasSet aliases_; |
| 11517 | MaybeTrapSiteInfo maybeTrap_; |
| 11518 | |
| 11519 | MWasmLoadElementKA(MDefinition* ka, MDefinition* base, MDefinition* index, |
| 11520 | MIRType type, MWideningOp wideningOp, Scale scale, |
| 11521 | AliasSet aliases, |
| 11522 | MaybeTrapSiteInfo maybeTrap = mozilla::Nothing()) |
| 11523 | : MTernaryInstruction(classOpcode, ka, base, index), |
| 11524 | wideningOp_(wideningOp), |
| 11525 | scale_(scale), |
| 11526 | aliases_(aliases), |
| 11527 | maybeTrap_(maybeTrap) { |
| 11528 | MOZ_ASSERT(base->type() == MIRType::WasmArrayData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::WasmArrayData)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(base->type() == MIRType::WasmArrayData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("base->type() == MIRType::WasmArrayData" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11528); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::WasmArrayData" ")"); do { *((volatile int*)__null) = 11528; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11529 | MOZ_ASSERT(aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmArrayDataArea).flags() || aliases.flags() == AliasSet:: Load(AliasSet::Any).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11531); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11531; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11530 | AliasSet::Load(AliasSet::WasmArrayDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmArrayDataArea).flags() || aliases.flags() == AliasSet:: Load(AliasSet::Any).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11531); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11531; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11531 | aliases.flags() == AliasSet::Load(AliasSet::Any).flags())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any) .flags())>::isValid, "invalid assertion condition"); if (( __builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Load(AliasSet ::WasmArrayDataArea).flags() || aliases.flags() == AliasSet:: Load(AliasSet::Any).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11531); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Load(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Load(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11531; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11532 | setResultType(type); |
| 11533 | if (maybeTrap_) { |
| 11534 | setGuard(); |
| 11535 | } |
| 11536 | } |
| 11537 | |
| 11538 | public: |
| 11539 | INSTRUCTION_HEADER(WasmLoadElementKA) |
| 11540 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11541 | NAMED_OPERANDS((0, ka), (1, base), (2, index))MDefinition* ka() const { return getOperand(0); } MDefinition * base() const { return getOperand(1); } MDefinition* index() const { return getOperand(2); } |
| 11542 | |
| 11543 | MWideningOp wideningOp() const { return wideningOp_; } |
| 11544 | Scale scale() const { return scale_; } |
| 11545 | AliasSet getAliasSet() const override { return aliases_; } |
| 11546 | MaybeTrapSiteInfo maybeTrap() const { return maybeTrap_; } |
| 11547 | |
| 11548 | #ifdef JS_JITSPEW1 |
| 11549 | void getExtras(ExtrasCollector* extras) override { |
| 11550 | char buf[96]; |
| 11551 | SprintfLiteral(buf, "(wideningOp=%s, scale=%s)", |
| 11552 | StringFromMWideningOp(wideningOp_), StringFromScale(scale_)); |
| 11553 | extras->add(buf); |
| 11554 | } |
| 11555 | #endif |
| 11556 | }; |
| 11557 | |
| 11558 | // Stores a non-reference value to anlocation, denoted as a fixed offset from |
| 11559 | // a base pointer, which (it is assumed) is within a wasm object. This field |
| 11560 | // may be any value type, _excluding_ references. References _must_ use the |
| 11561 | // 'Ref' variant of this instruction. The offset must be representable as a |
| 11562 | // 31-bit unsigned integer. |
| 11563 | // |
| 11564 | // This instruction takes a second object `ka` that must be kept alive, as |
| 11565 | // described for MWasmLoadFieldKA above. |
| 11566 | class MWasmStoreFieldKA : public MTernaryInstruction, |
| 11567 | public NoTypePolicy::Data { |
| 11568 | uint32_t offset_; |
| 11569 | MNarrowingOp narrowingOp_; |
| 11570 | AliasSet aliases_; |
| 11571 | MaybeTrapSiteInfo maybeTrap_; |
| 11572 | |
| 11573 | MWasmStoreFieldKA(MDefinition* ka, MDefinition* obj, size_t offset, |
| 11574 | MDefinition* value, MNarrowingOp narrowingOp, |
| 11575 | AliasSet aliases, |
| 11576 | MaybeTrapSiteInfo maybeTrap = mozilla::Nothing()) |
| 11577 | : MTernaryInstruction(classOpcode, ka, obj, value), |
| 11578 | offset_(uint32_t(offset)), |
| 11579 | narrowingOp_(narrowingOp), |
| 11580 | aliases_(aliases), |
| 11581 | maybeTrap_(maybeTrap) { |
| 11582 | MOZ_ASSERT(offset <= INT32_MAX)do { static_assert( mozilla::detail::AssertionConditionType< decltype(offset <= (2147483647))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(offset <= (2147483647)))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("offset <= (2147483647)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11582); AnnotateMozCrashReason("MOZ_ASSERT" "(" "offset <= (2147483647)" ")"); do { *((volatile int*)__null) = 11582; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11583 | MOZ_ASSERT(value->type() != MIRType::WasmAnyRef)do { static_assert( mozilla::detail::AssertionConditionType< decltype(value->type() != MIRType::WasmAnyRef)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(value->type() != MIRType::WasmAnyRef))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("value->type() != MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11583); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() != MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 11583; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11584 | // "if you want to narrow the value when it is stored, the source type |
| 11585 | // must be Int32". |
| 11586 | MOZ_ASSERT_IF(narrowingOp != MNarrowingOp::None,do { if (narrowingOp != MNarrowingOp::None) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(value-> type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(value->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("value->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11587); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 11587; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); } } while (false) |
| 11587 | value->type() == MIRType::Int32)do { if (narrowingOp != MNarrowingOp::None) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(value-> type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(value->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("value->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11587); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 11587; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); } } while (false); |
| 11588 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11595; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11589 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11595; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11590 | AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11595; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11591 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11595; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11592 | AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11595; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11593 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11595; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11594 | AliasSet::Store(AliasSet::WasmArrayDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11595; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11595 | aliases.flags() == AliasSet::Store(AliasSet::Any).flags())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11595); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11595; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11596 | if (maybeTrap_) { |
| 11597 | setGuard(); |
| 11598 | } |
| 11599 | } |
| 11600 | |
| 11601 | public: |
| 11602 | INSTRUCTION_HEADER(WasmStoreFieldKA) |
| 11603 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11604 | NAMED_OPERANDS((0, ka), (1, obj), (2, value))MDefinition* ka() const { return getOperand(0); } MDefinition * obj() const { return getOperand(1); } MDefinition* value() const { return getOperand(2); } |
| 11605 | |
| 11606 | uint32_t offset() const { return offset_; } |
| 11607 | MNarrowingOp narrowingOp() const { return narrowingOp_; } |
| 11608 | AliasSet getAliasSet() const override { return aliases_; } |
| 11609 | MaybeTrapSiteInfo maybeTrap() const { return maybeTrap_; } |
| 11610 | |
| 11611 | #ifdef JS_JITSPEW1 |
| 11612 | void getExtras(ExtrasCollector* extras) override { |
| 11613 | char buf[96]; |
| 11614 | SprintfLiteral(buf, "(offs=%lld, narrowingOp=%s)", (long long int)offset_, |
| 11615 | StringFromMNarrowingOp(narrowingOp_)); |
| 11616 | extras->add(buf); |
| 11617 | } |
| 11618 | #endif |
| 11619 | }; |
| 11620 | |
| 11621 | // Stores a reference value to a location, denoted as a fixed offset from a |
| 11622 | // base pointer, which (it is assumed) is within a wasm object. This |
| 11623 | // instruction emits a pre-barrier. A post barrier _must_ be performed |
| 11624 | // separately. The offset must be representable as a 31-bit unsigned integer. |
| 11625 | // |
| 11626 | // This instruction takes a second object `ka` that must be kept alive, as |
| 11627 | // described for MWasmLoadFieldKA above. |
| 11628 | class MWasmStoreFieldRefKA : public MAryInstruction<4>, |
| 11629 | public NoTypePolicy::Data { |
| 11630 | uint32_t offset_; |
| 11631 | AliasSet aliases_; |
| 11632 | MaybeTrapSiteInfo maybeTrap_; |
| 11633 | WasmPreBarrierKind preBarrierKind_; |
| 11634 | |
| 11635 | MWasmStoreFieldRefKA(MDefinition* instance, MDefinition* ka, MDefinition* obj, |
| 11636 | size_t offset, MDefinition* value, AliasSet aliases, |
| 11637 | MaybeTrapSiteInfo maybeTrap, |
| 11638 | WasmPreBarrierKind preBarrierKind) |
| 11639 | : MAryInstruction<4>(classOpcode), |
| 11640 | offset_(uint32_t(offset)), |
| 11641 | aliases_(aliases), |
| 11642 | maybeTrap_(maybeTrap), |
| 11643 | preBarrierKind_(preBarrierKind) { |
| 11644 | MOZ_ASSERT(obj->type() == TargetWordMIRType() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(obj->type() == TargetWordMIRType() || obj->type () == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(obj->type() == TargetWordMIRType () || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "obj->type() == TargetWordMIRType() || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "obj->type() == TargetWordMIRType() || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData" ")"); do { *((volatile int*)__null) = 11647; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11645 | obj->type() == MIRType::Pointer ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(obj->type() == TargetWordMIRType() || obj->type () == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(obj->type() == TargetWordMIRType () || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "obj->type() == TargetWordMIRType() || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "obj->type() == TargetWordMIRType() || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData" ")"); do { *((volatile int*)__null) = 11647; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11646 | obj->type() == MIRType::WasmAnyRef ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(obj->type() == TargetWordMIRType() || obj->type () == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(obj->type() == TargetWordMIRType () || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "obj->type() == TargetWordMIRType() || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "obj->type() == TargetWordMIRType() || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData" ")"); do { *((volatile int*)__null) = 11647; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11647 | obj->type() == MIRType::WasmArrayData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(obj->type() == TargetWordMIRType() || obj->type () == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(obj->type() == TargetWordMIRType () || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "obj->type() == TargetWordMIRType() || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "obj->type() == TargetWordMIRType() || obj->type() == MIRType::Pointer || obj->type() == MIRType::WasmAnyRef || obj->type() == MIRType::WasmArrayData" ")"); do { *((volatile int*)__null) = 11647; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11648 | MOZ_ASSERT(offset <= INT32_MAX)do { static_assert( mozilla::detail::AssertionConditionType< decltype(offset <= (2147483647))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(offset <= (2147483647)))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("offset <= (2147483647)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11648); AnnotateMozCrashReason("MOZ_ASSERT" "(" "offset <= (2147483647)" ")"); do { *((volatile int*)__null) = 11648; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11649 | MOZ_ASSERT(value->type() == MIRType::WasmAnyRef)do { static_assert( mozilla::detail::AssertionConditionType< decltype(value->type() == MIRType::WasmAnyRef)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(value->type() == MIRType::WasmAnyRef))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("value->type() == MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() == MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 11649; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11650 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11657; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11651 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11657; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11652 | AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11657; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11653 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11657; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11654 | AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11657; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11655 | aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11657; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11656 | AliasSet::Store(AliasSet::WasmArrayDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11657; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11657 | aliases.flags() == AliasSet::Store(AliasSet::Any).flags())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmStructInlineDataArea).flags() || aliases.flags( ) == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags () || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmStructInlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmStructOutlineDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11657; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11658 | initOperand(0, instance); |
| 11659 | initOperand(1, ka); |
| 11660 | initOperand(2, obj); |
| 11661 | initOperand(3, value); |
| 11662 | if (maybeTrap_) { |
| 11663 | setGuard(); |
| 11664 | } |
| 11665 | } |
| 11666 | |
| 11667 | public: |
| 11668 | INSTRUCTION_HEADER(WasmStoreFieldRefKA) |
| 11669 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11670 | NAMED_OPERANDS((0, instance), (1, ka), (2, obj), (3, value))MDefinition* instance() const { return getOperand(0); } MDefinition * ka() const { return getOperand(1); } MDefinition* obj() const { return getOperand(2); } MDefinition* value() const { return getOperand(3); } |
| 11671 | |
| 11672 | uint32_t offset() const { return offset_; } |
| 11673 | AliasSet getAliasSet() const override { return aliases_; } |
| 11674 | MaybeTrapSiteInfo maybeTrap() const { return maybeTrap_; } |
| 11675 | WasmPreBarrierKind preBarrierKind() const { return preBarrierKind_; } |
| 11676 | |
| 11677 | #ifdef JS_JITSPEW1 |
| 11678 | void getExtras(ExtrasCollector* extras) override { |
| 11679 | char buf[64]; |
| 11680 | SprintfLiteral(buf, "(offs=%lld)", (long long int)offset_); |
| 11681 | extras->add(buf); |
| 11682 | } |
| 11683 | #endif |
| 11684 | }; |
| 11685 | |
| 11686 | // Stores a non-reference value to a base pointer, given an index and element |
| 11687 | // size. This field may be any value type, excluding references. References MUST |
| 11688 | // use the 'Ref' variant of this instruction. |
| 11689 | // |
| 11690 | // The element size is implicitly defined by MIRType and MNarrowingOp. For |
| 11691 | // example, MIRType::Float32 indicates an element size of 32 bits, and |
| 11692 | // MIRType::Int32 and MNarrowingOp::To16 together indicate an element size of 16 |
| 11693 | // bits. |
| 11694 | // |
| 11695 | // This instruction takes a second object `ka` that must be kept alive, as |
| 11696 | // described for MWasmLoadFieldKA above. |
| 11697 | class MWasmStoreElementKA : public MQuaternaryInstruction, |
| 11698 | public NoTypePolicy::Data { |
| 11699 | MNarrowingOp narrowingOp_; |
| 11700 | Scale scale_; |
| 11701 | AliasSet aliases_; |
| 11702 | MaybeTrapSiteInfo maybeTrap_; |
| 11703 | |
| 11704 | MWasmStoreElementKA(MDefinition* ka, MDefinition* base, MDefinition* index, |
| 11705 | MDefinition* value, MNarrowingOp narrowingOp, Scale scale, |
| 11706 | AliasSet aliases, |
| 11707 | MaybeTrapSiteInfo maybeTrap = mozilla::Nothing()) |
| 11708 | : MQuaternaryInstruction(classOpcode, ka, base, index, value), |
| 11709 | narrowingOp_(narrowingOp), |
| 11710 | scale_(scale), |
| 11711 | aliases_(aliases), |
| 11712 | maybeTrap_(maybeTrap) { |
| 11713 | MOZ_ASSERT(base->type() == MIRType::WasmArrayData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::WasmArrayData)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(base->type() == MIRType::WasmArrayData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("base->type() == MIRType::WasmArrayData" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::WasmArrayData" ")"); do { *((volatile int*)__null) = 11713; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11714 | MOZ_ASSERT(value->type() != MIRType::WasmAnyRef)do { static_assert( mozilla::detail::AssertionConditionType< decltype(value->type() != MIRType::WasmAnyRef)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(value->type() != MIRType::WasmAnyRef))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("value->type() != MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() != MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 11714; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11715 | // "if you want to narrow the value when it is stored, the source type |
| 11716 | // must be Int32". |
| 11717 | MOZ_ASSERT_IF(narrowingOp != MNarrowingOp::None,do { if (narrowingOp != MNarrowingOp::None) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(value-> type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(value->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("value->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11718); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 11718; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); } } while (false) |
| 11718 | value->type() == MIRType::Int32)do { if (narrowingOp != MNarrowingOp::None) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(value-> type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(value->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("value->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11718); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 11718; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); } } while (false); |
| 11719 | MOZ_ASSERT(aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet ::Store(AliasSet::Any).flags()))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11721; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11720 | AliasSet::Store(AliasSet::WasmArrayDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet ::Store(AliasSet::Any).flags()))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11721; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11721 | aliases.flags() == AliasSet::Store(AliasSet::Any).flags())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet ::Store(AliasSet::Any).flags()))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11721; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11722 | if (maybeTrap_) { |
| 11723 | setGuard(); |
| 11724 | } |
| 11725 | } |
| 11726 | |
| 11727 | public: |
| 11728 | INSTRUCTION_HEADER(WasmStoreElementKA) |
| 11729 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11730 | NAMED_OPERANDS((0, ka), (1, base), (2, index), (3, value))MDefinition* ka() const { return getOperand(0); } MDefinition * base() const { return getOperand(1); } MDefinition* index() const { return getOperand(2); } MDefinition* value() const { return getOperand(3); } |
| 11731 | |
| 11732 | MNarrowingOp narrowingOp() const { return narrowingOp_; } |
| 11733 | Scale scale() const { return scale_; } |
| 11734 | AliasSet getAliasSet() const override { return aliases_; } |
| 11735 | MaybeTrapSiteInfo maybeTrap() const { return maybeTrap_; } |
| 11736 | |
| 11737 | #ifdef JS_JITSPEW1 |
| 11738 | void getExtras(ExtrasCollector* extras) override { |
| 11739 | char buf[96]; |
| 11740 | SprintfLiteral(buf, "(narrowingOp=%s, scale=%s)", |
| 11741 | StringFromMNarrowingOp(narrowingOp_), |
| 11742 | StringFromScale(scale_)); |
| 11743 | extras->add(buf); |
| 11744 | } |
| 11745 | #endif |
| 11746 | }; |
| 11747 | |
| 11748 | // Stores a reference value to a base pointer, given an index and element size. |
| 11749 | // This instruction emits a pre-barrier. A post barrier MUST be performed |
| 11750 | // separately. |
| 11751 | // |
| 11752 | // The element size is implicitly defined by MIRType and MNarrowingOp, as |
| 11753 | // described for MWasmStoreElementKA above. |
| 11754 | // |
| 11755 | // This instruction takes a second object `ka` that must be kept alive, as |
| 11756 | // described for MWasmLoadFieldKA above. |
| 11757 | class MWasmStoreElementRefKA : public MAryInstruction<5>, |
| 11758 | public NoTypePolicy::Data { |
| 11759 | AliasSet aliases_; |
| 11760 | MaybeTrapSiteInfo maybeTrap_; |
| 11761 | WasmPreBarrierKind preBarrierKind_; |
| 11762 | |
| 11763 | MWasmStoreElementRefKA(MDefinition* instance, MDefinition* ka, |
| 11764 | MDefinition* base, MDefinition* index, |
| 11765 | MDefinition* value, AliasSet aliases, |
| 11766 | MaybeTrapSiteInfo maybeTrap, |
| 11767 | WasmPreBarrierKind preBarrierKind) |
| 11768 | : MAryInstruction<5>(classOpcode), |
| 11769 | aliases_(aliases), |
| 11770 | maybeTrap_(maybeTrap), |
| 11771 | preBarrierKind_(preBarrierKind) { |
| 11772 | MOZ_ASSERT(base->type() == MIRType::WasmArrayData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::WasmArrayData)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(base->type() == MIRType::WasmArrayData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("base->type() == MIRType::WasmArrayData" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11772); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::WasmArrayData" ")"); do { *((volatile int*)__null) = 11772; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11773 | MOZ_ASSERT(value->type() == MIRType::WasmAnyRef)do { static_assert( mozilla::detail::AssertionConditionType< decltype(value->type() == MIRType::WasmAnyRef)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(value->type() == MIRType::WasmAnyRef))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("value->type() == MIRType::WasmAnyRef" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11773); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() == MIRType::WasmAnyRef" ")"); do { *((volatile int*)__null) = 11773; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11774 | MOZ_ASSERT(aliases.flags() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet ::Store(AliasSet::Any).flags()))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11776); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11776; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11775 | AliasSet::Store(AliasSet::WasmArrayDataArea).flags() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet ::Store(AliasSet::Any).flags()))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11776); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11776; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false) |
| 11776 | aliases.flags() == AliasSet::Store(AliasSet::Any).flags())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea ).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any ).flags())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(aliases.flags() == AliasSet::Store( AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet ::Store(AliasSet::Any).flags()))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11776); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aliases.flags() == AliasSet::Store(AliasSet::WasmArrayDataArea).flags() || aliases.flags() == AliasSet::Store(AliasSet::Any).flags()" ")"); do { *((volatile int*)__null) = 11776; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11777 | initOperand(0, instance); |
| 11778 | initOperand(1, ka); |
| 11779 | initOperand(2, base); |
| 11780 | initOperand(3, index); |
| 11781 | initOperand(4, value); |
| 11782 | if (maybeTrap_) { |
| 11783 | setGuard(); |
| 11784 | } |
| 11785 | } |
| 11786 | |
| 11787 | public: |
| 11788 | INSTRUCTION_HEADER(WasmStoreElementRefKA) |
| 11789 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11790 | NAMED_OPERANDS((0, instance), (1, ka), (2, base), (3, index), (4, value))MDefinition* instance() const { return getOperand(0); } MDefinition * ka() const { return getOperand(1); } MDefinition* base() const { return getOperand(2); } MDefinition* index() const { return getOperand(3); } MDefinition* value() const { return getOperand (4); } |
| 11791 | |
| 11792 | AliasSet getAliasSet() const override { return aliases_; } |
| 11793 | MaybeTrapSiteInfo maybeTrap() const { return maybeTrap_; } |
| 11794 | WasmPreBarrierKind preBarrierKind() const { return preBarrierKind_; } |
| 11795 | }; |
| 11796 | |
| 11797 | class MWasmRefIsSubtypeOfAbstract : public MUnaryInstruction, |
| 11798 | public NoTypePolicy::Data { |
| 11799 | wasm::RefType sourceType_; |
| 11800 | wasm::RefType destType_; |
| 11801 | |
| 11802 | MWasmRefIsSubtypeOfAbstract(MDefinition* ref, wasm::RefType sourceType, |
| 11803 | wasm::RefType destType) |
| 11804 | : MUnaryInstruction(classOpcode, ref), |
| 11805 | sourceType_(sourceType), |
| 11806 | destType_(destType) { |
| 11807 | MOZ_ASSERT(!destType.isTypeRef())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!destType.isTypeRef())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!destType.isTypeRef()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("!destType.isTypeRef()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11807); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!destType.isTypeRef()" ")"); do { *((volatile int*)__null) = 11807; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11808 | setResultType(MIRType::Int32); |
| 11809 | setMovable(); |
| 11810 | } |
| 11811 | |
| 11812 | public: |
| 11813 | INSTRUCTION_HEADER(WasmRefIsSubtypeOfAbstract) |
| 11814 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11815 | NAMED_OPERANDS((0, ref))MDefinition* ref() const { return getOperand(0); } |
| 11816 | |
| 11817 | wasm::RefType sourceType() const { return sourceType_; }; |
| 11818 | wasm::RefType destType() const { return destType_; }; |
| 11819 | |
| 11820 | bool congruentTo(const MDefinition* ins) const override { |
| 11821 | return congruentIfOperandsEqual(ins) && |
| 11822 | sourceType() == ins->toWasmRefIsSubtypeOfAbstract()->sourceType() && |
| 11823 | destType() == ins->toWasmRefIsSubtypeOfAbstract()->destType(); |
| 11824 | } |
| 11825 | |
| 11826 | HashNumber valueHash() const override { |
| 11827 | HashNumber hn = MUnaryInstruction::valueHash(); |
| 11828 | hn = addU64ToHash(hn, sourceType().packed().bits()); |
| 11829 | hn = addU64ToHash(hn, destType().packed().bits()); |
| 11830 | return hn; |
| 11831 | } |
| 11832 | |
| 11833 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 11834 | }; |
| 11835 | |
| 11836 | // Tests if the wasm ref `ref` is a subtype of `superSTV`. |
| 11837 | // The actual super type definition must be known at compile time, so that the |
| 11838 | // subtyping depth of super type depth can be used. |
| 11839 | class MWasmRefIsSubtypeOfConcrete : public MBinaryInstruction, |
| 11840 | public NoTypePolicy::Data { |
| 11841 | wasm::RefType sourceType_; |
| 11842 | wasm::RefType destType_; |
| 11843 | |
| 11844 | MWasmRefIsSubtypeOfConcrete(MDefinition* ref, MDefinition* superSTV, |
| 11845 | wasm::RefType sourceType, wasm::RefType destType) |
| 11846 | : MBinaryInstruction(classOpcode, ref, superSTV), |
| 11847 | sourceType_(sourceType), |
| 11848 | destType_(destType) { |
| 11849 | MOZ_ASSERT(destType.isTypeRef())do { static_assert( mozilla::detail::AssertionConditionType< decltype(destType.isTypeRef())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(destType.isTypeRef()))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("destType.isTypeRef()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "destType.isTypeRef()" ")"); do { *((volatile int*)__null) = 11849; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11850 | setResultType(MIRType::Int32); |
| 11851 | setMovable(); |
| 11852 | } |
| 11853 | |
| 11854 | public: |
| 11855 | INSTRUCTION_HEADER(WasmRefIsSubtypeOfConcrete) |
| 11856 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11857 | NAMED_OPERANDS((0, ref), (1, superSTV))MDefinition* ref() const { return getOperand(0); } MDefinition * superSTV() const { return getOperand(1); } |
| 11858 | |
| 11859 | wasm::RefType sourceType() const { return sourceType_; }; |
| 11860 | wasm::RefType destType() const { return destType_; }; |
| 11861 | |
| 11862 | bool congruentTo(const MDefinition* ins) const override { |
| 11863 | return congruentIfOperandsEqual(ins) && |
| 11864 | sourceType() == ins->toWasmRefIsSubtypeOfConcrete()->sourceType() && |
| 11865 | destType() == ins->toWasmRefIsSubtypeOfConcrete()->destType(); |
| 11866 | } |
| 11867 | |
| 11868 | HashNumber valueHash() const override { |
| 11869 | HashNumber hn = MBinaryInstruction::valueHash(); |
| 11870 | hn = addU64ToHash(hn, sourceType().packed().bits()); |
| 11871 | hn = addU64ToHash(hn, destType().packed().bits()); |
| 11872 | return hn; |
| 11873 | } |
| 11874 | |
| 11875 | MDefinition* foldsTo(TempAllocator& alloc) override; |
| 11876 | }; |
| 11877 | |
| 11878 | class MWasmNewStructObject : public MBinaryInstruction, |
| 11879 | public NoTypePolicy::Data { |
| 11880 | private: |
| 11881 | bool isOutline_; |
| 11882 | bool zeroFields_; |
| 11883 | gc::AllocKind allocKind_; |
| 11884 | |
| 11885 | MWasmNewStructObject(MDefinition* instance, MDefinition* typeDefData, |
| 11886 | bool isOutline, bool zeroFields, gc::AllocKind allocKind) |
| 11887 | : MBinaryInstruction(classOpcode, instance, typeDefData), |
| 11888 | isOutline_(isOutline), |
| 11889 | zeroFields_(zeroFields), |
| 11890 | allocKind_(allocKind) { |
| 11891 | setResultType(MIRType::WasmAnyRef); |
| 11892 | } |
| 11893 | |
| 11894 | public: |
| 11895 | INSTRUCTION_HEADER(WasmNewStructObject) |
| 11896 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11897 | NAMED_OPERANDS((0, instance), (1, typeDefData))MDefinition* instance() const { return getOperand(0); } MDefinition * typeDefData() const { return getOperand(1); } |
| 11898 | |
| 11899 | AliasSet getAliasSet() const override { |
| 11900 | if (js::SupportDifferentialTesting()) { |
| 11901 | // Consider allocations effectful for differential testing. |
| 11902 | return MDefinition::getAliasSet(); |
| 11903 | } |
| 11904 | return AliasSet::None(); |
| 11905 | } |
| 11906 | bool isOutline() const { return isOutline_; } |
| 11907 | bool zeroFields() const { return zeroFields_; } |
| 11908 | gc::AllocKind allocKind() const { return allocKind_; } |
| 11909 | }; |
| 11910 | |
| 11911 | class MWasmNewArrayObject : public MTernaryInstruction, |
| 11912 | public NoTypePolicy::Data { |
| 11913 | private: |
| 11914 | uint32_t elemSize_; |
| 11915 | bool zeroFields_; |
| 11916 | wasm::BytecodeOffset bytecodeOffset_; |
| 11917 | |
| 11918 | MWasmNewArrayObject(MDefinition* instance, MDefinition* numElements, |
| 11919 | MDefinition* typeDefData, uint32_t elemSize, |
| 11920 | bool zeroFields, wasm::BytecodeOffset bytecodeOffset) |
| 11921 | : MTernaryInstruction(classOpcode, instance, numElements, typeDefData), |
| 11922 | elemSize_(elemSize), |
| 11923 | zeroFields_(zeroFields), |
| 11924 | bytecodeOffset_(bytecodeOffset) { |
| 11925 | setResultType(MIRType::WasmAnyRef); |
| 11926 | } |
| 11927 | |
| 11928 | public: |
| 11929 | INSTRUCTION_HEADER(WasmNewArrayObject) |
| 11930 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11931 | NAMED_OPERANDS((0, instance), (1, numElements), (2, typeDefData))MDefinition* instance() const { return getOperand(0); } MDefinition * numElements() const { return getOperand(1); } MDefinition* typeDefData () const { return getOperand(2); } |
| 11932 | |
| 11933 | AliasSet getAliasSet() const override { |
| 11934 | if (js::SupportDifferentialTesting()) { |
| 11935 | // Consider allocations effectful for differential testing. |
| 11936 | return MDefinition::getAliasSet(); |
| 11937 | } |
| 11938 | return AliasSet::None(); |
| 11939 | } |
| 11940 | uint32_t elemSize() const { return elemSize_; } |
| 11941 | bool zeroFields() const { return zeroFields_; } |
| 11942 | wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; } |
| 11943 | }; |
| 11944 | |
| 11945 | #ifdef FUZZING_JS_FUZZILLI |
| 11946 | class MFuzzilliHash : public MUnaryInstruction, public NoTypePolicy::Data { |
| 11947 | explicit MFuzzilliHash(MDefinition* obj) |
| 11948 | : MUnaryInstruction(classOpcode, obj) { |
| 11949 | setResultType(MIRType::Int32); |
| 11950 | setMovable(); |
| 11951 | } |
| 11952 | |
| 11953 | public: |
| 11954 | INSTRUCTION_HEADER(FuzzilliHash); |
| 11955 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11956 | ALLOW_CLONE(MFuzzilliHash)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MFuzzilliHash (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 11957 | |
| 11958 | # ifdef DEBUG1 |
| 11959 | bool isConsistentFloat32Use(MUse* use) const override { return true; } |
| 11960 | # endif |
| 11961 | |
| 11962 | AliasSet getAliasSet() const override { |
| 11963 | MDefinition* obj = getOperand(0); |
| 11964 | if (obj->type() == MIRType::Object || obj->type() == MIRType::Value) { |
| 11965 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
| 11966 | AliasSet::DynamicSlot | AliasSet::Element | |
| 11967 | AliasSet::UnboxedElement); |
| 11968 | } |
| 11969 | return AliasSet::None(); |
| 11970 | } |
| 11971 | }; |
| 11972 | |
| 11973 | class MFuzzilliHashStore : public MUnaryInstruction, public NoTypePolicy::Data { |
| 11974 | explicit MFuzzilliHashStore(MDefinition* obj) |
| 11975 | : MUnaryInstruction(classOpcode, obj) { |
| 11976 | MOZ_ASSERT(obj->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(obj->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(obj->type() == MIRType::Int32 ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "obj->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11976); AnnotateMozCrashReason("MOZ_ASSERT" "(" "obj->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 11976; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 11977 | |
| 11978 | setResultType(MIRType::None); |
| 11979 | } |
| 11980 | |
| 11981 | public: |
| 11982 | INSTRUCTION_HEADER(FuzzilliHashStore); |
| 11983 | TRIVIAL_NEW_WRAPPERStemplate <typename... Args> static MThisOpcode* New(TempAllocator & alloc, Args&&... args) { return new (alloc) MThisOpcode (std::forward<Args>(args)...); } template <typename... Args> static MThisOpcode* New(TempAllocator::Fallible alloc , Args&&... args) { return new (alloc) MThisOpcode(std ::forward<Args>(args)...); } |
| 11984 | ALLOW_CLONE(MFuzzilliHashStore)bool canClone() const override { return true; } MInstruction* clone(TempAllocator& alloc, const MDefinitionVector& inputs) const override { MInstruction* res = new (alloc) MFuzzilliHashStore (*this); for (size_t i = 0; i < numOperands(); i++) res-> replaceOperand(i, inputs[i]); return res; } |
| 11985 | |
| 11986 | // this is a store and hence effectful, however no other load can |
| 11987 | // alias with the store |
| 11988 | AliasSet getAliasSet() const override { |
| 11989 | return AliasSet::Store(AliasSet::FuzzilliHash); |
| 11990 | } |
| 11991 | }; |
| 11992 | #endif |
| 11993 | |
| 11994 | #undef INSTRUCTION_HEADER |
| 11995 | |
| 11996 | void MUse::init(MDefinition* producer, MNode* consumer) { |
| 11997 | MOZ_ASSERT(!consumer_, "Initializing MUse that already has a consumer")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!consumer_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!consumer_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!consumer_" " (" "Initializing MUse that already has a consumer" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11997); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!consumer_" ") (" "Initializing MUse that already has a consumer" ")"); do { *((volatile int*)__null) = 11997; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 11998 | MOZ_ASSERT(!producer_, "Initializing MUse that already has a producer")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!producer_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!producer_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!producer_" " (" "Initializing MUse that already has a producer" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 11998); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!producer_" ") (" "Initializing MUse that already has a producer" ")"); do { *((volatile int*)__null) = 11998; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 11999 | initUnchecked(producer, consumer); |
| 12000 | } |
| 12001 | |
| 12002 | void MUse::initUnchecked(MDefinition* producer, MNode* consumer) { |
| 12003 | MOZ_ASSERT(consumer, "Initializing to null consumer")do { static_assert( mozilla::detail::AssertionConditionType< decltype(consumer)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(consumer))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("consumer" " (" "Initializing to null consumer" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 12003); AnnotateMozCrashReason("MOZ_ASSERT" "(" "consumer" ") (" "Initializing to null consumer" ")"); do { *((volatile int*) __null) = 12003; __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 12004 | consumer_ = consumer; |
| 12005 | producer_ = producer; |
| 12006 | producer_->addUseUnchecked(this); |
| 12007 | } |
| 12008 | |
| 12009 | void MUse::initUncheckedWithoutProducer(MNode* consumer) { |
| 12010 | MOZ_ASSERT(consumer, "Initializing to null consumer")do { static_assert( mozilla::detail::AssertionConditionType< decltype(consumer)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(consumer))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("consumer" " (" "Initializing to null consumer" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 12010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "consumer" ") (" "Initializing to null consumer" ")"); do { *((volatile int*) __null) = 12010; __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 12011 | consumer_ = consumer; |
| 12012 | producer_ = nullptr; |
| 12013 | } |
| 12014 | |
| 12015 | void MUse::replaceProducer(MDefinition* producer) { |
| 12016 | MOZ_ASSERT(consumer_, "Resetting MUse without a consumer")do { static_assert( mozilla::detail::AssertionConditionType< decltype(consumer_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(consumer_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("consumer_" " (" "Resetting MUse without a consumer" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 12016); AnnotateMozCrashReason("MOZ_ASSERT" "(" "consumer_" ") (" "Resetting MUse without a consumer" ")"); do { *((volatile int*)__null) = 12016; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 12017 | producer_->removeUse(this); |
| 12018 | producer_ = producer; |
| 12019 | producer_->addUse(this); |
| 12020 | } |
| 12021 | |
| 12022 | void MUse::releaseProducer() { |
| 12023 | MOZ_ASSERT(consumer_, "Clearing MUse without a consumer")do { static_assert( mozilla::detail::AssertionConditionType< decltype(consumer_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(consumer_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("consumer_" " (" "Clearing MUse without a consumer" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 12023); AnnotateMozCrashReason("MOZ_ASSERT" "(" "consumer_" ") (" "Clearing MUse without a consumer" ")"); do { *((volatile int*)__null) = 12023; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 12024 | producer_->removeUse(this); |
| 12025 | producer_ = nullptr; |
| 12026 | } |
| 12027 | |
| 12028 | // Implement cast functions now that the compiler can see the inheritance. |
| 12029 | |
| 12030 | MDefinition* MNode::toDefinition() { |
| 12031 | MOZ_ASSERT(isDefinition())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isDefinition())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isDefinition()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isDefinition()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 12031); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isDefinition()" ")"); do { *((volatile int*)__null) = 12031; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 12032 | return (MDefinition*)this; |
| 12033 | } |
| 12034 | |
| 12035 | MResumePoint* MNode::toResumePoint() { |
| 12036 | MOZ_ASSERT(isResumePoint())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isResumePoint())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isResumePoint()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isResumePoint()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 12036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isResumePoint()" ")"); do { *((volatile int*)__null) = 12036; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 12037 | return (MResumePoint*)this; |
| 12038 | } |
| 12039 | |
| 12040 | MInstruction* MDefinition::toInstruction() { |
| 12041 | MOZ_ASSERT(!isPhi())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!isPhi())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!isPhi()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!isPhi()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 12041); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isPhi()" ")" ); do { *((volatile int*)__null) = 12041; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 12042 | return (MInstruction*)this; |
| 12043 | } |
| 12044 | |
| 12045 | const MInstruction* MDefinition::toInstruction() const { |
| 12046 | MOZ_ASSERT(!isPhi())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!isPhi())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!isPhi()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!isPhi()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 12046); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isPhi()" ")" ); do { *((volatile int*)__null) = 12046; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 12047 | return (const MInstruction*)this; |
| 12048 | } |
| 12049 | |
| 12050 | MControlInstruction* MDefinition::toControlInstruction() { |
| 12051 | MOZ_ASSERT(isControlInstruction())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isControlInstruction())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isControlInstruction()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("isControlInstruction()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.h" , 12051); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isControlInstruction()" ")"); do { *((volatile int*)__null) = 12051; __attribute__(( nomerge)) ::abort(); } while (false); } } while (false); |
| 12052 | return (MControlInstruction*)this; |
| 12053 | } |
| 12054 | |
| 12055 | MConstant* MDefinition::maybeConstantValue() { |
| 12056 | MDefinition* op = this; |
| 12057 | if (op->isBox()) { |
| 12058 | op = op->toBox()->input(); |
| 12059 | } |
| 12060 | if (op->isConstant()) { |
| 12061 | return op->toConstant(); |
| 12062 | } |
| 12063 | return nullptr; |
| 12064 | } |
| 12065 | |
| 12066 | #ifdef ENABLE_WASM_SIMD1 |
| 12067 | MWasmShuffleSimd128* BuildWasmShuffleSimd128(TempAllocator& alloc, |
| 12068 | const int8_t* control, |
| 12069 | MDefinition* lhs, |
| 12070 | MDefinition* rhs); |
| 12071 | #endif // ENABLE_WASM_SIMD |
| 12072 | |
| 12073 | } // namespace jit |
| 12074 | } // namespace js |
| 12075 | |
| 12076 | #endif /* jit_MIR_h */ |