Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp
Warning:line 1486, column 15
Value stored to 'name' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_js_src_jit8.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D WASM_SUPPORTS_HUGE_MEMORY -D JS_CACHEIR_SPEW -D JS_STRUCTURED_SPEW -D JS_HAS_CTYPES -D FFI_BUILDING -D EXPORT_JS_API -D MOZ_HAS_MOZGLUE -D MOZ_SUPPORT_LEAKCHECKING -I /var/lib/jenkins/workspace/firefox-scan-build/js/src/jit -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src -I /var/lib/jenkins/workspace/firefox-scan-build/js/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-09-22-115206-3586786-1 -x c++ Unified_cpp_js_src_jit8.cpp
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "jit/MIR.h"
8
9#include "mozilla/EndianUtils.h"
10#include "mozilla/FloatingPoint.h"
11#include "mozilla/MathAlgorithms.h"
12#include "mozilla/Maybe.h"
13#include "mozilla/ScopeExit.h"
14
15#include <array>
16#include <utility>
17
18#include "jslibmath.h"
19#include "jsmath.h"
20#include "jsnum.h"
21
22#include "builtin/RegExp.h"
23#include "jit/AtomicOperations.h"
24#include "jit/CompileInfo.h"
25#include "jit/KnownClass.h"
26#include "jit/MIR-wasm.h"
27#include "jit/MIRGraph.h"
28#include "jit/RangeAnalysis.h"
29#include "jit/VMFunctions.h"
30#include "jit/WarpBuilderShared.h"
31#include "js/Conversions.h"
32#include "js/experimental/JitInfo.h" // JSJitInfo, JSTypedMethodJitInfo
33#include "js/ScalarType.h" // js::Scalar::Type
34#include "util/Text.h"
35#include "util/Unicode.h"
36#include "vm/BigIntType.h"
37#include "vm/Float16.h"
38#include "vm/Iteration.h" // js::NativeIterator
39#include "vm/PlainObject.h" // js::PlainObject
40#include "vm/Uint8Clamped.h"
41
42#include "vm/BytecodeUtil-inl.h"
43#include "vm/JSAtomUtils-inl.h" // TypeName
44
45using namespace js;
46using namespace js::jit;
47
48using JS::ToInt32;
49
50using mozilla::IsFloat32Representable;
51using mozilla::IsPowerOfTwo;
52using mozilla::NumbersAreIdentical;
53
54NON_GC_POINTER_TYPE_ASSERTIONS_GENERATEDstatic_assert(!std::is_base_of_v<gc::Cell, BuiltinObjectKind
>, "Ensure that BuiltinObjectKind is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, FunctionFlags
>, "Ensure that FunctionFlags is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, FunctionFlags
::FunctionKind>, "Ensure that FunctionFlags::FunctionKind is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, MemoryBarrierRequirement
>, "Ensure that MemoryBarrierRequirement is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, PropertyKey>
, "Ensure that PropertyKey is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, RealmFuses::FuseIndex
>, "Ensure that RealmFuses::FuseIndex is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, SimdShuffle>
, "Ensure that SimdShuffle is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, bool>, "Ensure that bool is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, const void>
, "Ensure that const void is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, gc::Heap>,
"Ensure that gc::Heap is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, int32_t>, "Ensure that int32_t is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, jsid>, "Ensure that jsid is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, size_t>, "Ensure that size_t is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, uint16_t>,
"Ensure that uint16_t is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, uint32_t>,
"Ensure that uint32_t is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, uint8_t>, "Ensure that uint8_t is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, unsigned>,
"Ensure that unsigned is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, wasm::BytecodeOffset
>, "Ensure that wasm::BytecodeOffset is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, wasm::FieldWideningOp
>, "Ensure that wasm::FieldWideningOp is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, wasm::SimdOp>
, "Ensure that wasm::SimdOp is added to the gc_pointer_types list in GenerateMIRFiles.py."
);static_assert(!std::is_base_of_v<gc::Cell, wasm::Trap>
, "Ensure that wasm::Trap is added to the gc_pointer_types list in GenerateMIRFiles.py."
);
55
56#ifdef DEBUG1
57size_t MUse::index() const { return consumer()->indexOf(this); }
58#endif
59
60template <size_t Op>
61static void ConvertDefinitionToDouble(TempAllocator& alloc, MDefinition* def,
62 MInstruction* consumer) {
63 MInstruction* replace = MToDouble::New(alloc, def);
64 consumer->replaceOperand(Op, replace);
65 consumer->block()->insertBefore(consumer, replace);
66}
67
68template <size_t Arity, size_t Index>
69static void ConvertOperandToDouble(MAryInstruction<Arity>* def,
70 TempAllocator& alloc) {
71 static_assert(Index < Arity);
72 auto* operand = def->getOperand(Index);
73 if (operand->type() == MIRType::Float32) {
74 ConvertDefinitionToDouble<Index>(alloc, operand, def);
75 }
76}
77
78template <size_t Arity, size_t... ISeq>
79static void ConvertOperandsToDouble(MAryInstruction<Arity>* def,
80 TempAllocator& alloc,
81 std::index_sequence<ISeq...>) {
82 (ConvertOperandToDouble<Arity, ISeq>(def, alloc), ...);
83}
84
85template <size_t Arity>
86static void ConvertOperandsToDouble(MAryInstruction<Arity>* def,
87 TempAllocator& alloc) {
88 ConvertOperandsToDouble<Arity>(def, alloc, std::make_index_sequence<Arity>{});
89}
90
91template <size_t Arity, size_t... ISeq>
92static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def,
93 std::index_sequence<ISeq...>) {
94 return (def->getOperand(ISeq)->canProduceFloat32() && ...);
95}
96
97template <size_t Arity>
98static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def) {
99 return AllOperandsCanProduceFloat32<Arity>(def,
100 std::make_index_sequence<Arity>{});
101}
102
103static bool CheckUsesAreFloat32Consumers(const MInstruction* ins) {
104 if (ins->isImplicitlyUsed()) {
105 return false;
106 }
107 bool allConsumerUses = true;
108 for (MUseDefIterator use(ins); allConsumerUses && use; use++) {
109 allConsumerUses &= use.def()->canConsumeFloat32(use.use());
110 }
111 return allConsumerUses;
112}
113
114#ifdef JS_JITSPEW1
115static const char* OpcodeName(MDefinition::Opcode op) {
116 static const char* const names[] = {
117# define NAME(x) #x,
118 MIR_OPCODE_LIST(NAME)NAME(Start)NAME(OsrEntry)NAME(Nop)NAME(LimitedTruncate)NAME(Constant
)NAME(WasmNullConstant)NAME(WasmFloatConstant)NAME(Parameter)
NAME(Callee)NAME(IsConstructing)NAME(TableSwitch)NAME(Goto)NAME
(Test)NAME(Return)NAME(Throw)NAME(ThrowWithStack)NAME(NewArray
)NAME(NewArrayDynamicLength)NAME(NewTypedArray)NAME(NewTypedArrayDynamicLength
)NAME(NewTypedArrayFromArray)NAME(NewTypedArrayFromArrayBuffer
)NAME(NewObject)NAME(NewPlainObject)NAME(NewArrayObject)NAME(
NewIterator)NAME(ObjectState)NAME(ArrayState)NAME(BindFunction
)NAME(NewBoundFunction)NAME(BoundFunctionNumArgs)NAME(GuardBoundFunctionIsConstructor
)NAME(MutateProto)NAME(InitPropGetterSetter)NAME(InitElemGetterSetter
)NAME(Call)NAME(CallClassHook)NAME(ApplyArgs)NAME(ApplyArgsObj
)NAME(ApplyArray)NAME(ConstructArgs)NAME(ConstructArray)NAME(
Bail)NAME(Unreachable)NAME(EncodeSnapshot)NAME(AssertRecoveredOnBailout
)NAME(AssertFloat32)NAME(Compare)NAME(SameValueDouble)NAME(SameValue
)NAME(Box)NAME(Unbox)NAME(AssertRange)NAME(AssertClass)NAME(AssertShape
)NAME(CreateThis)NAME(CreateArgumentsObject)NAME(CreateInlinedArgumentsObject
)NAME(GetInlinedArgument)NAME(GetInlinedArgumentHole)NAME(GetArgumentsObjectArg
)NAME(SetArgumentsObjectArg)NAME(LoadArgumentsObjectArg)NAME(
LoadArgumentsObjectArgHole)NAME(InArgumentsObjectArg)NAME(ArgumentsObjectLength
)NAME(ArrayFromArgumentsObject)NAME(GuardArgumentsObjectFlags
)NAME(LoadScriptedProxyHandler)NAME(CheckScriptedProxyGetResult
)NAME(IdToStringOrSymbol)NAME(ReturnFromCtor)NAME(ToDouble)NAME
(ToFloat32)NAME(ToFloat16)NAME(WasmUnsignedToDouble)NAME(WasmUnsignedToFloat32
)NAME(WrapInt64ToInt32)NAME(ExtendInt32ToInt64)NAME(WasmBuiltinTruncateToInt64
)NAME(WasmTruncateToInt64)NAME(WasmTruncateToInt32)NAME(WasmAnyRefFromJSValue
)NAME(WasmAnyRefFromJSObject)NAME(WasmAnyRefFromJSString)NAME
(WasmAnyRefIsJSString)NAME(WasmTrapIfAnyRefIsNotJSString)NAME
(WasmNewI31Ref)NAME(WasmI31RefGet)NAME(Int32ToIntPtr)NAME(NonNegativeIntPtrToInt32
)NAME(IntPtrToDouble)NAME(AdjustDataViewLength)NAME(Int64ToFloatingPoint
)NAME(BuiltinInt64ToFloatingPoint)NAME(ToNumberInt32)NAME(BooleanToInt32
)NAME(TruncateToInt32)NAME(WasmBuiltinTruncateToInt32)NAME(ToBigInt
)NAME(ToInt64)NAME(TruncateBigIntToInt64)NAME(Int32ToBigInt)NAME
(Int64ToBigInt)NAME(Int64ToIntPtr)NAME(IntPtrToInt64)NAME(ToString
)NAME(BitNot)NAME(TypeOf)NAME(TypeOfName)NAME(TypeOfIs)NAME(ToAsyncIter
)NAME(ToPropertyKeyCache)NAME(BitAnd)NAME(BitOr)NAME(BitXor)NAME
(Lsh)NAME(Rsh)NAME(Ursh)NAME(SignExtendInt32)NAME(SignExtendInt64
)NAME(MinMax)NAME(MinMaxArray)NAME(Abs)NAME(Clz)NAME(Ctz)NAME
(Popcnt)NAME(Sqrt)NAME(CopySign)NAME(Atan2)NAME(Hypot)NAME(Pow
)NAME(PowHalf)NAME(Random)NAME(Sign)NAME(MathFunction)NAME(Add
)NAME(Sub)NAME(Mul)NAME(Div)NAME(WasmBuiltinDivI64)NAME(Mod)NAME
(WasmBuiltinModD)NAME(WasmBuiltinModI64)NAME(BigIntAdd)NAME(BigIntSub
)NAME(BigIntMul)NAME(BigIntDiv)NAME(BigIntMod)NAME(BigIntPow)
NAME(BigIntBitAnd)NAME(BigIntBitOr)NAME(BigIntBitXor)NAME(BigIntLsh
)NAME(BigIntRsh)NAME(BigIntIncrement)NAME(BigIntDecrement)NAME
(BigIntNegate)NAME(BigIntBitNot)NAME(BigIntToIntPtr)NAME(IntPtrToBigInt
)NAME(BigIntPtrAdd)NAME(BigIntPtrSub)NAME(BigIntPtrMul)NAME(BigIntPtrDiv
)NAME(BigIntPtrMod)NAME(BigIntPtrPow)NAME(BigIntPtrBitAnd)NAME
(BigIntPtrBitOr)NAME(BigIntPtrBitXor)NAME(BigIntPtrLsh)NAME(BigIntPtrRsh
)NAME(BigIntPtrBitNot)NAME(Int32ToStringWithBase)NAME(NumberParseInt
)NAME(DoubleParseInt)NAME(Concat)NAME(LinearizeString)NAME(LinearizeForCharAccess
)NAME(LinearizeForCodePointAccess)NAME(ToRelativeStringIndex)
NAME(CharCodeAt)NAME(CharCodeAtOrNegative)NAME(CodePointAt)NAME
(CodePointAtOrNegative)NAME(NegativeToNaN)NAME(NegativeToUndefined
)NAME(FromCharCode)NAME(FromCharCodeEmptyIfNegative)NAME(FromCharCodeUndefinedIfNegative
)NAME(FromCodePoint)NAME(StringIncludes)NAME(StringIndexOf)NAME
(StringLastIndexOf)NAME(StringStartsWith)NAME(StringEndsWith)
NAME(StringConvertCase)NAME(CharCodeConvertCase)NAME(StringTrimStartIndex
)NAME(StringTrimEndIndex)NAME(StringSplit)NAME(BoxNonStrictThis
)NAME(ImplicitThis)NAME(Phi)NAME(Beta)NAME(NaNToZero)NAME(OsrValue
)NAME(OsrEnvironmentChain)NAME(OsrArgumentsObject)NAME(OsrReturnValue
)NAME(BinaryCache)NAME(UnaryCache)NAME(CheckOverRecursed)NAME
(InterruptCheck)NAME(WasmInterruptCheck)NAME(WasmTrap)NAME(WasmTrapIfNull
)NAME(LexicalCheck)NAME(ThrowRuntimeLexicalError)NAME(ThrowMsg
)NAME(GlobalDeclInstantiation)NAME(RegExp)NAME(RegExpMatcher)
NAME(RegExpSearcher)NAME(RegExpSearcherLastLimit)NAME(RegExpExecMatch
)NAME(RegExpExecTest)NAME(RegExpHasCaptureGroups)NAME(RegExpPrototypeOptimizable
)NAME(RegExpInstanceOptimizable)NAME(GetFirstDollarIndex)NAME
(StringReplace)NAME(Substr)NAME(ModuleMetadata)NAME(DynamicImport
)NAME(Lambda)NAME(FunctionWithProto)NAME(SetFunName)NAME(Slots
)NAME(Elements)NAME(InitializedLength)NAME(SetInitializedLength
)NAME(ArrayLength)NAME(SetArrayLength)NAME(FunctionLength)NAME
(FunctionName)NAME(GetNextEntryForIterator)NAME(ArrayBufferByteLength
)NAME(ArrayBufferViewLength)NAME(ArrayBufferViewByteOffset)NAME
(ArrayBufferViewElements)NAME(ResizableTypedArrayByteOffsetMaybeOutOfBounds
)NAME(ResizableTypedArrayLength)NAME(ResizableDataViewByteLength
)NAME(GrowableSharedArrayBufferByteLength)NAME(TypedArrayElementSize
)NAME(GuardHasAttachedArrayBuffer)NAME(GuardResizableArrayBufferViewInBounds
)NAME(GuardResizableArrayBufferViewInBoundsOrDetached)NAME(GuardNumberToIntPtrIndex
)NAME(KeepAliveObject)NAME(DebugEnterGCUnsafeRegion)NAME(DebugLeaveGCUnsafeRegion
)NAME(Not)NAME(BoundsCheck)NAME(BoundsCheckLower)NAME(SpectreMaskIndex
)NAME(LoadElement)NAME(LoadElementAndUnbox)NAME(LoadElementHole
)NAME(StoreElement)NAME(StoreHoleValueElement)NAME(StoreElementHole
)NAME(ArrayPopShift)NAME(ArrayPush)NAME(ArraySlice)NAME(ArgumentsSlice
)NAME(FrameArgumentsSlice)NAME(InlineArgumentsSlice)NAME(NormalizeSliceTerm
)NAME(ArrayJoin)NAME(ObjectKeys)NAME(ObjectKeysLength)NAME(LoadUnboxedScalar
)NAME(LoadDataViewElement)NAME(LoadTypedArrayElementHole)NAME
(StoreUnboxedScalar)NAME(StoreDataViewElement)NAME(StoreTypedArrayElementHole
)NAME(EffectiveAddress)NAME(ClampToUint8)NAME(LoadFixedSlot)NAME
(LoadFixedSlotAndUnbox)NAME(LoadDynamicSlotAndUnbox)NAME(StoreFixedSlot
)NAME(GetPropertyCache)NAME(HomeObjectSuperBase)NAME(GetPropSuperCache
)NAME(BindNameCache)NAME(CallBindVar)NAME(GuardShape)NAME(GuardFuse
)NAME(GuardMultipleShapes)NAME(GuardProto)NAME(GuardNullProto
)NAME(GuardIsNativeObject)NAME(GuardGlobalGeneration)NAME(GuardIsProxy
)NAME(GuardIsNotDOMProxy)NAME(GuardIsNotProxy)NAME(ProxyGet)NAME
(ProxyGetByValue)NAME(ProxyHasProp)NAME(ProxySet)NAME(ProxySetByValue
)NAME(CallSetArrayLength)NAME(MegamorphicLoadSlot)NAME(MegamorphicLoadSlotPermissive
)NAME(MegamorphicLoadSlotByValue)NAME(MegamorphicLoadSlotByValuePermissive
)NAME(MegamorphicStoreSlot)NAME(MegamorphicHasProp)NAME(SmallObjectVariableKeyHasProp
)NAME(GuardIsNotArrayBufferMaybeShared)NAME(GuardIsTypedArray
)NAME(GuardIsFixedLengthTypedArray)NAME(GuardIsResizableTypedArray
)NAME(GuardHasProxyHandler)NAME(NurseryObject)NAME(GuardValue
)NAME(GuardNullOrUndefined)NAME(GuardIsNotObject)NAME(GuardFunctionFlags
)NAME(GuardFunctionIsNonBuiltinCtor)NAME(GuardFunctionKind)NAME
(GuardFunctionScript)NAME(GuardObjectIdentity)NAME(GuardSpecificFunction
)NAME(GuardSpecificAtom)NAME(GuardSpecificSymbol)NAME(GuardSpecificInt32
)NAME(GuardStringToIndex)NAME(GuardStringToInt32)NAME(GuardStringToDouble
)NAME(GuardNoDenseElements)NAME(GuardTagNotEqual)NAME(LoadDynamicSlot
)NAME(FunctionEnvironment)NAME(NewLexicalEnvironmentObject)NAME
(NewClassBodyEnvironmentObject)NAME(NewVarEnvironmentObject)NAME
(HomeObject)NAME(AddAndStoreSlot)NAME(AllocateAndStoreSlot)NAME
(AddSlotAndCallAddPropHook)NAME(StoreDynamicSlot)NAME(GetNameCache
)NAME(CallGetIntrinsicValue)NAME(DeleteProperty)NAME(DeleteElement
)NAME(SetPropertyCache)NAME(MegamorphicSetElement)NAME(SetDOMProperty
)NAME(GetDOMProperty)NAME(GetDOMMember)NAME(ObjectToIterator)
NAME(ValueToIterator)NAME(IteratorHasIndices)NAME(LoadSlotByIteratorIndex
)NAME(StoreSlotByIteratorIndex)NAME(LoadDOMExpandoValue)NAME(
LoadDOMExpandoValueGuardGeneration)NAME(LoadDOMExpandoValueIgnoreGeneration
)NAME(GuardDOMExpandoMissingOrGuardShape)NAME(StringLength)NAME
(Floor)NAME(Ceil)NAME(Round)NAME(Trunc)NAME(NearbyInt)NAME(GetIteratorCache
)NAME(OptimizeSpreadCallCache)NAME(IteratorMore)NAME(IsNoIter
)NAME(IteratorEnd)NAME(CloseIterCache)NAME(OptimizeGetIteratorCache
)NAME(InCache)NAME(InArray)NAME(GuardElementNotHole)NAME(NewPrivateName
)NAME(CheckPrivateFieldCache)NAME(HasOwnCache)NAME(InstanceOf
)NAME(InstanceOfCache)NAME(ArgumentsLength)NAME(GetFrameArgument
)NAME(GetFrameArgumentHole)NAME(NewTarget)NAME(Rest)NAME(PostWriteBarrier
)NAME(PostWriteElementBarrier)NAME(AssertCanElidePostWriteBarrier
)NAME(NewNamedLambdaObject)NAME(NewCallObject)NAME(NewStringObject
)NAME(IsCallable)NAME(IsConstructor)NAME(IsCrossRealmArrayConstructor
)NAME(IsObject)NAME(IsNullOrUndefined)NAME(HasClass)NAME(GuardToClass
)NAME(GuardToEitherClass)NAME(GuardToFunction)NAME(IsArray)NAME
(IsTypedArray)NAME(ObjectClassToString)NAME(CheckReturn)NAME(
CheckThis)NAME(AsyncResolve)NAME(AsyncReject)NAME(GeneratorReturn
)NAME(AsyncAwait)NAME(CheckThisReinit)NAME(Generator)NAME(CanSkipAwait
)NAME(MaybeExtractAwaitValue)NAME(IncrementWarmUpCounter)NAME
(AtomicIsLockFree)NAME(CompareExchangeTypedArrayElement)NAME(
AtomicExchangeTypedArrayElement)NAME(AtomicTypedArrayElementBinop
)NAME(Debugger)NAME(CheckIsObj)NAME(CheckObjCoercible)NAME(CheckClassHeritage
)NAME(DebugCheckSelfHosted)NAME(IsPackedArray)NAME(GuardArrayIsPacked
)NAME(GetPrototypeOf)NAME(ObjectWithProto)NAME(ObjectStaticProto
)NAME(ConstantProto)NAME(BuiltinObject)NAME(SuperFunction)NAME
(InitHomeObject)NAME(IsTypedArrayConstructor)NAME(LoadValueTag
)NAME(LoadWrapperTarget)NAME(GuardHasGetterSetter)NAME(GuardIsExtensible
)NAME(GuardInt32IsNonNegative)NAME(GuardInt32Range)NAME(GuardIndexIsNotDenseElement
)NAME(GuardIndexIsValidUpdateOrAdd)NAME(CallAddOrUpdateSparseElement
)NAME(CallGetSparseElement)NAME(CallNativeGetElement)NAME(CallNativeGetElementSuper
)NAME(CallObjectHasSparseElement)NAME(BigIntAsIntN)NAME(BigIntAsUintN
)NAME(GuardNonGCThing)NAME(ToHashableNonGCThing)NAME(ToHashableString
)NAME(ToHashableValue)NAME(HashNonGCThing)NAME(HashString)NAME
(HashSymbol)NAME(HashBigInt)NAME(HashObject)NAME(HashValue)NAME
(SetObjectHasNonBigInt)NAME(SetObjectHasBigInt)NAME(SetObjectHasValue
)NAME(SetObjectHasValueVMCall)NAME(SetObjectSize)NAME(MapObjectHasNonBigInt
)NAME(MapObjectHasBigInt)NAME(MapObjectHasValue)NAME(MapObjectHasValueVMCall
)NAME(MapObjectGetNonBigInt)NAME(MapObjectGetBigInt)NAME(MapObjectGetValue
)NAME(MapObjectGetValueVMCall)NAME(MapObjectSize)NAME(PostIntPtrConversion
)NAME(WasmNeg)NAME(WasmBinaryBitwise)NAME(WasmLoadInstance)NAME
(WasmStoreInstance)NAME(WasmHeapReg)NAME(WasmBoundsCheck)NAME
(WasmBoundsCheckRange32)NAME(WasmExtendU32Index)NAME(WasmWrapU32Index
)NAME(WasmClampTable64Index)NAME(WasmAddOffset)NAME(WasmAlignmentCheck
)NAME(WasmLoad)NAME(WasmStore)NAME(AsmJSLoadHeap)NAME(AsmJSStoreHeap
)NAME(WasmFence)NAME(WasmCompareExchangeHeap)NAME(WasmAtomicExchangeHeap
)NAME(WasmAtomicBinopHeap)NAME(WasmLoadInstanceDataField)NAME
(WasmLoadGlobalCell)NAME(WasmLoadTableElement)NAME(WasmStoreInstanceDataField
)NAME(WasmStoreGlobalCell)NAME(WasmStoreStackResult)NAME(WasmDerivedPointer
)NAME(WasmDerivedIndexPointer)NAME(WasmStoreRef)NAME(WasmPostWriteBarrierImmediate
)NAME(WasmPostWriteBarrierIndex)NAME(WasmParameter)NAME(WasmReturn
)NAME(WasmReturnVoid)NAME(WasmStackArg)NAME(WasmRegisterResult
)NAME(WasmFloatRegisterResult)NAME(WasmRegister64Result)NAME(
WasmStackResultArea)NAME(WasmStackResult)NAME(WasmCallCatchable
)NAME(WasmCallUncatchable)NAME(WasmCallLandingPrePad)NAME(WasmReturnCall
)NAME(WasmSelect)NAME(WasmReinterpret)NAME(Rotate)NAME(WasmStackSwitchToMain
)NAME(WasmStackSwitchToSuspendable)NAME(WasmStackContinueOnSuspendable
)NAME(WasmBinarySimd128)NAME(WasmBinarySimd128WithConstant)NAME
(WasmShiftSimd128)NAME(WasmShuffleSimd128)NAME(WasmReplaceLaneSimd128
)NAME(WasmUnarySimd128)NAME(WasmTernarySimd128)NAME(WasmScalarToSimd128
)NAME(WasmReduceSimd128)NAME(WasmLoadLaneSimd128)NAME(WasmStoreLaneSimd128
)NAME(UnreachableResult)NAME(IonToWasmCall)NAME(WasmLoadField
)NAME(WasmLoadFieldKA)NAME(WasmLoadElementKA)NAME(WasmStoreFieldKA
)NAME(WasmStoreFieldRefKA)NAME(WasmStoreElementKA)NAME(WasmStoreElementRefKA
)NAME(WasmRefIsSubtypeOfConcrete)NAME(WasmRefIsSubtypeOfAbstract
)NAME(WasmNewStructObject)NAME(WasmNewArrayObject)
119# undef NAME
120 };
121 return names[unsigned(op)];
122}
123
124void MDefinition::PrintOpcodeName(GenericPrinter& out, Opcode op) {
125 const char* name = OpcodeName(op);
126 size_t len = strlen(name);
127 for (size_t i = 0; i < len; i++) {
128 out.printf("%c", unicode::ToLowerCase(name[i]));
129 }
130}
131
132uint32_t js::jit::GetMBasicBlockId(const MBasicBlock* block) {
133 return block->id();
134}
135#endif
136
137static MConstant* EvaluateInt64ConstantOperands(TempAllocator& alloc,
138 MBinaryInstruction* ins) {
139 MDefinition* left = ins->getOperand(0);
140 MDefinition* right = ins->getOperand(1);
141
142 if (!left->isConstant() || !right->isConstant()) {
143 return nullptr;
144 }
145
146 MOZ_ASSERT(left->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::Int64)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::Int64", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::Int64"
")"); do { *((volatile int*)__null) = 146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
147 MOZ_ASSERT(right->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::Int64)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::Int64", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int64"
")"); do { *((volatile int*)__null) = 147; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
148
149 int64_t lhs = left->toConstant()->toInt64();
150 int64_t rhs = right->toConstant()->toInt64();
151 int64_t ret;
152
153 switch (ins->op()) {
154 case MDefinition::Opcode::BitAnd:
155 ret = lhs & rhs;
156 break;
157 case MDefinition::Opcode::BitOr:
158 ret = lhs | rhs;
159 break;
160 case MDefinition::Opcode::BitXor:
161 ret = lhs ^ rhs;
162 break;
163 case MDefinition::Opcode::Lsh:
164 ret = lhs << (rhs & 0x3F);
165 break;
166 case MDefinition::Opcode::Rsh:
167 ret = lhs >> (rhs & 0x3F);
168 break;
169 case MDefinition::Opcode::Ursh:
170 ret = uint64_t(lhs) >> (uint64_t(rhs) & 0x3F);
171 break;
172 case MDefinition::Opcode::Add:
173 ret = lhs + rhs;
174 break;
175 case MDefinition::Opcode::Sub:
176 ret = lhs - rhs;
177 break;
178 case MDefinition::Opcode::Mul:
179 ret = lhs * rhs;
180 break;
181 case MDefinition::Opcode::Div:
182 if (rhs == 0) {
183 // Division by zero will trap at runtime.
184 return nullptr;
185 }
186 if (ins->toDiv()->isUnsigned()) {
187 ret = int64_t(uint64_t(lhs) / uint64_t(rhs));
188 } else if (lhs == INT64_MIN(-9223372036854775807L -1) || rhs == -1) {
189 // Overflow will trap at runtime.
190 return nullptr;
191 } else {
192 ret = lhs / rhs;
193 }
194 break;
195 case MDefinition::Opcode::Mod:
196 if (rhs == 0) {
197 // Division by zero will trap at runtime.
198 return nullptr;
199 }
200 if (!ins->toMod()->isUnsigned() && (lhs < 0 || rhs < 0)) {
201 // Handle all negative values at runtime, for simplicity.
202 return nullptr;
203 }
204 ret = int64_t(uint64_t(lhs) % uint64_t(rhs));
205 break;
206 default:
207 MOZ_CRASH("NYI")do { do { } while (false); MOZ_ReportCrash("" "NYI", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 207); AnnotateMozCrashReason("MOZ_CRASH(" "NYI" ")"); do { *
((volatile int*)__null) = 207; __attribute__((nomerge)) ::abort
(); } while (false); } while (false)
;
208 }
209
210 return MConstant::NewInt64(alloc, ret);
211}
212
213static MConstant* EvaluateConstantOperands(TempAllocator& alloc,
214 MBinaryInstruction* ins,
215 bool* ptypeChange = nullptr) {
216 MDefinition* left = ins->getOperand(0);
217 MDefinition* right = ins->getOperand(1);
218
219 MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTypeRepresentableAsDouble(left->type()))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(IsTypeRepresentableAsDouble(left->type())))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsTypeRepresentableAsDouble(left->type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(left->type())"
")"); do { *((volatile int*)__null) = 219; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
220 MOZ_ASSERT(IsTypeRepresentableAsDouble(right->type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTypeRepresentableAsDouble(right->type()))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(IsTypeRepresentableAsDouble(right->type())))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeRepresentableAsDouble(right->type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(right->type())"
")"); do { *((volatile int*)__null) = 220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
221
222 if (!left->isConstant() || !right->isConstant()) {
223 return nullptr;
224 }
225
226 MConstant* lhs = left->toConstant();
227 MConstant* rhs = right->toConstant();
228 double ret = JS::GenericNaN();
229
230 switch (ins->op()) {
231 case MDefinition::Opcode::BitAnd:
232 ret = double(lhs->toInt32() & rhs->toInt32());
233 break;
234 case MDefinition::Opcode::BitOr:
235 ret = double(lhs->toInt32() | rhs->toInt32());
236 break;
237 case MDefinition::Opcode::BitXor:
238 ret = double(lhs->toInt32() ^ rhs->toInt32());
239 break;
240 case MDefinition::Opcode::Lsh:
241 ret = double(uint32_t(lhs->toInt32()) << (rhs->toInt32() & 0x1F));
242 break;
243 case MDefinition::Opcode::Rsh:
244 ret = double(lhs->toInt32() >> (rhs->toInt32() & 0x1F));
245 break;
246 case MDefinition::Opcode::Ursh:
247 ret = double(uint32_t(lhs->toInt32()) >> (rhs->toInt32() & 0x1F));
248 break;
249 case MDefinition::Opcode::Add:
250 ret = lhs->numberToDouble() + rhs->numberToDouble();
251 break;
252 case MDefinition::Opcode::Sub:
253 ret = lhs->numberToDouble() - rhs->numberToDouble();
254 break;
255 case MDefinition::Opcode::Mul:
256 ret = lhs->numberToDouble() * rhs->numberToDouble();
257 break;
258 case MDefinition::Opcode::Div:
259 if (ins->toDiv()->isUnsigned()) {
260 if (rhs->isInt32(0)) {
261 if (ins->toDiv()->trapOnError()) {
262 return nullptr;
263 }
264 ret = 0.0;
265 } else {
266 ret = double(uint32_t(lhs->toInt32()) / uint32_t(rhs->toInt32()));
267 }
268 } else {
269 ret = NumberDiv(lhs->numberToDouble(), rhs->numberToDouble());
270 }
271 break;
272 case MDefinition::Opcode::Mod:
273 if (ins->toMod()->isUnsigned()) {
274 if (rhs->isInt32(0)) {
275 if (ins->toMod()->trapOnError()) {
276 return nullptr;
277 }
278 ret = 0.0;
279 } else {
280 ret = double(uint32_t(lhs->toInt32()) % uint32_t(rhs->toInt32()));
281 }
282 } else {
283 ret = NumberMod(lhs->numberToDouble(), rhs->numberToDouble());
284 }
285 break;
286 default:
287 MOZ_CRASH("NYI")do { do { } while (false); MOZ_ReportCrash("" "NYI", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 287); AnnotateMozCrashReason("MOZ_CRASH(" "NYI" ")"); do { *
((volatile int*)__null) = 287; __attribute__((nomerge)) ::abort
(); } while (false); } while (false)
;
288 }
289
290 if (ins->type() == MIRType::Float32) {
291 return MConstant::NewFloat32(alloc, float(ret));
292 }
293 if (ins->type() == MIRType::Double) {
294 return MConstant::New(alloc, DoubleValue(ret));
295 }
296
297 Value retVal;
298 retVal.setNumber(JS::CanonicalizeNaN(ret));
299
300 // If this was an int32 operation but the result isn't an int32 (for
301 // example, a division where the numerator isn't evenly divisible by the
302 // denominator), decline folding.
303 MOZ_ASSERT(ins->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ins->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::Int32
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ins->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 303); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 303; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
304 if (!retVal.isInt32()) {
305 if (ptypeChange) {
306 *ptypeChange = true;
307 }
308 return nullptr;
309 }
310
311 return MConstant::New(alloc, retVal);
312}
313
314static MConstant* EvaluateConstantNaNOperand(MBinaryInstruction* ins) {
315 auto* left = ins->lhs();
316 auto* right = ins->rhs();
317
318 MOZ_ASSERT(IsTypeRepresentableAsDouble(left->type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTypeRepresentableAsDouble(left->type()))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(IsTypeRepresentableAsDouble(left->type())))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsTypeRepresentableAsDouble(left->type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(left->type())"
")"); do { *((volatile int*)__null) = 318; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
319 MOZ_ASSERT(IsTypeRepresentableAsDouble(right->type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTypeRepresentableAsDouble(right->type()))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(IsTypeRepresentableAsDouble(right->type())))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeRepresentableAsDouble(right->type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(right->type())"
")"); do { *((volatile int*)__null) = 319; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
320 MOZ_ASSERT(left->type() == ins->type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == ins->type())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == ins->type
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == ins->type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == ins->type()"
")"); do { *((volatile int*)__null) = 320; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
321 MOZ_ASSERT(right->type() == ins->type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == ins->type())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == ins->
type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == ins->type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 321); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == ins->type()"
")"); do { *((volatile int*)__null) = 321; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
322
323 // Don't fold NaN if we can't return a floating point type.
324 if (!IsFloatingPointType(ins->type())) {
325 return nullptr;
326 }
327
328 MOZ_ASSERT(!left->isConstant() || !right->isConstant(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!left->isConstant() || !right->isConstant())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!left->isConstant() || !right->isConstant())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!left->isConstant() || !right->isConstant()"
" (" "EvaluateConstantOperands should have handled this case"
")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!left->isConstant() || !right->isConstant()"
") (" "EvaluateConstantOperands should have handled this case"
")"); do { *((volatile int*)__null) = 329; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
329 "EvaluateConstantOperands should have handled this case")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!left->isConstant() || !right->isConstant())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!left->isConstant() || !right->isConstant())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("!left->isConstant() || !right->isConstant()"
" (" "EvaluateConstantOperands should have handled this case"
")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!left->isConstant() || !right->isConstant()"
") (" "EvaluateConstantOperands should have handled this case"
")"); do { *((volatile int*)__null) = 329; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
330
331 // One operand must be a constant NaN.
332 MConstant* cst;
333 if (left->isConstant()) {
334 cst = left->toConstant();
335 } else if (right->isConstant()) {
336 cst = right->toConstant();
337 } else {
338 return nullptr;
339 }
340 if (!std::isnan(cst->numberToDouble())) {
341 return nullptr;
342 }
343
344 // Fold to constant NaN.
345 return cst;
346}
347
348static MMul* EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins) {
349 // we should fold only when it is a floating point operation
350 if (!IsFloatingPointType(ins->type())) {
351 return nullptr;
352 }
353
354 MDefinition* left = ins->getOperand(0);
355 MDefinition* right = ins->getOperand(1);
356
357 if (!right->isConstant()) {
358 return nullptr;
359 }
360
361 int32_t num;
362 if (!mozilla::NumberIsInt32(right->toConstant()->numberToDouble(), &num)) {
363 return nullptr;
364 }
365
366 // check if rhs is a power of two
367 if (mozilla::Abs(num) & (mozilla::Abs(num) - 1)) {
368 return nullptr;
369 }
370
371 Value ret;
372 ret.setDouble(1.0 / double(num));
373
374 MConstant* foldedRhs;
375 if (ins->type() == MIRType::Float32) {
376 foldedRhs = MConstant::NewFloat32(alloc, ret.toDouble());
377 } else {
378 foldedRhs = MConstant::New(alloc, ret);
379 }
380
381 MOZ_ASSERT(foldedRhs->type() == ins->type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(foldedRhs->type() == ins->type())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(foldedRhs->type() == ins->type()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("foldedRhs->type() == ins->type()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 381); AnnotateMozCrashReason("MOZ_ASSERT" "(" "foldedRhs->type() == ins->type()"
")"); do { *((volatile int*)__null) = 381; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
382 ins->block()->insertBefore(ins, foldedRhs);
383
384 MMul* mul = MMul::New(alloc, left, foldedRhs, ins->type());
385 mul->setMustPreserveNaN(ins->mustPreserveNaN());
386 return mul;
387}
388
389#ifdef JS_JITSPEW1
390const char* MDefinition::opName() const { return OpcodeName(op()); }
391
392void MDefinition::printName(GenericPrinter& out) const {
393 PrintOpcodeName(out, op());
394 out.printf("%u", id());
395}
396#endif
397
398HashNumber MDefinition::valueHash() const {
399 HashNumber out = HashNumber(op());
400 for (size_t i = 0, e = numOperands(); i < e; i++) {
401 out = addU32ToHash(out, getOperand(i)->id());
402 }
403 if (MDefinition* dep = dependency()) {
404 out = addU32ToHash(out, dep->id());
405 }
406 return out;
407}
408
409HashNumber MNullaryInstruction::valueHash() const {
410 HashNumber hash = HashNumber(op());
411 if (MDefinition* dep = dependency()) {
412 hash = addU32ToHash(hash, dep->id());
413 }
414 MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 414); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 414; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
415 return hash;
416}
417
418HashNumber MUnaryInstruction::valueHash() const {
419 HashNumber hash = HashNumber(op());
420 hash = addU32ToHash(hash, getOperand(0)->id());
421 if (MDefinition* dep = dependency()) {
422 hash = addU32ToHash(hash, dep->id());
423 }
424 MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 424); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 424; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
425 return hash;
426}
427
428HashNumber MBinaryInstruction::valueHash() const {
429 HashNumber hash = HashNumber(op());
430 hash = addU32ToHash(hash, getOperand(0)->id());
431 hash = addU32ToHash(hash, getOperand(1)->id());
432 if (MDefinition* dep = dependency()) {
433 hash = addU32ToHash(hash, dep->id());
434 }
435 MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 435); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 435; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
436 return hash;
437}
438
439HashNumber MTernaryInstruction::valueHash() const {
440 HashNumber hash = HashNumber(op());
441 hash = addU32ToHash(hash, getOperand(0)->id());
442 hash = addU32ToHash(hash, getOperand(1)->id());
443 hash = addU32ToHash(hash, getOperand(2)->id());
444 if (MDefinition* dep = dependency()) {
445 hash = addU32ToHash(hash, dep->id());
446 }
447 MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 447); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 447; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
448 return hash;
449}
450
451HashNumber MQuaternaryInstruction::valueHash() const {
452 HashNumber hash = HashNumber(op());
453 hash = addU32ToHash(hash, getOperand(0)->id());
454 hash = addU32ToHash(hash, getOperand(1)->id());
455 hash = addU32ToHash(hash, getOperand(2)->id());
456 hash = addU32ToHash(hash, getOperand(3)->id());
457 if (MDefinition* dep = dependency()) {
458 hash = addU32ToHash(hash, dep->id());
459 }
460 MOZ_ASSERT(hash == MDefinition::valueHash())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(hash == MDefinition::valueHash())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(hash == MDefinition::valueHash
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("hash == MDefinition::valueHash()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 460); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 460; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
461 return hash;
462}
463
464const MDefinition* MDefinition::skipObjectGuards() const {
465 const MDefinition* result = this;
466 // These instructions don't modify the object and just guard specific
467 // properties.
468 while (true) {
469 if (result->isGuardShape()) {
470 result = result->toGuardShape()->object();
471 continue;
472 }
473 if (result->isGuardNullProto()) {
474 result = result->toGuardNullProto()->object();
475 continue;
476 }
477 if (result->isGuardProto()) {
478 result = result->toGuardProto()->object();
479 continue;
480 }
481
482 break;
483 }
484
485 return result;
486}
487
488bool MDefinition::congruentIfOperandsEqual(const MDefinition* ins) const {
489 if (op() != ins->op()) {
490 return false;
491 }
492
493 if (type() != ins->type()) {
494 return false;
495 }
496
497 if (isEffectful() || ins->isEffectful()) {
498 return false;
499 }
500
501 if (numOperands() != ins->numOperands()) {
502 return false;
503 }
504
505 for (size_t i = 0, e = numOperands(); i < e; i++) {
506 if (getOperand(i) != ins->getOperand(i)) {
507 return false;
508 }
509 }
510
511 return true;
512}
513
514MDefinition* MDefinition::foldsTo(TempAllocator& alloc) {
515 // In the default case, there are no constants to fold.
516 return this;
517}
518
519bool MDefinition::mightBeMagicType() const {
520 if (IsMagicType(type())) {
521 return true;
522 }
523
524 if (MIRType::Value != type()) {
525 return false;
526 }
527
528 return true;
529}
530
531bool MDefinition::definitelyType(std::initializer_list<MIRType> types) const {
532#ifdef DEBUG1
533 // Only support specialized, non-magic types.
534 auto isSpecializedNonMagic = [](MIRType type) {
535 return type <= MIRType::Object;
536 };
537#endif
538
539 MOZ_ASSERT(types.size() > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(types.size() > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(types.size() > 0))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("types.size() > 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "types.size() > 0"
")"); do { *((volatile int*)__null) = 539; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
540 MOZ_ASSERT(std::all_of(types.begin(), types.end(), isSpecializedNonMagic))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(std::all_of(types.begin(), types.end(), isSpecializedNonMagic
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(std::all_of(types.begin(), types.end(), isSpecializedNonMagic
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("std::all_of(types.begin(), types.end(), isSpecializedNonMagic)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 540); AnnotateMozCrashReason("MOZ_ASSERT" "(" "std::all_of(types.begin(), types.end(), isSpecializedNonMagic)"
")"); do { *((volatile int*)__null) = 540; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
541
542 if (type() == MIRType::Value) {
543 return false;
544 }
545
546 return std::find(types.begin(), types.end(), type()) != types.end();
547}
548
549MDefinition* MInstruction::foldsToStore(TempAllocator& alloc) {
550 if (!dependency()) {
551 return nullptr;
552 }
553
554 MDefinition* store = dependency();
555 if (mightAlias(store) != AliasType::MustAlias) {
556 return nullptr;
557 }
558
559 if (!store->block()->dominates(block())) {
560 return nullptr;
561 }
562
563 MDefinition* value;
564 switch (store->op()) {
565 case Opcode::StoreFixedSlot:
566 value = store->toStoreFixedSlot()->value();
567 break;
568 case Opcode::StoreDynamicSlot:
569 value = store->toStoreDynamicSlot()->value();
570 break;
571 case Opcode::StoreElement:
572 value = store->toStoreElement()->value();
573 break;
574 default:
575 MOZ_CRASH("unknown store")do { do { } while (false); MOZ_ReportCrash("" "unknown store"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 575); AnnotateMozCrashReason("MOZ_CRASH(" "unknown store" ")"
); do { *((volatile int*)__null) = 575; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
576 }
577
578 // If the type are matching then we return the value which is used as
579 // argument of the store.
580 if (value->type() != type()) {
581 // If we expect to read a type which is more generic than the type seen
582 // by the store, then we box the value used by the store.
583 if (type() != MIRType::Value) {
584 return nullptr;
585 }
586
587 MOZ_ASSERT(value->type() < MIRType::Value)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(value->type() < MIRType::Value)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(value->type() < MIRType
::Value))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("value->type() < MIRType::Value", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 587); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() < MIRType::Value"
")"); do { *((volatile int*)__null) = 587; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
588 MBox* box = MBox::New(alloc, value);
589 value = box;
590 }
591
592 return value;
593}
594
595void MDefinition::analyzeEdgeCasesForward() {}
596
597void MDefinition::analyzeEdgeCasesBackward() {}
598
599void MInstruction::setResumePoint(MResumePoint* resumePoint) {
600 MOZ_ASSERT(!resumePoint_)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!resumePoint_)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!resumePoint_))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!resumePoint_",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 600); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!resumePoint_"
")"); do { *((volatile int*)__null) = 600; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
601 resumePoint_ = resumePoint;
602 resumePoint_->setInstruction(this);
603}
604
605void MInstruction::stealResumePoint(MInstruction* other) {
606 MResumePoint* resumePoint = other->resumePoint_;
607 other->resumePoint_ = nullptr;
608
609 resumePoint->resetInstruction();
610 setResumePoint(resumePoint);
611}
612
613void MInstruction::moveResumePointAsEntry() {
614 MOZ_ASSERT(isNop())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isNop())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isNop()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isNop()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 614); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNop()" ")"
); do { *((volatile int*)__null) = 614; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
615 block()->clearEntryResumePoint();
616 block()->setEntryResumePoint(resumePoint_);
617 resumePoint_->resetInstruction();
618 resumePoint_ = nullptr;
619}
620
621void MInstruction::clearResumePoint() {
622 resumePoint_->resetInstruction();
623 block()->discardPreAllocatedResumePoint(resumePoint_);
624 resumePoint_ = nullptr;
625}
626
627MDefinition* MTest::foldsDoubleNegation(TempAllocator& alloc) {
628 MDefinition* op = getOperand(0);
629
630 if (op->isNot()) {
631 // If the operand of the Not is itself a Not, they cancel out.
632 MDefinition* opop = op->getOperand(0);
633 if (opop->isNot()) {
634 return MTest::New(alloc, opop->toNot()->input(), ifTrue(), ifFalse());
635 }
636 return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue());
637 }
638 return nullptr;
639}
640
641MDefinition* MTest::foldsConstant(TempAllocator& alloc) {
642 MDefinition* op = getOperand(0);
643 if (MConstant* opConst = op->maybeConstantValue()) {
644 bool b;
645 if (opConst->valueToBoolean(&b)) {
646 return MGoto::New(alloc, b ? ifTrue() : ifFalse());
647 }
648 }
649 return nullptr;
650}
651
652MDefinition* MTest::foldsTypes(TempAllocator& alloc) {
653 MDefinition* op = getOperand(0);
654
655 switch (op->type()) {
656 case MIRType::Undefined:
657 case MIRType::Null:
658 return MGoto::New(alloc, ifFalse());
659 case MIRType::Symbol:
660 return MGoto::New(alloc, ifTrue());
661 default:
662 break;
663 }
664 return nullptr;
665}
666
667class UsesIterator {
668 MDefinition* def_;
669
670 public:
671 explicit UsesIterator(MDefinition* def) : def_(def) {}
672 auto begin() const { return def_->usesBegin(); }
673 auto end() const { return def_->usesEnd(); }
674};
675
676static bool AllInstructionsDeadIfUnused(MBasicBlock* block) {
677 for (auto* ins : *block) {
678 // Skip trivial instructions.
679 if (ins->isNop() || ins->isGoto()) {
680 continue;
681 }
682
683 // All uses must be within the current block.
684 for (auto* use : UsesIterator(ins)) {
685 if (use->consumer()->block() != block) {
686 return false;
687 }
688 }
689
690 // All instructions within this block must be dead if unused.
691 if (!DeadIfUnused(ins)) {
692 return false;
693 }
694 }
695 return true;
696}
697
698MDefinition* MTest::foldsNeedlessControlFlow(TempAllocator& alloc) {
699 // All instructions within both successors need be dead if unused.
700 if (!AllInstructionsDeadIfUnused(ifTrue()) ||
701 !AllInstructionsDeadIfUnused(ifFalse())) {
702 return nullptr;
703 }
704
705 // Both successors must have the same target successor.
706 if (ifTrue()->numSuccessors() != 1 || ifFalse()->numSuccessors() != 1) {
707 return nullptr;
708 }
709 if (ifTrue()->getSuccessor(0) != ifFalse()->getSuccessor(0)) {
710 return nullptr;
711 }
712
713 // The target successor's phis must be redundant. Redundant phis should have
714 // been removed in an earlier pass, so only check if any phis are present,
715 // which is a stronger condition.
716 if (ifTrue()->successorWithPhis()) {
717 return nullptr;
718 }
719
720 return MGoto::New(alloc, ifTrue());
721}
722
723// If a test is dominated by either the true or false path of a previous test of
724// the same condition, then the test is redundant and can be converted into a
725// goto true or goto false, respectively.
726MDefinition* MTest::foldsRedundantTest(TempAllocator& alloc) {
727 MBasicBlock* myBlock = this->block();
728 MDefinition* originalInput = getOperand(0);
729
730 // Handle single and double negatives. This ensures that we do not miss a
731 // folding opportunity due to a condition being inverted.
732 MDefinition* newInput = input();
733 bool inverted = false;
734 if (originalInput->isNot()) {
735 newInput = originalInput->toNot()->input();
736 inverted = true;
737 if (originalInput->toNot()->input()->isNot()) {
738 newInput = originalInput->toNot()->input()->toNot()->input();
739 inverted = false;
740 }
741 }
742
743 // The specific order of traversal does not matter. If there are multiple
744 // dominating redundant tests, they will either agree on direction (in which
745 // case we will prune the same way regardless of order), or they will
746 // disagree, in which case we will eventually be marked entirely dead by the
747 // folding of the redundant parent.
748 for (MUseIterator i(newInput->usesBegin()), e(newInput->usesEnd()); i != e;
749 ++i) {
750 if (!i->consumer()->isDefinition()) {
751 continue;
752 }
753 if (!i->consumer()->toDefinition()->isTest()) {
754 continue;
755 }
756 MTest* otherTest = i->consumer()->toDefinition()->toTest();
757 if (otherTest == this) {
758 continue;
759 }
760
761 if (otherTest->ifFalse()->dominates(myBlock)) {
762 // This test cannot be true, so fold to a goto false.
763 return MGoto::New(alloc, inverted ? ifTrue() : ifFalse());
764 }
765 if (otherTest->ifTrue()->dominates(myBlock)) {
766 // This test cannot be false, so fold to a goto true.
767 return MGoto::New(alloc, inverted ? ifFalse() : ifTrue());
768 }
769 }
770
771 return nullptr;
772}
773
774MDefinition* MTest::foldsTo(TempAllocator& alloc) {
775 if (MDefinition* def = foldsRedundantTest(alloc)) {
776 return def;
777 }
778
779 if (MDefinition* def = foldsDoubleNegation(alloc)) {
780 return def;
781 }
782
783 if (MDefinition* def = foldsConstant(alloc)) {
784 return def;
785 }
786
787 if (MDefinition* def = foldsTypes(alloc)) {
788 return def;
789 }
790
791 if (MDefinition* def = foldsNeedlessControlFlow(alloc)) {
792 return def;
793 }
794
795 return this;
796}
797
798AliasSet MThrow::getAliasSet() const {
799 return AliasSet::Store(AliasSet::ExceptionState);
800}
801
802AliasSet MThrowWithStack::getAliasSet() const {
803 return AliasSet::Store(AliasSet::ExceptionState);
804}
805
806AliasSet MNewArrayDynamicLength::getAliasSet() const {
807 return AliasSet::Store(AliasSet::ExceptionState);
808}
809
810AliasSet MNewTypedArrayDynamicLength::getAliasSet() const {
811 return AliasSet::Store(AliasSet::ExceptionState);
812}
813
814#ifdef JS_JITSPEW1
815void MDefinition::printOpcode(GenericPrinter& out) const {
816 PrintOpcodeName(out, op());
817 for (size_t j = 0, e = numOperands(); j < e; j++) {
818 out.printf(" ");
819 if (getUseFor(j)->hasProducer()) {
820 getOperand(j)->printName(out);
821 out.printf(":%s", StringFromMIRType(getOperand(j)->type()));
822 } else {
823 out.printf("(null)");
824 }
825 }
826}
827
828void MDefinition::dump(GenericPrinter& out) const {
829 printName(out);
830 out.printf(":%s", StringFromMIRType(type()));
831 out.printf(" = ");
832 printOpcode(out);
833 out.printf("\n");
834
835 if (isInstruction()) {
836 if (MResumePoint* resume = toInstruction()->resumePoint()) {
837 resume->dump(out);
838 }
839 }
840}
841
842void MDefinition::dump() const {
843 Fprinter out(stderrstderr);
844 dump(out);
845 out.finish();
846}
847
848void MDefinition::dumpLocation(GenericPrinter& out) const {
849 MResumePoint* rp = nullptr;
850 const char* linkWord = nullptr;
851 if (isInstruction() && toInstruction()->resumePoint()) {
852 rp = toInstruction()->resumePoint();
853 linkWord = "at";
854 } else {
855 rp = block()->entryResumePoint();
856 linkWord = "after";
857 }
858
859 while (rp) {
860 JSScript* script = rp->block()->info().script();
861 uint32_t lineno = PCToLineNumber(rp->block()->info().script(), rp->pc());
862 out.printf(" %s %s:%u\n", linkWord, script->filename(), lineno);
863 rp = rp->caller();
864 linkWord = "in";
865 }
866}
867
868void MDefinition::dumpLocation() const {
869 Fprinter out(stderrstderr);
870 dumpLocation(out);
871 out.finish();
872}
873#endif
874
875#if defined(DEBUG1) || defined(JS_JITSPEW1)
876size_t MDefinition::useCount() const {
877 size_t count = 0;
878 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
879 count++;
880 }
881 return count;
882}
883
884size_t MDefinition::defUseCount() const {
885 size_t count = 0;
886 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
887 if ((*i)->consumer()->isDefinition()) {
888 count++;
889 }
890 }
891 return count;
892}
893#endif
894
895bool MDefinition::hasOneUse() const {
896 MUseIterator i(uses_.begin());
897 if (i == uses_.end()) {
898 return false;
899 }
900 i++;
901 return i == uses_.end();
902}
903
904bool MDefinition::hasOneDefUse() const {
905 bool hasOneDefUse = false;
906 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
907 if (!(*i)->consumer()->isDefinition()) {
908 continue;
909 }
910
911 // We already have a definition use. So 1+
912 if (hasOneDefUse) {
913 return false;
914 }
915
916 // We saw one definition. Loop to test if there is another.
917 hasOneDefUse = true;
918 }
919
920 return hasOneDefUse;
921}
922
923bool MDefinition::hasOneLiveDefUse() const {
924 bool hasOneDefUse = false;
925 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
926 if (!(*i)->consumer()->isDefinition()) {
927 continue;
928 }
929
930 MDefinition* def = (*i)->consumer()->toDefinition();
931 if (def->isRecoveredOnBailout()) {
932 continue;
933 }
934
935 // We already have a definition use. So 1+
936 if (hasOneDefUse) {
937 return false;
938 }
939
940 // We saw one definition. Loop to test if there is another.
941 hasOneDefUse = true;
942 }
943
944 return hasOneDefUse;
945}
946
947bool MDefinition::hasDefUses() const {
948 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
949 if ((*i)->consumer()->isDefinition()) {
950 return true;
951 }
952 }
953
954 return false;
955}
956
957bool MDefinition::hasLiveDefUses() const {
958 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
959 MNode* ins = (*i)->consumer();
960 if (ins->isDefinition()) {
961 if (!ins->toDefinition()->isRecoveredOnBailout()) {
962 return true;
963 }
964 } else {
965 MOZ_ASSERT(ins->isResumePoint())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ins->isResumePoint())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ins->isResumePoint()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("ins->isResumePoint()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 965); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->isResumePoint()"
")"); do { *((volatile int*)__null) = 965; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
966 if (!ins->toResumePoint()->isRecoverableOperand(*i)) {
967 return true;
968 }
969 }
970 }
971
972 return false;
973}
974
975MDefinition* MDefinition::maybeSingleDefUse() const {
976 MUseDefIterator use(this);
977 if (!use) {
978 // No def-uses.
979 return nullptr;
980 }
981
982 MDefinition* useDef = use.def();
983
984 use++;
985 if (use) {
986 // More than one def-use.
987 return nullptr;
988 }
989
990 return useDef;
991}
992
993MDefinition* MDefinition::maybeMostRecentlyAddedDefUse() const {
994 MUseDefIterator use(this);
995 if (!use) {
996 // No def-uses.
997 return nullptr;
998 }
999
1000 MDefinition* mostRecentUse = use.def();
1001
1002#ifdef DEBUG1
1003 // This function relies on addUse adding new uses to the front of the list.
1004 // Check this invariant by asserting the next few uses are 'older'. Skip this
1005 // for phis because setBackedge can add a new use for a loop phi even if the
1006 // loop body has a use with an id greater than the loop phi's id.
1007 if (!mostRecentUse->isPhi()) {
1008 static constexpr size_t NumUsesToCheck = 3;
1009 use++;
1010 for (size_t i = 0; use && i < NumUsesToCheck; i++, use++) {
1011 MOZ_ASSERT(use.def()->id() <= mostRecentUse->id())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(use.def()->id() <= mostRecentUse->id())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(use.def()->id() <= mostRecentUse->id()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("use.def()->id() <= mostRecentUse->id()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1011); AnnotateMozCrashReason("MOZ_ASSERT" "(" "use.def()->id() <= mostRecentUse->id()"
")"); do { *((volatile int*)__null) = 1011; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1012 }
1013 }
1014#endif
1015
1016 return mostRecentUse;
1017}
1018
1019void MDefinition::replaceAllUsesWith(MDefinition* dom) {
1020 for (size_t i = 0, e = numOperands(); i < e; ++i) {
1021 getOperand(i)->setImplicitlyUsedUnchecked();
1022 }
1023
1024 justReplaceAllUsesWith(dom);
1025}
1026
1027void MDefinition::justReplaceAllUsesWith(MDefinition* dom) {
1028 MOZ_ASSERT(dom != nullptr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dom != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(dom != nullptr))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("dom != nullptr"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1028); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != nullptr"
")"); do { *((volatile int*)__null) = 1028; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1029 MOZ_ASSERT(dom != this)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dom != this)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(dom != this))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("dom != this", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1029); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != this"
")"); do { *((volatile int*)__null) = 1029; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1030
1031 // Carry over the fact the value has uses which are no longer inspectable
1032 // with the graph.
1033 if (isImplicitlyUsed()) {
1034 dom->setImplicitlyUsedUnchecked();
1035 }
1036
1037 for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i) {
1038 i->setProducerUnchecked(dom);
1039 }
1040 dom->uses_.takeElements(uses_);
1041}
1042
1043bool MDefinition::optimizeOutAllUses(TempAllocator& alloc) {
1044 for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
1045 MUse* use = *i++;
1046 MConstant* constant = use->consumer()->block()->optimizedOutConstant(alloc);
1047 if (!alloc.ensureBallast()) {
1048 return false;
1049 }
1050
1051 // Update the resume point operand to use the optimized-out constant.
1052 use->setProducerUnchecked(constant);
1053 constant->addUseUnchecked(use);
1054 }
1055
1056 // Remove dangling pointers.
1057 this->uses_.clear();
1058 return true;
1059}
1060
1061void MDefinition::replaceAllLiveUsesWith(MDefinition* dom) {
1062 for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
1063 MUse* use = *i++;
1064 MNode* consumer = use->consumer();
1065 if (consumer->isResumePoint()) {
1066 continue;
1067 }
1068 if (consumer->isDefinition() &&
1069 consumer->toDefinition()->isRecoveredOnBailout()) {
1070 continue;
1071 }
1072
1073 // Update the operand to use the dominating definition.
1074 use->replaceProducer(dom);
1075 }
1076}
1077
1078MConstant* MConstant::New(TempAllocator& alloc, const Value& v) {
1079 return new (alloc) MConstant(alloc, v);
1080}
1081
1082MConstant* MConstant::New(TempAllocator::Fallible alloc, const Value& v) {
1083 return new (alloc) MConstant(alloc.alloc, v);
1084}
1085
1086MConstant* MConstant::NewFloat32(TempAllocator& alloc, double d) {
1087 MOZ_ASSERT(std::isnan(d) || d == double(float(d)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(std::isnan(d) || d == double(float(d)))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(std::isnan(d) || d == double(float(d))))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("std::isnan(d) || d == double(float(d))"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1087); AnnotateMozCrashReason("MOZ_ASSERT" "(" "std::isnan(d) || d == double(float(d))"
")"); do { *((volatile int*)__null) = 1087; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1088 return new (alloc) MConstant(float(d));
1089}
1090
1091MConstant* MConstant::NewInt64(TempAllocator& alloc, int64_t i) {
1092 return new (alloc) MConstant(MIRType::Int64, i);
1093}
1094
1095MConstant* MConstant::NewIntPtr(TempAllocator& alloc, intptr_t i) {
1096 return new (alloc) MConstant(MIRType::IntPtr, i);
1097}
1098
1099MConstant* MConstant::New(TempAllocator& alloc, const Value& v, MIRType type) {
1100 if (type == MIRType::Float32) {
1101 return NewFloat32(alloc, v.toNumber());
1102 }
1103 MConstant* res = New(alloc, v);
1104 MOZ_ASSERT(res->type() == type)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(res->type() == type)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(res->type() == type))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("res->type() == type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "res->type() == type"
")"); do { *((volatile int*)__null) = 1104; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1105 return res;
1106}
1107
1108MConstant* MConstant::NewObject(TempAllocator& alloc, JSObject* v) {
1109 return new (alloc) MConstant(v);
1110}
1111
1112MConstant* MConstant::NewShape(TempAllocator& alloc, Shape* s) {
1113 return new (alloc) MConstant(s);
1114}
1115
1116static MIRType MIRTypeFromValue(const js::Value& vp) {
1117 if (vp.isDouble()) {
1118 return MIRType::Double;
1119 }
1120 if (vp.isMagic()) {
1121 switch (vp.whyMagic()) {
1122 case JS_OPTIMIZED_OUT:
1123 return MIRType::MagicOptimizedOut;
1124 case JS_ELEMENTS_HOLE:
1125 return MIRType::MagicHole;
1126 case JS_IS_CONSTRUCTING:
1127 return MIRType::MagicIsConstructing;
1128 case JS_UNINITIALIZED_LEXICAL:
1129 return MIRType::MagicUninitializedLexical;
1130 default:
1131 MOZ_ASSERT_UNREACHABLE("Unexpected magic constant")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unexpected magic constant" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected magic constant" ")");
do { *((volatile int*)__null) = 1131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1132 }
1133 }
1134 return MIRTypeFromValueType(vp.extractNonDoubleType());
1135}
1136
1137MConstant::MConstant(TempAllocator& alloc, const js::Value& vp)
1138 : MNullaryInstruction(classOpcode) {
1139 setResultType(MIRTypeFromValue(vp));
1140
1141 MOZ_ASSERT(payload_.asBits == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(payload_.asBits == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(payload_.asBits == 0))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("payload_.asBits == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1141); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0"
")"); do { *((volatile int*)__null) = 1141; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1142
1143 switch (type()) {
1144 case MIRType::Undefined:
1145 case MIRType::Null:
1146 break;
1147 case MIRType::Boolean:
1148 payload_.b = vp.toBoolean();
1149 break;
1150 case MIRType::Int32:
1151 payload_.i32 = vp.toInt32();
1152 break;
1153 case MIRType::Double:
1154 payload_.d = vp.toDouble();
1155 break;
1156 case MIRType::String: {
1157 JSString* str = vp.toString();
1158 if (str->isAtomRef()) {
1159 str = str->atom();
1160 }
1161 MOZ_ASSERT(!IsInsideNursery(str))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsInsideNursery(str))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsInsideNursery(str)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!IsInsideNursery(str)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(str)"
")"); do { *((volatile int*)__null) = 1161; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1162 MOZ_ASSERT(str->isAtom())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(str->isAtom())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(str->isAtom()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("str->isAtom()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "str->isAtom()"
")"); do { *((volatile int*)__null) = 1162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1163 payload_.str = vp.toString();
1164 break;
1165 }
1166 case MIRType::Symbol:
1167 payload_.sym = vp.toSymbol();
1168 break;
1169 case MIRType::BigInt:
1170 MOZ_ASSERT(!IsInsideNursery(vp.toBigInt()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsInsideNursery(vp.toBigInt()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsInsideNursery(vp.toBigInt
())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!IsInsideNursery(vp.toBigInt())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1170); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(vp.toBigInt())"
")"); do { *((volatile int*)__null) = 1170; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1171 payload_.bi = vp.toBigInt();
1172 break;
1173 case MIRType::Object:
1174 MOZ_ASSERT(!IsInsideNursery(&vp.toObject()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsInsideNursery(&vp.toObject()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsInsideNursery(&vp.toObject
())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!IsInsideNursery(&vp.toObject())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1174); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(&vp.toObject())"
")"); do { *((volatile int*)__null) = 1174; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1175 payload_.obj = &vp.toObject();
1176 break;
1177 case MIRType::MagicOptimizedOut:
1178 case MIRType::MagicHole:
1179 case MIRType::MagicIsConstructing:
1180 case MIRType::MagicUninitializedLexical:
1181 break;
1182 default:
1183 MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1183); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type"
")"); do { *((volatile int*)__null) = 1183; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1184 }
1185
1186 setMovable();
1187}
1188
1189MConstant::MConstant(JSObject* obj) : MNullaryInstruction(classOpcode) {
1190 MOZ_ASSERT(!IsInsideNursery(obj))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsInsideNursery(obj))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsInsideNursery(obj)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!IsInsideNursery(obj)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1190); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(obj)"
")"); do { *((volatile int*)__null) = 1190; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1191 setResultType(MIRType::Object);
1192 payload_.obj = obj;
1193 setMovable();
1194}
1195
1196MConstant::MConstant(Shape* shape) : MNullaryInstruction(classOpcode) {
1197 setResultType(MIRType::Shape);
1198 payload_.shape = shape;
1199 setMovable();
1200}
1201
1202MConstant::MConstant(float f) : MNullaryInstruction(classOpcode) {
1203 setResultType(MIRType::Float32);
1204 payload_.f = f;
1205 setMovable();
1206}
1207
1208MConstant::MConstant(MIRType type, int64_t i)
1209 : MNullaryInstruction(classOpcode) {
1210 MOZ_ASSERT(type == MIRType::Int64 || type == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type == MIRType::Int64 || type == MIRType::IntPtr)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(type == MIRType::Int64 || type == MIRType::IntPtr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("type == MIRType::Int64 || type == MIRType::IntPtr"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int64 || type == MIRType::IntPtr"
")"); do { *((volatile int*)__null) = 1210; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1211 setResultType(type);
1212 if (type == MIRType::Int64) {
1213 payload_.i64 = i;
1214 } else {
1215 payload_.iptr = i;
1216 }
1217 setMovable();
1218}
1219
1220#ifdef DEBUG1
1221void MConstant::assertInitializedPayload() const {
1222 // valueHash() and equals() expect the unused payload bits to be
1223 // initialized to zero. Assert this in debug builds.
1224
1225 switch (type()) {
1226 case MIRType::Int32:
1227 case MIRType::Float32:
1228# if MOZ_LITTLE_ENDIAN()1
1229 MOZ_ASSERT((payload_.asBits >> 32) == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((payload_.asBits >> 32) == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((payload_.asBits >> 32
) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(payload_.asBits >> 32) == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1229); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0"
")"); do { *((volatile int*)__null) = 1229; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1230# else
1231 MOZ_ASSERT((payload_.asBits << 32) == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((payload_.asBits << 32) == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((payload_.asBits << 32
) == 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(payload_.asBits << 32) == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1231); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0"
")"); do { *((volatile int*)__null) = 1231; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1232# endif
1233 break;
1234 case MIRType::Boolean:
1235# if MOZ_LITTLE_ENDIAN()1
1236 MOZ_ASSERT((payload_.asBits >> 1) == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((payload_.asBits >> 1) == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((payload_.asBits >> 1)
== 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(payload_.asBits >> 1) == 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1236); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 1) == 0"
")"); do { *((volatile int*)__null) = 1236; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1237# else
1238 MOZ_ASSERT((payload_.asBits & ~(1ULL << 56)) == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((payload_.asBits & ~(1ULL << 56)) == 0)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((payload_.asBits & ~(1ULL << 56)) == 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("(payload_.asBits & ~(1ULL << 56)) == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits & ~(1ULL << 56)) == 0"
")"); do { *((volatile int*)__null) = 1238; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1239# endif
1240 break;
1241 case MIRType::Double:
1242 case MIRType::Int64:
1243 break;
1244 case MIRType::String:
1245 case MIRType::Object:
1246 case MIRType::Symbol:
1247 case MIRType::BigInt:
1248 case MIRType::IntPtr:
1249 case MIRType::Shape:
1250# if MOZ_LITTLE_ENDIAN()1
1251 MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits >> 32) == 0)do { if (64 == 32) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype((payload_.asBits >> 32) == 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((payload_.asBits >> 32) == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(payload_.asBits >> 32) == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1251); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0"
")"); do { *((volatile int*)__null) = 1251; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1252# else
1253 MOZ_ASSERT_IF(JS_BITS_PER_WORD == 32, (payload_.asBits << 32) == 0)do { if (64 == 32) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype((payload_.asBits << 32) == 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!((payload_.asBits << 32) == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(payload_.asBits << 32) == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1253); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0"
")"); do { *((volatile int*)__null) = 1253; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1254# endif
1255 break;
1256 default:
1257 MOZ_ASSERT(IsNullOrUndefined(type()) || IsMagicType(type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsNullOrUndefined(type()) || IsMagicType(type()))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(IsNullOrUndefined(type()) || IsMagicType(type())))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("IsNullOrUndefined(type()) || IsMagicType(type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNullOrUndefined(type()) || IsMagicType(type())"
")"); do { *((volatile int*)__null) = 1257; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1258 MOZ_ASSERT(payload_.asBits == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(payload_.asBits == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(payload_.asBits == 0))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("payload_.asBits == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1258); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0"
")"); do { *((volatile int*)__null) = 1258; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1259 break;
1260 }
1261}
1262#endif
1263
1264HashNumber MConstant::valueHash() const {
1265 static_assert(sizeof(Payload) == sizeof(uint64_t),
1266 "Code below assumes payload fits in 64 bits");
1267
1268 assertInitializedPayload();
1269 return ConstantValueHash(type(), payload_.asBits);
1270}
1271
1272HashNumber MConstantProto::valueHash() const {
1273 HashNumber hash = protoObject()->valueHash();
1274 const MDefinition* receiverObject = getReceiverObject();
1275 if (receiverObject) {
1276 hash = addU32ToHash(hash, receiverObject->id());
1277 }
1278 return hash;
1279}
1280
1281bool MConstant::congruentTo(const MDefinition* ins) const {
1282 return ins->isConstant() && equals(ins->toConstant());
1283}
1284
1285#ifdef JS_JITSPEW1
1286void MConstant::printOpcode(GenericPrinter& out) const {
1287 PrintOpcodeName(out, op());
1288 out.printf(" ");
1289 switch (type()) {
1290 case MIRType::Undefined:
1291 out.printf("undefined");
1292 break;
1293 case MIRType::Null:
1294 out.printf("null");
1295 break;
1296 case MIRType::Boolean:
1297 out.printf(toBoolean() ? "true" : "false");
1298 break;
1299 case MIRType::Int32:
1300 out.printf("0x%x", uint32_t(toInt32()));
1301 break;
1302 case MIRType::Int64:
1303 out.printf("0x%" PRIx64"l" "x", uint64_t(toInt64()));
1304 break;
1305 case MIRType::IntPtr:
1306 out.printf("0x%" PRIxPTR"l" "x", uintptr_t(toIntPtr()));
1307 break;
1308 case MIRType::Double:
1309 out.printf("%.16g", toDouble());
1310 break;
1311 case MIRType::Float32: {
1312 float val = toFloat32();
1313 out.printf("%.16g", val);
1314 break;
1315 }
1316 case MIRType::Object:
1317 if (toObject().is<JSFunction>()) {
1318 JSFunction* fun = &toObject().as<JSFunction>();
1319 if (fun->maybePartialDisplayAtom()) {
1320 out.put("function ");
1321 EscapedStringPrinter(out, fun->maybePartialDisplayAtom(), 0);
1322 } else {
1323 out.put("unnamed function");
1324 }
1325 if (fun->hasBaseScript()) {
1326 BaseScript* script = fun->baseScript();
1327 out.printf(" (%s:%u)", script->filename() ? script->filename() : "",
1328 script->lineno());
1329 }
1330 out.printf(" at %p", (void*)fun);
1331 break;
1332 }
1333 out.printf("object %p (%s)", (void*)&toObject(),
1334 toObject().getClass()->name);
1335 break;
1336 case MIRType::Symbol:
1337 out.printf("symbol at %p", (void*)toSymbol());
1338 break;
1339 case MIRType::BigInt:
1340 out.printf("BigInt at %p", (void*)toBigInt());
1341 break;
1342 case MIRType::String:
1343 out.printf("string %p", (void*)toString());
1344 break;
1345 case MIRType::Shape:
1346 out.printf("shape at %p", (void*)toShape());
1347 break;
1348 case MIRType::MagicHole:
1349 out.printf("magic hole");
1350 break;
1351 case MIRType::MagicIsConstructing:
1352 out.printf("magic is-constructing");
1353 break;
1354 case MIRType::MagicOptimizedOut:
1355 out.printf("magic optimized-out");
1356 break;
1357 case MIRType::MagicUninitializedLexical:
1358 out.printf("magic uninitialized-lexical");
1359 break;
1360 default:
1361 MOZ_CRASH("unexpected type")do { do { } while (false); MOZ_ReportCrash("" "unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1361); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected type"
")"); do { *((volatile int*)__null) = 1361; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1362 }
1363}
1364#endif
1365
1366bool MConstant::canProduceFloat32() const {
1367 if (!isTypeRepresentableAsDouble()) {
1368 return false;
1369 }
1370
1371 if (type() == MIRType::Int32) {
1372 return IsFloat32Representable(static_cast<double>(toInt32()));
1373 }
1374 if (type() == MIRType::Double) {
1375 return IsFloat32Representable(toDouble());
1376 }
1377 MOZ_ASSERT(type() == MIRType::Float32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Float32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Float32))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Float32"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1377); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Float32"
")"); do { *((volatile int*)__null) = 1377; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1378 return true;
1379}
1380
1381Value MConstant::toJSValue() const {
1382 // Wasm has types like int64 that cannot be stored as js::Value. It also
1383 // doesn't want the NaN canonicalization enforced by js::Value.
1384 MOZ_ASSERT(!IsCompilingWasm())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsCompilingWasm())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsCompilingWasm()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!IsCompilingWasm()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1384); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsCompilingWasm()"
")"); do { *((volatile int*)__null) = 1384; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1385
1386 switch (type()) {
1387 case MIRType::Undefined:
1388 return UndefinedValue();
1389 case MIRType::Null:
1390 return NullValue();
1391 case MIRType::Boolean:
1392 return BooleanValue(toBoolean());
1393 case MIRType::Int32:
1394 return Int32Value(toInt32());
1395 case MIRType::Double:
1396 return DoubleValue(toDouble());
1397 case MIRType::Float32:
1398 return Float32Value(toFloat32());
1399 case MIRType::String:
1400 return StringValue(toString());
1401 case MIRType::Symbol:
1402 return SymbolValue(toSymbol());
1403 case MIRType::BigInt:
1404 return BigIntValue(toBigInt());
1405 case MIRType::Object:
1406 return ObjectValue(toObject());
1407 case MIRType::Shape:
1408 return PrivateGCThingValue(toShape());
1409 case MIRType::MagicOptimizedOut:
1410 return MagicValue(JS_OPTIMIZED_OUT);
1411 case MIRType::MagicHole:
1412 return MagicValue(JS_ELEMENTS_HOLE);
1413 case MIRType::MagicIsConstructing:
1414 return MagicValue(JS_IS_CONSTRUCTING);
1415 case MIRType::MagicUninitializedLexical:
1416 return MagicValue(JS_UNINITIALIZED_LEXICAL);
1417 default:
1418 MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1418); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type"
")"); do { *((volatile int*)__null) = 1418; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1419 }
1420}
1421
1422bool MConstant::valueToBoolean(bool* res) const {
1423 switch (type()) {
1424 case MIRType::Boolean:
1425 *res = toBoolean();
1426 return true;
1427 case MIRType::Int32:
1428 *res = toInt32() != 0;
1429 return true;
1430 case MIRType::Int64:
1431 *res = toInt64() != 0;
1432 return true;
1433 case MIRType::Double:
1434 *res = !std::isnan(toDouble()) && toDouble() != 0.0;
1435 return true;
1436 case MIRType::Float32:
1437 *res = !std::isnan(toFloat32()) && toFloat32() != 0.0f;
1438 return true;
1439 case MIRType::Null:
1440 case MIRType::Undefined:
1441 *res = false;
1442 return true;
1443 case MIRType::Symbol:
1444 *res = true;
1445 return true;
1446 case MIRType::BigInt:
1447 *res = !toBigInt()->isZero();
1448 return true;
1449 case MIRType::String:
1450 *res = toString()->length() != 0;
1451 return true;
1452 case MIRType::Object:
1453 // TODO(Warp): Lazy groups have been removed.
1454 // We have to call EmulatesUndefined but that reads obj->group->clasp
1455 // and so it's racy when the object has a lazy group. The main callers
1456 // of this (MTest, MNot) already know how to fold the object case, so
1457 // just give up.
1458 return false;
1459 default:
1460 MOZ_ASSERT(IsMagicType(type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsMagicType(type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsMagicType(type())))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("IsMagicType(type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1460); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsMagicType(type())"
")"); do { *((volatile int*)__null) = 1460; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1461 return false;
1462 }
1463}
1464
1465#ifdef JS_JITSPEW1
1466void MControlInstruction::printOpcode(GenericPrinter& out) const {
1467 MDefinition::printOpcode(out);
1468 for (size_t j = 0; j < numSuccessors(); j++) {
1469 if (getSuccessor(j)) {
1470 out.printf(" block%u", getSuccessor(j)->id());
1471 } else {
1472 out.printf(" (null-to-be-patched)");
1473 }
1474 }
1475}
1476
1477void MCompare::printOpcode(GenericPrinter& out) const {
1478 MDefinition::printOpcode(out);
1479 out.printf(" %s", CodeName(jsop()));
1480}
1481
1482void MTypeOfIs::printOpcode(GenericPrinter& out) const {
1483 MDefinition::printOpcode(out);
1484 out.printf(" %s", CodeName(jsop()));
1485
1486 const char* name = "";
Value stored to 'name' during its initialization is never read
1487 switch (jstype()) {
1488 case JSTYPE_UNDEFINED:
1489 name = "undefined";
1490 break;
1491 case JSTYPE_OBJECT:
1492 name = "object";
1493 break;
1494 case JSTYPE_FUNCTION:
1495 name = "function";
1496 break;
1497 case JSTYPE_STRING:
1498 name = "string";
1499 break;
1500 case JSTYPE_NUMBER:
1501 name = "number";
1502 break;
1503 case JSTYPE_BOOLEAN:
1504 name = "boolean";
1505 break;
1506 case JSTYPE_SYMBOL:
1507 name = "symbol";
1508 break;
1509 case JSTYPE_BIGINT:
1510 name = "bigint";
1511 break;
1512# ifdef ENABLE_RECORD_TUPLE
1513 case JSTYPE_RECORD:
1514 case JSTYPE_TUPLE:
1515# endif
1516 case JSTYPE_LIMIT:
1517 MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1517); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type"
")"); do { *((volatile int*)__null) = 1517; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1518 }
1519 out.printf(" '%s'", name);
1520}
1521
1522void MLoadUnboxedScalar::printOpcode(GenericPrinter& out) const {
1523 MDefinition::printOpcode(out);
1524 out.printf(" %s", Scalar::name(storageType()));
1525}
1526
1527void MLoadDataViewElement::printOpcode(GenericPrinter& out) const {
1528 MDefinition::printOpcode(out);
1529 out.printf(" %s", Scalar::name(storageType()));
1530}
1531
1532void MAssertRange::printOpcode(GenericPrinter& out) const {
1533 MDefinition::printOpcode(out);
1534 out.put(" ");
1535 assertedRange()->dump(out);
1536}
1537
1538void MNearbyInt::printOpcode(GenericPrinter& out) const {
1539 MDefinition::printOpcode(out);
1540 const char* roundingModeStr = nullptr;
1541 switch (roundingMode_) {
1542 case RoundingMode::Up:
1543 roundingModeStr = "(up)";
1544 break;
1545 case RoundingMode::Down:
1546 roundingModeStr = "(down)";
1547 break;
1548 case RoundingMode::NearestTiesToEven:
1549 roundingModeStr = "(nearest ties even)";
1550 break;
1551 case RoundingMode::TowardsZero:
1552 roundingModeStr = "(towards zero)";
1553 break;
1554 }
1555 out.printf(" %s", roundingModeStr);
1556}
1557#endif
1558
1559AliasSet MRandom::getAliasSet() const { return AliasSet::Store(AliasSet::RNG); }
1560
1561MDefinition* MSign::foldsTo(TempAllocator& alloc) {
1562 MDefinition* input = getOperand(0);
1563 if (!input->isConstant() ||
1564 !input->toConstant()->isTypeRepresentableAsDouble()) {
1565 return this;
1566 }
1567
1568 double in = input->toConstant()->numberToDouble();
1569 double out = js::math_sign_impl(in);
1570
1571 if (type() == MIRType::Int32) {
1572 // Decline folding if this is an int32 operation, but the result type
1573 // isn't an int32.
1574 Value outValue = NumberValue(out);
1575 if (!outValue.isInt32()) {
1576 return this;
1577 }
1578
1579 return MConstant::New(alloc, outValue);
1580 }
1581
1582 return MConstant::New(alloc, DoubleValue(out));
1583}
1584
1585const char* MMathFunction::FunctionName(UnaryMathFunction function) {
1586 return GetUnaryMathFunctionName(function);
1587}
1588
1589#ifdef JS_JITSPEW1
1590void MMathFunction::printOpcode(GenericPrinter& out) const {
1591 MDefinition::printOpcode(out);
1592 out.printf(" %s", FunctionName(function()));
1593}
1594#endif
1595
1596MDefinition* MMathFunction::foldsTo(TempAllocator& alloc) {
1597 MDefinition* input = getOperand(0);
1598 if (!input->isConstant() ||
1599 !input->toConstant()->isTypeRepresentableAsDouble()) {
1600 return this;
1601 }
1602
1603 UnaryMathFunctionType funPtr = GetUnaryMathFunctionPtr(function());
1604
1605 double in = input->toConstant()->numberToDouble();
1606
1607 // The function pointer call can't GC.
1608 JS::AutoSuppressGCAnalysis nogc;
1609 double out = funPtr(in);
1610
1611 if (input->type() == MIRType::Float32) {
1612 return MConstant::NewFloat32(alloc, out);
1613 }
1614 return MConstant::New(alloc, DoubleValue(out));
1615}
1616
1617MDefinition* MAtomicIsLockFree::foldsTo(TempAllocator& alloc) {
1618 MDefinition* input = getOperand(0);
1619 if (!input->isConstant() || input->type() != MIRType::Int32) {
1620 return this;
1621 }
1622
1623 int32_t i = input->toConstant()->toInt32();
1624 return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfreeJS(i)));
1625}
1626
1627// Define |THIS_SLOT| as part of this translation unit, as it is used to
1628// specialized the parameterized |New| function calls introduced by
1629// TRIVIAL_NEW_WRAPPERS.
1630const int32_t MParameter::THIS_SLOT;
1631
1632#ifdef JS_JITSPEW1
1633void MParameter::printOpcode(GenericPrinter& out) const {
1634 PrintOpcodeName(out, op());
1635 if (index() == THIS_SLOT) {
1636 out.printf(" THIS_SLOT");
1637 } else {
1638 out.printf(" %d", index());
1639 }
1640}
1641#endif
1642
1643HashNumber MParameter::valueHash() const {
1644 HashNumber hash = MDefinition::valueHash();
1645 hash = addU32ToHash(hash, index_);
1646 return hash;
1647}
1648
1649bool MParameter::congruentTo(const MDefinition* ins) const {
1650 if (!ins->isParameter()) {
1651 return false;
1652 }
1653
1654 return ins->toParameter()->index() == index_;
1655}
1656
1657WrappedFunction::WrappedFunction(JSFunction* nativeFun, uint16_t nargs,
1658 FunctionFlags flags)
1659 : nativeFun_(nativeFun), nargs_(nargs), flags_(flags) {
1660 MOZ_ASSERT_IF(nativeFun, isNativeWithoutJitEntry())do { if (nativeFun) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(isNativeWithoutJitEntry())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isNativeWithoutJitEntry())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("isNativeWithoutJitEntry()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNativeWithoutJitEntry()"
")"); do { *((volatile int*)__null) = 1660; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1661
1662#ifdef DEBUG1
1663 // If we are not running off-main thread we can assert that the
1664 // metadata is consistent.
1665 if (!CanUseExtraThreads() && nativeFun) {
1666 MOZ_ASSERT(nativeFun->nargs() == nargs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nativeFun->nargs() == nargs)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nativeFun->nargs() == nargs
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"nativeFun->nargs() == nargs", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1666); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->nargs() == nargs"
")"); do { *((volatile int*)__null) = 1666; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1667
1668 MOZ_ASSERT(nativeFun->isNativeWithoutJitEntry() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()"
")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1669 isNativeWithoutJitEntry())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()"
")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1670 MOZ_ASSERT(nativeFun->hasJitEntry() == hasJitEntry())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nativeFun->hasJitEntry() == hasJitEntry())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(nativeFun->hasJitEntry() == hasJitEntry()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("nativeFun->hasJitEntry() == hasJitEntry()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1670); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->hasJitEntry() == hasJitEntry()"
")"); do { *((volatile int*)__null) = 1670; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1671 MOZ_ASSERT(nativeFun->isConstructor() == isConstructor())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nativeFun->isConstructor() == isConstructor())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nativeFun->isConstructor() == isConstructor()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("nativeFun->isConstructor() == isConstructor()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isConstructor() == isConstructor()"
")"); do { *((volatile int*)__null) = 1671; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1672 MOZ_ASSERT(nativeFun->isClassConstructor() == isClassConstructor())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nativeFun->isClassConstructor() == isClassConstructor
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(nativeFun->isClassConstructor() == isClassConstructor
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nativeFun->isClassConstructor() == isClassConstructor()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1672); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isClassConstructor() == isClassConstructor()"
")"); do { *((volatile int*)__null) = 1672; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1673 }
1674#endif
1675}
1676
1677MCall* MCall::New(TempAllocator& alloc, WrappedFunction* target, size_t maxArgc,
1678 size_t numActualArgs, bool construct, bool ignoresReturnValue,
1679 bool isDOMCall, mozilla::Maybe<DOMObjectKind> objectKind) {
1680 MOZ_ASSERT(isDOMCall == objectKind.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isDOMCall == objectKind.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isDOMCall == objectKind.isSome
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("isDOMCall == objectKind.isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1680); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isDOMCall == objectKind.isSome()"
")"); do { *((volatile int*)__null) = 1680; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1681 MOZ_ASSERT(maxArgc >= numActualArgs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(maxArgc >= numActualArgs)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(maxArgc >= numActualArgs)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("maxArgc >= numActualArgs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1681); AnnotateMozCrashReason("MOZ_ASSERT" "(" "maxArgc >= numActualArgs"
")"); do { *((volatile int*)__null) = 1681; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1682 MCall* ins;
1683 if (isDOMCall) {
1684 MOZ_ASSERT(!construct)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!construct)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!construct))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!construct", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!construct"
")"); do { *((volatile int*)__null) = 1684; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1685 ins = new (alloc) MCallDOMNative(target, numActualArgs, *objectKind);
1686 } else {
1687 ins =
1688 new (alloc) MCall(target, numActualArgs, construct, ignoresReturnValue);
1689 }
1690 if (!ins->init(alloc, maxArgc + NumNonArgumentOperands)) {
1691 return nullptr;
1692 }
1693 return ins;
1694}
1695
1696AliasSet MCallDOMNative::getAliasSet() const {
1697 const JSJitInfo* jitInfo = getJitInfo();
1698
1699 // If we don't know anything about the types of our arguments, we have to
1700 // assume that type-coercions can have side-effects, so we need to alias
1701 // everything.
1702 if (jitInfo->aliasSet() == JSJitInfo::AliasEverything ||
1703 !jitInfo->isTypedMethodJitInfo()) {
1704 return AliasSet::Store(AliasSet::Any);
1705 }
1706
1707 uint32_t argIndex = 0;
1708 const JSTypedMethodJitInfo* methodInfo =
1709 reinterpret_cast<const JSTypedMethodJitInfo*>(jitInfo);
1710 for (const JSJitInfo::ArgType* argType = methodInfo->argTypes;
1711 *argType != JSJitInfo::ArgTypeListEnd; ++argType, ++argIndex) {
1712 if (argIndex >= numActualArgs()) {
1713 // Passing through undefined can't have side-effects
1714 continue;
1715 }
1716 // getArg(0) is "this", so skip it
1717 MDefinition* arg = getArg(argIndex + 1);
1718 MIRType actualType = arg->type();
1719 // The only way to reliably avoid side-effects given the information we
1720 // have here is if we're passing in a known primitive value to an
1721 // argument that expects a primitive value.
1722 //
1723 // XXXbz maybe we need to communicate better information. For example,
1724 // a sequence argument will sort of unavoidably have side effects, while
1725 // a typed array argument won't have any, but both are claimed to be
1726 // JSJitInfo::Object. But if we do that, we need to watch out for our
1727 // movability/DCE-ability bits: if we have an arg type that can reliably
1728 // throw an exception on conversion, that might not affect our alias set
1729 // per se, but it should prevent us being moved or DCE-ed, unless we
1730 // know the incoming things match that arg type and won't throw.
1731 //
1732 if ((actualType == MIRType::Value || actualType == MIRType::Object) ||
1733 (*argType & JSJitInfo::Object)) {
1734 return AliasSet::Store(AliasSet::Any);
1735 }
1736 }
1737
1738 // We checked all the args, and they check out. So we only alias DOM
1739 // mutations or alias nothing, depending on the alias set in the jitinfo.
1740 if (jitInfo->aliasSet() == JSJitInfo::AliasNone) {
1741 return AliasSet::None();
1742 }
1743
1744 MOZ_ASSERT(jitInfo->aliasSet() == JSJitInfo::AliasDOMSets)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(jitInfo->aliasSet() == JSJitInfo::AliasDOMSets)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(jitInfo->aliasSet() == JSJitInfo::AliasDOMSets)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("jitInfo->aliasSet() == JSJitInfo::AliasDOMSets"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1744); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() == JSJitInfo::AliasDOMSets"
")"); do { *((volatile int*)__null) = 1744; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1745 return AliasSet::Load(AliasSet::DOMProperty);
1746}
1747
1748void MCallDOMNative::computeMovable() {
1749 // We are movable if the jitinfo says we can be and if we're also not
1750 // effectful. The jitinfo can't check for the latter, since it depends on
1751 // the types of our arguments.
1752 const JSJitInfo* jitInfo = getJitInfo();
1753
1754 MOZ_ASSERT_IF(jitInfo->isMovable,do { if (jitInfo->isMovable) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(jitInfo->aliasSet
() != JSJitInfo::AliasEverything)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(jitInfo->aliasSet() != JSJitInfo
::AliasEverything))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("jitInfo->aliasSet() != JSJitInfo::AliasEverything", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1755); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything"
")"); do { *((volatile int*)__null) = 1755; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1755 jitInfo->aliasSet() != JSJitInfo::AliasEverything)do { if (jitInfo->isMovable) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(jitInfo->aliasSet
() != JSJitInfo::AliasEverything)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(jitInfo->aliasSet() != JSJitInfo
::AliasEverything))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("jitInfo->aliasSet() != JSJitInfo::AliasEverything", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1755); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything"
")"); do { *((volatile int*)__null) = 1755; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1756
1757 if (jitInfo->isMovable && !isEffectful()) {
1758 setMovable();
1759 }
1760}
1761
1762bool MCallDOMNative::congruentTo(const MDefinition* ins) const {
1763 if (!isMovable()) {
1764 return false;
1765 }
1766
1767 if (!ins->isCall()) {
1768 return false;
1769 }
1770
1771 const MCall* call = ins->toCall();
1772
1773 if (!call->isCallDOMNative()) {
1774 return false;
1775 }
1776
1777 if (getSingleTarget() != call->getSingleTarget()) {
1778 return false;
1779 }
1780
1781 if (isConstructing() != call->isConstructing()) {
1782 return false;
1783 }
1784
1785 if (numActualArgs() != call->numActualArgs()) {
1786 return false;
1787 }
1788
1789 if (!congruentIfOperandsEqual(call)) {
1790 return false;
1791 }
1792
1793 // The other call had better be movable at this point!
1794 MOZ_ASSERT(call->isMovable())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(call->isMovable())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(call->isMovable()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("call->isMovable()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1794); AnnotateMozCrashReason("MOZ_ASSERT" "(" "call->isMovable()"
")"); do { *((volatile int*)__null) = 1794; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1795
1796 return true;
1797}
1798
1799const JSJitInfo* MCallDOMNative::getJitInfo() const {
1800 MOZ_ASSERT(getSingleTarget()->hasJitInfo())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(getSingleTarget()->hasJitInfo())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(getSingleTarget()->hasJitInfo
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("getSingleTarget()->hasJitInfo()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getSingleTarget()->hasJitInfo()"
")"); do { *((volatile int*)__null) = 1800; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1801 return getSingleTarget()->jitInfo();
1802}
1803
1804MCallClassHook* MCallClassHook::New(TempAllocator& alloc, JSNative target,
1805 uint32_t argc, bool constructing) {
1806 auto* ins = new (alloc) MCallClassHook(target, constructing);
1807
1808 // Add callee + |this| + (if constructing) newTarget.
1809 uint32_t numOperands = 2 + argc + constructing;
1810
1811 if (!ins->init(alloc, numOperands)) {
1812 return nullptr;
1813 }
1814
1815 return ins;
1816}
1817
1818MDefinition* MStringLength::foldsTo(TempAllocator& alloc) {
1819 if (string()->isConstant()) {
1820 JSString* str = string()->toConstant()->toString();
1821 return MConstant::New(alloc, Int32Value(str->length()));
1822 }
1823
1824 // MFromCharCode returns a one-element string.
1825 if (string()->isFromCharCode()) {
1826 return MConstant::New(alloc, Int32Value(1));
1827 }
1828
1829 return this;
1830}
1831
1832MDefinition* MConcat::foldsTo(TempAllocator& alloc) {
1833 if (lhs()->isConstant() && lhs()->toConstant()->toString()->empty()) {
1834 return rhs();
1835 }
1836
1837 if (rhs()->isConstant() && rhs()->toConstant()->toString()->empty()) {
1838 return lhs();
1839 }
1840
1841 return this;
1842}
1843
1844MDefinition* MStringConvertCase::foldsTo(TempAllocator& alloc) {
1845 MDefinition* string = this->string();
1846
1847 // Handle the pattern |str[idx].toUpperCase()| and simplify it from
1848 // |StringConvertCase(FromCharCode(CharCodeAt(str, idx)))| to just
1849 // |CharCodeConvertCase(CharCodeAt(str, idx))|.
1850 if (string->isFromCharCode()) {
1851 auto* charCode = string->toFromCharCode()->code();
1852 auto mode = mode_ == Mode::LowerCase ? MCharCodeConvertCase::LowerCase
1853 : MCharCodeConvertCase::UpperCase;
1854 return MCharCodeConvertCase::New(alloc, charCode, mode);
1855 }
1856
1857 // Handle the pattern |num.toString(base).toUpperCase()| and simplify it to
1858 // directly return the string representation in the correct case.
1859 if (string->isInt32ToStringWithBase()) {
1860 auto* toString = string->toInt32ToStringWithBase();
1861
1862 bool lowerCase = mode_ == Mode::LowerCase;
1863 if (toString->lowerCase() == lowerCase) {
1864 return toString;
1865 }
1866 return MInt32ToStringWithBase::New(alloc, toString->input(),
1867 toString->base(), lowerCase);
1868 }
1869
1870 return this;
1871}
1872
1873static bool IsSubstrTo(MSubstr* substr, int32_t len) {
1874 // We want to match this pattern:
1875 //
1876 // Substr(string, Constant(0), Min(Constant(length), StringLength(string)))
1877 //
1878 // which is generated for the self-hosted `String.p.{substring,slice,substr}`
1879 // functions when called with constants `start` and `end` parameters.
1880
1881 auto isConstantZero = [](auto* def) {
1882 return def->isConstant() && def->toConstant()->isInt32(0);
1883 };
1884
1885 if (!isConstantZero(substr->begin())) {
1886 return false;
1887 }
1888
1889 auto* length = substr->length();
1890 if (length->isBitOr()) {
1891 // Unnecessary bit-ops haven't yet been removed.
1892 auto* bitOr = length->toBitOr();
1893 if (isConstantZero(bitOr->lhs())) {
1894 length = bitOr->rhs();
1895 } else if (isConstantZero(bitOr->rhs())) {
1896 length = bitOr->lhs();
1897 }
1898 }
1899 if (!length->isMinMax() || length->toMinMax()->isMax()) {
1900 return false;
1901 }
1902
1903 auto* min = length->toMinMax();
1904 if (!min->lhs()->isConstant() && !min->rhs()->isConstant()) {
1905 return false;
1906 }
1907
1908 auto* minConstant = min->lhs()->isConstant() ? min->lhs()->toConstant()
1909 : min->rhs()->toConstant();
1910
1911 auto* minOperand = min->lhs()->isConstant() ? min->rhs() : min->lhs();
1912 if (!minOperand->isStringLength() ||
1913 minOperand->toStringLength()->string() != substr->string()) {
1914 return false;
1915 }
1916
1917 // Ensure |len| matches the substring's length.
1918 return minConstant->isInt32(len);
1919}
1920
1921MDefinition* MSubstr::foldsTo(TempAllocator& alloc) {
1922 // Fold |str.substring(0, 1)| to |str.charAt(0)|.
1923 if (!IsSubstrTo(this, 1)) {
1924 return this;
1925 }
1926
1927 auto* charCode = MCharCodeAtOrNegative::New(alloc, string(), begin());
1928 block()->insertBefore(this, charCode);
1929
1930 return MFromCharCodeEmptyIfNegative::New(alloc, charCode);
1931}
1932
1933MDefinition* MCharCodeAt::foldsTo(TempAllocator& alloc) {
1934 MDefinition* string = this->string();
1935 if (!string->isConstant() && !string->isFromCharCode()) {
1936 return this;
1937 }
1938
1939 MDefinition* index = this->index();
1940 if (index->isSpectreMaskIndex()) {
1941 index = index->toSpectreMaskIndex()->index();
1942 }
1943 if (!index->isConstant()) {
1944 return this;
1945 }
1946 int32_t idx = index->toConstant()->toInt32();
1947
1948 // Handle the pattern |s[idx].charCodeAt(0)|.
1949 if (string->isFromCharCode()) {
1950 if (idx != 0) {
1951 return this;
1952 }
1953
1954 // Simplify |CharCodeAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just
1955 // |CharCodeAt(s, idx)|.
1956 auto* charCode = string->toFromCharCode()->code();
1957 if (!charCode->isCharCodeAt()) {
1958 return this;
1959 }
1960
1961 return charCode;
1962 }
1963
1964 JSLinearString* str = &string->toConstant()->toString()->asLinear();
1965 if (idx < 0 || uint32_t(idx) >= str->length()) {
1966 return this;
1967 }
1968
1969 char16_t ch = str->latin1OrTwoByteChar(idx);
1970 return MConstant::New(alloc, Int32Value(ch));
1971}
1972
1973MDefinition* MCodePointAt::foldsTo(TempAllocator& alloc) {
1974 MDefinition* string = this->string();
1975 if (!string->isConstant() && !string->isFromCharCode()) {
1976 return this;
1977 }
1978
1979 MDefinition* index = this->index();
1980 if (index->isSpectreMaskIndex()) {
1981 index = index->toSpectreMaskIndex()->index();
1982 }
1983 if (!index->isConstant()) {
1984 return this;
1985 }
1986 int32_t idx = index->toConstant()->toInt32();
1987
1988 // Handle the pattern |s[idx].codePointAt(0)|.
1989 if (string->isFromCharCode()) {
1990 if (idx != 0) {
1991 return this;
1992 }
1993
1994 // Simplify |CodePointAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just
1995 // |CharCodeAt(s, idx)|.
1996 auto* charCode = string->toFromCharCode()->code();
1997 if (!charCode->isCharCodeAt()) {
1998 return this;
1999 }
2000
2001 return charCode;
2002 }
2003
2004 JSLinearString* str = &string->toConstant()->toString()->asLinear();
2005 if (idx < 0 || uint32_t(idx) >= str->length()) {
2006 return this;
2007 }
2008
2009 char32_t first = str->latin1OrTwoByteChar(idx);
2010 if (unicode::IsLeadSurrogate(first) && uint32_t(idx) + 1 < str->length()) {
2011 char32_t second = str->latin1OrTwoByteChar(idx + 1);
2012 if (unicode::IsTrailSurrogate(second)) {
2013 first = unicode::UTF16Decode(first, second);
2014 }
2015 }
2016 return MConstant::New(alloc, Int32Value(first));
2017}
2018
2019MDefinition* MToRelativeStringIndex::foldsTo(TempAllocator& alloc) {
2020 MDefinition* index = this->index();
2021 MDefinition* length = this->length();
2022
2023 if (!index->isConstant()) {
2024 return this;
2025 }
2026 if (!length->isStringLength() && !length->isConstant()) {
2027 return this;
2028 }
2029 MOZ_ASSERT_IF(length->isConstant(), length->toConstant()->toInt32() >= 0)do { if (length->isConstant()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(length->toConstant
()->toInt32() >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length->toConstant()->
toInt32() >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("length->toConstant()->toInt32() >= 0", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2029); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length->toConstant()->toInt32() >= 0"
")"); do { *((volatile int*)__null) = 2029; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2030
2031 int32_t relativeIndex = index->toConstant()->toInt32();
2032 if (relativeIndex >= 0) {
2033 return index;
2034 }
2035
2036 // Safe to truncate because |length| is never negative.
2037 return MAdd::New(alloc, index, length, TruncateKind::Truncate);
2038}
2039
2040template <size_t Arity>
2041[[nodiscard]] static bool EnsureFloatInputOrConvert(
2042 MAryInstruction<Arity>* owner, TempAllocator& alloc) {
2043 MOZ_ASSERT(!IsFloatingPointType(owner->type()),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFloatingPointType(owner->type()))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!IsFloatingPointType(owner->type())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsFloatingPointType(owner->type())"
" (" "Floating point types must check consumers" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2044); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())"
") (" "Floating point types must check consumers" ")"); do {
*((volatile int*)__null) = 2044; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2044 "Floating point types must check consumers")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFloatingPointType(owner->type()))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!IsFloatingPointType(owner->type())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsFloatingPointType(owner->type())"
" (" "Floating point types must check consumers" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2044); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())"
") (" "Floating point types must check consumers" ")"); do {
*((volatile int*)__null) = 2044; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2045
2046 if (AllOperandsCanProduceFloat32(owner)) {
2047 return true;
2048 }
2049 ConvertOperandsToDouble(owner, alloc);
2050 return false;
2051}
2052
2053template <size_t Arity>
2054[[nodiscard]] static bool EnsureFloatConsumersAndInputOrConvert(
2055 MAryInstruction<Arity>* owner, TempAllocator& alloc) {
2056 MOZ_ASSERT(IsFloatingPointType(owner->type()),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFloatingPointType(owner->type()))>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(IsFloatingPointType(owner->type())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("IsFloatingPointType(owner->type())"
" (" "Integer types don't need to check consumers" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())"
") (" "Integer types don't need to check consumers" ")"); do
{ *((volatile int*)__null) = 2057; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2057 "Integer types don't need to check consumers")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsFloatingPointType(owner->type()))>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(IsFloatingPointType(owner->type())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("IsFloatingPointType(owner->type())"
" (" "Integer types don't need to check consumers" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())"
") (" "Integer types don't need to check consumers" ")"); do
{ *((volatile int*)__null) = 2057; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2058
2059 if (AllOperandsCanProduceFloat32(owner) &&
2060 CheckUsesAreFloat32Consumers(owner)) {
2061 return true;
2062 }
2063 ConvertOperandsToDouble(owner, alloc);
2064 return false;
2065}
2066
2067void MFloor::trySpecializeFloat32(TempAllocator& alloc) {
2068 MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2068); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2068; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2069 if (EnsureFloatInputOrConvert(this, alloc)) {
2070 specialization_ = MIRType::Float32;
2071 }
2072}
2073
2074void MCeil::trySpecializeFloat32(TempAllocator& alloc) {
2075 MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2075); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2075; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2076 if (EnsureFloatInputOrConvert(this, alloc)) {
2077 specialization_ = MIRType::Float32;
2078 }
2079}
2080
2081void MRound::trySpecializeFloat32(TempAllocator& alloc) {
2082 MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2082; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2083 if (EnsureFloatInputOrConvert(this, alloc)) {
2084 specialization_ = MIRType::Float32;
2085 }
2086}
2087
2088void MTrunc::trySpecializeFloat32(TempAllocator& alloc) {
2089 MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2089); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2089; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2090 if (EnsureFloatInputOrConvert(this, alloc)) {
2091 specialization_ = MIRType::Float32;
2092 }
2093}
2094
2095void MNearbyInt::trySpecializeFloat32(TempAllocator& alloc) {
2096 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
2097 specialization_ = MIRType::Float32;
2098 setResultType(MIRType::Float32);
2099 }
2100}
2101
2102MGoto* MGoto::New(TempAllocator& alloc, MBasicBlock* target) {
2103 return new (alloc) MGoto(target);
2104}
2105
2106MGoto* MGoto::New(TempAllocator::Fallible alloc, MBasicBlock* target) {
2107 MOZ_ASSERT(target)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(target)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(target))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("target", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2107); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")"
); do { *((volatile int*)__null) = 2107; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2108 return new (alloc) MGoto(target);
2109}
2110
2111MGoto* MGoto::New(TempAllocator& alloc) { return new (alloc) MGoto(nullptr); }
2112
2113MDefinition* MBox::foldsTo(TempAllocator& alloc) {
2114 if (input()->isUnbox()) {
2115 return input()->toUnbox()->input();
2116 }
2117 return this;
2118}
2119
2120#ifdef JS_JITSPEW1
2121void MUnbox::printOpcode(GenericPrinter& out) const {
2122 PrintOpcodeName(out, op());
2123 out.printf(" ");
2124 getOperand(0)->printName(out);
2125 out.printf(" ");
2126
2127 switch (type()) {
2128 case MIRType::Int32:
2129 out.printf("to Int32");
2130 break;
2131 case MIRType::Double:
2132 out.printf("to Double");
2133 break;
2134 case MIRType::Boolean:
2135 out.printf("to Boolean");
2136 break;
2137 case MIRType::String:
2138 out.printf("to String");
2139 break;
2140 case MIRType::Symbol:
2141 out.printf("to Symbol");
2142 break;
2143 case MIRType::BigInt:
2144 out.printf("to BigInt");
2145 break;
2146 case MIRType::Object:
2147 out.printf("to Object");
2148 break;
2149 default:
2150 break;
2151 }
2152
2153 switch (mode()) {
2154 case Fallible:
2155 out.printf(" (fallible)");
2156 break;
2157 case Infallible:
2158 out.printf(" (infallible)");
2159 break;
2160 default:
2161 break;
2162 }
2163}
2164#endif
2165
2166MDefinition* MUnbox::foldsTo(TempAllocator& alloc) {
2167 if (input()->isBox()) {
2168 MDefinition* unboxed = input()->toBox()->input();
2169
2170 // Fold MUnbox(MBox(x)) => x if types match.
2171 if (unboxed->type() == type()) {
2172 if (fallible()) {
2173 unboxed->setImplicitlyUsedUnchecked();
2174 }
2175 return unboxed;
2176 }
2177
2178 // Fold MUnbox(MBox(x)) => MToDouble(x) if possible.
2179 if (type() == MIRType::Double &&
2180 IsTypeRepresentableAsDouble(unboxed->type())) {
2181 if (unboxed->isConstant()) {
2182 return MConstant::New(
2183 alloc, DoubleValue(unboxed->toConstant()->numberToDouble()));
2184 }
2185
2186 return MToDouble::New(alloc, unboxed);
2187 }
2188
2189 // MUnbox<Int32>(MBox<Double>(x)) will always fail, even if x can be
2190 // represented as an Int32. Fold to avoid unnecessary bailouts.
2191 if (type() == MIRType::Int32 && unboxed->type() == MIRType::Double) {
2192 auto* folded = MToNumberInt32::New(alloc, unboxed,
2193 IntConversionInputKind::NumbersOnly);
2194 folded->setGuard();
2195 return folded;
2196 }
2197 }
2198
2199 return this;
2200}
2201
2202#ifdef DEBUG1
2203void MPhi::assertLoopPhi() const {
2204 // getLoopPredecessorOperand and getLoopBackedgeOperand rely on these
2205 // predecessors being at known indices.
2206 if (block()->numPredecessors() == 2) {
2207 MBasicBlock* pred = block()->getPredecessor(0);
2208 MBasicBlock* back = block()->getPredecessor(1);
2209 MOZ_ASSERT(pred == block()->loopPredecessor())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pred == block()->loopPredecessor())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(pred == block()->loopPredecessor()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("pred == block()->loopPredecessor()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2209); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred == block()->loopPredecessor()"
")"); do { *((volatile int*)__null) = 2209; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2210 MOZ_ASSERT(pred->successorWithPhis() == block())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pred->successorWithPhis() == block())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(pred->successorWithPhis() == block()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("pred->successorWithPhis() == block()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->successorWithPhis() == block()"
")"); do { *((volatile int*)__null) = 2210; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2211 MOZ_ASSERT(pred->positionInPhiSuccessor() == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pred->positionInPhiSuccessor() == 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(pred->positionInPhiSuccessor() == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("pred->positionInPhiSuccessor() == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2211); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->positionInPhiSuccessor() == 0"
")"); do { *((volatile int*)__null) = 2211; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2212 MOZ_ASSERT(back == block()->backedge())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(back == block()->backedge())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(back == block()->backedge
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("back == block()->backedge()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()"
")"); do { *((volatile int*)__null) = 2212; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2213 MOZ_ASSERT(back->successorWithPhis() == block())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(back->successorWithPhis() == block())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(back->successorWithPhis() == block()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("back->successorWithPhis() == block()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2213); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()"
")"); do { *((volatile int*)__null) = 2213; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2214 MOZ_ASSERT(back->positionInPhiSuccessor() == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(back->positionInPhiSuccessor() == 1)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(back->positionInPhiSuccessor() == 1))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("back->positionInPhiSuccessor() == 1"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 1"
")"); do { *((volatile int*)__null) = 2214; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2215 } else {
2216 // After we remove fake loop predecessors for loop headers that
2217 // are only reachable via OSR, the only predecessor is the
2218 // loop backedge.
2219 MOZ_ASSERT(block()->numPredecessors() == 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(block()->numPredecessors() == 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(block()->numPredecessors(
) == 1))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("block()->numPredecessors() == 1", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 1"
")"); do { *((volatile int*)__null) = 2219; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2220 MOZ_ASSERT(block()->graph().osrBlock())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(block()->graph().osrBlock())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(block()->graph().osrBlock
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("block()->graph().osrBlock()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->graph().osrBlock()"
")"); do { *((volatile int*)__null) = 2220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2221 MOZ_ASSERT(!block()->graph().canBuildDominators())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!block()->graph().canBuildDominators())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!block()->graph().canBuildDominators()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!block()->graph().canBuildDominators()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!block()->graph().canBuildDominators()"
")"); do { *((volatile int*)__null) = 2221; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2222 MBasicBlock* back = block()->getPredecessor(0);
2223 MOZ_ASSERT(back == block()->backedge())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(back == block()->backedge())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(back == block()->backedge
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("back == block()->backedge()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()"
")"); do { *((volatile int*)__null) = 2223; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2224 MOZ_ASSERT(back->successorWithPhis() == block())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(back->successorWithPhis() == block())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(back->successorWithPhis() == block()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("back->successorWithPhis() == block()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2224); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()"
")"); do { *((volatile int*)__null) = 2224; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2225 MOZ_ASSERT(back->positionInPhiSuccessor() == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(back->positionInPhiSuccessor() == 0)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(back->positionInPhiSuccessor() == 0))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("back->positionInPhiSuccessor() == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 0"
")"); do { *((volatile int*)__null) = 2225; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2226 }
2227}
2228#endif
2229
2230MDefinition* MPhi::getLoopPredecessorOperand() const {
2231 // This should not be called after removing fake loop predecessors.
2232 MOZ_ASSERT(block()->numPredecessors() == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(block()->numPredecessors() == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(block()->numPredecessors(
) == 2))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("block()->numPredecessors() == 2", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2232); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2"
")"); do { *((volatile int*)__null) = 2232; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2233 assertLoopPhi();
2234 return getOperand(0);
2235}
2236
2237MDefinition* MPhi::getLoopBackedgeOperand() const {
2238 assertLoopPhi();
2239 uint32_t idx = block()->numPredecessors() == 2 ? 1 : 0;
2240 return getOperand(idx);
2241}
2242
2243void MPhi::removeOperand(size_t index) {
2244 MOZ_ASSERT(index < numOperands())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(index < numOperands())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(index < numOperands()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("index < numOperands()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index < numOperands()"
")"); do { *((volatile int*)__null) = 2244; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2245 MOZ_ASSERT(getUseFor(index)->index() == index)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(getUseFor(index)->index() == index)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(getUseFor(index)->index() == index))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("getUseFor(index)->index() == index"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->index() == index"
")"); do { *((volatile int*)__null) = 2245; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2246 MOZ_ASSERT(getUseFor(index)->consumer() == this)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(getUseFor(index)->consumer() == this)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(getUseFor(index)->consumer() == this))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("getUseFor(index)->consumer() == this"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2246); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->consumer() == this"
")"); do { *((volatile int*)__null) = 2246; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2247
2248 // If we have phi(..., a, b, c, d, ..., z) and we plan
2249 // on removing a, then first shift downward so that we have
2250 // phi(..., b, c, d, ..., z, z):
2251 MUse* p = inputs_.begin() + index;
2252 MUse* e = inputs_.end();
2253 p->producer()->removeUse(p);
2254 for (; p < e - 1; ++p) {
2255 MDefinition* producer = (p + 1)->producer();
2256 p->setProducerUnchecked(producer);
2257 producer->replaceUse(p + 1, p);
2258 }
2259
2260 // truncate the inputs_ list:
2261 inputs_.popBack();
2262}
2263
2264void MPhi::removeAllOperands() {
2265 for (MUse& p : inputs_) {
2266 p.producer()->removeUse(&p);
2267 }
2268 inputs_.clear();
2269}
2270
2271MDefinition* MPhi::foldsTernary(TempAllocator& alloc) {
2272 /* Look if this MPhi is a ternary construct.
2273 * This is a very loose term as it actually only checks for
2274 *
2275 * MTest X
2276 * / \
2277 * ... ...
2278 * \ /
2279 * MPhi X Y
2280 *
2281 * Which we will simply call:
2282 * x ? x : y or x ? y : x
2283 */
2284
2285 if (numOperands() != 2) {
2286 return nullptr;
2287 }
2288
2289 MOZ_ASSERT(block()->numPredecessors() == 2)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(block()->numPredecessors() == 2)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(block()->numPredecessors(
) == 2))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("block()->numPredecessors() == 2", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2289); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2"
")"); do { *((volatile int*)__null) = 2289; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2290
2291 MBasicBlock* pred = block()->immediateDominator();
2292 if (!pred || !pred->lastIns()->isTest()) {
2293 return nullptr;
2294 }
2295
2296 MTest* test = pred->lastIns()->toTest();
2297
2298 // True branch may only dominate one edge of MPhi.
2299 if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
2300 test->ifTrue()->dominates(block()->getPredecessor(1))) {
2301 return nullptr;
2302 }
2303
2304 // False branch may only dominate one edge of MPhi.
2305 if (test->ifFalse()->dominates(block()->getPredecessor(0)) ==
2306 test->ifFalse()->dominates(block()->getPredecessor(1))) {
2307 return nullptr;
2308 }
2309
2310 // True and false branch must dominate different edges of MPhi.
2311 if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
2312 test->ifFalse()->dominates(block()->getPredecessor(0))) {
2313 return nullptr;
2314 }
2315
2316 // We found a ternary construct.
2317 bool firstIsTrueBranch =
2318 test->ifTrue()->dominates(block()->getPredecessor(0));
2319 MDefinition* trueDef = firstIsTrueBranch ? getOperand(0) : getOperand(1);
2320 MDefinition* falseDef = firstIsTrueBranch ? getOperand(1) : getOperand(0);
2321
2322 // Accept either
2323 // testArg ? testArg : constant or
2324 // testArg ? constant : testArg
2325 if (!trueDef->isConstant() && !falseDef->isConstant()) {
2326 return nullptr;
2327 }
2328
2329 MConstant* c =
2330 trueDef->isConstant() ? trueDef->toConstant() : falseDef->toConstant();
2331 MDefinition* testArg = (trueDef == c) ? falseDef : trueDef;
2332 if (testArg != test->input()) {
2333 return nullptr;
2334 }
2335
2336 // This check should be a tautology, except that the constant might be the
2337 // result of the removal of a branch. In such case the domination scope of
2338 // the block which is holding the constant might be incomplete. This
2339 // condition is used to prevent doing this optimization based on incomplete
2340 // information.
2341 //
2342 // As GVN removed a branch, it will update the dominations rules before
2343 // trying to fold this MPhi again. Thus, this condition does not inhibit
2344 // this optimization.
2345 MBasicBlock* truePred = block()->getPredecessor(firstIsTrueBranch ? 0 : 1);
2346 MBasicBlock* falsePred = block()->getPredecessor(firstIsTrueBranch ? 1 : 0);
2347 if (!trueDef->block()->dominates(truePred) ||
2348 !falseDef->block()->dominates(falsePred)) {
2349 return nullptr;
2350 }
2351
2352 // If testArg is an int32 type we can:
2353 // - fold testArg ? testArg : 0 to testArg
2354 // - fold testArg ? 0 : testArg to 0
2355 if (testArg->type() == MIRType::Int32 && c->numberToDouble() == 0) {
2356 testArg->setGuardRangeBailoutsUnchecked();
2357
2358 // When folding to the constant we need to hoist it.
2359 if (trueDef == c && !c->block()->dominates(block())) {
2360 c->block()->moveBefore(pred->lastIns(), c);
2361 }
2362 return trueDef;
2363 }
2364
2365 // If testArg is an double type we can:
2366 // - fold testArg ? testArg : 0.0 to MNaNToZero(testArg)
2367 if (testArg->type() == MIRType::Double &&
2368 mozilla::IsPositiveZero(c->numberToDouble()) && c != trueDef) {
2369 MNaNToZero* replace = MNaNToZero::New(alloc, testArg);
2370 test->block()->insertBefore(test, replace);
2371 return replace;
2372 }
2373
2374 // If testArg is a string type we can:
2375 // - fold testArg ? testArg : "" to testArg
2376 // - fold testArg ? "" : testArg to ""
2377 if (testArg->type() == MIRType::String &&
2378 c->toString() == GetJitContext()->runtime->emptyString()) {
2379 // When folding to the constant we need to hoist it.
2380 if (trueDef == c && !c->block()->dominates(block())) {
2381 c->block()->moveBefore(pred->lastIns(), c);
2382 }
2383 return trueDef;
2384 }
2385
2386 return nullptr;
2387}
2388
2389MDefinition* MPhi::operandIfRedundant() {
2390 if (inputs_.length() == 0) {
2391 return nullptr;
2392 }
2393
2394 // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
2395 // returns the operand that it will always be equal to (a, in
2396 // those two cases).
2397 MDefinition* first = getOperand(0);
2398 for (size_t i = 1, e = numOperands(); i < e; i++) {
2399 MDefinition* op = getOperand(i);
2400 if (op != first && op != this) {
2401 return nullptr;
2402 }
2403 }
2404 return first;
2405}
2406
2407MDefinition* MPhi::foldsTo(TempAllocator& alloc) {
2408 if (MDefinition* def = operandIfRedundant()) {
2409 return def;
2410 }
2411
2412 if (MDefinition* def = foldsTernary(alloc)) {
2413 return def;
2414 }
2415
2416 return this;
2417}
2418
2419bool MPhi::congruentTo(const MDefinition* ins) const {
2420 if (!ins->isPhi()) {
2421 return false;
2422 }
2423
2424 // Phis in different blocks may have different control conditions.
2425 // For example, these phis:
2426 //
2427 // if (p)
2428 // goto a
2429 // a:
2430 // t = phi(x, y)
2431 //
2432 // if (q)
2433 // goto b
2434 // b:
2435 // s = phi(x, y)
2436 //
2437 // have identical operands, but they are not equvalent because t is
2438 // effectively p?x:y and s is effectively q?x:y.
2439 //
2440 // For now, consider phis in different blocks incongruent.
2441 if (ins->block() != block()) {
2442 return false;
2443 }
2444
2445 return congruentIfOperandsEqual(ins);
2446}
2447
2448void MPhi::updateForReplacement(MPhi* other) {
2449 // This function is called to fix the current Phi flags using it as a
2450 // replacement of the other Phi instruction |other|.
2451 //
2452 // When dealing with usage analysis, any Use will replace all other values,
2453 // such as Unused and Unknown. Unless both are Unused, the merge would be
2454 // Unknown.
2455 if (usageAnalysis_ == PhiUsage::Used ||
2456 other->usageAnalysis_ == PhiUsage::Used) {
2457 usageAnalysis_ = PhiUsage::Used;
2458 } else if (usageAnalysis_ != other->usageAnalysis_) {
2459 // this == unused && other == unknown
2460 // or this == unknown && other == unused
2461 usageAnalysis_ = PhiUsage::Unknown;
2462 } else {
2463 // this == unused && other == unused
2464 // or this == unknown && other = unknown
2465 MOZ_ASSERT(usageAnalysis_ == PhiUsage::Unused ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(usageAnalysis_ == PhiUsage::Unused || usageAnalysis_
== PhiUsage::Unknown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(usageAnalysis_ == PhiUsage::
Unused || usageAnalysis_ == PhiUsage::Unknown))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown"
")"); do { *((volatile int*)__null) = 2466; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2466 usageAnalysis_ == PhiUsage::Unknown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(usageAnalysis_ == PhiUsage::Unused || usageAnalysis_
== PhiUsage::Unknown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(usageAnalysis_ == PhiUsage::
Unused || usageAnalysis_ == PhiUsage::Unknown))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown"
")"); do { *((volatile int*)__null) = 2466; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2467 MOZ_ASSERT(usageAnalysis_ == other->usageAnalysis_)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(usageAnalysis_ == other->usageAnalysis_)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(usageAnalysis_ == other->usageAnalysis_))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("usageAnalysis_ == other->usageAnalysis_"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2467); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == other->usageAnalysis_"
")"); do { *((volatile int*)__null) = 2467; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2468 }
2469}
2470
2471/* static */
2472bool MPhi::markIteratorPhis(const PhiVector& iterators) {
2473 // Find and mark phis that must transitively hold an iterator live.
2474
2475 Vector<MPhi*, 8, SystemAllocPolicy> worklist;
2476
2477 for (MPhi* iter : iterators) {
2478 if (!iter->isInWorklist()) {
2479 if (!worklist.append(iter)) {
2480 return false;
2481 }
2482 iter->setInWorklist();
2483 }
2484 }
2485
2486 while (!worklist.empty()) {
2487 MPhi* phi = worklist.popCopy();
2488 phi->setNotInWorklist();
2489
2490 phi->setIterator();
2491 phi->setImplicitlyUsedUnchecked();
2492
2493 for (MUseDefIterator iter(phi); iter; iter++) {
2494 MDefinition* use = iter.def();
2495 if (!use->isInWorklist() && use->isPhi() && !use->toPhi()->isIterator()) {
2496 if (!worklist.append(use->toPhi())) {
2497 return false;
2498 }
2499 use->setInWorklist();
2500 }
2501 }
2502 }
2503
2504 return true;
2505}
2506
2507bool MPhi::typeIncludes(MDefinition* def) {
2508 MOZ_ASSERT(!IsMagicType(def->type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsMagicType(def->type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsMagicType(def->type())
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!IsMagicType(def->type())", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2508); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsMagicType(def->type())"
")"); do { *((volatile int*)__null) = 2508; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2509
2510 if (def->type() == MIRType::Int32 && this->type() == MIRType::Double) {
2511 return true;
2512 }
2513
2514 if (def->type() == MIRType::Value) {
2515 // This phi must be able to be any value.
2516 return this->type() == MIRType::Value;
2517 }
2518
2519 return this->mightBeType(def->type());
2520}
2521
2522void MCallBase::addArg(size_t argnum, MDefinition* arg) {
2523 // The operand vector is initialized in reverse order by WarpBuilder.
2524 // It cannot be checked for consistency until all arguments are added.
2525 // FixedList doesn't initialize its elements, so do an unchecked init.
2526 initOperand(argnum + NumNonArgumentOperands, arg);
2527}
2528
2529static inline bool IsConstant(MDefinition* def, double v) {
2530 if (!def->isConstant()) {
2531 return false;
2532 }
2533
2534 return NumbersAreIdentical(def->toConstant()->numberToDouble(), v);
2535}
2536
2537MDefinition* MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc) {
2538 // Identity operations are removed (for int32 only) in foldUnnecessaryBitop.
2539
2540 if (type() == MIRType::Int32) {
2541 if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
2542 return folded;
2543 }
2544 } else if (type() == MIRType::Int64) {
2545 if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
2546 return folded;
2547 }
2548 }
2549
2550 return this;
2551}
2552
2553MDefinition* MBinaryBitwiseInstruction::foldUnnecessaryBitop() {
2554 // It's probably OK to perform this optimization only for int32, as it will
2555 // have the greatest effect for asm.js code that is compiled with the JS
2556 // pipeline, and that code will not see int64 values.
2557
2558 if (type() != MIRType::Int32) {
2559 return this;
2560 }
2561
2562 // Fold unsigned shift right operator when the second operand is zero and
2563 // the only use is an unsigned modulo. Thus, the expression
2564 // |(x >>> 0) % y| becomes |x % y|.
2565 if (isUrsh() && IsUint32Type(this)) {
2566 MDefinition* defUse = maybeSingleDefUse();
2567 if (defUse && defUse->isMod() && defUse->toMod()->isUnsigned()) {
2568 return getOperand(0);
2569 }
2570 }
2571
2572 // Eliminate bitwise operations that are no-ops when used on integer
2573 // inputs, such as (x | 0).
2574
2575 MDefinition* lhs = getOperand(0);
2576 MDefinition* rhs = getOperand(1);
2577
2578 if (IsConstant(lhs, 0)) {
2579 return foldIfZero(0);
2580 }
2581
2582 if (IsConstant(rhs, 0)) {
2583 return foldIfZero(1);
2584 }
2585
2586 if (IsConstant(lhs, -1)) {
2587 return foldIfNegOne(0);
2588 }
2589
2590 if (IsConstant(rhs, -1)) {
2591 return foldIfNegOne(1);
2592 }
2593
2594 if (lhs == rhs) {
2595 return foldIfEqual();
2596 }
2597
2598 if (maskMatchesRightRange) {
2599 MOZ_ASSERT(lhs->isConstant())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->isConstant())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->isConstant()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("lhs->isConstant()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2599); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->isConstant()"
")"); do { *((volatile int*)__null) = 2599; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2600 MOZ_ASSERT(lhs->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->type() == MIRType::Int32
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"lhs->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2600); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2600; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2601 return foldIfAllBitsSet(0);
2602 }
2603
2604 if (maskMatchesLeftRange) {
2605 MOZ_ASSERT(rhs->isConstant())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->isConstant())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs->isConstant()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("rhs->isConstant()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2605); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->isConstant()"
")"); do { *((volatile int*)__null) = 2605; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2606 MOZ_ASSERT(rhs->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs->type() == MIRType::Int32
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"rhs->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2606); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2606; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2607 return foldIfAllBitsSet(1);
2608 }
2609
2610 return this;
2611}
2612
2613static inline bool CanProduceNegativeZero(MDefinition* def) {
2614 // Test if this instruction can produce negative zero even when bailing out
2615 // and changing types.
2616 switch (def->op()) {
2617 case MDefinition::Opcode::Constant:
2618 if (def->type() == MIRType::Double &&
2619 def->toConstant()->toDouble() == -0.0) {
2620 return true;
2621 }
2622 [[fallthrough]];
2623 case MDefinition::Opcode::BitAnd:
2624 case MDefinition::Opcode::BitOr:
2625 case MDefinition::Opcode::BitXor:
2626 case MDefinition::Opcode::BitNot:
2627 case MDefinition::Opcode::Lsh:
2628 case MDefinition::Opcode::Rsh:
2629 return false;
2630 default:
2631 return true;
2632 }
2633}
2634
2635static inline bool NeedNegativeZeroCheck(MDefinition* def) {
2636 if (def->isGuard() || def->isGuardRangeBailouts()) {
2637 return true;
2638 }
2639
2640 // Test if all uses have the same semantics for -0 and 0
2641 for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
2642 if (use->consumer()->isResumePoint()) {
2643 return true;
2644 }
2645
2646 MDefinition* use_def = use->consumer()->toDefinition();
2647 switch (use_def->op()) {
2648 case MDefinition::Opcode::Add: {
2649 // If add is truncating -0 and 0 are observed as the same.
2650 if (use_def->toAdd()->isTruncated()) {
2651 break;
2652 }
2653
2654 // x + y gives -0, when both x and y are -0
2655
2656 // Figure out the order in which the addition's operands will
2657 // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR
2658 // definitions for us so that this just requires comparing ids.
2659 MDefinition* first = use_def->toAdd()->lhs();
2660 MDefinition* second = use_def->toAdd()->rhs();
2661 if (first->id() > second->id()) {
2662 std::swap(first, second);
2663 }
2664 // Negative zero checks can be removed on the first executed
2665 // operand only if it is guaranteed the second executed operand
2666 // will produce a value other than -0. While the second is
2667 // typed as an int32, a bailout taken between execution of the
2668 // operands may change that type and cause a -0 to flow to the
2669 // second.
2670 //
2671 // There is no way to test whether there are any bailouts
2672 // between execution of the operands, so remove negative
2673 // zero checks from the first only if the second's type is
2674 // independent from type changes that may occur after bailing.
2675 if (def == first && CanProduceNegativeZero(second)) {
2676 return true;
2677 }
2678
2679 // The negative zero check can always be removed on the second
2680 // executed operand; by the time this executes the first will have
2681 // been evaluated as int32 and the addition's result cannot be -0.
2682 break;
2683 }
2684 case MDefinition::Opcode::Sub: {
2685 // If sub is truncating -0 and 0 are observed as the same
2686 if (use_def->toSub()->isTruncated()) {
2687 break;
2688 }
2689
2690 // x + y gives -0, when x is -0 and y is 0
2691
2692 // We can remove the negative zero check on the rhs, only if we
2693 // are sure the lhs isn't negative zero.
2694
2695 // The lhs is typed as integer (i.e. not -0.0), but it can bailout
2696 // and change type. This should be fine if the lhs is executed
2697 // first. However if the rhs is executed first, the lhs can bail,
2698 // change type and become -0.0 while the rhs has already been
2699 // optimized to not make a difference between zero and negative zero.
2700 MDefinition* lhs = use_def->toSub()->lhs();
2701 MDefinition* rhs = use_def->toSub()->rhs();
2702 if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs)) {
2703 return true;
2704 }
2705
2706 [[fallthrough]];
2707 }
2708 case MDefinition::Opcode::StoreElement:
2709 case MDefinition::Opcode::StoreHoleValueElement:
2710 case MDefinition::Opcode::LoadElement:
2711 case MDefinition::Opcode::LoadElementHole:
2712 case MDefinition::Opcode::LoadUnboxedScalar:
2713 case MDefinition::Opcode::LoadDataViewElement:
2714 case MDefinition::Opcode::LoadTypedArrayElementHole:
2715 case MDefinition::Opcode::CharCodeAt:
2716 case MDefinition::Opcode::Mod:
2717 case MDefinition::Opcode::InArray:
2718 // Only allowed to remove check when definition is the second operand
2719 if (use_def->getOperand(0) == def) {
2720 return true;
2721 }
2722 for (size_t i = 2, e = use_def->numOperands(); i < e; i++) {
2723 if (use_def->getOperand(i) == def) {
2724 return true;
2725 }
2726 }
2727 break;
2728 case MDefinition::Opcode::BoundsCheck:
2729 // Only allowed to remove check when definition is the first operand
2730 if (use_def->toBoundsCheck()->getOperand(1) == def) {
2731 return true;
2732 }
2733 break;
2734 case MDefinition::Opcode::ToString:
2735 case MDefinition::Opcode::FromCharCode:
2736 case MDefinition::Opcode::FromCodePoint:
2737 case MDefinition::Opcode::TableSwitch:
2738 case MDefinition::Opcode::Compare:
2739 case MDefinition::Opcode::BitAnd:
2740 case MDefinition::Opcode::BitOr:
2741 case MDefinition::Opcode::BitXor:
2742 case MDefinition::Opcode::Abs:
2743 case MDefinition::Opcode::TruncateToInt32:
2744 // Always allowed to remove check. No matter which operand.
2745 break;
2746 case MDefinition::Opcode::StoreElementHole:
2747 case MDefinition::Opcode::StoreTypedArrayElementHole:
2748 case MDefinition::Opcode::PostWriteElementBarrier:
2749 // Only allowed to remove check when definition is the third operand.
2750 for (size_t i = 0, e = use_def->numOperands(); i < e; i++) {
2751 if (i == 2) {
2752 continue;
2753 }
2754 if (use_def->getOperand(i) == def) {
2755 return true;
2756 }
2757 }
2758 break;
2759 default:
2760 return true;
2761 }
2762 }
2763 return false;
2764}
2765
2766#ifdef JS_JITSPEW1
2767void MBinaryArithInstruction::printOpcode(GenericPrinter& out) const {
2768 MDefinition::printOpcode(out);
2769
2770 switch (type()) {
2771 case MIRType::Int32:
2772 if (isDiv()) {
2773 out.printf(" [%s]", toDiv()->isUnsigned() ? "uint32" : "int32");
2774 } else if (isMod()) {
2775 out.printf(" [%s]", toMod()->isUnsigned() ? "uint32" : "int32");
2776 } else {
2777 out.printf(" [int32]");
2778 }
2779 break;
2780 case MIRType::Int64:
2781 if (isDiv()) {
2782 out.printf(" [%s]", toDiv()->isUnsigned() ? "uint64" : "int64");
2783 } else if (isMod()) {
2784 out.printf(" [%s]", toMod()->isUnsigned() ? "uint64" : "int64");
2785 } else {
2786 out.printf(" [int64]");
2787 }
2788 break;
2789 case MIRType::Float32:
2790 out.printf(" [float]");
2791 break;
2792 case MIRType::Double:
2793 out.printf(" [double]");
2794 break;
2795 default:
2796 break;
2797 }
2798}
2799#endif
2800
2801MDefinition* MRsh::foldsTo(TempAllocator& alloc) {
2802 MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc);
2803
2804 if (f != this) {
2805 return f;
2806 }
2807
2808 MDefinition* lhs = getOperand(0);
2809 MDefinition* rhs = getOperand(1);
2810
2811 // It's probably OK to perform this optimization only for int32, as it will
2812 // have the greatest effect for asm.js code that is compiled with the JS
2813 // pipeline, and that code will not see int64 values.
2814
2815 if (!lhs->isLsh() || !rhs->isConstant() || rhs->type() != MIRType::Int32) {
2816 return this;
2817 }
2818
2819 if (!lhs->getOperand(1)->isConstant() ||
2820 lhs->getOperand(1)->type() != MIRType::Int32) {
2821 return this;
2822 }
2823
2824 uint32_t shift = rhs->toConstant()->toInt32();
2825 uint32_t shift_lhs = lhs->getOperand(1)->toConstant()->toInt32();
2826 if (shift != shift_lhs) {
2827 return this;
2828 }
2829
2830 switch (shift) {
2831 case 16:
2832 return MSignExtendInt32::New(alloc, lhs->getOperand(0),
2833 MSignExtendInt32::Half);
2834 case 24:
2835 return MSignExtendInt32::New(alloc, lhs->getOperand(0),
2836 MSignExtendInt32::Byte);
2837 }
2838
2839 return this;
2840}
2841
2842MDefinition* MBinaryArithInstruction::foldsTo(TempAllocator& alloc) {
2843 MOZ_ASSERT(IsNumberType(type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsNumberType(type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsNumberType(type())))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2843); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 2843; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2844
2845 MDefinition* lhs = getOperand(0);
2846 MDefinition* rhs = getOperand(1);
2847
2848 if (type() == MIRType::Int64) {
2849 MOZ_ASSERT(!isTruncated())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isTruncated())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isTruncated()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!isTruncated()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isTruncated()"
")"); do { *((volatile int*)__null) = 2849; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2850
2851 if (MConstant* folded = EvaluateInt64ConstantOperands(alloc, this)) {
2852 if (!folded->block()) {
2853 block()->insertBefore(this, folded);
2854 }
2855 return folded;
2856 }
2857 if (isSub() || isDiv() || isMod()) {
2858 return this;
2859 }
2860 if (rhs->isConstant() &&
2861 rhs->toConstant()->toInt64() == int64_t(getIdentity())) {
2862 return lhs;
2863 }
2864 if (lhs->isConstant() &&
2865 lhs->toConstant()->toInt64() == int64_t(getIdentity())) {
2866 return rhs;
2867 }
2868 return this;
2869 }
2870
2871 if (MConstant* folded = EvaluateConstantOperands(alloc, this)) {
2872 if (isTruncated()) {
2873 if (!folded->block()) {
2874 block()->insertBefore(this, folded);
2875 }
2876 if (folded->type() != MIRType::Int32) {
2877 return MTruncateToInt32::New(alloc, folded);
2878 }
2879 }
2880 return folded;
2881 }
2882
2883 if (MConstant* folded = EvaluateConstantNaNOperand(this)) {
2884 MOZ_ASSERT(!isTruncated())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isTruncated())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isTruncated()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!isTruncated()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2884); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isTruncated()"
")"); do { *((volatile int*)__null) = 2884; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2885 return folded;
2886 }
2887
2888 if (mustPreserveNaN_) {
2889 return this;
2890 }
2891
2892 // 0 + -0 = 0. So we can't remove addition
2893 if (isAdd() && type() != MIRType::Int32) {
2894 return this;
2895 }
2896
2897 if (IsConstant(rhs, getIdentity())) {
2898 if (isTruncated()) {
2899 return MTruncateToInt32::New(alloc, lhs);
2900 }
2901 return lhs;
2902 }
2903
2904 // subtraction isn't commutative. So we can't remove subtraction when lhs
2905 // equals 0
2906 if (isSub()) {
2907 return this;
2908 }
2909
2910 if (IsConstant(lhs, getIdentity())) {
2911 if (isTruncated()) {
2912 return MTruncateToInt32::New(alloc, rhs);
2913 }
2914 return rhs; // id op x => x
2915 }
2916
2917 return this;
2918}
2919
2920void MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc) {
2921 MOZ_ASSERT(IsNumberType(type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsNumberType(type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsNumberType(type())))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2921); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 2921; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2922
2923 // Do not use Float32 if we can use int32.
2924 if (type() == MIRType::Int32) {
2925 return;
2926 }
2927
2928 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
2929 setResultType(MIRType::Float32);
2930 }
2931}
2932
2933void MMinMax::trySpecializeFloat32(TempAllocator& alloc) {
2934 if (type() == MIRType::Int32) {
2935 return;
2936 }
2937
2938 MDefinition* left = lhs();
2939 MDefinition* right = rhs();
2940
2941 if ((left->canProduceFloat32() ||
2942 (left->isMinMax() && left->type() == MIRType::Float32)) &&
2943 (right->canProduceFloat32() ||
2944 (right->isMinMax() && right->type() == MIRType::Float32))) {
2945 setResultType(MIRType::Float32);
2946 } else {
2947 ConvertOperandsToDouble(this, alloc);
2948 }
2949}
2950
2951MDefinition* MMinMax::foldsTo(TempAllocator& alloc) {
2952 MOZ_ASSERT(lhs()->type() == type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs()->type() == type())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs()->type() == type()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("lhs()->type() == type()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2952); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == type()"
")"); do { *((volatile int*)__null) = 2952; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2953 MOZ_ASSERT(rhs()->type() == type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs()->type() == type())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs()->type() == type()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("rhs()->type() == type()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2953); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == type()"
")"); do { *((volatile int*)__null) = 2953; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2954
2955 if (lhs() == rhs()) {
2956 return lhs();
2957 }
2958
2959 auto foldConstants = [&alloc](MDefinition* lhs, MDefinition* rhs,
2960 bool isMax) -> MConstant* {
2961 MOZ_ASSERT(lhs->type() == rhs->type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->type() == rhs->type())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->type() == rhs->type
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("lhs->type() == rhs->type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2961); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == rhs->type()"
")"); do { *((volatile int*)__null) = 2961; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2962 MOZ_ASSERT(lhs->toConstant()->isTypeRepresentableAsDouble())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->toConstant()->isTypeRepresentableAsDouble
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(lhs->toConstant()->isTypeRepresentableAsDouble
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("lhs->toConstant()->isTypeRepresentableAsDouble()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2962); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->toConstant()->isTypeRepresentableAsDouble()"
")"); do { *((volatile int*)__null) = 2962; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2963 MOZ_ASSERT(rhs->toConstant()->isTypeRepresentableAsDouble())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->toConstant()->isTypeRepresentableAsDouble
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(rhs->toConstant()->isTypeRepresentableAsDouble
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("rhs->toConstant()->isTypeRepresentableAsDouble()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->toConstant()->isTypeRepresentableAsDouble()"
")"); do { *((volatile int*)__null) = 2963; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2964
2965 double lnum = lhs->toConstant()->numberToDouble();
2966 double rnum = rhs->toConstant()->numberToDouble();
2967
2968 double result;
2969 if (isMax) {
2970 result = js::math_max_impl(lnum, rnum);
2971 } else {
2972 result = js::math_min_impl(lnum, rnum);
2973 }
2974
2975 // The folded MConstant should maintain the same MIRType with the original
2976 // inputs.
2977 if (lhs->type() == MIRType::Int32) {
2978 int32_t cast;
2979 if (mozilla::NumberEqualsInt32(result, &cast)) {
2980 return MConstant::New(alloc, Int32Value(cast));
2981 }
2982 return nullptr;
2983 }
2984 if (lhs->type() == MIRType::Float32) {
2985 return MConstant::NewFloat32(alloc, result);
2986 }
2987 MOZ_ASSERT(lhs->type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->type() == MIRType::Double)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->type() == MIRType::Double
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"lhs->type() == MIRType::Double", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 2987); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 2987; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2988 return MConstant::New(alloc, DoubleValue(result));
2989 };
2990
2991 // Try to fold the following patterns when |x| and |y| are constants.
2992 //
2993 // min(min(x, z), min(y, z)) = min(min(x, y), z)
2994 // max(max(x, z), max(y, z)) = max(max(x, y), z)
2995 // max(min(x, z), min(y, z)) = min(max(x, y), z)
2996 // min(max(x, z), max(y, z)) = max(min(x, y), z)
2997 if (lhs()->isMinMax() && rhs()->isMinMax()) {
2998 do {
2999 auto* left = lhs()->toMinMax();
3000 auto* right = rhs()->toMinMax();
3001 if (left->isMax() != right->isMax()) {
3002 break;
3003 }
3004
3005 MDefinition* x;
3006 MDefinition* y;
3007 MDefinition* z;
3008 if (left->lhs() == right->lhs()) {
3009 std::tie(x, y, z) = std::tuple{left->rhs(), right->rhs(), left->lhs()};
3010 } else if (left->lhs() == right->rhs()) {
3011 std::tie(x, y, z) = std::tuple{left->rhs(), right->lhs(), left->lhs()};
3012 } else if (left->rhs() == right->lhs()) {
3013 std::tie(x, y, z) = std::tuple{left->lhs(), right->rhs(), left->rhs()};
3014 } else if (left->rhs() == right->rhs()) {
3015 std::tie(x, y, z) = std::tuple{left->lhs(), right->lhs(), left->rhs()};
3016 } else {
3017 break;
3018 }
3019
3020 if (!x->isConstant() || !x->toConstant()->isTypeRepresentableAsDouble() ||
3021 !y->isConstant() || !y->toConstant()->isTypeRepresentableAsDouble()) {
3022 break;
3023 }
3024
3025 if (auto* folded = foldConstants(x, y, isMax())) {
3026 block()->insertBefore(this, folded);
3027 return MMinMax::New(alloc, folded, z, type(), left->isMax());
3028 }
3029 } while (false);
3030 }
3031
3032 // Fold min/max operations with same inputs.
3033 if (lhs()->isMinMax() || rhs()->isMinMax()) {
3034 auto* other = lhs()->isMinMax() ? lhs()->toMinMax() : rhs()->toMinMax();
3035 auto* operand = lhs()->isMinMax() ? rhs() : lhs();
3036
3037 if (operand == other->lhs() || operand == other->rhs()) {
3038 if (isMax() == other->isMax()) {
3039 // min(x, min(x, y)) = min(x, y)
3040 // max(x, max(x, y)) = max(x, y)
3041 return other;
3042 }
3043 if (!IsFloatingPointType(type())) {
3044 // When neither value is NaN:
3045 // max(x, min(x, y)) = x
3046 // min(x, max(x, y)) = x
3047
3048 // Ensure that any bailouts that we depend on to guarantee that |y| is
3049 // Int32 are not removed.
3050 auto* otherOp = operand == other->lhs() ? other->rhs() : other->lhs();
3051 otherOp->setGuardRangeBailoutsUnchecked();
3052
3053 return operand;
3054 }
3055 }
3056 }
3057
3058 if (!lhs()->isConstant() && !rhs()->isConstant()) {
3059 return this;
3060 }
3061
3062 // Directly apply math utility to compare the rhs() and lhs() when
3063 // they are both constants.
3064 if (lhs()->isConstant() && rhs()->isConstant()) {
3065 if (!lhs()->toConstant()->isTypeRepresentableAsDouble() ||
3066 !rhs()->toConstant()->isTypeRepresentableAsDouble()) {
3067 return this;
3068 }
3069
3070 if (auto* folded = foldConstants(lhs(), rhs(), isMax())) {
3071 return folded;
3072 }
3073 }
3074
3075 MDefinition* operand = lhs()->isConstant() ? rhs() : lhs();
3076 MConstant* constant =
3077 lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant();
3078
3079 if (operand->isToDouble() &&
3080 operand->getOperand(0)->type() == MIRType::Int32) {
3081 // min(int32, cte >= INT32_MAX) = int32
3082 if (!isMax() && constant->isTypeRepresentableAsDouble() &&
3083 constant->numberToDouble() >= INT32_MAX(2147483647)) {
3084 MLimitedTruncate* limit = MLimitedTruncate::New(
3085 alloc, operand->getOperand(0), TruncateKind::NoTruncate);
3086 block()->insertBefore(this, limit);
3087 MToDouble* toDouble = MToDouble::New(alloc, limit);
3088 return toDouble;
3089 }
3090
3091 // max(int32, cte <= INT32_MIN) = int32
3092 if (isMax() && constant->isTypeRepresentableAsDouble() &&
3093 constant->numberToDouble() <= INT32_MIN(-2147483647-1)) {
3094 MLimitedTruncate* limit = MLimitedTruncate::New(
3095 alloc, operand->getOperand(0), TruncateKind::NoTruncate);
3096 block()->insertBefore(this, limit);
3097 MToDouble* toDouble = MToDouble::New(alloc, limit);
3098 return toDouble;
3099 }
3100 }
3101
3102 auto foldLength = [](MDefinition* operand, MConstant* constant,
3103 bool isMax) -> MDefinition* {
3104 if ((operand->isArrayLength() || operand->isArrayBufferViewLength() ||
3105 operand->isArgumentsLength() || operand->isStringLength()) &&
3106 constant->type() == MIRType::Int32) {
3107 // (Array|ArrayBufferView|Arguments|String)Length is always >= 0.
3108 // max(array.length, cte <= 0) = array.length
3109 // min(array.length, cte <= 0) = cte
3110 if (constant->toInt32() <= 0) {
3111 return isMax ? operand : constant;
3112 }
3113 }
3114 return nullptr;
3115 };
3116
3117 if (auto* folded = foldLength(operand, constant, isMax())) {
3118 return folded;
3119 }
3120
3121 // Attempt to fold nested min/max operations which are produced by
3122 // self-hosted built-in functions.
3123 if (operand->isMinMax()) {
3124 auto* other = operand->toMinMax();
3125 MOZ_ASSERT(other->lhs()->type() == type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(other->lhs()->type() == type())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(other->lhs()->type() ==
type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("other->lhs()->type() == type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3125); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->lhs()->type() == type()"
")"); do { *((volatile int*)__null) = 3125; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3126 MOZ_ASSERT(other->rhs()->type() == type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(other->rhs()->type() == type())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(other->rhs()->type() ==
type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("other->rhs()->type() == type()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->rhs()->type() == type()"
")"); do { *((volatile int*)__null) = 3126; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3127
3128 MConstant* otherConstant = nullptr;
3129 MDefinition* otherOperand = nullptr;
3130 if (other->lhs()->isConstant()) {
3131 otherConstant = other->lhs()->toConstant();
3132 otherOperand = other->rhs();
3133 } else if (other->rhs()->isConstant()) {
3134 otherConstant = other->rhs()->toConstant();
3135 otherOperand = other->lhs();
3136 }
3137
3138 if (otherConstant && constant->isTypeRepresentableAsDouble() &&
3139 otherConstant->isTypeRepresentableAsDouble()) {
3140 if (isMax() == other->isMax()) {
3141 // Fold min(x, min(y, z)) to min(min(x, y), z) with constant min(x, y).
3142 // Fold max(x, max(y, z)) to max(max(x, y), z) with constant max(x, y).
3143 if (auto* left = foldConstants(constant, otherConstant, isMax())) {
3144 block()->insertBefore(this, left);
3145 return MMinMax::New(alloc, left, otherOperand, type(), isMax());
3146 }
3147 } else {
3148 // Fold min(x, max(y, z)) to max(min(x, y), min(x, z)).
3149 // Fold max(x, min(y, z)) to min(max(x, y), max(x, z)).
3150 //
3151 // But only do this when min(x, z) can also be simplified.
3152 if (auto* right = foldLength(otherOperand, constant, isMax())) {
3153 if (auto* left = foldConstants(constant, otherConstant, isMax())) {
3154 block()->insertBefore(this, left);
3155 return MMinMax::New(alloc, left, right, type(), !isMax());
3156 }
3157 }
3158 }
3159 }
3160 }
3161
3162 return this;
3163}
3164
3165#ifdef JS_JITSPEW1
3166void MMinMax::printOpcode(GenericPrinter& out) const {
3167 MDefinition::printOpcode(out);
3168 out.printf(" (%s)", isMax() ? "max" : "min");
3169}
3170
3171void MMinMaxArray::printOpcode(GenericPrinter& out) const {
3172 MDefinition::printOpcode(out);
3173 out.printf(" (%s)", isMax() ? "max" : "min");
3174}
3175#endif
3176
3177MDefinition* MPow::foldsConstant(TempAllocator& alloc) {
3178 // Both `x` and `p` in `x^p` must be constants in order to precompute.
3179 if (!input()->isConstant() || !power()->isConstant()) {
3180 return nullptr;
3181 }
3182 if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
3183 return nullptr;
3184 }
3185 if (!input()->toConstant()->isTypeRepresentableAsDouble()) {
3186 return nullptr;
3187 }
3188
3189 double x = input()->toConstant()->numberToDouble();
3190 double p = power()->toConstant()->numberToDouble();
3191 double result = js::ecmaPow(x, p);
3192 if (type() == MIRType::Int32) {
3193 int32_t cast;
3194 if (!mozilla::NumberIsInt32(result, &cast)) {
3195 // Reject folding if the result isn't an int32, because we'll bail anyway.
3196 return nullptr;
3197 }
3198 return MConstant::New(alloc, Int32Value(cast));
3199 }
3200 return MConstant::New(alloc, DoubleValue(result));
3201}
3202
3203MDefinition* MPow::foldsConstantPower(TempAllocator& alloc) {
3204 // If `p` in `x^p` isn't constant, we can't apply these folds.
3205 if (!power()->isConstant()) {
3206 return nullptr;
3207 }
3208 if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
3209 return nullptr;
3210 }
3211
3212 MOZ_ASSERT(type() == MIRType::Double || type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Double || type() == MIRType::Int32
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(type() == MIRType::Double || type() == MIRType::Int32
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"type() == MIRType::Double || type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double || type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3212; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3213
3214 // NOTE: The optimizations must match the optimizations used in |js::ecmaPow|
3215 // resp. |js::powi| to avoid differential testing issues.
3216
3217 double pow = power()->toConstant()->numberToDouble();
3218
3219 // Math.pow(x, 0.5) is a sqrt with edge-case detection.
3220 if (pow == 0.5) {
3221 MOZ_ASSERT(type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Double)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Double)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Double"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3221); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 3221; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3222 return MPowHalf::New(alloc, input());
3223 }
3224
3225 // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
3226 if (pow == -0.5) {
3227 MOZ_ASSERT(type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Double)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Double)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Double"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3227); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 3227; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3228 MPowHalf* half = MPowHalf::New(alloc, input());
3229 block()->insertBefore(this, half);
3230 MConstant* one = MConstant::New(alloc, DoubleValue(1.0));
3231 block()->insertBefore(this, one);
3232 return MDiv::New(alloc, one, half, MIRType::Double);
3233 }
3234
3235 // Math.pow(x, 1) == x.
3236 if (pow == 1.0) {
3237 return input();
3238 }
3239
3240 auto multiply = [this, &alloc](MDefinition* lhs, MDefinition* rhs) {
3241 MMul* mul = MMul::New(alloc, lhs, rhs, type());
3242 mul->setBailoutKind(bailoutKind());
3243
3244 // Multiplying the same number can't yield negative zero.
3245 mul->setCanBeNegativeZero(lhs != rhs && canBeNegativeZero());
3246 return mul;
3247 };
3248
3249 // Math.pow(x, 2) == x*x.
3250 if (pow == 2.0) {
3251 return multiply(input(), input());
3252 }
3253
3254 // Math.pow(x, 3) == x*x*x.
3255 if (pow == 3.0) {
3256 MMul* mul1 = multiply(input(), input());
3257 block()->insertBefore(this, mul1);
3258 return multiply(input(), mul1);
3259 }
3260
3261 // Math.pow(x, 4) == y*y, where y = x*x.
3262 if (pow == 4.0) {
3263 MMul* y = multiply(input(), input());
3264 block()->insertBefore(this, y);
3265 return multiply(y, y);
3266 }
3267
3268 // Math.pow(x, NaN) == NaN.
3269 if (std::isnan(pow)) {
3270 return power();
3271 }
3272
3273 // No optimization
3274 return nullptr;
3275}
3276
3277MDefinition* MPow::foldsTo(TempAllocator& alloc) {
3278 if (MDefinition* def = foldsConstant(alloc)) {
3279 return def;
3280 }
3281 if (MDefinition* def = foldsConstantPower(alloc)) {
3282 return def;
3283 }
3284 return this;
3285}
3286
3287MDefinition* MBigIntPow::foldsTo(TempAllocator& alloc) {
3288 auto* base = lhs();
3289 MOZ_ASSERT(base->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(base->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(base->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("base->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3289); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 3289; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3290
3291 auto* power = rhs();
3292 MOZ_ASSERT(power->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(power->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(power->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("power->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "power->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 3292; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3293
3294 // |power| must be a constant.
3295 if (!power->isConstant()) {
3296 return this;
3297 }
3298
3299 int32_t pow;
3300 if (BigInt::isInt32(power->toConstant()->toBigInt(), &pow)) {
3301 // x ** 1n == x.
3302 if (pow == 1) {
3303 return base;
3304 }
3305
3306 // x ** 2n == x*x.
3307 if (pow == 2) {
3308 auto* mul = MBigIntMul::New(alloc, base, base);
3309 mul->setBailoutKind(bailoutKind());
3310 return mul;
3311 }
3312 }
3313
3314 // No optimization
3315 return this;
3316}
3317
3318bool MBigIntPtrBinaryArithInstruction::isMaybeZero(MDefinition* ins) {
3319 MOZ_ASSERT(ins->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ins->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::IntPtr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ins->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::IntPtr"
")"); do { *((volatile int*)__null) = 3319; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3320 if (ins->isBigIntToIntPtr()) {
3321 ins = ins->toBigIntToIntPtr()->input();
3322 }
3323 if (ins->isConstant()) {
3324 if (ins->type() == MIRType::IntPtr) {
3325 return ins->toConstant()->toIntPtr() == 0;
3326 }
3327 MOZ_ASSERT(ins->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ins->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::BigInt
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ins->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3327); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 3327; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3328 return ins->toConstant()->toBigInt()->isZero();
3329 }
3330 return true;
3331}
3332
3333bool MBigIntPtrBinaryArithInstruction::isMaybeNegative(MDefinition* ins) {
3334 MOZ_ASSERT(ins->type() == MIRType::IntPtr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ins->type() == MIRType::IntPtr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::IntPtr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ins->type() == MIRType::IntPtr", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3334); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::IntPtr"
")"); do { *((volatile int*)__null) = 3334; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3335 if (ins->isBigIntToIntPtr()) {
3336 ins = ins->toBigIntToIntPtr()->input();
3337 }
3338 if (ins->isConstant()) {
3339 if (ins->type() == MIRType::IntPtr) {
3340 return ins->toConstant()->toIntPtr() < 0;
3341 }
3342 MOZ_ASSERT(ins->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ins->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::BigInt
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ins->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3342); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 3342; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3343 return ins->toConstant()->toBigInt()->isNegative();
3344 }
3345 return true;
3346}
3347
3348MDefinition* MInt32ToIntPtr::foldsTo(TempAllocator& alloc) {
3349 MDefinition* def = input();
3350 if (def->isConstant()) {
3351 int32_t i = def->toConstant()->toInt32();
3352 return MConstant::NewIntPtr(alloc, intptr_t(i));
3353 }
3354
3355 if (def->isNonNegativeIntPtrToInt32()) {
3356 return def->toNonNegativeIntPtrToInt32()->input();
3357 }
3358
3359 return this;
3360}
3361
3362bool MAbs::fallible() const {
3363 return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds());
3364}
3365
3366void MAbs::trySpecializeFloat32(TempAllocator& alloc) {
3367 // Do not use Float32 if we can use int32.
3368 if (input()->type() == MIRType::Int32) {
3369 return;
3370 }
3371
3372 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
3373 setResultType(MIRType::Float32);
3374 }
3375}
3376
3377MDefinition* MDiv::foldsTo(TempAllocator& alloc) {
3378 MOZ_ASSERT(IsNumberType(type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsNumberType(type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsNumberType(type())))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3378); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 3378; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3379
3380 if (type() == MIRType::Int64) {
3381 if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
3382 return folded;
3383 }
3384 return this;
3385 }
3386
3387 if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
3388 return folded;
3389 }
3390
3391 if (MDefinition* folded = EvaluateExactReciprocal(alloc, this)) {
3392 return folded;
3393 }
3394
3395 return this;
3396}
3397
3398void MDiv::analyzeEdgeCasesForward() {
3399 // This is only meaningful when doing integer division.
3400 if (type() != MIRType::Int32) {
3401 return;
3402 }
3403
3404 MOZ_ASSERT(lhs()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs()->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs()->type() == MIRType::
Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("lhs()->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3404; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3405 MOZ_ASSERT(rhs()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs()->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs()->type() == MIRType::
Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("rhs()->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3405); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3405; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3406
3407 // Try removing divide by zero check
3408 if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
3409 canBeDivideByZero_ = false;
3410 }
3411
3412 // If lhs is a constant int != INT32_MIN, then
3413 // negative overflow check can be skipped.
3414 if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(INT32_MIN(-2147483647-1))) {
3415 canBeNegativeOverflow_ = false;
3416 }
3417
3418 // If rhs is a constant int != -1, likewise.
3419 if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(-1)) {
3420 canBeNegativeOverflow_ = false;
3421 }
3422
3423 // If lhs is != 0, then negative zero check can be skipped.
3424 if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(0)) {
3425 setCanBeNegativeZero(false);
3426 }
3427
3428 // If rhs is >= 0, likewise.
3429 if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
3430 if (rhs()->toConstant()->toInt32() >= 0) {
3431 setCanBeNegativeZero(false);
3432 }
3433 }
3434}
3435
3436void MDiv::analyzeEdgeCasesBackward() {
3437 if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) {
3438 setCanBeNegativeZero(false);
3439 }
3440}
3441
3442bool MDiv::fallible() const { return !isTruncated(); }
3443
3444MDefinition* MMod::foldsTo(TempAllocator& alloc) {
3445 MOZ_ASSERT(IsNumberType(type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsNumberType(type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsNumberType(type())))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("IsNumberType(type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 3445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3446
3447 if (type() == MIRType::Int64) {
3448 if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
3449 return folded;
3450 }
3451 } else {
3452 if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
3453 return folded;
3454 }
3455 }
3456 return this;
3457}
3458
3459void MMod::analyzeEdgeCasesForward() {
3460 // These optimizations make sense only for integer division
3461 if (type() != MIRType::Int32) {
3462 return;
3463 }
3464
3465 if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
3466 canBeDivideByZero_ = false;
3467 }
3468
3469 if (rhs()->isConstant()) {
3470 int32_t n = rhs()->toConstant()->toInt32();
3471 if (n > 0 && !IsPowerOfTwo(uint32_t(n))) {
3472 canBePowerOfTwoDivisor_ = false;
3473 }
3474 }
3475}
3476
3477bool MMod::fallible() const {
3478 return !isTruncated() &&
3479 (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend());
3480}
3481
3482void MMathFunction::trySpecializeFloat32(TempAllocator& alloc) {
3483 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
3484 setResultType(MIRType::Float32);
3485 specialization_ = MIRType::Float32;
3486 }
3487}
3488
3489bool MMathFunction::isFloat32Commutative() const {
3490 switch (function_) {
3491 case UnaryMathFunction::Floor:
3492 case UnaryMathFunction::Ceil:
3493 case UnaryMathFunction::Round:
3494 case UnaryMathFunction::Trunc:
3495 return true;
3496 default:
3497 return false;
3498 }
3499}
3500
3501MHypot* MHypot::New(TempAllocator& alloc, const MDefinitionVector& vector) {
3502 uint32_t length = vector.length();
3503 MHypot* hypot = new (alloc) MHypot;
3504 if (!hypot->init(alloc, length)) {
3505 return nullptr;
3506 }
3507
3508 for (uint32_t i = 0; i < length; ++i) {
3509 hypot->initOperand(i, vector[i]);
3510 }
3511 return hypot;
3512}
3513
3514bool MAdd::fallible() const {
3515 // the add is fallible if range analysis does not say that it is finite, AND
3516 // either the truncation analysis shows that there are non-truncated uses.
3517 if (truncateKind() >= TruncateKind::IndirectTruncate) {
3518 return false;
3519 }
3520 if (range() && range()->hasInt32Bounds()) {
3521 return false;
3522 }
3523 return true;
3524}
3525
3526bool MSub::fallible() const {
3527 // see comment in MAdd::fallible()
3528 if (truncateKind() >= TruncateKind::IndirectTruncate) {
3529 return false;
3530 }
3531 if (range() && range()->hasInt32Bounds()) {
3532 return false;
3533 }
3534 return true;
3535}
3536
3537MDefinition* MSub::foldsTo(TempAllocator& alloc) {
3538 MDefinition* out = MBinaryArithInstruction::foldsTo(alloc);
3539 if (out != this) {
3540 return out;
3541 }
3542
3543 if (type() != MIRType::Int32) {
3544 return this;
3545 }
3546
3547 // Optimize X - X to 0. This optimization is only valid for Int32
3548 // values. Subtracting a floating point value from itself returns
3549 // NaN when the operand is either Infinity or NaN.
3550 if (lhs() == rhs()) {
3551 // Ensure that any bailouts that we depend on to guarantee that X
3552 // is Int32 are not removed.
3553 lhs()->setGuardRangeBailoutsUnchecked();
3554 return MConstant::New(alloc, Int32Value(0));
3555 }
3556
3557 return this;
3558}
3559
3560MDefinition* MMul::foldsTo(TempAllocator& alloc) {
3561 MDefinition* out = MBinaryArithInstruction::foldsTo(alloc);
3562 if (out != this) {
3563 return out;
3564 }
3565
3566 if (type() != MIRType::Int32) {
3567 return this;
3568 }
3569
3570 if (lhs() == rhs()) {
3571 setCanBeNegativeZero(false);
3572 }
3573
3574 return this;
3575}
3576
3577void MMul::analyzeEdgeCasesForward() {
3578 // Try to remove the check for negative zero
3579 // This only makes sense when using the integer multiplication
3580 if (type() != MIRType::Int32) {
3581 return;
3582 }
3583
3584 // If lhs is > 0, no need for negative zero check.
3585 if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) {
3586 if (lhs()->toConstant()->toInt32() > 0) {
3587 setCanBeNegativeZero(false);
3588 }
3589 }
3590
3591 // If rhs is > 0, likewise.
3592 if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
3593 if (rhs()->toConstant()->toInt32() > 0) {
3594 setCanBeNegativeZero(false);
3595 }
3596 }
3597}
3598
3599void MMul::analyzeEdgeCasesBackward() {
3600 if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) {
3601 setCanBeNegativeZero(false);
3602 }
3603}
3604
3605bool MMul::canOverflow() const {
3606 if (isTruncated()) {
3607 return false;
3608 }
3609 return !range() || !range()->hasInt32Bounds();
3610}
3611
3612bool MUrsh::fallible() const {
3613 if (bailoutsDisabled()) {
3614 return false;
3615 }
3616 return !range() || !range()->hasInt32Bounds();
3617}
3618
3619MIRType MCompare::inputType() {
3620 switch (compareType_) {
3621 case Compare_Undefined:
3622 return MIRType::Undefined;
3623 case Compare_Null:
3624 return MIRType::Null;
3625 case Compare_UInt32:
3626 case Compare_Int32:
3627 return MIRType::Int32;
3628 case Compare_IntPtr:
3629 case Compare_UIntPtr:
3630 return MIRType::IntPtr;
3631 case Compare_Double:
3632 return MIRType::Double;
3633 case Compare_Float32:
3634 return MIRType::Float32;
3635 case Compare_String:
3636 return MIRType::String;
3637 case Compare_Symbol:
3638 return MIRType::Symbol;
3639 case Compare_Object:
3640 return MIRType::Object;
3641 case Compare_BigInt:
3642 case Compare_BigInt_Int32:
3643 case Compare_BigInt_Double:
3644 case Compare_BigInt_String:
3645 return MIRType::BigInt;
3646 default:
3647 MOZ_CRASH("No known conversion")do { do { } while (false); MOZ_ReportCrash("" "No known conversion"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3647); AnnotateMozCrashReason("MOZ_CRASH(" "No known conversion"
")"); do { *((volatile int*)__null) = 3647; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3648 }
3649}
3650
3651static inline bool MustBeUInt32(MDefinition* def, MDefinition** pwrapped) {
3652 if (def->isUrsh()) {
3653 *pwrapped = def->toUrsh()->lhs();
3654 MDefinition* rhs = def->toUrsh()->rhs();
3655 return def->toUrsh()->bailoutsDisabled() && rhs->maybeConstantValue() &&
3656 rhs->maybeConstantValue()->isInt32(0);
3657 }
3658
3659 if (MConstant* defConst = def->maybeConstantValue()) {
3660 *pwrapped = defConst;
3661 return defConst->type() == MIRType::Int32 && defConst->toInt32() >= 0;
3662 }
3663
3664 *pwrapped = nullptr; // silence GCC warning
3665 return false;
3666}
3667
3668/* static */
3669bool MBinaryInstruction::unsignedOperands(MDefinition* left,
3670 MDefinition* right) {
3671 MDefinition* replace;
3672 if (!MustBeUInt32(left, &replace)) {
3673 return false;
3674 }
3675 if (replace->type() != MIRType::Int32) {
3676 return false;
3677 }
3678 if (!MustBeUInt32(right, &replace)) {
3679 return false;
3680 }
3681 if (replace->type() != MIRType::Int32) {
3682 return false;
3683 }
3684 return true;
3685}
3686
3687bool MBinaryInstruction::unsignedOperands() {
3688 return unsignedOperands(getOperand(0), getOperand(1));
3689}
3690
3691void MBinaryInstruction::replaceWithUnsignedOperands() {
3692 MOZ_ASSERT(unsignedOperands())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(unsignedOperands())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(unsignedOperands()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("unsignedOperands()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3692); AnnotateMozCrashReason("MOZ_ASSERT" "(" "unsignedOperands()"
")"); do { *((volatile int*)__null) = 3692; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3693
3694 for (size_t i = 0; i < numOperands(); i++) {
3695 MDefinition* replace;
3696 MustBeUInt32(getOperand(i), &replace);
3697 if (replace == getOperand(i)) {
3698 continue;
3699 }
3700
3701 getOperand(i)->setImplicitlyUsedUnchecked();
3702 replaceOperand(i, replace);
3703 }
3704}
3705
3706MDefinition* MBitNot::foldsTo(TempAllocator& alloc) {
3707 if (type() == MIRType::Int64) {
3708 return this;
3709 }
3710 MOZ_ASSERT(type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Int32))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Int32"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3710); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3710; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3711
3712 MDefinition* input = getOperand(0);
3713
3714 if (input->isConstant()) {
3715 js::Value v = Int32Value(~(input->toConstant()->toInt32()));
3716 return MConstant::New(alloc, v);
3717 }
3718
3719 if (input->isBitNot()) {
3720 MOZ_ASSERT(input->toBitNot()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(input->toBitNot()->type() == MIRType::Int32)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(input->toBitNot()->type() == MIRType::Int32)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("input->toBitNot()->type() == MIRType::Int32"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3720); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3720; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3721 MOZ_ASSERT(input->toBitNot()->getOperand(0)->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(input->toBitNot()->getOperand(0)->type() ==
MIRType::Int32)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(input->toBitNot()->getOperand
(0)->type() == MIRType::Int32))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("input->toBitNot()->getOperand(0)->type() == MIRType::Int32"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->getOperand(0)->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3721; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3722 return MTruncateToInt32::New(alloc,
3723 input->toBitNot()->input()); // ~~x => x | 0
3724 }
3725
3726 return this;
3727}
3728
3729static void AssertKnownClass(TempAllocator& alloc, MInstruction* ins,
3730 MDefinition* obj) {
3731#ifdef DEBUG1
3732 const JSClass* clasp = GetObjectKnownJSClass(obj);
3733 MOZ_ASSERT(clasp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(clasp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(clasp))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("clasp", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3733); AnnotateMozCrashReason("MOZ_ASSERT" "(" "clasp" ")")
; do { *((volatile int*)__null) = 3733; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3734
3735 auto* assert = MAssertClass::New(alloc, obj, clasp);
3736 ins->block()->insertBefore(ins, assert);
3737#endif
3738}
3739
3740MDefinition* MBoxNonStrictThis::foldsTo(TempAllocator& alloc) {
3741 MDefinition* in = input();
3742 if (in->isBox()) {
3743 in = in->toBox()->input();
3744 }
3745
3746 if (in->type() == MIRType::Object) {
3747 return in;
3748 }
3749
3750 return this;
3751}
3752
3753AliasSet MLoadArgumentsObjectArg::getAliasSet() const {
3754 return AliasSet::Load(AliasSet::Any);
3755}
3756
3757AliasSet MLoadArgumentsObjectArgHole::getAliasSet() const {
3758 return AliasSet::Load(AliasSet::Any);
3759}
3760
3761AliasSet MInArgumentsObjectArg::getAliasSet() const {
3762 // Loads |arguments.length|, but not the actual element, so we can use the
3763 // same alias-set as MArgumentsObjectLength.
3764 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
3765 AliasSet::DynamicSlot);
3766}
3767
3768AliasSet MArgumentsObjectLength::getAliasSet() const {
3769 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
3770 AliasSet::DynamicSlot);
3771}
3772
3773bool MGuardArgumentsObjectFlags::congruentTo(const MDefinition* ins) const {
3774 if (!ins->isGuardArgumentsObjectFlags() ||
3775 ins->toGuardArgumentsObjectFlags()->flags() != flags()) {
3776 return false;
3777 }
3778 return congruentIfOperandsEqual(ins);
3779}
3780
3781AliasSet MGuardArgumentsObjectFlags::getAliasSet() const {
3782 // The flags are packed with the length in a fixed private slot.
3783 return AliasSet::Load(AliasSet::FixedSlot);
3784}
3785
3786MDefinition* MIdToStringOrSymbol::foldsTo(TempAllocator& alloc) {
3787 if (idVal()->isBox()) {
3788 auto* input = idVal()->toBox()->input();
3789 MIRType idType = input->type();
3790 if (idType == MIRType::String || idType == MIRType::Symbol) {
3791 return idVal();
3792 }
3793 if (idType == MIRType::Int32) {
3794 auto* toString =
3795 MToString::New(alloc, input, MToString::SideEffectHandling::Bailout);
3796 block()->insertBefore(this, toString);
3797
3798 return MBox::New(alloc, toString);
3799 }
3800 }
3801
3802 return this;
3803}
3804
3805MDefinition* MReturnFromCtor::foldsTo(TempAllocator& alloc) {
3806 MDefinition* rval = value();
3807 if (rval->isBox()) {
3808 rval = rval->toBox()->input();
3809 }
3810
3811 if (rval->type() == MIRType::Object) {
3812 return rval;
3813 }
3814
3815 if (rval->type() != MIRType::Value) {
3816 return object();
3817 }
3818
3819 return this;
3820}
3821
3822MDefinition* MTypeOf::foldsTo(TempAllocator& alloc) {
3823 MDefinition* unboxed = input();
3824 if (unboxed->isBox()) {
3825 unboxed = unboxed->toBox()->input();
3826 }
3827
3828 JSType type;
3829 switch (unboxed->type()) {
3830 case MIRType::Double:
3831 case MIRType::Float32:
3832 case MIRType::Int32:
3833 type = JSTYPE_NUMBER;
3834 break;
3835 case MIRType::String:
3836 type = JSTYPE_STRING;
3837 break;
3838 case MIRType::Symbol:
3839 type = JSTYPE_SYMBOL;
3840 break;
3841 case MIRType::BigInt:
3842 type = JSTYPE_BIGINT;
3843 break;
3844 case MIRType::Null:
3845 type = JSTYPE_OBJECT;
3846 break;
3847 case MIRType::Undefined:
3848 type = JSTYPE_UNDEFINED;
3849 break;
3850 case MIRType::Boolean:
3851 type = JSTYPE_BOOLEAN;
3852 break;
3853 case MIRType::Object: {
3854 KnownClass known = GetObjectKnownClass(unboxed);
3855 if (known != KnownClass::None) {
3856 if (known == KnownClass::Function) {
3857 type = JSTYPE_FUNCTION;
3858 } else {
3859 type = JSTYPE_OBJECT;
3860 }
3861
3862 AssertKnownClass(alloc, this, unboxed);
3863 break;
3864 }
3865 [[fallthrough]];
3866 }
3867 default:
3868 return this;
3869 }
3870
3871 return MConstant::New(alloc, Int32Value(static_cast<int32_t>(type)));
3872}
3873
3874MDefinition* MTypeOfName::foldsTo(TempAllocator& alloc) {
3875 MOZ_ASSERT(input()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(input()->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(input()->type() == MIRType
::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("input()->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3875; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3876
3877 if (!input()->isConstant()) {
3878 return this;
3879 }
3880
3881 static_assert(JSTYPE_UNDEFINED == 0);
3882
3883 int32_t type = input()->toConstant()->toInt32();
3884 MOZ_ASSERT(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3884); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT"
")"); do { *((volatile int*)__null) = 3884; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3885
3886 JSString* name =
3887 TypeName(static_cast<JSType>(type), GetJitContext()->runtime->names());
3888 return MConstant::New(alloc, StringValue(name));
3889}
3890
3891MUrsh* MUrsh::NewWasm(TempAllocator& alloc, MDefinition* left,
3892 MDefinition* right, MIRType type) {
3893 MUrsh* ins = new (alloc) MUrsh(left, right, type);
3894
3895 // Since Ion has no UInt32 type, we use Int32 and we have a special
3896 // exception to the type rules: we can return values in
3897 // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type
3898 // without bailing out. This is necessary because Ion has no UInt32
3899 // type and we can't have bailouts in wasm code.
3900 ins->bailoutsDisabled_ = true;
3901
3902 return ins;
3903}
3904
3905MResumePoint* MResumePoint::New(TempAllocator& alloc, MBasicBlock* block,
3906 jsbytecode* pc, ResumeMode mode) {
3907 MResumePoint* resume = new (alloc) MResumePoint(block, pc, mode);
3908 if (!resume->init(alloc)) {
3909 block->discardPreAllocatedResumePoint(resume);
3910 return nullptr;
3911 }
3912 resume->inherit(block);
3913 return resume;
3914}
3915
3916MResumePoint::MResumePoint(MBasicBlock* block, jsbytecode* pc, ResumeMode mode)
3917 : MNode(block, Kind::ResumePoint),
3918 pc_(pc),
3919 instruction_(nullptr),
3920 mode_(mode) {
3921 block->addResumePoint(this);
3922}
3923
3924bool MResumePoint::init(TempAllocator& alloc) {
3925 return operands_.init(alloc, block()->stackDepth());
3926}
3927
3928MResumePoint* MResumePoint::caller() const {
3929 return block()->callerResumePoint();
3930}
3931
3932void MResumePoint::inherit(MBasicBlock* block) {
3933 // FixedList doesn't initialize its elements, so do unchecked inits.
3934 for (size_t i = 0; i < stackDepth(); i++) {
3935 initOperand(i, block->getSlot(i));
3936 }
3937}
3938
3939void MResumePoint::addStore(TempAllocator& alloc, MDefinition* store,
3940 const MResumePoint* cache) {
3941 MOZ_ASSERT(block()->outerResumePoint() != this)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(block()->outerResumePoint() != this)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(block()->outerResumePoint() != this))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("block()->outerResumePoint() != this"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3941); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->outerResumePoint() != this"
")"); do { *((volatile int*)__null) = 3941; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3942 MOZ_ASSERT_IF(cache, !cache->stores_.empty())do { if (cache) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!cache->stores_.empty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!cache->stores_.empty()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!cache->stores_.empty()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3942); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!cache->stores_.empty()"
")"); do { *((volatile int*)__null) = 3942; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3943
3944 if (cache && cache->stores_.begin()->operand == store) {
3945 // If the last resume point had the same side-effect stack, then we can
3946 // reuse the current side effect without cloning it. This is a simple
3947 // way to share common context by making a spaghetti stack.
3948 if (++cache->stores_.begin() == stores_.begin()) {
3949 stores_.copy(cache->stores_);
3950 return;
3951 }
3952 }
3953
3954 // Ensure that the store would not be deleted by DCE.
3955 MOZ_ASSERT(store->isEffectful())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(store->isEffectful())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(store->isEffectful()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("store->isEffectful()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "store->isEffectful()"
")"); do { *((volatile int*)__null) = 3955; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3956
3957 MStoreToRecover* top = new (alloc) MStoreToRecover(store);
3958 stores_.push(top);
3959}
3960
3961#ifdef JS_JITSPEW1
3962void MResumePoint::dump(GenericPrinter& out) const {
3963 out.printf("resumepoint mode=");
3964
3965 switch (mode()) {
3966 case ResumeMode::ResumeAt:
3967 if (instruction_) {
3968 out.printf("ResumeAt(%u)", instruction_->id());
3969 } else {
3970 out.printf("ResumeAt");
3971 }
3972 break;
3973 default:
3974 out.put(ResumeModeToString(mode()));
3975 break;
3976 }
3977
3978 if (MResumePoint* c = caller()) {
3979 out.printf(" (caller in block%u)", c->block()->id());
3980 }
3981
3982 for (size_t i = 0; i < numOperands(); i++) {
3983 out.printf(" ");
3984 if (operands_[i].hasProducer()) {
3985 getOperand(i)->printName(out);
3986 } else {
3987 out.printf("(null)");
3988 }
3989 }
3990 out.printf("\n");
3991}
3992
3993void MResumePoint::dump() const {
3994 Fprinter out(stderrstderr);
3995 dump(out);
3996 out.finish();
3997}
3998#endif
3999
4000bool MResumePoint::isObservableOperand(MUse* u) const {
4001 return isObservableOperand(indexOf(u));
4002}
4003
4004bool MResumePoint::isObservableOperand(size_t index) const {
4005 return block()->info().isObservableSlot(index);
4006}
4007
4008bool MResumePoint::isRecoverableOperand(MUse* u) const {
4009 return block()->info().isRecoverableOperand(indexOf(u));
4010}
4011
4012MDefinition* MBigIntToIntPtr::foldsTo(TempAllocator& alloc) {
4013 MDefinition* def = input();
4014
4015 // If the operand converts an IntPtr to BigInt, drop both conversions.
4016 if (def->isIntPtrToBigInt()) {
4017 return def->toIntPtrToBigInt()->input();
4018 }
4019
4020 // Fold this operation if the input operand is constant.
4021 if (def->isConstant()) {
4022 BigInt* bigInt = def->toConstant()->toBigInt();
4023 intptr_t i;
4024 if (BigInt::isIntPtr(bigInt, &i)) {
4025 return MConstant::NewIntPtr(alloc, i);
4026 }
4027 }
4028
4029 // Fold BigIntToIntPtr(Int64ToBigInt(int64)) to Int64ToIntPtr(int64)
4030 if (def->isInt64ToBigInt()) {
4031 auto* toBigInt = def->toInt64ToBigInt();
4032 return MInt64ToIntPtr::New(alloc, toBigInt->input(),
4033 toBigInt->elementType());
4034 }
4035
4036 return this;
4037}
4038
4039MDefinition* MIntPtrToBigInt::foldsTo(TempAllocator& alloc) {
4040 MDefinition* def = input();
4041
4042 // If the operand converts a BigInt to IntPtr, drop both conversions.
4043 if (def->isBigIntToIntPtr()) {
4044 return def->toBigIntToIntPtr()->input();
4045 }
4046
4047 return this;
4048}
4049
4050MDefinition* MTruncateBigIntToInt64::foldsTo(TempAllocator& alloc) {
4051 MDefinition* input = getOperand(0);
4052
4053 if (input->isBox()) {
4054 input = input->getOperand(0);
4055 }
4056
4057 // If the operand converts an I64 to BigInt, drop both conversions.
4058 if (input->isInt64ToBigInt()) {
4059 return input->getOperand(0);
4060 }
4061
4062 // If the operand converts an I32 to BigInt, extend the I32 to I64.
4063 if (input->isInt32ToBigInt()) {
4064 auto* int32 = input->toInt32ToBigInt()->input();
4065 if (int32->isConstant()) {
4066 int32_t c = int32->toConstant()->toInt32();
4067 return MConstant::NewInt64(alloc, int64_t(c));
4068 }
4069 return MExtendInt32ToInt64::New(alloc, int32, /* isUnsigned = */ false);
4070 }
4071
4072 // If the operand is an IntPtr, extend the IntPtr to I64.
4073 if (input->isIntPtrToBigInt()) {
4074 auto* intPtr = input->toIntPtrToBigInt()->input();
4075 return MIntPtrToInt64::New(alloc, intPtr);
4076 }
4077
4078 // Fold this operation if the input operand is constant.
4079 if (input->isConstant()) {
4080 return MConstant::NewInt64(
4081 alloc, BigInt::toInt64(input->toConstant()->toBigInt()));
4082 }
4083
4084 return this;
4085}
4086
4087MDefinition* MToInt64::foldsTo(TempAllocator& alloc) {
4088 MDefinition* input = getOperand(0);
4089
4090 if (input->isBox()) {
4091 input = input->getOperand(0);
4092 }
4093
4094 // Unwrap MInt64ToBigInt: MToInt64(MInt64ToBigInt(int64)) = int64.
4095 if (input->isInt64ToBigInt()) {
4096 return input->getOperand(0);
4097 }
4098
4099 // Unwrap Int32ToBigInt:
4100 // MToInt64(MInt32ToBigInt(int32)) = MExtendInt32ToInt64(int32).
4101 if (input->isInt32ToBigInt()) {
4102 auto* int32 = input->toInt32ToBigInt()->input();
4103 if (int32->isConstant()) {
4104 int32_t c = int32->toConstant()->toInt32();
4105 return MConstant::NewInt64(alloc, int64_t(c));
4106 }
4107 return MExtendInt32ToInt64::New(alloc, int32, /* isUnsigned = */ false);
4108 }
4109
4110 // When the input is an Int64 already, just return it.
4111 if (input->type() == MIRType::Int64) {
4112 return input;
4113 }
4114
4115 // Fold this operation if the input operand is constant.
4116 if (input->isConstant()) {
4117 switch (input->type()) {
4118 case MIRType::Boolean:
4119 return MConstant::NewInt64(alloc, input->toConstant()->toBoolean());
4120 default:
4121 break;
4122 }
4123 }
4124
4125 return this;
4126}
4127
4128MDefinition* MToNumberInt32::foldsTo(TempAllocator& alloc) {
4129 // Fold this operation if the input operand is constant.
4130 if (MConstant* cst = input()->maybeConstantValue()) {
4131 switch (cst->type()) {
4132 case MIRType::Null:
4133 if (conversion() == IntConversionInputKind::Any) {
4134 return MConstant::New(alloc, Int32Value(0));
4135 }
4136 break;
4137 case MIRType::Boolean:
4138 if (conversion() == IntConversionInputKind::Any) {
4139 return MConstant::New(alloc, Int32Value(cst->toBoolean()));
4140 }
4141 break;
4142 case MIRType::Int32:
4143 return MConstant::New(alloc, Int32Value(cst->toInt32()));
4144 case MIRType::Float32:
4145 case MIRType::Double:
4146 int32_t ival;
4147 // Only the value within the range of Int32 can be substituted as
4148 // constant.
4149 if (mozilla::NumberIsInt32(cst->numberToDouble(), &ival)) {
4150 return MConstant::New(alloc, Int32Value(ival));
4151 }
4152 break;
4153 default:
4154 break;
4155 }
4156 }
4157
4158 MDefinition* input = getOperand(0);
4159 if (input->isBox()) {
4160 input = input->toBox()->input();
4161 }
4162
4163 // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
4164 // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
4165 // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
4166 // is folded to a MTruncateToInt32 node, which will result in this MIR:
4167 // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
4168 // the MUrsh node's type is int32 (since uint32 is not implemented), and
4169 // that would fold the MTruncateToInt32 node. This will make the modulo
4170 // unsigned, while is should have been signed.
4171 if (input->type() == MIRType::Int32 && !IsUint32Type(input)) {
4172 return input;
4173 }
4174
4175 return this;
4176}
4177
4178MDefinition* MBooleanToInt32::foldsTo(TempAllocator& alloc) {
4179 MDefinition* input = getOperand(0);
4180 MOZ_ASSERT(input->type() == MIRType::Boolean)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(input->type() == MIRType::Boolean)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(input->type() == MIRType::
Boolean))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("input->type() == MIRType::Boolean", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4180); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 4180; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4181
4182 if (input->isConstant()) {
4183 return MConstant::New(alloc, Int32Value(input->toConstant()->toBoolean()));
4184 }
4185
4186 return this;
4187}
4188
4189void MToNumberInt32::analyzeEdgeCasesBackward() {
4190 if (!NeedNegativeZeroCheck(this)) {
4191 setNeedsNegativeZeroCheck(false);
4192 }
4193}
4194
4195MDefinition* MTruncateToInt32::foldsTo(TempAllocator& alloc) {
4196 MDefinition* input = getOperand(0);
4197 if (input->isBox()) {
4198 input = input->getOperand(0);
4199 }
4200
4201 // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
4202 // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
4203 // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
4204 // is folded to a MTruncateToInt32 node, which will result in this MIR:
4205 // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
4206 // the MUrsh node's type is int32 (since uint32 is not implemented), and
4207 // that would fold the MTruncateToInt32 node. This will make the modulo
4208 // unsigned, while is should have been signed.
4209 if (input->type() == MIRType::Int32 && !IsUint32Type(input)) {
4210 return input;
4211 }
4212
4213 if (input->type() == MIRType::Double && input->isConstant()) {
4214 int32_t ret = ToInt32(input->toConstant()->toDouble());
4215 return MConstant::New(alloc, Int32Value(ret));
4216 }
4217
4218 return this;
4219}
4220
4221MDefinition* MWrapInt64ToInt32::foldsTo(TempAllocator& alloc) {
4222 MDefinition* input = this->input();
4223 if (input->isConstant()) {
4224 uint64_t c = input->toConstant()->toInt64();
4225 int32_t output = bottomHalf() ? int32_t(c) : int32_t(c >> 32);
4226 return MConstant::New(alloc, Int32Value(output));
4227 }
4228
4229 return this;
4230}
4231
4232MDefinition* MExtendInt32ToInt64::foldsTo(TempAllocator& alloc) {
4233 MDefinition* input = this->input();
4234 if (input->isConstant()) {
4235 int32_t c = input->toConstant()->toInt32();
4236 int64_t res = isUnsigned() ? int64_t(uint32_t(c)) : int64_t(c);
4237 return MConstant::NewInt64(alloc, res);
4238 }
4239
4240 return this;
4241}
4242
4243MDefinition* MSignExtendInt32::foldsTo(TempAllocator& alloc) {
4244 MDefinition* input = this->input();
4245 if (input->isConstant()) {
4246 int32_t c = input->toConstant()->toInt32();
4247 int32_t res;
4248 switch (mode_) {
4249 case Byte:
4250 res = int32_t(int8_t(c & 0xFF));
4251 break;
4252 case Half:
4253 res = int32_t(int16_t(c & 0xFFFF));
4254 break;
4255 }
4256 return MConstant::New(alloc, Int32Value(res));
4257 }
4258
4259 return this;
4260}
4261
4262MDefinition* MSignExtendInt64::foldsTo(TempAllocator& alloc) {
4263 MDefinition* input = this->input();
4264 if (input->isConstant()) {
4265 int64_t c = input->toConstant()->toInt64();
4266 int64_t res;
4267 switch (mode_) {
4268 case Byte:
4269 res = int64_t(int8_t(c & 0xFF));
4270 break;
4271 case Half:
4272 res = int64_t(int16_t(c & 0xFFFF));
4273 break;
4274 case Word:
4275 res = int64_t(int32_t(c & 0xFFFFFFFFU));
4276 break;
4277 }
4278 return MConstant::NewInt64(alloc, res);
4279 }
4280
4281 return this;
4282}
4283
4284MDefinition* MToDouble::foldsTo(TempAllocator& alloc) {
4285 MDefinition* input = getOperand(0);
4286 if (input->isBox()) {
4287 input = input->getOperand(0);
4288 }
4289
4290 if (input->type() == MIRType::Double) {
4291 return input;
4292 }
4293
4294 if (input->isConstant() &&
4295 input->toConstant()->isTypeRepresentableAsDouble()) {
4296 return MConstant::New(alloc,
4297 DoubleValue(input->toConstant()->numberToDouble()));
4298 }
4299
4300 return this;
4301}
4302
4303MDefinition* MToFloat32::foldsTo(TempAllocator& alloc) {
4304 MDefinition* input = getOperand(0);
4305 if (input->isBox()) {
4306 input = input->getOperand(0);
4307 }
4308
4309 if (input->type() == MIRType::Float32) {
4310 return input;
4311 }
4312
4313 // If x is a Float32, Float32(Double(x)) == x
4314 if (!mustPreserveNaN_ && input->isToDouble() &&
4315 input->toToDouble()->input()->type() == MIRType::Float32) {
4316 return input->toToDouble()->input();
4317 }
4318
4319 if (input->isConstant() &&
4320 input->toConstant()->isTypeRepresentableAsDouble()) {
4321 return MConstant::NewFloat32(alloc,
4322 float(input->toConstant()->numberToDouble()));
4323 }
4324
4325 // Fold ToFloat32(ToDouble(int32)) to ToFloat32(int32).
4326 if (input->isToDouble() &&
4327 input->toToDouble()->input()->type() == MIRType::Int32) {
4328 return MToFloat32::New(alloc, input->toToDouble()->input());
4329 }
4330
4331 return this;
4332}
4333
4334MDefinition* MToFloat16::foldsTo(TempAllocator& alloc) {
4335 MDefinition* in = input();
4336 if (in->isBox()) {
4337 in = in->toBox()->input();
4338 }
4339
4340 if (in->isConstant()) {
4341 auto* cst = in->toConstant();
4342 if (cst->isTypeRepresentableAsDouble()) {
4343 double num = cst->numberToDouble();
4344 return MConstant::NewFloat32(alloc, static_cast<float>(js::float16{num}));
4345 }
4346 }
4347
4348 auto isFloat16 = [](auto* def) -> MDefinition* {
4349 // ToFloat16(ToDouble(float16)) => float16
4350 // ToFloat16(ToFloat32(float16)) => float16
4351 if (def->isToDouble()) {
4352 def = def->toToDouble()->input();
4353 } else if (def->isToFloat32()) {
4354 def = def->toToFloat32()->input();
4355 }
4356
4357 // ToFloat16(ToFloat16(x)) => ToFloat16(x)
4358 if (def->isToFloat16()) {
4359 return def;
4360 }
4361
4362 // ToFloat16(LoadFloat16(x)) => LoadFloat16(x)
4363 if (def->isLoadUnboxedScalar() &&
4364 def->toLoadUnboxedScalar()->storageType() == Scalar::Float16) {
4365 return def;
4366 }
4367 if (def->isLoadDataViewElement() &&
4368 def->toLoadDataViewElement()->storageType() == Scalar::Float16) {
4369 return def;
4370 }
4371 return nullptr;
4372 };
4373
4374 // Fold loads which are guaranteed to return Float16.
4375 if (auto* f16 = isFloat16(in)) {
4376 return f16;
4377 }
4378
4379 // Fold ToFloat16(ToDouble(float32)) to ToFloat16(float32).
4380 // Fold ToFloat16(ToDouble(int32)) to ToFloat16(int32).
4381 if (in->isToDouble()) {
4382 auto* toDoubleInput = in->toToDouble()->input();
4383 if (toDoubleInput->type() == MIRType::Float32 ||
4384 toDoubleInput->type() == MIRType::Int32) {
4385 return MToFloat16::New(alloc, toDoubleInput);
4386 }
4387 }
4388
4389 return this;
4390}
4391
4392MDefinition* MToString::foldsTo(TempAllocator& alloc) {
4393 MDefinition* in = input();
4394 if (in->isBox()) {
4395 in = in->getOperand(0);
4396 }
4397
4398 if (in->type() == MIRType::String) {
4399 return in;
4400 }
4401 return this;
4402}
4403
4404MDefinition* MClampToUint8::foldsTo(TempAllocator& alloc) {
4405 if (MConstant* inputConst = input()->maybeConstantValue()) {
4406 if (inputConst->isTypeRepresentableAsDouble()) {
4407 int32_t clamped = ClampDoubleToUint8(inputConst->numberToDouble());
4408 return MConstant::New(alloc, Int32Value(clamped));
4409 }
4410 }
4411 return this;
4412}
4413
4414bool MCompare::tryFoldEqualOperands(bool* result) {
4415 if (lhs() != rhs()) {
4416 return false;
4417 }
4418
4419 // Intuitively somebody would think that if lhs === rhs,
4420 // then we can just return true. (Or false for !==)
4421 // However NaN !== NaN is true! So we spend some time trying
4422 // to eliminate this case.
4423
4424 if (!IsStrictEqualityOp(jsop())) {
4425 return false;
4426 }
4427
4428 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4429 compareType_ == Compare_Undefined || compareType_ == Compare_Null ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4430 compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4431 compareType_ == Compare_UInt64 || compareType_ == Compare_Double ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4432 compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4433 compareType_ == Compare_UIntPtr || compareType_ == Compare_String ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4434 compareType_ == Compare_Object || compareType_ == Compare_Symbol ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4435 compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4436 compareType_ == Compare_BigInt_Double ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4437 compareType_ == Compare_BigInt_String)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(compareType_ == Compare_Undefined || compareType_ ==
Compare_Null || compareType_ == Compare_Int32 || compareType_
== Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_
== Compare_Double || compareType_ == Compare_Float32 || compareType_
== Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_
== Compare_String || compareType_ == Compare_Object || compareType_
== Compare_Symbol || compareType_ == Compare_BigInt || compareType_
== Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(compareType_ == Compare_Undefined
|| compareType_ == Compare_Null || compareType_ == Compare_Int32
|| compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64
|| compareType_ == Compare_Double || compareType_ == Compare_Float32
|| compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr
|| compareType_ == Compare_String || compareType_ == Compare_Object
|| compareType_ == Compare_Symbol || compareType_ == Compare_BigInt
|| compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double
|| compareType_ == Compare_BigInt_String))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4437); AnnotateMozCrashReason("MOZ_ASSERT" "(" "compareType_ == Compare_Undefined || compareType_ == Compare_Null || compareType_ == Compare_Int32 || compareType_ == Compare_UInt32 || compareType_ == Compare_UInt64 || compareType_ == Compare_Double || compareType_ == Compare_Float32 || compareType_ == Compare_IntPtr || compareType_ == Compare_UIntPtr || compareType_ == Compare_String || compareType_ == Compare_Object || compareType_ == Compare_Symbol || compareType_ == Compare_BigInt || compareType_ == Compare_BigInt_Int32 || compareType_ == Compare_BigInt_Double || compareType_ == Compare_BigInt_String"
")"); do { *((volatile int*)__null) = 4437; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4438
4439 if (isDoubleComparison() || isFloat32Comparison()) {
4440 if (!operandsAreNeverNaN()) {
4441 return false;
4442 }
4443 }
4444
4445 lhs()->setGuardRangeBailoutsUnchecked();
4446
4447 *result = (jsop() == JSOp::StrictEq);
4448 return true;
4449}
4450
4451static JSType TypeOfName(const JSLinearString* str) {
4452 static constexpr std::array types = {
4453 JSTYPE_UNDEFINED, JSTYPE_OBJECT, JSTYPE_FUNCTION, JSTYPE_STRING,
4454 JSTYPE_NUMBER, JSTYPE_BOOLEAN, JSTYPE_SYMBOL, JSTYPE_BIGINT,
4455#ifdef ENABLE_RECORD_TUPLE
4456 JSTYPE_RECORD, JSTYPE_TUPLE,
4457#endif
4458 };
4459 static_assert(types.size() == JSTYPE_LIMIT);
4460
4461 const JSAtomState& names = GetJitContext()->runtime->names();
4462 for (auto type : types) {
4463 if (EqualStrings(str, TypeName(type, names))) {
4464 return type;
4465 }
4466 }
4467 return JSTYPE_LIMIT;
4468}
4469
4470struct TypeOfCompareInput {
4471 // The `typeof expr` side of the comparison.
4472 // MTypeOfName for JSOp::Typeof/JSOp::TypeofExpr, and
4473 // MTypeOf for JSOp::TypeofEq (same pointer as typeOf).
4474 MDefinition* typeOfSide;
4475
4476 // The actual `typeof` operation.
4477 MTypeOf* typeOf;
4478
4479 // The string side of the comparison.
4480 JSType type;
4481
4482 // True if the comparison uses raw JSType (Generated for JSOp::TypeofEq).
4483 bool isIntComparison;
4484
4485 TypeOfCompareInput(MDefinition* typeOfSide, MTypeOf* typeOf, JSType type,
4486 bool isIntComparison)
4487 : typeOfSide(typeOfSide),
4488 typeOf(typeOf),
4489 type(type),
4490 isIntComparison(isIntComparison) {}
4491};
4492
4493static mozilla::Maybe<TypeOfCompareInput> IsTypeOfCompare(MCompare* ins) {
4494 if (!IsEqualityOp(ins->jsop())) {
4495 return mozilla::Nothing();
4496 }
4497
4498 if (ins->compareType() == MCompare::Compare_Int32) {
4499 auto* lhs = ins->lhs();
4500 auto* rhs = ins->rhs();
4501
4502 if (ins->type() != MIRType::Boolean || lhs->type() != MIRType::Int32 ||
4503 rhs->type() != MIRType::Int32) {
4504 return mozilla::Nothing();
4505 }
4506
4507 // NOTE: The comparison is generated inside JIT, and typeof should always
4508 // be in the LHS.
4509 if (!lhs->isTypeOf() || !rhs->isConstant()) {
4510 return mozilla::Nothing();
4511 }
4512
4513 auto* typeOf = lhs->toTypeOf();
4514 auto* constant = rhs->toConstant();
4515
4516 JSType type = JSType(constant->toInt32());
4517 return mozilla::Some(TypeOfCompareInput(typeOf, typeOf, type, true));
4518 }
4519
4520 if (ins->compareType() != MCompare::Compare_String) {
4521 return mozilla::Nothing();
4522 }
4523
4524 auto* lhs = ins->lhs();
4525 auto* rhs = ins->rhs();
4526
4527 MOZ_ASSERT(ins->type() == MIRType::Boolean)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ins->type() == MIRType::Boolean)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ins->type() == MIRType::Boolean
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ins->type() == MIRType::Boolean", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4527); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 4527; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4528 MOZ_ASSERT(lhs->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lhs->type() == MIRType::String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lhs->type() == MIRType::String
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"lhs->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4528); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4528; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4529 MOZ_ASSERT(rhs->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(rhs->type() == MIRType::String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(rhs->type() == MIRType::String
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"rhs->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4529; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4530
4531 if (!lhs->isTypeOfName() && !rhs->isTypeOfName()) {
4532 return mozilla::Nothing();
4533 }
4534 if (!lhs->isConstant() && !rhs->isConstant()) {
4535 return mozilla::Nothing();
4536 }
4537
4538 auto* typeOfName =
4539 lhs->isTypeOfName() ? lhs->toTypeOfName() : rhs->toTypeOfName();
4540 auto* typeOf = typeOfName->input()->toTypeOf();
4541
4542 auto* constant = lhs->isConstant() ? lhs->toConstant() : rhs->toConstant();
4543
4544 JSType type = TypeOfName(&constant->toString()->asLinear());
4545 return mozilla::Some(TypeOfCompareInput(typeOfName, typeOf, type, false));
4546}
4547
4548bool MCompare::tryFoldTypeOf(bool* result) {
4549 auto typeOfCompare = IsTypeOfCompare(this);
4550 if (!typeOfCompare) {
4551 return false;
4552 }
4553 auto* typeOf = typeOfCompare->typeOf;
4554 JSType type = typeOfCompare->type;
4555
4556 switch (type) {
4557 case JSTYPE_BOOLEAN:
4558 if (!typeOf->input()->mightBeType(MIRType::Boolean)) {
4559 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4560 return true;
4561 }
4562 break;
4563 case JSTYPE_NUMBER:
4564 if (!typeOf->input()->mightBeType(MIRType::Int32) &&
4565 !typeOf->input()->mightBeType(MIRType::Float32) &&
4566 !typeOf->input()->mightBeType(MIRType::Double)) {
4567 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4568 return true;
4569 }
4570 break;
4571 case JSTYPE_STRING:
4572 if (!typeOf->input()->mightBeType(MIRType::String)) {
4573 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4574 return true;
4575 }
4576 break;
4577 case JSTYPE_SYMBOL:
4578 if (!typeOf->input()->mightBeType(MIRType::Symbol)) {
4579 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4580 return true;
4581 }
4582 break;
4583 case JSTYPE_BIGINT:
4584 if (!typeOf->input()->mightBeType(MIRType::BigInt)) {
4585 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4586 return true;
4587 }
4588 break;
4589 case JSTYPE_OBJECT:
4590 if (!typeOf->input()->mightBeType(MIRType::Object) &&
4591 !typeOf->input()->mightBeType(MIRType::Null)) {
4592 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4593 return true;
4594 }
4595 break;
4596 case JSTYPE_UNDEFINED:
4597 if (!typeOf->input()->mightBeType(MIRType::Object) &&
4598 !typeOf->input()->mightBeType(MIRType::Undefined)) {
4599 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4600 return true;
4601 }
4602 break;
4603 case JSTYPE_FUNCTION:
4604 if (!typeOf->input()->mightBeType(MIRType::Object)) {
4605 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4606 return true;
4607 }
4608 break;
4609 case JSTYPE_LIMIT:
4610 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4611 return true;
4612#ifdef ENABLE_RECORD_TUPLE
4613 case JSTYPE_RECORD:
4614 case JSTYPE_TUPLE:
4615 MOZ_CRASH("Records and Tuples are not supported yet.")do { do { } while (false); MOZ_ReportCrash("" "Records and Tuples are not supported yet."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4615); AnnotateMozCrashReason("MOZ_CRASH(" "Records and Tuples are not supported yet."
")"); do { *((volatile int*)__null) = 4615; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4616#endif
4617 }
4618
4619 return false;
4620}
4621
4622bool MCompare::tryFold(bool* result) {
4623 JSOp op = jsop();
4624
4625 if (tryFoldEqualOperands(result)) {
4626 return true;
4627 }
4628
4629 if (tryFoldTypeOf(result)) {
4630 return true;
4631 }
4632
4633 if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) {
4634 // The LHS is the value we want to test against null or undefined.
4635 if (IsStrictEqualityOp(op)) {
4636 if (lhs()->type() == inputType()) {
4637 *result = (op == JSOp::StrictEq);
4638 return true;
4639 }
4640 if (!lhs()->mightBeType(inputType())) {
4641 *result = (op == JSOp::StrictNe);
4642 return true;
4643 }
4644 } else {
4645 MOZ_ASSERT(IsLooseEqualityOp(op))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsLooseEqualityOp(op))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsLooseEqualityOp(op)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("IsLooseEqualityOp(op)"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4645); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsLooseEqualityOp(op)"
")"); do { *((volatile int*)__null) = 4645; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4646 if (IsNullOrUndefined(lhs()->type())) {
4647 *result = (op == JSOp::Eq);
4648 return true;
4649 }
4650 if (!lhs()->mightBeType(MIRType::Null) &&
4651 !lhs()->mightBeType(MIRType::Undefined) &&
4652 !lhs()->mightBeType(MIRType::Object)) {
4653 *result = (op == JSOp::Ne);
4654 return true;
4655 }
4656 }
4657 return false;
4658 }
4659
4660 return false;
4661}
4662
4663template <typename T>
4664static bool FoldComparison(JSOp op, T left, T right) {
4665 switch (op) {
4666 case JSOp::Lt:
4667 return left < right;
4668 case JSOp::Le:
4669 return left <= right;
4670 case JSOp::Gt:
4671 return left > right;
4672 case JSOp::Ge:
4673 return left >= right;
4674 case JSOp::StrictEq:
4675 case JSOp::Eq:
4676 return left == right;
4677 case JSOp::StrictNe:
4678 case JSOp::Ne:
4679 return left != right;
4680 default:
4681 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4681); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 4681; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4682 }
4683}
4684
4685static bool FoldBigIntComparison(JSOp op, const BigInt* left, double right) {
4686 switch (op) {
4687 case JSOp::Lt:
4688 return BigInt::lessThan(left, right).valueOr(false);
4689 case JSOp::Le:
4690 return !BigInt::lessThan(right, left).valueOr(true);
4691 case JSOp::Gt:
4692 return BigInt::lessThan(right, left).valueOr(false);
4693 case JSOp::Ge:
4694 return !BigInt::lessThan(left, right).valueOr(true);
4695 case JSOp::StrictEq:
4696 case JSOp::Eq:
4697 return BigInt::equal(left, right);
4698 case JSOp::StrictNe:
4699 case JSOp::Ne:
4700 return !BigInt::equal(left, right);
4701 default:
4702 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4702); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 4702; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4703 }
4704}
4705
4706bool MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) {
4707 if (type() != MIRType::Boolean && type() != MIRType::Int32) {
4708 return false;
4709 }
4710
4711 MDefinition* left = getOperand(0);
4712 MDefinition* right = getOperand(1);
4713
4714 if (compareType() == Compare_Double) {
4715 // Optimize "MCompare MConstant (MToDouble SomethingInInt32Range).
4716 // In most cases the MToDouble was added, because the constant is
4717 // a double.
4718 // e.g. v < 9007199254740991, where v is an int32 is always true.
4719 if (!lhs()->isConstant() && !rhs()->isConstant()) {
4720 return false;
4721 }
4722
4723 MDefinition* operand = left->isConstant() ? right : left;
4724 MConstant* constant =
4725 left->isConstant() ? left->toConstant() : right->toConstant();
4726 MOZ_ASSERT(constant->type() == MIRType::Double)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(constant->type() == MIRType::Double)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(constant->type() == MIRType::Double))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("constant->type() == MIRType::Double"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4726); AnnotateMozCrashReason("MOZ_ASSERT" "(" "constant->type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 4726; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4727 double cte = constant->toDouble();
4728
4729 if (operand->isToDouble() &&
4730 operand->getOperand(0)->type() == MIRType::Int32) {
4731 bool replaced = false;
4732 switch (jsop_) {
4733 case JSOp::Lt:
4734 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4735 *result = !((constant == lhs()) ^ (cte < INT32_MIN(-2147483647-1)));
4736 replaced = true;
4737 }
4738 break;
4739 case JSOp::Le:
4740 if (constant == lhs()) {
4741 if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) {
4742 *result = (cte <= INT32_MIN(-2147483647-1));
4743 replaced = true;
4744 }
4745 } else {
4746 if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4747 *result = (cte >= INT32_MIN(-2147483647-1));
4748 replaced = true;
4749 }
4750 }
4751 break;
4752 case JSOp::Gt:
4753 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4754 *result = !((constant == rhs()) ^ (cte < INT32_MIN(-2147483647-1)));
4755 replaced = true;
4756 }
4757 break;
4758 case JSOp::Ge:
4759 if (constant == lhs()) {
4760 if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4761 *result = (cte >= INT32_MAX(2147483647));
4762 replaced = true;
4763 }
4764 } else {
4765 if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) {
4766 *result = (cte <= INT32_MIN(-2147483647-1));
4767 replaced = true;
4768 }
4769 }
4770 break;
4771 case JSOp::StrictEq: // Fall through.
4772 case JSOp::Eq:
4773 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4774 *result = false;
4775 replaced = true;
4776 }
4777 break;
4778 case JSOp::StrictNe: // Fall through.
4779 case JSOp::Ne:
4780 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4781 *result = true;
4782 replaced = true;
4783 }
4784 break;
4785 default:
4786 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4786); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 4786; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4787 }
4788 if (replaced) {
4789 MLimitedTruncate* limit = MLimitedTruncate::New(
4790 alloc, operand->getOperand(0), TruncateKind::NoTruncate);
4791 limit->setGuardUnchecked();
4792 block()->insertBefore(this, limit);
4793 return true;
4794 }
4795 }
4796
4797 // Optimize comparison against NaN.
4798 if (std::isnan(cte)) {
4799 switch (jsop_) {
4800 case JSOp::Lt:
4801 case JSOp::Le:
4802 case JSOp::Gt:
4803 case JSOp::Ge:
4804 case JSOp::Eq:
4805 case JSOp::StrictEq:
4806 *result = false;
4807 break;
4808 case JSOp::Ne:
4809 case JSOp::StrictNe:
4810 *result = true;
4811 break;
4812 default:
4813 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4813); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 4813; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4814 }
4815 return true;
4816 }
4817 }
4818
4819 if (!left->isConstant() || !right->isConstant()) {
4820 return false;
4821 }
4822
4823 MConstant* lhs = left->toConstant();
4824 MConstant* rhs = right->toConstant();
4825
4826 switch (compareType()) {
4827 case Compare_Int32:
4828 case Compare_Double:
4829 case Compare_Float32: {
4830 *result =
4831 FoldComparison(jsop_, lhs->numberToDouble(), rhs->numberToDouble());
4832 return true;
4833 }
4834 case Compare_UInt32: {
4835 *result = FoldComparison(jsop_, uint32_t(lhs->toInt32()),
4836 uint32_t(rhs->toInt32()));
4837 return true;
4838 }
4839 case Compare_Int64: {
4840 *result = FoldComparison(jsop_, lhs->toInt64(), rhs->toInt64());
4841 return true;
4842 }
4843 case Compare_UInt64: {
4844 *result = FoldComparison(jsop_, uint64_t(lhs->toInt64()),
4845 uint64_t(rhs->toInt64()));
4846 return true;
4847 }
4848 case Compare_IntPtr: {
4849 *result = FoldComparison(jsop_, lhs->toIntPtr(), rhs->toIntPtr());
4850 return true;
4851 }
4852 case Compare_UIntPtr: {
4853 *result = FoldComparison(jsop_, uintptr_t(lhs->toIntPtr()),
4854 uintptr_t(rhs->toIntPtr()));
4855 return true;
4856 }
4857 case Compare_String: {
4858 int32_t comp = CompareStrings(&lhs->toString()->asLinear(),
4859 &rhs->toString()->asLinear());
4860 *result = FoldComparison(jsop_, comp, 0);
4861 return true;
4862 }
4863 case Compare_BigInt: {
4864 int32_t comp = BigInt::compare(lhs->toBigInt(), rhs->toBigInt());
4865 *result = FoldComparison(jsop_, comp, 0);
4866 return true;
4867 }
4868 case Compare_BigInt_Int32:
4869 case Compare_BigInt_Double: {
4870 *result =
4871 FoldBigIntComparison(jsop_, lhs->toBigInt(), rhs->numberToDouble());
4872 return true;
4873 }
4874 case Compare_BigInt_String: {
4875 JSLinearString* linear = &rhs->toString()->asLinear();
4876 if (!linear->hasIndexValue()) {
4877 return false;
4878 }
4879 *result =
4880 FoldBigIntComparison(jsop_, lhs->toBigInt(), linear->getIndexValue());
4881 return true;
4882 }
4883
4884 case Compare_Undefined:
4885 case Compare_Null:
4886 case Compare_Symbol:
4887 case Compare_Object:
4888 case Compare_WasmAnyRef:
4889 return false;
4890 }
4891
4892 MOZ_CRASH("unexpected compare type")do { do { } while (false); MOZ_ReportCrash("" "unexpected compare type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4892); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected compare type"
")"); do { *((volatile int*)__null) = 4892; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4893}
4894
4895MDefinition* MCompare::tryFoldTypeOf(TempAllocator& alloc) {
4896 auto typeOfCompare = IsTypeOfCompare(this);
4897 if (!typeOfCompare) {
4898 return this;
4899 }
4900 auto* typeOf = typeOfCompare->typeOf;
4901 JSType type = typeOfCompare->type;
4902
4903 auto* input = typeOf->input();
4904 MOZ_ASSERT(input->type() == MIRType::Value ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(input->type() == MIRType::Value || input->type
() == MIRType::Object)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(input->type() == MIRType::
Value || input->type() == MIRType::Object))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("input->type() == MIRType::Value || input->type() == MIRType::Object"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4905); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object"
")"); do { *((volatile int*)__null) = 4905; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4905 input->type() == MIRType::Object)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(input->type() == MIRType::Value || input->type
() == MIRType::Object)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(input->type() == MIRType::
Value || input->type() == MIRType::Object))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("input->type() == MIRType::Value || input->type() == MIRType::Object"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4905); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object"
")"); do { *((volatile int*)__null) = 4905; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4906
4907 // Constant typeof folding handles the other cases.
4908 MOZ_ASSERT_IF(input->type() == MIRType::Object, type == JSTYPE_UNDEFINED ||do { if (input->type() == MIRType::Object) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(type ==
JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT ||
type == JSTYPE_FUNCTION))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4910); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
")"); do { *((volatile int*)__null) = 4910; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4909 type == JSTYPE_OBJECT ||do { if (input->type() == MIRType::Object) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(type ==
JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT ||
type == JSTYPE_FUNCTION))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4910); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
")"); do { *((volatile int*)__null) = 4910; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4910 type == JSTYPE_FUNCTION)do { if (input->type() == MIRType::Object) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(type ==
JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT ||
type == JSTYPE_FUNCTION))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4910); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
")"); do { *((volatile int*)__null) = 4910; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4911
4912 MOZ_ASSERT(type != JSTYPE_LIMIT, "unknown typeof strings folded earlier")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type != JSTYPE_LIMIT)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type != JSTYPE_LIMIT))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("type != JSTYPE_LIMIT"
" (" "unknown typeof strings folded earlier" ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4912); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type != JSTYPE_LIMIT"
") (" "unknown typeof strings folded earlier" ")"); do { *((
volatile int*)__null) = 4912; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4913
4914 // If there's only a single use, assume this |typeof| is used in a simple
4915 // comparison context.
4916 //
4917 // if (typeof thing === "number") { ... }
4918 //
4919 // It'll be compiled into something similar to:
4920 //
4921 // if (IsNumber(thing)) { ... }
4922 //
4923 // This heuristic can go wrong when repeated |typeof| are used in consecutive
4924 // if-statements.
4925 //
4926 // if (typeof thing === "number") { ... }
4927 // else if (typeof thing === "string") { ... }
4928 // ... repeated for all possible types
4929 //
4930 // In that case it'd more efficient to emit MTypeOf compared to MTypeOfIs. We
4931 // don't yet handle that case, because it'd require a separate optimization
4932 // pass to correctly detect it.
4933 if (typeOfCompare->typeOfSide->hasOneUse()) {
4934 return MTypeOfIs::New(alloc, input, jsop(), type);
4935 }
4936
4937 if (typeOfCompare->isIntComparison) {
4938 // Already optimized.
4939 return this;
4940 }
4941
4942 MConstant* cst = MConstant::New(alloc, Int32Value(type));
4943 block()->insertBefore(this, cst);
4944
4945 return MCompare::New(alloc, typeOf, cst, jsop(), MCompare::Compare_Int32);
4946}
4947
4948MDefinition* MCompare::tryFoldCharCompare(TempAllocator& alloc) {
4949 if (compareType() != Compare_String) {
4950 return this;
4951 }
4952
4953 MDefinition* left = lhs();
4954 MOZ_ASSERT(left->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4954); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4954; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4955
4956 MDefinition* right = rhs();
4957 MOZ_ASSERT(right->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4957; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4958
4959 // |str[i]| is compiled as |MFromCharCode(MCharCodeAt(str, i))|.
4960 // Out-of-bounds access is compiled as
4961 // |FromCharCodeEmptyIfNegative(CharCodeAtOrNegative(str, i))|.
4962 auto isCharAccess = [](MDefinition* ins) {
4963 if (ins->isFromCharCode()) {
4964 return ins->toFromCharCode()->code()->isCharCodeAt();
4965 }
4966 if (ins->isFromCharCodeEmptyIfNegative()) {
4967 auto* fromCharCode = ins->toFromCharCodeEmptyIfNegative();
4968 return fromCharCode->code()->isCharCodeAtOrNegative();
4969 }
4970 return false;
4971 };
4972
4973 auto charAccessCode = [](MDefinition* ins) {
4974 if (ins->isFromCharCode()) {
4975 return ins->toFromCharCode()->code();
4976 }
4977 return ins->toFromCharCodeEmptyIfNegative()->code();
4978 };
4979
4980 if (left->isConstant() || right->isConstant()) {
4981 // Try to optimize |MConstant(string) <compare> (MFromCharCode MCharCodeAt)|
4982 // as |MConstant(charcode) <compare> MCharCodeAt|.
4983 MConstant* constant;
4984 MDefinition* operand;
4985 if (left->isConstant()) {
4986 constant = left->toConstant();
4987 operand = right;
4988 } else {
4989 constant = right->toConstant();
4990 operand = left;
4991 }
4992
4993 if (constant->toString()->length() != 1 || !isCharAccess(operand)) {
4994 return this;
4995 }
4996
4997 char16_t charCode = constant->toString()->asLinear().latin1OrTwoByteChar(0);
4998 MConstant* charCodeConst = MConstant::New(alloc, Int32Value(charCode));
4999 block()->insertBefore(this, charCodeConst);
5000
5001 MDefinition* charCodeAt = charAccessCode(operand);
5002
5003 if (left->isConstant()) {
5004 left = charCodeConst;
5005 right = charCodeAt;
5006 } else {
5007 left = charCodeAt;
5008 right = charCodeConst;
5009 }
5010 } else if (isCharAccess(left) && isCharAccess(right)) {
5011 // Try to optimize |(MFromCharCode MCharCodeAt) <compare> (MFromCharCode
5012 // MCharCodeAt)| as |MCharCodeAt <compare> MCharCodeAt|.
5013
5014 left = charAccessCode(left);
5015 right = charAccessCode(right);
5016 } else {
5017 return this;
5018 }
5019
5020 return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32);
5021}
5022
5023MDefinition* MCompare::tryFoldStringCompare(TempAllocator& alloc) {
5024 if (compareType() != Compare_String) {
5025 return this;
5026 }
5027
5028 MDefinition* left = lhs();
5029 MOZ_ASSERT(left->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5029); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5029; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5030
5031 MDefinition* right = rhs();
5032 MOZ_ASSERT(right->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5033
5034 if (!left->isConstant() && !right->isConstant()) {
5035 return this;
5036 }
5037
5038 // Try to optimize |string <compare> MConstant("")| as |MStringLength(string)
5039 // <compare> MConstant(0)|.
5040
5041 MConstant* constant =
5042 left->isConstant() ? left->toConstant() : right->toConstant();
5043 if (!constant->toString()->empty()) {
5044 return this;
5045 }
5046
5047 MDefinition* operand = left->isConstant() ? right : left;
5048
5049 auto* strLength = MStringLength::New(alloc, operand);
5050 block()->insertBefore(this, strLength);
5051
5052 auto* zero = MConstant::New(alloc, Int32Value(0));
5053 block()->insertBefore(this, zero);
5054
5055 if (left->isConstant()) {
5056 left = zero;
5057 right = strLength;
5058 } else {
5059 left = strLength;
5060 right = zero;
5061 }
5062
5063 return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32);
5064}
5065
5066MDefinition* MCompare::tryFoldStringSubstring(TempAllocator& alloc) {
5067 if (compareType() != Compare_String) {
5068 return this;
5069 }
5070 if (!IsEqualityOp(jsop())) {
5071 return this;
5072 }
5073
5074 auto* left = lhs();
5075 MOZ_ASSERT(left->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5075); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5075; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5076
5077 auto* right = rhs();
5078 MOZ_ASSERT(right->type() == MIRType::String)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::String)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
String))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::String", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5078); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5078; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5079
5080 // One operand must be a constant string.
5081 if (!left->isConstant() && !right->isConstant()) {
5082 return this;
5083 }
5084
5085 // The constant string must be non-empty.
5086 auto* constant =
5087 left->isConstant() ? left->toConstant() : right->toConstant();
5088 if (constant->toString()->empty()) {
5089 return this;
5090 }
5091
5092 // The other operand must be a substring operation.
5093 auto* operand = left->isConstant() ? right : left;
5094 if (!operand->isSubstr()) {
5095 return this;
5096 }
5097 auto* substr = operand->toSubstr();
5098
5099 static_assert(JSString::MAX_LENGTH < INT32_MAX(2147483647),
5100 "string length can be casted to int32_t");
5101
5102 if (!IsSubstrTo(substr, int32_t(constant->toString()->length()))) {
5103 return this;
5104 }
5105
5106 // Now fold code like |str.substring(0, 2) == "aa"| to |str.startsWith("aa")|.
5107
5108 auto* startsWith = MStringStartsWith::New(alloc, substr->string(), constant);
5109 if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) {
5110 return startsWith;
5111 }
5112
5113 // Invert for inequality.
5114 MOZ_ASSERT(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("jsop() == JSOp::Ne || jsop() == JSOp::StrictNe"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5114); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe"
")"); do { *((volatile int*)__null) = 5114; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5115
5116 block()->insertBefore(this, startsWith);
5117 return MNot::New(alloc, startsWith);
5118}
5119
5120MDefinition* MCompare::tryFoldStringIndexOf(TempAllocator& alloc) {
5121 if (compareType() != Compare_Int32) {
5122 return this;
5123 }
5124 if (!IsEqualityOp(jsop())) {
5125 return this;
5126 }
5127
5128 auto* left = lhs();
5129 MOZ_ASSERT(left->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5129); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 5129; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5130
5131 auto* right = rhs();
5132 MOZ_ASSERT(right->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 5132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5133
5134 // One operand must be a constant integer.
5135 if (!left->isConstant() && !right->isConstant()) {
5136 return this;
5137 }
5138
5139 // The constant must be zero.
5140 auto* constant =
5141 left->isConstant() ? left->toConstant() : right->toConstant();
5142 if (!constant->isInt32(0)) {
5143 return this;
5144 }
5145
5146 // The other operand must be an indexOf operation.
5147 auto* operand = left->isConstant() ? right : left;
5148 if (!operand->isStringIndexOf()) {
5149 return this;
5150 }
5151
5152 // Fold |str.indexOf(searchStr) == 0| to |str.startsWith(searchStr)|.
5153
5154 auto* indexOf = operand->toStringIndexOf();
5155 auto* startsWith =
5156 MStringStartsWith::New(alloc, indexOf->string(), indexOf->searchString());
5157 if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) {
5158 return startsWith;
5159 }
5160
5161 // Invert for inequality.
5162 MOZ_ASSERT(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(jsop() == JSOp::Ne || jsop() == JSOp::StrictNe))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("jsop() == JSOp::Ne || jsop() == JSOp::StrictNe"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe"
")"); do { *((volatile int*)__null) = 5162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5163
5164 block()->insertBefore(this, startsWith);
5165 return MNot::New(alloc, startsWith);
5166}
5167
5168MDefinition* MCompare::tryFoldBigInt64(TempAllocator& alloc) {
5169 if (compareType() == Compare_BigInt) {
5170 auto* left = lhs();
5171 MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5171); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5171; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5172
5173 auto* right = rhs();
5174 MOZ_ASSERT(right->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5174); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5174; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5175
5176 // At least one operand must be MInt64ToBigInt.
5177 if (!left->isInt64ToBigInt() && !right->isInt64ToBigInt()) {
5178 return this;
5179 }
5180
5181 // Unwrap MInt64ToBigInt on both sides and perform a Int64 comparison.
5182 if (left->isInt64ToBigInt() && right->isInt64ToBigInt()) {
5183 auto* lhsInt64 = left->toInt64ToBigInt();
5184 auto* rhsInt64 = right->toInt64ToBigInt();
5185
5186 // Don't optimize if Int64 against Uint64 comparison.
5187 if (lhsInt64->elementType() != rhsInt64->elementType()) {
5188 return this;
5189 }
5190
5191 bool isSigned = lhsInt64->elementType() == Scalar::BigInt64;
5192 auto compareType =
5193 isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64;
5194 return MCompare::New(alloc, lhsInt64->input(), rhsInt64->input(), jsop_,
5195 compareType);
5196 }
5197
5198 // Optimize IntPtr x Int64 comparison to Int64 x Int64 comparison.
5199 if (left->isIntPtrToBigInt() || right->isIntPtrToBigInt()) {
5200 auto* int64ToBigInt = left->isInt64ToBigInt() ? left->toInt64ToBigInt()
5201 : right->toInt64ToBigInt();
5202
5203 // Can't optimize when comparing Uint64 against IntPtr.
5204 if (int64ToBigInt->elementType() == Scalar::BigUint64) {
5205 return this;
5206 }
5207
5208 auto* intPtrToBigInt = left->isIntPtrToBigInt()
5209 ? left->toIntPtrToBigInt()
5210 : right->toIntPtrToBigInt();
5211
5212 auto* intPtrToInt64 = MIntPtrToInt64::New(alloc, intPtrToBigInt->input());
5213 block()->insertBefore(this, intPtrToInt64);
5214
5215 if (left == int64ToBigInt) {
5216 left = int64ToBigInt->input();
5217 right = intPtrToInt64;
5218 } else {
5219 left = intPtrToInt64;
5220 right = int64ToBigInt->input();
5221 }
5222 return MCompare::New(alloc, left, right, jsop_, MCompare::Compare_Int64);
5223 }
5224
5225 // The other operand must be a constant.
5226 if (!left->isConstant() && !right->isConstant()) {
5227 return this;
5228 }
5229
5230 auto* int64ToBigInt = left->isInt64ToBigInt() ? left->toInt64ToBigInt()
5231 : right->toInt64ToBigInt();
5232 bool isSigned = int64ToBigInt->elementType() == Scalar::BigInt64;
5233
5234 auto* constant =
5235 left->isConstant() ? left->toConstant() : right->toConstant();
5236 auto* bigInt = constant->toBigInt();
5237
5238 // Extract the BigInt value if representable as Int64/Uint64.
5239 mozilla::Maybe<int64_t> value;
5240 if (isSigned) {
5241 int64_t x;
5242 if (BigInt::isInt64(bigInt, &x)) {
5243 value = mozilla::Some(x);
5244 }
5245 } else {
5246 uint64_t x;
5247 if (BigInt::isUint64(bigInt, &x)) {
5248 value = mozilla::Some(static_cast<int64_t>(x));
5249 }
5250 }
5251
5252 // The comparison is a constant if the BigInt has too many digits.
5253 if (!value) {
5254 int32_t repr = bigInt->isNegative() ? -1 : 1;
5255
5256 bool result;
5257 if (left == int64ToBigInt) {
5258 result = FoldComparison(jsop_, 0, repr);
5259 } else {
5260 result = FoldComparison(jsop_, repr, 0);
5261 }
5262 return MConstant::New(alloc, BooleanValue(result));
5263 }
5264
5265 auto* cst = MConstant::NewInt64(alloc, *value);
5266 block()->insertBefore(this, cst);
5267
5268 auto compareType =
5269 isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64;
5270 if (left == int64ToBigInt) {
5271 return MCompare::New(alloc, int64ToBigInt->input(), cst, jsop_,
5272 compareType);
5273 }
5274 return MCompare::New(alloc, cst, int64ToBigInt->input(), jsop_,
5275 compareType);
5276 }
5277
5278 if (compareType() == Compare_BigInt_Int32) {
5279 auto* left = lhs();
5280 MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5280); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5280; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5281
5282 auto* right = rhs();
5283 MOZ_ASSERT(right->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5283); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 5283; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5284
5285 // Optimize MInt64ToBigInt against a constant int32.
5286 if (!left->isInt64ToBigInt() || !right->isConstant()) {
5287 return this;
5288 }
5289
5290 auto* int64ToBigInt = left->toInt64ToBigInt();
5291 bool isSigned = int64ToBigInt->elementType() == Scalar::BigInt64;
5292
5293 int32_t constInt32 = right->toConstant()->toInt32();
5294
5295 // The unsigned comparison against a negative operand is a constant.
5296 if (!isSigned && constInt32 < 0) {
5297 bool result = FoldComparison(jsop_, 0, constInt32);
5298 return MConstant::New(alloc, BooleanValue(result));
5299 }
5300
5301 auto* cst = MConstant::NewInt64(alloc, int64_t(constInt32));
5302 block()->insertBefore(this, cst);
5303
5304 auto compareType =
5305 isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64;
5306 return MCompare::New(alloc, int64ToBigInt->input(), cst, jsop_,
5307 compareType);
5308 }
5309
5310 return this;
5311}
5312
5313MDefinition* MCompare::tryFoldBigIntPtr(TempAllocator& alloc) {
5314 if (compareType() == Compare_BigInt) {
5315 auto* left = lhs();
5316 MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5316); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5316; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5317
5318 auto* right = rhs();
5319 MOZ_ASSERT(right->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5319; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5320
5321 // At least one operand must be MIntPtrToBigInt.
5322 if (!left->isIntPtrToBigInt() && !right->isIntPtrToBigInt()) {
5323 return this;
5324 }
5325
5326 // Unwrap MIntPtrToBigInt on both sides and perform an IntPtr comparison.
5327 if (left->isIntPtrToBigInt() && right->isIntPtrToBigInt()) {
5328 auto* lhsIntPtr = left->toIntPtrToBigInt();
5329 auto* rhsIntPtr = right->toIntPtrToBigInt();
5330
5331 return MCompare::New(alloc, lhsIntPtr->input(), rhsIntPtr->input(), jsop_,
5332 MCompare::Compare_IntPtr);
5333 }
5334
5335 // The other operand must be a constant.
5336 if (!left->isConstant() && !right->isConstant()) {
5337 return this;
5338 }
5339
5340 auto* intPtrToBigInt = left->isIntPtrToBigInt() ? left->toIntPtrToBigInt()
5341 : right->toIntPtrToBigInt();
5342
5343 auto* constant =
5344 left->isConstant() ? left->toConstant() : right->toConstant();
5345 auto* bigInt = constant->toBigInt();
5346
5347 // Extract the BigInt value if representable as intptr_t.
5348 intptr_t value;
5349 if (!BigInt::isIntPtr(bigInt, &value)) {
5350 // The comparison is a constant if the BigInt has too many digits.
5351 int32_t repr = bigInt->isNegative() ? -1 : 1;
5352
5353 bool result;
5354 if (left == intPtrToBigInt) {
5355 result = FoldComparison(jsop_, 0, repr);
5356 } else {
5357 result = FoldComparison(jsop_, repr, 0);
5358 }
5359 return MConstant::New(alloc, BooleanValue(result));
5360 }
5361
5362 auto* cst = MConstant::NewIntPtr(alloc, value);
5363 block()->insertBefore(this, cst);
5364
5365 if (left == intPtrToBigInt) {
5366 left = intPtrToBigInt->input();
5367 right = cst;
5368 } else {
5369 left = cst;
5370 right = intPtrToBigInt->input();
5371 }
5372 return MCompare::New(alloc, left, right, jsop_, MCompare::Compare_IntPtr);
5373 }
5374
5375 if (compareType() == Compare_BigInt_Int32) {
5376 auto* left = lhs();
5377 MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5377); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5377; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5378
5379 auto* right = rhs();
5380 MOZ_ASSERT(right->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5380); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 5380; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5381
5382 // Optimize MIntPtrToBigInt against a constant int32.
5383 if (!left->isIntPtrToBigInt() || !right->isConstant()) {
5384 return this;
5385 }
5386
5387 auto* cst =
5388 MConstant::NewIntPtr(alloc, intptr_t(right->toConstant()->toInt32()));
5389 block()->insertBefore(this, cst);
5390
5391 return MCompare::New(alloc, left->toIntPtrToBigInt()->input(), cst, jsop_,
5392 MCompare::Compare_IntPtr);
5393 }
5394
5395 return this;
5396}
5397
5398MDefinition* MCompare::tryFoldBigInt(TempAllocator& alloc) {
5399 if (compareType() != Compare_BigInt) {
5400 return this;
5401 }
5402
5403 auto* left = lhs();
5404 MOZ_ASSERT(left->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(left->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(left->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("left->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5404; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5405
5406 auto* right = rhs();
5407 MOZ_ASSERT(right->type() == MIRType::BigInt)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(right->type() == MIRType::BigInt)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(right->type() == MIRType::
BigInt))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("right->type() == MIRType::BigInt", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5407; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5408
5409 // One operand must be a constant.
5410 if (!left->isConstant() && !right->isConstant()) {
5411 return this;
5412 }
5413
5414 auto* constant =
5415 left->isConstant() ? left->toConstant() : right->toConstant();
5416 auto* operand = left->isConstant() ? right : left;
5417
5418 // The constant must be representable as an Int32.
5419 int32_t x;
5420 if (!BigInt::isInt32(constant->toBigInt(), &x)) {
5421 return this;
5422 }
5423
5424 MConstant* int32Const = MConstant::New(alloc, Int32Value(x));
5425 block()->insertBefore(this, int32Const);
5426
5427 auto op = jsop();
5428 if (IsStrictEqualityOp(op)) {
5429 // Compare_BigInt_Int32 is only valid for loose comparison.
5430 op = op == JSOp::StrictEq ? JSOp::Eq : JSOp::Ne;
5431 } else if (operand == right) {
5432 // Reverse the comparison operator if the operands were reordered.
5433 op = ReverseCompareOp(op);
5434 }
5435
5436 return MCompare::New(alloc, operand, int32Const, op,
5437 MCompare::Compare_BigInt_Int32);
5438}
5439
5440MDefinition* MCompare::foldsTo(TempAllocator& alloc) {
5441 bool result;
5442
5443 if (tryFold(&result) || evaluateConstantOperands(alloc, &result)) {
5444 if (type() == MIRType::Int32) {
5445 return MConstant::New(alloc, Int32Value(result));
5446 }
5447
5448 MOZ_ASSERT(type() == MIRType::Boolean)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Boolean)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(type() == MIRType::Boolean))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("type() == MIRType::Boolean"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5448); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 5448; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5449 return MConstant::New(alloc, BooleanValue(result));
5450 }
5451
5452 if (MDefinition* folded = tryFoldTypeOf(alloc); folded != this) {
5453 return folded;
5454 }
5455
5456 if (MDefinition* folded = tryFoldCharCompare(alloc); folded != this) {
5457 return folded;
5458 }
5459
5460 if (MDefinition* folded = tryFoldStringCompare(alloc); folded != this) {
5461 return folded;
5462 }
5463
5464 if (MDefinition* folded = tryFoldStringSubstring(alloc); folded != this) {
5465 return folded;
5466 }
5467
5468 if (MDefinition* folded = tryFoldStringIndexOf(alloc); folded != this) {
5469 return folded;
5470 }
5471
5472 if (MDefinition* folded = tryFoldBigInt64(alloc); folded != this) {
5473 return folded;
5474 }
5475
5476 if (MDefinition* folded = tryFoldBigIntPtr(alloc); folded != this) {
5477 return folded;
5478 }
5479
5480 if (MDefinition* folded = tryFoldBigInt(alloc); folded != this) {
5481 return folded;
5482 }
5483
5484 return this;
5485}
5486
5487void MCompare::trySpecializeFloat32(TempAllocator& alloc) {
5488 if (AllOperandsCanProduceFloat32(this) && compareType_ == Compare_Double) {
5489 compareType_ = Compare_Float32;
5490 } else {
5491 ConvertOperandsToDouble(this, alloc);
5492 }
5493}
5494
5495MDefinition* MNot::foldsTo(TempAllocator& alloc) {
5496 // Fold if the input is constant
5497 if (MConstant* inputConst = input()->maybeConstantValue()) {
5498 bool b;
5499 if (inputConst->valueToBoolean(&b)) {
5500 if (type() == MIRType::Int32 || type() == MIRType::Int64) {
5501 return MConstant::New(alloc, Int32Value(!b));
5502 }
5503 return MConstant::New(alloc, BooleanValue(!b));
5504 }
5505 }
5506
5507 // If the operand of the Not is itself a Not, they cancel out. But we can't
5508 // always convert Not(Not(x)) to x because that may loose the conversion to
5509 // boolean. We can simplify Not(Not(Not(x))) to Not(x) though.
5510 MDefinition* op = getOperand(0);
5511 if (op->isNot()) {
5512 MDefinition* opop = op->getOperand(0);
5513 if (opop->isNot()) {
5514 return opop;
5515 }
5516 }
5517
5518 // Not of an undefined or null value is always true
5519 if (input()->type() == MIRType::Undefined ||
5520 input()->type() == MIRType::Null) {
5521 return MConstant::New(alloc, BooleanValue(true));
5522 }
5523
5524 // Not of a symbol is always false.
5525 if (input()->type() == MIRType::Symbol) {
5526 return MConstant::New(alloc, BooleanValue(false));
5527 }
5528
5529 // Drop the conversion in `Not(Int64ToBigInt(int64))` to `Not(int64)`.
5530 if (input()->isInt64ToBigInt()) {
5531 return MNot::New(alloc, input()->toInt64ToBigInt()->input());
5532 }
5533
5534 // Drop the conversion in `Not(IntPtrToBigInt(intptr))` to `Not(intptr)`.
5535 if (input()->isIntPtrToBigInt()) {
5536 return MNot::New(alloc, input()->toIntPtrToBigInt()->input());
5537 }
5538
5539 return this;
5540}
5541
5542void MNot::trySpecializeFloat32(TempAllocator& alloc) {
5543 (void)EnsureFloatInputOrConvert(this, alloc);
5544}
5545
5546#ifdef JS_JITSPEW1
5547void MBeta::printOpcode(GenericPrinter& out) const {
5548 MDefinition::printOpcode(out);
5549
5550 out.printf(" ");
5551 comparison_->dump(out);
5552}
5553#endif
5554
5555AliasSet MCreateThis::getAliasSet() const {
5556 return AliasSet::Load(AliasSet::Any);
5557}
5558
5559bool MGetArgumentsObjectArg::congruentTo(const MDefinition* ins) const {
5560 if (!ins->isGetArgumentsObjectArg()) {
5561 return false;
5562 }
5563 if (ins->toGetArgumentsObjectArg()->argno() != argno()) {
5564 return false;
5565 }
5566 return congruentIfOperandsEqual(ins);
5567}
5568
5569AliasSet MGetArgumentsObjectArg::getAliasSet() const {
5570 return AliasSet::Load(AliasSet::Any);
5571}
5572
5573AliasSet MSetArgumentsObjectArg::getAliasSet() const {
5574 return AliasSet::Store(AliasSet::Any);
5575}
5576
5577MObjectState::MObjectState(MObjectState* state)
5578 : MVariadicInstruction(classOpcode),
5579 numSlots_(state->numSlots_),
5580 numFixedSlots_(state->numFixedSlots_) {
5581 // This instruction is only used as a summary for bailout paths.
5582 setResultType(MIRType::Object);
5583 setRecoveredOnBailout();
5584}
5585
5586MObjectState::MObjectState(JSObject* templateObject)
5587 : MObjectState(templateObject->as<NativeObject>().shape()) {}
5588
5589MObjectState::MObjectState(const Shape* shape)
5590 : MVariadicInstruction(classOpcode) {
5591 // This instruction is only used as a summary for bailout paths.
5592 setResultType(MIRType::Object);
5593 setRecoveredOnBailout();
5594
5595 numSlots_ = shape->asShared().slotSpan();
5596 numFixedSlots_ = shape->asShared().numFixedSlots();
5597}
5598
5599/* static */
5600JSObject* MObjectState::templateObjectOf(MDefinition* obj) {
5601 // MNewPlainObject uses a shape constant, not an object.
5602 MOZ_ASSERT(!obj->isNewPlainObject())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!obj->isNewPlainObject())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!obj->isNewPlainObject())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!obj->isNewPlainObject()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5602); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!obj->isNewPlainObject()"
")"); do { *((volatile int*)__null) = 5602; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5603
5604 if (obj->isNewObject()) {
5605 return obj->toNewObject()->templateObject();
5606 } else if (obj->isNewCallObject()) {
5607 return obj->toNewCallObject()->templateObject();
5608 } else if (obj->isNewIterator()) {
5609 return obj->toNewIterator()->templateObject();
5610 }
5611
5612 MOZ_CRASH("unreachable")do { do { } while (false); MOZ_ReportCrash("" "unreachable", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5612); AnnotateMozCrashReason("MOZ_CRASH(" "unreachable" ")"
); do { *((volatile int*)__null) = 5612; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
5613}
5614
5615bool MObjectState::init(TempAllocator& alloc, MDefinition* obj) {
5616 if (!MVariadicInstruction::init(alloc, numSlots() + 1)) {
5617 return false;
5618 }
5619 // +1, for the Object.
5620 initOperand(0, obj);
5621 return true;
5622}
5623
5624void MObjectState::initFromTemplateObject(TempAllocator& alloc,
5625 MDefinition* undefinedVal) {
5626 if (object()->isNewPlainObject()) {
5627 MOZ_ASSERT(object()->toNewPlainObject()->shape()->asShared().slotSpan() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(object()->toNewPlainObject()->shape()->asShared
().slotSpan() == numSlots())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(object()->toNewPlainObject
()->shape()->asShared().slotSpan() == numSlots()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5628); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()"
")"); do { *((volatile int*)__null) = 5628; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5628 numSlots())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(object()->toNewPlainObject()->shape()->asShared
().slotSpan() == numSlots())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(object()->toNewPlainObject
()->shape()->asShared().slotSpan() == numSlots()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5628); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()"
")"); do { *((volatile int*)__null) = 5628; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5629 for (size_t i = 0; i < numSlots(); i++) {
5630 initSlot(i, undefinedVal);
5631 }
5632 return;
5633 }
5634
5635 JSObject* templateObject = templateObjectOf(object());
5636
5637 // Initialize all the slots of the object state with the value contained in
5638 // the template object. This is needed to account values which are baked in
5639 // the template objects and not visible in IonMonkey, such as the
5640 // uninitialized-lexical magic value of call objects.
5641
5642 MOZ_ASSERT(templateObject->is<NativeObject>())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(templateObject->is<NativeObject>())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(templateObject->is<NativeObject>()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("templateObject->is<NativeObject>()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5642); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject->is<NativeObject>()"
")"); do { *((volatile int*)__null) = 5642; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5643 NativeObject& nativeObject = templateObject->as<NativeObject>();
5644 MOZ_ASSERT(nativeObject.slotSpan() == numSlots())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nativeObject.slotSpan() == numSlots())>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(nativeObject.slotSpan() == numSlots()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("nativeObject.slotSpan() == numSlots()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeObject.slotSpan() == numSlots()"
")"); do { *((volatile int*)__null) = 5644; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5645
5646 for (size_t i = 0; i < numSlots(); i++) {
5647 Value val = nativeObject.getSlot(i);
5648 MDefinition* def = undefinedVal;
5649 if (!val.isUndefined()) {
5650 MConstant* ins = MConstant::New(alloc, val);
5651 block()->insertBefore(this, ins);
5652 def = ins;
5653 }
5654 initSlot(i, def);
5655 }
5656}
5657
5658MObjectState* MObjectState::New(TempAllocator& alloc, MDefinition* obj) {
5659 MObjectState* res;
5660 if (obj->isNewPlainObject()) {
5661 const Shape* shape = obj->toNewPlainObject()->shape();
5662 res = new (alloc) MObjectState(shape);
5663 } else {
5664 JSObject* templateObject = templateObjectOf(obj);
5665 MOZ_ASSERT(templateObject, "Unexpected object creation.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(templateObject)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(templateObject))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("templateObject"
" (" "Unexpected object creation." ")", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5665); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject"
") (" "Unexpected object creation." ")"); do { *((volatile int
*)__null) = 5665; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5666 res = new (alloc) MObjectState(templateObject);
5667 }
5668
5669 if (!res || !res->init(alloc, obj)) {
5670 return nullptr;
5671 }
5672 return res;
5673}
5674
5675MObjectState* MObjectState::Copy(TempAllocator& alloc, MObjectState* state) {
5676 MObjectState* res = new (alloc) MObjectState(state);
5677 if (!res || !res->init(alloc, state->object())) {
5678 return nullptr;
5679 }
5680 for (size_t i = 0; i < res->numSlots(); i++) {
5681 res->initSlot(i, state->getSlot(i));
5682 }
5683 return res;
5684}
5685
5686MArrayState::MArrayState(MDefinition* arr) : MVariadicInstruction(classOpcode) {
5687 // This instruction is only used as a summary for bailout paths.
5688 setResultType(MIRType::Object);
5689 setRecoveredOnBailout();
5690 if (arr->isNewArrayObject()) {
5691 numElements_ = arr->toNewArrayObject()->length();
5692 } else {
5693 numElements_ = arr->toNewArray()->length();
5694 }
5695}
5696
5697bool MArrayState::init(TempAllocator& alloc, MDefinition* obj,
5698 MDefinition* len) {
5699 if (!MVariadicInstruction::init(alloc, numElements() + 2)) {
5700 return false;
5701 }
5702 // +1, for the Array object.
5703 initOperand(0, obj);
5704 // +1, for the length value of the array.
5705 initOperand(1, len);
5706 return true;
5707}
5708
5709void MArrayState::initFromTemplateObject(TempAllocator& alloc,
5710 MDefinition* undefinedVal) {
5711 for (size_t i = 0; i < numElements(); i++) {
5712 initElement(i, undefinedVal);
5713 }
5714}
5715
5716MArrayState* MArrayState::New(TempAllocator& alloc, MDefinition* arr,
5717 MDefinition* initLength) {
5718 MArrayState* res = new (alloc) MArrayState(arr);
5719 if (!res || !res->init(alloc, arr, initLength)) {
5720 return nullptr;
5721 }
5722 return res;
5723}
5724
5725MArrayState* MArrayState::Copy(TempAllocator& alloc, MArrayState* state) {
5726 MDefinition* arr = state->array();
5727 MDefinition* len = state->initializedLength();
5728 MArrayState* res = new (alloc) MArrayState(arr);
5729 if (!res || !res->init(alloc, arr, len)) {
5730 return nullptr;
5731 }
5732 for (size_t i = 0; i < res->numElements(); i++) {
5733 res->initElement(i, state->getElement(i));
5734 }
5735 return res;
5736}
5737
5738MNewArray::MNewArray(uint32_t length, MConstant* templateConst,
5739 gc::Heap initialHeap, bool vmCall)
5740 : MUnaryInstruction(classOpcode, templateConst),
5741 length_(length),
5742 initialHeap_(initialHeap),
5743 vmCall_(vmCall) {
5744 setResultType(MIRType::Object);
5745}
5746
5747MDefinition::AliasType MLoadFixedSlot::mightAlias(
5748 const MDefinition* def) const {
5749 if (def->isStoreFixedSlot()) {
5750 const MStoreFixedSlot* store = def->toStoreFixedSlot();
5751 if (store->slot() != slot()) {
5752 return AliasType::NoAlias;
5753 }
5754 if (store->object() != object()) {
5755 return AliasType::MayAlias;
5756 }
5757 return AliasType::MustAlias;
5758 }
5759 return AliasType::MayAlias;
5760}
5761
5762MDefinition* MLoadFixedSlot::foldsTo(TempAllocator& alloc) {
5763 if (MDefinition* def = foldsToStore(alloc)) {
5764 return def;
5765 }
5766
5767 return this;
5768}
5769
5770MDefinition::AliasType MLoadFixedSlotAndUnbox::mightAlias(
5771 const MDefinition* def) const {
5772 if (def->isStoreFixedSlot()) {
5773 const MStoreFixedSlot* store = def->toStoreFixedSlot();
5774 if (store->slot() != slot()) {
5775 return AliasType::NoAlias;
5776 }
5777 if (store->object() != object()) {
5778 return AliasType::MayAlias;
5779 }
5780 return AliasType::MustAlias;
5781 }
5782 return AliasType::MayAlias;
5783}
5784
5785MDefinition* MLoadFixedSlotAndUnbox::foldsTo(TempAllocator& alloc) {
5786 if (MDefinition* def = foldsToStore(alloc)) {
5787 return def;
5788 }
5789
5790 return this;
5791}
5792
5793MDefinition::AliasType MLoadDynamicSlot::mightAlias(
5794 const MDefinition* def) const {
5795 if (def->isStoreDynamicSlot()) {
5796 const MStoreDynamicSlot* store = def->toStoreDynamicSlot();
5797 if (store->slot() != slot()) {
5798 return AliasType::NoAlias;
5799 }
5800
5801 if (store->slots() != slots()) {
5802 return AliasType::MayAlias;
5803 }
5804
5805 return AliasType::MustAlias;
5806 }
5807 return AliasType::MayAlias;
5808}
5809
5810HashNumber MLoadDynamicSlot::valueHash() const {
5811 HashNumber hash = MDefinition::valueHash();
5812 hash = addU32ToHash(hash, slot_);
5813 return hash;
5814}
5815
5816MDefinition* MLoadDynamicSlot::foldsTo(TempAllocator& alloc) {
5817 if (MDefinition* def = foldsToStore(alloc)) {
5818 return def;
5819 }
5820
5821 return this;
5822}
5823
5824#ifdef JS_JITSPEW1
5825void MLoadDynamicSlot::printOpcode(GenericPrinter& out) const {
5826 MDefinition::printOpcode(out);
5827 out.printf(" (slot %u)", slot());
5828}
5829
5830void MLoadDynamicSlotAndUnbox::printOpcode(GenericPrinter& out) const {
5831 MDefinition::printOpcode(out);
5832 out.printf(" (slot %zu)", slot());
5833}
5834
5835void MStoreDynamicSlot::printOpcode(GenericPrinter& out) const {
5836 MDefinition::printOpcode(out);
5837 out.printf(" (slot %u)", slot());
5838}
5839
5840void MLoadFixedSlot::printOpcode(GenericPrinter& out) const {
5841 MDefinition::printOpcode(out);
5842 out.printf(" (slot %zu)", slot());
5843}
5844
5845void MLoadFixedSlotAndUnbox::printOpcode(GenericPrinter& out) const {
5846 MDefinition::printOpcode(out);
5847 out.printf(" (slot %zu)", slot());
5848}
5849
5850void MStoreFixedSlot::printOpcode(GenericPrinter& out) const {
5851 MDefinition::printOpcode(out);
5852 out.printf(" (slot %zu)", slot());
5853}
5854#endif
5855
5856MDefinition* MGuardFunctionScript::foldsTo(TempAllocator& alloc) {
5857 MDefinition* in = input();
5858 if (in->isLambda() &&
5859 in->toLambda()->templateFunction()->baseScript() == expected()) {
5860 return in;
5861 }
5862 return this;
5863}
5864
5865MDefinition* MFunctionEnvironment::foldsTo(TempAllocator& alloc) {
5866 if (input()->isLambda()) {
5867 return input()->toLambda()->environmentChain();
5868 }
5869 if (input()->isFunctionWithProto()) {
5870 return input()->toFunctionWithProto()->environmentChain();
5871 }
5872 return this;
5873}
5874
5875static bool AddIsANonZeroAdditionOf(MAdd* add, MDefinition* ins) {
5876 if (add->lhs() != ins && add->rhs() != ins) {
5877 return false;
5878 }
5879 MDefinition* other = (add->lhs() == ins) ? add->rhs() : add->lhs();
5880 if (!IsNumberType(other->type())) {
5881 return false;
5882 }
5883 if (!other->isConstant()) {
5884 return false;
5885 }
5886 if (other->toConstant()->numberToDouble() == 0) {
5887 return false;
5888 }
5889 return true;
5890}
5891
5892// Skip over instructions that usually appear between the actual index
5893// value being used and the MLoadElement.
5894// They don't modify the index value in a meaningful way.
5895static MDefinition* SkipUninterestingInstructions(MDefinition* ins) {
5896 // Drop the MToNumberInt32 added by the TypePolicy for double and float
5897 // values.
5898 if (ins->isToNumberInt32()) {
5899 return SkipUninterestingInstructions(ins->toToNumberInt32()->input());
5900 }
5901
5902 // Ignore the bounds check, which don't modify the index.
5903 if (ins->isBoundsCheck()) {
5904 return SkipUninterestingInstructions(ins->toBoundsCheck()->index());
5905 }
5906
5907 // Masking the index for Spectre-mitigation is not observable.
5908 if (ins->isSpectreMaskIndex()) {
5909 return SkipUninterestingInstructions(ins->toSpectreMaskIndex()->index());
5910 }
5911
5912 return ins;
5913}
5914
5915static bool DefinitelyDifferentValue(MDefinition* ins1, MDefinition* ins2) {
5916 ins1 = SkipUninterestingInstructions(ins1);
5917 ins2 = SkipUninterestingInstructions(ins2);
5918
5919 if (ins1 == ins2) {
5920 return false;
5921 }
5922
5923 // For constants check they are not equal.
5924 if (ins1->isConstant() && ins2->isConstant()) {
5925 MConstant* cst1 = ins1->toConstant();
5926 MConstant* cst2 = ins2->toConstant();
5927
5928 if (!cst1->isTypeRepresentableAsDouble() ||
5929 !cst2->isTypeRepresentableAsDouble()) {
5930 return false;
5931 }
5932
5933 // Be conservative and only allow values that fit into int32.
5934 int32_t n1, n2;
5935 if (!mozilla::NumberIsInt32(cst1->numberToDouble(), &n1) ||
5936 !mozilla::NumberIsInt32(cst2->numberToDouble(), &n2)) {
5937 return false;
5938 }
5939
5940 return n1 != n2;
5941 }
5942
5943 // Check if "ins1 = ins2 + cte", which would make both instructions
5944 // have different values.
5945 if (ins1->isAdd()) {
5946 if (AddIsANonZeroAdditionOf(ins1->toAdd(), ins2)) {
5947 return true;
5948 }
5949 }
5950 if (ins2->isAdd()) {
5951 if (AddIsANonZeroAdditionOf(ins2->toAdd(), ins1)) {
5952 return true;
5953 }
5954 }
5955
5956 return false;
5957}
5958
5959MDefinition::AliasType MLoadElement::mightAlias(const MDefinition* def) const {
5960 if (def->isStoreElement()) {
5961 const MStoreElement* store = def->toStoreElement();
5962 if (store->index() != index()) {
5963 if (DefinitelyDifferentValue(store->index(), index())) {
5964 return AliasType::NoAlias;
5965 }
5966 return AliasType::MayAlias;
5967 }
5968
5969 if (store->elements() != elements()) {
5970 return AliasType::MayAlias;
5971 }
5972
5973 return AliasType::MustAlias;
5974 }
5975 return AliasType::MayAlias;
5976}
5977
5978MDefinition* MLoadElement::foldsTo(TempAllocator& alloc) {
5979 if (MDefinition* def = foldsToStore(alloc)) {
5980 return def;
5981 }
5982
5983 return this;
5984}
5985
5986void MSqrt::trySpecializeFloat32(TempAllocator& alloc) {
5987 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
5988 setResultType(MIRType::Float32);
5989 specialization_ = MIRType::Float32;
5990 }
5991}
5992
5993MDefinition* MClz::foldsTo(TempAllocator& alloc) {
5994 if (num()->isConstant()) {
5995 MConstant* c = num()->toConstant();
5996 if (type() == MIRType::Int32) {
5997 int32_t n = c->toInt32();
5998 if (n == 0) {
5999 return MConstant::New(alloc, Int32Value(32));
6000 }
6001 return MConstant::New(alloc,
6002 Int32Value(mozilla::CountLeadingZeroes32(n)));
6003 }
6004 int64_t n = c->toInt64();
6005 if (n == 0) {
6006 return MConstant::NewInt64(alloc, int64_t(64));
6007 }
6008 return MConstant::NewInt64(alloc,
6009 int64_t(mozilla::CountLeadingZeroes64(n)));
6010 }
6011
6012 return this;
6013}
6014
6015MDefinition* MCtz::foldsTo(TempAllocator& alloc) {
6016 if (num()->isConstant()) {
6017 MConstant* c = num()->toConstant();
6018 if (type() == MIRType::Int32) {
6019 int32_t n = num()->toConstant()->toInt32();
6020 if (n == 0) {
6021 return MConstant::New(alloc, Int32Value(32));
6022 }
6023 return MConstant::New(alloc,
6024 Int32Value(mozilla::CountTrailingZeroes32(n)));
6025 }
6026 int64_t n = c->toInt64();
6027 if (n == 0) {
6028 return MConstant::NewInt64(alloc, int64_t(64));
6029 }
6030 return MConstant::NewInt64(alloc,
6031 int64_t(mozilla::CountTrailingZeroes64(n)));
6032 }
6033
6034 return this;
6035}
6036
6037MDefinition* MPopcnt::foldsTo(TempAllocator& alloc) {
6038 if (num()->isConstant()) {
6039 MConstant* c = num()->toConstant();
6040 if (type() == MIRType::Int32) {
6041 int32_t n = num()->toConstant()->toInt32();
6042 return MConstant::New(alloc, Int32Value(mozilla::CountPopulation32(n)));
6043 }
6044 int64_t n = c->toInt64();
6045 return MConstant::NewInt64(alloc, int64_t(mozilla::CountPopulation64(n)));
6046 }
6047
6048 return this;
6049}
6050
6051MDefinition* MBoundsCheck::foldsTo(TempAllocator& alloc) {
6052 if (type() == MIRType::Int32 && index()->isConstant() &&
6053 length()->isConstant()) {
6054 uint32_t len = length()->toConstant()->toInt32();
6055 uint32_t idx = index()->toConstant()->toInt32();
6056 if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len) {
6057 return index();
6058 }
6059 }
6060
6061 return this;
6062}
6063
6064MDefinition* MTableSwitch::foldsTo(TempAllocator& alloc) {
6065 MDefinition* op = getOperand(0);
6066
6067 // If we only have one successor, convert to a plain goto to the only
6068 // successor. TableSwitch indices are numeric; other types will always go to
6069 // the only successor.
6070 if (numSuccessors() == 1 ||
6071 (op->type() != MIRType::Value && !IsNumberType(op->type()))) {
6072 return MGoto::New(alloc, getDefault());
6073 }
6074
6075 if (MConstant* opConst = op->maybeConstantValue()) {
6076 if (op->type() == MIRType::Int32) {
6077 int32_t i = opConst->toInt32() - low_;
6078 MBasicBlock* target;
6079 if (size_t(i) < numCases()) {
6080 target = getCase(size_t(i));
6081 } else {
6082 target = getDefault();
6083 }
6084 MOZ_ASSERT(target)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(target)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(target))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("target", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 6084); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")"
); do { *((volatile int*)__null) = 6084; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6085 return MGoto::New(alloc, target);
6086 }
6087 }
6088
6089 return this;
6090}
6091
6092MDefinition* MArrayJoin::foldsTo(TempAllocator& alloc) {
6093 MDefinition* arr = array();
6094
6095 if (!arr->isStringSplit()) {
6096 return this;
6097 }
6098
6099 setRecoveredOnBailout();
6100 if (arr->hasLiveDefUses()) {
6101 setNotRecoveredOnBailout();
6102 return this;
6103 }
6104
6105 // The MStringSplit won't generate any code.
6106 arr->setRecoveredOnBailout();
6107
6108 // We're replacing foo.split(bar).join(baz) by
6109 // foo.replace(bar, baz). MStringSplit could be recovered by
6110 // a bailout. As we are removing its last use, and its result
6111 // could be captured by a resume point, this MStringSplit will
6112 // be executed on the bailout path.
6113 MDefinition* string = arr->toStringSplit()->string();
6114 MDefinition* pattern = arr->toStringSplit()->separator();
6115 MDefinition* replacement = sep();
6116
6117 MStringReplace* substr =
6118 MStringReplace::New(alloc, string, pattern, replacement);
6119 substr->setFlatReplacement();
6120 return substr;
6121}
6122
6123MDefinition* MGetFirstDollarIndex::foldsTo(TempAllocator& alloc) {
6124 MDefinition* strArg = str();
6125 if (!strArg->isConstant()) {
6126 return this;
6127 }
6128
6129 JSLinearString* str = &strArg->toConstant()->toString()->asLinear();
6130 int32_t index = GetFirstDollarIndexRawFlat(str);
6131 return MConstant::New(alloc, Int32Value(index));
6132}
6133
6134AliasSet MThrowRuntimeLexicalError::getAliasSet() const {
6135 return AliasSet::Store(AliasSet::ExceptionState);
6136}
6137
6138AliasSet MSlots::getAliasSet() const {
6139 return AliasSet::Load(AliasSet::ObjectFields);
6140}
6141
6142MDefinition::AliasType MSlots::mightAlias(const MDefinition* store) const {
6143 // ArrayPush only modifies object elements, but not object slots.
6144 if (store->isArrayPush()) {
6145 return AliasType::NoAlias;
6146 }
6147 return MInstruction::mightAlias(store);
6148}
6149
6150AliasSet MElements::getAliasSet() const {
6151 return AliasSet::Load(AliasSet::ObjectFields);
6152}
6153
6154AliasSet MInitializedLength::getAliasSet() const {
6155 return AliasSet::Load(AliasSet::ObjectFields);
6156}
6157
6158AliasSet MSetInitializedLength::getAliasSet() const {
6159 return AliasSet::Store(AliasSet::ObjectFields);
6160}
6161
6162AliasSet MObjectKeysLength::getAliasSet() const {
6163 return AliasSet::Load(AliasSet::ObjectFields);
6164}
6165
6166AliasSet MArrayLength::getAliasSet() const {
6167 return AliasSet::Load(AliasSet::ObjectFields);
6168}
6169
6170AliasSet MSetArrayLength::getAliasSet() const {
6171 return AliasSet::Store(AliasSet::ObjectFields);
6172}
6173
6174AliasSet MFunctionLength::getAliasSet() const {
6175 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6176 AliasSet::DynamicSlot);
6177}
6178
6179AliasSet MFunctionName::getAliasSet() const {
6180 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6181 AliasSet::DynamicSlot);
6182}
6183
6184AliasSet MArrayBufferByteLength::getAliasSet() const {
6185 return AliasSet::Load(AliasSet::FixedSlot);
6186}
6187
6188AliasSet MArrayBufferViewLength::getAliasSet() const {
6189 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset);
6190}
6191
6192AliasSet MArrayBufferViewByteOffset::getAliasSet() const {
6193 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset);
6194}
6195
6196AliasSet MArrayBufferViewElements::getAliasSet() const {
6197 return AliasSet::Load(AliasSet::ObjectFields);
6198}
6199
6200AliasSet MGuardHasAttachedArrayBuffer::getAliasSet() const {
6201 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot);
6202}
6203
6204AliasSet MResizableTypedArrayByteOffsetMaybeOutOfBounds::getAliasSet() const {
6205 // Loads the byteOffset and additionally checks for detached buffers, so the
6206 // alias set also has to include |ObjectFields| and |FixedSlot|.
6207 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset |
6208 AliasSet::ObjectFields | AliasSet::FixedSlot);
6209}
6210
6211AliasSet MResizableTypedArrayLength::getAliasSet() const {
6212 // Loads the length and byteOffset slots, the shared-elements flag, the
6213 // auto-length fixed slot, and the shared raw-buffer length.
6214 auto flags = AliasSet::ArrayBufferViewLengthOrOffset |
6215 AliasSet::ObjectFields | AliasSet::FixedSlot |
6216 AliasSet::SharedArrayRawBufferLength;
6217
6218 // When a barrier is needed make the instruction effectful by giving it a
6219 // "store" effect. Also prevent reordering LoadUnboxedScalar before this
6220 // instruction by including |UnboxedElement| in the alias set.
6221 if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
6222 return AliasSet::Store(flags | AliasSet::UnboxedElement);
6223 }
6224 return AliasSet::Load(flags);
6225}
6226
6227bool MResizableTypedArrayLength::congruentTo(const MDefinition* ins) const {
6228 if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
6229 return false;
6230 }
6231 return congruentIfOperandsEqual(ins);
6232}
6233
6234AliasSet MResizableDataViewByteLength::getAliasSet() const {
6235 // Loads the length and byteOffset slots, the shared-elements flag, the
6236 // auto-length fixed slot, and the shared raw-buffer length.
6237 auto flags = AliasSet::ArrayBufferViewLengthOrOffset |
6238 AliasSet::ObjectFields | AliasSet::FixedSlot |
6239 AliasSet::SharedArrayRawBufferLength;
6240
6241 // When a barrier is needed make the instruction effectful by giving it a
6242 // "store" effect. Also prevent reordering LoadUnboxedScalar before this
6243 // instruction by including |UnboxedElement| in the alias set.
6244 if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
6245 return AliasSet::Store(flags | AliasSet::UnboxedElement);
6246 }
6247 return AliasSet::Load(flags);
6248}
6249
6250bool MResizableDataViewByteLength::congruentTo(const MDefinition* ins) const {
6251 if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
6252 return false;
6253 }
6254 return congruentIfOperandsEqual(ins);
6255}
6256
6257AliasSet MGrowableSharedArrayBufferByteLength::getAliasSet() const {
6258 // Requires a barrier, so make the instruction effectful by giving it a
6259 // "store" effect. Also prevent reordering LoadUnboxedScalar before this
6260 // instruction by including |UnboxedElement| in the alias set.
6261 return AliasSet::Store(AliasSet::FixedSlot |
6262 AliasSet::SharedArrayRawBufferLength |
6263 AliasSet::UnboxedElement);
6264}
6265
6266AliasSet MGuardResizableArrayBufferViewInBounds::getAliasSet() const {
6267 // Additionally reads the |initialLength| and |initialByteOffset| slots, but
6268 // since these can't change after construction, we don't need to track them.
6269 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset);
6270}
6271
6272AliasSet MGuardResizableArrayBufferViewInBoundsOrDetached::getAliasSet() const {
6273 // Loads the byteOffset and additionally checks for detached buffers, so the
6274 // alias set also has to include |ObjectFields| and |FixedSlot|.
6275 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset |
6276 AliasSet::ObjectFields | AliasSet::FixedSlot);
6277}
6278
6279AliasSet MArrayPush::getAliasSet() const {
6280 return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
6281}
6282
6283MDefinition* MGuardNumberToIntPtrIndex::foldsTo(TempAllocator& alloc) {
6284 MDefinition* input = this->input();
6285
6286 if (input->isToDouble() && input->getOperand(0)->type() == MIRType::Int32) {
6287 return MInt32ToIntPtr::New(alloc, input->getOperand(0));
6288 }
6289
6290 if (!input->isConstant()) {
6291 return this;
6292 }
6293
6294 // Fold constant double representable as intptr to intptr.
6295 int64_t ival;
6296 if (!mozilla::NumberEqualsInt64(input->toConstant()->toDouble(), &ival)) {
6297 // If not representable as an int64, this access is equal to an OOB access.
6298 // So replace it with a known int64/intptr value which also produces an OOB
6299 // access. If we don't support OOB accesses we have to bail out.
6300 if (!supportOOB()) {
6301 return this;
6302 }
6303 ival = -1;
6304 }
6305
6306 if (ival < INTPTR_MIN(-9223372036854775807L-1) || ival > INTPTR_MAX(9223372036854775807L)) {
6307 return this;
6308 }
6309
6310 return MConstant::NewIntPtr(alloc, intptr_t(ival));
6311}
6312
6313MDefinition* MIsObject::foldsTo(TempAllocator& alloc) {
6314 if (!object()->isBox()) {
6315 return this;
6316 }
6317
6318 MDefinition* unboxed = object()->getOperand(0);
6319 if (unboxed->type() == MIRType::Object) {
6320 return MConstant::New(alloc, BooleanValue(true));
6321 }
6322
6323 return this;
6324}
6325
6326MDefinition* MIsNullOrUndefined::foldsTo(TempAllocator& alloc) {
6327 MDefinition* input = value();
6328 if (input->isBox()) {
6329 input = input->toBox()->input();
6330 }
6331
6332 if (input->definitelyType({MIRType::Null, MIRType::Undefined})) {
6333 return MConstant::New(alloc, BooleanValue(true));
6334 }
6335
6336 if (!input->mightBeType(MIRType::Null) &&
6337 !input->mightBeType(MIRType::Undefined)) {
6338 return MConstant::New(alloc, BooleanValue(false));
6339 }
6340
6341 return this;
6342}
6343
6344AliasSet MHomeObjectSuperBase::getAliasSet() const {
6345 return AliasSet::Load(AliasSet::ObjectFields);
6346}
6347
6348MDefinition* MGuardValue::foldsTo(TempAllocator& alloc) {
6349 if (MConstant* cst = value()->maybeConstantValue()) {
6350 if (cst->toJSValue() == expected()) {
6351 return value();
6352 }
6353 }
6354
6355 return this;
6356}
6357
6358MDefinition* MGuardNullOrUndefined::foldsTo(TempAllocator& alloc) {
6359 MDefinition* input = value();
6360 if (input->isBox()) {
6361 input = input->toBox()->input();
6362 }
6363
6364 if (input->definitelyType({MIRType::Null, MIRType::Undefined})) {
6365 return value();
6366 }
6367
6368 return this;
6369}
6370
6371MDefinition* MGuardIsNotObject::foldsTo(TempAllocator& alloc) {
6372 MDefinition* input = value();
6373 if (input->isBox()) {
6374 input = input->toBox()->input();
6375 }
6376
6377 if (!input->mightBeType(MIRType::Object)) {
6378 return value();
6379 }
6380
6381 return this;
6382}
6383
6384MDefinition* MGuardObjectIdentity::foldsTo(TempAllocator& alloc) {
6385 if (object()->isConstant() && expected()->isConstant()) {
6386 JSObject* obj = &object()->toConstant()->toObject();
6387 JSObject* other = &expected()->toConstant()->toObject();
6388 if (!bailOnEquality()) {
6389 if (obj == other) {
6390 return object();
6391 }
6392 } else {
6393 if (obj != other) {
6394 return object();
6395 }
6396 }
6397 }
6398
6399 if (!bailOnEquality() && object()->isNurseryObject() &&
6400 expected()->isNurseryObject()) {
6401 uint32_t objIndex = object()->toNurseryObject()->nurseryIndex();
6402 uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex();
6403 if (objIndex == otherIndex) {
6404 return object();
6405 }
6406 }
6407
6408 return this;
6409}
6410
6411MDefinition* MGuardSpecificFunction::foldsTo(TempAllocator& alloc) {
6412 if (function()->isConstant() && expected()->isConstant()) {
6413 JSObject* fun = &function()->toConstant()->toObject();
6414 JSObject* other = &expected()->toConstant()->toObject();
6415 if (fun == other) {
6416 return function();
6417 }
6418 }
6419
6420 if (function()->isNurseryObject() && expected()->isNurseryObject()) {
6421 uint32_t funIndex = function()->toNurseryObject()->nurseryIndex();
6422 uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex();
6423 if (funIndex == otherIndex) {
6424 return function();
6425 }
6426 }
6427
6428 return this;
6429}
6430
6431MDefinition* MGuardSpecificAtom::foldsTo(TempAllocator& alloc) {
6432 if (str()->isConstant()) {
6433 JSString* s = str()->toConstant()->toString();
6434 if (s->isAtom()) {
6435 JSAtom* cstAtom = &s->asAtom();
6436 if (cstAtom == atom()) {
6437 return str();
6438 }
6439 }
6440 }
6441
6442 return this;
6443}
6444
6445MDefinition* MGuardSpecificSymbol::foldsTo(TempAllocator& alloc) {
6446 if (symbol()->isConstant()) {
6447 if (symbol()->toConstant()->toSymbol() == expected()) {
6448 return symbol();
6449 }
6450 }
6451
6452 return this;
6453}
6454
6455MDefinition* MGuardSpecificInt32::foldsTo(TempAllocator& alloc) {
6456 if (num()->isConstant() && num()->toConstant()->isInt32(expected())) {
6457 return num();
6458 }
6459 return this;
6460}
6461
6462bool MCallBindVar::congruentTo(const MDefinition* ins) const {
6463 if (!ins->isCallBindVar()) {
6464 return false;
6465 }
6466 return congruentIfOperandsEqual(ins);
6467}
6468
6469bool MGuardShape::congruentTo(const MDefinition* ins) const {
6470 if (!ins->isGuardShape()) {
6471 return false;
6472 }
6473 if (shape() != ins->toGuardShape()->shape()) {
6474 return false;
6475 }
6476 return congruentIfOperandsEqual(ins);
6477}
6478
6479AliasSet MGuardShape::getAliasSet() const {
6480 return AliasSet::Load(AliasSet::ObjectFields);
6481}
6482
6483MDefinition::AliasType MGuardShape::mightAlias(const MDefinition* store) const {
6484 // These instructions only modify object elements, but not the shape.
6485 if (store->isStoreElementHole() || store->isArrayPush()) {
6486 return AliasType::NoAlias;
6487 }
6488 if (object()->isConstantProto()) {
6489 const MDefinition* receiverObject =
6490 object()->toConstantProto()->getReceiverObject();
6491 switch (store->op()) {
6492 case MDefinition::Opcode::StoreFixedSlot:
6493 if (store->toStoreFixedSlot()->object()->skipObjectGuards() ==
6494 receiverObject) {
6495 return AliasType::NoAlias;
6496 }
6497 break;
6498 case MDefinition::Opcode::StoreDynamicSlot:
6499 if (store->toStoreDynamicSlot()
6500 ->slots()
6501 ->toSlots()
6502 ->object()
6503 ->skipObjectGuards() == receiverObject) {
6504 return AliasType::NoAlias;
6505 }
6506 break;
6507 case MDefinition::Opcode::AddAndStoreSlot:
6508 if (store->toAddAndStoreSlot()->object()->skipObjectGuards() ==
6509 receiverObject) {
6510 return AliasType::NoAlias;
6511 }
6512 break;
6513 case MDefinition::Opcode::AllocateAndStoreSlot:
6514 if (store->toAllocateAndStoreSlot()->object()->skipObjectGuards() ==
6515 receiverObject) {
6516 return AliasType::NoAlias;
6517 }
6518 break;
6519 default:
6520 break;
6521 }
6522 }
6523 return MInstruction::mightAlias(store);
6524}
6525
6526bool MGuardFuse::congruentTo(const MDefinition* ins) const {
6527 if (!ins->isGuardFuse()) {
6528 return false;
6529 }
6530 if (fuseIndex() != ins->toGuardFuse()->fuseIndex()) {
6531 return false;
6532 }
6533 return congruentIfOperandsEqual(ins);
6534}
6535
6536AliasSet MGuardFuse::getAliasSet() const {
6537 // The alias set below reflects the set of operations which could cause a fuse
6538 // to be popped, and therefore MGuardFuse aliases with.
6539 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::DynamicSlot |
6540 AliasSet::FixedSlot |
6541 AliasSet::GlobalGenerationCounter);
6542}
6543
6544AliasSet MGuardMultipleShapes::getAliasSet() const {
6545 // Note: This instruction loads the elements of the ListObject used to
6546 // store the list of shapes, but that object is internal and not exposed
6547 // to script, so it doesn't have to be in the alias set.
6548 return AliasSet::Load(AliasSet::ObjectFields);
6549}
6550
6551AliasSet MGuardGlobalGeneration::getAliasSet() const {
6552 return AliasSet::Load(AliasSet::GlobalGenerationCounter);
6553}
6554
6555bool MGuardGlobalGeneration::congruentTo(const MDefinition* ins) const {
6556 return ins->isGuardGlobalGeneration() &&
6557 ins->toGuardGlobalGeneration()->expected() == expected() &&
6558 ins->toGuardGlobalGeneration()->generationAddr() == generationAddr();
6559}
6560
6561MDefinition* MGuardIsNotProxy::foldsTo(TempAllocator& alloc) {
6562 KnownClass known = GetObjectKnownClass(object());
6563 if (known == KnownClass::None) {
6564 return this;
6565 }
6566
6567 MOZ_ASSERT(!GetObjectKnownJSClass(object())->isProxyObject())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!GetObjectKnownJSClass(object())->isProxyObject()
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!GetObjectKnownJSClass(object())->isProxyObject()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!GetObjectKnownJSClass(object())->isProxyObject()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 6567); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetObjectKnownJSClass(object())->isProxyObject()"
")"); do { *((volatile int*)__null) = 6567; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6568 AssertKnownClass(alloc, this, object());
6569 return object();
6570}
6571
6572AliasSet MMegamorphicLoadSlotByValue::getAliasSet() const {
6573 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6574 AliasSet::DynamicSlot);
6575}
6576
6577MDefinition* MMegamorphicLoadSlotByValue::foldsTo(TempAllocator& alloc) {
6578 MDefinition* input = idVal();
6579 if (input->isBox()) {
6580 input = input->toBox()->input();
6581 }
6582
6583 MDefinition* result = this;
6584
6585 if (input->isConstant()) {
6586 MConstant* constant = input->toConstant();
6587 if (constant->type() == MIRType::Symbol) {
6588 PropertyKey id = PropertyKey::Symbol(constant->toSymbol());
6589 result = MMegamorphicLoadSlot::New(alloc, object(), id);
6590 }
6591
6592 if (constant->type() == MIRType::String) {
6593 JSString* str = constant->toString();
6594 if (str->isAtom() && !str->asAtom().isIndex()) {
6595 PropertyKey id = PropertyKey::NonIntAtom(str);
6596 result = MMegamorphicLoadSlot::New(alloc, object(), id);
6597 }
6598 }
6599 }
6600
6601 if (result != this) {
6602 result->setDependency(dependency());
6603 }
6604
6605 return result;
6606}
6607
6608MDefinition* MMegamorphicLoadSlotByValuePermissive::foldsTo(
6609 TempAllocator& alloc) {
6610 MDefinition* input = idVal();
6611 if (input->isBox()) {
6612 input = input->toBox()->input();
6613 }
6614
6615 MDefinition* result = this;
6616
6617 if (input->isConstant()) {
6618 MConstant* constant = input->toConstant();
6619 if (constant->type() == MIRType::Symbol) {
6620 PropertyKey id = PropertyKey::Symbol(constant->toSymbol());
6621 result = MMegamorphicLoadSlotPermissive::New(alloc, object(), id);
6622 }
6623
6624 if (constant->type() == MIRType::String) {
6625 JSString* str = constant->toString();
6626 if (str->isAtom() && !str->asAtom().isIndex()) {
6627 PropertyKey id = PropertyKey::NonIntAtom(str);
6628 result = MMegamorphicLoadSlotPermissive::New(alloc, object(), id);
6629 }
6630 }
6631 }
6632
6633 if (result != this) {
6634 result->toMegamorphicLoadSlotPermissive()->stealResumePoint(this);
6635 }
6636
6637 return result;
6638}
6639
6640bool MMegamorphicLoadSlot::congruentTo(const MDefinition* ins) const {
6641 if (!ins->isMegamorphicLoadSlot()) {
6642 return false;
6643 }
6644 if (ins->toMegamorphicLoadSlot()->name() != name()) {
6645 return false;
6646 }
6647 return congruentIfOperandsEqual(ins);
6648}
6649
6650AliasSet MMegamorphicLoadSlot::getAliasSet() const {
6651 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6652 AliasSet::DynamicSlot);
6653}
6654
6655bool MSmallObjectVariableKeyHasProp::congruentTo(const MDefinition* ins) const {
6656 if (!ins->isSmallObjectVariableKeyHasProp()) {
6657 return false;
6658 }
6659 if (ins->toSmallObjectVariableKeyHasProp()->shape() != shape()) {
6660 return false;
6661 }
6662 return congruentIfOperandsEqual(ins);
6663}
6664
6665AliasSet MSmallObjectVariableKeyHasProp::getAliasSet() const {
6666 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6667 AliasSet::DynamicSlot);
6668}
6669
6670bool MMegamorphicHasProp::congruentTo(const MDefinition* ins) const {
6671 if (!ins->isMegamorphicHasProp()) {
6672 return false;
6673 }
6674 if (ins->toMegamorphicHasProp()->hasOwn() != hasOwn()) {
6675 return false;
6676 }
6677 return congruentIfOperandsEqual(ins);
6678}
6679
6680AliasSet MMegamorphicHasProp::getAliasSet() const {
6681 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6682 AliasSet::DynamicSlot);
6683}
6684
6685bool MNurseryObject::congruentTo(const MDefinition* ins) const {
6686 if (!ins->isNurseryObject()) {
6687 return false;
6688 }
6689 return nurseryIndex() == ins->toNurseryObject()->nurseryIndex();
6690}
6691
6692AliasSet MGuardFunctionIsNonBuiltinCtor::getAliasSet() const {
6693 return AliasSet::Load(AliasSet::ObjectFields);
6694}
6695
6696bool MGuardFunctionKind::congruentTo(const MDefinition* ins) const {
6697 if (!ins->isGuardFunctionKind()) {
6698 return false;
6699 }
6700 if (expected() != ins->toGuardFunctionKind()->expected()) {
6701 return false;
6702 }
6703 if (bailOnEquality() != ins->toGuardFunctionKind()->bailOnEquality()) {
6704 return false;
6705 }
6706 return congruentIfOperandsEqual(ins);
6707}
6708
6709AliasSet MGuardFunctionKind::getAliasSet() const {
6710 return AliasSet::Load(AliasSet::ObjectFields);
6711}
6712
6713bool MGuardFunctionScript::congruentTo(const MDefinition* ins) const {
6714 if (!ins->isGuardFunctionScript()) {
6715 return false;
6716 }
6717 if (expected() != ins->toGuardFunctionScript()->expected()) {
6718 return false;
6719 }
6720 return congruentIfOperandsEqual(ins);
6721}
6722
6723AliasSet MGuardFunctionScript::getAliasSet() const {
6724 // A JSFunction's BaseScript pointer is immutable. Relazification of
6725 // top-level/named self-hosted functions is an exception to this, but we don't
6726 // use this guard for those self-hosted functions.
6727 // See IRGenerator::emitCalleeGuard.
6728 MOZ_ASSERT_IF(flags_.isSelfHostedOrIntrinsic(), flags_.isLambda())do { if (flags_.isSelfHostedOrIntrinsic()) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(flags_.
isLambda())>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(flags_.isLambda()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("flags_.isLambda()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 6728); AnnotateMozCrashReason("MOZ_ASSERT" "(" "flags_.isLambda()"
")"); do { *((volatile int*)__null) = 6728; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
6729 return AliasSet::None();
6730}
6731
6732bool MGuardSpecificAtom::congruentTo(const MDefinition* ins) const {
6733 if (!ins->isGuardSpecificAtom()) {
6734 return false;
6735 }
6736 if (atom() != ins->toGuardSpecificAtom()->atom()) {
6737 return false;
6738 }
6739 return congruentIfOperandsEqual(ins);
6740}
6741
6742MDefinition* MGuardStringToIndex::foldsTo(TempAllocator& alloc) {
6743 if (!string()->isConstant()) {
6744 return this;
6745 }
6746
6747 JSString* str = string()->toConstant()->toString();
6748
6749 int32_t index = GetIndexFromString(str);
6750 if (index < 0) {
6751 return this;
6752 }
6753
6754 return MConstant::New(alloc, Int32Value(index));
6755}
6756
6757MDefinition* MGuardStringToInt32::foldsTo(TempAllocator& alloc) {
6758 if (!string()->isConstant()) {
6759 return this;
6760 }
6761
6762 JSLinearString* str = &string()->toConstant()->toString()->asLinear();
6763 double number = LinearStringToNumber(str);
6764
6765 int32_t n;
6766 if (!mozilla::NumberIsInt32(number, &n)) {
6767 return this;
6768 }
6769
6770 return MConstant::New(alloc, Int32Value(n));
6771}
6772
6773MDefinition* MGuardStringToDouble::foldsTo(TempAllocator& alloc) {
6774 if (!string()->isConstant()) {
6775 return this;
6776 }
6777
6778 JSLinearString* str = &string()->toConstant()->toString()->asLinear();
6779 double number = LinearStringToNumber(str);
6780 return MConstant::New(alloc, DoubleValue(number));
6781}
6782
6783AliasSet MGuardNoDenseElements::getAliasSet() const {
6784 return AliasSet::Load(AliasSet::ObjectFields);
6785}
6786
6787AliasSet MIteratorHasIndices::getAliasSet() const {
6788 return AliasSet::Load(AliasSet::ObjectFields);
6789}
6790
6791AliasSet MAllocateAndStoreSlot::getAliasSet() const {
6792 return AliasSet::Store(AliasSet::ObjectFields | AliasSet::DynamicSlot);
6793}
6794
6795AliasSet MLoadDOMExpandoValue::getAliasSet() const {
6796 return AliasSet::Load(AliasSet::DOMProxyExpando);
6797}
6798
6799AliasSet MLoadDOMExpandoValueIgnoreGeneration::getAliasSet() const {
6800 return AliasSet::Load(AliasSet::DOMProxyExpando);
6801}
6802
6803bool MGuardDOMExpandoMissingOrGuardShape::congruentTo(
6804 const MDefinition* ins) const {
6805 if (!ins->isGuardDOMExpandoMissingOrGuardShape()) {
6806 return false;
6807 }
6808 if (shape() != ins->toGuardDOMExpandoMissingOrGuardShape()->shape()) {
6809 return false;
6810 }
6811 return congruentIfOperandsEqual(ins);
6812}
6813
6814AliasSet MGuardDOMExpandoMissingOrGuardShape::getAliasSet() const {
6815 return AliasSet::Load(AliasSet::ObjectFields);
6816}
6817
6818MDefinition* MGuardToClass::foldsTo(TempAllocator& alloc) {
6819 const JSClass* clasp = GetObjectKnownJSClass(object());
6820 if (!clasp || getClass() != clasp) {
6821 return this;
6822 }
6823
6824 AssertKnownClass(alloc, this, object());
6825 return object();
6826}
6827
6828MDefinition* MGuardToEitherClass::foldsTo(TempAllocator& alloc) {
6829 const JSClass* clasp = GetObjectKnownJSClass(object());
6830 if (!clasp || (getClass1() != clasp && getClass2() != clasp)) {
6831 return this;
6832 }
6833
6834 AssertKnownClass(alloc, this, object());
6835 return object();
6836}
6837
6838MDefinition* MGuardToFunction::foldsTo(TempAllocator& alloc) {
6839 if (GetObjectKnownClass(object()) != KnownClass::Function) {
6840 return this;
6841 }
6842
6843 AssertKnownClass(alloc, this, object());
6844 return object();
6845}
6846
6847MDefinition* MHasClass::foldsTo(TempAllocator& alloc) {
6848 const JSClass* clasp = GetObjectKnownJSClass(object());
6849 if (!clasp) {
6850 return this;
6851 }
6852
6853 AssertKnownClass(alloc, this, object());
6854 return MConstant::New(alloc, BooleanValue(getClass() == clasp));
6855}
6856
6857MDefinition* MIsCallable::foldsTo(TempAllocator& alloc) {
6858 if (input()->type() != MIRType::Object) {
6859 return this;
6860 }
6861
6862 KnownClass known = GetObjectKnownClass(input());
6863 if (known == KnownClass::None) {
6864 return this;
6865 }
6866
6867 AssertKnownClass(alloc, this, input());
6868 return MConstant::New(alloc, BooleanValue(known == KnownClass::Function));
6869}
6870
6871MDefinition* MIsArray::foldsTo(TempAllocator& alloc) {
6872 if (input()->type() != MIRType::Object) {
6873 return this;
6874 }
6875
6876 KnownClass known = GetObjectKnownClass(input());
6877 if (known == KnownClass::None) {
6878 return this;
6879 }
6880
6881 AssertKnownClass(alloc, this, input());
6882 return MConstant::New(alloc, BooleanValue(known == KnownClass::Array));
6883}
6884
6885AliasSet MObjectClassToString::getAliasSet() const {
6886 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6887 AliasSet::DynamicSlot);
6888}
6889
6890MDefinition* MGuardIsNotArrayBufferMaybeShared::foldsTo(TempAllocator& alloc) {
6891 switch (GetObjectKnownClass(object())) {
6892 case KnownClass::PlainObject:
6893 case KnownClass::Array:
6894 case KnownClass::Function:
6895 case KnownClass::RegExp:
6896 case KnownClass::ArrayIterator:
6897 case KnownClass::StringIterator:
6898 case KnownClass::RegExpStringIterator: {
6899 AssertKnownClass(alloc, this, object());
6900 return object();
6901 }
6902 case KnownClass::None:
6903 break;
6904 }
6905
6906 return this;
6907}
6908
6909MDefinition* MCheckIsObj::foldsTo(TempAllocator& alloc) {
6910 if (!input()->isBox()) {
6911 return this;
6912 }
6913
6914 MDefinition* unboxed = input()->getOperand(0);
6915 if (unboxed->type() == MIRType::Object) {
6916 return unboxed;
6917 }
6918
6919 return this;
6920}
6921
6922AliasSet MCheckIsObj::getAliasSet() const {
6923 return AliasSet::Store(AliasSet::ExceptionState);
6924}
6925
6926#ifdef JS_PUNBOX641
6927AliasSet MCheckScriptedProxyGetResult::getAliasSet() const {
6928 return AliasSet::Store(AliasSet::ExceptionState);
6929}
6930#endif
6931
6932static bool IsBoxedObject(MDefinition* def) {
6933 MOZ_ASSERT(def->type() == MIRType::Value)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(def->type() == MIRType::Value)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(def->type() == MIRType::Value
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"def->type() == MIRType::Value", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 6933); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::Value"
")"); do { *((volatile int*)__null) = 6933; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6934
6935 if (def->isBox()) {
6936 return def->toBox()->input()->type() == MIRType::Object;
6937 }
6938
6939 // Construct calls are always returning a boxed object.
6940 //
6941 // TODO: We should consider encoding this directly in the graph instead of
6942 // having to special case it here.
6943 if (def->isCall()) {
6944 return def->toCall()->isConstructing();
6945 }
6946 if (def->isConstructArray()) {
6947 return true;
6948 }
6949 if (def->isConstructArgs()) {
6950 return true;
6951 }
6952
6953 return false;
6954}
6955
6956MDefinition* MCheckReturn::foldsTo(TempAllocator& alloc) {
6957 auto* returnVal = returnValue();
6958 if (!returnVal->isBox()) {
6959 return this;
6960 }
6961
6962 auto* unboxedReturnVal = returnVal->toBox()->input();
6963 if (unboxedReturnVal->type() == MIRType::Object) {
6964 return returnVal;
6965 }
6966
6967 if (unboxedReturnVal->type() != MIRType::Undefined) {
6968 return this;
6969 }
6970
6971 auto* thisVal = thisValue();
6972 if (IsBoxedObject(thisVal)) {
6973 return thisVal;
6974 }
6975
6976 return this;
6977}
6978
6979MDefinition* MCheckThis::foldsTo(TempAllocator& alloc) {
6980 MDefinition* input = thisValue();
6981 if (!input->isBox()) {
6982 return this;
6983 }
6984
6985 MDefinition* unboxed = input->getOperand(0);
6986 if (unboxed->mightBeMagicType()) {
6987 return this;
6988 }
6989
6990 return input;
6991}
6992
6993MDefinition* MCheckThisReinit::foldsTo(TempAllocator& alloc) {
6994 MDefinition* input = thisValue();
6995 if (!input->isBox()) {
6996 return this;
6997 }
6998
6999 MDefinition* unboxed = input->getOperand(0);
7000 if (unboxed->type() != MIRType::MagicUninitializedLexical) {
7001 return this;
7002 }
7003
7004 return input;
7005}
7006
7007MDefinition* MCheckObjCoercible::foldsTo(TempAllocator& alloc) {
7008 MDefinition* input = checkValue();
7009 if (!input->isBox()) {
7010 return this;
7011 }
7012
7013 MDefinition* unboxed = input->getOperand(0);
7014 if (unboxed->mightBeType(MIRType::Null) ||
7015 unboxed->mightBeType(MIRType::Undefined)) {
7016 return this;
7017 }
7018
7019 return input;
7020}
7021
7022AliasSet MCheckObjCoercible::getAliasSet() const {
7023 return AliasSet::Store(AliasSet::ExceptionState);
7024}
7025
7026AliasSet MCheckReturn::getAliasSet() const {
7027 return AliasSet::Store(AliasSet::ExceptionState);
7028}
7029
7030AliasSet MCheckThis::getAliasSet() const {
7031 return AliasSet::Store(AliasSet::ExceptionState);
7032}
7033
7034AliasSet MCheckThisReinit::getAliasSet() const {
7035 return AliasSet::Store(AliasSet::ExceptionState);
7036}
7037
7038AliasSet MIsPackedArray::getAliasSet() const {
7039 return AliasSet::Load(AliasSet::ObjectFields);
7040}
7041
7042AliasSet MGuardArrayIsPacked::getAliasSet() const {
7043 return AliasSet::Load(AliasSet::ObjectFields);
7044}
7045
7046AliasSet MSuperFunction::getAliasSet() const {
7047 return AliasSet::Load(AliasSet::ObjectFields);
7048}
7049
7050AliasSet MInitHomeObject::getAliasSet() const {
7051 return AliasSet::Store(AliasSet::ObjectFields);
7052}
7053
7054AliasSet MLoadWrapperTarget::getAliasSet() const {
7055 return AliasSet::Load(AliasSet::Any);
7056}
7057
7058bool MLoadWrapperTarget::congruentTo(const MDefinition* ins) const {
7059 if (!ins->isLoadWrapperTarget()) {
7060 return false;
7061 }
7062 if (ins->toLoadWrapperTarget()->fallible() != fallible()) {
7063 return false;
7064 }
7065 return congruentIfOperandsEqual(ins);
7066}
7067
7068AliasSet MGuardHasGetterSetter::getAliasSet() const {
7069 return AliasSet::Load(AliasSet::ObjectFields);
7070}
7071
7072bool MGuardHasGetterSetter::congruentTo(const MDefinition* ins) const {
7073 if (!ins->isGuardHasGetterSetter()) {
7074 return false;
7075 }
7076 if (ins->toGuardHasGetterSetter()->propId() != propId()) {
7077 return false;
7078 }
7079 if (ins->toGuardHasGetterSetter()->getterSetter() != getterSetter()) {
7080 return false;
7081 }
7082 return congruentIfOperandsEqual(ins);
7083}
7084
7085AliasSet MGuardIsExtensible::getAliasSet() const {
7086 return AliasSet::Load(AliasSet::ObjectFields);
7087}
7088
7089AliasSet MGuardIndexIsNotDenseElement::getAliasSet() const {
7090 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::Element);
7091}
7092
7093AliasSet MGuardIndexIsValidUpdateOrAdd::getAliasSet() const {
7094 return AliasSet::Load(AliasSet::ObjectFields);
7095}
7096
7097AliasSet MCallObjectHasSparseElement::getAliasSet() const {
7098 return AliasSet::Load(AliasSet::Element | AliasSet::ObjectFields |
7099 AliasSet::FixedSlot | AliasSet::DynamicSlot);
7100}
7101
7102AliasSet MLoadSlotByIteratorIndex::getAliasSet() const {
7103 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
7104 AliasSet::DynamicSlot | AliasSet::Element);
7105}
7106
7107AliasSet MStoreSlotByIteratorIndex::getAliasSet() const {
7108 return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot |
7109 AliasSet::DynamicSlot | AliasSet::Element);
7110}
7111
7112MDefinition* MGuardInt32IsNonNegative::foldsTo(TempAllocator& alloc) {
7113 MOZ_ASSERT(index()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(index()->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(index()->type() == MIRType
::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("index()->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 7113; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7114
7115 MDefinition* input = index();
7116 if (!input->isConstant() || input->toConstant()->toInt32() < 0) {
7117 return this;
7118 }
7119 return input;
7120}
7121
7122MDefinition* MGuardInt32Range::foldsTo(TempAllocator& alloc) {
7123 MOZ_ASSERT(input()->type() == MIRType::Int32)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(input()->type() == MIRType::Int32)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(input()->type() == MIRType
::Int32))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("input()->type() == MIRType::Int32", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7123); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 7123; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7124 MOZ_ASSERT(minimum() <= maximum())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(minimum() <= maximum())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(minimum() <= maximum())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("minimum() <= maximum()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7124); AnnotateMozCrashReason("MOZ_ASSERT" "(" "minimum() <= maximum()"
")"); do { *((volatile int*)__null) = 7124; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7125
7126 MDefinition* in = input();
7127 if (!in->isConstant()) {
7128 return this;
7129 }
7130 int32_t cst = in->toConstant()->toInt32();
7131 if (cst < minimum() || cst > maximum()) {
7132 return this;
7133 }
7134 return in;
7135}
7136
7137MDefinition* MGuardNonGCThing::foldsTo(TempAllocator& alloc) {
7138 if (!input()->isBox()) {
7139 return this;
7140 }
7141
7142 MDefinition* unboxed = input()->getOperand(0);
7143 if (!IsNonGCThing(unboxed->type())) {
7144 return this;
7145 }
7146 return input();
7147}
7148
7149AliasSet MSetObjectHasNonBigInt::getAliasSet() const {
7150 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7151}
7152
7153AliasSet MSetObjectHasBigInt::getAliasSet() const {
7154 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7155}
7156
7157AliasSet MSetObjectHasValue::getAliasSet() const {
7158 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7159}
7160
7161AliasSet MSetObjectHasValueVMCall::getAliasSet() const {
7162 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7163}
7164
7165AliasSet MSetObjectSize::getAliasSet() const {
7166 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7167}
7168
7169AliasSet MMapObjectHasNonBigInt::getAliasSet() const {
7170 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7171}
7172
7173AliasSet MMapObjectHasBigInt::getAliasSet() const {
7174 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7175}
7176
7177AliasSet MMapObjectHasValue::getAliasSet() const {
7178 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7179}
7180
7181AliasSet MMapObjectHasValueVMCall::getAliasSet() const {
7182 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7183}
7184
7185AliasSet MMapObjectGetNonBigInt::getAliasSet() const {
7186 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7187}
7188
7189AliasSet MMapObjectGetBigInt::getAliasSet() const {
7190 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7191}
7192
7193AliasSet MMapObjectGetValue::getAliasSet() const {
7194 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7195}
7196
7197AliasSet MMapObjectGetValueVMCall::getAliasSet() const {
7198 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7199}
7200
7201AliasSet MMapObjectSize::getAliasSet() const {
7202 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7203}
7204
7205MBindFunction* MBindFunction::New(TempAllocator& alloc, MDefinition* target,
7206 uint32_t argc, JSObject* templateObj) {
7207 auto* ins = new (alloc) MBindFunction(templateObj);
7208 if (!ins->init(alloc, NumNonArgumentOperands + argc)) {
7209 return nullptr;
7210 }
7211 ins->initOperand(0, target);
7212 return ins;
7213}
7214
7215MCreateInlinedArgumentsObject* MCreateInlinedArgumentsObject::New(
7216 TempAllocator& alloc, MDefinition* callObj, MDefinition* callee,
7217 MDefinitionVector& args, ArgumentsObject* templateObj) {
7218 MCreateInlinedArgumentsObject* ins =
7219 new (alloc) MCreateInlinedArgumentsObject(templateObj);
7220
7221 uint32_t argc = args.length();
7222 MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7222); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7222; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7223
7224 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7225 return nullptr;
7226 }
7227
7228 ins->initOperand(0, callObj);
7229 ins->initOperand(1, callee);
7230 for (uint32_t i = 0; i < argc; i++) {
7231 ins->initOperand(i + NumNonArgumentOperands, args[i]);
7232 }
7233
7234 return ins;
7235}
7236
7237MGetInlinedArgument* MGetInlinedArgument::New(
7238 TempAllocator& alloc, MDefinition* index,
7239 MCreateInlinedArgumentsObject* args) {
7240 MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument();
7241
7242 uint32_t argc = args->numActuals();
7243 MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7243); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7243; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7244
7245 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7246 return nullptr;
7247 }
7248
7249 ins->initOperand(0, index);
7250 for (uint32_t i = 0; i < argc; i++) {
7251 ins->initOperand(i + NumNonArgumentOperands, args->getArg(i));
7252 }
7253
7254 return ins;
7255}
7256
7257MGetInlinedArgument* MGetInlinedArgument::New(TempAllocator& alloc,
7258 MDefinition* index,
7259 const CallInfo& callInfo) {
7260 MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument();
7261
7262 uint32_t argc = callInfo.argc();
7263 MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7263; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7264
7265 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7266 return nullptr;
7267 }
7268
7269 ins->initOperand(0, index);
7270 for (uint32_t i = 0; i < argc; i++) {
7271 ins->initOperand(i + NumNonArgumentOperands, callInfo.getArg(i));
7272 }
7273
7274 return ins;
7275}
7276
7277MDefinition* MGetInlinedArgument::foldsTo(TempAllocator& alloc) {
7278 MDefinition* indexDef = SkipUninterestingInstructions(index());
7279 if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) {
7280 return this;
7281 }
7282
7283 int32_t indexConst = indexDef->toConstant()->toInt32();
7284 if (indexConst < 0 || uint32_t(indexConst) >= numActuals()) {
7285 return this;
7286 }
7287
7288 MDefinition* arg = getArg(indexConst);
7289 if (arg->type() != MIRType::Value) {
7290 arg = MBox::New(alloc, arg);
7291 }
7292
7293 return arg;
7294}
7295
7296MGetInlinedArgumentHole* MGetInlinedArgumentHole::New(
7297 TempAllocator& alloc, MDefinition* index,
7298 MCreateInlinedArgumentsObject* args) {
7299 auto* ins = new (alloc) MGetInlinedArgumentHole();
7300
7301 uint32_t argc = args->numActuals();
7302 MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7302); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7302; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7303
7304 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7305 return nullptr;
7306 }
7307
7308 ins->initOperand(0, index);
7309 for (uint32_t i = 0; i < argc; i++) {
7310 ins->initOperand(i + NumNonArgumentOperands, args->getArg(i));
7311 }
7312
7313 return ins;
7314}
7315
7316MDefinition* MGetInlinedArgumentHole::foldsTo(TempAllocator& alloc) {
7317 MDefinition* indexDef = SkipUninterestingInstructions(index());
7318 if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) {
7319 return this;
7320 }
7321
7322 int32_t indexConst = indexDef->toConstant()->toInt32();
7323 if (indexConst < 0) {
7324 return this;
7325 }
7326
7327 MDefinition* arg;
7328 if (uint32_t(indexConst) < numActuals()) {
7329 arg = getArg(indexConst);
7330
7331 if (arg->type() != MIRType::Value) {
7332 arg = MBox::New(alloc, arg);
7333 }
7334 } else {
7335 auto* undefined = MConstant::New(alloc, UndefinedValue());
7336 block()->insertBefore(this, undefined);
7337
7338 arg = MBox::New(alloc, undefined);
7339 }
7340
7341 return arg;
7342}
7343
7344MInlineArgumentsSlice* MInlineArgumentsSlice::New(
7345 TempAllocator& alloc, MDefinition* begin, MDefinition* count,
7346 MCreateInlinedArgumentsObject* args, JSObject* templateObj,
7347 gc::Heap initialHeap) {
7348 auto* ins = new (alloc) MInlineArgumentsSlice(templateObj, initialHeap);
7349
7350 uint32_t argc = args->numActuals();
7351 MOZ_ASSERT(argc <= ArgumentsObject::MaxInlinedArgs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(argc <= ArgumentsObject::MaxInlinedArgs)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(argc <= ArgumentsObject::MaxInlinedArgs))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("argc <= ArgumentsObject::MaxInlinedArgs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7351); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7351; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7352
7353 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7354 return nullptr;
7355 }
7356
7357 ins->initOperand(0, begin);
7358 ins->initOperand(1, count);
7359 for (uint32_t i = 0; i < argc; i++) {
7360 ins->initOperand(i + NumNonArgumentOperands, args->getArg(i));
7361 }
7362
7363 return ins;
7364}
7365
7366MDefinition* MArrayLength::foldsTo(TempAllocator& alloc) {
7367 // Object.keys() is potentially effectful, in case of Proxies. Otherwise, when
7368 // it is only computed for its length property, there is no need to
7369 // materialize the Array which results from it and it can be marked as
7370 // recovered on bailout as long as no properties are added to / removed from
7371 // the object.
7372 MDefinition* elems = elements();
7373 if (!elems->isElements()) {
7374 return this;
7375 }
7376
7377 MDefinition* guardshape = elems->toElements()->object();
7378 if (!guardshape->isGuardShape()) {
7379 return this;
7380 }
7381
7382 // The Guard shape is guarding the shape of the object returned by
7383 // Object.keys, this guard can be removed as knowing the function is good
7384 // enough to infer that we are returning an array.
7385 MDefinition* keys = guardshape->toGuardShape()->object();
7386 if (!keys->isObjectKeys()) {
7387 return this;
7388 }
7389
7390 // Object.keys() inline cache guards against proxies when creating the IC. We
7391 // rely on this here as we are looking to elide `Object.keys(...)` call, which
7392 // is only possible if we know for sure that no side-effect might have
7393 // happened.
7394 MDefinition* noproxy = keys->toObjectKeys()->object();
7395 if (!noproxy->isGuardIsNotProxy()) {
7396 // The guard might have been replaced by an assertion, in case the class is
7397 // known at compile time. IF the guard has been removed check whether check
7398 // has been removed.
7399 MOZ_RELEASE_ASSERT(GetObjectKnownClass(noproxy) != KnownClass::None)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(GetObjectKnownClass(noproxy) != KnownClass::None)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(GetObjectKnownClass(noproxy) != KnownClass::None))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("GetObjectKnownClass(noproxy) != KnownClass::None"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7399); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "GetObjectKnownClass(noproxy) != KnownClass::None"
")"); do { *((volatile int*)__null) = 7399; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7400 MOZ_RELEASE_ASSERT(!GetObjectKnownJSClass(noproxy)->isProxyObject())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!GetObjectKnownJSClass(noproxy)->isProxyObject())
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!GetObjectKnownJSClass(noproxy)->isProxyObject())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!GetObjectKnownJSClass(noproxy)->isProxyObject()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7400); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!GetObjectKnownJSClass(noproxy)->isProxyObject()"
")"); do { *((volatile int*)__null) = 7400; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7401 }
7402
7403 // Check if both the elements and the Object.keys() have a single use. We only
7404 // check for live uses, and are ok if a branch which was previously using the
7405 // keys array has been removed since.
7406 if (!elems->hasOneLiveDefUse() || !guardshape->hasOneLiveDefUse() ||
7407 !keys->hasOneLiveDefUse()) {
7408 return this;
7409 }
7410
7411 // Check that the latest active resume point is the one from Object.keys(), in
7412 // order to steal it. If this is not the latest active resume point then some
7413 // side-effect might happen which updates the content of the object, making
7414 // any recovery of the keys exhibit a different behavior than expected.
7415 if (keys->toObjectKeys()->resumePoint() != block()->activeResumePoint(this)) {
7416 return this;
7417 }
7418
7419 // Verify whether any resume point captures the keys array after any aliasing
7420 // mutations. If this were to be the case the recovery of ObjectKeys on
7421 // bailout might compute a version which might not match with the elided
7422 // result.
7423 //
7424 // Iterate over the resume point uses of ObjectKeys, and check whether the
7425 // instructions they are attached to are aliasing Object fields. If so, skip
7426 // this optimization.
7427 AliasSet enumKeysAliasSet = AliasSet::Load(AliasSet::Flag::ObjectFields);
7428 for (auto* use : UsesIterator(keys)) {
7429 if (!use->consumer()->isResumePoint()) {
7430 // There is only a single use, and this is the length computation as
7431 // asserted with `hasOneLiveDefUse`.
7432 continue;
7433 }
7434
7435 MResumePoint* rp = use->consumer()->toResumePoint();
7436 if (!rp->instruction()) {
7437 // If there is no instruction, this is a resume point which is attached to
7438 // the entry of a block. Thus no risk of mutating the object on which the
7439 // keys are queried.
7440 continue;
7441 }
7442
7443 MInstruction* ins = rp->instruction();
7444 if (ins == keys) {
7445 continue;
7446 }
7447
7448 // Check whether the instruction can potentially alias the object fields of
7449 // the object from which we are querying the keys.
7450 AliasSet mightAlias = ins->getAliasSet() & enumKeysAliasSet;
7451 if (!mightAlias.isNone()) {
7452 return this;
7453 }
7454 }
7455
7456 // Flag every instructions since Object.keys(..) as recovered on bailout, and
7457 // make Object.keys(..) be the recovered value in-place of the shape guard.
7458 setRecoveredOnBailout();
7459 elems->setRecoveredOnBailout();
7460 guardshape->replaceAllUsesWith(keys);
7461 guardshape->block()->discard(guardshape->toGuardShape());
7462 keys->setRecoveredOnBailout();
7463
7464 // Steal the resume point from Object.keys, which is ok as we confirmed that
7465 // there is no other resume point in-between.
7466 MObjectKeysLength* keysLength = MObjectKeysLength::New(alloc, noproxy);
7467 keysLength->stealResumePoint(keys->toObjectKeys());
7468
7469 return keysLength;
7470}
7471
7472MDefinition* MNormalizeSliceTerm::foldsTo(TempAllocator& alloc) {
7473 auto* length = this->length();
7474 if (!length->isConstant() && !length->isArgumentsLength()) {
7475 return this;
7476 }
7477
7478 if (length->isConstant()) {
7479 int32_t lengthConst = length->toConstant()->toInt32();
7480 MOZ_ASSERT(lengthConst >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(lengthConst >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(lengthConst >= 0))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("lengthConst >= 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 7480); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lengthConst >= 0"
")"); do { *((volatile int*)__null) = 7480; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7481
7482 // Result is always zero when |length| is zero.
7483 if (lengthConst == 0) {
7484 return length;
7485 }
7486
7487 auto* value = this->value();
7488 if (value->isConstant()) {
7489 int32_t valueConst = value->toConstant()->toInt32();
7490
7491 int32_t normalized;
7492 if (valueConst < 0) {
7493 normalized = std::max(valueConst + lengthConst, 0);
7494 } else {
7495 normalized = std::min(valueConst, lengthConst);
7496 }
7497
7498 if (normalized == valueConst) {
7499 return value;
7500 }
7501 if (normalized == lengthConst) {
7502 return length;
7503 }
7504 return MConstant::New(alloc, Int32Value(normalized));
7505 }
7506
7507 return this;
7508 }
7509
7510 auto* value = this->value();
7511 if (value->isConstant()) {
7512 int32_t valueConst = value->toConstant()->toInt32();
7513
7514 // Minimum of |value| and |length|.
7515 if (valueConst > 0) {
7516 bool isMax = false;
7517 return MMinMax::New(alloc, value, length, MIRType::Int32, isMax);
7518 }
7519
7520 // Maximum of |value + length| and zero.
7521 if (valueConst < 0) {
7522 // Safe to truncate because |length| is never negative.
7523 auto* add = MAdd::New(alloc, value, length, TruncateKind::Truncate);
7524 block()->insertBefore(this, add);
7525
7526 auto* zero = MConstant::New(alloc, Int32Value(0));
7527 block()->insertBefore(this, zero);
7528
7529 bool isMax = true;
7530 return MMinMax::New(alloc, add, zero, MIRType::Int32, isMax);
7531 }
7532
7533 // Directly return the value when it's zero.
7534 return value;
7535 }
7536
7537 // Normalizing MArgumentsLength is a no-op.
7538 if (value->isArgumentsLength()) {
7539 return value;
7540 }
7541
7542 return this;
7543}
7544
7545bool MInt32ToStringWithBase::congruentTo(const MDefinition* ins) const {
7546 if (!ins->isInt32ToStringWithBase()) {
7547 return false;
7548 }
7549 if (ins->toInt32ToStringWithBase()->lowerCase() != lowerCase()) {
7550 return false;
7551 }
7552 return congruentIfOperandsEqual(ins);
7553}