Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp
Warning:line 1488, 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_jit9.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-20/lib/clang/20 -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 _GLIBCXX_ASSERTIONS -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-20/lib/clang/20/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-2025-01-20-090804-167946-1 -x c++ Unified_cpp_js_src_jit9.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::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."
);static_assert(!std::is_base_of_v<gc::Cell, wasm::TrapSiteDesc
>, "Ensure that wasm::TrapSiteDesc 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(IntPtrLimitedTruncate
)NAME(Int64LimitedTruncate)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(NewMapObject)NAME(NewSetObject
)NAME(NewMapObjectFromIterable)NAME(NewSetObjectFromIterable)
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
(WasmAnyRefJSStringLength)NAME(WasmNewI31Ref)NAME(WasmI31RefGet
)NAME(Int32ToIntPtr)NAME(NonNegativeIntPtrToInt32)NAME(IntPtrToDouble
)NAME(AdjustDataViewLength)NAME(Int64ToFloatingPoint)NAME(BuiltinInt64ToFloatingPoint
)NAME(ToNumberInt32)NAME(BooleanToInt32)NAME(TruncateToInt32)
NAME(WasmBuiltinTruncateToInt32)NAME(ToBigInt)NAME(ToInt64)NAME
(TruncateBigIntToInt64)NAME(Int64ToBigInt)NAME(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(SignExtendIntPtr
)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(AtomicPause)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(SetObjectDelete)NAME(SetObjectAdd
)NAME(SetObjectSize)NAME(MapObjectHasNonBigInt)NAME(MapObjectHasBigInt
)NAME(MapObjectHasValue)NAME(MapObjectHasValueVMCall)NAME(MapObjectGetNonBigInt
)NAME(MapObjectGetBigInt)NAME(MapObjectGetValue)NAME(MapObjectGetValueVMCall
)NAME(MapObjectDelete)NAME(MapObjectSet)NAME(MapObjectSize)NAME
(DateFillLocalTimeSlots)NAME(DateHoursFromSecondsIntoYear)NAME
(DateMinutesFromSecondsIntoYear)NAME(DateSecondsFromSecondsIntoYear
)NAME(PostIntPtrConversion)NAME(WasmNeg)NAME(WasmBinaryBitwise
)NAME(WasmLoadInstance)NAME(WasmStoreInstance)NAME(WasmHeapReg
)NAME(WasmBoundsCheck)NAME(WasmBoundsCheckRange32)NAME(WasmExtendU32Index
)NAME(WasmWrapU32Index)NAME(WasmClampTable64Address)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(ReinterpretCast)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)NAME(AddDisposableResource
)NAME(TakeDisposeCapability)NAME(CreateSuppressedError)
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 return false;
972}
973
974MDefinition* MDefinition::maybeSingleDefUse() const {
975 MUseDefIterator use(this);
976 if (!use) {
977 // No def-uses.
978 return nullptr;
979 }
980
981 MDefinition* useDef = use.def();
982
983 use++;
984 if (use) {
985 // More than one def-use.
986 return nullptr;
987 }
988
989 return useDef;
990}
991
992MDefinition* MDefinition::maybeMostRecentlyAddedDefUse() const {
993 MUseDefIterator use(this);
994 if (!use) {
995 // No def-uses.
996 return nullptr;
997 }
998
999 MDefinition* mostRecentUse = use.def();
1000
1001#ifdef DEBUG1
1002 // This function relies on addUse adding new uses to the front of the list.
1003 // Check this invariant by asserting the next few uses are 'older'. Skip this
1004 // for phis because setBackedge can add a new use for a loop phi even if the
1005 // loop body has a use with an id greater than the loop phi's id.
1006 if (!mostRecentUse->isPhi()) {
1007 static constexpr size_t NumUsesToCheck = 3;
1008 use++;
1009 for (size_t i = 0; use && i < NumUsesToCheck; i++, use++) {
1010 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"
, 1010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "use.def()->id() <= mostRecentUse->id()"
")"); do { *((volatile int*)__null) = 1010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1011 }
1012 }
1013#endif
1014
1015 return mostRecentUse;
1016}
1017
1018void MDefinition::replaceAllUsesWith(MDefinition* dom) {
1019 for (size_t i = 0, e = numOperands(); i < e; ++i) {
1020 getOperand(i)->setImplicitlyUsedUnchecked();
1021 }
1022
1023 justReplaceAllUsesWith(dom);
1024}
1025
1026void MDefinition::justReplaceAllUsesWith(MDefinition* dom) {
1027 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"
, 1027); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != nullptr"
")"); do { *((volatile int*)__null) = 1027; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1028 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"
, 1028); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != this"
")"); do { *((volatile int*)__null) = 1028; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1029
1030 // Carry over the fact the value has uses which are no longer inspectable
1031 // with the graph.
1032 if (isImplicitlyUsed()) {
1033 dom->setImplicitlyUsedUnchecked();
1034 }
1035
1036 for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i) {
1037 i->setProducerUnchecked(dom);
1038 }
1039 dom->uses_.takeElements(uses_);
1040}
1041
1042bool MDefinition::optimizeOutAllUses(TempAllocator& alloc) {
1043 for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
1044 MUse* use = *i++;
1045 MConstant* constant = use->consumer()->block()->optimizedOutConstant(alloc);
1046 if (!alloc.ensureBallast()) {
1047 return false;
1048 }
1049
1050 // Update the resume point operand to use the optimized-out constant.
1051 use->setProducerUnchecked(constant);
1052 constant->addUseUnchecked(use);
1053 }
1054
1055 // Remove dangling pointers.
1056 this->uses_.clear();
1057 return true;
1058}
1059
1060void MDefinition::replaceAllLiveUsesWith(MDefinition* dom) {
1061 for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
1062 MUse* use = *i++;
1063 MNode* consumer = use->consumer();
1064 if (consumer->isResumePoint()) {
1065 continue;
1066 }
1067 if (consumer->isDefinition() &&
1068 consumer->toDefinition()->isRecoveredOnBailout()) {
1069 continue;
1070 }
1071
1072 // Update the operand to use the dominating definition.
1073 use->replaceProducer(dom);
1074 }
1075}
1076
1077MConstant* MConstant::New(TempAllocator& alloc, const Value& v) {
1078 return new (alloc) MConstant(alloc, v);
1079}
1080
1081MConstant* MConstant::New(TempAllocator::Fallible alloc, const Value& v) {
1082 return new (alloc) MConstant(alloc.alloc, v);
1083}
1084
1085MConstant* MConstant::NewFloat32(TempAllocator& alloc, double d) {
1086 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"
, 1086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "std::isnan(d) || d == double(float(d))"
")"); do { *((volatile int*)__null) = 1086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1087 return new (alloc) MConstant(float(d));
1088}
1089
1090MConstant* MConstant::NewInt64(TempAllocator& alloc, int64_t i) {
1091 return new (alloc) MConstant(MIRType::Int64, i);
1092}
1093
1094MConstant* MConstant::NewIntPtr(TempAllocator& alloc, intptr_t i) {
1095 return new (alloc) MConstant(MIRType::IntPtr, i);
1096}
1097
1098MConstant* MConstant::New(TempAllocator& alloc, const Value& v, MIRType type) {
1099 if (type == MIRType::Float32) {
1100 return NewFloat32(alloc, v.toNumber());
1101 }
1102 MConstant* res = New(alloc, v);
1103 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"
, 1103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "res->type() == type"
")"); do { *((volatile int*)__null) = 1103; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1104 return res;
1105}
1106
1107MConstant* MConstant::NewObject(TempAllocator& alloc, JSObject* v) {
1108 return new (alloc) MConstant(v);
1109}
1110
1111MConstant* MConstant::NewShape(TempAllocator& alloc, Shape* s) {
1112 return new (alloc) MConstant(s);
1113}
1114
1115static MIRType MIRTypeFromValue(const js::Value& vp) {
1116 if (vp.isDouble()) {
1117 return MIRType::Double;
1118 }
1119 if (vp.isMagic()) {
1120 switch (vp.whyMagic()) {
1121 case JS_OPTIMIZED_OUT:
1122 return MIRType::MagicOptimizedOut;
1123 case JS_ELEMENTS_HOLE:
1124 return MIRType::MagicHole;
1125 case JS_IS_CONSTRUCTING:
1126 return MIRType::MagicIsConstructing;
1127 case JS_UNINITIALIZED_LEXICAL:
1128 return MIRType::MagicUninitializedLexical;
1129 default:
1130 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"
, 1130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected magic constant" ")");
do { *((volatile int*)__null) = 1130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1131 }
1132 }
1133 return MIRTypeFromValueType(vp.extractNonDoubleType());
1134}
1135
1136MConstant::MConstant(TempAllocator& alloc, const js::Value& vp)
1137 : MNullaryInstruction(classOpcode) {
1138 setResultType(MIRTypeFromValue(vp));
1139
1140 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"
, 1140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0"
")"); do { *((volatile int*)__null) = 1140; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1141
1142 switch (type()) {
1143 case MIRType::Undefined:
1144 case MIRType::Null:
1145 break;
1146 case MIRType::Boolean:
1147 payload_.b = vp.toBoolean();
1148 break;
1149 case MIRType::Int32:
1150 payload_.i32 = vp.toInt32();
1151 break;
1152 case MIRType::Double:
1153 payload_.d = vp.toDouble();
1154 break;
1155 case MIRType::String: {
1156 JSString* str = vp.toString();
1157 if (str->isAtomRef()) {
1158 str = str->atom();
1159 }
1160 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"
, 1160); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(str)"
")"); do { *((volatile int*)__null) = 1160; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1161 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"
, 1161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "str->isAtom()"
")"); do { *((volatile int*)__null) = 1161; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1162 payload_.str = vp.toString();
1163 break;
1164 }
1165 case MIRType::Symbol:
1166 payload_.sym = vp.toSymbol();
1167 break;
1168 case MIRType::BigInt:
1169 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"
, 1169); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(vp.toBigInt())"
")"); do { *((volatile int*)__null) = 1169; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1170 payload_.bi = vp.toBigInt();
1171 break;
1172 case MIRType::Object:
1173 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"
, 1173); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(&vp.toObject())"
")"); do { *((volatile int*)__null) = 1173; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1174 payload_.obj = &vp.toObject();
1175 break;
1176 case MIRType::MagicOptimizedOut:
1177 case MIRType::MagicHole:
1178 case MIRType::MagicIsConstructing:
1179 case MIRType::MagicUninitializedLexical:
1180 break;
1181 default:
1182 MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1182); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type"
")"); do { *((volatile int*)__null) = 1182; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1183 }
1184
1185 setMovable();
1186}
1187
1188MConstant::MConstant(JSObject* obj) : MNullaryInstruction(classOpcode) {
1189 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"
, 1189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(obj)"
")"); do { *((volatile int*)__null) = 1189; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1190 setResultType(MIRType::Object);
1191 payload_.obj = obj;
1192 setMovable();
1193}
1194
1195MConstant::MConstant(Shape* shape) : MNullaryInstruction(classOpcode) {
1196 setResultType(MIRType::Shape);
1197 payload_.shape = shape;
1198 setMovable();
1199}
1200
1201MConstant::MConstant(float f) : MNullaryInstruction(classOpcode) {
1202 setResultType(MIRType::Float32);
1203 payload_.f = f;
1204 setMovable();
1205}
1206
1207MConstant::MConstant(MIRType type, int64_t i)
1208 : MNullaryInstruction(classOpcode) {
1209 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"
, 1209); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int64 || type == MIRType::IntPtr"
")"); do { *((volatile int*)__null) = 1209; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1210 setResultType(type);
1211 if (type == MIRType::Int64) {
1212 payload_.i64 = i;
1213 } else {
1214 payload_.iptr = i;
1215 }
1216 setMovable();
1217}
1218
1219#ifdef DEBUG1
1220void MConstant::assertInitializedPayload() const {
1221 // valueHash() and equals() expect the unused payload bits to be
1222 // initialized to zero. Assert this in debug builds.
1223
1224 switch (type()) {
1225 case MIRType::Int32:
1226 case MIRType::Float32:
1227# if MOZ_LITTLE_ENDIAN()1
1228 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"
, 1228); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0"
")"); do { *((volatile int*)__null) = 1228; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1229# else
1230 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"
, 1230); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0"
")"); do { *((volatile int*)__null) = 1230; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1231# endif
1232 break;
1233 case MIRType::Boolean:
1234# if MOZ_LITTLE_ENDIAN()1
1235 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"
, 1235); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 1) == 0"
")"); do { *((volatile int*)__null) = 1235; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1236# else
1237 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"
, 1237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits & ~(1ULL << 56)) == 0"
")"); do { *((volatile int*)__null) = 1237; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1238# endif
1239 break;
1240 case MIRType::Double:
1241 case MIRType::Int64:
1242 break;
1243 case MIRType::String:
1244 case MIRType::Object:
1245 case MIRType::Symbol:
1246 case MIRType::BigInt:
1247 case MIRType::IntPtr:
1248 case MIRType::Shape:
1249# if MOZ_LITTLE_ENDIAN()1
1250 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"
, 1250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0"
")"); do { *((volatile int*)__null) = 1250; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1251# else
1252 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"
, 1252); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0"
")"); do { *((volatile int*)__null) = 1252; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1253# endif
1254 break;
1255 default:
1256 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"
, 1256); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNullOrUndefined(type()) || IsMagicType(type())"
")"); do { *((volatile int*)__null) = 1256; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1257 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"
, 1257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0"
")"); do { *((volatile int*)__null) = 1257; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1258 break;
1259 }
1260}
1261#endif
1262
1263HashNumber MConstant::valueHash() const {
1264 static_assert(sizeof(Payload) == sizeof(uint64_t),
1265 "Code below assumes payload fits in 64 bits");
1266
1267 assertInitializedPayload();
1268 return ConstantValueHash(type(), payload_.asBits);
1269}
1270
1271HashNumber MConstantProto::valueHash() const {
1272 HashNumber hash = protoObject()->valueHash();
1273 const MDefinition* receiverObject = getReceiverObject();
1274 if (receiverObject) {
1275 hash = addU32ToHash(hash, receiverObject->id());
1276 }
1277 return hash;
1278}
1279
1280bool MConstant::congruentTo(const MDefinition* ins) const {
1281 return ins->isConstant() && equals(ins->toConstant());
1282}
1283
1284#ifdef JS_JITSPEW1
1285void MConstant::printOpcode(GenericPrinter& out) const {
1286 PrintOpcodeName(out, op());
1287 out.printf(" ");
1288 switch (type()) {
1289 case MIRType::Undefined:
1290 out.printf("undefined");
1291 break;
1292 case MIRType::Null:
1293 out.printf("null");
1294 break;
1295 case MIRType::Boolean:
1296 out.printf(toBoolean() ? "true" : "false");
1297 break;
1298 case MIRType::Int32:
1299 out.printf("0x%x", uint32_t(toInt32()));
1300 break;
1301 case MIRType::Int64:
1302 out.printf("0x%" PRIx64"l" "x", uint64_t(toInt64()));
1303 break;
1304 case MIRType::IntPtr:
1305 out.printf("0x%" PRIxPTR"l" "x", uintptr_t(toIntPtr()));
1306 break;
1307 case MIRType::Double:
1308 out.printf("%.16g", toDouble());
1309 break;
1310 case MIRType::Float32: {
1311 float val = toFloat32();
1312 out.printf("%.16g", val);
1313 break;
1314 }
1315 case MIRType::Object:
1316 if (toObject().is<JSFunction>()) {
1317 JSFunction* fun = &toObject().as<JSFunction>();
1318 if (fun->maybePartialDisplayAtom()) {
1319 out.put("function ");
1320 EscapedStringPrinter(out, fun->maybePartialDisplayAtom(), 0);
1321 } else {
1322 out.put("unnamed function");
1323 }
1324 if (fun->hasBaseScript()) {
1325 BaseScript* script = fun->baseScript();
1326 out.printf(" (%s:%u)", script->filename() ? script->filename() : "",
1327 script->lineno());
1328 }
1329 out.printf(" at %p", (void*)fun);
1330 break;
1331 }
1332 out.printf("object %p (%s)", (void*)&toObject(),
1333 toObject().getClass()->name);
1334 break;
1335 case MIRType::Symbol:
1336 out.printf("symbol at %p", (void*)toSymbol());
1337 break;
1338 case MIRType::BigInt:
1339 out.printf("BigInt at %p", (void*)toBigInt());
1340 break;
1341 case MIRType::String:
1342 out.printf("string %p", (void*)toString());
1343 break;
1344 case MIRType::Shape:
1345 out.printf("shape at %p", (void*)toShape());
1346 break;
1347 case MIRType::MagicHole:
1348 out.printf("magic hole");
1349 break;
1350 case MIRType::MagicIsConstructing:
1351 out.printf("magic is-constructing");
1352 break;
1353 case MIRType::MagicOptimizedOut:
1354 out.printf("magic optimized-out");
1355 break;
1356 case MIRType::MagicUninitializedLexical:
1357 out.printf("magic uninitialized-lexical");
1358 break;
1359 default:
1360 MOZ_CRASH("unexpected type")do { do { } while (false); MOZ_ReportCrash("" "unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1360); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected type"
")"); do { *((volatile int*)__null) = 1360; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1361 }
1362}
1363#endif
1364
1365bool MConstant::canProduceFloat32() const {
1366 if (!isTypeRepresentableAsDouble()) {
1367 return false;
1368 }
1369
1370 if (type() == MIRType::Int32) {
1371 return IsFloat32Representable(static_cast<double>(toInt32()));
1372 }
1373 if (type() == MIRType::Double) {
1374 return IsFloat32Representable(toDouble());
1375 }
1376 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"
, 1376); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Float32"
")"); do { *((volatile int*)__null) = 1376; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1377 return true;
1378}
1379
1380Value MConstant::toJSValue() const {
1381 // Wasm has types like int64 that cannot be stored as js::Value. It also
1382 // doesn't want the NaN canonicalization enforced by js::Value.
1383 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"
, 1383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsCompilingWasm()"
")"); do { *((volatile int*)__null) = 1383; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1384
1385 switch (type()) {
1386 case MIRType::Undefined:
1387 return UndefinedValue();
1388 case MIRType::Null:
1389 return NullValue();
1390 case MIRType::Boolean:
1391 return BooleanValue(toBoolean());
1392 case MIRType::Int32:
1393 return Int32Value(toInt32());
1394 case MIRType::Double:
1395 return DoubleValue(toDouble());
1396 case MIRType::Float32:
1397 return Float32Value(toFloat32());
1398 case MIRType::String:
1399 return StringValue(toString());
1400 case MIRType::Symbol:
1401 return SymbolValue(toSymbol());
1402 case MIRType::BigInt:
1403 return BigIntValue(toBigInt());
1404 case MIRType::Object:
1405 return ObjectValue(toObject());
1406 case MIRType::Shape:
1407 return PrivateGCThingValue(toShape());
1408 case MIRType::MagicOptimizedOut:
1409 return MagicValue(JS_OPTIMIZED_OUT);
1410 case MIRType::MagicHole:
1411 return MagicValue(JS_ELEMENTS_HOLE);
1412 case MIRType::MagicIsConstructing:
1413 return MagicValue(JS_IS_CONSTRUCTING);
1414 case MIRType::MagicUninitializedLexical:
1415 return MagicValue(JS_UNINITIALIZED_LEXICAL);
1416 default:
1417 MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1417); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type"
")"); do { *((volatile int*)__null) = 1417; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1418 }
1419}
1420
1421bool MConstant::valueToBoolean(bool* res) const {
1422 switch (type()) {
1423 case MIRType::Boolean:
1424 *res = toBoolean();
1425 return true;
1426 case MIRType::Int32:
1427 *res = toInt32() != 0;
1428 return true;
1429 case MIRType::Int64:
1430 *res = toInt64() != 0;
1431 return true;
1432 case MIRType::IntPtr:
1433 *res = toIntPtr() != 0;
1434 return true;
1435 case MIRType::Double:
1436 *res = !std::isnan(toDouble()) && toDouble() != 0.0;
1437 return true;
1438 case MIRType::Float32:
1439 *res = !std::isnan(toFloat32()) && toFloat32() != 0.0f;
1440 return true;
1441 case MIRType::Null:
1442 case MIRType::Undefined:
1443 *res = false;
1444 return true;
1445 case MIRType::Symbol:
1446 *res = true;
1447 return true;
1448 case MIRType::BigInt:
1449 *res = !toBigInt()->isZero();
1450 return true;
1451 case MIRType::String:
1452 *res = toString()->length() != 0;
1453 return true;
1454 case MIRType::Object:
1455 // TODO(Warp): Lazy groups have been removed.
1456 // We have to call EmulatesUndefined but that reads obj->group->clasp
1457 // and so it's racy when the object has a lazy group. The main callers
1458 // of this (MTest, MNot) already know how to fold the object case, so
1459 // just give up.
1460 return false;
1461 default:
1462 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"
, 1462); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsMagicType(type())"
")"); do { *((volatile int*)__null) = 1462; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1463 return false;
1464 }
1465}
1466
1467#ifdef JS_JITSPEW1
1468void MControlInstruction::printOpcode(GenericPrinter& out) const {
1469 MDefinition::printOpcode(out);
1470 for (size_t j = 0; j < numSuccessors(); j++) {
1471 if (getSuccessor(j)) {
1472 out.printf(" block%u", getSuccessor(j)->id());
1473 } else {
1474 out.printf(" (null-to-be-patched)");
1475 }
1476 }
1477}
1478
1479void MCompare::printOpcode(GenericPrinter& out) const {
1480 MDefinition::printOpcode(out);
1481 out.printf(" %s", CodeName(jsop()));
1482}
1483
1484void MTypeOfIs::printOpcode(GenericPrinter& out) const {
1485 MDefinition::printOpcode(out);
1486 out.printf(" %s", CodeName(jsop()));
1487
1488 const char* name = "";
Value stored to 'name' during its initialization is never read
1489 switch (jstype()) {
1490 case JSTYPE_UNDEFINED:
1491 name = "undefined";
1492 break;
1493 case JSTYPE_OBJECT:
1494 name = "object";
1495 break;
1496 case JSTYPE_FUNCTION:
1497 name = "function";
1498 break;
1499 case JSTYPE_STRING:
1500 name = "string";
1501 break;
1502 case JSTYPE_NUMBER:
1503 name = "number";
1504 break;
1505 case JSTYPE_BOOLEAN:
1506 name = "boolean";
1507 break;
1508 case JSTYPE_SYMBOL:
1509 name = "symbol";
1510 break;
1511 case JSTYPE_BIGINT:
1512 name = "bigint";
1513 break;
1514# ifdef ENABLE_RECORD_TUPLE
1515 case JSTYPE_RECORD:
1516 case JSTYPE_TUPLE:
1517# endif
1518 case JSTYPE_LIMIT:
1519 MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1519); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type"
")"); do { *((volatile int*)__null) = 1519; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1520 }
1521 out.printf(" '%s'", name);
1522}
1523
1524void MLoadUnboxedScalar::printOpcode(GenericPrinter& out) const {
1525 MDefinition::printOpcode(out);
1526 out.printf(" %s", Scalar::name(storageType()));
1527}
1528
1529void MLoadDataViewElement::printOpcode(GenericPrinter& out) const {
1530 MDefinition::printOpcode(out);
1531 out.printf(" %s", Scalar::name(storageType()));
1532}
1533
1534void MAssertRange::printOpcode(GenericPrinter& out) const {
1535 MDefinition::printOpcode(out);
1536 out.put(" ");
1537 assertedRange()->dump(out);
1538}
1539
1540void MNearbyInt::printOpcode(GenericPrinter& out) const {
1541 MDefinition::printOpcode(out);
1542 const char* roundingModeStr = nullptr;
1543 switch (roundingMode_) {
1544 case RoundingMode::Up:
1545 roundingModeStr = "(up)";
1546 break;
1547 case RoundingMode::Down:
1548 roundingModeStr = "(down)";
1549 break;
1550 case RoundingMode::NearestTiesToEven:
1551 roundingModeStr = "(nearest ties even)";
1552 break;
1553 case RoundingMode::TowardsZero:
1554 roundingModeStr = "(towards zero)";
1555 break;
1556 }
1557 out.printf(" %s", roundingModeStr);
1558}
1559#endif
1560
1561AliasSet MRandom::getAliasSet() const { return AliasSet::Store(AliasSet::RNG); }
1562
1563MDefinition* MSign::foldsTo(TempAllocator& alloc) {
1564 MDefinition* input = getOperand(0);
1565 if (!input->isConstant() ||
1566 !input->toConstant()->isTypeRepresentableAsDouble()) {
1567 return this;
1568 }
1569
1570 double in = input->toConstant()->numberToDouble();
1571 double out = js::math_sign_impl(in);
1572
1573 if (type() == MIRType::Int32) {
1574 // Decline folding if this is an int32 operation, but the result type
1575 // isn't an int32.
1576 Value outValue = NumberValue(out);
1577 if (!outValue.isInt32()) {
1578 return this;
1579 }
1580
1581 return MConstant::New(alloc, outValue);
1582 }
1583
1584 return MConstant::New(alloc, DoubleValue(out));
1585}
1586
1587const char* MMathFunction::FunctionName(UnaryMathFunction function) {
1588 return GetUnaryMathFunctionName(function);
1589}
1590
1591#ifdef JS_JITSPEW1
1592void MMathFunction::printOpcode(GenericPrinter& out) const {
1593 MDefinition::printOpcode(out);
1594 out.printf(" %s", FunctionName(function()));
1595}
1596#endif
1597
1598MDefinition* MMathFunction::foldsTo(TempAllocator& alloc) {
1599 MDefinition* input = getOperand(0);
1600 if (!input->isConstant() ||
1601 !input->toConstant()->isTypeRepresentableAsDouble()) {
1602 return this;
1603 }
1604
1605 UnaryMathFunctionType funPtr = GetUnaryMathFunctionPtr(function());
1606
1607 double in = input->toConstant()->numberToDouble();
1608
1609 // The function pointer call can't GC.
1610 JS::AutoSuppressGCAnalysis nogc;
1611 double out = funPtr(in);
1612
1613 if (input->type() == MIRType::Float32) {
1614 return MConstant::NewFloat32(alloc, out);
1615 }
1616 return MConstant::New(alloc, DoubleValue(out));
1617}
1618
1619MDefinition* MAtomicIsLockFree::foldsTo(TempAllocator& alloc) {
1620 MDefinition* input = getOperand(0);
1621 if (!input->isConstant() || input->type() != MIRType::Int32) {
1622 return this;
1623 }
1624
1625 int32_t i = input->toConstant()->toInt32();
1626 return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfreeJS(i)));
1627}
1628
1629// Define |THIS_SLOT| as part of this translation unit, as it is used to
1630// specialized the parameterized |New| function calls introduced by
1631// TRIVIAL_NEW_WRAPPERS.
1632const int32_t MParameter::THIS_SLOT;
1633
1634#ifdef JS_JITSPEW1
1635void MParameter::printOpcode(GenericPrinter& out) const {
1636 PrintOpcodeName(out, op());
1637 if (index() == THIS_SLOT) {
1638 out.printf(" THIS_SLOT");
1639 } else {
1640 out.printf(" %d", index());
1641 }
1642}
1643#endif
1644
1645HashNumber MParameter::valueHash() const {
1646 HashNumber hash = MDefinition::valueHash();
1647 hash = addU32ToHash(hash, index_);
1648 return hash;
1649}
1650
1651bool MParameter::congruentTo(const MDefinition* ins) const {
1652 if (!ins->isParameter()) {
1653 return false;
1654 }
1655
1656 return ins->toParameter()->index() == index_;
1657}
1658
1659WrappedFunction::WrappedFunction(JSFunction* nativeFun, uint16_t nargs,
1660 FunctionFlags flags)
1661 : nativeFun_(nativeFun), nargs_(nargs), flags_(flags) {
1662 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"
, 1662); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNativeWithoutJitEntry()"
")"); do { *((volatile int*)__null) = 1662; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1663
1664#ifdef DEBUG1
1665 // If we are not running off-main thread we can assert that the
1666 // metadata is consistent.
1667 if (!CanUseExtraThreads() && nativeFun) {
1668 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"
, 1668); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->nargs() == nargs"
")"); do { *((volatile int*)__null) = 1668; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1669
1670 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"
, 1671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()"
")"); do { *((volatile int*)__null) = 1671; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1671 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"
, 1671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()"
")"); do { *((volatile int*)__null) = 1671; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1672 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"
, 1672); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->hasJitEntry() == hasJitEntry()"
")"); do { *((volatile int*)__null) = 1672; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1673 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"
, 1673); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isConstructor() == isConstructor()"
")"); do { *((volatile int*)__null) = 1673; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1674 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"
, 1674); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isClassConstructor() == isClassConstructor()"
")"); do { *((volatile int*)__null) = 1674; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1675 }
1676#endif
1677}
1678
1679MCall* MCall::New(TempAllocator& alloc, WrappedFunction* target, size_t maxArgc,
1680 size_t numActualArgs, bool construct, bool ignoresReturnValue,
1681 bool isDOMCall, mozilla::Maybe<DOMObjectKind> objectKind,
1682 mozilla::Maybe<gc::Heap> initialHeap) {
1683 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"
, 1683); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isDOMCall == objectKind.isSome()"
")"); do { *((volatile int*)__null) = 1683; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1684 MOZ_ASSERT(isDOMCall == initialHeap.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isDOMCall == initialHeap.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isDOMCall == initialHeap.isSome
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("isDOMCall == initialHeap.isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isDOMCall == initialHeap.isSome()"
")"); do { *((volatile int*)__null) = 1684; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1685
1686 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"
, 1686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "maxArgc >= numActualArgs"
")"); do { *((volatile int*)__null) = 1686; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1687 MCall* ins;
1688 if (isDOMCall) {
1689 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"
, 1689); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!construct"
")"); do { *((volatile int*)__null) = 1689; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1690 ins = new (alloc)
1691 MCallDOMNative(target, numActualArgs, *objectKind, *initialHeap);
1692 } else {
1693 ins =
1694 new (alloc) MCall(target, numActualArgs, construct, ignoresReturnValue);
1695 }
1696 if (!ins->init(alloc, maxArgc + NumNonArgumentOperands)) {
1697 return nullptr;
1698 }
1699 return ins;
1700}
1701
1702AliasSet MCallDOMNative::getAliasSet() const {
1703 const JSJitInfo* jitInfo = getJitInfo();
1704
1705 // If we don't know anything about the types of our arguments, we have to
1706 // assume that type-coercions can have side-effects, so we need to alias
1707 // everything.
1708 if (jitInfo->aliasSet() == JSJitInfo::AliasEverything ||
1709 !jitInfo->isTypedMethodJitInfo()) {
1710 return AliasSet::Store(AliasSet::Any);
1711 }
1712
1713 uint32_t argIndex = 0;
1714 const JSTypedMethodJitInfo* methodInfo =
1715 reinterpret_cast<const JSTypedMethodJitInfo*>(jitInfo);
1716 for (const JSJitInfo::ArgType* argType = methodInfo->argTypes;
1717 *argType != JSJitInfo::ArgTypeListEnd; ++argType, ++argIndex) {
1718 if (argIndex >= numActualArgs()) {
1719 // Passing through undefined can't have side-effects
1720 continue;
1721 }
1722 // getArg(0) is "this", so skip it
1723 MDefinition* arg = getArg(argIndex + 1);
1724 MIRType actualType = arg->type();
1725 // The only way to reliably avoid side-effects given the information we
1726 // have here is if we're passing in a known primitive value to an
1727 // argument that expects a primitive value.
1728 //
1729 // XXXbz maybe we need to communicate better information. For example,
1730 // a sequence argument will sort of unavoidably have side effects, while
1731 // a typed array argument won't have any, but both are claimed to be
1732 // JSJitInfo::Object. But if we do that, we need to watch out for our
1733 // movability/DCE-ability bits: if we have an arg type that can reliably
1734 // throw an exception on conversion, that might not affect our alias set
1735 // per se, but it should prevent us being moved or DCE-ed, unless we
1736 // know the incoming things match that arg type and won't throw.
1737 //
1738 if ((actualType == MIRType::Value || actualType == MIRType::Object) ||
1739 (*argType & JSJitInfo::Object)) {
1740 return AliasSet::Store(AliasSet::Any);
1741 }
1742 }
1743
1744 // We checked all the args, and they check out. So we only alias DOM
1745 // mutations or alias nothing, depending on the alias set in the jitinfo.
1746 if (jitInfo->aliasSet() == JSJitInfo::AliasNone) {
1747 return AliasSet::None();
1748 }
1749
1750 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"
, 1750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() == JSJitInfo::AliasDOMSets"
")"); do { *((volatile int*)__null) = 1750; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1751 return AliasSet::Load(AliasSet::DOMProperty);
1752}
1753
1754void MCallDOMNative::computeMovable() {
1755 // We are movable if the jitinfo says we can be and if we're also not
1756 // effectful. The jitinfo can't check for the latter, since it depends on
1757 // the types of our arguments.
1758 const JSJitInfo* jitInfo = getJitInfo();
1759
1760 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"
, 1761); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything"
")"); do { *((volatile int*)__null) = 1761; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1761 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"
, 1761); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything"
")"); do { *((volatile int*)__null) = 1761; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1762
1763 if (jitInfo->isMovable && !isEffectful()) {
1764 setMovable();
1765 }
1766}
1767
1768bool MCallDOMNative::congruentTo(const MDefinition* ins) const {
1769 if (!isMovable()) {
1770 return false;
1771 }
1772
1773 if (!ins->isCall()) {
1774 return false;
1775 }
1776
1777 const MCall* call = ins->toCall();
1778
1779 if (!call->isCallDOMNative()) {
1780 return false;
1781 }
1782
1783 if (getSingleTarget() != call->getSingleTarget()) {
1784 return false;
1785 }
1786
1787 if (isConstructing() != call->isConstructing()) {
1788 return false;
1789 }
1790
1791 if (numActualArgs() != call->numActualArgs()) {
1792 return false;
1793 }
1794
1795 if (!congruentIfOperandsEqual(call)) {
1796 return false;
1797 }
1798
1799 // The other call had better be movable at this point!
1800 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"
, 1800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "call->isMovable()"
")"); do { *((volatile int*)__null) = 1800; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1801
1802 return true;
1803}
1804
1805const JSJitInfo* MCallDOMNative::getJitInfo() const {
1806 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"
, 1806); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getSingleTarget()->hasJitInfo()"
")"); do { *((volatile int*)__null) = 1806; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1807 return getSingleTarget()->jitInfo();
1808}
1809
1810MCallClassHook* MCallClassHook::New(TempAllocator& alloc, JSNative target,
1811 uint32_t argc, bool constructing) {
1812 auto* ins = new (alloc) MCallClassHook(target, constructing);
1813
1814 // Add callee + |this| + (if constructing) newTarget.
1815 uint32_t numOperands = 2 + argc + constructing;
1816
1817 if (!ins->init(alloc, numOperands)) {
1818 return nullptr;
1819 }
1820
1821 return ins;
1822}
1823
1824MDefinition* MStringLength::foldsTo(TempAllocator& alloc) {
1825 if (string()->isConstant()) {
1826 JSString* str = string()->toConstant()->toString();
1827 return MConstant::New(alloc, Int32Value(str->length()));
1828 }
1829
1830 // MFromCharCode returns a one-element string.
1831 if (string()->isFromCharCode()) {
1832 return MConstant::New(alloc, Int32Value(1));
1833 }
1834
1835 return this;
1836}
1837
1838MDefinition* MConcat::foldsTo(TempAllocator& alloc) {
1839 if (lhs()->isConstant() && lhs()->toConstant()->toString()->empty()) {
1840 return rhs();
1841 }
1842
1843 if (rhs()->isConstant() && rhs()->toConstant()->toString()->empty()) {
1844 return lhs();
1845 }
1846
1847 return this;
1848}
1849
1850MDefinition* MStringConvertCase::foldsTo(TempAllocator& alloc) {
1851 MDefinition* string = this->string();
1852
1853 // Handle the pattern |str[idx].toUpperCase()| and simplify it from
1854 // |StringConvertCase(FromCharCode(CharCodeAt(str, idx)))| to just
1855 // |CharCodeConvertCase(CharCodeAt(str, idx))|.
1856 if (string->isFromCharCode()) {
1857 auto* charCode = string->toFromCharCode()->code();
1858 auto mode = mode_ == Mode::LowerCase ? MCharCodeConvertCase::LowerCase
1859 : MCharCodeConvertCase::UpperCase;
1860 return MCharCodeConvertCase::New(alloc, charCode, mode);
1861 }
1862
1863 // Handle the pattern |num.toString(base).toUpperCase()| and simplify it to
1864 // directly return the string representation in the correct case.
1865 if (string->isInt32ToStringWithBase()) {
1866 auto* toString = string->toInt32ToStringWithBase();
1867
1868 bool lowerCase = mode_ == Mode::LowerCase;
1869 if (toString->lowerCase() == lowerCase) {
1870 return toString;
1871 }
1872 return MInt32ToStringWithBase::New(alloc, toString->input(),
1873 toString->base(), lowerCase);
1874 }
1875
1876 return this;
1877}
1878
1879static bool IsSubstrTo(MSubstr* substr, int32_t len) {
1880 // We want to match this pattern:
1881 //
1882 // Substr(string, Constant(0), Min(Constant(length), StringLength(string)))
1883 //
1884 // which is generated for the self-hosted `String.p.{substring,slice,substr}`
1885 // functions when called with constants `start` and `end` parameters.
1886
1887 auto isConstantZero = [](auto* def) {
1888 return def->isConstant() && def->toConstant()->isInt32(0);
1889 };
1890
1891 if (!isConstantZero(substr->begin())) {
1892 return false;
1893 }
1894
1895 auto* length = substr->length();
1896 if (length->isBitOr()) {
1897 // Unnecessary bit-ops haven't yet been removed.
1898 auto* bitOr = length->toBitOr();
1899 if (isConstantZero(bitOr->lhs())) {
1900 length = bitOr->rhs();
1901 } else if (isConstantZero(bitOr->rhs())) {
1902 length = bitOr->lhs();
1903 }
1904 }
1905 if (!length->isMinMax() || length->toMinMax()->isMax()) {
1906 return false;
1907 }
1908
1909 auto* min = length->toMinMax();
1910 if (!min->lhs()->isConstant() && !min->rhs()->isConstant()) {
1911 return false;
1912 }
1913
1914 auto* minConstant = min->lhs()->isConstant() ? min->lhs()->toConstant()
1915 : min->rhs()->toConstant();
1916
1917 auto* minOperand = min->lhs()->isConstant() ? min->rhs() : min->lhs();
1918 if (!minOperand->isStringLength() ||
1919 minOperand->toStringLength()->string() != substr->string()) {
1920 return false;
1921 }
1922
1923 // Ensure |len| matches the substring's length.
1924 return minConstant->isInt32(len);
1925}
1926
1927MDefinition* MSubstr::foldsTo(TempAllocator& alloc) {
1928 // Fold |str.substring(0, 1)| to |str.charAt(0)|.
1929 if (!IsSubstrTo(this, 1)) {
1930 return this;
1931 }
1932
1933 auto* charCode = MCharCodeAtOrNegative::New(alloc, string(), begin());
1934 block()->insertBefore(this, charCode);
1935
1936 return MFromCharCodeEmptyIfNegative::New(alloc, charCode);
1937}
1938
1939MDefinition* MCharCodeAt::foldsTo(TempAllocator& alloc) {
1940 MDefinition* string = this->string();
1941 if (!string->isConstant() && !string->isFromCharCode()) {
1942 return this;
1943 }
1944
1945 MDefinition* index = this->index();
1946 if (index->isSpectreMaskIndex()) {
1947 index = index->toSpectreMaskIndex()->index();
1948 }
1949 if (!index->isConstant()) {
1950 return this;
1951 }
1952 int32_t idx = index->toConstant()->toInt32();
1953
1954 // Handle the pattern |s[idx].charCodeAt(0)|.
1955 if (string->isFromCharCode()) {
1956 if (idx != 0) {
1957 return this;
1958 }
1959
1960 // Simplify |CharCodeAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just
1961 // |CharCodeAt(s, idx)|.
1962 auto* charCode = string->toFromCharCode()->code();
1963 if (!charCode->isCharCodeAt()) {
1964 return this;
1965 }
1966
1967 return charCode;
1968 }
1969
1970 JSLinearString* str = &string->toConstant()->toString()->asLinear();
1971 if (idx < 0 || uint32_t(idx) >= str->length()) {
1972 return this;
1973 }
1974
1975 char16_t ch = str->latin1OrTwoByteChar(idx);
1976 return MConstant::New(alloc, Int32Value(ch));
1977}
1978
1979MDefinition* MCodePointAt::foldsTo(TempAllocator& alloc) {
1980 MDefinition* string = this->string();
1981 if (!string->isConstant() && !string->isFromCharCode()) {
1982 return this;
1983 }
1984
1985 MDefinition* index = this->index();
1986 if (index->isSpectreMaskIndex()) {
1987 index = index->toSpectreMaskIndex()->index();
1988 }
1989 if (!index->isConstant()) {
1990 return this;
1991 }
1992 int32_t idx = index->toConstant()->toInt32();
1993
1994 // Handle the pattern |s[idx].codePointAt(0)|.
1995 if (string->isFromCharCode()) {
1996 if (idx != 0) {
1997 return this;
1998 }
1999
2000 // Simplify |CodePointAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just
2001 // |CharCodeAt(s, idx)|.
2002 auto* charCode = string->toFromCharCode()->code();
2003 if (!charCode->isCharCodeAt()) {
2004 return this;
2005 }
2006
2007 return charCode;
2008 }
2009
2010 JSLinearString* str = &string->toConstant()->toString()->asLinear();
2011 if (idx < 0 || uint32_t(idx) >= str->length()) {
2012 return this;
2013 }
2014
2015 char32_t first = str->latin1OrTwoByteChar(idx);
2016 if (unicode::IsLeadSurrogate(first) && uint32_t(idx) + 1 < str->length()) {
2017 char32_t second = str->latin1OrTwoByteChar(idx + 1);
2018 if (unicode::IsTrailSurrogate(second)) {
2019 first = unicode::UTF16Decode(first, second);
2020 }
2021 }
2022 return MConstant::New(alloc, Int32Value(first));
2023}
2024
2025MDefinition* MToRelativeStringIndex::foldsTo(TempAllocator& alloc) {
2026 MDefinition* index = this->index();
2027 MDefinition* length = this->length();
2028
2029 if (!index->isConstant()) {
2030 return this;
2031 }
2032 if (!length->isStringLength() && !length->isConstant()) {
2033 return this;
2034 }
2035 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"
, 2035); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length->toConstant()->toInt32() >= 0"
")"); do { *((volatile int*)__null) = 2035; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2036
2037 int32_t relativeIndex = index->toConstant()->toInt32();
2038 if (relativeIndex >= 0) {
2039 return index;
2040 }
2041
2042 // Safe to truncate because |length| is never negative.
2043 return MAdd::New(alloc, index, length, TruncateKind::Truncate);
2044}
2045
2046template <size_t Arity>
2047[[nodiscard]] static bool EnsureFloatInputOrConvert(
2048 MAryInstruction<Arity>* owner, TempAllocator& alloc) {
2049 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"
, 2050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())"
") (" "Floating point types must check consumers" ")"); do {
*((volatile int*)__null) = 2050; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2050 "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"
, 2050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())"
") (" "Floating point types must check consumers" ")"); do {
*((volatile int*)__null) = 2050; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2051
2052 if (AllOperandsCanProduceFloat32(owner)) {
2053 return true;
2054 }
2055 ConvertOperandsToDouble(owner, alloc);
2056 return false;
2057}
2058
2059template <size_t Arity>
2060[[nodiscard]] static bool EnsureFloatConsumersAndInputOrConvert(
2061 MAryInstruction<Arity>* owner, TempAllocator& alloc) {
2062 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"
, 2063); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())"
") (" "Integer types don't need to check consumers" ")"); do
{ *((volatile int*)__null) = 2063; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2063 "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"
, 2063); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())"
") (" "Integer types don't need to check consumers" ")"); do
{ *((volatile int*)__null) = 2063; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2064
2065 if (AllOperandsCanProduceFloat32(owner) &&
2066 CheckUsesAreFloat32Consumers(owner)) {
2067 return true;
2068 }
2069 ConvertOperandsToDouble(owner, alloc);
2070 return false;
2071}
2072
2073void MFloor::trySpecializeFloat32(TempAllocator& alloc) {
2074 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"
, 2074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2074; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2075 if (EnsureFloatInputOrConvert(this, alloc)) {
2076 specialization_ = MIRType::Float32;
2077 }
2078}
2079
2080void MCeil::trySpecializeFloat32(TempAllocator& alloc) {
2081 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"
, 2081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2081; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2082 if (EnsureFloatInputOrConvert(this, alloc)) {
2083 specialization_ = MIRType::Float32;
2084 }
2085}
2086
2087void MRound::trySpecializeFloat32(TempAllocator& alloc) {
2088 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"
, 2088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2089 if (EnsureFloatInputOrConvert(this, alloc)) {
2090 specialization_ = MIRType::Float32;
2091 }
2092}
2093
2094void MTrunc::trySpecializeFloat32(TempAllocator& alloc) {
2095 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"
, 2095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2095; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2096 if (EnsureFloatInputOrConvert(this, alloc)) {
2097 specialization_ = MIRType::Float32;
2098 }
2099}
2100
2101void MNearbyInt::trySpecializeFloat32(TempAllocator& alloc) {
2102 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
2103 specialization_ = MIRType::Float32;
2104 setResultType(MIRType::Float32);
2105 }
2106}
2107
2108MGoto* MGoto::New(TempAllocator& alloc, MBasicBlock* target) {
2109 return new (alloc) MGoto(target);
2110}
2111
2112MGoto* MGoto::New(TempAllocator::Fallible alloc, MBasicBlock* target) {
2113 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"
, 2113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")"
); do { *((volatile int*)__null) = 2113; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2114 return new (alloc) MGoto(target);
2115}
2116
2117MGoto* MGoto::New(TempAllocator& alloc) { return new (alloc) MGoto(nullptr); }
2118
2119MDefinition* MBox::foldsTo(TempAllocator& alloc) {
2120 if (input()->isUnbox()) {
2121 return input()->toUnbox()->input();
2122 }
2123 return this;
2124}
2125
2126#ifdef JS_JITSPEW1
2127void MUnbox::printOpcode(GenericPrinter& out) const {
2128 PrintOpcodeName(out, op());
2129 out.printf(" ");
2130 getOperand(0)->printName(out);
2131 out.printf(" ");
2132
2133 switch (type()) {
2134 case MIRType::Int32:
2135 out.printf("to Int32");
2136 break;
2137 case MIRType::Double:
2138 out.printf("to Double");
2139 break;
2140 case MIRType::Boolean:
2141 out.printf("to Boolean");
2142 break;
2143 case MIRType::String:
2144 out.printf("to String");
2145 break;
2146 case MIRType::Symbol:
2147 out.printf("to Symbol");
2148 break;
2149 case MIRType::BigInt:
2150 out.printf("to BigInt");
2151 break;
2152 case MIRType::Object:
2153 out.printf("to Object");
2154 break;
2155 default:
2156 break;
2157 }
2158
2159 switch (mode()) {
2160 case Fallible:
2161 out.printf(" (fallible)");
2162 break;
2163 case Infallible:
2164 out.printf(" (infallible)");
2165 break;
2166 default:
2167 break;
2168 }
2169}
2170#endif
2171
2172MDefinition* MUnbox::foldsTo(TempAllocator& alloc) {
2173 if (input()->isBox()) {
2174 MDefinition* unboxed = input()->toBox()->input();
2175
2176 // Fold MUnbox(MBox(x)) => x if types match.
2177 if (unboxed->type() == type()) {
2178 if (fallible()) {
2179 unboxed->setImplicitlyUsedUnchecked();
2180 }
2181 return unboxed;
2182 }
2183
2184 // Fold MUnbox(MBox(x)) => MToDouble(x) if possible.
2185 if (type() == MIRType::Double &&
2186 IsTypeRepresentableAsDouble(unboxed->type())) {
2187 if (unboxed->isConstant()) {
2188 return MConstant::New(
2189 alloc, DoubleValue(unboxed->toConstant()->numberToDouble()));
2190 }
2191
2192 return MToDouble::New(alloc, unboxed);
2193 }
2194
2195 // MUnbox<Int32>(MBox<Double>(x)) will always fail, even if x can be
2196 // represented as an Int32. Fold to avoid unnecessary bailouts.
2197 if (type() == MIRType::Int32 && unboxed->type() == MIRType::Double) {
2198 auto* folded = MToNumberInt32::New(alloc, unboxed,
2199 IntConversionInputKind::NumbersOnly);
2200 folded->setGuard();
2201 return folded;
2202 }
2203 }
2204
2205 return this;
2206}
2207
2208#ifdef DEBUG1
2209void MPhi::assertLoopPhi() const {
2210 // getLoopPredecessorOperand and getLoopBackedgeOperand rely on these
2211 // predecessors being at known indices.
2212 if (block()->numPredecessors() == 2) {
2213 MBasicBlock* pred = block()->getPredecessor(0);
2214 MBasicBlock* back = block()->getPredecessor(1);
2215 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"
, 2215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred == block()->loopPredecessor()"
")"); do { *((volatile int*)__null) = 2215; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2216 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"
, 2216); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->successorWithPhis() == block()"
")"); do { *((volatile int*)__null) = 2216; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2217 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"
, 2217); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->positionInPhiSuccessor() == 0"
")"); do { *((volatile int*)__null) = 2217; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2218 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"
, 2218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()"
")"); do { *((volatile int*)__null) = 2218; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2219 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"
, 2219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()"
")"); do { *((volatile int*)__null) = 2219; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2220 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"
, 2220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 1"
")"); do { *((volatile int*)__null) = 2220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2221 } else {
2222 // After we remove fake loop predecessors for loop headers that
2223 // are only reachable via OSR, the only predecessor is the
2224 // loop backedge.
2225 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"
, 2225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 1"
")"); do { *((volatile int*)__null) = 2225; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2226 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"
, 2226); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->graph().osrBlock()"
")"); do { *((volatile int*)__null) = 2226; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2227 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"
, 2227); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!block()->graph().canBuildDominators()"
")"); do { *((volatile int*)__null) = 2227; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2228 MBasicBlock* back = block()->getPredecessor(0);
2229 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"
, 2229); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()"
")"); do { *((volatile int*)__null) = 2229; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2230 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"
, 2230); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()"
")"); do { *((volatile int*)__null) = 2230; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2231 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"
, 2231); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 0"
")"); do { *((volatile int*)__null) = 2231; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2232 }
2233}
2234#endif
2235
2236MDefinition* MPhi::getLoopPredecessorOperand() const {
2237 // This should not be called after removing fake loop predecessors.
2238 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"
, 2238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2"
")"); do { *((volatile int*)__null) = 2238; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2239 assertLoopPhi();
2240 return getOperand(0);
2241}
2242
2243MDefinition* MPhi::getLoopBackedgeOperand() const {
2244 assertLoopPhi();
2245 uint32_t idx = block()->numPredecessors() == 2 ? 1 : 0;
2246 return getOperand(idx);
2247}
2248
2249void MPhi::removeOperand(size_t index) {
2250 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"
, 2250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index < numOperands()"
")"); do { *((volatile int*)__null) = 2250; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2251 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"
, 2251); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->index() == index"
")"); do { *((volatile int*)__null) = 2251; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2252 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"
, 2252); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->consumer() == this"
")"); do { *((volatile int*)__null) = 2252; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2253
2254 // If we have phi(..., a, b, c, d, ..., z) and we plan
2255 // on removing a, then first shift downward so that we have
2256 // phi(..., b, c, d, ..., z, z):
2257 MUse* p = inputs_.begin() + index;
2258 MUse* e = inputs_.end();
2259 p->producer()->removeUse(p);
2260 for (; p < e - 1; ++p) {
2261 MDefinition* producer = (p + 1)->producer();
2262 p->setProducerUnchecked(producer);
2263 producer->replaceUse(p + 1, p);
2264 }
2265
2266 // truncate the inputs_ list:
2267 inputs_.popBack();
2268}
2269
2270void MPhi::removeAllOperands() {
2271 for (MUse& p : inputs_) {
2272 p.producer()->removeUse(&p);
2273 }
2274 inputs_.clear();
2275}
2276
2277MDefinition* MPhi::foldsTernary(TempAllocator& alloc) {
2278 /* Look if this MPhi is a ternary construct.
2279 * This is a very loose term as it actually only checks for
2280 *
2281 * MTest X
2282 * / \
2283 * ... ...
2284 * \ /
2285 * MPhi X Y
2286 *
2287 * Which we will simply call:
2288 * x ? x : y or x ? y : x
2289 */
2290
2291 if (numOperands() != 2) {
2292 return nullptr;
2293 }
2294
2295 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"
, 2295); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2"
")"); do { *((volatile int*)__null) = 2295; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2296
2297 MBasicBlock* pred = block()->immediateDominator();
2298 if (!pred || !pred->lastIns()->isTest()) {
2299 return nullptr;
2300 }
2301
2302 MTest* test = pred->lastIns()->toTest();
2303
2304 // True branch may only dominate one edge of MPhi.
2305 if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
2306 test->ifTrue()->dominates(block()->getPredecessor(1))) {
2307 return nullptr;
2308 }
2309
2310 // False branch may only dominate one edge of MPhi.
2311 if (test->ifFalse()->dominates(block()->getPredecessor(0)) ==
2312 test->ifFalse()->dominates(block()->getPredecessor(1))) {
2313 return nullptr;
2314 }
2315
2316 // True and false branch must dominate different edges of MPhi.
2317 if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
2318 test->ifFalse()->dominates(block()->getPredecessor(0))) {
2319 return nullptr;
2320 }
2321
2322 // We found a ternary construct.
2323 bool firstIsTrueBranch =
2324 test->ifTrue()->dominates(block()->getPredecessor(0));
2325 MDefinition* trueDef = firstIsTrueBranch ? getOperand(0) : getOperand(1);
2326 MDefinition* falseDef = firstIsTrueBranch ? getOperand(1) : getOperand(0);
2327
2328 // Accept either
2329 // testArg ? testArg : constant or
2330 // testArg ? constant : testArg
2331 if (!trueDef->isConstant() && !falseDef->isConstant()) {
2332 return nullptr;
2333 }
2334
2335 MConstant* c =
2336 trueDef->isConstant() ? trueDef->toConstant() : falseDef->toConstant();
2337 MDefinition* testArg = (trueDef == c) ? falseDef : trueDef;
2338 if (testArg != test->input()) {
2339 return nullptr;
2340 }
2341
2342 // This check should be a tautology, except that the constant might be the
2343 // result of the removal of a branch. In such case the domination scope of
2344 // the block which is holding the constant might be incomplete. This
2345 // condition is used to prevent doing this optimization based on incomplete
2346 // information.
2347 //
2348 // As GVN removed a branch, it will update the dominations rules before
2349 // trying to fold this MPhi again. Thus, this condition does not inhibit
2350 // this optimization.
2351 MBasicBlock* truePred = block()->getPredecessor(firstIsTrueBranch ? 0 : 1);
2352 MBasicBlock* falsePred = block()->getPredecessor(firstIsTrueBranch ? 1 : 0);
2353 if (!trueDef->block()->dominates(truePred) ||
2354 !falseDef->block()->dominates(falsePred)) {
2355 return nullptr;
2356 }
2357
2358 // If testArg is an int32 type we can:
2359 // - fold testArg ? testArg : 0 to testArg
2360 // - fold testArg ? 0 : testArg to 0
2361 if (testArg->type() == MIRType::Int32 && c->numberToDouble() == 0) {
2362 testArg->setGuardRangeBailoutsUnchecked();
2363
2364 // When folding to the constant we need to hoist it.
2365 if (trueDef == c && !c->block()->dominates(block())) {
2366 c->block()->moveBefore(pred->lastIns(), c);
2367 }
2368 return trueDef;
2369 }
2370
2371 // If testArg is an double type we can:
2372 // - fold testArg ? testArg : 0.0 to MNaNToZero(testArg)
2373 if (testArg->type() == MIRType::Double &&
2374 mozilla::IsPositiveZero(c->numberToDouble()) && c != trueDef) {
2375 MNaNToZero* replace = MNaNToZero::New(alloc, testArg);
2376 test->block()->insertBefore(test, replace);
2377 return replace;
2378 }
2379
2380 // If testArg is a string type we can:
2381 // - fold testArg ? testArg : "" to testArg
2382 // - fold testArg ? "" : testArg to ""
2383 if (testArg->type() == MIRType::String &&
2384 c->toString() == GetJitContext()->runtime->emptyString()) {
2385 // When folding to the constant we need to hoist it.
2386 if (trueDef == c && !c->block()->dominates(block())) {
2387 c->block()->moveBefore(pred->lastIns(), c);
2388 }
2389 return trueDef;
2390 }
2391
2392 return nullptr;
2393}
2394
2395MDefinition* MPhi::operandIfRedundant() {
2396 if (inputs_.length() == 0) {
2397 return nullptr;
2398 }
2399
2400 // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
2401 // returns the operand that it will always be equal to (a, in
2402 // those two cases).
2403 MDefinition* first = getOperand(0);
2404 for (size_t i = 1, e = numOperands(); i < e; i++) {
2405 MDefinition* op = getOperand(i);
2406 if (op != first && op != this) {
2407 return nullptr;
2408 }
2409 }
2410 return first;
2411}
2412
2413MDefinition* MPhi::foldsTo(TempAllocator& alloc) {
2414 if (MDefinition* def = operandIfRedundant()) {
2415 return def;
2416 }
2417
2418 if (MDefinition* def = foldsTernary(alloc)) {
2419 return def;
2420 }
2421
2422 return this;
2423}
2424
2425bool MPhi::congruentTo(const MDefinition* ins) const {
2426 if (!ins->isPhi()) {
2427 return false;
2428 }
2429
2430 // Phis in different blocks may have different control conditions.
2431 // For example, these phis:
2432 //
2433 // if (p)
2434 // goto a
2435 // a:
2436 // t = phi(x, y)
2437 //
2438 // if (q)
2439 // goto b
2440 // b:
2441 // s = phi(x, y)
2442 //
2443 // have identical operands, but they are not equvalent because t is
2444 // effectively p?x:y and s is effectively q?x:y.
2445 //
2446 // For now, consider phis in different blocks incongruent.
2447 if (ins->block() != block()) {
2448 return false;
2449 }
2450
2451 return congruentIfOperandsEqual(ins);
2452}
2453
2454void MPhi::updateForReplacement(MPhi* other) {
2455 // This function is called to fix the current Phi flags using it as a
2456 // replacement of the other Phi instruction |other|.
2457 //
2458 // When dealing with usage analysis, any Use will replace all other values,
2459 // such as Unused and Unknown. Unless both are Unused, the merge would be
2460 // Unknown.
2461 if (usageAnalysis_ == PhiUsage::Used ||
2462 other->usageAnalysis_ == PhiUsage::Used) {
2463 usageAnalysis_ = PhiUsage::Used;
2464 } else if (usageAnalysis_ != other->usageAnalysis_) {
2465 // this == unused && other == unknown
2466 // or this == unknown && other == unused
2467 usageAnalysis_ = PhiUsage::Unknown;
2468 } else {
2469 // this == unused && other == unused
2470 // or this == unknown && other = unknown
2471 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"
, 2472); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown"
")"); do { *((volatile int*)__null) = 2472; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2472 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"
, 2472); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown"
")"); do { *((volatile int*)__null) = 2472; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2473 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"
, 2473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == other->usageAnalysis_"
")"); do { *((volatile int*)__null) = 2473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2474 }
2475}
2476
2477/* static */
2478bool MPhi::markIteratorPhis(const PhiVector& iterators) {
2479 // Find and mark phis that must transitively hold an iterator live.
2480
2481 Vector<MPhi*, 8, SystemAllocPolicy> worklist;
2482
2483 for (MPhi* iter : iterators) {
2484 if (!iter->isInWorklist()) {
2485 if (!worklist.append(iter)) {
2486 return false;
2487 }
2488 iter->setInWorklist();
2489 }
2490 }
2491
2492 while (!worklist.empty()) {
2493 MPhi* phi = worklist.popCopy();
2494 phi->setNotInWorklist();
2495
2496 phi->setIterator();
2497 phi->setImplicitlyUsedUnchecked();
2498
2499 for (MUseDefIterator iter(phi); iter; iter++) {
2500 MDefinition* use = iter.def();
2501 if (!use->isInWorklist() && use->isPhi() && !use->toPhi()->isIterator()) {
2502 if (!worklist.append(use->toPhi())) {
2503 return false;
2504 }
2505 use->setInWorklist();
2506 }
2507 }
2508 }
2509
2510 return true;
2511}
2512
2513bool MPhi::typeIncludes(MDefinition* def) {
2514 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"
, 2514); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsMagicType(def->type())"
")"); do { *((volatile int*)__null) = 2514; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2515
2516 if (def->type() == MIRType::Int32 && this->type() == MIRType::Double) {
2517 return true;
2518 }
2519
2520 if (def->type() == MIRType::Value) {
2521 // This phi must be able to be any value.
2522 return this->type() == MIRType::Value;
2523 }
2524
2525 return this->mightBeType(def->type());
2526}
2527
2528void MCallBase::addArg(size_t argnum, MDefinition* arg) {
2529 // The operand vector is initialized in reverse order by WarpBuilder.
2530 // It cannot be checked for consistency until all arguments are added.
2531 // FixedList doesn't initialize its elements, so do an unchecked init.
2532 initOperand(argnum + NumNonArgumentOperands, arg);
2533}
2534
2535static inline bool IsConstant(MDefinition* def, double v) {
2536 if (!def->isConstant()) {
2537 return false;
2538 }
2539
2540 return NumbersAreIdentical(def->toConstant()->numberToDouble(), v);
2541}
2542
2543MDefinition* MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc) {
2544 // Identity operations are removed (for int32 only) in foldUnnecessaryBitop.
2545
2546 if (type() == MIRType::Int32) {
2547 if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
2548 return folded;
2549 }
2550 } else if (type() == MIRType::Int64) {
2551 if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
2552 return folded;
2553 }
2554 }
2555
2556 return this;
2557}
2558
2559MDefinition* MBinaryBitwiseInstruction::foldUnnecessaryBitop() {
2560 // It's probably OK to perform this optimization only for int32, as it will
2561 // have the greatest effect for asm.js code that is compiled with the JS
2562 // pipeline, and that code will not see int64 values.
2563
2564 if (type() != MIRType::Int32) {
2565 return this;
2566 }
2567
2568 // Fold unsigned shift right operator when the second operand is zero and
2569 // the only use is an unsigned modulo. Thus, the expression
2570 // |(x >>> 0) % y| becomes |x % y|.
2571 if (isUrsh() && IsUint32Type(this)) {
2572 MDefinition* defUse = maybeSingleDefUse();
2573 if (defUse && defUse->isMod() && defUse->toMod()->isUnsigned()) {
2574 return getOperand(0);
2575 }
2576 }
2577
2578 // Eliminate bitwise operations that are no-ops when used on integer
2579 // inputs, such as (x | 0).
2580
2581 MDefinition* lhs = getOperand(0);
2582 MDefinition* rhs = getOperand(1);
2583
2584 if (IsConstant(lhs, 0)) {
2585 return foldIfZero(0);
2586 }
2587
2588 if (IsConstant(rhs, 0)) {
2589 return foldIfZero(1);
2590 }
2591
2592 if (IsConstant(lhs, -1)) {
2593 return foldIfNegOne(0);
2594 }
2595
2596 if (IsConstant(rhs, -1)) {
2597 return foldIfNegOne(1);
2598 }
2599
2600 if (lhs == rhs) {
2601 return foldIfEqual();
2602 }
2603
2604 if (maskMatchesRightRange) {
2605 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"
, 2605); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->isConstant()"
")"); do { *((volatile int*)__null) = 2605; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2606 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"
, 2606); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2606; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2607 return foldIfAllBitsSet(0);
2608 }
2609
2610 if (maskMatchesLeftRange) {
2611 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"
, 2611); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->isConstant()"
")"); do { *((volatile int*)__null) = 2611; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2612 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"
, 2612); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2612; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2613 return foldIfAllBitsSet(1);
2614 }
2615
2616 return this;
2617}
2618
2619static inline bool CanProduceNegativeZero(MDefinition* def) {
2620 // Test if this instruction can produce negative zero even when bailing out
2621 // and changing types.
2622 switch (def->op()) {
2623 case MDefinition::Opcode::Constant:
2624 if (def->type() == MIRType::Double &&
2625 def->toConstant()->toDouble() == -0.0) {
2626 return true;
2627 }
2628 [[fallthrough]];
2629 case MDefinition::Opcode::BitAnd:
2630 case MDefinition::Opcode::BitOr:
2631 case MDefinition::Opcode::BitXor:
2632 case MDefinition::Opcode::BitNot:
2633 case MDefinition::Opcode::Lsh:
2634 case MDefinition::Opcode::Rsh:
2635 return false;
2636 default:
2637 return true;
2638 }
2639}
2640
2641static inline bool NeedNegativeZeroCheck(MDefinition* def) {
2642 if (def->isGuard() || def->isGuardRangeBailouts()) {
2643 return true;
2644 }
2645
2646 // Test if all uses have the same semantics for -0 and 0
2647 for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
2648 if (use->consumer()->isResumePoint()) {
2649 return true;
2650 }
2651
2652 MDefinition* use_def = use->consumer()->toDefinition();
2653 switch (use_def->op()) {
2654 case MDefinition::Opcode::Add: {
2655 // If add is truncating -0 and 0 are observed as the same.
2656 if (use_def->toAdd()->isTruncated()) {
2657 break;
2658 }
2659
2660 // x + y gives -0, when both x and y are -0
2661
2662 // Figure out the order in which the addition's operands will
2663 // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR
2664 // definitions for us so that this just requires comparing ids.
2665 MDefinition* first = use_def->toAdd()->lhs();
2666 MDefinition* second = use_def->toAdd()->rhs();
2667 if (first->id() > second->id()) {
2668 std::swap(first, second);
2669 }
2670 // Negative zero checks can be removed on the first executed
2671 // operand only if it is guaranteed the second executed operand
2672 // will produce a value other than -0. While the second is
2673 // typed as an int32, a bailout taken between execution of the
2674 // operands may change that type and cause a -0 to flow to the
2675 // second.
2676 //
2677 // There is no way to test whether there are any bailouts
2678 // between execution of the operands, so remove negative
2679 // zero checks from the first only if the second's type is
2680 // independent from type changes that may occur after bailing.
2681 if (def == first && CanProduceNegativeZero(second)) {
2682 return true;
2683 }
2684
2685 // The negative zero check can always be removed on the second
2686 // executed operand; by the time this executes the first will have
2687 // been evaluated as int32 and the addition's result cannot be -0.
2688 break;
2689 }
2690 case MDefinition::Opcode::Sub: {
2691 // If sub is truncating -0 and 0 are observed as the same
2692 if (use_def->toSub()->isTruncated()) {
2693 break;
2694 }
2695
2696 // x + y gives -0, when x is -0 and y is 0
2697
2698 // We can remove the negative zero check on the rhs, only if we
2699 // are sure the lhs isn't negative zero.
2700
2701 // The lhs is typed as integer (i.e. not -0.0), but it can bailout
2702 // and change type. This should be fine if the lhs is executed
2703 // first. However if the rhs is executed first, the lhs can bail,
2704 // change type and become -0.0 while the rhs has already been
2705 // optimized to not make a difference between zero and negative zero.
2706 MDefinition* lhs = use_def->toSub()->lhs();
2707 MDefinition* rhs = use_def->toSub()->rhs();
2708 if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs)) {
2709 return true;
2710 }
2711
2712 [[fallthrough]];
2713 }
2714 case MDefinition::Opcode::StoreElement:
2715 case MDefinition::Opcode::StoreHoleValueElement:
2716 case MDefinition::Opcode::LoadElement:
2717 case MDefinition::Opcode::LoadElementHole:
2718 case MDefinition::Opcode::LoadUnboxedScalar:
2719 case MDefinition::Opcode::LoadDataViewElement:
2720 case MDefinition::Opcode::LoadTypedArrayElementHole:
2721 case MDefinition::Opcode::CharCodeAt:
2722 case MDefinition::Opcode::Mod:
2723 case MDefinition::Opcode::InArray:
2724 // Only allowed to remove check when definition is the second operand
2725 if (use_def->getOperand(0) == def) {
2726 return true;
2727 }
2728 for (size_t i = 2, e = use_def->numOperands(); i < e; i++) {
2729 if (use_def->getOperand(i) == def) {
2730 return true;
2731 }
2732 }
2733 break;
2734 case MDefinition::Opcode::BoundsCheck:
2735 // Only allowed to remove check when definition is the first operand
2736 if (use_def->toBoundsCheck()->getOperand(1) == def) {
2737 return true;
2738 }
2739 break;
2740 case MDefinition::Opcode::ToString:
2741 case MDefinition::Opcode::FromCharCode:
2742 case MDefinition::Opcode::FromCodePoint:
2743 case MDefinition::Opcode::TableSwitch:
2744 case MDefinition::Opcode::Compare:
2745 case MDefinition::Opcode::BitAnd:
2746 case MDefinition::Opcode::BitOr:
2747 case MDefinition::Opcode::BitXor:
2748 case MDefinition::Opcode::Abs:
2749 case MDefinition::Opcode::TruncateToInt32:
2750 // Always allowed to remove check. No matter which operand.
2751 break;
2752 case MDefinition::Opcode::StoreElementHole:
2753 case MDefinition::Opcode::StoreTypedArrayElementHole:
2754 case MDefinition::Opcode::PostWriteElementBarrier:
2755 // Only allowed to remove check when definition is the third operand.
2756 for (size_t i = 0, e = use_def->numOperands(); i < e; i++) {
2757 if (i == 2) {
2758 continue;
2759 }
2760 if (use_def->getOperand(i) == def) {
2761 return true;
2762 }
2763 }
2764 break;
2765 default:
2766 return true;
2767 }
2768 }
2769 return false;
2770}
2771
2772#ifdef JS_JITSPEW1
2773void MBinaryArithInstruction::printOpcode(GenericPrinter& out) const {
2774 MDefinition::printOpcode(out);
2775
2776 switch (type()) {
2777 case MIRType::Int32:
2778 if (isDiv()) {
2779 out.printf(" [%s]", toDiv()->isUnsigned() ? "uint32" : "int32");
2780 } else if (isMod()) {
2781 out.printf(" [%s]", toMod()->isUnsigned() ? "uint32" : "int32");
2782 } else {
2783 out.printf(" [int32]");
2784 }
2785 break;
2786 case MIRType::Int64:
2787 if (isDiv()) {
2788 out.printf(" [%s]", toDiv()->isUnsigned() ? "uint64" : "int64");
2789 } else if (isMod()) {
2790 out.printf(" [%s]", toMod()->isUnsigned() ? "uint64" : "int64");
2791 } else {
2792 out.printf(" [int64]");
2793 }
2794 break;
2795 case MIRType::Float32:
2796 out.printf(" [float]");
2797 break;
2798 case MIRType::Double:
2799 out.printf(" [double]");
2800 break;
2801 default:
2802 break;
2803 }
2804}
2805#endif
2806
2807MDefinition* MRsh::foldsTo(TempAllocator& alloc) {
2808 MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc);
2809
2810 if (f != this) {
2811 return f;
2812 }
2813
2814 MDefinition* lhs = getOperand(0);
2815 MDefinition* rhs = getOperand(1);
2816
2817 // It's probably OK to perform this optimization only for int32, as it will
2818 // have the greatest effect for asm.js code that is compiled with the JS
2819 // pipeline, and that code will not see int64 values.
2820
2821 if (!lhs->isLsh() || !rhs->isConstant() || rhs->type() != MIRType::Int32) {
2822 return this;
2823 }
2824
2825 if (!lhs->getOperand(1)->isConstant() ||
2826 lhs->getOperand(1)->type() != MIRType::Int32) {
2827 return this;
2828 }
2829
2830 uint32_t shift = rhs->toConstant()->toInt32();
2831 uint32_t shift_lhs = lhs->getOperand(1)->toConstant()->toInt32();
2832 if (shift != shift_lhs) {
2833 return this;
2834 }
2835
2836 switch (shift) {
2837 case 16:
2838 return MSignExtendInt32::New(alloc, lhs->getOperand(0),
2839 MSignExtendInt32::Half);
2840 case 24:
2841 return MSignExtendInt32::New(alloc, lhs->getOperand(0),
2842 MSignExtendInt32::Byte);
2843 }
2844
2845 return this;
2846}
2847
2848MDefinition* MBinaryArithInstruction::foldsTo(TempAllocator& alloc) {
2849 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"
, 2849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 2849; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2850
2851 MDefinition* lhs = getOperand(0);
2852 MDefinition* rhs = getOperand(1);
2853
2854 if (type() == MIRType::Int64) {
2855 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"
, 2855); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isTruncated()"
")"); do { *((volatile int*)__null) = 2855; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2856
2857 if (MConstant* folded = EvaluateInt64ConstantOperands(alloc, this)) {
2858 if (!folded->block()) {
2859 block()->insertBefore(this, folded);
2860 }
2861 return folded;
2862 }
2863 if (isSub() || isDiv() || isMod()) {
2864 return this;
2865 }
2866 if (rhs->isConstant() &&
2867 rhs->toConstant()->toInt64() == int64_t(getIdentity())) {
2868 return lhs;
2869 }
2870 if (lhs->isConstant() &&
2871 lhs->toConstant()->toInt64() == int64_t(getIdentity())) {
2872 return rhs;
2873 }
2874 return this;
2875 }
2876
2877 if (MConstant* folded = EvaluateConstantOperands(alloc, this)) {
2878 if (isTruncated()) {
2879 if (!folded->block()) {
2880 block()->insertBefore(this, folded);
2881 }
2882 if (folded->type() != MIRType::Int32) {
2883 return MTruncateToInt32::New(alloc, folded);
2884 }
2885 }
2886 return folded;
2887 }
2888
2889 if (MConstant* folded = EvaluateConstantNaNOperand(this)) {
2890 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"
, 2890); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isTruncated()"
")"); do { *((volatile int*)__null) = 2890; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2891 return folded;
2892 }
2893
2894 if (mustPreserveNaN_) {
2895 return this;
2896 }
2897
2898 // 0 + -0 = 0. So we can't remove addition
2899 if (isAdd() && type() != MIRType::Int32) {
2900 return this;
2901 }
2902
2903 if (IsConstant(rhs, getIdentity())) {
2904 if (isTruncated()) {
2905 return MTruncateToInt32::New(alloc, lhs);
2906 }
2907 return lhs;
2908 }
2909
2910 // subtraction isn't commutative. So we can't remove subtraction when lhs
2911 // equals 0
2912 if (isSub()) {
2913 return this;
2914 }
2915
2916 if (IsConstant(lhs, getIdentity())) {
2917 if (isTruncated()) {
2918 return MTruncateToInt32::New(alloc, rhs);
2919 }
2920 return rhs; // id op x => x
2921 }
2922
2923 return this;
2924}
2925
2926void MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc) {
2927 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"
, 2927); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 2927; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2928
2929 // Do not use Float32 if we can use int32.
2930 if (type() == MIRType::Int32) {
2931 return;
2932 }
2933
2934 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
2935 setResultType(MIRType::Float32);
2936 }
2937}
2938
2939void MMinMax::trySpecializeFloat32(TempAllocator& alloc) {
2940 if (type() == MIRType::Int32) {
2941 return;
2942 }
2943
2944 MDefinition* left = lhs();
2945 MDefinition* right = rhs();
2946
2947 if ((left->canProduceFloat32() ||
2948 (left->isMinMax() && left->type() == MIRType::Float32)) &&
2949 (right->canProduceFloat32() ||
2950 (right->isMinMax() && right->type() == MIRType::Float32))) {
2951 setResultType(MIRType::Float32);
2952 } else {
2953 ConvertOperandsToDouble(this, alloc);
2954 }
2955}
2956
2957MDefinition* MMinMax::foldsTo(TempAllocator& alloc) {
2958 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"
, 2958); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == type()"
")"); do { *((volatile int*)__null) = 2958; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2959 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"
, 2959); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == type()"
")"); do { *((volatile int*)__null) = 2959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2960
2961 if (lhs() == rhs()) {
2962 return lhs();
2963 }
2964
2965 auto foldConstants = [&alloc](MDefinition* lhs, MDefinition* rhs,
2966 bool isMax) -> MConstant* {
2967 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"
, 2967); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == rhs->type()"
")"); do { *((volatile int*)__null) = 2967; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2968 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"
, 2968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->toConstant()->isTypeRepresentableAsDouble()"
")"); do { *((volatile int*)__null) = 2968; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2969 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"
, 2969); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->toConstant()->isTypeRepresentableAsDouble()"
")"); do { *((volatile int*)__null) = 2969; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2970
2971 double lnum = lhs->toConstant()->numberToDouble();
2972 double rnum = rhs->toConstant()->numberToDouble();
2973
2974 double result;
2975 if (isMax) {
2976 result = js::math_max_impl(lnum, rnum);
2977 } else {
2978 result = js::math_min_impl(lnum, rnum);
2979 }
2980
2981 // The folded MConstant should maintain the same MIRType with the original
2982 // inputs.
2983 if (lhs->type() == MIRType::Int32) {
2984 int32_t cast;
2985 if (mozilla::NumberEqualsInt32(result, &cast)) {
2986 return MConstant::New(alloc, Int32Value(cast));
2987 }
2988 return nullptr;
2989 }
2990 if (lhs->type() == MIRType::Float32) {
2991 return MConstant::NewFloat32(alloc, result);
2992 }
2993 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"
, 2993); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 2993; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2994 return MConstant::New(alloc, DoubleValue(result));
2995 };
2996
2997 // Try to fold the following patterns when |x| and |y| are constants.
2998 //
2999 // min(min(x, z), min(y, z)) = min(min(x, y), z)
3000 // max(max(x, z), max(y, z)) = max(max(x, y), z)
3001 // max(min(x, z), min(y, z)) = min(max(x, y), z)
3002 // min(max(x, z), max(y, z)) = max(min(x, y), z)
3003 if (lhs()->isMinMax() && rhs()->isMinMax()) {
3004 do {
3005 auto* left = lhs()->toMinMax();
3006 auto* right = rhs()->toMinMax();
3007 if (left->isMax() != right->isMax()) {
3008 break;
3009 }
3010
3011 MDefinition* x;
3012 MDefinition* y;
3013 MDefinition* z;
3014 if (left->lhs() == right->lhs()) {
3015 std::tie(x, y, z) = std::tuple{left->rhs(), right->rhs(), left->lhs()};
3016 } else if (left->lhs() == right->rhs()) {
3017 std::tie(x, y, z) = std::tuple{left->rhs(), right->lhs(), left->lhs()};
3018 } else if (left->rhs() == right->lhs()) {
3019 std::tie(x, y, z) = std::tuple{left->lhs(), right->rhs(), left->rhs()};
3020 } else if (left->rhs() == right->rhs()) {
3021 std::tie(x, y, z) = std::tuple{left->lhs(), right->lhs(), left->rhs()};
3022 } else {
3023 break;
3024 }
3025
3026 if (!x->isConstant() || !x->toConstant()->isTypeRepresentableAsDouble() ||
3027 !y->isConstant() || !y->toConstant()->isTypeRepresentableAsDouble()) {
3028 break;
3029 }
3030
3031 if (auto* folded = foldConstants(x, y, isMax())) {
3032 block()->insertBefore(this, folded);
3033 return MMinMax::New(alloc, folded, z, type(), left->isMax());
3034 }
3035 } while (false);
3036 }
3037
3038 // Fold min/max operations with same inputs.
3039 if (lhs()->isMinMax() || rhs()->isMinMax()) {
3040 auto* other = lhs()->isMinMax() ? lhs()->toMinMax() : rhs()->toMinMax();
3041 auto* operand = lhs()->isMinMax() ? rhs() : lhs();
3042
3043 if (operand == other->lhs() || operand == other->rhs()) {
3044 if (isMax() == other->isMax()) {
3045 // min(x, min(x, y)) = min(x, y)
3046 // max(x, max(x, y)) = max(x, y)
3047 return other;
3048 }
3049 if (!IsFloatingPointType(type())) {
3050 // When neither value is NaN:
3051 // max(x, min(x, y)) = x
3052 // min(x, max(x, y)) = x
3053
3054 // Ensure that any bailouts that we depend on to guarantee that |y| is
3055 // Int32 are not removed.
3056 auto* otherOp = operand == other->lhs() ? other->rhs() : other->lhs();
3057 otherOp->setGuardRangeBailoutsUnchecked();
3058
3059 return operand;
3060 }
3061 }
3062 }
3063
3064 if (!lhs()->isConstant() && !rhs()->isConstant()) {
3065 return this;
3066 }
3067
3068 // Directly apply math utility to compare the rhs() and lhs() when
3069 // they are both constants.
3070 if (lhs()->isConstant() && rhs()->isConstant()) {
3071 if (!lhs()->toConstant()->isTypeRepresentableAsDouble() ||
3072 !rhs()->toConstant()->isTypeRepresentableAsDouble()) {
3073 return this;
3074 }
3075
3076 if (auto* folded = foldConstants(lhs(), rhs(), isMax())) {
3077 return folded;
3078 }
3079 }
3080
3081 MDefinition* operand = lhs()->isConstant() ? rhs() : lhs();
3082 MConstant* constant =
3083 lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant();
3084
3085 if (operand->isToDouble() &&
3086 operand->getOperand(0)->type() == MIRType::Int32) {
3087 // min(int32, cte >= INT32_MAX) = int32
3088 if (!isMax() && constant->isTypeRepresentableAsDouble() &&
3089 constant->numberToDouble() >= INT32_MAX(2147483647)) {
3090 MLimitedTruncate* limit = MLimitedTruncate::New(
3091 alloc, operand->getOperand(0), TruncateKind::NoTruncate);
3092 block()->insertBefore(this, limit);
3093 MToDouble* toDouble = MToDouble::New(alloc, limit);
3094 return toDouble;
3095 }
3096
3097 // max(int32, cte <= INT32_MIN) = int32
3098 if (isMax() && constant->isTypeRepresentableAsDouble() &&
3099 constant->numberToDouble() <= INT32_MIN(-2147483647-1)) {
3100 MLimitedTruncate* limit = MLimitedTruncate::New(
3101 alloc, operand->getOperand(0), TruncateKind::NoTruncate);
3102 block()->insertBefore(this, limit);
3103 MToDouble* toDouble = MToDouble::New(alloc, limit);
3104 return toDouble;
3105 }
3106 }
3107
3108 auto foldLength = [](MDefinition* operand, MConstant* constant,
3109 bool isMax) -> MDefinition* {
3110 if ((operand->isArrayLength() || operand->isArrayBufferViewLength() ||
3111 operand->isArgumentsLength() || operand->isStringLength()) &&
3112 constant->type() == MIRType::Int32) {
3113 // (Array|ArrayBufferView|Arguments|String)Length is always >= 0.
3114 // max(array.length, cte <= 0) = array.length
3115 // min(array.length, cte <= 0) = cte
3116 if (constant->toInt32() <= 0) {
3117 return isMax ? operand : constant;
3118 }
3119 }
3120 return nullptr;
3121 };
3122
3123 if (auto* folded = foldLength(operand, constant, isMax())) {
3124 return folded;
3125 }
3126
3127 // Attempt to fold nested min/max operations which are produced by
3128 // self-hosted built-in functions.
3129 if (operand->isMinMax()) {
3130 auto* other = operand->toMinMax();
3131 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"
, 3131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->lhs()->type() == type()"
")"); do { *((volatile int*)__null) = 3131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3132 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"
, 3132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->rhs()->type() == type()"
")"); do { *((volatile int*)__null) = 3132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3133
3134 MConstant* otherConstant = nullptr;
3135 MDefinition* otherOperand = nullptr;
3136 if (other->lhs()->isConstant()) {
3137 otherConstant = other->lhs()->toConstant();
3138 otherOperand = other->rhs();
3139 } else if (other->rhs()->isConstant()) {
3140 otherConstant = other->rhs()->toConstant();
3141 otherOperand = other->lhs();
3142 }
3143
3144 if (otherConstant && constant->isTypeRepresentableAsDouble() &&
3145 otherConstant->isTypeRepresentableAsDouble()) {
3146 if (isMax() == other->isMax()) {
3147 // Fold min(x, min(y, z)) to min(min(x, y), z) with constant min(x, y).
3148 // Fold max(x, max(y, z)) to max(max(x, y), z) with constant max(x, y).
3149 if (auto* left = foldConstants(constant, otherConstant, isMax())) {
3150 block()->insertBefore(this, left);
3151 return MMinMax::New(alloc, left, otherOperand, type(), isMax());
3152 }
3153 } else {
3154 // Fold min(x, max(y, z)) to max(min(x, y), min(x, z)).
3155 // Fold max(x, min(y, z)) to min(max(x, y), max(x, z)).
3156 //
3157 // But only do this when min(x, z) can also be simplified.
3158 if (auto* right = foldLength(otherOperand, constant, isMax())) {
3159 if (auto* left = foldConstants(constant, otherConstant, isMax())) {
3160 block()->insertBefore(this, left);
3161 return MMinMax::New(alloc, left, right, type(), !isMax());
3162 }
3163 }
3164 }
3165 }
3166 }
3167
3168 return this;
3169}
3170
3171#ifdef JS_JITSPEW1
3172void MMinMax::printOpcode(GenericPrinter& out) const {
3173 MDefinition::printOpcode(out);
3174 out.printf(" (%s)", isMax() ? "max" : "min");
3175}
3176
3177void MMinMaxArray::printOpcode(GenericPrinter& out) const {
3178 MDefinition::printOpcode(out);
3179 out.printf(" (%s)", isMax() ? "max" : "min");
3180}
3181#endif
3182
3183MDefinition* MPow::foldsConstant(TempAllocator& alloc) {
3184 // Both `x` and `p` in `x^p` must be constants in order to precompute.
3185 if (!input()->isConstant() || !power()->isConstant()) {
3186 return nullptr;
3187 }
3188 if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
3189 return nullptr;
3190 }
3191 if (!input()->toConstant()->isTypeRepresentableAsDouble()) {
3192 return nullptr;
3193 }
3194
3195 double x = input()->toConstant()->numberToDouble();
3196 double p = power()->toConstant()->numberToDouble();
3197 double result = js::ecmaPow(x, p);
3198 if (type() == MIRType::Int32) {
3199 int32_t cast;
3200 if (!mozilla::NumberIsInt32(result, &cast)) {
3201 // Reject folding if the result isn't an int32, because we'll bail anyway.
3202 return nullptr;
3203 }
3204 return MConstant::New(alloc, Int32Value(cast));
3205 }
3206 return MConstant::New(alloc, DoubleValue(result));
3207}
3208
3209MDefinition* MPow::foldsConstantPower(TempAllocator& alloc) {
3210 // If `p` in `x^p` isn't constant, we can't apply these folds.
3211 if (!power()->isConstant()) {
3212 return nullptr;
3213 }
3214 if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
3215 return nullptr;
3216 }
3217
3218 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"
, 3218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double || type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3218; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3219
3220 // NOTE: The optimizations must match the optimizations used in |js::ecmaPow|
3221 // resp. |js::powi| to avoid differential testing issues.
3222
3223 double pow = power()->toConstant()->numberToDouble();
3224
3225 // Math.pow(x, 0.5) is a sqrt with edge-case detection.
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 return MPowHalf::New(alloc, input());
3229 }
3230
3231 // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
3232 if (pow == -0.5) {
3233 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"
, 3233); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 3233; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3234 MPowHalf* half = MPowHalf::New(alloc, input());
3235 block()->insertBefore(this, half);
3236 MConstant* one = MConstant::New(alloc, DoubleValue(1.0));
3237 block()->insertBefore(this, one);
3238 return MDiv::New(alloc, one, half, MIRType::Double);
3239 }
3240
3241 // Math.pow(x, 1) == x.
3242 if (pow == 1.0) {
3243 return input();
3244 }
3245
3246 auto multiply = [this, &alloc](MDefinition* lhs, MDefinition* rhs) {
3247 MMul* mul = MMul::New(alloc, lhs, rhs, type());
3248 mul->setBailoutKind(bailoutKind());
3249
3250 // Multiplying the same number can't yield negative zero.
3251 mul->setCanBeNegativeZero(lhs != rhs && canBeNegativeZero());
3252 return mul;
3253 };
3254
3255 // Math.pow(x, 2) == x*x.
3256 if (pow == 2.0) {
3257 return multiply(input(), input());
3258 }
3259
3260 // Math.pow(x, 3) == x*x*x.
3261 if (pow == 3.0) {
3262 MMul* mul1 = multiply(input(), input());
3263 block()->insertBefore(this, mul1);
3264 return multiply(input(), mul1);
3265 }
3266
3267 // Math.pow(x, 4) == y*y, where y = x*x.
3268 if (pow == 4.0) {
3269 MMul* y = multiply(input(), input());
3270 block()->insertBefore(this, y);
3271 return multiply(y, y);
3272 }
3273
3274 // Math.pow(x, NaN) == NaN.
3275 if (std::isnan(pow)) {
3276 return power();
3277 }
3278
3279 // No optimization
3280 return nullptr;
3281}
3282
3283MDefinition* MPow::foldsTo(TempAllocator& alloc) {
3284 if (MDefinition* def = foldsConstant(alloc)) {
3285 return def;
3286 }
3287 if (MDefinition* def = foldsConstantPower(alloc)) {
3288 return def;
3289 }
3290 return this;
3291}
3292
3293MDefinition* MBigIntPow::foldsTo(TempAllocator& alloc) {
3294 auto* base = lhs();
3295 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"
, 3295); AnnotateMozCrashReason("MOZ_ASSERT" "(" "base->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 3295; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3296
3297 auto* power = rhs();
3298 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"
, 3298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "power->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 3298; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3299
3300 // |power| must be a constant.
3301 if (!power->isConstant()) {
3302 return this;
3303 }
3304
3305 int32_t pow;
3306 if (BigInt::isInt32(power->toConstant()->toBigInt(), &pow)) {
3307 // x ** 1n == x.
3308 if (pow == 1) {
3309 return base;
3310 }
3311
3312 // x ** 2n == x*x.
3313 if (pow == 2) {
3314 auto* mul = MBigIntMul::New(alloc, base, base);
3315 mul->setBailoutKind(bailoutKind());
3316 return mul;
3317 }
3318 }
3319
3320 // No optimization
3321 return this;
3322}
3323
3324MDefinition* MBigIntAsIntN::foldsTo(TempAllocator& alloc) {
3325 auto* bitsDef = bits();
3326 if (!bitsDef->isConstant()) {
3327 return this;
3328 }
3329
3330 // Negative |bits| throw an error and too large |bits| don't fit into Int64.
3331 int32_t bitsInt = bitsDef->toConstant()->toInt32();
3332 if (bitsInt < 0 || bitsInt > 64) {
3333 return this;
3334 }
3335
3336 // Prefer sign-extension if possible.
3337 bool canSignExtend = false;
3338 switch (bitsInt) {
3339 case 8:
3340 case 16:
3341 case 32:
3342 case 64:
3343 canSignExtend = true;
3344 break;
3345 }
3346
3347 // Ensure the input is either IntPtr or Int64 typed.
3348 auto* inputDef = input();
3349 if (inputDef->isIntPtrToBigInt()) {
3350 inputDef = inputDef->toIntPtrToBigInt()->input();
3351
3352 if (!canSignExtend) {
3353 auto* int64 = MIntPtrToInt64::New(alloc, inputDef);
3354 block()->insertBefore(this, int64);
3355 inputDef = int64;
3356 }
3357 } else if (inputDef->isInt64ToBigInt()) {
3358 inputDef = inputDef->toInt64ToBigInt()->input();
3359 } else {
3360 auto* truncate = MTruncateBigIntToInt64::New(alloc, inputDef);
3361 block()->insertBefore(this, truncate);
3362 inputDef = truncate;
3363 }
3364
3365 if (inputDef->type() == MIRType::IntPtr) {
3366 MOZ_ASSERT(canSignExtend)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(canSignExtend)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(canSignExtend))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("canSignExtend",
"/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3366); AnnotateMozCrashReason("MOZ_ASSERT" "(" "canSignExtend"
")"); do { *((volatile int*)__null) = 3366; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3367
3368 // If |bits| is larger-or-equal to |BigInt::DigitBits|, return the input.
3369 if (size_t(bitsInt) >= BigInt::DigitBits) {
3370 auto* limited = MIntPtrLimitedTruncate::New(alloc, inputDef);
3371 block()->insertBefore(this, limited);
3372 inputDef = limited;
3373 } else {
3374 MOZ_ASSERT(bitsInt < 64)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bitsInt < 64)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bitsInt < 64))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("bitsInt < 64"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3374); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bitsInt < 64"
")"); do { *((volatile int*)__null) = 3374; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3375
3376 // Otherwise extension is the way to go.
3377 MSignExtendIntPtr::Mode mode;
3378 switch (bitsInt) {
3379 case 8:
3380 mode = MSignExtendIntPtr::Byte;
3381 break;
3382 case 16:
3383 mode = MSignExtendIntPtr::Half;
3384 break;
3385 case 32:
3386 mode = MSignExtendIntPtr::Word;
3387 break;
3388 }
3389
3390 auto* extend = MSignExtendIntPtr::New(alloc, inputDef, mode);
3391 block()->insertBefore(this, extend);
3392 inputDef = extend;
3393 }
3394
3395 return MIntPtrToBigInt::New(alloc, inputDef);
3396 }
3397 MOZ_ASSERT(inputDef->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inputDef->type() == MIRType::Int64)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(inputDef->type() == MIRType::Int64))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("inputDef->type() == MIRType::Int64"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3397); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputDef->type() == MIRType::Int64"
")"); do { *((volatile int*)__null) = 3397; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3398
3399 if (canSignExtend) {
3400 // If |bits| is equal to 64, return the input.
3401 if (bitsInt == 64) {
3402 auto* limited = MInt64LimitedTruncate::New(alloc, inputDef);
3403 block()->insertBefore(this, limited);
3404 inputDef = limited;
3405 } else {
3406 MOZ_ASSERT(bitsInt < 64)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bitsInt < 64)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bitsInt < 64))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("bitsInt < 64"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3406); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bitsInt < 64"
")"); do { *((volatile int*)__null) = 3406; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3407
3408 // Otherwise extension is the way to go.
3409 MSignExtendInt64::Mode mode;
3410 switch (bitsInt) {
3411 case 8:
3412 mode = MSignExtendInt64::Byte;
3413 break;
3414 case 16:
3415 mode = MSignExtendInt64::Half;
3416 break;
3417 case 32:
3418 mode = MSignExtendInt64::Word;
3419 break;
3420 }
3421
3422 auto* extend = MSignExtendInt64::New(alloc, inputDef, mode);
3423 block()->insertBefore(this, extend);
3424 inputDef = extend;
3425 }
3426 } else {
3427 MOZ_ASSERT(bitsInt < 64)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bitsInt < 64)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bitsInt < 64))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("bitsInt < 64"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3427); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bitsInt < 64"
")"); do { *((volatile int*)__null) = 3427; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3428
3429 uint64_t mask = 0;
3430 if (bitsInt > 0) {
3431 mask = uint64_t(-1) >> (64 - bitsInt);
3432 }
3433
3434 auto* cst = MConstant::NewInt64(alloc, int64_t(mask));
3435 block()->insertBefore(this, cst);
3436
3437 // Mask off any excess bits.
3438 auto* bitAnd = MBitAnd::New(alloc, inputDef, cst, MIRType::Int64);
3439 block()->insertBefore(this, bitAnd);
3440
3441 auto* shift = MConstant::NewInt64(alloc, int64_t(64 - bitsInt));
3442 block()->insertBefore(this, shift);
3443
3444 // Left-shift to make the sign-bit the left-most bit.
3445 auto* lsh = MLsh::New(alloc, bitAnd, shift, MIRType::Int64);
3446 block()->insertBefore(this, lsh);
3447
3448 // Right-shift to propagate the sign-bit.
3449 auto* rsh = MRsh::New(alloc, lsh, shift, MIRType::Int64);
3450 block()->insertBefore(this, rsh);
3451
3452 inputDef = rsh;
3453 }
3454
3455 return MInt64ToBigInt::New(alloc, inputDef, /* isSigned = */ true);
3456}
3457
3458MDefinition* MBigIntAsUintN::foldsTo(TempAllocator& alloc) {
3459 auto* bitsDef = bits();
3460 if (!bitsDef->isConstant()) {
3461 return this;
3462 }
3463
3464 // Negative |bits| throw an error and too large |bits| don't fit into Int64.
3465 int32_t bitsInt = bitsDef->toConstant()->toInt32();
3466 if (bitsInt < 0 || bitsInt > 64) {
3467 return this;
3468 }
3469
3470 // Ensure the input is Int64 typed.
3471 auto* inputDef = input();
3472 if (inputDef->isIntPtrToBigInt()) {
3473 inputDef = inputDef->toIntPtrToBigInt()->input();
3474
3475 auto* int64 = MIntPtrToInt64::New(alloc, inputDef);
3476 block()->insertBefore(this, int64);
3477 inputDef = int64;
3478 } else if (inputDef->isInt64ToBigInt()) {
3479 inputDef = inputDef->toInt64ToBigInt()->input();
3480 } else {
3481 auto* truncate = MTruncateBigIntToInt64::New(alloc, inputDef);
3482 block()->insertBefore(this, truncate);
3483 inputDef = truncate;
3484 }
3485 MOZ_ASSERT(inputDef->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(inputDef->type() == MIRType::Int64)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(inputDef->type() == MIRType::Int64))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("inputDef->type() == MIRType::Int64"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 3485); AnnotateMozCrashReason("MOZ_ASSERT" "(" "inputDef->type() == MIRType::Int64"
")"); do { *((volatile int*)__null) = 3485; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3486
3487 if (bitsInt < 64) {
3488 uint64_t mask = 0;
3489 if (bitsInt > 0) {
3490 mask = uint64_t(-1) >> (64 - bitsInt);
3491 }
3492
3493 // Mask off any excess bits.
3494 auto* cst = MConstant::NewInt64(alloc, int64_t(mask));
3495 block()->insertBefore(this, cst);
3496
3497 auto* bitAnd = MBitAnd::New(alloc, inputDef, cst, MIRType::Int64);
3498 block()->insertBefore(this, bitAnd);
3499
3500 inputDef = bitAnd;
3501 }
3502
3503 return MInt64ToBigInt::New(alloc, inputDef, /* isSigned = */ false);
3504}
3505
3506bool MBigIntPtrBinaryArithInstruction::isMaybeZero(MDefinition* ins) {
3507 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"
, 3507); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::IntPtr"
")"); do { *((volatile int*)__null) = 3507; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3508 if (ins->isBigIntToIntPtr()) {
3509 ins = ins->toBigIntToIntPtr()->input();
3510 }
3511 if (ins->isConstant()) {
3512 if (ins->type() == MIRType::IntPtr) {
3513 return ins->toConstant()->toIntPtr() == 0;
3514 }
3515 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"
, 3515); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 3515; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3516 return ins->toConstant()->toBigInt()->isZero();
3517 }
3518 return true;
3519}
3520
3521bool MBigIntPtrBinaryArithInstruction::isMaybeNegative(MDefinition* ins) {
3522 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"
, 3522); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::IntPtr"
")"); do { *((volatile int*)__null) = 3522; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3523 if (ins->isBigIntToIntPtr()) {
3524 ins = ins->toBigIntToIntPtr()->input();
3525 }
3526 if (ins->isConstant()) {
3527 if (ins->type() == MIRType::IntPtr) {
3528 return ins->toConstant()->toIntPtr() < 0;
3529 }
3530 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"
, 3530); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 3530; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3531 return ins->toConstant()->toBigInt()->isNegative();
3532 }
3533 return true;
3534}
3535
3536MDefinition* MInt32ToIntPtr::foldsTo(TempAllocator& alloc) {
3537 MDefinition* def = input();
3538 if (def->isConstant()) {
3539 int32_t i = def->toConstant()->toInt32();
3540 return MConstant::NewIntPtr(alloc, intptr_t(i));
3541 }
3542
3543 if (def->isNonNegativeIntPtrToInt32()) {
3544 return def->toNonNegativeIntPtrToInt32()->input();
3545 }
3546
3547 return this;
3548}
3549
3550bool MAbs::fallible() const {
3551 return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds());
3552}
3553
3554void MAbs::trySpecializeFloat32(TempAllocator& alloc) {
3555 // Do not use Float32 if we can use int32.
3556 if (input()->type() == MIRType::Int32) {
3557 return;
3558 }
3559
3560 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
3561 setResultType(MIRType::Float32);
3562 }
3563}
3564
3565MDefinition* MDiv::foldsTo(TempAllocator& alloc) {
3566 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"
, 3566); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 3566; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3567
3568 if (type() == MIRType::Int64) {
3569 if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
3570 return folded;
3571 }
3572 return this;
3573 }
3574
3575 if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
3576 return folded;
3577 }
3578
3579 if (MDefinition* folded = EvaluateExactReciprocal(alloc, this)) {
3580 return folded;
3581 }
3582
3583 return this;
3584}
3585
3586void MDiv::analyzeEdgeCasesForward() {
3587 // This is only meaningful when doing integer division.
3588 if (type() != MIRType::Int32) {
3589 return;
3590 }
3591
3592 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"
, 3592); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3592; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3593 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"
, 3593); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3593; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3594
3595 // Try removing divide by zero check
3596 if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
3597 canBeDivideByZero_ = false;
3598 }
3599
3600 // If lhs is a constant int != INT32_MIN, then
3601 // negative overflow check can be skipped.
3602 if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(INT32_MIN(-2147483647-1))) {
3603 canBeNegativeOverflow_ = false;
3604 }
3605
3606 // If rhs is a constant int != -1, likewise.
3607 if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(-1)) {
3608 canBeNegativeOverflow_ = false;
3609 }
3610
3611 // If lhs is != 0, then negative zero check can be skipped.
3612 if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(0)) {
3613 setCanBeNegativeZero(false);
3614 }
3615
3616 // If rhs is >= 0, likewise.
3617 if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
3618 if (rhs()->toConstant()->toInt32() >= 0) {
3619 setCanBeNegativeZero(false);
3620 }
3621 }
3622}
3623
3624void MDiv::analyzeEdgeCasesBackward() {
3625 // In general, canBeNegativeZero_ is only valid for integer divides.
3626 // It's fine to access here because we're only using it to avoid
3627 // wasting effort to decide whether we can clear an already cleared
3628 // flag.
3629 if (canBeNegativeZero_ && !NeedNegativeZeroCheck(this)) {
3630 setCanBeNegativeZero(false);
3631 }
3632}
3633
3634bool MDiv::fallible() const { return !isTruncated(); }
3635
3636MDefinition* MMod::foldsTo(TempAllocator& alloc) {
3637 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"
, 3637); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 3637; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3638
3639 if (type() == MIRType::Int64) {
3640 if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
3641 return folded;
3642 }
3643 } else {
3644 if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
3645 return folded;
3646 }
3647 }
3648 return this;
3649}
3650
3651void MMod::analyzeEdgeCasesForward() {
3652 // These optimizations make sense only for integer division
3653 if (type() != MIRType::Int32) {
3654 return;
3655 }
3656
3657 if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
3658 canBeDivideByZero_ = false;
3659 }
3660
3661 if (rhs()->isConstant()) {
3662 int32_t n = rhs()->toConstant()->toInt32();
3663 if (n > 0 && !IsPowerOfTwo(uint32_t(n))) {
3664 canBePowerOfTwoDivisor_ = false;
3665 }
3666 }
3667}
3668
3669bool MMod::fallible() const {
3670 return !isTruncated() &&
3671 (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend());
3672}
3673
3674void MMathFunction::trySpecializeFloat32(TempAllocator& alloc) {
3675 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
3676 setResultType(MIRType::Float32);
3677 specialization_ = MIRType::Float32;
3678 }
3679}
3680
3681bool MMathFunction::isFloat32Commutative() const {
3682 switch (function_) {
3683 case UnaryMathFunction::Floor:
3684 case UnaryMathFunction::Ceil:
3685 case UnaryMathFunction::Round:
3686 case UnaryMathFunction::Trunc:
3687 return true;
3688 default:
3689 return false;
3690 }
3691}
3692
3693MHypot* MHypot::New(TempAllocator& alloc, const MDefinitionVector& vector) {
3694 uint32_t length = vector.length();
3695 MHypot* hypot = new (alloc) MHypot;
3696 if (!hypot->init(alloc, length)) {
3697 return nullptr;
3698 }
3699
3700 for (uint32_t i = 0; i < length; ++i) {
3701 hypot->initOperand(i, vector[i]);
3702 }
3703 return hypot;
3704}
3705
3706bool MAdd::fallible() const {
3707 // the add is fallible if range analysis does not say that it is finite, AND
3708 // either the truncation analysis shows that there are non-truncated uses.
3709 if (truncateKind() >= TruncateKind::IndirectTruncate) {
3710 return false;
3711 }
3712 if (range() && range()->hasInt32Bounds()) {
3713 return false;
3714 }
3715 return true;
3716}
3717
3718bool MSub::fallible() const {
3719 // see comment in MAdd::fallible()
3720 if (truncateKind() >= TruncateKind::IndirectTruncate) {
3721 return false;
3722 }
3723 if (range() && range()->hasInt32Bounds()) {
3724 return false;
3725 }
3726 return true;
3727}
3728
3729MDefinition* MSub::foldsTo(TempAllocator& alloc) {
3730 MDefinition* out = MBinaryArithInstruction::foldsTo(alloc);
3731 if (out != this) {
3732 return out;
3733 }
3734
3735 if (type() != MIRType::Int32) {
3736 return this;
3737 }
3738
3739 // Optimize X - X to 0. This optimization is only valid for Int32
3740 // values. Subtracting a floating point value from itself returns
3741 // NaN when the operand is either Infinity or NaN.
3742 if (lhs() == rhs()) {
3743 // Ensure that any bailouts that we depend on to guarantee that X
3744 // is Int32 are not removed.
3745 lhs()->setGuardRangeBailoutsUnchecked();
3746 return MConstant::New(alloc, Int32Value(0));
3747 }
3748
3749 return this;
3750}
3751
3752MDefinition* MMul::foldsTo(TempAllocator& alloc) {
3753 MDefinition* out = MBinaryArithInstruction::foldsTo(alloc);
3754 if (out != this) {
3755 return out;
3756 }
3757
3758 if (type() != MIRType::Int32) {
3759 return this;
3760 }
3761
3762 if (lhs() == rhs()) {
3763 setCanBeNegativeZero(false);
3764 }
3765
3766 return this;
3767}
3768
3769void MMul::analyzeEdgeCasesForward() {
3770 // Try to remove the check for negative zero
3771 // This only makes sense when using the integer multiplication
3772 if (type() != MIRType::Int32) {
3773 return;
3774 }
3775
3776 // If lhs is > 0, no need for negative zero check.
3777 if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) {
3778 if (lhs()->toConstant()->toInt32() > 0) {
3779 setCanBeNegativeZero(false);
3780 }
3781 }
3782
3783 // If rhs is > 0, likewise.
3784 if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
3785 if (rhs()->toConstant()->toInt32() > 0) {
3786 setCanBeNegativeZero(false);
3787 }
3788 }
3789}
3790
3791void MMul::analyzeEdgeCasesBackward() {
3792 if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) {
3793 setCanBeNegativeZero(false);
3794 }
3795}
3796
3797bool MMul::canOverflow() const {
3798 if (isTruncated()) {
3799 return false;
3800 }
3801 return !range() || !range()->hasInt32Bounds();
3802}
3803
3804bool MUrsh::fallible() const {
3805 if (bailoutsDisabled()) {
3806 return false;
3807 }
3808 return !range() || !range()->hasInt32Bounds();
3809}
3810
3811MIRType MCompare::inputType() {
3812 switch (compareType_) {
3813 case Compare_Undefined:
3814 return MIRType::Undefined;
3815 case Compare_Null:
3816 return MIRType::Null;
3817 case Compare_UInt32:
3818 case Compare_Int32:
3819 return MIRType::Int32;
3820 case Compare_IntPtr:
3821 case Compare_UIntPtr:
3822 return MIRType::IntPtr;
3823 case Compare_Double:
3824 return MIRType::Double;
3825 case Compare_Float32:
3826 return MIRType::Float32;
3827 case Compare_String:
3828 return MIRType::String;
3829 case Compare_Symbol:
3830 return MIRType::Symbol;
3831 case Compare_Object:
3832 return MIRType::Object;
3833 case Compare_BigInt:
3834 case Compare_BigInt_Int32:
3835 case Compare_BigInt_Double:
3836 case Compare_BigInt_String:
3837 return MIRType::BigInt;
3838 default:
3839 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"
, 3839); AnnotateMozCrashReason("MOZ_CRASH(" "No known conversion"
")"); do { *((volatile int*)__null) = 3839; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3840 }
3841}
3842
3843static inline bool MustBeUInt32(MDefinition* def, MDefinition** pwrapped) {
3844 if (def->isUrsh()) {
3845 *pwrapped = def->toUrsh()->lhs();
3846 MDefinition* rhs = def->toUrsh()->rhs();
3847 return def->toUrsh()->bailoutsDisabled() && rhs->maybeConstantValue() &&
3848 rhs->maybeConstantValue()->isInt32(0);
3849 }
3850
3851 if (MConstant* defConst = def->maybeConstantValue()) {
3852 *pwrapped = defConst;
3853 return defConst->type() == MIRType::Int32 && defConst->toInt32() >= 0;
3854 }
3855
3856 *pwrapped = nullptr; // silence GCC warning
3857 return false;
3858}
3859
3860/* static */
3861bool MBinaryInstruction::unsignedOperands(MDefinition* left,
3862 MDefinition* right) {
3863 MDefinition* replace;
3864 if (!MustBeUInt32(left, &replace)) {
3865 return false;
3866 }
3867 if (replace->type() != MIRType::Int32) {
3868 return false;
3869 }
3870 if (!MustBeUInt32(right, &replace)) {
3871 return false;
3872 }
3873 if (replace->type() != MIRType::Int32) {
3874 return false;
3875 }
3876 return true;
3877}
3878
3879bool MBinaryInstruction::unsignedOperands() {
3880 return unsignedOperands(getOperand(0), getOperand(1));
3881}
3882
3883void MBinaryInstruction::replaceWithUnsignedOperands() {
3884 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"
, 3884); AnnotateMozCrashReason("MOZ_ASSERT" "(" "unsignedOperands()"
")"); do { *((volatile int*)__null) = 3884; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3885
3886 for (size_t i = 0; i < numOperands(); i++) {
3887 MDefinition* replace;
3888 MustBeUInt32(getOperand(i), &replace);
3889 if (replace == getOperand(i)) {
3890 continue;
3891 }
3892
3893 getOperand(i)->setImplicitlyUsedUnchecked();
3894 replaceOperand(i, replace);
3895 }
3896}
3897
3898MDefinition* MBitNot::foldsTo(TempAllocator& alloc) {
3899 if (type() == MIRType::Int64) {
3900 return this;
3901 }
3902 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"
, 3902); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3902; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3903
3904 MDefinition* input = getOperand(0);
3905
3906 if (input->isConstant()) {
3907 js::Value v = Int32Value(~(input->toConstant()->toInt32()));
3908 return MConstant::New(alloc, v);
3909 }
3910
3911 if (input->isBitNot()) {
3912 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"
, 3912); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3912; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3913 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"
, 3913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->getOperand(0)->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3913; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3914 return MTruncateToInt32::New(alloc,
3915 input->toBitNot()->input()); // ~~x => x | 0
3916 }
3917
3918 return this;
3919}
3920
3921static void AssertKnownClass(TempAllocator& alloc, MInstruction* ins,
3922 MDefinition* obj) {
3923#ifdef DEBUG1
3924 const JSClass* clasp = GetObjectKnownJSClass(obj);
3925 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"
, 3925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "clasp" ")")
; do { *((volatile int*)__null) = 3925; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3926
3927 auto* assert = MAssertClass::New(alloc, obj, clasp);
3928 ins->block()->insertBefore(ins, assert);
3929#endif
3930}
3931
3932MDefinition* MBoxNonStrictThis::foldsTo(TempAllocator& alloc) {
3933 MDefinition* in = input();
3934 if (in->isBox()) {
3935 in = in->toBox()->input();
3936 }
3937
3938 if (in->type() == MIRType::Object) {
3939 return in;
3940 }
3941
3942 return this;
3943}
3944
3945AliasSet MLoadArgumentsObjectArg::getAliasSet() const {
3946 return AliasSet::Load(AliasSet::Any);
3947}
3948
3949AliasSet MLoadArgumentsObjectArgHole::getAliasSet() const {
3950 return AliasSet::Load(AliasSet::Any);
3951}
3952
3953AliasSet MInArgumentsObjectArg::getAliasSet() const {
3954 // Loads |arguments.length|, but not the actual element, so we can use the
3955 // same alias-set as MArgumentsObjectLength.
3956 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
3957 AliasSet::DynamicSlot);
3958}
3959
3960AliasSet MArgumentsObjectLength::getAliasSet() const {
3961 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
3962 AliasSet::DynamicSlot);
3963}
3964
3965bool MGuardArgumentsObjectFlags::congruentTo(const MDefinition* ins) const {
3966 if (!ins->isGuardArgumentsObjectFlags() ||
3967 ins->toGuardArgumentsObjectFlags()->flags() != flags()) {
3968 return false;
3969 }
3970 return congruentIfOperandsEqual(ins);
3971}
3972
3973AliasSet MGuardArgumentsObjectFlags::getAliasSet() const {
3974 // The flags are packed with the length in a fixed private slot.
3975 return AliasSet::Load(AliasSet::FixedSlot);
3976}
3977
3978MDefinition* MIdToStringOrSymbol::foldsTo(TempAllocator& alloc) {
3979 if (idVal()->isBox()) {
3980 auto* input = idVal()->toBox()->input();
3981 MIRType idType = input->type();
3982 if (idType == MIRType::String || idType == MIRType::Symbol) {
3983 return idVal();
3984 }
3985 if (idType == MIRType::Int32) {
3986 auto* toString =
3987 MToString::New(alloc, input, MToString::SideEffectHandling::Bailout);
3988 block()->insertBefore(this, toString);
3989
3990 return MBox::New(alloc, toString);
3991 }
3992 }
3993
3994 return this;
3995}
3996
3997MDefinition* MReturnFromCtor::foldsTo(TempAllocator& alloc) {
3998 MDefinition* rval = value();
3999 if (rval->isBox()) {
4000 rval = rval->toBox()->input();
4001 }
4002
4003 if (rval->type() == MIRType::Object) {
4004 return rval;
4005 }
4006
4007 if (rval->type() != MIRType::Value) {
4008 return object();
4009 }
4010
4011 return this;
4012}
4013
4014MDefinition* MTypeOf::foldsTo(TempAllocator& alloc) {
4015 MDefinition* unboxed = input();
4016 if (unboxed->isBox()) {
4017 unboxed = unboxed->toBox()->input();
4018 }
4019
4020 JSType type;
4021 switch (unboxed->type()) {
4022 case MIRType::Double:
4023 case MIRType::Float32:
4024 case MIRType::Int32:
4025 type = JSTYPE_NUMBER;
4026 break;
4027 case MIRType::String:
4028 type = JSTYPE_STRING;
4029 break;
4030 case MIRType::Symbol:
4031 type = JSTYPE_SYMBOL;
4032 break;
4033 case MIRType::BigInt:
4034 type = JSTYPE_BIGINT;
4035 break;
4036 case MIRType::Null:
4037 type = JSTYPE_OBJECT;
4038 break;
4039 case MIRType::Undefined:
4040 type = JSTYPE_UNDEFINED;
4041 break;
4042 case MIRType::Boolean:
4043 type = JSTYPE_BOOLEAN;
4044 break;
4045 case MIRType::Object: {
4046 KnownClass known = GetObjectKnownClass(unboxed);
4047 if (known != KnownClass::None) {
4048 if (known == KnownClass::Function) {
4049 type = JSTYPE_FUNCTION;
4050 } else {
4051 type = JSTYPE_OBJECT;
4052 }
4053
4054 AssertKnownClass(alloc, this, unboxed);
4055 break;
4056 }
4057 [[fallthrough]];
4058 }
4059 default:
4060 return this;
4061 }
4062
4063 return MConstant::New(alloc, Int32Value(static_cast<int32_t>(type)));
4064}
4065
4066MDefinition* MTypeOfName::foldsTo(TempAllocator& alloc) {
4067 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"
, 4067); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 4067; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4068
4069 if (!input()->isConstant()) {
4070 return this;
4071 }
4072
4073 static_assert(JSTYPE_UNDEFINED == 0);
4074
4075 int32_t type = input()->toConstant()->toInt32();
4076 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"
, 4076); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT"
")"); do { *((volatile int*)__null) = 4076; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4077
4078 JSString* name =
4079 TypeName(static_cast<JSType>(type), GetJitContext()->runtime->names());
4080 return MConstant::New(alloc, StringValue(name));
4081}
4082
4083MUrsh* MUrsh::NewWasm(TempAllocator& alloc, MDefinition* left,
4084 MDefinition* right, MIRType type) {
4085 MUrsh* ins = new (alloc) MUrsh(left, right, type);
4086
4087 // Since Ion has no UInt32 type, we use Int32 and we have a special
4088 // exception to the type rules: we can return values in
4089 // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type
4090 // without bailing out. This is necessary because Ion has no UInt32
4091 // type and we can't have bailouts in wasm code.
4092 ins->bailoutsDisabled_ = true;
4093
4094 return ins;
4095}
4096
4097MResumePoint* MResumePoint::New(TempAllocator& alloc, MBasicBlock* block,
4098 jsbytecode* pc, ResumeMode mode) {
4099 MResumePoint* resume = new (alloc) MResumePoint(block, pc, mode);
4100 if (!resume->init(alloc)) {
4101 block->discardPreAllocatedResumePoint(resume);
4102 return nullptr;
4103 }
4104 resume->inherit(block);
4105 return resume;
4106}
4107
4108MResumePoint::MResumePoint(MBasicBlock* block, jsbytecode* pc, ResumeMode mode)
4109 : MNode(block, Kind::ResumePoint),
4110 pc_(pc),
4111 instruction_(nullptr),
4112 mode_(mode) {
4113 block->addResumePoint(this);
4114}
4115
4116bool MResumePoint::init(TempAllocator& alloc) {
4117 return operands_.init(alloc, block()->stackDepth());
4118}
4119
4120MResumePoint* MResumePoint::caller() const {
4121 return block()->callerResumePoint();
4122}
4123
4124void MResumePoint::inherit(MBasicBlock* block) {
4125 // FixedList doesn't initialize its elements, so do unchecked inits.
4126 for (size_t i = 0; i < stackDepth(); i++) {
4127 initOperand(i, block->getSlot(i));
4128 }
4129}
4130
4131void MResumePoint::addStore(TempAllocator& alloc, MDefinition* store,
4132 const MResumePoint* cache) {
4133 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"
, 4133); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->outerResumePoint() != this"
")"); do { *((volatile int*)__null) = 4133; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4134 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"
, 4134); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!cache->stores_.empty()"
")"); do { *((volatile int*)__null) = 4134; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4135
4136 if (cache && cache->stores_.begin()->operand == store) {
4137 // If the last resume point had the same side-effect stack, then we can
4138 // reuse the current side effect without cloning it. This is a simple
4139 // way to share common context by making a spaghetti stack.
4140 if (++cache->stores_.begin() == stores_.begin()) {
4141 stores_.copy(cache->stores_);
4142 return;
4143 }
4144 }
4145
4146 // Ensure that the store would not be deleted by DCE.
4147 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"
, 4147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "store->isEffectful()"
")"); do { *((volatile int*)__null) = 4147; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4148
4149 MStoreToRecover* top = new (alloc) MStoreToRecover(store);
4150 stores_.push(top);
4151}
4152
4153#ifdef JS_JITSPEW1
4154void MResumePoint::dump(GenericPrinter& out) const {
4155 out.printf("resumepoint mode=");
4156
4157 switch (mode()) {
4158 case ResumeMode::ResumeAt:
4159 if (instruction_) {
4160 out.printf("ResumeAt(%u)", instruction_->id());
4161 } else {
4162 out.printf("ResumeAt");
4163 }
4164 break;
4165 default:
4166 out.put(ResumeModeToString(mode()));
4167 break;
4168 }
4169
4170 if (MResumePoint* c = caller()) {
4171 out.printf(" (caller in block%u)", c->block()->id());
4172 }
4173
4174 for (size_t i = 0; i < numOperands(); i++) {
4175 out.printf(" ");
4176 if (operands_[i].hasProducer()) {
4177 getOperand(i)->printName(out);
4178 } else {
4179 out.printf("(null)");
4180 }
4181 }
4182 out.printf("\n");
4183}
4184
4185void MResumePoint::dump() const {
4186 Fprinter out(stderrstderr);
4187 dump(out);
4188 out.finish();
4189}
4190#endif
4191
4192bool MResumePoint::isObservableOperand(MUse* u) const {
4193 return isObservableOperand(indexOf(u));
4194}
4195
4196bool MResumePoint::isObservableOperand(size_t index) const {
4197 return block()->info().isObservableSlot(index);
4198}
4199
4200bool MResumePoint::isRecoverableOperand(MUse* u) const {
4201 return block()->info().isRecoverableOperand(indexOf(u));
4202}
4203
4204MDefinition* MBigIntToIntPtr::foldsTo(TempAllocator& alloc) {
4205 MDefinition* def = input();
4206
4207 // If the operand converts an IntPtr to BigInt, drop both conversions.
4208 if (def->isIntPtrToBigInt()) {
4209 return def->toIntPtrToBigInt()->input();
4210 }
4211
4212 // Fold this operation if the input operand is constant.
4213 if (def->isConstant()) {
4214 BigInt* bigInt = def->toConstant()->toBigInt();
4215 intptr_t i;
4216 if (BigInt::isIntPtr(bigInt, &i)) {
4217 return MConstant::NewIntPtr(alloc, i);
4218 }
4219 }
4220
4221 // Fold BigIntToIntPtr(Int64ToBigInt(int64)) to Int64ToIntPtr(int64)
4222 if (def->isInt64ToBigInt()) {
4223 auto* toBigInt = def->toInt64ToBigInt();
4224 return MInt64ToIntPtr::New(alloc, toBigInt->input(), toBigInt->isSigned());
4225 }
4226
4227 return this;
4228}
4229
4230MDefinition* MIntPtrToBigInt::foldsTo(TempAllocator& alloc) {
4231 MDefinition* def = input();
4232
4233 // If the operand converts a BigInt to IntPtr, drop both conversions.
4234 if (def->isBigIntToIntPtr()) {
4235 return def->toBigIntToIntPtr()->input();
4236 }
4237
4238 return this;
4239}
4240
4241MDefinition* MTruncateBigIntToInt64::foldsTo(TempAllocator& alloc) {
4242 MDefinition* input = getOperand(0);
4243
4244 if (input->isBox()) {
4245 input = input->getOperand(0);
4246 }
4247
4248 // If the operand converts an I64 to BigInt, drop both conversions.
4249 if (input->isInt64ToBigInt()) {
4250 return input->getOperand(0);
4251 }
4252
4253 // If the operand is an IntPtr, extend the IntPtr to I64.
4254 if (input->isIntPtrToBigInt()) {
4255 auto* intPtr = input->toIntPtrToBigInt()->input();
4256 if (intPtr->isConstant()) {
4257 intptr_t c = intPtr->toConstant()->toIntPtr();
4258 return MConstant::NewInt64(alloc, int64_t(c));
4259 }
4260 return MIntPtrToInt64::New(alloc, intPtr);
4261 }
4262
4263 // Fold this operation if the input operand is constant.
4264 if (input->isConstant()) {
4265 return MConstant::NewInt64(
4266 alloc, BigInt::toInt64(input->toConstant()->toBigInt()));
4267 }
4268
4269 return this;
4270}
4271
4272MDefinition* MToInt64::foldsTo(TempAllocator& alloc) {
4273 MDefinition* input = getOperand(0);
4274
4275 if (input->isBox()) {
4276 input = input->getOperand(0);
4277 }
4278
4279 // Unwrap MInt64ToBigInt: MToInt64(MInt64ToBigInt(int64)) = int64.
4280 if (input->isInt64ToBigInt()) {
4281 return input->getOperand(0);
4282 }
4283
4284 // Unwrap IntPtrToBigInt:
4285 // MToInt64(MIntPtrToBigInt(intptr)) = MIntPtrToInt64(intptr).
4286 if (input->isIntPtrToBigInt()) {
4287 auto* intPtr = input->toIntPtrToBigInt()->input();
4288 if (intPtr->isConstant()) {
4289 intptr_t c = intPtr->toConstant()->toIntPtr();
4290 return MConstant::NewInt64(alloc, int64_t(c));
4291 }
4292 return MIntPtrToInt64::New(alloc, intPtr);
4293 }
4294
4295 // When the input is an Int64 already, just return it.
4296 if (input->type() == MIRType::Int64) {
4297 return input;
4298 }
4299
4300 // Fold this operation if the input operand is constant.
4301 if (input->isConstant()) {
4302 switch (input->type()) {
4303 case MIRType::Boolean:
4304 return MConstant::NewInt64(alloc, input->toConstant()->toBoolean());
4305 default:
4306 break;
4307 }
4308 }
4309
4310 return this;
4311}
4312
4313MDefinition* MToNumberInt32::foldsTo(TempAllocator& alloc) {
4314 // Fold this operation if the input operand is constant.
4315 if (MConstant* cst = input()->maybeConstantValue()) {
4316 switch (cst->type()) {
4317 case MIRType::Null:
4318 if (conversion() == IntConversionInputKind::Any) {
4319 return MConstant::New(alloc, Int32Value(0));
4320 }
4321 break;
4322 case MIRType::Boolean:
4323 if (conversion() == IntConversionInputKind::Any) {
4324 return MConstant::New(alloc, Int32Value(cst->toBoolean()));
4325 }
4326 break;
4327 case MIRType::Int32:
4328 return MConstant::New(alloc, Int32Value(cst->toInt32()));
4329 case MIRType::Float32:
4330 case MIRType::Double:
4331 int32_t ival;
4332 // Only the value within the range of Int32 can be substituted as
4333 // constant.
4334 if (mozilla::NumberIsInt32(cst->numberToDouble(), &ival)) {
4335 return MConstant::New(alloc, Int32Value(ival));
4336 }
4337 break;
4338 default:
4339 break;
4340 }
4341 }
4342
4343 MDefinition* input = getOperand(0);
4344 if (input->isBox()) {
4345 input = input->toBox()->input();
4346 }
4347
4348 // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
4349 // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
4350 // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
4351 // is folded to a MTruncateToInt32 node, which will result in this MIR:
4352 // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
4353 // the MUrsh node's type is int32 (since uint32 is not implemented), and
4354 // that would fold the MTruncateToInt32 node. This will make the modulo
4355 // unsigned, while is should have been signed.
4356 if (input->type() == MIRType::Int32 && !IsUint32Type(input)) {
4357 return input;
4358 }
4359
4360 return this;
4361}
4362
4363MDefinition* MBooleanToInt32::foldsTo(TempAllocator& alloc) {
4364 MDefinition* input = getOperand(0);
4365 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"
, 4365); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 4365; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4366
4367 if (input->isConstant()) {
4368 return MConstant::New(alloc, Int32Value(input->toConstant()->toBoolean()));
4369 }
4370
4371 return this;
4372}
4373
4374void MToNumberInt32::analyzeEdgeCasesBackward() {
4375 if (!NeedNegativeZeroCheck(this)) {
4376 setNeedsNegativeZeroCheck(false);
4377 }
4378}
4379
4380MDefinition* MTruncateToInt32::foldsTo(TempAllocator& alloc) {
4381 MDefinition* input = getOperand(0);
4382 if (input->isBox()) {
4383 input = input->getOperand(0);
4384 }
4385
4386 // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
4387 // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
4388 // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
4389 // is folded to a MTruncateToInt32 node, which will result in this MIR:
4390 // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
4391 // the MUrsh node's type is int32 (since uint32 is not implemented), and
4392 // that would fold the MTruncateToInt32 node. This will make the modulo
4393 // unsigned, while is should have been signed.
4394 if (input->type() == MIRType::Int32 && !IsUint32Type(input)) {
4395 return input;
4396 }
4397
4398 if (input->type() == MIRType::Double && input->isConstant()) {
4399 int32_t ret = ToInt32(input->toConstant()->toDouble());
4400 return MConstant::New(alloc, Int32Value(ret));
4401 }
4402
4403 return this;
4404}
4405
4406MDefinition* MWrapInt64ToInt32::foldsTo(TempAllocator& alloc) {
4407 MDefinition* input = this->input();
4408 if (input->isConstant()) {
4409 uint64_t c = input->toConstant()->toInt64();
4410 int32_t output = bottomHalf() ? int32_t(c) : int32_t(c >> 32);
4411 return MConstant::New(alloc, Int32Value(output));
4412 }
4413
4414 return this;
4415}
4416
4417MDefinition* MExtendInt32ToInt64::foldsTo(TempAllocator& alloc) {
4418 MDefinition* input = this->input();
4419 if (input->isConstant()) {
4420 int32_t c = input->toConstant()->toInt32();
4421 int64_t res = isUnsigned() ? int64_t(uint32_t(c)) : int64_t(c);
4422 return MConstant::NewInt64(alloc, res);
4423 }
4424
4425 return this;
4426}
4427
4428MDefinition* MSignExtendInt32::foldsTo(TempAllocator& alloc) {
4429 MDefinition* input = this->input();
4430 if (input->isConstant()) {
4431 int32_t c = input->toConstant()->toInt32();
4432 int32_t res;
4433 switch (mode_) {
4434 case Byte:
4435 res = int32_t(int8_t(c & 0xFF));
4436 break;
4437 case Half:
4438 res = int32_t(int16_t(c & 0xFFFF));
4439 break;
4440 }
4441 return MConstant::New(alloc, Int32Value(res));
4442 }
4443
4444 return this;
4445}
4446
4447MDefinition* MSignExtendInt64::foldsTo(TempAllocator& alloc) {
4448 MDefinition* input = this->input();
4449 if (input->isConstant()) {
4450 int64_t c = input->toConstant()->toInt64();
4451 int64_t res;
4452 switch (mode_) {
4453 case Byte:
4454 res = int64_t(int8_t(c & 0xFF));
4455 break;
4456 case Half:
4457 res = int64_t(int16_t(c & 0xFFFF));
4458 break;
4459 case Word:
4460 res = int64_t(int32_t(c & 0xFFFFFFFFU));
4461 break;
4462 }
4463 return MConstant::NewInt64(alloc, res);
4464 }
4465
4466 return this;
4467}
4468
4469MDefinition* MSignExtendIntPtr::foldsTo(TempAllocator& alloc) {
4470 MDefinition* input = this->input();
4471 if (input->isConstant()) {
4472 intptr_t c = input->toConstant()->toIntPtr();
4473 intptr_t res;
4474 switch (mode_) {
4475 case Byte:
4476 res = intptr_t(int8_t(c & 0xFF));
4477 break;
4478 case Half:
4479 res = intptr_t(int16_t(c & 0xFFFF));
4480 break;
4481 case Word:
4482 res = intptr_t(int32_t(c & 0xFFFFFFFFU));
4483 break;
4484 }
4485 return MConstant::NewIntPtr(alloc, res);
4486 }
4487
4488 return this;
4489}
4490
4491MDefinition* MToDouble::foldsTo(TempAllocator& alloc) {
4492 MDefinition* input = getOperand(0);
4493 if (input->isBox()) {
4494 input = input->getOperand(0);
4495 }
4496
4497 if (input->type() == MIRType::Double) {
4498 return input;
4499 }
4500
4501 if (input->isConstant() &&
4502 input->toConstant()->isTypeRepresentableAsDouble()) {
4503 return MConstant::New(alloc,
4504 DoubleValue(input->toConstant()->numberToDouble()));
4505 }
4506
4507 return this;
4508}
4509
4510MDefinition* MToFloat32::foldsTo(TempAllocator& alloc) {
4511 MDefinition* input = getOperand(0);
4512 if (input->isBox()) {
4513 input = input->getOperand(0);
4514 }
4515
4516 if (input->type() == MIRType::Float32) {
4517 return input;
4518 }
4519
4520 // If x is a Float32, Float32(Double(x)) == x
4521 if (!mustPreserveNaN_ && input->isToDouble() &&
4522 input->toToDouble()->input()->type() == MIRType::Float32) {
4523 return input->toToDouble()->input();
4524 }
4525
4526 if (input->isConstant() &&
4527 input->toConstant()->isTypeRepresentableAsDouble()) {
4528 return MConstant::NewFloat32(alloc,
4529 float(input->toConstant()->numberToDouble()));
4530 }
4531
4532 // Fold ToFloat32(ToDouble(int32)) to ToFloat32(int32).
4533 if (input->isToDouble() &&
4534 input->toToDouble()->input()->type() == MIRType::Int32) {
4535 return MToFloat32::New(alloc, input->toToDouble()->input());
4536 }
4537
4538 return this;
4539}
4540
4541MDefinition* MToFloat16::foldsTo(TempAllocator& alloc) {
4542 MDefinition* in = input();
4543 if (in->isBox()) {
4544 in = in->toBox()->input();
4545 }
4546
4547 if (in->isConstant()) {
4548 auto* cst = in->toConstant();
4549 if (cst->isTypeRepresentableAsDouble()) {
4550 double num = cst->numberToDouble();
4551 return MConstant::NewFloat32(alloc, static_cast<float>(js::float16{num}));
4552 }
4553 }
4554
4555 auto isFloat16 = [](auto* def) -> MDefinition* {
4556 // ToFloat16(ToDouble(float16)) => float16
4557 // ToFloat16(ToFloat32(float16)) => float16
4558 if (def->isToDouble()) {
4559 def = def->toToDouble()->input();
4560 } else if (def->isToFloat32()) {
4561 def = def->toToFloat32()->input();
4562 }
4563
4564 // ToFloat16(ToFloat16(x)) => ToFloat16(x)
4565 if (def->isToFloat16()) {
4566 return def;
4567 }
4568
4569 // ToFloat16(LoadFloat16(x)) => LoadFloat16(x)
4570 if (def->isLoadUnboxedScalar() &&
4571 def->toLoadUnboxedScalar()->storageType() == Scalar::Float16) {
4572 return def;
4573 }
4574 if (def->isLoadDataViewElement() &&
4575 def->toLoadDataViewElement()->storageType() == Scalar::Float16) {
4576 return def;
4577 }
4578 return nullptr;
4579 };
4580
4581 // Fold loads which are guaranteed to return Float16.
4582 if (auto* f16 = isFloat16(in)) {
4583 return f16;
4584 }
4585
4586 // Fold ToFloat16(ToDouble(float32)) to ToFloat16(float32).
4587 // Fold ToFloat16(ToDouble(int32)) to ToFloat16(int32).
4588 if (in->isToDouble()) {
4589 auto* toDoubleInput = in->toToDouble()->input();
4590 if (toDoubleInput->type() == MIRType::Float32 ||
4591 toDoubleInput->type() == MIRType::Int32) {
4592 return MToFloat16::New(alloc, toDoubleInput);
4593 }
4594 }
4595
4596 return this;
4597}
4598
4599MDefinition* MToString::foldsTo(TempAllocator& alloc) {
4600 MDefinition* in = input();
4601 if (in->isBox()) {
4602 in = in->getOperand(0);
4603 }
4604
4605 if (in->type() == MIRType::String) {
4606 return in;
4607 }
4608 return this;
4609}
4610
4611MDefinition* MClampToUint8::foldsTo(TempAllocator& alloc) {
4612 if (MConstant* inputConst = input()->maybeConstantValue()) {
4613 if (inputConst->isTypeRepresentableAsDouble()) {
4614 int32_t clamped = ClampDoubleToUint8(inputConst->numberToDouble());
4615 return MConstant::New(alloc, Int32Value(clamped));
4616 }
4617 }
4618 return this;
4619}
4620
4621bool MCompare::tryFoldEqualOperands(bool* result) {
4622 if (lhs() != rhs()) {
4623 return false;
4624 }
4625
4626 // Intuitively somebody would think that if lhs === rhs,
4627 // then we can just return true. (Or false for !==)
4628 // However NaN !== NaN is true! So we spend some time trying
4629 // to eliminate this case.
4630
4631 if (!IsEqualityOp(jsop())) {
4632 return false;
4633 }
4634
4635 switch (compareType_) {
4636 case Compare_Int32:
4637 case Compare_UInt32:
4638 case Compare_Int64:
4639 case Compare_UInt64:
4640 case Compare_IntPtr:
4641 case Compare_UIntPtr:
4642 case Compare_Float32:
4643 case Compare_Double:
4644 case Compare_String:
4645 case Compare_Object:
4646 case Compare_Symbol:
4647 case Compare_BigInt:
4648 case Compare_WasmAnyRef:
4649 case Compare_Null:
4650 case Compare_Undefined:
4651 break;
4652 case Compare_BigInt_Int32:
4653 case Compare_BigInt_String:
4654 case Compare_BigInt_Double:
4655 MOZ_CRASH("Expecting different operands for lhs and rhs")do { do { } while (false); MOZ_ReportCrash("" "Expecting different operands for lhs and rhs"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4655); AnnotateMozCrashReason("MOZ_CRASH(" "Expecting different operands for lhs and rhs"
")"); do { *((volatile int*)__null) = 4655; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4656 }
4657
4658 if (isDoubleComparison() || isFloat32Comparison()) {
4659 if (!operandsAreNeverNaN()) {
4660 return false;
4661 }
4662 } else {
4663 MOZ_ASSERT(!IsFloatingPointType(lhs()->type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsFloatingPointType(lhs()->type()))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!IsFloatingPointType(lhs()->type())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!IsFloatingPointType(lhs()->type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4663); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(lhs()->type())"
")"); do { *((volatile int*)__null) = 4663; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4664 }
4665
4666 lhs()->setGuardRangeBailoutsUnchecked();
4667
4668 *result = (jsop() == JSOp::StrictEq || jsop() == JSOp::Eq);
4669 return true;
4670}
4671
4672static JSType TypeOfName(const JSLinearString* str) {
4673 static constexpr std::array types = {
4674 JSTYPE_UNDEFINED, JSTYPE_OBJECT, JSTYPE_FUNCTION, JSTYPE_STRING,
4675 JSTYPE_NUMBER, JSTYPE_BOOLEAN, JSTYPE_SYMBOL, JSTYPE_BIGINT,
4676#ifdef ENABLE_RECORD_TUPLE
4677 JSTYPE_RECORD, JSTYPE_TUPLE,
4678#endif
4679 };
4680 static_assert(types.size() == JSTYPE_LIMIT);
4681
4682 const JSAtomState& names = GetJitContext()->runtime->names();
4683 for (auto type : types) {
4684 if (EqualStrings(str, TypeName(type, names))) {
4685 return type;
4686 }
4687 }
4688 return JSTYPE_LIMIT;
4689}
4690
4691struct TypeOfCompareInput {
4692 // The `typeof expr` side of the comparison.
4693 // MTypeOfName for JSOp::Typeof/JSOp::TypeofExpr, and
4694 // MTypeOf for JSOp::TypeofEq (same pointer as typeOf).
4695 MDefinition* typeOfSide;
4696
4697 // The actual `typeof` operation.
4698 MTypeOf* typeOf;
4699
4700 // The string side of the comparison.
4701 JSType type;
4702
4703 // True if the comparison uses raw JSType (Generated for JSOp::TypeofEq).
4704 bool isIntComparison;
4705
4706 TypeOfCompareInput(MDefinition* typeOfSide, MTypeOf* typeOf, JSType type,
4707 bool isIntComparison)
4708 : typeOfSide(typeOfSide),
4709 typeOf(typeOf),
4710 type(type),
4711 isIntComparison(isIntComparison) {}
4712};
4713
4714static mozilla::Maybe<TypeOfCompareInput> IsTypeOfCompare(MCompare* ins) {
4715 if (!IsEqualityOp(ins->jsop())) {
4716 return mozilla::Nothing();
4717 }
4718
4719 if (ins->compareType() == MCompare::Compare_Int32) {
4720 auto* lhs = ins->lhs();
4721 auto* rhs = ins->rhs();
4722
4723 if (ins->type() != MIRType::Boolean || lhs->type() != MIRType::Int32 ||
4724 rhs->type() != MIRType::Int32) {
4725 return mozilla::Nothing();
4726 }
4727
4728 // NOTE: The comparison is generated inside JIT, and typeof should always
4729 // be in the LHS.
4730 if (!lhs->isTypeOf() || !rhs->isConstant()) {
4731 return mozilla::Nothing();
4732 }
4733
4734 auto* typeOf = lhs->toTypeOf();
4735 auto* constant = rhs->toConstant();
4736
4737 JSType type = JSType(constant->toInt32());
4738 return mozilla::Some(TypeOfCompareInput(typeOf, typeOf, type, true));
4739 }
4740
4741 if (ins->compareType() != MCompare::Compare_String) {
4742 return mozilla::Nothing();
4743 }
4744
4745 auto* lhs = ins->lhs();
4746 auto* rhs = ins->rhs();
4747
4748 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"
, 4748); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 4748; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4749 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"
, 4749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4749; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4750 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"
, 4750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4750; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4751
4752 if (!lhs->isTypeOfName() && !rhs->isTypeOfName()) {
4753 return mozilla::Nothing();
4754 }
4755 if (!lhs->isConstant() && !rhs->isConstant()) {
4756 return mozilla::Nothing();
4757 }
4758
4759 auto* typeOfName =
4760 lhs->isTypeOfName() ? lhs->toTypeOfName() : rhs->toTypeOfName();
4761 auto* typeOf = typeOfName->input()->toTypeOf();
4762
4763 auto* constant = lhs->isConstant() ? lhs->toConstant() : rhs->toConstant();
4764
4765 JSType type = TypeOfName(&constant->toString()->asLinear());
4766 return mozilla::Some(TypeOfCompareInput(typeOfName, typeOf, type, false));
4767}
4768
4769bool MCompare::tryFoldTypeOf(bool* result) {
4770 auto typeOfCompare = IsTypeOfCompare(this);
4771 if (!typeOfCompare) {
4772 return false;
4773 }
4774 auto* typeOf = typeOfCompare->typeOf;
4775 JSType type = typeOfCompare->type;
4776
4777 switch (type) {
4778 case JSTYPE_BOOLEAN:
4779 if (!typeOf->input()->mightBeType(MIRType::Boolean)) {
4780 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4781 return true;
4782 }
4783 break;
4784 case JSTYPE_NUMBER:
4785 if (!typeOf->input()->mightBeType(MIRType::Int32) &&
4786 !typeOf->input()->mightBeType(MIRType::Float32) &&
4787 !typeOf->input()->mightBeType(MIRType::Double)) {
4788 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4789 return true;
4790 }
4791 break;
4792 case JSTYPE_STRING:
4793 if (!typeOf->input()->mightBeType(MIRType::String)) {
4794 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4795 return true;
4796 }
4797 break;
4798 case JSTYPE_SYMBOL:
4799 if (!typeOf->input()->mightBeType(MIRType::Symbol)) {
4800 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4801 return true;
4802 }
4803 break;
4804 case JSTYPE_BIGINT:
4805 if (!typeOf->input()->mightBeType(MIRType::BigInt)) {
4806 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4807 return true;
4808 }
4809 break;
4810 case JSTYPE_OBJECT:
4811 if (!typeOf->input()->mightBeType(MIRType::Object) &&
4812 !typeOf->input()->mightBeType(MIRType::Null)) {
4813 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4814 return true;
4815 }
4816 break;
4817 case JSTYPE_UNDEFINED:
4818 if (!typeOf->input()->mightBeType(MIRType::Object) &&
4819 !typeOf->input()->mightBeType(MIRType::Undefined)) {
4820 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4821 return true;
4822 }
4823 break;
4824 case JSTYPE_FUNCTION:
4825 if (!typeOf->input()->mightBeType(MIRType::Object)) {
4826 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4827 return true;
4828 }
4829 break;
4830 case JSTYPE_LIMIT:
4831 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4832 return true;
4833#ifdef ENABLE_RECORD_TUPLE
4834 case JSTYPE_RECORD:
4835 case JSTYPE_TUPLE:
4836 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"
, 4836); AnnotateMozCrashReason("MOZ_CRASH(" "Records and Tuples are not supported yet."
")"); do { *((volatile int*)__null) = 4836; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4837#endif
4838 }
4839
4840 return false;
4841}
4842
4843bool MCompare::tryFold(bool* result) {
4844 JSOp op = jsop();
4845
4846 if (tryFoldEqualOperands(result)) {
4847 return true;
4848 }
4849
4850 if (tryFoldTypeOf(result)) {
4851 return true;
4852 }
4853
4854 if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) {
4855 // The LHS is the value we want to test against null or undefined.
4856 if (IsStrictEqualityOp(op)) {
4857 if (lhs()->type() == inputType()) {
4858 *result = (op == JSOp::StrictEq);
4859 return true;
4860 }
4861 if (!lhs()->mightBeType(inputType())) {
4862 *result = (op == JSOp::StrictNe);
4863 return true;
4864 }
4865 } else {
4866 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"
, 4866); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsLooseEqualityOp(op)"
")"); do { *((volatile int*)__null) = 4866; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4867 if (IsNullOrUndefined(lhs()->type())) {
4868 *result = (op == JSOp::Eq);
4869 return true;
4870 }
4871 if (!lhs()->mightBeType(MIRType::Null) &&
4872 !lhs()->mightBeType(MIRType::Undefined) &&
4873 !lhs()->mightBeType(MIRType::Object)) {
4874 *result = (op == JSOp::Ne);
4875 return true;
4876 }
4877 }
4878 return false;
4879 }
4880
4881 return false;
4882}
4883
4884template <typename T>
4885static bool FoldComparison(JSOp op, T left, T right) {
4886 switch (op) {
4887 case JSOp::Lt:
4888 return left < right;
4889 case JSOp::Le:
4890 return left <= right;
4891 case JSOp::Gt:
4892 return left > right;
4893 case JSOp::Ge:
4894 return left >= right;
4895 case JSOp::StrictEq:
4896 case JSOp::Eq:
4897 return left == right;
4898 case JSOp::StrictNe:
4899 case JSOp::Ne:
4900 return left != right;
4901 default:
4902 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4902); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 4902; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4903 }
4904}
4905
4906static bool FoldBigIntComparison(JSOp op, const BigInt* left, double right) {
4907 switch (op) {
4908 case JSOp::Lt:
4909 return BigInt::lessThan(left, right).valueOr(false);
4910 case JSOp::Le:
4911 return !BigInt::lessThan(right, left).valueOr(true);
4912 case JSOp::Gt:
4913 return BigInt::lessThan(right, left).valueOr(false);
4914 case JSOp::Ge:
4915 return !BigInt::lessThan(left, right).valueOr(true);
4916 case JSOp::StrictEq:
4917 case JSOp::Eq:
4918 return BigInt::equal(left, right);
4919 case JSOp::StrictNe:
4920 case JSOp::Ne:
4921 return !BigInt::equal(left, right);
4922 default:
4923 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4923); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 4923; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4924 }
4925}
4926
4927bool MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) {
4928 if (type() != MIRType::Boolean && type() != MIRType::Int32) {
4929 return false;
4930 }
4931
4932 MDefinition* left = getOperand(0);
4933 MDefinition* right = getOperand(1);
4934
4935 if (compareType() == Compare_Double) {
4936 // Optimize "MCompare MConstant (MToDouble SomethingInInt32Range).
4937 // In most cases the MToDouble was added, because the constant is
4938 // a double.
4939 // e.g. v < 9007199254740991, where v is an int32 is always true.
4940 if (!lhs()->isConstant() && !rhs()->isConstant()) {
4941 return false;
4942 }
4943
4944 MDefinition* operand = left->isConstant() ? right : left;
4945 MConstant* constant =
4946 left->isConstant() ? left->toConstant() : right->toConstant();
4947 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"
, 4947); AnnotateMozCrashReason("MOZ_ASSERT" "(" "constant->type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 4947; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4948 double cte = constant->toDouble();
4949
4950 if (operand->isToDouble() &&
4951 operand->getOperand(0)->type() == MIRType::Int32) {
4952 bool replaced = false;
4953 switch (jsop_) {
4954 case JSOp::Lt:
4955 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4956 *result = !((constant == lhs()) ^ (cte < INT32_MIN(-2147483647-1)));
4957 replaced = true;
4958 }
4959 break;
4960 case JSOp::Le:
4961 if (constant == lhs()) {
4962 if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) {
4963 *result = (cte <= INT32_MIN(-2147483647-1));
4964 replaced = true;
4965 }
4966 } else {
4967 if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4968 *result = (cte >= INT32_MIN(-2147483647-1));
4969 replaced = true;
4970 }
4971 }
4972 break;
4973 case JSOp::Gt:
4974 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4975 *result = !((constant == rhs()) ^ (cte < INT32_MIN(-2147483647-1)));
4976 replaced = true;
4977 }
4978 break;
4979 case JSOp::Ge:
4980 if (constant == lhs()) {
4981 if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4982 *result = (cte >= INT32_MAX(2147483647));
4983 replaced = true;
4984 }
4985 } else {
4986 if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) {
4987 *result = (cte <= INT32_MIN(-2147483647-1));
4988 replaced = true;
4989 }
4990 }
4991 break;
4992 case JSOp::StrictEq: // Fall through.
4993 case JSOp::Eq:
4994 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4995 *result = false;
4996 replaced = true;
4997 }
4998 break;
4999 case JSOp::StrictNe: // Fall through.
5000 case JSOp::Ne:
5001 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
5002 *result = true;
5003 replaced = true;
5004 }
5005 break;
5006 default:
5007 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5007); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 5007; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
5008 }
5009 if (replaced) {
5010 MLimitedTruncate* limit = MLimitedTruncate::New(
5011 alloc, operand->getOperand(0), TruncateKind::NoTruncate);
5012 limit->setGuardUnchecked();
5013 block()->insertBefore(this, limit);
5014 return true;
5015 }
5016 }
5017
5018 // Optimize comparison against NaN.
5019 if (std::isnan(cte)) {
5020 switch (jsop_) {
5021 case JSOp::Lt:
5022 case JSOp::Le:
5023 case JSOp::Gt:
5024 case JSOp::Ge:
5025 case JSOp::Eq:
5026 case JSOp::StrictEq:
5027 *result = false;
5028 break;
5029 case JSOp::Ne:
5030 case JSOp::StrictNe:
5031 *result = true;
5032 break;
5033 default:
5034 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5034); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 5034; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
5035 }
5036 return true;
5037 }
5038 }
5039
5040 if (!left->isConstant() || !right->isConstant()) {
5041 return false;
5042 }
5043
5044 MConstant* lhs = left->toConstant();
5045 MConstant* rhs = right->toConstant();
5046
5047 switch (compareType()) {
5048 case Compare_Int32:
5049 case Compare_Double:
5050 case Compare_Float32: {
5051 *result =
5052 FoldComparison(jsop_, lhs->numberToDouble(), rhs->numberToDouble());
5053 return true;
5054 }
5055 case Compare_UInt32: {
5056 *result = FoldComparison(jsop_, uint32_t(lhs->toInt32()),
5057 uint32_t(rhs->toInt32()));
5058 return true;
5059 }
5060 case Compare_Int64: {
5061 *result = FoldComparison(jsop_, lhs->toInt64(), rhs->toInt64());
5062 return true;
5063 }
5064 case Compare_UInt64: {
5065 *result = FoldComparison(jsop_, uint64_t(lhs->toInt64()),
5066 uint64_t(rhs->toInt64()));
5067 return true;
5068 }
5069 case Compare_IntPtr: {
5070 *result = FoldComparison(jsop_, lhs->toIntPtr(), rhs->toIntPtr());
5071 return true;
5072 }
5073 case Compare_UIntPtr: {
5074 *result = FoldComparison(jsop_, uintptr_t(lhs->toIntPtr()),
5075 uintptr_t(rhs->toIntPtr()));
5076 return true;
5077 }
5078 case Compare_String: {
5079 int32_t comp = CompareStrings(&lhs->toString()->asLinear(),
5080 &rhs->toString()->asLinear());
5081 *result = FoldComparison(jsop_, comp, 0);
5082 return true;
5083 }
5084 case Compare_BigInt: {
5085 int32_t comp = BigInt::compare(lhs->toBigInt(), rhs->toBigInt());
5086 *result = FoldComparison(jsop_, comp, 0);
5087 return true;
5088 }
5089 case Compare_BigInt_Int32:
5090 case Compare_BigInt_Double: {
5091 *result =
5092 FoldBigIntComparison(jsop_, lhs->toBigInt(), rhs->numberToDouble());
5093 return true;
5094 }
5095 case Compare_BigInt_String: {
5096 JSLinearString* linear = &rhs->toString()->asLinear();
5097 if (!linear->hasIndexValue()) {
5098 return false;
5099 }
5100 *result =
5101 FoldBigIntComparison(jsop_, lhs->toBigInt(), linear->getIndexValue());
5102 return true;
5103 }
5104
5105 case Compare_Undefined:
5106 case Compare_Null:
5107 case Compare_Symbol:
5108 case Compare_Object:
5109 case Compare_WasmAnyRef:
5110 return false;
5111 }
5112
5113 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"
, 5113); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected compare type"
")"); do { *((volatile int*)__null) = 5113; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
5114}
5115
5116MDefinition* MCompare::tryFoldTypeOf(TempAllocator& alloc) {
5117 auto typeOfCompare = IsTypeOfCompare(this);
5118 if (!typeOfCompare) {
5119 return this;
5120 }
5121 auto* typeOf = typeOfCompare->typeOf;
5122 JSType type = typeOfCompare->type;
5123
5124 auto* input = typeOf->input();
5125 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"
, 5126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object"
")"); do { *((volatile int*)__null) = 5126; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5126 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"
, 5126); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object"
")"); do { *((volatile int*)__null) = 5126; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5127
5128 // Constant typeof folding handles the other cases.
5129 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"
, 5131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
")"); do { *((volatile int*)__null) = 5131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5130 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"
, 5131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
")"); do { *((volatile int*)__null) = 5131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5131 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"
, 5131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
")"); do { *((volatile int*)__null) = 5131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5132
5133 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"
, 5133); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type != JSTYPE_LIMIT"
") (" "unknown typeof strings folded earlier" ")"); do { *((
volatile int*)__null) = 5133; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
5134
5135 // If there's only a single use, assume this |typeof| is used in a simple
5136 // comparison context.
5137 //
5138 // if (typeof thing === "number") { ... }
5139 //
5140 // It'll be compiled into something similar to:
5141 //
5142 // if (IsNumber(thing)) { ... }
5143 //
5144 // This heuristic can go wrong when repeated |typeof| are used in consecutive
5145 // if-statements.
5146 //
5147 // if (typeof thing === "number") { ... }
5148 // else if (typeof thing === "string") { ... }
5149 // ... repeated for all possible types
5150 //
5151 // In that case it'd more efficient to emit MTypeOf compared to MTypeOfIs. We
5152 // don't yet handle that case, because it'd require a separate optimization
5153 // pass to correctly detect it.
5154 if (typeOfCompare->typeOfSide->hasOneUse()) {
5155 return MTypeOfIs::New(alloc, input, jsop(), type);
5156 }
5157
5158 if (typeOfCompare->isIntComparison) {
5159 // Already optimized.
5160 return this;
5161 }
5162
5163 MConstant* cst = MConstant::New(alloc, Int32Value(type));
5164 block()->insertBefore(this, cst);
5165
5166 return MCompare::New(alloc, typeOf, cst, jsop(), MCompare::Compare_Int32);
5167}
5168
5169MDefinition* MCompare::tryFoldCharCompare(TempAllocator& alloc) {
5170 if (compareType() != Compare_String) {
5171 return this;
5172 }
5173
5174 MDefinition* left = lhs();
5175 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"
, 5175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5176
5177 MDefinition* right = rhs();
5178 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"
, 5178); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5178; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5179
5180 // |str[i]| is compiled as |MFromCharCode(MCharCodeAt(str, i))|.
5181 // Out-of-bounds access is compiled as
5182 // |FromCharCodeEmptyIfNegative(CharCodeAtOrNegative(str, i))|.
5183 auto isCharAccess = [](MDefinition* ins) {
5184 if (ins->isFromCharCode()) {
5185 return ins->toFromCharCode()->code()->isCharCodeAt();
5186 }
5187 if (ins->isFromCharCodeEmptyIfNegative()) {
5188 auto* fromCharCode = ins->toFromCharCodeEmptyIfNegative();
5189 return fromCharCode->code()->isCharCodeAtOrNegative();
5190 }
5191 return false;
5192 };
5193
5194 auto charAccessCode = [](MDefinition* ins) {
5195 if (ins->isFromCharCode()) {
5196 return ins->toFromCharCode()->code();
5197 }
5198 return ins->toFromCharCodeEmptyIfNegative()->code();
5199 };
5200
5201 if (left->isConstant() || right->isConstant()) {
5202 // Try to optimize |MConstant(string) <compare> (MFromCharCode MCharCodeAt)|
5203 // as |MConstant(charcode) <compare> MCharCodeAt|.
5204 MConstant* constant;
5205 MDefinition* operand;
5206 if (left->isConstant()) {
5207 constant = left->toConstant();
5208 operand = right;
5209 } else {
5210 constant = right->toConstant();
5211 operand = left;
5212 }
5213
5214 if (constant->toString()->length() != 1 || !isCharAccess(operand)) {
5215 return this;
5216 }
5217
5218 char16_t charCode = constant->toString()->asLinear().latin1OrTwoByteChar(0);
5219 MConstant* charCodeConst = MConstant::New(alloc, Int32Value(charCode));
5220 block()->insertBefore(this, charCodeConst);
5221
5222 MDefinition* charCodeAt = charAccessCode(operand);
5223
5224 if (left->isConstant()) {
5225 left = charCodeConst;
5226 right = charCodeAt;
5227 } else {
5228 left = charCodeAt;
5229 right = charCodeConst;
5230 }
5231 } else if (isCharAccess(left) && isCharAccess(right)) {
5232 // Try to optimize |(MFromCharCode MCharCodeAt) <compare> (MFromCharCode
5233 // MCharCodeAt)| as |MCharCodeAt <compare> MCharCodeAt|.
5234
5235 left = charAccessCode(left);
5236 right = charAccessCode(right);
5237 } else {
5238 return this;
5239 }
5240
5241 return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32);
5242}
5243
5244MDefinition* MCompare::tryFoldStringCompare(TempAllocator& alloc) {
5245 if (compareType() != Compare_String) {
5246 return this;
5247 }
5248
5249 MDefinition* left = lhs();
5250 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"
, 5250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5250; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5251
5252 MDefinition* right = rhs();
5253 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"
, 5253); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5253; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5254
5255 if (!left->isConstant() && !right->isConstant()) {
5256 return this;
5257 }
5258
5259 // Try to optimize |string <compare> MConstant("")| as |MStringLength(string)
5260 // <compare> MConstant(0)|.
5261
5262 MConstant* constant =
5263 left->isConstant() ? left->toConstant() : right->toConstant();
5264 if (!constant->toString()->empty()) {
5265 return this;
5266 }
5267
5268 MDefinition* operand = left->isConstant() ? right : left;
5269
5270 auto* strLength = MStringLength::New(alloc, operand);
5271 block()->insertBefore(this, strLength);
5272
5273 auto* zero = MConstant::New(alloc, Int32Value(0));
5274 block()->insertBefore(this, zero);
5275
5276 if (left->isConstant()) {
5277 left = zero;
5278 right = strLength;
5279 } else {
5280 left = strLength;
5281 right = zero;
5282 }
5283
5284 return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32);
5285}
5286
5287MDefinition* MCompare::tryFoldStringSubstring(TempAllocator& alloc) {
5288 if (compareType() != Compare_String) {
5289 return this;
5290 }
5291 if (!IsEqualityOp(jsop())) {
5292 return this;
5293 }
5294
5295 auto* left = lhs();
5296 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"
, 5296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5296; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5297
5298 auto* right = rhs();
5299 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"
, 5299); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 5299; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5300
5301 // One operand must be a constant string.
5302 if (!left->isConstant() && !right->isConstant()) {
5303 return this;
5304 }
5305
5306 // The constant string must be non-empty.
5307 auto* constant =
5308 left->isConstant() ? left->toConstant() : right->toConstant();
5309 if (constant->toString()->empty()) {
5310 return this;
5311 }
5312
5313 // The other operand must be a substring operation.
5314 auto* operand = left->isConstant() ? right : left;
5315 if (!operand->isSubstr()) {
5316 return this;
5317 }
5318 auto* substr = operand->toSubstr();
5319
5320 static_assert(JSString::MAX_LENGTH < INT32_MAX(2147483647),
5321 "string length can be casted to int32_t");
5322
5323 if (!IsSubstrTo(substr, int32_t(constant->toString()->length()))) {
5324 return this;
5325 }
5326
5327 // Now fold code like |str.substring(0, 2) == "aa"| to |str.startsWith("aa")|.
5328
5329 auto* startsWith = MStringStartsWith::New(alloc, substr->string(), constant);
5330 if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) {
5331 return startsWith;
5332 }
5333
5334 // Invert for inequality.
5335 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"
, 5335); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe"
")"); do { *((volatile int*)__null) = 5335; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5336
5337 block()->insertBefore(this, startsWith);
5338 return MNot::New(alloc, startsWith);
5339}
5340
5341MDefinition* MCompare::tryFoldStringIndexOf(TempAllocator& alloc) {
5342 if (compareType() != Compare_Int32) {
5343 return this;
5344 }
5345 if (!IsEqualityOp(jsop())) {
5346 return this;
5347 }
5348
5349 auto* left = lhs();
5350 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"
, 5350); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 5350; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5351
5352 auto* right = rhs();
5353 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"
, 5353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 5353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5354
5355 // One operand must be a constant integer.
5356 if (!left->isConstant() && !right->isConstant()) {
5357 return this;
5358 }
5359
5360 // The constant must be zero.
5361 auto* constant =
5362 left->isConstant() ? left->toConstant() : right->toConstant();
5363 if (!constant->isInt32(0)) {
5364 return this;
5365 }
5366
5367 // The other operand must be an indexOf operation.
5368 auto* operand = left->isConstant() ? right : left;
5369 if (!operand->isStringIndexOf()) {
5370 return this;
5371 }
5372
5373 // Fold |str.indexOf(searchStr) == 0| to |str.startsWith(searchStr)|.
5374
5375 auto* indexOf = operand->toStringIndexOf();
5376 auto* startsWith =
5377 MStringStartsWith::New(alloc, indexOf->string(), indexOf->searchString());
5378 if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) {
5379 return startsWith;
5380 }
5381
5382 // Invert for inequality.
5383 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"
, 5383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe"
")"); do { *((volatile int*)__null) = 5383; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5384
5385 block()->insertBefore(this, startsWith);
5386 return MNot::New(alloc, startsWith);
5387}
5388
5389MDefinition* MCompare::tryFoldBigInt64(TempAllocator& alloc) {
5390 if (compareType() == Compare_BigInt) {
5391 auto* left = lhs();
5392 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"
, 5392); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5392; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5393
5394 auto* right = rhs();
5395 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"
, 5395); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5395; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5396
5397 // At least one operand must be MInt64ToBigInt.
5398 if (!left->isInt64ToBigInt() && !right->isInt64ToBigInt()) {
5399 return this;
5400 }
5401
5402 // Unwrap MInt64ToBigInt on both sides and perform a Int64 comparison.
5403 if (left->isInt64ToBigInt() && right->isInt64ToBigInt()) {
5404 auto* lhsInt64 = left->toInt64ToBigInt();
5405 auto* rhsInt64 = right->toInt64ToBigInt();
5406
5407 // Don't optimize if Int64 against Uint64 comparison.
5408 if (lhsInt64->isSigned() != rhsInt64->isSigned()) {
5409 return this;
5410 }
5411
5412 bool isSigned = lhsInt64->isSigned();
5413 auto compareType =
5414 isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64;
5415 return MCompare::New(alloc, lhsInt64->input(), rhsInt64->input(), jsop_,
5416 compareType);
5417 }
5418
5419 // Optimize IntPtr x Int64 comparison to Int64 x Int64 comparison.
5420 if (left->isIntPtrToBigInt() || right->isIntPtrToBigInt()) {
5421 auto* int64ToBigInt = left->isInt64ToBigInt() ? left->toInt64ToBigInt()
5422 : right->toInt64ToBigInt();
5423
5424 // Can't optimize when comparing Uint64 against IntPtr.
5425 if (!int64ToBigInt->isSigned()) {
5426 return this;
5427 }
5428
5429 auto* intPtrToBigInt = left->isIntPtrToBigInt()
5430 ? left->toIntPtrToBigInt()
5431 : right->toIntPtrToBigInt();
5432
5433 auto* intPtrToInt64 = MIntPtrToInt64::New(alloc, intPtrToBigInt->input());
5434 block()->insertBefore(this, intPtrToInt64);
5435
5436 if (left == int64ToBigInt) {
5437 left = int64ToBigInt->input();
5438 right = intPtrToInt64;
5439 } else {
5440 left = intPtrToInt64;
5441 right = int64ToBigInt->input();
5442 }
5443 return MCompare::New(alloc, left, right, jsop_, MCompare::Compare_Int64);
5444 }
5445
5446 // The other operand must be a constant.
5447 if (!left->isConstant() && !right->isConstant()) {
5448 return this;
5449 }
5450
5451 auto* int64ToBigInt = left->isInt64ToBigInt() ? left->toInt64ToBigInt()
5452 : right->toInt64ToBigInt();
5453 bool isSigned = int64ToBigInt->isSigned();
5454
5455 auto* constant =
5456 left->isConstant() ? left->toConstant() : right->toConstant();
5457 auto* bigInt = constant->toBigInt();
5458
5459 // Extract the BigInt value if representable as Int64/Uint64.
5460 mozilla::Maybe<int64_t> value;
5461 if (isSigned) {
5462 int64_t x;
5463 if (BigInt::isInt64(bigInt, &x)) {
5464 value = mozilla::Some(x);
5465 }
5466 } else {
5467 uint64_t x;
5468 if (BigInt::isUint64(bigInt, &x)) {
5469 value = mozilla::Some(static_cast<int64_t>(x));
5470 }
5471 }
5472
5473 // The comparison is a constant if the BigInt has too many digits.
5474 if (!value) {
5475 int32_t repr = bigInt->isNegative() ? -1 : 1;
5476
5477 bool result;
5478 if (left == int64ToBigInt) {
5479 result = FoldComparison(jsop_, 0, repr);
5480 } else {
5481 result = FoldComparison(jsop_, repr, 0);
5482 }
5483 return MConstant::New(alloc, BooleanValue(result));
5484 }
5485
5486 auto* cst = MConstant::NewInt64(alloc, *value);
5487 block()->insertBefore(this, cst);
5488
5489 auto compareType =
5490 isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64;
5491 if (left == int64ToBigInt) {
5492 return MCompare::New(alloc, int64ToBigInt->input(), cst, jsop_,
5493 compareType);
5494 }
5495 return MCompare::New(alloc, cst, int64ToBigInt->input(), jsop_,
5496 compareType);
5497 }
5498
5499 if (compareType() == Compare_BigInt_Int32) {
5500 auto* left = lhs();
5501 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"
, 5501); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5501; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5502
5503 auto* right = rhs();
5504 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"
, 5504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 5504; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5505
5506 // Optimize MInt64ToBigInt against a constant int32.
5507 if (!left->isInt64ToBigInt() || !right->isConstant()) {
5508 return this;
5509 }
5510
5511 auto* int64ToBigInt = left->toInt64ToBigInt();
5512 bool isSigned = int64ToBigInt->isSigned();
5513
5514 int32_t constInt32 = right->toConstant()->toInt32();
5515
5516 // The unsigned comparison against a negative operand is a constant.
5517 if (!isSigned && constInt32 < 0) {
5518 bool result = FoldComparison(jsop_, 0, constInt32);
5519 return MConstant::New(alloc, BooleanValue(result));
5520 }
5521
5522 auto* cst = MConstant::NewInt64(alloc, int64_t(constInt32));
5523 block()->insertBefore(this, cst);
5524
5525 auto compareType =
5526 isSigned ? MCompare::Compare_Int64 : MCompare::Compare_UInt64;
5527 return MCompare::New(alloc, int64ToBigInt->input(), cst, jsop_,
5528 compareType);
5529 }
5530
5531 return this;
5532}
5533
5534MDefinition* MCompare::tryFoldBigIntPtr(TempAllocator& alloc) {
5535 if (compareType() == Compare_BigInt) {
5536 auto* left = lhs();
5537 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"
, 5537); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5537; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5538
5539 auto* right = rhs();
5540 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"
, 5540); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5540; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5541
5542 // At least one operand must be MIntPtrToBigInt.
5543 if (!left->isIntPtrToBigInt() && !right->isIntPtrToBigInt()) {
5544 return this;
5545 }
5546
5547 // Unwrap MIntPtrToBigInt on both sides and perform an IntPtr comparison.
5548 if (left->isIntPtrToBigInt() && right->isIntPtrToBigInt()) {
5549 auto* lhsIntPtr = left->toIntPtrToBigInt();
5550 auto* rhsIntPtr = right->toIntPtrToBigInt();
5551
5552 return MCompare::New(alloc, lhsIntPtr->input(), rhsIntPtr->input(), jsop_,
5553 MCompare::Compare_IntPtr);
5554 }
5555
5556 // The other operand must be a constant.
5557 if (!left->isConstant() && !right->isConstant()) {
5558 return this;
5559 }
5560
5561 auto* intPtrToBigInt = left->isIntPtrToBigInt() ? left->toIntPtrToBigInt()
5562 : right->toIntPtrToBigInt();
5563
5564 auto* constant =
5565 left->isConstant() ? left->toConstant() : right->toConstant();
5566 auto* bigInt = constant->toBigInt();
5567
5568 // Extract the BigInt value if representable as intptr_t.
5569 intptr_t value;
5570 if (!BigInt::isIntPtr(bigInt, &value)) {
5571 // The comparison is a constant if the BigInt has too many digits.
5572 int32_t repr = bigInt->isNegative() ? -1 : 1;
5573
5574 bool result;
5575 if (left == intPtrToBigInt) {
5576 result = FoldComparison(jsop_, 0, repr);
5577 } else {
5578 result = FoldComparison(jsop_, repr, 0);
5579 }
5580 return MConstant::New(alloc, BooleanValue(result));
5581 }
5582
5583 auto* cst = MConstant::NewIntPtr(alloc, value);
5584 block()->insertBefore(this, cst);
5585
5586 if (left == intPtrToBigInt) {
5587 left = intPtrToBigInt->input();
5588 right = cst;
5589 } else {
5590 left = cst;
5591 right = intPtrToBigInt->input();
5592 }
5593 return MCompare::New(alloc, left, right, jsop_, MCompare::Compare_IntPtr);
5594 }
5595
5596 if (compareType() == Compare_BigInt_Int32) {
5597 auto* left = lhs();
5598 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"
, 5598); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5598; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5599
5600 auto* right = rhs();
5601 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"
, 5601); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 5601; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5602
5603 // Optimize MIntPtrToBigInt against a constant int32.
5604 if (!left->isIntPtrToBigInt() || !right->isConstant()) {
5605 return this;
5606 }
5607
5608 auto* cst =
5609 MConstant::NewIntPtr(alloc, intptr_t(right->toConstant()->toInt32()));
5610 block()->insertBefore(this, cst);
5611
5612 return MCompare::New(alloc, left->toIntPtrToBigInt()->input(), cst, jsop_,
5613 MCompare::Compare_IntPtr);
5614 }
5615
5616 return this;
5617}
5618
5619MDefinition* MCompare::tryFoldBigInt(TempAllocator& alloc) {
5620 if (compareType() != Compare_BigInt) {
5621 return this;
5622 }
5623
5624 auto* left = lhs();
5625 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"
, 5625); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5625; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5626
5627 auto* right = rhs();
5628 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"
, 5628); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::BigInt"
")"); do { *((volatile int*)__null) = 5628; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5629
5630 // One operand must be a constant.
5631 if (!left->isConstant() && !right->isConstant()) {
5632 return this;
5633 }
5634
5635 auto* constant =
5636 left->isConstant() ? left->toConstant() : right->toConstant();
5637 auto* operand = left->isConstant() ? right : left;
5638
5639 // The constant must be representable as an Int32.
5640 int32_t x;
5641 if (!BigInt::isInt32(constant->toBigInt(), &x)) {
5642 return this;
5643 }
5644
5645 MConstant* int32Const = MConstant::New(alloc, Int32Value(x));
5646 block()->insertBefore(this, int32Const);
5647
5648 auto op = jsop();
5649 if (IsStrictEqualityOp(op)) {
5650 // Compare_BigInt_Int32 is only valid for loose comparison.
5651 op = op == JSOp::StrictEq ? JSOp::Eq : JSOp::Ne;
5652 } else if (operand == right) {
5653 // Reverse the comparison operator if the operands were reordered.
5654 op = ReverseCompareOp(op);
5655 }
5656
5657 return MCompare::New(alloc, operand, int32Const, op,
5658 MCompare::Compare_BigInt_Int32);
5659}
5660
5661MDefinition* MCompare::foldsTo(TempAllocator& alloc) {
5662 bool result;
5663
5664 if (tryFold(&result) || evaluateConstantOperands(alloc, &result)) {
5665 if (type() == MIRType::Int32) {
5666 return MConstant::New(alloc, Int32Value(result));
5667 }
5668
5669 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"
, 5669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 5669; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5670 return MConstant::New(alloc, BooleanValue(result));
5671 }
5672
5673 if (MDefinition* folded = tryFoldTypeOf(alloc); folded != this) {
5674 return folded;
5675 }
5676
5677 if (MDefinition* folded = tryFoldCharCompare(alloc); folded != this) {
5678 return folded;
5679 }
5680
5681 if (MDefinition* folded = tryFoldStringCompare(alloc); folded != this) {
5682 return folded;
5683 }
5684
5685 if (MDefinition* folded = tryFoldStringSubstring(alloc); folded != this) {
5686 return folded;
5687 }
5688
5689 if (MDefinition* folded = tryFoldStringIndexOf(alloc); folded != this) {
5690 return folded;
5691 }
5692
5693 if (MDefinition* folded = tryFoldBigInt64(alloc); folded != this) {
5694 return folded;
5695 }
5696
5697 if (MDefinition* folded = tryFoldBigIntPtr(alloc); folded != this) {
5698 return folded;
5699 }
5700
5701 if (MDefinition* folded = tryFoldBigInt(alloc); folded != this) {
5702 return folded;
5703 }
5704
5705 return this;
5706}
5707
5708void MCompare::trySpecializeFloat32(TempAllocator& alloc) {
5709 if (AllOperandsCanProduceFloat32(this) && compareType_ == Compare_Double) {
5710 compareType_ = Compare_Float32;
5711 } else {
5712 ConvertOperandsToDouble(this, alloc);
5713 }
5714}
5715
5716MDefinition* MSameValue::foldsTo(TempAllocator& alloc) {
5717 MDefinition* lhs = left();
5718 if (lhs->isBox()) {
5719 lhs = lhs->toBox()->input();
5720 }
5721
5722 MDefinition* rhs = right();
5723 if (rhs->isBox()) {
5724 rhs = rhs->toBox()->input();
5725 }
5726
5727 // Trivially true if both operands are the same.
5728 if (lhs == rhs) {
5729 return MConstant::New(alloc, BooleanValue(true));
5730 }
5731
5732 // CacheIR optimizes the following cases, so don't bother to handle them here:
5733 // 1. Both inputs are numbers (int32 or double).
5734 // 2. Both inputs are strictly different types.
5735 // 3. Both inputs are the same type.
5736
5737 // Optimize when one operand is guaranteed to be |null|.
5738 if (lhs->type() == MIRType::Null || rhs->type() == MIRType::Null) {
5739 // The `null` value must be the right-hand side operand.
5740 auto* input = lhs->type() == MIRType::Null ? rhs : lhs;
5741 auto* cst = lhs->type() == MIRType::Null ? lhs : rhs;
5742 return MCompare::New(alloc, input, cst, JSOp::StrictEq,
5743 MCompare::Compare_Null);
5744 }
5745
5746 // Optimize when one operand is guaranteed to be |undefined|.
5747 if (lhs->type() == MIRType::Undefined || rhs->type() == MIRType::Undefined) {
5748 // The `undefined` value must be the right-hand side operand.
5749 auto* input = lhs->type() == MIRType::Undefined ? rhs : lhs;
5750 auto* cst = lhs->type() == MIRType::Undefined ? lhs : rhs;
5751 return MCompare::New(alloc, input, cst, JSOp::StrictEq,
5752 MCompare::Compare_Undefined);
5753 }
5754
5755 return this;
5756}
5757
5758MDefinition* MSameValueDouble::foldsTo(TempAllocator& alloc) {
5759 // Trivially true if both operands are the same.
5760 if (left() == right()) {
5761 return MConstant::New(alloc, BooleanValue(true));
5762 }
5763
5764 // At least one operand must be a constant.
5765 if (!left()->isConstant() && !right()->isConstant()) {
5766 return this;
5767 }
5768
5769 auto* input = left()->isConstant() ? right() : left();
5770 auto* cst = left()->isConstant() ? left() : right();
5771 double dbl = cst->toConstant()->toDouble();
5772
5773 // Use bitwise comparison for +/-0.
5774 if (dbl == 0.0) {
5775 auto* reinterp = MReinterpretCast::New(alloc, input, MIRType::Int64);
5776 block()->insertBefore(this, reinterp);
5777
5778 auto* zeroBitsCst =
5779 MConstant::NewInt64(alloc, mozilla::BitwiseCast<int64_t>(dbl));
5780 block()->insertBefore(this, zeroBitsCst);
5781
5782 return MCompare::New(alloc, reinterp, zeroBitsCst, JSOp::StrictEq,
5783 MCompare::Compare_Int64);
5784 }
5785
5786 // Fold `Object.is(d, NaN)` to `d !== d`.
5787 if (std::isnan(dbl)) {
5788 return MCompare::New(alloc, input, input, JSOp::StrictNe,
5789 MCompare::Compare_Double);
5790 }
5791
5792 // Otherwise fold to MCompare.
5793 return MCompare::New(alloc, left(), right(), JSOp::StrictEq,
5794 MCompare::Compare_Double);
5795}
5796
5797MDefinition* MNot::foldsTo(TempAllocator& alloc) {
5798 auto foldConstant = [&alloc](MDefinition* input, MIRType type) -> MConstant* {
5799 MConstant* inputConst = input->maybeConstantValue();
5800 if (!inputConst) {
5801 return nullptr;
5802 }
5803 bool b;
5804 if (!inputConst->valueToBoolean(&b)) {
5805 return nullptr;
5806 }
5807 if (type == MIRType::Int32) {
5808 return MConstant::New(alloc, Int32Value(!b));
5809 }
5810 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"
, 5810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 5810; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5811 return MConstant::New(alloc, BooleanValue(!b));
5812 };
5813
5814 // Fold if the input is constant.
5815 if (MConstant* folded = foldConstant(input(), type())) {
5816 return folded;
5817 }
5818
5819 // If the operand of the Not is itself a Not, they cancel out. But we can't
5820 // always convert Not(Not(x)) to x because that may loose the conversion to
5821 // boolean. We can simplify Not(Not(Not(x))) to Not(x) though.
5822 MDefinition* op = getOperand(0);
5823 if (op->isNot()) {
5824 MDefinition* opop = op->getOperand(0);
5825 if (opop->isNot()) {
5826 return opop;
5827 }
5828 }
5829
5830 // Not of an undefined or null value is always true
5831 if (input()->type() == MIRType::Undefined ||
5832 input()->type() == MIRType::Null) {
5833 return MConstant::New(alloc, BooleanValue(true));
5834 }
5835
5836 // Not of a symbol is always false.
5837 if (input()->type() == MIRType::Symbol) {
5838 return MConstant::New(alloc, BooleanValue(false));
5839 }
5840
5841 // Drop the conversion in `Not(Int64ToBigInt(int64))` to `Not(int64)`.
5842 if (input()->isInt64ToBigInt()) {
5843 MDefinition* int64 = input()->toInt64ToBigInt()->input();
5844 if (MConstant* folded = foldConstant(int64, type())) {
5845 return folded;
5846 }
5847 return MNot::New(alloc, int64);
5848 }
5849
5850 // Drop the conversion in `Not(IntPtrToBigInt(intptr))` to `Not(intptr)`.
5851 if (input()->isIntPtrToBigInt()) {
5852 MDefinition* intPtr = input()->toIntPtrToBigInt()->input();
5853 if (MConstant* folded = foldConstant(intPtr, type())) {
5854 return folded;
5855 }
5856 return MNot::New(alloc, intPtr);
5857 }
5858
5859 return this;
5860}
5861
5862void MNot::trySpecializeFloat32(TempAllocator& alloc) {
5863 (void)EnsureFloatInputOrConvert(this, alloc);
5864}
5865
5866#ifdef JS_JITSPEW1
5867void MBeta::printOpcode(GenericPrinter& out) const {
5868 MDefinition::printOpcode(out);
5869
5870 out.printf(" ");
5871 comparison_->dump(out);
5872}
5873#endif
5874
5875AliasSet MCreateThis::getAliasSet() const {
5876 return AliasSet::Load(AliasSet::Any);
5877}
5878
5879bool MGetArgumentsObjectArg::congruentTo(const MDefinition* ins) const {
5880 if (!ins->isGetArgumentsObjectArg()) {
5881 return false;
5882 }
5883 if (ins->toGetArgumentsObjectArg()->argno() != argno()) {
5884 return false;
5885 }
5886 return congruentIfOperandsEqual(ins);
5887}
5888
5889AliasSet MGetArgumentsObjectArg::getAliasSet() const {
5890 return AliasSet::Load(AliasSet::Any);
5891}
5892
5893AliasSet MSetArgumentsObjectArg::getAliasSet() const {
5894 return AliasSet::Store(AliasSet::Any);
5895}
5896
5897MObjectState::MObjectState(MObjectState* state)
5898 : MVariadicInstruction(classOpcode),
5899 numSlots_(state->numSlots_),
5900 numFixedSlots_(state->numFixedSlots_) {
5901 // This instruction is only used as a summary for bailout paths.
5902 setResultType(MIRType::Object);
5903 setRecoveredOnBailout();
5904}
5905
5906MObjectState::MObjectState(JSObject* templateObject)
5907 : MObjectState(templateObject->as<NativeObject>().shape()) {}
5908
5909MObjectState::MObjectState(const Shape* shape)
5910 : MVariadicInstruction(classOpcode) {
5911 // This instruction is only used as a summary for bailout paths.
5912 setResultType(MIRType::Object);
5913 setRecoveredOnBailout();
5914
5915 numSlots_ = shape->asShared().slotSpan();
5916 numFixedSlots_ = shape->asShared().numFixedSlots();
5917}
5918
5919/* static */
5920JSObject* MObjectState::templateObjectOf(MDefinition* obj) {
5921 // MNewPlainObject uses a shape constant, not an object.
5922 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"
, 5922); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!obj->isNewPlainObject()"
")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5923
5924 if (obj->isNewObject()) {
5925 return obj->toNewObject()->templateObject();
5926 } else if (obj->isNewCallObject()) {
5927 return obj->toNewCallObject()->templateObject();
5928 } else if (obj->isNewIterator()) {
5929 return obj->toNewIterator()->templateObject();
5930 }
5931
5932 MOZ_CRASH("unreachable")do { do { } while (false); MOZ_ReportCrash("" "unreachable", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5932); AnnotateMozCrashReason("MOZ_CRASH(" "unreachable" ")"
); do { *((volatile int*)__null) = 5932; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
5933}
5934
5935bool MObjectState::init(TempAllocator& alloc, MDefinition* obj) {
5936 if (!MVariadicInstruction::init(alloc, numSlots() + 1)) {
5937 return false;
5938 }
5939 // +1, for the Object.
5940 initOperand(0, obj);
5941 return true;
5942}
5943
5944void MObjectState::initFromTemplateObject(TempAllocator& alloc,
5945 MDefinition* undefinedVal) {
5946 if (object()->isNewPlainObject()) {
5947 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"
, 5948); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()"
")"); do { *((volatile int*)__null) = 5948; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5948 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"
, 5948); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()"
")"); do { *((volatile int*)__null) = 5948; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5949 for (size_t i = 0; i < numSlots(); i++) {
5950 initSlot(i, undefinedVal);
5951 }
5952 return;
5953 }
5954
5955 JSObject* templateObject = templateObjectOf(object());
5956
5957 // Initialize all the slots of the object state with the value contained in
5958 // the template object. This is needed to account values which are baked in
5959 // the template objects and not visible in IonMonkey, such as the
5960 // uninitialized-lexical magic value of call objects.
5961
5962 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"
, 5962); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject->is<NativeObject>()"
")"); do { *((volatile int*)__null) = 5962; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5963 NativeObject& nativeObject = templateObject->as<NativeObject>();
5964 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"
, 5964); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeObject.slotSpan() == numSlots()"
")"); do { *((volatile int*)__null) = 5964; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5965
5966 for (size_t i = 0; i < numSlots(); i++) {
5967 Value val = nativeObject.getSlot(i);
5968 MDefinition* def = undefinedVal;
5969 if (!val.isUndefined()) {
5970 MConstant* ins = MConstant::New(alloc, val);
5971 block()->insertBefore(this, ins);
5972 def = ins;
5973 }
5974 initSlot(i, def);
5975 }
5976}
5977
5978MObjectState* MObjectState::New(TempAllocator& alloc, MDefinition* obj) {
5979 MObjectState* res;
5980 if (obj->isNewPlainObject()) {
5981 const Shape* shape = obj->toNewPlainObject()->shape();
5982 res = new (alloc) MObjectState(shape);
5983 } else {
5984 JSObject* templateObject = templateObjectOf(obj);
5985 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"
, 5985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject"
") (" "Unexpected object creation." ")"); do { *((volatile int
*)__null) = 5985; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5986 res = new (alloc) MObjectState(templateObject);
5987 }
5988
5989 if (!res || !res->init(alloc, obj)) {
5990 return nullptr;
5991 }
5992 return res;
5993}
5994
5995MObjectState* MObjectState::Copy(TempAllocator& alloc, MObjectState* state) {
5996 MObjectState* res = new (alloc) MObjectState(state);
5997 if (!res || !res->init(alloc, state->object())) {
5998 return nullptr;
5999 }
6000 for (size_t i = 0; i < res->numSlots(); i++) {
6001 res->initSlot(i, state->getSlot(i));
6002 }
6003 return res;
6004}
6005
6006MArrayState::MArrayState(MDefinition* arr) : MVariadicInstruction(classOpcode) {
6007 // This instruction is only used as a summary for bailout paths.
6008 setResultType(MIRType::Object);
6009 setRecoveredOnBailout();
6010 if (arr->isNewArrayObject()) {
6011 numElements_ = arr->toNewArrayObject()->length();
6012 } else {
6013 numElements_ = arr->toNewArray()->length();
6014 }
6015}
6016
6017bool MArrayState::init(TempAllocator& alloc, MDefinition* obj,
6018 MDefinition* len) {
6019 if (!MVariadicInstruction::init(alloc, numElements() + 2)) {
6020 return false;
6021 }
6022 // +1, for the Array object.
6023 initOperand(0, obj);
6024 // +1, for the length value of the array.
6025 initOperand(1, len);
6026 return true;
6027}
6028
6029void MArrayState::initFromTemplateObject(TempAllocator& alloc,
6030 MDefinition* undefinedVal) {
6031 for (size_t i = 0; i < numElements(); i++) {
6032 initElement(i, undefinedVal);
6033 }
6034}
6035
6036MArrayState* MArrayState::New(TempAllocator& alloc, MDefinition* arr,
6037 MDefinition* initLength) {
6038 MArrayState* res = new (alloc) MArrayState(arr);
6039 if (!res || !res->init(alloc, arr, initLength)) {
6040 return nullptr;
6041 }
6042 return res;
6043}
6044
6045MArrayState* MArrayState::Copy(TempAllocator& alloc, MArrayState* state) {
6046 MDefinition* arr = state->array();
6047 MDefinition* len = state->initializedLength();
6048 MArrayState* res = new (alloc) MArrayState(arr);
6049 if (!res || !res->init(alloc, arr, len)) {
6050 return nullptr;
6051 }
6052 for (size_t i = 0; i < res->numElements(); i++) {
6053 res->initElement(i, state->getElement(i));
6054 }
6055 return res;
6056}
6057
6058MNewArray::MNewArray(uint32_t length, MConstant* templateConst,
6059 gc::Heap initialHeap, bool vmCall)
6060 : MUnaryInstruction(classOpcode, templateConst),
6061 length_(length),
6062 initialHeap_(initialHeap),
6063 vmCall_(vmCall) {
6064 setResultType(MIRType::Object);
6065}
6066
6067MDefinition::AliasType MLoadFixedSlot::mightAlias(
6068 const MDefinition* def) const {
6069 if (def->isStoreFixedSlot()) {
6070 const MStoreFixedSlot* store = def->toStoreFixedSlot();
6071 if (store->slot() != slot()) {
6072 return AliasType::NoAlias;
6073 }
6074 if (store->object() != object()) {
6075 return AliasType::MayAlias;
6076 }
6077 return AliasType::MustAlias;
6078 }
6079 return AliasType::MayAlias;
6080}
6081
6082MDefinition* MLoadFixedSlot::foldsTo(TempAllocator& alloc) {
6083 if (MDefinition* def = foldsToStore(alloc)) {
6084 return def;
6085 }
6086
6087 return this;
6088}
6089
6090MDefinition::AliasType MLoadFixedSlotAndUnbox::mightAlias(
6091 const MDefinition* def) const {
6092 if (def->isStoreFixedSlot()) {
6093 const MStoreFixedSlot* store = def->toStoreFixedSlot();
6094 if (store->slot() != slot()) {
6095 return AliasType::NoAlias;
6096 }
6097 if (store->object() != object()) {
6098 return AliasType::MayAlias;
6099 }
6100 return AliasType::MustAlias;
6101 }
6102 return AliasType::MayAlias;
6103}
6104
6105MDefinition* MLoadFixedSlotAndUnbox::foldsTo(TempAllocator& alloc) {
6106 if (MDefinition* def = foldsToStore(alloc)) {
6107 return def;
6108 }
6109
6110 return this;
6111}
6112
6113MDefinition::AliasType MLoadDynamicSlot::mightAlias(
6114 const MDefinition* def) const {
6115 if (def->isStoreDynamicSlot()) {
6116 const MStoreDynamicSlot* store = def->toStoreDynamicSlot();
6117 if (store->slot() != slot()) {
6118 return AliasType::NoAlias;
6119 }
6120
6121 if (store->slots() != slots()) {
6122 return AliasType::MayAlias;
6123 }
6124
6125 return AliasType::MustAlias;
6126 }
6127 return AliasType::MayAlias;
6128}
6129
6130HashNumber MLoadDynamicSlot::valueHash() const {
6131 HashNumber hash = MDefinition::valueHash();
6132 hash = addU32ToHash(hash, slot_);
6133 return hash;
6134}
6135
6136MDefinition* MLoadDynamicSlot::foldsTo(TempAllocator& alloc) {
6137 if (MDefinition* def = foldsToStore(alloc)) {
6138 return def;
6139 }
6140
6141 return this;
6142}
6143
6144#ifdef JS_JITSPEW1
6145void MLoadDynamicSlot::printOpcode(GenericPrinter& out) const {
6146 MDefinition::printOpcode(out);
6147 out.printf(" (slot %u)", slot());
6148}
6149
6150void MLoadDynamicSlotAndUnbox::printOpcode(GenericPrinter& out) const {
6151 MDefinition::printOpcode(out);
6152 out.printf(" (slot %zu)", slot());
6153}
6154
6155void MStoreDynamicSlot::printOpcode(GenericPrinter& out) const {
6156 MDefinition::printOpcode(out);
6157 out.printf(" (slot %u)", slot());
6158}
6159
6160void MLoadFixedSlot::printOpcode(GenericPrinter& out) const {
6161 MDefinition::printOpcode(out);
6162 out.printf(" (slot %zu)", slot());
6163}
6164
6165void MLoadFixedSlotAndUnbox::printOpcode(GenericPrinter& out) const {
6166 MDefinition::printOpcode(out);
6167 out.printf(" (slot %zu)", slot());
6168}
6169
6170void MStoreFixedSlot::printOpcode(GenericPrinter& out) const {
6171 MDefinition::printOpcode(out);
6172 out.printf(" (slot %zu)", slot());
6173}
6174#endif
6175
6176MDefinition* MGuardFunctionScript::foldsTo(TempAllocator& alloc) {
6177 MDefinition* in = input();
6178 if (in->isLambda() &&
6179 in->toLambda()->templateFunction()->baseScript() == expected()) {
6180 return in;
6181 }
6182 return this;
6183}
6184
6185MDefinition* MFunctionEnvironment::foldsTo(TempAllocator& alloc) {
6186 if (input()->isLambda()) {
6187 return input()->toLambda()->environmentChain();
6188 }
6189 if (input()->isFunctionWithProto()) {
6190 return input()->toFunctionWithProto()->environmentChain();
6191 }
6192 return this;
6193}
6194
6195static bool AddIsANonZeroAdditionOf(MAdd* add, MDefinition* ins) {
6196 if (add->lhs() != ins && add->rhs() != ins) {
6197 return false;
6198 }
6199 MDefinition* other = (add->lhs() == ins) ? add->rhs() : add->lhs();
6200 if (!IsNumberType(other->type())) {
6201 return false;
6202 }
6203 if (!other->isConstant()) {
6204 return false;
6205 }
6206 if (other->toConstant()->numberToDouble() == 0) {
6207 return false;
6208 }
6209 return true;
6210}
6211
6212// Skip over instructions that usually appear between the actual index
6213// value being used and the MLoadElement.
6214// They don't modify the index value in a meaningful way.
6215static MDefinition* SkipUninterestingInstructions(MDefinition* ins) {
6216 // Drop the MToNumberInt32 added by the TypePolicy for double and float
6217 // values.
6218 if (ins->isToNumberInt32()) {
6219 return SkipUninterestingInstructions(ins->toToNumberInt32()->input());
6220 }
6221
6222 // Ignore the bounds check, which don't modify the index.
6223 if (ins->isBoundsCheck()) {
6224 return SkipUninterestingInstructions(ins->toBoundsCheck()->index());
6225 }
6226
6227 // Masking the index for Spectre-mitigation is not observable.
6228 if (ins->isSpectreMaskIndex()) {
6229 return SkipUninterestingInstructions(ins->toSpectreMaskIndex()->index());
6230 }
6231
6232 return ins;
6233}
6234
6235static bool DefinitelyDifferentValue(MDefinition* ins1, MDefinition* ins2) {
6236 ins1 = SkipUninterestingInstructions(ins1);
6237 ins2 = SkipUninterestingInstructions(ins2);
6238
6239 if (ins1 == ins2) {
6240 return false;
6241 }
6242
6243 // For constants check they are not equal.
6244 if (ins1->isConstant() && ins2->isConstant()) {
6245 MConstant* cst1 = ins1->toConstant();
6246 MConstant* cst2 = ins2->toConstant();
6247
6248 if (!cst1->isTypeRepresentableAsDouble() ||
6249 !cst2->isTypeRepresentableAsDouble()) {
6250 return false;
6251 }
6252
6253 // Be conservative and only allow values that fit into int32.
6254 int32_t n1, n2;
6255 if (!mozilla::NumberIsInt32(cst1->numberToDouble(), &n1) ||
6256 !mozilla::NumberIsInt32(cst2->numberToDouble(), &n2)) {
6257 return false;
6258 }
6259
6260 return n1 != n2;
6261 }
6262
6263 // Check if "ins1 = ins2 + cte", which would make both instructions
6264 // have different values.
6265 if (ins1->isAdd()) {
6266 if (AddIsANonZeroAdditionOf(ins1->toAdd(), ins2)) {
6267 return true;
6268 }
6269 }
6270 if (ins2->isAdd()) {
6271 if (AddIsANonZeroAdditionOf(ins2->toAdd(), ins1)) {
6272 return true;
6273 }
6274 }
6275
6276 return false;
6277}
6278
6279MDefinition::AliasType MLoadElement::mightAlias(const MDefinition* def) const {
6280 if (def->isStoreElement()) {
6281 const MStoreElement* store = def->toStoreElement();
6282 if (store->index() != index()) {
6283 if (DefinitelyDifferentValue(store->index(), index())) {
6284 return AliasType::NoAlias;
6285 }
6286 return AliasType::MayAlias;
6287 }
6288
6289 if (store->elements() != elements()) {
6290 return AliasType::MayAlias;
6291 }
6292
6293 return AliasType::MustAlias;
6294 }
6295 return AliasType::MayAlias;
6296}
6297
6298MDefinition* MLoadElement::foldsTo(TempAllocator& alloc) {
6299 if (MDefinition* def = foldsToStore(alloc)) {
6300 return def;
6301 }
6302
6303 return this;
6304}
6305
6306void MSqrt::trySpecializeFloat32(TempAllocator& alloc) {
6307 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
6308 setResultType(MIRType::Float32);
6309 specialization_ = MIRType::Float32;
6310 }
6311}
6312
6313MDefinition* MClz::foldsTo(TempAllocator& alloc) {
6314 if (num()->isConstant()) {
6315 MConstant* c = num()->toConstant();
6316 if (type() == MIRType::Int32) {
6317 int32_t n = c->toInt32();
6318 if (n == 0) {
6319 return MConstant::New(alloc, Int32Value(32));
6320 }
6321 return MConstant::New(alloc,
6322 Int32Value(mozilla::CountLeadingZeroes32(n)));
6323 }
6324 int64_t n = c->toInt64();
6325 if (n == 0) {
6326 return MConstant::NewInt64(alloc, int64_t(64));
6327 }
6328 return MConstant::NewInt64(alloc,
6329 int64_t(mozilla::CountLeadingZeroes64(n)));
6330 }
6331
6332 return this;
6333}
6334
6335MDefinition* MCtz::foldsTo(TempAllocator& alloc) {
6336 if (num()->isConstant()) {
6337 MConstant* c = num()->toConstant();
6338 if (type() == MIRType::Int32) {
6339 int32_t n = num()->toConstant()->toInt32();
6340 if (n == 0) {
6341 return MConstant::New(alloc, Int32Value(32));
6342 }
6343 return MConstant::New(alloc,
6344 Int32Value(mozilla::CountTrailingZeroes32(n)));
6345 }
6346 int64_t n = c->toInt64();
6347 if (n == 0) {
6348 return MConstant::NewInt64(alloc, int64_t(64));
6349 }
6350 return MConstant::NewInt64(alloc,
6351 int64_t(mozilla::CountTrailingZeroes64(n)));
6352 }
6353
6354 return this;
6355}
6356
6357MDefinition* MPopcnt::foldsTo(TempAllocator& alloc) {
6358 if (num()->isConstant()) {
6359 MConstant* c = num()->toConstant();
6360 if (type() == MIRType::Int32) {
6361 int32_t n = num()->toConstant()->toInt32();
6362 return MConstant::New(alloc, Int32Value(mozilla::CountPopulation32(n)));
6363 }
6364 int64_t n = c->toInt64();
6365 return MConstant::NewInt64(alloc, int64_t(mozilla::CountPopulation64(n)));
6366 }
6367
6368 return this;
6369}
6370
6371MDefinition* MBoundsCheck::foldsTo(TempAllocator& alloc) {
6372 if (type() == MIRType::Int32 && index()->isConstant() &&
6373 length()->isConstant()) {
6374 uint32_t len = length()->toConstant()->toInt32();
6375 uint32_t idx = index()->toConstant()->toInt32();
6376 if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len) {
6377 return index();
6378 }
6379 }
6380
6381 return this;
6382}
6383
6384MDefinition* MTableSwitch::foldsTo(TempAllocator& alloc) {
6385 MDefinition* op = getOperand(0);
6386
6387 // If we only have one successor, convert to a plain goto to the only
6388 // successor. TableSwitch indices are numeric; other types will always go to
6389 // the only successor.
6390 if (numSuccessors() == 1 ||
6391 (op->type() != MIRType::Value && !IsNumberType(op->type()))) {
6392 return MGoto::New(alloc, getDefault());
6393 }
6394
6395 if (MConstant* opConst = op->maybeConstantValue()) {
6396 if (op->type() == MIRType::Int32) {
6397 int32_t i = opConst->toInt32() - low_;
6398 MBasicBlock* target;
6399 if (size_t(i) < numCases()) {
6400 target = getCase(size_t(i));
6401 } else {
6402 target = getDefault();
6403 }
6404 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"
, 6404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")"
); do { *((volatile int*)__null) = 6404; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6405 return MGoto::New(alloc, target);
6406 }
6407 }
6408
6409 return this;
6410}
6411
6412MDefinition* MArrayJoin::foldsTo(TempAllocator& alloc) {
6413 MDefinition* arr = array();
6414
6415 if (!arr->isStringSplit()) {
6416 return this;
6417 }
6418
6419 setRecoveredOnBailout();
6420 if (arr->hasLiveDefUses()) {
6421 setNotRecoveredOnBailout();
6422 return this;
6423 }
6424
6425 // The MStringSplit won't generate any code.
6426 arr->setRecoveredOnBailout();
6427
6428 // We're replacing foo.split(bar).join(baz) by
6429 // foo.replace(bar, baz). MStringSplit could be recovered by
6430 // a bailout. As we are removing its last use, and its result
6431 // could be captured by a resume point, this MStringSplit will
6432 // be executed on the bailout path.
6433 MDefinition* string = arr->toStringSplit()->string();
6434 MDefinition* pattern = arr->toStringSplit()->separator();
6435 MDefinition* replacement = sep();
6436
6437 MStringReplace* substr =
6438 MStringReplace::New(alloc, string, pattern, replacement);
6439 substr->setFlatReplacement();
6440 return substr;
6441}
6442
6443MDefinition* MGetFirstDollarIndex::foldsTo(TempAllocator& alloc) {
6444 MDefinition* strArg = str();
6445 if (!strArg->isConstant()) {
6446 return this;
6447 }
6448
6449 JSLinearString* str = &strArg->toConstant()->toString()->asLinear();
6450 int32_t index = GetFirstDollarIndexRawFlat(str);
6451 return MConstant::New(alloc, Int32Value(index));
6452}
6453
6454AliasSet MThrowRuntimeLexicalError::getAliasSet() const {
6455 return AliasSet::Store(AliasSet::ExceptionState);
6456}
6457
6458AliasSet MSlots::getAliasSet() const {
6459 return AliasSet::Load(AliasSet::ObjectFields);
6460}
6461
6462MDefinition::AliasType MSlots::mightAlias(const MDefinition* store) const {
6463 // ArrayPush only modifies object elements, but not object slots.
6464 if (store->isArrayPush()) {
6465 return AliasType::NoAlias;
6466 }
6467 return MInstruction::mightAlias(store);
6468}
6469
6470AliasSet MElements::getAliasSet() const {
6471 return AliasSet::Load(AliasSet::ObjectFields);
6472}
6473
6474AliasSet MInitializedLength::getAliasSet() const {
6475 return AliasSet::Load(AliasSet::ObjectFields);
6476}
6477
6478AliasSet MSetInitializedLength::getAliasSet() const {
6479 return AliasSet::Store(AliasSet::ObjectFields);
6480}
6481
6482AliasSet MObjectKeysLength::getAliasSet() const {
6483 return AliasSet::Load(AliasSet::ObjectFields);
6484}
6485
6486AliasSet MArrayLength::getAliasSet() const {
6487 return AliasSet::Load(AliasSet::ObjectFields);
6488}
6489
6490AliasSet MSetArrayLength::getAliasSet() const {
6491 return AliasSet::Store(AliasSet::ObjectFields);
6492}
6493
6494AliasSet MFunctionLength::getAliasSet() const {
6495 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6496 AliasSet::DynamicSlot);
6497}
6498
6499AliasSet MFunctionName::getAliasSet() const {
6500 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6501 AliasSet::DynamicSlot);
6502}
6503
6504AliasSet MArrayBufferByteLength::getAliasSet() const {
6505 return AliasSet::Load(AliasSet::FixedSlot);
6506}
6507
6508AliasSet MArrayBufferViewLength::getAliasSet() const {
6509 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset);
6510}
6511
6512AliasSet MArrayBufferViewByteOffset::getAliasSet() const {
6513 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset);
6514}
6515
6516AliasSet MArrayBufferViewElements::getAliasSet() const {
6517 return AliasSet::Load(AliasSet::ObjectFields);
6518}
6519
6520AliasSet MGuardHasAttachedArrayBuffer::getAliasSet() const {
6521 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot);
6522}
6523
6524AliasSet MResizableTypedArrayByteOffsetMaybeOutOfBounds::getAliasSet() const {
6525 // Loads the byteOffset and additionally checks for detached buffers, so the
6526 // alias set also has to include |ObjectFields| and |FixedSlot|.
6527 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset |
6528 AliasSet::ObjectFields | AliasSet::FixedSlot);
6529}
6530
6531AliasSet MResizableTypedArrayLength::getAliasSet() const {
6532 // Loads the length and byteOffset slots, the shared-elements flag, the
6533 // auto-length fixed slot, and the shared raw-buffer length.
6534 auto flags = AliasSet::ArrayBufferViewLengthOrOffset |
6535 AliasSet::ObjectFields | AliasSet::FixedSlot |
6536 AliasSet::SharedArrayRawBufferLength;
6537
6538 // When a barrier is needed make the instruction effectful by giving it a
6539 // "store" effect. Also prevent reordering LoadUnboxedScalar before this
6540 // instruction by including |UnboxedElement| in the alias set.
6541 if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
6542 return AliasSet::Store(flags | AliasSet::UnboxedElement);
6543 }
6544 return AliasSet::Load(flags);
6545}
6546
6547bool MResizableTypedArrayLength::congruentTo(const MDefinition* ins) const {
6548 if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
6549 return false;
6550 }
6551 return congruentIfOperandsEqual(ins);
6552}
6553
6554AliasSet MResizableDataViewByteLength::getAliasSet() const {
6555 // Loads the length and byteOffset slots, the shared-elements flag, the
6556 // auto-length fixed slot, and the shared raw-buffer length.
6557 auto flags = AliasSet::ArrayBufferViewLengthOrOffset |
6558 AliasSet::ObjectFields | AliasSet::FixedSlot |
6559 AliasSet::SharedArrayRawBufferLength;
6560
6561 // When a barrier is needed make the instruction effectful by giving it a
6562 // "store" effect. Also prevent reordering LoadUnboxedScalar before this
6563 // instruction by including |UnboxedElement| in the alias set.
6564 if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
6565 return AliasSet::Store(flags | AliasSet::UnboxedElement);
6566 }
6567 return AliasSet::Load(flags);
6568}
6569
6570bool MResizableDataViewByteLength::congruentTo(const MDefinition* ins) const {
6571 if (requiresMemoryBarrier() == MemoryBarrierRequirement::Required) {
6572 return false;
6573 }
6574 return congruentIfOperandsEqual(ins);
6575}
6576
6577AliasSet MGrowableSharedArrayBufferByteLength::getAliasSet() const {
6578 // Requires a barrier, so make the instruction effectful by giving it a
6579 // "store" effect. Also prevent reordering LoadUnboxedScalar before this
6580 // instruction by including |UnboxedElement| in the alias set.
6581 return AliasSet::Store(AliasSet::FixedSlot |
6582 AliasSet::SharedArrayRawBufferLength |
6583 AliasSet::UnboxedElement);
6584}
6585
6586AliasSet MGuardResizableArrayBufferViewInBounds::getAliasSet() const {
6587 // Additionally reads the |initialLength| and |initialByteOffset| slots, but
6588 // since these can't change after construction, we don't need to track them.
6589 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset);
6590}
6591
6592AliasSet MGuardResizableArrayBufferViewInBoundsOrDetached::getAliasSet() const {
6593 // Loads the byteOffset and additionally checks for detached buffers, so the
6594 // alias set also has to include |ObjectFields| and |FixedSlot|.
6595 return AliasSet::Load(AliasSet::ArrayBufferViewLengthOrOffset |
6596 AliasSet::ObjectFields | AliasSet::FixedSlot);
6597}
6598
6599AliasSet MArrayPush::getAliasSet() const {
6600 return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
6601}
6602
6603MDefinition* MGuardNumberToIntPtrIndex::foldsTo(TempAllocator& alloc) {
6604 MDefinition* input = this->input();
6605
6606 if (input->isToDouble() && input->getOperand(0)->type() == MIRType::Int32) {
6607 return MInt32ToIntPtr::New(alloc, input->getOperand(0));
6608 }
6609
6610 if (!input->isConstant()) {
6611 return this;
6612 }
6613
6614 // Fold constant double representable as intptr to intptr.
6615 int64_t ival;
6616 if (!mozilla::NumberEqualsInt64(input->toConstant()->toDouble(), &ival)) {
6617 // If not representable as an int64, this access is equal to an OOB access.
6618 // So replace it with a known int64/intptr value which also produces an OOB
6619 // access. If we don't support OOB accesses we have to bail out.
6620 if (!supportOOB()) {
6621 return this;
6622 }
6623 ival = -1;
6624 }
6625
6626 if (ival < INTPTR_MIN(-9223372036854775807L-1) || ival > INTPTR_MAX(9223372036854775807L)) {
6627 return this;
6628 }
6629
6630 return MConstant::NewIntPtr(alloc, intptr_t(ival));
6631}
6632
6633MDefinition* MIsObject::foldsTo(TempAllocator& alloc) {
6634 if (!object()->isBox()) {
6635 return this;
6636 }
6637
6638 MDefinition* unboxed = object()->getOperand(0);
6639 if (unboxed->type() == MIRType::Object) {
6640 return MConstant::New(alloc, BooleanValue(true));
6641 }
6642
6643 return this;
6644}
6645
6646MDefinition* MIsNullOrUndefined::foldsTo(TempAllocator& alloc) {
6647 MDefinition* input = value();
6648 if (input->isBox()) {
6649 input = input->toBox()->input();
6650 }
6651
6652 if (input->definitelyType({MIRType::Null, MIRType::Undefined})) {
6653 return MConstant::New(alloc, BooleanValue(true));
6654 }
6655
6656 if (!input->mightBeType(MIRType::Null) &&
6657 !input->mightBeType(MIRType::Undefined)) {
6658 return MConstant::New(alloc, BooleanValue(false));
6659 }
6660
6661 return this;
6662}
6663
6664AliasSet MHomeObjectSuperBase::getAliasSet() const {
6665 return AliasSet::Load(AliasSet::ObjectFields);
6666}
6667
6668MDefinition* MGuardValue::foldsTo(TempAllocator& alloc) {
6669 if (MConstant* cst = value()->maybeConstantValue()) {
6670 if (cst->toJSValue() == expected()) {
6671 return value();
6672 }
6673 }
6674
6675 return this;
6676}
6677
6678MDefinition* MGuardNullOrUndefined::foldsTo(TempAllocator& alloc) {
6679 MDefinition* input = value();
6680 if (input->isBox()) {
6681 input = input->toBox()->input();
6682 }
6683
6684 if (input->definitelyType({MIRType::Null, MIRType::Undefined})) {
6685 return value();
6686 }
6687
6688 return this;
6689}
6690
6691MDefinition* MGuardIsNotObject::foldsTo(TempAllocator& alloc) {
6692 MDefinition* input = value();
6693 if (input->isBox()) {
6694 input = input->toBox()->input();
6695 }
6696
6697 if (!input->mightBeType(MIRType::Object)) {
6698 return value();
6699 }
6700
6701 return this;
6702}
6703
6704MDefinition* MGuardObjectIdentity::foldsTo(TempAllocator& alloc) {
6705 if (object()->isConstant() && expected()->isConstant()) {
6706 JSObject* obj = &object()->toConstant()->toObject();
6707 JSObject* other = &expected()->toConstant()->toObject();
6708 if (!bailOnEquality()) {
6709 if (obj == other) {
6710 return object();
6711 }
6712 } else {
6713 if (obj != other) {
6714 return object();
6715 }
6716 }
6717 }
6718
6719 if (!bailOnEquality() && object()->isNurseryObject() &&
6720 expected()->isNurseryObject()) {
6721 uint32_t objIndex = object()->toNurseryObject()->nurseryIndex();
6722 uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex();
6723 if (objIndex == otherIndex) {
6724 return object();
6725 }
6726 }
6727
6728 return this;
6729}
6730
6731MDefinition* MGuardSpecificFunction::foldsTo(TempAllocator& alloc) {
6732 if (function()->isConstant() && expected()->isConstant()) {
6733 JSObject* fun = &function()->toConstant()->toObject();
6734 JSObject* other = &expected()->toConstant()->toObject();
6735 if (fun == other) {
6736 return function();
6737 }
6738 }
6739
6740 if (function()->isNurseryObject() && expected()->isNurseryObject()) {
6741 uint32_t funIndex = function()->toNurseryObject()->nurseryIndex();
6742 uint32_t otherIndex = expected()->toNurseryObject()->nurseryIndex();
6743 if (funIndex == otherIndex) {
6744 return function();
6745 }
6746 }
6747
6748 return this;
6749}
6750
6751MDefinition* MGuardSpecificAtom::foldsTo(TempAllocator& alloc) {
6752 if (str()->isConstant()) {
6753 JSString* s = str()->toConstant()->toString();
6754 if (s->isAtom()) {
6755 JSAtom* cstAtom = &s->asAtom();
6756 if (cstAtom == atom()) {
6757 return str();
6758 }
6759 }
6760 }
6761
6762 return this;
6763}
6764
6765MDefinition* MGuardSpecificSymbol::foldsTo(TempAllocator& alloc) {
6766 if (symbol()->isConstant()) {
6767 if (symbol()->toConstant()->toSymbol() == expected()) {
6768 return symbol();
6769 }
6770 }
6771
6772 return this;
6773}
6774
6775MDefinition* MGuardSpecificInt32::foldsTo(TempAllocator& alloc) {
6776 if (num()->isConstant() && num()->toConstant()->isInt32(expected())) {
6777 return num();
6778 }
6779 return this;
6780}
6781
6782bool MCallBindVar::congruentTo(const MDefinition* ins) const {
6783 if (!ins->isCallBindVar()) {
6784 return false;
6785 }
6786 return congruentIfOperandsEqual(ins);
6787}
6788
6789bool MGuardShape::congruentTo(const MDefinition* ins) const {
6790 if (!ins->isGuardShape()) {
6791 return false;
6792 }
6793 if (shape() != ins->toGuardShape()->shape()) {
6794 return false;
6795 }
6796 return congruentIfOperandsEqual(ins);
6797}
6798
6799AliasSet MGuardShape::getAliasSet() const {
6800 return AliasSet::Load(AliasSet::ObjectFields);
6801}
6802
6803MDefinition::AliasType MGuardShape::mightAlias(const MDefinition* store) const {
6804 // These instructions only modify object elements, but not the shape.
6805 if (store->isStoreElementHole() || store->isArrayPush()) {
6806 return AliasType::NoAlias;
6807 }
6808 if (object()->isConstantProto()) {
6809 const MDefinition* receiverObject =
6810 object()->toConstantProto()->getReceiverObject();
6811 switch (store->op()) {
6812 case MDefinition::Opcode::StoreFixedSlot:
6813 if (store->toStoreFixedSlot()->object()->skipObjectGuards() ==
6814 receiverObject) {
6815 return AliasType::NoAlias;
6816 }
6817 break;
6818 case MDefinition::Opcode::StoreDynamicSlot:
6819 if (store->toStoreDynamicSlot()
6820 ->slots()
6821 ->toSlots()
6822 ->object()
6823 ->skipObjectGuards() == receiverObject) {
6824 return AliasType::NoAlias;
6825 }
6826 break;
6827 case MDefinition::Opcode::AddAndStoreSlot:
6828 if (store->toAddAndStoreSlot()->object()->skipObjectGuards() ==
6829 receiverObject) {
6830 return AliasType::NoAlias;
6831 }
6832 break;
6833 case MDefinition::Opcode::AllocateAndStoreSlot:
6834 if (store->toAllocateAndStoreSlot()->object()->skipObjectGuards() ==
6835 receiverObject) {
6836 return AliasType::NoAlias;
6837 }
6838 break;
6839 default:
6840 break;
6841 }
6842 }
6843 return MInstruction::mightAlias(store);
6844}
6845
6846bool MGuardFuse::congruentTo(const MDefinition* ins) const {
6847 if (!ins->isGuardFuse()) {
6848 return false;
6849 }
6850 if (fuseIndex() != ins->toGuardFuse()->fuseIndex()) {
6851 return false;
6852 }
6853 return congruentIfOperandsEqual(ins);
6854}
6855
6856AliasSet MGuardFuse::getAliasSet() const {
6857 // The alias set below reflects the set of operations which could cause a fuse
6858 // to be popped, and therefore MGuardFuse aliases with.
6859 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::DynamicSlot |
6860 AliasSet::FixedSlot |
6861 AliasSet::GlobalGenerationCounter);
6862}
6863
6864AliasSet MGuardMultipleShapes::getAliasSet() const {
6865 // Note: This instruction loads the elements of the ListObject used to
6866 // store the list of shapes, but that object is internal and not exposed
6867 // to script, so it doesn't have to be in the alias set.
6868 return AliasSet::Load(AliasSet::ObjectFields);
6869}
6870
6871AliasSet MGuardGlobalGeneration::getAliasSet() const {
6872 return AliasSet::Load(AliasSet::GlobalGenerationCounter);
6873}
6874
6875bool MGuardGlobalGeneration::congruentTo(const MDefinition* ins) const {
6876 return ins->isGuardGlobalGeneration() &&
6877 ins->toGuardGlobalGeneration()->expected() == expected() &&
6878 ins->toGuardGlobalGeneration()->generationAddr() == generationAddr();
6879}
6880
6881MDefinition* MGuardIsNotProxy::foldsTo(TempAllocator& alloc) {
6882 KnownClass known = GetObjectKnownClass(object());
6883 if (known == KnownClass::None) {
6884 return this;
6885 }
6886
6887 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"
, 6887); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetObjectKnownJSClass(object())->isProxyObject()"
")"); do { *((volatile int*)__null) = 6887; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6888 AssertKnownClass(alloc, this, object());
6889 return object();
6890}
6891
6892AliasSet MMegamorphicLoadSlotByValue::getAliasSet() const {
6893 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6894 AliasSet::DynamicSlot);
6895}
6896
6897MDefinition* MMegamorphicLoadSlotByValue::foldsTo(TempAllocator& alloc) {
6898 MDefinition* input = idVal();
6899 if (input->isBox()) {
6900 input = input->toBox()->input();
6901 }
6902
6903 MDefinition* result = this;
6904
6905 if (input->isConstant()) {
6906 MConstant* constant = input->toConstant();
6907 if (constant->type() == MIRType::Symbol) {
6908 PropertyKey id = PropertyKey::Symbol(constant->toSymbol());
6909 result = MMegamorphicLoadSlot::New(alloc, object(), id);
6910 }
6911
6912 if (constant->type() == MIRType::String) {
6913 JSString* str = constant->toString();
6914 if (str->isAtom() && !str->asAtom().isIndex()) {
6915 PropertyKey id = PropertyKey::NonIntAtom(str);
6916 result = MMegamorphicLoadSlot::New(alloc, object(), id);
6917 }
6918 }
6919 }
6920
6921 if (result != this) {
6922 result->setDependency(dependency());
6923 }
6924
6925 return result;
6926}
6927
6928MDefinition* MMegamorphicLoadSlotByValuePermissive::foldsTo(
6929 TempAllocator& alloc) {
6930 MDefinition* input = idVal();
6931 if (input->isBox()) {
6932 input = input->toBox()->input();
6933 }
6934
6935 MDefinition* result = this;
6936
6937 if (input->isConstant()) {
6938 MConstant* constant = input->toConstant();
6939 if (constant->type() == MIRType::Symbol) {
6940 PropertyKey id = PropertyKey::Symbol(constant->toSymbol());
6941 result = MMegamorphicLoadSlotPermissive::New(alloc, object(), id);
6942 }
6943
6944 if (constant->type() == MIRType::String) {
6945 JSString* str = constant->toString();
6946 if (str->isAtom() && !str->asAtom().isIndex()) {
6947 PropertyKey id = PropertyKey::NonIntAtom(str);
6948 result = MMegamorphicLoadSlotPermissive::New(alloc, object(), id);
6949 }
6950 }
6951 }
6952
6953 if (result != this) {
6954 result->toMegamorphicLoadSlotPermissive()->stealResumePoint(this);
6955 }
6956
6957 return result;
6958}
6959
6960bool MMegamorphicLoadSlot::congruentTo(const MDefinition* ins) const {
6961 if (!ins->isMegamorphicLoadSlot()) {
6962 return false;
6963 }
6964 if (ins->toMegamorphicLoadSlot()->name() != name()) {
6965 return false;
6966 }
6967 return congruentIfOperandsEqual(ins);
6968}
6969
6970AliasSet MMegamorphicLoadSlot::getAliasSet() const {
6971 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6972 AliasSet::DynamicSlot);
6973}
6974
6975bool MSmallObjectVariableKeyHasProp::congruentTo(const MDefinition* ins) const {
6976 if (!ins->isSmallObjectVariableKeyHasProp()) {
6977 return false;
6978 }
6979 if (ins->toSmallObjectVariableKeyHasProp()->shape() != shape()) {
6980 return false;
6981 }
6982 return congruentIfOperandsEqual(ins);
6983}
6984
6985AliasSet MSmallObjectVariableKeyHasProp::getAliasSet() const {
6986 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
6987 AliasSet::DynamicSlot);
6988}
6989
6990bool MMegamorphicHasProp::congruentTo(const MDefinition* ins) const {
6991 if (!ins->isMegamorphicHasProp()) {
6992 return false;
6993 }
6994 if (ins->toMegamorphicHasProp()->hasOwn() != hasOwn()) {
6995 return false;
6996 }
6997 return congruentIfOperandsEqual(ins);
6998}
6999
7000AliasSet MMegamorphicHasProp::getAliasSet() const {
7001 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
7002 AliasSet::DynamicSlot);
7003}
7004
7005bool MNurseryObject::congruentTo(const MDefinition* ins) const {
7006 if (!ins->isNurseryObject()) {
7007 return false;
7008 }
7009 return nurseryIndex() == ins->toNurseryObject()->nurseryIndex();
7010}
7011
7012AliasSet MGuardFunctionIsNonBuiltinCtor::getAliasSet() const {
7013 return AliasSet::Load(AliasSet::ObjectFields);
7014}
7015
7016bool MGuardFunctionKind::congruentTo(const MDefinition* ins) const {
7017 if (!ins->isGuardFunctionKind()) {
7018 return false;
7019 }
7020 if (expected() != ins->toGuardFunctionKind()->expected()) {
7021 return false;
7022 }
7023 if (bailOnEquality() != ins->toGuardFunctionKind()->bailOnEquality()) {
7024 return false;
7025 }
7026 return congruentIfOperandsEqual(ins);
7027}
7028
7029AliasSet MGuardFunctionKind::getAliasSet() const {
7030 return AliasSet::Load(AliasSet::ObjectFields);
7031}
7032
7033bool MGuardFunctionScript::congruentTo(const MDefinition* ins) const {
7034 if (!ins->isGuardFunctionScript()) {
7035 return false;
7036 }
7037 if (expected() != ins->toGuardFunctionScript()->expected()) {
7038 return false;
7039 }
7040 return congruentIfOperandsEqual(ins);
7041}
7042
7043AliasSet MGuardFunctionScript::getAliasSet() const {
7044 // A JSFunction's BaseScript pointer is immutable. Relazification of
7045 // top-level/named self-hosted functions is an exception to this, but we don't
7046 // use this guard for those self-hosted functions.
7047 // See IRGenerator::emitCalleeGuard.
7048 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"
, 7048); AnnotateMozCrashReason("MOZ_ASSERT" "(" "flags_.isLambda()"
")"); do { *((volatile int*)__null) = 7048; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
7049 return AliasSet::None();
7050}
7051
7052bool MGuardSpecificAtom::congruentTo(const MDefinition* ins) const {
7053 if (!ins->isGuardSpecificAtom()) {
7054 return false;
7055 }
7056 if (atom() != ins->toGuardSpecificAtom()->atom()) {
7057 return false;
7058 }
7059 return congruentIfOperandsEqual(ins);
7060}
7061
7062MDefinition* MGuardStringToIndex::foldsTo(TempAllocator& alloc) {
7063 if (!string()->isConstant()) {
7064 return this;
7065 }
7066
7067 JSString* str = string()->toConstant()->toString();
7068
7069 int32_t index = GetIndexFromString(str);
7070 if (index < 0) {
7071 return this;
7072 }
7073
7074 return MConstant::New(alloc, Int32Value(index));
7075}
7076
7077MDefinition* MGuardStringToInt32::foldsTo(TempAllocator& alloc) {
7078 if (!string()->isConstant()) {
7079 return this;
7080 }
7081
7082 JSLinearString* str = &string()->toConstant()->toString()->asLinear();
7083 double number = LinearStringToNumber(str);
7084
7085 int32_t n;
7086 if (!mozilla::NumberIsInt32(number, &n)) {
7087 return this;
7088 }
7089
7090 return MConstant::New(alloc, Int32Value(n));
7091}
7092
7093MDefinition* MGuardStringToDouble::foldsTo(TempAllocator& alloc) {
7094 if (!string()->isConstant()) {
7095 return this;
7096 }
7097
7098 JSLinearString* str = &string()->toConstant()->toString()->asLinear();
7099 double number = LinearStringToNumber(str);
7100 return MConstant::New(alloc, DoubleValue(number));
7101}
7102
7103AliasSet MGuardNoDenseElements::getAliasSet() const {
7104 return AliasSet::Load(AliasSet::ObjectFields);
7105}
7106
7107AliasSet MIteratorHasIndices::getAliasSet() const {
7108 return AliasSet::Load(AliasSet::ObjectFields);
7109}
7110
7111AliasSet MAllocateAndStoreSlot::getAliasSet() const {
7112 return AliasSet::Store(AliasSet::ObjectFields | AliasSet::DynamicSlot);
7113}
7114
7115AliasSet MLoadDOMExpandoValue::getAliasSet() const {
7116 return AliasSet::Load(AliasSet::DOMProxyExpando);
7117}
7118
7119AliasSet MLoadDOMExpandoValueIgnoreGeneration::getAliasSet() const {
7120 return AliasSet::Load(AliasSet::DOMProxyExpando);
7121}
7122
7123bool MGuardDOMExpandoMissingOrGuardShape::congruentTo(
7124 const MDefinition* ins) const {
7125 if (!ins->isGuardDOMExpandoMissingOrGuardShape()) {
7126 return false;
7127 }
7128 if (shape() != ins->toGuardDOMExpandoMissingOrGuardShape()->shape()) {
7129 return false;
7130 }
7131 return congruentIfOperandsEqual(ins);
7132}
7133
7134AliasSet MGuardDOMExpandoMissingOrGuardShape::getAliasSet() const {
7135 return AliasSet::Load(AliasSet::ObjectFields);
7136}
7137
7138MDefinition* MGuardToClass::foldsTo(TempAllocator& alloc) {
7139 const JSClass* clasp = GetObjectKnownJSClass(object());
7140 if (!clasp || getClass() != clasp) {
7141 return this;
7142 }
7143
7144 AssertKnownClass(alloc, this, object());
7145 return object();
7146}
7147
7148MDefinition* MGuardToEitherClass::foldsTo(TempAllocator& alloc) {
7149 const JSClass* clasp = GetObjectKnownJSClass(object());
7150 if (!clasp || (getClass1() != clasp && getClass2() != clasp)) {
7151 return this;
7152 }
7153
7154 AssertKnownClass(alloc, this, object());
7155 return object();
7156}
7157
7158MDefinition* MGuardToFunction::foldsTo(TempAllocator& alloc) {
7159 if (GetObjectKnownClass(object()) != KnownClass::Function) {
7160 return this;
7161 }
7162
7163 AssertKnownClass(alloc, this, object());
7164 return object();
7165}
7166
7167MDefinition* MHasClass::foldsTo(TempAllocator& alloc) {
7168 const JSClass* clasp = GetObjectKnownJSClass(object());
7169 if (!clasp) {
7170 return this;
7171 }
7172
7173 AssertKnownClass(alloc, this, object());
7174 return MConstant::New(alloc, BooleanValue(getClass() == clasp));
7175}
7176
7177MDefinition* MIsCallable::foldsTo(TempAllocator& alloc) {
7178 if (input()->type() != MIRType::Object) {
7179 return this;
7180 }
7181
7182 KnownClass known = GetObjectKnownClass(input());
7183 if (known == KnownClass::None) {
7184 return this;
7185 }
7186
7187 AssertKnownClass(alloc, this, input());
7188 return MConstant::New(alloc, BooleanValue(known == KnownClass::Function));
7189}
7190
7191MDefinition* MIsArray::foldsTo(TempAllocator& alloc) {
7192 if (input()->type() != MIRType::Object) {
7193 return this;
7194 }
7195
7196 KnownClass known = GetObjectKnownClass(input());
7197 if (known == KnownClass::None) {
7198 return this;
7199 }
7200
7201 AssertKnownClass(alloc, this, input());
7202 return MConstant::New(alloc, BooleanValue(known == KnownClass::Array));
7203}
7204
7205AliasSet MObjectClassToString::getAliasSet() const {
7206 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
7207 AliasSet::DynamicSlot);
7208}
7209
7210MDefinition* MGuardIsNotArrayBufferMaybeShared::foldsTo(TempAllocator& alloc) {
7211 switch (GetObjectKnownClass(object())) {
7212 case KnownClass::PlainObject:
7213 case KnownClass::Array:
7214 case KnownClass::Function:
7215 case KnownClass::RegExp:
7216 case KnownClass::ArrayIterator:
7217 case KnownClass::StringIterator:
7218 case KnownClass::RegExpStringIterator: {
7219 AssertKnownClass(alloc, this, object());
7220 return object();
7221 }
7222 case KnownClass::None:
7223 break;
7224 }
7225
7226 return this;
7227}
7228
7229MDefinition* MCheckIsObj::foldsTo(TempAllocator& alloc) {
7230 if (!input()->isBox()) {
7231 return this;
7232 }
7233
7234 MDefinition* unboxed = input()->getOperand(0);
7235 if (unboxed->type() == MIRType::Object) {
7236 return unboxed;
7237 }
7238
7239 return this;
7240}
7241
7242AliasSet MCheckIsObj::getAliasSet() const {
7243 return AliasSet::Store(AliasSet::ExceptionState);
7244}
7245
7246#ifdef JS_PUNBOX641
7247AliasSet MCheckScriptedProxyGetResult::getAliasSet() const {
7248 return AliasSet::Store(AliasSet::ExceptionState);
7249}
7250#endif
7251
7252static bool IsBoxedObject(MDefinition* def) {
7253 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"
, 7253); AnnotateMozCrashReason("MOZ_ASSERT" "(" "def->type() == MIRType::Value"
")"); do { *((volatile int*)__null) = 7253; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7254
7255 if (def->isBox()) {
7256 return def->toBox()->input()->type() == MIRType::Object;
7257 }
7258
7259 // Construct calls are always returning a boxed object.
7260 //
7261 // TODO: We should consider encoding this directly in the graph instead of
7262 // having to special case it here.
7263 if (def->isCall()) {
7264 return def->toCall()->isConstructing();
7265 }
7266 if (def->isConstructArray()) {
7267 return true;
7268 }
7269 if (def->isConstructArgs()) {
7270 return true;
7271 }
7272
7273 return false;
7274}
7275
7276MDefinition* MCheckReturn::foldsTo(TempAllocator& alloc) {
7277 auto* returnVal = returnValue();
7278 if (!returnVal->isBox()) {
7279 return this;
7280 }
7281
7282 auto* unboxedReturnVal = returnVal->toBox()->input();
7283 if (unboxedReturnVal->type() == MIRType::Object) {
7284 return returnVal;
7285 }
7286
7287 if (unboxedReturnVal->type() != MIRType::Undefined) {
7288 return this;
7289 }
7290
7291 auto* thisVal = thisValue();
7292 if (IsBoxedObject(thisVal)) {
7293 return thisVal;
7294 }
7295
7296 return this;
7297}
7298
7299MDefinition* MCheckThis::foldsTo(TempAllocator& alloc) {
7300 MDefinition* input = thisValue();
7301 if (!input->isBox()) {
7302 return this;
7303 }
7304
7305 MDefinition* unboxed = input->getOperand(0);
7306 if (unboxed->mightBeMagicType()) {
7307 return this;
7308 }
7309
7310 return input;
7311}
7312
7313MDefinition* MCheckThisReinit::foldsTo(TempAllocator& alloc) {
7314 MDefinition* input = thisValue();
7315 if (!input->isBox()) {
7316 return this;
7317 }
7318
7319 MDefinition* unboxed = input->getOperand(0);
7320 if (unboxed->type() != MIRType::MagicUninitializedLexical) {
7321 return this;
7322 }
7323
7324 return input;
7325}
7326
7327MDefinition* MCheckObjCoercible::foldsTo(TempAllocator& alloc) {
7328 MDefinition* input = checkValue();
7329 if (!input->isBox()) {
7330 return this;
7331 }
7332
7333 MDefinition* unboxed = input->getOperand(0);
7334 if (unboxed->mightBeType(MIRType::Null) ||
7335 unboxed->mightBeType(MIRType::Undefined)) {
7336 return this;
7337 }
7338
7339 return input;
7340}
7341
7342AliasSet MCheckObjCoercible::getAliasSet() const {
7343 return AliasSet::Store(AliasSet::ExceptionState);
7344}
7345
7346AliasSet MCheckReturn::getAliasSet() const {
7347 return AliasSet::Store(AliasSet::ExceptionState);
7348}
7349
7350AliasSet MCheckThis::getAliasSet() const {
7351 return AliasSet::Store(AliasSet::ExceptionState);
7352}
7353
7354AliasSet MCheckThisReinit::getAliasSet() const {
7355 return AliasSet::Store(AliasSet::ExceptionState);
7356}
7357
7358AliasSet MIsPackedArray::getAliasSet() const {
7359 return AliasSet::Load(AliasSet::ObjectFields);
7360}
7361
7362AliasSet MGuardArrayIsPacked::getAliasSet() const {
7363 return AliasSet::Load(AliasSet::ObjectFields);
7364}
7365
7366AliasSet MSuperFunction::getAliasSet() const {
7367 return AliasSet::Load(AliasSet::ObjectFields);
7368}
7369
7370AliasSet MInitHomeObject::getAliasSet() const {
7371 return AliasSet::Store(AliasSet::ObjectFields);
7372}
7373
7374AliasSet MLoadWrapperTarget::getAliasSet() const {
7375 return AliasSet::Load(AliasSet::Any);
7376}
7377
7378bool MLoadWrapperTarget::congruentTo(const MDefinition* ins) const {
7379 if (!ins->isLoadWrapperTarget()) {
7380 return false;
7381 }
7382 if (ins->toLoadWrapperTarget()->fallible() != fallible()) {
7383 return false;
7384 }
7385 return congruentIfOperandsEqual(ins);
7386}
7387
7388AliasSet MGuardHasGetterSetter::getAliasSet() const {
7389 return AliasSet::Load(AliasSet::ObjectFields);
7390}
7391
7392bool MGuardHasGetterSetter::congruentTo(const MDefinition* ins) const {
7393 if (!ins->isGuardHasGetterSetter()) {
7394 return false;
7395 }
7396 if (ins->toGuardHasGetterSetter()->propId() != propId()) {
7397 return false;
7398 }
7399 if (ins->toGuardHasGetterSetter()->getterSetter() != getterSetter()) {
7400 return false;
7401 }
7402 return congruentIfOperandsEqual(ins);
7403}
7404
7405AliasSet MGuardIsExtensible::getAliasSet() const {
7406 return AliasSet::Load(AliasSet::ObjectFields);
7407}
7408
7409AliasSet MGuardIndexIsNotDenseElement::getAliasSet() const {
7410 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::Element);
7411}
7412
7413AliasSet MGuardIndexIsValidUpdateOrAdd::getAliasSet() const {
7414 return AliasSet::Load(AliasSet::ObjectFields);
7415}
7416
7417AliasSet MCallObjectHasSparseElement::getAliasSet() const {
7418 return AliasSet::Load(AliasSet::Element | AliasSet::ObjectFields |
7419 AliasSet::FixedSlot | AliasSet::DynamicSlot);
7420}
7421
7422AliasSet MLoadSlotByIteratorIndex::getAliasSet() const {
7423 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
7424 AliasSet::DynamicSlot | AliasSet::Element);
7425}
7426
7427AliasSet MStoreSlotByIteratorIndex::getAliasSet() const {
7428 return AliasSet::Store(AliasSet::ObjectFields | AliasSet::FixedSlot |
7429 AliasSet::DynamicSlot | AliasSet::Element);
7430}
7431
7432MDefinition* MGuardInt32IsNonNegative::foldsTo(TempAllocator& alloc) {
7433 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"
, 7433); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 7433; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7434
7435 MDefinition* input = index();
7436 if (!input->isConstant() || input->toConstant()->toInt32() < 0) {
7437 return this;
7438 }
7439 return input;
7440}
7441
7442MDefinition* MGuardInt32Range::foldsTo(TempAllocator& alloc) {
7443 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"
, 7443); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 7443; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7444 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"
, 7444); AnnotateMozCrashReason("MOZ_ASSERT" "(" "minimum() <= maximum()"
")"); do { *((volatile int*)__null) = 7444; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7445
7446 MDefinition* in = input();
7447 if (!in->isConstant()) {
7448 return this;
7449 }
7450 int32_t cst = in->toConstant()->toInt32();
7451 if (cst < minimum() || cst > maximum()) {
7452 return this;
7453 }
7454 return in;
7455}
7456
7457MDefinition* MGuardNonGCThing::foldsTo(TempAllocator& alloc) {
7458 if (!input()->isBox()) {
7459 return this;
7460 }
7461
7462 MDefinition* unboxed = input()->getOperand(0);
7463 if (!IsNonGCThing(unboxed->type())) {
7464 return this;
7465 }
7466 return input();
7467}
7468
7469AliasSet MSetObjectHasNonBigInt::getAliasSet() const {
7470 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7471}
7472
7473AliasSet MSetObjectHasBigInt::getAliasSet() const {
7474 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7475}
7476
7477AliasSet MSetObjectHasValue::getAliasSet() const {
7478 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7479}
7480
7481AliasSet MSetObjectHasValueVMCall::getAliasSet() const {
7482 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7483}
7484
7485AliasSet MSetObjectSize::getAliasSet() const {
7486 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7487}
7488
7489AliasSet MMapObjectHasNonBigInt::getAliasSet() const {
7490 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7491}
7492
7493AliasSet MMapObjectHasBigInt::getAliasSet() const {
7494 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7495}
7496
7497AliasSet MMapObjectHasValue::getAliasSet() const {
7498 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7499}
7500
7501AliasSet MMapObjectHasValueVMCall::getAliasSet() const {
7502 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7503}
7504
7505AliasSet MMapObjectGetNonBigInt::getAliasSet() const {
7506 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7507}
7508
7509AliasSet MMapObjectGetBigInt::getAliasSet() const {
7510 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7511}
7512
7513AliasSet MMapObjectGetValue::getAliasSet() const {
7514 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7515}
7516
7517AliasSet MMapObjectGetValueVMCall::getAliasSet() const {
7518 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7519}
7520
7521AliasSet MMapObjectSize::getAliasSet() const {
7522 return AliasSet::Load(AliasSet::MapOrSetHashTable);
7523}
7524
7525AliasSet MDateFillLocalTimeSlots::getAliasSet() const {
7526 // Reads and stores fixed slots. Additional reads from DateTimeInfo don't need
7527 // to be tracked, because they don't interact with other alias set states.
7528 return AliasSet::Store(AliasSet::FixedSlot);
7529}
7530
7531MBindFunction* MBindFunction::New(TempAllocator& alloc, MDefinition* target,
7532 uint32_t argc, JSObject* templateObj) {
7533 auto* ins = new (alloc) MBindFunction(templateObj);
7534 if (!ins->init(alloc, NumNonArgumentOperands + argc)) {
7535 return nullptr;
7536 }
7537 ins->initOperand(0, target);
7538 return ins;
7539}
7540
7541MCreateInlinedArgumentsObject* MCreateInlinedArgumentsObject::New(
7542 TempAllocator& alloc, MDefinition* callObj, MDefinition* callee,
7543 MDefinitionVector& args, ArgumentsObject* templateObj) {
7544 MCreateInlinedArgumentsObject* ins =
7545 new (alloc) MCreateInlinedArgumentsObject(templateObj);
7546
7547 uint32_t argc = args.length();
7548 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"
, 7548); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7548; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7549
7550 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7551 return nullptr;
7552 }
7553
7554 ins->initOperand(0, callObj);
7555 ins->initOperand(1, callee);
7556 for (uint32_t i = 0; i < argc; i++) {
7557 ins->initOperand(i + NumNonArgumentOperands, args[i]);
7558 }
7559
7560 return ins;
7561}
7562
7563MGetInlinedArgument* MGetInlinedArgument::New(
7564 TempAllocator& alloc, MDefinition* index,
7565 MCreateInlinedArgumentsObject* args) {
7566 MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument();
7567
7568 uint32_t argc = args->numActuals();
7569 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"
, 7569); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7569; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7570
7571 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7572 return nullptr;
7573 }
7574
7575 ins->initOperand(0, index);
7576 for (uint32_t i = 0; i < argc; i++) {
7577 ins->initOperand(i + NumNonArgumentOperands, args->getArg(i));
7578 }
7579
7580 return ins;
7581}
7582
7583MGetInlinedArgument* MGetInlinedArgument::New(TempAllocator& alloc,
7584 MDefinition* index,
7585 const CallInfo& callInfo) {
7586 MGetInlinedArgument* ins = new (alloc) MGetInlinedArgument();
7587
7588 uint32_t argc = callInfo.argc();
7589 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"
, 7589); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7589; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7590
7591 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7592 return nullptr;
7593 }
7594
7595 ins->initOperand(0, index);
7596 for (uint32_t i = 0; i < argc; i++) {
7597 ins->initOperand(i + NumNonArgumentOperands, callInfo.getArg(i));
7598 }
7599
7600 return ins;
7601}
7602
7603MDefinition* MGetInlinedArgument::foldsTo(TempAllocator& alloc) {
7604 MDefinition* indexDef = SkipUninterestingInstructions(index());
7605 if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) {
7606 return this;
7607 }
7608
7609 int32_t indexConst = indexDef->toConstant()->toInt32();
7610 if (indexConst < 0 || uint32_t(indexConst) >= numActuals()) {
7611 return this;
7612 }
7613
7614 MDefinition* arg = getArg(indexConst);
7615 if (arg->type() != MIRType::Value) {
7616 arg = MBox::New(alloc, arg);
7617 }
7618
7619 return arg;
7620}
7621
7622MGetInlinedArgumentHole* MGetInlinedArgumentHole::New(
7623 TempAllocator& alloc, MDefinition* index,
7624 MCreateInlinedArgumentsObject* args) {
7625 auto* ins = new (alloc) MGetInlinedArgumentHole();
7626
7627 uint32_t argc = args->numActuals();
7628 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"
, 7628); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7628; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7629
7630 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7631 return nullptr;
7632 }
7633
7634 ins->initOperand(0, index);
7635 for (uint32_t i = 0; i < argc; i++) {
7636 ins->initOperand(i + NumNonArgumentOperands, args->getArg(i));
7637 }
7638
7639 return ins;
7640}
7641
7642MDefinition* MGetInlinedArgumentHole::foldsTo(TempAllocator& alloc) {
7643 MDefinition* indexDef = SkipUninterestingInstructions(index());
7644 if (!indexDef->isConstant() || indexDef->type() != MIRType::Int32) {
7645 return this;
7646 }
7647
7648 int32_t indexConst = indexDef->toConstant()->toInt32();
7649 if (indexConst < 0) {
7650 return this;
7651 }
7652
7653 MDefinition* arg;
7654 if (uint32_t(indexConst) < numActuals()) {
7655 arg = getArg(indexConst);
7656
7657 if (arg->type() != MIRType::Value) {
7658 arg = MBox::New(alloc, arg);
7659 }
7660 } else {
7661 auto* undefined = MConstant::New(alloc, UndefinedValue());
7662 block()->insertBefore(this, undefined);
7663
7664 arg = MBox::New(alloc, undefined);
7665 }
7666
7667 return arg;
7668}
7669
7670MInlineArgumentsSlice* MInlineArgumentsSlice::New(
7671 TempAllocator& alloc, MDefinition* begin, MDefinition* count,
7672 MCreateInlinedArgumentsObject* args, JSObject* templateObj,
7673 gc::Heap initialHeap) {
7674 auto* ins = new (alloc) MInlineArgumentsSlice(templateObj, initialHeap);
7675
7676 uint32_t argc = args->numActuals();
7677 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"
, 7677); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argc <= ArgumentsObject::MaxInlinedArgs"
")"); do { *((volatile int*)__null) = 7677; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7678
7679 if (!ins->init(alloc, argc + NumNonArgumentOperands)) {
7680 return nullptr;
7681 }
7682
7683 ins->initOperand(0, begin);
7684 ins->initOperand(1, count);
7685 for (uint32_t i = 0; i < argc; i++) {
7686 ins->initOperand(i + NumNonArgumentOperands, args->getArg(i));
7687 }
7688
7689 return ins;
7690}
7691
7692MDefinition* MArrayLength::foldsTo(TempAllocator& alloc) {
7693 // Object.keys() is potentially effectful, in case of Proxies. Otherwise, when
7694 // it is only computed for its length property, there is no need to
7695 // materialize the Array which results from it and it can be marked as
7696 // recovered on bailout as long as no properties are added to / removed from
7697 // the object.
7698 MDefinition* elems = elements();
7699 if (!elems->isElements()) {
7700 return this;
7701 }
7702
7703 MDefinition* guardshape = elems->toElements()->object();
7704 if (!guardshape->isGuardShape()) {
7705 return this;
7706 }
7707
7708 // The Guard shape is guarding the shape of the object returned by
7709 // Object.keys, this guard can be removed as knowing the function is good
7710 // enough to infer that we are returning an array.
7711 MDefinition* keys = guardshape->toGuardShape()->object();
7712 if (!keys->isObjectKeys()) {
7713 return this;
7714 }
7715
7716 // Object.keys() inline cache guards against proxies when creating the IC. We
7717 // rely on this here as we are looking to elide `Object.keys(...)` call, which
7718 // is only possible if we know for sure that no side-effect might have
7719 // happened.
7720 MDefinition* noproxy = keys->toObjectKeys()->object();
7721 if (!noproxy->isGuardIsNotProxy()) {
7722 // The guard might have been replaced by an assertion, in case the class is
7723 // known at compile time. IF the guard has been removed check whether check
7724 // has been removed.
7725 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"
, 7725); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "GetObjectKnownClass(noproxy) != KnownClass::None"
")"); do { *((volatile int*)__null) = 7725; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7726 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"
, 7726); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!GetObjectKnownJSClass(noproxy)->isProxyObject()"
")"); do { *((volatile int*)__null) = 7726; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7727 }
7728
7729 // Check if both the elements and the Object.keys() have a single use. We only
7730 // check for live uses, and are ok if a branch which was previously using the
7731 // keys array has been removed since.
7732 if (!elems->hasOneLiveDefUse() || !guardshape->hasOneLiveDefUse() ||
7733 !keys->hasOneLiveDefUse()) {
7734 return this;
7735 }
7736
7737 // Check that the latest active resume point is the one from Object.keys(), in
7738 // order to steal it. If this is not the latest active resume point then some
7739 // side-effect might happen which updates the content of the object, making
7740 // any recovery of the keys exhibit a different behavior than expected.
7741 if (keys->toObjectKeys()->resumePoint() != block()->activeResumePoint(this)) {
7742 return this;
7743 }
7744
7745 // Verify whether any resume point captures the keys array after any aliasing
7746 // mutations. If this were to be the case the recovery of ObjectKeys on
7747 // bailout might compute a version which might not match with the elided
7748 // result.
7749 //
7750 // Iterate over the resume point uses of ObjectKeys, and check whether the
7751 // instructions they are attached to are aliasing Object fields. If so, skip
7752 // this optimization.
7753 AliasSet enumKeysAliasSet = AliasSet::Load(AliasSet::Flag::ObjectFields);
7754 for (auto* use : UsesIterator(keys)) {
7755 if (!use->consumer()->isResumePoint()) {
7756 // There is only a single use, and this is the length computation as
7757 // asserted with `hasOneLiveDefUse`.
7758 continue;
7759 }
7760
7761 MResumePoint* rp = use->consumer()->toResumePoint();
7762 if (!rp->instruction()) {
7763 // If there is no instruction, this is a resume point which is attached to
7764 // the entry of a block. Thus no risk of mutating the object on which the
7765 // keys are queried.
7766 continue;
7767 }
7768
7769 MInstruction* ins = rp->instruction();
7770 if (ins == keys) {
7771 continue;
7772 }
7773
7774 // Check whether the instruction can potentially alias the object fields of
7775 // the object from which we are querying the keys.
7776 AliasSet mightAlias = ins->getAliasSet() & enumKeysAliasSet;
7777 if (!mightAlias.isNone()) {
7778 return this;
7779 }
7780 }
7781
7782 // Flag every instructions since Object.keys(..) as recovered on bailout, and
7783 // make Object.keys(..) be the recovered value in-place of the shape guard.
7784 setRecoveredOnBailout();
7785 elems->setRecoveredOnBailout();
7786 guardshape->replaceAllUsesWith(keys);
7787 guardshape->block()->discard(guardshape->toGuardShape());
7788 keys->setRecoveredOnBailout();
7789
7790 // Steal the resume point from Object.keys, which is ok as we confirmed that
7791 // there is no other resume point in-between.
7792 MObjectKeysLength* keysLength = MObjectKeysLength::New(alloc, noproxy);
7793 keysLength->stealResumePoint(keys->toObjectKeys());
7794
7795 // Set the dependency of the newly created instruction. Unfortunately
7796 // MObjectKeys (keys) is an instruction with a Store(Any) alias set, as it
7797 // could be used with proxies which can re-enter JavaScript.
7798 //
7799 // Thus, the loadDependency field of MObjectKeys is null. On the other hand
7800 // MObjectKeysLength has a Load alias set. Thus, instead of reconstructing the
7801 // Alias Analysis by updating every instructions which depends on MObjectKeys
7802 // and finding the matching store instruction, we reuse the MObjectKeys as any
7803 // store instruction, despite it being marked as recovered-on-bailout.
7804 keysLength->setDependency(keys);
7805
7806 return keysLength;
7807}
7808
7809MDefinition* MNormalizeSliceTerm::foldsTo(TempAllocator& alloc) {
7810 auto* length = this->length();
7811 if (!length->isConstant() && !length->isArgumentsLength()) {
7812 return this;
7813 }
7814
7815 if (length->isConstant()) {
7816 int32_t lengthConst = length->toConstant()->toInt32();
7817 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"
, 7817); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lengthConst >= 0"
")"); do { *((volatile int*)__null) = 7817; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7818
7819 // Result is always zero when |length| is zero.
7820 if (lengthConst == 0) {
7821 return length;
7822 }
7823
7824 auto* value = this->value();
7825 if (value->isConstant()) {
7826 int32_t valueConst = value->toConstant()->toInt32();
7827
7828 int32_t normalized;
7829 if (valueConst < 0) {
7830 normalized = std::max(valueConst + lengthConst, 0);
7831 } else {
7832 normalized = std::min(valueConst, lengthConst);
7833 }
7834
7835 if (normalized == valueConst) {
7836 return value;
7837 }
7838 if (normalized == lengthConst) {
7839 return length;
7840 }
7841 return MConstant::New(alloc, Int32Value(normalized));
7842 }
7843
7844 return this;
7845 }
7846
7847 auto* value = this->value();
7848 if (value->isConstant()) {
7849 int32_t valueConst = value->toConstant()->toInt32();
7850
7851 // Minimum of |value| and |length|.
7852 if (valueConst > 0) {
7853 bool isMax = false;
7854 return MMinMax::New(alloc, value, length, MIRType::Int32, isMax);
7855 }
7856
7857 // Maximum of |value + length| and zero.
7858 if (valueConst < 0) {
7859 // Safe to truncate because |length| is never negative.
7860 auto* add = MAdd::New(alloc, value, length, TruncateKind::Truncate);
7861 block()->insertBefore(this, add);
7862
7863 auto* zero = MConstant::New(alloc, Int32Value(0));
7864 block()->insertBefore(this, zero);
7865
7866 bool isMax = true;
7867 return MMinMax::New(alloc, add, zero, MIRType::Int32, isMax);
7868 }
7869
7870 // Directly return the value when it's zero.
7871 return value;
7872 }
7873
7874 // Normalizing MArgumentsLength is a no-op.
7875 if (value->isArgumentsLength()) {
7876 return value;
7877 }
7878
7879 return this;
7880}
7881
7882bool MInt32ToStringWithBase::congruentTo(const MDefinition* ins) const {
7883 if (!ins->isInt32ToStringWithBase()) {
7884 return false;
7885 }
7886 if (ins->toInt32ToStringWithBase()->lowerCase() != lowerCase()) {
7887 return false;
7888 }
7889 return congruentIfOperandsEqual(ins);
7890}