File: | var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp |
Warning: | line 1454, 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/CheckedInt.h" |
10 | #include "mozilla/EndianUtils.h" |
11 | #include "mozilla/FloatingPoint.h" |
12 | #include "mozilla/MathAlgorithms.h" |
13 | #include "mozilla/Maybe.h" |
14 | #include "mozilla/ScopeExit.h" |
15 | |
16 | #include <array> |
17 | #include <utility> |
18 | |
19 | #include "jslibmath.h" |
20 | #include "jsmath.h" |
21 | #include "jsnum.h" |
22 | |
23 | #include "builtin/RegExp.h" |
24 | #include "jit/AtomicOperations.h" |
25 | #include "jit/CompileInfo.h" |
26 | #include "jit/KnownClass.h" |
27 | #include "jit/MIR-wasm.h" |
28 | #include "jit/MIRGraph.h" |
29 | #include "jit/RangeAnalysis.h" |
30 | #include "jit/VMFunctions.h" |
31 | #include "jit/WarpBuilderShared.h" |
32 | #include "js/Conversions.h" |
33 | #include "js/experimental/JitInfo.h" // JSJitInfo, JSTypedMethodJitInfo |
34 | #include "js/ScalarType.h" // js::Scalar::Type |
35 | #include "util/Text.h" |
36 | #include "util/Unicode.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/JSAtomUtils-inl.h" // TypeName |
43 | |
44 | using namespace js; |
45 | using namespace js::jit; |
46 | |
47 | using JS::ToInt32; |
48 | |
49 | using mozilla::CheckedInt; |
50 | using mozilla::DebugOnly; |
51 | using mozilla::IsFloat32Representable; |
52 | using mozilla::IsPowerOfTwo; |
53 | using mozilla::Maybe; |
54 | using mozilla::NumbersAreIdentical; |
55 | |
56 | 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." ); |
57 | |
58 | #ifdef DEBUG1 |
59 | size_t MUse::index() const { return consumer()->indexOf(this); } |
60 | #endif |
61 | |
62 | template <size_t Op> |
63 | static void ConvertDefinitionToDouble(TempAllocator& alloc, MDefinition* def, |
64 | MInstruction* consumer) { |
65 | MInstruction* replace = MToDouble::New(alloc, def); |
66 | consumer->replaceOperand(Op, replace); |
67 | consumer->block()->insertBefore(consumer, replace); |
68 | } |
69 | |
70 | template <size_t Arity, size_t Index> |
71 | static void ConvertOperandToDouble(MAryInstruction<Arity>* def, |
72 | TempAllocator& alloc) { |
73 | static_assert(Index < Arity); |
74 | auto* operand = def->getOperand(Index); |
75 | if (operand->type() == MIRType::Float32) { |
76 | ConvertDefinitionToDouble<Index>(alloc, operand, def); |
77 | } |
78 | } |
79 | |
80 | template <size_t Arity, size_t... ISeq> |
81 | static void ConvertOperandsToDouble(MAryInstruction<Arity>* def, |
82 | TempAllocator& alloc, |
83 | std::index_sequence<ISeq...>) { |
84 | (ConvertOperandToDouble<Arity, ISeq>(def, alloc), ...); |
85 | } |
86 | |
87 | template <size_t Arity> |
88 | static void ConvertOperandsToDouble(MAryInstruction<Arity>* def, |
89 | TempAllocator& alloc) { |
90 | ConvertOperandsToDouble<Arity>(def, alloc, std::make_index_sequence<Arity>{}); |
91 | } |
92 | |
93 | template <size_t Arity, size_t... ISeq> |
94 | static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def, |
95 | std::index_sequence<ISeq...>) { |
96 | return (def->getOperand(ISeq)->canProduceFloat32() && ...); |
97 | } |
98 | |
99 | template <size_t Arity> |
100 | static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def) { |
101 | return AllOperandsCanProduceFloat32<Arity>(def, |
102 | std::make_index_sequence<Arity>{}); |
103 | } |
104 | |
105 | static bool CheckUsesAreFloat32Consumers(const MInstruction* ins) { |
106 | if (ins->isImplicitlyUsed()) { |
107 | return false; |
108 | } |
109 | bool allConsumerUses = true; |
110 | for (MUseDefIterator use(ins); allConsumerUses && use; use++) { |
111 | allConsumerUses &= use.def()->canConsumeFloat32(use.use()); |
112 | } |
113 | return allConsumerUses; |
114 | } |
115 | |
116 | #ifdef JS_JITSPEW1 |
117 | static const char* OpcodeName(MDefinition::Opcode op) { |
118 | static const char* const names[] = { |
119 | # define NAME(x) #x, |
120 | 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 (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(Int64ToBigInt)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(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) |
121 | # undef NAME |
122 | }; |
123 | return names[unsigned(op)]; |
124 | } |
125 | |
126 | void MDefinition::PrintOpcodeName(GenericPrinter& out, Opcode op) { |
127 | const char* name = OpcodeName(op); |
128 | size_t len = strlen(name); |
129 | for (size_t i = 0; i < len; i++) { |
130 | out.printf("%c", unicode::ToLowerCase(name[i])); |
131 | } |
132 | } |
133 | |
134 | uint32_t js::jit::GetMBasicBlockId(const MBasicBlock* block) { |
135 | return block->id(); |
136 | } |
137 | #endif |
138 | |
139 | static MConstant* EvaluateInt64ConstantOperands(TempAllocator& alloc, |
140 | MBinaryInstruction* ins) { |
141 | MDefinition* left = ins->getOperand(0); |
142 | MDefinition* right = ins->getOperand(1); |
143 | |
144 | if (!left->isConstant() || !right->isConstant()) { |
145 | return nullptr; |
146 | } |
147 | |
148 | 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" , 148); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 148; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
149 | 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" , 149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int64" ")"); do { *((volatile int*)__null) = 149; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
150 | |
151 | int64_t lhs = left->toConstant()->toInt64(); |
152 | int64_t rhs = right->toConstant()->toInt64(); |
153 | int64_t ret; |
154 | |
155 | switch (ins->op()) { |
156 | case MDefinition::Opcode::BitAnd: |
157 | ret = lhs & rhs; |
158 | break; |
159 | case MDefinition::Opcode::BitOr: |
160 | ret = lhs | rhs; |
161 | break; |
162 | case MDefinition::Opcode::BitXor: |
163 | ret = lhs ^ rhs; |
164 | break; |
165 | case MDefinition::Opcode::Lsh: |
166 | ret = lhs << (rhs & 0x3F); |
167 | break; |
168 | case MDefinition::Opcode::Rsh: |
169 | ret = lhs >> (rhs & 0x3F); |
170 | break; |
171 | case MDefinition::Opcode::Ursh: |
172 | ret = uint64_t(lhs) >> (uint64_t(rhs) & 0x3F); |
173 | break; |
174 | case MDefinition::Opcode::Add: |
175 | ret = lhs + rhs; |
176 | break; |
177 | case MDefinition::Opcode::Sub: |
178 | ret = lhs - rhs; |
179 | break; |
180 | case MDefinition::Opcode::Mul: |
181 | ret = lhs * rhs; |
182 | break; |
183 | case MDefinition::Opcode::Div: |
184 | if (rhs == 0) { |
185 | // Division by zero will trap at runtime. |
186 | return nullptr; |
187 | } |
188 | if (ins->toDiv()->isUnsigned()) { |
189 | ret = int64_t(uint64_t(lhs) / uint64_t(rhs)); |
190 | } else if (lhs == INT64_MIN(-9223372036854775807L -1) || rhs == -1) { |
191 | // Overflow will trap at runtime. |
192 | return nullptr; |
193 | } else { |
194 | ret = lhs / rhs; |
195 | } |
196 | break; |
197 | case MDefinition::Opcode::Mod: |
198 | if (rhs == 0) { |
199 | // Division by zero will trap at runtime. |
200 | return nullptr; |
201 | } |
202 | if (!ins->toMod()->isUnsigned() && (lhs < 0 || rhs < 0)) { |
203 | // Handle all negative values at runtime, for simplicity. |
204 | return nullptr; |
205 | } |
206 | ret = int64_t(uint64_t(lhs) % uint64_t(rhs)); |
207 | break; |
208 | default: |
209 | MOZ_CRASH("NYI")do { do { } while (false); MOZ_ReportCrash("" "NYI", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 209); AnnotateMozCrashReason("MOZ_CRASH(" "NYI" ")"); do { * ((volatile int*)__null) = 209; __attribute__((nomerge)) ::abort (); } while (false); } while (false); |
210 | } |
211 | |
212 | return MConstant::NewInt64(alloc, ret); |
213 | } |
214 | |
215 | static MConstant* EvaluateConstantOperands(TempAllocator& alloc, |
216 | MBinaryInstruction* ins, |
217 | bool* ptypeChange = nullptr) { |
218 | MDefinition* left = ins->getOperand(0); |
219 | MDefinition* right = ins->getOperand(1); |
220 | |
221 | 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" , 221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(left->type())" ")"); do { *((volatile int*)__null) = 221; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
222 | 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" , 222); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(right->type())" ")"); do { *((volatile int*)__null) = 222; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
223 | |
224 | if (!left->isConstant() || !right->isConstant()) { |
225 | return nullptr; |
226 | } |
227 | |
228 | MConstant* lhs = left->toConstant(); |
229 | MConstant* rhs = right->toConstant(); |
230 | double ret = JS::GenericNaN(); |
231 | |
232 | switch (ins->op()) { |
233 | case MDefinition::Opcode::BitAnd: |
234 | ret = double(lhs->toInt32() & rhs->toInt32()); |
235 | break; |
236 | case MDefinition::Opcode::BitOr: |
237 | ret = double(lhs->toInt32() | rhs->toInt32()); |
238 | break; |
239 | case MDefinition::Opcode::BitXor: |
240 | ret = double(lhs->toInt32() ^ rhs->toInt32()); |
241 | break; |
242 | case MDefinition::Opcode::Lsh: |
243 | ret = double(uint32_t(lhs->toInt32()) << (rhs->toInt32() & 0x1F)); |
244 | break; |
245 | case MDefinition::Opcode::Rsh: |
246 | ret = double(lhs->toInt32() >> (rhs->toInt32() & 0x1F)); |
247 | break; |
248 | case MDefinition::Opcode::Ursh: |
249 | ret = double(uint32_t(lhs->toInt32()) >> (rhs->toInt32() & 0x1F)); |
250 | break; |
251 | case MDefinition::Opcode::Add: |
252 | ret = lhs->numberToDouble() + rhs->numberToDouble(); |
253 | break; |
254 | case MDefinition::Opcode::Sub: |
255 | ret = lhs->numberToDouble() - rhs->numberToDouble(); |
256 | break; |
257 | case MDefinition::Opcode::Mul: |
258 | ret = lhs->numberToDouble() * rhs->numberToDouble(); |
259 | break; |
260 | case MDefinition::Opcode::Div: |
261 | if (ins->toDiv()->isUnsigned()) { |
262 | if (rhs->isInt32(0)) { |
263 | if (ins->toDiv()->trapOnError()) { |
264 | return nullptr; |
265 | } |
266 | ret = 0.0; |
267 | } else { |
268 | ret = double(uint32_t(lhs->toInt32()) / uint32_t(rhs->toInt32())); |
269 | } |
270 | } else { |
271 | ret = NumberDiv(lhs->numberToDouble(), rhs->numberToDouble()); |
272 | } |
273 | break; |
274 | case MDefinition::Opcode::Mod: |
275 | if (ins->toMod()->isUnsigned()) { |
276 | if (rhs->isInt32(0)) { |
277 | if (ins->toMod()->trapOnError()) { |
278 | return nullptr; |
279 | } |
280 | ret = 0.0; |
281 | } else { |
282 | ret = double(uint32_t(lhs->toInt32()) % uint32_t(rhs->toInt32())); |
283 | } |
284 | } else { |
285 | ret = NumberMod(lhs->numberToDouble(), rhs->numberToDouble()); |
286 | } |
287 | break; |
288 | default: |
289 | MOZ_CRASH("NYI")do { do { } while (false); MOZ_ReportCrash("" "NYI", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 289); AnnotateMozCrashReason("MOZ_CRASH(" "NYI" ")"); do { * ((volatile int*)__null) = 289; __attribute__((nomerge)) ::abort (); } while (false); } while (false); |
290 | } |
291 | |
292 | if (ins->type() == MIRType::Float32) { |
293 | return MConstant::NewFloat32(alloc, float(ret)); |
294 | } |
295 | if (ins->type() == MIRType::Double) { |
296 | return MConstant::New(alloc, DoubleValue(ret)); |
297 | } |
298 | |
299 | Value retVal; |
300 | retVal.setNumber(JS::CanonicalizeNaN(ret)); |
301 | |
302 | // If this was an int32 operation but the result isn't an int32 (for |
303 | // example, a division where the numerator isn't evenly divisible by the |
304 | // denominator), decline folding. |
305 | 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" , 305); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 305; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
306 | if (!retVal.isInt32()) { |
307 | if (ptypeChange) { |
308 | *ptypeChange = true; |
309 | } |
310 | return nullptr; |
311 | } |
312 | |
313 | return MConstant::New(alloc, retVal); |
314 | } |
315 | |
316 | static MMul* EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins) { |
317 | // we should fold only when it is a floating point operation |
318 | if (!IsFloatingPointType(ins->type())) { |
319 | return nullptr; |
320 | } |
321 | |
322 | MDefinition* left = ins->getOperand(0); |
323 | MDefinition* right = ins->getOperand(1); |
324 | |
325 | if (!right->isConstant()) { |
326 | return nullptr; |
327 | } |
328 | |
329 | int32_t num; |
330 | if (!mozilla::NumberIsInt32(right->toConstant()->numberToDouble(), &num)) { |
331 | return nullptr; |
332 | } |
333 | |
334 | // check if rhs is a power of two |
335 | if (mozilla::Abs(num) & (mozilla::Abs(num) - 1)) { |
336 | return nullptr; |
337 | } |
338 | |
339 | Value ret; |
340 | ret.setDouble(1.0 / double(num)); |
341 | |
342 | MConstant* foldedRhs; |
343 | if (ins->type() == MIRType::Float32) { |
344 | foldedRhs = MConstant::NewFloat32(alloc, ret.toDouble()); |
345 | } else { |
346 | foldedRhs = MConstant::New(alloc, ret); |
347 | } |
348 | |
349 | 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" , 349); AnnotateMozCrashReason("MOZ_ASSERT" "(" "foldedRhs->type() == ins->type()" ")"); do { *((volatile int*)__null) = 349; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
350 | ins->block()->insertBefore(ins, foldedRhs); |
351 | |
352 | MMul* mul = MMul::New(alloc, left, foldedRhs, ins->type()); |
353 | mul->setMustPreserveNaN(ins->mustPreserveNaN()); |
354 | return mul; |
355 | } |
356 | |
357 | #ifdef JS_JITSPEW1 |
358 | const char* MDefinition::opName() const { return OpcodeName(op()); } |
359 | |
360 | void MDefinition::printName(GenericPrinter& out) const { |
361 | PrintOpcodeName(out, op()); |
362 | out.printf("%u", id()); |
363 | } |
364 | #endif |
365 | |
366 | HashNumber MDefinition::valueHash() const { |
367 | HashNumber out = HashNumber(op()); |
368 | for (size_t i = 0, e = numOperands(); i < e; i++) { |
369 | out = addU32ToHash(out, getOperand(i)->id()); |
370 | } |
371 | if (MDefinition* dep = dependency()) { |
372 | out = addU32ToHash(out, dep->id()); |
373 | } |
374 | return out; |
375 | } |
376 | |
377 | HashNumber MNullaryInstruction::valueHash() const { |
378 | HashNumber hash = HashNumber(op()); |
379 | if (MDefinition* dep = dependency()) { |
380 | hash = addU32ToHash(hash, dep->id()); |
381 | } |
382 | 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" , 382); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 382; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
383 | return hash; |
384 | } |
385 | |
386 | HashNumber MUnaryInstruction::valueHash() const { |
387 | HashNumber hash = HashNumber(op()); |
388 | hash = addU32ToHash(hash, getOperand(0)->id()); |
389 | if (MDefinition* dep = dependency()) { |
390 | hash = addU32ToHash(hash, dep->id()); |
391 | } |
392 | 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" , 392); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 392; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
393 | return hash; |
394 | } |
395 | |
396 | HashNumber MBinaryInstruction::valueHash() const { |
397 | HashNumber hash = HashNumber(op()); |
398 | hash = addU32ToHash(hash, getOperand(0)->id()); |
399 | hash = addU32ToHash(hash, getOperand(1)->id()); |
400 | if (MDefinition* dep = dependency()) { |
401 | hash = addU32ToHash(hash, dep->id()); |
402 | } |
403 | 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" , 403); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 403; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
404 | return hash; |
405 | } |
406 | |
407 | HashNumber MTernaryInstruction::valueHash() const { |
408 | HashNumber hash = HashNumber(op()); |
409 | hash = addU32ToHash(hash, getOperand(0)->id()); |
410 | hash = addU32ToHash(hash, getOperand(1)->id()); |
411 | hash = addU32ToHash(hash, getOperand(2)->id()); |
412 | if (MDefinition* dep = dependency()) { |
413 | hash = addU32ToHash(hash, dep->id()); |
414 | } |
415 | 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" , 415); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 415; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
416 | return hash; |
417 | } |
418 | |
419 | HashNumber MQuaternaryInstruction::valueHash() const { |
420 | HashNumber hash = HashNumber(op()); |
421 | hash = addU32ToHash(hash, getOperand(0)->id()); |
422 | hash = addU32ToHash(hash, getOperand(1)->id()); |
423 | hash = addU32ToHash(hash, getOperand(2)->id()); |
424 | hash = addU32ToHash(hash, getOperand(3)->id()); |
425 | if (MDefinition* dep = dependency()) { |
426 | hash = addU32ToHash(hash, dep->id()); |
427 | } |
428 | 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" , 428); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()" ")"); do { *((volatile int*)__null) = 428; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
429 | return hash; |
430 | } |
431 | |
432 | const MDefinition* MDefinition::skipObjectGuards() const { |
433 | const MDefinition* result = this; |
434 | // These instructions don't modify the object and just guard specific |
435 | // properties. |
436 | while (true) { |
437 | if (result->isGuardShape()) { |
438 | result = result->toGuardShape()->object(); |
439 | continue; |
440 | } |
441 | if (result->isGuardNullProto()) { |
442 | result = result->toGuardNullProto()->object(); |
443 | continue; |
444 | } |
445 | if (result->isGuardProto()) { |
446 | result = result->toGuardProto()->object(); |
447 | continue; |
448 | } |
449 | |
450 | break; |
451 | } |
452 | |
453 | return result; |
454 | } |
455 | |
456 | bool MDefinition::congruentIfOperandsEqual(const MDefinition* ins) const { |
457 | if (op() != ins->op()) { |
458 | return false; |
459 | } |
460 | |
461 | if (type() != ins->type()) { |
462 | return false; |
463 | } |
464 | |
465 | if (isEffectful() || ins->isEffectful()) { |
466 | return false; |
467 | } |
468 | |
469 | if (numOperands() != ins->numOperands()) { |
470 | return false; |
471 | } |
472 | |
473 | for (size_t i = 0, e = numOperands(); i < e; i++) { |
474 | if (getOperand(i) != ins->getOperand(i)) { |
475 | return false; |
476 | } |
477 | } |
478 | |
479 | return true; |
480 | } |
481 | |
482 | MDefinition* MDefinition::foldsTo(TempAllocator& alloc) { |
483 | // In the default case, there are no constants to fold. |
484 | return this; |
485 | } |
486 | |
487 | bool MDefinition::mightBeMagicType() const { |
488 | if (IsMagicType(type())) { |
489 | return true; |
490 | } |
491 | |
492 | if (MIRType::Value != type()) { |
493 | return false; |
494 | } |
495 | |
496 | return true; |
497 | } |
498 | |
499 | bool MDefinition::definitelyType(std::initializer_list<MIRType> types) const { |
500 | #ifdef DEBUG1 |
501 | // Only support specialized, non-magic types. |
502 | auto isSpecializedNonMagic = [](MIRType type) { |
503 | return type <= MIRType::Object; |
504 | }; |
505 | #endif |
506 | |
507 | 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" , 507); AnnotateMozCrashReason("MOZ_ASSERT" "(" "types.size() > 0" ")"); do { *((volatile int*)__null) = 507; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
508 | 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" , 508); AnnotateMozCrashReason("MOZ_ASSERT" "(" "std::all_of(types.begin(), types.end(), isSpecializedNonMagic)" ")"); do { *((volatile int*)__null) = 508; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
509 | |
510 | if (type() == MIRType::Value) { |
511 | return false; |
512 | } |
513 | |
514 | return std::find(types.begin(), types.end(), type()) != types.end(); |
515 | } |
516 | |
517 | MDefinition* MInstruction::foldsToStore(TempAllocator& alloc) { |
518 | if (!dependency()) { |
519 | return nullptr; |
520 | } |
521 | |
522 | MDefinition* store = dependency(); |
523 | if (mightAlias(store) != AliasType::MustAlias) { |
524 | return nullptr; |
525 | } |
526 | |
527 | if (!store->block()->dominates(block())) { |
528 | return nullptr; |
529 | } |
530 | |
531 | MDefinition* value; |
532 | switch (store->op()) { |
533 | case Opcode::StoreFixedSlot: |
534 | value = store->toStoreFixedSlot()->value(); |
535 | break; |
536 | case Opcode::StoreDynamicSlot: |
537 | value = store->toStoreDynamicSlot()->value(); |
538 | break; |
539 | case Opcode::StoreElement: |
540 | value = store->toStoreElement()->value(); |
541 | break; |
542 | default: |
543 | MOZ_CRASH("unknown store")do { do { } while (false); MOZ_ReportCrash("" "unknown store" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 543); AnnotateMozCrashReason("MOZ_CRASH(" "unknown store" ")" ); do { *((volatile int*)__null) = 543; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
544 | } |
545 | |
546 | // If the type are matching then we return the value which is used as |
547 | // argument of the store. |
548 | if (value->type() != type()) { |
549 | // If we expect to read a type which is more generic than the type seen |
550 | // by the store, then we box the value used by the store. |
551 | if (type() != MIRType::Value) { |
552 | return nullptr; |
553 | } |
554 | |
555 | 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" , 555); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() < MIRType::Value" ")"); do { *((volatile int*)__null) = 555; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
556 | MBox* box = MBox::New(alloc, value); |
557 | value = box; |
558 | } |
559 | |
560 | return value; |
561 | } |
562 | |
563 | void MDefinition::analyzeEdgeCasesForward() {} |
564 | |
565 | void MDefinition::analyzeEdgeCasesBackward() {} |
566 | |
567 | void MInstruction::setResumePoint(MResumePoint* resumePoint) { |
568 | 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" , 568); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!resumePoint_" ")"); do { *((volatile int*)__null) = 568; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
569 | resumePoint_ = resumePoint; |
570 | resumePoint_->setInstruction(this); |
571 | } |
572 | |
573 | void MInstruction::stealResumePoint(MInstruction* other) { |
574 | MResumePoint* resumePoint = other->resumePoint_; |
575 | other->resumePoint_ = nullptr; |
576 | |
577 | resumePoint->resetInstruction(); |
578 | setResumePoint(resumePoint); |
579 | } |
580 | |
581 | void MInstruction::moveResumePointAsEntry() { |
582 | 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" , 582); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNop()" ")" ); do { *((volatile int*)__null) = 582; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
583 | block()->clearEntryResumePoint(); |
584 | block()->setEntryResumePoint(resumePoint_); |
585 | resumePoint_->resetInstruction(); |
586 | resumePoint_ = nullptr; |
587 | } |
588 | |
589 | void MInstruction::clearResumePoint() { |
590 | resumePoint_->resetInstruction(); |
591 | block()->discardPreAllocatedResumePoint(resumePoint_); |
592 | resumePoint_ = nullptr; |
593 | } |
594 | |
595 | MDefinition* MTest::foldsDoubleNegation(TempAllocator& alloc) { |
596 | MDefinition* op = getOperand(0); |
597 | |
598 | if (op->isNot()) { |
599 | // If the operand of the Not is itself a Not, they cancel out. |
600 | MDefinition* opop = op->getOperand(0); |
601 | if (opop->isNot()) { |
602 | return MTest::New(alloc, opop->toNot()->input(), ifTrue(), ifFalse()); |
603 | } |
604 | return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue()); |
605 | } |
606 | return nullptr; |
607 | } |
608 | |
609 | MDefinition* MTest::foldsConstant(TempAllocator& alloc) { |
610 | MDefinition* op = getOperand(0); |
611 | if (MConstant* opConst = op->maybeConstantValue()) { |
612 | bool b; |
613 | if (opConst->valueToBoolean(&b)) { |
614 | return MGoto::New(alloc, b ? ifTrue() : ifFalse()); |
615 | } |
616 | } |
617 | return nullptr; |
618 | } |
619 | |
620 | MDefinition* MTest::foldsTypes(TempAllocator& alloc) { |
621 | MDefinition* op = getOperand(0); |
622 | |
623 | switch (op->type()) { |
624 | case MIRType::Undefined: |
625 | case MIRType::Null: |
626 | return MGoto::New(alloc, ifFalse()); |
627 | case MIRType::Symbol: |
628 | return MGoto::New(alloc, ifTrue()); |
629 | default: |
630 | break; |
631 | } |
632 | return nullptr; |
633 | } |
634 | |
635 | class UsesIterator { |
636 | MDefinition* def_; |
637 | |
638 | public: |
639 | explicit UsesIterator(MDefinition* def) : def_(def) {} |
640 | auto begin() const { return def_->usesBegin(); } |
641 | auto end() const { return def_->usesEnd(); } |
642 | }; |
643 | |
644 | static bool AllInstructionsDeadIfUnused(MBasicBlock* block) { |
645 | for (auto* ins : *block) { |
646 | // Skip trivial instructions. |
647 | if (ins->isNop() || ins->isGoto()) { |
648 | continue; |
649 | } |
650 | |
651 | // All uses must be within the current block. |
652 | for (auto* use : UsesIterator(ins)) { |
653 | if (use->consumer()->block() != block) { |
654 | return false; |
655 | } |
656 | } |
657 | |
658 | // All instructions within this block must be dead if unused. |
659 | if (!DeadIfUnused(ins)) { |
660 | return false; |
661 | } |
662 | } |
663 | return true; |
664 | } |
665 | |
666 | MDefinition* MTest::foldsNeedlessControlFlow(TempAllocator& alloc) { |
667 | // All instructions within both successors need be dead if unused. |
668 | if (!AllInstructionsDeadIfUnused(ifTrue()) || |
669 | !AllInstructionsDeadIfUnused(ifFalse())) { |
670 | return nullptr; |
671 | } |
672 | |
673 | // Both successors must have the same target successor. |
674 | if (ifTrue()->numSuccessors() != 1 || ifFalse()->numSuccessors() != 1) { |
675 | return nullptr; |
676 | } |
677 | if (ifTrue()->getSuccessor(0) != ifFalse()->getSuccessor(0)) { |
678 | return nullptr; |
679 | } |
680 | |
681 | // The target successor's phis must be redundant. Redundant phis should have |
682 | // been removed in an earlier pass, so only check if any phis are present, |
683 | // which is a stronger condition. |
684 | if (ifTrue()->successorWithPhis()) { |
685 | return nullptr; |
686 | } |
687 | |
688 | return MGoto::New(alloc, ifTrue()); |
689 | } |
690 | |
691 | // If a test is dominated by either the true or false path of a previous test of |
692 | // the same condition, then the test is redundant and can be converted into a |
693 | // goto true or goto false, respectively. |
694 | MDefinition* MTest::foldsRedundantTest(TempAllocator& alloc) { |
695 | MBasicBlock* myBlock = this->block(); |
696 | MDefinition* originalInput = getOperand(0); |
697 | |
698 | // Handle single and double negatives. This ensures that we do not miss a |
699 | // folding opportunity due to a condition being inverted. |
700 | MDefinition* newInput = input(); |
701 | bool inverted = false; |
702 | if (originalInput->isNot()) { |
703 | newInput = originalInput->toNot()->input(); |
704 | inverted = true; |
705 | if (originalInput->toNot()->input()->isNot()) { |
706 | newInput = originalInput->toNot()->input()->toNot()->input(); |
707 | inverted = false; |
708 | } |
709 | } |
710 | |
711 | // The specific order of traversal does not matter. If there are multiple |
712 | // dominating redundant tests, they will either agree on direction (in which |
713 | // case we will prune the same way regardless of order), or they will |
714 | // disagree, in which case we will eventually be marked entirely dead by the |
715 | // folding of the redundant parent. |
716 | for (MUseIterator i(newInput->usesBegin()), e(newInput->usesEnd()); i != e; |
717 | ++i) { |
718 | if (!i->consumer()->isDefinition()) { |
719 | continue; |
720 | } |
721 | if (!i->consumer()->toDefinition()->isTest()) { |
722 | continue; |
723 | } |
724 | MTest* otherTest = i->consumer()->toDefinition()->toTest(); |
725 | if (otherTest == this) { |
726 | continue; |
727 | } |
728 | |
729 | if (otherTest->ifFalse()->dominates(myBlock)) { |
730 | // This test cannot be true, so fold to a goto false. |
731 | return MGoto::New(alloc, inverted ? ifTrue() : ifFalse()); |
732 | } |
733 | if (otherTest->ifTrue()->dominates(myBlock)) { |
734 | // This test cannot be false, so fold to a goto true. |
735 | return MGoto::New(alloc, inverted ? ifFalse() : ifTrue()); |
736 | } |
737 | } |
738 | |
739 | return nullptr; |
740 | } |
741 | |
742 | MDefinition* MTest::foldsTo(TempAllocator& alloc) { |
743 | if (MDefinition* def = foldsRedundantTest(alloc)) { |
744 | return def; |
745 | } |
746 | |
747 | if (MDefinition* def = foldsDoubleNegation(alloc)) { |
748 | return def; |
749 | } |
750 | |
751 | if (MDefinition* def = foldsConstant(alloc)) { |
752 | return def; |
753 | } |
754 | |
755 | if (MDefinition* def = foldsTypes(alloc)) { |
756 | return def; |
757 | } |
758 | |
759 | if (MDefinition* def = foldsNeedlessControlFlow(alloc)) { |
760 | return def; |
761 | } |
762 | |
763 | return this; |
764 | } |
765 | |
766 | AliasSet MThrow::getAliasSet() const { |
767 | return AliasSet::Store(AliasSet::ExceptionState); |
768 | } |
769 | |
770 | AliasSet MThrowWithStack::getAliasSet() const { |
771 | return AliasSet::Store(AliasSet::ExceptionState); |
772 | } |
773 | |
774 | AliasSet MNewArrayDynamicLength::getAliasSet() const { |
775 | return AliasSet::Store(AliasSet::ExceptionState); |
776 | } |
777 | |
778 | AliasSet MNewTypedArrayDynamicLength::getAliasSet() const { |
779 | return AliasSet::Store(AliasSet::ExceptionState); |
780 | } |
781 | |
782 | #ifdef JS_JITSPEW1 |
783 | void MDefinition::printOpcode(GenericPrinter& out) const { |
784 | PrintOpcodeName(out, op()); |
785 | for (size_t j = 0, e = numOperands(); j < e; j++) { |
786 | out.printf(" "); |
787 | if (getUseFor(j)->hasProducer()) { |
788 | getOperand(j)->printName(out); |
789 | out.printf(":%s", StringFromMIRType(getOperand(j)->type())); |
790 | } else { |
791 | out.printf("(null)"); |
792 | } |
793 | } |
794 | } |
795 | |
796 | void MDefinition::dump(GenericPrinter& out) const { |
797 | printName(out); |
798 | out.printf(":%s", StringFromMIRType(type())); |
799 | out.printf(" = "); |
800 | printOpcode(out); |
801 | out.printf("\n"); |
802 | |
803 | if (isInstruction()) { |
804 | if (MResumePoint* resume = toInstruction()->resumePoint()) { |
805 | resume->dump(out); |
806 | } |
807 | } |
808 | } |
809 | |
810 | void MDefinition::dump() const { |
811 | Fprinter out(stderrstderr); |
812 | dump(out); |
813 | out.finish(); |
814 | } |
815 | |
816 | void MDefinition::dumpLocation(GenericPrinter& out) const { |
817 | MResumePoint* rp = nullptr; |
818 | const char* linkWord = nullptr; |
819 | if (isInstruction() && toInstruction()->resumePoint()) { |
820 | rp = toInstruction()->resumePoint(); |
821 | linkWord = "at"; |
822 | } else { |
823 | rp = block()->entryResumePoint(); |
824 | linkWord = "after"; |
825 | } |
826 | |
827 | while (rp) { |
828 | JSScript* script = rp->block()->info().script(); |
829 | uint32_t lineno = PCToLineNumber(rp->block()->info().script(), rp->pc()); |
830 | out.printf(" %s %s:%u\n", linkWord, script->filename(), lineno); |
831 | rp = rp->caller(); |
832 | linkWord = "in"; |
833 | } |
834 | } |
835 | |
836 | void MDefinition::dumpLocation() const { |
837 | Fprinter out(stderrstderr); |
838 | dumpLocation(out); |
839 | out.finish(); |
840 | } |
841 | #endif |
842 | |
843 | #if defined(DEBUG1) || defined(JS_JITSPEW1) |
844 | size_t MDefinition::useCount() const { |
845 | size_t count = 0; |
846 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
847 | count++; |
848 | } |
849 | return count; |
850 | } |
851 | |
852 | size_t MDefinition::defUseCount() const { |
853 | size_t count = 0; |
854 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
855 | if ((*i)->consumer()->isDefinition()) { |
856 | count++; |
857 | } |
858 | } |
859 | return count; |
860 | } |
861 | #endif |
862 | |
863 | bool MDefinition::hasOneUse() const { |
864 | MUseIterator i(uses_.begin()); |
865 | if (i == uses_.end()) { |
866 | return false; |
867 | } |
868 | i++; |
869 | return i == uses_.end(); |
870 | } |
871 | |
872 | bool MDefinition::hasOneDefUse() const { |
873 | bool hasOneDefUse = false; |
874 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
875 | if (!(*i)->consumer()->isDefinition()) { |
876 | continue; |
877 | } |
878 | |
879 | // We already have a definition use. So 1+ |
880 | if (hasOneDefUse) { |
881 | return false; |
882 | } |
883 | |
884 | // We saw one definition. Loop to test if there is another. |
885 | hasOneDefUse = true; |
886 | } |
887 | |
888 | return hasOneDefUse; |
889 | } |
890 | |
891 | bool MDefinition::hasOneLiveDefUse() const { |
892 | bool hasOneDefUse = false; |
893 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
894 | if (!(*i)->consumer()->isDefinition()) { |
895 | continue; |
896 | } |
897 | |
898 | MDefinition* def = (*i)->consumer()->toDefinition(); |
899 | if (def->isRecoveredOnBailout()) { |
900 | continue; |
901 | } |
902 | |
903 | // We already have a definition use. So 1+ |
904 | if (hasOneDefUse) { |
905 | return false; |
906 | } |
907 | |
908 | // We saw one definition. Loop to test if there is another. |
909 | hasOneDefUse = true; |
910 | } |
911 | |
912 | return hasOneDefUse; |
913 | } |
914 | |
915 | bool MDefinition::hasDefUses() const { |
916 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
917 | if ((*i)->consumer()->isDefinition()) { |
918 | return true; |
919 | } |
920 | } |
921 | |
922 | return false; |
923 | } |
924 | |
925 | bool MDefinition::hasLiveDefUses() const { |
926 | for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) { |
927 | MNode* ins = (*i)->consumer(); |
928 | if (ins->isDefinition()) { |
929 | if (!ins->toDefinition()->isRecoveredOnBailout()) { |
930 | return true; |
931 | } |
932 | } else { |
933 | 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" , 933); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->isResumePoint()" ")"); do { *((volatile int*)__null) = 933; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
934 | if (!ins->toResumePoint()->isRecoverableOperand(*i)) { |
935 | return true; |
936 | } |
937 | } |
938 | } |
939 | |
940 | return false; |
941 | } |
942 | |
943 | MDefinition* MDefinition::maybeSingleDefUse() const { |
944 | MUseDefIterator use(this); |
945 | if (!use) { |
946 | // No def-uses. |
947 | return nullptr; |
948 | } |
949 | |
950 | MDefinition* useDef = use.def(); |
951 | |
952 | use++; |
953 | if (use) { |
954 | // More than one def-use. |
955 | return nullptr; |
956 | } |
957 | |
958 | return useDef; |
959 | } |
960 | |
961 | MDefinition* MDefinition::maybeMostRecentlyAddedDefUse() const { |
962 | MUseDefIterator use(this); |
963 | if (!use) { |
964 | // No def-uses. |
965 | return nullptr; |
966 | } |
967 | |
968 | MDefinition* mostRecentUse = use.def(); |
969 | |
970 | #ifdef DEBUG1 |
971 | // This function relies on addUse adding new uses to the front of the list. |
972 | // Check this invariant by asserting the next few uses are 'older'. Skip this |
973 | // for phis because setBackedge can add a new use for a loop phi even if the |
974 | // loop body has a use with an id greater than the loop phi's id. |
975 | if (!mostRecentUse->isPhi()) { |
976 | static constexpr size_t NumUsesToCheck = 3; |
977 | use++; |
978 | for (size_t i = 0; use && i < NumUsesToCheck; i++, use++) { |
979 | 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" , 979); AnnotateMozCrashReason("MOZ_ASSERT" "(" "use.def()->id() <= mostRecentUse->id()" ")"); do { *((volatile int*)__null) = 979; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
980 | } |
981 | } |
982 | #endif |
983 | |
984 | return mostRecentUse; |
985 | } |
986 | |
987 | void MDefinition::replaceAllUsesWith(MDefinition* dom) { |
988 | for (size_t i = 0, e = numOperands(); i < e; ++i) { |
989 | getOperand(i)->setImplicitlyUsedUnchecked(); |
990 | } |
991 | |
992 | justReplaceAllUsesWith(dom); |
993 | } |
994 | |
995 | void MDefinition::justReplaceAllUsesWith(MDefinition* dom) { |
996 | 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" , 996); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != nullptr" ")"); do { *((volatile int*)__null) = 996; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
997 | 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" , 997); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != this" ")"); do { *((volatile int*)__null) = 997; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
998 | |
999 | // Carry over the fact the value has uses which are no longer inspectable |
1000 | // with the graph. |
1001 | if (isImplicitlyUsed()) { |
1002 | dom->setImplicitlyUsedUnchecked(); |
1003 | } |
1004 | |
1005 | for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i) { |
1006 | i->setProducerUnchecked(dom); |
1007 | } |
1008 | dom->uses_.takeElements(uses_); |
1009 | } |
1010 | |
1011 | bool MDefinition::optimizeOutAllUses(TempAllocator& alloc) { |
1012 | for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) { |
1013 | MUse* use = *i++; |
1014 | MConstant* constant = use->consumer()->block()->optimizedOutConstant(alloc); |
1015 | if (!alloc.ensureBallast()) { |
1016 | return false; |
1017 | } |
1018 | |
1019 | // Update the resume point operand to use the optimized-out constant. |
1020 | use->setProducerUnchecked(constant); |
1021 | constant->addUseUnchecked(use); |
1022 | } |
1023 | |
1024 | // Remove dangling pointers. |
1025 | this->uses_.clear(); |
1026 | return true; |
1027 | } |
1028 | |
1029 | void MDefinition::replaceAllLiveUsesWith(MDefinition* dom) { |
1030 | for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) { |
1031 | MUse* use = *i++; |
1032 | MNode* consumer = use->consumer(); |
1033 | if (consumer->isResumePoint()) { |
1034 | continue; |
1035 | } |
1036 | if (consumer->isDefinition() && |
1037 | consumer->toDefinition()->isRecoveredOnBailout()) { |
1038 | continue; |
1039 | } |
1040 | |
1041 | // Update the operand to use the dominating definition. |
1042 | use->replaceProducer(dom); |
1043 | } |
1044 | } |
1045 | |
1046 | MConstant* MConstant::New(TempAllocator& alloc, const Value& v) { |
1047 | return new (alloc) MConstant(alloc, v); |
1048 | } |
1049 | |
1050 | MConstant* MConstant::New(TempAllocator::Fallible alloc, const Value& v) { |
1051 | return new (alloc) MConstant(alloc.alloc, v); |
1052 | } |
1053 | |
1054 | MConstant* MConstant::NewFloat32(TempAllocator& alloc, double d) { |
1055 | 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" , 1055); AnnotateMozCrashReason("MOZ_ASSERT" "(" "std::isnan(d) || d == double(float(d))" ")"); do { *((volatile int*)__null) = 1055; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1056 | return new (alloc) MConstant(float(d)); |
1057 | } |
1058 | |
1059 | MConstant* MConstant::NewInt64(TempAllocator& alloc, int64_t i) { |
1060 | return new (alloc) MConstant(MIRType::Int64, i); |
1061 | } |
1062 | |
1063 | MConstant* MConstant::NewIntPtr(TempAllocator& alloc, intptr_t i) { |
1064 | return new (alloc) MConstant(MIRType::IntPtr, i); |
1065 | } |
1066 | |
1067 | MConstant* MConstant::New(TempAllocator& alloc, const Value& v, MIRType type) { |
1068 | if (type == MIRType::Float32) { |
1069 | return NewFloat32(alloc, v.toNumber()); |
1070 | } |
1071 | MConstant* res = New(alloc, v); |
1072 | 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" , 1072); AnnotateMozCrashReason("MOZ_ASSERT" "(" "res->type() == type" ")"); do { *((volatile int*)__null) = 1072; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1073 | return res; |
1074 | } |
1075 | |
1076 | MConstant* MConstant::NewObject(TempAllocator& alloc, JSObject* v) { |
1077 | return new (alloc) MConstant(v); |
1078 | } |
1079 | |
1080 | MConstant* MConstant::NewShape(TempAllocator& alloc, Shape* s) { |
1081 | return new (alloc) MConstant(s); |
1082 | } |
1083 | |
1084 | static MIRType MIRTypeFromValue(const js::Value& vp) { |
1085 | if (vp.isDouble()) { |
1086 | return MIRType::Double; |
1087 | } |
1088 | if (vp.isMagic()) { |
1089 | switch (vp.whyMagic()) { |
1090 | case JS_OPTIMIZED_OUT: |
1091 | return MIRType::MagicOptimizedOut; |
1092 | case JS_ELEMENTS_HOLE: |
1093 | return MIRType::MagicHole; |
1094 | case JS_IS_CONSTRUCTING: |
1095 | return MIRType::MagicIsConstructing; |
1096 | case JS_UNINITIALIZED_LEXICAL: |
1097 | return MIRType::MagicUninitializedLexical; |
1098 | default: |
1099 | 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" , 1099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected magic constant" ")"); do { *((volatile int*)__null) = 1099; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1100 | } |
1101 | } |
1102 | return MIRTypeFromValueType(vp.extractNonDoubleType()); |
1103 | } |
1104 | |
1105 | MConstant::MConstant(TempAllocator& alloc, const js::Value& vp) |
1106 | : MNullaryInstruction(classOpcode) { |
1107 | setResultType(MIRTypeFromValue(vp)); |
1108 | |
1109 | 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" , 1109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0" ")"); do { *((volatile int*)__null) = 1109; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1110 | |
1111 | switch (type()) { |
1112 | case MIRType::Undefined: |
1113 | case MIRType::Null: |
1114 | break; |
1115 | case MIRType::Boolean: |
1116 | payload_.b = vp.toBoolean(); |
1117 | break; |
1118 | case MIRType::Int32: |
1119 | payload_.i32 = vp.toInt32(); |
1120 | break; |
1121 | case MIRType::Double: |
1122 | payload_.d = vp.toDouble(); |
1123 | break; |
1124 | case MIRType::String: { |
1125 | JSString* str = vp.toString(); |
1126 | if (str->isAtomRef()) { |
1127 | str = str->atom(); |
1128 | } |
1129 | 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" , 1129); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(str)" ")"); do { *((volatile int*)__null) = 1129; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1130 | 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" , 1130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "str->isAtom()" ")"); do { *((volatile int*)__null) = 1130; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1131 | payload_.str = vp.toString(); |
1132 | break; |
1133 | } |
1134 | case MIRType::Symbol: |
1135 | payload_.sym = vp.toSymbol(); |
1136 | break; |
1137 | case MIRType::BigInt: |
1138 | 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" , 1138); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(vp.toBigInt())" ")"); do { *((volatile int*)__null) = 1138; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1139 | payload_.bi = vp.toBigInt(); |
1140 | break; |
1141 | case MIRType::Object: |
1142 | 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" , 1142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(&vp.toObject())" ")"); do { *((volatile int*)__null) = 1142; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1143 | payload_.obj = &vp.toObject(); |
1144 | break; |
1145 | case MIRType::MagicOptimizedOut: |
1146 | case MIRType::MagicHole: |
1147 | case MIRType::MagicIsConstructing: |
1148 | case MIRType::MagicUninitializedLexical: |
1149 | break; |
1150 | default: |
1151 | MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1151); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type" ")"); do { *((volatile int*)__null) = 1151; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
1152 | } |
1153 | |
1154 | setMovable(); |
1155 | } |
1156 | |
1157 | MConstant::MConstant(JSObject* obj) : MNullaryInstruction(classOpcode) { |
1158 | 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" , 1158); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(obj)" ")"); do { *((volatile int*)__null) = 1158; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1159 | setResultType(MIRType::Object); |
1160 | payload_.obj = obj; |
1161 | setMovable(); |
1162 | } |
1163 | |
1164 | MConstant::MConstant(Shape* shape) : MNullaryInstruction(classOpcode) { |
1165 | setResultType(MIRType::Shape); |
1166 | payload_.shape = shape; |
1167 | setMovable(); |
1168 | } |
1169 | |
1170 | MConstant::MConstant(float f) : MNullaryInstruction(classOpcode) { |
1171 | setResultType(MIRType::Float32); |
1172 | payload_.f = f; |
1173 | setMovable(); |
1174 | } |
1175 | |
1176 | MConstant::MConstant(MIRType type, int64_t i) |
1177 | : MNullaryInstruction(classOpcode) { |
1178 | 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" , 1178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int64 || type == MIRType::IntPtr" ")"); do { *((volatile int*)__null) = 1178; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1179 | setResultType(type); |
1180 | if (type == MIRType::Int64) { |
1181 | payload_.i64 = i; |
1182 | } else { |
1183 | payload_.iptr = i; |
1184 | } |
1185 | setMovable(); |
1186 | } |
1187 | |
1188 | #ifdef DEBUG1 |
1189 | void MConstant::assertInitializedPayload() const { |
1190 | // valueHash() and equals() expect the unused payload bits to be |
1191 | // initialized to zero. Assert this in debug builds. |
1192 | |
1193 | switch (type()) { |
1194 | case MIRType::Int32: |
1195 | case MIRType::Float32: |
1196 | # if MOZ_LITTLE_ENDIAN()1 |
1197 | 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" , 1197); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0" ")"); do { *((volatile int*)__null) = 1197; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1198 | # else |
1199 | 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" , 1199); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0" ")"); do { *((volatile int*)__null) = 1199; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1200 | # endif |
1201 | break; |
1202 | case MIRType::Boolean: |
1203 | # if MOZ_LITTLE_ENDIAN()1 |
1204 | 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" , 1204); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 1) == 0" ")"); do { *((volatile int*)__null) = 1204; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1205 | # else |
1206 | 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" , 1206); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits & ~(1ULL << 56)) == 0" ")"); do { *((volatile int*)__null) = 1206; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1207 | # endif |
1208 | break; |
1209 | case MIRType::Double: |
1210 | case MIRType::Int64: |
1211 | break; |
1212 | case MIRType::String: |
1213 | case MIRType::Object: |
1214 | case MIRType::Symbol: |
1215 | case MIRType::BigInt: |
1216 | case MIRType::IntPtr: |
1217 | case MIRType::Shape: |
1218 | # if MOZ_LITTLE_ENDIAN()1 |
1219 | 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" , 1219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0" ")"); do { *((volatile int*)__null) = 1219; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1220 | # else |
1221 | 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" , 1221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0" ")"); do { *((volatile int*)__null) = 1221; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1222 | # endif |
1223 | break; |
1224 | default: |
1225 | 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" , 1225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNullOrUndefined(type()) || IsMagicType(type())" ")"); do { *((volatile int*)__null) = 1225; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1226 | 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" , 1226); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0" ")"); do { *((volatile int*)__null) = 1226; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1227 | break; |
1228 | } |
1229 | } |
1230 | #endif |
1231 | |
1232 | HashNumber MConstant::valueHash() const { |
1233 | static_assert(sizeof(Payload) == sizeof(uint64_t), |
1234 | "Code below assumes payload fits in 64 bits"); |
1235 | |
1236 | assertInitializedPayload(); |
1237 | return ConstantValueHash(type(), payload_.asBits); |
1238 | } |
1239 | |
1240 | HashNumber MConstantProto::valueHash() const { |
1241 | HashNumber hash = protoObject()->valueHash(); |
1242 | const MDefinition* receiverObject = getReceiverObject(); |
1243 | if (receiverObject) { |
1244 | hash = addU32ToHash(hash, receiverObject->id()); |
1245 | } |
1246 | return hash; |
1247 | } |
1248 | |
1249 | bool MConstant::congruentTo(const MDefinition* ins) const { |
1250 | return ins->isConstant() && equals(ins->toConstant()); |
1251 | } |
1252 | |
1253 | #ifdef JS_JITSPEW1 |
1254 | void MConstant::printOpcode(GenericPrinter& out) const { |
1255 | PrintOpcodeName(out, op()); |
1256 | out.printf(" "); |
1257 | switch (type()) { |
1258 | case MIRType::Undefined: |
1259 | out.printf("undefined"); |
1260 | break; |
1261 | case MIRType::Null: |
1262 | out.printf("null"); |
1263 | break; |
1264 | case MIRType::Boolean: |
1265 | out.printf(toBoolean() ? "true" : "false"); |
1266 | break; |
1267 | case MIRType::Int32: |
1268 | out.printf("0x%x", uint32_t(toInt32())); |
1269 | break; |
1270 | case MIRType::Int64: |
1271 | out.printf("0x%" PRIx64"l" "x", uint64_t(toInt64())); |
1272 | break; |
1273 | case MIRType::IntPtr: |
1274 | out.printf("0x%" PRIxPTR"l" "x", uintptr_t(toIntPtr())); |
1275 | break; |
1276 | case MIRType::Double: |
1277 | out.printf("%.16g", toDouble()); |
1278 | break; |
1279 | case MIRType::Float32: { |
1280 | float val = toFloat32(); |
1281 | out.printf("%.16g", val); |
1282 | break; |
1283 | } |
1284 | case MIRType::Object: |
1285 | if (toObject().is<JSFunction>()) { |
1286 | JSFunction* fun = &toObject().as<JSFunction>(); |
1287 | if (fun->maybePartialDisplayAtom()) { |
1288 | out.put("function "); |
1289 | EscapedStringPrinter(out, fun->maybePartialDisplayAtom(), 0); |
1290 | } else { |
1291 | out.put("unnamed function"); |
1292 | } |
1293 | if (fun->hasBaseScript()) { |
1294 | BaseScript* script = fun->baseScript(); |
1295 | out.printf(" (%s:%u)", script->filename() ? script->filename() : "", |
1296 | script->lineno()); |
1297 | } |
1298 | out.printf(" at %p", (void*)fun); |
1299 | break; |
1300 | } |
1301 | out.printf("object %p (%s)", (void*)&toObject(), |
1302 | toObject().getClass()->name); |
1303 | break; |
1304 | case MIRType::Symbol: |
1305 | out.printf("symbol at %p", (void*)toSymbol()); |
1306 | break; |
1307 | case MIRType::BigInt: |
1308 | out.printf("BigInt at %p", (void*)toBigInt()); |
1309 | break; |
1310 | case MIRType::String: |
1311 | out.printf("string %p", (void*)toString()); |
1312 | break; |
1313 | case MIRType::Shape: |
1314 | out.printf("shape at %p", (void*)toShape()); |
1315 | break; |
1316 | case MIRType::MagicHole: |
1317 | out.printf("magic hole"); |
1318 | break; |
1319 | case MIRType::MagicIsConstructing: |
1320 | out.printf("magic is-constructing"); |
1321 | break; |
1322 | case MIRType::MagicOptimizedOut: |
1323 | out.printf("magic optimized-out"); |
1324 | break; |
1325 | case MIRType::MagicUninitializedLexical: |
1326 | out.printf("magic uninitialized-lexical"); |
1327 | break; |
1328 | default: |
1329 | MOZ_CRASH("unexpected type")do { do { } while (false); MOZ_ReportCrash("" "unexpected type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1329); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected type" ")"); do { *((volatile int*)__null) = 1329; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
1330 | } |
1331 | } |
1332 | #endif |
1333 | |
1334 | bool MConstant::canProduceFloat32() const { |
1335 | if (!isTypeRepresentableAsDouble()) { |
1336 | return false; |
1337 | } |
1338 | |
1339 | if (type() == MIRType::Int32) { |
1340 | return IsFloat32Representable(static_cast<double>(toInt32())); |
1341 | } |
1342 | if (type() == MIRType::Double) { |
1343 | return IsFloat32Representable(toDouble()); |
1344 | } |
1345 | 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" , 1345); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Float32" ")"); do { *((volatile int*)__null) = 1345; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1346 | return true; |
1347 | } |
1348 | |
1349 | Value MConstant::toJSValue() const { |
1350 | // Wasm has types like int64 that cannot be stored as js::Value. It also |
1351 | // doesn't want the NaN canonicalization enforced by js::Value. |
1352 | 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" , 1352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsCompilingWasm()" ")"); do { *((volatile int*)__null) = 1352; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1353 | |
1354 | switch (type()) { |
1355 | case MIRType::Undefined: |
1356 | return UndefinedValue(); |
1357 | case MIRType::Null: |
1358 | return NullValue(); |
1359 | case MIRType::Boolean: |
1360 | return BooleanValue(toBoolean()); |
1361 | case MIRType::Int32: |
1362 | return Int32Value(toInt32()); |
1363 | case MIRType::Double: |
1364 | return DoubleValue(toDouble()); |
1365 | case MIRType::Float32: |
1366 | return Float32Value(toFloat32()); |
1367 | case MIRType::String: |
1368 | return StringValue(toString()); |
1369 | case MIRType::Symbol: |
1370 | return SymbolValue(toSymbol()); |
1371 | case MIRType::BigInt: |
1372 | return BigIntValue(toBigInt()); |
1373 | case MIRType::Object: |
1374 | return ObjectValue(toObject()); |
1375 | case MIRType::Shape: |
1376 | return PrivateGCThingValue(toShape()); |
1377 | case MIRType::MagicOptimizedOut: |
1378 | return MagicValue(JS_OPTIMIZED_OUT); |
1379 | case MIRType::MagicHole: |
1380 | return MagicValue(JS_ELEMENTS_HOLE); |
1381 | case MIRType::MagicIsConstructing: |
1382 | return MagicValue(JS_IS_CONSTRUCTING); |
1383 | case MIRType::MagicUninitializedLexical: |
1384 | return MagicValue(JS_UNINITIALIZED_LEXICAL); |
1385 | default: |
1386 | MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1386); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type" ")"); do { *((volatile int*)__null) = 1386; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
1387 | } |
1388 | } |
1389 | |
1390 | bool MConstant::valueToBoolean(bool* res) const { |
1391 | switch (type()) { |
1392 | case MIRType::Boolean: |
1393 | *res = toBoolean(); |
1394 | return true; |
1395 | case MIRType::Int32: |
1396 | *res = toInt32() != 0; |
1397 | return true; |
1398 | case MIRType::Int64: |
1399 | *res = toInt64() != 0; |
1400 | return true; |
1401 | case MIRType::Double: |
1402 | *res = !std::isnan(toDouble()) && toDouble() != 0.0; |
1403 | return true; |
1404 | case MIRType::Float32: |
1405 | *res = !std::isnan(toFloat32()) && toFloat32() != 0.0f; |
1406 | return true; |
1407 | case MIRType::Null: |
1408 | case MIRType::Undefined: |
1409 | *res = false; |
1410 | return true; |
1411 | case MIRType::Symbol: |
1412 | *res = true; |
1413 | return true; |
1414 | case MIRType::BigInt: |
1415 | *res = !toBigInt()->isZero(); |
1416 | return true; |
1417 | case MIRType::String: |
1418 | *res = toString()->length() != 0; |
1419 | return true; |
1420 | case MIRType::Object: |
1421 | // TODO(Warp): Lazy groups have been removed. |
1422 | // We have to call EmulatesUndefined but that reads obj->group->clasp |
1423 | // and so it's racy when the object has a lazy group. The main callers |
1424 | // of this (MTest, MNot) already know how to fold the object case, so |
1425 | // just give up. |
1426 | return false; |
1427 | default: |
1428 | 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" , 1428); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsMagicType(type())" ")"); do { *((volatile int*)__null) = 1428; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1429 | return false; |
1430 | } |
1431 | } |
1432 | |
1433 | #ifdef JS_JITSPEW1 |
1434 | void MControlInstruction::printOpcode(GenericPrinter& out) const { |
1435 | MDefinition::printOpcode(out); |
1436 | for (size_t j = 0; j < numSuccessors(); j++) { |
1437 | if (getSuccessor(j)) { |
1438 | out.printf(" block%u", getSuccessor(j)->id()); |
1439 | } else { |
1440 | out.printf(" (null-to-be-patched)"); |
1441 | } |
1442 | } |
1443 | } |
1444 | |
1445 | void MCompare::printOpcode(GenericPrinter& out) const { |
1446 | MDefinition::printOpcode(out); |
1447 | out.printf(" %s", CodeName(jsop())); |
1448 | } |
1449 | |
1450 | void MTypeOfIs::printOpcode(GenericPrinter& out) const { |
1451 | MDefinition::printOpcode(out); |
1452 | out.printf(" %s", CodeName(jsop())); |
1453 | |
1454 | const char* name = ""; |
Value stored to 'name' during its initialization is never read | |
1455 | switch (jstype()) { |
1456 | case JSTYPE_UNDEFINED: |
1457 | name = "undefined"; |
1458 | break; |
1459 | case JSTYPE_OBJECT: |
1460 | name = "object"; |
1461 | break; |
1462 | case JSTYPE_FUNCTION: |
1463 | name = "function"; |
1464 | break; |
1465 | case JSTYPE_STRING: |
1466 | name = "string"; |
1467 | break; |
1468 | case JSTYPE_NUMBER: |
1469 | name = "number"; |
1470 | break; |
1471 | case JSTYPE_BOOLEAN: |
1472 | name = "boolean"; |
1473 | break; |
1474 | case JSTYPE_SYMBOL: |
1475 | name = "symbol"; |
1476 | break; |
1477 | case JSTYPE_BIGINT: |
1478 | name = "bigint"; |
1479 | break; |
1480 | # ifdef ENABLE_RECORD_TUPLE |
1481 | case JSTYPE_RECORD: |
1482 | case JSTYPE_TUPLE: |
1483 | # endif |
1484 | case JSTYPE_LIMIT: |
1485 | MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 1485); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type" ")"); do { *((volatile int*)__null) = 1485; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
1486 | } |
1487 | out.printf(" '%s'", name); |
1488 | } |
1489 | |
1490 | void MLoadUnboxedScalar::printOpcode(GenericPrinter& out) const { |
1491 | MDefinition::printOpcode(out); |
1492 | out.printf(" %s", Scalar::name(storageType())); |
1493 | } |
1494 | |
1495 | void MLoadDataViewElement::printOpcode(GenericPrinter& out) const { |
1496 | MDefinition::printOpcode(out); |
1497 | out.printf(" %s", Scalar::name(storageType())); |
1498 | } |
1499 | |
1500 | void MAssertRange::printOpcode(GenericPrinter& out) const { |
1501 | MDefinition::printOpcode(out); |
1502 | out.put(" "); |
1503 | assertedRange()->dump(out); |
1504 | } |
1505 | |
1506 | void MNearbyInt::printOpcode(GenericPrinter& out) const { |
1507 | MDefinition::printOpcode(out); |
1508 | const char* roundingModeStr = nullptr; |
1509 | switch (roundingMode_) { |
1510 | case RoundingMode::Up: |
1511 | roundingModeStr = "(up)"; |
1512 | break; |
1513 | case RoundingMode::Down: |
1514 | roundingModeStr = "(down)"; |
1515 | break; |
1516 | case RoundingMode::NearestTiesToEven: |
1517 | roundingModeStr = "(nearest ties even)"; |
1518 | break; |
1519 | case RoundingMode::TowardsZero: |
1520 | roundingModeStr = "(towards zero)"; |
1521 | break; |
1522 | } |
1523 | out.printf(" %s", roundingModeStr); |
1524 | } |
1525 | #endif |
1526 | |
1527 | AliasSet MRandom::getAliasSet() const { return AliasSet::Store(AliasSet::RNG); } |
1528 | |
1529 | MDefinition* MSign::foldsTo(TempAllocator& alloc) { |
1530 | MDefinition* input = getOperand(0); |
1531 | if (!input->isConstant() || |
1532 | !input->toConstant()->isTypeRepresentableAsDouble()) { |
1533 | return this; |
1534 | } |
1535 | |
1536 | double in = input->toConstant()->numberToDouble(); |
1537 | double out = js::math_sign_impl(in); |
1538 | |
1539 | if (type() == MIRType::Int32) { |
1540 | // Decline folding if this is an int32 operation, but the result type |
1541 | // isn't an int32. |
1542 | Value outValue = NumberValue(out); |
1543 | if (!outValue.isInt32()) { |
1544 | return this; |
1545 | } |
1546 | |
1547 | return MConstant::New(alloc, outValue); |
1548 | } |
1549 | |
1550 | return MConstant::New(alloc, DoubleValue(out)); |
1551 | } |
1552 | |
1553 | const char* MMathFunction::FunctionName(UnaryMathFunction function) { |
1554 | return GetUnaryMathFunctionName(function); |
1555 | } |
1556 | |
1557 | #ifdef JS_JITSPEW1 |
1558 | void MMathFunction::printOpcode(GenericPrinter& out) const { |
1559 | MDefinition::printOpcode(out); |
1560 | out.printf(" %s", FunctionName(function())); |
1561 | } |
1562 | #endif |
1563 | |
1564 | MDefinition* MMathFunction::foldsTo(TempAllocator& alloc) { |
1565 | MDefinition* input = getOperand(0); |
1566 | if (!input->isConstant() || |
1567 | !input->toConstant()->isTypeRepresentableAsDouble()) { |
1568 | return this; |
1569 | } |
1570 | |
1571 | UnaryMathFunctionType funPtr = GetUnaryMathFunctionPtr(function()); |
1572 | |
1573 | double in = input->toConstant()->numberToDouble(); |
1574 | |
1575 | // The function pointer call can't GC. |
1576 | JS::AutoSuppressGCAnalysis nogc; |
1577 | double out = funPtr(in); |
1578 | |
1579 | if (input->type() == MIRType::Float32) { |
1580 | return MConstant::NewFloat32(alloc, out); |
1581 | } |
1582 | return MConstant::New(alloc, DoubleValue(out)); |
1583 | } |
1584 | |
1585 | MDefinition* MAtomicIsLockFree::foldsTo(TempAllocator& alloc) { |
1586 | MDefinition* input = getOperand(0); |
1587 | if (!input->isConstant() || input->type() != MIRType::Int32) { |
1588 | return this; |
1589 | } |
1590 | |
1591 | int32_t i = input->toConstant()->toInt32(); |
1592 | return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfreeJS(i))); |
1593 | } |
1594 | |
1595 | // Define |THIS_SLOT| as part of this translation unit, as it is used to |
1596 | // specialized the parameterized |New| function calls introduced by |
1597 | // TRIVIAL_NEW_WRAPPERS. |
1598 | const int32_t MParameter::THIS_SLOT; |
1599 | |
1600 | #ifdef JS_JITSPEW1 |
1601 | void MParameter::printOpcode(GenericPrinter& out) const { |
1602 | PrintOpcodeName(out, op()); |
1603 | if (index() == THIS_SLOT) { |
1604 | out.printf(" THIS_SLOT"); |
1605 | } else { |
1606 | out.printf(" %d", index()); |
1607 | } |
1608 | } |
1609 | #endif |
1610 | |
1611 | HashNumber MParameter::valueHash() const { |
1612 | HashNumber hash = MDefinition::valueHash(); |
1613 | hash = addU32ToHash(hash, index_); |
1614 | return hash; |
1615 | } |
1616 | |
1617 | bool MParameter::congruentTo(const MDefinition* ins) const { |
1618 | if (!ins->isParameter()) { |
1619 | return false; |
1620 | } |
1621 | |
1622 | return ins->toParameter()->index() == index_; |
1623 | } |
1624 | |
1625 | WrappedFunction::WrappedFunction(JSFunction* nativeFun, uint16_t nargs, |
1626 | FunctionFlags flags) |
1627 | : nativeFun_(nativeFun), nargs_(nargs), flags_(flags) { |
1628 | 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" , 1628); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNativeWithoutJitEntry()" ")"); do { *((volatile int*)__null) = 1628; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1629 | |
1630 | #ifdef DEBUG1 |
1631 | // If we are not running off-main thread we can assert that the |
1632 | // metadata is consistent. |
1633 | if (!CanUseExtraThreads() && nativeFun) { |
1634 | 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" , 1634); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->nargs() == nargs" ")"); do { *((volatile int*)__null) = 1634; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1635 | |
1636 | 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" , 1637); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()" ")"); do { *((volatile int*)__null) = 1637; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
1637 | 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" , 1637); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()" ")"); do { *((volatile int*)__null) = 1637; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1638 | 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" , 1638); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->hasJitEntry() == hasJitEntry()" ")"); do { *((volatile int*)__null) = 1638; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1639 | 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" , 1639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isConstructor() == isConstructor()" ")"); do { *((volatile int*)__null) = 1639; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1640 | 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" , 1640); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isClassConstructor() == isClassConstructor()" ")"); do { *((volatile int*)__null) = 1640; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1641 | } |
1642 | #endif |
1643 | } |
1644 | |
1645 | MCall* MCall::New(TempAllocator& alloc, WrappedFunction* target, size_t maxArgc, |
1646 | size_t numActualArgs, bool construct, bool ignoresReturnValue, |
1647 | bool isDOMCall, mozilla::Maybe<DOMObjectKind> objectKind) { |
1648 | 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" , 1648); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isDOMCall == objectKind.isSome()" ")"); do { *((volatile int*)__null) = 1648; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1649 | 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" , 1649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "maxArgc >= numActualArgs" ")"); do { *((volatile int*)__null) = 1649; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1650 | MCall* ins; |
1651 | if (isDOMCall) { |
1652 | 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" , 1652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!construct" ")"); do { *((volatile int*)__null) = 1652; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1653 | ins = new (alloc) MCallDOMNative(target, numActualArgs, *objectKind); |
1654 | } else { |
1655 | ins = |
1656 | new (alloc) MCall(target, numActualArgs, construct, ignoresReturnValue); |
1657 | } |
1658 | if (!ins->init(alloc, maxArgc + NumNonArgumentOperands)) { |
1659 | return nullptr; |
1660 | } |
1661 | return ins; |
1662 | } |
1663 | |
1664 | AliasSet MCallDOMNative::getAliasSet() const { |
1665 | const JSJitInfo* jitInfo = getJitInfo(); |
1666 | |
1667 | // If we don't know anything about the types of our arguments, we have to |
1668 | // assume that type-coercions can have side-effects, so we need to alias |
1669 | // everything. |
1670 | if (jitInfo->aliasSet() == JSJitInfo::AliasEverything || |
1671 | !jitInfo->isTypedMethodJitInfo()) { |
1672 | return AliasSet::Store(AliasSet::Any); |
1673 | } |
1674 | |
1675 | uint32_t argIndex = 0; |
1676 | const JSTypedMethodJitInfo* methodInfo = |
1677 | reinterpret_cast<const JSTypedMethodJitInfo*>(jitInfo); |
1678 | for (const JSJitInfo::ArgType* argType = methodInfo->argTypes; |
1679 | *argType != JSJitInfo::ArgTypeListEnd; ++argType, ++argIndex) { |
1680 | if (argIndex >= numActualArgs()) { |
1681 | // Passing through undefined can't have side-effects |
1682 | continue; |
1683 | } |
1684 | // getArg(0) is "this", so skip it |
1685 | MDefinition* arg = getArg(argIndex + 1); |
1686 | MIRType actualType = arg->type(); |
1687 | // The only way to reliably avoid side-effects given the information we |
1688 | // have here is if we're passing in a known primitive value to an |
1689 | // argument that expects a primitive value. |
1690 | // |
1691 | // XXXbz maybe we need to communicate better information. For example, |
1692 | // a sequence argument will sort of unavoidably have side effects, while |
1693 | // a typed array argument won't have any, but both are claimed to be |
1694 | // JSJitInfo::Object. But if we do that, we need to watch out for our |
1695 | // movability/DCE-ability bits: if we have an arg type that can reliably |
1696 | // throw an exception on conversion, that might not affect our alias set |
1697 | // per se, but it should prevent us being moved or DCE-ed, unless we |
1698 | // know the incoming things match that arg type and won't throw. |
1699 | // |
1700 | if ((actualType == MIRType::Value || actualType == MIRType::Object) || |
1701 | (*argType & JSJitInfo::Object)) { |
1702 | return AliasSet::Store(AliasSet::Any); |
1703 | } |
1704 | } |
1705 | |
1706 | // We checked all the args, and they check out. So we only alias DOM |
1707 | // mutations or alias nothing, depending on the alias set in the jitinfo. |
1708 | if (jitInfo->aliasSet() == JSJitInfo::AliasNone) { |
1709 | return AliasSet::None(); |
1710 | } |
1711 | |
1712 | 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" , 1712); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() == JSJitInfo::AliasDOMSets" ")"); do { *((volatile int*)__null) = 1712; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1713 | return AliasSet::Load(AliasSet::DOMProperty); |
1714 | } |
1715 | |
1716 | void MCallDOMNative::computeMovable() { |
1717 | // We are movable if the jitinfo says we can be and if we're also not |
1718 | // effectful. The jitinfo can't check for the latter, since it depends on |
1719 | // the types of our arguments. |
1720 | const JSJitInfo* jitInfo = getJitInfo(); |
1721 | |
1722 | 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" , 1723); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything" ")"); do { *((volatile int*)__null) = 1723; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) |
1723 | 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" , 1723); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything" ")"); do { *((volatile int*)__null) = 1723; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1724 | |
1725 | if (jitInfo->isMovable && !isEffectful()) { |
1726 | setMovable(); |
1727 | } |
1728 | } |
1729 | |
1730 | bool MCallDOMNative::congruentTo(const MDefinition* ins) const { |
1731 | if (!isMovable()) { |
1732 | return false; |
1733 | } |
1734 | |
1735 | if (!ins->isCall()) { |
1736 | return false; |
1737 | } |
1738 | |
1739 | const MCall* call = ins->toCall(); |
1740 | |
1741 | if (!call->isCallDOMNative()) { |
1742 | return false; |
1743 | } |
1744 | |
1745 | if (getSingleTarget() != call->getSingleTarget()) { |
1746 | return false; |
1747 | } |
1748 | |
1749 | if (isConstructing() != call->isConstructing()) { |
1750 | return false; |
1751 | } |
1752 | |
1753 | if (numActualArgs() != call->numActualArgs()) { |
1754 | return false; |
1755 | } |
1756 | |
1757 | if (!congruentIfOperandsEqual(call)) { |
1758 | return false; |
1759 | } |
1760 | |
1761 | // The other call had better be movable at this point! |
1762 | 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" , 1762); AnnotateMozCrashReason("MOZ_ASSERT" "(" "call->isMovable()" ")"); do { *((volatile int*)__null) = 1762; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1763 | |
1764 | return true; |
1765 | } |
1766 | |
1767 | const JSJitInfo* MCallDOMNative::getJitInfo() const { |
1768 | 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" , 1768); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getSingleTarget()->hasJitInfo()" ")"); do { *((volatile int*)__null) = 1768; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1769 | return getSingleTarget()->jitInfo(); |
1770 | } |
1771 | |
1772 | MCallClassHook* MCallClassHook::New(TempAllocator& alloc, JSNative target, |
1773 | uint32_t argc, bool constructing) { |
1774 | auto* ins = new (alloc) MCallClassHook(target, constructing); |
1775 | |
1776 | // Add callee + |this| + (if constructing) newTarget. |
1777 | uint32_t numOperands = 2 + argc + constructing; |
1778 | |
1779 | if (!ins->init(alloc, numOperands)) { |
1780 | return nullptr; |
1781 | } |
1782 | |
1783 | return ins; |
1784 | } |
1785 | |
1786 | MDefinition* MStringLength::foldsTo(TempAllocator& alloc) { |
1787 | if (string()->isConstant()) { |
1788 | JSString* str = string()->toConstant()->toString(); |
1789 | return MConstant::New(alloc, Int32Value(str->length())); |
1790 | } |
1791 | |
1792 | // MFromCharCode returns a one-element string. |
1793 | if (string()->isFromCharCode()) { |
1794 | return MConstant::New(alloc, Int32Value(1)); |
1795 | } |
1796 | |
1797 | return this; |
1798 | } |
1799 | |
1800 | MDefinition* MConcat::foldsTo(TempAllocator& alloc) { |
1801 | if (lhs()->isConstant() && lhs()->toConstant()->toString()->empty()) { |
1802 | return rhs(); |
1803 | } |
1804 | |
1805 | if (rhs()->isConstant() && rhs()->toConstant()->toString()->empty()) { |
1806 | return lhs(); |
1807 | } |
1808 | |
1809 | return this; |
1810 | } |
1811 | |
1812 | MDefinition* MStringConvertCase::foldsTo(TempAllocator& alloc) { |
1813 | MDefinition* string = this->string(); |
1814 | |
1815 | // Handle the pattern |str[idx].toUpperCase()| and simplify it from |
1816 | // |StringConvertCase(FromCharCode(CharCodeAt(str, idx)))| to just |
1817 | // |CharCodeConvertCase(CharCodeAt(str, idx))|. |
1818 | if (string->isFromCharCode()) { |
1819 | auto* charCode = string->toFromCharCode()->code(); |
1820 | auto mode = mode_ == Mode::LowerCase ? MCharCodeConvertCase::LowerCase |
1821 | : MCharCodeConvertCase::UpperCase; |
1822 | return MCharCodeConvertCase::New(alloc, charCode, mode); |
1823 | } |
1824 | |
1825 | // Handle the pattern |num.toString(base).toUpperCase()| and simplify it to |
1826 | // directly return the string representation in the correct case. |
1827 | if (string->isInt32ToStringWithBase()) { |
1828 | auto* toString = string->toInt32ToStringWithBase(); |
1829 | |
1830 | bool lowerCase = mode_ == Mode::LowerCase; |
1831 | if (toString->lowerCase() == lowerCase) { |
1832 | return toString; |
1833 | } |
1834 | return MInt32ToStringWithBase::New(alloc, toString->input(), |
1835 | toString->base(), lowerCase); |
1836 | } |
1837 | |
1838 | return this; |
1839 | } |
1840 | |
1841 | static bool IsSubstrTo(MSubstr* substr, int32_t len) { |
1842 | // We want to match this pattern: |
1843 | // |
1844 | // Substr(string, Constant(0), Min(Constant(length), StringLength(string))) |
1845 | // |
1846 | // which is generated for the self-hosted `String.p.{substring,slice,substr}` |
1847 | // functions when called with constants `start` and `end` parameters. |
1848 | |
1849 | auto isConstantZero = [](auto* def) { |
1850 | return def->isConstant() && def->toConstant()->isInt32(0); |
1851 | }; |
1852 | |
1853 | if (!isConstantZero(substr->begin())) { |
1854 | return false; |
1855 | } |
1856 | |
1857 | auto* length = substr->length(); |
1858 | if (length->isBitOr()) { |
1859 | // Unnecessary bit-ops haven't yet been removed. |
1860 | auto* bitOr = length->toBitOr(); |
1861 | if (isConstantZero(bitOr->lhs())) { |
1862 | length = bitOr->rhs(); |
1863 | } else if (isConstantZero(bitOr->rhs())) { |
1864 | length = bitOr->lhs(); |
1865 | } |
1866 | } |
1867 | if (!length->isMinMax() || length->toMinMax()->isMax()) { |
1868 | return false; |
1869 | } |
1870 | |
1871 | auto* min = length->toMinMax(); |
1872 | if (!min->lhs()->isConstant() && !min->rhs()->isConstant()) { |
1873 | return false; |
1874 | } |
1875 | |
1876 | auto* minConstant = min->lhs()->isConstant() ? min->lhs()->toConstant() |
1877 | : min->rhs()->toConstant(); |
1878 | |
1879 | auto* minOperand = min->lhs()->isConstant() ? min->rhs() : min->lhs(); |
1880 | if (!minOperand->isStringLength() || |
1881 | minOperand->toStringLength()->string() != substr->string()) { |
1882 | return false; |
1883 | } |
1884 | |
1885 | // Ensure |len| matches the substring's length. |
1886 | return minConstant->isInt32(len); |
1887 | } |
1888 | |
1889 | MDefinition* MSubstr::foldsTo(TempAllocator& alloc) { |
1890 | // Fold |str.substring(0, 1)| to |str.charAt(0)|. |
1891 | if (!IsSubstrTo(this, 1)) { |
1892 | return this; |
1893 | } |
1894 | |
1895 | auto* charCode = MCharCodeAtOrNegative::New(alloc, string(), begin()); |
1896 | block()->insertBefore(this, charCode); |
1897 | |
1898 | return MFromCharCodeEmptyIfNegative::New(alloc, charCode); |
1899 | } |
1900 | |
1901 | MDefinition* MCharCodeAt::foldsTo(TempAllocator& alloc) { |
1902 | MDefinition* string = this->string(); |
1903 | if (!string->isConstant() && !string->isFromCharCode()) { |
1904 | return this; |
1905 | } |
1906 | |
1907 | MDefinition* index = this->index(); |
1908 | if (index->isSpectreMaskIndex()) { |
1909 | index = index->toSpectreMaskIndex()->index(); |
1910 | } |
1911 | if (!index->isConstant()) { |
1912 | return this; |
1913 | } |
1914 | int32_t idx = index->toConstant()->toInt32(); |
1915 | |
1916 | // Handle the pattern |s[idx].charCodeAt(0)|. |
1917 | if (string->isFromCharCode()) { |
1918 | if (idx != 0) { |
1919 | return this; |
1920 | } |
1921 | |
1922 | // Simplify |CharCodeAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just |
1923 | // |CharCodeAt(s, idx)|. |
1924 | auto* charCode = string->toFromCharCode()->code(); |
1925 | if (!charCode->isCharCodeAt()) { |
1926 | return this; |
1927 | } |
1928 | |
1929 | return charCode; |
1930 | } |
1931 | |
1932 | JSLinearString* str = &string->toConstant()->toString()->asLinear(); |
1933 | if (idx < 0 || uint32_t(idx) >= str->length()) { |
1934 | return this; |
1935 | } |
1936 | |
1937 | char16_t ch = str->latin1OrTwoByteChar(idx); |
1938 | return MConstant::New(alloc, Int32Value(ch)); |
1939 | } |
1940 | |
1941 | MDefinition* MCodePointAt::foldsTo(TempAllocator& alloc) { |
1942 | MDefinition* string = this->string(); |
1943 | if (!string->isConstant() && !string->isFromCharCode()) { |
1944 | return this; |
1945 | } |
1946 | |
1947 | MDefinition* index = this->index(); |
1948 | if (index->isSpectreMaskIndex()) { |
1949 | index = index->toSpectreMaskIndex()->index(); |
1950 | } |
1951 | if (!index->isConstant()) { |
1952 | return this; |
1953 | } |
1954 | int32_t idx = index->toConstant()->toInt32(); |
1955 | |
1956 | // Handle the pattern |s[idx].codePointAt(0)|. |
1957 | if (string->isFromCharCode()) { |
1958 | if (idx != 0) { |
1959 | return this; |
1960 | } |
1961 | |
1962 | // Simplify |CodePointAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just |
1963 | // |CharCodeAt(s, idx)|. |
1964 | auto* charCode = string->toFromCharCode()->code(); |
1965 | if (!charCode->isCharCodeAt()) { |
1966 | return this; |
1967 | } |
1968 | |
1969 | return charCode; |
1970 | } |
1971 | |
1972 | JSLinearString* str = &string->toConstant()->toString()->asLinear(); |
1973 | if (idx < 0 || uint32_t(idx) >= str->length()) { |
1974 | return this; |
1975 | } |
1976 | |
1977 | char32_t first = str->latin1OrTwoByteChar(idx); |
1978 | if (unicode::IsLeadSurrogate(first) && uint32_t(idx) + 1 < str->length()) { |
1979 | char32_t second = str->latin1OrTwoByteChar(idx + 1); |
1980 | if (unicode::IsTrailSurrogate(second)) { |
1981 | first = unicode::UTF16Decode(first, second); |
1982 | } |
1983 | } |
1984 | return MConstant::New(alloc, Int32Value(first)); |
1985 | } |
1986 | |
1987 | MDefinition* MToRelativeStringIndex::foldsTo(TempAllocator& alloc) { |
1988 | MDefinition* index = this->index(); |
1989 | MDefinition* length = this->length(); |
1990 | |
1991 | if (!index->isConstant()) { |
1992 | return this; |
1993 | } |
1994 | if (!length->isStringLength() && !length->isConstant()) { |
1995 | return this; |
1996 | } |
1997 | 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" , 1997); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length->toConstant()->toInt32() >= 0" ")"); do { *((volatile int*)__null) = 1997; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1998 | |
1999 | int32_t relativeIndex = index->toConstant()->toInt32(); |
2000 | if (relativeIndex >= 0) { |
2001 | return index; |
2002 | } |
2003 | |
2004 | // Safe to truncate because |length| is never negative. |
2005 | return MAdd::New(alloc, index, length, TruncateKind::Truncate); |
2006 | } |
2007 | |
2008 | template <size_t Arity> |
2009 | [[nodiscard]] static bool EnsureFloatInputOrConvert( |
2010 | MAryInstruction<Arity>* owner, TempAllocator& alloc) { |
2011 | 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" , 2012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())" ") (" "Floating point types must check consumers" ")"); do { *((volatile int*)__null) = 2012; __attribute__((nomerge)) :: abort(); } while (false); } } while (false) |
2012 | "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" , 2012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())" ") (" "Floating point types must check consumers" ")"); do { *((volatile int*)__null) = 2012; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
2013 | |
2014 | if (AllOperandsCanProduceFloat32(owner)) { |
2015 | return true; |
2016 | } |
2017 | ConvertOperandsToDouble(owner, alloc); |
2018 | return false; |
2019 | } |
2020 | |
2021 | template <size_t Arity> |
2022 | [[nodiscard]] static bool EnsureFloatConsumersAndInputOrConvert( |
2023 | MAryInstruction<Arity>* owner, TempAllocator& alloc) { |
2024 | 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" , 2025); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())" ") (" "Integer types don't need to check consumers" ")"); do { *((volatile int*)__null) = 2025; __attribute__((nomerge)) :: abort(); } while (false); } } while (false) |
2025 | "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" , 2025); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())" ") (" "Integer types don't need to check consumers" ")"); do { *((volatile int*)__null) = 2025; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
2026 | |
2027 | if (AllOperandsCanProduceFloat32(owner) && |
2028 | CheckUsesAreFloat32Consumers(owner)) { |
2029 | return true; |
2030 | } |
2031 | ConvertOperandsToDouble(owner, alloc); |
2032 | return false; |
2033 | } |
2034 | |
2035 | void MFloor::trySpecializeFloat32(TempAllocator& alloc) { |
2036 | 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" , 2036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2036; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2037 | if (EnsureFloatInputOrConvert(this, alloc)) { |
2038 | specialization_ = MIRType::Float32; |
2039 | } |
2040 | } |
2041 | |
2042 | void MCeil::trySpecializeFloat32(TempAllocator& alloc) { |
2043 | 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" , 2043); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2043; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2044 | if (EnsureFloatInputOrConvert(this, alloc)) { |
2045 | specialization_ = MIRType::Float32; |
2046 | } |
2047 | } |
2048 | |
2049 | void MRound::trySpecializeFloat32(TempAllocator& alloc) { |
2050 | 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" , 2050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2050; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2051 | if (EnsureFloatInputOrConvert(this, alloc)) { |
2052 | specialization_ = MIRType::Float32; |
2053 | } |
2054 | } |
2055 | |
2056 | void MTrunc::trySpecializeFloat32(TempAllocator& alloc) { |
2057 | 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" , 2057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2057; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2058 | if (EnsureFloatInputOrConvert(this, alloc)) { |
2059 | specialization_ = MIRType::Float32; |
2060 | } |
2061 | } |
2062 | |
2063 | void MNearbyInt::trySpecializeFloat32(TempAllocator& alloc) { |
2064 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
2065 | specialization_ = MIRType::Float32; |
2066 | setResultType(MIRType::Float32); |
2067 | } |
2068 | } |
2069 | |
2070 | MGoto* MGoto::New(TempAllocator& alloc, MBasicBlock* target) { |
2071 | return new (alloc) MGoto(target); |
2072 | } |
2073 | |
2074 | MGoto* MGoto::New(TempAllocator::Fallible alloc, MBasicBlock* target) { |
2075 | 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" , 2075); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")" ); do { *((volatile int*)__null) = 2075; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2076 | return new (alloc) MGoto(target); |
2077 | } |
2078 | |
2079 | MGoto* MGoto::New(TempAllocator& alloc) { return new (alloc) MGoto(nullptr); } |
2080 | |
2081 | MDefinition* MBox::foldsTo(TempAllocator& alloc) { |
2082 | if (input()->isUnbox()) { |
2083 | return input()->toUnbox()->input(); |
2084 | } |
2085 | return this; |
2086 | } |
2087 | |
2088 | #ifdef JS_JITSPEW1 |
2089 | void MUnbox::printOpcode(GenericPrinter& out) const { |
2090 | PrintOpcodeName(out, op()); |
2091 | out.printf(" "); |
2092 | getOperand(0)->printName(out); |
2093 | out.printf(" "); |
2094 | |
2095 | switch (type()) { |
2096 | case MIRType::Int32: |
2097 | out.printf("to Int32"); |
2098 | break; |
2099 | case MIRType::Double: |
2100 | out.printf("to Double"); |
2101 | break; |
2102 | case MIRType::Boolean: |
2103 | out.printf("to Boolean"); |
2104 | break; |
2105 | case MIRType::String: |
2106 | out.printf("to String"); |
2107 | break; |
2108 | case MIRType::Symbol: |
2109 | out.printf("to Symbol"); |
2110 | break; |
2111 | case MIRType::BigInt: |
2112 | out.printf("to BigInt"); |
2113 | break; |
2114 | case MIRType::Object: |
2115 | out.printf("to Object"); |
2116 | break; |
2117 | default: |
2118 | break; |
2119 | } |
2120 | |
2121 | switch (mode()) { |
2122 | case Fallible: |
2123 | out.printf(" (fallible)"); |
2124 | break; |
2125 | case Infallible: |
2126 | out.printf(" (infallible)"); |
2127 | break; |
2128 | default: |
2129 | break; |
2130 | } |
2131 | } |
2132 | #endif |
2133 | |
2134 | MDefinition* MUnbox::foldsTo(TempAllocator& alloc) { |
2135 | if (input()->isBox()) { |
2136 | MDefinition* unboxed = input()->toBox()->input(); |
2137 | |
2138 | // Fold MUnbox(MBox(x)) => x if types match. |
2139 | if (unboxed->type() == type()) { |
2140 | if (fallible()) { |
2141 | unboxed->setImplicitlyUsedUnchecked(); |
2142 | } |
2143 | return unboxed; |
2144 | } |
2145 | |
2146 | // Fold MUnbox(MBox(x)) => MToDouble(x) if possible. |
2147 | if (type() == MIRType::Double && |
2148 | IsTypeRepresentableAsDouble(unboxed->type())) { |
2149 | if (unboxed->isConstant()) { |
2150 | return MConstant::New( |
2151 | alloc, DoubleValue(unboxed->toConstant()->numberToDouble())); |
2152 | } |
2153 | |
2154 | return MToDouble::New(alloc, unboxed); |
2155 | } |
2156 | |
2157 | // MUnbox<Int32>(MBox<Double>(x)) will always fail, even if x can be |
2158 | // represented as an Int32. Fold to avoid unnecessary bailouts. |
2159 | if (type() == MIRType::Int32 && unboxed->type() == MIRType::Double) { |
2160 | auto* folded = MToNumberInt32::New(alloc, unboxed, |
2161 | IntConversionInputKind::NumbersOnly); |
2162 | folded->setGuard(); |
2163 | return folded; |
2164 | } |
2165 | } |
2166 | |
2167 | return this; |
2168 | } |
2169 | |
2170 | #ifdef DEBUG1 |
2171 | void MPhi::assertLoopPhi() const { |
2172 | // getLoopPredecessorOperand and getLoopBackedgeOperand rely on these |
2173 | // predecessors being at known indices. |
2174 | if (block()->numPredecessors() == 2) { |
2175 | MBasicBlock* pred = block()->getPredecessor(0); |
2176 | MBasicBlock* back = block()->getPredecessor(1); |
2177 | 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" , 2177); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred == block()->loopPredecessor()" ")"); do { *((volatile int*)__null) = 2177; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2178 | 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" , 2178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->successorWithPhis() == block()" ")"); do { *((volatile int*)__null) = 2178; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2179 | 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" , 2179); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->positionInPhiSuccessor() == 0" ")"); do { *((volatile int*)__null) = 2179; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2180 | 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" , 2180); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()" ")"); do { *((volatile int*)__null) = 2180; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2181 | 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" , 2181); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()" ")"); do { *((volatile int*)__null) = 2181; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2182 | 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" , 2182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 1" ")"); do { *((volatile int*)__null) = 2182; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2183 | } else { |
2184 | // After we remove fake loop predecessors for loop headers that |
2185 | // are only reachable via OSR, the only predecessor is the |
2186 | // loop backedge. |
2187 | 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" , 2187); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 1" ")"); do { *((volatile int*)__null) = 2187; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2188 | 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" , 2188); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->graph().osrBlock()" ")"); do { *((volatile int*)__null) = 2188; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2189 | 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" , 2189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!block()->graph().canBuildDominators()" ")"); do { *((volatile int*)__null) = 2189; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2190 | MBasicBlock* back = block()->getPredecessor(0); |
2191 | 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" , 2191); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()" ")"); do { *((volatile int*)__null) = 2191; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2192 | 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" , 2192); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()" ")"); do { *((volatile int*)__null) = 2192; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2193 | 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" , 2193); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 0" ")"); do { *((volatile int*)__null) = 2193; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2194 | } |
2195 | } |
2196 | #endif |
2197 | |
2198 | MDefinition* MPhi::getLoopPredecessorOperand() const { |
2199 | // This should not be called after removing fake loop predecessors. |
2200 | 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" , 2200); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2" ")"); do { *((volatile int*)__null) = 2200; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2201 | assertLoopPhi(); |
2202 | return getOperand(0); |
2203 | } |
2204 | |
2205 | MDefinition* MPhi::getLoopBackedgeOperand() const { |
2206 | assertLoopPhi(); |
2207 | uint32_t idx = block()->numPredecessors() == 2 ? 1 : 0; |
2208 | return getOperand(idx); |
2209 | } |
2210 | |
2211 | void MPhi::removeOperand(size_t index) { |
2212 | 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" , 2212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index < numOperands()" ")"); do { *((volatile int*)__null) = 2212; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2213 | 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" , 2213); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->index() == index" ")"); do { *((volatile int*)__null) = 2213; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2214 | 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" , 2214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->consumer() == this" ")"); do { *((volatile int*)__null) = 2214; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2215 | |
2216 | // If we have phi(..., a, b, c, d, ..., z) and we plan |
2217 | // on removing a, then first shift downward so that we have |
2218 | // phi(..., b, c, d, ..., z, z): |
2219 | MUse* p = inputs_.begin() + index; |
2220 | MUse* e = inputs_.end(); |
2221 | p->producer()->removeUse(p); |
2222 | for (; p < e - 1; ++p) { |
2223 | MDefinition* producer = (p + 1)->producer(); |
2224 | p->setProducerUnchecked(producer); |
2225 | producer->replaceUse(p + 1, p); |
2226 | } |
2227 | |
2228 | // truncate the inputs_ list: |
2229 | inputs_.popBack(); |
2230 | } |
2231 | |
2232 | void MPhi::removeAllOperands() { |
2233 | for (MUse& p : inputs_) { |
2234 | p.producer()->removeUse(&p); |
2235 | } |
2236 | inputs_.clear(); |
2237 | } |
2238 | |
2239 | MDefinition* MPhi::foldsTernary(TempAllocator& alloc) { |
2240 | /* Look if this MPhi is a ternary construct. |
2241 | * This is a very loose term as it actually only checks for |
2242 | * |
2243 | * MTest X |
2244 | * / \ |
2245 | * ... ... |
2246 | * \ / |
2247 | * MPhi X Y |
2248 | * |
2249 | * Which we will simply call: |
2250 | * x ? x : y or x ? y : x |
2251 | */ |
2252 | |
2253 | if (numOperands() != 2) { |
2254 | return nullptr; |
2255 | } |
2256 | |
2257 | 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" , 2257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2" ")"); do { *((volatile int*)__null) = 2257; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2258 | |
2259 | MBasicBlock* pred = block()->immediateDominator(); |
2260 | if (!pred || !pred->lastIns()->isTest()) { |
2261 | return nullptr; |
2262 | } |
2263 | |
2264 | MTest* test = pred->lastIns()->toTest(); |
2265 | |
2266 | // True branch may only dominate one edge of MPhi. |
2267 | if (test->ifTrue()->dominates(block()->getPredecessor(0)) == |
2268 | test->ifTrue()->dominates(block()->getPredecessor(1))) { |
2269 | return nullptr; |
2270 | } |
2271 | |
2272 | // False branch may only dominate one edge of MPhi. |
2273 | if (test->ifFalse()->dominates(block()->getPredecessor(0)) == |
2274 | test->ifFalse()->dominates(block()->getPredecessor(1))) { |
2275 | return nullptr; |
2276 | } |
2277 | |
2278 | // True and false branch must dominate different edges of MPhi. |
2279 | if (test->ifTrue()->dominates(block()->getPredecessor(0)) == |
2280 | test->ifFalse()->dominates(block()->getPredecessor(0))) { |
2281 | return nullptr; |
2282 | } |
2283 | |
2284 | // We found a ternary construct. |
2285 | bool firstIsTrueBranch = |
2286 | test->ifTrue()->dominates(block()->getPredecessor(0)); |
2287 | MDefinition* trueDef = firstIsTrueBranch ? getOperand(0) : getOperand(1); |
2288 | MDefinition* falseDef = firstIsTrueBranch ? getOperand(1) : getOperand(0); |
2289 | |
2290 | // Accept either |
2291 | // testArg ? testArg : constant or |
2292 | // testArg ? constant : testArg |
2293 | if (!trueDef->isConstant() && !falseDef->isConstant()) { |
2294 | return nullptr; |
2295 | } |
2296 | |
2297 | MConstant* c = |
2298 | trueDef->isConstant() ? trueDef->toConstant() : falseDef->toConstant(); |
2299 | MDefinition* testArg = (trueDef == c) ? falseDef : trueDef; |
2300 | if (testArg != test->input()) { |
2301 | return nullptr; |
2302 | } |
2303 | |
2304 | // This check should be a tautology, except that the constant might be the |
2305 | // result of the removal of a branch. In such case the domination scope of |
2306 | // the block which is holding the constant might be incomplete. This |
2307 | // condition is used to prevent doing this optimization based on incomplete |
2308 | // information. |
2309 | // |
2310 | // As GVN removed a branch, it will update the dominations rules before |
2311 | // trying to fold this MPhi again. Thus, this condition does not inhibit |
2312 | // this optimization. |
2313 | MBasicBlock* truePred = block()->getPredecessor(firstIsTrueBranch ? 0 : 1); |
2314 | MBasicBlock* falsePred = block()->getPredecessor(firstIsTrueBranch ? 1 : 0); |
2315 | if (!trueDef->block()->dominates(truePred) || |
2316 | !falseDef->block()->dominates(falsePred)) { |
2317 | return nullptr; |
2318 | } |
2319 | |
2320 | // If testArg is an int32 type we can: |
2321 | // - fold testArg ? testArg : 0 to testArg |
2322 | // - fold testArg ? 0 : testArg to 0 |
2323 | if (testArg->type() == MIRType::Int32 && c->numberToDouble() == 0) { |
2324 | testArg->setGuardRangeBailoutsUnchecked(); |
2325 | |
2326 | // When folding to the constant we need to hoist it. |
2327 | if (trueDef == c && !c->block()->dominates(block())) { |
2328 | c->block()->moveBefore(pred->lastIns(), c); |
2329 | } |
2330 | return trueDef; |
2331 | } |
2332 | |
2333 | // If testArg is an double type we can: |
2334 | // - fold testArg ? testArg : 0.0 to MNaNToZero(testArg) |
2335 | if (testArg->type() == MIRType::Double && |
2336 | mozilla::IsPositiveZero(c->numberToDouble()) && c != trueDef) { |
2337 | MNaNToZero* replace = MNaNToZero::New(alloc, testArg); |
2338 | test->block()->insertBefore(test, replace); |
2339 | return replace; |
2340 | } |
2341 | |
2342 | // If testArg is a string type we can: |
2343 | // - fold testArg ? testArg : "" to testArg |
2344 | // - fold testArg ? "" : testArg to "" |
2345 | if (testArg->type() == MIRType::String && |
2346 | c->toString() == GetJitContext()->runtime->emptyString()) { |
2347 | // When folding to the constant we need to hoist it. |
2348 | if (trueDef == c && !c->block()->dominates(block())) { |
2349 | c->block()->moveBefore(pred->lastIns(), c); |
2350 | } |
2351 | return trueDef; |
2352 | } |
2353 | |
2354 | return nullptr; |
2355 | } |
2356 | |
2357 | MDefinition* MPhi::operandIfRedundant() { |
2358 | if (inputs_.length() == 0) { |
2359 | return nullptr; |
2360 | } |
2361 | |
2362 | // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)), |
2363 | // returns the operand that it will always be equal to (a, in |
2364 | // those two cases). |
2365 | MDefinition* first = getOperand(0); |
2366 | for (size_t i = 1, e = numOperands(); i < e; i++) { |
2367 | MDefinition* op = getOperand(i); |
2368 | if (op != first && op != this) { |
2369 | return nullptr; |
2370 | } |
2371 | } |
2372 | return first; |
2373 | } |
2374 | |
2375 | MDefinition* MPhi::foldsTo(TempAllocator& alloc) { |
2376 | if (MDefinition* def = operandIfRedundant()) { |
2377 | return def; |
2378 | } |
2379 | |
2380 | if (MDefinition* def = foldsTernary(alloc)) { |
2381 | return def; |
2382 | } |
2383 | |
2384 | return this; |
2385 | } |
2386 | |
2387 | bool MPhi::congruentTo(const MDefinition* ins) const { |
2388 | if (!ins->isPhi()) { |
2389 | return false; |
2390 | } |
2391 | |
2392 | // Phis in different blocks may have different control conditions. |
2393 | // For example, these phis: |
2394 | // |
2395 | // if (p) |
2396 | // goto a |
2397 | // a: |
2398 | // t = phi(x, y) |
2399 | // |
2400 | // if (q) |
2401 | // goto b |
2402 | // b: |
2403 | // s = phi(x, y) |
2404 | // |
2405 | // have identical operands, but they are not equvalent because t is |
2406 | // effectively p?x:y and s is effectively q?x:y. |
2407 | // |
2408 | // For now, consider phis in different blocks incongruent. |
2409 | if (ins->block() != block()) { |
2410 | return false; |
2411 | } |
2412 | |
2413 | return congruentIfOperandsEqual(ins); |
2414 | } |
2415 | |
2416 | void MPhi::updateForReplacement(MPhi* other) { |
2417 | // This function is called to fix the current Phi flags using it as a |
2418 | // replacement of the other Phi instruction |other|. |
2419 | // |
2420 | // When dealing with usage analysis, any Use will replace all other values, |
2421 | // such as Unused and Unknown. Unless both are Unused, the merge would be |
2422 | // Unknown. |
2423 | if (usageAnalysis_ == PhiUsage::Used || |
2424 | other->usageAnalysis_ == PhiUsage::Used) { |
2425 | usageAnalysis_ = PhiUsage::Used; |
2426 | } else if (usageAnalysis_ != other->usageAnalysis_) { |
2427 | // this == unused && other == unknown |
2428 | // or this == unknown && other == unused |
2429 | usageAnalysis_ = PhiUsage::Unknown; |
2430 | } else { |
2431 | // this == unused && other == unused |
2432 | // or this == unknown && other = unknown |
2433 | 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" , 2434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown" ")"); do { *((volatile int*)__null) = 2434; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
2434 | 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" , 2434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown" ")"); do { *((volatile int*)__null) = 2434; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2435 | 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" , 2435); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == other->usageAnalysis_" ")"); do { *((volatile int*)__null) = 2435; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2436 | } |
2437 | } |
2438 | |
2439 | /* static */ |
2440 | bool MPhi::markIteratorPhis(const PhiVector& iterators) { |
2441 | // Find and mark phis that must transitively hold an iterator live. |
2442 | |
2443 | Vector<MPhi*, 8, SystemAllocPolicy> worklist; |
2444 | |
2445 | for (MPhi* iter : iterators) { |
2446 | if (!iter->isInWorklist()) { |
2447 | if (!worklist.append(iter)) { |
2448 | return false; |
2449 | } |
2450 | iter->setInWorklist(); |
2451 | } |
2452 | } |
2453 | |
2454 | while (!worklist.empty()) { |
2455 | MPhi* phi = worklist.popCopy(); |
2456 | phi->setNotInWorklist(); |
2457 | |
2458 | phi->setIterator(); |
2459 | phi->setImplicitlyUsedUnchecked(); |
2460 | |
2461 | for (MUseDefIterator iter(phi); iter; iter++) { |
2462 | MDefinition* use = iter.def(); |
2463 | if (!use->isInWorklist() && use->isPhi() && !use->toPhi()->isIterator()) { |
2464 | if (!worklist.append(use->toPhi())) { |
2465 | return false; |
2466 | } |
2467 | use->setInWorklist(); |
2468 | } |
2469 | } |
2470 | } |
2471 | |
2472 | return true; |
2473 | } |
2474 | |
2475 | bool MPhi::typeIncludes(MDefinition* def) { |
2476 | 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" , 2476); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsMagicType(def->type())" ")"); do { *((volatile int*)__null) = 2476; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2477 | |
2478 | if (def->type() == MIRType::Int32 && this->type() == MIRType::Double) { |
2479 | return true; |
2480 | } |
2481 | |
2482 | if (def->type() == MIRType::Value) { |
2483 | // This phi must be able to be any value. |
2484 | return this->type() == MIRType::Value; |
2485 | } |
2486 | |
2487 | return this->mightBeType(def->type()); |
2488 | } |
2489 | |
2490 | void MCallBase::addArg(size_t argnum, MDefinition* arg) { |
2491 | // The operand vector is initialized in reverse order by WarpBuilder. |
2492 | // It cannot be checked for consistency until all arguments are added. |
2493 | // FixedList doesn't initialize its elements, so do an unchecked init. |
2494 | initOperand(argnum + NumNonArgumentOperands, arg); |
2495 | } |
2496 | |
2497 | static inline bool IsConstant(MDefinition* def, double v) { |
2498 | if (!def->isConstant()) { |
2499 | return false; |
2500 | } |
2501 | |
2502 | return NumbersAreIdentical(def->toConstant()->numberToDouble(), v); |
2503 | } |
2504 | |
2505 | MDefinition* MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc) { |
2506 | // Identity operations are removed (for int32 only) in foldUnnecessaryBitop. |
2507 | |
2508 | if (type() == MIRType::Int32) { |
2509 | if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) { |
2510 | return folded; |
2511 | } |
2512 | } else if (type() == MIRType::Int64) { |
2513 | if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) { |
2514 | return folded; |
2515 | } |
2516 | } |
2517 | |
2518 | return this; |
2519 | } |
2520 | |
2521 | MDefinition* MBinaryBitwiseInstruction::foldUnnecessaryBitop() { |
2522 | // It's probably OK to perform this optimization only for int32, as it will |
2523 | // have the greatest effect for asm.js code that is compiled with the JS |
2524 | // pipeline, and that code will not see int64 values. |
2525 | |
2526 | if (type() != MIRType::Int32) { |
2527 | return this; |
2528 | } |
2529 | |
2530 | // Fold unsigned shift right operator when the second operand is zero and |
2531 | // the only use is an unsigned modulo. Thus, the expression |
2532 | // |(x >>> 0) % y| becomes |x % y|. |
2533 | if (isUrsh() && IsUint32Type(this)) { |
2534 | MDefinition* defUse = maybeSingleDefUse(); |
2535 | if (defUse && defUse->isMod() && defUse->toMod()->isUnsigned()) { |
2536 | return getOperand(0); |
2537 | } |
2538 | } |
2539 | |
2540 | // Eliminate bitwise operations that are no-ops when used on integer |
2541 | // inputs, such as (x | 0). |
2542 | |
2543 | MDefinition* lhs = getOperand(0); |
2544 | MDefinition* rhs = getOperand(1); |
2545 | |
2546 | if (IsConstant(lhs, 0)) { |
2547 | return foldIfZero(0); |
2548 | } |
2549 | |
2550 | if (IsConstant(rhs, 0)) { |
2551 | return foldIfZero(1); |
2552 | } |
2553 | |
2554 | if (IsConstant(lhs, -1)) { |
2555 | return foldIfNegOne(0); |
2556 | } |
2557 | |
2558 | if (IsConstant(rhs, -1)) { |
2559 | return foldIfNegOne(1); |
2560 | } |
2561 | |
2562 | if (lhs == rhs) { |
2563 | return foldIfEqual(); |
2564 | } |
2565 | |
2566 | if (maskMatchesRightRange) { |
2567 | 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" , 2567); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->isConstant()" ")"); do { *((volatile int*)__null) = 2567; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2568 | 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" , 2568); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2568; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2569 | return foldIfAllBitsSet(0); |
2570 | } |
2571 | |
2572 | if (maskMatchesLeftRange) { |
2573 | 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" , 2573); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->isConstant()" ")"); do { *((volatile int*)__null) = 2573; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2574 | 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" , 2574); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 2574; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2575 | return foldIfAllBitsSet(1); |
2576 | } |
2577 | |
2578 | return this; |
2579 | } |
2580 | |
2581 | static inline bool CanProduceNegativeZero(MDefinition* def) { |
2582 | // Test if this instruction can produce negative zero even when bailing out |
2583 | // and changing types. |
2584 | switch (def->op()) { |
2585 | case MDefinition::Opcode::Constant: |
2586 | if (def->type() == MIRType::Double && |
2587 | def->toConstant()->toDouble() == -0.0) { |
2588 | return true; |
2589 | } |
2590 | [[fallthrough]]; |
2591 | case MDefinition::Opcode::BitAnd: |
2592 | case MDefinition::Opcode::BitOr: |
2593 | case MDefinition::Opcode::BitXor: |
2594 | case MDefinition::Opcode::BitNot: |
2595 | case MDefinition::Opcode::Lsh: |
2596 | case MDefinition::Opcode::Rsh: |
2597 | return false; |
2598 | default: |
2599 | return true; |
2600 | } |
2601 | } |
2602 | |
2603 | static inline bool NeedNegativeZeroCheck(MDefinition* def) { |
2604 | if (def->isGuard() || def->isGuardRangeBailouts()) { |
2605 | return true; |
2606 | } |
2607 | |
2608 | // Test if all uses have the same semantics for -0 and 0 |
2609 | for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) { |
2610 | if (use->consumer()->isResumePoint()) { |
2611 | return true; |
2612 | } |
2613 | |
2614 | MDefinition* use_def = use->consumer()->toDefinition(); |
2615 | switch (use_def->op()) { |
2616 | case MDefinition::Opcode::Add: { |
2617 | // If add is truncating -0 and 0 are observed as the same. |
2618 | if (use_def->toAdd()->isTruncated()) { |
2619 | break; |
2620 | } |
2621 | |
2622 | // x + y gives -0, when both x and y are -0 |
2623 | |
2624 | // Figure out the order in which the addition's operands will |
2625 | // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR |
2626 | // definitions for us so that this just requires comparing ids. |
2627 | MDefinition* first = use_def->toAdd()->lhs(); |
2628 | MDefinition* second = use_def->toAdd()->rhs(); |
2629 | if (first->id() > second->id()) { |
2630 | std::swap(first, second); |
2631 | } |
2632 | // Negative zero checks can be removed on the first executed |
2633 | // operand only if it is guaranteed the second executed operand |
2634 | // will produce a value other than -0. While the second is |
2635 | // typed as an int32, a bailout taken between execution of the |
2636 | // operands may change that type and cause a -0 to flow to the |
2637 | // second. |
2638 | // |
2639 | // There is no way to test whether there are any bailouts |
2640 | // between execution of the operands, so remove negative |
2641 | // zero checks from the first only if the second's type is |
2642 | // independent from type changes that may occur after bailing. |
2643 | if (def == first && CanProduceNegativeZero(second)) { |
2644 | return true; |
2645 | } |
2646 | |
2647 | // The negative zero check can always be removed on the second |
2648 | // executed operand; by the time this executes the first will have |
2649 | // been evaluated as int32 and the addition's result cannot be -0. |
2650 | break; |
2651 | } |
2652 | case MDefinition::Opcode::Sub: { |
2653 | // If sub is truncating -0 and 0 are observed as the same |
2654 | if (use_def->toSub()->isTruncated()) { |
2655 | break; |
2656 | } |
2657 | |
2658 | // x + y gives -0, when x is -0 and y is 0 |
2659 | |
2660 | // We can remove the negative zero check on the rhs, only if we |
2661 | // are sure the lhs isn't negative zero. |
2662 | |
2663 | // The lhs is typed as integer (i.e. not -0.0), but it can bailout |
2664 | // and change type. This should be fine if the lhs is executed |
2665 | // first. However if the rhs is executed first, the lhs can bail, |
2666 | // change type and become -0.0 while the rhs has already been |
2667 | // optimized to not make a difference between zero and negative zero. |
2668 | MDefinition* lhs = use_def->toSub()->lhs(); |
2669 | MDefinition* rhs = use_def->toSub()->rhs(); |
2670 | if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs)) { |
2671 | return true; |
2672 | } |
2673 | |
2674 | [[fallthrough]]; |
2675 | } |
2676 | case MDefinition::Opcode::StoreElement: |
2677 | case MDefinition::Opcode::StoreHoleValueElement: |
2678 | case MDefinition::Opcode::LoadElement: |
2679 | case MDefinition::Opcode::LoadElementHole: |
2680 | case MDefinition::Opcode::LoadUnboxedScalar: |
2681 | case MDefinition::Opcode::LoadDataViewElement: |
2682 | case MDefinition::Opcode::LoadTypedArrayElementHole: |
2683 | case MDefinition::Opcode::CharCodeAt: |
2684 | case MDefinition::Opcode::Mod: |
2685 | case MDefinition::Opcode::InArray: |
2686 | // Only allowed to remove check when definition is the second operand |
2687 | if (use_def->getOperand(0) == def) { |
2688 | return true; |
2689 | } |
2690 | for (size_t i = 2, e = use_def->numOperands(); i < e; i++) { |
2691 | if (use_def->getOperand(i) == def) { |
2692 | return true; |
2693 | } |
2694 | } |
2695 | break; |
2696 | case MDefinition::Opcode::BoundsCheck: |
2697 | // Only allowed to remove check when definition is the first operand |
2698 | if (use_def->toBoundsCheck()->getOperand(1) == def) { |
2699 | return true; |
2700 | } |
2701 | break; |
2702 | case MDefinition::Opcode::ToString: |
2703 | case MDefinition::Opcode::FromCharCode: |
2704 | case MDefinition::Opcode::FromCodePoint: |
2705 | case MDefinition::Opcode::TableSwitch: |
2706 | case MDefinition::Opcode::Compare: |
2707 | case MDefinition::Opcode::BitAnd: |
2708 | case MDefinition::Opcode::BitOr: |
2709 | case MDefinition::Opcode::BitXor: |
2710 | case MDefinition::Opcode::Abs: |
2711 | case MDefinition::Opcode::TruncateToInt32: |
2712 | // Always allowed to remove check. No matter which operand. |
2713 | break; |
2714 | case MDefinition::Opcode::StoreElementHole: |
2715 | case MDefinition::Opcode::StoreTypedArrayElementHole: |
2716 | case MDefinition::Opcode::PostWriteElementBarrier: |
2717 | // Only allowed to remove check when definition is the third operand. |
2718 | for (size_t i = 0, e = use_def->numOperands(); i < e; i++) { |
2719 | if (i == 2) { |
2720 | continue; |
2721 | } |
2722 | if (use_def->getOperand(i) == def) { |
2723 | return true; |
2724 | } |
2725 | } |
2726 | break; |
2727 | default: |
2728 | return true; |
2729 | } |
2730 | } |
2731 | return false; |
2732 | } |
2733 | |
2734 | #ifdef JS_JITSPEW1 |
2735 | void MBinaryArithInstruction::printOpcode(GenericPrinter& out) const { |
2736 | MDefinition::printOpcode(out); |
2737 | |
2738 | switch (type()) { |
2739 | case MIRType::Int32: |
2740 | if (isDiv()) { |
2741 | out.printf(" [%s]", toDiv()->isUnsigned() ? "uint32" : "int32"); |
2742 | } else if (isMod()) { |
2743 | out.printf(" [%s]", toMod()->isUnsigned() ? "uint32" : "int32"); |
2744 | } else { |
2745 | out.printf(" [int32]"); |
2746 | } |
2747 | break; |
2748 | case MIRType::Int64: |
2749 | if (isDiv()) { |
2750 | out.printf(" [%s]", toDiv()->isUnsigned() ? "uint64" : "int64"); |
2751 | } else if (isMod()) { |
2752 | out.printf(" [%s]", toMod()->isUnsigned() ? "uint64" : "int64"); |
2753 | } else { |
2754 | out.printf(" [int64]"); |
2755 | } |
2756 | break; |
2757 | case MIRType::Float32: |
2758 | out.printf(" [float]"); |
2759 | break; |
2760 | case MIRType::Double: |
2761 | out.printf(" [double]"); |
2762 | break; |
2763 | default: |
2764 | break; |
2765 | } |
2766 | } |
2767 | #endif |
2768 | |
2769 | MDefinition* MRsh::foldsTo(TempAllocator& alloc) { |
2770 | MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc); |
2771 | |
2772 | if (f != this) { |
2773 | return f; |
2774 | } |
2775 | |
2776 | MDefinition* lhs = getOperand(0); |
2777 | MDefinition* rhs = getOperand(1); |
2778 | |
2779 | // It's probably OK to perform this optimization only for int32, as it will |
2780 | // have the greatest effect for asm.js code that is compiled with the JS |
2781 | // pipeline, and that code will not see int64 values. |
2782 | |
2783 | if (!lhs->isLsh() || !rhs->isConstant() || rhs->type() != MIRType::Int32) { |
2784 | return this; |
2785 | } |
2786 | |
2787 | if (!lhs->getOperand(1)->isConstant() || |
2788 | lhs->getOperand(1)->type() != MIRType::Int32) { |
2789 | return this; |
2790 | } |
2791 | |
2792 | uint32_t shift = rhs->toConstant()->toInt32(); |
2793 | uint32_t shift_lhs = lhs->getOperand(1)->toConstant()->toInt32(); |
2794 | if (shift != shift_lhs) { |
2795 | return this; |
2796 | } |
2797 | |
2798 | switch (shift) { |
2799 | case 16: |
2800 | return MSignExtendInt32::New(alloc, lhs->getOperand(0), |
2801 | MSignExtendInt32::Half); |
2802 | case 24: |
2803 | return MSignExtendInt32::New(alloc, lhs->getOperand(0), |
2804 | MSignExtendInt32::Byte); |
2805 | } |
2806 | |
2807 | return this; |
2808 | } |
2809 | |
2810 | MDefinition* MBinaryArithInstruction::foldsTo(TempAllocator& alloc) { |
2811 | 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" , 2811); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())" ")"); do { *((volatile int*)__null) = 2811; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2812 | |
2813 | MDefinition* lhs = getOperand(0); |
2814 | MDefinition* rhs = getOperand(1); |
2815 | |
2816 | if (type() == MIRType::Int64) { |
2817 | 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" , 2817); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isTruncated()" ")"); do { *((volatile int*)__null) = 2817; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2818 | |
2819 | if (MConstant* folded = EvaluateInt64ConstantOperands(alloc, this)) { |
2820 | if (!folded->block()) { |
2821 | block()->insertBefore(this, folded); |
2822 | } |
2823 | return folded; |
2824 | } |
2825 | if (isSub() || isDiv() || isMod()) { |
2826 | return this; |
2827 | } |
2828 | if (rhs->isConstant() && |
2829 | rhs->toConstant()->toInt64() == int64_t(getIdentity())) { |
2830 | return lhs; |
2831 | } |
2832 | if (lhs->isConstant() && |
2833 | lhs->toConstant()->toInt64() == int64_t(getIdentity())) { |
2834 | return rhs; |
2835 | } |
2836 | return this; |
2837 | } |
2838 | |
2839 | if (MConstant* folded = EvaluateConstantOperands(alloc, this)) { |
2840 | if (isTruncated()) { |
2841 | if (!folded->block()) { |
2842 | block()->insertBefore(this, folded); |
2843 | } |
2844 | if (folded->type() != MIRType::Int32) { |
2845 | return MTruncateToInt32::New(alloc, folded); |
2846 | } |
2847 | } |
2848 | return folded; |
2849 | } |
2850 | |
2851 | if (mustPreserveNaN_) { |
2852 | return this; |
2853 | } |
2854 | |
2855 | // 0 + -0 = 0. So we can't remove addition |
2856 | if (isAdd() && type() != MIRType::Int32) { |
2857 | return this; |
2858 | } |
2859 | |
2860 | if (IsConstant(rhs, getIdentity())) { |
2861 | if (isTruncated()) { |
2862 | return MTruncateToInt32::New(alloc, lhs); |
2863 | } |
2864 | return lhs; |
2865 | } |
2866 | |
2867 | // subtraction isn't commutative. So we can't remove subtraction when lhs |
2868 | // equals 0 |
2869 | if (isSub()) { |
2870 | return this; |
2871 | } |
2872 | |
2873 | if (IsConstant(lhs, getIdentity())) { |
2874 | if (isTruncated()) { |
2875 | return MTruncateToInt32::New(alloc, rhs); |
2876 | } |
2877 | return rhs; // id op x => x |
2878 | } |
2879 | |
2880 | return this; |
2881 | } |
2882 | |
2883 | void MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc) { |
2884 | 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" , 2884); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())" ")"); do { *((volatile int*)__null) = 2884; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2885 | |
2886 | // Do not use Float32 if we can use int32. |
2887 | if (type() == MIRType::Int32) { |
2888 | return; |
2889 | } |
2890 | |
2891 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
2892 | setResultType(MIRType::Float32); |
2893 | } |
2894 | } |
2895 | |
2896 | void MMinMax::trySpecializeFloat32(TempAllocator& alloc) { |
2897 | if (type() == MIRType::Int32) { |
2898 | return; |
2899 | } |
2900 | |
2901 | MDefinition* left = lhs(); |
2902 | MDefinition* right = rhs(); |
2903 | |
2904 | if ((left->canProduceFloat32() || |
2905 | (left->isMinMax() && left->type() == MIRType::Float32)) && |
2906 | (right->canProduceFloat32() || |
2907 | (right->isMinMax() && right->type() == MIRType::Float32))) { |
2908 | setResultType(MIRType::Float32); |
2909 | } else { |
2910 | ConvertOperandsToDouble(this, alloc); |
2911 | } |
2912 | } |
2913 | |
2914 | MDefinition* MMinMax::foldsTo(TempAllocator& alloc) { |
2915 | 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" , 2915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == type()" ")"); do { *((volatile int*)__null) = 2915; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2916 | 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" , 2916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == type()" ")"); do { *((volatile int*)__null) = 2916; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2917 | |
2918 | if (lhs() == rhs()) { |
2919 | return lhs(); |
2920 | } |
2921 | |
2922 | auto foldConstants = [&alloc](MDefinition* lhs, MDefinition* rhs, |
2923 | bool isMax) -> MConstant* { |
2924 | 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" , 2924); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == rhs->type()" ")"); do { *((volatile int*)__null) = 2924; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2925 | 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" , 2925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->toConstant()->isTypeRepresentableAsDouble()" ")"); do { *((volatile int*)__null) = 2925; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2926 | 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" , 2926); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->toConstant()->isTypeRepresentableAsDouble()" ")"); do { *((volatile int*)__null) = 2926; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2927 | |
2928 | double lnum = lhs->toConstant()->numberToDouble(); |
2929 | double rnum = rhs->toConstant()->numberToDouble(); |
2930 | |
2931 | double result; |
2932 | if (isMax) { |
2933 | result = js::math_max_impl(lnum, rnum); |
2934 | } else { |
2935 | result = js::math_min_impl(lnum, rnum); |
2936 | } |
2937 | |
2938 | // The folded MConstant should maintain the same MIRType with the original |
2939 | // inputs. |
2940 | if (lhs->type() == MIRType::Int32) { |
2941 | int32_t cast; |
2942 | if (mozilla::NumberEqualsInt32(result, &cast)) { |
2943 | return MConstant::New(alloc, Int32Value(cast)); |
2944 | } |
2945 | return nullptr; |
2946 | } |
2947 | if (lhs->type() == MIRType::Float32) { |
2948 | return MConstant::NewFloat32(alloc, result); |
2949 | } |
2950 | 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" , 2950); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 2950; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2951 | return MConstant::New(alloc, DoubleValue(result)); |
2952 | }; |
2953 | |
2954 | // Try to fold the following patterns when |x| and |y| are constants. |
2955 | // |
2956 | // min(min(x, z), min(y, z)) = min(min(x, y), z) |
2957 | // max(max(x, z), max(y, z)) = max(max(x, y), z) |
2958 | // max(min(x, z), min(y, z)) = min(max(x, y), z) |
2959 | // min(max(x, z), max(y, z)) = max(min(x, y), z) |
2960 | if (lhs()->isMinMax() && rhs()->isMinMax()) { |
2961 | do { |
2962 | auto* left = lhs()->toMinMax(); |
2963 | auto* right = rhs()->toMinMax(); |
2964 | if (left->isMax() != right->isMax()) { |
2965 | break; |
2966 | } |
2967 | |
2968 | MDefinition* x; |
2969 | MDefinition* y; |
2970 | MDefinition* z; |
2971 | if (left->lhs() == right->lhs()) { |
2972 | std::tie(x, y, z) = std::tuple{left->rhs(), right->rhs(), left->lhs()}; |
2973 | } else if (left->lhs() == right->rhs()) { |
2974 | std::tie(x, y, z) = std::tuple{left->rhs(), right->lhs(), left->lhs()}; |
2975 | } else if (left->rhs() == right->lhs()) { |
2976 | std::tie(x, y, z) = std::tuple{left->lhs(), right->rhs(), left->rhs()}; |
2977 | } else if (left->rhs() == right->rhs()) { |
2978 | std::tie(x, y, z) = std::tuple{left->lhs(), right->lhs(), left->rhs()}; |
2979 | } else { |
2980 | break; |
2981 | } |
2982 | |
2983 | if (!x->isConstant() || !x->toConstant()->isTypeRepresentableAsDouble() || |
2984 | !y->isConstant() || !y->toConstant()->isTypeRepresentableAsDouble()) { |
2985 | break; |
2986 | } |
2987 | |
2988 | if (auto* folded = foldConstants(x, y, isMax())) { |
2989 | block()->insertBefore(this, folded); |
2990 | return MMinMax::New(alloc, folded, z, type(), left->isMax()); |
2991 | } |
2992 | } while (false); |
2993 | } |
2994 | |
2995 | // Fold min/max operations with same inputs. |
2996 | if (lhs()->isMinMax() || rhs()->isMinMax()) { |
2997 | auto* other = lhs()->isMinMax() ? lhs()->toMinMax() : rhs()->toMinMax(); |
2998 | auto* operand = lhs()->isMinMax() ? rhs() : lhs(); |
2999 | |
3000 | if (operand == other->lhs() || operand == other->rhs()) { |
3001 | if (isMax() == other->isMax()) { |
3002 | // min(x, min(x, y)) = min(x, y) |
3003 | // max(x, max(x, y)) = max(x, y) |
3004 | return other; |
3005 | } |
3006 | if (!IsFloatingPointType(type())) { |
3007 | // When neither value is NaN: |
3008 | // max(x, min(x, y)) = x |
3009 | // min(x, max(x, y)) = x |
3010 | |
3011 | // Ensure that any bailouts that we depend on to guarantee that |y| is |
3012 | // Int32 are not removed. |
3013 | auto* otherOp = operand == other->lhs() ? other->rhs() : other->lhs(); |
3014 | otherOp->setGuardRangeBailoutsUnchecked(); |
3015 | |
3016 | return operand; |
3017 | } |
3018 | } |
3019 | } |
3020 | |
3021 | if (!lhs()->isConstant() && !rhs()->isConstant()) { |
3022 | return this; |
3023 | } |
3024 | |
3025 | // Directly apply math utility to compare the rhs() and lhs() when |
3026 | // they are both constants. |
3027 | if (lhs()->isConstant() && rhs()->isConstant()) { |
3028 | if (!lhs()->toConstant()->isTypeRepresentableAsDouble() || |
3029 | !rhs()->toConstant()->isTypeRepresentableAsDouble()) { |
3030 | return this; |
3031 | } |
3032 | |
3033 | if (auto* folded = foldConstants(lhs(), rhs(), isMax())) { |
3034 | return folded; |
3035 | } |
3036 | } |
3037 | |
3038 | MDefinition* operand = lhs()->isConstant() ? rhs() : lhs(); |
3039 | MConstant* constant = |
3040 | lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant(); |
3041 | |
3042 | if (operand->isToDouble() && |
3043 | operand->getOperand(0)->type() == MIRType::Int32) { |
3044 | // min(int32, cte >= INT32_MAX) = int32 |
3045 | if (!isMax() && constant->isTypeRepresentableAsDouble() && |
3046 | constant->numberToDouble() >= INT32_MAX(2147483647)) { |
3047 | MLimitedTruncate* limit = MLimitedTruncate::New( |
3048 | alloc, operand->getOperand(0), TruncateKind::NoTruncate); |
3049 | block()->insertBefore(this, limit); |
3050 | MToDouble* toDouble = MToDouble::New(alloc, limit); |
3051 | return toDouble; |
3052 | } |
3053 | |
3054 | // max(int32, cte <= INT32_MIN) = int32 |
3055 | if (isMax() && constant->isTypeRepresentableAsDouble() && |
3056 | constant->numberToDouble() <= INT32_MIN(-2147483647-1)) { |
3057 | MLimitedTruncate* limit = MLimitedTruncate::New( |
3058 | alloc, operand->getOperand(0), TruncateKind::NoTruncate); |
3059 | block()->insertBefore(this, limit); |
3060 | MToDouble* toDouble = MToDouble::New(alloc, limit); |
3061 | return toDouble; |
3062 | } |
3063 | } |
3064 | |
3065 | auto foldLength = [](MDefinition* operand, MConstant* constant, |
3066 | bool isMax) -> MDefinition* { |
3067 | if ((operand->isArrayLength() || operand->isArrayBufferViewLength() || |
3068 | operand->isArgumentsLength() || operand->isStringLength()) && |
3069 | constant->type() == MIRType::Int32) { |
3070 | // (Array|ArrayBufferView|Arguments|String)Length is always >= 0. |
3071 | // max(array.length, cte <= 0) = array.length |
3072 | // min(array.length, cte <= 0) = cte |
3073 | if (constant->toInt32() <= 0) { |
3074 | return isMax ? operand : constant; |
3075 | } |
3076 | } |
3077 | return nullptr; |
3078 | }; |
3079 | |
3080 | if (auto* folded = foldLength(operand, constant, isMax())) { |
3081 | return folded; |
3082 | } |
3083 | |
3084 | // Attempt to fold nested min/max operations which are produced by |
3085 | // self-hosted built-in functions. |
3086 | if (operand->isMinMax()) { |
3087 | auto* other = operand->toMinMax(); |
3088 | 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" , 3088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->lhs()->type() == type()" ")"); do { *((volatile int*)__null) = 3088; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3089 | 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" , 3089); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->rhs()->type() == type()" ")"); do { *((volatile int*)__null) = 3089; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3090 | |
3091 | MConstant* otherConstant = nullptr; |
3092 | MDefinition* otherOperand = nullptr; |
3093 | if (other->lhs()->isConstant()) { |
3094 | otherConstant = other->lhs()->toConstant(); |
3095 | otherOperand = other->rhs(); |
3096 | } else if (other->rhs()->isConstant()) { |
3097 | otherConstant = other->rhs()->toConstant(); |
3098 | otherOperand = other->lhs(); |
3099 | } |
3100 | |
3101 | if (otherConstant && constant->isTypeRepresentableAsDouble() && |
3102 | otherConstant->isTypeRepresentableAsDouble()) { |
3103 | if (isMax() == other->isMax()) { |
3104 | // Fold min(x, min(y, z)) to min(min(x, y), z) with constant min(x, y). |
3105 | // Fold max(x, max(y, z)) to max(max(x, y), z) with constant max(x, y). |
3106 | if (auto* left = foldConstants(constant, otherConstant, isMax())) { |
3107 | block()->insertBefore(this, left); |
3108 | return MMinMax::New(alloc, left, otherOperand, type(), isMax()); |
3109 | } |
3110 | } else { |
3111 | // Fold min(x, max(y, z)) to max(min(x, y), min(x, z)). |
3112 | // Fold max(x, min(y, z)) to min(max(x, y), max(x, z)). |
3113 | // |
3114 | // But only do this when min(x, z) can also be simplified. |
3115 | if (auto* right = foldLength(otherOperand, constant, isMax())) { |
3116 | if (auto* left = foldConstants(constant, otherConstant, isMax())) { |
3117 | block()->insertBefore(this, left); |
3118 | return MMinMax::New(alloc, left, right, type(), !isMax()); |
3119 | } |
3120 | } |
3121 | } |
3122 | } |
3123 | } |
3124 | |
3125 | return this; |
3126 | } |
3127 | |
3128 | #ifdef JS_JITSPEW1 |
3129 | void MMinMax::printOpcode(GenericPrinter& out) const { |
3130 | MDefinition::printOpcode(out); |
3131 | out.printf(" (%s)", isMax() ? "max" : "min"); |
3132 | } |
3133 | |
3134 | void MMinMaxArray::printOpcode(GenericPrinter& out) const { |
3135 | MDefinition::printOpcode(out); |
3136 | out.printf(" (%s)", isMax() ? "max" : "min"); |
3137 | } |
3138 | #endif |
3139 | |
3140 | MDefinition* MPow::foldsConstant(TempAllocator& alloc) { |
3141 | // Both `x` and `p` in `x^p` must be constants in order to precompute. |
3142 | if (!input()->isConstant() || !power()->isConstant()) { |
3143 | return nullptr; |
3144 | } |
3145 | if (!power()->toConstant()->isTypeRepresentableAsDouble()) { |
3146 | return nullptr; |
3147 | } |
3148 | if (!input()->toConstant()->isTypeRepresentableAsDouble()) { |
3149 | return nullptr; |
3150 | } |
3151 | |
3152 | double x = input()->toConstant()->numberToDouble(); |
3153 | double p = power()->toConstant()->numberToDouble(); |
3154 | double result = js::ecmaPow(x, p); |
3155 | if (type() == MIRType::Int32) { |
3156 | int32_t cast; |
3157 | if (!mozilla::NumberIsInt32(result, &cast)) { |
3158 | // Reject folding if the result isn't an int32, because we'll bail anyway. |
3159 | return nullptr; |
3160 | } |
3161 | return MConstant::New(alloc, Int32Value(cast)); |
3162 | } |
3163 | return MConstant::New(alloc, DoubleValue(result)); |
3164 | } |
3165 | |
3166 | MDefinition* MPow::foldsConstantPower(TempAllocator& alloc) { |
3167 | // If `p` in `x^p` isn't constant, we can't apply these folds. |
3168 | if (!power()->isConstant()) { |
3169 | return nullptr; |
3170 | } |
3171 | if (!power()->toConstant()->isTypeRepresentableAsDouble()) { |
3172 | return nullptr; |
3173 | } |
3174 | |
3175 | 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" , 3175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double || type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3175; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3176 | |
3177 | // NOTE: The optimizations must match the optimizations used in |js::ecmaPow| |
3178 | // resp. |js::powi| to avoid differential testing issues. |
3179 | |
3180 | double pow = power()->toConstant()->numberToDouble(); |
3181 | |
3182 | // Math.pow(x, 0.5) is a sqrt with edge-case detection. |
3183 | if (pow == 0.5) { |
3184 | 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" , 3184); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 3184; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3185 | return MPowHalf::New(alloc, input()); |
3186 | } |
3187 | |
3188 | // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases. |
3189 | if (pow == -0.5) { |
3190 | 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" , 3190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 3190; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3191 | MPowHalf* half = MPowHalf::New(alloc, input()); |
3192 | block()->insertBefore(this, half); |
3193 | MConstant* one = MConstant::New(alloc, DoubleValue(1.0)); |
3194 | block()->insertBefore(this, one); |
3195 | return MDiv::New(alloc, one, half, MIRType::Double); |
3196 | } |
3197 | |
3198 | // Math.pow(x, 1) == x. |
3199 | if (pow == 1.0) { |
3200 | return input(); |
3201 | } |
3202 | |
3203 | auto multiply = [this, &alloc](MDefinition* lhs, MDefinition* rhs) { |
3204 | MMul* mul = MMul::New(alloc, lhs, rhs, type()); |
3205 | mul->setBailoutKind(bailoutKind()); |
3206 | |
3207 | // Multiplying the same number can't yield negative zero. |
3208 | mul->setCanBeNegativeZero(lhs != rhs && canBeNegativeZero()); |
3209 | return mul; |
3210 | }; |
3211 | |
3212 | // Math.pow(x, 2) == x*x. |
3213 | if (pow == 2.0) { |
3214 | return multiply(input(), input()); |
3215 | } |
3216 | |
3217 | // Math.pow(x, 3) == x*x*x. |
3218 | if (pow == 3.0) { |
3219 | MMul* mul1 = multiply(input(), input()); |
3220 | block()->insertBefore(this, mul1); |
3221 | return multiply(input(), mul1); |
3222 | } |
3223 | |
3224 | // Math.pow(x, 4) == y*y, where y = x*x. |
3225 | if (pow == 4.0) { |
3226 | MMul* y = multiply(input(), input()); |
3227 | block()->insertBefore(this, y); |
3228 | return multiply(y, y); |
3229 | } |
3230 | |
3231 | // No optimization |
3232 | return nullptr; |
3233 | } |
3234 | |
3235 | MDefinition* MPow::foldsTo(TempAllocator& alloc) { |
3236 | if (MDefinition* def = foldsConstant(alloc)) { |
3237 | return def; |
3238 | } |
3239 | if (MDefinition* def = foldsConstantPower(alloc)) { |
3240 | return def; |
3241 | } |
3242 | return this; |
3243 | } |
3244 | |
3245 | MDefinition* MInt32ToIntPtr::foldsTo(TempAllocator& alloc) { |
3246 | MDefinition* def = input(); |
3247 | if (def->isConstant()) { |
3248 | int32_t i = def->toConstant()->toInt32(); |
3249 | return MConstant::NewIntPtr(alloc, intptr_t(i)); |
3250 | } |
3251 | |
3252 | if (def->isNonNegativeIntPtrToInt32()) { |
3253 | return def->toNonNegativeIntPtrToInt32()->input(); |
3254 | } |
3255 | |
3256 | return this; |
3257 | } |
3258 | |
3259 | bool MAbs::fallible() const { |
3260 | return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds()); |
3261 | } |
3262 | |
3263 | void MAbs::trySpecializeFloat32(TempAllocator& alloc) { |
3264 | // Do not use Float32 if we can use int32. |
3265 | if (input()->type() == MIRType::Int32) { |
3266 | return; |
3267 | } |
3268 | |
3269 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
3270 | setResultType(MIRType::Float32); |
3271 | } |
3272 | } |
3273 | |
3274 | MDefinition* MDiv::foldsTo(TempAllocator& alloc) { |
3275 | 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" , 3275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())" ")"); do { *((volatile int*)__null) = 3275; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3276 | |
3277 | if (type() == MIRType::Int64) { |
3278 | if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) { |
3279 | return folded; |
3280 | } |
3281 | return this; |
3282 | } |
3283 | |
3284 | if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) { |
3285 | return folded; |
3286 | } |
3287 | |
3288 | if (MDefinition* folded = EvaluateExactReciprocal(alloc, this)) { |
3289 | return folded; |
3290 | } |
3291 | |
3292 | return this; |
3293 | } |
3294 | |
3295 | void MDiv::analyzeEdgeCasesForward() { |
3296 | // This is only meaningful when doing integer division. |
3297 | if (type() != MIRType::Int32) { |
3298 | return; |
3299 | } |
3300 | |
3301 | 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" , 3301); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3301; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3302 | 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" , 3302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3302; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3303 | |
3304 | // Try removing divide by zero check |
3305 | if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) { |
3306 | canBeDivideByZero_ = false; |
3307 | } |
3308 | |
3309 | // If lhs is a constant int != INT32_MIN, then |
3310 | // negative overflow check can be skipped. |
3311 | if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(INT32_MIN(-2147483647-1))) { |
3312 | canBeNegativeOverflow_ = false; |
3313 | } |
3314 | |
3315 | // If rhs is a constant int != -1, likewise. |
3316 | if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(-1)) { |
3317 | canBeNegativeOverflow_ = false; |
3318 | } |
3319 | |
3320 | // If lhs is != 0, then negative zero check can be skipped. |
3321 | if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(0)) { |
3322 | setCanBeNegativeZero(false); |
3323 | } |
3324 | |
3325 | // If rhs is >= 0, likewise. |
3326 | if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) { |
3327 | if (rhs()->toConstant()->toInt32() >= 0) { |
3328 | setCanBeNegativeZero(false); |
3329 | } |
3330 | } |
3331 | } |
3332 | |
3333 | void MDiv::analyzeEdgeCasesBackward() { |
3334 | if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) { |
3335 | setCanBeNegativeZero(false); |
3336 | } |
3337 | } |
3338 | |
3339 | bool MDiv::fallible() const { return !isTruncated(); } |
3340 | |
3341 | MDefinition* MMod::foldsTo(TempAllocator& alloc) { |
3342 | 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" , 3342); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())" ")"); do { *((volatile int*)__null) = 3342; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3343 | |
3344 | if (type() == MIRType::Int64) { |
3345 | if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) { |
3346 | return folded; |
3347 | } |
3348 | } else { |
3349 | if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) { |
3350 | return folded; |
3351 | } |
3352 | } |
3353 | return this; |
3354 | } |
3355 | |
3356 | void MMod::analyzeEdgeCasesForward() { |
3357 | // These optimizations make sense only for integer division |
3358 | if (type() != MIRType::Int32) { |
3359 | return; |
3360 | } |
3361 | |
3362 | if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) { |
3363 | canBeDivideByZero_ = false; |
3364 | } |
3365 | |
3366 | if (rhs()->isConstant()) { |
3367 | int32_t n = rhs()->toConstant()->toInt32(); |
3368 | if (n > 0 && !IsPowerOfTwo(uint32_t(n))) { |
3369 | canBePowerOfTwoDivisor_ = false; |
3370 | } |
3371 | } |
3372 | } |
3373 | |
3374 | bool MMod::fallible() const { |
3375 | return !isTruncated() && |
3376 | (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend()); |
3377 | } |
3378 | |
3379 | void MMathFunction::trySpecializeFloat32(TempAllocator& alloc) { |
3380 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
3381 | setResultType(MIRType::Float32); |
3382 | specialization_ = MIRType::Float32; |
3383 | } |
3384 | } |
3385 | |
3386 | bool MMathFunction::isFloat32Commutative() const { |
3387 | switch (function_) { |
3388 | case UnaryMathFunction::Floor: |
3389 | case UnaryMathFunction::Ceil: |
3390 | case UnaryMathFunction::Round: |
3391 | case UnaryMathFunction::Trunc: |
3392 | return true; |
3393 | default: |
3394 | return false; |
3395 | } |
3396 | } |
3397 | |
3398 | MHypot* MHypot::New(TempAllocator& alloc, const MDefinitionVector& vector) { |
3399 | uint32_t length = vector.length(); |
3400 | MHypot* hypot = new (alloc) MHypot; |
3401 | if (!hypot->init(alloc, length)) { |
3402 | return nullptr; |
3403 | } |
3404 | |
3405 | for (uint32_t i = 0; i < length; ++i) { |
3406 | hypot->initOperand(i, vector[i]); |
3407 | } |
3408 | return hypot; |
3409 | } |
3410 | |
3411 | bool MAdd::fallible() const { |
3412 | // the add is fallible if range analysis does not say that it is finite, AND |
3413 | // either the truncation analysis shows that there are non-truncated uses. |
3414 | if (truncateKind() >= TruncateKind::IndirectTruncate) { |
3415 | return false; |
3416 | } |
3417 | if (range() && range()->hasInt32Bounds()) { |
3418 | return false; |
3419 | } |
3420 | return true; |
3421 | } |
3422 | |
3423 | bool MSub::fallible() const { |
3424 | // see comment in MAdd::fallible() |
3425 | if (truncateKind() >= TruncateKind::IndirectTruncate) { |
3426 | return false; |
3427 | } |
3428 | if (range() && range()->hasInt32Bounds()) { |
3429 | return false; |
3430 | } |
3431 | return true; |
3432 | } |
3433 | |
3434 | MDefinition* MSub::foldsTo(TempAllocator& alloc) { |
3435 | MDefinition* out = MBinaryArithInstruction::foldsTo(alloc); |
3436 | if (out != this) { |
3437 | return out; |
3438 | } |
3439 | |
3440 | if (type() != MIRType::Int32) { |
3441 | return this; |
3442 | } |
3443 | |
3444 | // Optimize X - X to 0. This optimization is only valid for Int32 |
3445 | // values. Subtracting a floating point value from itself returns |
3446 | // NaN when the operand is either Infinity or NaN. |
3447 | if (lhs() == rhs()) { |
3448 | // Ensure that any bailouts that we depend on to guarantee that X |
3449 | // is Int32 are not removed. |
3450 | lhs()->setGuardRangeBailoutsUnchecked(); |
3451 | return MConstant::New(alloc, Int32Value(0)); |
3452 | } |
3453 | |
3454 | return this; |
3455 | } |
3456 | |
3457 | MDefinition* MMul::foldsTo(TempAllocator& alloc) { |
3458 | MDefinition* out = MBinaryArithInstruction::foldsTo(alloc); |
3459 | if (out != this) { |
3460 | return out; |
3461 | } |
3462 | |
3463 | if (type() != MIRType::Int32) { |
3464 | return this; |
3465 | } |
3466 | |
3467 | if (lhs() == rhs()) { |
3468 | setCanBeNegativeZero(false); |
3469 | } |
3470 | |
3471 | return this; |
3472 | } |
3473 | |
3474 | void MMul::analyzeEdgeCasesForward() { |
3475 | // Try to remove the check for negative zero |
3476 | // This only makes sense when using the integer multiplication |
3477 | if (type() != MIRType::Int32) { |
3478 | return; |
3479 | } |
3480 | |
3481 | // If lhs is > 0, no need for negative zero check. |
3482 | if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) { |
3483 | if (lhs()->toConstant()->toInt32() > 0) { |
3484 | setCanBeNegativeZero(false); |
3485 | } |
3486 | } |
3487 | |
3488 | // If rhs is > 0, likewise. |
3489 | if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) { |
3490 | if (rhs()->toConstant()->toInt32() > 0) { |
3491 | setCanBeNegativeZero(false); |
3492 | } |
3493 | } |
3494 | } |
3495 | |
3496 | void MMul::analyzeEdgeCasesBackward() { |
3497 | if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) { |
3498 | setCanBeNegativeZero(false); |
3499 | } |
3500 | } |
3501 | |
3502 | bool MMul::canOverflow() const { |
3503 | if (isTruncated()) { |
3504 | return false; |
3505 | } |
3506 | return !range() || !range()->hasInt32Bounds(); |
3507 | } |
3508 | |
3509 | bool MUrsh::fallible() const { |
3510 | if (bailoutsDisabled()) { |
3511 | return false; |
3512 | } |
3513 | return !range() || !range()->hasInt32Bounds(); |
3514 | } |
3515 | |
3516 | MIRType MCompare::inputType() { |
3517 | switch (compareType_) { |
3518 | case Compare_Undefined: |
3519 | return MIRType::Undefined; |
3520 | case Compare_Null: |
3521 | return MIRType::Null; |
3522 | case Compare_UInt32: |
3523 | case Compare_Int32: |
3524 | return MIRType::Int32; |
3525 | case Compare_UIntPtr: |
3526 | return MIRType::IntPtr; |
3527 | case Compare_Double: |
3528 | return MIRType::Double; |
3529 | case Compare_Float32: |
3530 | return MIRType::Float32; |
3531 | case Compare_String: |
3532 | return MIRType::String; |
3533 | case Compare_Symbol: |
3534 | return MIRType::Symbol; |
3535 | case Compare_Object: |
3536 | return MIRType::Object; |
3537 | case Compare_BigInt: |
3538 | case Compare_BigInt_Int32: |
3539 | case Compare_BigInt_Double: |
3540 | case Compare_BigInt_String: |
3541 | return MIRType::BigInt; |
3542 | default: |
3543 | 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" , 3543); AnnotateMozCrashReason("MOZ_CRASH(" "No known conversion" ")"); do { *((volatile int*)__null) = 3543; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
3544 | } |
3545 | } |
3546 | |
3547 | static inline bool MustBeUInt32(MDefinition* def, MDefinition** pwrapped) { |
3548 | if (def->isUrsh()) { |
3549 | *pwrapped = def->toUrsh()->lhs(); |
3550 | MDefinition* rhs = def->toUrsh()->rhs(); |
3551 | return def->toUrsh()->bailoutsDisabled() && rhs->maybeConstantValue() && |
3552 | rhs->maybeConstantValue()->isInt32(0); |
3553 | } |
3554 | |
3555 | if (MConstant* defConst = def->maybeConstantValue()) { |
3556 | *pwrapped = defConst; |
3557 | return defConst->type() == MIRType::Int32 && defConst->toInt32() >= 0; |
3558 | } |
3559 | |
3560 | *pwrapped = nullptr; // silence GCC warning |
3561 | return false; |
3562 | } |
3563 | |
3564 | /* static */ |
3565 | bool MBinaryInstruction::unsignedOperands(MDefinition* left, |
3566 | MDefinition* right) { |
3567 | MDefinition* replace; |
3568 | if (!MustBeUInt32(left, &replace)) { |
3569 | return false; |
3570 | } |
3571 | if (replace->type() != MIRType::Int32) { |
3572 | return false; |
3573 | } |
3574 | if (!MustBeUInt32(right, &replace)) { |
3575 | return false; |
3576 | } |
3577 | if (replace->type() != MIRType::Int32) { |
3578 | return false; |
3579 | } |
3580 | return true; |
3581 | } |
3582 | |
3583 | bool MBinaryInstruction::unsignedOperands() { |
3584 | return unsignedOperands(getOperand(0), getOperand(1)); |
3585 | } |
3586 | |
3587 | void MBinaryInstruction::replaceWithUnsignedOperands() { |
3588 | 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" , 3588); AnnotateMozCrashReason("MOZ_ASSERT" "(" "unsignedOperands()" ")"); do { *((volatile int*)__null) = 3588; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3589 | |
3590 | for (size_t i = 0; i < numOperands(); i++) { |
3591 | MDefinition* replace; |
3592 | MustBeUInt32(getOperand(i), &replace); |
3593 | if (replace == getOperand(i)) { |
3594 | continue; |
3595 | } |
3596 | |
3597 | getOperand(i)->setImplicitlyUsedUnchecked(); |
3598 | replaceOperand(i, replace); |
3599 | } |
3600 | } |
3601 | |
3602 | MDefinition* MBitNot::foldsTo(TempAllocator& alloc) { |
3603 | if (type() == MIRType::Int64) { |
3604 | return this; |
3605 | } |
3606 | 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" , 3606); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3606; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3607 | |
3608 | MDefinition* input = getOperand(0); |
3609 | |
3610 | if (input->isConstant()) { |
3611 | js::Value v = Int32Value(~(input->toConstant()->toInt32())); |
3612 | return MConstant::New(alloc, v); |
3613 | } |
3614 | |
3615 | if (input->isBitNot()) { |
3616 | 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" , 3616); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3616; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3617 | 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" , 3617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->getOperand(0)->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3617; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3618 | return MTruncateToInt32::New(alloc, |
3619 | input->toBitNot()->input()); // ~~x => x | 0 |
3620 | } |
3621 | |
3622 | return this; |
3623 | } |
3624 | |
3625 | static void AssertKnownClass(TempAllocator& alloc, MInstruction* ins, |
3626 | MDefinition* obj) { |
3627 | #ifdef DEBUG1 |
3628 | const JSClass* clasp = GetObjectKnownJSClass(obj); |
3629 | 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" , 3629); AnnotateMozCrashReason("MOZ_ASSERT" "(" "clasp" ")") ; do { *((volatile int*)__null) = 3629; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3630 | |
3631 | auto* assert = MAssertClass::New(alloc, obj, clasp); |
3632 | ins->block()->insertBefore(ins, assert); |
3633 | #endif |
3634 | } |
3635 | |
3636 | MDefinition* MBoxNonStrictThis::foldsTo(TempAllocator& alloc) { |
3637 | MDefinition* in = input(); |
3638 | if (in->isBox()) { |
3639 | in = in->toBox()->input(); |
3640 | } |
3641 | |
3642 | if (in->type() == MIRType::Object) { |
3643 | return in; |
3644 | } |
3645 | |
3646 | return this; |
3647 | } |
3648 | |
3649 | AliasSet MLoadArgumentsObjectArg::getAliasSet() const { |
3650 | return AliasSet::Load(AliasSet::Any); |
3651 | } |
3652 | |
3653 | AliasSet MLoadArgumentsObjectArgHole::getAliasSet() const { |
3654 | return AliasSet::Load(AliasSet::Any); |
3655 | } |
3656 | |
3657 | AliasSet MInArgumentsObjectArg::getAliasSet() const { |
3658 | // Loads |arguments.length|, but not the actual element, so we can use the |
3659 | // same alias-set as MArgumentsObjectLength. |
3660 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
3661 | AliasSet::DynamicSlot); |
3662 | } |
3663 | |
3664 | AliasSet MArgumentsObjectLength::getAliasSet() const { |
3665 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
3666 | AliasSet::DynamicSlot); |
3667 | } |
3668 | |
3669 | bool MGuardArgumentsObjectFlags::congruentTo(const MDefinition* ins) const { |
3670 | if (!ins->isGuardArgumentsObjectFlags() || |
3671 | ins->toGuardArgumentsObjectFlags()->flags() != flags()) { |
3672 | return false; |
3673 | } |
3674 | return congruentIfOperandsEqual(ins); |
3675 | } |
3676 | |
3677 | AliasSet MGuardArgumentsObjectFlags::getAliasSet() const { |
3678 | // The flags are packed with the length in a fixed private slot. |
3679 | return AliasSet::Load(AliasSet::FixedSlot); |
3680 | } |
3681 | |
3682 | MDefinition* MIdToStringOrSymbol::foldsTo(TempAllocator& alloc) { |
3683 | if (idVal()->isBox()) { |
3684 | auto* input = idVal()->toBox()->input(); |
3685 | MIRType idType = input->type(); |
3686 | if (idType == MIRType::String || idType == MIRType::Symbol) { |
3687 | return idVal(); |
3688 | } |
3689 | if (idType == MIRType::Int32) { |
3690 | auto* toString = |
3691 | MToString::New(alloc, input, MToString::SideEffectHandling::Bailout); |
3692 | block()->insertBefore(this, toString); |
3693 | |
3694 | return MBox::New(alloc, toString); |
3695 | } |
3696 | } |
3697 | |
3698 | return this; |
3699 | } |
3700 | |
3701 | MDefinition* MReturnFromCtor::foldsTo(TempAllocator& alloc) { |
3702 | MDefinition* rval = value(); |
3703 | if (rval->isBox()) { |
3704 | rval = rval->toBox()->input(); |
3705 | } |
3706 | |
3707 | if (rval->type() == MIRType::Object) { |
3708 | return rval; |
3709 | } |
3710 | |
3711 | if (rval->type() != MIRType::Value) { |
3712 | return object(); |
3713 | } |
3714 | |
3715 | return this; |
3716 | } |
3717 | |
3718 | MDefinition* MTypeOf::foldsTo(TempAllocator& alloc) { |
3719 | MDefinition* unboxed = input(); |
3720 | if (unboxed->isBox()) { |
3721 | unboxed = unboxed->toBox()->input(); |
3722 | } |
3723 | |
3724 | JSType type; |
3725 | switch (unboxed->type()) { |
3726 | case MIRType::Double: |
3727 | case MIRType::Float32: |
3728 | case MIRType::Int32: |
3729 | type = JSTYPE_NUMBER; |
3730 | break; |
3731 | case MIRType::String: |
3732 | type = JSTYPE_STRING; |
3733 | break; |
3734 | case MIRType::Symbol: |
3735 | type = JSTYPE_SYMBOL; |
3736 | break; |
3737 | case MIRType::BigInt: |
3738 | type = JSTYPE_BIGINT; |
3739 | break; |
3740 | case MIRType::Null: |
3741 | type = JSTYPE_OBJECT; |
3742 | break; |
3743 | case MIRType::Undefined: |
3744 | type = JSTYPE_UNDEFINED; |
3745 | break; |
3746 | case MIRType::Boolean: |
3747 | type = JSTYPE_BOOLEAN; |
3748 | break; |
3749 | case MIRType::Object: { |
3750 | KnownClass known = GetObjectKnownClass(unboxed); |
3751 | if (known != KnownClass::None) { |
3752 | if (known == KnownClass::Function) { |
3753 | type = JSTYPE_FUNCTION; |
3754 | } else { |
3755 | type = JSTYPE_OBJECT; |
3756 | } |
3757 | |
3758 | AssertKnownClass(alloc, this, unboxed); |
3759 | break; |
3760 | } |
3761 | [[fallthrough]]; |
3762 | } |
3763 | default: |
3764 | return this; |
3765 | } |
3766 | |
3767 | return MConstant::New(alloc, Int32Value(static_cast<int32_t>(type))); |
3768 | } |
3769 | |
3770 | MDefinition* MTypeOfName::foldsTo(TempAllocator& alloc) { |
3771 | 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" , 3771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 3771; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3772 | |
3773 | if (!input()->isConstant()) { |
3774 | return this; |
3775 | } |
3776 | |
3777 | static_assert(JSTYPE_UNDEFINED == 0); |
3778 | |
3779 | int32_t type = input()->toConstant()->toInt32(); |
3780 | 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" , 3780); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT" ")"); do { *((volatile int*)__null) = 3780; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3781 | |
3782 | JSString* name = |
3783 | TypeName(static_cast<JSType>(type), GetJitContext()->runtime->names()); |
3784 | return MConstant::New(alloc, StringValue(name)); |
3785 | } |
3786 | |
3787 | MUrsh* MUrsh::NewWasm(TempAllocator& alloc, MDefinition* left, |
3788 | MDefinition* right, MIRType type) { |
3789 | MUrsh* ins = new (alloc) MUrsh(left, right, type); |
3790 | |
3791 | // Since Ion has no UInt32 type, we use Int32 and we have a special |
3792 | // exception to the type rules: we can return values in |
3793 | // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type |
3794 | // without bailing out. This is necessary because Ion has no UInt32 |
3795 | // type and we can't have bailouts in wasm code. |
3796 | ins->bailoutsDisabled_ = true; |
3797 | |
3798 | return ins; |
3799 | } |
3800 | |
3801 | MResumePoint* MResumePoint::New(TempAllocator& alloc, MBasicBlock* block, |
3802 | jsbytecode* pc, ResumeMode mode) { |
3803 | MResumePoint* resume = new (alloc) MResumePoint(block, pc, mode); |
3804 | if (!resume->init(alloc)) { |
3805 | block->discardPreAllocatedResumePoint(resume); |
3806 | return nullptr; |
3807 | } |
3808 | resume->inherit(block); |
3809 | return resume; |
3810 | } |
3811 | |
3812 | MResumePoint::MResumePoint(MBasicBlock* block, jsbytecode* pc, ResumeMode mode) |
3813 | : MNode(block, Kind::ResumePoint), |
3814 | pc_(pc), |
3815 | instruction_(nullptr), |
3816 | mode_(mode) { |
3817 | block->addResumePoint(this); |
3818 | } |
3819 | |
3820 | bool MResumePoint::init(TempAllocator& alloc) { |
3821 | return operands_.init(alloc, block()->stackDepth()); |
3822 | } |
3823 | |
3824 | MResumePoint* MResumePoint::caller() const { |
3825 | return block()->callerResumePoint(); |
3826 | } |
3827 | |
3828 | void MResumePoint::inherit(MBasicBlock* block) { |
3829 | // FixedList doesn't initialize its elements, so do unchecked inits. |
3830 | for (size_t i = 0; i < stackDepth(); i++) { |
3831 | initOperand(i, block->getSlot(i)); |
3832 | } |
3833 | } |
3834 | |
3835 | void MResumePoint::addStore(TempAllocator& alloc, MDefinition* store, |
3836 | const MResumePoint* cache) { |
3837 | 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" , 3837); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->outerResumePoint() != this" ")"); do { *((volatile int*)__null) = 3837; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3838 | 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" , 3838); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!cache->stores_.empty()" ")"); do { *((volatile int*)__null) = 3838; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
3839 | |
3840 | if (cache && cache->stores_.begin()->operand == store) { |
3841 | // If the last resume point had the same side-effect stack, then we can |
3842 | // reuse the current side effect without cloning it. This is a simple |
3843 | // way to share common context by making a spaghetti stack. |
3844 | if (++cache->stores_.begin() == stores_.begin()) { |
3845 | stores_.copy(cache->stores_); |
3846 | return; |
3847 | } |
3848 | } |
3849 | |
3850 | // Ensure that the store would not be deleted by DCE. |
3851 | 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" , 3851); AnnotateMozCrashReason("MOZ_ASSERT" "(" "store->isEffectful()" ")"); do { *((volatile int*)__null) = 3851; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3852 | |
3853 | MStoreToRecover* top = new (alloc) MStoreToRecover(store); |
3854 | stores_.push(top); |
3855 | } |
3856 | |
3857 | #ifdef JS_JITSPEW1 |
3858 | void MResumePoint::dump(GenericPrinter& out) const { |
3859 | out.printf("resumepoint mode="); |
3860 | |
3861 | switch (mode()) { |
3862 | case ResumeMode::ResumeAt: |
3863 | if (instruction_) { |
3864 | out.printf("ResumeAt(%u)", instruction_->id()); |
3865 | } else { |
3866 | out.printf("ResumeAt"); |
3867 | } |
3868 | break; |
3869 | default: |
3870 | out.put(ResumeModeToString(mode())); |
3871 | break; |
3872 | } |
3873 | |
3874 | if (MResumePoint* c = caller()) { |
3875 | out.printf(" (caller in block%u)", c->block()->id()); |
3876 | } |
3877 | |
3878 | for (size_t i = 0; i < numOperands(); i++) { |
3879 | out.printf(" "); |
3880 | if (operands_[i].hasProducer()) { |
3881 | getOperand(i)->printName(out); |
3882 | } else { |
3883 | out.printf("(null)"); |
3884 | } |
3885 | } |
3886 | out.printf("\n"); |
3887 | } |
3888 | |
3889 | void MResumePoint::dump() const { |
3890 | Fprinter out(stderrstderr); |
3891 | dump(out); |
3892 | out.finish(); |
3893 | } |
3894 | #endif |
3895 | |
3896 | bool MResumePoint::isObservableOperand(MUse* u) const { |
3897 | return isObservableOperand(indexOf(u)); |
3898 | } |
3899 | |
3900 | bool MResumePoint::isObservableOperand(size_t index) const { |
3901 | return block()->info().isObservableSlot(index); |
3902 | } |
3903 | |
3904 | bool MResumePoint::isRecoverableOperand(MUse* u) const { |
3905 | return block()->info().isRecoverableOperand(indexOf(u)); |
3906 | } |
3907 | |
3908 | MDefinition* MTruncateBigIntToInt64::foldsTo(TempAllocator& alloc) { |
3909 | MDefinition* input = getOperand(0); |
3910 | |
3911 | if (input->isBox()) { |
3912 | input = input->getOperand(0); |
3913 | } |
3914 | |
3915 | // If the operand converts an I64 to BigInt, drop both conversions. |
3916 | if (input->isInt64ToBigInt()) { |
3917 | return input->getOperand(0); |
3918 | } |
3919 | |
3920 | // Fold this operation if the input operand is constant. |
3921 | if (input->isConstant()) { |
3922 | return MConstant::NewInt64( |
3923 | alloc, BigInt::toInt64(input->toConstant()->toBigInt())); |
3924 | } |
3925 | |
3926 | return this; |
3927 | } |
3928 | |
3929 | MDefinition* MToInt64::foldsTo(TempAllocator& alloc) { |
3930 | MDefinition* input = getOperand(0); |
3931 | |
3932 | if (input->isBox()) { |
3933 | input = input->getOperand(0); |
3934 | } |
3935 | |
3936 | // Unwrap MInt64ToBigInt: MToInt64(MInt64ToBigInt(int64)) = int64. |
3937 | if (input->isInt64ToBigInt()) { |
3938 | return input->getOperand(0); |
3939 | } |
3940 | |
3941 | // When the input is an Int64 already, just return it. |
3942 | if (input->type() == MIRType::Int64) { |
3943 | return input; |
3944 | } |
3945 | |
3946 | // Fold this operation if the input operand is constant. |
3947 | if (input->isConstant()) { |
3948 | switch (input->type()) { |
3949 | case MIRType::Boolean: |
3950 | return MConstant::NewInt64(alloc, input->toConstant()->toBoolean()); |
3951 | default: |
3952 | break; |
3953 | } |
3954 | } |
3955 | |
3956 | return this; |
3957 | } |
3958 | |
3959 | MDefinition* MToNumberInt32::foldsTo(TempAllocator& alloc) { |
3960 | // Fold this operation if the input operand is constant. |
3961 | if (MConstant* cst = input()->maybeConstantValue()) { |
3962 | switch (cst->type()) { |
3963 | case MIRType::Null: |
3964 | if (conversion() == IntConversionInputKind::Any) { |
3965 | return MConstant::New(alloc, Int32Value(0)); |
3966 | } |
3967 | break; |
3968 | case MIRType::Boolean: |
3969 | if (conversion() == IntConversionInputKind::Any) { |
3970 | return MConstant::New(alloc, Int32Value(cst->toBoolean())); |
3971 | } |
3972 | break; |
3973 | case MIRType::Int32: |
3974 | return MConstant::New(alloc, Int32Value(cst->toInt32())); |
3975 | case MIRType::Float32: |
3976 | case MIRType::Double: |
3977 | int32_t ival; |
3978 | // Only the value within the range of Int32 can be substituted as |
3979 | // constant. |
3980 | if (mozilla::NumberIsInt32(cst->numberToDouble(), &ival)) { |
3981 | return MConstant::New(alloc, Int32Value(ival)); |
3982 | } |
3983 | break; |
3984 | default: |
3985 | break; |
3986 | } |
3987 | } |
3988 | |
3989 | MDefinition* input = getOperand(0); |
3990 | if (input->isBox()) { |
3991 | input = input->toBox()->input(); |
3992 | } |
3993 | |
3994 | // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh |
3995 | // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js, |
3996 | // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator |
3997 | // is folded to a MTruncateToInt32 node, which will result in this MIR: |
3998 | // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that |
3999 | // the MUrsh node's type is int32 (since uint32 is not implemented), and |
4000 | // that would fold the MTruncateToInt32 node. This will make the modulo |
4001 | // unsigned, while is should have been signed. |
4002 | if (input->type() == MIRType::Int32 && !IsUint32Type(input)) { |
4003 | return input; |
4004 | } |
4005 | |
4006 | return this; |
4007 | } |
4008 | |
4009 | MDefinition* MBooleanToInt32::foldsTo(TempAllocator& alloc) { |
4010 | MDefinition* input = getOperand(0); |
4011 | 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" , 4011); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Boolean" ")"); do { *((volatile int*)__null) = 4011; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4012 | |
4013 | if (input->isConstant()) { |
4014 | return MConstant::New(alloc, Int32Value(input->toConstant()->toBoolean())); |
4015 | } |
4016 | |
4017 | return this; |
4018 | } |
4019 | |
4020 | void MToNumberInt32::analyzeEdgeCasesBackward() { |
4021 | if (!NeedNegativeZeroCheck(this)) { |
4022 | setNeedsNegativeZeroCheck(false); |
4023 | } |
4024 | } |
4025 | |
4026 | MDefinition* MTruncateToInt32::foldsTo(TempAllocator& alloc) { |
4027 | MDefinition* input = getOperand(0); |
4028 | if (input->isBox()) { |
4029 | input = input->getOperand(0); |
4030 | } |
4031 | |
4032 | // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh |
4033 | // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js, |
4034 | // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator |
4035 | // is folded to a MTruncateToInt32 node, which will result in this MIR: |
4036 | // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that |
4037 | // the MUrsh node's type is int32 (since uint32 is not implemented), and |
4038 | // that would fold the MTruncateToInt32 node. This will make the modulo |
4039 | // unsigned, while is should have been signed. |
4040 | if (input->type() == MIRType::Int32 && !IsUint32Type(input)) { |
4041 | return input; |
4042 | } |
4043 | |
4044 | if (input->type() == MIRType::Double && input->isConstant()) { |
4045 | int32_t ret = ToInt32(input->toConstant()->toDouble()); |
4046 | return MConstant::New(alloc, Int32Value(ret)); |
4047 | } |
4048 | |
4049 | return this; |
4050 | } |
4051 | |
4052 | MDefinition* MWrapInt64ToInt32::foldsTo(TempAllocator& alloc) { |
4053 | MDefinition* input = this->input(); |
4054 | if (input->isConstant()) { |
4055 | uint64_t c = input->toConstant()->toInt64(); |
4056 | int32_t output = bottomHalf() ? int32_t(c) : int32_t(c >> 32); |
4057 | return MConstant::New(alloc, Int32Value(output)); |
4058 | } |
4059 | |
4060 | return this; |
4061 | } |
4062 | |
4063 | MDefinition* MExtendInt32ToInt64::foldsTo(TempAllocator& alloc) { |
4064 | MDefinition* input = this->input(); |
4065 | if (input->isConstant()) { |
4066 | int32_t c = input->toConstant()->toInt32(); |
4067 | int64_t res = isUnsigned() ? int64_t(uint32_t(c)) : int64_t(c); |
4068 | return MConstant::NewInt64(alloc, res); |
4069 | } |
4070 | |
4071 | return this; |
4072 | } |
4073 | |
4074 | MDefinition* MSignExtendInt32::foldsTo(TempAllocator& alloc) { |
4075 | MDefinition* input = this->input(); |
4076 | if (input->isConstant()) { |
4077 | int32_t c = input->toConstant()->toInt32(); |
4078 | int32_t res; |
4079 | switch (mode_) { |
4080 | case Byte: |
4081 | res = int32_t(int8_t(c & 0xFF)); |
4082 | break; |
4083 | case Half: |
4084 | res = int32_t(int16_t(c & 0xFFFF)); |
4085 | break; |
4086 | } |
4087 | return MConstant::New(alloc, Int32Value(res)); |
4088 | } |
4089 | |
4090 | return this; |
4091 | } |
4092 | |
4093 | MDefinition* MSignExtendInt64::foldsTo(TempAllocator& alloc) { |
4094 | MDefinition* input = this->input(); |
4095 | if (input->isConstant()) { |
4096 | int64_t c = input->toConstant()->toInt64(); |
4097 | int64_t res; |
4098 | switch (mode_) { |
4099 | case Byte: |
4100 | res = int64_t(int8_t(c & 0xFF)); |
4101 | break; |
4102 | case Half: |
4103 | res = int64_t(int16_t(c & 0xFFFF)); |
4104 | break; |
4105 | case Word: |
4106 | res = int64_t(int32_t(c & 0xFFFFFFFFU)); |
4107 | break; |
4108 | } |
4109 | return MConstant::NewInt64(alloc, res); |
4110 | } |
4111 | |
4112 | return this; |
4113 | } |
4114 | |
4115 | MDefinition* MToDouble::foldsTo(TempAllocator& alloc) { |
4116 | MDefinition* input = getOperand(0); |
4117 | if (input->isBox()) { |
4118 | input = input->getOperand(0); |
4119 | } |
4120 | |
4121 | if (input->type() == MIRType::Double) { |
4122 | return input; |
4123 | } |
4124 | |
4125 | if (input->isConstant() && |
4126 | input->toConstant()->isTypeRepresentableAsDouble()) { |
4127 | return MConstant::New(alloc, |
4128 | DoubleValue(input->toConstant()->numberToDouble())); |
4129 | } |
4130 | |
4131 | return this; |
4132 | } |
4133 | |
4134 | MDefinition* MToFloat32::foldsTo(TempAllocator& alloc) { |
4135 | MDefinition* input = getOperand(0); |
4136 | if (input->isBox()) { |
4137 | input = input->getOperand(0); |
4138 | } |
4139 | |
4140 | if (input->type() == MIRType::Float32) { |
4141 | return input; |
4142 | } |
4143 | |
4144 | // If x is a Float32, Float32(Double(x)) == x |
4145 | if (!mustPreserveNaN_ && input->isToDouble() && |
4146 | input->toToDouble()->input()->type() == MIRType::Float32) { |
4147 | return input->toToDouble()->input(); |
4148 | } |
4149 | |
4150 | if (input->isConstant() && |
4151 | input->toConstant()->isTypeRepresentableAsDouble()) { |
4152 | return MConstant::NewFloat32(alloc, |
4153 | float(input->toConstant()->numberToDouble())); |
4154 | } |
4155 | |
4156 | // Fold ToFloat32(ToDouble(int32)) to ToFloat32(int32). |
4157 | if (input->isToDouble() && |
4158 | input->toToDouble()->input()->type() == MIRType::Int32) { |
4159 | return MToFloat32::New(alloc, input->toToDouble()->input()); |
4160 | } |
4161 | |
4162 | return this; |
4163 | } |
4164 | |
4165 | MDefinition* MToFloat16::foldsTo(TempAllocator& alloc) { |
4166 | MDefinition* in = input(); |
4167 | if (in->isBox()) { |
4168 | in = in->toBox()->input(); |
4169 | } |
4170 | |
4171 | if (in->isConstant()) { |
4172 | auto* cst = in->toConstant(); |
4173 | if (cst->isTypeRepresentableAsDouble()) { |
4174 | double num = cst->numberToDouble(); |
4175 | return MConstant::NewFloat32(alloc, static_cast<float>(js::float16{num})); |
4176 | } |
4177 | } |
4178 | |
4179 | auto isFloat16 = [](auto* def) -> MDefinition* { |
4180 | // ToFloat16(ToDouble(float16)) => float16 |
4181 | // ToFloat16(ToFloat32(float16)) => float16 |
4182 | if (def->isToDouble()) { |
4183 | def = def->toToDouble()->input(); |
4184 | } else if (def->isToFloat32()) { |
4185 | def = def->toToFloat32()->input(); |
4186 | } |
4187 | |
4188 | // ToFloat16(ToFloat16(x)) => ToFloat16(x) |
4189 | if (def->isToFloat16()) { |
4190 | return def; |
4191 | } |
4192 | |
4193 | // ToFloat16(LoadFloat16(x)) => LoadFloat16(x) |
4194 | if (def->isLoadUnboxedScalar() && |
4195 | def->toLoadUnboxedScalar()->storageType() == Scalar::Float16) { |
4196 | return def; |
4197 | } |
4198 | if (def->isLoadDataViewElement() && |
4199 | def->toLoadDataViewElement()->storageType() == Scalar::Float16) { |
4200 | return def; |
4201 | } |
4202 | return nullptr; |
4203 | }; |
4204 | |
4205 | // Fold loads which are guaranteed to return Float16. |
4206 | if (auto* f16 = isFloat16(in)) { |
4207 | return f16; |
4208 | } |
4209 | |
4210 | // Fold ToFloat16(ToDouble(float32)) to ToFloat16(float32). |
4211 | // Fold ToFloat16(ToDouble(int32)) to ToFloat16(int32). |
4212 | if (in->isToDouble()) { |
4213 | auto* toDoubleInput = in->toToDouble()->input(); |
4214 | if (toDoubleInput->type() == MIRType::Float32 || |
4215 | toDoubleInput->type() == MIRType::Int32) { |
4216 | return MToFloat16::New(alloc, toDoubleInput); |
4217 | } |
4218 | } |
4219 | |
4220 | return this; |
4221 | } |
4222 | |
4223 | MDefinition* MToString::foldsTo(TempAllocator& alloc) { |
4224 | MDefinition* in = input(); |
4225 | if (in->isBox()) { |
4226 | in = in->getOperand(0); |
4227 | } |
4228 | |
4229 | if (in->type() == MIRType::String) { |
4230 | return in; |
4231 | } |
4232 | return this; |
4233 | } |
4234 | |
4235 | MDefinition* MClampToUint8::foldsTo(TempAllocator& alloc) { |
4236 | if (MConstant* inputConst = input()->maybeConstantValue()) { |
4237 | if (inputConst->isTypeRepresentableAsDouble()) { |
4238 | int32_t clamped = ClampDoubleToUint8(inputConst->numberToDouble()); |
4239 | return MConstant::New(alloc, Int32Value(clamped)); |
4240 | } |
4241 | } |
4242 | return this; |
4243 | } |
4244 | |
4245 | bool MCompare::tryFoldEqualOperands(bool* result) { |
4246 | if (lhs() != rhs()) { |
4247 | return false; |
4248 | } |
4249 | |
4250 | // Intuitively somebody would think that if lhs === rhs, |
4251 | // then we can just return true. (Or false for !==) |
4252 | // However NaN !== NaN is true! So we spend some time trying |
4253 | // to eliminate this case. |
4254 | |
4255 | if (!IsStrictEqualityOp(jsop())) { |
4256 | return false; |
4257 | } |
4258 | |
4259 | 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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4260 | 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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4261 | 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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4262 | 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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4263 | compareType_ == Compare_Float32 || compareType_ == Compare_UIntPtr ||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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4264 | compareType_ == Compare_String || compareType_ == Compare_Object ||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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4265 | compareType_ == Compare_Symbol || compareType_ == Compare_BigInt ||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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4266 | 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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4267 | 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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4268 | 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_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_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_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" , 4268); 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_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) = 4268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4269 | |
4270 | if (isDoubleComparison() || isFloat32Comparison()) { |
4271 | if (!operandsAreNeverNaN()) { |
4272 | return false; |
4273 | } |
4274 | } |
4275 | |
4276 | lhs()->setGuardRangeBailoutsUnchecked(); |
4277 | |
4278 | *result = (jsop() == JSOp::StrictEq); |
4279 | return true; |
4280 | } |
4281 | |
4282 | static JSType TypeOfName(const JSLinearString* str) { |
4283 | static constexpr std::array types = { |
4284 | JSTYPE_UNDEFINED, JSTYPE_OBJECT, JSTYPE_FUNCTION, JSTYPE_STRING, |
4285 | JSTYPE_NUMBER, JSTYPE_BOOLEAN, JSTYPE_SYMBOL, JSTYPE_BIGINT, |
4286 | #ifdef ENABLE_RECORD_TUPLE |
4287 | JSTYPE_RECORD, JSTYPE_TUPLE, |
4288 | #endif |
4289 | }; |
4290 | static_assert(types.size() == JSTYPE_LIMIT); |
4291 | |
4292 | const JSAtomState& names = GetJitContext()->runtime->names(); |
4293 | for (auto type : types) { |
4294 | if (EqualStrings(str, TypeName(type, names))) { |
4295 | return type; |
4296 | } |
4297 | } |
4298 | return JSTYPE_LIMIT; |
4299 | } |
4300 | |
4301 | struct TypeOfCompareInput { |
4302 | // The `typeof expr` side of the comparison. |
4303 | // MTypeOfName for JSOp::Typeof/JSOp::TypeofExpr, and |
4304 | // MTypeOf for JSOp::TypeofEq (same pointer as typeOf). |
4305 | MDefinition* typeOfSide; |
4306 | |
4307 | // The actual `typeof` operation. |
4308 | MTypeOf* typeOf; |
4309 | |
4310 | // The string side of the comparison. |
4311 | JSType type; |
4312 | |
4313 | // True if the comparison uses raw JSType (Generated for JSOp::TypeofEq). |
4314 | bool isIntComparison; |
4315 | |
4316 | TypeOfCompareInput(MDefinition* typeOfSide, MTypeOf* typeOf, JSType type, |
4317 | bool isIntComparison) |
4318 | : typeOfSide(typeOfSide), |
4319 | typeOf(typeOf), |
4320 | type(type), |
4321 | isIntComparison(isIntComparison) {} |
4322 | }; |
4323 | |
4324 | static mozilla::Maybe<TypeOfCompareInput> IsTypeOfCompare(MCompare* ins) { |
4325 | if (!IsEqualityOp(ins->jsop())) { |
4326 | return mozilla::Nothing(); |
4327 | } |
4328 | |
4329 | if (ins->compareType() == MCompare::Compare_Int32) { |
4330 | auto* lhs = ins->lhs(); |
4331 | auto* rhs = ins->rhs(); |
4332 | |
4333 | if (ins->type() != MIRType::Boolean || lhs->type() != MIRType::Int32 || |
4334 | rhs->type() != MIRType::Int32) { |
4335 | return mozilla::Nothing(); |
4336 | } |
4337 | |
4338 | // NOTE: The comparison is generated inside JIT, and typeof should always |
4339 | // be in the LHS. |
4340 | if (!lhs->isTypeOf() || !rhs->isConstant()) { |
4341 | return mozilla::Nothing(); |
4342 | } |
4343 | |
4344 | auto* typeOf = lhs->toTypeOf(); |
4345 | auto* constant = rhs->toConstant(); |
4346 | |
4347 | JSType type = JSType(constant->toInt32()); |
4348 | return mozilla::Some(TypeOfCompareInput(typeOf, typeOf, type, true)); |
4349 | } |
4350 | |
4351 | if (ins->compareType() != MCompare::Compare_String) { |
4352 | return mozilla::Nothing(); |
4353 | } |
4354 | |
4355 | auto* lhs = ins->lhs(); |
4356 | auto* rhs = ins->rhs(); |
4357 | |
4358 | 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" , 4358); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::Boolean" ")"); do { *((volatile int*)__null) = 4358; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4359 | 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" , 4359); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4359; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4360 | 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" , 4360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4360; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4361 | |
4362 | if (!lhs->isTypeOfName() && !rhs->isTypeOfName()) { |
4363 | return mozilla::Nothing(); |
4364 | } |
4365 | if (!lhs->isConstant() && !rhs->isConstant()) { |
4366 | return mozilla::Nothing(); |
4367 | } |
4368 | |
4369 | auto* typeOfName = |
4370 | lhs->isTypeOfName() ? lhs->toTypeOfName() : rhs->toTypeOfName(); |
4371 | auto* typeOf = typeOfName->input()->toTypeOf(); |
4372 | |
4373 | auto* constant = lhs->isConstant() ? lhs->toConstant() : rhs->toConstant(); |
4374 | |
4375 | JSType type = TypeOfName(&constant->toString()->asLinear()); |
4376 | return mozilla::Some(TypeOfCompareInput(typeOfName, typeOf, type, false)); |
4377 | } |
4378 | |
4379 | bool MCompare::tryFoldTypeOf(bool* result) { |
4380 | auto typeOfCompare = IsTypeOfCompare(this); |
4381 | if (!typeOfCompare) { |
4382 | return false; |
4383 | } |
4384 | auto* typeOf = typeOfCompare->typeOf; |
4385 | JSType type = typeOfCompare->type; |
4386 | |
4387 | switch (type) { |
4388 | case JSTYPE_BOOLEAN: |
4389 | if (!typeOf->input()->mightBeType(MIRType::Boolean)) { |
4390 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4391 | return true; |
4392 | } |
4393 | break; |
4394 | case JSTYPE_NUMBER: |
4395 | if (!typeOf->input()->mightBeType(MIRType::Int32) && |
4396 | !typeOf->input()->mightBeType(MIRType::Float32) && |
4397 | !typeOf->input()->mightBeType(MIRType::Double)) { |
4398 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4399 | return true; |
4400 | } |
4401 | break; |
4402 | case JSTYPE_STRING: |
4403 | if (!typeOf->input()->mightBeType(MIRType::String)) { |
4404 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4405 | return true; |
4406 | } |
4407 | break; |
4408 | case JSTYPE_SYMBOL: |
4409 | if (!typeOf->input()->mightBeType(MIRType::Symbol)) { |
4410 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4411 | return true; |
4412 | } |
4413 | break; |
4414 | case JSTYPE_BIGINT: |
4415 | if (!typeOf->input()->mightBeType(MIRType::BigInt)) { |
4416 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4417 | return true; |
4418 | } |
4419 | break; |
4420 | case JSTYPE_OBJECT: |
4421 | if (!typeOf->input()->mightBeType(MIRType::Object) && |
4422 | !typeOf->input()->mightBeType(MIRType::Null)) { |
4423 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4424 | return true; |
4425 | } |
4426 | break; |
4427 | case JSTYPE_UNDEFINED: |
4428 | if (!typeOf->input()->mightBeType(MIRType::Object) && |
4429 | !typeOf->input()->mightBeType(MIRType::Undefined)) { |
4430 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4431 | return true; |
4432 | } |
4433 | break; |
4434 | case JSTYPE_FUNCTION: |
4435 | if (!typeOf->input()->mightBeType(MIRType::Object)) { |
4436 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4437 | return true; |
4438 | } |
4439 | break; |
4440 | case JSTYPE_LIMIT: |
4441 | *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne); |
4442 | return true; |
4443 | #ifdef ENABLE_RECORD_TUPLE |
4444 | case JSTYPE_RECORD: |
4445 | case JSTYPE_TUPLE: |
4446 | 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" , 4446); AnnotateMozCrashReason("MOZ_CRASH(" "Records and Tuples are not supported yet." ")"); do { *((volatile int*)__null) = 4446; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4447 | #endif |
4448 | } |
4449 | |
4450 | return false; |
4451 | } |
4452 | |
4453 | bool MCompare::tryFold(bool* result) { |
4454 | JSOp op = jsop(); |
4455 | |
4456 | if (tryFoldEqualOperands(result)) { |
4457 | return true; |
4458 | } |
4459 | |
4460 | if (tryFoldTypeOf(result)) { |
4461 | return true; |
4462 | } |
4463 | |
4464 | if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) { |
4465 | // The LHS is the value we want to test against null or undefined. |
4466 | if (IsStrictEqualityOp(op)) { |
4467 | if (lhs()->type() == inputType()) { |
4468 | *result = (op == JSOp::StrictEq); |
4469 | return true; |
4470 | } |
4471 | if (!lhs()->mightBeType(inputType())) { |
4472 | *result = (op == JSOp::StrictNe); |
4473 | return true; |
4474 | } |
4475 | } else { |
4476 | 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" , 4476); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsLooseEqualityOp(op)" ")"); do { *((volatile int*)__null) = 4476; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4477 | if (IsNullOrUndefined(lhs()->type())) { |
4478 | *result = (op == JSOp::Eq); |
4479 | return true; |
4480 | } |
4481 | if (!lhs()->mightBeType(MIRType::Null) && |
4482 | !lhs()->mightBeType(MIRType::Undefined) && |
4483 | !lhs()->mightBeType(MIRType::Object)) { |
4484 | *result = (op == JSOp::Ne); |
4485 | return true; |
4486 | } |
4487 | } |
4488 | return false; |
4489 | } |
4490 | |
4491 | return false; |
4492 | } |
4493 | |
4494 | template <typename T> |
4495 | static bool FoldComparison(JSOp op, T left, T right) { |
4496 | switch (op) { |
4497 | case JSOp::Lt: |
4498 | return left < right; |
4499 | case JSOp::Le: |
4500 | return left <= right; |
4501 | case JSOp::Gt: |
4502 | return left > right; |
4503 | case JSOp::Ge: |
4504 | return left >= right; |
4505 | case JSOp::StrictEq: |
4506 | case JSOp::Eq: |
4507 | return left == right; |
4508 | case JSOp::StrictNe: |
4509 | case JSOp::Ne: |
4510 | return left != right; |
4511 | default: |
4512 | MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op." , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4512); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op." ")"); do { *((volatile int*)__null) = 4512; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4513 | } |
4514 | } |
4515 | |
4516 | bool MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) { |
4517 | if (type() != MIRType::Boolean && type() != MIRType::Int32) { |
4518 | return false; |
4519 | } |
4520 | |
4521 | MDefinition* left = getOperand(0); |
4522 | MDefinition* right = getOperand(1); |
4523 | |
4524 | if (compareType() == Compare_Double) { |
4525 | // Optimize "MCompare MConstant (MToDouble SomethingInInt32Range). |
4526 | // In most cases the MToDouble was added, because the constant is |
4527 | // a double. |
4528 | // e.g. v < 9007199254740991, where v is an int32 is always true. |
4529 | if (!lhs()->isConstant() && !rhs()->isConstant()) { |
4530 | return false; |
4531 | } |
4532 | |
4533 | MDefinition* operand = left->isConstant() ? right : left; |
4534 | MConstant* constant = |
4535 | left->isConstant() ? left->toConstant() : right->toConstant(); |
4536 | 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" , 4536); AnnotateMozCrashReason("MOZ_ASSERT" "(" "constant->type() == MIRType::Double" ")"); do { *((volatile int*)__null) = 4536; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4537 | double cte = constant->toDouble(); |
4538 | |
4539 | if (operand->isToDouble() && |
4540 | operand->getOperand(0)->type() == MIRType::Int32) { |
4541 | bool replaced = false; |
4542 | switch (jsop_) { |
4543 | case JSOp::Lt: |
4544 | if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4545 | *result = !((constant == lhs()) ^ (cte < INT32_MIN(-2147483647-1))); |
4546 | replaced = true; |
4547 | } |
4548 | break; |
4549 | case JSOp::Le: |
4550 | if (constant == lhs()) { |
4551 | if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) { |
4552 | *result = (cte <= INT32_MIN(-2147483647-1)); |
4553 | replaced = true; |
4554 | } |
4555 | } else { |
4556 | if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4557 | *result = (cte >= INT32_MIN(-2147483647-1)); |
4558 | replaced = true; |
4559 | } |
4560 | } |
4561 | break; |
4562 | case JSOp::Gt: |
4563 | if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4564 | *result = !((constant == rhs()) ^ (cte < INT32_MIN(-2147483647-1))); |
4565 | replaced = true; |
4566 | } |
4567 | break; |
4568 | case JSOp::Ge: |
4569 | if (constant == lhs()) { |
4570 | if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4571 | *result = (cte >= INT32_MAX(2147483647)); |
4572 | replaced = true; |
4573 | } |
4574 | } else { |
4575 | if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) { |
4576 | *result = (cte <= INT32_MIN(-2147483647-1)); |
4577 | replaced = true; |
4578 | } |
4579 | } |
4580 | break; |
4581 | case JSOp::StrictEq: // Fall through. |
4582 | case JSOp::Eq: |
4583 | if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4584 | *result = false; |
4585 | replaced = true; |
4586 | } |
4587 | break; |
4588 | case JSOp::StrictNe: // Fall through. |
4589 | case JSOp::Ne: |
4590 | if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) { |
4591 | *result = true; |
4592 | replaced = true; |
4593 | } |
4594 | break; |
4595 | default: |
4596 | MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op." , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4596); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op." ")"); do { *((volatile int*)__null) = 4596; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4597 | } |
4598 | if (replaced) { |
4599 | MLimitedTruncate* limit = MLimitedTruncate::New( |
4600 | alloc, operand->getOperand(0), TruncateKind::NoTruncate); |
4601 | limit->setGuardUnchecked(); |
4602 | block()->insertBefore(this, limit); |
4603 | return true; |
4604 | } |
4605 | } |
4606 | |
4607 | // Optimize comparison against NaN. |
4608 | if (std::isnan(cte)) { |
4609 | switch (jsop_) { |
4610 | case JSOp::Lt: |
4611 | case JSOp::Le: |
4612 | case JSOp::Gt: |
4613 | case JSOp::Ge: |
4614 | case JSOp::Eq: |
4615 | case JSOp::StrictEq: |
4616 | *result = false; |
4617 | break; |
4618 | case JSOp::Ne: |
4619 | case JSOp::StrictNe: |
4620 | *result = true; |
4621 | break; |
4622 | default: |
4623 | MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op." , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 4623); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op." ")"); do { *((volatile int*)__null) = 4623; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
4624 | } |
4625 | return true; |
4626 | } |
4627 | } |
4628 | |
4629 | if (!left->isConstant() || !right->isConstant()) { |
4630 | return false; |
4631 | } |
4632 | |
4633 | MConstant* lhs = left->toConstant(); |
4634 | MConstant* rhs = right->toConstant(); |
4635 | |
4636 | // Fold away some String equality comparisons. |
4637 | if (lhs->type() == MIRType::String && rhs->type() == MIRType::String) { |
4638 | int32_t comp = 0; // Default to equal. |
4639 | if (left != right) { |
4640 | comp = CompareStrings(&lhs->toString()->asLinear(), |
4641 | &rhs->toString()->asLinear()); |
4642 | } |
4643 | *result = FoldComparison(jsop_, comp, 0); |
4644 | return true; |
4645 | } |
4646 | |
4647 | if (compareType_ == Compare_UInt32) { |
4648 | *result = FoldComparison(jsop_, uint32_t(lhs->toInt32()), |
4649 | uint32_t(rhs->toInt32())); |
4650 | return true; |
4651 | } |
4652 | |
4653 | if (compareType_ == Compare_Int64) { |
4654 | *result = FoldComparison(jsop_, lhs->toInt64(), rhs->toInt64()); |
4655 | return true; |
4656 | } |
4657 | |
4658 | if (compareType_ == Compare_UInt64) { |
4659 | *result = FoldComparison(jsop_, uint64_t(lhs->toInt64()), |
4660 | uint64_t(rhs->toInt64())); |
4661 | return true; |
4662 | } |
4663 | |
4664 | if (lhs->isTypeRepresentableAsDouble() && |
4665 | rhs->isTypeRepresentableAsDouble()) { |
4666 | *result = |
4667 | FoldComparison(jsop_, lhs->numberToDouble(), rhs->numberToDouble()); |
4668 | return true; |
4669 | } |
4670 | |
4671 | return false; |
4672 | } |
4673 | |
4674 | MDefinition* MCompare::tryFoldTypeOf(TempAllocator& alloc) { |
4675 | auto typeOfCompare = IsTypeOfCompare(this); |
4676 | if (!typeOfCompare) { |
4677 | return this; |
4678 | } |
4679 | auto* typeOf = typeOfCompare->typeOf; |
4680 | JSType type = typeOfCompare->type; |
4681 | |
4682 | auto* input = typeOf->input(); |
4683 | 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" , 4684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 4684; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4684 | 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" , 4684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object" ")"); do { *((volatile int*)__null) = 4684; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4685 | |
4686 | // Constant typeof folding handles the other cases. |
4687 | 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" , 4689); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION" ")"); do { *((volatile int*)__null) = 4689; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) |
4688 | 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" , 4689); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION" ")"); do { *((volatile int*)__null) = 4689; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) |
4689 | 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" , 4689); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION" ")"); do { *((volatile int*)__null) = 4689; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
4690 | |
4691 | 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" , 4691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type != JSTYPE_LIMIT" ") (" "unknown typeof strings folded earlier" ")"); do { *(( volatile int*)__null) = 4691; __attribute__((nomerge)) ::abort (); } while (false); } } while (false); |
4692 | |
4693 | // If there's only a single use, assume this |typeof| is used in a simple |
4694 | // comparison context. |
4695 | // |
4696 | // if (typeof thing === "number") { ... } |
4697 | // |
4698 | // It'll be compiled into something similar to: |
4699 | // |
4700 | // if (IsNumber(thing)) { ... } |
4701 | // |
4702 | // This heuristic can go wrong when repeated |typeof| are used in consecutive |
4703 | // if-statements. |
4704 | // |
4705 | // if (typeof thing === "number") { ... } |
4706 | // else if (typeof thing === "string") { ... } |
4707 | // ... repeated for all possible types |
4708 | // |
4709 | // In that case it'd more efficient to emit MTypeOf compared to MTypeOfIs. We |
4710 | // don't yet handle that case, because it'd require a separate optimization |
4711 | // pass to correctly detect it. |
4712 | if (typeOfCompare->typeOfSide->hasOneUse()) { |
4713 | return MTypeOfIs::New(alloc, input, jsop(), type); |
4714 | } |
4715 | |
4716 | if (typeOfCompare->isIntComparison) { |
4717 | // Already optimized. |
4718 | return this; |
4719 | } |
4720 | |
4721 | MConstant* cst = MConstant::New(alloc, Int32Value(type)); |
4722 | block()->insertBefore(this, cst); |
4723 | |
4724 | return MCompare::New(alloc, typeOf, cst, jsop(), MCompare::Compare_Int32); |
4725 | } |
4726 | |
4727 | MDefinition* MCompare::tryFoldCharCompare(TempAllocator& alloc) { |
4728 | if (compareType() != Compare_String) { |
4729 | return this; |
4730 | } |
4731 | |
4732 | MDefinition* left = lhs(); |
4733 | 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" , 4733); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4733; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4734 | |
4735 | MDefinition* right = rhs(); |
4736 | 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" , 4736); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4736; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4737 | |
4738 | // |str[i]| is compiled as |MFromCharCode(MCharCodeAt(str, i))|. |
4739 | // Out-of-bounds access is compiled as |
4740 | // |FromCharCodeEmptyIfNegative(CharCodeAtOrNegative(str, i))|. |
4741 | auto isCharAccess = [](MDefinition* ins) { |
4742 | if (ins->isFromCharCode()) { |
4743 | return ins->toFromCharCode()->code()->isCharCodeAt(); |
4744 | } |
4745 | if (ins->isFromCharCodeEmptyIfNegative()) { |
4746 | auto* fromCharCode = ins->toFromCharCodeEmptyIfNegative(); |
4747 | return fromCharCode->code()->isCharCodeAtOrNegative(); |
4748 | } |
4749 | return false; |
4750 | }; |
4751 | |
4752 | auto charAccessCode = [](MDefinition* ins) { |
4753 | if (ins->isFromCharCode()) { |
4754 | return ins->toFromCharCode()->code(); |
4755 | } |
4756 | return ins->toFromCharCodeEmptyIfNegative()->code(); |
4757 | }; |
4758 | |
4759 | if (left->isConstant() || right->isConstant()) { |
4760 | // Try to optimize |MConstant(string) <compare> (MFromCharCode MCharCodeAt)| |
4761 | // as |MConstant(charcode) <compare> MCharCodeAt|. |
4762 | MConstant* constant; |
4763 | MDefinition* operand; |
4764 | if (left->isConstant()) { |
4765 | constant = left->toConstant(); |
4766 | operand = right; |
4767 | } else { |
4768 | constant = right->toConstant(); |
4769 | operand = left; |
4770 | } |
4771 | |
4772 | if (constant->toString()->length() != 1 || !isCharAccess(operand)) { |
4773 | return this; |
4774 | } |
4775 | |
4776 | char16_t charCode = constant->toString()->asLinear().latin1OrTwoByteChar(0); |
4777 | MConstant* charCodeConst = MConstant::New(alloc, Int32Value(charCode)); |
4778 | block()->insertBefore(this, charCodeConst); |
4779 | |
4780 | MDefinition* charCodeAt = charAccessCode(operand); |
4781 | |
4782 | if (left->isConstant()) { |
4783 | left = charCodeConst; |
4784 | right = charCodeAt; |
4785 | } else { |
4786 | left = charCodeAt; |
4787 | right = charCodeConst; |
4788 | } |
4789 | } else if (isCharAccess(left) && isCharAccess(right)) { |
4790 | // Try to optimize |(MFromCharCode MCharCodeAt) <compare> (MFromCharCode |
4791 | // MCharCodeAt)| as |MCharCodeAt <compare> MCharCodeAt|. |
4792 | |
4793 | left = charAccessCode(left); |
4794 | right = charAccessCode(right); |
4795 | } else { |
4796 | return this; |
4797 | } |
4798 | |
4799 | return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32); |
4800 | } |
4801 | |
4802 | MDefinition* MCompare::tryFoldStringCompare(TempAllocator& alloc) { |
4803 | if (compareType() != Compare_String) { |
4804 | return this; |
4805 | } |
4806 | |
4807 | MDefinition* left = lhs(); |
4808 | 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" , 4808); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4808; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4809 | |
4810 | MDefinition* right = rhs(); |
4811 | 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" , 4811); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4811; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4812 | |
4813 | if (!left->isConstant() && !right->isConstant()) { |
4814 | return this; |
4815 | } |
4816 | |
4817 | // Try to optimize |string <compare> MConstant("")| as |MStringLength(string) |
4818 | // <compare> MConstant(0)|. |
4819 | |
4820 | MConstant* constant = |
4821 | left->isConstant() ? left->toConstant() : right->toConstant(); |
4822 | if (!constant->toString()->empty()) { |
4823 | return this; |
4824 | } |
4825 | |
4826 | MDefinition* operand = left->isConstant() ? right : left; |
4827 | |
4828 | auto* strLength = MStringLength::New(alloc, operand); |
4829 | block()->insertBefore(this, strLength); |
4830 | |
4831 | auto* zero = MConstant::New(alloc, Int32Value(0)); |
4832 | block()->insertBefore(this, zero); |
4833 | |
4834 | if (left->isConstant()) { |
4835 | left = zero; |
4836 | right = strLength; |
4837 | } else { |
4838 | left = strLength; |
4839 | right = zero; |
4840 | } |
4841 | |
4842 | return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32); |
4843 | } |
4844 | |
4845 | MDefinition* MCompare::tryFoldStringSubstring(TempAllocator& alloc) { |
4846 | if (compareType() != Compare_String) { |
4847 | return this; |
4848 | } |
4849 | if (!IsEqualityOp(jsop())) { |
4850 | return this; |
4851 | } |
4852 | |
4853 | auto* left = lhs(); |
4854 | 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" , 4854); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4854; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4855 | |
4856 | auto* right = rhs(); |
4857 | 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" , 4857); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String" ")"); do { *((volatile int*)__null) = 4857; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4858 | |
4859 | // One operand must be a constant string. |
4860 | if (!left->isConstant() && !right->isConstant()) { |
4861 | return this; |
4862 | } |
4863 | |
4864 | // The constant string must be non-empty. |
4865 | auto* constant = |
4866 | left->isConstant() ? left->toConstant() : right->toConstant(); |
4867 | if (constant->toString()->empty()) { |
4868 | return this; |
4869 | } |
4870 | |
4871 | // The other operand must be a substring operation. |
4872 | auto* operand = left->isConstant() ? right : left; |
4873 | if (!operand->isSubstr()) { |
4874 | return this; |
4875 | } |
4876 | auto* substr = operand->toSubstr(); |
4877 | |
4878 | static_assert(JSString::MAX_LENGTH < INT32_MAX(2147483647), |
4879 | "string length can be casted to int32_t"); |
4880 | |
4881 | if (!IsSubstrTo(substr, int32_t(constant->toString()->length()))) { |
4882 | return this; |
4883 | } |
4884 | |
4885 | // Now fold code like |str.substring(0, 2) == "aa"| to |str.startsWith("aa")|. |
4886 | |
4887 | auto* startsWith = MStringStartsWith::New(alloc, substr->string(), constant); |
4888 | if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) { |
4889 | return startsWith; |
4890 | } |
4891 | |
4892 | // Invert for inequality. |
4893 | 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" , 4893); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe" ")"); do { *((volatile int*)__null) = 4893; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4894 | |
4895 | block()->insertBefore(this, startsWith); |
4896 | return MNot::New(alloc, startsWith); |
4897 | } |
4898 | |
4899 | MDefinition* MCompare::tryFoldStringIndexOf(TempAllocator& alloc) { |
4900 | if (compareType() != Compare_Int32) { |
4901 | return this; |
4902 | } |
4903 | if (!IsEqualityOp(jsop())) { |
4904 | return this; |
4905 | } |
4906 | |
4907 | auto* left = lhs(); |
4908 | 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" , 4908); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 4908; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4909 | |
4910 | auto* right = rhs(); |
4911 | 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" , 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4912 | |
4913 | // One operand must be a constant integer. |
4914 | if (!left->isConstant() && !right->isConstant()) { |
4915 | return this; |
4916 | } |
4917 | |
4918 | // The constant must be zero. |
4919 | auto* constant = |
4920 | left->isConstant() ? left->toConstant() : right->toConstant(); |
4921 | if (!constant->isInt32(0)) { |
4922 | return this; |
4923 | } |
4924 | |
4925 | // The other operand must be an indexOf operation. |
4926 | auto* operand = left->isConstant() ? right : left; |
4927 | if (!operand->isStringIndexOf()) { |
4928 | return this; |
4929 | } |
4930 | |
4931 | // Fold |str.indexOf(searchStr) == 0| to |str.startsWith(searchStr)|. |
4932 | |
4933 | auto* indexOf = operand->toStringIndexOf(); |
4934 | auto* startsWith = |
4935 | MStringStartsWith::New(alloc, indexOf->string(), indexOf->searchString()); |
4936 | if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) { |
4937 | return startsWith; |
4938 | } |
4939 | |
4940 | // Invert for inequality. |
4941 | 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" , 4941); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe" ")"); do { *((volatile int*)__null) = 4941; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4942 | |
4943 | block()->insertBefore(this, startsWith); |
4944 | return MNot::New(alloc, startsWith); |
4945 | } |
4946 | |
4947 | MDefinition* MCompare::foldsTo(TempAllocator& alloc) { |
4948 | bool result; |
4949 | |
4950 | if (tryFold(&result) || evaluateConstantOperands(alloc, &result)) { |
4951 | if (type() == MIRType::Int32) { |
4952 | return MConstant::New(alloc, Int32Value(result)); |
4953 | } |
4954 | |
4955 | 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" , 4955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Boolean" ")"); do { *((volatile int*)__null) = 4955; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4956 | return MConstant::New(alloc, BooleanValue(result)); |
4957 | } |
4958 | |
4959 | if (MDefinition* folded = tryFoldTypeOf(alloc); folded != this) { |
4960 | return folded; |
4961 | } |
4962 | |
4963 | if (MDefinition* folded = tryFoldCharCompare(alloc); folded != this) { |
4964 | return folded; |
4965 | } |
4966 | |
4967 | if (MDefinition* folded = tryFoldStringCompare(alloc); folded != this) { |
4968 | return folded; |
4969 | } |
4970 | |
4971 | if (MDefinition* folded = tryFoldStringSubstring(alloc); folded != this) { |
4972 | return folded; |
4973 | } |
4974 | |
4975 | if (MDefinition* folded = tryFoldStringIndexOf(alloc); folded != this) { |
4976 | return folded; |
4977 | } |
4978 | |
4979 | return this; |
4980 | } |
4981 | |
4982 | void MCompare::trySpecializeFloat32(TempAllocator& alloc) { |
4983 | if (AllOperandsCanProduceFloat32(this) && compareType_ == Compare_Double) { |
4984 | compareType_ = Compare_Float32; |
4985 | } else { |
4986 | ConvertOperandsToDouble(this, alloc); |
4987 | } |
4988 | } |
4989 | |
4990 | MDefinition* MNot::foldsTo(TempAllocator& alloc) { |
4991 | // Fold if the input is constant |
4992 | if (MConstant* inputConst = input()->maybeConstantValue()) { |
4993 | bool b; |
4994 | if (inputConst->valueToBoolean(&b)) { |
4995 | if (type() == MIRType::Int32 || type() == MIRType::Int64) { |
4996 | return MConstant::New(alloc, Int32Value(!b)); |
4997 | } |
4998 | return MConstant::New(alloc, BooleanValue(!b)); |
4999 | } |
5000 | } |
5001 | |
5002 | // If the operand of the Not is itself a Not, they cancel out. But we can't |
5003 | // always convert Not(Not(x)) to x because that may loose the conversion to |
5004 | // boolean. We can simplify Not(Not(Not(x))) to Not(x) though. |
5005 | MDefinition* op = getOperand(0); |
5006 | if (op->isNot()) { |
5007 | MDefinition* opop = op->getOperand(0); |
5008 | if (opop->isNot()) { |
5009 | return opop; |
5010 | } |
5011 | } |
5012 | |
5013 | // Not of an undefined or null value is always true |
5014 | if (input()->type() == MIRType::Undefined || |
5015 | input()->type() == MIRType::Null) { |
5016 | return MConstant::New(alloc, BooleanValue(true)); |
5017 | } |
5018 | |
5019 | // Not of a symbol is always false. |
5020 | if (input()->type() == MIRType::Symbol) { |
5021 | return MConstant::New(alloc, BooleanValue(false)); |
5022 | } |
5023 | |
5024 | return this; |
5025 | } |
5026 | |
5027 | void MNot::trySpecializeFloat32(TempAllocator& alloc) { |
5028 | (void)EnsureFloatInputOrConvert(this, alloc); |
5029 | } |
5030 | |
5031 | #ifdef JS_JITSPEW1 |
5032 | void MBeta::printOpcode(GenericPrinter& out) const { |
5033 | MDefinition::printOpcode(out); |
5034 | |
5035 | out.printf(" "); |
5036 | comparison_->dump(out); |
5037 | } |
5038 | #endif |
5039 | |
5040 | AliasSet MCreateThis::getAliasSet() const { |
5041 | return AliasSet::Load(AliasSet::Any); |
5042 | } |
5043 | |
5044 | bool MGetArgumentsObjectArg::congruentTo(const MDefinition* ins) const { |
5045 | if (!ins->isGetArgumentsObjectArg()) { |
5046 | return false; |
5047 | } |
5048 | if (ins->toGetArgumentsObjectArg()->argno() != argno()) { |
5049 | return false; |
5050 | } |
5051 | return congruentIfOperandsEqual(ins); |
5052 | } |
5053 | |
5054 | AliasSet MGetArgumentsObjectArg::getAliasSet() const { |
5055 | return AliasSet::Load(AliasSet::Any); |
5056 | } |
5057 | |
5058 | AliasSet MSetArgumentsObjectArg::getAliasSet() const { |
5059 | return AliasSet::Store(AliasSet::Any); |
5060 | } |
5061 | |
5062 | MObjectState::MObjectState(MObjectState* state) |
5063 | : MVariadicInstruction(classOpcode), |
5064 | numSlots_(state->numSlots_), |
5065 | numFixedSlots_(state->numFixedSlots_) { |
5066 | // This instruction is only used as a summary for bailout paths. |
5067 | setResultType(MIRType::Object); |
5068 | setRecoveredOnBailout(); |
5069 | } |
5070 | |
5071 | MObjectState::MObjectState(JSObject* templateObject) |
5072 | : MObjectState(templateObject->as<NativeObject>().shape()) {} |
5073 | |
5074 | MObjectState::MObjectState(const Shape* shape) |
5075 | : MVariadicInstruction(classOpcode) { |
5076 | // This instruction is only used as a summary for bailout paths. |
5077 | setResultType(MIRType::Object); |
5078 | setRecoveredOnBailout(); |
5079 | |
5080 | numSlots_ = shape->asShared().slotSpan(); |
5081 | numFixedSlots_ = shape->asShared().numFixedSlots(); |
5082 | } |
5083 | |
5084 | /* static */ |
5085 | JSObject* MObjectState::templateObjectOf(MDefinition* obj) { |
5086 | // MNewPlainObject uses a shape constant, not an object. |
5087 | 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" , 5087); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!obj->isNewPlainObject()" ")"); do { *((volatile int*)__null) = 5087; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5088 | |
5089 | if (obj->isNewObject()) { |
5090 | return obj->toNewObject()->templateObject(); |
5091 | } else if (obj->isNewCallObject()) { |
5092 | return obj->toNewCallObject()->templateObject(); |
5093 | } else if (obj->isNewIterator()) { |
5094 | return obj->toNewIterator()->templateObject(); |
5095 | } |
5096 | |
5097 | MOZ_CRASH("unreachable")do { do { } while (false); MOZ_ReportCrash("" "unreachable", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp" , 5097); AnnotateMozCrashReason("MOZ_CRASH(" "unreachable" ")" ); do { *((volatile int*)__null) = 5097; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
5098 | } |
5099 | |
5100 | bool MObjectState::init(TempAllocator& alloc, MDefinition* obj) { |
5101 | if (!MVariadicInstruction::init(alloc, numSlots() + 1)) { |
5102 | return false; |
5103 | } |
5104 | // +1, for the Object. |
5105 | initOperand(0, obj); |
5106 | return true; |
5107 | } |
5108 | |
5109 | void MObjectState::initFromTemplateObject(TempAllocator& alloc, |
5110 | MDefinition* undefinedVal) { |
5111 | if (object()->isNewPlainObject()) { |
5112 | 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" , 5113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()" ")"); do { *((volatile int*)__null) = 5113; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
5113 | 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" , 5113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()" ")"); do { *((volatile int*)__null) = 5113; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5114 | for (size_t i = 0; i < numSlots(); i++) { |
5115 | initSlot(i, undefinedVal); |
5116 | } |
5117 | return; |
5118 | } |
5119 | |
5120 | JSObject* templateObject = templateObjectOf(object()); |
5121 | |
5122 | // Initialize all the slots of the object state with the value contained in |
5123 | // the template object. This is needed to account values which are baked in |
5124 | // the template objects and not visible in IonMonkey, such as the |
5125 | // uninitialized-lexical magic value of call objects. |
5126 | |
5127 | 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" , 5127); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject->is<NativeObject>()" ")"); do { *((volatile int*)__null) = 5127; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5128 | NativeObject& nativeObject = templateObject->as<NativeObject>(); |
5129 | 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" , 5129); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeObject.slotSpan() == numSlots()" ")"); do { *((volatile int*)__null) = 5129; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5130 | |
5131 | for (size_t i = 0; i < numSlots(); i++) { |
5132 | Value val = nativeObject.getSlot(i); |
5133 | MDefinition* def = undefinedVal; |
5134 | if (!val.isUndefined()) { |
5135 | MConstant* ins = MConstant::New(alloc, val); |
5136 | block()->insertBefore(this, ins); |
5137 | def = ins; |
5138 | } |
5139 | initSlot(i, def); |
5140 | } |
5141 | } |
5142 | |
5143 | MObjectState* MObjectState::New(TempAllocator& alloc, MDefinition* obj) { |
5144 | MObjectState* res; |
5145 | if (obj->isNewPlainObject()) { |
5146 | const Shape* shape = obj->toNewPlainObject()->shape(); |
5147 | res = new (alloc) MObjectState(shape); |
5148 | } else { |
5149 | JSObject* templateObject = templateObjectOf(obj); |
5150 | 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" , 5150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject" ") (" "Unexpected object creation." ")"); do { *((volatile int *)__null) = 5150; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
5151 | res = new (alloc) MObjectState(templateObject); |
5152 | } |
5153 | |
5154 | if (!res || !res->init(alloc, obj)) { |
5155 | return nullptr; |
5156 | } |
5157 | return res; |
5158 | } |
5159 | |
5160 | MObjectState* MObjectState::Copy(TempAllocator& alloc, MObjectState* state) { |
5161 | MObjectState* res = new (alloc) MObjectState(state); |
5162 | if (!res || !res->init(alloc, state->object())) { |
5163 | return nullptr; |
5164 | } |
5165 | for (size_t i = 0; i < res->numSlots(); i++) { |
5166 | res->initSlot(i, state->getSlot(i)); |
5167 | } |
5168 | return res; |
5169 | } |
5170 | |
5171 | MArrayState::MArrayState(MDefinition* arr) : MVariadicInstruction(classOpcode) { |
5172 | // This instruction is only used as a summary for bailout paths. |
5173 | setResultType(MIRType::Object); |
5174 | setRecoveredOnBailout(); |
5175 | if (arr->isNewArrayObject()) { |
5176 | numElements_ = arr->toNewArrayObject()->length(); |
5177 | } else { |
5178 | numElements_ = arr->toNewArray()->length(); |
5179 | } |
5180 | } |
5181 | |
5182 | bool MArrayState::init(TempAllocator& alloc, MDefinition* obj, |
5183 | MDefinition* len) { |
5184 | if (!MVariadicInstruction::init(alloc, numElements() + 2)) { |
5185 | return false; |
5186 | } |
5187 | // +1, for the Array object. |
5188 | initOperand(0, obj); |
5189 | // +1, for the length value of the array. |
5190 | initOperand(1, len); |
5191 | return true; |
5192 | } |
5193 | |
5194 | void MArrayState::initFromTemplateObject(TempAllocator& alloc, |
5195 | MDefinition* undefinedVal) { |
5196 | for (size_t i = 0; i < numElements(); i++) { |
5197 | initElement(i, undefinedVal); |
5198 | } |
5199 | } |
5200 | |
5201 | MArrayState* MArrayState::New(TempAllocator& alloc, MDefinition* arr, |
5202 | MDefinition* initLength) { |
5203 | MArrayState* res = new (alloc) MArrayState(arr); |
5204 | if (!res || !res->init(alloc, arr, initLength)) { |
5205 | return nullptr; |
5206 | } |
5207 | return res; |
5208 | } |
5209 | |
5210 | MArrayState* MArrayState::Copy(TempAllocator& alloc, MArrayState* state) { |
5211 | MDefinition* arr = state->array(); |
5212 | MDefinition* len = state->initializedLength(); |
5213 | MArrayState* res = new (alloc) MArrayState(arr); |
5214 | if (!res || !res->init(alloc, arr, len)) { |
5215 | return nullptr; |
5216 | } |
5217 | for (size_t i = 0; i < res->numElements(); i++) { |
5218 | res->initElement(i, state->getElement(i)); |
5219 | } |
5220 | return res; |
5221 | } |
5222 | |
5223 | MNewArray::MNewArray(uint32_t length, MConstant* templateConst, |
5224 | gc::Heap initialHeap, bool vmCall) |
5225 | : MUnaryInstruction(classOpcode, templateConst), |
5226 | length_(length), |
5227 | initialHeap_(initialHeap), |
5228 | vmCall_(vmCall) { |
5229 | setResultType(MIRType::Object); |
5230 | } |
5231 | |
5232 | MDefinition::AliasType MLoadFixedSlot::mightAlias( |
5233 | const MDefinition* def) const { |
5234 | if (def->isStoreFixedSlot()) { |
5235 | const MStoreFixedSlot* store = def->toStoreFixedSlot(); |
5236 | if (store->slot() != slot()) { |
5237 | return AliasType::NoAlias; |
5238 | } |
5239 | if (store->object() != object()) { |
5240 | return AliasType::MayAlias; |
5241 | } |
5242 | return AliasType::MustAlias; |
5243 | } |
5244 | return AliasType::MayAlias; |
5245 | } |
5246 | |
5247 | MDefinition* MLoadFixedSlot::foldsTo(TempAllocator& alloc) { |
5248 | if (MDefinition* def = foldsToStore(alloc)) { |
5249 | return def; |
5250 | } |
5251 | |
5252 | return this; |
5253 | } |
5254 | |
5255 | MDefinition::AliasType MLoadFixedSlotAndUnbox::mightAlias( |
5256 | const MDefinition* def) const { |
5257 | if (def->isStoreFixedSlot()) { |
5258 | const MStoreFixedSlot* store = def->toStoreFixedSlot(); |
5259 | if (store->slot() != slot()) { |
5260 | return AliasType::NoAlias; |
5261 | } |
5262 | if (store->object() != object()) { |
5263 | return AliasType::MayAlias; |
5264 | } |
5265 | return AliasType::MustAlias; |
5266 | } |
5267 | return AliasType::MayAlias; |
5268 | } |
5269 | |
5270 | MDefinition* MLoadFixedSlotAndUnbox::foldsTo(TempAllocator& alloc) { |
5271 | if (MDefinition* def = foldsToStore(alloc)) { |
5272 | return def; |
5273 | } |
5274 | |
5275 | return this; |
5276 | } |
5277 | |
5278 | MDefinition::AliasType MLoadDynamicSlot::mightAlias( |
5279 | const MDefinition* def) const { |
5280 | if (def->isStoreDynamicSlot()) { |
5281 | const MStoreDynamicSlot* store = def->toStoreDynamicSlot(); |
5282 | if (store->slot() != slot()) { |
5283 | return AliasType::NoAlias; |
5284 | } |
5285 | |
5286 | if (store->slots() != slots()) { |
5287 | return AliasType::MayAlias; |
5288 | } |
5289 | |
5290 | return AliasType::MustAlias; |
5291 | } |
5292 | return AliasType::MayAlias; |
5293 | } |
5294 | |
5295 | HashNumber MLoadDynamicSlot::valueHash() const { |
5296 | HashNumber hash = MDefinition::valueHash(); |
5297 | hash = addU32ToHash(hash, slot_); |
5298 | return hash; |
5299 | } |
5300 | |
5301 | MDefinition* MLoadDynamicSlot::foldsTo(TempAllocator& alloc) { |
5302 | if (MDefinition* def = foldsToStore(alloc)) { |
5303 | return def; |
5304 | } |
5305 | |
5306 | return this; |
5307 | } |
5308 | |
5309 | #ifdef JS_JITSPEW1 |
5310 | void MLoadDynamicSlot::printOpcode(GenericPrinter& out) const { |
5311 | MDefinition::printOpcode(out); |
5312 | out.printf(" (slot %u)", slot()); |
5313 | } |
5314 | |
5315 | void MLoadDynamicSlotAndUnbox::printOpcode(GenericPrinter& out) const { |
5316 | MDefinition::printOpcode(out); |
5317 | out.printf(" (slot %zu)", slot()); |
5318 | } |
5319 | |
5320 | void MStoreDynamicSlot::printOpcode(GenericPrinter& out) const { |
5321 | MDefinition::printOpcode(out); |
5322 | out.printf(" (slot %u)", slot()); |
5323 | } |
5324 | |
5325 | void MLoadFixedSlot::printOpcode(GenericPrinter& out) const { |
5326 | MDefinition::printOpcode(out); |
5327 | out.printf(" (slot %zu)", slot()); |
5328 | } |
5329 | |
5330 | void MLoadFixedSlotAndUnbox::printOpcode(GenericPrinter& out) const { |
5331 | MDefinition::printOpcode(out); |
5332 | out.printf(" (slot %zu)", slot()); |
5333 | } |
5334 | |
5335 | void MStoreFixedSlot::printOpcode(GenericPrinter& out) const { |
5336 | MDefinition::printOpcode(out); |
5337 | out.printf(" (slot %zu)", slot()); |
5338 | } |
5339 | #endif |
5340 | |
5341 | MDefinition* MGuardFunctionScript::foldsTo(TempAllocator& alloc) { |
5342 | MDefinition* in = input(); |
5343 | if (in->isLambda() && |
5344 | in->toLambda()->templateFunction()->baseScript() == expected()) { |
5345 | return in; |
5346 | } |
5347 | return this; |
5348 | } |
5349 | |
5350 | MDefinition* MFunctionEnvironment::foldsTo(TempAllocator& alloc) { |
5351 | if (input()->isLambda()) { |
5352 | return input()->toLambda()->environmentChain(); |
5353 | } |
5354 | if (input()->isFunctionWithProto()) { |
5355 | return input()->toFunctionWithProto()->environmentChain(); |
5356 | } |
5357 | return this; |
5358 | } |
5359 | |
5360 | static bool AddIsANonZeroAdditionOf(MAdd* add, MDefinition* ins) { |
5361 | if (add->lhs() != ins && add->rhs() != ins) { |
5362 | return false; |
5363 | } |
5364 | MDefinition* other = (add->lhs() == ins) ? add->rhs() : add->lhs(); |
5365 | if (!IsNumberType(other->type())) { |
5366 | return false; |
5367 | } |
5368 | if (!other->isConstant()) { |
5369 | return false; |
5370 | } |
5371 | if (other->toConstant()->numberToDouble() == 0) { |
5372 | return false; |
5373 | } |
5374 | return true; |
5375 | } |
5376 | |
5377 | // Skip over instructions that usually appear between the actual index |
5378 | // value being used and the MLoadElement. |
5379 | // They don't modify the index value in a meaningful way. |
5380 | static MDefinition* SkipUninterestingInstructions(MDefinition* ins) { |
5381 | // Drop the MToNumberInt32 added by the TypePolicy for double and float |
5382 | // values. |
5383 | if (ins->isToNumberInt32()) { |
5384 | return SkipUninterestingInstructions(ins->toToNumberInt32()->input()); |
5385 | } |
5386 | |
5387 | // Ignore the bounds check, which don't modify the index. |
5388 | if (ins->isBoundsCheck()) { |
5389 | return SkipUninterestingInstructions(ins->toBoundsCheck()->index()); |
5390 | } |
5391 | |
5392 | // Masking the index for Spectre-mitigation is not observable. |
5393 | if (ins->isSpectreMaskIndex()) { |
5394 | return SkipUninterestingInstructions(ins->toSpectreMaskIndex()->index()); |
5395 | } |
5396 | |
5397 | return ins; |
5398 | } |
5399 | |
5400 | static bool DefinitelyDifferentValue(MDefinition* ins1, MDefinition* ins2) { |
5401 | ins1 = SkipUninterestingInstructions(ins1); |
5402 | ins2 = SkipUninterestingInstructions(ins2); |
5403 | |
5404 | if (ins1 == ins2) { |
5405 | return false; |
5406 | } |
5407 | |
5408 | // For constants check they are not equal. |
5409 | if (ins1->isConstant() && ins2->isConstant()) { |
5410 | MConstant* cst1 = ins1->toConstant(); |
5411 | MConstant* cst2 = ins2->toConstant(); |
5412 | |
5413 | if (!cst1->isTypeRepresentableAsDouble() || |
5414 | !cst2->isTypeRepresentableAsDouble()) { |
5415 | return false; |
5416 | } |
5417 | |
5418 | // Be conservative and only allow values that fit into int32. |
5419 | int32_t n1, n2; |
5420 | if (!mozilla::NumberIsInt32(cst1->numberToDouble(), &n1) || |
5421 | !mozilla::NumberIsInt32(cst2->numberToDouble(), &n2)) { |
5422 | return false; |
5423 | } |
5424 | |
5425 | return n1 != n2; |
5426 | } |
5427 | |
5428 | // Check if "ins1 = ins2 + cte", which would make both instructions |
5429 | // have different values. |
5430 | if (ins1->isAdd()) { |
5431 | if (AddIsANonZeroAdditionOf(ins1->toAdd(), ins2)) { |
5432 | return true; |
5433 | } |
5434 | } |
5435 | if (ins2->isAdd()) { |
5436 | if (AddIsANonZeroAdditionOf(ins2->toAdd(), ins1)) { |
5437 | return true; |
5438 | } |
5439 | } |
5440 | |
5441 | return false; |
5442 | } |
5443 | |
5444 | MDefinition::AliasType MLoadElement::mightAlias(const MDefinition* def) const { |
5445 | if (def->isStoreElement()) { |
5446 | const MStoreElement* store = def->toStoreElement(); |
5447 | if (store->index() != index()) { |
5448 | if (DefinitelyDifferentValue(store->index(), index())) { |
5449 | return AliasType::NoAlias; |
5450 | } |
5451 | return AliasType::MayAlias; |
5452 | } |
5453 | |
5454 | if (store->elements() != elements()) { |
5455 | return AliasType::MayAlias; |
5456 | } |
5457 | |
5458 | return AliasType::MustAlias; |
5459 | } |
5460 | return AliasType::MayAlias; |
5461 | } |
5462 | |
5463 | MDefinition* MLoadElement::foldsTo(TempAllocator& alloc) { |
5464 | if (MDefinition* def = foldsToStore(alloc)) { |
5465 | return def; |
5466 | } |
5467 | |
5468 | return this; |
5469 | } |
5470 | |
5471 | void MSqrt::trySpecializeFloat32(TempAllocator& alloc) { |
5472 | if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) { |
5473 | setResultType(MIRType::Float32); |
5474 | specialization_ = MIRType::Float32; |
5475 | } |
5476 | } |
5477 | |
5478 | MDefinition* MClz::foldsTo(TempAllocator& alloc) { |
5479 | if (num()->isConstant()) { |
5480 | MConstant* c = num()->toConstant(); |
5481 | if (type() == MIRType::Int32) { |
5482 | int32_t n = c->toInt32(); |
5483 | if (n == 0) { |
5484 | return MConstant::New(alloc, Int32Value(32)); |
5485 | } |
5486 | return MConstant::New(alloc, |
5487 | Int32Value(mozilla::CountLeadingZeroes32(n))); |
5488 | } |
5489 | int64_t n = c->toInt64(); |
5490 | if (n == 0) { |
5491 | return MConstant::NewInt64(alloc, int64_t(64)); |
5492 | } |
5493 | return MConstant::NewInt64(alloc, |
5494 | int64_t(mozilla::CountLeadingZeroes64(n))); |
5495 | } |
5496 | |
5497 | return this; |
5498 | } |
5499 | |
5500 | MDefinition* MCtz::foldsTo(TempAllocator& alloc) { |
5501 | if (num()->isConstant()) { |
5502 | MConstant* c = num()->toConstant(); |
5503 | if (type() == MIRType::Int32) { |
5504 | int32_t n = num()->toConstant()->toInt32(); |
5505 | if (n == 0) { |
5506 | return MConstant::New(alloc, Int32Value(32)); |
5507 | } |
5508 | return MConstant::New(alloc, |
5509 | Int32Value(mozilla::CountTrailingZeroes32(n))); |
5510 | } |
5511 | int64_t n = c->toInt64(); |
5512 | if (n == 0) { |
5513 | return MConstant::NewInt64(alloc, int64_t(64)); |
5514 | } |
5515 | return MConstant::NewInt64(alloc, |
5516 | int64_t(mozilla::CountTrailingZeroes64(n))); |
5517 | } |
5518 | |
5519 | return this; |
5520 | } |
5521 | |
5522 | MDefinition* MPopcnt::foldsTo(TempAllocator& alloc) { |
5523 | if (num()->isConstant()) { |
5524 | MConstant* c = num()->toConstant(); |
5525 | if (type() == MIRType::Int32) { |
5526 | int32_t n = num()->toConstant()->toInt32(); |
5527 | return MConstant::New(alloc, Int32Value(mozilla::CountPopulation32(n))); |
5528 | } |
5529 | int64_t n = c->toInt64(); |
5530 | return MConstant::NewInt64(alloc, int64_t(mozilla::CountPopulation64(n))); |
5531 | } |
5532 | |
5533 | return this; |
5534 | } |
5535 | |
5536 | MDefinition* MBoundsCheck::foldsTo(TempAllocator& alloc) { |
5537 | if (type() == MIRType::Int32 && index()->isConstant() && |
5538 | length()->isConstant()) { |
5539 | uint32_t len = length()->toConstant()->toInt32(); |
5540 | uint32_t idx = index()->toConstant()->toInt32(); |
5541 | if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len) { |
5542 | return index(); |
5543 | } |
5544 | } |
5545 | |
5546 | return this; |
5547 | } |
5548 | |
5549 | MDefinition* MTableSwitch::foldsTo(TempAllocator& alloc) { |
5550 | MDefinition* op = getOperand(0); |
5551 | |
5552 | // If we only have one successor, convert to a plain goto to the only |
5553 | // successor. TableSwitch indices are numeric; other types will always go to |
5554 | // the only successor. |
5555 | if (numSuccessors() == 1 || |
5556 | (op->type() != MIRType::Value && !IsNumberType(op->type()))) { |
5557 | return MGoto::New(alloc, getDefault()); |
5558 | } |
5559 | |
5560 | if (MConstant* opConst = op->maybeConstantValue()) { |
5561 | if (op->type() == MIRType::Int32) { |
5562 | int32_t i = opConst->toInt32() - low_; |
5563 | MBasicBlock* target; |
5564 | if (size_t(i) < numCases()) { |
5565 | target = getCase(size_t(i)); |
5566 | } else { |
5567 | target = getDefault(); |
5568 | } |
5569 | 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" , 5569); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")" ); do { *((volatile int*)__null) = 5569; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5570 | return MGoto::New(alloc, target); |
5571 | } |
5572 | } |
5573 | |
5574 | return this; |
5575 | } |
5576 | |
5577 | MDefinition* MArrayJoin::foldsTo(TempAllocator& alloc) { |
5578 | MDefinition* arr = array(); |
5579 | |
5580 | if (!arr->isStringSplit()) { |
5581 | return this; |
5582 | } |
5583 | |
5584 | setRecoveredOnBailout(); |
5585 | if (arr->hasLiveDefUses()) { |
5586 | setNotRecoveredOnBailout(); |
5587 | return this; |
5588 | } |
5589 | |
5590 | // The MStringSplit won't generate any code. |
5591 | arr->setRecoveredOnBailout(); |
5592 | |
5593 | // We're replacing foo.split(bar).join(baz) by |
5594 | // foo.replace(bar, baz). MStringSplit could be recovered by |
5595 | // a bailout. As we are removing its last use, and its result |
5596 | // could be captured by a resume point, this MStringSplit will |
5597 | // be executed on the bailout path. |
5598 | MDefinition* string = arr->toStringSplit()->string(); |
5599 | MDefinition* pattern = arr->toStringSplit()->separator(); |
5600 | MDefinition* replacement = sep(); |
5601 | |
5602 | MStringReplace* substr = |
5603 | MStringReplace::New(alloc, string, pattern, replacement); |
5604 | substr->setFlatReplacement(); |
5605 | return substr; |
5606 | } |
5607 | |
5608 | MDefinition* MGetFirstDollarIndex::foldsTo(TempAllocator& alloc) { |
5609 | MDefinition* strArg = str(); |
5610 | if (!strArg->isConstant()) { |
5611 | return this; |
5612 | } |
5613 | |
5614 | JSLinearString* str = &strArg->toConstant()->toString()->asLinear(); |
5615 | int32_t index = GetFirstDollarIndexRawFlat(str); |
5616 | return MConstant::New(alloc, Int32Value(index)); |
5617 | } |
5618 | |
5619 | AliasSet MThrowRuntimeLexicalError::getAliasSet() const { |
5620 | return AliasSet::Store(AliasSet::ExceptionState); |
5621 | } |
5622 | |
5623 | AliasSet MSlots::getAliasSet() const { |
5624 | return AliasSet::Load(AliasSet::ObjectFields); |
5625 | } |
5626 | |
5627 | MDefinition::AliasType MSlots::mightAlias(const MDefinition* store) const { |
5628 | // ArrayPush only modifies object elements, but not object slots. |
5629 | if (store->isArrayPush()) { |
5630 | return AliasType::NoAlias; |
5631 | } |
5632 | return MInstruction::mightAlias(store); |
5633 | } |
5634 | |
5635 | AliasSet MElements::getAliasSet() const { |
5636 | return AliasSet::Load(AliasSet::ObjectFields); |
5637 | } |
5638 | |
5639 | AliasSet MInitializedLength::getAliasSet() const { |
5640 | return AliasSet::Load(AliasSet::ObjectFields); |
5641 | } |
5642 | |
5643 | AliasSet MSetInitializedLength::getAliasSet() const { |
5644 | return AliasSet::Store(AliasSet::ObjectFields); |
5645 | } |
5646 | |
5647 | AliasSet MObjectKeysLength::getAliasSet() const { |
5648 | return AliasSet::Load(AliasSet::ObjectFields); |
5649 | } |
5650 | |
5651 | AliasSet MArrayLength::getAliasSet() const { |
5652 | return AliasSet::Load(AliasSet::ObjectFields); |
5653 | } |
5654 | |
5655 | AliasSet MSetArrayLength::getAliasSet() const { |
5656 | return AliasSet::Store(AliasSet::ObjectFields); |
5657 | } |
5658 | |
5659 | AliasSet MFunctionLength::getAliasSet() const { |
5660 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
5661 | AliasSet::DynamicSlot); |
5662 | } |
5663 | |
5664 | AliasSet MFunctionName::getAliasSet() const { |
5665 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
5666 | AliasSet::DynamicSlot); |
5667 | } |
5668 | |
5669 | AliasSet MArrayBufferByteLength::getAliasSet() const { |
5670 | return AliasSet::Load(AliasSet::FixedSlot); |
5671 | } |
5672 | |
5673 | AliasSet MArrayBufferViewLength::getAliasSet() const { |
5674 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset); |
5675 | } |
5676 | |
5677 | AliasSet MArrayBufferViewByteOffset::getAliasSet() const { |
5678 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset); |
5679 | } |
5680 | |
5681 | AliasSet MArrayBufferViewElements::getAliasSet() const { |
5682 | return AliasSet::Load(AliasSet::ObjectFields); |
5683 | } |
5684 | |
5685 | AliasSet MGuardHasAttachedArrayBuffer::getAliasSet() const { |
5686 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot); |
5687 | } |
5688 | |
5689 | AliasSet MResizableTypedArrayByteOffsetMaybeOutOfBounds::getAliasSet() const { |
5690 | // Loads the byteOffset and additionally checks for detached buffers, so the |
5691 | // alias set also has to include |ObjectFields| and |FixedSlot|. |
5692 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset | |
5693 | AliasSet::ObjectFields | AliasSet::FixedSlot); |
5694 | } |
5695 | |
5696 | AliasSet MResizableTypedArrayLength::getAliasSet() const { |
5697 | // Loads the length and byteOffset slots, the shared-elements flag, the |
5698 | // auto-length fixed slot, and the shared raw-buffer length. |
5699 | auto flags = AliasSet::ArrayBufferViewLengthOrOffset | |
5700 | AliasSet::ObjectFields | AliasSet::FixedSlot | |
5701 | AliasSet::SharedArrayRawBufferLength; |
5702 | |
5703 | // When a barrier is needed make the instruction effectful by giving it a |
5704 | // "store" effect. Also prevent reordering LoadUnboxedScalar before this |
5705 | // instruction by including |UnboxedElement| in the alias set. |
5706 | if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) { |
5707 | return AliasSet::Store(flags | AliasSet::UnboxedElement); |
5708 | } |
5709 | return AliasSet::Load(flags); |
5710 | } |
5711 | |
5712 | bool MResizableTypedArrayLength::congruentTo(const MDefinition* ins) const { |
5713 | if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) { |
5714 | return false; |
5715 | } |
5716 | return congruentIfOperandsEqual(ins); |
5717 | } |
5718 | |
5719 | AliasSet MResizableDataViewByteLength::getAliasSet() const { |
5720 | // Loads the length and byteOffset slots, the shared-elements flag, the |
5721 | // auto-length fixed slot, and the shared raw-buffer length. |
5722 | auto flags = AliasSet::ArrayBufferViewLengthOrOffset | |
5723 | AliasSet::ObjectFields | AliasSet::FixedSlot | |
5724 | AliasSet::SharedArrayRawBufferLength; |
5725 | |
5726 | // When a barrier is needed make the instruction effectful by giving it a |
5727 | // "store" effect. Also prevent reordering LoadUnboxedScalar before this |
5728 | // instruction by including |UnboxedElement| in the alias set. |
5729 | if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) { |
5730 | return AliasSet::Store(flags | AliasSet::UnboxedElement); |
5731 | } |
5732 | return AliasSet::Load(flags); |
5733 | } |
5734 | |
5735 | bool MResizableDataViewByteLength::congruentTo(const MDefinition* ins) const { |
5736 | if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) { |
5737 | return false; |
5738 | } |
5739 | return congruentIfOperandsEqual(ins); |
5740 | } |
5741 | |
5742 | AliasSet MGrowableSharedArrayBufferByteLength::getAliasSet() const { |
5743 | // Requires a barrier, so make the instruction effectful by giving it a |
5744 | // "store" effect. Also prevent reordering LoadUnboxedScalar before this |
5745 | // instruction by including |UnboxedElement| in the alias set. |
5746 | return AliasSet::Store(AliasSet::FixedSlot | |
5747 | AliasSet::SharedArrayRawBufferLength | |
5748 | AliasSet::UnboxedElement); |
5749 | } |
5750 | |
5751 | AliasSet MGuardResizableArrayBufferViewInBounds::getAliasSet() const { |
5752 | // Additionally reads the |initialLength| and |initialByteOffset| slots, but |
5753 | // since these can't change after construction, we don't need to track them. |
5754 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset); |
5755 | } |
5756 | |
5757 | AliasSet MGuardResizableArrayBufferViewInBoundsOrDetached::getAliasSet() const { |
5758 | // Loads the byteOffset and additionally checks for detached buffers, so the |
5759 | // alias set also has to include |ObjectFields| and |FixedSlot|. |
5760 | return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset | |
5761 | AliasSet::ObjectFields | AliasSet::FixedSlot); |
5762 | } |
5763 | |
5764 | AliasSet MArrayPush::getAliasSet() const { |
5765 | return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element); |
5766 | } |
5767 | |
5768 | MDefinition* MGuardNumberToIntPtrIndex::foldsTo(TempAllocator& alloc) { |
5769 | MDefinition* input = this->input(); |
5770 | |
5771 | if (input->isToDouble() && input->getOperand(0)->type() == MIRType::Int32) { |
5772 | return MInt32ToIntPtr::New(alloc, input->getOperand(0)); |
5773 | } |
5774 | |
5775 | if (!input->isConstant()) { |
5776 | return this; |
5777 | } |
5778 | |
5779 | // Fold constant double representable as intptr to intptr. |
5780 | int64_t ival; |
5781 | if (!mozilla::NumberEqualsInt64(input->toConstant()->toDouble(), &ival)) { |
5782 | // If not representable as an int64, this access is equal to an OOB access. |
5783 | // So replace it with a known int64/intptr value which also produces an OOB |
5784 | // access. If we don't support OOB accesses we have to bail out. |
5785 | if (!supportOOB()) { |
5786 | return this; |
5787 | } |
5788 | ival = -1; |
5789 | } |
5790 | |
5791 | if (ival < INTPTR_MIN(-9223372036854775807L-1) || ival > INTPTR_MAX(9223372036854775807L)) { |
5792 | return this; |
5793 | } |
5794 | |
5795 | return MConstant::NewIntPtr(alloc, intptr_t(ival)); |
5796 | } |
5797 | |
5798 | MDefinition* MIsObject::foldsTo(TempAllocator& alloc) { |
5799 | if (!object()->isBox()) { |
5800 | return this; |
5801 | } |
5802 | |
5803 | MDefinition* unboxed = object()->getOperand(0); |
5804 | if (unboxed->type() == MIRType::Object) { |
5805 | return MConstant::New(alloc, BooleanValue(true)); |
5806 | } |
5807 | |
5808 | return this; |
5809 | } |
5810 | |
5811 | MDefinition* MIsNullOrUndefined::foldsTo(TempAllocator& alloc) { |
5812 | MDefinition* input = value(); |
5813 | if (input->isBox()) { |
5814 | input = input->toBox()->input(); |
5815 | } |
5816 | |
5817 | if (input->definitelyType({MIRType::Null, MIRType::Undefined})) { |
5818 | return MConstant::New(alloc, BooleanValue(true)); |
5819 | } |
5820 | |
5821 | if (!input->mightBeType(MIRType::Null) && |
5822 | !input->mightBeType(MIRType::Undefined)) { |
5823 | return MConstant::New(alloc, BooleanValue(false)); |
5824 | } |
5825 | |
5826 | return this; |
5827 | } |
5828 | |
5829 | AliasSet MHomeObjectSuperBase::getAliasSet() const { |
5830 | return AliasSet::Load(AliasSet::ObjectFields); |
5831 | } |
5832 | |
5833 | MDefinition* MGuardValue::foldsTo(TempAllocator& alloc) { |
5834 | if (MConstant* cst = value()->maybeConstantValue()) { |
5835 | if (cst->toJSValue() == expected()) { |
5836 | return value(); |
5837 | } |
5838 | } |
5839 | |
5840 | return this; |
5841 | } |
5842 | |
5843 | MDefinition* MGuardNullOrUndefined::foldsTo(TempAllocator& alloc) { |
5844 | MDefinition* input = value(); |
5845 | if (input->isBox()) { |
5846 | input = input->toBox()->input(); |
5847 | } |
5848 | |
5849 | if (input->definitelyType({MIRType::Null, MIRType::Undefined})) { |
5850 | return value(); |
5851 | } |
5852 | |
5853 | return this; |
5854 | } |
5855 | |
5856 | MDefinition* MGuardIsNotObject::foldsTo(TempAllocator& alloc) { |
5857 | MDefinition* input = value(); |
5858 | if (input->isBox()) { |
5859 | input = input->toBox()->input(); |
5860 | } |
5861 | |
5862 | if (!input->mightBeType(MIRType::Object)) { |
5863 | return value(); |
5864 | } |
5865 | |
5866 | return this; |
5867 | } |
5868 | |
5869 | MDefinition* MGuardObjectIdentity::foldsTo(TempAllocator& alloc) { |
5870 | if (object()->isConstant() && expected()->isConstant()) { |
5871 | JSObject* obj = &object()->toConstant()->toObject(); |
5872 | JSObject* other = &expected()->toConstant()->toObject(); |
5873 | if (!bailOnEquality()) { |
5874 | if (obj == other) { |
5875 | return object(); |
5876 | } |
5877 | } else { |
5878 | if (obj != other) { |
5879 | return object(); |
5880 | } |
5881 | } |
5882 | } |
5883 | |
5884 | if (!bailOnEquality() && object()->isNurseryObject() && |
5885 | expected()->isNurseryObject()) { |
5886 | uint32_t objIndex = object()->toNurseryObject()->nurseryIndex(); |
5887 | uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex(); |
5888 | if (objIndex == otherIndex) { |
5889 | return object(); |
5890 | } |
5891 | } |
5892 | |
5893 | return this; |
5894 | } |
5895 | |
5896 | MDefinition* MGuardSpecificFunction::foldsTo(TempAllocator& alloc) { |
5897 | if (function()->isConstant() && expected()->isConstant()) { |
5898 | JSObject* fun = &function()->toConstant()->toObject(); |
5899 | JSObject* other = &expected()->toConstant()->toObject(); |
5900 | if (fun == other) { |
5901 | return function(); |
5902 | } |
5903 | } |
5904 | |
5905 | if (function()->isNurseryObject() && expected()->isNurseryObject()) { |
5906 | uint32_t funIndex = function()->toNurseryObject()->nurseryIndex(); |
5907 | uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex(); |
5908 | if (funIndex == otherIndex) { |
5909 | return function(); |
5910 | } |
5911 | } |
5912 | |
5913 | return this; |
5914 | } |
5915 | |
5916 | MDefinition* MGuardSpecificAtom::foldsTo(TempAllocator& alloc) { |
5917 | if (str()->isConstant()) { |
5918 | JSString* s = str()->toConstant()->toString(); |
5919 | if (s->isAtom()) { |
5920 | JSAtom* cstAtom = &s->asAtom(); |
5921 | if (cstAtom == atom()) { |
5922 | return str(); |
5923 | } |
5924 | } |
5925 | } |
5926 | |
5927 | return this; |
5928 | } |
5929 | |
5930 | MDefinition* MGuardSpecificSymbol::foldsTo(TempAllocator& alloc) { |
5931 | if (symbol()->isConstant()) { |
5932 | if (symbol()->toConstant()->toSymbol() == expected()) { |
5933 | return symbol(); |
5934 | } |
5935 | } |
5936 | |
5937 | return this; |
5938 | } |
5939 | |
5940 | MDefinition* MGuardSpecificInt32::foldsTo(TempAllocator& alloc) { |
5941 | if (num()->isConstant() && num()->toConstant()->isInt32(expected())) { |
5942 | return num(); |
5943 | } |
5944 | return this; |
5945 | } |
5946 | |
5947 | bool MCallBindVar::congruentTo(const MDefinition* ins) const { |
5948 | if (!ins->isCallBindVar()) { |
5949 | return false; |
5950 | } |
5951 | return congruentIfOperandsEqual(ins); |
5952 | } |
5953 | |
5954 | bool MGuardShape::congruentTo(const MDefinition* ins) const { |
5955 | if (!ins->isGuardShape()) { |
5956 | return false; |
5957 | } |
5958 | if (shape() != ins->toGuardShape()->shape()) { |
5959 | return false; |
5960 | } |
5961 | return congruentIfOperandsEqual(ins); |
5962 | } |
5963 | |
5964 | AliasSet MGuardShape::getAliasSet() const { |
5965 | return AliasSet::Load(AliasSet::ObjectFields); |
5966 | } |
5967 | |
5968 | MDefinition::AliasType MGuardShape::mightAlias(const MDefinition* store) const { |
5969 | // These instructions only modify object elements, but not the shape. |
5970 | if (store->isStoreElementHole() || store->isArrayPush()) { |
5971 | return AliasType::NoAlias; |
5972 | } |
5973 | if (object()->isConstantProto()) { |
5974 | const MDefinition* receiverObject = |
5975 | object()->toConstantProto()->getReceiverObject(); |
5976 | switch (store->op()) { |
5977 | case MDefinition::Opcode::StoreFixedSlot: |
5978 | if (store->toStoreFixedSlot()->object()->skipObjectGuards() == |
5979 | receiverObject) { |
5980 | return AliasType::NoAlias; |
5981 | } |
5982 | break; |
5983 | case MDefinition::Opcode::StoreDynamicSlot: |
5984 | if (store->toStoreDynamicSlot() |
5985 | ->slots() |
5986 | ->toSlots() |
5987 | ->object() |
5988 | ->skipObjectGuards() == receiverObject) { |
5989 | return AliasType::NoAlias; |
5990 | } |
5991 | break; |
5992 | case MDefinition::Opcode::AddAndStoreSlot: |
5993 | if (store->toAddAndStoreSlot()->object()->skipObjectGuards() == |
5994 | receiverObject) { |
5995 | return AliasType::NoAlias; |
5996 | } |
5997 | break; |
5998 | case MDefinition::Opcode::AllocateAndStoreSlot: |
5999 | if (store->toAllocateAndStoreSlot()->object()->skipObjectGuards() == |
6000 | receiverObject) { |
6001 | return AliasType::NoAlias; |
6002 | } |
6003 | break; |
6004 | default: |
6005 | break; |
6006 | } |
6007 | } |
6008 | return MInstruction::mightAlias(store); |
6009 | } |
6010 | |
6011 | bool MGuardFuse::congruentTo(const MDefinition* ins) const { |
6012 | if (!ins->isGuardFuse()) { |
6013 | return false; |
6014 | } |
6015 | if (fuseIndex() != ins->toGuardFuse()->fuseIndex()) { |
6016 | return false; |
6017 | } |
6018 | return congruentIfOperandsEqual(ins); |
6019 | } |
6020 | |
6021 | AliasSet MGuardFuse::getAliasSet() const { |
6022 | // The alias set below reflects the set of operations which could cause a fuse |
6023 | // to be popped, and therefore MGuardFuse aliases with. |
6024 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::DynamicSlot | |
6025 | AliasSet::FixedSlot | |
6026 | AliasSet::GlobalGenerationCounter); |
6027 | } |
6028 | |
6029 | AliasSet MGuardMultipleShapes::getAliasSet() const { |
6030 | // Note: This instruction loads the elements of the ListObject used to |
6031 | // store the list of shapes, but that object is internal and not exposed |
6032 | // to script, so it doesn't have to be in the alias set. |
6033 | return AliasSet::Load(AliasSet::ObjectFields); |
6034 | } |
6035 | |
6036 | AliasSet MGuardGlobalGeneration::getAliasSet() const { |
6037 | return AliasSet::Load(AliasSet::GlobalGenerationCounter); |
6038 | } |
6039 | |
6040 | bool MGuardGlobalGeneration::congruentTo(const MDefinition* ins) const { |
6041 | return ins->isGuardGlobalGeneration() && |
6042 | ins->toGuardGlobalGeneration()->expected() == expected() && |
6043 | ins->toGuardGlobalGeneration()->generationAddr() == generationAddr(); |
6044 | } |
6045 | |
6046 | MDefinition* MGuardIsNotProxy::foldsTo(TempAllocator& alloc) { |
6047 | KnownClass known = GetObjectKnownClass(object()); |
6048 | if (known == KnownClass::None) { |
6049 | return this; |
6050 | } |
6051 | |
6052 | 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" , 6052); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetObjectKnownJSClass(object())->isProxyObject()" ")"); do { *((volatile int*)__null) = 6052; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6053 | AssertKnownClass(alloc, this, object()); |
6054 | return object(); |
6055 | } |
6056 | |
6057 | AliasSet MMegamorphicLoadSlotByValue::getAliasSet() const { |
6058 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6059 | AliasSet::DynamicSlot); |
6060 | } |
6061 | |
6062 | MDefinition* MMegamorphicLoadSlotByValue::foldsTo(TempAllocator& alloc) { |
6063 | MDefinition* input = idVal(); |
6064 | if (input->isBox()) { |
6065 | input = input->toBox()->input(); |
6066 | } |
6067 | |
6068 | MDefinition* result = this; |
6069 | |
6070 | if (input->isConstant()) { |
6071 | MConstant* constant = input->toConstant(); |
6072 | if (constant->type() == MIRType::Symbol) { |
6073 | PropertyKey id = PropertyKey::Symbol(constant->toSymbol()); |
6074 | result = MMegamorphicLoadSlot::New(alloc, object(), id); |
6075 | } |
6076 | |
6077 | if (constant->type() == MIRType::String) { |
6078 | JSString* str = constant->toString(); |
6079 | if (str->isAtom() && !str->asAtom().isIndex()) { |
6080 | PropertyKey id = PropertyKey::NonIntAtom(str); |
6081 | result = MMegamorphicLoadSlot::New(alloc, object(), id); |
6082 | } |
6083 | } |
6084 | } |
6085 | |
6086 | if (result != this) { |
6087 | result->setDependency(dependency()); |
6088 | } |
6089 | |
6090 | return result; |
6091 | } |
6092 | |
6093 | MDefinition* MMegamorphicLoadSlotByValuePermissive::foldsTo( |
6094 | TempAllocator& alloc) { |
6095 | MDefinition* input = idVal(); |
6096 | if (input->isBox()) { |
6097 | input = input->toBox()->input(); |
6098 | } |
6099 | |
6100 | MDefinition* result = this; |
6101 | |
6102 | if (input->isConstant()) { |
6103 | MConstant* constant = input->toConstant(); |
6104 | if (constant->type() == MIRType::Symbol) { |
6105 | PropertyKey id = PropertyKey::Symbol(constant->toSymbol()); |
6106 | result = MMegamorphicLoadSlotPermissive::New(alloc, object(), id); |
6107 | } |
6108 | |
6109 | if (constant->type() == MIRType::String) { |
6110 | JSString* str = constant->toString(); |
6111 | if (str->isAtom() && !str->asAtom().isIndex()) { |
6112 | PropertyKey id = PropertyKey::NonIntAtom(str); |
6113 | result = MMegamorphicLoadSlotPermissive::New(alloc, object(), id); |
6114 | } |
6115 | } |
6116 | } |
6117 | |
6118 | if (result != this) { |
6119 | result->toMegamorphicLoadSlotPermissive()->stealResumePoint(this); |
6120 | } |
6121 | |
6122 | return result; |
6123 | } |
6124 | |
6125 | bool MMegamorphicLoadSlot::congruentTo(const MDefinition* ins) const { |
6126 | if (!ins->isMegamorphicLoadSlot()) { |
6127 | return false; |
6128 | } |
6129 | if (ins->toMegamorphicLoadSlot()->name() != name()) { |
6130 | return false; |
6131 | } |
6132 | return congruentIfOperandsEqual(ins); |
6133 | } |
6134 | |
6135 | AliasSet MMegamorphicLoadSlot::getAliasSet() const { |
6136 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6137 | AliasSet::DynamicSlot); |
6138 | } |
6139 | |
6140 | bool MSmallObjectVariableKeyHasProp::congruentTo(const MDefinition* ins) const { |
6141 | if (!ins->isSmallObjectVariableKeyHasProp()) { |
6142 | return false; |
6143 | } |
6144 | if (ins->toSmallObjectVariableKeyHasProp()->shape() != shape()) { |
6145 | return false; |
6146 | } |
6147 | return congruentIfOperandsEqual(ins); |
6148 | } |
6149 | |
6150 | AliasSet MSmallObjectVariableKeyHasProp::getAliasSet() const { |
6151 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6152 | AliasSet::DynamicSlot); |
6153 | } |
6154 | |
6155 | bool MMegamorphicHasProp::congruentTo(const MDefinition* ins) const { |
6156 | if (!ins->isMegamorphicHasProp()) { |
6157 | return false; |
6158 | } |
6159 | if (ins->toMegamorphicHasProp()->hasOwn() != hasOwn()) { |
6160 | return false; |
6161 | } |
6162 | return congruentIfOperandsEqual(ins); |
6163 | } |
6164 | |
6165 | AliasSet MMegamorphicHasProp::getAliasSet() const { |
6166 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6167 | AliasSet::DynamicSlot); |
6168 | } |
6169 | |
6170 | bool MNurseryObject::congruentTo(const MDefinition* ins) const { |
6171 | if (!ins->isNurseryObject()) { |
6172 | return false; |
6173 | } |
6174 | return nurseryIndex() == ins->toNurseryObject()->nurseryIndex(); |
6175 | } |
6176 | |
6177 | AliasSet MGuardFunctionIsNonBuiltinCtor::getAliasSet() const { |
6178 | return AliasSet::Load(AliasSet::ObjectFields); |
6179 | } |
6180 | |
6181 | bool MGuardFunctionKind::congruentTo(const MDefinition* ins) const { |
6182 | if (!ins->isGuardFunctionKind()) { |
6183 | return false; |
6184 | } |
6185 | if (expected() != ins->toGuardFunctionKind()->expected()) { |
6186 | return false; |
6187 | } |
6188 | if (bailOnEquality() != ins->toGuardFunctionKind()->bailOnEquality()) { |
6189 | return false; |
6190 | } |
6191 | return congruentIfOperandsEqual(ins); |
6192 | } |
6193 | |
6194 | AliasSet MGuardFunctionKind::getAliasSet() const { |
6195 | return AliasSet::Load(AliasSet::ObjectFields); |
6196 | } |
6197 | |
6198 | bool MGuardFunctionScript::congruentTo(const MDefinition* ins) const { |
6199 | if (!ins->isGuardFunctionScript()) { |
6200 | return false; |
6201 | } |
6202 | if (expected() != ins->toGuardFunctionScript()->expected()) { |
6203 | return false; |
6204 | } |
6205 | return congruentIfOperandsEqual(ins); |
6206 | } |
6207 | |
6208 | AliasSet MGuardFunctionScript::getAliasSet() const { |
6209 | // A JSFunction's BaseScript pointer is immutable. Relazification of |
6210 | // top-level/named self-hosted functions is an exception to this, but we don't |
6211 | // use this guard for those self-hosted functions. |
6212 | // See IRGenerator::emitCalleeGuard. |
6213 | 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" , 6213); AnnotateMozCrashReason("MOZ_ASSERT" "(" "flags_.isLambda()" ")"); do { *((volatile int*)__null) = 6213; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
6214 | return AliasSet::None(); |
6215 | } |
6216 | |
6217 | bool MGuardSpecificAtom::congruentTo(const MDefinition* ins) const { |
6218 | if (!ins->isGuardSpecificAtom()) { |
6219 | return false; |
6220 | } |
6221 | if (atom() != ins->toGuardSpecificAtom()->atom()) { |
6222 | return false; |
6223 | } |
6224 | return congruentIfOperandsEqual(ins); |
6225 | } |
6226 | |
6227 | MDefinition* MGuardStringToIndex::foldsTo(TempAllocator& alloc) { |
6228 | if (!string()->isConstant()) { |
6229 | return this; |
6230 | } |
6231 | |
6232 | JSString* str = string()->toConstant()->toString(); |
6233 | |
6234 | int32_t index = GetIndexFromString(str); |
6235 | if (index < 0) { |
6236 | return this; |
6237 | } |
6238 | |
6239 | return MConstant::New(alloc, Int32Value(index)); |
6240 | } |
6241 | |
6242 | MDefinition* MGuardStringToInt32::foldsTo(TempAllocator& alloc) { |
6243 | if (!string()->isConstant()) { |
6244 | return this; |
6245 | } |
6246 | |
6247 | JSLinearString* str = &string()->toConstant()->toString()->asLinear(); |
6248 | double number = LinearStringToNumber(str); |
6249 | |
6250 | int32_t n; |
6251 | if (!mozilla::NumberIsInt32(number, &n)) { |
6252 | return this; |
6253 | } |
6254 | |
6255 | return MConstant::New(alloc, Int32Value(n)); |
6256 | } |
6257 | |
6258 | MDefinition* MGuardStringToDouble::foldsTo(TempAllocator& alloc) { |
6259 | if (!string()->isConstant()) { |
6260 | return this; |
6261 | } |
6262 | |
6263 | JSLinearString* str = &string()->toConstant()->toString()->asLinear(); |
6264 | double number = LinearStringToNumber(str); |
6265 | return MConstant::New(alloc, DoubleValue(number)); |
6266 | } |
6267 | |
6268 | AliasSet MGuardNoDenseElements::getAliasSet() const { |
6269 | return AliasSet::Load(AliasSet::ObjectFields); |
6270 | } |
6271 | |
6272 | AliasSet MIteratorHasIndices::getAliasSet() const { |
6273 | return AliasSet::Load(AliasSet::ObjectFields); |
6274 | } |
6275 | |
6276 | AliasSet MAllocateAndStoreSlot::getAliasSet() const { |
6277 | return AliasSet::Store(AliasSet::ObjectFields | AliasSet::DynamicSlot); |
6278 | } |
6279 | |
6280 | AliasSet MLoadDOMExpandoValue::getAliasSet() const { |
6281 | return AliasSet::Load(AliasSet::DOMProxyExpando); |
6282 | } |
6283 | |
6284 | AliasSet MLoadDOMExpandoValueIgnoreGeneration::getAliasSet() const { |
6285 | return AliasSet::Load(AliasSet::DOMProxyExpando); |
6286 | } |
6287 | |
6288 | bool MGuardDOMExpandoMissingOrGuardShape::congruentTo( |
6289 | const MDefinition* ins) const { |
6290 | if (!ins->isGuardDOMExpandoMissingOrGuardShape()) { |
6291 | return false; |
6292 | } |
6293 | if (shape() != ins->toGuardDOMExpandoMissingOrGuardShape()->shape()) { |
6294 | return false; |
6295 | } |
6296 | return congruentIfOperandsEqual(ins); |
6297 | } |
6298 | |
6299 | AliasSet MGuardDOMExpandoMissingOrGuardShape::getAliasSet() const { |
6300 | return AliasSet::Load(AliasSet::ObjectFields); |
6301 | } |
6302 | |
6303 | MDefinition* MGuardToClass::foldsTo(TempAllocator& alloc) { |
6304 | const JSClass* clasp = GetObjectKnownJSClass(object()); |
6305 | if (!clasp || getClass() != clasp) { |
6306 | return this; |
6307 | } |
6308 | |
6309 | AssertKnownClass(alloc, this, object()); |
6310 | return object(); |
6311 | } |
6312 | |
6313 | MDefinition* MGuardToEitherClass::foldsTo(TempAllocator& alloc) { |
6314 | const JSClass* clasp = GetObjectKnownJSClass(object()); |
6315 | if (!clasp || (getClass1() != clasp && getClass2() != clasp)) { |
6316 | return this; |
6317 | } |
6318 | |
6319 | AssertKnownClass(alloc, this, object()); |
6320 | return object(); |
6321 | } |
6322 | |
6323 | MDefinition* MGuardToFunction::foldsTo(TempAllocator& alloc) { |
6324 | if (GetObjectKnownClass(object()) != KnownClass::Function) { |
6325 | return this; |
6326 | } |
6327 | |
6328 | AssertKnownClass(alloc, this, object()); |
6329 | return object(); |
6330 | } |
6331 | |
6332 | MDefinition* MHasClass::foldsTo(TempAllocator& alloc) { |
6333 | const JSClass* clasp = GetObjectKnownJSClass(object()); |
6334 | if (!clasp) { |
6335 | return this; |
6336 | } |
6337 | |
6338 | AssertKnownClass(alloc, this, object()); |
6339 | return MConstant::New(alloc, BooleanValue(getClass() == clasp)); |
6340 | } |
6341 | |
6342 | MDefinition* MIsCallable::foldsTo(TempAllocator& alloc) { |
6343 | if (input()->type() != MIRType::Object) { |
6344 | return this; |
6345 | } |
6346 | |
6347 | KnownClass known = GetObjectKnownClass(input()); |
6348 | if (known == KnownClass::None) { |
6349 | return this; |
6350 | } |
6351 | |
6352 | AssertKnownClass(alloc, this, input()); |
6353 | return MConstant::New(alloc, BooleanValue(known == KnownClass::Function)); |
6354 | } |
6355 | |
6356 | MDefinition* MIsArray::foldsTo(TempAllocator& alloc) { |
6357 | if (input()->type() != MIRType::Object) { |
6358 | return this; |
6359 | } |
6360 | |
6361 | KnownClass known = GetObjectKnownClass(input()); |
6362 | if (known == KnownClass::None) { |
6363 | return this; |
6364 | } |
6365 | |
6366 | AssertKnownClass(alloc, this, input()); |
6367 | return MConstant::New(alloc, BooleanValue(known == KnownClass::Array)); |
6368 | } |
6369 | |
6370 | AliasSet MObjectClassToString::getAliasSet() const { |
6371 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6372 | AliasSet::DynamicSlot); |
6373 | } |
6374 | |
6375 | MDefinition* MGuardIsNotArrayBufferMaybeShared::foldsTo(TempAllocator& alloc) { |
6376 | switch (GetObjectKnownClass(object())) { |
6377 | case KnownClass::PlainObject: |
6378 | case KnownClass::Array: |
6379 | case KnownClass::Function: |
6380 | case KnownClass::RegExp: |
6381 | case KnownClass::ArrayIterator: |
6382 | case KnownClass::StringIterator: |
6383 | case KnownClass::RegExpStringIterator: { |
6384 | AssertKnownClass(alloc, this, object()); |
6385 | return object(); |
6386 | } |
6387 | case KnownClass::None: |
6388 | break; |
6389 | } |
6390 | |
6391 | return this; |
6392 | } |
6393 | |
6394 | MDefinition* MCheckIsObj::foldsTo(TempAllocator& alloc) { |
6395 | if (!input()->isBox()) { |
6396 | return this; |
6397 | } |
6398 | |
6399 | MDefinition* unboxed = input()->getOperand(0); |
6400 | if (unboxed->type() == MIRType::Object) { |
6401 | return unboxed; |
6402 | } |
6403 | |
6404 | return this; |
6405 | } |
6406 | |
6407 | AliasSet MCheckIsObj::getAliasSet() const { |
6408 | return AliasSet::Store(AliasSet::ExceptionState); |
6409 | } |
6410 | |
6411 | #ifdef JS_PUNBOX641 |
6412 | AliasSet MCheckScriptedProxyGetResult::getAliasSet() const { |
6413 | return AliasSet::Store(AliasSet::ExceptionState); |
6414 | } |
6415 | #endif |
6416 | |
6417 | static bool IsBoxedObject(MDefinition* def) { |
6418 | 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" , 6418); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::Value" ")"); do { *((volatile int*)__null) = 6418; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6419 | |
6420 | if (def->isBox()) { |
6421 | return def->toBox()->input()->type() == MIRType::Object; |
6422 | } |
6423 | |
6424 | // Construct calls are always returning a boxed object. |
6425 | // |
6426 | // TODO: We should consider encoding this directly in the graph instead of |
6427 | // having to special case it here. |
6428 | if (def->isCall()) { |
6429 | return def->toCall()->isConstructing(); |
6430 | } |
6431 | if (def->isConstructArray()) { |
6432 | return true; |
6433 | } |
6434 | if (def->isConstructArgs()) { |
6435 | return true; |
6436 | } |
6437 | |
6438 | return false; |
6439 | } |
6440 | |
6441 | MDefinition* MCheckReturn::foldsTo(TempAllocator& alloc) { |
6442 | auto* returnVal = returnValue(); |
6443 | if (!returnVal->isBox()) { |
6444 | return this; |
6445 | } |
6446 | |
6447 | auto* unboxedReturnVal = returnVal->toBox()->input(); |
6448 | if (unboxedReturnVal->type() == MIRType::Object) { |
6449 | return returnVal; |
6450 | } |
6451 | |
6452 | if (unboxedReturnVal->type() != MIRType::Undefined) { |
6453 | return this; |
6454 | } |
6455 | |
6456 | auto* thisVal = thisValue(); |
6457 | if (IsBoxedObject(thisVal)) { |
6458 | return thisVal; |
6459 | } |
6460 | |
6461 | return this; |
6462 | } |
6463 | |
6464 | MDefinition* MCheckThis::foldsTo(TempAllocator& alloc) { |
6465 | MDefinition* input = thisValue(); |
6466 | if (!input->isBox()) { |
6467 | return this; |
6468 | } |
6469 | |
6470 | MDefinition* unboxed = input->getOperand(0); |
6471 | if (unboxed->mightBeMagicType()) { |
6472 | return this; |
6473 | } |
6474 | |
6475 | return input; |
6476 | } |
6477 | |
6478 | MDefinition* MCheckThisReinit::foldsTo(TempAllocator& alloc) { |
6479 | MDefinition* input = thisValue(); |
6480 | if (!input->isBox()) { |
6481 | return this; |
6482 | } |
6483 | |
6484 | MDefinition* unboxed = input->getOperand(0); |
6485 | if (unboxed->type() != MIRType::MagicUninitializedLexical) { |
6486 | return this; |
6487 | } |
6488 | |
6489 | return input; |
6490 | } |
6491 | |
6492 | MDefinition* MCheckObjCoercible::foldsTo(TempAllocator& alloc) { |
6493 | MDefinition* input = checkValue(); |
6494 | if (!input->isBox()) { |
6495 | return this; |
6496 | } |
6497 | |
6498 | MDefinition* unboxed = input->getOperand(0); |
6499 | if (unboxed->mightBeType(MIRType::Null) || |
6500 | unboxed->mightBeType(MIRType::Undefined)) { |
6501 | return this; |
6502 | } |
6503 | |
6504 | return input; |
6505 | } |
6506 | |
6507 | AliasSet MCheckObjCoercible::getAliasSet() const { |
6508 | return AliasSet::Store(AliasSet::ExceptionState); |
6509 | } |
6510 | |
6511 | AliasSet MCheckReturn::getAliasSet() const { |
6512 | return AliasSet::Store(AliasSet::ExceptionState); |
6513 | } |
6514 | |
6515 | AliasSet MCheckThis::getAliasSet() const { |
6516 | return AliasSet::Store(AliasSet::ExceptionState); |
6517 | } |
6518 | |
6519 | AliasSet MCheckThisReinit::getAliasSet() const { |
6520 | return AliasSet::Store(AliasSet::ExceptionState); |
6521 | } |
6522 | |
6523 | AliasSet MIsPackedArray::getAliasSet() const { |
6524 | return AliasSet::Load(AliasSet::ObjectFields); |
6525 | } |
6526 | |
6527 | AliasSet MGuardArrayIsPacked::getAliasSet() const { |
6528 | return AliasSet::Load(AliasSet::ObjectFields); |
6529 | } |
6530 | |
6531 | AliasSet MSuperFunction::getAliasSet() const { |
6532 | return AliasSet::Load(AliasSet::ObjectFields); |
6533 | } |
6534 | |
6535 | AliasSet MInitHomeObject::getAliasSet() const { |
6536 | return AliasSet::Store(AliasSet::ObjectFields); |
6537 | } |
6538 | |
6539 | AliasSet MLoadWrapperTarget::getAliasSet() const { |
6540 | return AliasSet::Load(AliasSet::Any); |
6541 | } |
6542 | |
6543 | bool MLoadWrapperTarget::congruentTo(const MDefinition* ins) const { |
6544 | if (!ins->isLoadWrapperTarget()) { |
6545 | return false; |
6546 | } |
6547 | if (ins->toLoadWrapperTarget()->fallible() != fallible()) { |
6548 | return false; |
6549 | } |
6550 | return congruentIfOperandsEqual(ins); |
6551 | } |
6552 | |
6553 | AliasSet MGuardHasGetterSetter::getAliasSet() const { |
6554 | return AliasSet::Load(AliasSet::ObjectFields); |
6555 | } |
6556 | |
6557 | bool MGuardHasGetterSetter::congruentTo(const MDefinition* ins) const { |
6558 | if (!ins->isGuardHasGetterSetter()) { |
6559 | return false; |
6560 | } |
6561 | if (ins->toGuardHasGetterSetter()->propId() != propId()) { |
6562 | return false; |
6563 | } |
6564 | if (ins->toGuardHasGetterSetter()->getterSetter() != getterSetter()) { |
6565 | return false; |
6566 | } |
6567 | return congruentIfOperandsEqual(ins); |
6568 | } |
6569 | |
6570 | AliasSet MGuardIsExtensible::getAliasSet() const { |
6571 | return AliasSet::Load(AliasSet::ObjectFields); |
6572 | } |
6573 | |
6574 | AliasSet MGuardIndexIsNotDenseElement::getAliasSet() const { |
6575 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::Element); |
6576 | } |
6577 | |
6578 | AliasSet MGuardIndexIsValidUpdateOrAdd::getAliasSet() const { |
6579 | return AliasSet::Load(AliasSet::ObjectFields); |
6580 | } |
6581 | |
6582 | AliasSet MCallObjectHasSparseElement::getAliasSet() const { |
6583 | return AliasSet::Load(AliasSet::Element | AliasSet::ObjectFields | |
6584 | AliasSet::FixedSlot | AliasSet::DynamicSlot); |
6585 | } |
6586 | |
6587 | AliasSet MLoadSlotByIteratorIndex::getAliasSet() const { |
6588 | return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6589 | AliasSet::DynamicSlot | AliasSet::Element); |
6590 | } |
6591 | |
6592 | AliasSet MStoreSlotByIteratorIndex::getAliasSet() const { |
6593 | return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot | |
6594 | AliasSet::DynamicSlot | AliasSet::Element); |
6595 | } |
6596 | |
6597 | MDefinition* MGuardInt32IsNonNegative::foldsTo(TempAllocator& alloc) { |
6598 | 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" , 6598); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 6598; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6599 | |
6600 | MDefinition* input = index(); |
6601 | if (!input->isConstant() || input->toConstant()->toInt32() < 0) { |
6602 | return this; |
6603 | } |
6604 | return input; |
6605 | } |
6606 | |
6607 | MDefinition* MGuardInt32Range::foldsTo(TempAllocator& alloc) { |
6608 | 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" , 6608); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input()->type() == MIRType::Int32" ")"); do { *((volatile int*)__null) = 6608; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6609 | 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" , 6609); AnnotateMozCrashReason("MOZ_ASSERT" "(" "minimum() <= maximum()" ")"); do { *((volatile int*)__null) = 6609; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6610 | |
6611 | MDefinition* in = input(); |
6612 | if (!in->isConstant()) { |
6613 | return this; |
6614 | } |
6615 | int32_t cst = in->toConstant()->toInt32(); |
6616 | if (cst < minimum() || cst > maximum()) { |
6617 | return this; |
6618 | } |
6619 | return in; |
6620 | } |
6621 | |
6622 | MDefinition* MGuardNonGCThing::foldsTo(TempAllocator& alloc) { |
6623 | if (!input()->isBox()) { |
6624 | return this; |
6625 | } |
6626 | |
6627 | MDefinition* unboxed = input()->getOperand(0); |
6628 | if (!IsNonGCThing(unboxed->type())) { |
6629 | return this; |
6630 | } |
6631 | return input(); |
6632 | } |
6633 | |
6634 | AliasSet MSetObjectHasNonBigInt::getAliasSet() const { |
6635 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6636 | } |
6637 | |
6638 | AliasSet MSetObjectHasBigInt::getAliasSet() const { |
6639 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6640 | } |
6641 | |
6642 | AliasSet MSetObjectHasValue::getAliasSet() const { |
6643 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6644 | } |
6645 | |
6646 | AliasSet MSetObjectHasValueVMCall::getAliasSet() const { |
6647 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6648 | } |
6649 | |
6650 | AliasSet MSetObjectSize::getAliasSet() const { |
6651 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6652 | } |
6653 | |
6654 | AliasSet MMapObjectHasNonBigInt::getAliasSet() const { |
6655 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6656 | } |
6657 | |
6658 | AliasSet MMapObjectHasBigInt::getAliasSet() const { |
6659 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6660 | } |
6661 | |
6662 | AliasSet MMapObjectHasValue::getAliasSet() const { |
6663 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6664 | } |
6665 | |
6666 | AliasSet MMapObjectHasValueVMCall::getAliasSet() const { |
6667 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6668 | } |
6669 | |
6670 | AliasSet MMapObjectGetNonBigInt::getAliasSet() const { |
6671 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6672 | } |
6673 | |
6674 | AliasSet MMapObjectGetBigInt::getAliasSet() const { |
6675 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6676 | } |
6677 | |
6678 | AliasSet MMapObjectGetValue::getAliasSet() const { |
6679 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6680 | } |
6681 | |
6682 | AliasSet MMapObjectGetValueVMCall::getAliasSet() const { |
6683 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6684 | } |
6685 | |
6686 | AliasSet MMapObjectSize::getAliasSet() const { |
6687 | return AliasSet::Load(AliasSet::MapOrSetHashTable); |
6688 | } |
6689 | |
6690 | MBindFunction* MBindFunction::New(TempAllocator& alloc, MDefinition* target, |
6691 | uint32_t argc, JSObject* templateObj) { |
6692 | auto* ins = new (alloc) MBindFunction(templateObj); |
6693 | if (!ins->init(alloc, NumNonArgumentOperands + argc)) { |
6694 | return nullptr; |
6695 | } |
6696 | ins->initOperand(0, target); |
6697 | return ins; |
6698 | } |
6699 | |
6700 | MCreateInlinedArgumentsObject* MCreateInlinedArgumentsObject::New( |
6701 | TempAllocator& alloc, MDefinition* callObj, MDefinition* callee, |
6702 | MDefinitionVector& args, ArgumentsObject* templateObj) { |
6703 | MCreateInlinedArgumentsObject* ins = |
6704 | new (alloc) MCreateInlinedArgumentsObject(templateObj); |
6705 | |
6706 | uint32_t argc = args.length(); |
6707 | 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" , 6707); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 6707; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6708 | |
6709 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
6710 | return nullptr; |
6711 | } |
6712 | |
6713 | ins->initOperand(0, callObj); |
6714 | ins->initOperand(1, callee); |
6715 | for (uint32_t i = 0; i < argc; i++) { |
6716 | ins->initOperand(i + NumNonArgumentOperands, args[i]); |
6717 | } |
6718 | |
6719 | return ins; |
6720 | } |
6721 | |
6722 | MGetInlinedArgument* MGetInlinedArgument::New( |
6723 | TempAllocator& alloc, MDefinition* index, |
6724 | MCreateInlinedArgumentsObject* args) { |
6725 | MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument(); |
6726 | |
6727 | uint32_t argc = args->numActuals(); |
6728 | 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" , 6728); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 6728; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6729 | |
6730 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
6731 | return nullptr; |
6732 | } |
6733 | |
6734 | ins->initOperand(0, index); |
6735 | for (uint32_t i = 0; i < argc; i++) { |
6736 | ins->initOperand(i + NumNonArgumentOperands, args->getArg(i)); |
6737 | } |
6738 | |
6739 | return ins; |
6740 | } |
6741 | |
6742 | MGetInlinedArgument* MGetInlinedArgument::New(TempAllocator& alloc, |
6743 | MDefinition* index, |
6744 | const CallInfo& callInfo) { |
6745 | MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument(); |
6746 | |
6747 | uint32_t argc = callInfo.argc(); |
6748 | 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" , 6748); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 6748; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6749 | |
6750 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
6751 | return nullptr; |
6752 | } |
6753 | |
6754 | ins->initOperand(0, index); |
6755 | for (uint32_t i = 0; i < argc; i++) { |
6756 | ins->initOperand(i + NumNonArgumentOperands, callInfo.getArg(i)); |
6757 | } |
6758 | |
6759 | return ins; |
6760 | } |
6761 | |
6762 | MDefinition* MGetInlinedArgument::foldsTo(TempAllocator& alloc) { |
6763 | MDefinition* indexDef = SkipUninterestingInstructions(index()); |
6764 | if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) { |
6765 | return this; |
6766 | } |
6767 | |
6768 | int32_t indexConst = indexDef->toConstant()->toInt32(); |
6769 | if (indexConst < 0 || uint32_t(indexConst) >= numActuals()) { |
6770 | return this; |
6771 | } |
6772 | |
6773 | MDefinition* arg = getArg(indexConst); |
6774 | if (arg->type() != MIRType::Value) { |
6775 | arg = MBox::New(alloc, arg); |
6776 | } |
6777 | |
6778 | return arg; |
6779 | } |
6780 | |
6781 | MGetInlinedArgumentHole* MGetInlinedArgumentHole::New( |
6782 | TempAllocator& alloc, MDefinition* index, |
6783 | MCreateInlinedArgumentsObject* args) { |
6784 | auto* ins = new (alloc) MGetInlinedArgumentHole(); |
6785 | |
6786 | uint32_t argc = args->numActuals(); |
6787 | 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" , 6787); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 6787; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6788 | |
6789 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
6790 | return nullptr; |
6791 | } |
6792 | |
6793 | ins->initOperand(0, index); |
6794 | for (uint32_t i = 0; i < argc; i++) { |
6795 | ins->initOperand(i + NumNonArgumentOperands, args->getArg(i)); |
6796 | } |
6797 | |
6798 | return ins; |
6799 | } |
6800 | |
6801 | MDefinition* MGetInlinedArgumentHole::foldsTo(TempAllocator& alloc) { |
6802 | MDefinition* indexDef = SkipUninterestingInstructions(index()); |
6803 | if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) { |
6804 | return this; |
6805 | } |
6806 | |
6807 | int32_t indexConst = indexDef->toConstant()->toInt32(); |
6808 | if (indexConst < 0) { |
6809 | return this; |
6810 | } |
6811 | |
6812 | MDefinition* arg; |
6813 | if (uint32_t(indexConst) < numActuals()) { |
6814 | arg = getArg(indexConst); |
6815 | |
6816 | if (arg->type() != MIRType::Value) { |
6817 | arg = MBox::New(alloc, arg); |
6818 | } |
6819 | } else { |
6820 | auto* undefined = MConstant::New(alloc, UndefinedValue()); |
6821 | block()->insertBefore(this, undefined); |
6822 | |
6823 | arg = MBox::New(alloc, undefined); |
6824 | } |
6825 | |
6826 | return arg; |
6827 | } |
6828 | |
6829 | MInlineArgumentsSlice* MInlineArgumentsSlice::New( |
6830 | TempAllocator& alloc, MDefinition* begin, MDefinition* count, |
6831 | MCreateInlinedArgumentsObject* args, JSObject* templateObj, |
6832 | gc::Heap initialHeap) { |
6833 | auto* ins = new (alloc) MInlineArgumentsSlice(templateObj, initialHeap); |
6834 | |
6835 | uint32_t argc = args->numActuals(); |
6836 | 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" , 6836); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs" ")"); do { *((volatile int*)__null) = 6836; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6837 | |
6838 | if (!ins->init(alloc, argc + NumNonArgumentOperands)) { |
6839 | return nullptr; |
6840 | } |
6841 | |
6842 | ins->initOperand(0, begin); |
6843 | ins->initOperand(1, count); |
6844 | for (uint32_t i = 0; i < argc; i++) { |
6845 | ins->initOperand(i + NumNonArgumentOperands, args->getArg(i)); |
6846 | } |
6847 | |
6848 | return ins; |
6849 | } |
6850 | |
6851 | MDefinition* MArrayLength::foldsTo(TempAllocator& alloc) { |
6852 | // Object.keys() is potentially effectful, in case of Proxies. Otherwise, when |
6853 | // it is only computed for its length property, there is no need to |
6854 | // materialize the Array which results from it and it can be marked as |
6855 | // recovered on bailout as long as no properties are added to / removed from |
6856 | // the object. |
6857 | MDefinition* elems = elements(); |
6858 | if (!elems->isElements()) { |
6859 | return this; |
6860 | } |
6861 | |
6862 | MDefinition* guardshape = elems->toElements()->object(); |
6863 | if (!guardshape->isGuardShape()) { |
6864 | return this; |
6865 | } |
6866 | |
6867 | // The Guard shape is guarding the shape of the object returned by |
6868 | // Object.keys, this guard can be removed as knowing the function is good |
6869 | // enough to infer that we are returning an array. |
6870 | MDefinition* keys = guardshape->toGuardShape()->object(); |
6871 | if (!keys->isObjectKeys()) { |
6872 | return this; |
6873 | } |
6874 | |
6875 | // Object.keys() inline cache guards against proxies when creating the IC. We |
6876 | // rely on this here as we are looking to elide `Object.keys(...)` call, which |
6877 | // is only possible if we know for sure that no side-effect might have |
6878 | // happened. |
6879 | MDefinition* noproxy = keys->toObjectKeys()->object(); |
6880 | if (!noproxy->isGuardIsNotProxy()) { |
6881 | // The guard might have been replaced by an assertion, in case the class is |
6882 | // known at compile time. IF the guard has been removed check whether check |
6883 | // has been removed. |
6884 | 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" , 6884); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "GetObjectKnownClass(noproxy) != KnownClass::None" ")"); do { *((volatile int*)__null) = 6884; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6885 | 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" , 6885); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!GetObjectKnownJSClass(noproxy)->isProxyObject()" ")"); do { *((volatile int*)__null) = 6885; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6886 | } |
6887 | |
6888 | // Check if both the elements and the Object.keys() have a single use. We only |
6889 | // check for live uses, and are ok if a branch which was previously using the |
6890 | // keys array has been removed since. |
6891 | if (!elems->hasOneLiveDefUse() || !guardshape->hasOneLiveDefUse() || |
6892 | !keys->hasOneLiveDefUse()) { |
6893 | return this; |
6894 | } |
6895 | |
6896 | // Check that the latest active resume point is the one from Object.keys(), in |
6897 | // order to steal it. If this is not the latest active resume point then some |
6898 | // side-effect might happen which updates the content of the object, making |
6899 | // any recovery of the keys exhibit a different behavior than expected. |
6900 | if (keys->toObjectKeys()->resumePoint() != block()->activeResumePoint(this)) { |
6901 | return this; |
6902 | } |
6903 | |
6904 | // Verify whether any resume point captures the keys array after any aliasing |
6905 | // mutations. If this were to be the case the recovery of ObjectKeys on |
6906 | // bailout might compute a version which might not match with the elided |
6907 | // result. |
6908 | // |
6909 | // Iterate over the resume point uses of ObjectKeys, and check whether the |
6910 | // instructions they are attached to are aliasing Object fields. If so, skip |
6911 | // this optimization. |
6912 | AliasSet enumKeysAliasSet = AliasSet::Load(AliasSet::Flag::ObjectFields); |
6913 | for (auto* use : UsesIterator(keys)) { |
6914 | if (!use->consumer()->isResumePoint()) { |
6915 | // There is only a single use, and this is the length computation as |
6916 | // asserted with `hasOneLiveDefUse`. |
6917 | continue; |
6918 | } |
6919 | |
6920 | MResumePoint* rp = use->consumer()->toResumePoint(); |
6921 | if (!rp->instruction()) { |
6922 | // If there is no instruction, this is a resume point which is attached to |
6923 | // the entry of a block. Thus no risk of mutating the object on which the |
6924 | // keys are queried. |
6925 | continue; |
6926 | } |
6927 | |
6928 | MInstruction* ins = rp->instruction(); |
6929 | if (ins == keys) { |
6930 | continue; |
6931 | } |
6932 | |
6933 | // Check whether the instruction can potentially alias the object fields of |
6934 | // the object from which we are querying the keys. |
6935 | AliasSet mightAlias = ins->getAliasSet() & enumKeysAliasSet; |
6936 | if (!mightAlias.isNone()) { |
6937 | return this; |
6938 | } |
6939 | } |
6940 | |
6941 | // Flag every instructions since Object.keys(..) as recovered on bailout, and |
6942 | // make Object.keys(..) be the recovered value in-place of the shape guard. |
6943 | setRecoveredOnBailout(); |
6944 | elems->setRecoveredOnBailout(); |
6945 | guardshape->replaceAllUsesWith(keys); |
6946 | guardshape->block()->discard(guardshape->toGuardShape()); |
6947 | keys->setRecoveredOnBailout(); |
6948 | |
6949 | // Steal the resume point from Object.keys, which is ok as we confirmed that |
6950 | // there is no other resume point in-between. |
6951 | MObjectKeysLength* keysLength = MObjectKeysLength::New(alloc, noproxy); |
6952 | keysLength->stealResumePoint(keys->toObjectKeys()); |
6953 | |
6954 | return keysLength; |
6955 | } |
6956 | |
6957 | MDefinition* MNormalizeSliceTerm::foldsTo(TempAllocator& alloc) { |
6958 | auto* length = this->length(); |
6959 | if (!length->isConstant() && !length->isArgumentsLength()) { |
6960 | return this; |
6961 | } |
6962 | |
6963 | if (length->isConstant()) { |
6964 | int32_t lengthConst = length->toConstant()->toInt32(); |
6965 | 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" , 6965); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lengthConst >= 0" ")"); do { *((volatile int*)__null) = 6965; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6966 | |
6967 | // Result is always zero when |length| is zero. |
6968 | if (lengthConst == 0) { |
6969 | return length; |
6970 | } |
6971 | |
6972 | auto* value = this->value(); |
6973 | if (value->isConstant()) { |
6974 | int32_t valueConst = value->toConstant()->toInt32(); |
6975 | |
6976 | int32_t normalized; |
6977 | if (valueConst < 0) { |
6978 | normalized = std::max(valueConst + lengthConst, 0); |
6979 | } else { |
6980 | normalized = std::min(valueConst, lengthConst); |
6981 | } |
6982 | |
6983 | if (normalized == valueConst) { |
6984 | return value; |
6985 | } |
6986 | if (normalized == lengthConst) { |
6987 | return length; |
6988 | } |
6989 | return MConstant::New(alloc, Int32Value(normalized)); |
6990 | } |
6991 | |
6992 | return this; |
6993 | } |
6994 | |
6995 | auto* value = this->value(); |
6996 | if (value->isConstant()) { |
6997 | int32_t valueConst = value->toConstant()->toInt32(); |
6998 | |
6999 | // Minimum of |value| and |length|. |
7000 | if (valueConst > 0) { |
7001 | bool isMax = false; |
7002 | return MMinMax::New(alloc, value, length, MIRType::Int32, isMax); |
7003 | } |
7004 | |
7005 | // Maximum of |value + length| and zero. |
7006 | if (valueConst < 0) { |
7007 | // Safe to truncate because |length| is never negative. |
7008 | auto* add = MAdd::New(alloc, value, length, TruncateKind::Truncate); |
7009 | block()->insertBefore(this, add); |
7010 | |
7011 | auto* zero = MConstant::New(alloc, Int32Value(0)); |
7012 | block()->insertBefore(this, zero); |
7013 | |
7014 | bool isMax = true; |
7015 | return MMinMax::New(alloc, add, zero, MIRType::Int32, isMax); |
7016 | } |
7017 | |
7018 | // Directly return the value when it's zero. |
7019 | return value; |
7020 | } |
7021 | |
7022 | // Normalizing MArgumentsLength is a no-op. |
7023 | if (value->isArgumentsLength()) { |
7024 | return value; |
7025 | } |
7026 | |
7027 | return this; |
7028 | } |
7029 | |
7030 | bool MInt32ToStringWithBase::congruentTo(const MDefinition* ins) const { |
7031 | if (!ins->isInt32ToStringWithBase()) { |
7032 | return false; |
7033 | } |
7034 | if (ins->toInt32ToStringWithBase()->lowerCase() != lowerCase()) { |
7035 | return false; |
7036 | } |
7037 | return congruentIfOperandsEqual(ins); |
7038 | } |