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 */ |