File: | var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp |
Warning: | line 1486, column 15 Value stored to 'name' 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 | #include "jit/MIR.h" |
8 | |
9 | #include "mozilla/EndianUtils.h" |
10 | #include "mozilla/FloatingPoint.h" |
11 | #include "mozilla/MathAlgorithms.h" |
12 | #include "mozilla/Maybe.h" |
13 | #include "mozilla/ScopeExit.h" |
14 | |
15 | #include <array> |
16 | #include <utility> |
17 | |
18 | #include "jslibmath.h" |
19 | #include "jsmath.h" |
20 | #include "jsnum.h" |
21 | |
22 | #include "builtin/RegExp.h" |
23 | #include "jit/AtomicOperations.h" |
24 | #include "jit/CompileInfo.h" |
25 | #include "jit/KnownClass.h" |
26 | #include "jit/MIR-wasm.h" |
27 | #include "jit/MIRGraph.h" |
28 | #include "jit/RangeAnalysis.h" |
29 | #include "jit/VMFunctions.h" |
30 | #include "jit/WarpBuilderShared.h" |
31 | #include "js/Conversions.h" |
32 | #include "js/experimental/JitInfo.h" // JSJitInfo, JSTypedMethodJitInfo |
33 | #include "js/ScalarType.h" // js::Scalar::Type |
34 | #include "util/Text.h" |
35 | #include "util/Unicode.h" |
36 | #include "vm/BigIntType.h" |
37 | #include "vm/Float16.h" |
38 | #include "vm/Iteration.h" // js::NativeIterator |
39 | #include "vm/PlainObject.h" // js::PlainObject |
40 | #include "vm/Uint8Clamped.h" |
41 | |
42 | #include "vm/BytecodeUtil-inl.h" |
43 | #include "vm/JSAtomUtils-inl.h" // TypeName |
44 | |
45 | using namespace js; |
46 | using namespace js::jit; |
47 | |
48 | using JS::ToInt32; |
49 | |
50 | using mozilla::IsFloat32Representable; |
51 | using mozilla::IsPowerOfTwo; |
52 | using mozilla::NumbersAreIdentical; |
53 | |
54 | NON_GC_POINTER_TYPE_ASSERTIONS_GENERATEDstatic_assert(!std::is_base_of_v<gc::Cell, BuiltinObjectKind >, "Ensure that BuiltinObjectKind is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, FunctionFlags >, "Ensure that FunctionFlags is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, FunctionFlags ::FunctionKind>, "Ensure that FunctionFlags::FunctionKind is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, MemoryBarrierRequirement >, "Ensure that MemoryBarrierRequirement is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, PropertyKey> , "Ensure that PropertyKey is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, RealmFuses::FuseIndex >, "Ensure that RealmFuses::FuseIndex is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, SimdShuffle> , "Ensure that SimdShuffle is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, bool>, "Ensure that bool is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, const void> , "Ensure that const void is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, gc::Heap>, "Ensure that gc::Heap is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, int32_t>, "Ensure that int32_t is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, jsid>, "Ensure that jsid is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, size_t>, "Ensure that size_t is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, uint16_t>, "Ensure that uint16_t is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, uint32_t>, "Ensure that uint32_t is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, uint8_t>, "Ensure that uint8_t is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, unsigned>, "Ensure that unsigned is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, wasm::BytecodeOffset >, "Ensure that wasm::BytecodeOffset is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, wasm::FieldWideningOp >, "Ensure that wasm::FieldWideningOp is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, wasm::SimdOp> , "Ensure that wasm::SimdOp is added to the gc_pointer_types list in GenerateMIRFiles.py." );static_assert(!std::is_base_of_v<gc::Cell, wasm::Trap> , "Ensure that wasm::Trap is added to the gc_pointer_types list in GenerateMIRFiles.py." ); |
55 | |
56 | #ifdef DEBUG1 |
57 | size_t MUse::index() const { return consumer()->indexOf(this); } |
58 | #endif |
59 | |
60 | template <size_t Op> |
61 | static void ConvertDefinitionToDouble(TempAllocator& alloc, MDefinition* def, |
62 | MInstruction* consumer) { |
63 | MInstruction* replace = MToDouble::New(alloc, def); |
64 | consumer->replaceOperand(Op, replace); |
65 | consumer->block()->insertBefore(consumer, replace); |
66 | } |
67 | |
68 | template <size_t Arity, size_t Index> |
69 | static void ConvertOperandToDouble(MAryInstruction<Arity>* def, |
70 | TempAllocator& alloc) { |
71 | static_assert(Index < Arity); |
72 | auto* operand = def->getOperand(Index); |
73 | if (operand->type() == MIRType::Float32) { |
74 | ConvertDefinitionToDouble<Index>(alloc, operand, def); |
75 | } |
76 | } |
77 | |
78 | template <size_t Arity, size_t... ISeq> |
79 | static void ConvertOperandsToDouble(MAryInstruction<Arity>* def, |
80 | TempAllocator& alloc, |
81 | std::index_sequence<ISeq...>) { |
82 | (ConvertOperandToDouble<Arity, ISeq>(def, alloc), ...); |
83 | } |
84 | |
85 | template <size_t Arity> |
86 | static void ConvertOperandsToDouble(MAryInstruction<Arity>* def, |
87 | TempAllocator& alloc) { |
88 | ConvertOperandsToDouble<Arity>(def, alloc, std::make_index_sequence<Arity>{}); |
89 | } |
90 | |
91 | template <size_t Arity, size_t... ISeq> |
92 | static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def, |
93 | std::index_sequence<ISeq...>) { |
94 | return (def->getOperand(ISeq)->canProduceFloat32() && ...); |
95 | } |
96 | |
97 | template <size_t Arity> |
98 | static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def) { |
99 | return AllOperandsCanProduceFloat32<Arity>(def, |
100 | std::make_index_sequence<Arity>{}); |
101 | } |
102 | |
103 | static bool CheckUsesAreFloat32Consumers(const MInstruction* ins) { |
104 | if (ins->isImplicitlyUsed()) { |
105 | return false; |
106 | } |
107 | bool allConsumerUses = true; |
108 | for (MUseDefIterator use(ins); allConsumerUses && use; use++) { |
109 | allConsumerUses &= use.def()->canConsumeFloat32(use.use()); |
110 | } |
111 | return allConsumerUses; |
112 | } |
113 | |
114 | #ifdef JS_JITSPEW1 |
115 | static const char* OpcodeName(MDefinition::Opcode op) { |
116 | static const char* const names[] = { |
117 | # define NAME(x) #x, |
118 | MIR_OPCODE_LIST(NAME)NAME(Start)NAME(OsrEntry)NAME(Nop)NAME(LimitedTruncate)NAME(Constant )NAME(WasmNullConstant)NAME(WasmFloatConstant)NAME(Parameter) NAME(Callee)NAME(IsConstructing)NAME(TableSwitch)NAME(Goto)NAME (Test)NAME(Return)NAME(Throw)NAME(ThrowWithStack)NAME(NewArray )NAME(NewArrayDynamicLength)NAME(NewTypedArray)NAME(NewTypedArrayDynamicLength )NAME(NewTypedArrayFromArray)NAME(NewTypedArrayFromArrayBuffer )NAME(NewObject)NAME(NewPlainObject)NAME(NewArrayObject)NAME( NewIterator)NAME(ObjectState)NAME(ArrayState)NAME(BindFunction )NAME(NewBoundFunction)NAME(BoundFunctionNumArgs)NAME(GuardBoundFunctionIsConstructor )NAME(MutateProto)NAME(InitPropGetterSetter)NAME(InitElemGetterSetter )NAME(Call)NAME(CallClassHook)NAME(ApplyArgs)NAME(ApplyArgsObj )NAME(ApplyArray)NAME(ConstructArgs)NAME(ConstructArray)NAME( Bail)NAME(Unreachable)NAME(EncodeSnapshot)NAME(AssertRecoveredOnBailout )NAME(AssertFloat32)NAME(Compare)NAME(SameValueDouble)NAME(SameValue )NAME(Box)NAME(Unbox)NAME(AssertRange)NAME(AssertClass)NAME(AssertShape )NAME(CreateThis)NAME(CreateArgumentsObject)NAME(CreateInlinedArgumentsObject )NAME(GetInlinedArgument)NAME(GetInlinedArgumentHole)NAME(GetArgumentsObjectArg )NAME(SetArgumentsObjectArg)NAME(LoadArgumentsObjectArg)NAME( LoadArgumentsObjectArgHole)NAME(InArgumentsObjectArg)NAME(ArgumentsObjectLength )NAME(ArrayFromArgumentsObject)NAME(GuardArgumentsObjectFlags )NAME(LoadScriptedProxyHandler)NAME(CheckScriptedProxyGetResult )NAME(IdToStringOrSymbol)NAME(ReturnFromCtor)NAME(ToDouble)NAME (ToFloat32)NAME(ToFloat16)NAME(WasmUnsignedToDouble)NAME(WasmUnsignedToFloat32 )NAME(WrapInt64ToInt32)NAME(ExtendInt32ToInt64)NAME(WasmBuiltinTruncateToInt64 )NAME(WasmTruncateToInt64)NAME(WasmTruncateToInt32)NAME(WasmAnyRefFromJSValue )NAME(WasmAnyRefFromJSObject)NAME(WasmAnyRefFromJSString)NAME (WasmAnyRefIsJSString)NAME(WasmTrapIfAnyRefIsNotJSString)NAME (WasmNewI31Ref)NAME(WasmI31RefGet)NAME(Int32ToIntPtr)NAME(NonNegativeIntPtrToInt32 )NAME(IntPtrToDouble)NAME(AdjustDataViewLength)NAME(Int64ToFloatingPoint )NAME(BuiltinInt64ToFloatingPoint)NAME(ToNumberInt32)NAME(BooleanToInt32 )NAME(TruncateToInt32)NAME(WasmBuiltinTruncateToInt32)NAME(ToBigInt )NAME(ToInt64)NAME(TruncateBigIntToInt64)NAME(Int32ToBigInt)NAME (Int64ToBigInt)NAME(Int64ToIntPtr)NAME(IntPtrToInt64)NAME(ToString )NAME(BitNot)NAME(TypeOf)NAME(TypeOfName)NAME(TypeOfIs)NAME(ToAsyncIter )NAME(ToPropertyKeyCache)NAME(BitAnd)NAME(BitOr)NAME(BitXor)NAME (Lsh)NAME(Rsh)NAME(Ursh)NAME(SignExtendInt32)NAME(SignExtendInt64 )NAME(MinMax)NAME(MinMaxArray)NAME(Abs)NAME(Clz)NAME(Ctz)NAME (Popcnt)NAME(Sqrt)NAME(CopySign)NAME(Atan2)NAME(Hypot)NAME(Pow )NAME(PowHalf)NAME(Random)NAME(Sign)NAME(MathFunction)NAME(Add )NAME(Sub)NAME(Mul)NAME(Div)NAME(WasmBuiltinDivI64)NAME(Mod)NAME (WasmBuiltinModD)NAME(WasmBuiltinModI64)NAME(BigIntAdd)NAME(BigIntSub )NAME(BigIntMul)NAME(BigIntDiv)NAME(BigIntMod)NAME(BigIntPow) NAME(BigIntBitAnd)NAME(BigIntBitOr)NAME(BigIntBitXor)NAME(BigIntLsh )NAME(BigIntRsh)NAME(BigIntIncrement)NAME(BigIntDecrement)NAME (BigIntNegate)NAME(BigIntBitNot)NAME(BigIntToIntPtr)NAME(IntPtrToBigInt )NAME(BigIntPtrAdd)NAME(BigIntPtrSub)NAME(BigIntPtrMul)NAME(BigIntPtrDiv )NAME(BigIntPtrMod)NAME(BigIntPtrPow)NAME(BigIntPtrBitAnd)NAME (BigIntPtrBitOr)NAME(BigIntPtrBitXor)NAME(BigIntPtrLsh)NAME(BigIntPtrRsh )NAME(BigIntPtrBitNot)NAME(Int32ToStringWithBase)NAME(NumberParseInt )NAME(DoubleParseInt)NAME(Concat)NAME(LinearizeString)NAME(LinearizeForCharAccess )NAME(LinearizeForCodePointAccess)NAME(ToRelativeStringIndex) NAME(CharCodeAt)NAME(CharCodeAtOrNegative)NAME(CodePointAt)NAME (CodePointAtOrNegative)NAME(NegativeToNaN)NAME(NegativeToUndefined )NAME(FromCharCode)NAME(FromCharCodeEmptyIfNegative)NAME(FromCharCodeUndefinedIfNegative )NAME(FromCodePoint)NAME(StringIncludes)NAME(StringIndexOf)NAME (StringLastIndexOf)NAME(StringStartsWith)NAME(StringEndsWith) NAME(StringConvertCase)NAME(CharCodeConvertCase)NAME(StringTrimStartIndex )NAME(StringTrimEndIndex)NAME(StringSplit)NAME(BoxNonStrictThis )NAME(ImplicitThis)NAME(Phi)NAME(Beta)NAME(NaNToZero)NAME(OsrValue )NAME(OsrEnvironmentChain)NAME(OsrArgumentsObject)NAME(OsrReturnValue )NAME(BinaryCache)NAME(UnaryCache)NAME(CheckOverRecursed)NAME (InterruptCheck)NAME(WasmInterruptCheck)NAME(WasmTrap)NAME(WasmTrapIfNull )NAME(LexicalCheck)NAME(ThrowRuntimeLexicalError)NAME(ThrowMsg )NAME(GlobalDeclInstantiation)NAME(RegExp)NAME(RegExpMatcher) NAME(RegExpSearcher)NAME(RegExpSearcherLastLimit)NAME(RegExpExecMatch )NAME(RegExpExecTest)NAME(RegExpHasCaptureGroups)NAME(RegExpPrototypeOptimizable )NAME(RegExpInstanceOptimizable)NAME(GetFirstDollarIndex)NAME (StringReplace)NAME(Substr)NAME(ModuleMetadata)NAME(DynamicImport )NAME(Lambda)NAME(FunctionWithProto)NAME(SetFunName)NAME(Slots )NAME(Elements)NAME(InitializedLength)NAME(SetInitializedLength )NAME(ArrayLength)NAME(SetArrayLength)NAME(FunctionLength)NAME (FunctionName)NAME(GetNextEntryForIterator)NAME(ArrayBufferByteLength )NAME(ArrayBufferViewLength)NAME(ArrayBufferViewByteOffset)NAME (ArrayBufferViewElements)NAME(ResizableTypedArrayByteOffsetMaybeOutOfBounds )NAME(ResizableTypedArrayLength)NAME(ResizableDataViewByteLength )NAME(GrowableSharedArrayBufferByteLength)NAME(TypedArrayElementSize )NAME(GuardHasAttachedArrayBuffer)NAME(GuardResizableArrayBufferViewInBounds )NAME(GuardResizableArrayBufferViewInBoundsOrDetached)NAME(GuardNumberToIntPtrIndex )NAME(KeepAliveObject)NAME(DebugEnterGCUnsafeRegion)NAME(DebugLeaveGCUnsafeRegion )NAME(Not)NAME(BoundsCheck)NAME(BoundsCheckLower)NAME(SpectreMaskIndex )NAME(LoadElement)NAME(LoadElementAndUnbox)NAME(LoadElementHole )NAME(StoreElement)NAME(StoreHoleValueElement)NAME(StoreElementHole )NAME(ArrayPopShift)NAME(ArrayPush)NAME(ArraySlice)NAME(ArgumentsSlice )NAME(FrameArgumentsSlice)NAME(InlineArgumentsSlice)NAME(NormalizeSliceTerm )NAME(ArrayJoin)NAME(ObjectKeys)NAME(ObjectKeysLength)NAME(LoadUnboxedScalar )NAME(LoadDataViewElement)NAME(LoadTypedArrayElementHole)NAME (StoreUnboxedScalar)NAME(StoreDataViewElement)NAME(StoreTypedArrayElementHole )NAME(EffectiveAddress)NAME(ClampToUint8)NAME(LoadFixedSlot)NAME (LoadFixedSlotAndUnbox)NAME(LoadDynamicSlotAndUnbox)NAME(StoreFixedSlot )NAME(GetPropertyCache)NAME(HomeObjectSuperBase)NAME(GetPropSuperCache )NAME(BindNameCache)NAME(CallBindVar)NAME(GuardShape)NAME(GuardFuse )NAME(GuardMultipleShapes)NAME(GuardProto)NAME(GuardNullProto )NAME(GuardIsNativeObject)NAME(GuardGlobalGeneration)NAME(GuardIsProxy )NAME(GuardIsNotDOMProxy)NAME(GuardIsNotProxy)NAME(ProxyGet)NAME (ProxyGetByValue)NAME(ProxyHasProp)NAME(ProxySet)NAME(ProxySetByValue )NAME(CallSetArrayLength)NAME(MegamorphicLoadSlot)NAME(MegamorphicLoadSlotPermissive )NAME(MegamorphicLoadSlotByValue)NAME(MegamorphicLoadSlotByValuePermissive )NAME(MegamorphicStoreSlot)NAME(MegamorphicHasProp)NAME(SmallObjectVariableKeyHasProp )NAME(GuardIsNotArrayBufferMaybeShared)NAME(GuardIsTypedArray )NAME(GuardIsFixedLengthTypedArray)NAME(GuardIsResizableTypedArray )NAME(GuardHasProxyHandler)NAME(NurseryObject)NAME(GuardValue )NAME(GuardNullOrUndefined)NAME(GuardIsNotObject)NAME(GuardFunctionFlags )NAME(GuardFunctionIsNonBuiltinCtor)NAME(GuardFunctionKind)NAME (GuardFunctionScript)NAME(GuardObjectIdentity)NAME(GuardSpecificFunction )NAME(GuardSpecificAtom)NAME(GuardSpecificSymbol)NAME(GuardSpecificInt32 )NAME(GuardStringToIndex)NAME(GuardStringToInt32)NAME(GuardStringToDouble )NAME(GuardNoDenseElements)NAME(GuardTagNotEqual)NAME(LoadDynamicSlot )NAME(FunctionEnvironment)NAME(NewLexicalEnvironmentObject)NAME (NewClassBodyEnvironmentObject)NAME(NewVarEnvironmentObject)NAME (HomeObject)NAME(AddAndStoreSlot)NAME(AllocateAndStoreSlot)NAME (AddSlotAndCallAddPropHook)NAME(StoreDynamicSlot)NAME(GetNameCache )NAME(CallGetIntrinsicValue)NAME(DeleteProperty)NAME(DeleteElement )NAME(SetPropertyCache)NAME(MegamorphicSetElement)NAME(SetDOMProperty )NAME(GetDOMProperty)NAME(GetDOMMember)NAME(ObjectToIterator) NAME(ValueToIterator)NAME(IteratorHasIndices)NAME(LoadSlotByIteratorIndex )NAME(StoreSlotByIteratorIndex)NAME(LoadDOMExpandoValue)NAME( LoadDOMExpandoValueGuardGeneration)NAME(LoadDOMExpandoValueIgnoreGeneration )NAME(GuardDOMExpandoMissingOrGuardShape)NAME(StringLength)NAME (Floor)NAME(Ceil)NAME(Round)NAME(Trunc)NAME(NearbyInt)NAME(GetIteratorCache )NAME(OptimizeSpreadCallCache)NAME(IteratorMore)NAME(IsNoIter )NAME(IteratorEnd)NAME(CloseIterCache)NAME(OptimizeGetIteratorCache )NAME(InCache)NAME(InArray)NAME(GuardElementNotHole)NAME(NewPrivateName )NAME(CheckPrivateFieldCache)NAME(HasOwnCache)NAME(InstanceOf )NAME(InstanceOfCache)NAME(ArgumentsLength)NAME(GetFrameArgument )NAME(GetFrameArgumentHole)NAME(NewTarget)NAME(Rest)NAME(PostWriteBarrier )NAME(PostWriteElementBarrier)NAME(AssertCanElidePostWriteBarrier )NAME(NewNamedLambdaObject)NAME(NewCallObject)NAME(NewStringObject )NAME(IsCallable)NAME(IsConstructor)NAME(IsCrossRealmArrayConstructor )NAME(IsObject)NAME(IsNullOrUndefined)NAME(HasClass)NAME(GuardToClass )NAME(GuardToEitherClass)NAME(GuardToFunction)NAME(IsArray)NAME (IsTypedArray)NAME(ObjectClassToString)NAME(CheckReturn)NAME( CheckThis)NAME(AsyncResolve)NAME(AsyncReject)NAME(GeneratorReturn )NAME(AsyncAwait)NAME(CheckThisReinit)NAME(Generator)NAME(CanSkipAwait )NAME(MaybeExtractAwaitValue)NAME(IncrementWarmUpCounter)NAME (AtomicIsLockFree)NAME(CompareExchangeTypedArrayElement)NAME( AtomicExchangeTypedArrayElement)NAME(AtomicTypedArrayElementBinop )NAME(Debugger)NAME(CheckIsObj)NAME(CheckObjCoercible)NAME(CheckClassHeritage )NAME(DebugCheckSelfHosted)NAME(IsPackedArray)NAME(GuardArrayIsPacked )NAME(GetPrototypeOf)NAME(ObjectWithProto)NAME(ObjectStaticProto )NAME(ConstantProto)NAME(BuiltinObject)NAME(SuperFunction)NAME (InitHomeObject)NAME(IsTypedArrayConstructor)NAME(LoadValueTag )NAME(LoadWrapperTarget)NAME(GuardHasGetterSetter)NAME(GuardIsExtensible )NAME(GuardInt32IsNonNegative)NAME(GuardInt32Range)NAME(GuardIndexIsNotDenseElement )NAME(GuardIndexIsValidUpdateOrAdd)NAME(CallAddOrUpdateSparseElement )NAME(CallGetSparseElement)NAME(CallNativeGetElement)NAME(CallNativeGetElementSuper )NAME(CallObjectHasSparseElement)NAME(BigIntAsIntN)NAME(BigIntAsUintN )NAME(GuardNonGCThing)NAME(ToHashableNonGCThing)NAME(ToHashableString )NAME(ToHashableValue)NAME(HashNonGCThing)NAME(HashString)NAME (HashSymbol)NAME(HashBigInt)NAME(HashObject)NAME(HashValue)NAME (SetObjectHasNonBigInt)NAME(SetObjectHasBigInt)NAME(SetObjectHasValue )NAME(SetObjectHasValueVMCall)NAME(SetObjectSize)NAME(MapObjectHasNonBigInt )NAME(MapObjectHasBigInt)NAME(MapObjectHasValue)NAME(MapObjectHasValueVMCall )NAME(MapObjectGetNonBigInt)NAME(MapObjectGetBigInt)NAME(MapObjectGetValue )NAME(MapObjectGetValueVMCall)NAME(MapObjectSize)NAME(PostIntPtrConversion )NAME(WasmNeg)NAME(WasmBinaryBitwise)NAME(WasmLoadInstance)NAME (WasmStoreInstance)NAME(WasmHeapReg)NAME(WasmBoundsCheck)NAME (WasmBoundsCheckRange32)NAME(WasmExtendU32Index)NAME(WasmWrapU32Index )NAME(WasmClampTable64Index)NAME(WasmAddOffset)NAME(WasmAlignmentCheck )NAME(WasmLoad)NAME(WasmStore)NAME(AsmJSLoadHeap)NAME(AsmJSStoreHeap )NAME(WasmFence)NAME(WasmCompareExchangeHeap)NAME(WasmAtomicExchangeHeap )NAME(WasmAtomicBinopHeap)NAME(WasmLoadInstanceDataField)NAME (WasmLoadGlobalCell)NAME(WasmLoadTableElement)NAME(WasmStoreInstanceDataField )NAME(WasmStoreGlobalCell)NAME(WasmStoreStackResult)NAME(WasmDerivedPointer )NAME(WasmDerivedIndexPointer)NAME(WasmStoreRef)NAME(WasmPostWriteBarrierImmediate )NAME(WasmPostWriteBarrierIndex)NAME(WasmParameter)NAME(WasmReturn )NAME(WasmReturnVoid)NAME(WasmStackArg)NAME(WasmRegisterResult )NAME(WasmFloatRegisterResult)NAME(WasmRegister64Result)NAME( WasmStackResultArea)NAME(WasmStackResult)NAME(WasmCallCatchable )NAME(WasmCallUncatchable)NAME(WasmCallLandingPrePad)NAME(WasmReturnCall )NAME(WasmSelect)NAME(WasmReinterpret)NAME(Rotate)NAME(WasmStackSwitchToMain )NAME(WasmStackSwitchToSuspendable)NAME(WasmStackContinueOnSuspendable )NAME(WasmBinarySimd128)NAME(WasmBinarySimd128WithConstant)NAME (WasmShiftSimd128)NAME(WasmShuffleSimd128)NAME(WasmReplaceLaneSimd128 )NAME(WasmUnarySimd128)NAME(WasmTernarySimd128)NAME(WasmScalarToSimd128 )NAME(WasmReduceSimd128)NAME(WasmLoadLaneSimd128)NAME(WasmStoreLaneSimd128 )NAME(UnreachableResult)NAME(IonToWasmCall)NAME(WasmLoadField )NAME(WasmLoadFieldKA)NAME(WasmLoadElementKA)NAME(WasmStoreFieldKA )NAME(WasmStoreFieldRefKA)NAME(WasmStoreElementKA)NAME(WasmStoreElementRefKA )NAME(WasmRefIsSubtypeOfConcrete)NAME(WasmRefIsSubtypeOfAbstract )NAME(WasmNewStructObject)NAME(WasmNewArrayObject) |
119 | # undef NAME |
120 | }; |
121 | return names[unsigned(op)]; |
122 | } |
123 | |
124 | void MDefinition::PrintOpcodeName(GenericPrinter& out, Opcode op) { |
125 | const char* name = OpcodeName(op); |
126 | size_t len = strlen(name); |
127 | for (size_t i = 0; i < len; i++) { |
128 | out.printf("%c", unicode::ToLowerCase(name[i])); |
129 | } |
130 | } |
131 | |
132 | uint32_t js::jit::GetMBasicBlockId(const MBasicBlock* block) { |
133 | return block->id(); |
134 | } |
135 | #endif |
136 | |
137 | static MConstant* EvaluateInt64ConstantOperands(TempAllocator& alloc, |
138 | MBinaryInstruction* ins) { |
139 | MDefinition* left = ins->getOperand(0); |
140 | MDefinition* right = ins->getOperand(1); |
141 | |
142 | if (!left->isConstant() || !right->isConstant()) { |
143 | return nullptr; |
144 | } |
145 | |
146 | MOZ_ASSERT(left->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::Int64)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::Int64", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 146; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
147 | MOZ_ASSERT(right->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::Int64)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::Int64", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 147; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
148 | |
149 | int64_t lhs = left->toConstant()->toInt64(); |
150 | int64_t rhs = right->toConstant()->toInt64(); |
151 | int64_t ret; |
152 | |
153 | switch (ins->op()) { |
154 | case MDefinition::Opcode::BitAnd: |
155 | ret = lhs & rhs; |
156 | break; |
157 | case MDefinition::Opcode::BitOr: |
158 | ret = lhs | rhs; |
159 | break; |
160 | case MDefinition::Opcode::BitXor: |
161 | ret = lhs ^ rhs; |
162 | break; |
163 | case MDefinition::Opcode::Lsh: |
164 | ret = lhs << (rhs & 0x3F); |
165 | break; |
166 | case MDefinition::Opcode::Rsh: |
167 | ret = lhs >> (rhs & 0x3F); |
168 | break; |
169 | case MDefinition::Opcode::Ursh: |
170 | ret = uint64_t(lhs) >> (uint64_t(rhs) & 0x3F); |
171 | break; |
172 | case MDefinition::Opcode::Add: |
173 | ret = lhs + rhs; |
174 | break; |
175 | case MDefinition::Opcode::Sub: |
176 | ret = lhs - rhs; |
177 | break; |
178 | case MDefinition::Opcode::Mul: |
179 | ret = lhs * rhs; |
180 | break; |
181 | case MDefinition::Opcode::Div: |
182 | if (rhs == 0) { |
183 | // Division by zero will trap at runtime. |
184 | return nullptr; |
185 | } |
186 | if (ins->toDiv()->isUnsigned()) { |
187 | ret = int64_t(uint64_t(lhs) / uint64_t(rhs)); |
188 | } else if (lhs == INT64_MIN(-9223372036854775807L -1) || rhs == -1) { |
189 | // Overflow will trap at runtime. |
190 | return nullptr; |
191 | } else { |
192 | ret = lhs / rhs; |
193 | } |
194 | break; |
195 | case MDefinition::Opcode::Mod: |
196 | if (rhs == 0) { |
197 | // Division by zero will trap at runtime. |
198 | return nullptr; |
199 | } |
200 | if (!ins->toMod()->isUnsigned() && (lhs < 0 || rhs < 0)) { |
201 | // Handle all negative values at runtime, for simplicity. |
202 | return nullptr; |
203 | } |
204 | ret = int64_t(uint64_t(lhs) % uint64_t(rhs)); |
205 | break; |
206 | default: |
207 | MOZ_CRASH("NYI")do { do { } while (false); MOZ_ReportCrash("" "NYI", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 207); AnnotateMozCrashReason("MOZ_CRASH(" "NYI" ")"); do { * ((volatile int*)__null) = 207; __attribute__((nomerge)) ::abort (); } while (false); } while (false); |
208 | } |
209 | |
210 | return MConstant::NewInt64(alloc, ret); |
211 | } |
212 | |
213 | static MConstant* EvaluateConstantOperands(TempAllocator& alloc, |
214 | MBinaryInstruction* ins, |
215 | bool* ptypeChange = nullptr) { |
216 | MDefinition* left = ins->getOperand(0); |
217 | MDefinition* right = ins->getOperand(1); |
218 | |
219 | MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeRepresentableAsDouble(left->type()))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(IsTypeRepresentableAsDouble(left->type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeRepresentableAsDouble(left->type())" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(left->type())" ")"); do { *((volatile int*)__null) = 219; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
220 | MOZ_ASSERT(IsTypeRepresentableAsDouble(right->type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeRepresentableAsDouble(right->type()))>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsTypeRepresentableAsDouble(right->type())))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeRepresentableAsDouble(right->type())" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(right->type())" ")"); do { *((volatile int*)__null) = 220; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
221 | |
222 | if (!left->isConstant() || !right->isConstant()) { |
223 | return nullptr; |
224 | } |
225 | |
226 | MConstant* lhs = left->toConstant(); |
227 | MConstant* rhs = right->toConstant(); |
228 | double ret = JS::GenericNaN(); |
229 | |
230 | switch (ins->op()) { |
231 | case MDefinition::Opcode::BitAnd: |
232 | ret = double(lhs->toInt32() & rhs->toInt32()); |
233 | break; |
234 | case MDefinition::Opcode::BitOr: |
235 | ret = double(lhs->toInt32() | rhs->toInt32()); |
236 | break; |
237 | case MDefinition::Opcode::BitXor: |
238 | ret = double(lhs->toInt32() ^ rhs->toInt32()); |
239 | break; |
240 | case MDefinition::Opcode::Lsh: |
241 | ret = double(uint32_t(lhs->toInt32()) << (rhs->toInt32() & 0x1F)); |
242 | break; |
243 | case MDefinition::Opcode::Rsh: |
244 | ret = double(lhs->toInt32() >> (rhs->toInt32() & 0x1F)); |
245 | break; |
246 | case MDefinition::Opcode::Ursh: |
247 | ret = double(uint32_t(lhs->toInt32()) >> (rhs->toInt32() & 0x1F)); |
248 | break; |
249 | case MDefinition::Opcode::Add: |
250 | ret = lhs->numberToDouble() + rhs->numberToDouble(); |
251 | break; |
252 | case MDefinition::Opcode::Sub: |
253 | ret = lhs->numberToDouble() - rhs->numberToDouble(); |
254 | break; |
255 | case MDefinition::Opcode::Mul: |
256 | ret = lhs->numberToDouble() * rhs->numberToDouble(); |
257 | break; |
258 | case MDefinition::Opcode::Div: |
259 | if (ins->toDiv()->isUnsigned()) { |
260 | if (rhs->isInt32(0)) { |
261 | if (ins->toDiv()->trapOnError()) { |
262 | return nullptr; |
263 | } |
264 | ret = 0.0; |
265 | } else { |
266 | ret = double(uint32_t(lhs->toInt32()) / uint32_t(rhs->toInt32())); |
267 | } |
268 | } else { |
269 | ret = NumberDiv(lhs->numberToDouble(), rhs->numberToDouble()); |
270 | } |
271 | break; |
272 | case MDefinition::Opcode::Mod: |
273 | if (ins->toMod()->isUnsigned()) { |
274 | if (rhs->isInt32(0)) { |
275 | if (ins->toMod()->trapOnError()) { |
276 | return nullptr; |
277 | } |
278 | ret = 0.0; |
279 | } else { |
280 | ret = double(uint32_t(lhs->toInt32()) % uint32_t(rhs->toInt32())); |
281 | } |
282 | } else { |
283 | ret = NumberMod(lhs->numberToDouble(), rhs->numberToDouble()); |
284 | } |
285 | break; |
286 | default: |
287 | MOZ_CRASH("NYI")do { do { } while (false); MOZ_ReportCrash("" "NYI", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 287); AnnotateMozCrashReason("MOZ_CRASH(" "NYI" ")"); do { * ((volatile int*)__null) = 287; __attribute__((nomerge)) ::abort (); } while (false); } while (false); |
288 | } |
289 | |
290 | if (ins->type() == MIRType::Float32) { |
291 | return MConstant::NewFloat32(alloc, float(ret)); |
292 | } |
293 | if (ins->type() == MIRType::Double) { |
294 | return MConstant::New(alloc, DoubleValue(ret)); |
295 | } |
296 | |
297 | Value retVal; |
298 | retVal.setNumber(JS::CanonicalizeNaN(ret)); |
299 | |
300 | // If this was an int32 operation but the result isn't an int32 (for |
301 | // example, a division where the numerator isn't evenly divisible by the |
302 | // denominator), decline folding. |
303 | MOZ_ASSERT(ins->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(ins->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::Int32 ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "ins->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 303); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 303; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
304 | if (!retVal.isInt32()) { |
305 | if (ptypeChange) { |
306 | *ptypeChange = true; |
307 | } |
308 | return nullptr; |
309 | } |
310 | |
311 | return MConstant::New(alloc, retVal); |
312 | } |
313 | |
314 | static MConstant* EvaluateConstantNaNOperand(MBinaryInstruction* ins) { |
315 | auto* left = ins->lhs(); |
316 | auto* right = ins->rhs(); |
317 | |
318 | MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeRepresentableAsDouble(left->type()))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(IsTypeRepresentableAsDouble(left->type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeRepresentableAsDouble(left->type())" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(left->type())" ")"); do { *((volatile int*)__null) = 318; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
319 | MOZ_ASSERT(IsTypeRepresentableAsDouble(right->type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeRepresentableAsDouble(right->type()))>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsTypeRepresentableAsDouble(right->type())))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeRepresentableAsDouble(right->type())" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(right->type())" ")"); do { *((volatile int*)__null) = 319; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
320 | MOZ_ASSERT(left->type() == ins->type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == ins->type())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == ins->type ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == ins->type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == ins->type()" ")"); do { *((volatile int*)__null) = 320; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
321 | MOZ_ASSERT(right->type() == ins->type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == ins->type())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == ins-> type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == ins->type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 321); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == ins->type()" ")"); do { *((volatile int*)__null) = 321; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
322 | |
323 | // Don't fold NaN if we can't return a floating point type. |
324 | if (!IsFloatingPointType(ins->type())) { |
325 | return nullptr; |
326 | } |
327 | |
328 | MOZ_ASSERT(!left->isConstant() || !right->isConstant(),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!left->isConstant() || !right->isConstant())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!left->isConstant() || !right->isConstant()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("!left->isConstant() || !right->isConstant()" " (" "EvaluateConstantOperands should have handled this case" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!left->isConstant() || !right->isConstant()" ") (" "EvaluateConstantOperands should have handled this case" ")"); do { *((volatile int*)__null) = 329; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
329 | "EvaluateConstantOperands should have handled this case")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!left->isConstant() || !right->isConstant())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!left->isConstant() || !right->isConstant()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("!left->isConstant() || !right->isConstant()" " (" "EvaluateConstantOperands should have handled this case" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!left->isConstant() || !right->isConstant()" ") (" "EvaluateConstantOperands should have handled this case" ")"); do { *((volatile int*)__null) = 329; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
330 | |
331 | // One operand must be a constant NaN. |
332 | MConstant* cst; |
333 | if (left->isConstant()) { |
334 | cst = left->toConstant(); |
335 | } else if (right->isConstant()) { |
336 | cst = right->toConstant(); |
337 | } else { |
338 | return nullptr; |
339 | } |
340 | if (!std::isnan(cst->numberToDouble())) { |
341 | return nullptr; |
342 | } |
343 | |
344 | // Fold to constant NaN. |
345 | return cst; |
346 | } |
347 | |
348 | static MMul* EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins) { |
349 | // we should fold only when it is a floating point operation |
350 | if (!IsFloatingPointType(ins->type())) { |
351 | return nullptr; |
352 | } |
353 | |
354 | MDefinition* left = ins->getOperand(0); |
355 | MDefinition* right = ins->getOperand(1); |
356 | |
357 | if (!right->isConstant()) { |
358 | return nullptr; |
359 | } |
360 | |
361 | int32_t num; |
362 | if (!mozilla::NumberIsInt32(right->toConstant()->numberToDouble(), &num)) { |
363 | return nullptr; |
364 | } |
365 | |
366 | // check if rhs is a power of two |
367 | if (mozilla::Abs(num) & (mozilla::Abs(num) - 1)) { |
368 | return nullptr; |
369 | } |
370 | |
371 | Value ret; |
372 | ret.setDouble(1.0 / double(num)); |
373 | |
374 | MConstant* foldedRhs; |
375 | if (ins->type() == MIRType::Float32) { |
376 | foldedRhs = MConstant::NewFloat32(alloc, ret.toDouble()); |
377 | } else { |
378 | foldedRhs = MConstant::New(alloc, ret); |
379 | } |
380 | |
381 | MOZ_ASSERT(foldedRhs->type() == ins->type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(foldedRhs->type() == ins->type())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(foldedRhs->type() == ins->type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("foldedRhs->type() == ins->type()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "foldedRhs->type() == ins->type()" ")"); do { *((volatile int*)__null) = 381; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
382 | ins->block()->insertBefore(ins, foldedRhs); |
383 | |
384 | MMul* mul = MMul::New(alloc, left, foldedRhs, ins->type()); |
385 | mul->setMustPreserveNaN(ins->mustPreserveNaN()); |
386 | return mul; |
387 | } |
388 | |
389 | #ifdef JS_JITSPEW1 |
390 | const char* MDefinition::opName() const { return OpcodeName(op()); } |
391 | |
392 | void MDefinition::printName(GenericPrinter& out) const { |
393 | PrintOpcodeName(out, op()); |
394 | out.printf("%u", id()); |
395 | } |
396 | #endif |
397 | |
398 | HashNumber MDefinition::valueHash() const { |
399 | HashNumber out = HashNumber(op()); |
400 | for (size_t i = 0, e = numOperands(); i < e; i++) { |
401 | out = addU32ToHash(out, getOperand(i)->id()); |
402 | } |
403 | if (MDefinition* dep = dependency()) { |
404 | out = addU32ToHash(out, dep->id()); |
405 | } |
406 | return out; |
407 | } |
408 | |
409 | HashNumber MNullaryInstruction::valueHash() const { |
410 | HashNumber hash = HashNumber(op()); |
411 | if (MDefinition* dep = dependency()) { |
412 | hash = addU32ToHash(hash, dep->id()); |
413 | } |
414 | MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 414); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 414; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
415 | return hash; |
416 | } |
417 | |
418 | HashNumber MUnaryInstruction::valueHash() const { |
419 | HashNumber hash = HashNumber(op()); |
420 | hash = addU32ToHash(hash, getOperand(0)->id()); |
421 | if (MDefinition* dep = dependency()) { |
422 | hash = addU32ToHash(hash, dep->id()); |
423 | } |
424 | MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 424); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 424; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
425 | return hash; |
426 | } |
427 | |
428 | HashNumber MBinaryInstruction::valueHash() const { |
429 | HashNumber hash = HashNumber(op()); |
430 | hash = addU32ToHash(hash, getOperand(0)->id()); |
431 | hash = addU32ToHash(hash, getOperand(1)->id()); |
432 | if (MDefinition* dep = dependency()) { |
433 | hash = addU32ToHash(hash, dep->id()); |
434 | } |
435 | MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 435); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 435; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
436 | return hash; |
437 | } |
438 | |
439 | HashNumber MTernaryInstruction::valueHash() const { |
440 | HashNumber hash = HashNumber(op()); |
441 | hash = addU32ToHash(hash, getOperand(0)->id()); |
442 | hash = addU32ToHash(hash, getOperand(1)->id()); |
443 | hash = addU32ToHash(hash, getOperand(2)->id()); |
444 | if (MDefinition* dep = dependency()) { |
445 | hash = addU32ToHash(hash, dep->id()); |
446 | } |
447 | MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 447); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 447; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
448 | return hash; |
449 | } |
450 | |
451 | HashNumber MQuaternaryInstruction::valueHash() const { |
452 | HashNumber hash = HashNumber(op()); |
453 | hash = addU32ToHash(hash, getOperand(0)->id()); |
454 | hash = addU32ToHash(hash, getOperand(1)->id()); |
455 | hash = addU32ToHash(hash, getOperand(2)->id()); |
456 | hash = addU32ToHash(hash, getOperand(3)->id()); |
457 | if (MDefinition* dep = dependency()) { |
458 | hash = addU32ToHash(hash, dep->id()); |
459 | } |
460 | MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType< decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 460); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 460; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
461 | return hash; |
462 | } |
463 | |
464 | const MDefinition* MDefinition::skipObjectGuards() const { |
465 | const MDefinition* result = this; |
466 | // These instructions don't modify the object and just guard specific |
467 | // properties. |
468 | while (true) { |
469 | if (result->isGuardShape()) { |
470 | result = result->toGuardShape()->object(); |
471 | continue; |
472 | } |
473 | if (result->isGuardNullProto()) { |
474 | result = result->toGuardNullProto()->object(); |
475 | continue; |
476 | } |
477 | if (result->isGuardProto()) { |
478 | result = result->toGuardProto()->object(); |
479 | continue; |
480 | } |
481 | |
482 | break; |
483 | } |
484 | |
485 | return result; |
486 | } |
487 | |
488 | bool MDefinition::congruentIfOperandsEqual(const MDefinition* ins) const { |
489 | if (op() != ins->op()) { |
490 | return false; |
491 | } |
492 | |
493 | if (type() != ins->type()) { |
494 | return false; |
495 | } |
496 | |
497 | if (isEffectful() || ins->isEffectful()) { |
498 | return false; |
499 | } |
500 | |
501 | if (numOperands() != ins->numOperands()) { |
502 | return false; |
503 | } |
504 | |
505 | for (size_t i = 0, e = numOperands(); i < e; i++) { |
506 | if (getOperand(i) != ins->getOperand(i)) { |
507 | return false; |
508 | } |
509 | } |
510 | |
511 | return true; |
512 | } |
513 | |
514 | MDefinition* MDefinition::foldsTo(TempAllocator& alloc) { |
515 | // In the default case, there are no constants to fold. |
516 | return this; |
517 | } |
518 | |
519 | bool MDefinition::mightBeMagicType() const { |
520 | if (IsMagicType(type())) { |
521 | return true; |
522 | } |
523 | |
524 | if (MIRType::Value != type()) { |
525 | return false; |
526 | } |
527 | |
528 | return true; |
529 | } |
530 | |
531 | bool MDefinition::definitelyType(std::initializer_list<MIRType> types) const { |
532 | #ifdef DEBUG1 |
533 | // Only support specialized, non-magic types. |
534 | auto isSpecializedNonMagic = [](MIRType type) { |
535 | return type <= MIRType::Object; |
536 | }; |
537 | #endif |
538 | |
539 | MOZ_ASSERT(types.size() > 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(types.size() > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(types.size() > 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("types.size() > 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "types.size() > 0" ")"); do { *((volatile int*)__null) = 539; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
540 | MOZ_ASSERT(std::all_of(types.begin(), types.end(), isSpecializedNonMagic))do { static_assert( mozilla::detail::AssertionConditionType< decltype(std::all_of(types.begin(), types.end(), isSpecializedNonMagic ))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(std::all_of(types.begin(), types.end(), isSpecializedNonMagic )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("std::all_of(types.begin(), types.end(), isSpecializedNonMagic)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 540); AnnotateMozCrashReason("MOZ_ASSERT" "(" "std::all_of(types.begin(), types.end(), isSpecializedNonMagic)" ")"); do { *((volatile int*)__null) = 540; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
541 | |
542 | if (type() == MIRType::Value) { |
543 | return false; |
544 | } |
545 | |
546 | return std::find(types.begin(), types.end(), type()) != types.end(); |
547 | } |
548 | |
549 | MDefinition* MInstruction::foldsToStore(TempAllocator& alloc) { |
550 | if (!dependency()) { |
551 | return nullptr; |
552 | } |
553 | |
554 | MDefinition* store = dependency(); |
555 | if (mightAlias(store) != AliasType::MustAlias) { |
556 | return nullptr; |
557 | } |
558 | |
559 | if (!store->block()->dominates(block())) { |
560 | return nullptr; |
561 | } |
562 | |
563 | MDefinition* value; |
564 | switch (store->op()) { |
565 | case Opcode::StoreFixedSlot: |
566 | value = store->toStoreFixedSlot()->value(); |
567 | break; |
568 | case Opcode::StoreDynamicSlot: |
569 | value = store->toStoreDynamicSlot()->value(); |
570 | break; |
571 | case Opcode::StoreElement: |
572 | value = store->toStoreElement()->value(); |
573 | break; |
574 | default: |
575 | MOZ_CRASH("unknown store")do { do { } while (false); MOZ_ReportCrash("" "unknown store" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 575); AnnotateMozCrashReason("MOZ_CRASH(" "unknown store" ")" ); do { *((volatile int*)__null) = 575; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
576 | } |
577 | |
578 | // If the type are matching then we return the value which is used as |
579 | // argument of the store. |
580 | if (value->type() != type()) { |
581 | // If we expect to read a type which is more generic than the type seen |
582 | // by the store, then we box the value used by the store. |
583 | if (type() != MIRType::Value) { |
584 | return nullptr; |
585 | } |
586 | |
587 | MOZ_ASSERT(value->type() < MIRType::Value)do { static_assert( mozilla::detail::AssertionConditionType< decltype(value->type() < MIRType::Value)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(value->type() < MIRType ::Value))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("value->type() < MIRType::Value", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 587); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() < MIRType::Value" ")"); do { *((volatile int*)__null) = 587; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
588 | MBox* box = MBox::New(alloc, value); |
589 | value = box; |
590 | } |
591 | |
592 | return value; |
593 | } |
594 | |
595 | void MDefinition::analyzeEdgeCasesForward() {} |
596 | |
597 | void MDefinition::analyzeEdgeCasesBackward() {} |
598 | |
599 | void MInstruction::setResumePoint(MResumePoint* resumePoint) { |
600 | MOZ_ASSERT(!resumePoint_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!resumePoint_)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!resumePoint_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!resumePoint_", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 600); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!resumePoint_" ")"); do { *((volatile int*)__null) = 600; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
601 | resumePoint_ = resumePoint; |
602 | resumePoint_->setInstruction(this); |
603 | } |
604 | |
605 | void MInstruction::stealResumePoint(MInstruction* other) { |
606 | MResumePoint* resumePoint = other->resumePoint_; |
607 | other->resumePoint_ = nullptr; |
608 | |
609 | resumePoint->resetInstruction(); |
610 | setResumePoint(resumePoint); |
611 | } |
612 | |
613 | void MInstruction::moveResumePointAsEntry() { |
614 | MOZ_ASSERT(isNop())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isNop())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isNop()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("isNop()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 614); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNop()" ")" ); do { *((volatile int*)__null) = 614; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
615 | block()->clearEntryResumePoint(); |
616 | block()->setEntryResumePoint(resumePoint_); |
617 | resumePoint_->resetInstruction(); |
618 | resumePoint_ = nullptr; |
619 | } |
620 | |
621 | void MInstruction::clearResumePoint() { |
622 | resumePoint_->resetInstruction(); |
623 | block()->discardPreAllocatedResumePoint(resumePoint_); |
624 | resumePoint_ = nullptr; |
625 | } |
626 | |
627 | MDefinition* MTest::foldsDoubleNegation(TempAllocator& alloc) { |
628 | MDefinition* op = getOperand(0); |
629 | |
630 | if (op->isNot()) { |
631 | // If the operand of the Not is itself a Not, they cancel out. |
632 | MDefinition* opop = op->getOperand(0); |
633 | if (opop->isNot()) { |
634 | return MTest::New(alloc, opop->toNot()->input(), ifTrue(), ifFalse()); |
635 | } |
636 | return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue()); |
637 | } |
638 | return nullptr; |
639 | } |
640 | |
641 | MDefinition* MTest::foldsConstant(TempAllocator& alloc) { |
642 | MDefinition* op = getOperand(0); |
643 | if (MConstant* opConst = op->maybeConstantValue()) { |
644 | bool b; |
645 | if (opConst->valueToBoolean(&b)) { |
646 | return MGoto::New(alloc, b ? ifTrue() : ifFalse()); |
647 | } |
648 | } |
649 | return nullptr; |
650 | } |
651 | |
652 | MDefinition* MTest::foldsTypes(TempAllocator& alloc) { |
653 | MDefinition* op = getOperand(0); |
654 | |
655 | switch (op->type()) { |
656 | case MIRType::Undefined: |
657 | case MIRType::Null: |
658 | return MGoto::New(alloc, ifFalse()); |
659 | case MIRType::Symbol: |
660 | return MGoto::New(alloc, ifTrue()); |
661 | default: |
662 | break; |
663 | } |
664 | return nullptr; |
665 | } |
666 | |
667 | class UsesIterator { |
668 | MDefinition* def_; |
669 | |
670 | public: |
671 | explicit UsesIterator(MDefinition* def) : def_(def) {} |
672 | auto begin() const { return def_->usesBegin(); } |
673 | auto end() const { return def_->usesEnd(); } |
674 | }; |
675 | |
676 | static bool AllInstructionsDeadIfUnused(MBasicBlock* block) { |
677 | for (auto* ins : *block) { |
678 | // Skip trivial instructions. |
679 | if (ins->isNop() || ins->isGoto()) { |
680 | continue; |
681 | } |
682 | |
683 | // All uses must be within the current block. |
684 | for (auto* use : UsesIterator(ins)) { |
685 | if (use->consumer()->block() != block) { |
686 | return false; |
687 | } |
688 | } |
689 | |
690 | // All instructions within this block must be dead if unused. |
691 | if (!DeadIfUnused(ins)) { |
692 | return false; |
693 | } |
694 | } |
695 | return true; |
696 | } |
697 | |
698 | MDefinition* MTest::foldsNeedlessControlFlow(TempAllocator& alloc) { |
699 | // All instructions within both successors need be dead if unused. |
700 | if (!AllInstructionsDeadIfUnused(ifTrue()) || |
701 | !AllInstructionsDeadIfUnused(ifFalse())) { |
702 | return nullptr; |
703 | } |
704 | |
705 | // Both successors must have the same target successor. |
706 | if (ifTrue()->numSuccessors() != 1 || ifFalse()->numSuccessors() != 1) { |
707 | return nullptr; |
708 | } |
709 | if (ifTrue()->getSuccessor(0) != ifFalse()->getSuccessor(0)) { |
710 | return nullptr; |
711 | } |
712 | |
713 | // The target successor's phis must be redundant. Redundant phis should have |
714 | // been removed in an earlier pass, so only check if any phis are present, |
715 | // which is a stronger condition. |
716 | if (ifTrue()->successorWithPhis()) { |
717 | return nullptr; |
718 | } |
719 | |
720 | return MGoto::New(alloc, ifTrue()); |
721 | } |
722 | |
723 | // If a test is dominated by either the true or false path of a previous test of |
724 | // the same condition, then the test is redundant and can be converted into a |
725 | // goto true or goto false, respectively. |
726 | MDefinition* MTest::foldsRedundantTest(TempAllocator& alloc) { |
727 | MBasicBlock* myBlock = this->block(); |
728 | MDefinition* originalInput = getOperand(0); |
729 | |
730 | // Handle single and double negatives. This ensures that we do not miss a |
731 | // folding opportunity due to a condition being inverted. |
732 | MDefinition* newInput = input(); |
733 | bool inverted = false; |
734 | if (originalInput->isNot()) { |
735 | newInput = originalInput->toNot()->input(); |
736 | inverted = true; |
737 | if (originalInput->toNot()->input()->isNot()) { |
738 | newInput = originalInput->toNot()->input()->toNot()->input(); |
739 | inverted = false; |
740 | } |
741 | } |
742 | |
743 | // The specific order of traversal does not matter. If there are multiple |
744 | // dominating redundant tests, they will either agree on direction (in which |
745 | // case we will prune the same way regardless of order), or they will |
746 | // disagree, in which case we will eventually be marked entirely dead by the |
747 | // folding of the redundant parent. |
748 | for (MUseIterator i(newInput->usesBegin()), e(newInput->usesEnd()); i != e; |
749 | ++i) { |
750 | if (!i->consumer()->isDefinition()) { |
751 | continue; |
752 | } |
753 | if (!i->consumer()->toDefinition()->isTest()) { |
754 | continue; |
755 | } |
756 | MTest* otherTest = i->consumer()->toDefinition()->toTest(); |
757 | if (otherTest == this) { |
758 | continue; |
759 | } |
760 | |
761 | if (otherTest->ifFalse()->dominates(myBlock)) { |
762 | // This test cannot be true, so fold to a goto false. |
763 | return MGoto::New(alloc, inverted ? ifTrue() : ifFalse()); |
764 | } |
765 | if (otherTest->ifTrue()->dominates(myBlock)) { |
766 | // This test cannot be false, so fold to a goto true. |
767 | return MGoto::New(alloc, inverted ? ifFalse() : ifTrue()); |
768 | } |
769 | } |
770 | |
771 | return nullptr; |
772 | } |
773 | |
774 | MDefinition* MTest::foldsTo(TempAllocator& alloc) { |
775 | if (MDefinition* def = foldsRedundantTest(alloc)) { |
776 | return def; |
777 | } |
778 | |
779 | if (MDefinition* def = foldsDoubleNegation(alloc)) { |
780 | return def; |
781 | } |
782 | |
783 | if (MDefinition* def = foldsConstant(alloc)) { |
784 | return def; |
785 | } |
786 | |
787 | if (MDefinition* def = foldsTypes(alloc)) { |
788 | return def; |
789 | } |
790 | |
791 | if (MDefinition* def = foldsNeedlessControlFlow(alloc)) { |
792 | return def; |
793 | } |
794 | |
795 | return this; |
796 | } |
797 | |
798 | AliasSet MThrow::getAliasSet() const { |
799 | return AliasSet::Store(AliasSet::ExceptionState); |
800 | } |
801 | |
802 | AliasSet MThrowWithStack::getAliasSet() const { |
803 | return AliasSet::Store(AliasSet::ExceptionState); |
804 | } |
805 | |
806 | AliasSet MNewArrayDynamicLength::getAliasSet() const { |
807 | return AliasSet::Store(AliasSet::ExceptionState); |
808 | } |
809 | |
810 | AliasSet MNewTypedArrayDynamicLength::getAliasSet() const { |
811 | return AliasSet::Store(AliasSet::ExceptionState); |
812 | } |
813 | |
814 | #ifdef JS_JITSPEW1 |
815 | void MDefinition::printOpcode(GenericPrinter& out) const { |
816 | PrintOpcodeName(out, op()); |
817 | for (size_t j = 0, e = numOperands(); j < e; j++) { |
818 | out.printf(" "); |
819 | if (getUseFor(j)->hasProducer()) { |
820 | getOperand(j)->printName(out); |
821 | out.printf(":%s", StringFromMIRType(getOperand(j)->type())); |
822 | } else { |
823 | out.printf("(null)"); |
824 | } |
825 | } |
826 | } |
827 | |
828 | void MDefinition::dump(GenericPrinter& out) const { |
829 | printName(out); |
830 | out.printf(":%s", StringFromMIRType(type())); |
831 | out.printf(" = "); |
832 | printOpcode(out); |
833 | out.printf("\n"); |
834 | |
835 | if (isInstruction()) { |
836 | if (MResumePoint* resume = toInstruction()->resumePoint()) { |
837 | resume->dump(out); |
838 | } |
839 | } |
840 | } |
841 | |
842 | void MDefinition::dump() const { |
843 | Fprinter out(stderrstderr); |
844 | dump(out); |
845 | out.finish(); |
846 | } |
847 | |
848 | void MDefinition::dumpLocation(GenericPrinter& out) const { |
849 | MResumePoint* rp = nullptr; |
850 | const char* linkWord = nullptr; |
851 | if (isInstruction() && toInstruction()->resumePoint()) { |
852 | rp = toInstruction()->resumePoint(); |
853 | linkWord = "at"; |
854 | } else { |
855 | rp = block()->entryResumePoint(); |
856 | linkWord = "after"; |
857 | } |
858 | |
859 | while (rp) { |
860 | JSScript* script = rp->block()->info().script(); |
861 | uint32_t lineno = PCToLineNumber(rp->block()->info().script(), rp->pc()); |
862 | out.printf(" %s %s:%u\n", linkWord, script->filename(), lineno); |
863 | rp = rp->caller(); |
864 | linkWord = "in"; |
865 | } |
866 | } |
867 | |
868 | void MDefinition::dumpLocation() const { |
869 | Fprinter out(stderrstderr); |
870 | dumpLocation(out); |
871 | out.finish(); |
872 | } |
873 | #endif |
874 | |
875 | #if defined(DEBUG1) || defined(JS_JITSPEW1) |
876 | size_t MDefinition::useCount() const { |
877 | size_t count = 0; |
878 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
879 | count++; |
880 | } |
881 | return count; |
882 | } |
883 | |
884 | size_t MDefinition::defUseCount() const { |
885 | size_t count = 0; |
886 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
887 | if ((*i)->consumer()->isDefinition()) { |
888 | count++; |
889 | } |
890 | } |
891 | return count; |
892 | } |
893 | #endif |
894 | |
895 | bool MDefinition::hasOneUse() const { |
896 | MUseIterator i(uses_.begin()); |
897 | if (i == uses_.end()) { |
898 | return false; |
899 | } |
900 | i++; |
901 | return i == uses_.end(); |
902 | } |
903 | |
904 | bool MDefinition::hasOneDefUse() const { |
905 | bool hasOneDefUse = false; |
906 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
907 | if (!(*i)->consumer()->isDefinition()) { |
908 | continue; |
909 | } |
910 | |
911 | // We already have a definition use. So 1+ |
912 | if (hasOneDefUse) { |
913 | return false; |
914 | } |
915 | |
916 | // We saw one definition. Loop to test if there is another. |
917 | hasOneDefUse = true; |
918 | } |
919 | |
920 | return hasOneDefUse; |
921 | } |
922 | |
923 | bool MDefinition::hasOneLiveDefUse() const { |
924 | bool hasOneDefUse = false; |
925 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
926 | if (!(*i)->consumer()->isDefinition()) { |
927 | continue; |
928 | } |
929 | |
930 | MDefinition* def = (*i)->consumer()->toDefinition(); |
931 | if (def->isRecoveredOnBailout()) { |
932 | continue; |
933 | } |
934 | |
935 | // We already have a definition use. So 1+ |
936 | if (hasOneDefUse) { |
937 | return false; |
938 | } |
939 | |
940 | // We saw one definition. Loop to test if there is another. |
941 | hasOneDefUse = true; |
942 | } |
943 | |
944 | return hasOneDefUse; |
945 | } |
946 | |
947 | bool MDefinition::hasDefUses() const { |
948 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
949 | if ((*i)->consumer()->isDefinition()) { |
950 | return true; |
951 | } |
952 | } |
953 | |
954 | return false; |
955 | } |
956 | |
957 | bool MDefinition::hasLiveDefUses() const { |
958 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
959 | MNode* ins = (*i)->consumer(); |
960 | if (ins->isDefinition()) { |
961 | if (!ins->toDefinition()->isRecoveredOnBailout()) { |
962 | return true; |
963 | } |
964 | } else { |
965 | MOZ_ASSERT(ins->isResumePoint())do { static_assert( mozilla::detail::AssertionConditionType< decltype(ins->isResumePoint())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(ins->isResumePoint()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("ins->isResumePoint()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 965); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->isResumePoint()" ")"); do { *((volatile int*)__null) = 965; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
966 | if (!ins->toResumePoint()->isRecoverableOperand(*i)) { |
967 | return true; |
968 | } |
969 | } |
970 | } |
971 | |
972 | return false; |
973 | } |
974 | |
975 | MDefinition* MDefinition::maybeSingleDefUse() const { |
976 | MUseDefIterator use(this); |
977 | if (!use) { |
978 | // No def-uses. |
979 | return nullptr; |
980 | } |
981 | |
982 | MDefinition* useDef = use.def(); |
983 | |
984 | use++; |
985 | if (use) { |
986 | // More than one def-use. |
987 | return nullptr; |
988 | } |
989 | |
990 | return useDef; |
991 | } |
992 | |
993 | MDefinition* MDefinition::maybeMostRecentlyAddedDefUse() const { |
994 | MUseDefIterator use(this); |
995 | if (!use) { |
996 | // No def-uses. |
997 | return nullptr; |
998 | } |
999 | |
1000 | MDefinition* mostRecentUse = use.def(); |
1001 | |
1002 | #ifdef DEBUG1 |
1003 | // This function relies on addUse adding new uses to the front of the list. |
1004 | // Check this invariant by asserting the next few uses are 'older'. Skip this |
1005 | // for phis because setBackedge can add a new use for a loop phi even if the |
1006 | // loop body has a use with an id greater than the loop phi's id. |
1007 | if (!mostRecentUse->isPhi()) { |
1008 | static constexpr size_t NumUsesToCheck = 3; |
1009 | use++; |
1010 | for (size_t i = 0; use && i < NumUsesToCheck; i++, use++) { |
1011 | MOZ_ASSERT(use.def()->id() <= mostRecentUse->id())do { static_assert( mozilla::detail::AssertionConditionType< decltype(use.def()->id() <= mostRecentUse->id())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(use.def()->id() <= mostRecentUse->id()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("use.def()->id() <= mostRecentUse->id()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1011); AnnotateMozCrashReason("MOZ_ASSERT" "(" "use.def()->id() <= mostRecentUse->id()" ")"); do { *((volatile int*)__null) = 1011; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1012 | } |
1013 | } |
1014 | #endif |
1015 | |
1016 | return mostRecentUse; |
1017 | } |
1018 | |
1019 | void MDefinition::replaceAllUsesWith(MDefinition* dom) { |
1020 | for (size_t i = 0, e = numOperands(); i < e; ++i) { |
1021 | getOperand(i)->setImplicitlyUsedUnchecked(); |
1022 | } |
1023 | |
1024 | justReplaceAllUsesWith(dom); |
1025 | } |
1026 | |
1027 | void MDefinition::justReplaceAllUsesWith(MDefinition* dom) { |
1028 | MOZ_ASSERT(dom != nullptr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(dom != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(dom != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("dom != nullptr" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1028); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != nullptr" ")"); do { *((volatile int*)__null) = 1028; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1029 | MOZ_ASSERT(dom != this)do { static_assert( mozilla::detail::AssertionConditionType< decltype(dom != this)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(dom != this))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("dom != this", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1029); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != this" ")"); do { *((volatile int*)__null) = 1029; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1030 | |
1031 | // Carry over the fact the value has uses which are no longer inspectable |
1032 | // with the graph. |
1033 | if (isImplicitlyUsed()) { |
1034 | dom->setImplicitlyUsedUnchecked(); |
1035 | } |
1036 | |
1037 | for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i) { |
1038 | i->setProducerUnchecked(dom); |
1039 | } |
1040 | dom->uses_.takeElements(uses_); |
1041 | } |
1042 | |
1043 | bool MDefinition::optimizeOutAllUses(TempAllocator& alloc) { |
1044 | for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) { |
1045 | MUse* use = *i++; |
1046 | MConstant* constant = use->consumer()->block()->optimizedOutConstant(alloc); |
1047 | if (!alloc.ensureBallast()) { |
1048 | return false; |
1049 | } |
1050 | |
1051 | // Update the resume point operand to use the optimized-out constant. |
1052 | use->setProducerUnchecked(constant); |
1053 | constant->addUseUnchecked(use); |
1054 | } |
1055 | |
1056 | // Remove dangling pointers. |
1057 | this->uses_.clear(); |
1058 | return true; |
1059 | } |
1060 | |
1061 | void MDefinition::replaceAllLiveUsesWith(MDefinition* dom) { |
1062 | for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) { |
1063 | MUse* use = *i++; |
1064 | MNode* consumer = use->consumer(); |
1065 | if (consumer->isResumePoint()) { |
1066 | continue; |
1067 | } |
1068 | if (consumer->isDefinition() && |
1069 | consumer->toDefinition()->isRecoveredOnBailout()) { |
1070 | continue; |
1071 | } |
1072 | |
1073 | // Update the operand to use the dominating definition. |
1074 | use->replaceProducer(dom); |
1075 | } |
1076 | } |
1077 | |
1078 | MConstant* MConstant::New(TempAllocator& alloc, const Value& v) { |
1079 | return new (alloc) MConstant(alloc, v); |
1080 | } |
1081 | |
1082 | MConstant* MConstant::New(TempAllocator::Fallible alloc, const Value& v) { |
1083 | return new (alloc) MConstant(alloc.alloc, v); |
1084 | } |
1085 | |
1086 | MConstant* MConstant::NewFloat32(TempAllocator& alloc, double d) { |
1087 | MOZ_ASSERT(std::isnan(d) || d == double(float(d)))do { static_assert( mozilla::detail::AssertionConditionType< decltype(std::isnan(d) || d == double(float(d)))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(std::isnan(d) || d == double(float(d))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("std::isnan(d) || d == double(float(d))" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1087); AnnotateMozCrashReason("MOZ_ASSERT" "(" "std::isnan(d) || d == double(float(d))" ")"); do { *((volatile int*)__null) = 1087; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1088 | return new (alloc) MConstant(float(d)); |
1089 | } |
1090 | |
1091 | MConstant* MConstant::NewInt64(TempAllocator& alloc, int64_t i) { |
1092 | return new (alloc) MConstant(MIRType::Int64, i); |
1093 | } |
1094 | |
1095 | MConstant* MConstant::NewIntPtr(TempAllocator& alloc, intptr_t i) { |
1096 | return new (alloc) MConstant(MIRType::IntPtr, i); |
1097 | } |
1098 | |
1099 | MConstant* MConstant::New(TempAllocator& alloc, const Value& v, MIRType type) { |
1100 | if (type == MIRType::Float32) { |
1101 | return NewFloat32(alloc, v.toNumber()); |
1102 | } |
1103 | MConstant* res = New(alloc, v); |
1104 | MOZ_ASSERT(res->type() == type)do { static_assert( mozilla::detail::AssertionConditionType< decltype(res->type() == type)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(res->type() == type))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("res->type() == type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "res->type() == type" ")"); do { *((volatile int*)__null) = 1104; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1105 | return res; |
1106 | } |
1107 | |
1108 | MConstant* MConstant::NewObject(TempAllocator& alloc, JSObject* v) { |
1109 | return new (alloc) MConstant(v); |
1110 | } |
1111 | |
1112 | MConstant* MConstant::NewShape(TempAllocator& alloc, Shape* s) { |
1113 | return new (alloc) MConstant(s); |
1114 | } |
1115 | |
1116 | static MIRType MIRTypeFromValue(const js::Value& vp) { |
1117 | if (vp.isDouble()) { |
1118 | return MIRType::Double; |
1119 | } |
1120 | if (vp.isMagic()) { |
1121 | switch (vp.whyMagic()) { |
1122 | case JS_OPTIMIZED_OUT: |
1123 | return MIRType::MagicOptimizedOut; |
1124 | case JS_ELEMENTS_HOLE: |
1125 | return MIRType::MagicHole; |
1126 | case JS_IS_CONSTRUCTING: |
1127 | return MIRType::MagicIsConstructing; |
1128 | case JS_UNINITIALIZED_LEXICAL: |
1129 | return MIRType::MagicUninitializedLexical; |
1130 | default: |
1131 | MOZ_ASSERT_UNREACHABLE("Unexpected magic constant")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected magic constant" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected magic constant" ")"); do { *((volatile int*)__null) = 1131; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1132 | } |
1133 | } |
1134 | return MIRTypeFromValueType(vp.extractNonDoubleType()); |
1135 | } |
1136 | |
1137 | MConstant::MConstant(TempAllocator& alloc, const js::Value& vp) |
1138 | : MNullaryInstruction(classOpcode) { |
1139 | setResultType(MIRTypeFromValue(vp)); |
1140 | |
1141 | MOZ_ASSERT(payload_.asBits == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(payload_.asBits == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(payload_.asBits == 0))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("payload_.asBits == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1141); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0" ")"); do { *((volatile int*)__null) = 1141; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1142 | |
1143 | switch (type()) { |
1144 | case MIRType::Undefined: |
1145 | case MIRType::Null: |
1146 | break; |
1147 | case MIRType::Boolean: |
1148 | payload_.b = vp.toBoolean(); |
1149 | break; |
1150 | case MIRType::Int32: |
1151 | payload_.i32 = vp.toInt32(); |
1152 | break; |
1153 | case MIRType::Double: |
1154 | payload_.d = vp.toDouble(); |
1155 | break; |
1156 | case MIRType::String: { |
1157 | JSString* str = vp.toString(); |
1158 | if (str->isAtomRef()) { |
1159 | str = str->atom(); |
1160 | } |
1161 | MOZ_ASSERT(!IsInsideNursery(str))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsInsideNursery(str))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsInsideNursery(str)))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("!IsInsideNursery(str)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(str)" ")"); do { *((volatile int*)__null) = 1161; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1162 | MOZ_ASSERT(str->isAtom())do { static_assert( mozilla::detail::AssertionConditionType< decltype(str->isAtom())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(str->isAtom()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("str->isAtom()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "str->isAtom()" ")"); do { *((volatile int*)__null) = 1162; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1163 | payload_.str = vp.toString(); |
1164 | break; |
1165 | } |
1166 | case MIRType::Symbol: |
1167 | payload_.sym = vp.toSymbol(); |
1168 | break; |
1169 | case MIRType::BigInt: |
1170 | MOZ_ASSERT(!IsInsideNursery(vp.toBigInt()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsInsideNursery(vp.toBigInt()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsInsideNursery(vp.toBigInt ())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsInsideNursery(vp.toBigInt())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1170); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(vp.toBigInt())" ")"); do { *((volatile int*)__null) = 1170; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1171 | payload_.bi = vp.toBigInt(); |
1172 | break; |
1173 | case MIRType::Object: |
1174 | MOZ_ASSERT(!IsInsideNursery(&vp.toObject()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsInsideNursery(&vp.toObject()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsInsideNursery(&vp.toObject ())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsInsideNursery(&vp.toObject())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1174); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(&vp.toObject())" ")"); do { *((volatile int*)__null) = 1174; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1175 | payload_.obj = &vp.toObject(); |
1176 | break; |
1177 | case MIRType::MagicOptimizedOut: |
1178 | case MIRType::MagicHole: |
1179 | case MIRType::MagicIsConstructing: |
1180 | case MIRType::MagicUninitializedLexical: |
1181 | break; |
1182 | default: |
1183 | MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1183); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type" ")"); do { *((volatile int*)__null) = 1183; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
1184 | } |
1185 | |
1186 | setMovable(); |
1187 | } |
1188 | |
1189 | MConstant::MConstant(JSObject* obj) : MNullaryInstruction(classOpcode) { |
1190 | MOZ_ASSERT(!IsInsideNursery(obj))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsInsideNursery(obj))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsInsideNursery(obj)))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("!IsInsideNursery(obj)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(obj)" ")"); do { *((volatile int*)__null) = 1190; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1191 | setResultType(MIRType::Object); |
1192 | payload_.obj = obj; |
1193 | setMovable(); |
1194 | } |
1195 | |
1196 | MConstant::MConstant(Shape* shape) : MNullaryInstruction(classOpcode) { |
1197 | setResultType(MIRType::Shape); |
1198 | payload_.shape = shape; |
1199 | setMovable(); |
1200 | } |
1201 | |
1202 | MConstant::MConstant(float f) : MNullaryInstruction(classOpcode) { |
1203 | setResultType(MIRType::Float32); |
1204 | payload_.f = f; |
1205 | setMovable(); |
1206 | } |
1207 | |
1208 | MConstant::MConstant(MIRType type, int64_t i) |
1209 | : MNullaryInstruction(classOpcode) { |
1210 | MOZ_ASSERT(type == MIRType::Int64 || type == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type == MIRType::Int64 || type == MIRType::IntPtr)> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == MIRType::Int64 || type == MIRType::IntPtr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Int64 || type == MIRType::IntPtr" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int64 || type == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 1210; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1211 | setResultType(type); |
1212 | if (type == MIRType::Int64) { |
1213 | payload_.i64 = i; |
1214 | } else { |
1215 | payload_.iptr = i; |
1216 | } |
1217 | setMovable(); |
1218 | } |
1219 | |
1220 | #ifdef DEBUG1 |
1221 | void MConstant::assertInitializedPayload() const { |
1222 | // valueHash() and equals() expect the unused payload bits to be |
1223 | // initialized to zero. Assert this in debug builds. |
1224 | |
1225 | switch (type()) { |
1226 | case MIRType::Int32: |
1227 | case MIRType::Float32: |
1228 | # if MOZ_LITTLE_ENDIAN()1 |
1229 | MOZ_ASSERT((payload_.asBits >> 32) == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype((payload_.asBits >> 32) == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!((payload_.asBits >> 32 ) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("(payload_.asBits >> 32) == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1229); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0" ")"); do { *((volatile int*)__null) = 1229; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1230 | # else |
1231 | MOZ_ASSERT((payload_.asBits << 32) == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype((payload_.asBits << 32) == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!((payload_.asBits << 32 ) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("(payload_.asBits << 32) == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1231); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0" ")"); do { *((volatile int*)__null) = 1231; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1232 | # endif |
1233 | break; |
1234 | case MIRType::Boolean: |
1235 | # if MOZ_LITTLE_ENDIAN()1 |
1236 | MOZ_ASSERT((payload_.asBits >> 1) == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype((payload_.asBits >> 1) == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!((payload_.asBits >> 1) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("(payload_.asBits >> 1) == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1236); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 1) == 0" ")"); do { *((volatile int*)__null) = 1236; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1237 | # else |
1238 | MOZ_ASSERT((payload_.asBits & ~(1ULL << 56)) == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype((payload_.asBits & ~(1ULL << 56)) == 0)> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!((payload_.asBits & ~(1ULL << 56)) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("(payload_.asBits & ~(1ULL << 56)) == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits & ~(1ULL << 56)) == 0" ")"); do { *((volatile int*)__null) = 1238; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1239 | # endif |
1240 | break; |
1241 | case MIRType::Double: |
1242 | case MIRType::Int64: |
1243 | break; |
1244 | case MIRType::String: |
1245 | case MIRType::Object: |
1246 | case MIRType::Symbol: |
1247 | case MIRType::BigInt: |
1248 | case MIRType::IntPtr: |
1249 | case MIRType::Shape: |
1250 | # if MOZ_LITTLE_ENDIAN()1 |
1251 | MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits >> 32) == 0)do { if (64 == 32) { do { static_assert( mozilla::detail::AssertionConditionType <decltype((payload_.asBits >> 32) == 0)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!((payload_.asBits >> 32) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("(payload_.asBits >> 32) == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1251); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0" ")"); do { *((volatile int*)__null) = 1251; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1252 | # else |
1253 | MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits << 32) == 0)do { if (64 == 32) { do { static_assert( mozilla::detail::AssertionConditionType <decltype((payload_.asBits << 32) == 0)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!((payload_.asBits << 32) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("(payload_.asBits << 32) == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1253); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0" ")"); do { *((volatile int*)__null) = 1253; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1254 | # endif |
1255 | break; |
1256 | default: |
1257 | MOZ_ASSERT(IsNullOrUndefined(type()) || IsMagicType(type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsNullOrUndefined(type()) || IsMagicType(type()))> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(IsNullOrUndefined(type()) || IsMagicType(type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsNullOrUndefined(type()) || IsMagicType(type())" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNullOrUndefined(type()) || IsMagicType(type())" ")"); do { *((volatile int*)__null) = 1257; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1258 | MOZ_ASSERT(payload_.asBits == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(payload_.asBits == 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(payload_.asBits == 0))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("payload_.asBits == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1258); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0" ")"); do { *((volatile int*)__null) = 1258; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1259 | break; |
1260 | } |
1261 | } |
1262 | #endif |
1263 | |
1264 | HashNumber MConstant::valueHash() const { |
1265 | static_assert(sizeof(Payload) == sizeof(uint64_t), |
1266 | "Code below assumes payload fits in 64 bits"); |
1267 | |
1268 | assertInitializedPayload(); |
1269 | return ConstantValueHash(type(), payload_.asBits); |
1270 | } |
1271 | |
1272 | HashNumber MConstantProto::valueHash() const { |
1273 | HashNumber hash = protoObject()->valueHash(); |
1274 | const MDefinition* receiverObject = getReceiverObject(); |
1275 | if (receiverObject) { |
1276 | hash = addU32ToHash(hash, receiverObject->id()); |
1277 | } |
1278 | return hash; |
1279 | } |
1280 | |
1281 | bool MConstant::congruentTo(const MDefinition* ins) const { |
1282 | return ins->isConstant() && equals(ins->toConstant()); |
1283 | } |
1284 | |
1285 | #ifdef JS_JITSPEW1 |
1286 | void MConstant::printOpcode(GenericPrinter& out) const { |
1287 | PrintOpcodeName(out, op()); |
1288 | out.printf(" "); |
1289 | switch (type()) { |
1290 | case MIRType::Undefined: |
1291 | out.printf("undefined"); |
1292 | break; |
1293 | case MIRType::Null: |
1294 | out.printf("null"); |
1295 | break; |
1296 | case MIRType::Boolean: |
1297 | out.printf(toBoolean() ? "true" : "false"); |
1298 | break; |
1299 | case MIRType::Int32: |
1300 | out.printf("0x%x", uint32_t(toInt32())); |
1301 | break; |
1302 | case MIRType::Int64: |
1303 | out.printf("0x%" PRIx64"l" "x", uint64_t(toInt64())); |
1304 | break; |
1305 | case MIRType::IntPtr: |
1306 | out.printf("0x%" PRIxPTR"l" "x", uintptr_t(toIntPtr())); |
1307 | break; |
1308 | case MIRType::Double: |
1309 | out.printf("%.16g", toDouble()); |
1310 | break; |
1311 | case MIRType::Float32: { |
1312 | float val = toFloat32(); |
1313 | out.printf("%.16g", val); |
1314 | break; |
1315 | } |
1316 | case MIRType::Object: |
1317 | if (toObject().is<JSFunction>()) { |
1318 | JSFunction* fun = &toObject().as<JSFunction>(); |
1319 | if (fun->maybePartialDisplayAtom()) { |
1320 | out.put("function "); |
1321 | EscapedStringPrinter(out, fun->maybePartialDisplayAtom(), 0); |
1322 | } else { |
1323 | out.put("unnamed function"); |
1324 | } |
1325 | if (fun->hasBaseScript()) { |
1326 | BaseScript* script = fun->baseScript(); |
1327 | out.printf(" (%s:%u)", script->filename() ? script->filename() : "", |
1328 | script->lineno()); |
1329 | } |
1330 | out.printf(" at %p", (void*)fun); |
1331 | break; |
1332 | } |
1333 | out.printf("object %p (%s)", (void*)&toObject(), |
1334 | toObject().getClass()->name); |
1335 | break; |
1336 | case MIRType::Symbol: |
1337 | out.printf("symbol at %p", (void*)toSymbol()); |
1338 | break; |
1339 | case MIRType::BigInt: |
1340 | out.printf("BigInt at %p", (void*)toBigInt()); |
1341 | break; |
1342 | case MIRType::String: |
1343 | out.printf("string %p", (void*)toString()); |
1344 | break; |
1345 | case MIRType::Shape: |
1346 | out.printf("shape at %p", (void*)toShape()); |
1347 | break; |
1348 | case MIRType::MagicHole: |
1349 | out.printf("magic hole"); |
1350 | break; |
1351 | case MIRType::MagicIsConstructing: |
1352 | out.printf("magic is-constructing"); |
1353 | break; |
1354 | case MIRType::MagicOptimizedOut: |
1355 | out.printf("magic optimized-out"); |
1356 | break; |
1357 | case MIRType::MagicUninitializedLexical: |
1358 | out.printf("magic uninitialized-lexical"); |
1359 | break; |
1360 | default: |
1361 | MOZ_CRASH("unexpected type")do { do { } while (false); MOZ_ReportCrash("" "unexpected type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1361); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected type" ")"); do { *((volatile int*)__null) = 1361; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
1362 | } |
1363 | } |
1364 | #endif |
1365 | |
1366 | bool MConstant::canProduceFloat32() const { |
1367 | if (!isTypeRepresentableAsDouble()) { |
1368 | return false; |
1369 | } |
1370 | |
1371 | if (type() == MIRType::Int32) { |
1372 | return IsFloat32Representable(static_cast<double>(toInt32())); |
1373 | } |
1374 | if (type() == MIRType::Double) { |
1375 | return IsFloat32Representable(toDouble()); |
1376 | } |
1377 | 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.cpp" , 1377); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Float32" ")"); do { *((volatile int*)__null) = 1377; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1378 | return true; |
1379 | } |
1380 | |
1381 | Value MConstant::toJSValue() const { |
1382 | // Wasm has types like int64 that cannot be stored as js::Value. It also |
1383 | // doesn't want the NaN canonicalization enforced by js::Value. |
1384 | MOZ_ASSERT(!IsCompilingWasm())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsCompilingWasm())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsCompilingWasm()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!IsCompilingWasm()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1384); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsCompilingWasm()" ")"); do { *((volatile int*)__null) = 1384; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1385 | |
1386 | switch (type()) { |
1387 | case MIRType::Undefined: |
1388 | return UndefinedValue(); |
1389 | case MIRType::Null: |
1390 | return NullValue(); |
1391 | case MIRType::Boolean: |
1392 | return BooleanValue(toBoolean()); |
1393 | case MIRType::Int32: |
1394 | return Int32Value(toInt32()); |
1395 | case MIRType::Double: |
1396 | return DoubleValue(toDouble()); |
1397 | case MIRType::Float32: |
1398 | return Float32Value(toFloat32()); |
1399 | case MIRType::String: |
1400 | return StringValue(toString()); |
1401 | case MIRType::Symbol: |
1402 | return SymbolValue(toSymbol()); |
1403 | case MIRType::BigInt: |
1404 | return BigIntValue(toBigInt()); |
1405 | case MIRType::Object: |
1406 | return ObjectValue(toObject()); |
1407 | case MIRType::Shape: |
1408 | return PrivateGCThingValue(toShape()); |
1409 | case MIRType::MagicOptimizedOut: |
1410 | return MagicValue(JS_OPTIMIZED_OUT); |
1411 | case MIRType::MagicHole: |
1412 | return MagicValue(JS_ELEMENTS_HOLE); |
1413 | case MIRType::MagicIsConstructing: |
1414 | return MagicValue(JS_IS_CONSTRUCTING); |
1415 | case MIRType::MagicUninitializedLexical: |
1416 | return MagicValue(JS_UNINITIALIZED_LEXICAL); |
1417 | default: |
1418 | MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1418); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type" ")"); do { *((volatile int*)__null) = 1418; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
1419 | } |
1420 | } |
1421 | |
1422 | bool MConstant::valueToBoolean(bool* res) const { |
1423 | switch (type()) { |
1424 | case MIRType::Boolean: |
1425 | *res = toBoolean(); |
1426 | return true; |
1427 | case MIRType::Int32: |
1428 | *res = toInt32() != 0; |
1429 | return true; |
1430 | case MIRType::Int64: |
1431 | *res = toInt64() != 0; |
1432 | return true; |
1433 | case MIRType::Double: |
1434 | *res = !std::isnan(toDouble()) && toDouble() != 0.0; |
1435 | return true; |
1436 | case MIRType::Float32: |
1437 | *res = !std::isnan(toFloat32()) && toFloat32() != 0.0f; |
1438 | return true; |
1439 | case MIRType::Null: |
1440 | case MIRType::Undefined: |
1441 | *res = false; |
1442 | return true; |
1443 | case MIRType::Symbol: |
1444 | *res = true; |
1445 | return true; |
1446 | case MIRType::BigInt: |
1447 | *res = !toBigInt()->isZero(); |
1448 | return true; |
1449 | case MIRType::String: |
1450 | *res = toString()->length() != 0; |
1451 | return true; |
1452 | case MIRType::Object: |
1453 | // TODO(Warp): Lazy groups have been removed. |
1454 | // We have to call EmulatesUndefined but that reads obj->group->clasp |
1455 | // and so it's racy when the object has a lazy group. The main callers |
1456 | // of this (MTest, MNot) already know how to fold the object case, so |
1457 | // just give up. |
1458 | return false; |
1459 | default: |
1460 | MOZ_ASSERT(IsMagicType(type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsMagicType(type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsMagicType(type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsMagicType(type())" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1460); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsMagicType(type())" ")"); do { *((volatile int*)__null) = 1460; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1461 | return false; |
1462 | } |
1463 | } |
1464 | |
1465 | #ifdef JS_JITSPEW1 |
1466 | void MControlInstruction::printOpcode(GenericPrinter& out) const { |
1467 | MDefinition::printOpcode(out); |
1468 | for (size_t j = 0; j < numSuccessors(); j++) { |
1469 | if (getSuccessor(j)) { |
1470 | out.printf(" block%u", getSuccessor(j)->id()); |
1471 | } else { |
1472 | out.printf(" (null-to-be-patched)"); |
1473 | } |
1474 | } |
1475 | } |
1476 | |
1477 | void MCompare::printOpcode(GenericPrinter& out) const { |
1478 | MDefinition::printOpcode(out); |
1479 | out.printf(" %s", CodeName(jsop())); |
1480 | } |
1481 | |
1482 | void MTypeOfIs::printOpcode(GenericPrinter& out) const { |
1483 | MDefinition::printOpcode(out); |
1484 | out.printf(" %s", CodeName(jsop())); |
1485 | |
1486 | const char* name = ""; |
Value stored to 'name' during its initialization is never read | |
1487 | switch (jstype()) { |
1488 | case JSTYPE_UNDEFINED: |
1489 | name = "undefined"; |
1490 | break; |
1491 | case JSTYPE_OBJECT: |
1492 | name = "object"; |
1493 | break; |
1494 | case JSTYPE_FUNCTION: |
1495 | name = "function"; |
1496 | break; |
1497 | case JSTYPE_STRING: |
1498 | name = "string"; |
1499 | break; |
1500 | case JSTYPE_NUMBER: |
1501 | name = "number"; |
1502 | break; |
1503 | case JSTYPE_BOOLEAN: |
1504 | name = "boolean"; |
1505 | break; |
1506 | case JSTYPE_SYMBOL: |
1507 | name = "symbol"; |
1508 | break; |
1509 | case JSTYPE_BIGINT: |
1510 | name = "bigint"; |
1511 | break; |
1512 | # ifdef ENABLE_RECORD_TUPLE |
1513 | case JSTYPE_RECORD: |
1514 | case JSTYPE_TUPLE: |
1515 | # endif |
1516 | case JSTYPE_LIMIT: |
1517 | MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1517); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type" ")"); do { *((volatile int*)__null) = 1517; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
1518 | } |
1519 | out.printf(" '%s'", name); |
1520 | } |
1521 | |
1522 | void MLoadUnboxedScalar::printOpcode(GenericPrinter& out) const { |
1523 | MDefinition::printOpcode(out); |
1524 | out.printf(" %s", Scalar::name(storageType())); |
1525 | } |
1526 | |
1527 | void MLoadDataViewElement::printOpcode(GenericPrinter& out) const { |
1528 | MDefinition::printOpcode(out); |
1529 | out.printf(" %s", Scalar::name(storageType())); |
1530 | } |
1531 | |
1532 | void MAssertRange::printOpcode(GenericPrinter& out) const { |
1533 | MDefinition::printOpcode(out); |
1534 | out.put(" "); |
1535 | assertedRange()->dump(out); |
1536 | } |
1537 | |
1538 | void MNearbyInt::printOpcode(GenericPrinter& out) const { |
1539 | MDefinition::printOpcode(out); |
1540 | const char* roundingModeStr = nullptr; |
1541 | switch (roundingMode_) { |
1542 | case RoundingMode::Up: |
1543 | roundingModeStr = "(up)"; |
1544 | break; |
1545 | case RoundingMode::Down: |
1546 | roundingModeStr = "(down)"; |
1547 | break; |
1548 | case RoundingMode::NearestTiesToEven: |
1549 | roundingModeStr = "(nearest ties even)"; |
1550 | break; |
1551 | case RoundingMode::TowardsZero: |
1552 | roundingModeStr = "(towards zero)"; |
1553 | break; |
1554 | } |
1555 | out.printf(" %s", roundingModeStr); |
1556 | } |
1557 | #endif |
1558 | |
1559 | AliasSet MRandom::getAliasSet() const { return AliasSet::Store(AliasSet::RNG); } |
1560 | |
1561 | MDefinition* MSign::foldsTo(TempAllocator& alloc) { |
1562 | MDefinition* input = getOperand(0); |
1563 | if (!input->isConstant() || |
1564 | !input->toConstant()->isTypeRepresentableAsDouble()) { |
1565 | return this; |
1566 | } |
1567 | |
1568 | double in = input->toConstant()->numberToDouble(); |
1569 | double out = js::math_sign_impl(in); |
1570 | |
1571 | if (type() == MIRType::Int32) { |
1572 | // Decline folding if this is an int32 operation, but the result type |
1573 | // isn't an int32. |
1574 | Value outValue = NumberValue(out); |
1575 | if (!outValue.isInt32()) { |
1576 | return this; |
1577 | } |
1578 | |
1579 | return MConstant::New(alloc, outValue); |
1580 | } |
1581 | |
1582 | return MConstant::New(alloc, DoubleValue(out)); |
1583 | } |
1584 | |
1585 | const char* MMathFunction::FunctionName(UnaryMathFunction function) { |
1586 | return GetUnaryMathFunctionName(function); |
1587 | } |
1588 | |
1589 | #ifdef JS_JITSPEW1 |
1590 | void MMathFunction::printOpcode(GenericPrinter& out) const { |
1591 | MDefinition::printOpcode(out); |
1592 | out.printf(" %s", FunctionName(function())); |
1593 | } |
1594 | #endif |
1595 | |
1596 | MDefinition* MMathFunction::foldsTo(TempAllocator& alloc) { |
1597 | MDefinition* input = getOperand(0); |
1598 | if (!input->isConstant() || |
1599 | !input->toConstant()->isTypeRepresentableAsDouble()) { |
1600 | return this; |
1601 | } |
1602 | |
1603 | UnaryMathFunctionType funPtr = GetUnaryMathFunctionPtr(function()); |
1604 | |
1605 | double in = input->toConstant()->numberToDouble(); |
1606 | |
1607 | // The function pointer call can't GC. |
1608 | JS::AutoSuppressGCAnalysis nogc; |
1609 | double out = funPtr(in); |
1610 | |
1611 | if (input->type() == MIRType::Float32) { |
1612 | return MConstant::NewFloat32(alloc, out); |
1613 | } |
1614 | return MConstant::New(alloc, DoubleValue(out)); |
1615 | } |
1616 | |
1617 | MDefinition* MAtomicIsLockFree::foldsTo(TempAllocator& alloc) { |
1618 | MDefinition* input = getOperand(0); |
1619 | if (!input->isConstant() || input->type() != MIRType::Int32) { |
1620 | return this; |
1621 | } |
1622 | |
1623 | int32_t i = input->toConstant()->toInt32(); |
1624 | return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfreeJS(i))); |
1625 | } |
1626 | |
1627 | // Define |THIS_SLOT| as part of this translation unit, as it is used to |
1628 | // specialized the parameterized |New| function calls introduced by |
1629 | // TRIVIAL_NEW_WRAPPERS. |
1630 | const int32_t MParameter::THIS_SLOT; |
1631 | |
1632 | #ifdef JS_JITSPEW1 |
1633 | void MParameter::printOpcode(GenericPrinter& out) const { |
1634 | PrintOpcodeName(out, op()); |
1635 | if (index() == THIS_SLOT) { |
1636 | out.printf(" THIS_SLOT"); |
1637 | } else { |
1638 | out.printf(" %d", index()); |
1639 | } |
1640 | } |
1641 | #endif |
1642 | |
1643 | HashNumber MParameter::valueHash() const { |
1644 | HashNumber hash = MDefinition::valueHash(); |
1645 | hash = addU32ToHash(hash, index_); |
1646 | return hash; |
1647 | } |
1648 | |
1649 | bool MParameter::congruentTo(const MDefinition* ins) const { |
1650 | if (!ins->isParameter()) { |
1651 | return false; |
1652 | } |
1653 | |
1654 | return ins->toParameter()->index() == index_; |
1655 | } |
1656 | |
1657 | WrappedFunction::WrappedFunction(JSFunction* nativeFun, uint16_t nargs, |
1658 | FunctionFlags flags) |
1659 | : nativeFun_(nativeFun), nargs_(nargs), flags_(flags) { |
1660 | MOZ_ASSERT_IF(nativeFun, isNativeWithoutJitEntry())do { if (nativeFun) { 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.cpp" , 1660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNativeWithoutJitEntry()" ")"); do { *((volatile int*)__null) = 1660; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1661 | |
1662 | #ifdef DEBUG1 |
1663 | // If we are not running off-main thread we can assert that the |
1664 | // metadata is consistent. |
1665 | if (!CanUseExtraThreads() && nativeFun) { |
1666 | MOZ_ASSERT(nativeFun->nargs() == nargs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(nativeFun->nargs() == nargs)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(nativeFun->nargs() == nargs ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "nativeFun->nargs() == nargs", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1666); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->nargs() == nargs" ")"); do { *((volatile int*)__null) = 1666; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1667 | |
1668 | MOZ_ASSERT(nativeFun->isNativeWithoutJitEntry() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()" ")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
1669 | isNativeWithoutJitEntry())do { static_assert( mozilla::detail::AssertionConditionType< decltype(nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()" ")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1670 | MOZ_ASSERT(nativeFun->hasJitEntry() == hasJitEntry())do { static_assert( mozilla::detail::AssertionConditionType< decltype(nativeFun->hasJitEntry() == hasJitEntry())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(nativeFun->hasJitEntry() == hasJitEntry()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("nativeFun->hasJitEntry() == hasJitEntry()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1670); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->hasJitEntry() == hasJitEntry()" ")"); do { *((volatile int*)__null) = 1670; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1671 | MOZ_ASSERT(nativeFun->isConstructor() == isConstructor())do { static_assert( mozilla::detail::AssertionConditionType< decltype(nativeFun->isConstructor() == isConstructor())> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(nativeFun->isConstructor() == isConstructor()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("nativeFun->isConstructor() == isConstructor()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isConstructor() == isConstructor()" ")"); do { *((volatile int*)__null) = 1671; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1672 | MOZ_ASSERT(nativeFun->isClassConstructor() == isClassConstructor())do { static_assert( mozilla::detail::AssertionConditionType< decltype(nativeFun->isClassConstructor() == isClassConstructor ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(nativeFun->isClassConstructor() == isClassConstructor ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("nativeFun->isClassConstructor() == isClassConstructor()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1672); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isClassConstructor() == isClassConstructor()" ")"); do { *((volatile int*)__null) = 1672; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1673 | } |
1674 | #endif |
1675 | } |
1676 | |
1677 | MCall* MCall::New(TempAllocator& alloc, WrappedFunction* target, size_t maxArgc, |
1678 | size_t numActualArgs, bool construct, bool ignoresReturnValue, |
1679 | bool isDOMCall, mozilla::Maybe<DOMObjectKind> objectKind) { |
1680 | MOZ_ASSERT(isDOMCall == objectKind.isSome())do { static_assert( mozilla::detail::AssertionConditionType< decltype(isDOMCall == objectKind.isSome())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(isDOMCall == objectKind.isSome ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("isDOMCall == objectKind.isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1680); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isDOMCall == objectKind.isSome()" ")"); do { *((volatile int*)__null) = 1680; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1681 | MOZ_ASSERT(maxArgc >= numActualArgs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(maxArgc >= numActualArgs)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(maxArgc >= numActualArgs) )), 0))) { do { } while (false); MOZ_ReportAssertionFailure("maxArgc >= numActualArgs" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1681); AnnotateMozCrashReason("MOZ_ASSERT" "(" "maxArgc >= numActualArgs" ")"); do { *((volatile int*)__null) = 1681; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1682 | MCall* ins; |
1683 | if (isDOMCall) { |
1684 | 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.cpp" , 1684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!construct" ")"); do { *((volatile int*)__null) = 1684; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1685 | ins = new (alloc) MCallDOMNative(target, numActualArgs, *objectKind); |
1686 | } else { |
1687 | ins = |
1688 | new (alloc) MCall(target, numActualArgs, construct, ignoresReturnValue); |
1689 | } |
1690 | if (!ins->init(alloc, maxArgc + NumNonArgumentOperands)) { |
1691 | return nullptr; |
1692 | } |
1693 | return ins; |
1694 | } |
1695 | |
1696 | AliasSet MCallDOMNative::getAliasSet() const { |
1697 | const JSJitInfo* jitInfo = getJitInfo(); |
1698 | |
1699 | // If we don't know anything about the types of our arguments, we have to |
1700 | // assume that type-coercions can have side-effects, so we need to alias |
1701 | // everything. |
1702 | if (jitInfo->aliasSet() == JSJitInfo::AliasEverything || |
1703 | !jitInfo->isTypedMethodJitInfo()) { |
1704 | return AliasSet::Store(AliasSet::Any); |
1705 | } |
1706 | |
1707 | uint32_t argIndex = 0; |
1708 | const JSTypedMethodJitInfo* methodInfo = |
1709 | reinterpret_cast<const JSTypedMethodJitInfo*>(jitInfo); |
1710 | for (const JSJitInfo::ArgType* argType = methodInfo->argTypes; |
1711 | *argType != JSJitInfo::ArgTypeListEnd; ++argType, ++argIndex) { |
1712 | if (argIndex >= numActualArgs()) { |
1713 | // Passing through undefined can't have side-effects |
1714 | continue; |
1715 | } |
1716 | // getArg(0) is "this", so skip it |
1717 | MDefinition* arg = getArg(argIndex + 1); |
1718 | MIRType actualType = arg->type(); |
1719 | // The only way to reliably avoid side-effects given the information we |
1720 | // have here is if we're passing in a known primitive value to an |
1721 | // argument that expects a primitive value. |
1722 | // |
1723 | // XXXbz maybe we need to communicate better information. For example, |
1724 | // a sequence argument will sort of unavoidably have side effects, while |
1725 | // a typed array argument won't have any, but both are claimed to be |
1726 | // JSJitInfo::Object. But if we do that, we need to watch out for our |
1727 | // movability/DCE-ability bits: if we have an arg type that can reliably |
1728 | // throw an exception on conversion, that might not affect our alias set |
1729 | // per se, but it should prevent us being moved or DCE-ed, unless we |
1730 | // know the incoming things match that arg type and won't throw. |
1731 | // |
1732 | if ((actualType == MIRType::Value || actualType == MIRType::Object) || |
1733 | (*argType & JSJitInfo::Object)) { |
1734 | return AliasSet::Store(AliasSet::Any); |
1735 | } |
1736 | } |
1737 | |
1738 | // We checked all the args, and they check out. So we only alias DOM |
1739 | // mutations or alias nothing, depending on the alias set in the jitinfo. |
1740 | if (jitInfo->aliasSet() == JSJitInfo::AliasNone) { |
1741 | return AliasSet::None(); |
1742 | } |
1743 | |
1744 | MOZ_ASSERT(jitInfo->aliasSet() == JSJitInfo::AliasDOMSets)do { static_assert( mozilla::detail::AssertionConditionType< decltype(jitInfo->aliasSet() == JSJitInfo::AliasDOMSets)> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(jitInfo->aliasSet() == JSJitInfo::AliasDOMSets))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("jitInfo->aliasSet() == JSJitInfo::AliasDOMSets" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1744); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() == JSJitInfo::AliasDOMSets" ")"); do { *((volatile int*)__null) = 1744; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1745 | return AliasSet::Load(AliasSet::DOMProperty); |
1746 | } |
1747 | |
1748 | void MCallDOMNative::computeMovable() { |
1749 | // We are movable if the jitinfo says we can be and if we're also not |
1750 | // effectful. The jitinfo can't check for the latter, since it depends on |
1751 | // the types of our arguments. |
1752 | const JSJitInfo* jitInfo = getJitInfo(); |
1753 | |
1754 | MOZ_ASSERT_IF(jitInfo->isMovable,do { if (jitInfo->isMovable) { 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.cpp" , 1755); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything" ")"); do { *((volatile int*)__null) = 1755; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) |
1755 | jitInfo->aliasSet() != JSJitInfo::AliasEverything)do { if (jitInfo->isMovable) { 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.cpp" , 1755); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything" ")"); do { *((volatile int*)__null) = 1755; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1756 | |
1757 | if (jitInfo->isMovable && !isEffectful()) { |
1758 | setMovable(); |
1759 | } |
1760 | } |
1761 | |
1762 | bool MCallDOMNative::congruentTo(const MDefinition* ins) const { |
1763 | if (!isMovable()) { |
1764 | return false; |
1765 | } |
1766 | |
1767 | if (!ins->isCall()) { |
1768 | return false; |
1769 | } |
1770 | |
1771 | const MCall* call = ins->toCall(); |
1772 | |
1773 | if (!call->isCallDOMNative()) { |
1774 | return false; |
1775 | } |
1776 | |
1777 | if (getSingleTarget() != call->getSingleTarget()) { |
1778 | return false; |
1779 | } |
1780 | |
1781 | if (isConstructing() != call->isConstructing()) { |
1782 | return false; |
1783 | } |
1784 | |
1785 | if (numActualArgs() != call->numActualArgs()) { |
1786 | return false; |
1787 | } |
1788 | |
1789 | if (!congruentIfOperandsEqual(call)) { |
1790 | return false; |
1791 | } |
1792 | |
1793 | // The other call had better be movable at this point! |
1794 | MOZ_ASSERT(call->isMovable())do { static_assert( mozilla::detail::AssertionConditionType< decltype(call->isMovable())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(call->isMovable()))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("call->isMovable()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1794); AnnotateMozCrashReason("MOZ_ASSERT" "(" "call->isMovable()" ")"); do { *((volatile int*)__null) = 1794; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1795 | |
1796 | return true; |
1797 | } |
1798 | |
1799 | const JSJitInfo* MCallDOMNative::getJitInfo() const { |
1800 | MOZ_ASSERT(getSingleTarget()->hasJitInfo())do { static_assert( mozilla::detail::AssertionConditionType< decltype(getSingleTarget()->hasJitInfo())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(getSingleTarget()->hasJitInfo ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("getSingleTarget()->hasJitInfo()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getSingleTarget()->hasJitInfo()" ")"); do { *((volatile int*)__null) = 1800; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1801 | return getSingleTarget()->jitInfo(); |
1802 | } |
1803 | |
1804 | MCallClassHook* MCallClassHook::New(TempAllocator& alloc, JSNative target, |
1805 | uint32_t argc, bool constructing) { |
1806 | auto* ins = new (alloc) MCallClassHook(target, constructing); |
1807 | |
1808 | // Add callee + |this| + (if constructing) newTarget. |
1809 | uint32_t numOperands = 2 + argc + constructing; |
1810 | |
1811 | if (!ins->init(alloc, numOperands)) { |
1812 | return nullptr; |
1813 | } |
1814 | |
1815 | return ins; |
1816 | } |
1817 | |
1818 | MDefinition* MStringLength::foldsTo(TempAllocator& alloc) { |
1819 | if (string()->isConstant()) { |
1820 | JSString* str = string()->toConstant()->toString(); |
1821 | return MConstant::New(alloc, Int32Value(str->length())); |
1822 | } |
1823 | |
1824 | // MFromCharCode returns a one-element string. |
1825 | if (string()->isFromCharCode()) { |
1826 | return MConstant::New(alloc, Int32Value(1)); |
1827 | } |
1828 | |
1829 | return this; |
1830 | } |
1831 | |
1832 | MDefinition* MConcat::foldsTo(TempAllocator& alloc) { |
1833 | if (lhs()->isConstant() && lhs()->toConstant()->toString()->empty()) { |
1834 | return rhs(); |
1835 | } |
1836 | |
1837 | if (rhs()->isConstant() && rhs()->toConstant()->toString()->empty()) { |
1838 | return lhs(); |
1839 | } |
1840 | |
1841 | return this; |
1842 | } |
1843 | |
1844 | MDefinition* MStringConvertCase::foldsTo(TempAllocator& alloc) { |
1845 | MDefinition* string = this->string(); |
1846 | |
1847 | // Handle the pattern |str[idx].toUpperCase()| and simplify it from |
1848 | // |StringConvertCase(FromCharCode(CharCodeAt(str, idx)))| to just |
1849 | // |CharCodeConvertCase(CharCodeAt(str, idx))|. |
1850 | if (string->isFromCharCode()) { |
1851 | auto* charCode = string->toFromCharCode()->code(); |
1852 | auto mode = mode_ == Mode::LowerCase ? MCharCodeConvertCase::LowerCase |
1853 | : MCharCodeConvertCase::UpperCase; |
1854 | return MCharCodeConvertCase::New(alloc, charCode, mode); |
1855 | } |
1856 | |
1857 | // Handle the pattern |num.toString(base).toUpperCase()| and simplify it to |
1858 | // directly return the string representation in the correct case. |
1859 | if (string->isInt32ToStringWithBase()) { |
1860 | auto* toString = string->toInt32ToStringWithBase(); |
1861 | |
1862 | bool lowerCase = mode_ == Mode::LowerCase; |
1863 | if (toString->lowerCase() == lowerCase) { |
1864 | return toString; |
1865 | } |
1866 | return MInt32ToStringWithBase::New(alloc, toString->input(), |
1867 | toString->base(), lowerCase); |
1868 | } |
1869 | |
1870 | return this; |
1871 | } |
1872 | |
1873 | static bool IsSubstrTo(MSubstr* substr, int32_t len) { |
1874 | // We want to match this pattern: |
1875 | // |
1876 | // Substr(string, Constant(0), Min(Constant(length), StringLength(string))) |
1877 | // |
1878 | // which is generated for the self-hosted `String.p.{substring,slice,substr}` |
1879 | // functions when called with constants `start` and `end` parameters. |
1880 | |
1881 | auto isConstantZero = [](auto* def) { |
1882 | return def->isConstant() && def->toConstant()->isInt32(0); |
1883 | }; |
1884 | |
1885 | if (!isConstantZero(substr->begin())) { |
1886 | return false; |
1887 | } |
1888 | |
1889 | auto* length = substr->length(); |
1890 | if (length->isBitOr()) { |
1891 | // Unnecessary bit-ops haven't yet been removed. |
1892 | auto* bitOr = length->toBitOr(); |
1893 | if (isConstantZero(bitOr->lhs())) { |
1894 | length = bitOr->rhs(); |
1895 | } else if (isConstantZero(bitOr->rhs())) { |
1896 | length = bitOr->lhs(); |
1897 | } |
1898 | } |
1899 | if (!length->isMinMax() || length->toMinMax()->isMax()) { |
1900 | return false; |
1901 | } |
1902 | |
1903 | auto* min = length->toMinMax(); |
1904 | if (!min->lhs()->isConstant() && !min->rhs()->isConstant()) { |
1905 | return false; |
1906 | } |
1907 | |
1908 | auto* minConstant = min->lhs()->isConstant() ? min->lhs()->toConstant() |
1909 | : min->rhs()->toConstant(); |
1910 | |
1911 | auto* minOperand = min->lhs()->isConstant() ? min->rhs() : min->lhs(); |
1912 | if (!minOperand->isStringLength() || |
1913 | minOperand->toStringLength()->string() != substr->string()) { |
1914 | return false; |
1915 | } |
1916 | |
1917 | // Ensure |len| matches the substring's length. |
1918 | return minConstant->isInt32(len); |
1919 | } |
1920 | |
1921 | MDefinition* MSubstr::foldsTo(TempAllocator& alloc) { |
1922 | // Fold |str.substring(0, 1)| to |str.charAt(0)|. |
1923 | if (!IsSubstrTo(this, 1)) { |
1924 | return this; |
1925 | } |
1926 | |
1927 | auto* charCode = MCharCodeAtOrNegative::New(alloc, string(), begin()); |
1928 | block()->insertBefore(this, charCode); |
1929 | |
1930 | return MFromCharCodeEmptyIfNegative::New(alloc, charCode); |
1931 | } |
1932 | |
1933 | MDefinition* MCharCodeAt::foldsTo(TempAllocator& alloc) { |
1934 | MDefinition* string = this->string(); |
1935 | if (!string->isConstant() && !string->isFromCharCode()) { |
1936 | return this; |
1937 | } |
1938 | |
1939 | MDefinition* index = this->index(); |
1940 | if (index->isSpectreMaskIndex()) { |
1941 | index = index->toSpectreMaskIndex()->index(); |
1942 | } |
1943 | if (!index->isConstant()) { |
1944 | return this; |
1945 | } |
1946 | int32_t idx = index->toConstant()->toInt32(); |
1947 | |
1948 | // Handle the pattern |s[idx].charCodeAt(0)|. |
1949 | if (string->isFromCharCode()) { |
1950 | if (idx != 0) { |
1951 | return this; |
1952 | } |
1953 | |
1954 | // Simplify |CharCodeAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just |
1955 | // |CharCodeAt(s, idx)|. |
1956 | auto* charCode = string->toFromCharCode()->code(); |
1957 | if (!charCode->isCharCodeAt()) { |
1958 | return this; |
1959 | } |
1960 | |
1961 | return charCode; |
1962 | } |
1963 | |
1964 | JSLinearString* str = &string->toConstant()->toString()->asLinear(); |
1965 | if (idx < 0 || uint32_t(idx) >= str->length()) { |
1966 | return this; |
1967 | } |
1968 | |
1969 | char16_t ch = str->latin1OrTwoByteChar(idx); |
1970 | return MConstant::New(alloc, Int32Value(ch)); |
1971 | } |
1972 | |
1973 | MDefinition* MCodePointAt::foldsTo(TempAllocator& alloc) { |
1974 | MDefinition* string = this->string(); |
1975 | if (!string->isConstant() && !string->isFromCharCode()) { |
1976 | return this; |
1977 | } |
1978 | |
1979 | MDefinition* index = this->index(); |
1980 | if (index->isSpectreMaskIndex()) { |
1981 | index = index->toSpectreMaskIndex()->index(); |
1982 | } |
1983 | if (!index->isConstant()) { |
1984 | return this; |
1985 | } |
1986 | int32_t idx = index->toConstant()->toInt32(); |
1987 | |
1988 | // Handle the pattern |s[idx].codePointAt(0)|. |
1989 | if (string->isFromCharCode()) { |
1990 | if (idx != 0) { |
1991 | return this; |
1992 | } |
1993 | |
1994 | // Simplify |CodePointAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just |
1995 | // |CharCodeAt(s, idx)|. |
1996 | auto* charCode = string->toFromCharCode()->code(); |
1997 | if (!charCode->isCharCodeAt()) { |
1998 | return this; |
1999 | } |
2000 | |
2001 | return charCode; |
2002 | } |
2003 | |
2004 | JSLinearString* str = &string->toConstant()->toString()->asLinear(); |
2005 | if (idx < 0 || uint32_t(idx) >= str->length()) { |
2006 | return this; |
2007 | } |
2008 | |
2009 | char32_t first = str->latin1OrTwoByteChar(idx); |
2010 | if (unicode::IsLeadSurrogate(first) && uint32_t(idx) + 1 < str->length()) { |
2011 | char32_t second = str->latin1OrTwoByteChar(idx + 1); |
2012 | if (unicode::IsTrailSurrogate(second)) { |
2013 | first = unicode::UTF16Decode(first, second); |
2014 | } |
2015 | } |
2016 | return MConstant::New(alloc, Int32Value(first)); |
2017 | } |
2018 | |
2019 | MDefinition* MToRelativeStringIndex::foldsTo(TempAllocator& alloc) { |
2020 | MDefinition* index = this->index(); |
2021 | MDefinition* length = this->length(); |
2022 | |
2023 | if (!index->isConstant()) { |
2024 | return this; |
2025 | } |
2026 | if (!length->isStringLength() && !length->isConstant()) { |
2027 | return this; |
2028 | } |
2029 | MOZ_ASSERT_IF(length->isConstant(), length->toConstant()->toInt32() >= 0)do { if (length->isConstant()) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(length->toConstant ()->toInt32() >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(length->toConstant()-> toInt32() >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("length->toConstant()->toInt32() >= 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2029); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length->toConstant()->toInt32() >= 0" ")"); do { *((volatile int*)__null) = 2029; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
2030 | |
2031 | int32_t relativeIndex = index->toConstant()->toInt32(); |
2032 | if (relativeIndex >= 0) { |
2033 | return index; |
2034 | } |
2035 | |
2036 | // Safe to truncate because |length| is never negative. |
2037 | return MAdd::New(alloc, index, length, TruncateKind::Truncate); |
2038 | } |
2039 | |
2040 | template <size_t Arity> |
2041 | [[nodiscard]] static bool EnsureFloatInputOrConvert( |
2042 | MAryInstruction<Arity>* owner, TempAllocator& alloc) { |
2043 | MOZ_ASSERT(!IsFloatingPointType(owner->type()),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsFloatingPointType(owner->type()))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(!IsFloatingPointType(owner->type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!IsFloatingPointType(owner->type())" " (" "Floating point types must check consumers" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2044); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())" ") (" "Floating point types must check consumers" ")"); do { *((volatile int*)__null) = 2044; __attribute__((nomerge)) :: abort(); } while (false); } } while (false) |
2044 | "Floating point types must check consumers")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsFloatingPointType(owner->type()))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(!IsFloatingPointType(owner->type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!IsFloatingPointType(owner->type())" " (" "Floating point types must check consumers" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2044); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())" ") (" "Floating point types must check consumers" ")"); do { *((volatile int*)__null) = 2044; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
2045 | |
2046 | if (AllOperandsCanProduceFloat32(owner)) { |
2047 | return true; |
2048 | } |
2049 | ConvertOperandsToDouble(owner, alloc); |
2050 | return false; |
2051 | } |
2052 | |
2053 | template <size_t Arity> |
2054 | [[nodiscard]] static bool EnsureFloatConsumersAndInputOrConvert( |
2055 | MAryInstruction<Arity>* owner, TempAllocator& alloc) { |
2056 | MOZ_ASSERT(IsFloatingPointType(owner->type()),do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsFloatingPointType(owner->type()))>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(IsFloatingPointType(owner->type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsFloatingPointType(owner->type())" " (" "Integer types don't need to check consumers" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())" ") (" "Integer types don't need to check consumers" ")"); do { *((volatile int*)__null) = 2057; __attribute__((nomerge)) :: abort(); } while (false); } } while (false) |
2057 | "Integer types don't need to check consumers")do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsFloatingPointType(owner->type()))>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(IsFloatingPointType(owner->type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsFloatingPointType(owner->type())" " (" "Integer types don't need to check consumers" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())" ") (" "Integer types don't need to check consumers" ")"); do { *((volatile int*)__null) = 2057; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
2058 | |
2059 | if (AllOperandsCanProduceFloat32(owner) && |
2060 | CheckUsesAreFloat32Consumers(owner)) { |
2061 | return true; |
2062 | } |
2063 | ConvertOperandsToDouble(owner, alloc); |
2064 | return false; |
2065 | } |
2066 | |
2067 | void MFloor::trySpecializeFloat32(TempAllocator& alloc) { |
2068 | 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.cpp" , 2068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2068; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2069 | if (EnsureFloatInputOrConvert(this, alloc)) { |
2070 | specialization_ = MIRType::Float32; |
2071 | } |
2072 | } |
2073 | |
2074 | void MCeil::trySpecializeFloat32(TempAllocator& alloc) { |
2075 | 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.cpp" , 2075); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2075; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2076 | if (EnsureFloatInputOrConvert(this, alloc)) { |
2077 | specialization_ = MIRType::Float32; |
2078 | } |
2079 | } |
2080 | |
2081 | void MRound::trySpecializeFloat32(TempAllocator& alloc) { |
2082 | 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.cpp" , 2082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2082; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2083 | if (EnsureFloatInputOrConvert(this, alloc)) { |
2084 | specialization_ = MIRType::Float32; |
2085 | } |
2086 | } |
2087 | |
2088 | void MTrunc::trySpecializeFloat32(TempAllocator& alloc) { |
2089 | 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.cpp" , 2089); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2089; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2090 | if (EnsureFloatInputOrConvert(this, alloc)) { |
2091 | specialization_ = MIRType::Float32; |
2092 | } |
2093 | } |
2094 | |
2095 | void MNearbyInt::trySpecializeFloat32(TempAllocator& alloc) { |
2096 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
2097 | specialization_ = MIRType::Float32; |
2098 | setResultType(MIRType::Float32); |
2099 | } |
2100 | } |
2101 | |
2102 | MGoto* MGoto::New(TempAllocator& alloc, MBasicBlock* target) { |
2103 | return new (alloc) MGoto(target); |
2104 | } |
2105 | |
2106 | MGoto* MGoto::New(TempAllocator::Fallible alloc, MBasicBlock* target) { |
2107 | MOZ_ASSERT(target)do { static_assert( mozilla::detail::AssertionConditionType< decltype(target)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(target))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("target", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2107); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")" ); do { *((volatile int*)__null) = 2107; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2108 | return new (alloc) MGoto(target); |
2109 | } |
2110 | |
2111 | MGoto* MGoto::New(TempAllocator& alloc) { return new (alloc) MGoto(nullptr); } |
2112 | |
2113 | MDefinition* MBox::foldsTo(TempAllocator& alloc) { |
2114 | if (input()->isUnbox()) { |
2115 | return input()->toUnbox()->input(); |
2116 | } |
2117 | return this; |
2118 | } |
2119 | |
2120 | #ifdef JS_JITSPEW1 |
2121 | void MUnbox::printOpcode(GenericPrinter& out) const { |
2122 | PrintOpcodeName(out, op()); |
2123 | out.printf(" "); |
2124 | getOperand(0)->printName(out); |
2125 | out.printf(" "); |
2126 | |
2127 | switch (type()) { |
2128 | case MIRType::Int32: |
2129 | out.printf("to Int32"); |
2130 | break; |
2131 | case MIRType::Double: |
2132 | out.printf("to Double"); |
2133 | break; |
2134 | case MIRType::Boolean: |
2135 | out.printf("to Boolean"); |
2136 | break; |
2137 | case MIRType::String: |
2138 | out.printf("to String"); |
2139 | break; |
2140 | case MIRType::Symbol: |
2141 | out.printf("to Symbol"); |
2142 | break; |
2143 | case MIRType::BigInt: |
2144 | out.printf("to BigInt"); |
2145 | break; |
2146 | case MIRType::Object: |
2147 | out.printf("to Object"); |
2148 | break; |
2149 | default: |
2150 | break; |
2151 | } |
2152 | |
2153 | switch (mode()) { |
2154 | case Fallible: |
2155 | out.printf(" (fallible)"); |
2156 | break; |
2157 | case Infallible: |
2158 | out.printf(" (infallible)"); |
2159 | break; |
2160 | default: |
2161 | break; |
2162 | } |
2163 | } |
2164 | #endif |
2165 | |
2166 | MDefinition* MUnbox::foldsTo(TempAllocator& alloc) { |
2167 | if (input()->isBox()) { |
2168 | MDefinition* unboxed = input()->toBox()->input(); |
2169 | |
2170 | // Fold MUnbox(MBox(x)) => x if types match. |
2171 | if (unboxed->type() == type()) { |
2172 | if (fallible()) { |
2173 | unboxed->setImplicitlyUsedUnchecked(); |
2174 | } |
2175 | return unboxed; |
2176 | } |
2177 | |
2178 | // Fold MUnbox(MBox(x)) => MToDouble(x) if possible. |
2179 | if (type() == MIRType::Double && |
2180 | IsTypeRepresentableAsDouble(unboxed->type())) { |
2181 | if (unboxed->isConstant()) { |
2182 | return MConstant::New( |
2183 | alloc, DoubleValue(unboxed->toConstant()->numberToDouble())); |
2184 | } |
2185 | |
2186 | return MToDouble::New(alloc, unboxed); |
2187 | } |
2188 | |
2189 | // MUnbox<Int32>(MBox<Double>(x)) will always fail, even if x can be |
2190 | // represented as an Int32. Fold to avoid unnecessary bailouts. |
2191 | if (type() == MIRType::Int32 && unboxed->type() == MIRType::Double) { |
2192 | auto* folded = MToNumberInt32::New(alloc, unboxed, |
2193 | IntConversionInputKind::NumbersOnly); |
2194 | folded->setGuard(); |
2195 | return folded; |
2196 | } |
2197 | } |
2198 | |
2199 | return this; |
2200 | } |
2201 | |
2202 | #ifdef DEBUG1 |
2203 | void MPhi::assertLoopPhi() const { |
2204 | // getLoopPredecessorOperand and getLoopBackedgeOperand rely on these |
2205 | // predecessors being at known indices. |
2206 | if (block()->numPredecessors() == 2) { |
2207 | MBasicBlock* pred = block()->getPredecessor(0); |
2208 | MBasicBlock* back = block()->getPredecessor(1); |
2209 | MOZ_ASSERT(pred == block()->loopPredecessor())do { static_assert( mozilla::detail::AssertionConditionType< decltype(pred == block()->loopPredecessor())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(pred == block()->loopPredecessor()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("pred == block()->loopPredecessor()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2209); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred == block()->loopPredecessor()" ")"); do { *((volatile int*)__null) = 2209; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2210 | MOZ_ASSERT(pred->successorWithPhis() == block())do { static_assert( mozilla::detail::AssertionConditionType< decltype(pred->successorWithPhis() == block())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(pred->successorWithPhis() == block()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("pred->successorWithPhis() == block()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->successorWithPhis() == block()" ")"); do { *((volatile int*)__null) = 2210; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2211 | MOZ_ASSERT(pred->positionInPhiSuccessor() == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(pred->positionInPhiSuccessor() == 0)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(pred->positionInPhiSuccessor() == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("pred->positionInPhiSuccessor() == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2211); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->positionInPhiSuccessor() == 0" ")"); do { *((volatile int*)__null) = 2211; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2212 | MOZ_ASSERT(back == block()->backedge())do { static_assert( mozilla::detail::AssertionConditionType< decltype(back == block()->backedge())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(back == block()->backedge ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("back == block()->backedge()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()" ")"); do { *((volatile int*)__null) = 2212; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2213 | MOZ_ASSERT(back->successorWithPhis() == block())do { static_assert( mozilla::detail::AssertionConditionType< decltype(back->successorWithPhis() == block())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(back->successorWithPhis() == block()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("back->successorWithPhis() == block()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2213); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()" ")"); do { *((volatile int*)__null) = 2213; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2214 | MOZ_ASSERT(back->positionInPhiSuccessor() == 1)do { static_assert( mozilla::detail::AssertionConditionType< decltype(back->positionInPhiSuccessor() == 1)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(back->positionInPhiSuccessor() == 1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("back->positionInPhiSuccessor() == 1" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 1" ")"); do { *((volatile int*)__null) = 2214; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2215 | } else { |
2216 | // After we remove fake loop predecessors for loop headers that |
2217 | // are only reachable via OSR, the only predecessor is the |
2218 | // loop backedge. |
2219 | MOZ_ASSERT(block()->numPredecessors() == 1)do { static_assert( mozilla::detail::AssertionConditionType< decltype(block()->numPredecessors() == 1)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(block()->numPredecessors( ) == 1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("block()->numPredecessors() == 1", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 1" ")"); do { *((volatile int*)__null) = 2219; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2220 | MOZ_ASSERT(block()->graph().osrBlock())do { static_assert( mozilla::detail::AssertionConditionType< decltype(block()->graph().osrBlock())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(block()->graph().osrBlock ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("block()->graph().osrBlock()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->graph().osrBlock()" ")"); do { *((volatile int*)__null) = 2220; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2221 | MOZ_ASSERT(!block()->graph().canBuildDominators())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!block()->graph().canBuildDominators())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(!block()->graph().canBuildDominators()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!block()->graph().canBuildDominators()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!block()->graph().canBuildDominators()" ")"); do { *((volatile int*)__null) = 2221; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2222 | MBasicBlock* back = block()->getPredecessor(0); |
2223 | MOZ_ASSERT(back == block()->backedge())do { static_assert( mozilla::detail::AssertionConditionType< decltype(back == block()->backedge())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(back == block()->backedge ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("back == block()->backedge()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()" ")"); do { *((volatile int*)__null) = 2223; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2224 | MOZ_ASSERT(back->successorWithPhis() == block())do { static_assert( mozilla::detail::AssertionConditionType< decltype(back->successorWithPhis() == block())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(back->successorWithPhis() == block()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("back->successorWithPhis() == block()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2224); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()" ")"); do { *((volatile int*)__null) = 2224; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2225 | MOZ_ASSERT(back->positionInPhiSuccessor() == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(back->positionInPhiSuccessor() == 0)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(back->positionInPhiSuccessor() == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("back->positionInPhiSuccessor() == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 0" ")"); do { *((volatile int*)__null) = 2225; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2226 | } |
2227 | } |
2228 | #endif |
2229 | |
2230 | MDefinition* MPhi::getLoopPredecessorOperand() const { |
2231 | // This should not be called after removing fake loop predecessors. |
2232 | MOZ_ASSERT(block()->numPredecessors() == 2)do { static_assert( mozilla::detail::AssertionConditionType< decltype(block()->numPredecessors() == 2)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(block()->numPredecessors( ) == 2))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("block()->numPredecessors() == 2", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2232); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2" ")"); do { *((volatile int*)__null) = 2232; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2233 | assertLoopPhi(); |
2234 | return getOperand(0); |
2235 | } |
2236 | |
2237 | MDefinition* MPhi::getLoopBackedgeOperand() const { |
2238 | assertLoopPhi(); |
2239 | uint32_t idx = block()->numPredecessors() == 2 ? 1 : 0; |
2240 | return getOperand(idx); |
2241 | } |
2242 | |
2243 | void MPhi::removeOperand(size_t index) { |
2244 | 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.cpp" , 2244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index < numOperands()" ")"); do { *((volatile int*)__null) = 2244; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2245 | MOZ_ASSERT(getUseFor(index)->index() == index)do { static_assert( mozilla::detail::AssertionConditionType< decltype(getUseFor(index)->index() == index)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(getUseFor(index)->index() == index))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("getUseFor(index)->index() == index" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->index() == index" ")"); do { *((volatile int*)__null) = 2245; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2246 | MOZ_ASSERT(getUseFor(index)->consumer() == this)do { static_assert( mozilla::detail::AssertionConditionType< decltype(getUseFor(index)->consumer() == this)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(getUseFor(index)->consumer() == this))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("getUseFor(index)->consumer() == this" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->consumer() == this" ")"); do { *((volatile int*)__null) = 2246; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2247 | |
2248 | // If we have phi(..., a, b, c, d, ..., z) and we plan |
2249 | // on removing a, then first shift downward so that we have |
2250 | // phi(..., b, c, d, ..., z, z): |
2251 | MUse* p = inputs_.begin() + index; |
2252 | MUse* e = inputs_.end(); |
2253 | p->producer()->removeUse(p); |
2254 | for (; p < e - 1; ++p) { |
2255 | MDefinition* producer = (p + 1)->producer(); |
2256 | p->setProducerUnchecked(producer); |
2257 | producer->replaceUse(p + 1, p); |
2258 | } |
2259 | |
2260 | // truncate the inputs_ list: |
2261 | inputs_.popBack(); |
2262 | } |
2263 | |
2264 | void MPhi::removeAllOperands() { |
2265 | for (MUse& p : inputs_) { |
2266 | p.producer()->removeUse(&p); |
2267 | } |
2268 | inputs_.clear(); |
2269 | } |
2270 | |
2271 | MDefinition* MPhi::foldsTernary(TempAllocator& alloc) { |
2272 | /* Look if this MPhi is a ternary construct. |
2273 | * This is a very loose term as it actually only checks for |
2274 | * |
2275 | * MTest X |
2276 | * / \ |
2277 | * ... ... |
2278 | * \ / |
2279 | * MPhi X Y |
2280 | * |
2281 | * Which we will simply call: |
2282 | * x ? x : y or x ? y : x |
2283 | */ |
2284 | |
2285 | if (numOperands() != 2) { |
2286 | return nullptr; |
2287 | } |
2288 | |
2289 | MOZ_ASSERT(block()->numPredecessors() == 2)do { static_assert( mozilla::detail::AssertionConditionType< decltype(block()->numPredecessors() == 2)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(block()->numPredecessors( ) == 2))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("block()->numPredecessors() == 2", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2289); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2" ")"); do { *((volatile int*)__null) = 2289; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2290 | |
2291 | MBasicBlock* pred = block()->immediateDominator(); |
2292 | if (!pred || !pred->lastIns()->isTest()) { |
2293 | return nullptr; |
2294 | } |
2295 | |
2296 | MTest* test = pred->lastIns()->toTest(); |
2297 | |
2298 | // True branch may only dominate one edge of MPhi. |
2299 | if (test->ifTrue()->dominates(block()->getPredecessor(0)) == |
2300 | test->ifTrue()->dominates(block()->getPredecessor(1))) { |
2301 | return nullptr; |
2302 | } |
2303 | |
2304 | // False branch may only dominate one edge of MPhi. |
2305 | if (test->ifFalse()->dominates(block()->getPredecessor(0)) == |
2306 | test->ifFalse()->dominates(block()->getPredecessor(1))) { |
2307 | return nullptr; |
2308 | } |
2309 | |
2310 | // True and false branch must dominate different edges of MPhi. |
2311 | if (test->ifTrue()->dominates(block()->getPredecessor(0)) == |
2312 | test->ifFalse()->dominates(block()->getPredecessor(0))) { |
2313 | return nullptr; |
2314 | } |
2315 | |
2316 | // We found a ternary construct. |
2317 | bool firstIsTrueBranch = |
2318 | test->ifTrue()->dominates(block()->getPredecessor(0)); |
2319 | MDefinition* trueDef = firstIsTrueBranch ? getOperand(0) : getOperand(1); |
2320 | MDefinition* falseDef = firstIsTrueBranch ? getOperand(1) : getOperand(0); |
2321 | |
2322 | // Accept either |
2323 | // testArg ? testArg : constant or |
2324 | // testArg ? constant : testArg |
2325 | if (!trueDef->isConstant() && !falseDef->isConstant()) { |
2326 | return nullptr; |
2327 | } |
2328 | |
2329 | MConstant* c = |
2330 | trueDef->isConstant() ? trueDef->toConstant() : falseDef->toConstant(); |
2331 | MDefinition* testArg = (trueDef == c) ? falseDef : trueDef; |
2332 | if (testArg != test->input()) { |
2333 | return nullptr; |
2334 | } |
2335 | |
2336 | // This check should be a tautology, except that the constant might be the |
2337 | // result of the removal of a branch. In such case the domination scope of |
2338 | // the block which is holding the constant might be incomplete. This |
2339 | // condition is used to prevent doing this optimization based on incomplete |
2340 | // information. |
2341 | // |
2342 | // As GVN removed a branch, it will update the dominations rules before |
2343 | // trying to fold this MPhi again. Thus, this condition does not inhibit |
2344 | // this optimization. |
2345 | MBasicBlock* truePred = block()->getPredecessor(firstIsTrueBranch ? 0 : 1); |
2346 | MBasicBlock* falsePred = block()->getPredecessor(firstIsTrueBranch ? 1 : 0); |
2347 | if (!trueDef->block()->dominates(truePred) || |
2348 | !falseDef->block()->dominates(falsePred)) { |
2349 | return nullptr; |
2350 | } |
2351 | |
2352 | // If testArg is an int32 type we can: |
2353 | // - fold testArg ? testArg : 0 to testArg |
2354 | // - fold testArg ? 0 : testArg to 0 |
2355 | if (testArg->type() == MIRType::Int32 && c->numberToDouble() == 0) { |
2356 | testArg->setGuardRangeBailoutsUnchecked(); |
2357 | |
2358 | // When folding to the constant we need to hoist it. |
2359 | if (trueDef == c && !c->block()->dominates(block())) { |
2360 | c->block()->moveBefore(pred->lastIns(), c); |
2361 | } |
2362 | return trueDef; |
2363 | } |
2364 | |
2365 | // If testArg is an double type we can: |
2366 | // - fold testArg ? testArg : 0.0 to MNaNToZero(testArg) |
2367 | if (testArg->type() == MIRType::Double && |
2368 | mozilla::IsPositiveZero(c->numberToDouble()) && c != trueDef) { |
2369 | MNaNToZero* replace = MNaNToZero::New(alloc, testArg); |
2370 | test->block()->insertBefore(test, replace); |
2371 | return replace; |
2372 | } |
2373 | |
2374 | // If testArg is a string type we can: |
2375 | // - fold testArg ? testArg : "" to testArg |
2376 | // - fold testArg ? "" : testArg to "" |
2377 | if (testArg->type() == MIRType::String && |
2378 | c->toString() == GetJitContext()->runtime->emptyString()) { |
2379 | // When folding to the constant we need to hoist it. |
2380 | if (trueDef == c && !c->block()->dominates(block())) { |
2381 | c->block()->moveBefore(pred->lastIns(), c); |
2382 | } |
2383 | return trueDef; |
2384 | } |
2385 | |
2386 | return nullptr; |
2387 | } |
2388 | |
2389 | MDefinition* MPhi::operandIfRedundant() { |
2390 | if (inputs_.length() == 0) { |
2391 | return nullptr; |
2392 | } |
2393 | |
2394 | // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)), |
2395 | // returns the operand that it will always be equal to (a, in |
2396 | // those two cases). |
2397 | MDefinition* first = getOperand(0); |
2398 | for (size_t i = 1, e = numOperands(); i < e; i++) { |
2399 | MDefinition* op = getOperand(i); |
2400 | if (op != first && op != this) { |
2401 | return nullptr; |
2402 | } |
2403 | } |
2404 | return first; |
2405 | } |
2406 | |
2407 | MDefinition* MPhi::foldsTo(TempAllocator& alloc) { |
2408 | if (MDefinition* def = operandIfRedundant()) { |
2409 | return def; |
2410 | } |
2411 | |
2412 | if (MDefinition* def = foldsTernary(alloc)) { |
2413 | return def; |
2414 | } |
2415 | |
2416 | return this; |
2417 | } |
2418 | |
2419 | bool MPhi::congruentTo(const MDefinition* ins) const { |
2420 | if (!ins->isPhi()) { |
2421 | return false; |
2422 | } |
2423 | |
2424 | // Phis in different blocks may have different control conditions. |
2425 | // For example, these phis: |
2426 | // |
2427 | // if (p) |
2428 | // goto a |
2429 | // a: |
2430 | // t = phi(x, y) |
2431 | // |
2432 | // if (q) |
2433 | // goto b |
2434 | // b: |
2435 | // s = phi(x, y) |
2436 | // |
2437 | // have identical operands, but they are not equvalent because t is |
2438 | // effectively p?x:y and s is effectively q?x:y. |
2439 | // |
2440 | // For now, consider phis in different blocks incongruent. |
2441 | if (ins->block() != block()) { |
2442 | return false; |
2443 | } |
2444 | |
2445 | return congruentIfOperandsEqual(ins); |
2446 | } |
2447 | |
2448 | void MPhi::updateForReplacement(MPhi* other) { |
2449 | // This function is called to fix the current Phi flags using it as a |
2450 | // replacement of the other Phi instruction |other|. |
2451 | // |
2452 | // When dealing with usage analysis, any Use will replace all other values, |
2453 | // such as Unused and Unknown. Unless both are Unused, the merge would be |
2454 | // Unknown. |
2455 | if (usageAnalysis_ == PhiUsage::Used || |
2456 | other->usageAnalysis_ == PhiUsage::Used) { |
2457 | usageAnalysis_ = PhiUsage::Used; |
2458 | } else if (usageAnalysis_ != other->usageAnalysis_) { |
2459 | // this == unused && other == unknown |
2460 | // or this == unknown && other == unused |
2461 | usageAnalysis_ = PhiUsage::Unknown; |
2462 | } else { |
2463 | // this == unused && other == unused |
2464 | // or this == unknown && other = unknown |
2465 | MOZ_ASSERT(usageAnalysis_ == PhiUsage::Unused ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(usageAnalysis_ == PhiUsage:: Unused || usageAnalysis_ == PhiUsage::Unknown))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown" ")"); do { *((volatile int*)__null) = 2466; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
2466 | usageAnalysis_ == PhiUsage::Unknown)do { static_assert( mozilla::detail::AssertionConditionType< decltype(usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(usageAnalysis_ == PhiUsage:: Unused || usageAnalysis_ == PhiUsage::Unknown))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown" ")"); do { *((volatile int*)__null) = 2466; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2467 | MOZ_ASSERT(usageAnalysis_ == other->usageAnalysis_)do { static_assert( mozilla::detail::AssertionConditionType< decltype(usageAnalysis_ == other->usageAnalysis_)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(usageAnalysis_ == other->usageAnalysis_))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("usageAnalysis_ == other->usageAnalysis_" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2467); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == other->usageAnalysis_" ")"); do { *((volatile int*)__null) = 2467; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2468 | } |
2469 | } |
2470 | |
2471 | /* static */ |
2472 | bool MPhi::markIteratorPhis(const PhiVector& iterators) { |
2473 | // Find and mark phis that must transitively hold an iterator live. |
2474 | |
2475 | Vector<MPhi*, 8, SystemAllocPolicy> worklist; |
2476 | |
2477 | for (MPhi* iter : iterators) { |
2478 | if (!iter->isInWorklist()) { |
2479 | if (!worklist.append(iter)) { |
2480 | return false; |
2481 | } |
2482 | iter->setInWorklist(); |
2483 | } |
2484 | } |
2485 | |
2486 | while (!worklist.empty()) { |
2487 | MPhi* phi = worklist.popCopy(); |
2488 | phi->setNotInWorklist(); |
2489 | |
2490 | phi->setIterator(); |
2491 | phi->setImplicitlyUsedUnchecked(); |
2492 | |
2493 | for (MUseDefIterator iter(phi); iter; iter++) { |
2494 | MDefinition* use = iter.def(); |
2495 | if (!use->isInWorklist() && use->isPhi() && !use->toPhi()->isIterator()) { |
2496 | if (!worklist.append(use->toPhi())) { |
2497 | return false; |
2498 | } |
2499 | use->setInWorklist(); |
2500 | } |
2501 | } |
2502 | } |
2503 | |
2504 | return true; |
2505 | } |
2506 | |
2507 | bool MPhi::typeIncludes(MDefinition* def) { |
2508 | MOZ_ASSERT(!IsMagicType(def->type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsMagicType(def->type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsMagicType(def->type()) ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "!IsMagicType(def->type())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2508); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsMagicType(def->type())" ")"); do { *((volatile int*)__null) = 2508; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2509 | |
2510 | if (def->type() == MIRType::Int32 && this->type() == MIRType::Double) { |
2511 | return true; |
2512 | } |
2513 | |
2514 | if (def->type() == MIRType::Value) { |
2515 | // This phi must be able to be any value. |
2516 | return this->type() == MIRType::Value; |
2517 | } |
2518 | |
2519 | return this->mightBeType(def->type()); |
2520 | } |
2521 | |
2522 | void MCallBase::addArg(size_t argnum, MDefinition* arg) { |
2523 | // The operand vector is initialized in reverse order by WarpBuilder. |
2524 | // It cannot be checked for consistency until all arguments are added. |
2525 | // FixedList doesn't initialize its elements, so do an unchecked init. |
2526 | initOperand(argnum + NumNonArgumentOperands, arg); |
2527 | } |
2528 | |
2529 | static inline bool IsConstant(MDefinition* def, double v) { |
2530 | if (!def->isConstant()) { |
2531 | return false; |
2532 | } |
2533 | |
2534 | return NumbersAreIdentical(def->toConstant()->numberToDouble(), v); |
2535 | } |
2536 | |
2537 | MDefinition* MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc) { |
2538 | // Identity operations are removed (for int32 only) in foldUnnecessaryBitop. |
2539 | |
2540 | if (type() == MIRType::Int32) { |
2541 | if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) { |
2542 | return folded; |
2543 | } |
2544 | } else if (type() == MIRType::Int64) { |
2545 | if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) { |
2546 | return folded; |
2547 | } |
2548 | } |
2549 | |
2550 | return this; |
2551 | } |
2552 | |
2553 | MDefinition* MBinaryBitwiseInstruction::foldUnnecessaryBitop() { |
2554 | // It's probably OK to perform this optimization only for int32, as it will |
2555 | // have the greatest effect for asm.js code that is compiled with the JS |
2556 | // pipeline, and that code will not see int64 values. |
2557 | |
2558 | if (type() != MIRType::Int32) { |
2559 | return this; |
2560 | } |
2561 | |
2562 | // Fold unsigned shift right operator when the second operand is zero and |
2563 | // the only use is an unsigned modulo. Thus, the expression |
2564 | // |(x >>> 0) % y| becomes |x % y|. |
2565 | if (isUrsh() && IsUint32Type(this)) { |
2566 | MDefinition* defUse = maybeSingleDefUse(); |
2567 | if (defUse && defUse->isMod() && defUse->toMod()->isUnsigned()) { |
2568 | return getOperand(0); |
2569 | } |
2570 | } |
2571 | |
2572 | // Eliminate bitwise operations that are no-ops when used on integer |
2573 | // inputs, such as (x | 0). |
2574 | |
2575 | MDefinition* lhs = getOperand(0); |
2576 | MDefinition* rhs = getOperand(1); |
2577 | |
2578 | if (IsConstant(lhs, 0)) { |
2579 | return foldIfZero(0); |
2580 | } |
2581 | |
2582 | if (IsConstant(rhs, 0)) { |
2583 | return foldIfZero(1); |
2584 | } |
2585 | |
2586 | if (IsConstant(lhs, -1)) { |
2587 | return foldIfNegOne(0); |
2588 | } |
2589 | |
2590 | if (IsConstant(rhs, -1)) { |
2591 | return foldIfNegOne(1); |
2592 | } |
2593 | |
2594 | if (lhs == rhs) { |
2595 | return foldIfEqual(); |
2596 | } |
2597 | |
2598 | if (maskMatchesRightRange) { |
2599 | MOZ_ASSERT(lhs->isConstant())do { static_assert( mozilla::detail::AssertionConditionType< decltype(lhs->isConstant())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(lhs->isConstant()))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("lhs->isConstant()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2599); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->isConstant()" ")"); do { *((volatile int*)__null) = 2599; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2600 | MOZ_ASSERT(lhs->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(lhs->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(lhs->type() == MIRType::Int32 ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "lhs->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2600); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2600; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2601 | return foldIfAllBitsSet(0); |
2602 | } |
2603 | |
2604 | if (maskMatchesLeftRange) { |
2605 | MOZ_ASSERT(rhs->isConstant())do { static_assert( mozilla::detail::AssertionConditionType< decltype(rhs->isConstant())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(rhs->isConstant()))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("rhs->isConstant()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2605); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->isConstant()" ")"); do { *((volatile int*)__null) = 2605; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2606 | MOZ_ASSERT(rhs->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(rhs->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(rhs->type() == MIRType::Int32 ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "rhs->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2606); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2606; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2607 | return foldIfAllBitsSet(1); |
2608 | } |
2609 | |
2610 | return this; |
2611 | } |
2612 | |
2613 | static inline bool CanProduceNegativeZero(MDefinition* def) { |
2614 | // Test if this instruction can produce negative zero even when bailing out |
2615 | // and changing types. |
2616 | switch (def->op()) { |
2617 | case MDefinition::Opcode::Constant: |
2618 | if (def->type() == MIRType::Double && |
2619 | def->toConstant()->toDouble() == -0.0) { |
2620 | return true; |
2621 | } |
2622 | [[fallthrough]]; |
2623 | case MDefinition::Opcode::BitAnd: |
2624 | case MDefinition::Opcode::BitOr: |
2625 | case MDefinition::Opcode::BitXor: |
2626 | case MDefinition::Opcode::BitNot: |
2627 | case MDefinition::Opcode::Lsh: |
2628 | case MDefinition::Opcode::Rsh: |
2629 | return false; |
2630 | default: |
2631 | return true; |
2632 | } |
2633 | } |
2634 | |
2635 | static inline bool NeedNegativeZeroCheck(MDefinition* def) { |
2636 | if (def->isGuard() || def->isGuardRangeBailouts()) { |
2637 | return true; |
2638 | } |
2639 | |
2640 | // Test if all uses have the same semantics for -0 and 0 |
2641 | for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) { |
2642 | if (use->consumer()->isResumePoint()) { |
2643 | return true; |
2644 | } |
2645 | |
2646 | MDefinition* use_def = use->consumer()->toDefinition(); |
2647 | switch (use_def->op()) { |
2648 | case MDefinition::Opcode::Add: { |
2649 | // If add is truncating -0 and 0 are observed as the same. |
2650 | if (use_def->toAdd()->isTruncated()) { |
2651 | break; |
2652 | } |
2653 | |
2654 | // x + y gives -0, when both x and y are -0 |
2655 | |
2656 | // Figure out the order in which the addition's operands will |
2657 | // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR |
2658 | // definitions for us so that this just requires comparing ids. |
2659 | MDefinition* first = use_def->toAdd()->lhs(); |
2660 | MDefinition* second = use_def->toAdd()->rhs(); |
2661 | if (first->id() > second->id()) { |
2662 | std::swap(first, second); |
2663 | } |
2664 | // Negative zero checks can be removed on the first executed |
2665 | // operand only if it is guaranteed the second executed operand |
2666 | // will produce a value other than -0. While the second is |
2667 | // typed as an int32, a bailout taken between execution of the |
2668 | // operands may change that type and cause a -0 to flow to the |
2669 | // second. |
2670 | // |
2671 | // There is no way to test whether there are any bailouts |
2672 | // between execution of the operands, so remove negative |
2673 | // zero checks from the first only if the second's type is |
2674 | // independent from type changes that may occur after bailing. |
2675 | if (def == first && CanProduceNegativeZero(second)) { |
2676 | return true; |
2677 | } |
2678 | |
2679 | // The negative zero check can always be removed on the second |
2680 | // executed operand; by the time this executes the first will have |
2681 | // been evaluated as int32 and the addition's result cannot be -0. |
2682 | break; |
2683 | } |
2684 | case MDefinition::Opcode::Sub: { |
2685 | // If sub is truncating -0 and 0 are observed as the same |
2686 | if (use_def->toSub()->isTruncated()) { |
2687 | break; |
2688 | } |
2689 | |
2690 | // x + y gives -0, when x is -0 and y is 0 |
2691 | |
2692 | // We can remove the negative zero check on the rhs, only if we |
2693 | // are sure the lhs isn't negative zero. |
2694 | |
2695 | // The lhs is typed as integer (i.e. not -0.0), but it can bailout |
2696 | // and change type. This should be fine if the lhs is executed |
2697 | // first. However if the rhs is executed first, the lhs can bail, |
2698 | // change type and become -0.0 while the rhs has already been |
2699 | // optimized to not make a difference between zero and negative zero. |
2700 | MDefinition* lhs = use_def->toSub()->lhs(); |
2701 | MDefinition* rhs = use_def->toSub()->rhs(); |
2702 | if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs)) { |
2703 | return true; |
2704 | } |
2705 | |
2706 | [[fallthrough]]; |
2707 | } |
2708 | case MDefinition::Opcode::StoreElement: |
2709 | case MDefinition::Opcode::StoreHoleValueElement: |
2710 | case MDefinition::Opcode::LoadElement: |
2711 | case MDefinition::Opcode::LoadElementHole: |
2712 | case MDefinition::Opcode::LoadUnboxedScalar: |
2713 | case MDefinition::Opcode::LoadDataViewElement: |
2714 | case MDefinition::Opcode::LoadTypedArrayElementHole: |
2715 | case MDefinition::Opcode::CharCodeAt: |
2716 | case MDefinition::Opcode::Mod: |
2717 | case MDefinition::Opcode::InArray: |
2718 | // Only allowed to remove check when definition is the second operand |
2719 | if (use_def->getOperand(0) == def) { |
2720 | return true; |
2721 | } |
2722 | for (size_t i = 2, e = use_def->numOperands(); i < e; i++) { |
2723 | if (use_def->getOperand(i) == def) { |
2724 | return true; |
2725 | } |
2726 | } |
2727 | break; |
2728 | case MDefinition::Opcode::BoundsCheck: |
2729 | // Only allowed to remove check when definition is the first operand |
2730 | if (use_def->toBoundsCheck()->getOperand(1) == def) { |
2731 | return true; |
2732 | } |
2733 | break; |
2734 | case MDefinition::Opcode::ToString: |
2735 | case MDefinition::Opcode::FromCharCode: |
2736 | case MDefinition::Opcode::FromCodePoint: |
2737 | case MDefinition::Opcode::TableSwitch: |
2738 | case MDefinition::Opcode::Compare: |
2739 | case MDefinition::Opcode::BitAnd: |
2740 | case MDefinition::Opcode::BitOr: |
2741 | case MDefinition::Opcode::BitXor: |
2742 | case MDefinition::Opcode::Abs: |
2743 | case MDefinition::Opcode::TruncateToInt32: |
2744 | // Always allowed to remove check. No matter which operand. |
2745 | break; |
2746 | case MDefinition::Opcode::StoreElementHole: |
2747 | case MDefinition::Opcode::StoreTypedArrayElementHole: |
2748 | case MDefinition::Opcode::PostWriteElementBarrier: |
2749 | // Only allowed to remove check when definition is the third operand. |
2750 | for (size_t i = 0, e = use_def->numOperands(); i < e; i++) { |
2751 | if (i == 2) { |
2752 | continue; |
2753 | } |
2754 | if (use_def->getOperand(i) == def) { |
2755 | return true; |
2756 | } |
2757 | } |
2758 | break; |
2759 | default: |
2760 | return true; |
2761 | } |
2762 | } |
2763 | return false; |
2764 | } |
2765 | |
2766 | #ifdef JS_JITSPEW1 |
2767 | void MBinaryArithInstruction::printOpcode(GenericPrinter& out) const { |
2768 | MDefinition::printOpcode(out); |
2769 | |
2770 | switch (type()) { |
2771 | case MIRType::Int32: |
2772 | if (isDiv()) { |
2773 | out.printf(" [%s]", toDiv()->isUnsigned() ? "uint32" : "int32"); |
2774 | } else if (isMod()) { |
2775 | out.printf(" [%s]", toMod()->isUnsigned() ? "uint32" : "int32"); |
2776 | } else { |
2777 | out.printf(" [int32]"); |
2778 | } |
2779 | break; |
2780 | case MIRType::Int64: |
2781 | if (isDiv()) { |
2782 | out.printf(" [%s]", toDiv()->isUnsigned() ? "uint64" : "int64"); |
2783 | } else if (isMod()) { |
2784 | out.printf(" [%s]", toMod()->isUnsigned() ? "uint64" : "int64"); |
2785 | } else { |
2786 | out.printf(" [int64]"); |
2787 | } |
2788 | break; |
2789 | case MIRType::Float32: |
2790 | out.printf(" [float]"); |
2791 | break; |
2792 | case MIRType::Double: |
2793 | out.printf(" [double]"); |
2794 | break; |
2795 | default: |
2796 | break; |
2797 | } |
2798 | } |
2799 | #endif |
2800 | |
2801 | MDefinition* MRsh::foldsTo(TempAllocator& alloc) { |
2802 | MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc); |
2803 | |
2804 | if (f != this) { |
2805 | return f; |
2806 | } |
2807 | |
2808 | MDefinition* lhs = getOperand(0); |
2809 | MDefinition* rhs = getOperand(1); |
2810 | |
2811 | // It's probably OK to perform this optimization only for int32, as it will |
2812 | // have the greatest effect for asm.js code that is compiled with the JS |
2813 | // pipeline, and that code will not see int64 values. |
2814 | |
2815 | if (!lhs->isLsh() || !rhs->isConstant() || rhs->type() != MIRType::Int32) { |
2816 | return this; |
2817 | } |
2818 | |
2819 | if (!lhs->getOperand(1)->isConstant() || |
2820 | lhs->getOperand(1)->type() != MIRType::Int32) { |
2821 | return this; |
2822 | } |
2823 | |
2824 | uint32_t shift = rhs->toConstant()->toInt32(); |
2825 | uint32_t shift_lhs = lhs->getOperand(1)->toConstant()->toInt32(); |
2826 | if (shift != shift_lhs) { |
2827 | return this; |
2828 | } |
2829 | |
2830 | switch (shift) { |
2831 | case 16: |
2832 | return MSignExtendInt32::New(alloc, lhs->getOperand(0), |
2833 | MSignExtendInt32::Half); |
2834 | case 24: |
2835 | return MSignExtendInt32::New(alloc, lhs->getOperand(0), |
2836 | MSignExtendInt32::Byte); |
2837 | } |
2838 | |
2839 | return this; |
2840 | } |
2841 | |
2842 | MDefinition* MBinaryArithInstruction::foldsTo(TempAllocator& alloc) { |
2843 | 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.cpp" , 2843); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())" ")"); do { *((volatile int*)__null) = 2843; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2844 | |
2845 | MDefinition* lhs = getOperand(0); |
2846 | MDefinition* rhs = getOperand(1); |
2847 | |
2848 | if (type() == MIRType::Int64) { |
2849 | MOZ_ASSERT(!isTruncated())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!isTruncated())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!isTruncated()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!isTruncated()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isTruncated()" ")"); do { *((volatile int*)__null) = 2849; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2850 | |
2851 | if (MConstant* folded = EvaluateInt64ConstantOperands(alloc, this)) { |
2852 | if (!folded->block()) { |
2853 | block()->insertBefore(this, folded); |
2854 | } |
2855 | return folded; |
2856 | } |
2857 | if (isSub() || isDiv() || isMod()) { |
2858 | return this; |
2859 | } |
2860 | if (rhs->isConstant() && |
2861 | rhs->toConstant()->toInt64() == int64_t(getIdentity())) { |
2862 | return lhs; |
2863 | } |
2864 | if (lhs->isConstant() && |
2865 | lhs->toConstant()->toInt64() == int64_t(getIdentity())) { |
2866 | return rhs; |
2867 | } |
2868 | return this; |
2869 | } |
2870 | |
2871 | if (MConstant* folded = EvaluateConstantOperands(alloc, this)) { |
2872 | if (isTruncated()) { |
2873 | if (!folded->block()) { |
2874 | block()->insertBefore(this, folded); |
2875 | } |
2876 | if (folded->type() != MIRType::Int32) { |
2877 | return MTruncateToInt32::New(alloc, folded); |
2878 | } |
2879 | } |
2880 | return folded; |
2881 | } |
2882 | |
2883 | if (MConstant* folded = EvaluateConstantNaNOperand(this)) { |
2884 | MOZ_ASSERT(!isTruncated())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!isTruncated())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!isTruncated()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!isTruncated()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2884); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isTruncated()" ")"); do { *((volatile int*)__null) = 2884; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2885 | return folded; |
2886 | } |
2887 | |
2888 | if (mustPreserveNaN_) { |
2889 | return this; |
2890 | } |
2891 | |
2892 | // 0 + -0 = 0. So we can't remove addition |
2893 | if (isAdd() && type() != MIRType::Int32) { |
2894 | return this; |
2895 | } |
2896 | |
2897 | if (IsConstant(rhs, getIdentity())) { |
2898 | if (isTruncated()) { |
2899 | return MTruncateToInt32::New(alloc, lhs); |
2900 | } |
2901 | return lhs; |
2902 | } |
2903 | |
2904 | // subtraction isn't commutative. So we can't remove subtraction when lhs |
2905 | // equals 0 |
2906 | if (isSub()) { |
2907 | return this; |
2908 | } |
2909 | |
2910 | if (IsConstant(lhs, getIdentity())) { |
2911 | if (isTruncated()) { |
2912 | return MTruncateToInt32::New(alloc, rhs); |
2913 | } |
2914 | return rhs; // id op x => x |
2915 | } |
2916 | |
2917 | return this; |
2918 | } |
2919 | |
2920 | void MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc) { |
2921 | 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.cpp" , 2921); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())" ")"); do { *((volatile int*)__null) = 2921; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2922 | |
2923 | // Do not use Float32 if we can use int32. |
2924 | if (type() == MIRType::Int32) { |
2925 | return; |
2926 | } |
2927 | |
2928 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
2929 | setResultType(MIRType::Float32); |
2930 | } |
2931 | } |
2932 | |
2933 | void MMinMax::trySpecializeFloat32(TempAllocator& alloc) { |
2934 | if (type() == MIRType::Int32) { |
2935 | return; |
2936 | } |
2937 | |
2938 | MDefinition* left = lhs(); |
2939 | MDefinition* right = rhs(); |
2940 | |
2941 | if ((left->canProduceFloat32() || |
2942 | (left->isMinMax() && left->type() == MIRType::Float32)) && |
2943 | (right->canProduceFloat32() || |
2944 | (right->isMinMax() && right->type() == MIRType::Float32))) { |
2945 | setResultType(MIRType::Float32); |
2946 | } else { |
2947 | ConvertOperandsToDouble(this, alloc); |
2948 | } |
2949 | } |
2950 | |
2951 | MDefinition* MMinMax::foldsTo(TempAllocator& alloc) { |
2952 | MOZ_ASSERT(lhs()->type() == type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(lhs()->type() == type())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(lhs()->type() == type())) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("lhs()->type() == type()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2952); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == type()" ")"); do { *((volatile int*)__null) = 2952; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2953 | MOZ_ASSERT(rhs()->type() == type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(rhs()->type() == type())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(rhs()->type() == type())) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("rhs()->type() == type()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2953); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == type()" ")"); do { *((volatile int*)__null) = 2953; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2954 | |
2955 | if (lhs() == rhs()) { |
2956 | return lhs(); |
2957 | } |
2958 | |
2959 | auto foldConstants = [&alloc](MDefinition* lhs, MDefinition* rhs, |
2960 | bool isMax) -> MConstant* { |
2961 | MOZ_ASSERT(lhs->type() == rhs->type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(lhs->type() == rhs->type())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(lhs->type() == rhs->type ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("lhs->type() == rhs->type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2961); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == rhs->type()" ")"); do { *((volatile int*)__null) = 2961; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2962 | MOZ_ASSERT(lhs->toConstant()->isTypeRepresentableAsDouble())do { static_assert( mozilla::detail::AssertionConditionType< decltype(lhs->toConstant()->isTypeRepresentableAsDouble ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(lhs->toConstant()->isTypeRepresentableAsDouble ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("lhs->toConstant()->isTypeRepresentableAsDouble()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2962); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->toConstant()->isTypeRepresentableAsDouble()" ")"); do { *((volatile int*)__null) = 2962; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2963 | MOZ_ASSERT(rhs->toConstant()->isTypeRepresentableAsDouble())do { static_assert( mozilla::detail::AssertionConditionType< decltype(rhs->toConstant()->isTypeRepresentableAsDouble ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(rhs->toConstant()->isTypeRepresentableAsDouble ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("rhs->toConstant()->isTypeRepresentableAsDouble()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->toConstant()->isTypeRepresentableAsDouble()" ")"); do { *((volatile int*)__null) = 2963; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2964 | |
2965 | double lnum = lhs->toConstant()->numberToDouble(); |
2966 | double rnum = rhs->toConstant()->numberToDouble(); |
2967 | |
2968 | double result; |
2969 | if (isMax) { |
2970 | result = js::math_max_impl(lnum, rnum); |
2971 | } else { |
2972 | result = js::math_min_impl(lnum, rnum); |
2973 | } |
2974 | |
2975 | // The folded MConstant should maintain the same MIRType with the original |
2976 | // inputs. |
2977 | if (lhs->type() == MIRType::Int32) { |
2978 | int32_t cast; |
2979 | if (mozilla::NumberEqualsInt32(result, &cast)) { |
2980 | return MConstant::New(alloc, Int32Value(cast)); |
2981 | } |
2982 | return nullptr; |
2983 | } |
2984 | if (lhs->type() == MIRType::Float32) { |
2985 | return MConstant::NewFloat32(alloc, result); |
2986 | } |
2987 | MOZ_ASSERT(lhs->type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType< decltype(lhs->type() == MIRType::Double)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(lhs->type() == MIRType::Double ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "lhs->type() == MIRType::Double", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 2987); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 2987; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2988 | return MConstant::New(alloc, DoubleValue(result)); |
2989 | }; |
2990 | |
2991 | // Try to fold the following patterns when |x| and |y| are constants. |
2992 | // |
2993 | // min(min(x, z), min(y, z)) = min(min(x, y), z) |
2994 | // max(max(x, z), max(y, z)) = max(max(x, y), z) |
2995 | // max(min(x, z), min(y, z)) = min(max(x, y), z) |
2996 | // min(max(x, z), max(y, z)) = max(min(x, y), z) |
2997 | if (lhs()->isMinMax() && rhs()->isMinMax()) { |
2998 | do { |
2999 | auto* left = lhs()->toMinMax(); |
3000 | auto* right = rhs()->toMinMax(); |
3001 | if (left->isMax() != right->isMax()) { |
3002 | break; |
3003 | } |
3004 | |
3005 | MDefinition* x; |
3006 | MDefinition* y; |
3007 | MDefinition* z; |
3008 | if (left->lhs() == right->lhs()) { |
3009 | std::tie(x, y, z) = std::tuple{left->rhs(), right->rhs(), left->lhs()}; |
3010 | } else if (left->lhs() == right->rhs()) { |
3011 | std::tie(x, y, z) = std::tuple{left->rhs(), right->lhs(), left->lhs()}; |
3012 | } else if (left->rhs() == right->lhs()) { |
3013 | std::tie(x, y, z) = std::tuple{left->lhs(), right->rhs(), left->rhs()}; |
3014 | } else if (left->rhs() == right->rhs()) { |
3015 | std::tie(x, y, z) = std::tuple{left->lhs(), right->lhs(), left->rhs()}; |
3016 | } else { |
3017 | break; |
3018 | } |
3019 | |
3020 | if (!x->isConstant() || !x->toConstant()->isTypeRepresentableAsDouble() || |
3021 | !y->isConstant() || !y->toConstant()->isTypeRepresentableAsDouble()) { |
3022 | break; |
3023 | } |
3024 | |
3025 | if (auto* folded = foldConstants(x, y, isMax())) { |
3026 | block()->insertBefore(this, folded); |
3027 | return MMinMax::New(alloc, folded, z, type(), left->isMax()); |
3028 | } |
3029 | } while (false); |
3030 | } |
3031 | |
3032 | // Fold min/max operations with same inputs. |
3033 | if (lhs()->isMinMax() || rhs()->isMinMax()) { |
3034 | auto* other = lhs()->isMinMax() ? lhs()->toMinMax() : rhs()->toMinMax(); |
3035 | auto* operand = lhs()->isMinMax() ? rhs() : lhs(); |
3036 | |
3037 | if (operand == other->lhs() || operand == other->rhs()) { |
3038 | if (isMax() == other->isMax()) { |
3039 | // min(x, min(x, y)) = min(x, y) |
3040 | // max(x, max(x, y)) = max(x, y) |
3041 | return other; |
3042 | } |
3043 | if (!IsFloatingPointType(type())) { |
3044 | // When neither value is NaN: |
3045 | // max(x, min(x, y)) = x |
3046 | // min(x, max(x, y)) = x |
3047 | |
3048 | // Ensure that any bailouts that we depend on to guarantee that |y| is |
3049 | // Int32 are not removed. |
3050 | auto* otherOp = operand == other->lhs() ? other->rhs() : other->lhs(); |
3051 | otherOp->setGuardRangeBailoutsUnchecked(); |
3052 | |
3053 | return operand; |
3054 | } |
3055 | } |
3056 | } |
3057 | |
3058 | if (!lhs()->isConstant() && !rhs()->isConstant()) { |
3059 | return this; |
3060 | } |
3061 | |
3062 | // Directly apply math utility to compare the rhs() and lhs() when |
3063 | // they are both constants. |
3064 | if (lhs()->isConstant() && rhs()->isConstant()) { |
3065 | if (!lhs()->toConstant()->isTypeRepresentableAsDouble() || |
3066 | !rhs()->toConstant()->isTypeRepresentableAsDouble()) { |
3067 | return this; |
3068 | } |
3069 | |
3070 | if (auto* folded = foldConstants(lhs(), rhs(), isMax())) { |
3071 | return folded; |
3072 | } |
3073 | } |
3074 | |
3075 | MDefinition* operand = lhs()->isConstant() ? rhs() : lhs(); |
3076 | MConstant* constant = |
3077 | lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant(); |
3078 | |
3079 | if (operand->isToDouble() && |
3080 | operand->getOperand(0)->type() == MIRType::Int32) { |
3081 | // min(int32, cte >= INT32_MAX) = int32 |
3082 | if (!isMax() && constant->isTypeRepresentableAsDouble() && |
3083 | constant->numberToDouble() >= INT32_MAX(2147483647)) { |
3084 | MLimitedTruncate* limit = MLimitedTruncate::New( |
3085 | alloc, operand->getOperand(0), TruncateKind::NoTruncate); |
3086 | block()->insertBefore(this, limit); |
3087 | MToDouble* toDouble = MToDouble::New(alloc, limit); |
3088 | return toDouble; |
3089 | } |
3090 | |
3091 | // max(int32, cte <= INT32_MIN) = int32 |
3092 | if (isMax() && constant->isTypeRepresentableAsDouble() && |
3093 | constant->numberToDouble() <= INT32_MIN(-2147483647-1)) { |
3094 | MLimitedTruncate* limit = MLimitedTruncate::New( |
3095 | alloc, operand->getOperand(0), TruncateKind::NoTruncate); |
3096 | block()->insertBefore(this, limit); |
3097 | MToDouble* toDouble = MToDouble::New(alloc, limit); |
3098 | return toDouble; |
3099 | } |
3100 | } |
3101 | |
3102 | auto foldLength = [](MDefinition* operand, MConstant* constant, |
3103 | bool isMax) -> MDefinition* { |
3104 | if ((operand->isArrayLength() || operand->isArrayBufferViewLength() || |
3105 | operand->isArgumentsLength() || operand->isStringLength()) && |
3106 | constant->type() == MIRType::Int32) { |
3107 | // (Array|ArrayBufferView|Arguments|String)Length is always >= 0. |
3108 | // max(array.length, cte <= 0) = array.length |
3109 | // min(array.length, cte <= 0) = cte |
3110 | if (constant->toInt32() <= 0) { |
3111 | return isMax ? operand : constant; |
3112 | } |
3113 | } |
3114 | return nullptr; |
3115 | }; |
3116 | |
3117 | if (auto* folded = foldLength(operand, constant, isMax())) { |
3118 | return folded; |
3119 | } |
3120 | |
3121 | // Attempt to fold nested min/max operations which are produced by |
3122 | // self-hosted built-in functions. |
3123 | if (operand->isMinMax()) { |
3124 | auto* other = operand->toMinMax(); |
3125 | MOZ_ASSERT(other->lhs()->type() == type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(other->lhs()->type() == type())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(other->lhs()->type() == type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("other->lhs()->type() == type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3125); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->lhs()->type() == type()" ")"); do { *((volatile int*)__null) = 3125; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3126 | MOZ_ASSERT(other->rhs()->type() == type())do { static_assert( mozilla::detail::AssertionConditionType< decltype(other->rhs()->type() == type())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(other->rhs()->type() == type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("other->rhs()->type() == type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->rhs()->type() == type()" ")"); do { *((volatile int*)__null) = 3126; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3127 | |
3128 | MConstant* otherConstant = nullptr; |
3129 | MDefinition* otherOperand = nullptr; |
3130 | if (other->lhs()->isConstant()) { |
3131 | otherConstant = other->lhs()->toConstant(); |
3132 | otherOperand = other->rhs(); |
3133 | } else if (other->rhs()->isConstant()) { |
3134 | otherConstant = other->rhs()->toConstant(); |
3135 | otherOperand = other->lhs(); |
3136 | } |
3137 | |
3138 | if (otherConstant && constant->isTypeRepresentableAsDouble() && |
3139 | otherConstant->isTypeRepresentableAsDouble()) { |
3140 | if (isMax() == other->isMax()) { |
3141 | // Fold min(x, min(y, z)) to min(min(x, y), z) with constant min(x, y). |
3142 | // Fold max(x, max(y, z)) to max(max(x, y), z) with constant max(x, y). |
3143 | if (auto* left = foldConstants(constant, otherConstant, isMax())) { |
3144 | block()->insertBefore(this, left); |
3145 | return MMinMax::New(alloc, left, otherOperand, type(), isMax()); |
3146 | } |
3147 | } else { |
3148 | // Fold min(x, max(y, z)) to max(min(x, y), min(x, z)). |
3149 | // Fold max(x, min(y, z)) to min(max(x, y), max(x, z)). |
3150 | // |
3151 | // But only do this when min(x, z) can also be simplified. |
3152 | if (auto* right = foldLength(otherOperand, constant, isMax())) { |
3153 | if (auto* left = foldConstants(constant, otherConstant, isMax())) { |
3154 | block()->insertBefore(this, left); |
3155 | return MMinMax::New(alloc, left, right, type(), !isMax()); |
3156 | } |
3157 | } |
3158 | } |
3159 | } |
3160 | } |
3161 | |
3162 | return this; |
3163 | } |
3164 | |
3165 | #ifdef JS_JITSPEW1 |
3166 | void MMinMax::printOpcode(GenericPrinter& out) const { |
3167 | MDefinition::printOpcode(out); |
3168 | out.printf(" (%s)", isMax() ? "max" : "min"); |
3169 | } |
3170 | |
3171 | void MMinMaxArray::printOpcode(GenericPrinter& out) const { |
3172 | MDefinition::printOpcode(out); |
3173 | out.printf(" (%s)", isMax() ? "max" : "min"); |
3174 | } |
3175 | #endif |
3176 | |
3177 | MDefinition* MPow::foldsConstant(TempAllocator& alloc) { |
3178 | // Both `x` and `p` in `x^p` must be constants in order to precompute. |
3179 | if (!input()->isConstant() || !power()->isConstant()) { |
3180 | return nullptr; |
3181 | } |
3182 | if (!power()->toConstant()->isTypeRepresentableAsDouble()) { |
3183 | return nullptr; |
3184 | } |
3185 | if (!input()->toConstant()->isTypeRepresentableAsDouble()) { |
3186 | return nullptr; |
3187 | } |
3188 | |
3189 | double x = input()->toConstant()->numberToDouble(); |
3190 | double p = power()->toConstant()->numberToDouble(); |
3191 | double result = js::ecmaPow(x, p); |
3192 | if (type() == MIRType::Int32) { |
3193 | int32_t cast; |
3194 | if (!mozilla::NumberIsInt32(result, &cast)) { |
3195 | // Reject folding if the result isn't an int32, because we'll bail anyway. |
3196 | return nullptr; |
3197 | } |
3198 | return MConstant::New(alloc, Int32Value(cast)); |
3199 | } |
3200 | return MConstant::New(alloc, DoubleValue(result)); |
3201 | } |
3202 | |
3203 | MDefinition* MPow::foldsConstantPower(TempAllocator& alloc) { |
3204 | // If `p` in `x^p` isn't constant, we can't apply these folds. |
3205 | if (!power()->isConstant()) { |
3206 | return nullptr; |
3207 | } |
3208 | if (!power()->toConstant()->isTypeRepresentableAsDouble()) { |
3209 | return nullptr; |
3210 | } |
3211 | |
3212 | MOZ_ASSERT(type() == MIRType::Double || type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(type() == MIRType::Double || type() == MIRType::Int32 )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type() == MIRType::Double || type() == MIRType::Int32 ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "type() == MIRType::Double || type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double || type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3212; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3213 | |
3214 | // NOTE: The optimizations must match the optimizations used in |js::ecmaPow| |
3215 | // resp. |js::powi| to avoid differential testing issues. |
3216 | |
3217 | double pow = power()->toConstant()->numberToDouble(); |
3218 | |
3219 | // Math.pow(x, 0.5) is a sqrt with edge-case detection. |
3220 | if (pow == 0.5) { |
3221 | 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.cpp" , 3221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 3221; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3222 | return MPowHalf::New(alloc, input()); |
3223 | } |
3224 | |
3225 | // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases. |
3226 | if (pow == -0.5) { |
3227 | 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.cpp" , 3227); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 3227; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3228 | MPowHalf* half = MPowHalf::New(alloc, input()); |
3229 | block()->insertBefore(this, half); |
3230 | MConstant* one = MConstant::New(alloc, DoubleValue(1.0)); |
3231 | block()->insertBefore(this, one); |
3232 | return MDiv::New(alloc, one, half, MIRType::Double); |
3233 | } |
3234 | |
3235 | // Math.pow(x, 1) == x. |
3236 | if (pow == 1.0) { |
3237 | return input(); |
3238 | } |
3239 | |
3240 | auto multiply = [this, &alloc](MDefinition* lhs, MDefinition* rhs) { |
3241 | MMul* mul = MMul::New(alloc, lhs, rhs, type()); |
3242 | mul->setBailoutKind(bailoutKind()); |
3243 | |
3244 | // Multiplying the same number can't yield negative zero. |
3245 | mul->setCanBeNegativeZero(lhs != rhs && canBeNegativeZero()); |
3246 | return mul; |
3247 | }; |
3248 | |
3249 | // Math.pow(x, 2) == x*x. |
3250 | if (pow == 2.0) { |
3251 | return multiply(input(), input()); |
3252 | } |
3253 | |
3254 | // Math.pow(x, 3) == x*x*x. |
3255 | if (pow == 3.0) { |
3256 | MMul* mul1 = multiply(input(), input()); |
3257 | block()->insertBefore(this, mul1); |
3258 | return multiply(input(), mul1); |
3259 | } |
3260 | |
3261 | // Math.pow(x, 4) == y*y, where y = x*x. |
3262 | if (pow == 4.0) { |
3263 | MMul* y = multiply(input(), input()); |
3264 | block()->insertBefore(this, y); |
3265 | return multiply(y, y); |
3266 | } |
3267 | |
3268 | // Math.pow(x, NaN) == NaN. |
3269 | if (std::isnan(pow)) { |
3270 | return power(); |
3271 | } |
3272 | |
3273 | // No optimization |
3274 | return nullptr; |
3275 | } |
3276 | |
3277 | MDefinition* MPow::foldsTo(TempAllocator& alloc) { |
3278 | if (MDefinition* def = foldsConstant(alloc)) { |
3279 | return def; |
3280 | } |
3281 | if (MDefinition* def = foldsConstantPower(alloc)) { |
3282 | return def; |
3283 | } |
3284 | return this; |
3285 | } |
3286 | |
3287 | MDefinition* MBigIntPow::foldsTo(TempAllocator& alloc) { |
3288 | auto* base = lhs(); |
3289 | MOZ_ASSERT(base->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(base->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(base->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("base->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3289); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 3289; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3290 | |
3291 | auto* power = rhs(); |
3292 | MOZ_ASSERT(power->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(power->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(power->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("power->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "power->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 3292; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3293 | |
3294 | // |power| must be a constant. |
3295 | if (!power->isConstant()) { |
3296 | return this; |
3297 | } |
3298 | |
3299 | int32_t pow; |
3300 | if (BigInt::isInt32(power->toConstant()->toBigInt(), &pow)) { |
3301 | // x ** 1n == x. |
3302 | if (pow == 1) { |
3303 | return base; |
3304 | } |
3305 | |
3306 | // x ** 2n == x*x. |
3307 | if (pow == 2) { |
3308 | auto* mul = MBigIntMul::New(alloc, base, base); |
3309 | mul->setBailoutKind(bailoutKind()); |
3310 | return mul; |
3311 | } |
3312 | } |
3313 | |
3314 | // No optimization |
3315 | return this; |
3316 | } |
3317 | |
3318 | bool MBigIntPtrBinaryArithInstruction::isMaybeZero(MDefinition* ins) { |
3319 | MOZ_ASSERT(ins->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(ins->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::IntPtr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "ins->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 3319; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3320 | if (ins->isBigIntToIntPtr()) { |
3321 | ins = ins->toBigIntToIntPtr()->input(); |
3322 | } |
3323 | if (ins->isConstant()) { |
3324 | if (ins->type() == MIRType::IntPtr) { |
3325 | return ins->toConstant()->toIntPtr() == 0; |
3326 | } |
3327 | MOZ_ASSERT(ins->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(ins->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::BigInt ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "ins->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3327); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 3327; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3328 | return ins->toConstant()->toBigInt()->isZero(); |
3329 | } |
3330 | return true; |
3331 | } |
3332 | |
3333 | bool MBigIntPtrBinaryArithInstruction::isMaybeNegative(MDefinition* ins) { |
3334 | MOZ_ASSERT(ins->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType< decltype(ins->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::IntPtr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "ins->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3334); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 3334; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3335 | if (ins->isBigIntToIntPtr()) { |
3336 | ins = ins->toBigIntToIntPtr()->input(); |
3337 | } |
3338 | if (ins->isConstant()) { |
3339 | if (ins->type() == MIRType::IntPtr) { |
3340 | return ins->toConstant()->toIntPtr() < 0; |
3341 | } |
3342 | MOZ_ASSERT(ins->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(ins->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::BigInt ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "ins->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3342); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 3342; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3343 | return ins->toConstant()->toBigInt()->isNegative(); |
3344 | } |
3345 | return true; |
3346 | } |
3347 | |
3348 | MDefinition* MInt32ToIntPtr::foldsTo(TempAllocator& alloc) { |
3349 | MDefinition* def = input(); |
3350 | if (def->isConstant()) { |
3351 | int32_t i = def->toConstant()->toInt32(); |
3352 | return MConstant::NewIntPtr(alloc, intptr_t(i)); |
3353 | } |
3354 | |
3355 | if (def->isNonNegativeIntPtrToInt32()) { |
3356 | return def->toNonNegativeIntPtrToInt32()->input(); |
3357 | } |
3358 | |
3359 | return this; |
3360 | } |
3361 | |
3362 | bool MAbs::fallible() const { |
3363 | return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds()); |
3364 | } |
3365 | |
3366 | void MAbs::trySpecializeFloat32(TempAllocator& alloc) { |
3367 | // Do not use Float32 if we can use int32. |
3368 | if (input()->type() == MIRType::Int32) { |
3369 | return; |
3370 | } |
3371 | |
3372 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
3373 | setResultType(MIRType::Float32); |
3374 | } |
3375 | } |
3376 | |
3377 | MDefinition* MDiv::foldsTo(TempAllocator& alloc) { |
3378 | 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.cpp" , 3378); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())" ")"); do { *((volatile int*)__null) = 3378; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3379 | |
3380 | if (type() == MIRType::Int64) { |
3381 | if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) { |
3382 | return folded; |
3383 | } |
3384 | return this; |
3385 | } |
3386 | |
3387 | if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) { |
3388 | return folded; |
3389 | } |
3390 | |
3391 | if (MDefinition* folded = EvaluateExactReciprocal(alloc, this)) { |
3392 | return folded; |
3393 | } |
3394 | |
3395 | return this; |
3396 | } |
3397 | |
3398 | void MDiv::analyzeEdgeCasesForward() { |
3399 | // This is only meaningful when doing integer division. |
3400 | if (type() != MIRType::Int32) { |
3401 | return; |
3402 | } |
3403 | |
3404 | MOZ_ASSERT(lhs()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(lhs()->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(lhs()->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("lhs()->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3404; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3405 | MOZ_ASSERT(rhs()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(rhs()->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(rhs()->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("rhs()->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3405); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3405; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3406 | |
3407 | // Try removing divide by zero check |
3408 | if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) { |
3409 | canBeDivideByZero_ = false; |
3410 | } |
3411 | |
3412 | // If lhs is a constant int != INT32_MIN, then |
3413 | // negative overflow check can be skipped. |
3414 | if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(INT32_MIN(-2147483647-1))) { |
3415 | canBeNegativeOverflow_ = false; |
3416 | } |
3417 | |
3418 | // If rhs is a constant int != -1, likewise. |
3419 | if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(-1)) { |
3420 | canBeNegativeOverflow_ = false; |
3421 | } |
3422 | |
3423 | // If lhs is != 0, then negative zero check can be skipped. |
3424 | if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(0)) { |
3425 | setCanBeNegativeZero(false); |
3426 | } |
3427 | |
3428 | // If rhs is >= 0, likewise. |
3429 | if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) { |
3430 | if (rhs()->toConstant()->toInt32() >= 0) { |
3431 | setCanBeNegativeZero(false); |
3432 | } |
3433 | } |
3434 | } |
3435 | |
3436 | void MDiv::analyzeEdgeCasesBackward() { |
3437 | if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) { |
3438 | setCanBeNegativeZero(false); |
3439 | } |
3440 | } |
3441 | |
3442 | bool MDiv::fallible() const { return !isTruncated(); } |
3443 | |
3444 | MDefinition* MMod::foldsTo(TempAllocator& alloc) { |
3445 | 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.cpp" , 3445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())" ")"); do { *((volatile int*)__null) = 3445; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3446 | |
3447 | if (type() == MIRType::Int64) { |
3448 | if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) { |
3449 | return folded; |
3450 | } |
3451 | } else { |
3452 | if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) { |
3453 | return folded; |
3454 | } |
3455 | } |
3456 | return this; |
3457 | } |
3458 | |
3459 | void MMod::analyzeEdgeCasesForward() { |
3460 | // These optimizations make sense only for integer division |
3461 | if (type() != MIRType::Int32) { |
3462 | return; |
3463 | } |
3464 | |
3465 | if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) { |
3466 | canBeDivideByZero_ = false; |
3467 | } |
3468 | |
3469 | if (rhs()->isConstant()) { |
3470 | int32_t n = rhs()->toConstant()->toInt32(); |
3471 | if (n > 0 && !IsPowerOfTwo(uint32_t(n))) { |
3472 | canBePowerOfTwoDivisor_ = false; |
3473 | } |
3474 | } |
3475 | } |
3476 | |
3477 | bool MMod::fallible() const { |
3478 | return !isTruncated() && |
3479 | (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend()); |
3480 | } |
3481 | |
3482 | void MMathFunction::trySpecializeFloat32(TempAllocator& alloc) { |
3483 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
3484 | setResultType(MIRType::Float32); |
3485 | specialization_ = MIRType::Float32; |
3486 | } |
3487 | } |
3488 | |
3489 | bool MMathFunction::isFloat32Commutative() const { |
3490 | switch (function_) { |
3491 | case UnaryMathFunction::Floor: |
3492 | case UnaryMathFunction::Ceil: |
3493 | case UnaryMathFunction::Round: |
3494 | case UnaryMathFunction::Trunc: |
3495 | return true; |
3496 | default: |
3497 | return false; |
3498 | } |
3499 | } |
3500 | |
3501 | MHypot* MHypot::New(TempAllocator& alloc, const MDefinitionVector& vector) { |
3502 | uint32_t length = vector.length(); |
3503 | MHypot* hypot = new (alloc) MHypot; |
3504 | if (!hypot->init(alloc, length)) { |
3505 | return nullptr; |
3506 | } |
3507 | |
3508 | for (uint32_t i = 0; i < length; ++i) { |
3509 | hypot->initOperand(i, vector[i]); |
3510 | } |
3511 | return hypot; |
3512 | } |
3513 | |
3514 | bool MAdd::fallible() const { |
3515 | // the add is fallible if range analysis does not say that it is finite, AND |
3516 | // either the truncation analysis shows that there are non-truncated uses. |
3517 | if (truncateKind() >= TruncateKind::IndirectTruncate) { |
3518 | return false; |
3519 | } |
3520 | if (range() && range()->hasInt32Bounds()) { |
3521 | return false; |
3522 | } |
3523 | return true; |
3524 | } |
3525 | |
3526 | bool MSub::fallible() const { |
3527 | // see comment in MAdd::fallible() |
3528 | if (truncateKind() >= TruncateKind::IndirectTruncate) { |
3529 | return false; |
3530 | } |
3531 | if (range() && range()->hasInt32Bounds()) { |
3532 | return false; |
3533 | } |
3534 | return true; |
3535 | } |
3536 | |
3537 | MDefinition* MSub::foldsTo(TempAllocator& alloc) { |
3538 | MDefinition* out = MBinaryArithInstruction::foldsTo(alloc); |
3539 | if (out != this) { |
3540 | return out; |
3541 | } |
3542 | |
3543 | if (type() != MIRType::Int32) { |
3544 | return this; |
3545 | } |
3546 | |
3547 | // Optimize X - X to 0. This optimization is only valid for Int32 |
3548 | // values. Subtracting a floating point value from itself returns |
3549 | // NaN when the operand is either Infinity or NaN. |
3550 | if (lhs() == rhs()) { |
3551 | // Ensure that any bailouts that we depend on to guarantee that X |
3552 | // is Int32 are not removed. |
3553 | lhs()->setGuardRangeBailoutsUnchecked(); |
3554 | return MConstant::New(alloc, Int32Value(0)); |
3555 | } |
3556 | |
3557 | return this; |
3558 | } |
3559 | |
3560 | MDefinition* MMul::foldsTo(TempAllocator& alloc) { |
3561 | MDefinition* out = MBinaryArithInstruction::foldsTo(alloc); |
3562 | if (out != this) { |
3563 | return out; |
3564 | } |
3565 | |
3566 | if (type() != MIRType::Int32) { |
3567 | return this; |
3568 | } |
3569 | |
3570 | if (lhs() == rhs()) { |
3571 | setCanBeNegativeZero(false); |
3572 | } |
3573 | |
3574 | return this; |
3575 | } |
3576 | |
3577 | void MMul::analyzeEdgeCasesForward() { |
3578 | // Try to remove the check for negative zero |
3579 | // This only makes sense when using the integer multiplication |
3580 | if (type() != MIRType::Int32) { |
3581 | return; |
3582 | } |
3583 | |
3584 | // If lhs is > 0, no need for negative zero check. |
3585 | if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) { |
3586 | if (lhs()->toConstant()->toInt32() > 0) { |
3587 | setCanBeNegativeZero(false); |
3588 | } |
3589 | } |
3590 | |
3591 | // If rhs is > 0, likewise. |
3592 | if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) { |
3593 | if (rhs()->toConstant()->toInt32() > 0) { |
3594 | setCanBeNegativeZero(false); |
3595 | } |
3596 | } |
3597 | } |
3598 | |
3599 | void MMul::analyzeEdgeCasesBackward() { |
3600 | if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) { |
3601 | setCanBeNegativeZero(false); |
3602 | } |
3603 | } |
3604 | |
3605 | bool MMul::canOverflow() const { |
3606 | if (isTruncated()) { |
3607 | return false; |
3608 | } |
3609 | return !range() || !range()->hasInt32Bounds(); |
3610 | } |
3611 | |
3612 | bool MUrsh::fallible() const { |
3613 | if (bailoutsDisabled()) { |
3614 | return false; |
3615 | } |
3616 | return !range() || !range()->hasInt32Bounds(); |
3617 | } |
3618 | |
3619 | MIRType MCompare::inputType() { |
3620 | switch (compareType_) { |
3621 | case Compare_Undefined: |
3622 | return MIRType::Undefined; |
3623 | case Compare_Null: |
3624 | return MIRType::Null; |
3625 | case Compare_UInt32: |
3626 | case Compare_Int32: |
3627 | return MIRType::Int32; |
3628 | case Compare_IntPtr: |
3629 | case Compare_UIntPtr: |
3630 | return MIRType::IntPtr; |
3631 | case Compare_Double: |
3632 | return MIRType::Double; |
3633 | case Compare_Float32: |
3634 | return MIRType::Float32; |
3635 | case Compare_String: |
3636 | return MIRType::String; |
3637 | case Compare_Symbol: |
3638 | return MIRType::Symbol; |
3639 | case Compare_Object: |
3640 | return MIRType::Object; |
3641 | case Compare_BigInt: |
3642 | case Compare_BigInt_Int32: |
3643 | case Compare_BigInt_Double: |
3644 | case Compare_BigInt_String: |
3645 | return MIRType::BigInt; |
3646 | default: |
3647 | MOZ_CRASH("No known conversion")do { do { } while (false); MOZ_ReportCrash("" "No known conversion" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3647); AnnotateMozCrashReason("MOZ_CRASH(" "No known conversion" ")"); do { *((volatile int*)__null) = 3647; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
3648 | } |
3649 | } |
3650 | |
3651 | static inline bool MustBeUInt32(MDefinition* def, MDefinition** pwrapped) { |
3652 | if (def->isUrsh()) { |
3653 | *pwrapped = def->toUrsh()->lhs(); |
3654 | MDefinition* rhs = def->toUrsh()->rhs(); |
3655 | return def->toUrsh()->bailoutsDisabled() && rhs->maybeConstantValue() && |
3656 | rhs->maybeConstantValue()->isInt32(0); |
3657 | } |
3658 | |
3659 | if (MConstant* defConst = def->maybeConstantValue()) { |
3660 | *pwrapped = defConst; |
3661 | return defConst->type() == MIRType::Int32 && defConst->toInt32() >= 0; |
3662 | } |
3663 | |
3664 | *pwrapped = nullptr; // silence GCC warning |
3665 | return false; |
3666 | } |
3667 | |
3668 | /* static */ |
3669 | bool MBinaryInstruction::unsignedOperands(MDefinition* left, |
3670 | MDefinition* right) { |
3671 | MDefinition* replace; |
3672 | if (!MustBeUInt32(left, &replace)) { |
3673 | return false; |
3674 | } |
3675 | if (replace->type() != MIRType::Int32) { |
3676 | return false; |
3677 | } |
3678 | if (!MustBeUInt32(right, &replace)) { |
3679 | return false; |
3680 | } |
3681 | if (replace->type() != MIRType::Int32) { |
3682 | return false; |
3683 | } |
3684 | return true; |
3685 | } |
3686 | |
3687 | bool MBinaryInstruction::unsignedOperands() { |
3688 | return unsignedOperands(getOperand(0), getOperand(1)); |
3689 | } |
3690 | |
3691 | void MBinaryInstruction::replaceWithUnsignedOperands() { |
3692 | MOZ_ASSERT(unsignedOperands())do { static_assert( mozilla::detail::AssertionConditionType< decltype(unsignedOperands())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(unsignedOperands()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("unsignedOperands()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3692); AnnotateMozCrashReason("MOZ_ASSERT" "(" "unsignedOperands()" ")"); do { *((volatile int*)__null) = 3692; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3693 | |
3694 | for (size_t i = 0; i < numOperands(); i++) { |
3695 | MDefinition* replace; |
3696 | MustBeUInt32(getOperand(i), &replace); |
3697 | if (replace == getOperand(i)) { |
3698 | continue; |
3699 | } |
3700 | |
3701 | getOperand(i)->setImplicitlyUsedUnchecked(); |
3702 | replaceOperand(i, replace); |
3703 | } |
3704 | } |
3705 | |
3706 | MDefinition* MBitNot::foldsTo(TempAllocator& alloc) { |
3707 | if (type() == MIRType::Int64) { |
3708 | return this; |
3709 | } |
3710 | 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.cpp" , 3710); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3710; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3711 | |
3712 | MDefinition* input = getOperand(0); |
3713 | |
3714 | if (input->isConstant()) { |
3715 | js::Value v = Int32Value(~(input->toConstant()->toInt32())); |
3716 | return MConstant::New(alloc, v); |
3717 | } |
3718 | |
3719 | if (input->isBitNot()) { |
3720 | MOZ_ASSERT(input->toBitNot()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(input->toBitNot()->type() == MIRType::Int32)> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(input->toBitNot()->type() == MIRType::Int32))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("input->toBitNot()->type() == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3720); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3720; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3721 | MOZ_ASSERT(input->toBitNot()->getOperand(0)->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(input->toBitNot()->getOperand(0)->type() == MIRType::Int32)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(input->toBitNot()->getOperand (0)->type() == MIRType::Int32))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("input->toBitNot()->getOperand(0)->type() == MIRType::Int32" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->getOperand(0)->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3721; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3722 | return MTruncateToInt32::New(alloc, |
3723 | input->toBitNot()->input()); // ~~x => x | 0 |
3724 | } |
3725 | |
3726 | return this; |
3727 | } |
3728 | |
3729 | static void AssertKnownClass(TempAllocator& alloc, MInstruction* ins, |
3730 | MDefinition* obj) { |
3731 | #ifdef DEBUG1 |
3732 | const JSClass* clasp = GetObjectKnownJSClass(obj); |
3733 | MOZ_ASSERT(clasp)do { static_assert( mozilla::detail::AssertionConditionType< decltype(clasp)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(clasp))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("clasp", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3733); AnnotateMozCrashReason("MOZ_ASSERT" "(" "clasp" ")") ; do { *((volatile int*)__null) = 3733; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3734 | |
3735 | auto* assert = MAssertClass::New(alloc, obj, clasp); |
3736 | ins->block()->insertBefore(ins, assert); |
3737 | #endif |
3738 | } |
3739 | |
3740 | MDefinition* MBoxNonStrictThis::foldsTo(TempAllocator& alloc) { |
3741 | MDefinition* in = input(); |
3742 | if (in->isBox()) { |
3743 | in = in->toBox()->input(); |
3744 | } |
3745 | |
3746 | if (in->type() == MIRType::Object) { |
3747 | return in; |
3748 | } |
3749 | |
3750 | return this; |
3751 | } |
3752 | |
3753 | AliasSet MLoadArgumentsObjectArg::getAliasSet() const { |
3754 | return AliasSet::Load(AliasSet::Any); |
3755 | } |
3756 | |
3757 | AliasSet MLoadArgumentsObjectArgHole::getAliasSet() const { |
3758 | return AliasSet::Load(AliasSet::Any); |
3759 | } |
3760 | |
3761 | AliasSet MInArgumentsObjectArg::getAliasSet() const { |
3762 | // Loads |arguments.length|, but not the actual element, so we can use the |
3763 | // same alias-set as MArgumentsObjectLength. |
3764 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
3765 | AliasSet::DynamicSlot); |
3766 | } |
3767 | |
3768 | AliasSet MArgumentsObjectLength::getAliasSet() const { |
3769 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
3770 | AliasSet::DynamicSlot); |
3771 | } |
3772 | |
3773 | bool MGuardArgumentsObjectFlags::congruentTo(const MDefinition* ins) const { |
3774 | if (!ins->isGuardArgumentsObjectFlags() || |
3775 | ins->toGuardArgumentsObjectFlags()->flags() != flags()) { |
3776 | return false; |
3777 | } |
3778 | return congruentIfOperandsEqual(ins); |
3779 | } |
3780 | |
3781 | AliasSet MGuardArgumentsObjectFlags::getAliasSet() const { |
3782 | // The flags are packed with the length in a fixed private slot. |
3783 | return AliasSet::Load(AliasSet::FixedSlot); |
3784 | } |
3785 | |
3786 | MDefinition* MIdToStringOrSymbol::foldsTo(TempAllocator& alloc) { |
3787 | if (idVal()->isBox()) { |
3788 | auto* input = idVal()->toBox()->input(); |
3789 | MIRType idType = input->type(); |
3790 | if (idType == MIRType::String || idType == MIRType::Symbol) { |
3791 | return idVal(); |
3792 | } |
3793 | if (idType == MIRType::Int32) { |
3794 | auto* toString = |
3795 | MToString::New(alloc, input, MToString::SideEffectHandling::Bailout); |
3796 | block()->insertBefore(this, toString); |
3797 | |
3798 | return MBox::New(alloc, toString); |
3799 | } |
3800 | } |
3801 | |
3802 | return this; |
3803 | } |
3804 | |
3805 | MDefinition* MReturnFromCtor::foldsTo(TempAllocator& alloc) { |
3806 | MDefinition* rval = value(); |
3807 | if (rval->isBox()) { |
3808 | rval = rval->toBox()->input(); |
3809 | } |
3810 | |
3811 | if (rval->type() == MIRType::Object) { |
3812 | return rval; |
3813 | } |
3814 | |
3815 | if (rval->type() != MIRType::Value) { |
3816 | return object(); |
3817 | } |
3818 | |
3819 | return this; |
3820 | } |
3821 | |
3822 | MDefinition* MTypeOf::foldsTo(TempAllocator& alloc) { |
3823 | MDefinition* unboxed = input(); |
3824 | if (unboxed->isBox()) { |
3825 | unboxed = unboxed->toBox()->input(); |
3826 | } |
3827 | |
3828 | JSType type; |
3829 | switch (unboxed->type()) { |
3830 | case MIRType::Double: |
3831 | case MIRType::Float32: |
3832 | case MIRType::Int32: |
3833 | type = JSTYPE_NUMBER; |
3834 | break; |
3835 | case MIRType::String: |
3836 | type = JSTYPE_STRING; |
3837 | break; |
3838 | case MIRType::Symbol: |
3839 | type = JSTYPE_SYMBOL; |
3840 | break; |
3841 | case MIRType::BigInt: |
3842 | type = JSTYPE_BIGINT; |
3843 | break; |
3844 | case MIRType::Null: |
3845 | type = JSTYPE_OBJECT; |
3846 | break; |
3847 | case MIRType::Undefined: |
3848 | type = JSTYPE_UNDEFINED; |
3849 | break; |
3850 | case MIRType::Boolean: |
3851 | type = JSTYPE_BOOLEAN; |
3852 | break; |
3853 | case MIRType::Object: { |
3854 | KnownClass known = GetObjectKnownClass(unboxed); |
3855 | if (known != KnownClass::None) { |
3856 | if (known == KnownClass::Function) { |
3857 | type = JSTYPE_FUNCTION; |
3858 | } else { |
3859 | type = JSTYPE_OBJECT; |
3860 | } |
3861 | |
3862 | AssertKnownClass(alloc, this, unboxed); |
3863 | break; |
3864 | } |
3865 | [[fallthrough]]; |
3866 | } |
3867 | default: |
3868 | return this; |
3869 | } |
3870 | |
3871 | return MConstant::New(alloc, Int32Value(static_cast<int32_t>(type))); |
3872 | } |
3873 | |
3874 | MDefinition* MTypeOfName::foldsTo(TempAllocator& alloc) { |
3875 | MOZ_ASSERT(input()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(input()->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(input()->type() == MIRType ::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("input()->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3875; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3876 | |
3877 | if (!input()->isConstant()) { |
3878 | return this; |
3879 | } |
3880 | |
3881 | static_assert(JSTYPE_UNDEFINED == 0); |
3882 | |
3883 | int32_t type = input()->toConstant()->toInt32(); |
3884 | MOZ_ASSERT(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT)do { static_assert( mozilla::detail::AssertionConditionType< decltype(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3884); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT" ")"); do { *((volatile int*)__null) = 3884; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3885 | |
3886 | JSString* name = |
3887 | TypeName(static_cast<JSType>(type), GetJitContext()->runtime->names()); |
3888 | return MConstant::New(alloc, StringValue(name)); |
3889 | } |
3890 | |
3891 | MUrsh* MUrsh::NewWasm(TempAllocator& alloc, MDefinition* left, |
3892 | MDefinition* right, MIRType type) { |
3893 | MUrsh* ins = new (alloc) MUrsh(left, right, type); |
3894 | |
3895 | // Since Ion has no UInt32 type, we use Int32 and we have a special |
3896 | // exception to the type rules: we can return values in |
3897 | // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type |
3898 | // without bailing out. This is necessary because Ion has no UInt32 |
3899 | // type and we can't have bailouts in wasm code. |
3900 | ins->bailoutsDisabled_ = true; |
3901 | |
3902 | return ins; |
3903 | } |
3904 | |
3905 | MResumePoint* MResumePoint::New(TempAllocator& alloc, MBasicBlock* block, |
3906 | jsbytecode* pc, ResumeMode mode) { |
3907 | MResumePoint* resume = new (alloc) MResumePoint(block, pc, mode); |
3908 | if (!resume->init(alloc)) { |
3909 | block->discardPreAllocatedResumePoint(resume); |
3910 | return nullptr; |
3911 | } |
3912 | resume->inherit(block); |
3913 | return resume; |
3914 | } |
3915 | |
3916 | MResumePoint::MResumePoint(MBasicBlock* block, jsbytecode* pc, ResumeMode mode) |
3917 | : MNode(block, Kind::ResumePoint), |
3918 | pc_(pc), |
3919 | instruction_(nullptr), |
3920 | mode_(mode) { |
3921 | block->addResumePoint(this); |
3922 | } |
3923 | |
3924 | bool MResumePoint::init(TempAllocator& alloc) { |
3925 | return operands_.init(alloc, block()->stackDepth()); |
3926 | } |
3927 | |
3928 | MResumePoint* MResumePoint::caller() const { |
3929 | return block()->callerResumePoint(); |
3930 | } |
3931 | |
3932 | void MResumePoint::inherit(MBasicBlock* block) { |
3933 | // FixedList doesn't initialize its elements, so do unchecked inits. |
3934 | for (size_t i = 0; i < stackDepth(); i++) { |
3935 | initOperand(i, block->getSlot(i)); |
3936 | } |
3937 | } |
3938 | |
3939 | void MResumePoint::addStore(TempAllocator& alloc, MDefinition* store, |
3940 | const MResumePoint* cache) { |
3941 | MOZ_ASSERT(block()->outerResumePoint() != this)do { static_assert( mozilla::detail::AssertionConditionType< decltype(block()->outerResumePoint() != this)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(block()->outerResumePoint() != this))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("block()->outerResumePoint() != this" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3941); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->outerResumePoint() != this" ")"); do { *((volatile int*)__null) = 3941; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3942 | MOZ_ASSERT_IF(cache, !cache->stores_.empty())do { if (cache) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(!cache->stores_.empty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!cache->stores_.empty())) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!cache->stores_.empty()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3942); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!cache->stores_.empty()" ")"); do { *((volatile int*)__null) = 3942; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
3943 | |
3944 | if (cache && cache->stores_.begin()->operand == store) { |
3945 | // If the last resume point had the same side-effect stack, then we can |
3946 | // reuse the current side effect without cloning it. This is a simple |
3947 | // way to share common context by making a spaghetti stack. |
3948 | if (++cache->stores_.begin() == stores_.begin()) { |
3949 | stores_.copy(cache->stores_); |
3950 | return; |
3951 | } |
3952 | } |
3953 | |
3954 | // Ensure that the store would not be deleted by DCE. |
3955 | MOZ_ASSERT(store->isEffectful())do { static_assert( mozilla::detail::AssertionConditionType< decltype(store->isEffectful())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(store->isEffectful()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("store->isEffectful()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 3955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "store->isEffectful()" ")"); do { *((volatile int*)__null) = 3955; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3956 | |
3957 | MStoreToRecover* top = new (alloc) MStoreToRecover(store); |
3958 | stores_.push(top); |
3959 | } |
3960 | |
3961 | #ifdef JS_JITSPEW1 |
3962 | void MResumePoint::dump(GenericPrinter& out) const { |
3963 | out.printf("resumepoint mode="); |
3964 | |
3965 | switch (mode()) { |
3966 | case ResumeMode::ResumeAt: |
3967 | if (instruction_) { |
3968 | out.printf("ResumeAt(%u)", instruction_->id()); |
3969 | } else { |
3970 | out.printf("ResumeAt"); |
3971 | } |
3972 | break; |
3973 | default: |
3974 | out.put(ResumeModeToString(mode())); |
3975 | break; |
3976 | } |
3977 | |
3978 | if (MResumePoint* c = caller()) { |
3979 | out.printf(" (caller in block%u)", c->block()->id()); |
3980 | } |
3981 | |
3982 | for (size_t i = 0; i < numOperands(); i++) { |
3983 | out.printf(" "); |
3984 | if (operands_[i].hasProducer()) { |
3985 | getOperand(i)->printName(out); |
3986 | } else { |
3987 | out.printf("(null)"); |
3988 | } |
3989 | } |
3990 | out.printf("\n"); |
3991 | } |
3992 | |
3993 | void MResumePoint::dump() const { |
3994 | Fprinter out(stderrstderr); |
3995 | dump(out); |
3996 | out.finish(); |
3997 | } |
3998 | #endif |
3999 | |
4000 | bool MResumePoint::isObservableOperand(MUse* u) const { |
4001 | return isObservableOperand(indexOf(u)); |
4002 | } |
4003 | |
4004 | bool MResumePoint::isObservableOperand(size_t index) const { |
4005 | return block()->info().isObservableSlot(index); |
4006 | } |
4007 | |
4008 | bool MResumePoint::isRecoverableOperand(MUse* u) const { |
4009 | return block()->info().isRecoverableOperand(indexOf(u)); |
4010 | } |
4011 | |
4012 | MDefinition* MBigIntToIntPtr::foldsTo(TempAllocator& alloc) { |
4013 | MDefinition* def = input(); |
4014 | |
4015 | // If the operand converts an IntPtr to BigInt, drop both conversions. |
4016 | if (def->isIntPtrToBigInt()) { |
4017 | return def->toIntPtrToBigInt()->input(); |
4018 | } |
4019 | |
4020 | // Fold this operation if the input operand is constant. |
4021 | if (def->isConstant()) { |
4022 | BigInt* bigInt = def->toConstant()->toBigInt(); |
4023 | intptr_t i; |
4024 | if (BigInt::isIntPtr(bigInt, &i)) { |
4025 | return MConstant::NewIntPtr(alloc, i); |
4026 | } |
4027 | } |
4028 | |
4029 | // Fold BigIntToIntPtr(Int64ToBigInt(int64)) to Int64ToIntPtr(int64) |
4030 | if (def->isInt64ToBigInt()) { |
4031 | auto* toBigInt = def->toInt64ToBigInt(); |
4032 | return MInt64ToIntPtr::New(alloc, toBigInt->input(), |
4033 | toBigInt->elementType()); |
4034 | } |
4035 | |
4036 | return this; |
4037 | } |
4038 | |
4039 | MDefinition* MIntPtrToBigInt::foldsTo(TempAllocator& alloc) { |
4040 | MDefinition* def = input(); |
4041 | |
4042 | // If the operand converts a BigInt to IntPtr, drop both conversions. |
4043 | if (def->isBigIntToIntPtr()) { |
4044 | return def->toBigIntToIntPtr()->input(); |
4045 | } |
4046 | |
4047 | return this; |
4048 | } |
4049 | |
4050 | MDefinition* MTruncateBigIntToInt64::foldsTo(TempAllocator& alloc) { |
4051 | MDefinition* input = getOperand(0); |
4052 | |
4053 | if (input->isBox()) { |
4054 | input = input->getOperand(0); |
4055 | } |
4056 | |
4057 | // If the operand converts an I64 to BigInt, drop both conversions. |
4058 | if (input->isInt64ToBigInt()) { |
4059 | return input->getOperand(0); |
4060 | } |
4061 | |
4062 | // If the operand converts an I32 to BigInt, extend the I32 to I64. |
4063 | if (input->isInt32ToBigInt()) { |
4064 | auto* int32 = input->toInt32ToBigInt()->input(); |
4065 | if (int32->isConstant()) { |
4066 | int32_t c = int32->toConstant()->toInt32(); |
4067 | return MConstant::NewInt64(alloc, int64_t(c)); |
4068 | } |
4069 | return MExtendInt32ToInt64::New(alloc, int32, /* isUnsigned = */ false); |
4070 | } |
4071 | |
4072 | // If the operand is an IntPtr, extend the IntPtr to I64. |
4073 | if (input->isIntPtrToBigInt()) { |
4074 | auto* intPtr = input->toIntPtrToBigInt()->input(); |
4075 | return MIntPtrToInt64::New(alloc, intPtr); |
4076 | } |
4077 | |
4078 | // Fold this operation if the input operand is constant. |
4079 | if (input->isConstant()) { |
4080 | return MConstant::NewInt64( |
4081 | alloc, BigInt::toInt64(input->toConstant()->toBigInt())); |
4082 | } |
4083 | |
4084 | return this; |
4085 | } |
4086 | |
4087 | MDefinition* MToInt64::foldsTo(TempAllocator& alloc) { |
4088 | MDefinition* input = getOperand(0); |
4089 | |
4090 | if (input->isBox()) { |
4091 | input = input->getOperand(0); |
4092 | } |
4093 | |
4094 | // Unwrap MInt64ToBigInt: MToInt64(MInt64ToBigInt(int64)) = int64. |
4095 | if (input->isInt64ToBigInt()) { |
4096 | return input->getOperand(0); |
4097 | } |
4098 | |
4099 | // Unwrap Int32ToBigInt: |
4100 | // MToInt64(MInt32ToBigInt(int32)) = MExtendInt32ToInt64(int32). |
4101 | if (input->isInt32ToBigInt()) { |
4102 | auto* int32 = input->toInt32ToBigInt()->input(); |
4103 | if (int32->isConstant()) { |
4104 | int32_t c = int32->toConstant()->toInt32(); |
4105 | return MConstant::NewInt64(alloc, int64_t(c)); |
4106 | } |
4107 | return MExtendInt32ToInt64::New(alloc, int32, /* isUnsigned = */ false); |
4108 | } |
4109 | |
4110 | // When the input is an Int64 already, just return it. |
4111 | if (input->type() == MIRType::Int64) { |
4112 | return input; |
4113 | } |
4114 | |
4115 | // Fold this operation if the input operand is constant. |
4116 | if (input->isConstant()) { |
4117 | switch (input->type()) { |
4118 | case MIRType::Boolean: |
4119 | return MConstant::NewInt64(alloc, input->toConstant()->toBoolean()); |
4120 | default: |
4121 | break; |
4122 | } |
4123 | } |
4124 | |
4125 | return this; |
4126 | } |
4127 | |
4128 | MDefinition* MToNumberInt32::foldsTo(TempAllocator& alloc) { |
4129 | // Fold this operation if the input operand is constant. |
4130 | if (MConstant* cst = input()->maybeConstantValue()) { |
4131 | switch (cst->type()) { |
4132 | case MIRType::Null: |
4133 | if (conversion() == IntConversionInputKind::Any) { |
4134 | return MConstant::New(alloc, Int32Value(0)); |
4135 | } |
4136 | break; |
4137 | case MIRType::Boolean: |
4138 | if (conversion() == IntConversionInputKind::Any) { |
4139 | return MConstant::New(alloc, Int32Value(cst->toBoolean())); |
4140 | } |
4141 | break; |
4142 | case MIRType::Int32: |
4143 | return MConstant::New(alloc, Int32Value(cst->toInt32())); |
4144 | case MIRType::Float32: |
4145 | case MIRType::Double: |
4146 | int32_t ival; |
4147 | // Only the value within the range of Int32 can be substituted as |
4148 | // constant. |
4149 | if (mozilla::NumberIsInt32(cst->numberToDouble(), &ival)) { |
4150 | return MConstant::New(alloc, Int32Value(ival)); |
4151 | } |
4152 | break; |
4153 | default: |
4154 | break; |
4155 | } |
4156 | } |
4157 | |
4158 | MDefinition* input = getOperand(0); |
4159 | if (input->isBox()) { |
4160 | input = input->toBox()->input(); |
4161 | } |
4162 | |
4163 | // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh |
4164 | // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js, |
4165 | // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator |
4166 | // is folded to a MTruncateToInt32 node, which will result in this MIR: |
4167 | // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that |
4168 | // the MUrsh node's type is int32 (since uint32 is not implemented), and |
4169 | // that would fold the MTruncateToInt32 node. This will make the modulo |
4170 | // unsigned, while is should have been signed. |
4171 | if (input->type() == MIRType::Int32 && !IsUint32Type(input)) { |
4172 | return input; |
4173 | } |
4174 | |
4175 | return this; |
4176 | } |
4177 | |
4178 | MDefinition* MBooleanToInt32::foldsTo(TempAllocator& alloc) { |
4179 | MDefinition* input = getOperand(0); |
4180 | MOZ_ASSERT(input->type() == MIRType::Boolean)do { static_assert( mozilla::detail::AssertionConditionType< decltype(input->type() == MIRType::Boolean)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(input->type() == MIRType:: Boolean))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("input->type() == MIRType::Boolean", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4180); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Boolean" ")"); do { *((volatile int*)__null) = 4180; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4181 | |
4182 | if (input->isConstant()) { |
4183 | return MConstant::New(alloc, Int32Value(input->toConstant()->toBoolean())); |
4184 | } |
4185 | |
4186 | return this; |
4187 | } |
4188 | |
4189 | void MToNumberInt32::analyzeEdgeCasesBackward() { |
4190 | if (!NeedNegativeZeroCheck(this)) { |
4191 | setNeedsNegativeZeroCheck(false); |
4192 | } |
4193 | } |
4194 | |
4195 | MDefinition* MTruncateToInt32::foldsTo(TempAllocator& alloc) { |
4196 | MDefinition* input = getOperand(0); |
4197 | if (input->isBox()) { |
4198 | input = input->getOperand(0); |
4199 | } |
4200 | |
4201 | // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh |
4202 | // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js, |
4203 | // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator |
4204 | // is folded to a MTruncateToInt32 node, which will result in this MIR: |
4205 | // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that |
4206 | // the MUrsh node's type is int32 (since uint32 is not implemented), and |
4207 | // that would fold the MTruncateToInt32 node. This will make the modulo |
4208 | // unsigned, while is should have been signed. |
4209 | if (input->type() == MIRType::Int32 && !IsUint32Type(input)) { |
4210 | return input; |
4211 | } |
4212 | |
4213 | if (input->type() == MIRType::Double && input->isConstant()) { |
4214 | int32_t ret = ToInt32(input->toConstant()->toDouble()); |
4215 | return MConstant::New(alloc, Int32Value(ret)); |
4216 | } |
4217 | |
4218 | return this; |
4219 | } |
4220 | |
4221 | MDefinition* MWrapInt64ToInt32::foldsTo(TempAllocator& alloc) { |
4222 | MDefinition* input = this->input(); |
4223 | if (input->isConstant()) { |
4224 | uint64_t c = input->toConstant()->toInt64(); |
4225 | int32_t output = bottomHalf() ? int32_t(c) : int32_t(c >> 32); |
4226 | return MConstant::New(alloc, Int32Value(output)); |
4227 | } |
4228 | |
4229 | return this; |
4230 | } |
4231 | |
4232 | MDefinition* MExtendInt32ToInt64::foldsTo(TempAllocator& alloc) { |
4233 | MDefinition* input = this->input(); |
4234 | if (input->isConstant()) { |
4235 | int32_t c = input->toConstant()->toInt32(); |
4236 | int64_t res = isUnsigned() ? int64_t(uint32_t(c)) : int64_t(c); |
4237 | return MConstant::NewInt64(alloc, res); |
4238 | } |
4239 | |
4240 | return this; |
4241 | } |
4242 | |
4243 | MDefinition* MSignExtendInt32::foldsTo(TempAllocator& alloc) { |
4244 | MDefinition* input = this->input(); |
4245 | if (input->isConstant()) { |
4246 | int32_t c = input->toConstant()->toInt32(); |
4247 | int32_t res; |
4248 | switch (mode_) { |
4249 | case Byte: |
4250 | res = int32_t(int8_t(c & 0xFF)); |
4251 | break; |
4252 | case Half: |
4253 | res = int32_t(int16_t(c & 0xFFFF)); |
4254 | break; |
4255 | } |
4256 | return MConstant::New(alloc, Int32Value(res)); |
4257 | } |
4258 | |
4259 | return this; |
4260 | } |
4261 | |
4262 | MDefinition* MSignExtendInt64::foldsTo(TempAllocator& alloc) { |
4263 | MDefinition* input = this->input(); |
4264 | if (input->isConstant()) { |
4265 | int64_t c = input->toConstant()->toInt64(); |
4266 | int64_t res; |
4267 | switch (mode_) { |
4268 | case Byte: |
4269 | res = int64_t(int8_t(c & 0xFF)); |
4270 | break; |
4271 | case Half: |
4272 | res = int64_t(int16_t(c & 0xFFFF)); |
4273 | break; |
4274 | case Word: |
4275 | res = int64_t(int32_t(c & 0xFFFFFFFFU)); |
4276 | break; |
4277 | } |
4278 | return MConstant::NewInt64(alloc, res); |
4279 | } |
4280 | |
4281 | return this; |
4282 | } |
4283 | |
4284 | MDefinition* MToDouble::foldsTo(TempAllocator& alloc) { |
4285 | MDefinition* input = getOperand(0); |
4286 | if (input->isBox()) { |
4287 | input = input->getOperand(0); |
4288 | } |
4289 | |
4290 | if (input->type() == MIRType::Double) { |
4291 | return input; |
4292 | } |
4293 | |
4294 | if (input->isConstant() && |
4295 | input->toConstant()->isTypeRepresentableAsDouble()) { |
4296 | return MConstant::New(alloc, |
4297 | DoubleValue(input->toConstant()->numberToDouble())); |
4298 | } |
4299 | |
4300 | return this; |
4301 | } |
4302 | |
4303 | MDefinition* MToFloat32::foldsTo(TempAllocator& alloc) { |
4304 | MDefinition* input = getOperand(0); |
4305 | if (input->isBox()) { |
4306 | input = input->getOperand(0); |
4307 | } |
4308 | |
4309 | if (input->type() == MIRType::Float32) { |
4310 | return input; |
4311 | } |
4312 | |
4313 | // If x is a Float32, Float32(Double(x)) == x |
4314 | if (!mustPreserveNaN_ && input->isToDouble() && |
4315 | input->toToDouble()->input()->type() == MIRType::Float32) { |
4316 | return input->toToDouble()->input(); |
4317 | } |
4318 | |
4319 | if (input->isConstant() && |
4320 | input->toConstant()->isTypeRepresentableAsDouble()) { |
4321 | return MConstant::NewFloat32(alloc, |
4322 | float(input->toConstant()->numberToDouble())); |
4323 | } |
4324 | |
4325 | // Fold ToFloat32(ToDouble(int32)) to ToFloat32(int32). |
4326 | if (input->isToDouble() && |
4327 | input->toToDouble()->input()->type() == MIRType::Int32) { |
4328 | return MToFloat32::New(alloc, input->toToDouble()->input()); |
4329 | } |
4330 | |
4331 | return this; |
4332 | } |
4333 | |
4334 | MDefinition* MToFloat16::foldsTo(TempAllocator& alloc) { |
4335 | MDefinition* in = input(); |
4336 | if (in->isBox()) { |
4337 | in = in->toBox()->input(); |
4338 | } |
4339 | |
4340 | if (in->isConstant()) { |
4341 | auto* cst = in->toConstant(); |
4342 | if (cst->isTypeRepresentableAsDouble()) { |
4343 | double num = cst->numberToDouble(); |
4344 | return MConstant::NewFloat32(alloc, static_cast<float>(js::float16{num})); |
4345 | } |
4346 | } |
4347 | |
4348 | auto isFloat16 = [](auto* def) -> MDefinition* { |
4349 | // ToFloat16(ToDouble(float16)) => float16 |
4350 | // ToFloat16(ToFloat32(float16)) => float16 |
4351 | if (def->isToDouble()) { |
4352 | def = def->toToDouble()->input(); |
4353 | } else if (def->isToFloat32()) { |
4354 | def = def->toToFloat32()->input(); |
4355 | } |
4356 | |
4357 | // ToFloat16(ToFloat16(x)) => ToFloat16(x) |
4358 | if (def->isToFloat16()) { |
4359 | return def; |
4360 | } |
4361 | |
4362 | // ToFloat16(LoadFloat16(x)) => LoadFloat16(x) |
4363 | if (def->isLoadUnboxedScalar() && |
4364 | def->toLoadUnboxedScalar()->storageType() == Scalar::Float16) { |
4365 | return def; |
4366 | } |
4367 | if (def->isLoadDataViewElement() && |
4368 | def->toLoadDataViewElement()->storageType() == Scalar::Float16) { |
4369 | return def; |
4370 | } |
4371 | return nullptr; |
4372 | }; |
4373 | |
4374 | // Fold loads which are guaranteed to return Float16. |
4375 | if (auto* f16 = isFloat16(in)) { |
4376 | return f16; |
4377 | } |
4378 | |
4379 | // Fold ToFloat16(ToDouble(float32)) to ToFloat16(float32). |
4380 | // Fold ToFloat16(ToDouble(int32)) to ToFloat16(int32). |
4381 | if (in->isToDouble()) { |
4382 | auto* toDoubleInput = in->toToDouble()->input(); |
4383 | if (toDoubleInput->type() == MIRType::Float32 || |
4384 | toDoubleInput->type() == MIRType::Int32) { |
4385 | return MToFloat16::New(alloc, toDoubleInput); |
4386 | } |
4387 | } |
4388 | |
4389 | return this; |
4390 | } |
4391 | |
4392 | MDefinition* MToString::foldsTo(TempAllocator& alloc) { |
4393 | MDefinition* in = input(); |
4394 | if (in->isBox()) { |
4395 | in = in->getOperand(0); |
4396 | } |
4397 | |
4398 | if (in->type() == MIRType::String) { |
4399 | return in; |
4400 | } |
4401 | return this; |
4402 | } |
4403 | |
4404 | MDefinition* MClampToUint8::foldsTo(TempAllocator& alloc) { |
4405 | if (MConstant* inputConst = input()->maybeConstantValue()) { |
4406 | if (inputConst->isTypeRepresentableAsDouble()) { |
4407 | int32_t clamped = ClampDoubleToUint8(inputConst->numberToDouble()); |
4408 | return MConstant::New(alloc, Int32Value(clamped)); |
4409 | } |
4410 | } |
4411 | return this; |
4412 | } |
4413 | |
4414 | bool MCompare::tryFoldEqualOperands(bool* result) { |
4415 | if (lhs() != rhs()) { |
4416 | return false; |
4417 | } |
4418 | |
4419 | // Intuitively somebody would think that if lhs === rhs, |
4420 | // then we can just return true. (Or false for !==) |
4421 | // However NaN !== NaN is true! So we spend some time trying |
4422 | // to eliminate this case. |
4423 | |
4424 | if (!IsStrictEqualityOp(jsop())) { |
4425 | return false; |
4426 | } |
4427 | |
4428 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4429 | compareType_ == Compare_Undefined || compareType_ == Compare_Null ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4430 | compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4431 | compareType_ == Compare_UInt64 || compareType_ == Compare_Double ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4432 | compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4433 | compareType_ == Compare_UIntPtr || compareType_ == Compare_String ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4434 | compareType_ == Compare_Object || compareType_ == Compare_Symbol ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4435 | compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4436 | compareType_ == Compare_BigInt_Double ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4437 | compareType_ == Compare_BigInt_String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String" ")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4438 | |
4439 | if (isDoubleComparison() || isFloat32Comparison()) { |
4440 | if (!operandsAreNeverNaN()) { |
4441 | return false; |
4442 | } |
4443 | } |
4444 | |
4445 | lhs()->setGuardRangeBailoutsUnchecked(); |
4446 | |
4447 | *result = (jsop() == JSOp::StrictEq); |
4448 | return true; |
4449 | } |
4450 | |
4451 | static JSType TypeOfName(const JSLinearString* str) { |
4452 | static constexpr std::array types = { |
4453 | JSTYPE_UNDEFINED, JSTYPE_OBJECT, JSTYPE_FUNCTION, JSTYPE_STRING, |
4454 | JSTYPE_NUMBER, JSTYPE_BOOLEAN, JSTYPE_SYMBOL, JSTYPE_BIGINT, |
4455 | #ifdef ENABLE_RECORD_TUPLE |
4456 | JSTYPE_RECORD, JSTYPE_TUPLE, |
4457 | #endif |
4458 | }; |
4459 | static_assert(types.size() == JSTYPE_LIMIT); |
4460 | |
4461 | const JSAtomState& names = GetJitContext()->runtime->names(); |
4462 | for (auto type : types) { |
4463 | if (EqualStrings(str, TypeName(type, names))) { |
4464 | return type; |
4465 | } |
4466 | } |
4467 | return JSTYPE_LIMIT; |
4468 | } |
4469 | |
4470 | struct TypeOfCompareInput { |
4471 | // The `typeof expr` side of the comparison. |
4472 | // MTypeOfName for JSOp::Typeof/JSOp::TypeofExpr, and |
4473 | // MTypeOf for JSOp::TypeofEq (same pointer as typeOf). |
4474 | MDefinition* typeOfSide; |
4475 | |
4476 | // The actual `typeof` operation. |
4477 | MTypeOf* typeOf; |
4478 | |
4479 | // The string side of the comparison. |
4480 | JSType type; |
4481 | |
4482 | // True if the comparison uses raw JSType (Generated for JSOp::TypeofEq). |
4483 | bool isIntComparison; |
4484 | |
4485 | TypeOfCompareInput(MDefinition* typeOfSide, MTypeOf* typeOf, JSType type, |
4486 | bool isIntComparison) |
4487 | : typeOfSide(typeOfSide), |
4488 | typeOf(typeOf), |
4489 | type(type), |
4490 | isIntComparison(isIntComparison) {} |
4491 | }; |
4492 | |
4493 | static mozilla::Maybe<TypeOfCompareInput> IsTypeOfCompare(MCompare* ins) { |
4494 | if (!IsEqualityOp(ins->jsop())) { |
4495 | return mozilla::Nothing(); |
4496 | } |
4497 | |
4498 | if (ins->compareType() == MCompare::Compare_Int32) { |
4499 | auto* lhs = ins->lhs(); |
4500 | auto* rhs = ins->rhs(); |
4501 | |
4502 | if (ins->type() != MIRType::Boolean || lhs->type() != MIRType::Int32 || |
4503 | rhs->type() != MIRType::Int32) { |
4504 | return mozilla::Nothing(); |
4505 | } |
4506 | |
4507 | // NOTE: The comparison is generated inside JIT, and typeof should always |
4508 | // be in the LHS. |
4509 | if (!lhs->isTypeOf() || !rhs->isConstant()) { |
4510 | return mozilla::Nothing(); |
4511 | } |
4512 | |
4513 | auto* typeOf = lhs->toTypeOf(); |
4514 | auto* constant = rhs->toConstant(); |
4515 | |
4516 | JSType type = JSType(constant->toInt32()); |
4517 | return mozilla::Some(TypeOfCompareInput(typeOf, typeOf, type, true)); |
4518 | } |
4519 | |
4520 | if (ins->compareType() != MCompare::Compare_String) { |
4521 | return mozilla::Nothing(); |
4522 | } |
4523 | |
4524 | auto* lhs = ins->lhs(); |
4525 | auto* rhs = ins->rhs(); |
4526 | |
4527 | MOZ_ASSERT(ins->type() == MIRType::Boolean)do { static_assert( mozilla::detail::AssertionConditionType< decltype(ins->type() == MIRType::Boolean)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::Boolean ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "ins->type() == MIRType::Boolean", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4527); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::Boolean" ")"); do { *((volatile int*)__null) = 4527; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4528 | MOZ_ASSERT(lhs->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(lhs->type() == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(lhs->type() == MIRType::String ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "lhs->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4528); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4528; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4529 | MOZ_ASSERT(rhs->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(rhs->type() == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(rhs->type() == MIRType::String ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "rhs->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4529; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4530 | |
4531 | if (!lhs->isTypeOfName() && !rhs->isTypeOfName()) { |
4532 | return mozilla::Nothing(); |
4533 | } |
4534 | if (!lhs->isConstant() && !rhs->isConstant()) { |
4535 | return mozilla::Nothing(); |
4536 | } |
4537 | |
4538 | auto* typeOfName = |
4539 | lhs->isTypeOfName() ? lhs->toTypeOfName() : rhs->toTypeOfName(); |
4540 | auto* typeOf = typeOfName->input()->toTypeOf(); |
4541 | |
4542 | auto* constant = lhs->isConstant() ? lhs->toConstant() : rhs->toConstant(); |
4543 | |
4544 | JSType type = TypeOfName(&constant->toString()->asLinear()); |
4545 | return mozilla::Some(TypeOfCompareInput(typeOfName, typeOf, type, false)); |
4546 | } |
4547 | |
4548 | bool MCompare::tryFoldTypeOf(bool* result) { |
4549 | auto typeOfCompare = IsTypeOfCompare(this); |
4550 | if (!typeOfCompare) { |
4551 | return false; |
4552 | } |
4553 | auto* typeOf = typeOfCompare->typeOf; |
4554 | JSType type = typeOfCompare->type; |
4555 | |
4556 | switch (type) { |
4557 | case JSTYPE_BOOLEAN: |
4558 | if (!typeOf->input()->mightBeType(MIRType::Boolean)) { |
4559 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4560 | return true; |
4561 | } |
4562 | break; |
4563 | case JSTYPE_NUMBER: |
4564 | if (!typeOf->input()->mightBeType(MIRType::Int32) && |
4565 | !typeOf->input()->mightBeType(MIRType::Float32) && |
4566 | !typeOf->input()->mightBeType(MIRType::Double)) { |
4567 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4568 | return true; |
4569 | } |
4570 | break; |
4571 | case JSTYPE_STRING: |
4572 | if (!typeOf->input()->mightBeType(MIRType::String)) { |
4573 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4574 | return true; |
4575 | } |
4576 | break; |
4577 | case JSTYPE_SYMBOL: |
4578 | if (!typeOf->input()->mightBeType(MIRType::Symbol)) { |
4579 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4580 | return true; |
4581 | } |
4582 | break; |
4583 | case JSTYPE_BIGINT: |
4584 | if (!typeOf->input()->mightBeType(MIRType::BigInt)) { |
4585 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4586 | return true; |
4587 | } |
4588 | break; |
4589 | case JSTYPE_OBJECT: |
4590 | if (!typeOf->input()->mightBeType(MIRType::Object) && |
4591 | !typeOf->input()->mightBeType(MIRType::Null)) { |
4592 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4593 | return true; |
4594 | } |
4595 | break; |
4596 | case JSTYPE_UNDEFINED: |
4597 | if (!typeOf->input()->mightBeType(MIRType::Object) && |
4598 | !typeOf->input()->mightBeType(MIRType::Undefined)) { |
4599 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4600 | return true; |
4601 | } |
4602 | break; |
4603 | case JSTYPE_FUNCTION: |
4604 | if (!typeOf->input()->mightBeType(MIRType::Object)) { |
4605 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4606 | return true; |
4607 | } |
4608 | break; |
4609 | case JSTYPE_LIMIT: |
4610 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4611 | return true; |
4612 | #ifdef ENABLE_RECORD_TUPLE |
4613 | case JSTYPE_RECORD: |
4614 | case JSTYPE_TUPLE: |
4615 | MOZ_CRASH("Records and Tuples are not supported yet.")do { do { } while (false); MOZ_ReportCrash("" "Records and Tuples are not supported yet." , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4615); AnnotateMozCrashReason("MOZ_CRASH(" "Records and Tuples are not supported yet." ")"); do { *((volatile int*)__null) = 4615; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4616 | #endif |
4617 | } |
4618 | |
4619 | return false; |
4620 | } |
4621 | |
4622 | bool MCompare::tryFold(bool* result) { |
4623 | JSOp op = jsop(); |
4624 | |
4625 | if (tryFoldEqualOperands(result)) { |
4626 | return true; |
4627 | } |
4628 | |
4629 | if (tryFoldTypeOf(result)) { |
4630 | return true; |
4631 | } |
4632 | |
4633 | if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) { |
4634 | // The LHS is the value we want to test against null or undefined. |
4635 | if (IsStrictEqualityOp(op)) { |
4636 | if (lhs()->type() == inputType()) { |
4637 | *result = (op == JSOp::StrictEq); |
4638 | return true; |
4639 | } |
4640 | if (!lhs()->mightBeType(inputType())) { |
4641 | *result = (op == JSOp::StrictNe); |
4642 | return true; |
4643 | } |
4644 | } else { |
4645 | MOZ_ASSERT(IsLooseEqualityOp(op))do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsLooseEqualityOp(op))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsLooseEqualityOp(op)))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("IsLooseEqualityOp(op)" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4645); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsLooseEqualityOp(op)" ")"); do { *((volatile int*)__null) = 4645; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4646 | if (IsNullOrUndefined(lhs()->type())) { |
4647 | *result = (op == JSOp::Eq); |
4648 | return true; |
4649 | } |
4650 | if (!lhs()->mightBeType(MIRType::Null) && |
4651 | !lhs()->mightBeType(MIRType::Undefined) && |
4652 | !lhs()->mightBeType(MIRType::Object)) { |
4653 | *result = (op == JSOp::Ne); |
4654 | return true; |
4655 | } |
4656 | } |
4657 | return false; |
4658 | } |
4659 | |
4660 | return false; |
4661 | } |
4662 | |
4663 | template <typename T> |
4664 | static bool FoldComparison(JSOp op, T left, T right) { |
4665 | switch (op) { |
4666 | case JSOp::Lt: |
4667 | return left < right; |
4668 | case JSOp::Le: |
4669 | return left <= right; |
4670 | case JSOp::Gt: |
4671 | return left > right; |
4672 | case JSOp::Ge: |
4673 | return left >= right; |
4674 | case JSOp::StrictEq: |
4675 | case JSOp::Eq: |
4676 | return left == right; |
4677 | case JSOp::StrictNe: |
4678 | case JSOp::Ne: |
4679 | return left != right; |
4680 | default: |
4681 | MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op." , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4681); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op." ")"); do { *((volatile int*)__null) = 4681; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4682 | } |
4683 | } |
4684 | |
4685 | static bool FoldBigIntComparison(JSOp op, const BigInt* left, double right) { |
4686 | switch (op) { |
4687 | case JSOp::Lt: |
4688 | return BigInt::lessThan(left, right).valueOr(false); |
4689 | case JSOp::Le: |
4690 | return !BigInt::lessThan(right, left).valueOr(true); |
4691 | case JSOp::Gt: |
4692 | return BigInt::lessThan(right, left).valueOr(false); |
4693 | case JSOp::Ge: |
4694 | return !BigInt::lessThan(left, right).valueOr(true); |
4695 | case JSOp::StrictEq: |
4696 | case JSOp::Eq: |
4697 | return BigInt::equal(left, right); |
4698 | case JSOp::StrictNe: |
4699 | case JSOp::Ne: |
4700 | return !BigInt::equal(left, right); |
4701 | default: |
4702 | MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op." , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4702); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op." ")"); do { *((volatile int*)__null) = 4702; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4703 | } |
4704 | } |
4705 | |
4706 | bool MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) { |
4707 | if (type() != MIRType::Boolean && type() != MIRType::Int32) { |
4708 | return false; |
4709 | } |
4710 | |
4711 | MDefinition* left = getOperand(0); |
4712 | MDefinition* right = getOperand(1); |
4713 | |
4714 | if (compareType() == Compare_Double) { |
4715 | // Optimize "MCompare MConstant (MToDouble SomethingInInt32Range). |
4716 | // In most cases the MToDouble was added, because the constant is |
4717 | // a double. |
4718 | // e.g. v < 9007199254740991, where v is an int32 is always true. |
4719 | if (!lhs()->isConstant() && !rhs()->isConstant()) { |
4720 | return false; |
4721 | } |
4722 | |
4723 | MDefinition* operand = left->isConstant() ? right : left; |
4724 | MConstant* constant = |
4725 | left->isConstant() ? left->toConstant() : right->toConstant(); |
4726 | MOZ_ASSERT(constant->type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType< decltype(constant->type() == MIRType::Double)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(constant->type() == MIRType::Double))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("constant->type() == MIRType::Double" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4726); AnnotateMozCrashReason("MOZ_ASSERT" "(" "constant->type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 4726; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4727 | double cte = constant->toDouble(); |
4728 | |
4729 | if (operand->isToDouble() && |
4730 | operand->getOperand(0)->type() == MIRType::Int32) { |
4731 | bool replaced = false; |
4732 | switch (jsop_) { |
4733 | case JSOp::Lt: |
4734 | if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4735 | *result = !((constant == lhs()) ^ (cte < INT32_MIN(-2147483647-1))); |
4736 | replaced = true; |
4737 | } |
4738 | break; |
4739 | case JSOp::Le: |
4740 | if (constant == lhs()) { |
4741 | if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) { |
4742 | *result = (cte <= INT32_MIN(-2147483647-1)); |
4743 | replaced = true; |
4744 | } |
4745 | } else { |
4746 | if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4747 | *result = (cte >= INT32_MIN(-2147483647-1)); |
4748 | replaced = true; |
4749 | } |
4750 | } |
4751 | break; |
4752 | case JSOp::Gt: |
4753 | if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4754 | *result = !((constant == rhs()) ^ (cte < INT32_MIN(-2147483647-1))); |
4755 | replaced = true; |
4756 | } |
4757 | break; |
4758 | case JSOp::Ge: |
4759 | if (constant == lhs()) { |
4760 | if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4761 | *result = (cte >= INT32_MAX(2147483647)); |
4762 | replaced = true; |
4763 | } |
4764 | } else { |
4765 | if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) { |
4766 | *result = (cte <= INT32_MIN(-2147483647-1)); |
4767 | replaced = true; |
4768 | } |
4769 | } |
4770 | break; |
4771 | case JSOp::StrictEq: // Fall through. |
4772 | case JSOp::Eq: |
4773 | if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4774 | *result = false; |
4775 | replaced = true; |
4776 | } |
4777 | break; |
4778 | case JSOp::StrictNe: // Fall through. |
4779 | case JSOp::Ne: |
4780 | if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4781 | *result = true; |
4782 | replaced = true; |
4783 | } |
4784 | break; |
4785 | default: |
4786 | MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op." , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4786); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op." ")"); do { *((volatile int*)__null) = 4786; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4787 | } |
4788 | if (replaced) { |
4789 | MLimitedTruncate* limit = MLimitedTruncate::New( |
4790 | alloc, operand->getOperand(0), TruncateKind::NoTruncate); |
4791 | limit->setGuardUnchecked(); |
4792 | block()->insertBefore(this, limit); |
4793 | return true; |
4794 | } |
4795 | } |
4796 | |
4797 | // Optimize comparison against NaN. |
4798 | if (std::isnan(cte)) { |
4799 | switch (jsop_) { |
4800 | case JSOp::Lt: |
4801 | case JSOp::Le: |
4802 | case JSOp::Gt: |
4803 | case JSOp::Ge: |
4804 | case JSOp::Eq: |
4805 | case JSOp::StrictEq: |
4806 | *result = false; |
4807 | break; |
4808 | case JSOp::Ne: |
4809 | case JSOp::StrictNe: |
4810 | *result = true; |
4811 | break; |
4812 | default: |
4813 | MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op." , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4813); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op." ")"); do { *((volatile int*)__null) = 4813; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4814 | } |
4815 | return true; |
4816 | } |
4817 | } |
4818 | |
4819 | if (!left->isConstant() || !right->isConstant()) { |
4820 | return false; |
4821 | } |
4822 | |
4823 | MConstant* lhs = left->toConstant(); |
4824 | MConstant* rhs = right->toConstant(); |
4825 | |
4826 | switch (compareType()) { |
4827 | case Compare_Int32: |
4828 | case Compare_Double: |
4829 | case Compare_Float32: { |
4830 | *result = |
4831 | FoldComparison(jsop_, lhs->numberToDouble(), rhs->numberToDouble()); |
4832 | return true; |
4833 | } |
4834 | case Compare_UInt32: { |
4835 | *result = FoldComparison(jsop_, uint32_t(lhs->toInt32()), |
4836 | uint32_t(rhs->toInt32())); |
4837 | return true; |
4838 | } |
4839 | case Compare_Int64: { |
4840 | *result = FoldComparison(jsop_, lhs->toInt64(), rhs->toInt64()); |
4841 | return true; |
4842 | } |
4843 | case Compare_UInt64: { |
4844 | *result = FoldComparison(jsop_, uint64_t(lhs->toInt64()), |
4845 | uint64_t(rhs->toInt64())); |
4846 | return true; |
4847 | } |
4848 | case Compare_IntPtr: { |
4849 | *result = FoldComparison(jsop_, lhs->toIntPtr(), rhs->toIntPtr()); |
4850 | return true; |
4851 | } |
4852 | case Compare_UIntPtr: { |
4853 | *result = FoldComparison(jsop_, uintptr_t(lhs->toIntPtr()), |
4854 | uintptr_t(rhs->toIntPtr())); |
4855 | return true; |
4856 | } |
4857 | case Compare_String: { |
4858 | int32_t comp = CompareStrings(&lhs->toString()->asLinear(), |
4859 | &rhs->toString()->asLinear()); |
4860 | *result = FoldComparison(jsop_, comp, 0); |
4861 | return true; |
4862 | } |
4863 | case Compare_BigInt: { |
4864 | int32_t comp = BigInt::compare(lhs->toBigInt(), rhs->toBigInt()); |
4865 | *result = FoldComparison(jsop_, comp, 0); |
4866 | return true; |
4867 | } |
4868 | case Compare_BigInt_Int32: |
4869 | case Compare_BigInt_Double: { |
4870 | *result = |
4871 | FoldBigIntComparison(jsop_, lhs->toBigInt(), rhs->numberToDouble()); |
4872 | return true; |
4873 | } |
4874 | case Compare_BigInt_String: { |
4875 | JSLinearString* linear = &rhs->toString()->asLinear(); |
4876 | if (!linear->hasIndexValue()) { |
4877 | return false; |
4878 | } |
4879 | *result = |
4880 | FoldBigIntComparison(jsop_, lhs->toBigInt(), linear->getIndexValue()); |
4881 | return true; |
4882 | } |
4883 | |
4884 | case Compare_Undefined: |
4885 | case Compare_Null: |
4886 | case Compare_Symbol: |
4887 | case Compare_Object: |
4888 | case Compare_WasmAnyRef: |
4889 | return false; |
4890 | } |
4891 | |
4892 | 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.cpp" , 4892); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected compare type" ")"); do { *((volatile int*)__null) = 4892; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4893 | } |
4894 | |
4895 | MDefinition* MCompare::tryFoldTypeOf(TempAllocator& alloc) { |
4896 | auto typeOfCompare = IsTypeOfCompare(this); |
4897 | if (!typeOfCompare) { |
4898 | return this; |
4899 | } |
4900 | auto* typeOf = typeOfCompare->typeOf; |
4901 | JSType type = typeOfCompare->type; |
4902 | |
4903 | auto* input = typeOf->input(); |
4904 | MOZ_ASSERT(input->type() == MIRType::Value ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(input->type() == MIRType::Value || input->type () == MIRType::Object)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(input->type() == MIRType:: Value || input->type() == MIRType::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("input->type() == MIRType::Value || input->type() == MIRType::Object" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4905); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 4905; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4905 | input->type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType< decltype(input->type() == MIRType::Value || input->type () == MIRType::Object)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(input->type() == MIRType:: Value || input->type() == MIRType::Object))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("input->type() == MIRType::Value || input->type() == MIRType::Object" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4905); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 4905; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4906 | |
4907 | // Constant typeof folding handles the other cases. |
4908 | MOZ_ASSERT_IF(input->type() == MIRType::Object, type == JSTYPE_UNDEFINED ||do { if (input->type() == MIRType::Object) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4910); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION" ")"); do { *((volatile int*)__null) = 4910; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) |
4909 | type == JSTYPE_OBJECT ||do { if (input->type() == MIRType::Object) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4910); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION" ")"); do { *((volatile int*)__null) = 4910; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) |
4910 | type == JSTYPE_FUNCTION)do { if (input->type() == MIRType::Object) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4910); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION" ")"); do { *((volatile int*)__null) = 4910; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
4911 | |
4912 | MOZ_ASSERT(type != JSTYPE_LIMIT, "unknown typeof strings folded earlier")do { static_assert( mozilla::detail::AssertionConditionType< decltype(type != JSTYPE_LIMIT)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(type != JSTYPE_LIMIT))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("type != JSTYPE_LIMIT" " (" "unknown typeof strings folded earlier" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4912); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type != JSTYPE_LIMIT" ") (" "unknown typeof strings folded earlier" ")"); do { *(( volatile int*)__null) = 4912; __attribute__((nomerge)) ::abort (); } while (false); } } while (false); |
4913 | |
4914 | // If there's only a single use, assume this |typeof| is used in a simple |
4915 | // comparison context. |
4916 | // |
4917 | // if (typeof thing === "number") { ... } |
4918 | // |
4919 | // It'll be compiled into something similar to: |
4920 | // |
4921 | // if (IsNumber(thing)) { ... } |
4922 | // |
4923 | // This heuristic can go wrong when repeated |typeof| are used in consecutive |
4924 | // if-statements. |
4925 | // |
4926 | // if (typeof thing === "number") { ... } |
4927 | // else if (typeof thing === "string") { ... } |
4928 | // ... repeated for all possible types |
4929 | // |
4930 | // In that case it'd more efficient to emit MTypeOf compared to MTypeOfIs. We |
4931 | // don't yet handle that case, because it'd require a separate optimization |
4932 | // pass to correctly detect it. |
4933 | if (typeOfCompare->typeOfSide->hasOneUse()) { |
4934 | return MTypeOfIs::New(alloc, input, jsop(), type); |
4935 | } |
4936 | |
4937 | if (typeOfCompare->isIntComparison) { |
4938 | // Already optimized. |
4939 | return this; |
4940 | } |
4941 | |
4942 | MConstant* cst = MConstant::New(alloc, Int32Value(type)); |
4943 | block()->insertBefore(this, cst); |
4944 | |
4945 | return MCompare::New(alloc, typeOf, cst, jsop(), MCompare::Compare_Int32); |
4946 | } |
4947 | |
4948 | MDefinition* MCompare::tryFoldCharCompare(TempAllocator& alloc) { |
4949 | if (compareType() != Compare_String) { |
4950 | return this; |
4951 | } |
4952 | |
4953 | MDefinition* left = lhs(); |
4954 | MOZ_ASSERT(left->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4954); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4954; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4955 | |
4956 | MDefinition* right = rhs(); |
4957 | MOZ_ASSERT(right->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4957; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4958 | |
4959 | // |str[i]| is compiled as |MFromCharCode(MCharCodeAt(str, i))|. |
4960 | // Out-of-bounds access is compiled as |
4961 | // |FromCharCodeEmptyIfNegative(CharCodeAtOrNegative(str, i))|. |
4962 | auto isCharAccess = [](MDefinition* ins) { |
4963 | if (ins->isFromCharCode()) { |
4964 | return ins->toFromCharCode()->code()->isCharCodeAt(); |
4965 | } |
4966 | if (ins->isFromCharCodeEmptyIfNegative()) { |
4967 | auto* fromCharCode = ins->toFromCharCodeEmptyIfNegative(); |
4968 | return fromCharCode->code()->isCharCodeAtOrNegative(); |
4969 | } |
4970 | return false; |
4971 | }; |
4972 | |
4973 | auto charAccessCode = [](MDefinition* ins) { |
4974 | if (ins->isFromCharCode()) { |
4975 | return ins->toFromCharCode()->code(); |
4976 | } |
4977 | return ins->toFromCharCodeEmptyIfNegative()->code(); |
4978 | }; |
4979 | |
4980 | if (left->isConstant() || right->isConstant()) { |
4981 | // Try to optimize |MConstant(string) <compare> (MFromCharCode MCharCodeAt)| |
4982 | // as |MConstant(charcode) <compare> MCharCodeAt|. |
4983 | MConstant* constant; |
4984 | MDefinition* operand; |
4985 | if (left->isConstant()) { |
4986 | constant = left->toConstant(); |
4987 | operand = right; |
4988 | } else { |
4989 | constant = right->toConstant(); |
4990 | operand = left; |
4991 | } |
4992 | |
4993 | if (constant->toString()->length() != 1 || !isCharAccess(operand)) { |
4994 | return this; |
4995 | } |
4996 | |
4997 | char16_t charCode = constant->toString()->asLinear().latin1OrTwoByteChar(0); |
4998 | MConstant* charCodeConst = MConstant::New(alloc, Int32Value(charCode)); |
4999 | block()->insertBefore(this, charCodeConst); |
5000 | |
5001 | MDefinition* charCodeAt = charAccessCode(operand); |
5002 | |
5003 | if (left->isConstant()) { |
5004 | left = charCodeConst; |
5005 | right = charCodeAt; |
5006 | } else { |
5007 | left = charCodeAt; |
5008 | right = charCodeConst; |
5009 | } |
5010 | } else if (isCharAccess(left) && isCharAccess(right)) { |
5011 | // Try to optimize |(MFromCharCode MCharCodeAt) <compare> (MFromCharCode |
5012 | // MCharCodeAt)| as |MCharCodeAt <compare> MCharCodeAt|. |
5013 | |
5014 | left = charAccessCode(left); |
5015 | right = charAccessCode(right); |
5016 | } else { |
5017 | return this; |
5018 | } |
5019 | |
5020 | return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32); |
5021 | } |
5022 | |
5023 | MDefinition* MCompare::tryFoldStringCompare(TempAllocator& alloc) { |
5024 | if (compareType() != Compare_String) { |
5025 | return this; |
5026 | } |
5027 | |
5028 | MDefinition* left = lhs(); |
5029 | MOZ_ASSERT(left->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5029); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 5029; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5030 | |
5031 | MDefinition* right = rhs(); |
5032 | MOZ_ASSERT(right->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 5032; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5033 | |
5034 | if (!left->isConstant() && !right->isConstant()) { |
5035 | return this; |
5036 | } |
5037 | |
5038 | // Try to optimize |string <compare> MConstant("")| as |MStringLength(string) |
5039 | // <compare> MConstant(0)|. |
5040 | |
5041 | MConstant* constant = |
5042 | left->isConstant() ? left->toConstant() : right->toConstant(); |
5043 | if (!constant->toString()->empty()) { |
5044 | return this; |
5045 | } |
5046 | |
5047 | MDefinition* operand = left->isConstant() ? right : left; |
5048 | |
5049 | auto* strLength = MStringLength::New(alloc, operand); |
5050 | block()->insertBefore(this, strLength); |
5051 | |
5052 | auto* zero = MConstant::New(alloc, Int32Value(0)); |
5053 | block()->insertBefore(this, zero); |
5054 | |
5055 | if (left->isConstant()) { |
5056 | left = zero; |
5057 | right = strLength; |
5058 | } else { |
5059 | left = strLength; |
5060 | right = zero; |
5061 | } |
5062 | |
5063 | return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32); |
5064 | } |
5065 | |
5066 | MDefinition* MCompare::tryFoldStringSubstring(TempAllocator& alloc) { |
5067 | if (compareType() != Compare_String) { |
5068 | return this; |
5069 | } |
5070 | if (!IsEqualityOp(jsop())) { |
5071 | return this; |
5072 | } |
5073 | |
5074 | auto* left = lhs(); |
5075 | MOZ_ASSERT(left->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5075); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 5075; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5076 | |
5077 | auto* right = rhs(); |
5078 | MOZ_ASSERT(right->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::String)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5078); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 5078; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5079 | |
5080 | // One operand must be a constant string. |
5081 | if (!left->isConstant() && !right->isConstant()) { |
5082 | return this; |
5083 | } |
5084 | |
5085 | // The constant string must be non-empty. |
5086 | auto* constant = |
5087 | left->isConstant() ? left->toConstant() : right->toConstant(); |
5088 | if (constant->toString()->empty()) { |
5089 | return this; |
5090 | } |
5091 | |
5092 | // The other operand must be a substring operation. |
5093 | auto* operand = left->isConstant() ? right : left; |
5094 | if (!operand->isSubstr()) { |
5095 | return this; |
5096 | } |
5097 | auto* substr = operand->toSubstr(); |
5098 | |
5099 | static_assert(JSString::MAX_LENGTH < INT32_MAX(2147483647), |
5100 | "string length can be casted to int32_t"); |
5101 | |
5102 | if (!IsSubstrTo(substr, int32_t(constant->toString()->length()))) { |
5103 | return this; |
5104 | } |
5105 | |
5106 | // Now fold code like |str.substring(0, 2) == "aa"| to |str.startsWith("aa")|. |
5107 | |
5108 | auto* startsWith = MStringStartsWith::New(alloc, substr->string(), constant); |
5109 | if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) { |
5110 | return startsWith; |
5111 | } |
5112 | |
5113 | // Invert for inequality. |
5114 | MOZ_ASSERT(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe)do { static_assert( mozilla::detail::AssertionConditionType< decltype(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("jsop() == JSOp::Ne || jsop() == JSOp::StrictNe" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5114); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe" ")"); do { *((volatile int*)__null) = 5114; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5115 | |
5116 | block()->insertBefore(this, startsWith); |
5117 | return MNot::New(alloc, startsWith); |
5118 | } |
5119 | |
5120 | MDefinition* MCompare::tryFoldStringIndexOf(TempAllocator& alloc) { |
5121 | if (compareType() != Compare_Int32) { |
5122 | return this; |
5123 | } |
5124 | if (!IsEqualityOp(jsop())) { |
5125 | return this; |
5126 | } |
5127 | |
5128 | auto* left = lhs(); |
5129 | MOZ_ASSERT(left->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5129); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 5129; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5130 | |
5131 | auto* right = rhs(); |
5132 | MOZ_ASSERT(right->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 5132; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5133 | |
5134 | // One operand must be a constant integer. |
5135 | if (!left->isConstant() && !right->isConstant()) { |
5136 | return this; |
5137 | } |
5138 | |
5139 | // The constant must be zero. |
5140 | auto* constant = |
5141 | left->isConstant() ? left->toConstant() : right->toConstant(); |
5142 | if (!constant->isInt32(0)) { |
5143 | return this; |
5144 | } |
5145 | |
5146 | // The other operand must be an indexOf operation. |
5147 | auto* operand = left->isConstant() ? right : left; |
5148 | if (!operand->isStringIndexOf()) { |
5149 | return this; |
5150 | } |
5151 | |
5152 | // Fold |str.indexOf(searchStr) == 0| to |str.startsWith(searchStr)|. |
5153 | |
5154 | auto* indexOf = operand->toStringIndexOf(); |
5155 | auto* startsWith = |
5156 | MStringStartsWith::New(alloc, indexOf->string(), indexOf->searchString()); |
5157 | if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) { |
5158 | return startsWith; |
5159 | } |
5160 | |
5161 | // Invert for inequality. |
5162 | MOZ_ASSERT(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe)do { static_assert( mozilla::detail::AssertionConditionType< decltype(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("jsop() == JSOp::Ne || jsop() == JSOp::StrictNe" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe" ")"); do { *((volatile int*)__null) = 5162; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5163 | |
5164 | block()->insertBefore(this, startsWith); |
5165 | return MNot::New(alloc, startsWith); |
5166 | } |
5167 | |
5168 | MDefinition* MCompare::tryFoldBigInt64(TempAllocator& alloc) { |
5169 | if (compareType() == Compare_BigInt) { |
5170 | auto* left = lhs(); |
5171 | MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5171); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5171; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5172 | |
5173 | auto* right = rhs(); |
5174 | 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.cpp" , 5174); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5174; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5175 | |
5176 | // At least one operand must be MInt64ToBigInt. |
5177 | if (!left->isInt64ToBigInt() && !right->isInt64ToBigInt()) { |
5178 | return this; |
5179 | } |
5180 | |
5181 | // Unwrap MInt64ToBigInt on both sides and perform a Int64 comparison. |
5182 | if (left->isInt64ToBigInt() && right->isInt64ToBigInt()) { |
5183 | auto* lhsInt64 = left->toInt64ToBigInt(); |
5184 | auto* rhsInt64 = right->toInt64ToBigInt(); |
5185 | |
5186 | // Don't optimize if Int64 against Uint64 comparison. |
5187 | if (lhsInt64->elementType() != rhsInt64->elementType()) { |
5188 | return this; |
5189 | } |
5190 | |
5191 | bool isSigned = lhsInt64->elementType() == Scalar::BigInt64; |
5192 | auto compareType = |
5193 | isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64; |
5194 | return MCompare::New(alloc, lhsInt64->input(), rhsInt64->input(), jsop_, |
5195 | compareType); |
5196 | } |
5197 | |
5198 | // Optimize IntPtr x Int64 comparison to Int64 x Int64 comparison. |
5199 | if (left->isIntPtrToBigInt() || right->isIntPtrToBigInt()) { |
5200 | auto* int64ToBigInt = left->isInt64ToBigInt() ? left->toInt64ToBigInt() |
5201 | : right->toInt64ToBigInt(); |
5202 | |
5203 | // Can't optimize when comparing Uint64 against IntPtr. |
5204 | if (int64ToBigInt->elementType() == Scalar::BigUint64) { |
5205 | return this; |
5206 | } |
5207 | |
5208 | auto* intPtrToBigInt = left->isIntPtrToBigInt() |
5209 | ? left->toIntPtrToBigInt() |
5210 | : right->toIntPtrToBigInt(); |
5211 | |
5212 | auto* intPtrToInt64 = MIntPtrToInt64::New(alloc, intPtrToBigInt->input()); |
5213 | block()->insertBefore(this, intPtrToInt64); |
5214 | |
5215 | if (left == int64ToBigInt) { |
5216 | left = int64ToBigInt->input(); |
5217 | right = intPtrToInt64; |
5218 | } else { |
5219 | left = intPtrToInt64; |
5220 | right = int64ToBigInt->input(); |
5221 | } |
5222 | return MCompare::New(alloc, left, right, jsop_, MCompare::Compare_Int64); |
5223 | } |
5224 | |
5225 | // The other operand must be a constant. |
5226 | if (!left->isConstant() && !right->isConstant()) { |
5227 | return this; |
5228 | } |
5229 | |
5230 | auto* int64ToBigInt = left->isInt64ToBigInt() ? left->toInt64ToBigInt() |
5231 | : right->toInt64ToBigInt(); |
5232 | bool isSigned = int64ToBigInt->elementType() == Scalar::BigInt64; |
5233 | |
5234 | auto* constant = |
5235 | left->isConstant() ? left->toConstant() : right->toConstant(); |
5236 | auto* bigInt = constant->toBigInt(); |
5237 | |
5238 | // Extract the BigInt value if representable as Int64/Uint64. |
5239 | mozilla::Maybe<int64_t> value; |
5240 | if (isSigned) { |
5241 | int64_t x; |
5242 | if (BigInt::isInt64(bigInt, &x)) { |
5243 | value = mozilla::Some(x); |
5244 | } |
5245 | } else { |
5246 | uint64_t x; |
5247 | if (BigInt::isUint64(bigInt, &x)) { |
5248 | value = mozilla::Some(static_cast<int64_t>(x)); |
5249 | } |
5250 | } |
5251 | |
5252 | // The comparison is a constant if the BigInt has too many digits. |
5253 | if (!value) { |
5254 | int32_t repr = bigInt->isNegative() ? -1 : 1; |
5255 | |
5256 | bool result; |
5257 | if (left == int64ToBigInt) { |
5258 | result = FoldComparison(jsop_, 0, repr); |
5259 | } else { |
5260 | result = FoldComparison(jsop_, repr, 0); |
5261 | } |
5262 | return MConstant::New(alloc, BooleanValue(result)); |
5263 | } |
5264 | |
5265 | auto* cst = MConstant::NewInt64(alloc, *value); |
5266 | block()->insertBefore(this, cst); |
5267 | |
5268 | auto compareType = |
5269 | isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64; |
5270 | if (left == int64ToBigInt) { |
5271 | return MCompare::New(alloc, int64ToBigInt->input(), cst, jsop_, |
5272 | compareType); |
5273 | } |
5274 | return MCompare::New(alloc, cst, int64ToBigInt->input(), jsop_, |
5275 | compareType); |
5276 | } |
5277 | |
5278 | if (compareType() == Compare_BigInt_Int32) { |
5279 | auto* left = lhs(); |
5280 | MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5280); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5280; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5281 | |
5282 | auto* right = rhs(); |
5283 | MOZ_ASSERT(right->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5283); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 5283; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5284 | |
5285 | // Optimize MInt64ToBigInt against a constant int32. |
5286 | if (!left->isInt64ToBigInt() || !right->isConstant()) { |
5287 | return this; |
5288 | } |
5289 | |
5290 | auto* int64ToBigInt = left->toInt64ToBigInt(); |
5291 | bool isSigned = int64ToBigInt->elementType() == Scalar::BigInt64; |
5292 | |
5293 | int32_t constInt32 = right->toConstant()->toInt32(); |
5294 | |
5295 | // The unsigned comparison against a negative operand is a constant. |
5296 | if (!isSigned && constInt32 < 0) { |
5297 | bool result = FoldComparison(jsop_, 0, constInt32); |
5298 | return MConstant::New(alloc, BooleanValue(result)); |
5299 | } |
5300 | |
5301 | auto* cst = MConstant::NewInt64(alloc, int64_t(constInt32)); |
5302 | block()->insertBefore(this, cst); |
5303 | |
5304 | auto compareType = |
5305 | isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64; |
5306 | return MCompare::New(alloc, int64ToBigInt->input(), cst, jsop_, |
5307 | compareType); |
5308 | } |
5309 | |
5310 | return this; |
5311 | } |
5312 | |
5313 | MDefinition* MCompare::tryFoldBigIntPtr(TempAllocator& alloc) { |
5314 | if (compareType() == Compare_BigInt) { |
5315 | auto* left = lhs(); |
5316 | MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5316); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5316; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5317 | |
5318 | auto* right = rhs(); |
5319 | 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.cpp" , 5319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5319; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5320 | |
5321 | // At least one operand must be MIntPtrToBigInt. |
5322 | if (!left->isIntPtrToBigInt() && !right->isIntPtrToBigInt()) { |
5323 | return this; |
5324 | } |
5325 | |
5326 | // Unwrap MIntPtrToBigInt on both sides and perform an IntPtr comparison. |
5327 | if (left->isIntPtrToBigInt() && right->isIntPtrToBigInt()) { |
5328 | auto* lhsIntPtr = left->toIntPtrToBigInt(); |
5329 | auto* rhsIntPtr = right->toIntPtrToBigInt(); |
5330 | |
5331 | return MCompare::New(alloc, lhsIntPtr->input(), rhsIntPtr->input(), jsop_, |
5332 | MCompare::Compare_IntPtr); |
5333 | } |
5334 | |
5335 | // The other operand must be a constant. |
5336 | if (!left->isConstant() && !right->isConstant()) { |
5337 | return this; |
5338 | } |
5339 | |
5340 | auto* intPtrToBigInt = left->isIntPtrToBigInt() ? left->toIntPtrToBigInt() |
5341 | : right->toIntPtrToBigInt(); |
5342 | |
5343 | auto* constant = |
5344 | left->isConstant() ? left->toConstant() : right->toConstant(); |
5345 | auto* bigInt = constant->toBigInt(); |
5346 | |
5347 | // Extract the BigInt value if representable as intptr_t. |
5348 | intptr_t value; |
5349 | if (!BigInt::isIntPtr(bigInt, &value)) { |
5350 | // The comparison is a constant if the BigInt has too many digits. |
5351 | int32_t repr = bigInt->isNegative() ? -1 : 1; |
5352 | |
5353 | bool result; |
5354 | if (left == intPtrToBigInt) { |
5355 | result = FoldComparison(jsop_, 0, repr); |
5356 | } else { |
5357 | result = FoldComparison(jsop_, repr, 0); |
5358 | } |
5359 | return MConstant::New(alloc, BooleanValue(result)); |
5360 | } |
5361 | |
5362 | auto* cst = MConstant::NewIntPtr(alloc, value); |
5363 | block()->insertBefore(this, cst); |
5364 | |
5365 | if (left == intPtrToBigInt) { |
5366 | left = intPtrToBigInt->input(); |
5367 | right = cst; |
5368 | } else { |
5369 | left = cst; |
5370 | right = intPtrToBigInt->input(); |
5371 | } |
5372 | return MCompare::New(alloc, left, right, jsop_, MCompare::Compare_IntPtr); |
5373 | } |
5374 | |
5375 | if (compareType() == Compare_BigInt_Int32) { |
5376 | auto* left = lhs(); |
5377 | MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5377); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5377; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5378 | |
5379 | auto* right = rhs(); |
5380 | MOZ_ASSERT(right->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(right->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(right->type() == MIRType:: Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("right->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5380); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 5380; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5381 | |
5382 | // Optimize MIntPtrToBigInt against a constant int32. |
5383 | if (!left->isIntPtrToBigInt() || !right->isConstant()) { |
5384 | return this; |
5385 | } |
5386 | |
5387 | auto* cst = |
5388 | MConstant::NewIntPtr(alloc, intptr_t(right->toConstant()->toInt32())); |
5389 | block()->insertBefore(this, cst); |
5390 | |
5391 | return MCompare::New(alloc, left->toIntPtrToBigInt()->input(), cst, jsop_, |
5392 | MCompare::Compare_IntPtr); |
5393 | } |
5394 | |
5395 | return this; |
5396 | } |
5397 | |
5398 | MDefinition* MCompare::tryFoldBigInt(TempAllocator& alloc) { |
5399 | if (compareType() != Compare_BigInt) { |
5400 | return this; |
5401 | } |
5402 | |
5403 | auto* left = lhs(); |
5404 | MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType< decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(left->type() == MIRType:: BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5404; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5405 | |
5406 | auto* right = rhs(); |
5407 | 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.cpp" , 5407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt" ")"); do { *((volatile int*)__null) = 5407; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5408 | |
5409 | // One operand must be a constant. |
5410 | if (!left->isConstant() && !right->isConstant()) { |
5411 | return this; |
5412 | } |
5413 | |
5414 | auto* constant = |
5415 | left->isConstant() ? left->toConstant() : right->toConstant(); |
5416 | auto* operand = left->isConstant() ? right : left; |
5417 | |
5418 | // The constant must be representable as an Int32. |
5419 | int32_t x; |
5420 | if (!BigInt::isInt32(constant->toBigInt(), &x)) { |
5421 | return this; |
5422 | } |
5423 | |
5424 | MConstant* int32Const = MConstant::New(alloc, Int32Value(x)); |
5425 | block()->insertBefore(this, int32Const); |
5426 | |
5427 | auto op = jsop(); |
5428 | if (IsStrictEqualityOp(op)) { |
5429 | // Compare_BigInt_Int32 is only valid for loose comparison. |
5430 | op = op == JSOp::StrictEq ? JSOp::Eq : JSOp::Ne; |
5431 | } else if (operand == right) { |
5432 | // Reverse the comparison operator if the operands were reordered. |
5433 | op = ReverseCompareOp(op); |
5434 | } |
5435 | |
5436 | return MCompare::New(alloc, operand, int32Const, op, |
5437 | MCompare::Compare_BigInt_Int32); |
5438 | } |
5439 | |
5440 | MDefinition* MCompare::foldsTo(TempAllocator& alloc) { |
5441 | bool result; |
5442 | |
5443 | if (tryFold(&result) || evaluateConstantOperands(alloc, &result)) { |
5444 | if (type() == MIRType::Int32) { |
5445 | return MConstant::New(alloc, Int32Value(result)); |
5446 | } |
5447 | |
5448 | 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.cpp" , 5448); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Boolean" ")"); do { *((volatile int*)__null) = 5448; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5449 | return MConstant::New(alloc, BooleanValue(result)); |
5450 | } |
5451 | |
5452 | if (MDefinition* folded = tryFoldTypeOf(alloc); folded != this) { |
5453 | return folded; |
5454 | } |
5455 | |
5456 | if (MDefinition* folded = tryFoldCharCompare(alloc); folded != this) { |
5457 | return folded; |
5458 | } |
5459 | |
5460 | if (MDefinition* folded = tryFoldStringCompare(alloc); folded != this) { |
5461 | return folded; |
5462 | } |
5463 | |
5464 | if (MDefinition* folded = tryFoldStringSubstring(alloc); folded != this) { |
5465 | return folded; |
5466 | } |
5467 | |
5468 | if (MDefinition* folded = tryFoldStringIndexOf(alloc); folded != this) { |
5469 | return folded; |
5470 | } |
5471 | |
5472 | if (MDefinition* folded = tryFoldBigInt64(alloc); folded != this) { |
5473 | return folded; |
5474 | } |
5475 | |
5476 | if (MDefinition* folded = tryFoldBigIntPtr(alloc); folded != this) { |
5477 | return folded; |
5478 | } |
5479 | |
5480 | if (MDefinition* folded = tryFoldBigInt(alloc); folded != this) { |
5481 | return folded; |
5482 | } |
5483 | |
5484 | return this; |
5485 | } |
5486 | |
5487 | void MCompare::trySpecializeFloat32(TempAllocator& alloc) { |
5488 | if (AllOperandsCanProduceFloat32(this) && compareType_ == Compare_Double) { |
5489 | compareType_ = Compare_Float32; |
5490 | } else { |
5491 | ConvertOperandsToDouble(this, alloc); |
5492 | } |
5493 | } |
5494 | |
5495 | MDefinition* MNot::foldsTo(TempAllocator& alloc) { |
5496 | // Fold if the input is constant |
5497 | if (MConstant* inputConst = input()->maybeConstantValue()) { |
5498 | bool b; |
5499 | if (inputConst->valueToBoolean(&b)) { |
5500 | if (type() == MIRType::Int32 || type() == MIRType::Int64) { |
5501 | return MConstant::New(alloc, Int32Value(!b)); |
5502 | } |
5503 | return MConstant::New(alloc, BooleanValue(!b)); |
5504 | } |
5505 | } |
5506 | |
5507 | // If the operand of the Not is itself a Not, they cancel out. But we can't |
5508 | // always convert Not(Not(x)) to x because that may loose the conversion to |
5509 | // boolean. We can simplify Not(Not(Not(x))) to Not(x) though. |
5510 | MDefinition* op = getOperand(0); |
5511 | if (op->isNot()) { |
5512 | MDefinition* opop = op->getOperand(0); |
5513 | if (opop->isNot()) { |
5514 | return opop; |
5515 | } |
5516 | } |
5517 | |
5518 | // Not of an undefined or null value is always true |
5519 | if (input()->type() == MIRType::Undefined || |
5520 | input()->type() == MIRType::Null) { |
5521 | return MConstant::New(alloc, BooleanValue(true)); |
5522 | } |
5523 | |
5524 | // Not of a symbol is always false. |
5525 | if (input()->type() == MIRType::Symbol) { |
5526 | return MConstant::New(alloc, BooleanValue(false)); |
5527 | } |
5528 | |
5529 | // Drop the conversion in `Not(Int64ToBigInt(int64))` to `Not(int64)`. |
5530 | if (input()->isInt64ToBigInt()) { |
5531 | return MNot::New(alloc, input()->toInt64ToBigInt()->input()); |
5532 | } |
5533 | |
5534 | // Drop the conversion in `Not(IntPtrToBigInt(intptr))` to `Not(intptr)`. |
5535 | if (input()->isIntPtrToBigInt()) { |
5536 | return MNot::New(alloc, input()->toIntPtrToBigInt()->input()); |
5537 | } |
5538 | |
5539 | return this; |
5540 | } |
5541 | |
5542 | void MNot::trySpecializeFloat32(TempAllocator& alloc) { |
5543 | (void)EnsureFloatInputOrConvert(this, alloc); |
5544 | } |
5545 | |
5546 | #ifdef JS_JITSPEW1 |
5547 | void MBeta::printOpcode(GenericPrinter& out) const { |
5548 | MDefinition::printOpcode(out); |
5549 | |
5550 | out.printf(" "); |
5551 | comparison_->dump(out); |
5552 | } |
5553 | #endif |
5554 | |
5555 | AliasSet MCreateThis::getAliasSet() const { |
5556 | return AliasSet::Load(AliasSet::Any); |
5557 | } |
5558 | |
5559 | bool MGetArgumentsObjectArg::congruentTo(const MDefinition* ins) const { |
5560 | if (!ins->isGetArgumentsObjectArg()) { |
5561 | return false; |
5562 | } |
5563 | if (ins->toGetArgumentsObjectArg()->argno() != argno()) { |
5564 | return false; |
5565 | } |
5566 | return congruentIfOperandsEqual(ins); |
5567 | } |
5568 | |
5569 | AliasSet MGetArgumentsObjectArg::getAliasSet() const { |
5570 | return AliasSet::Load(AliasSet::Any); |
5571 | } |
5572 | |
5573 | AliasSet MSetArgumentsObjectArg::getAliasSet() const { |
5574 | return AliasSet::Store(AliasSet::Any); |
5575 | } |
5576 | |
5577 | MObjectState::MObjectState(MObjectState* state) |
5578 | : MVariadicInstruction(classOpcode), |
5579 | numSlots_(state->numSlots_), |
5580 | numFixedSlots_(state->numFixedSlots_) { |
5581 | // This instruction is only used as a summary for bailout paths. |
5582 | setResultType(MIRType::Object); |
5583 | setRecoveredOnBailout(); |
5584 | } |
5585 | |
5586 | MObjectState::MObjectState(JSObject* templateObject) |
5587 | : MObjectState(templateObject->as<NativeObject>().shape()) {} |
5588 | |
5589 | MObjectState::MObjectState(const Shape* shape) |
5590 | : MVariadicInstruction(classOpcode) { |
5591 | // This instruction is only used as a summary for bailout paths. |
5592 | setResultType(MIRType::Object); |
5593 | setRecoveredOnBailout(); |
5594 | |
5595 | numSlots_ = shape->asShared().slotSpan(); |
5596 | numFixedSlots_ = shape->asShared().numFixedSlots(); |
5597 | } |
5598 | |
5599 | /* static */ |
5600 | JSObject* MObjectState::templateObjectOf(MDefinition* obj) { |
5601 | // MNewPlainObject uses a shape constant, not an object. |
5602 | MOZ_ASSERT(!obj->isNewPlainObject())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!obj->isNewPlainObject())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!obj->isNewPlainObject()) )), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!obj->isNewPlainObject()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5602); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!obj->isNewPlainObject()" ")"); do { *((volatile int*)__null) = 5602; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5603 | |
5604 | if (obj->isNewObject()) { |
5605 | return obj->toNewObject()->templateObject(); |
5606 | } else if (obj->isNewCallObject()) { |
5607 | return obj->toNewCallObject()->templateObject(); |
5608 | } else if (obj->isNewIterator()) { |
5609 | return obj->toNewIterator()->templateObject(); |
5610 | } |
5611 | |
5612 | MOZ_CRASH("unreachable")do { do { } while (false); MOZ_ReportCrash("" "unreachable", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5612); AnnotateMozCrashReason("MOZ_CRASH(" "unreachable" ")" ); do { *((volatile int*)__null) = 5612; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
5613 | } |
5614 | |
5615 | bool MObjectState::init(TempAllocator& alloc, MDefinition* obj) { |
5616 | if (!MVariadicInstruction::init(alloc, numSlots() + 1)) { |
5617 | return false; |
5618 | } |
5619 | // +1, for the Object. |
5620 | initOperand(0, obj); |
5621 | return true; |
5622 | } |
5623 | |
5624 | void MObjectState::initFromTemplateObject(TempAllocator& alloc, |
5625 | MDefinition* undefinedVal) { |
5626 | if (object()->isNewPlainObject()) { |
5627 | MOZ_ASSERT(object()->toNewPlainObject()->shape()->asShared().slotSpan() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(object()->toNewPlainObject()->shape()->asShared ().slotSpan() == numSlots())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(object()->toNewPlainObject ()->shape()->asShared().slotSpan() == numSlots()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5628); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()" ")"); do { *((volatile int*)__null) = 5628; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
5628 | numSlots())do { static_assert( mozilla::detail::AssertionConditionType< decltype(object()->toNewPlainObject()->shape()->asShared ().slotSpan() == numSlots())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(object()->toNewPlainObject ()->shape()->asShared().slotSpan() == numSlots()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5628); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()" ")"); do { *((volatile int*)__null) = 5628; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5629 | for (size_t i = 0; i < numSlots(); i++) { |
5630 | initSlot(i, undefinedVal); |
5631 | } |
5632 | return; |
5633 | } |
5634 | |
5635 | JSObject* templateObject = templateObjectOf(object()); |
5636 | |
5637 | // Initialize all the slots of the object state with the value contained in |
5638 | // the template object. This is needed to account values which are baked in |
5639 | // the template objects and not visible in IonMonkey, such as the |
5640 | // uninitialized-lexical magic value of call objects. |
5641 | |
5642 | MOZ_ASSERT(templateObject->is<NativeObject>())do { static_assert( mozilla::detail::AssertionConditionType< decltype(templateObject->is<NativeObject>())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(templateObject->is<NativeObject>()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("templateObject->is<NativeObject>()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5642); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject->is<NativeObject>()" ")"); do { *((volatile int*)__null) = 5642; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5643 | NativeObject& nativeObject = templateObject->as<NativeObject>(); |
5644 | MOZ_ASSERT(nativeObject.slotSpan() == numSlots())do { static_assert( mozilla::detail::AssertionConditionType< decltype(nativeObject.slotSpan() == numSlots())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(! !(nativeObject.slotSpan() == numSlots()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("nativeObject.slotSpan() == numSlots()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeObject.slotSpan() == numSlots()" ")"); do { *((volatile int*)__null) = 5644; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5645 | |
5646 | for (size_t i = 0; i < numSlots(); i++) { |
5647 | Value val = nativeObject.getSlot(i); |
5648 | MDefinition* def = undefinedVal; |
5649 | if (!val.isUndefined()) { |
5650 | MConstant* ins = MConstant::New(alloc, val); |
5651 | block()->insertBefore(this, ins); |
5652 | def = ins; |
5653 | } |
5654 | initSlot(i, def); |
5655 | } |
5656 | } |
5657 | |
5658 | MObjectState* MObjectState::New(TempAllocator& alloc, MDefinition* obj) { |
5659 | MObjectState* res; |
5660 | if (obj->isNewPlainObject()) { |
5661 | const Shape* shape = obj->toNewPlainObject()->shape(); |
5662 | res = new (alloc) MObjectState(shape); |
5663 | } else { |
5664 | JSObject* templateObject = templateObjectOf(obj); |
5665 | MOZ_ASSERT(templateObject, "Unexpected object creation.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(templateObject)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(templateObject))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("templateObject" " (" "Unexpected object creation." ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5665); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject" ") (" "Unexpected object creation." ")"); do { *((volatile int *)__null) = 5665; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
5666 | res = new (alloc) MObjectState(templateObject); |
5667 | } |
5668 | |
5669 | if (!res || !res->init(alloc, obj)) { |
5670 | return nullptr; |
5671 | } |
5672 | return res; |
5673 | } |
5674 | |
5675 | MObjectState* MObjectState::Copy(TempAllocator& alloc, MObjectState* state) { |
5676 | MObjectState* res = new (alloc) MObjectState(state); |
5677 | if (!res || !res->init(alloc, state->object())) { |
5678 | return nullptr; |
5679 | } |
5680 | for (size_t i = 0; i < res->numSlots(); i++) { |
5681 | res->initSlot(i, state->getSlot(i)); |
5682 | } |
5683 | return res; |
5684 | } |
5685 | |
5686 | MArrayState::MArrayState(MDefinition* arr) : MVariadicInstruction(classOpcode) { |
5687 | // This instruction is only used as a summary for bailout paths. |
5688 | setResultType(MIRType::Object); |
5689 | setRecoveredOnBailout(); |
5690 | if (arr->isNewArrayObject()) { |
5691 | numElements_ = arr->toNewArrayObject()->length(); |
5692 | } else { |
5693 | numElements_ = arr->toNewArray()->length(); |
5694 | } |
5695 | } |
5696 | |
5697 | bool MArrayState::init(TempAllocator& alloc, MDefinition* obj, |
5698 | MDefinition* len) { |
5699 | if (!MVariadicInstruction::init(alloc, numElements() + 2)) { |
5700 | return false; |
5701 | } |
5702 | // +1, for the Array object. |
5703 | initOperand(0, obj); |
5704 | // +1, for the length value of the array. |
5705 | initOperand(1, len); |
5706 | return true; |
5707 | } |
5708 | |
5709 | void MArrayState::initFromTemplateObject(TempAllocator& alloc, |
5710 | MDefinition* undefinedVal) { |
5711 | for (size_t i = 0; i < numElements(); i++) { |
5712 | initElement(i, undefinedVal); |
5713 | } |
5714 | } |
5715 | |
5716 | MArrayState* MArrayState::New(TempAllocator& alloc, MDefinition* arr, |
5717 | MDefinition* initLength) { |
5718 | MArrayState* res = new (alloc) MArrayState(arr); |
5719 | if (!res || !res->init(alloc, arr, initLength)) { |
5720 | return nullptr; |
5721 | } |
5722 | return res; |
5723 | } |
5724 | |
5725 | MArrayState* MArrayState::Copy(TempAllocator& alloc, MArrayState* state) { |
5726 | MDefinition* arr = state->array(); |
5727 | MDefinition* len = state->initializedLength(); |
5728 | MArrayState* res = new (alloc) MArrayState(arr); |
5729 | if (!res || !res->init(alloc, arr, len)) { |
5730 | return nullptr; |
5731 | } |
5732 | for (size_t i = 0; i < res->numElements(); i++) { |
5733 | res->initElement(i, state->getElement(i)); |
5734 | } |
5735 | return res; |
5736 | } |
5737 | |
5738 | MNewArray::MNewArray(uint32_t length, MConstant* templateConst, |
5739 | gc::Heap initialHeap, bool vmCall) |
5740 | : MUnaryInstruction(classOpcode, templateConst), |
5741 | length_(length), |
5742 | initialHeap_(initialHeap), |
5743 | vmCall_(vmCall) { |
5744 | setResultType(MIRType::Object); |
5745 | } |
5746 | |
5747 | MDefinition::AliasType MLoadFixedSlot::mightAlias( |
5748 | const MDefinition* def) const { |
5749 | if (def->isStoreFixedSlot()) { |
5750 | const MStoreFixedSlot* store = def->toStoreFixedSlot(); |
5751 | if (store->slot() != slot()) { |
5752 | return AliasType::NoAlias; |
5753 | } |
5754 | if (store->object() != object()) { |
5755 | return AliasType::MayAlias; |
5756 | } |
5757 | return AliasType::MustAlias; |
5758 | } |
5759 | return AliasType::MayAlias; |
5760 | } |
5761 | |
5762 | MDefinition* MLoadFixedSlot::foldsTo(TempAllocator& alloc) { |
5763 | if (MDefinition* def = foldsToStore(alloc)) { |
5764 | return def; |
5765 | } |
5766 | |
5767 | return this; |
5768 | } |
5769 | |
5770 | MDefinition::AliasType MLoadFixedSlotAndUnbox::mightAlias( |
5771 | const MDefinition* def) const { |
5772 | if (def->isStoreFixedSlot()) { |
5773 | const MStoreFixedSlot* store = def->toStoreFixedSlot(); |
5774 | if (store->slot() != slot()) { |
5775 | return AliasType::NoAlias; |
5776 | } |
5777 | if (store->object() != object()) { |
5778 | return AliasType::MayAlias; |
5779 | } |
5780 | return AliasType::MustAlias; |
5781 | } |
5782 | return AliasType::MayAlias; |
5783 | } |
5784 | |
5785 | MDefinition* MLoadFixedSlotAndUnbox::foldsTo(TempAllocator& alloc) { |
5786 | if (MDefinition* def = foldsToStore(alloc)) { |
5787 | return def; |
5788 | } |
5789 | |
5790 | return this; |
5791 | } |
5792 | |
5793 | MDefinition::AliasType MLoadDynamicSlot::mightAlias( |
5794 | const MDefinition* def) const { |
5795 | if (def->isStoreDynamicSlot()) { |
5796 | const MStoreDynamicSlot* store = def->toStoreDynamicSlot(); |
5797 | if (store->slot() != slot()) { |
5798 | return AliasType::NoAlias; |
5799 | } |
5800 | |
5801 | if (store->slots() != slots()) { |
5802 | return AliasType::MayAlias; |
5803 | } |
5804 | |
5805 | return AliasType::MustAlias; |
5806 | } |
5807 | return AliasType::MayAlias; |
5808 | } |
5809 | |
5810 | HashNumber MLoadDynamicSlot::valueHash() const { |
5811 | HashNumber hash = MDefinition::valueHash(); |
5812 | hash = addU32ToHash(hash, slot_); |
5813 | return hash; |
5814 | } |
5815 | |
5816 | MDefinition* MLoadDynamicSlot::foldsTo(TempAllocator& alloc) { |
5817 | if (MDefinition* def = foldsToStore(alloc)) { |
5818 | return def; |
5819 | } |
5820 | |
5821 | return this; |
5822 | } |
5823 | |
5824 | #ifdef JS_JITSPEW1 |
5825 | void MLoadDynamicSlot::printOpcode(GenericPrinter& out) const { |
5826 | MDefinition::printOpcode(out); |
5827 | out.printf(" (slot %u)", slot()); |
5828 | } |
5829 | |
5830 | void MLoadDynamicSlotAndUnbox::printOpcode(GenericPrinter& out) const { |
5831 | MDefinition::printOpcode(out); |
5832 | out.printf(" (slot %zu)", slot()); |
5833 | } |
5834 | |
5835 | void MStoreDynamicSlot::printOpcode(GenericPrinter& out) const { |
5836 | MDefinition::printOpcode(out); |
5837 | out.printf(" (slot %u)", slot()); |
5838 | } |
5839 | |
5840 | void MLoadFixedSlot::printOpcode(GenericPrinter& out) const { |
5841 | MDefinition::printOpcode(out); |
5842 | out.printf(" (slot %zu)", slot()); |
5843 | } |
5844 | |
5845 | void MLoadFixedSlotAndUnbox::printOpcode(GenericPrinter& out) const { |
5846 | MDefinition::printOpcode(out); |
5847 | out.printf(" (slot %zu)", slot()); |
5848 | } |
5849 | |
5850 | void MStoreFixedSlot::printOpcode(GenericPrinter& out) const { |
5851 | MDefinition::printOpcode(out); |
5852 | out.printf(" (slot %zu)", slot()); |
5853 | } |
5854 | #endif |
5855 | |
5856 | MDefinition* MGuardFunctionScript::foldsTo(TempAllocator& alloc) { |
5857 | MDefinition* in = input(); |
5858 | if (in->isLambda() && |
5859 | in->toLambda()->templateFunction()->baseScript() == expected()) { |
5860 | return in; |
5861 | } |
5862 | return this; |
5863 | } |
5864 | |
5865 | MDefinition* MFunctionEnvironment::foldsTo(TempAllocator& alloc) { |
5866 | if (input()->isLambda()) { |
5867 | return input()->toLambda()->environmentChain(); |
5868 | } |
5869 | if (input()->isFunctionWithProto()) { |
5870 | return input()->toFunctionWithProto()->environmentChain(); |
5871 | } |
5872 | return this; |
5873 | } |
5874 | |
5875 | static bool AddIsANonZeroAdditionOf(MAdd* add, MDefinition* ins) { |
5876 | if (add->lhs() != ins && add->rhs() != ins) { |
5877 | return false; |
5878 | } |
5879 | MDefinition* other = (add->lhs() == ins) ? add->rhs() : add->lhs(); |
5880 | if (!IsNumberType(other->type())) { |
5881 | return false; |
5882 | } |
5883 | if (!other->isConstant()) { |
5884 | return false; |
5885 | } |
5886 | if (other->toConstant()->numberToDouble() == 0) { |
5887 | return false; |
5888 | } |
5889 | return true; |
5890 | } |
5891 | |
5892 | // Skip over instructions that usually appear between the actual index |
5893 | // value being used and the MLoadElement. |
5894 | // They don't modify the index value in a meaningful way. |
5895 | static MDefinition* SkipUninterestingInstructions(MDefinition* ins) { |
5896 | // Drop the MToNumberInt32 added by the TypePolicy for double and float |
5897 | // values. |
5898 | if (ins->isToNumberInt32()) { |
5899 | return SkipUninterestingInstructions(ins->toToNumberInt32()->input()); |
5900 | } |
5901 | |
5902 | // Ignore the bounds check, which don't modify the index. |
5903 | if (ins->isBoundsCheck()) { |
5904 | return SkipUninterestingInstructions(ins->toBoundsCheck()->index()); |
5905 | } |
5906 | |
5907 | // Masking the index for Spectre-mitigation is not observable. |
5908 | if (ins->isSpectreMaskIndex()) { |
5909 | return SkipUninterestingInstructions(ins->toSpectreMaskIndex()->index()); |
5910 | } |
5911 | |
5912 | return ins; |
5913 | } |
5914 | |
5915 | static bool DefinitelyDifferentValue(MDefinition* ins1, MDefinition* ins2) { |
5916 | ins1 = SkipUninterestingInstructions(ins1); |
5917 | ins2 = SkipUninterestingInstructions(ins2); |
5918 | |
5919 | if (ins1 == ins2) { |
5920 | return false; |
5921 | } |
5922 | |
5923 | // For constants check they are not equal. |
5924 | if (ins1->isConstant() && ins2->isConstant()) { |
5925 | MConstant* cst1 = ins1->toConstant(); |
5926 | MConstant* cst2 = ins2->toConstant(); |
5927 | |
5928 | if (!cst1->isTypeRepresentableAsDouble() || |
5929 | !cst2->isTypeRepresentableAsDouble()) { |
5930 | return false; |
5931 | } |
5932 | |
5933 | // Be conservative and only allow values that fit into int32. |
5934 | int32_t n1, n2; |
5935 | if (!mozilla::NumberIsInt32(cst1->numberToDouble(), &n1) || |
5936 | !mozilla::NumberIsInt32(cst2->numberToDouble(), &n2)) { |
5937 | return false; |
5938 | } |
5939 | |
5940 | return n1 != n2; |
5941 | } |
5942 | |
5943 | // Check if "ins1 = ins2 + cte", which would make both instructions |
5944 | // have different values. |
5945 | if (ins1->isAdd()) { |
5946 | if (AddIsANonZeroAdditionOf(ins1->toAdd(), ins2)) { |
5947 | return true; |
5948 | } |
5949 | } |
5950 | if (ins2->isAdd()) { |
5951 | if (AddIsANonZeroAdditionOf(ins2->toAdd(), ins1)) { |
5952 | return true; |
5953 | } |
5954 | } |
5955 | |
5956 | return false; |
5957 | } |
5958 | |
5959 | MDefinition::AliasType MLoadElement::mightAlias(const MDefinition* def) const { |
5960 | if (def->isStoreElement()) { |
5961 | const MStoreElement* store = def->toStoreElement(); |
5962 | if (store->index() != index()) { |
5963 | if (DefinitelyDifferentValue(store->index(), index())) { |
5964 | return AliasType::NoAlias; |
5965 | } |
5966 | return AliasType::MayAlias; |
5967 | } |
5968 | |
5969 | if (store->elements() != elements()) { |
5970 | return AliasType::MayAlias; |
5971 | } |
5972 | |
5973 | return AliasType::MustAlias; |
5974 | } |
5975 | return AliasType::MayAlias; |
5976 | } |
5977 | |
5978 | MDefinition* MLoadElement::foldsTo(TempAllocator& alloc) { |
5979 | if (MDefinition* def = foldsToStore(alloc)) { |
5980 | return def; |
5981 | } |
5982 | |
5983 | return this; |
5984 | } |
5985 | |
5986 | void MSqrt::trySpecializeFloat32(TempAllocator& alloc) { |
5987 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
5988 | setResultType(MIRType::Float32); |
5989 | specialization_ = MIRType::Float32; |
5990 | } |
5991 | } |
5992 | |
5993 | MDefinition* MClz::foldsTo(TempAllocator& alloc) { |
5994 | if (num()->isConstant()) { |
5995 | MConstant* c = num()->toConstant(); |
5996 | if (type() == MIRType::Int32) { |
5997 | int32_t n = c->toInt32(); |
5998 | if (n == 0) { |
5999 | return MConstant::New(alloc, Int32Value(32)); |
6000 | } |
6001 | return MConstant::New(alloc, |
6002 | Int32Value(mozilla::CountLeadingZeroes32(n))); |
6003 | } |
6004 | int64_t n = c->toInt64(); |
6005 | if (n == 0) { |
6006 | return MConstant::NewInt64(alloc, int64_t(64)); |
6007 | } |
6008 | return MConstant::NewInt64(alloc, |
6009 | int64_t(mozilla::CountLeadingZeroes64(n))); |
6010 | } |
6011 | |
6012 | return this; |
6013 | } |
6014 | |
6015 | MDefinition* MCtz::foldsTo(TempAllocator& alloc) { |
6016 | if (num()->isConstant()) { |
6017 | MConstant* c = num()->toConstant(); |
6018 | if (type() == MIRType::Int32) { |
6019 | int32_t n = num()->toConstant()->toInt32(); |
6020 | if (n == 0) { |
6021 | return MConstant::New(alloc, Int32Value(32)); |
6022 | } |
6023 | return MConstant::New(alloc, |
6024 | Int32Value(mozilla::CountTrailingZeroes32(n))); |
6025 | } |
6026 | int64_t n = c->toInt64(); |
6027 | if (n == 0) { |
6028 | return MConstant::NewInt64(alloc, int64_t(64)); |
6029 | } |
6030 | return MConstant::NewInt64(alloc, |
6031 | int64_t(mozilla::CountTrailingZeroes64(n))); |
6032 | } |
6033 | |
6034 | return this; |
6035 | } |
6036 | |
6037 | MDefinition* MPopcnt::foldsTo(TempAllocator& alloc) { |
6038 | if (num()->isConstant()) { |
6039 | MConstant* c = num()->toConstant(); |
6040 | if (type() == MIRType::Int32) { |
6041 | int32_t n = num()->toConstant()->toInt32(); |
6042 | return MConstant::New(alloc, Int32Value(mozilla::CountPopulation32(n))); |
6043 | } |
6044 | int64_t n = c->toInt64(); |
6045 | return MConstant::NewInt64(alloc, int64_t(mozilla::CountPopulation64(n))); |
6046 | } |
6047 | |
6048 | return this; |
6049 | } |
6050 | |
6051 | MDefinition* MBoundsCheck::foldsTo(TempAllocator& alloc) { |
6052 | if (type() == MIRType::Int32 && index()->isConstant() && |
6053 | length()->isConstant()) { |
6054 | uint32_t len = length()->toConstant()->toInt32(); |
6055 | uint32_t idx = index()->toConstant()->toInt32(); |
6056 | if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len) { |
6057 | return index(); |
6058 | } |
6059 | } |
6060 | |
6061 | return this; |
6062 | } |
6063 | |
6064 | MDefinition* MTableSwitch::foldsTo(TempAllocator& alloc) { |
6065 | MDefinition* op = getOperand(0); |
6066 | |
6067 | // If we only have one successor, convert to a plain goto to the only |
6068 | // successor. TableSwitch indices are numeric; other types will always go to |
6069 | // the only successor. |
6070 | if (numSuccessors() == 1 || |
6071 | (op->type() != MIRType::Value && !IsNumberType(op->type()))) { |
6072 | return MGoto::New(alloc, getDefault()); |
6073 | } |
6074 | |
6075 | if (MConstant* opConst = op->maybeConstantValue()) { |
6076 | if (op->type() == MIRType::Int32) { |
6077 | int32_t i = opConst->toInt32() - low_; |
6078 | MBasicBlock* target; |
6079 | if (size_t(i) < numCases()) { |
6080 | target = getCase(size_t(i)); |
6081 | } else { |
6082 | target = getDefault(); |
6083 | } |
6084 | MOZ_ASSERT(target)do { static_assert( mozilla::detail::AssertionConditionType< decltype(target)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(target))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("target", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 6084); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")" ); do { *((volatile int*)__null) = 6084; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6085 | return MGoto::New(alloc, target); |
6086 | } |
6087 | } |
6088 | |
6089 | return this; |
6090 | } |
6091 | |
6092 | MDefinition* MArrayJoin::foldsTo(TempAllocator& alloc) { |
6093 | MDefinition* arr = array(); |
6094 | |
6095 | if (!arr->isStringSplit()) { |
6096 | return this; |
6097 | } |
6098 | |
6099 | setRecoveredOnBailout(); |
6100 | if (arr->hasLiveDefUses()) { |
6101 | setNotRecoveredOnBailout(); |
6102 | return this; |
6103 | } |
6104 | |
6105 | // The MStringSplit won't generate any code. |
6106 | arr->setRecoveredOnBailout(); |
6107 | |
6108 | // We're replacing foo.split(bar).join(baz) by |
6109 | // foo.replace(bar, baz). MStringSplit could be recovered by |
6110 | // a bailout. As we are removing its last use, and its result |
6111 | // could be captured by a resume point, this MStringSplit will |
6112 | // be executed on the bailout path. |
6113 | MDefinition* string = arr->toStringSplit()->string(); |
6114 | MDefinition* pattern = arr->toStringSplit()->separator(); |
6115 | MDefinition* replacement = sep(); |
6116 | |
6117 | MStringReplace* substr = |
6118 | MStringReplace::New(alloc, string, pattern, replacement); |
6119 | substr->setFlatReplacement(); |
6120 | return substr; |
6121 | } |
6122 | |
6123 | MDefinition* MGetFirstDollarIndex::foldsTo(TempAllocator& alloc) { |
6124 | MDefinition* strArg = str(); |
6125 | if (!strArg->isConstant()) { |
6126 | return this; |
6127 | } |
6128 | |
6129 | JSLinearString* str = &strArg->toConstant()->toString()->asLinear(); |
6130 | int32_t index = GetFirstDollarIndexRawFlat(str); |
6131 | return MConstant::New(alloc, Int32Value(index)); |
6132 | } |
6133 | |
6134 | AliasSet MThrowRuntimeLexicalError::getAliasSet() const { |
6135 | return AliasSet::Store(AliasSet::ExceptionState); |
6136 | } |
6137 | |
6138 | AliasSet MSlots::getAliasSet() const { |
6139 | return AliasSet::Load(AliasSet::ObjectFields); |
6140 | } |
6141 | |
6142 | MDefinition::AliasType MSlots::mightAlias(const MDefinition* store) const { |
6143 | // ArrayPush only modifies object elements, but not object slots. |
6144 | if (store->isArrayPush()) { |
6145 | return AliasType::NoAlias; |
6146 | } |
6147 | return MInstruction::mightAlias(store); |
6148 | } |
6149 | |
6150 | AliasSet MElements::getAliasSet() const { |
6151 | return AliasSet::Load(AliasSet::ObjectFields); |
6152 | } |
6153 | |
6154 | AliasSet MInitializedLength::getAliasSet() const { |
6155 | return AliasSet::Load(AliasSet::ObjectFields); |
6156 | } |
6157 | |
6158 | AliasSet MSetInitializedLength::getAliasSet() const { |
6159 | return AliasSet::Store(AliasSet::ObjectFields); |
6160 | } |
6161 | |
6162 | AliasSet MObjectKeysLength::getAliasSet() const { |
6163 | return AliasSet::Load(AliasSet::ObjectFields); |
6164 | } |
6165 | |
6166 | AliasSet MArrayLength::getAliasSet() const { |
6167 | return AliasSet::Load(AliasSet::ObjectFields); |
6168 | } |
6169 | |
6170 | AliasSet MSetArrayLength::getAliasSet() const { |
6171 | return AliasSet::Store(AliasSet::ObjectFields); |
6172 | } |
6173 | |
6174 | AliasSet MFunctionLength::getAliasSet() const { |
6175 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6176 | AliasSet::DynamicSlot); |
6177 | } |
6178 | |
6179 | AliasSet MFunctionName::getAliasSet() const { |
6180 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6181 | AliasSet::DynamicSlot); |
6182 | } |
6183 | |
6184 | AliasSet MArrayBufferByteLength::getAliasSet() const { |
6185 | return AliasSet::Load(AliasSet::FixedSlot); |
6186 | } |
6187 | |
6188 | AliasSet MArrayBufferViewLength::getAliasSet() const { |
6189 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset); |
6190 | } |
6191 | |
6192 | AliasSet MArrayBufferViewByteOffset::getAliasSet() const { |
6193 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset); |
6194 | } |
6195 | |
6196 | AliasSet MArrayBufferViewElements::getAliasSet() const { |
6197 | return AliasSet::Load(AliasSet::ObjectFields); |
6198 | } |
6199 | |
6200 | AliasSet MGuardHasAttachedArrayBuffer::getAliasSet() const { |
6201 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot); |
6202 | } |
6203 | |
6204 | AliasSet MResizableTypedArrayByteOffsetMaybeOutOfBounds::getAliasSet() const { |
6205 | // Loads the byteOffset and additionally checks for detached buffers, so the |
6206 | // alias set also has to include |ObjectFields| and |FixedSlot|. |
6207 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset | |
6208 | AliasSet::ObjectFields | AliasSet::FixedSlot); |
6209 | } |
6210 | |
6211 | AliasSet MResizableTypedArrayLength::getAliasSet() const { |
6212 | // Loads the length and byteOffset slots, the shared-elements flag, the |
6213 | // auto-length fixed slot, and the shared raw-buffer length. |
6214 | auto flags = AliasSet::ArrayBufferViewLengthOrOffset | |
6215 | AliasSet::ObjectFields | AliasSet::FixedSlot | |
6216 | AliasSet::SharedArrayRawBufferLength; |
6217 | |
6218 | // When a barrier is needed make the instruction effectful by giving it a |
6219 | // "store" effect. Also prevent reordering LoadUnboxedScalar before this |
6220 | // instruction by including |UnboxedElement| in the alias set. |
6221 | if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) { |
6222 | return AliasSet::Store(flags | AliasSet::UnboxedElement); |
6223 | } |
6224 | return AliasSet::Load(flags); |
6225 | } |
6226 | |
6227 | bool MResizableTypedArrayLength::congruentTo(const MDefinition* ins) const { |
6228 | if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) { |
6229 | return false; |
6230 | } |
6231 | return congruentIfOperandsEqual(ins); |
6232 | } |
6233 | |
6234 | AliasSet MResizableDataViewByteLength::getAliasSet() const { |
6235 | // Loads the length and byteOffset slots, the shared-elements flag, the |
6236 | // auto-length fixed slot, and the shared raw-buffer length. |
6237 | auto flags = AliasSet::ArrayBufferViewLengthOrOffset | |
6238 | AliasSet::ObjectFields | AliasSet::FixedSlot | |
6239 | AliasSet::SharedArrayRawBufferLength; |
6240 | |
6241 | // When a barrier is needed make the instruction effectful by giving it a |
6242 | // "store" effect. Also prevent reordering LoadUnboxedScalar before this |
6243 | // instruction by including |UnboxedElement| in the alias set. |
6244 | if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) { |
6245 | return AliasSet::Store(flags | AliasSet::UnboxedElement); |
6246 | } |
6247 | return AliasSet::Load(flags); |
6248 | } |
6249 | |
6250 | bool MResizableDataViewByteLength::congruentTo(const MDefinition* ins) const { |
6251 | if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) { |
6252 | return false; |
6253 | } |
6254 | return congruentIfOperandsEqual(ins); |
6255 | } |
6256 | |
6257 | AliasSet MGrowableSharedArrayBufferByteLength::getAliasSet() const { |
6258 | // Requires a barrier, so make the instruction effectful by giving it a |
6259 | // "store" effect. Also prevent reordering LoadUnboxedScalar before this |
6260 | // instruction by including |UnboxedElement| in the alias set. |
6261 | return AliasSet::Store(AliasSet::FixedSlot | |
6262 | AliasSet::SharedArrayRawBufferLength | |
6263 | AliasSet::UnboxedElement); |
6264 | } |
6265 | |
6266 | AliasSet MGuardResizableArrayBufferViewInBounds::getAliasSet() const { |
6267 | // Additionally reads the |initialLength| and |initialByteOffset| slots, but |
6268 | // since these can't change after construction, we don't need to track them. |
6269 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset); |
6270 | } |
6271 | |
6272 | AliasSet MGuardResizableArrayBufferViewInBoundsOrDetached::getAliasSet() const { |
6273 | // Loads the byteOffset and additionally checks for detached buffers, so the |
6274 | // alias set also has to include |ObjectFields| and |FixedSlot|. |
6275 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset | |
6276 | AliasSet::ObjectFields | AliasSet::FixedSlot); |
6277 | } |
6278 | |
6279 | AliasSet MArrayPush::getAliasSet() const { |
6280 | return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); |
6281 | } |
6282 | |
6283 | MDefinition* MGuardNumberToIntPtrIndex::foldsTo(TempAllocator& alloc) { |
6284 | MDefinition* input = this->input(); |
6285 | |
6286 | if (input->isToDouble() && input->getOperand(0)->type() == MIRType::Int32) { |
6287 | return MInt32ToIntPtr::New(alloc, input->getOperand(0)); |
6288 | } |
6289 | |
6290 | if (!input->isConstant()) { |
6291 | return this; |
6292 | } |
6293 | |
6294 | // Fold constant double representable as intptr to intptr. |
6295 | int64_t ival; |
6296 | if (!mozilla::NumberEqualsInt64(input->toConstant()->toDouble(), &ival)) { |
6297 | // If not representable as an int64, this access is equal to an OOB access. |
6298 | // So replace it with a known int64/intptr value which also produces an OOB |
6299 | // access. If we don't support OOB accesses we have to bail out. |
6300 | if (!supportOOB()) { |
6301 | return this; |
6302 | } |
6303 | ival = -1; |
6304 | } |
6305 | |
6306 | if (ival < INTPTR_MIN(-9223372036854775807L-1) || ival > INTPTR_MAX(9223372036854775807L)) { |
6307 | return this; |
6308 | } |
6309 | |
6310 | return MConstant::NewIntPtr(alloc, intptr_t(ival)); |
6311 | } |
6312 | |
6313 | MDefinition* MIsObject::foldsTo(TempAllocator& alloc) { |
6314 | if (!object()->isBox()) { |
6315 | return this; |
6316 | } |
6317 | |
6318 | MDefinition* unboxed = object()->getOperand(0); |
6319 | if (unboxed->type() == MIRType::Object) { |
6320 | return MConstant::New(alloc, BooleanValue(true)); |
6321 | } |
6322 | |
6323 | return this; |
6324 | } |
6325 | |
6326 | MDefinition* MIsNullOrUndefined::foldsTo(TempAllocator& alloc) { |
6327 | MDefinition* input = value(); |
6328 | if (input->isBox()) { |
6329 | input = input->toBox()->input(); |
6330 | } |
6331 | |
6332 | if (input->definitelyType({MIRType::Null, MIRType::Undefined})) { |
6333 | return MConstant::New(alloc, BooleanValue(true)); |
6334 | } |
6335 | |
6336 | if (!input->mightBeType(MIRType::Null) && |
6337 | !input->mightBeType(MIRType::Undefined)) { |
6338 | return MConstant::New(alloc, BooleanValue(false)); |
6339 | } |
6340 | |
6341 | return this; |
6342 | } |
6343 | |
6344 | AliasSet MHomeObjectSuperBase::getAliasSet() const { |
6345 | return AliasSet::Load(AliasSet::ObjectFields); |
6346 | } |
6347 | |
6348 | MDefinition* MGuardValue::foldsTo(TempAllocator& alloc) { |
6349 | if (MConstant* cst = value()->maybeConstantValue()) { |
6350 | if (cst->toJSValue() == expected()) { |
6351 | return value(); |
6352 | } |
6353 | } |
6354 | |
6355 | return this; |
6356 | } |
6357 | |
6358 | MDefinition* MGuardNullOrUndefined::foldsTo(TempAllocator& alloc) { |
6359 | MDefinition* input = value(); |
6360 | if (input->isBox()) { |
6361 | input = input->toBox()->input(); |
6362 | } |
6363 | |
6364 | if (input->definitelyType({MIRType::Null, MIRType::Undefined})) { |
6365 | return value(); |
6366 | } |
6367 | |
6368 | return this; |
6369 | } |
6370 | |
6371 | MDefinition* MGuardIsNotObject::foldsTo(TempAllocator& alloc) { |
6372 | MDefinition* input = value(); |
6373 | if (input->isBox()) { |
6374 | input = input->toBox()->input(); |
6375 | } |
6376 | |
6377 | if (!input->mightBeType(MIRType::Object)) { |
6378 | return value(); |
6379 | } |
6380 | |
6381 | return this; |
6382 | } |
6383 | |
6384 | MDefinition* MGuardObjectIdentity::foldsTo(TempAllocator& alloc) { |
6385 | if (object()->isConstant() && expected()->isConstant()) { |
6386 | JSObject* obj = &object()->toConstant()->toObject(); |
6387 | JSObject* other = &expected()->toConstant()->toObject(); |
6388 | if (!bailOnEquality()) { |
6389 | if (obj == other) { |
6390 | return object(); |
6391 | } |
6392 | } else { |
6393 | if (obj != other) { |
6394 | return object(); |
6395 | } |
6396 | } |
6397 | } |
6398 | |
6399 | if (!bailOnEquality() && object()->isNurseryObject() && |
6400 | expected()->isNurseryObject()) { |
6401 | uint32_t objIndex = object()->toNurseryObject()->nurseryIndex(); |
6402 | uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex(); |
6403 | if (objIndex == otherIndex) { |
6404 | return object(); |
6405 | } |
6406 | } |
6407 | |
6408 | return this; |
6409 | } |
6410 | |
6411 | MDefinition* MGuardSpecificFunction::foldsTo(TempAllocator& alloc) { |
6412 | if (function()->isConstant() && expected()->isConstant()) { |
6413 | JSObject* fun = &function()->toConstant()->toObject(); |
6414 | JSObject* other = &expected()->toConstant()->toObject(); |
6415 | if (fun == other) { |
6416 | return function(); |
6417 | } |
6418 | } |
6419 | |
6420 | if (function()->isNurseryObject() && expected()->isNurseryObject()) { |
6421 | uint32_t funIndex = function()->toNurseryObject()->nurseryIndex(); |
6422 | uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex(); |
6423 | if (funIndex == otherIndex) { |
6424 | return function(); |
6425 | } |
6426 | } |
6427 | |
6428 | return this; |
6429 | } |
6430 | |
6431 | MDefinition* MGuardSpecificAtom::foldsTo(TempAllocator& alloc) { |
6432 | if (str()->isConstant()) { |
6433 | JSString* s = str()->toConstant()->toString(); |
6434 | if (s->isAtom()) { |
6435 | JSAtom* cstAtom = &s->asAtom(); |
6436 | if (cstAtom == atom()) { |
6437 | return str(); |
6438 | } |
6439 | } |
6440 | } |
6441 | |
6442 | return this; |
6443 | } |
6444 | |
6445 | MDefinition* MGuardSpecificSymbol::foldsTo(TempAllocator& alloc) { |
6446 | if (symbol()->isConstant()) { |
6447 | if (symbol()->toConstant()->toSymbol() == expected()) { |
6448 | return symbol(); |
6449 | } |
6450 | } |
6451 | |
6452 | return this; |
6453 | } |
6454 | |
6455 | MDefinition* MGuardSpecificInt32::foldsTo(TempAllocator& alloc) { |
6456 | if (num()->isConstant() && num()->toConstant()->isInt32(expected())) { |
6457 | return num(); |
6458 | } |
6459 | return this; |
6460 | } |
6461 | |
6462 | bool MCallBindVar::congruentTo(const MDefinition* ins) const { |
6463 | if (!ins->isCallBindVar()) { |
6464 | return false; |
6465 | } |
6466 | return congruentIfOperandsEqual(ins); |
6467 | } |
6468 | |
6469 | bool MGuardShape::congruentTo(const MDefinition* ins) const { |
6470 | if (!ins->isGuardShape()) { |
6471 | return false; |
6472 | } |
6473 | if (shape() != ins->toGuardShape()->shape()) { |
6474 | return false; |
6475 | } |
6476 | return congruentIfOperandsEqual(ins); |
6477 | } |
6478 | |
6479 | AliasSet MGuardShape::getAliasSet() const { |
6480 | return AliasSet::Load(AliasSet::ObjectFields); |
6481 | } |
6482 | |
6483 | MDefinition::AliasType MGuardShape::mightAlias(const MDefinition* store) const { |
6484 | // These instructions only modify object elements, but not the shape. |
6485 | if (store->isStoreElementHole() || store->isArrayPush()) { |
6486 | return AliasType::NoAlias; |
6487 | } |
6488 | if (object()->isConstantProto()) { |
6489 | const MDefinition* receiverObject = |
6490 | object()->toConstantProto()->getReceiverObject(); |
6491 | switch (store->op()) { |
6492 | case MDefinition::Opcode::StoreFixedSlot: |
6493 | if (store->toStoreFixedSlot()->object()->skipObjectGuards() == |
6494 | receiverObject) { |
6495 | return AliasType::NoAlias; |
6496 | } |
6497 | break; |
6498 | case MDefinition::Opcode::StoreDynamicSlot: |
6499 | if (store->toStoreDynamicSlot() |
6500 | ->slots() |
6501 | ->toSlots() |
6502 | ->object() |
6503 | ->skipObjectGuards() == receiverObject) { |
6504 | return AliasType::NoAlias; |
6505 | } |
6506 | break; |
6507 | case MDefinition::Opcode::AddAndStoreSlot: |
6508 | if (store->toAddAndStoreSlot()->object()->skipObjectGuards() == |
6509 | receiverObject) { |
6510 | return AliasType::NoAlias; |
6511 | } |
6512 | break; |
6513 | case MDefinition::Opcode::AllocateAndStoreSlot: |
6514 | if (store->toAllocateAndStoreSlot()->object()->skipObjectGuards() == |
6515 | receiverObject) { |
6516 | return AliasType::NoAlias; |
6517 | } |
6518 | break; |
6519 | default: |
6520 | break; |
6521 | } |
6522 | } |
6523 | return MInstruction::mightAlias(store); |
6524 | } |
6525 | |
6526 | bool MGuardFuse::congruentTo(const MDefinition* ins) const { |
6527 | if (!ins->isGuardFuse()) { |
6528 | return false; |
6529 | } |
6530 | if (fuseIndex() != ins->toGuardFuse()->fuseIndex()) { |
6531 | return false; |
6532 | } |
6533 | return congruentIfOperandsEqual(ins); |
6534 | } |
6535 | |
6536 | AliasSet MGuardFuse::getAliasSet() const { |
6537 | // The alias set below reflects the set of operations which could cause a fuse |
6538 | // to be popped, and therefore MGuardFuse aliases with. |
6539 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::DynamicSlot | |
6540 | AliasSet::FixedSlot | |
6541 | AliasSet::GlobalGenerationCounter); |
6542 | } |
6543 | |
6544 | AliasSet MGuardMultipleShapes::getAliasSet() const { |
6545 | // Note: This instruction loads the elements of the ListObject used to |
6546 | // store the list of shapes, but that object is internal and not exposed |
6547 | // to script, so it doesn't have to be in the alias set. |
6548 | return AliasSet::Load(AliasSet::ObjectFields); |
6549 | } |
6550 | |
6551 | AliasSet MGuardGlobalGeneration::getAliasSet() const { |
6552 | return AliasSet::Load(AliasSet::GlobalGenerationCounter); |
6553 | } |
6554 | |
6555 | bool MGuardGlobalGeneration::congruentTo(const MDefinition* ins) const { |
6556 | return ins->isGuardGlobalGeneration() && |
6557 | ins->toGuardGlobalGeneration()->expected() == expected() && |
6558 | ins->toGuardGlobalGeneration()->generationAddr() == generationAddr(); |
6559 | } |
6560 | |
6561 | MDefinition* MGuardIsNotProxy::foldsTo(TempAllocator& alloc) { |
6562 | KnownClass known = GetObjectKnownClass(object()); |
6563 | if (known == KnownClass::None) { |
6564 | return this; |
6565 | } |
6566 | |
6567 | MOZ_ASSERT(!GetObjectKnownJSClass(object())->isProxyObject())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!GetObjectKnownJSClass(object())->isProxyObject() )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!GetObjectKnownJSClass(object())->isProxyObject() ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "!GetObjectKnownJSClass(object())->isProxyObject()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 6567); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetObjectKnownJSClass(object())->isProxyObject()" ")"); do { *((volatile int*)__null) = 6567; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6568 | AssertKnownClass(alloc, this, object()); |
6569 | return object(); |
6570 | } |
6571 | |
6572 | AliasSet MMegamorphicLoadSlotByValue::getAliasSet() const { |
6573 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6574 | AliasSet::DynamicSlot); |
6575 | } |
6576 | |
6577 | MDefinition* MMegamorphicLoadSlotByValue::foldsTo(TempAllocator& alloc) { |
6578 | MDefinition* input = idVal(); |
6579 | if (input->isBox()) { |
6580 | input = input->toBox()->input(); |
6581 | } |
6582 | |
6583 | MDefinition* result = this; |
6584 | |
6585 | if (input->isConstant()) { |
6586 | MConstant* constant = input->toConstant(); |
6587 | if (constant->type() == MIRType::Symbol) { |
6588 | PropertyKey id = PropertyKey::Symbol(constant->toSymbol()); |
6589 | result = MMegamorphicLoadSlot::New(alloc, object(), id); |
6590 | } |
6591 | |
6592 | if (constant->type() == MIRType::String) { |
6593 | JSString* str = constant->toString(); |
6594 | if (str->isAtom() && !str->asAtom().isIndex()) { |
6595 | PropertyKey id = PropertyKey::NonIntAtom(str); |
6596 | result = MMegamorphicLoadSlot::New(alloc, object(), id); |
6597 | } |
6598 | } |
6599 | } |
6600 | |
6601 | if (result != this) { |
6602 | result->setDependency(dependency()); |
6603 | } |
6604 | |
6605 | return result; |
6606 | } |
6607 | |
6608 | MDefinition* MMegamorphicLoadSlotByValuePermissive::foldsTo( |
6609 | TempAllocator& alloc) { |
6610 | MDefinition* input = idVal(); |
6611 | if (input->isBox()) { |
6612 | input = input->toBox()->input(); |
6613 | } |
6614 | |
6615 | MDefinition* result = this; |
6616 | |
6617 | if (input->isConstant()) { |
6618 | MConstant* constant = input->toConstant(); |
6619 | if (constant->type() == MIRType::Symbol) { |
6620 | PropertyKey id = PropertyKey::Symbol(constant->toSymbol()); |
6621 | result = MMegamorphicLoadSlotPermissive::New(alloc, object(), id); |
6622 | } |
6623 | |
6624 | if (constant->type() == MIRType::String) { |
6625 | JSString* str = constant->toString(); |
6626 | if (str->isAtom() && !str->asAtom().isIndex()) { |
6627 | PropertyKey id = PropertyKey::NonIntAtom(str); |
6628 | result = MMegamorphicLoadSlotPermissive::New(alloc, object(), id); |
6629 | } |
6630 | } |
6631 | } |
6632 | |
6633 | if (result != this) { |
6634 | result->toMegamorphicLoadSlotPermissive()->stealResumePoint(this); |
6635 | } |
6636 | |
6637 | return result; |
6638 | } |
6639 | |
6640 | bool MMegamorphicLoadSlot::congruentTo(const MDefinition* ins) const { |
6641 | if (!ins->isMegamorphicLoadSlot()) { |
6642 | return false; |
6643 | } |
6644 | if (ins->toMegamorphicLoadSlot()->name() != name()) { |
6645 | return false; |
6646 | } |
6647 | return congruentIfOperandsEqual(ins); |
6648 | } |
6649 | |
6650 | AliasSet MMegamorphicLoadSlot::getAliasSet() const { |
6651 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6652 | AliasSet::DynamicSlot); |
6653 | } |
6654 | |
6655 | bool MSmallObjectVariableKeyHasProp::congruentTo(const MDefinition* ins) const { |
6656 | if (!ins->isSmallObjectVariableKeyHasProp()) { |
6657 | return false; |
6658 | } |
6659 | if (ins->toSmallObjectVariableKeyHasProp()->shape() != shape()) { |
6660 | return false; |
6661 | } |
6662 | return congruentIfOperandsEqual(ins); |
6663 | } |
6664 | |
6665 | AliasSet MSmallObjectVariableKeyHasProp::getAliasSet() const { |
6666 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6667 | AliasSet::DynamicSlot); |
6668 | } |
6669 | |
6670 | bool MMegamorphicHasProp::congruentTo(const MDefinition* ins) const { |
6671 | if (!ins->isMegamorphicHasProp()) { |
6672 | return false; |
6673 | } |
6674 | if (ins->toMegamorphicHasProp()->hasOwn() != hasOwn()) { |
6675 | return false; |
6676 | } |
6677 | return congruentIfOperandsEqual(ins); |
6678 | } |
6679 | |
6680 | AliasSet MMegamorphicHasProp::getAliasSet() const { |
6681 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6682 | AliasSet::DynamicSlot); |
6683 | } |
6684 | |
6685 | bool MNurseryObject::congruentTo(const MDefinition* ins) const { |
6686 | if (!ins->isNurseryObject()) { |
6687 | return false; |
6688 | } |
6689 | return nurseryIndex() == ins->toNurseryObject()->nurseryIndex(); |
6690 | } |
6691 | |
6692 | AliasSet MGuardFunctionIsNonBuiltinCtor::getAliasSet() const { |
6693 | return AliasSet::Load(AliasSet::ObjectFields); |
6694 | } |
6695 | |
6696 | bool MGuardFunctionKind::congruentTo(const MDefinition* ins) const { |
6697 | if (!ins->isGuardFunctionKind()) { |
6698 | return false; |
6699 | } |
6700 | if (expected() != ins->toGuardFunctionKind()->expected()) { |
6701 | return false; |
6702 | } |
6703 | if (bailOnEquality() != ins->toGuardFunctionKind()->bailOnEquality()) { |
6704 | return false; |
6705 | } |
6706 | return congruentIfOperandsEqual(ins); |
6707 | } |
6708 | |
6709 | AliasSet MGuardFunctionKind::getAliasSet() const { |
6710 | return AliasSet::Load(AliasSet::ObjectFields); |
6711 | } |
6712 | |
6713 | bool MGuardFunctionScript::congruentTo(const MDefinition* ins) const { |
6714 | if (!ins->isGuardFunctionScript()) { |
6715 | return false; |
6716 | } |
6717 | if (expected() != ins->toGuardFunctionScript()->expected()) { |
6718 | return false; |
6719 | } |
6720 | return congruentIfOperandsEqual(ins); |
6721 | } |
6722 | |
6723 | AliasSet MGuardFunctionScript::getAliasSet() const { |
6724 | // A JSFunction's BaseScript pointer is immutable. Relazification of |
6725 | // top-level/named self-hosted functions is an exception to this, but we don't |
6726 | // use this guard for those self-hosted functions. |
6727 | // See IRGenerator::emitCalleeGuard. |
6728 | MOZ_ASSERT_IF(flags_.isSelfHostedOrIntrinsic(), flags_.isLambda())do { if (flags_.isSelfHostedOrIntrinsic()) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(flags_. isLambda())>::isValid, "invalid assertion condition"); if ( (__builtin_expect(!!(!(!!(flags_.isLambda()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("flags_.isLambda()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 6728); AnnotateMozCrashReason("MOZ_ASSERT" "(" "flags_.isLambda()" ")"); do { *((volatile int*)__null) = 6728; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
6729 | return AliasSet::None(); |
6730 | } |
6731 | |
6732 | bool MGuardSpecificAtom::congruentTo(const MDefinition* ins) const { |
6733 | if (!ins->isGuardSpecificAtom()) { |
6734 | return false; |
6735 | } |
6736 | if (atom() != ins->toGuardSpecificAtom()->atom()) { |
6737 | return false; |
6738 | } |
6739 | return congruentIfOperandsEqual(ins); |
6740 | } |
6741 | |
6742 | MDefinition* MGuardStringToIndex::foldsTo(TempAllocator& alloc) { |
6743 | if (!string()->isConstant()) { |
6744 | return this; |
6745 | } |
6746 | |
6747 | JSString* str = string()->toConstant()->toString(); |
6748 | |
6749 | int32_t index = GetIndexFromString(str); |
6750 | if (index < 0) { |
6751 | return this; |
6752 | } |
6753 | |
6754 | return MConstant::New(alloc, Int32Value(index)); |
6755 | } |
6756 | |
6757 | MDefinition* MGuardStringToInt32::foldsTo(TempAllocator& alloc) { |
6758 | if (!string()->isConstant()) { |
6759 | return this; |
6760 | } |
6761 | |
6762 | JSLinearString* str = &string()->toConstant()->toString()->asLinear(); |
6763 | double number = LinearStringToNumber(str); |
6764 | |
6765 | int32_t n; |
6766 | if (!mozilla::NumberIsInt32(number, &n)) { |
6767 | return this; |
6768 | } |
6769 | |
6770 | return MConstant::New(alloc, Int32Value(n)); |
6771 | } |
6772 | |
6773 | MDefinition* MGuardStringToDouble::foldsTo(TempAllocator& alloc) { |
6774 | if (!string()->isConstant()) { |
6775 | return this; |
6776 | } |
6777 | |
6778 | JSLinearString* str = &string()->toConstant()->toString()->asLinear(); |
6779 | double number = LinearStringToNumber(str); |
6780 | return MConstant::New(alloc, DoubleValue(number)); |
6781 | } |
6782 | |
6783 | AliasSet MGuardNoDenseElements::getAliasSet() const { |
6784 | return AliasSet::Load(AliasSet::ObjectFields); |
6785 | } |
6786 | |
6787 | AliasSet MIteratorHasIndices::getAliasSet() const { |
6788 | return AliasSet::Load(AliasSet::ObjectFields); |
6789 | } |
6790 | |
6791 | AliasSet MAllocateAndStoreSlot::getAliasSet() const { |
6792 | return AliasSet::Store(AliasSet::ObjectFields | AliasSet::DynamicSlot); |
6793 | } |
6794 | |
6795 | AliasSet MLoadDOMExpandoValue::getAliasSet() const { |
6796 | return AliasSet::Load(AliasSet::DOMProxyExpando); |
6797 | } |
6798 | |
6799 | AliasSet MLoadDOMExpandoValueIgnoreGeneration::getAliasSet() const { |
6800 | return AliasSet::Load(AliasSet::DOMProxyExpando); |
6801 | } |
6802 | |
6803 | bool MGuardDOMExpandoMissingOrGuardShape::congruentTo( |
6804 | const MDefinition* ins) const { |
6805 | if (!ins->isGuardDOMExpandoMissingOrGuardShape()) { |
6806 | return false; |
6807 | } |
6808 | if (shape() != ins->toGuardDOMExpandoMissingOrGuardShape()->shape()) { |
6809 | return false; |
6810 | } |
6811 | return congruentIfOperandsEqual(ins); |
6812 | } |
6813 | |
6814 | AliasSet MGuardDOMExpandoMissingOrGuardShape::getAliasSet() const { |
6815 | return AliasSet::Load(AliasSet::ObjectFields); |
6816 | } |
6817 | |
6818 | MDefinition* MGuardToClass::foldsTo(TempAllocator& alloc) { |
6819 | const JSClass* clasp = GetObjectKnownJSClass(object()); |
6820 | if (!clasp || getClass() != clasp) { |
6821 | return this; |
6822 | } |
6823 | |
6824 | AssertKnownClass(alloc, this, object()); |
6825 | return object(); |
6826 | } |
6827 | |
6828 | MDefinition* MGuardToEitherClass::foldsTo(TempAllocator& alloc) { |
6829 | const JSClass* clasp = GetObjectKnownJSClass(object()); |
6830 | if (!clasp || (getClass1() != clasp && getClass2() != clasp)) { |
6831 | return this; |
6832 | } |
6833 | |
6834 | AssertKnownClass(alloc, this, object()); |
6835 | return object(); |
6836 | } |
6837 | |
6838 | MDefinition* MGuardToFunction::foldsTo(TempAllocator& alloc) { |
6839 | if (GetObjectKnownClass(object()) != KnownClass::Function) { |
6840 | return this; |
6841 | } |
6842 | |
6843 | AssertKnownClass(alloc, this, object()); |
6844 | return object(); |
6845 | } |
6846 | |
6847 | MDefinition* MHasClass::foldsTo(TempAllocator& alloc) { |
6848 | const JSClass* clasp = GetObjectKnownJSClass(object()); |
6849 | if (!clasp) { |
6850 | return this; |
6851 | } |
6852 | |
6853 | AssertKnownClass(alloc, this, object()); |
6854 | return MConstant::New(alloc, BooleanValue(getClass() == clasp)); |
6855 | } |
6856 | |
6857 | MDefinition* MIsCallable::foldsTo(TempAllocator& alloc) { |
6858 | if (input()->type() != MIRType::Object) { |
6859 | return this; |
6860 | } |
6861 | |
6862 | KnownClass known = GetObjectKnownClass(input()); |
6863 | if (known == KnownClass::None) { |
6864 | return this; |
6865 | } |
6866 | |
6867 | AssertKnownClass(alloc, this, input()); |
6868 | return MConstant::New(alloc, BooleanValue(known == KnownClass::Function)); |
6869 | } |
6870 | |
6871 | MDefinition* MIsArray::foldsTo(TempAllocator& alloc) { |
6872 | if (input()->type() != MIRType::Object) { |
6873 | return this; |
6874 | } |
6875 | |
6876 | KnownClass known = GetObjectKnownClass(input()); |
6877 | if (known == KnownClass::None) { |
6878 | return this; |
6879 | } |
6880 | |
6881 | AssertKnownClass(alloc, this, input()); |
6882 | return MConstant::New(alloc, BooleanValue(known == KnownClass::Array)); |
6883 | } |
6884 | |
6885 | AliasSet MObjectClassToString::getAliasSet() const { |
6886 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6887 | AliasSet::DynamicSlot); |
6888 | } |
6889 | |
6890 | MDefinition* MGuardIsNotArrayBufferMaybeShared::foldsTo(TempAllocator& alloc) { |
6891 | switch (GetObjectKnownClass(object())) { |
6892 | case KnownClass::PlainObject: |
6893 | case KnownClass::Array: |
6894 | case KnownClass::Function: |
6895 | case KnownClass::RegExp: |
6896 | case KnownClass::ArrayIterator: |
6897 | case KnownClass::StringIterator: |
6898 | case KnownClass::RegExpStringIterator: { |
6899 | AssertKnownClass(alloc, this, object()); |
6900 | return object(); |
6901 | } |
6902 | case KnownClass::None: |
6903 | break; |
6904 | } |
6905 | |
6906 | return this; |
6907 | } |
6908 | |
6909 | MDefinition* MCheckIsObj::foldsTo(TempAllocator& alloc) { |
6910 | if (!input()->isBox()) { |
6911 | return this; |
6912 | } |
6913 | |
6914 | MDefinition* unboxed = input()->getOperand(0); |
6915 | if (unboxed->type() == MIRType::Object) { |
6916 | return unboxed; |
6917 | } |
6918 | |
6919 | return this; |
6920 | } |
6921 | |
6922 | AliasSet MCheckIsObj::getAliasSet() const { |
6923 | return AliasSet::Store(AliasSet::ExceptionState); |
6924 | } |
6925 | |
6926 | #ifdef JS_PUNBOX641 |
6927 | AliasSet MCheckScriptedProxyGetResult::getAliasSet() const { |
6928 | return AliasSet::Store(AliasSet::ExceptionState); |
6929 | } |
6930 | #endif |
6931 | |
6932 | static bool IsBoxedObject(MDefinition* def) { |
6933 | MOZ_ASSERT(def->type() == MIRType::Value)do { static_assert( mozilla::detail::AssertionConditionType< decltype(def->type() == MIRType::Value)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(def->type() == MIRType::Value ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "def->type() == MIRType::Value", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 6933); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::Value" ")"); do { *((volatile int*)__null) = 6933; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6934 | |
6935 | if (def->isBox()) { |
6936 | return def->toBox()->input()->type() == MIRType::Object; |
6937 | } |
6938 | |
6939 | // Construct calls are always returning a boxed object. |
6940 | // |
6941 | // TODO: We should consider encoding this directly in the graph instead of |
6942 | // having to special case it here. |
6943 | if (def->isCall()) { |
6944 | return def->toCall()->isConstructing(); |
6945 | } |
6946 | if (def->isConstructArray()) { |
6947 | return true; |
6948 | } |
6949 | if (def->isConstructArgs()) { |
6950 | return true; |
6951 | } |
6952 | |
6953 | return false; |
6954 | } |
6955 | |
6956 | MDefinition* MCheckReturn::foldsTo(TempAllocator& alloc) { |
6957 | auto* returnVal = returnValue(); |
6958 | if (!returnVal->isBox()) { |
6959 | return this; |
6960 | } |
6961 | |
6962 | auto* unboxedReturnVal = returnVal->toBox()->input(); |
6963 | if (unboxedReturnVal->type() == MIRType::Object) { |
6964 | return returnVal; |
6965 | } |
6966 | |
6967 | if (unboxedReturnVal->type() != MIRType::Undefined) { |
6968 | return this; |
6969 | } |
6970 | |
6971 | auto* thisVal = thisValue(); |
6972 | if (IsBoxedObject(thisVal)) { |
6973 | return thisVal; |
6974 | } |
6975 | |
6976 | return this; |
6977 | } |
6978 | |
6979 | MDefinition* MCheckThis::foldsTo(TempAllocator& alloc) { |
6980 | MDefinition* input = thisValue(); |
6981 | if (!input->isBox()) { |
6982 | return this; |
6983 | } |
6984 | |
6985 | MDefinition* unboxed = input->getOperand(0); |
6986 | if (unboxed->mightBeMagicType()) { |
6987 | return this; |
6988 | } |
6989 | |
6990 | return input; |
6991 | } |
6992 | |
6993 | MDefinition* MCheckThisReinit::foldsTo(TempAllocator& alloc) { |
6994 | MDefinition* input = thisValue(); |
6995 | if (!input->isBox()) { |
6996 | return this; |
6997 | } |
6998 | |
6999 | MDefinition* unboxed = input->getOperand(0); |
7000 | if (unboxed->type() != MIRType::MagicUninitializedLexical) { |
7001 | return this; |
7002 | } |
7003 | |
7004 | return input; |
7005 | } |
7006 | |
7007 | MDefinition* MCheckObjCoercible::foldsTo(TempAllocator& alloc) { |
7008 | MDefinition* input = checkValue(); |
7009 | if (!input->isBox()) { |
7010 | return this; |
7011 | } |
7012 | |
7013 | MDefinition* unboxed = input->getOperand(0); |
7014 | if (unboxed->mightBeType(MIRType::Null) || |
7015 | unboxed->mightBeType(MIRType::Undefined)) { |
7016 | return this; |
7017 | } |
7018 | |
7019 | return input; |
7020 | } |
7021 | |
7022 | AliasSet MCheckObjCoercible::getAliasSet() const { |
7023 | return AliasSet::Store(AliasSet::ExceptionState); |
7024 | } |
7025 | |
7026 | AliasSet MCheckReturn::getAliasSet() const { |
7027 | return AliasSet::Store(AliasSet::ExceptionState); |
7028 | } |
7029 | |
7030 | AliasSet MCheckThis::getAliasSet() const { |
7031 | return AliasSet::Store(AliasSet::ExceptionState); |
7032 | } |
7033 | |
7034 | AliasSet MCheckThisReinit::getAliasSet() const { |
7035 | return AliasSet::Store(AliasSet::ExceptionState); |
7036 | } |
7037 | |
7038 | AliasSet MIsPackedArray::getAliasSet() const { |
7039 | return AliasSet::Load(AliasSet::ObjectFields); |
7040 | } |
7041 | |
7042 | AliasSet MGuardArrayIsPacked::getAliasSet() const { |
7043 | return AliasSet::Load(AliasSet::ObjectFields); |
7044 | } |
7045 | |
7046 | AliasSet MSuperFunction::getAliasSet() const { |
7047 | return AliasSet::Load(AliasSet::ObjectFields); |
7048 | } |
7049 | |
7050 | AliasSet MInitHomeObject::getAliasSet() const { |
7051 | return AliasSet::Store(AliasSet::ObjectFields); |
7052 | } |
7053 | |
7054 | AliasSet MLoadWrapperTarget::getAliasSet() const { |
7055 | return AliasSet::Load(AliasSet::Any); |
7056 | } |
7057 | |
7058 | bool MLoadWrapperTarget::congruentTo(const MDefinition* ins) const { |
7059 | if (!ins->isLoadWrapperTarget()) { |
7060 | return false; |
7061 | } |
7062 | if (ins->toLoadWrapperTarget()->fallible() != fallible()) { |
7063 | return false; |
7064 | } |
7065 | return congruentIfOperandsEqual(ins); |
7066 | } |
7067 | |
7068 | AliasSet MGuardHasGetterSetter::getAliasSet() const { |
7069 | return AliasSet::Load(AliasSet::ObjectFields); |
7070 | } |
7071 | |
7072 | bool MGuardHasGetterSetter::congruentTo(const MDefinition* ins) const { |
7073 | if (!ins->isGuardHasGetterSetter()) { |
7074 | return false; |
7075 | } |
7076 | if (ins->toGuardHasGetterSetter()->propId() != propId()) { |
7077 | return false; |
7078 | } |
7079 | if (ins->toGuardHasGetterSetter()->getterSetter() != getterSetter()) { |
7080 | return false; |
7081 | } |
7082 | return congruentIfOperandsEqual(ins); |
7083 | } |
7084 | |
7085 | AliasSet MGuardIsExtensible::getAliasSet() const { |
7086 | return AliasSet::Load(AliasSet::ObjectFields); |
7087 | } |
7088 | |
7089 | AliasSet MGuardIndexIsNotDenseElement::getAliasSet() const { |
7090 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::Element); |
7091 | } |
7092 | |
7093 | AliasSet MGuardIndexIsValidUpdateOrAdd::getAliasSet() const { |
7094 | return AliasSet::Load(AliasSet::ObjectFields); |
7095 | } |
7096 | |
7097 | AliasSet MCallObjectHasSparseElement::getAliasSet() const { |
7098 | return AliasSet::Load(AliasSet::Element | AliasSet::ObjectFields | |
7099 | AliasSet::FixedSlot | AliasSet::DynamicSlot); |
7100 | } |
7101 | |
7102 | AliasSet MLoadSlotByIteratorIndex::getAliasSet() const { |
7103 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
7104 | AliasSet::DynamicSlot | AliasSet::Element); |
7105 | } |
7106 | |
7107 | AliasSet MStoreSlotByIteratorIndex::getAliasSet() const { |
7108 | return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot | |
7109 | AliasSet::DynamicSlot | AliasSet::Element); |
7110 | } |
7111 | |
7112 | MDefinition* MGuardInt32IsNonNegative::foldsTo(TempAllocator& alloc) { |
7113 | 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.cpp" , 7113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 7113; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7114 | |
7115 | MDefinition* input = index(); |
7116 | if (!input->isConstant() || input->toConstant()->toInt32() < 0) { |
7117 | return this; |
7118 | } |
7119 | return input; |
7120 | } |
7121 | |
7122 | MDefinition* MGuardInt32Range::foldsTo(TempAllocator& alloc) { |
7123 | MOZ_ASSERT(input()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType< decltype(input()->type() == MIRType::Int32)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(input()->type() == MIRType ::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("input()->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7123); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 7123; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7124 | MOZ_ASSERT(minimum() <= maximum())do { static_assert( mozilla::detail::AssertionConditionType< decltype(minimum() <= maximum())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(minimum() <= maximum()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("minimum() <= maximum()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7124); AnnotateMozCrashReason("MOZ_ASSERT" "(" "minimum() <= maximum()" ")"); do { *((volatile int*)__null) = 7124; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7125 | |
7126 | MDefinition* in = input(); |
7127 | if (!in->isConstant()) { |
7128 | return this; |
7129 | } |
7130 | int32_t cst = in->toConstant()->toInt32(); |
7131 | if (cst < minimum() || cst > maximum()) { |
7132 | return this; |
7133 | } |
7134 | return in; |
7135 | } |
7136 | |
7137 | MDefinition* MGuardNonGCThing::foldsTo(TempAllocator& alloc) { |
7138 | if (!input()->isBox()) { |
7139 | return this; |
7140 | } |
7141 | |
7142 | MDefinition* unboxed = input()->getOperand(0); |
7143 | if (!IsNonGCThing(unboxed->type())) { |
7144 | return this; |
7145 | } |
7146 | return input(); |
7147 | } |
7148 | |
7149 | AliasSet MSetObjectHasNonBigInt::getAliasSet() const { |
7150 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7151 | } |
7152 | |
7153 | AliasSet MSetObjectHasBigInt::getAliasSet() const { |
7154 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7155 | } |
7156 | |
7157 | AliasSet MSetObjectHasValue::getAliasSet() const { |
7158 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7159 | } |
7160 | |
7161 | AliasSet MSetObjectHasValueVMCall::getAliasSet() const { |
7162 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7163 | } |
7164 | |
7165 | AliasSet MSetObjectSize::getAliasSet() const { |
7166 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7167 | } |
7168 | |
7169 | AliasSet MMapObjectHasNonBigInt::getAliasSet() const { |
7170 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7171 | } |
7172 | |
7173 | AliasSet MMapObjectHasBigInt::getAliasSet() const { |
7174 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7175 | } |
7176 | |
7177 | AliasSet MMapObjectHasValue::getAliasSet() const { |
7178 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7179 | } |
7180 | |
7181 | AliasSet MMapObjectHasValueVMCall::getAliasSet() const { |
7182 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7183 | } |
7184 | |
7185 | AliasSet MMapObjectGetNonBigInt::getAliasSet() const { |
7186 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7187 | } |
7188 | |
7189 | AliasSet MMapObjectGetBigInt::getAliasSet() const { |
7190 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7191 | } |
7192 | |
7193 | AliasSet MMapObjectGetValue::getAliasSet() const { |
7194 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7195 | } |
7196 | |
7197 | AliasSet MMapObjectGetValueVMCall::getAliasSet() const { |
7198 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7199 | } |
7200 | |
7201 | AliasSet MMapObjectSize::getAliasSet() const { |
7202 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
7203 | } |
7204 | |
7205 | MBindFunction* MBindFunction::New(TempAllocator& alloc, MDefinition* target, |
7206 | uint32_t argc, JSObject* templateObj) { |
7207 | auto* ins = new (alloc) MBindFunction(templateObj); |
7208 | if (!ins->init(alloc, NumNonArgumentOperands + argc)) { |
7209 | return nullptr; |
7210 | } |
7211 | ins->initOperand(0, target); |
7212 | return ins; |
7213 | } |
7214 | |
7215 | MCreateInlinedArgumentsObject* MCreateInlinedArgumentsObject::New( |
7216 | TempAllocator& alloc, MDefinition* callObj, MDefinition* callee, |
7217 | MDefinitionVector& args, ArgumentsObject* templateObj) { |
7218 | MCreateInlinedArgumentsObject* ins = |
7219 | new (alloc) MCreateInlinedArgumentsObject(templateObj); |
7220 | |
7221 | uint32_t argc = args.length(); |
7222 | MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7222); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 7222; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7223 | |
7224 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
7225 | return nullptr; |
7226 | } |
7227 | |
7228 | ins->initOperand(0, callObj); |
7229 | ins->initOperand(1, callee); |
7230 | for (uint32_t i = 0; i < argc; i++) { |
7231 | ins->initOperand(i + NumNonArgumentOperands, args[i]); |
7232 | } |
7233 | |
7234 | return ins; |
7235 | } |
7236 | |
7237 | MGetInlinedArgument* MGetInlinedArgument::New( |
7238 | TempAllocator& alloc, MDefinition* index, |
7239 | MCreateInlinedArgumentsObject* args) { |
7240 | MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument(); |
7241 | |
7242 | uint32_t argc = args->numActuals(); |
7243 | MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7243); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 7243; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7244 | |
7245 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
7246 | return nullptr; |
7247 | } |
7248 | |
7249 | ins->initOperand(0, index); |
7250 | for (uint32_t i = 0; i < argc; i++) { |
7251 | ins->initOperand(i + NumNonArgumentOperands, args->getArg(i)); |
7252 | } |
7253 | |
7254 | return ins; |
7255 | } |
7256 | |
7257 | MGetInlinedArgument* MGetInlinedArgument::New(TempAllocator& alloc, |
7258 | MDefinition* index, |
7259 | const CallInfo& callInfo) { |
7260 | MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument(); |
7261 | |
7262 | uint32_t argc = callInfo.argc(); |
7263 | MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 7263; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7264 | |
7265 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
7266 | return nullptr; |
7267 | } |
7268 | |
7269 | ins->initOperand(0, index); |
7270 | for (uint32_t i = 0; i < argc; i++) { |
7271 | ins->initOperand(i + NumNonArgumentOperands, callInfo.getArg(i)); |
7272 | } |
7273 | |
7274 | return ins; |
7275 | } |
7276 | |
7277 | MDefinition* MGetInlinedArgument::foldsTo(TempAllocator& alloc) { |
7278 | MDefinition* indexDef = SkipUninterestingInstructions(index()); |
7279 | if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) { |
7280 | return this; |
7281 | } |
7282 | |
7283 | int32_t indexConst = indexDef->toConstant()->toInt32(); |
7284 | if (indexConst < 0 || uint32_t(indexConst) >= numActuals()) { |
7285 | return this; |
7286 | } |
7287 | |
7288 | MDefinition* arg = getArg(indexConst); |
7289 | if (arg->type() != MIRType::Value) { |
7290 | arg = MBox::New(alloc, arg); |
7291 | } |
7292 | |
7293 | return arg; |
7294 | } |
7295 | |
7296 | MGetInlinedArgumentHole* MGetInlinedArgumentHole::New( |
7297 | TempAllocator& alloc, MDefinition* index, |
7298 | MCreateInlinedArgumentsObject* args) { |
7299 | auto* ins = new (alloc) MGetInlinedArgumentHole(); |
7300 | |
7301 | uint32_t argc = args->numActuals(); |
7302 | MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 7302; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7303 | |
7304 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
7305 | return nullptr; |
7306 | } |
7307 | |
7308 | ins->initOperand(0, index); |
7309 | for (uint32_t i = 0; i < argc; i++) { |
7310 | ins->initOperand(i + NumNonArgumentOperands, args->getArg(i)); |
7311 | } |
7312 | |
7313 | return ins; |
7314 | } |
7315 | |
7316 | MDefinition* MGetInlinedArgumentHole::foldsTo(TempAllocator& alloc) { |
7317 | MDefinition* indexDef = SkipUninterestingInstructions(index()); |
7318 | if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) { |
7319 | return this; |
7320 | } |
7321 | |
7322 | int32_t indexConst = indexDef->toConstant()->toInt32(); |
7323 | if (indexConst < 0) { |
7324 | return this; |
7325 | } |
7326 | |
7327 | MDefinition* arg; |
7328 | if (uint32_t(indexConst) < numActuals()) { |
7329 | arg = getArg(indexConst); |
7330 | |
7331 | if (arg->type() != MIRType::Value) { |
7332 | arg = MBox::New(alloc, arg); |
7333 | } |
7334 | } else { |
7335 | auto* undefined = MConstant::New(alloc, UndefinedValue()); |
7336 | block()->insertBefore(this, undefined); |
7337 | |
7338 | arg = MBox::New(alloc, undefined); |
7339 | } |
7340 | |
7341 | return arg; |
7342 | } |
7343 | |
7344 | MInlineArgumentsSlice* MInlineArgumentsSlice::New( |
7345 | TempAllocator& alloc, MDefinition* begin, MDefinition* count, |
7346 | MCreateInlinedArgumentsObject* args, JSObject* templateObj, |
7347 | gc::Heap initialHeap) { |
7348 | auto* ins = new (alloc) MInlineArgumentsSlice(templateObj, initialHeap); |
7349 | |
7350 | uint32_t argc = args->numActuals(); |
7351 | MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7351); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 7351; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7352 | |
7353 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
7354 | return nullptr; |
7355 | } |
7356 | |
7357 | ins->initOperand(0, begin); |
7358 | ins->initOperand(1, count); |
7359 | for (uint32_t i = 0; i < argc; i++) { |
7360 | ins->initOperand(i + NumNonArgumentOperands, args->getArg(i)); |
7361 | } |
7362 | |
7363 | return ins; |
7364 | } |
7365 | |
7366 | MDefinition* MArrayLength::foldsTo(TempAllocator& alloc) { |
7367 | // Object.keys() is potentially effectful, in case of Proxies. Otherwise, when |
7368 | // it is only computed for its length property, there is no need to |
7369 | // materialize the Array which results from it and it can be marked as |
7370 | // recovered on bailout as long as no properties are added to / removed from |
7371 | // the object. |
7372 | MDefinition* elems = elements(); |
7373 | if (!elems->isElements()) { |
7374 | return this; |
7375 | } |
7376 | |
7377 | MDefinition* guardshape = elems->toElements()->object(); |
7378 | if (!guardshape->isGuardShape()) { |
7379 | return this; |
7380 | } |
7381 | |
7382 | // The Guard shape is guarding the shape of the object returned by |
7383 | // Object.keys, this guard can be removed as knowing the function is good |
7384 | // enough to infer that we are returning an array. |
7385 | MDefinition* keys = guardshape->toGuardShape()->object(); |
7386 | if (!keys->isObjectKeys()) { |
7387 | return this; |
7388 | } |
7389 | |
7390 | // Object.keys() inline cache guards against proxies when creating the IC. We |
7391 | // rely on this here as we are looking to elide `Object.keys(...)` call, which |
7392 | // is only possible if we know for sure that no side-effect might have |
7393 | // happened. |
7394 | MDefinition* noproxy = keys->toObjectKeys()->object(); |
7395 | if (!noproxy->isGuardIsNotProxy()) { |
7396 | // The guard might have been replaced by an assertion, in case the class is |
7397 | // known at compile time. IF the guard has been removed check whether check |
7398 | // has been removed. |
7399 | MOZ_RELEASE_ASSERT(GetObjectKnownClass(noproxy) != KnownClass::None)do { static_assert( mozilla::detail::AssertionConditionType< decltype(GetObjectKnownClass(noproxy) != KnownClass::None)> ::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(GetObjectKnownClass(noproxy) != KnownClass::None))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("GetObjectKnownClass(noproxy) != KnownClass::None" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7399); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "GetObjectKnownClass(noproxy) != KnownClass::None" ")"); do { *((volatile int*)__null) = 7399; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7400 | MOZ_RELEASE_ASSERT(!GetObjectKnownJSClass(noproxy)->isProxyObject())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!GetObjectKnownJSClass(noproxy)->isProxyObject()) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(!GetObjectKnownJSClass(noproxy)->isProxyObject()) )), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!GetObjectKnownJSClass(noproxy)->isProxyObject()" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7400); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!GetObjectKnownJSClass(noproxy)->isProxyObject()" ")"); do { *((volatile int*)__null) = 7400; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7401 | } |
7402 | |
7403 | // Check if both the elements and the Object.keys() have a single use. We only |
7404 | // check for live uses, and are ok if a branch which was previously using the |
7405 | // keys array has been removed since. |
7406 | if (!elems->hasOneLiveDefUse() || !guardshape->hasOneLiveDefUse() || |
7407 | !keys->hasOneLiveDefUse()) { |
7408 | return this; |
7409 | } |
7410 | |
7411 | // Check that the latest active resume point is the one from Object.keys(), in |
7412 | // order to steal it. If this is not the latest active resume point then some |
7413 | // side-effect might happen which updates the content of the object, making |
7414 | // any recovery of the keys exhibit a different behavior than expected. |
7415 | if (keys->toObjectKeys()->resumePoint() != block()->activeResumePoint(this)) { |
7416 | return this; |
7417 | } |
7418 | |
7419 | // Verify whether any resume point captures the keys array after any aliasing |
7420 | // mutations. If this were to be the case the recovery of ObjectKeys on |
7421 | // bailout might compute a version which might not match with the elided |
7422 | // result. |
7423 | // |
7424 | // Iterate over the resume point uses of ObjectKeys, and check whether the |
7425 | // instructions they are attached to are aliasing Object fields. If so, skip |
7426 | // this optimization. |
7427 | AliasSet enumKeysAliasSet = AliasSet::Load(AliasSet::Flag::ObjectFields); |
7428 | for (auto* use : UsesIterator(keys)) { |
7429 | if (!use->consumer()->isResumePoint()) { |
7430 | // There is only a single use, and this is the length computation as |
7431 | // asserted with `hasOneLiveDefUse`. |
7432 | continue; |
7433 | } |
7434 | |
7435 | MResumePoint* rp = use->consumer()->toResumePoint(); |
7436 | if (!rp->instruction()) { |
7437 | // If there is no instruction, this is a resume point which is attached to |
7438 | // the entry of a block. Thus no risk of mutating the object on which the |
7439 | // keys are queried. |
7440 | continue; |
7441 | } |
7442 | |
7443 | MInstruction* ins = rp->instruction(); |
7444 | if (ins == keys) { |
7445 | continue; |
7446 | } |
7447 | |
7448 | // Check whether the instruction can potentially alias the object fields of |
7449 | // the object from which we are querying the keys. |
7450 | AliasSet mightAlias = ins->getAliasSet() & enumKeysAliasSet; |
7451 | if (!mightAlias.isNone()) { |
7452 | return this; |
7453 | } |
7454 | } |
7455 | |
7456 | // Flag every instructions since Object.keys(..) as recovered on bailout, and |
7457 | // make Object.keys(..) be the recovered value in-place of the shape guard. |
7458 | setRecoveredOnBailout(); |
7459 | elems->setRecoveredOnBailout(); |
7460 | guardshape->replaceAllUsesWith(keys); |
7461 | guardshape->block()->discard(guardshape->toGuardShape()); |
7462 | keys->setRecoveredOnBailout(); |
7463 | |
7464 | // Steal the resume point from Object.keys, which is ok as we confirmed that |
7465 | // there is no other resume point in-between. |
7466 | MObjectKeysLength* keysLength = MObjectKeysLength::New(alloc, noproxy); |
7467 | keysLength->stealResumePoint(keys->toObjectKeys()); |
7468 | |
7469 | return keysLength; |
7470 | } |
7471 | |
7472 | MDefinition* MNormalizeSliceTerm::foldsTo(TempAllocator& alloc) { |
7473 | auto* length = this->length(); |
7474 | if (!length->isConstant() && !length->isArgumentsLength()) { |
7475 | return this; |
7476 | } |
7477 | |
7478 | if (length->isConstant()) { |
7479 | int32_t lengthConst = length->toConstant()->toInt32(); |
7480 | MOZ_ASSERT(lengthConst >= 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(lengthConst >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(lengthConst >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("lengthConst >= 0" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 7480); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lengthConst >= 0" ")"); do { *((volatile int*)__null) = 7480; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
7481 | |
7482 | // Result is always zero when |length| is zero. |
7483 | if (lengthConst == 0) { |
7484 | return length; |
7485 | } |
7486 | |
7487 | auto* value = this->value(); |
7488 | if (value->isConstant()) { |
7489 | int32_t valueConst = value->toConstant()->toInt32(); |
7490 | |
7491 | int32_t normalized; |
7492 | if (valueConst < 0) { |
7493 | normalized = std::max(valueConst + lengthConst, 0); |
7494 | } else { |
7495 | normalized = std::min(valueConst, lengthConst); |
7496 | } |
7497 | |
7498 | if (normalized == valueConst) { |
7499 | return value; |
7500 | } |
7501 | if (normalized == lengthConst) { |
7502 | return length; |
7503 | } |
7504 | return MConstant::New(alloc, Int32Value(normalized)); |
7505 | } |
7506 | |
7507 | return this; |
7508 | } |
7509 | |
7510 | auto* value = this->value(); |
7511 | if (value->isConstant()) { |
7512 | int32_t valueConst = value->toConstant()->toInt32(); |
7513 | |
7514 | // Minimum of |value| and |length|. |
7515 | if (valueConst > 0) { |
7516 | bool isMax = false; |
7517 | return MMinMax::New(alloc, value, length, MIRType::Int32, isMax); |
7518 | } |
7519 | |
7520 | // Maximum of |value + length| and zero. |
7521 | if (valueConst < 0) { |
7522 | // Safe to truncate because |length| is never negative. |
7523 | auto* add = MAdd::New(alloc, value, length, TruncateKind::Truncate); |
7524 | block()->insertBefore(this, add); |
7525 | |
7526 | auto* zero = MConstant::New(alloc, Int32Value(0)); |
7527 | block()->insertBefore(this, zero); |
7528 | |
7529 | bool isMax = true; |
7530 | return MMinMax::New(alloc, add, zero, MIRType::Int32, isMax); |
7531 | } |
7532 | |
7533 | // Directly return the value when it's zero. |
7534 | return value; |
7535 | } |
7536 | |
7537 | // Normalizing MArgumentsLength is a no-op. |
7538 | if (value->isArgumentsLength()) { |
7539 | return value; |
7540 | } |
7541 | |
7542 | return this; |
7543 | } |
7544 | |
7545 | bool MInt32ToStringWithBase::congruentTo(const MDefinition* ins) const { |
7546 | if (!ins->isInt32ToStringWithBase()) { |
7547 | return false; |
7548 | } |
7549 | if (ins->toInt32ToStringWithBase()->lowerCase() != lowerCase()) { |
7550 | return false; |
7551 | } |
7552 | return congruentIfOperandsEqual(ins); |
7553 | } |