Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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