Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_js_src_jit8.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/js/src/jit -resource-dir /usr/lib/llvm-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/js/src/js-confdefs.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 -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/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../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-05-16-034744-15991-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/MIRGraph.h"
28#include "jit/RangeAnalysis.h"
29#include "jit/VMFunctions.h"
30#include "jit/WarpBuilderShared.h"
31#include "js/Conversions.h"
32#include "js/experimental/JitInfo.h" // JSJitInfo, JSTypedMethodJitInfo
33#include "js/ScalarType.h" // js::Scalar::Type
34#include "util/Text.h"
35#include "util/Unicode.h"
36#include "vm/Iteration.h" // js::NativeIterator
37#include "vm/PlainObject.h" // js::PlainObject
38#include "vm/Uint8Clamped.h"
39#include "wasm/WasmCode.h"
40#include "wasm/WasmFeatures.h" // for wasm::ReportSimdAnalysis
41
42#include "vm/JSAtomUtils-inl.h" // TypeName
43#include "wasm/WasmInstance-inl.h"
44
45using namespace js;
46using namespace js::jit;
47
48using JS::ToInt32;
49
50using mozilla::CheckedInt;
51using mozilla::DebugOnly;
52using mozilla::IsFloat32Representable;
53using mozilla::IsPowerOfTwo;
54using mozilla::Maybe;
55using mozilla::NumbersAreIdentical;
56
57NON_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."
);
58
59#ifdef DEBUG1
60size_t MUse::index() const { return consumer()->indexOf(this); }
61#endif
62
63template <size_t Op>
64static void ConvertDefinitionToDouble(TempAllocator& alloc, MDefinition* def,
65 MInstruction* consumer) {
66 MInstruction* replace = MToDouble::New(alloc, def);
67 consumer->replaceOperand(Op, replace);
68 consumer->block()->insertBefore(consumer, replace);
69}
70
71template <size_t Arity, size_t Index>
72static void ConvertOperandToDouble(MAryInstruction<Arity>* def,
73 TempAllocator& alloc) {
74 static_assert(Index < Arity);
75 auto* operand = def->getOperand(Index);
76 if (operand->type() == MIRType::Float32) {
77 ConvertDefinitionToDouble<Index>(alloc, operand, def);
78 }
79}
80
81template <size_t Arity, size_t... ISeq>
82static void ConvertOperandsToDouble(MAryInstruction<Arity>* def,
83 TempAllocator& alloc,
84 std::index_sequence<ISeq...>) {
85 (ConvertOperandToDouble<Arity, ISeq>(def, alloc), ...);
86}
87
88template <size_t Arity>
89static void ConvertOperandsToDouble(MAryInstruction<Arity>* def,
90 TempAllocator& alloc) {
91 ConvertOperandsToDouble<Arity>(def, alloc, std::make_index_sequence<Arity>{});
92}
93
94template <size_t Arity, size_t... ISeq>
95static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def,
96 std::index_sequence<ISeq...>) {
97 return (def->getOperand(ISeq)->canProduceFloat32() && ...);
98}
99
100template <size_t Arity>
101static bool AllOperandsCanProduceFloat32(MAryInstruction<Arity>* def) {
102 return AllOperandsCanProduceFloat32<Arity>(def,
103 std::make_index_sequence<Arity>{});
104}
105
106static bool CheckUsesAreFloat32Consumers(const MInstruction* ins) {
107 if (ins->isImplicitlyUsed()) {
108 return false;
109 }
110 bool allConsumerUses = true;
111 for (MUseDefIterator use(ins); allConsumerUses && use; use++) {
112 allConsumerUses &= use.def()->canConsumeFloat32(use.use());
113 }
114 return allConsumerUses;
115}
116
117#ifdef JS_JITSPEW1
118static const char* OpcodeName(MDefinition::Opcode op) {
119 static const char* const names[] = {
120# define NAME(x) #x,
121 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(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(MegamorphicLoadSlotByValue
)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(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)
122# undef NAME
123 };
124 return names[unsigned(op)];
125}
126
127void MDefinition::PrintOpcodeName(GenericPrinter& out, Opcode op) {
128 const char* name = OpcodeName(op);
129 size_t len = strlen(name);
130 for (size_t i = 0; i < len; i++) {
131 out.printf("%c", unicode::ToLowerCase(name[i]));
132 }
133}
134
135uint32_t js::jit::GetMBasicBlockId(const MBasicBlock* block) {
136 return block->id();
137}
138#endif
139
140static MConstant* EvaluateInt64ConstantOperands(TempAllocator& alloc,
141 MBinaryInstruction* ins) {
142 MDefinition* left = ins->getOperand(0);
143 MDefinition* right = ins->getOperand(1);
144
145 if (!left->isConstant() || !right->isConstant()) {
146 return nullptr;
147 }
148
149 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"
, 149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::Int64"
")"); do { *((volatile int*)__null) = 149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
150 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"
, 150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int64"
")"); do { *((volatile int*)__null) = 150; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
151
152 int64_t lhs = left->toConstant()->toInt64();
153 int64_t rhs = right->toConstant()->toInt64();
154 int64_t ret;
155
156 switch (ins->op()) {
157 case MDefinition::Opcode::BitAnd:
158 ret = lhs & rhs;
159 break;
160 case MDefinition::Opcode::BitOr:
161 ret = lhs | rhs;
162 break;
163 case MDefinition::Opcode::BitXor:
164 ret = lhs ^ rhs;
165 break;
166 case MDefinition::Opcode::Lsh:
167 ret = lhs << (rhs & 0x3F);
168 break;
169 case MDefinition::Opcode::Rsh:
170 ret = lhs >> (rhs & 0x3F);
171 break;
172 case MDefinition::Opcode::Ursh:
173 ret = uint64_t(lhs) >> (uint64_t(rhs) & 0x3F);
174 break;
175 case MDefinition::Opcode::Add:
176 ret = lhs + rhs;
177 break;
178 case MDefinition::Opcode::Sub:
179 ret = lhs - rhs;
180 break;
181 case MDefinition::Opcode::Mul:
182 ret = lhs * rhs;
183 break;
184 case MDefinition::Opcode::Div:
185 if (rhs == 0) {
186 // Division by zero will trap at runtime.
187 return nullptr;
188 }
189 if (ins->toDiv()->isUnsigned()) {
190 ret = int64_t(uint64_t(lhs) / uint64_t(rhs));
191 } else if (lhs == INT64_MIN(-9223372036854775807L -1) || rhs == -1) {
192 // Overflow will trap at runtime.
193 return nullptr;
194 } else {
195 ret = lhs / rhs;
196 }
197 break;
198 case MDefinition::Opcode::Mod:
199 if (rhs == 0) {
200 // Division by zero will trap at runtime.
201 return nullptr;
202 }
203 if (!ins->toMod()->isUnsigned() && (lhs < 0 || rhs < 0)) {
204 // Handle all negative values at runtime, for simplicity.
205 return nullptr;
206 }
207 ret = int64_t(uint64_t(lhs) % uint64_t(rhs));
208 break;
209 default:
210 MOZ_CRASH("NYI")do { do { } while (false); MOZ_ReportCrash("" "NYI", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 210); AnnotateMozCrashReason("MOZ_CRASH(" "NYI" ")"); do { *
((volatile int*)__null) = 210; __attribute__((nomerge)) ::abort
(); } while (false); } while (false)
;
211 }
212
213 return MConstant::NewInt64(alloc, ret);
214}
215
216static MConstant* EvaluateConstantOperands(TempAllocator& alloc,
217 MBinaryInstruction* ins,
218 bool* ptypeChange = nullptr) {
219 MDefinition* left = ins->getOperand(0);
220 MDefinition* right = ins->getOperand(1);
221
222 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"
, 222); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(left->type())"
")"); do { *((volatile int*)__null) = 222; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
223 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"
, 223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeRepresentableAsDouble(right->type())"
")"); do { *((volatile int*)__null) = 223; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
224
225 if (!left->isConstant() || !right->isConstant()) {
226 return nullptr;
227 }
228
229 MConstant* lhs = left->toConstant();
230 MConstant* rhs = right->toConstant();
231 double ret = JS::GenericNaN();
232
233 switch (ins->op()) {
234 case MDefinition::Opcode::BitAnd:
235 ret = double(lhs->toInt32() & rhs->toInt32());
236 break;
237 case MDefinition::Opcode::BitOr:
238 ret = double(lhs->toInt32() | rhs->toInt32());
239 break;
240 case MDefinition::Opcode::BitXor:
241 ret = double(lhs->toInt32() ^ rhs->toInt32());
242 break;
243 case MDefinition::Opcode::Lsh:
244 ret = double(uint32_t(lhs->toInt32()) << (rhs->toInt32() & 0x1F));
245 break;
246 case MDefinition::Opcode::Rsh:
247 ret = double(lhs->toInt32() >> (rhs->toInt32() & 0x1F));
248 break;
249 case MDefinition::Opcode::Ursh:
250 ret = double(uint32_t(lhs->toInt32()) >> (rhs->toInt32() & 0x1F));
251 break;
252 case MDefinition::Opcode::Add:
253 ret = lhs->numberToDouble() + rhs->numberToDouble();
254 break;
255 case MDefinition::Opcode::Sub:
256 ret = lhs->numberToDouble() - rhs->numberToDouble();
257 break;
258 case MDefinition::Opcode::Mul:
259 ret = lhs->numberToDouble() * rhs->numberToDouble();
260 break;
261 case MDefinition::Opcode::Div:
262 if (ins->toDiv()->isUnsigned()) {
263 if (rhs->isInt32(0)) {
264 if (ins->toDiv()->trapOnError()) {
265 return nullptr;
266 }
267 ret = 0.0;
268 } else {
269 ret = double(uint32_t(lhs->toInt32()) / uint32_t(rhs->toInt32()));
270 }
271 } else {
272 ret = NumberDiv(lhs->numberToDouble(), rhs->numberToDouble());
273 }
274 break;
275 case MDefinition::Opcode::Mod:
276 if (ins->toMod()->isUnsigned()) {
277 if (rhs->isInt32(0)) {
278 if (ins->toMod()->trapOnError()) {
279 return nullptr;
280 }
281 ret = 0.0;
282 } else {
283 ret = double(uint32_t(lhs->toInt32()) % uint32_t(rhs->toInt32()));
284 }
285 } else {
286 ret = NumberMod(lhs->numberToDouble(), rhs->numberToDouble());
287 }
288 break;
289 default:
290 MOZ_CRASH("NYI")do { do { } while (false); MOZ_ReportCrash("" "NYI", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 290); AnnotateMozCrashReason("MOZ_CRASH(" "NYI" ")"); do { *
((volatile int*)__null) = 290; __attribute__((nomerge)) ::abort
(); } while (false); } while (false)
;
291 }
292
293 if (ins->type() == MIRType::Float32) {
294 return MConstant::NewFloat32(alloc, float(ret));
295 }
296 if (ins->type() == MIRType::Double) {
297 return MConstant::New(alloc, DoubleValue(ret));
298 }
299
300 Value retVal;
301 retVal.setNumber(JS::CanonicalizeNaN(ret));
302
303 // If this was an int32 operation but the result isn't an int32 (for
304 // example, a division where the numerator isn't evenly divisible by the
305 // denominator), decline folding.
306 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"
, 306); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 306; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
307 if (!retVal.isInt32()) {
308 if (ptypeChange) {
309 *ptypeChange = true;
310 }
311 return nullptr;
312 }
313
314 return MConstant::New(alloc, retVal);
315}
316
317static MMul* EvaluateExactReciprocal(TempAllocator& alloc, MDiv* ins) {
318 // we should fold only when it is a floating point operation
319 if (!IsFloatingPointType(ins->type())) {
320 return nullptr;
321 }
322
323 MDefinition* left = ins->getOperand(0);
324 MDefinition* right = ins->getOperand(1);
325
326 if (!right->isConstant()) {
327 return nullptr;
328 }
329
330 int32_t num;
331 if (!mozilla::NumberIsInt32(right->toConstant()->numberToDouble(), &num)) {
332 return nullptr;
333 }
334
335 // check if rhs is a power of two
336 if (mozilla::Abs(num) & (mozilla::Abs(num) - 1)) {
337 return nullptr;
338 }
339
340 Value ret;
341 ret.setDouble(1.0 / double(num));
342
343 MConstant* foldedRhs;
344 if (ins->type() == MIRType::Float32) {
345 foldedRhs = MConstant::NewFloat32(alloc, ret.toDouble());
346 } else {
347 foldedRhs = MConstant::New(alloc, ret);
348 }
349
350 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"
, 350); AnnotateMozCrashReason("MOZ_ASSERT" "(" "foldedRhs->type() == ins->type()"
")"); do { *((volatile int*)__null) = 350; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
351 ins->block()->insertBefore(ins, foldedRhs);
352
353 MMul* mul = MMul::New(alloc, left, foldedRhs, ins->type());
354 mul->setMustPreserveNaN(ins->mustPreserveNaN());
355 return mul;
356}
357
358#ifdef JS_JITSPEW1
359const char* MDefinition::opName() const { return OpcodeName(op()); }
360
361void MDefinition::printName(GenericPrinter& out) const {
362 PrintOpcodeName(out, op());
363 out.printf("%u", id());
364}
365#endif
366
367HashNumber MDefinition::valueHash() const {
368 HashNumber out = HashNumber(op());
369 for (size_t i = 0, e = numOperands(); i < e; i++) {
370 out = addU32ToHash(out, getOperand(i)->id());
371 }
372 if (MDefinition* dep = dependency()) {
373 out = addU32ToHash(out, dep->id());
374 }
375 return out;
376}
377
378HashNumber MNullaryInstruction::valueHash() const {
379 HashNumber hash = HashNumber(op());
380 if (MDefinition* dep = dependency()) {
381 hash = addU32ToHash(hash, dep->id());
382 }
383 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"
, 383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 383; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
384 return hash;
385}
386
387HashNumber MUnaryInstruction::valueHash() const {
388 HashNumber hash = HashNumber(op());
389 hash = addU32ToHash(hash, getOperand(0)->id());
390 if (MDefinition* dep = dependency()) {
391 hash = addU32ToHash(hash, dep->id());
392 }
393 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"
, 393); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 393; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
394 return hash;
395}
396
397HashNumber MBinaryInstruction::valueHash() const {
398 HashNumber hash = HashNumber(op());
399 hash = addU32ToHash(hash, getOperand(0)->id());
400 hash = addU32ToHash(hash, getOperand(1)->id());
401 if (MDefinition* dep = dependency()) {
402 hash = addU32ToHash(hash, dep->id());
403 }
404 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"
, 404); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 404; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
405 return hash;
406}
407
408HashNumber MTernaryInstruction::valueHash() const {
409 HashNumber hash = HashNumber(op());
410 hash = addU32ToHash(hash, getOperand(0)->id());
411 hash = addU32ToHash(hash, getOperand(1)->id());
412 hash = addU32ToHash(hash, getOperand(2)->id());
413 if (MDefinition* dep = dependency()) {
414 hash = addU32ToHash(hash, dep->id());
415 }
416 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"
, 416); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 416; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
417 return hash;
418}
419
420HashNumber MQuaternaryInstruction::valueHash() const {
421 HashNumber hash = HashNumber(op());
422 hash = addU32ToHash(hash, getOperand(0)->id());
423 hash = addU32ToHash(hash, getOperand(1)->id());
424 hash = addU32ToHash(hash, getOperand(2)->id());
425 hash = addU32ToHash(hash, getOperand(3)->id());
426 if (MDefinition* dep = dependency()) {
427 hash = addU32ToHash(hash, dep->id());
428 }
429 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"
, 429); AnnotateMozCrashReason("MOZ_ASSERT" "(" "hash == MDefinition::valueHash()"
")"); do { *((volatile int*)__null) = 429; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
430 return hash;
431}
432
433const MDefinition* MDefinition::skipObjectGuards() const {
434 const MDefinition* result = this;
435 // These instructions don't modify the object and just guard specific
436 // properties.
437 while (true) {
438 if (result->isGuardShape()) {
439 result = result->toGuardShape()->object();
440 continue;
441 }
442 if (result->isGuardNullProto()) {
443 result = result->toGuardNullProto()->object();
444 continue;
445 }
446 if (result->isGuardProto()) {
447 result = result->toGuardProto()->object();
448 continue;
449 }
450
451 break;
452 }
453
454 return result;
455}
456
457bool MDefinition::congruentIfOperandsEqual(const MDefinition* ins) const {
458 if (op() != ins->op()) {
459 return false;
460 }
461
462 if (type() != ins->type()) {
463 return false;
464 }
465
466 if (isEffectful() || ins->isEffectful()) {
467 return false;
468 }
469
470 if (numOperands() != ins->numOperands()) {
471 return false;
472 }
473
474 for (size_t i = 0, e = numOperands(); i < e; i++) {
475 if (getOperand(i) != ins->getOperand(i)) {
476 return false;
477 }
478 }
479
480 return true;
481}
482
483MDefinition* MDefinition::foldsTo(TempAllocator& alloc) {
484 // In the default case, there are no constants to fold.
485 return this;
486}
487
488bool MDefinition::mightBeMagicType() const {
489 if (IsMagicType(type())) {
490 return true;
491 }
492
493 if (MIRType::Value != type()) {
494 return false;
495 }
496
497 return true;
498}
499
500bool MDefinition::definitelyType(std::initializer_list<MIRType> types) const {
501#ifdef DEBUG1
502 // Only support specialized, non-magic types.
503 auto isSpecializedNonMagic = [](MIRType type) {
504 return type <= MIRType::Object;
505 };
506#endif
507
508 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"
, 508); AnnotateMozCrashReason("MOZ_ASSERT" "(" "types.size() > 0"
")"); do { *((volatile int*)__null) = 508; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
509 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"
, 509); AnnotateMozCrashReason("MOZ_ASSERT" "(" "std::all_of(types.begin(), types.end(), isSpecializedNonMagic)"
")"); do { *((volatile int*)__null) = 509; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
510
511 if (type() == MIRType::Value) {
512 return false;
513 }
514
515 return std::find(types.begin(), types.end(), type()) != types.end();
516}
517
518MDefinition* MInstruction::foldsToStore(TempAllocator& alloc) {
519 if (!dependency()) {
520 return nullptr;
521 }
522
523 MDefinition* store = dependency();
524 if (mightAlias(store) != AliasType::MustAlias) {
525 return nullptr;
526 }
527
528 if (!store->block()->dominates(block())) {
529 return nullptr;
530 }
531
532 MDefinition* value;
533 switch (store->op()) {
534 case Opcode::StoreFixedSlot:
535 value = store->toStoreFixedSlot()->value();
536 break;
537 case Opcode::StoreDynamicSlot:
538 value = store->toStoreDynamicSlot()->value();
539 break;
540 case Opcode::StoreElement:
541 value = store->toStoreElement()->value();
542 break;
543 default:
544 MOZ_CRASH("unknown store")do { do { } while (false); MOZ_ReportCrash("" "unknown store"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 544); AnnotateMozCrashReason("MOZ_CRASH(" "unknown store" ")"
); do { *((volatile int*)__null) = 544; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
545 }
546
547 // If the type are matching then we return the value which is used as
548 // argument of the store.
549 if (value->type() != type()) {
550 // If we expect to read a type which is more generic than the type seen
551 // by the store, then we box the value used by the store.
552 if (type() != MIRType::Value) {
553 return nullptr;
554 }
555
556 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"
, 556); AnnotateMozCrashReason("MOZ_ASSERT" "(" "value->type() < MIRType::Value"
")"); do { *((volatile int*)__null) = 556; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
557 MBox* box = MBox::New(alloc, value);
558 value = box;
559 }
560
561 return value;
562}
563
564void MDefinition::analyzeEdgeCasesForward() {}
565
566void MDefinition::analyzeEdgeCasesBackward() {}
567
568void MInstruction::setResumePoint(MResumePoint* resumePoint) {
569 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"
, 569); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!resumePoint_"
")"); do { *((volatile int*)__null) = 569; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
570 resumePoint_ = resumePoint;
571 resumePoint_->setInstruction(this);
572}
573
574void MInstruction::stealResumePoint(MInstruction* other) {
575 MResumePoint* resumePoint = other->resumePoint_;
576 other->resumePoint_ = nullptr;
577
578 resumePoint->resetInstruction();
579 setResumePoint(resumePoint);
580}
581
582void MInstruction::moveResumePointAsEntry() {
583 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"
, 583); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNop()" ")"
); do { *((volatile int*)__null) = 583; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
584 block()->clearEntryResumePoint();
585 block()->setEntryResumePoint(resumePoint_);
586 resumePoint_->resetInstruction();
587 resumePoint_ = nullptr;
588}
589
590void MInstruction::clearResumePoint() {
591 resumePoint_->resetInstruction();
592 block()->discardPreAllocatedResumePoint(resumePoint_);
593 resumePoint_ = nullptr;
594}
595
596MDefinition* MTest::foldsDoubleNegation(TempAllocator& alloc) {
597 MDefinition* op = getOperand(0);
598
599 if (op->isNot()) {
600 // If the operand of the Not is itself a Not, they cancel out.
601 MDefinition* opop = op->getOperand(0);
602 if (opop->isNot()) {
603 return MTest::New(alloc, opop->toNot()->input(), ifTrue(), ifFalse());
604 }
605 return MTest::New(alloc, op->toNot()->input(), ifFalse(), ifTrue());
606 }
607 return nullptr;
608}
609
610MDefinition* MTest::foldsConstant(TempAllocator& alloc) {
611 MDefinition* op = getOperand(0);
612 if (MConstant* opConst = op->maybeConstantValue()) {
613 bool b;
614 if (opConst->valueToBoolean(&b)) {
615 return MGoto::New(alloc, b ? ifTrue() : ifFalse());
616 }
617 }
618 return nullptr;
619}
620
621MDefinition* MTest::foldsTypes(TempAllocator& alloc) {
622 MDefinition* op = getOperand(0);
623
624 switch (op->type()) {
625 case MIRType::Undefined:
626 case MIRType::Null:
627 return MGoto::New(alloc, ifFalse());
628 case MIRType::Symbol:
629 return MGoto::New(alloc, ifTrue());
630 default:
631 break;
632 }
633 return nullptr;
634}
635
636class UsesIterator {
637 MDefinition* def_;
638
639 public:
640 explicit UsesIterator(MDefinition* def) : def_(def) {}
641 auto begin() const { return def_->usesBegin(); }
642 auto end() const { return def_->usesEnd(); }
643};
644
645static bool AllInstructionsDeadIfUnused(MBasicBlock* block) {
646 for (auto* ins : *block) {
647 // Skip trivial instructions.
648 if (ins->isNop() || ins->isGoto()) {
649 continue;
650 }
651
652 // All uses must be within the current block.
653 for (auto* use : UsesIterator(ins)) {
654 if (use->consumer()->block() != block) {
655 return false;
656 }
657 }
658
659 // All instructions within this block must be dead if unused.
660 if (!DeadIfUnused(ins)) {
661 return false;
662 }
663 }
664 return true;
665}
666
667MDefinition* MTest::foldsNeedlessControlFlow(TempAllocator& alloc) {
668 // All instructions within both successors need be dead if unused.
669 if (!AllInstructionsDeadIfUnused(ifTrue()) ||
670 !AllInstructionsDeadIfUnused(ifFalse())) {
671 return nullptr;
672 }
673
674 // Both successors must have the same target successor.
675 if (ifTrue()->numSuccessors() != 1 || ifFalse()->numSuccessors() != 1) {
676 return nullptr;
677 }
678 if (ifTrue()->getSuccessor(0) != ifFalse()->getSuccessor(0)) {
679 return nullptr;
680 }
681
682 // The target successor's phis must be redundant. Redundant phis should have
683 // been removed in an earlier pass, so only check if any phis are present,
684 // which is a stronger condition.
685 if (ifTrue()->successorWithPhis()) {
686 return nullptr;
687 }
688
689 return MGoto::New(alloc, ifTrue());
690}
691
692// If a test is dominated by either the true or false path of a previous test of
693// the same condition, then the test is redundant and can be converted into a
694// goto true or goto false, respectively.
695MDefinition* MTest::foldsRedundantTest(TempAllocator& alloc) {
696 MBasicBlock* myBlock = this->block();
697 MDefinition* originalInput = getOperand(0);
698
699 // Handle single and double negatives. This ensures that we do not miss a
700 // folding opportunity due to a condition being inverted.
701 MDefinition* newInput = input();
702 bool inverted = false;
703 if (originalInput->isNot()) {
704 newInput = originalInput->toNot()->input();
705 inverted = true;
706 if (originalInput->toNot()->input()->isNot()) {
707 newInput = originalInput->toNot()->input()->toNot()->input();
708 inverted = false;
709 }
710 }
711
712 // The specific order of traversal does not matter. If there are multiple
713 // dominating redundant tests, they will either agree on direction (in which
714 // case we will prune the same way regardless of order), or they will
715 // disagree, in which case we will eventually be marked entirely dead by the
716 // folding of the redundant parent.
717 for (MUseIterator i(newInput->usesBegin()), e(newInput->usesEnd()); i != e;
718 ++i) {
719 if (!i->consumer()->isDefinition()) {
720 continue;
721 }
722 if (!i->consumer()->toDefinition()->isTest()) {
723 continue;
724 }
725 MTest* otherTest = i->consumer()->toDefinition()->toTest();
726 if (otherTest == this) {
727 continue;
728 }
729
730 if (otherTest->ifFalse()->dominates(myBlock)) {
731 // This test cannot be true, so fold to a goto false.
732 return MGoto::New(alloc, inverted ? ifTrue() : ifFalse());
733 }
734 if (otherTest->ifTrue()->dominates(myBlock)) {
735 // This test cannot be false, so fold to a goto true.
736 return MGoto::New(alloc, inverted ? ifFalse() : ifTrue());
737 }
738 }
739
740 return nullptr;
741}
742
743MDefinition* MTest::foldsTo(TempAllocator& alloc) {
744 if (MDefinition* def = foldsRedundantTest(alloc)) {
745 return def;
746 }
747
748 if (MDefinition* def = foldsDoubleNegation(alloc)) {
749 return def;
750 }
751
752 if (MDefinition* def = foldsConstant(alloc)) {
753 return def;
754 }
755
756 if (MDefinition* def = foldsTypes(alloc)) {
757 return def;
758 }
759
760 if (MDefinition* def = foldsNeedlessControlFlow(alloc)) {
761 return def;
762 }
763
764 return this;
765}
766
767AliasSet MThrow::getAliasSet() const {
768 return AliasSet::Store(AliasSet::ExceptionState);
769}
770
771AliasSet MThrowWithStack::getAliasSet() const {
772 return AliasSet::Store(AliasSet::ExceptionState);
773}
774
775AliasSet MNewArrayDynamicLength::getAliasSet() const {
776 return AliasSet::Store(AliasSet::ExceptionState);
777}
778
779AliasSet MNewTypedArrayDynamicLength::getAliasSet() const {
780 return AliasSet::Store(AliasSet::ExceptionState);
781}
782
783#ifdef JS_JITSPEW1
784void MDefinition::printOpcode(GenericPrinter& out) const {
785 PrintOpcodeName(out, op());
786 for (size_t j = 0, e = numOperands(); j < e; j++) {
787 out.printf(" ");
788 if (getUseFor(j)->hasProducer()) {
789 getOperand(j)->printName(out);
790 out.printf(":%s", StringFromMIRType(getOperand(j)->type()));
791 } else {
792 out.printf("(null)");
793 }
794 }
795}
796
797void MDefinition::dump(GenericPrinter& out) const {
798 printName(out);
799 out.printf(":%s", StringFromMIRType(type()));
800 out.printf(" = ");
801 printOpcode(out);
802 out.printf("\n");
803
804 if (isInstruction()) {
805 if (MResumePoint* resume = toInstruction()->resumePoint()) {
806 resume->dump(out);
807 }
808 }
809}
810
811void MDefinition::dump() const {
812 Fprinter out(stderrstderr);
813 dump(out);
814 out.finish();
815}
816
817void MDefinition::dumpLocation(GenericPrinter& out) const {
818 MResumePoint* rp = nullptr;
819 const char* linkWord = nullptr;
820 if (isInstruction() && toInstruction()->resumePoint()) {
821 rp = toInstruction()->resumePoint();
822 linkWord = "at";
823 } else {
824 rp = block()->entryResumePoint();
825 linkWord = "after";
826 }
827
828 while (rp) {
829 JSScript* script = rp->block()->info().script();
830 uint32_t lineno = PCToLineNumber(rp->block()->info().script(), rp->pc());
831 out.printf(" %s %s:%u\n", linkWord, script->filename(), lineno);
832 rp = rp->caller();
833 linkWord = "in";
834 }
835}
836
837void MDefinition::dumpLocation() const {
838 Fprinter out(stderrstderr);
839 dumpLocation(out);
840 out.finish();
841}
842#endif
843
844#if defined(DEBUG1) || defined(JS_JITSPEW1)
845size_t MDefinition::useCount() const {
846 size_t count = 0;
847 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
848 count++;
849 }
850 return count;
851}
852
853size_t MDefinition::defUseCount() const {
854 size_t count = 0;
855 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
856 if ((*i)->consumer()->isDefinition()) {
857 count++;
858 }
859 }
860 return count;
861}
862#endif
863
864bool MDefinition::hasOneUse() const {
865 MUseIterator i(uses_.begin());
866 if (i == uses_.end()) {
867 return false;
868 }
869 i++;
870 return i == uses_.end();
871}
872
873bool MDefinition::hasOneDefUse() const {
874 bool hasOneDefUse = false;
875 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
876 if (!(*i)->consumer()->isDefinition()) {
877 continue;
878 }
879
880 // We already have a definition use. So 1+
881 if (hasOneDefUse) {
882 return false;
883 }
884
885 // We saw one definition. Loop to test if there is another.
886 hasOneDefUse = true;
887 }
888
889 return hasOneDefUse;
890}
891
892bool MDefinition::hasOneLiveDefUse() const {
893 bool hasOneDefUse = false;
894 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
895 if (!(*i)->consumer()->isDefinition()) {
896 continue;
897 }
898
899 MDefinition* def = (*i)->consumer()->toDefinition();
900 if (def->isRecoveredOnBailout()) {
901 continue;
902 }
903
904 // We already have a definition use. So 1+
905 if (hasOneDefUse) {
906 return false;
907 }
908
909 // We saw one definition. Loop to test if there is another.
910 hasOneDefUse = true;
911 }
912
913 return hasOneDefUse;
914}
915
916bool MDefinition::hasDefUses() const {
917 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
918 if ((*i)->consumer()->isDefinition()) {
919 return true;
920 }
921 }
922
923 return false;
924}
925
926bool MDefinition::hasLiveDefUses() const {
927 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
928 MNode* ins = (*i)->consumer();
929 if (ins->isDefinition()) {
930 if (!ins->toDefinition()->isRecoveredOnBailout()) {
931 return true;
932 }
933 } else {
934 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"
, 934); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->isResumePoint()"
")"); do { *((volatile int*)__null) = 934; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
935 if (!ins->toResumePoint()->isRecoverableOperand(*i)) {
936 return true;
937 }
938 }
939 }
940
941 return false;
942}
943
944MDefinition* MDefinition::maybeSingleDefUse() const {
945 MUseDefIterator use(this);
946 if (!use) {
947 // No def-uses.
948 return nullptr;
949 }
950
951 MDefinition* useDef = use.def();
952
953 use++;
954 if (use) {
955 // More than one def-use.
956 return nullptr;
957 }
958
959 return useDef;
960}
961
962MDefinition* MDefinition::maybeMostRecentlyAddedDefUse() const {
963 MUseDefIterator use(this);
964 if (!use) {
965 // No def-uses.
966 return nullptr;
967 }
968
969 MDefinition* mostRecentUse = use.def();
970
971#ifdef DEBUG1
972 // This function relies on addUse adding new uses to the front of the list.
973 // Check this invariant by asserting the next few uses are 'older'. Skip this
974 // for phis because setBackedge can add a new use for a loop phi even if the
975 // loop body has a use with an id greater than the loop phi's id.
976 if (!mostRecentUse->isPhi()) {
977 static constexpr size_t NumUsesToCheck = 3;
978 use++;
979 for (size_t i = 0; use && i < NumUsesToCheck; i++, use++) {
980 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"
, 980); AnnotateMozCrashReason("MOZ_ASSERT" "(" "use.def()->id() <= mostRecentUse->id()"
")"); do { *((volatile int*)__null) = 980; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
981 }
982 }
983#endif
984
985 return mostRecentUse;
986}
987
988void MDefinition::replaceAllUsesWith(MDefinition* dom) {
989 for (size_t i = 0, e = numOperands(); i < e; ++i) {
990 getOperand(i)->setImplicitlyUsedUnchecked();
991 }
992
993 justReplaceAllUsesWith(dom);
994}
995
996void MDefinition::justReplaceAllUsesWith(MDefinition* dom) {
997 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"
, 997); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != nullptr"
")"); do { *((volatile int*)__null) = 997; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
998 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"
, 998); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dom != this"
")"); do { *((volatile int*)__null) = 998; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
999
1000 // Carry over the fact the value has uses which are no longer inspectable
1001 // with the graph.
1002 if (isImplicitlyUsed()) {
1003 dom->setImplicitlyUsedUnchecked();
1004 }
1005
1006 for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i) {
1007 i->setProducerUnchecked(dom);
1008 }
1009 dom->uses_.takeElements(uses_);
1010}
1011
1012bool MDefinition::optimizeOutAllUses(TempAllocator& alloc) {
1013 for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
1014 MUse* use = *i++;
1015 MConstant* constant = use->consumer()->block()->optimizedOutConstant(alloc);
1016 if (!alloc.ensureBallast()) {
1017 return false;
1018 }
1019
1020 // Update the resume point operand to use the optimized-out constant.
1021 use->setProducerUnchecked(constant);
1022 constant->addUseUnchecked(use);
1023 }
1024
1025 // Remove dangling pointers.
1026 this->uses_.clear();
1027 return true;
1028}
1029
1030void MDefinition::replaceAllLiveUsesWith(MDefinition* dom) {
1031 for (MUseIterator i(usesBegin()), e(usesEnd()); i != e;) {
1032 MUse* use = *i++;
1033 MNode* consumer = use->consumer();
1034 if (consumer->isResumePoint()) {
1035 continue;
1036 }
1037 if (consumer->isDefinition() &&
1038 consumer->toDefinition()->isRecoveredOnBailout()) {
1039 continue;
1040 }
1041
1042 // Update the operand to use the dominating definition.
1043 use->replaceProducer(dom);
1044 }
1045}
1046
1047MConstant* MConstant::New(TempAllocator& alloc, const Value& v) {
1048 return new (alloc) MConstant(alloc, v);
1049}
1050
1051MConstant* MConstant::New(TempAllocator::Fallible alloc, const Value& v) {
1052 return new (alloc) MConstant(alloc.alloc, v);
1053}
1054
1055MConstant* MConstant::NewFloat32(TempAllocator& alloc, double d) {
1056 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"
, 1056); AnnotateMozCrashReason("MOZ_ASSERT" "(" "std::isnan(d) || d == double(float(d))"
")"); do { *((volatile int*)__null) = 1056; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1057 return new (alloc) MConstant(float(d));
1058}
1059
1060MConstant* MConstant::NewInt64(TempAllocator& alloc, int64_t i) {
1061 return new (alloc) MConstant(MIRType::Int64, i);
1062}
1063
1064MConstant* MConstant::NewIntPtr(TempAllocator& alloc, intptr_t i) {
1065 return new (alloc) MConstant(MIRType::IntPtr, i);
1066}
1067
1068MConstant* MConstant::New(TempAllocator& alloc, const Value& v, MIRType type) {
1069 if (type == MIRType::Float32) {
1070 return NewFloat32(alloc, v.toNumber());
1071 }
1072 MConstant* res = New(alloc, v);
1073 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"
, 1073); AnnotateMozCrashReason("MOZ_ASSERT" "(" "res->type() == type"
")"); do { *((volatile int*)__null) = 1073; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1074 return res;
1075}
1076
1077MConstant* MConstant::NewObject(TempAllocator& alloc, JSObject* v) {
1078 return new (alloc) MConstant(v);
1079}
1080
1081MConstant* MConstant::NewShape(TempAllocator& alloc, Shape* s) {
1082 return new (alloc) MConstant(s);
1083}
1084
1085static MIRType MIRTypeFromValue(const js::Value& vp) {
1086 if (vp.isDouble()) {
1087 return MIRType::Double;
1088 }
1089 if (vp.isMagic()) {
1090 switch (vp.whyMagic()) {
1091 case JS_OPTIMIZED_OUT:
1092 return MIRType::MagicOptimizedOut;
1093 case JS_ELEMENTS_HOLE:
1094 return MIRType::MagicHole;
1095 case JS_IS_CONSTRUCTING:
1096 return MIRType::MagicIsConstructing;
1097 case JS_UNINITIALIZED_LEXICAL:
1098 return MIRType::MagicUninitializedLexical;
1099 default:
1100 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"
, 1100); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected magic constant" ")");
do { *((volatile int*)__null) = 1100; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1101 }
1102 }
1103 return MIRTypeFromValueType(vp.extractNonDoubleType());
1104}
1105
1106MConstant::MConstant(TempAllocator& alloc, const js::Value& vp)
1107 : MNullaryInstruction(classOpcode) {
1108 setResultType(MIRTypeFromValue(vp));
1109
1110 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"
, 1110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0"
")"); do { *((volatile int*)__null) = 1110; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1111
1112 switch (type()) {
1113 case MIRType::Undefined:
1114 case MIRType::Null:
1115 break;
1116 case MIRType::Boolean:
1117 payload_.b = vp.toBoolean();
1118 break;
1119 case MIRType::Int32:
1120 payload_.i32 = vp.toInt32();
1121 break;
1122 case MIRType::Double:
1123 payload_.d = vp.toDouble();
1124 break;
1125 case MIRType::String: {
1126 JSString* str = vp.toString();
1127 if (str->isAtomRef()) {
1128 str = str->atom();
1129 }
1130 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"
, 1130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(str)"
")"); do { *((volatile int*)__null) = 1130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1131 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"
, 1131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "str->isAtom()"
")"); do { *((volatile int*)__null) = 1131; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1132 payload_.str = vp.toString();
1133 break;
1134 }
1135 case MIRType::Symbol:
1136 payload_.sym = vp.toSymbol();
1137 break;
1138 case MIRType::BigInt:
1139 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"
, 1139); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(vp.toBigInt())"
")"); do { *((volatile int*)__null) = 1139; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1140 payload_.bi = vp.toBigInt();
1141 break;
1142 case MIRType::Object:
1143 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"
, 1143); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(&vp.toObject())"
")"); do { *((volatile int*)__null) = 1143; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1144 payload_.obj = &vp.toObject();
1145 break;
1146 case MIRType::MagicOptimizedOut:
1147 case MIRType::MagicHole:
1148 case MIRType::MagicIsConstructing:
1149 case MIRType::MagicUninitializedLexical:
1150 break;
1151 default:
1152 MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1152); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type"
")"); do { *((volatile int*)__null) = 1152; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1153 }
1154
1155 setMovable();
1156}
1157
1158MConstant::MConstant(JSObject* obj) : MNullaryInstruction(classOpcode) {
1159 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"
, 1159); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsInsideNursery(obj)"
")"); do { *((volatile int*)__null) = 1159; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1160 setResultType(MIRType::Object);
1161 payload_.obj = obj;
1162 setMovable();
1163}
1164
1165MConstant::MConstant(Shape* shape) : MNullaryInstruction(classOpcode) {
1166 setResultType(MIRType::Shape);
1167 payload_.shape = shape;
1168 setMovable();
1169}
1170
1171MConstant::MConstant(float f) : MNullaryInstruction(classOpcode) {
1172 setResultType(MIRType::Float32);
1173 payload_.f = f;
1174 setMovable();
1175}
1176
1177MConstant::MConstant(MIRType type, int64_t i)
1178 : MNullaryInstruction(classOpcode) {
1179 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"
, 1179); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == MIRType::Int64 || type == MIRType::IntPtr"
")"); do { *((volatile int*)__null) = 1179; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1180 setResultType(type);
1181 if (type == MIRType::Int64) {
1182 payload_.i64 = i;
1183 } else {
1184 payload_.iptr = i;
1185 }
1186 setMovable();
1187}
1188
1189#ifdef DEBUG1
1190void MConstant::assertInitializedPayload() const {
1191 // valueHash() and equals() expect the unused payload bits to be
1192 // initialized to zero. Assert this in debug builds.
1193
1194 switch (type()) {
1195 case MIRType::Int32:
1196 case MIRType::Float32:
1197# if MOZ_LITTLE_ENDIAN()1
1198 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"
, 1198); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0"
")"); do { *((volatile int*)__null) = 1198; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1199# else
1200 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"
, 1200); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0"
")"); do { *((volatile int*)__null) = 1200; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1201# endif
1202 break;
1203 case MIRType::Boolean:
1204# if MOZ_LITTLE_ENDIAN()1
1205 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"
, 1205); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 1) == 0"
")"); do { *((volatile int*)__null) = 1205; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1206# else
1207 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"
, 1207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits & ~(1ULL << 56)) == 0"
")"); do { *((volatile int*)__null) = 1207; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1208# endif
1209 break;
1210 case MIRType::Double:
1211 case MIRType::Int64:
1212 break;
1213 case MIRType::String:
1214 case MIRType::Object:
1215 case MIRType::Symbol:
1216 case MIRType::BigInt:
1217 case MIRType::IntPtr:
1218 case MIRType::Shape:
1219# if MOZ_LITTLE_ENDIAN()1
1220 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"
, 1220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits >> 32) == 0"
")"); do { *((volatile int*)__null) = 1220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1221# else
1222 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"
, 1222); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(payload_.asBits << 32) == 0"
")"); do { *((volatile int*)__null) = 1222; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1223# endif
1224 break;
1225 default:
1226 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"
, 1226); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNullOrUndefined(type()) || IsMagicType(type())"
")"); do { *((volatile int*)__null) = 1226; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1227 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"
, 1227); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload_.asBits == 0"
")"); do { *((volatile int*)__null) = 1227; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1228 break;
1229 }
1230}
1231#endif
1232
1233static HashNumber ConstantValueHash(MIRType type, uint64_t payload) {
1234 // Build a 64-bit value holding both the payload and the type.
1235 static const size_t TypeBits = 8;
1236 static const size_t TypeShift = 64 - TypeBits;
1237 MOZ_ASSERT(uintptr_t(type) <= (1 << TypeBits) - 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(uintptr_t(type) <= (1 << TypeBits) - 1)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(uintptr_t(type) <= (1 << TypeBits) - 1))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("uintptr_t(type) <= (1 << TypeBits) - 1"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "uintptr_t(type) <= (1 << TypeBits) - 1"
")"); do { *((volatile int*)__null) = 1237; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1238 uint64_t bits = (uint64_t(type) << TypeShift) ^ payload;
1239
1240 // Fold all 64 bits into the 32-bit result. It's tempting to just discard
1241 // half of the bits, as this is just a hash, however there are many common
1242 // patterns of values where only the low or the high bits vary, so
1243 // discarding either side would lead to excessive hash collisions.
1244 return (HashNumber)bits ^ (HashNumber)(bits >> 32);
1245}
1246
1247HashNumber MConstant::valueHash() const {
1248 static_assert(sizeof(Payload) == sizeof(uint64_t),
1249 "Code below assumes payload fits in 64 bits");
1250
1251 assertInitializedPayload();
1252 return ConstantValueHash(type(), payload_.asBits);
1253}
1254
1255HashNumber MConstantProto::valueHash() const {
1256 HashNumber hash = protoObject()->valueHash();
1257 const MDefinition* receiverObject = getReceiverObject();
1258 if (receiverObject) {
1259 hash = addU32ToHash(hash, receiverObject->id());
1260 }
1261 return hash;
1262}
1263
1264bool MConstant::congruentTo(const MDefinition* ins) const {
1265 return ins->isConstant() && equals(ins->toConstant());
1266}
1267
1268#ifdef JS_JITSPEW1
1269void MConstant::printOpcode(GenericPrinter& out) const {
1270 PrintOpcodeName(out, op());
1271 out.printf(" ");
1272 switch (type()) {
1273 case MIRType::Undefined:
1274 out.printf("undefined");
1275 break;
1276 case MIRType::Null:
1277 out.printf("null");
1278 break;
1279 case MIRType::Boolean:
1280 out.printf(toBoolean() ? "true" : "false");
1281 break;
1282 case MIRType::Int32:
1283 out.printf("0x%x", uint32_t(toInt32()));
1284 break;
1285 case MIRType::Int64:
1286 out.printf("0x%" PRIx64"l" "x", uint64_t(toInt64()));
1287 break;
1288 case MIRType::IntPtr:
1289 out.printf("0x%" PRIxPTR"l" "x", uintptr_t(toIntPtr()));
1290 break;
1291 case MIRType::Double:
1292 out.printf("%.16g", toDouble());
1293 break;
1294 case MIRType::Float32: {
1295 float val = toFloat32();
1296 out.printf("%.16g", val);
1297 break;
1298 }
1299 case MIRType::Object:
1300 if (toObject().is<JSFunction>()) {
1301 JSFunction* fun = &toObject().as<JSFunction>();
1302 if (fun->maybePartialDisplayAtom()) {
1303 out.put("function ");
1304 EscapedStringPrinter(out, fun->maybePartialDisplayAtom(), 0);
1305 } else {
1306 out.put("unnamed function");
1307 }
1308 if (fun->hasBaseScript()) {
1309 BaseScript* script = fun->baseScript();
1310 out.printf(" (%s:%u)", script->filename() ? script->filename() : "",
1311 script->lineno());
1312 }
1313 out.printf(" at %p", (void*)fun);
1314 break;
1315 }
1316 out.printf("object %p (%s)", (void*)&toObject(),
1317 toObject().getClass()->name);
1318 break;
1319 case MIRType::Symbol:
1320 out.printf("symbol at %p", (void*)toSymbol());
1321 break;
1322 case MIRType::BigInt:
1323 out.printf("BigInt at %p", (void*)toBigInt());
1324 break;
1325 case MIRType::String:
1326 out.printf("string %p", (void*)toString());
1327 break;
1328 case MIRType::Shape:
1329 out.printf("shape at %p", (void*)toShape());
1330 break;
1331 case MIRType::MagicHole:
1332 out.printf("magic hole");
1333 break;
1334 case MIRType::MagicIsConstructing:
1335 out.printf("magic is-constructing");
1336 break;
1337 case MIRType::MagicOptimizedOut:
1338 out.printf("magic optimized-out");
1339 break;
1340 case MIRType::MagicUninitializedLexical:
1341 out.printf("magic uninitialized-lexical");
1342 break;
1343 default:
1344 MOZ_CRASH("unexpected type")do { do { } while (false); MOZ_ReportCrash("" "unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1344); AnnotateMozCrashReason("MOZ_CRASH(" "unexpected type"
")"); do { *((volatile int*)__null) = 1344; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1345 }
1346}
1347#endif
1348
1349bool MConstant::canProduceFloat32() const {
1350 if (!isTypeRepresentableAsDouble()) {
1351 return false;
1352 }
1353
1354 if (type() == MIRType::Int32) {
1355 return IsFloat32Representable(static_cast<double>(toInt32()));
1356 }
1357 if (type() == MIRType::Double) {
1358 return IsFloat32Representable(toDouble());
1359 }
1360 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"
, 1360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Float32"
")"); do { *((volatile int*)__null) = 1360; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1361 return true;
1362}
1363
1364Value MConstant::toJSValue() const {
1365 // Wasm has types like int64 that cannot be stored as js::Value. It also
1366 // doesn't want the NaN canonicalization enforced by js::Value.
1367 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"
, 1367); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsCompilingWasm()"
")"); do { *((volatile int*)__null) = 1367; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1368
1369 switch (type()) {
1370 case MIRType::Undefined:
1371 return UndefinedValue();
1372 case MIRType::Null:
1373 return NullValue();
1374 case MIRType::Boolean:
1375 return BooleanValue(toBoolean());
1376 case MIRType::Int32:
1377 return Int32Value(toInt32());
1378 case MIRType::Double:
1379 return DoubleValue(toDouble());
1380 case MIRType::Float32:
1381 return Float32Value(toFloat32());
1382 case MIRType::String:
1383 return StringValue(toString());
1384 case MIRType::Symbol:
1385 return SymbolValue(toSymbol());
1386 case MIRType::BigInt:
1387 return BigIntValue(toBigInt());
1388 case MIRType::Object:
1389 return ObjectValue(toObject());
1390 case MIRType::Shape:
1391 return PrivateGCThingValue(toShape());
1392 case MIRType::MagicOptimizedOut:
1393 return MagicValue(JS_OPTIMIZED_OUT);
1394 case MIRType::MagicHole:
1395 return MagicValue(JS_ELEMENTS_HOLE);
1396 case MIRType::MagicIsConstructing:
1397 return MagicValue(JS_IS_CONSTRUCTING);
1398 case MIRType::MagicUninitializedLexical:
1399 return MagicValue(JS_UNINITIALIZED_LEXICAL);
1400 default:
1401 MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1401); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type"
")"); do { *((volatile int*)__null) = 1401; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1402 }
1403}
1404
1405bool MConstant::valueToBoolean(bool* res) const {
1406 switch (type()) {
1407 case MIRType::Boolean:
1408 *res = toBoolean();
1409 return true;
1410 case MIRType::Int32:
1411 *res = toInt32() != 0;
1412 return true;
1413 case MIRType::Int64:
1414 *res = toInt64() != 0;
1415 return true;
1416 case MIRType::Double:
1417 *res = !std::isnan(toDouble()) && toDouble() != 0.0;
1418 return true;
1419 case MIRType::Float32:
1420 *res = !std::isnan(toFloat32()) && toFloat32() != 0.0f;
1421 return true;
1422 case MIRType::Null:
1423 case MIRType::Undefined:
1424 *res = false;
1425 return true;
1426 case MIRType::Symbol:
1427 *res = true;
1428 return true;
1429 case MIRType::BigInt:
1430 *res = !toBigInt()->isZero();
1431 return true;
1432 case MIRType::String:
1433 *res = toString()->length() != 0;
1434 return true;
1435 case MIRType::Object:
1436 // TODO(Warp): Lazy groups have been removed.
1437 // We have to call EmulatesUndefined but that reads obj->group->clasp
1438 // and so it's racy when the object has a lazy group. The main callers
1439 // of this (MTest, MNot) already know how to fold the object case, so
1440 // just give up.
1441 return false;
1442 default:
1443 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"
, 1443); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsMagicType(type())"
")"); do { *((volatile int*)__null) = 1443; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1444 return false;
1445 }
1446}
1447
1448HashNumber MWasmFloatConstant::valueHash() const {
1449#ifdef ENABLE_WASM_SIMD1
1450 return ConstantValueHash(type(), u.bits_[0] ^ u.bits_[1]);
1451#else
1452 return ConstantValueHash(type(), u.bits_[0]);
1453#endif
1454}
1455
1456bool MWasmFloatConstant::congruentTo(const MDefinition* ins) const {
1457 return ins->isWasmFloatConstant() && type() == ins->type() &&
1458#ifdef ENABLE_WASM_SIMD1
1459 u.bits_[1] == ins->toWasmFloatConstant()->u.bits_[1] &&
1460#endif
1461 u.bits_[0] == ins->toWasmFloatConstant()->u.bits_[0];
1462}
1463
1464HashNumber MWasmNullConstant::valueHash() const {
1465 return ConstantValueHash(MIRType::WasmAnyRef, 0);
1466}
1467
1468#ifdef JS_JITSPEW1
1469void MControlInstruction::printOpcode(GenericPrinter& out) const {
1470 MDefinition::printOpcode(out);
1471 for (size_t j = 0; j < numSuccessors(); j++) {
1472 if (getSuccessor(j)) {
1473 out.printf(" block%u", getSuccessor(j)->id());
1474 } else {
1475 out.printf(" (null-to-be-patched)");
1476 }
1477 }
1478}
1479
1480void MCompare::printOpcode(GenericPrinter& out) const {
1481 MDefinition::printOpcode(out);
1482 out.printf(" %s", CodeName(jsop()));
1483}
1484
1485void MTypeOfIs::printOpcode(GenericPrinter& out) const {
1486 MDefinition::printOpcode(out);
1487 out.printf(" %s", CodeName(jsop()));
1488
1489 const char* name = "";
Value stored to 'name' during its initialization is never read
1490 switch (jstype()) {
1491 case JSTYPE_UNDEFINED:
1492 name = "undefined";
1493 break;
1494 case JSTYPE_OBJECT:
1495 name = "object";
1496 break;
1497 case JSTYPE_FUNCTION:
1498 name = "function";
1499 break;
1500 case JSTYPE_STRING:
1501 name = "string";
1502 break;
1503 case JSTYPE_NUMBER:
1504 name = "number";
1505 break;
1506 case JSTYPE_BOOLEAN:
1507 name = "boolean";
1508 break;
1509 case JSTYPE_SYMBOL:
1510 name = "symbol";
1511 break;
1512 case JSTYPE_BIGINT:
1513 name = "bigint";
1514 break;
1515# ifdef ENABLE_RECORD_TUPLE
1516 case JSTYPE_RECORD:
1517 case JSTYPE_TUPLE:
1518# endif
1519 case JSTYPE_LIMIT:
1520 MOZ_CRASH("Unexpected type")do { do { } while (false); MOZ_ReportCrash("" "Unexpected type"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1520); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected type"
")"); do { *((volatile int*)__null) = 1520; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
1521 }
1522 out.printf(" '%s'", name);
1523}
1524
1525void MLoadUnboxedScalar::printOpcode(GenericPrinter& out) const {
1526 MDefinition::printOpcode(out);
1527 out.printf(" %s", Scalar::name(storageType()));
1528}
1529
1530void MLoadDataViewElement::printOpcode(GenericPrinter& out) const {
1531 MDefinition::printOpcode(out);
1532 out.printf(" %s", Scalar::name(storageType()));
1533}
1534
1535void MAssertRange::printOpcode(GenericPrinter& out) const {
1536 MDefinition::printOpcode(out);
1537 out.put(" ");
1538 assertedRange()->dump(out);
1539}
1540
1541void MNearbyInt::printOpcode(GenericPrinter& out) const {
1542 MDefinition::printOpcode(out);
1543 const char* roundingModeStr = nullptr;
1544 switch (roundingMode_) {
1545 case RoundingMode::Up:
1546 roundingModeStr = "(up)";
1547 break;
1548 case RoundingMode::Down:
1549 roundingModeStr = "(down)";
1550 break;
1551 case RoundingMode::NearestTiesToEven:
1552 roundingModeStr = "(nearest ties even)";
1553 break;
1554 case RoundingMode::TowardsZero:
1555 roundingModeStr = "(towards zero)";
1556 break;
1557 }
1558 out.printf(" %s", roundingModeStr);
1559}
1560#endif
1561
1562AliasSet MRandom::getAliasSet() const { return AliasSet::Store(AliasSet::RNG); }
1563
1564MDefinition* MSign::foldsTo(TempAllocator& alloc) {
1565 MDefinition* input = getOperand(0);
1566 if (!input->isConstant() ||
1567 !input->toConstant()->isTypeRepresentableAsDouble()) {
1568 return this;
1569 }
1570
1571 double in = input->toConstant()->numberToDouble();
1572 double out = js::math_sign_impl(in);
1573
1574 if (type() == MIRType::Int32) {
1575 // Decline folding if this is an int32 operation, but the result type
1576 // isn't an int32.
1577 Value outValue = NumberValue(out);
1578 if (!outValue.isInt32()) {
1579 return this;
1580 }
1581
1582 return MConstant::New(alloc, outValue);
1583 }
1584
1585 return MConstant::New(alloc, DoubleValue(out));
1586}
1587
1588const char* MMathFunction::FunctionName(UnaryMathFunction function) {
1589 return GetUnaryMathFunctionName(function);
1590}
1591
1592#ifdef JS_JITSPEW1
1593void MMathFunction::printOpcode(GenericPrinter& out) const {
1594 MDefinition::printOpcode(out);
1595 out.printf(" %s", FunctionName(function()));
1596}
1597#endif
1598
1599MDefinition* MMathFunction::foldsTo(TempAllocator& alloc) {
1600 MDefinition* input = getOperand(0);
1601 if (!input->isConstant() ||
1602 !input->toConstant()->isTypeRepresentableAsDouble()) {
1603 return this;
1604 }
1605
1606 UnaryMathFunctionType funPtr = GetUnaryMathFunctionPtr(function());
1607
1608 double in = input->toConstant()->numberToDouble();
1609
1610 // The function pointer call can't GC.
1611 JS::AutoSuppressGCAnalysis nogc;
1612 double out = funPtr(in);
1613
1614 if (input->type() == MIRType::Float32) {
1615 return MConstant::NewFloat32(alloc, out);
1616 }
1617 return MConstant::New(alloc, DoubleValue(out));
1618}
1619
1620MDefinition* MAtomicIsLockFree::foldsTo(TempAllocator& alloc) {
1621 MDefinition* input = getOperand(0);
1622 if (!input->isConstant() || input->type() != MIRType::Int32) {
1623 return this;
1624 }
1625
1626 int32_t i = input->toConstant()->toInt32();
1627 return MConstant::New(alloc, BooleanValue(AtomicOperations::isLockfreeJS(i)));
1628}
1629
1630// Define |THIS_SLOT| as part of this translation unit, as it is used to
1631// specialized the parameterized |New| function calls introduced by
1632// TRIVIAL_NEW_WRAPPERS.
1633const int32_t MParameter::THIS_SLOT;
1634
1635#ifdef JS_JITSPEW1
1636void MParameter::printOpcode(GenericPrinter& out) const {
1637 PrintOpcodeName(out, op());
1638 if (index() == THIS_SLOT) {
1639 out.printf(" THIS_SLOT");
1640 } else {
1641 out.printf(" %d", index());
1642 }
1643}
1644#endif
1645
1646HashNumber MParameter::valueHash() const {
1647 HashNumber hash = MDefinition::valueHash();
1648 hash = addU32ToHash(hash, index_);
1649 return hash;
1650}
1651
1652bool MParameter::congruentTo(const MDefinition* ins) const {
1653 if (!ins->isParameter()) {
1654 return false;
1655 }
1656
1657 return ins->toParameter()->index() == index_;
1658}
1659
1660WrappedFunction::WrappedFunction(JSFunction* nativeFun, uint16_t nargs,
1661 FunctionFlags flags)
1662 : nativeFun_(nativeFun), nargs_(nargs), flags_(flags) {
1663 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"
, 1663); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isNativeWithoutJitEntry()"
")"); do { *((volatile int*)__null) = 1663; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1664
1665#ifdef DEBUG1
1666 // If we are not running off-main thread we can assert that the
1667 // metadata is consistent.
1668 if (!CanUseExtraThreads() && nativeFun) {
1669 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"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->nargs() == nargs"
")"); do { *((volatile int*)__null) = 1669; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1670
1671 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"
, 1672); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()"
")"); do { *((volatile int*)__null) = 1672; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1672 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"
, 1672); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isNativeWithoutJitEntry() == isNativeWithoutJitEntry()"
")"); do { *((volatile int*)__null) = 1672; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1673 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"
, 1673); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->hasJitEntry() == hasJitEntry()"
")"); do { *((volatile int*)__null) = 1673; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1674 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"
, 1674); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isConstructor() == isConstructor()"
")"); do { *((volatile int*)__null) = 1674; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1675 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"
, 1675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeFun->isClassConstructor() == isClassConstructor()"
")"); do { *((volatile int*)__null) = 1675; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1676 }
1677#endif
1678}
1679
1680MCall* MCall::New(TempAllocator& alloc, WrappedFunction* target, size_t maxArgc,
1681 size_t numActualArgs, bool construct, bool ignoresReturnValue,
1682 bool isDOMCall, mozilla::Maybe<DOMObjectKind> objectKind) {
1683 MOZ_ASSERT(isDOMCall == objectKind.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isDOMCall == objectKind.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isDOMCall == objectKind.isSome
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("isDOMCall == objectKind.isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 1683); AnnotateMozCrashReason("MOZ_ASSERT" "(" "isDOMCall == objectKind.isSome()"
")"); do { *((volatile int*)__null) = 1683; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1684 MOZ_ASSERT(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"
, 1684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "maxArgc >= numActualArgs"
")"); do { *((volatile int*)__null) = 1684; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1685 MCall* ins;
1686 if (isDOMCall) {
1687 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"
, 1687); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!construct"
")"); do { *((volatile int*)__null) = 1687; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1688 ins = new (alloc) MCallDOMNative(target, numActualArgs, *objectKind);
1689 } else {
1690 ins =
1691 new (alloc) MCall(target, numActualArgs, construct, ignoresReturnValue);
1692 }
1693 if (!ins->init(alloc, maxArgc + NumNonArgumentOperands)) {
1694 return nullptr;
1695 }
1696 return ins;
1697}
1698
1699AliasSet MCallDOMNative::getAliasSet() const {
1700 const JSJitInfo* jitInfo = getJitInfo();
1701
1702 // If we don't know anything about the types of our arguments, we have to
1703 // assume that type-coercions can have side-effects, so we need to alias
1704 // everything.
1705 if (jitInfo->aliasSet() == JSJitInfo::AliasEverything ||
1706 !jitInfo->isTypedMethodJitInfo()) {
1707 return AliasSet::Store(AliasSet::Any);
1708 }
1709
1710 uint32_t argIndex = 0;
1711 const JSTypedMethodJitInfo* methodInfo =
1712 reinterpret_cast<const JSTypedMethodJitInfo*>(jitInfo);
1713 for (const JSJitInfo::ArgType* argType = methodInfo->argTypes;
1714 *argType != JSJitInfo::ArgTypeListEnd; ++argType, ++argIndex) {
1715 if (argIndex >= numActualArgs()) {
1716 // Passing through undefined can't have side-effects
1717 continue;
1718 }
1719 // getArg(0) is "this", so skip it
1720 MDefinition* arg = getArg(argIndex + 1);
1721 MIRType actualType = arg->type();
1722 // The only way to reliably avoid side-effects given the information we
1723 // have here is if we're passing in a known primitive value to an
1724 // argument that expects a primitive value.
1725 //
1726 // XXXbz maybe we need to communicate better information. For example,
1727 // a sequence argument will sort of unavoidably have side effects, while
1728 // a typed array argument won't have any, but both are claimed to be
1729 // JSJitInfo::Object. But if we do that, we need to watch out for our
1730 // movability/DCE-ability bits: if we have an arg type that can reliably
1731 // throw an exception on conversion, that might not affect our alias set
1732 // per se, but it should prevent us being moved or DCE-ed, unless we
1733 // know the incoming things match that arg type and won't throw.
1734 //
1735 if ((actualType == MIRType::Value || actualType == MIRType::Object) ||
1736 (*argType & JSJitInfo::Object)) {
1737 return AliasSet::Store(AliasSet::Any);
1738 }
1739 }
1740
1741 // We checked all the args, and they check out. So we only alias DOM
1742 // mutations or alias nothing, depending on the alias set in the jitinfo.
1743 if (jitInfo->aliasSet() == JSJitInfo::AliasNone) {
1744 return AliasSet::None();
1745 }
1746
1747 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"
, 1747); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() == JSJitInfo::AliasDOMSets"
")"); do { *((volatile int*)__null) = 1747; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1748 return AliasSet::Load(AliasSet::DOMProperty);
1749}
1750
1751void MCallDOMNative::computeMovable() {
1752 // We are movable if the jitinfo says we can be and if we're also not
1753 // effectful. The jitinfo can't check for the latter, since it depends on
1754 // the types of our arguments.
1755 const JSJitInfo* jitInfo = getJitInfo();
1756
1757 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"
, 1758); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything"
")"); do { *((volatile int*)__null) = 1758; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1758 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"
, 1758); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jitInfo->aliasSet() != JSJitInfo::AliasEverything"
")"); do { *((volatile int*)__null) = 1758; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1759
1760 if (jitInfo->isMovable && !isEffectful()) {
1761 setMovable();
1762 }
1763}
1764
1765bool MCallDOMNative::congruentTo(const MDefinition* ins) const {
1766 if (!isMovable()) {
1767 return false;
1768 }
1769
1770 if (!ins->isCall()) {
1771 return false;
1772 }
1773
1774 const MCall* call = ins->toCall();
1775
1776 if (!call->isCallDOMNative()) {
1777 return false;
1778 }
1779
1780 if (getSingleTarget() != call->getSingleTarget()) {
1781 return false;
1782 }
1783
1784 if (isConstructing() != call->isConstructing()) {
1785 return false;
1786 }
1787
1788 if (numActualArgs() != call->numActualArgs()) {
1789 return false;
1790 }
1791
1792 if (!congruentIfOperandsEqual(call)) {
1793 return false;
1794 }
1795
1796 // The other call had better be movable at this point!
1797 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"
, 1797); AnnotateMozCrashReason("MOZ_ASSERT" "(" "call->isMovable()"
")"); do { *((volatile int*)__null) = 1797; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1798
1799 return true;
1800}
1801
1802const JSJitInfo* MCallDOMNative::getJitInfo() const {
1803 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"
, 1803); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getSingleTarget()->hasJitInfo()"
")"); do { *((volatile int*)__null) = 1803; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1804 return getSingleTarget()->jitInfo();
1805}
1806
1807MCallClassHook* MCallClassHook::New(TempAllocator& alloc, JSNative target,
1808 uint32_t argc, bool constructing) {
1809 auto* ins = new (alloc) MCallClassHook(target, constructing);
1810
1811 // Add callee + |this| + (if constructing) newTarget.
1812 uint32_t numOperands = 2 + argc + constructing;
1813
1814 if (!ins->init(alloc, numOperands)) {
1815 return nullptr;
1816 }
1817
1818 return ins;
1819}
1820
1821MDefinition* MStringLength::foldsTo(TempAllocator& alloc) {
1822 if (string()->isConstant()) {
1823 JSString* str = string()->toConstant()->toString();
1824 return MConstant::New(alloc, Int32Value(str->length()));
1825 }
1826
1827 // MFromCharCode returns a one-element string.
1828 if (string()->isFromCharCode()) {
1829 return MConstant::New(alloc, Int32Value(1));
1830 }
1831
1832 return this;
1833}
1834
1835MDefinition* MConcat::foldsTo(TempAllocator& alloc) {
1836 if (lhs()->isConstant() && lhs()->toConstant()->toString()->empty()) {
1837 return rhs();
1838 }
1839
1840 if (rhs()->isConstant() && rhs()->toConstant()->toString()->empty()) {
1841 return lhs();
1842 }
1843
1844 return this;
1845}
1846
1847MDefinition* MStringConvertCase::foldsTo(TempAllocator& alloc) {
1848 MDefinition* string = this->string();
1849
1850 // Handle the pattern |str[idx].toUpperCase()| and simplify it from
1851 // |StringConvertCase(FromCharCode(CharCodeAt(str, idx)))| to just
1852 // |CharCodeConvertCase(CharCodeAt(str, idx))|.
1853 if (string->isFromCharCode()) {
1854 auto* charCode = string->toFromCharCode()->code();
1855 auto mode = mode_ == Mode::LowerCase ? MCharCodeConvertCase::LowerCase
1856 : MCharCodeConvertCase::UpperCase;
1857 return MCharCodeConvertCase::New(alloc, charCode, mode);
1858 }
1859
1860 // Handle the pattern |num.toString(base).toUpperCase()| and simplify it to
1861 // directly return the string representation in the correct case.
1862 if (string->isInt32ToStringWithBase()) {
1863 auto* toString = string->toInt32ToStringWithBase();
1864
1865 bool lowerCase = mode_ == Mode::LowerCase;
1866 if (toString->lowerCase() == lowerCase) {
1867 return toString;
1868 }
1869 return MInt32ToStringWithBase::New(alloc, toString->input(),
1870 toString->base(), lowerCase);
1871 }
1872
1873 return this;
1874}
1875
1876static bool IsSubstrTo(MSubstr* substr, int32_t len) {
1877 // We want to match this pattern:
1878 //
1879 // Substr(string, Constant(0), Min(Constant(length), StringLength(string)))
1880 //
1881 // which is generated for the self-hosted `String.p.{substring,slice,substr}`
1882 // functions when called with constants `start` and `end` parameters.
1883
1884 auto isConstantZero = [](auto* def) {
1885 return def->isConstant() && def->toConstant()->isInt32(0);
1886 };
1887
1888 if (!isConstantZero(substr->begin())) {
1889 return false;
1890 }
1891
1892 auto* length = substr->length();
1893 if (length->isBitOr()) {
1894 // Unnecessary bit-ops haven't yet been removed.
1895 auto* bitOr = length->toBitOr();
1896 if (isConstantZero(bitOr->lhs())) {
1897 length = bitOr->rhs();
1898 } else if (isConstantZero(bitOr->rhs())) {
1899 length = bitOr->lhs();
1900 }
1901 }
1902 if (!length->isMinMax() || length->toMinMax()->isMax()) {
1903 return false;
1904 }
1905
1906 auto* min = length->toMinMax();
1907 if (!min->lhs()->isConstant() && !min->rhs()->isConstant()) {
1908 return false;
1909 }
1910
1911 auto* minConstant = min->lhs()->isConstant() ? min->lhs()->toConstant()
1912 : min->rhs()->toConstant();
1913
1914 auto* minOperand = min->lhs()->isConstant() ? min->rhs() : min->lhs();
1915 if (!minOperand->isStringLength() ||
1916 minOperand->toStringLength()->string() != substr->string()) {
1917 return false;
1918 }
1919
1920 // Ensure |len| matches the substring's length.
1921 return minConstant->isInt32(len);
1922}
1923
1924MDefinition* MSubstr::foldsTo(TempAllocator& alloc) {
1925 // Fold |str.substring(0, 1)| to |str.charAt(0)|.
1926 if (!IsSubstrTo(this, 1)) {
1927 return this;
1928 }
1929
1930 auto* charCode = MCharCodeAtOrNegative::New(alloc, string(), begin());
1931 block()->insertBefore(this, charCode);
1932
1933 return MFromCharCodeEmptyIfNegative::New(alloc, charCode);
1934}
1935
1936MDefinition* MCharCodeAt::foldsTo(TempAllocator& alloc) {
1937 MDefinition* string = this->string();
1938 if (!string->isConstant() && !string->isFromCharCode()) {
1939 return this;
1940 }
1941
1942 MDefinition* index = this->index();
1943 if (index->isSpectreMaskIndex()) {
1944 index = index->toSpectreMaskIndex()->index();
1945 }
1946 if (!index->isConstant()) {
1947 return this;
1948 }
1949 int32_t idx = index->toConstant()->toInt32();
1950
1951 // Handle the pattern |s[idx].charCodeAt(0)|.
1952 if (string->isFromCharCode()) {
1953 if (idx != 0) {
1954 return this;
1955 }
1956
1957 // Simplify |CharCodeAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just
1958 // |CharCodeAt(s, idx)|.
1959 auto* charCode = string->toFromCharCode()->code();
1960 if (!charCode->isCharCodeAt()) {
1961 return this;
1962 }
1963
1964 return charCode;
1965 }
1966
1967 JSLinearString* str = &string->toConstant()->toString()->asLinear();
1968 if (idx < 0 || uint32_t(idx) >= str->length()) {
1969 return this;
1970 }
1971
1972 char16_t ch = str->latin1OrTwoByteChar(idx);
1973 return MConstant::New(alloc, Int32Value(ch));
1974}
1975
1976MDefinition* MCodePointAt::foldsTo(TempAllocator& alloc) {
1977 MDefinition* string = this->string();
1978 if (!string->isConstant() && !string->isFromCharCode()) {
1979 return this;
1980 }
1981
1982 MDefinition* index = this->index();
1983 if (index->isSpectreMaskIndex()) {
1984 index = index->toSpectreMaskIndex()->index();
1985 }
1986 if (!index->isConstant()) {
1987 return this;
1988 }
1989 int32_t idx = index->toConstant()->toInt32();
1990
1991 // Handle the pattern |s[idx].codePointAt(0)|.
1992 if (string->isFromCharCode()) {
1993 if (idx != 0) {
1994 return this;
1995 }
1996
1997 // Simplify |CodePointAt(FromCharCode(CharCodeAt(s, idx)), 0)| to just
1998 // |CharCodeAt(s, idx)|.
1999 auto* charCode = string->toFromCharCode()->code();
2000 if (!charCode->isCharCodeAt()) {
2001 return this;
2002 }
2003
2004 return charCode;
2005 }
2006
2007 JSLinearString* str = &string->toConstant()->toString()->asLinear();
2008 if (idx < 0 || uint32_t(idx) >= str->length()) {
2009 return this;
2010 }
2011
2012 char32_t first = str->latin1OrTwoByteChar(idx);
2013 if (unicode::IsLeadSurrogate(first) && uint32_t(idx) + 1 < str->length()) {
2014 char32_t second = str->latin1OrTwoByteChar(idx + 1);
2015 if (unicode::IsTrailSurrogate(second)) {
2016 first = unicode::UTF16Decode(first, second);
2017 }
2018 }
2019 return MConstant::New(alloc, Int32Value(first));
2020}
2021
2022MDefinition* MToRelativeStringIndex::foldsTo(TempAllocator& alloc) {
2023 MDefinition* index = this->index();
2024 MDefinition* length = this->length();
2025
2026 if (!index->isConstant()) {
2027 return this;
2028 }
2029 if (!length->isStringLength() && !length->isConstant()) {
2030 return this;
2031 }
2032 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"
, 2032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "length->toConstant()->toInt32() >= 0"
")"); do { *((volatile int*)__null) = 2032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2033
2034 int32_t relativeIndex = index->toConstant()->toInt32();
2035 if (relativeIndex >= 0) {
2036 return index;
2037 }
2038
2039 // Safe to truncate because |length| is never negative.
2040 return MAdd::New(alloc, index, length, TruncateKind::Truncate);
2041}
2042
2043template <size_t Arity>
2044[[nodiscard]] static bool EnsureFloatInputOrConvert(
2045 MAryInstruction<Arity>* owner, TempAllocator& alloc) {
2046 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"
, 2047); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())"
") (" "Floating point types must check consumers" ")"); do {
*((volatile int*)__null) = 2047; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2047 "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"
, 2047); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsFloatingPointType(owner->type())"
") (" "Floating point types must check consumers" ")"); do {
*((volatile int*)__null) = 2047; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2048
2049 if (AllOperandsCanProduceFloat32(owner)) {
2050 return true;
2051 }
2052 ConvertOperandsToDouble(owner, alloc);
2053 return false;
2054}
2055
2056template <size_t Arity>
2057[[nodiscard]] static bool EnsureFloatConsumersAndInputOrConvert(
2058 MAryInstruction<Arity>* owner, TempAllocator& alloc) {
2059 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"
, 2060); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())"
") (" "Integer types don't need to check consumers" ")"); do
{ *((volatile int*)__null) = 2060; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2060 "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"
, 2060); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsFloatingPointType(owner->type())"
") (" "Integer types don't need to check consumers" ")"); do
{ *((volatile int*)__null) = 2060; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2061
2062 if (AllOperandsCanProduceFloat32(owner) &&
2063 CheckUsesAreFloat32Consumers(owner)) {
2064 return true;
2065 }
2066 ConvertOperandsToDouble(owner, alloc);
2067 return false;
2068}
2069
2070void MFloor::trySpecializeFloat32(TempAllocator& alloc) {
2071 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"
, 2071); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2071; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2072 if (EnsureFloatInputOrConvert(this, alloc)) {
2073 specialization_ = MIRType::Float32;
2074 }
2075}
2076
2077void MCeil::trySpecializeFloat32(TempAllocator& alloc) {
2078 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"
, 2078); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2078; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2079 if (EnsureFloatInputOrConvert(this, alloc)) {
2080 specialization_ = MIRType::Float32;
2081 }
2082}
2083
2084void MRound::trySpecializeFloat32(TempAllocator& alloc) {
2085 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"
, 2085); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2085; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2086 if (EnsureFloatInputOrConvert(this, alloc)) {
2087 specialization_ = MIRType::Float32;
2088 }
2089}
2090
2091void MTrunc::trySpecializeFloat32(TempAllocator& alloc) {
2092 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"
, 2092); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2092; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2093 if (EnsureFloatInputOrConvert(this, alloc)) {
2094 specialization_ = MIRType::Float32;
2095 }
2096}
2097
2098void MNearbyInt::trySpecializeFloat32(TempAllocator& alloc) {
2099 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
2100 specialization_ = MIRType::Float32;
2101 setResultType(MIRType::Float32);
2102 }
2103}
2104
2105MGoto* MGoto::New(TempAllocator& alloc, MBasicBlock* target) {
2106 return new (alloc) MGoto(target);
2107}
2108
2109MGoto* MGoto::New(TempAllocator::Fallible alloc, MBasicBlock* target) {
2110 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"
, 2110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "target" ")"
); do { *((volatile int*)__null) = 2110; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2111 return new (alloc) MGoto(target);
2112}
2113
2114MGoto* MGoto::New(TempAllocator& alloc) { return new (alloc) MGoto(nullptr); }
2115
2116MDefinition* MBox::foldsTo(TempAllocator& alloc) {
2117 if (input()->isUnbox()) {
2118 return input()->toUnbox()->input();
2119 }
2120 return this;
2121}
2122
2123#ifdef JS_JITSPEW1
2124void MUnbox::printOpcode(GenericPrinter& out) const {
2125 PrintOpcodeName(out, op());
2126 out.printf(" ");
2127 getOperand(0)->printName(out);
2128 out.printf(" ");
2129
2130 switch (type()) {
2131 case MIRType::Int32:
2132 out.printf("to Int32");
2133 break;
2134 case MIRType::Double:
2135 out.printf("to Double");
2136 break;
2137 case MIRType::Boolean:
2138 out.printf("to Boolean");
2139 break;
2140 case MIRType::String:
2141 out.printf("to String");
2142 break;
2143 case MIRType::Symbol:
2144 out.printf("to Symbol");
2145 break;
2146 case MIRType::BigInt:
2147 out.printf("to BigInt");
2148 break;
2149 case MIRType::Object:
2150 out.printf("to Object");
2151 break;
2152 default:
2153 break;
2154 }
2155
2156 switch (mode()) {
2157 case Fallible:
2158 out.printf(" (fallible)");
2159 break;
2160 case Infallible:
2161 out.printf(" (infallible)");
2162 break;
2163 default:
2164 break;
2165 }
2166}
2167#endif
2168
2169MDefinition* MUnbox::foldsTo(TempAllocator& alloc) {
2170 if (input()->isBox()) {
2171 MDefinition* unboxed = input()->toBox()->input();
2172
2173 // Fold MUnbox(MBox(x)) => x if types match.
2174 if (unboxed->type() == type()) {
2175 if (fallible()) {
2176 unboxed->setImplicitlyUsedUnchecked();
2177 }
2178 return unboxed;
2179 }
2180
2181 // Fold MUnbox(MBox(x)) => MToDouble(x) if possible.
2182 if (type() == MIRType::Double &&
2183 IsTypeRepresentableAsDouble(unboxed->type())) {
2184 if (unboxed->isConstant()) {
2185 return MConstant::New(
2186 alloc, DoubleValue(unboxed->toConstant()->numberToDouble()));
2187 }
2188
2189 return MToDouble::New(alloc, unboxed);
2190 }
2191
2192 // MUnbox<Int32>(MBox<Double>(x)) will always fail, even if x can be
2193 // represented as an Int32. Fold to avoid unnecessary bailouts.
2194 if (type() == MIRType::Int32 && unboxed->type() == MIRType::Double) {
2195 auto* folded = MToNumberInt32::New(alloc, unboxed,
2196 IntConversionInputKind::NumbersOnly);
2197 folded->setGuard();
2198 return folded;
2199 }
2200 }
2201
2202 return this;
2203}
2204
2205#ifdef DEBUG1
2206void MPhi::assertLoopPhi() const {
2207 // getLoopPredecessorOperand and getLoopBackedgeOperand rely on these
2208 // predecessors being at known indices.
2209 if (block()->numPredecessors() == 2) {
2210 MBasicBlock* pred = block()->getPredecessor(0);
2211 MBasicBlock* back = block()->getPredecessor(1);
2212 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"
, 2212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred == block()->loopPredecessor()"
")"); do { *((volatile int*)__null) = 2212; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2213 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"
, 2213); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->successorWithPhis() == block()"
")"); do { *((volatile int*)__null) = 2213; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2214 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"
, 2214); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pred->positionInPhiSuccessor() == 0"
")"); do { *((volatile int*)__null) = 2214; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2215 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"
, 2215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()"
")"); do { *((volatile int*)__null) = 2215; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2216 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"
, 2216); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()"
")"); do { *((volatile int*)__null) = 2216; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2217 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"
, 2217); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 1"
")"); do { *((volatile int*)__null) = 2217; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2218 } else {
2219 // After we remove fake loop predecessors for loop headers that
2220 // are only reachable via OSR, the only predecessor is the
2221 // loop backedge.
2222 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"
, 2222); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 1"
")"); do { *((volatile int*)__null) = 2222; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2223 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"
, 2223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->graph().osrBlock()"
")"); do { *((volatile int*)__null) = 2223; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2224 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"
, 2224); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!block()->graph().canBuildDominators()"
")"); do { *((volatile int*)__null) = 2224; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2225 MBasicBlock* back = block()->getPredecessor(0);
2226 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"
, 2226); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back == block()->backedge()"
")"); do { *((volatile int*)__null) = 2226; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2227 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"
, 2227); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->successorWithPhis() == block()"
")"); do { *((volatile int*)__null) = 2227; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2228 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"
, 2228); AnnotateMozCrashReason("MOZ_ASSERT" "(" "back->positionInPhiSuccessor() == 0"
")"); do { *((volatile int*)__null) = 2228; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2229 }
2230}
2231#endif
2232
2233MDefinition* MPhi::getLoopPredecessorOperand() const {
2234 // This should not be called after removing fake loop predecessors.
2235 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"
, 2235); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2"
")"); do { *((volatile int*)__null) = 2235; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2236 assertLoopPhi();
2237 return getOperand(0);
2238}
2239
2240MDefinition* MPhi::getLoopBackedgeOperand() const {
2241 assertLoopPhi();
2242 uint32_t idx = block()->numPredecessors() == 2 ? 1 : 0;
2243 return getOperand(idx);
2244}
2245
2246void MPhi::removeOperand(size_t index) {
2247 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"
, 2247); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index < numOperands()"
")"); do { *((volatile int*)__null) = 2247; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2248 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"
, 2248); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->index() == index"
")"); do { *((volatile int*)__null) = 2248; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2249 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"
, 2249); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getUseFor(index)->consumer() == this"
")"); do { *((volatile int*)__null) = 2249; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2250
2251 // If we have phi(..., a, b, c, d, ..., z) and we plan
2252 // on removing a, then first shift downward so that we have
2253 // phi(..., b, c, d, ..., z, z):
2254 MUse* p = inputs_.begin() + index;
2255 MUse* e = inputs_.end();
2256 p->producer()->removeUse(p);
2257 for (; p < e - 1; ++p) {
2258 MDefinition* producer = (p + 1)->producer();
2259 p->setProducerUnchecked(producer);
2260 producer->replaceUse(p + 1, p);
2261 }
2262
2263 // truncate the inputs_ list:
2264 inputs_.popBack();
2265}
2266
2267void MPhi::removeAllOperands() {
2268 for (MUse& p : inputs_) {
2269 p.producer()->removeUse(&p);
2270 }
2271 inputs_.clear();
2272}
2273
2274MDefinition* MPhi::foldsTernary(TempAllocator& alloc) {
2275 /* Look if this MPhi is a ternary construct.
2276 * This is a very loose term as it actually only checks for
2277 *
2278 * MTest X
2279 * / \
2280 * ... ...
2281 * \ /
2282 * MPhi X Y
2283 *
2284 * Which we will simply call:
2285 * x ? x : y or x ? y : x
2286 */
2287
2288 if (numOperands() != 2) {
2289 return nullptr;
2290 }
2291
2292 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"
, 2292); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->numPredecessors() == 2"
")"); do { *((volatile int*)__null) = 2292; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2293
2294 MBasicBlock* pred = block()->immediateDominator();
2295 if (!pred || !pred->lastIns()->isTest()) {
2296 return nullptr;
2297 }
2298
2299 MTest* test = pred->lastIns()->toTest();
2300
2301 // True branch may only dominate one edge of MPhi.
2302 if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
2303 test->ifTrue()->dominates(block()->getPredecessor(1))) {
2304 return nullptr;
2305 }
2306
2307 // False branch may only dominate one edge of MPhi.
2308 if (test->ifFalse()->dominates(block()->getPredecessor(0)) ==
2309 test->ifFalse()->dominates(block()->getPredecessor(1))) {
2310 return nullptr;
2311 }
2312
2313 // True and false branch must dominate different edges of MPhi.
2314 if (test->ifTrue()->dominates(block()->getPredecessor(0)) ==
2315 test->ifFalse()->dominates(block()->getPredecessor(0))) {
2316 return nullptr;
2317 }
2318
2319 // We found a ternary construct.
2320 bool firstIsTrueBranch =
2321 test->ifTrue()->dominates(block()->getPredecessor(0));
2322 MDefinition* trueDef = firstIsTrueBranch ? getOperand(0) : getOperand(1);
2323 MDefinition* falseDef = firstIsTrueBranch ? getOperand(1) : getOperand(0);
2324
2325 // Accept either
2326 // testArg ? testArg : constant or
2327 // testArg ? constant : testArg
2328 if (!trueDef->isConstant() && !falseDef->isConstant()) {
2329 return nullptr;
2330 }
2331
2332 MConstant* c =
2333 trueDef->isConstant() ? trueDef->toConstant() : falseDef->toConstant();
2334 MDefinition* testArg = (trueDef == c) ? falseDef : trueDef;
2335 if (testArg != test->input()) {
2336 return nullptr;
2337 }
2338
2339 // This check should be a tautology, except that the constant might be the
2340 // result of the removal of a branch. In such case the domination scope of
2341 // the block which is holding the constant might be incomplete. This
2342 // condition is used to prevent doing this optimization based on incomplete
2343 // information.
2344 //
2345 // As GVN removed a branch, it will update the dominations rules before
2346 // trying to fold this MPhi again. Thus, this condition does not inhibit
2347 // this optimization.
2348 MBasicBlock* truePred = block()->getPredecessor(firstIsTrueBranch ? 0 : 1);
2349 MBasicBlock* falsePred = block()->getPredecessor(firstIsTrueBranch ? 1 : 0);
2350 if (!trueDef->block()->dominates(truePred) ||
2351 !falseDef->block()->dominates(falsePred)) {
2352 return nullptr;
2353 }
2354
2355 // If testArg is an int32 type we can:
2356 // - fold testArg ? testArg : 0 to testArg
2357 // - fold testArg ? 0 : testArg to 0
2358 if (testArg->type() == MIRType::Int32 && c->numberToDouble() == 0) {
2359 testArg->setGuardRangeBailoutsUnchecked();
2360
2361 // When folding to the constant we need to hoist it.
2362 if (trueDef == c && !c->block()->dominates(block())) {
2363 c->block()->moveBefore(pred->lastIns(), c);
2364 }
2365 return trueDef;
2366 }
2367
2368 // If testArg is an double type we can:
2369 // - fold testArg ? testArg : 0.0 to MNaNToZero(testArg)
2370 if (testArg->type() == MIRType::Double &&
2371 mozilla::IsPositiveZero(c->numberToDouble()) && c != trueDef) {
2372 MNaNToZero* replace = MNaNToZero::New(alloc, testArg);
2373 test->block()->insertBefore(test, replace);
2374 return replace;
2375 }
2376
2377 // If testArg is a string type we can:
2378 // - fold testArg ? testArg : "" to testArg
2379 // - fold testArg ? "" : testArg to ""
2380 if (testArg->type() == MIRType::String &&
2381 c->toString() == GetJitContext()->runtime->emptyString()) {
2382 // When folding to the constant we need to hoist it.
2383 if (trueDef == c && !c->block()->dominates(block())) {
2384 c->block()->moveBefore(pred->lastIns(), c);
2385 }
2386 return trueDef;
2387 }
2388
2389 return nullptr;
2390}
2391
2392MDefinition* MPhi::operandIfRedundant() {
2393 if (inputs_.length() == 0) {
2394 return nullptr;
2395 }
2396
2397 // If this phi is redundant (e.g., phi(a,a) or b=phi(a,this)),
2398 // returns the operand that it will always be equal to (a, in
2399 // those two cases).
2400 MDefinition* first = getOperand(0);
2401 for (size_t i = 1, e = numOperands(); i < e; i++) {
2402 MDefinition* op = getOperand(i);
2403 if (op != first && op != this) {
2404 return nullptr;
2405 }
2406 }
2407 return first;
2408}
2409
2410MDefinition* MPhi::foldsTo(TempAllocator& alloc) {
2411 if (MDefinition* def = operandIfRedundant()) {
2412 return def;
2413 }
2414
2415 if (MDefinition* def = foldsTernary(alloc)) {
2416 return def;
2417 }
2418
2419 return this;
2420}
2421
2422bool MPhi::congruentTo(const MDefinition* ins) const {
2423 if (!ins->isPhi()) {
2424 return false;
2425 }
2426
2427 // Phis in different blocks may have different control conditions.
2428 // For example, these phis:
2429 //
2430 // if (p)
2431 // goto a
2432 // a:
2433 // t = phi(x, y)
2434 //
2435 // if (q)
2436 // goto b
2437 // b:
2438 // s = phi(x, y)
2439 //
2440 // have identical operands, but they are not equvalent because t is
2441 // effectively p?x:y and s is effectively q?x:y.
2442 //
2443 // For now, consider phis in different blocks incongruent.
2444 if (ins->block() != block()) {
2445 return false;
2446 }
2447
2448 return congruentIfOperandsEqual(ins);
2449}
2450
2451void MPhi::updateForReplacement(MPhi* other) {
2452 // This function is called to fix the current Phi flags using it as a
2453 // replacement of the other Phi instruction |other|.
2454 //
2455 // When dealing with usage analysis, any Use will replace all other values,
2456 // such as Unused and Unknown. Unless both are Unused, the merge would be
2457 // Unknown.
2458 if (usageAnalysis_ == PhiUsage::Used ||
2459 other->usageAnalysis_ == PhiUsage::Used) {
2460 usageAnalysis_ = PhiUsage::Used;
2461 } else if (usageAnalysis_ != other->usageAnalysis_) {
2462 // this == unused && other == unknown
2463 // or this == unknown && other == unused
2464 usageAnalysis_ = PhiUsage::Unknown;
2465 } else {
2466 // this == unused && other == unused
2467 // or this == unknown && other = unknown
2468 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"
, 2469); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown"
")"); do { *((volatile int*)__null) = 2469; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2469 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"
, 2469); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == PhiUsage::Unused || usageAnalysis_ == PhiUsage::Unknown"
")"); do { *((volatile int*)__null) = 2469; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2470 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"
, 2470); AnnotateMozCrashReason("MOZ_ASSERT" "(" "usageAnalysis_ == other->usageAnalysis_"
")"); do { *((volatile int*)__null) = 2470; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2471 }
2472}
2473
2474/* static */
2475bool MPhi::markIteratorPhis(const PhiVector& iterators) {
2476 // Find and mark phis that must transitively hold an iterator live.
2477
2478 Vector<MPhi*, 8, SystemAllocPolicy> worklist;
2479
2480 for (MPhi* iter : iterators) {
2481 if (!iter->isInWorklist()) {
2482 if (!worklist.append(iter)) {
2483 return false;
2484 }
2485 iter->setInWorklist();
2486 }
2487 }
2488
2489 while (!worklist.empty()) {
2490 MPhi* phi = worklist.popCopy();
2491 phi->setNotInWorklist();
2492
2493 phi->setIterator();
2494 phi->setImplicitlyUsedUnchecked();
2495
2496 for (MUseDefIterator iter(phi); iter; iter++) {
2497 MDefinition* use = iter.def();
2498 if (!use->isInWorklist() && use->isPhi() && !use->toPhi()->isIterator()) {
2499 if (!worklist.append(use->toPhi())) {
2500 return false;
2501 }
2502 use->setInWorklist();
2503 }
2504 }
2505 }
2506
2507 return true;
2508}
2509
2510bool MPhi::typeIncludes(MDefinition* def) {
2511 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"
, 2511); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsMagicType(def->type())"
")"); do { *((volatile int*)__null) = 2511; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2512
2513 if (def->type() == MIRType::Int32 && this->type() == MIRType::Double) {
2514 return true;
2515 }
2516
2517 if (def->type() == MIRType::Value) {
2518 // This phi must be able to be any value.
2519 return this->type() == MIRType::Value;
2520 }
2521
2522 return this->mightBeType(def->type());
2523}
2524
2525void MCallBase::addArg(size_t argnum, MDefinition* arg) {
2526 // The operand vector is initialized in reverse order by WarpBuilder.
2527 // It cannot be checked for consistency until all arguments are added.
2528 // FixedList doesn't initialize its elements, so do an unchecked init.
2529 initOperand(argnum + NumNonArgumentOperands, arg);
2530}
2531
2532static inline bool IsConstant(MDefinition* def, double v) {
2533 if (!def->isConstant()) {
2534 return false;
2535 }
2536
2537 return NumbersAreIdentical(def->toConstant()->numberToDouble(), v);
2538}
2539
2540MDefinition* MBinaryBitwiseInstruction::foldsTo(TempAllocator& alloc) {
2541 // Identity operations are removed (for int32 only) in foldUnnecessaryBitop.
2542
2543 if (type() == MIRType::Int32) {
2544 if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
2545 return folded;
2546 }
2547 } else if (type() == MIRType::Int64) {
2548 if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
2549 return folded;
2550 }
2551 }
2552
2553 return this;
2554}
2555
2556MDefinition* MBinaryBitwiseInstruction::foldUnnecessaryBitop() {
2557 // It's probably OK to perform this optimization only for int32, as it will
2558 // have the greatest effect for asm.js code that is compiled with the JS
2559 // pipeline, and that code will not see int64 values.
2560
2561 if (type() != MIRType::Int32) {
2562 return this;
2563 }
2564
2565 // Fold unsigned shift right operator when the second operand is zero and
2566 // the only use is an unsigned modulo. Thus, the expression
2567 // |(x >>> 0) % y| becomes |x % y|.
2568 if (isUrsh() && IsUint32Type(this)) {
2569 MDefinition* defUse = maybeSingleDefUse();
2570 if (defUse && defUse->isMod() && defUse->toMod()->isUnsigned()) {
2571 return getOperand(0);
2572 }
2573 }
2574
2575 // Eliminate bitwise operations that are no-ops when used on integer
2576 // inputs, such as (x | 0).
2577
2578 MDefinition* lhs = getOperand(0);
2579 MDefinition* rhs = getOperand(1);
2580
2581 if (IsConstant(lhs, 0)) {
2582 return foldIfZero(0);
2583 }
2584
2585 if (IsConstant(rhs, 0)) {
2586 return foldIfZero(1);
2587 }
2588
2589 if (IsConstant(lhs, -1)) {
2590 return foldIfNegOne(0);
2591 }
2592
2593 if (IsConstant(rhs, -1)) {
2594 return foldIfNegOne(1);
2595 }
2596
2597 if (lhs == rhs) {
2598 return foldIfEqual();
2599 }
2600
2601 if (maskMatchesRightRange) {
2602 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"
, 2602); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->isConstant()"
")"); do { *((volatile int*)__null) = 2602; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2603 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"
, 2603); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2603; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2604 return foldIfAllBitsSet(0);
2605 }
2606
2607 if (maskMatchesLeftRange) {
2608 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"
, 2608); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->isConstant()"
")"); do { *((volatile int*)__null) = 2608; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2609 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"
, 2609); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 2609; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2610 return foldIfAllBitsSet(1);
2611 }
2612
2613 return this;
2614}
2615
2616static inline bool CanProduceNegativeZero(MDefinition* def) {
2617 // Test if this instruction can produce negative zero even when bailing out
2618 // and changing types.
2619 switch (def->op()) {
2620 case MDefinition::Opcode::Constant:
2621 if (def->type() == MIRType::Double &&
2622 def->toConstant()->toDouble() == -0.0) {
2623 return true;
2624 }
2625 [[fallthrough]];
2626 case MDefinition::Opcode::BitAnd:
2627 case MDefinition::Opcode::BitOr:
2628 case MDefinition::Opcode::BitXor:
2629 case MDefinition::Opcode::BitNot:
2630 case MDefinition::Opcode::Lsh:
2631 case MDefinition::Opcode::Rsh:
2632 return false;
2633 default:
2634 return true;
2635 }
2636}
2637
2638static inline bool NeedNegativeZeroCheck(MDefinition* def) {
2639 if (def->isGuard() || def->isGuardRangeBailouts()) {
2640 return true;
2641 }
2642
2643 // Test if all uses have the same semantics for -0 and 0
2644 for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
2645 if (use->consumer()->isResumePoint()) {
2646 return true;
2647 }
2648
2649 MDefinition* use_def = use->consumer()->toDefinition();
2650 switch (use_def->op()) {
2651 case MDefinition::Opcode::Add: {
2652 // If add is truncating -0 and 0 are observed as the same.
2653 if (use_def->toAdd()->isTruncated()) {
2654 break;
2655 }
2656
2657 // x + y gives -0, when both x and y are -0
2658
2659 // Figure out the order in which the addition's operands will
2660 // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR
2661 // definitions for us so that this just requires comparing ids.
2662 MDefinition* first = use_def->toAdd()->lhs();
2663 MDefinition* second = use_def->toAdd()->rhs();
2664 if (first->id() > second->id()) {
2665 std::swap(first, second);
2666 }
2667 // Negative zero checks can be removed on the first executed
2668 // operand only if it is guaranteed the second executed operand
2669 // will produce a value other than -0. While the second is
2670 // typed as an int32, a bailout taken between execution of the
2671 // operands may change that type and cause a -0 to flow to the
2672 // second.
2673 //
2674 // There is no way to test whether there are any bailouts
2675 // between execution of the operands, so remove negative
2676 // zero checks from the first only if the second's type is
2677 // independent from type changes that may occur after bailing.
2678 if (def == first && CanProduceNegativeZero(second)) {
2679 return true;
2680 }
2681
2682 // The negative zero check can always be removed on the second
2683 // executed operand; by the time this executes the first will have
2684 // been evaluated as int32 and the addition's result cannot be -0.
2685 break;
2686 }
2687 case MDefinition::Opcode::Sub: {
2688 // If sub is truncating -0 and 0 are observed as the same
2689 if (use_def->toSub()->isTruncated()) {
2690 break;
2691 }
2692
2693 // x + y gives -0, when x is -0 and y is 0
2694
2695 // We can remove the negative zero check on the rhs, only if we
2696 // are sure the lhs isn't negative zero.
2697
2698 // The lhs is typed as integer (i.e. not -0.0), but it can bailout
2699 // and change type. This should be fine if the lhs is executed
2700 // first. However if the rhs is executed first, the lhs can bail,
2701 // change type and become -0.0 while the rhs has already been
2702 // optimized to not make a difference between zero and negative zero.
2703 MDefinition* lhs = use_def->toSub()->lhs();
2704 MDefinition* rhs = use_def->toSub()->rhs();
2705 if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs)) {
2706 return true;
2707 }
2708
2709 [[fallthrough]];
2710 }
2711 case MDefinition::Opcode::StoreElement:
2712 case MDefinition::Opcode::StoreHoleValueElement:
2713 case MDefinition::Opcode::LoadElement:
2714 case MDefinition::Opcode::LoadElementHole:
2715 case MDefinition::Opcode::LoadUnboxedScalar:
2716 case MDefinition::Opcode::LoadDataViewElement:
2717 case MDefinition::Opcode::LoadTypedArrayElementHole:
2718 case MDefinition::Opcode::CharCodeAt:
2719 case MDefinition::Opcode::Mod:
2720 case MDefinition::Opcode::InArray:
2721 // Only allowed to remove check when definition is the second operand
2722 if (use_def->getOperand(0) == def) {
2723 return true;
2724 }
2725 for (size_t i = 2, e = use_def->numOperands(); i < e; i++) {
2726 if (use_def->getOperand(i) == def) {
2727 return true;
2728 }
2729 }
2730 break;
2731 case MDefinition::Opcode::BoundsCheck:
2732 // Only allowed to remove check when definition is the first operand
2733 if (use_def->toBoundsCheck()->getOperand(1) == def) {
2734 return true;
2735 }
2736 break;
2737 case MDefinition::Opcode::ToString:
2738 case MDefinition::Opcode::FromCharCode:
2739 case MDefinition::Opcode::FromCodePoint:
2740 case MDefinition::Opcode::TableSwitch:
2741 case MDefinition::Opcode::Compare:
2742 case MDefinition::Opcode::BitAnd:
2743 case MDefinition::Opcode::BitOr:
2744 case MDefinition::Opcode::BitXor:
2745 case MDefinition::Opcode::Abs:
2746 case MDefinition::Opcode::TruncateToInt32:
2747 // Always allowed to remove check. No matter which operand.
2748 break;
2749 case MDefinition::Opcode::StoreElementHole:
2750 case MDefinition::Opcode::StoreTypedArrayElementHole:
2751 case MDefinition::Opcode::PostWriteElementBarrier:
2752 // Only allowed to remove check when definition is the third operand.
2753 for (size_t i = 0, e = use_def->numOperands(); i < e; i++) {
2754 if (i == 2) {
2755 continue;
2756 }
2757 if (use_def->getOperand(i) == def) {
2758 return true;
2759 }
2760 }
2761 break;
2762 default:
2763 return true;
2764 }
2765 }
2766 return false;
2767}
2768
2769#ifdef JS_JITSPEW1
2770void MBinaryArithInstruction::printOpcode(GenericPrinter& out) const {
2771 MDefinition::printOpcode(out);
2772
2773 switch (type()) {
2774 case MIRType::Int32:
2775 if (isDiv()) {
2776 out.printf(" [%s]", toDiv()->isUnsigned() ? "uint32" : "int32");
2777 } else if (isMod()) {
2778 out.printf(" [%s]", toMod()->isUnsigned() ? "uint32" : "int32");
2779 } else {
2780 out.printf(" [int32]");
2781 }
2782 break;
2783 case MIRType::Int64:
2784 if (isDiv()) {
2785 out.printf(" [%s]", toDiv()->isUnsigned() ? "uint64" : "int64");
2786 } else if (isMod()) {
2787 out.printf(" [%s]", toMod()->isUnsigned() ? "uint64" : "int64");
2788 } else {
2789 out.printf(" [int64]");
2790 }
2791 break;
2792 case MIRType::Float32:
2793 out.printf(" [float]");
2794 break;
2795 case MIRType::Double:
2796 out.printf(" [double]");
2797 break;
2798 default:
2799 break;
2800 }
2801}
2802#endif
2803
2804MDefinition* MRsh::foldsTo(TempAllocator& alloc) {
2805 MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc);
2806
2807 if (f != this) {
2808 return f;
2809 }
2810
2811 MDefinition* lhs = getOperand(0);
2812 MDefinition* rhs = getOperand(1);
2813
2814 // It's probably OK to perform this optimization only for int32, as it will
2815 // have the greatest effect for asm.js code that is compiled with the JS
2816 // pipeline, and that code will not see int64 values.
2817
2818 if (!lhs->isLsh() || !rhs->isConstant() || rhs->type() != MIRType::Int32) {
2819 return this;
2820 }
2821
2822 if (!lhs->getOperand(1)->isConstant() ||
2823 lhs->getOperand(1)->type() != MIRType::Int32) {
2824 return this;
2825 }
2826
2827 uint32_t shift = rhs->toConstant()->toInt32();
2828 uint32_t shift_lhs = lhs->getOperand(1)->toConstant()->toInt32();
2829 if (shift != shift_lhs) {
2830 return this;
2831 }
2832
2833 switch (shift) {
2834 case 16:
2835 return MSignExtendInt32::New(alloc, lhs->getOperand(0),
2836 MSignExtendInt32::Half);
2837 case 24:
2838 return MSignExtendInt32::New(alloc, lhs->getOperand(0),
2839 MSignExtendInt32::Byte);
2840 }
2841
2842 return this;
2843}
2844
2845MDefinition* MBinaryArithInstruction::foldsTo(TempAllocator& alloc) {
2846 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"
, 2846); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 2846; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2847
2848 MDefinition* lhs = getOperand(0);
2849 MDefinition* rhs = getOperand(1);
2850
2851 if (type() == MIRType::Int64) {
2852 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"
, 2852); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!isTruncated()"
")"); do { *((volatile int*)__null) = 2852; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2853
2854 if (MConstant* folded = EvaluateInt64ConstantOperands(alloc, this)) {
2855 if (!folded->block()) {
2856 block()->insertBefore(this, folded);
2857 }
2858 return folded;
2859 }
2860 if (isSub() || isDiv() || isMod()) {
2861 return this;
2862 }
2863 if (rhs->isConstant() &&
2864 rhs->toConstant()->toInt64() == int64_t(getIdentity())) {
2865 return lhs;
2866 }
2867 if (lhs->isConstant() &&
2868 lhs->toConstant()->toInt64() == int64_t(getIdentity())) {
2869 return rhs;
2870 }
2871 return this;
2872 }
2873
2874 if (MConstant* folded = EvaluateConstantOperands(alloc, this)) {
2875 if (isTruncated()) {
2876 if (!folded->block()) {
2877 block()->insertBefore(this, folded);
2878 }
2879 if (folded->type() != MIRType::Int32) {
2880 return MTruncateToInt32::New(alloc, folded);
2881 }
2882 }
2883 return folded;
2884 }
2885
2886 if (mustPreserveNaN_) {
2887 return this;
2888 }
2889
2890 // 0 + -0 = 0. So we can't remove addition
2891 if (isAdd() && type() != MIRType::Int32) {
2892 return this;
2893 }
2894
2895 if (IsConstant(rhs, getIdentity())) {
2896 if (isTruncated()) {
2897 return MTruncateToInt32::New(alloc, lhs);
2898 }
2899 return lhs;
2900 }
2901
2902 // subtraction isn't commutative. So we can't remove subtraction when lhs
2903 // equals 0
2904 if (isSub()) {
2905 return this;
2906 }
2907
2908 if (IsConstant(lhs, getIdentity())) {
2909 if (isTruncated()) {
2910 return MTruncateToInt32::New(alloc, rhs);
2911 }
2912 return rhs; // id op x => x
2913 }
2914
2915 return this;
2916}
2917
2918void MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc) {
2919 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"
, 2919); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 2919; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2920
2921 // Do not use Float32 if we can use int32.
2922 if (type() == MIRType::Int32) {
2923 return;
2924 }
2925
2926 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
2927 setResultType(MIRType::Float32);
2928 }
2929}
2930
2931void MMinMax::trySpecializeFloat32(TempAllocator& alloc) {
2932 if (type() == MIRType::Int32) {
2933 return;
2934 }
2935
2936 MDefinition* left = lhs();
2937 MDefinition* right = rhs();
2938
2939 if ((left->canProduceFloat32() ||
2940 (left->isMinMax() && left->type() == MIRType::Float32)) &&
2941 (right->canProduceFloat32() ||
2942 (right->isMinMax() && right->type() == MIRType::Float32))) {
2943 setResultType(MIRType::Float32);
2944 } else {
2945 ConvertOperandsToDouble(this, alloc);
2946 }
2947}
2948
2949MDefinition* MMinMax::foldsTo(TempAllocator& alloc) {
2950 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"
, 2950); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == type()"
")"); do { *((volatile int*)__null) = 2950; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2951 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"
, 2951); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == type()"
")"); do { *((volatile int*)__null) = 2951; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2952
2953 if (lhs() == rhs()) {
2954 return lhs();
2955 }
2956
2957 auto foldConstants = [&alloc](MDefinition* lhs, MDefinition* rhs,
2958 bool isMax) -> MConstant* {
2959 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"
, 2959); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == rhs->type()"
")"); do { *((volatile int*)__null) = 2959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2960 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"
, 2960); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->toConstant()->isTypeRepresentableAsDouble()"
")"); do { *((volatile int*)__null) = 2960; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2961 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"
, 2961); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->toConstant()->isTypeRepresentableAsDouble()"
")"); do { *((volatile int*)__null) = 2961; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2962
2963 double lnum = lhs->toConstant()->numberToDouble();
2964 double rnum = rhs->toConstant()->numberToDouble();
2965
2966 double result;
2967 if (isMax) {
2968 result = js::math_max_impl(lnum, rnum);
2969 } else {
2970 result = js::math_min_impl(lnum, rnum);
2971 }
2972
2973 // The folded MConstant should maintain the same MIRType with the original
2974 // inputs.
2975 if (lhs->type() == MIRType::Int32) {
2976 int32_t cast;
2977 if (mozilla::NumberEqualsInt32(result, &cast)) {
2978 return MConstant::New(alloc, Int32Value(cast));
2979 }
2980 return nullptr;
2981 }
2982 if (lhs->type() == MIRType::Float32) {
2983 return MConstant::NewFloat32(alloc, result);
2984 }
2985 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"
, 2985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 2985; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2986 return MConstant::New(alloc, DoubleValue(result));
2987 };
2988
2989 // Try to fold the following patterns when |x| and |y| are constants.
2990 //
2991 // min(min(x, z), min(y, z)) = min(min(x, y), z)
2992 // max(max(x, z), max(y, z)) = max(max(x, y), z)
2993 // max(min(x, z), min(y, z)) = min(max(x, y), z)
2994 // min(max(x, z), max(y, z)) = max(min(x, y), z)
2995 if (lhs()->isMinMax() && rhs()->isMinMax()) {
2996 do {
2997 auto* left = lhs()->toMinMax();
2998 auto* right = rhs()->toMinMax();
2999 if (left->isMax() != right->isMax()) {
3000 break;
3001 }
3002
3003 MDefinition* x;
3004 MDefinition* y;
3005 MDefinition* z;
3006 if (left->lhs() == right->lhs()) {
3007 std::tie(x, y, z) = std::tuple{left->rhs(), right->rhs(), left->lhs()};
3008 } else if (left->lhs() == right->rhs()) {
3009 std::tie(x, y, z) = std::tuple{left->rhs(), right->lhs(), left->lhs()};
3010 } else if (left->rhs() == right->lhs()) {
3011 std::tie(x, y, z) = std::tuple{left->lhs(), right->rhs(), left->rhs()};
3012 } else if (left->rhs() == right->rhs()) {
3013 std::tie(x, y, z) = std::tuple{left->lhs(), right->lhs(), left->rhs()};
3014 } else {
3015 break;
3016 }
3017
3018 if (!x->isConstant() || !x->toConstant()->isTypeRepresentableAsDouble() ||
3019 !y->isConstant() || !y->toConstant()->isTypeRepresentableAsDouble()) {
3020 break;
3021 }
3022
3023 if (auto* folded = foldConstants(x, y, isMax())) {
3024 block()->insertBefore(this, folded);
3025 return MMinMax::New(alloc, folded, z, type(), left->isMax());
3026 }
3027 } while (false);
3028 }
3029
3030 // Fold min/max operations with same inputs.
3031 if (lhs()->isMinMax() || rhs()->isMinMax()) {
3032 auto* other = lhs()->isMinMax() ? lhs()->toMinMax() : rhs()->toMinMax();
3033 auto* operand = lhs()->isMinMax() ? rhs() : lhs();
3034
3035 if (operand == other->lhs() || operand == other->rhs()) {
3036 if (isMax() == other->isMax()) {
3037 // min(x, min(x, y)) = min(x, y)
3038 // max(x, max(x, y)) = max(x, y)
3039 return other;
3040 }
3041 if (!IsFloatingPointType(type())) {
3042 // When neither value is NaN:
3043 // max(x, min(x, y)) = x
3044 // min(x, max(x, y)) = x
3045
3046 // Ensure that any bailouts that we depend on to guarantee that |y| is
3047 // Int32 are not removed.
3048 auto* otherOp = operand == other->lhs() ? other->rhs() : other->lhs();
3049 otherOp->setGuardRangeBailoutsUnchecked();
3050
3051 return operand;
3052 }
3053 }
3054 }
3055
3056 if (!lhs()->isConstant() && !rhs()->isConstant()) {
3057 return this;
3058 }
3059
3060 // Directly apply math utility to compare the rhs() and lhs() when
3061 // they are both constants.
3062 if (lhs()->isConstant() && rhs()->isConstant()) {
3063 if (!lhs()->toConstant()->isTypeRepresentableAsDouble() ||
3064 !rhs()->toConstant()->isTypeRepresentableAsDouble()) {
3065 return this;
3066 }
3067
3068 if (auto* folded = foldConstants(lhs(), rhs(), isMax())) {
3069 return folded;
3070 }
3071 }
3072
3073 MDefinition* operand = lhs()->isConstant() ? rhs() : lhs();
3074 MConstant* constant =
3075 lhs()->isConstant() ? lhs()->toConstant() : rhs()->toConstant();
3076
3077 if (operand->isToDouble() &&
3078 operand->getOperand(0)->type() == MIRType::Int32) {
3079 // min(int32, cte >= INT32_MAX) = int32
3080 if (!isMax() && constant->isTypeRepresentableAsDouble() &&
3081 constant->numberToDouble() >= INT32_MAX(2147483647)) {
3082 MLimitedTruncate* limit = MLimitedTruncate::New(
3083 alloc, operand->getOperand(0), TruncateKind::NoTruncate);
3084 block()->insertBefore(this, limit);
3085 MToDouble* toDouble = MToDouble::New(alloc, limit);
3086 return toDouble;
3087 }
3088
3089 // max(int32, cte <= INT32_MIN) = int32
3090 if (isMax() && constant->isTypeRepresentableAsDouble() &&
3091 constant->numberToDouble() <= INT32_MIN(-2147483647-1)) {
3092 MLimitedTruncate* limit = MLimitedTruncate::New(
3093 alloc, operand->getOperand(0), TruncateKind::NoTruncate);
3094 block()->insertBefore(this, limit);
3095 MToDouble* toDouble = MToDouble::New(alloc, limit);
3096 return toDouble;
3097 }
3098 }
3099
3100 auto foldLength = [](MDefinition* operand, MConstant* constant,
3101 bool isMax) -> MDefinition* {
3102 if ((operand->isArrayLength() || operand->isArrayBufferViewLength() ||
3103 operand->isArgumentsLength() || operand->isStringLength()) &&
3104 constant->type() == MIRType::Int32) {
3105 // (Array|ArrayBufferView|Arguments|String)Length is always >= 0.
3106 // max(array.length, cte <= 0) = array.length
3107 // min(array.length, cte <= 0) = cte
3108 if (constant->toInt32() <= 0) {
3109 return isMax ? operand : constant;
3110 }
3111 }
3112 return nullptr;
3113 };
3114
3115 if (auto* folded = foldLength(operand, constant, isMax())) {
3116 return folded;
3117 }
3118
3119 // Attempt to fold nested min/max operations which are produced by
3120 // self-hosted built-in functions.
3121 if (operand->isMinMax()) {
3122 auto* other = operand->toMinMax();
3123 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"
, 3123); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->lhs()->type() == type()"
")"); do { *((volatile int*)__null) = 3123; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3124 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"
, 3124); AnnotateMozCrashReason("MOZ_ASSERT" "(" "other->rhs()->type() == type()"
")"); do { *((volatile int*)__null) = 3124; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3125
3126 MConstant* otherConstant = nullptr;
3127 MDefinition* otherOperand = nullptr;
3128 if (other->lhs()->isConstant()) {
3129 otherConstant = other->lhs()->toConstant();
3130 otherOperand = other->rhs();
3131 } else if (other->rhs()->isConstant()) {
3132 otherConstant = other->rhs()->toConstant();
3133 otherOperand = other->lhs();
3134 }
3135
3136 if (otherConstant && constant->isTypeRepresentableAsDouble() &&
3137 otherConstant->isTypeRepresentableAsDouble()) {
3138 if (isMax() == other->isMax()) {
3139 // Fold min(x, min(y, z)) to min(min(x, y), z) with constant min(x, y).
3140 // Fold max(x, max(y, z)) to max(max(x, y), z) with constant max(x, y).
3141 if (auto* left = foldConstants(constant, otherConstant, isMax())) {
3142 block()->insertBefore(this, left);
3143 return MMinMax::New(alloc, left, otherOperand, type(), isMax());
3144 }
3145 } else {
3146 // Fold min(x, max(y, z)) to max(min(x, y), min(x, z)).
3147 // Fold max(x, min(y, z)) to min(max(x, y), max(x, z)).
3148 //
3149 // But only do this when min(x, z) can also be simplified.
3150 if (auto* right = foldLength(otherOperand, constant, isMax())) {
3151 if (auto* left = foldConstants(constant, otherConstant, isMax())) {
3152 block()->insertBefore(this, left);
3153 return MMinMax::New(alloc, left, right, type(), !isMax());
3154 }
3155 }
3156 }
3157 }
3158 }
3159
3160 return this;
3161}
3162
3163#ifdef JS_JITSPEW1
3164void MMinMax::printOpcode(GenericPrinter& out) const {
3165 MDefinition::printOpcode(out);
3166 out.printf(" (%s)", isMax() ? "max" : "min");
3167}
3168
3169void MMinMaxArray::printOpcode(GenericPrinter& out) const {
3170 MDefinition::printOpcode(out);
3171 out.printf(" (%s)", isMax() ? "max" : "min");
3172}
3173#endif
3174
3175MDefinition* MPow::foldsConstant(TempAllocator& alloc) {
3176 // Both `x` and `p` in `x^p` must be constants in order to precompute.
3177 if (!input()->isConstant() || !power()->isConstant()) {
3178 return nullptr;
3179 }
3180 if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
3181 return nullptr;
3182 }
3183 if (!input()->toConstant()->isTypeRepresentableAsDouble()) {
3184 return nullptr;
3185 }
3186
3187 double x = input()->toConstant()->numberToDouble();
3188 double p = power()->toConstant()->numberToDouble();
3189 double result = js::ecmaPow(x, p);
3190 if (type() == MIRType::Int32) {
3191 int32_t cast;
3192 if (!mozilla::NumberIsInt32(result, &cast)) {
3193 // Reject folding if the result isn't an int32, because we'll bail anyway.
3194 return nullptr;
3195 }
3196 return MConstant::New(alloc, Int32Value(cast));
3197 }
3198 return MConstant::New(alloc, DoubleValue(result));
3199}
3200
3201MDefinition* MPow::foldsConstantPower(TempAllocator& alloc) {
3202 // If `p` in `x^p` isn't constant, we can't apply these folds.
3203 if (!power()->isConstant()) {
3204 return nullptr;
3205 }
3206 if (!power()->toConstant()->isTypeRepresentableAsDouble()) {
3207 return nullptr;
3208 }
3209
3210 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"
, 3210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double || type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3210; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3211
3212 // NOTE: The optimizations must match the optimizations used in |js::ecmaPow|
3213 // resp. |js::powi| to avoid differential testing issues.
3214
3215 double pow = power()->toConstant()->numberToDouble();
3216
3217 // Math.pow(x, 0.5) is a sqrt with edge-case detection.
3218 if (pow == 0.5) {
3219 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"
, 3219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 3219; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3220 return MPowHalf::New(alloc, input());
3221 }
3222
3223 // Math.pow(x, -0.5) == 1 / Math.pow(x, 0.5), even for edge cases.
3224 if (pow == -0.5) {
3225 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"
, 3225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 3225; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3226 MPowHalf* half = MPowHalf::New(alloc, input());
3227 block()->insertBefore(this, half);
3228 MConstant* one = MConstant::New(alloc, DoubleValue(1.0));
3229 block()->insertBefore(this, one);
3230 return MDiv::New(alloc, one, half, MIRType::Double);
3231 }
3232
3233 // Math.pow(x, 1) == x.
3234 if (pow == 1.0) {
3235 return input();
3236 }
3237
3238 auto multiply = [this, &alloc](MDefinition* lhs, MDefinition* rhs) {
3239 MMul* mul = MMul::New(alloc, lhs, rhs, type());
3240 mul->setBailoutKind(bailoutKind());
3241
3242 // Multiplying the same number can't yield negative zero.
3243 mul->setCanBeNegativeZero(lhs != rhs && canBeNegativeZero());
3244 return mul;
3245 };
3246
3247 // Math.pow(x, 2) == x*x.
3248 if (pow == 2.0) {
3249 return multiply(input(), input());
3250 }
3251
3252 // Math.pow(x, 3) == x*x*x.
3253 if (pow == 3.0) {
3254 MMul* mul1 = multiply(input(), input());
3255 block()->insertBefore(this, mul1);
3256 return multiply(input(), mul1);
3257 }
3258
3259 // Math.pow(x, 4) == y*y, where y = x*x.
3260 if (pow == 4.0) {
3261 MMul* y = multiply(input(), input());
3262 block()->insertBefore(this, y);
3263 return multiply(y, y);
3264 }
3265
3266 // No optimization
3267 return nullptr;
3268}
3269
3270MDefinition* MPow::foldsTo(TempAllocator& alloc) {
3271 if (MDefinition* def = foldsConstant(alloc)) {
3272 return def;
3273 }
3274 if (MDefinition* def = foldsConstantPower(alloc)) {
3275 return def;
3276 }
3277 return this;
3278}
3279
3280MDefinition* MInt32ToIntPtr::foldsTo(TempAllocator& alloc) {
3281 MDefinition* def = input();
3282 if (def->isConstant()) {
3283 int32_t i = def->toConstant()->toInt32();
3284 return MConstant::NewIntPtr(alloc, intptr_t(i));
3285 }
3286
3287 if (def->isNonNegativeIntPtrToInt32()) {
3288 return def->toNonNegativeIntPtrToInt32()->input();
3289 }
3290
3291 return this;
3292}
3293
3294bool MAbs::fallible() const {
3295 return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds());
3296}
3297
3298void MAbs::trySpecializeFloat32(TempAllocator& alloc) {
3299 // Do not use Float32 if we can use int32.
3300 if (input()->type() == MIRType::Int32) {
3301 return;
3302 }
3303
3304 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
3305 setResultType(MIRType::Float32);
3306 }
3307}
3308
3309MDefinition* MDiv::foldsTo(TempAllocator& alloc) {
3310 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"
, 3310); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 3310; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3311
3312 if (type() == MIRType::Int64) {
3313 if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
3314 return folded;
3315 }
3316 return this;
3317 }
3318
3319 if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
3320 return folded;
3321 }
3322
3323 if (MDefinition* folded = EvaluateExactReciprocal(alloc, this)) {
3324 return folded;
3325 }
3326
3327 return this;
3328}
3329
3330void MDiv::analyzeEdgeCasesForward() {
3331 // This is only meaningful when doing integer division.
3332 if (type() != MIRType::Int32) {
3333 return;
3334 }
3335
3336 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"
, 3336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3336; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3337 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"
, 3337); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3337; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3338
3339 // Try removing divide by zero check
3340 if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
3341 canBeDivideByZero_ = false;
3342 }
3343
3344 // If lhs is a constant int != INT32_MIN, then
3345 // negative overflow check can be skipped.
3346 if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(INT32_MIN(-2147483647-1))) {
3347 canBeNegativeOverflow_ = false;
3348 }
3349
3350 // If rhs is a constant int != -1, likewise.
3351 if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(-1)) {
3352 canBeNegativeOverflow_ = false;
3353 }
3354
3355 // If lhs is != 0, then negative zero check can be skipped.
3356 if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(0)) {
3357 setCanBeNegativeZero(false);
3358 }
3359
3360 // If rhs is >= 0, likewise.
3361 if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
3362 if (rhs()->toConstant()->toInt32() >= 0) {
3363 setCanBeNegativeZero(false);
3364 }
3365 }
3366}
3367
3368void MDiv::analyzeEdgeCasesBackward() {
3369 if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) {
3370 setCanBeNegativeZero(false);
3371 }
3372}
3373
3374bool MDiv::fallible() const { return !isTruncated(); }
3375
3376MDefinition* MMod::foldsTo(TempAllocator& alloc) {
3377 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"
, 3377); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsNumberType(type())"
")"); do { *((volatile int*)__null) = 3377; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3378
3379 if (type() == MIRType::Int64) {
3380 if (MDefinition* folded = EvaluateInt64ConstantOperands(alloc, this)) {
3381 return folded;
3382 }
3383 } else {
3384 if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) {
3385 return folded;
3386 }
3387 }
3388 return this;
3389}
3390
3391void MMod::analyzeEdgeCasesForward() {
3392 // These optimizations make sense only for integer division
3393 if (type() != MIRType::Int32) {
3394 return;
3395 }
3396
3397 if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
3398 canBeDivideByZero_ = false;
3399 }
3400
3401 if (rhs()->isConstant()) {
3402 int32_t n = rhs()->toConstant()->toInt32();
3403 if (n > 0 && !IsPowerOfTwo(uint32_t(n))) {
3404 canBePowerOfTwoDivisor_ = false;
3405 }
3406 }
3407}
3408
3409bool MMod::fallible() const {
3410 return !isTruncated() &&
3411 (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend());
3412}
3413
3414void MMathFunction::trySpecializeFloat32(TempAllocator& alloc) {
3415 if (EnsureFloatConsumersAndInputOrConvert(this, alloc)) {
3416 setResultType(MIRType::Float32);
3417 specialization_ = MIRType::Float32;
3418 }
3419}
3420
3421bool MMathFunction::isFloat32Commutative() const {
3422 switch (function_) {
3423 case UnaryMathFunction::Floor:
3424 case UnaryMathFunction::Ceil:
3425 case UnaryMathFunction::Round:
3426 case UnaryMathFunction::Trunc:
3427 return true;
3428 default:
3429 return false;
3430 }
3431}
3432
3433MHypot* MHypot::New(TempAllocator& alloc, const MDefinitionVector& vector) {
3434 uint32_t length = vector.length();
3435 MHypot* hypot = new (alloc) MHypot;
3436 if (!hypot->init(alloc, length)) {
3437 return nullptr;
3438 }
3439
3440 for (uint32_t i = 0; i < length; ++i) {
3441 hypot->initOperand(i, vector[i]);
3442 }
3443 return hypot;
3444}
3445
3446bool MAdd::fallible() const {
3447 // the add is fallible if range analysis does not say that it is finite, AND
3448 // either the truncation analysis shows that there are non-truncated uses.
3449 if (truncateKind() >= TruncateKind::IndirectTruncate) {
3450 return false;
3451 }
3452 if (range() && range()->hasInt32Bounds()) {
3453 return false;
3454 }
3455 return true;
3456}
3457
3458bool MSub::fallible() const {
3459 // see comment in MAdd::fallible()
3460 if (truncateKind() >= TruncateKind::IndirectTruncate) {
3461 return false;
3462 }
3463 if (range() && range()->hasInt32Bounds()) {
3464 return false;
3465 }
3466 return true;
3467}
3468
3469MDefinition* MSub::foldsTo(TempAllocator& alloc) {
3470 MDefinition* out = MBinaryArithInstruction::foldsTo(alloc);
3471 if (out != this) {
3472 return out;
3473 }
3474
3475 if (type() != MIRType::Int32) {
3476 return this;
3477 }
3478
3479 // Optimize X - X to 0. This optimization is only valid for Int32
3480 // values. Subtracting a floating point value from itself returns
3481 // NaN when the operand is either Infinity or NaN.
3482 if (lhs() == rhs()) {
3483 // Ensure that any bailouts that we depend on to guarantee that X
3484 // is Int32 are not removed.
3485 lhs()->setGuardRangeBailoutsUnchecked();
3486 return MConstant::New(alloc, Int32Value(0));
3487 }
3488
3489 return this;
3490}
3491
3492MDefinition* MMul::foldsTo(TempAllocator& alloc) {
3493 MDefinition* out = MBinaryArithInstruction::foldsTo(alloc);
3494 if (out != this) {
3495 return out;
3496 }
3497
3498 if (type() != MIRType::Int32) {
3499 return this;
3500 }
3501
3502 if (lhs() == rhs()) {
3503 setCanBeNegativeZero(false);
3504 }
3505
3506 return this;
3507}
3508
3509void MMul::analyzeEdgeCasesForward() {
3510 // Try to remove the check for negative zero
3511 // This only makes sense when using the integer multiplication
3512 if (type() != MIRType::Int32) {
3513 return;
3514 }
3515
3516 // If lhs is > 0, no need for negative zero check.
3517 if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) {
3518 if (lhs()->toConstant()->toInt32() > 0) {
3519 setCanBeNegativeZero(false);
3520 }
3521 }
3522
3523 // If rhs is > 0, likewise.
3524 if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
3525 if (rhs()->toConstant()->toInt32() > 0) {
3526 setCanBeNegativeZero(false);
3527 }
3528 }
3529}
3530
3531void MMul::analyzeEdgeCasesBackward() {
3532 if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) {
3533 setCanBeNegativeZero(false);
3534 }
3535}
3536
3537bool MMul::canOverflow() const {
3538 if (isTruncated()) {
3539 return false;
3540 }
3541 return !range() || !range()->hasInt32Bounds();
3542}
3543
3544bool MUrsh::fallible() const {
3545 if (bailoutsDisabled()) {
3546 return false;
3547 }
3548 return !range() || !range()->hasInt32Bounds();
3549}
3550
3551MIRType MCompare::inputType() {
3552 switch (compareType_) {
3553 case Compare_Undefined:
3554 return MIRType::Undefined;
3555 case Compare_Null:
3556 return MIRType::Null;
3557 case Compare_UInt32:
3558 case Compare_Int32:
3559 return MIRType::Int32;
3560 case Compare_UIntPtr:
3561 return MIRType::IntPtr;
3562 case Compare_Double:
3563 return MIRType::Double;
3564 case Compare_Float32:
3565 return MIRType::Float32;
3566 case Compare_String:
3567 return MIRType::String;
3568 case Compare_Symbol:
3569 return MIRType::Symbol;
3570 case Compare_Object:
3571 return MIRType::Object;
3572 case Compare_BigInt:
3573 case Compare_BigInt_Int32:
3574 case Compare_BigInt_Double:
3575 case Compare_BigInt_String:
3576 return MIRType::BigInt;
3577 default:
3578 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"
, 3578); AnnotateMozCrashReason("MOZ_CRASH(" "No known conversion"
")"); do { *((volatile int*)__null) = 3578; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3579 }
3580}
3581
3582static inline bool MustBeUInt32(MDefinition* def, MDefinition** pwrapped) {
3583 if (def->isUrsh()) {
3584 *pwrapped = def->toUrsh()->lhs();
3585 MDefinition* rhs = def->toUrsh()->rhs();
3586 return def->toUrsh()->bailoutsDisabled() && rhs->maybeConstantValue() &&
3587 rhs->maybeConstantValue()->isInt32(0);
3588 }
3589
3590 if (MConstant* defConst = def->maybeConstantValue()) {
3591 *pwrapped = defConst;
3592 return defConst->type() == MIRType::Int32 && defConst->toInt32() >= 0;
3593 }
3594
3595 *pwrapped = nullptr; // silence GCC warning
3596 return false;
3597}
3598
3599/* static */
3600bool MBinaryInstruction::unsignedOperands(MDefinition* left,
3601 MDefinition* right) {
3602 MDefinition* replace;
3603 if (!MustBeUInt32(left, &replace)) {
3604 return false;
3605 }
3606 if (replace->type() != MIRType::Int32) {
3607 return false;
3608 }
3609 if (!MustBeUInt32(right, &replace)) {
3610 return false;
3611 }
3612 if (replace->type() != MIRType::Int32) {
3613 return false;
3614 }
3615 return true;
3616}
3617
3618bool MBinaryInstruction::unsignedOperands() {
3619 return unsignedOperands(getOperand(0), getOperand(1));
3620}
3621
3622void MBinaryInstruction::replaceWithUnsignedOperands() {
3623 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"
, 3623); AnnotateMozCrashReason("MOZ_ASSERT" "(" "unsignedOperands()"
")"); do { *((volatile int*)__null) = 3623; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3624
3625 for (size_t i = 0; i < numOperands(); i++) {
3626 MDefinition* replace;
3627 MustBeUInt32(getOperand(i), &replace);
3628 if (replace == getOperand(i)) {
3629 continue;
3630 }
3631
3632 getOperand(i)->setImplicitlyUsedUnchecked();
3633 replaceOperand(i, replace);
3634 }
3635}
3636
3637MDefinition* MBitNot::foldsTo(TempAllocator& alloc) {
3638 if (type() == MIRType::Int64) {
3639 return this;
3640 }
3641 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"
, 3641); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3641; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3642
3643 MDefinition* input = getOperand(0);
3644
3645 if (input->isConstant()) {
3646 js::Value v = Int32Value(~(input->toConstant()->toInt32()));
3647 return MConstant::New(alloc, v);
3648 }
3649
3650 if (input->isBitNot()) {
3651 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"
, 3651); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3651; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3652 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"
, 3652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->toBitNot()->getOperand(0)->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3652; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3653 return MTruncateToInt32::New(alloc,
3654 input->toBitNot()->input()); // ~~x => x | 0
3655 }
3656
3657 return this;
3658}
3659
3660static void AssertKnownClass(TempAllocator& alloc, MInstruction* ins,
3661 MDefinition* obj) {
3662#ifdef DEBUG1
3663 const JSClass* clasp = GetObjectKnownJSClass(obj);
3664 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"
, 3664); AnnotateMozCrashReason("MOZ_ASSERT" "(" "clasp" ")")
; do { *((volatile int*)__null) = 3664; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3665
3666 auto* assert = MAssertClass::New(alloc, obj, clasp);
3667 ins->block()->insertBefore(ins, assert);
3668#endif
3669}
3670
3671MDefinition* MBoxNonStrictThis::foldsTo(TempAllocator& alloc) {
3672 MDefinition* in = input();
3673 if (in->isBox()) {
3674 in = in->toBox()->input();
3675 }
3676
3677 if (in->type() == MIRType::Object) {
3678 return in;
3679 }
3680
3681 return this;
3682}
3683
3684AliasSet MLoadArgumentsObjectArg::getAliasSet() const {
3685 return AliasSet::Load(AliasSet::Any);
3686}
3687
3688AliasSet MLoadArgumentsObjectArgHole::getAliasSet() const {
3689 return AliasSet::Load(AliasSet::Any);
3690}
3691
3692AliasSet MInArgumentsObjectArg::getAliasSet() const {
3693 // Loads |arguments.length|, but not the actual element, so we can use the
3694 // same alias-set as MArgumentsObjectLength.
3695 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
3696 AliasSet::DynamicSlot);
3697}
3698
3699AliasSet MArgumentsObjectLength::getAliasSet() const {
3700 return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot |
3701 AliasSet::DynamicSlot);
3702}
3703
3704bool MGuardArgumentsObjectFlags::congruentTo(const MDefinition* ins) const {
3705 if (!ins->isGuardArgumentsObjectFlags() ||
3706 ins->toGuardArgumentsObjectFlags()->flags() != flags()) {
3707 return false;
3708 }
3709 return congruentIfOperandsEqual(ins);
3710}
3711
3712AliasSet MGuardArgumentsObjectFlags::getAliasSet() const {
3713 // The flags are packed with the length in a fixed private slot.
3714 return AliasSet::Load(AliasSet::FixedSlot);
3715}
3716
3717MDefinition* MIdToStringOrSymbol::foldsTo(TempAllocator& alloc) {
3718 if (idVal()->isBox()) {
3719 auto* input = idVal()->toBox()->input();
3720 MIRType idType = input->type();
3721 if (idType == MIRType::String || idType == MIRType::Symbol) {
3722 return idVal();
3723 }
3724 if (idType == MIRType::Int32) {
3725 auto* toString =
3726 MToString::New(alloc, input, MToString::SideEffectHandling::Bailout);
3727 block()->insertBefore(this, toString);
3728
3729 return MBox::New(alloc, toString);
3730 }
3731 }
3732
3733 return this;
3734}
3735
3736MDefinition* MReturnFromCtor::foldsTo(TempAllocator& alloc) {
3737 MDefinition* rval = value();
3738 if (rval->isBox()) {
3739 rval = rval->toBox()->input();
3740 }
3741
3742 if (rval->type() == MIRType::Object) {
3743 return rval;
3744 }
3745
3746 if (rval->type() != MIRType::Value) {
3747 return object();
3748 }
3749
3750 return this;
3751}
3752
3753MDefinition* MTypeOf::foldsTo(TempAllocator& alloc) {
3754 MDefinition* unboxed = input();
3755 if (unboxed->isBox()) {
3756 unboxed = unboxed->toBox()->input();
3757 }
3758
3759 JSType type;
3760 switch (unboxed->type()) {
3761 case MIRType::Double:
3762 case MIRType::Float32:
3763 case MIRType::Int32:
3764 type = JSTYPE_NUMBER;
3765 break;
3766 case MIRType::String:
3767 type = JSTYPE_STRING;
3768 break;
3769 case MIRType::Symbol:
3770 type = JSTYPE_SYMBOL;
3771 break;
3772 case MIRType::BigInt:
3773 type = JSTYPE_BIGINT;
3774 break;
3775 case MIRType::Null:
3776 type = JSTYPE_OBJECT;
3777 break;
3778 case MIRType::Undefined:
3779 type = JSTYPE_UNDEFINED;
3780 break;
3781 case MIRType::Boolean:
3782 type = JSTYPE_BOOLEAN;
3783 break;
3784 case MIRType::Object: {
3785 KnownClass known = GetObjectKnownClass(unboxed);
3786 if (known != KnownClass::None) {
3787 if (known == KnownClass::Function) {
3788 type = JSTYPE_FUNCTION;
3789 } else {
3790 type = JSTYPE_OBJECT;
3791 }
3792
3793 AssertKnownClass(alloc, this, unboxed);
3794 break;
3795 }
3796 [[fallthrough]];
3797 }
3798 default:
3799 return this;
3800 }
3801
3802 return MConstant::New(alloc, Int32Value(static_cast<int32_t>(type)));
3803}
3804
3805MDefinition* MTypeOfName::foldsTo(TempAllocator& alloc) {
3806 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"
, 3806); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input()->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 3806; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3807
3808 if (!input()->isConstant()) {
3809 return this;
3810 }
3811
3812 static_assert(JSTYPE_UNDEFINED == 0);
3813
3814 int32_t type = input()->toConstant()->toInt32();
3815 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"
, 3815); AnnotateMozCrashReason("MOZ_ASSERT" "(" "JSTYPE_UNDEFINED <= type && type < JSTYPE_LIMIT"
")"); do { *((volatile int*)__null) = 3815; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3816
3817 JSString* name =
3818 TypeName(static_cast<JSType>(type), GetJitContext()->runtime->names());
3819 return MConstant::New(alloc, StringValue(name));
3820}
3821
3822MUrsh* MUrsh::NewWasm(TempAllocator& alloc, MDefinition* left,
3823 MDefinition* right, MIRType type) {
3824 MUrsh* ins = new (alloc) MUrsh(left, right, type);
3825
3826 // Since Ion has no UInt32 type, we use Int32 and we have a special
3827 // exception to the type rules: we can return values in
3828 // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type
3829 // without bailing out. This is necessary because Ion has no UInt32
3830 // type and we can't have bailouts in wasm code.
3831 ins->bailoutsDisabled_ = true;
3832
3833 return ins;
3834}
3835
3836MResumePoint* MResumePoint::New(TempAllocator& alloc, MBasicBlock* block,
3837 jsbytecode* pc, ResumeMode mode) {
3838 MResumePoint* resume = new (alloc) MResumePoint(block, pc, mode);
3839 if (!resume->init(alloc)) {
3840 block->discardPreAllocatedResumePoint(resume);
3841 return nullptr;
3842 }
3843 resume->inherit(block);
3844 return resume;
3845}
3846
3847MResumePoint::MResumePoint(MBasicBlock* block, jsbytecode* pc, ResumeMode mode)
3848 : MNode(block, Kind::ResumePoint),
3849 pc_(pc),
3850 instruction_(nullptr),
3851 mode_(mode) {
3852 block->addResumePoint(this);
3853}
3854
3855bool MResumePoint::init(TempAllocator& alloc) {
3856 return operands_.init(alloc, block()->stackDepth());
3857}
3858
3859MResumePoint* MResumePoint::caller() const {
3860 return block()->callerResumePoint();
3861}
3862
3863void MResumePoint::inherit(MBasicBlock* block) {
3864 // FixedList doesn't initialize its elements, so do unchecked inits.
3865 for (size_t i = 0; i < stackDepth(); i++) {
3866 initOperand(i, block->getSlot(i));
3867 }
3868}
3869
3870void MResumePoint::addStore(TempAllocator& alloc, MDefinition* store,
3871 const MResumePoint* cache) {
3872 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"
, 3872); AnnotateMozCrashReason("MOZ_ASSERT" "(" "block()->outerResumePoint() != this"
")"); do { *((volatile int*)__null) = 3872; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3873 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"
, 3873); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!cache->stores_.empty()"
")"); do { *((volatile int*)__null) = 3873; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3874
3875 if (cache && cache->stores_.begin()->operand == store) {
3876 // If the last resume point had the same side-effect stack, then we can
3877 // reuse the current side effect without cloning it. This is a simple
3878 // way to share common context by making a spaghetti stack.
3879 if (++cache->stores_.begin() == stores_.begin()) {
3880 stores_.copy(cache->stores_);
3881 return;
3882 }
3883 }
3884
3885 // Ensure that the store would not be deleted by DCE.
3886 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"
, 3886); AnnotateMozCrashReason("MOZ_ASSERT" "(" "store->isEffectful()"
")"); do { *((volatile int*)__null) = 3886; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3887
3888 MStoreToRecover* top = new (alloc) MStoreToRecover(store);
3889 stores_.push(top);
3890}
3891
3892#ifdef JS_JITSPEW1
3893void MResumePoint::dump(GenericPrinter& out) const {
3894 out.printf("resumepoint mode=");
3895
3896 switch (mode()) {
3897 case ResumeMode::ResumeAt:
3898 if (instruction_) {
3899 out.printf("ResumeAt(%u)", instruction_->id());
3900 } else {
3901 out.printf("ResumeAt");
3902 }
3903 break;
3904 default:
3905 out.put(ResumeModeToString(mode()));
3906 break;
3907 }
3908
3909 if (MResumePoint* c = caller()) {
3910 out.printf(" (caller in block%u)", c->block()->id());
3911 }
3912
3913 for (size_t i = 0; i < numOperands(); i++) {
3914 out.printf(" ");
3915 if (operands_[i].hasProducer()) {
3916 getOperand(i)->printName(out);
3917 } else {
3918 out.printf("(null)");
3919 }
3920 }
3921 out.printf("\n");
3922}
3923
3924void MResumePoint::dump() const {
3925 Fprinter out(stderrstderr);
3926 dump(out);
3927 out.finish();
3928}
3929#endif
3930
3931bool MResumePoint::isObservableOperand(MUse* u) const {
3932 return isObservableOperand(indexOf(u));
3933}
3934
3935bool MResumePoint::isObservableOperand(size_t index) const {
3936 return block()->info().isObservableSlot(index);
3937}
3938
3939bool MResumePoint::isRecoverableOperand(MUse* u) const {
3940 return block()->info().isRecoverableOperand(indexOf(u));
3941}
3942
3943MDefinition* MTruncateBigIntToInt64::foldsTo(TempAllocator& alloc) {
3944 MDefinition* input = getOperand(0);
3945
3946 if (input->isBox()) {
3947 input = input->getOperand(0);
3948 }
3949
3950 // If the operand converts an I64 to BigInt, drop both conversions.
3951 if (input->isInt64ToBigInt()) {
3952 return input->getOperand(0);
3953 }
3954
3955 // Fold this operation if the input operand is constant.
3956 if (input->isConstant()) {
3957 return MConstant::NewInt64(
3958 alloc, BigInt::toInt64(input->toConstant()->toBigInt()));
3959 }
3960
3961 return this;
3962}
3963
3964MDefinition* MToInt64::foldsTo(TempAllocator& alloc) {
3965 MDefinition* input = getOperand(0);
3966
3967 if (input->isBox()) {
3968 input = input->getOperand(0);
3969 }
3970
3971 // Unwrap MInt64ToBigInt: MToInt64(MInt64ToBigInt(int64)) = int64.
3972 if (input->isInt64ToBigInt()) {
3973 return input->getOperand(0);
3974 }
3975
3976 // When the input is an Int64 already, just return it.
3977 if (input->type() == MIRType::Int64) {
3978 return input;
3979 }
3980
3981 // Fold this operation if the input operand is constant.
3982 if (input->isConstant()) {
3983 switch (input->type()) {
3984 case MIRType::Boolean:
3985 return MConstant::NewInt64(alloc, input->toConstant()->toBoolean());
3986 default:
3987 break;
3988 }
3989 }
3990
3991 return this;
3992}
3993
3994MDefinition* MToNumberInt32::foldsTo(TempAllocator& alloc) {
3995 // Fold this operation if the input operand is constant.
3996 if (MConstant* cst = input()->maybeConstantValue()) {
3997 switch (cst->type()) {
3998 case MIRType::Null:
3999 if (conversion() == IntConversionInputKind::Any) {
4000 return MConstant::New(alloc, Int32Value(0));
4001 }
4002 break;
4003 case MIRType::Boolean:
4004 if (conversion() == IntConversionInputKind::Any ||
4005 conversion() == IntConversionInputKind::NumbersOrBoolsOnly) {
4006 return MConstant::New(alloc, Int32Value(cst->toBoolean()));
4007 }
4008 break;
4009 case MIRType::Int32:
4010 return MConstant::New(alloc, Int32Value(cst->toInt32()));
4011 case MIRType::Float32:
4012 case MIRType::Double:
4013 int32_t ival;
4014 // Only the value within the range of Int32 can be substituted as
4015 // constant.
4016 if (mozilla::NumberIsInt32(cst->numberToDouble(), &ival)) {
4017 return MConstant::New(alloc, Int32Value(ival));
4018 }
4019 break;
4020 default:
4021 break;
4022 }
4023 }
4024
4025 MDefinition* input = getOperand(0);
4026 if (input->isBox()) {
4027 input = input->toBox()->input();
4028 }
4029
4030 // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
4031 // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
4032 // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
4033 // is folded to a MTruncateToInt32 node, which will result in this MIR:
4034 // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
4035 // the MUrsh node's type is int32 (since uint32 is not implemented), and
4036 // that would fold the MTruncateToInt32 node. This will make the modulo
4037 // unsigned, while is should have been signed.
4038 if (input->type() == MIRType::Int32 && !IsUint32Type(input)) {
4039 return input;
4040 }
4041
4042 return this;
4043}
4044
4045MDefinition* MBooleanToInt32::foldsTo(TempAllocator& alloc) {
4046 MDefinition* input = getOperand(0);
4047 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"
, 4047); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 4047; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4048
4049 if (input->isConstant()) {
4050 return MConstant::New(alloc, Int32Value(input->toConstant()->toBoolean()));
4051 }
4052
4053 return this;
4054}
4055
4056void MToNumberInt32::analyzeEdgeCasesBackward() {
4057 if (!NeedNegativeZeroCheck(this)) {
4058 setNeedsNegativeZeroCheck(false);
4059 }
4060}
4061
4062MDefinition* MTruncateToInt32::foldsTo(TempAllocator& alloc) {
4063 MDefinition* input = getOperand(0);
4064 if (input->isBox()) {
4065 input = input->getOperand(0);
4066 }
4067
4068 // Do not fold the TruncateToInt32 node when the input is uint32 (e.g. ursh
4069 // with a zero constant. Consider the test jit-test/tests/ion/bug1247880.js,
4070 // where the relevant code is: |(imul(1, x >>> 0) % 2)|. The imul operator
4071 // is folded to a MTruncateToInt32 node, which will result in this MIR:
4072 // MMod(MTruncateToInt32(MUrsh(x, MConstant(0))), MConstant(2)). Note that
4073 // the MUrsh node's type is int32 (since uint32 is not implemented), and
4074 // that would fold the MTruncateToInt32 node. This will make the modulo
4075 // unsigned, while is should have been signed.
4076 if (input->type() == MIRType::Int32 && !IsUint32Type(input)) {
4077 return input;
4078 }
4079
4080 if (input->type() == MIRType::Double && input->isConstant()) {
4081 int32_t ret = ToInt32(input->toConstant()->toDouble());
4082 return MConstant::New(alloc, Int32Value(ret));
4083 }
4084
4085 return this;
4086}
4087
4088MDefinition* MWasmTruncateToInt32::foldsTo(TempAllocator& alloc) {
4089 MDefinition* input = getOperand(0);
4090 if (input->type() == MIRType::Int32) {
4091 return input;
4092 }
4093
4094 if (input->type() == MIRType::Double && input->isConstant()) {
4095 double d = input->toConstant()->toDouble();
4096 if (std::isnan(d)) {
4097 return this;
4098 }
4099
4100 if (!isUnsigned() && d <= double(INT32_MAX(2147483647)) && d >= double(INT32_MIN(-2147483647-1))) {
4101 return MConstant::New(alloc, Int32Value(ToInt32(d)));
4102 }
4103
4104 if (isUnsigned() && d <= double(UINT32_MAX(4294967295U)) && d >= 0) {
4105 return MConstant::New(alloc, Int32Value(ToInt32(d)));
4106 }
4107 }
4108
4109 if (input->type() == MIRType::Float32 && input->isConstant()) {
4110 double f = double(input->toConstant()->toFloat32());
4111 if (std::isnan(f)) {
4112 return this;
4113 }
4114
4115 if (!isUnsigned() && f <= double(INT32_MAX(2147483647)) && f >= double(INT32_MIN(-2147483647-1))) {
4116 return MConstant::New(alloc, Int32Value(ToInt32(f)));
4117 }
4118
4119 if (isUnsigned() && f <= double(UINT32_MAX(4294967295U)) && f >= 0) {
4120 return MConstant::New(alloc, Int32Value(ToInt32(f)));
4121 }
4122 }
4123
4124 return this;
4125}
4126
4127MDefinition* MWrapInt64ToInt32::foldsTo(TempAllocator& alloc) {
4128 MDefinition* input = this->input();
4129 if (input->isConstant()) {
4130 uint64_t c = input->toConstant()->toInt64();
4131 int32_t output = bottomHalf() ? int32_t(c) : int32_t(c >> 32);
4132 return MConstant::New(alloc, Int32Value(output));
4133 }
4134
4135 return this;
4136}
4137
4138MDefinition* MExtendInt32ToInt64::foldsTo(TempAllocator& alloc) {
4139 MDefinition* input = this->input();
4140 if (input->isConstant()) {
4141 int32_t c = input->toConstant()->toInt32();
4142 int64_t res = isUnsigned() ? int64_t(uint32_t(c)) : int64_t(c);
4143 return MConstant::NewInt64(alloc, res);
4144 }
4145
4146 return this;
4147}
4148
4149MDefinition* MSignExtendInt32::foldsTo(TempAllocator& alloc) {
4150 MDefinition* input = this->input();
4151 if (input->isConstant()) {
4152 int32_t c = input->toConstant()->toInt32();
4153 int32_t res;
4154 switch (mode_) {
4155 case Byte:
4156 res = int32_t(int8_t(c & 0xFF));
4157 break;
4158 case Half:
4159 res = int32_t(int16_t(c & 0xFFFF));
4160 break;
4161 }
4162 return MConstant::New(alloc, Int32Value(res));
4163 }
4164
4165 return this;
4166}
4167
4168MDefinition* MSignExtendInt64::foldsTo(TempAllocator& alloc) {
4169 MDefinition* input = this->input();
4170 if (input->isConstant()) {
4171 int64_t c = input->toConstant()->toInt64();
4172 int64_t res;
4173 switch (mode_) {
4174 case Byte:
4175 res = int64_t(int8_t(c & 0xFF));
4176 break;
4177 case Half:
4178 res = int64_t(int16_t(c & 0xFFFF));
4179 break;
4180 case Word:
4181 res = int64_t(int32_t(c & 0xFFFFFFFFU));
4182 break;
4183 }
4184 return MConstant::NewInt64(alloc, res);
4185 }
4186
4187 return this;
4188}
4189
4190MDefinition* MToDouble::foldsTo(TempAllocator& alloc) {
4191 MDefinition* input = getOperand(0);
4192 if (input->isBox()) {
4193 input = input->getOperand(0);
4194 }
4195
4196 if (input->type() == MIRType::Double) {
4197 return input;
4198 }
4199
4200 if (input->isConstant() &&
4201 input->toConstant()->isTypeRepresentableAsDouble()) {
4202 return MConstant::New(alloc,
4203 DoubleValue(input->toConstant()->numberToDouble()));
4204 }
4205
4206 return this;
4207}
4208
4209MDefinition* MToFloat32::foldsTo(TempAllocator& alloc) {
4210 MDefinition* input = getOperand(0);
4211 if (input->isBox()) {
4212 input = input->getOperand(0);
4213 }
4214
4215 if (input->type() == MIRType::Float32) {
4216 return input;
4217 }
4218
4219 // If x is a Float32, Float32(Double(x)) == x
4220 if (!mustPreserveNaN_ && input->isToDouble() &&
4221 input->toToDouble()->input()->type() == MIRType::Float32) {
4222 return input->toToDouble()->input();
4223 }
4224
4225 if (input->isConstant() &&
4226 input->toConstant()->isTypeRepresentableAsDouble()) {
4227 return MConstant::NewFloat32(alloc,
4228 float(input->toConstant()->numberToDouble()));
4229 }
4230
4231 // Fold ToFloat32(ToDouble(int32)) to ToFloat32(int32).
4232 if (input->isToDouble() &&
4233 input->toToDouble()->input()->type() == MIRType::Int32) {
4234 return MToFloat32::New(alloc, input->toToDouble()->input());
4235 }
4236
4237 return this;
4238}
4239
4240MDefinition* MToString::foldsTo(TempAllocator& alloc) {
4241 MDefinition* in = input();
4242 if (in->isBox()) {
4243 in = in->getOperand(0);
4244 }
4245
4246 if (in->type() == MIRType::String) {
4247 return in;
4248 }
4249 return this;
4250}
4251
4252MDefinition* MClampToUint8::foldsTo(TempAllocator& alloc) {
4253 if (MConstant* inputConst = input()->maybeConstantValue()) {
4254 if (inputConst->isTypeRepresentableAsDouble()) {
4255 int32_t clamped = ClampDoubleToUint8(inputConst->numberToDouble());
4256 return MConstant::New(alloc, Int32Value(clamped));
4257 }
4258 }
4259 return this;
4260}
4261
4262bool MCompare::tryFoldEqualOperands(bool* result) {
4263 if (lhs() != rhs()) {
4264 return false;
4265 }
4266
4267 // Intuitively somebody would think that if lhs === rhs,
4268 // then we can just return true. (Or false for !==)
4269 // However NaN !== NaN is true! So we spend some time trying
4270 // to eliminate this case.
4271
4272 if (!IsStrictEqualityOp(jsop())) {
4273 return false;
4274 }
4275
4276 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4277 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4278 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4279 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4280 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4281 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4282 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4283 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4284 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4285 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"
, 4285); 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) = 4285; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4286
4287 if (isDoubleComparison() || isFloat32Comparison()) {
4288 if (!operandsAreNeverNaN()) {
4289 return false;
4290 }
4291 }
4292
4293 lhs()->setGuardRangeBailoutsUnchecked();
4294
4295 *result = (jsop() == JSOp::StrictEq);
4296 return true;
4297}
4298
4299static JSType TypeOfName(JSLinearString* str) {
4300 static constexpr std::array types = {
4301 JSTYPE_UNDEFINED, JSTYPE_OBJECT, JSTYPE_FUNCTION, JSTYPE_STRING,
4302 JSTYPE_NUMBER, JSTYPE_BOOLEAN, JSTYPE_SYMBOL, JSTYPE_BIGINT,
4303#ifdef ENABLE_RECORD_TUPLE
4304 JSTYPE_RECORD, JSTYPE_TUPLE,
4305#endif
4306 };
4307 static_assert(types.size() == JSTYPE_LIMIT);
4308
4309 const JSAtomState& names = GetJitContext()->runtime->names();
4310 for (auto type : types) {
4311 if (EqualStrings(str, TypeName(type, names))) {
4312 return type;
4313 }
4314 }
4315 return JSTYPE_LIMIT;
4316}
4317
4318struct TypeOfCompareInput {
4319 // The `typeof expr` side of the comparison.
4320 // MTypeOfName for JSOp::Typeof/JSOp::TypeofExpr, and
4321 // MTypeOf for JSOp::TypeofEq (same pointer as typeOf).
4322 MDefinition* typeOfSide;
4323
4324 // The actual `typeof` operation.
4325 MTypeOf* typeOf;
4326
4327 // The string side of the comparison.
4328 JSType type;
4329
4330 // True if the comparison uses raw JSType (Generated for JSOp::TypeofEq).
4331 bool isIntComparison;
4332
4333 TypeOfCompareInput(MDefinition* typeOfSide, MTypeOf* typeOf, JSType type,
4334 bool isIntComparison)
4335 : typeOfSide(typeOfSide),
4336 typeOf(typeOf),
4337 type(type),
4338 isIntComparison(isIntComparison) {}
4339};
4340
4341static mozilla::Maybe<TypeOfCompareInput> IsTypeOfCompare(MCompare* ins) {
4342 if (!IsEqualityOp(ins->jsop())) {
4343 return mozilla::Nothing();
4344 }
4345
4346 if (ins->compareType() == MCompare::Compare_Int32) {
4347 auto* lhs = ins->lhs();
4348 auto* rhs = ins->rhs();
4349
4350 if (ins->type() != MIRType::Boolean || lhs->type() != MIRType::Int32 ||
4351 rhs->type() != MIRType::Int32) {
4352 return mozilla::Nothing();
4353 }
4354
4355 // NOTE: The comparison is generated inside JIT, and typeof should always
4356 // be in the LHS.
4357 if (!lhs->isTypeOf() || !rhs->isConstant()) {
4358 return mozilla::Nothing();
4359 }
4360
4361 auto* typeOf = lhs->toTypeOf();
4362 auto* constant = rhs->toConstant();
4363
4364 JSType type = JSType(constant->toInt32());
4365 return mozilla::Some(TypeOfCompareInput(typeOf, typeOf, type, true));
4366 }
4367
4368 if (ins->compareType() != MCompare::Compare_String) {
4369 return mozilla::Nothing();
4370 }
4371
4372 auto* lhs = ins->lhs();
4373 auto* rhs = ins->rhs();
4374
4375 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"
, 4375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ins->type() == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 4375; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4376 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"
, 4376); AnnotateMozCrashReason("MOZ_ASSERT" "(" "lhs->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4376; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4377 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"
, 4377); AnnotateMozCrashReason("MOZ_ASSERT" "(" "rhs->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4377; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4378
4379 if (!lhs->isTypeOfName() && !rhs->isTypeOfName()) {
4380 return mozilla::Nothing();
4381 }
4382 if (!lhs->isConstant() && !rhs->isConstant()) {
4383 return mozilla::Nothing();
4384 }
4385
4386 auto* typeOfName =
4387 lhs->isTypeOfName() ? lhs->toTypeOfName() : rhs->toTypeOfName();
4388 auto* typeOf = typeOfName->input()->toTypeOf();
4389
4390 auto* constant = lhs->isConstant() ? lhs->toConstant() : rhs->toConstant();
4391
4392 JSType type = TypeOfName(&constant->toString()->asLinear());
4393 return mozilla::Some(TypeOfCompareInput(typeOfName, typeOf, type, false));
4394}
4395
4396bool MCompare::tryFoldTypeOf(bool* result) {
4397 auto typeOfCompare = IsTypeOfCompare(this);
4398 if (!typeOfCompare) {
4399 return false;
4400 }
4401 auto* typeOf = typeOfCompare->typeOf;
4402 JSType type = typeOfCompare->type;
4403
4404 switch (type) {
4405 case JSTYPE_BOOLEAN:
4406 if (!typeOf->input()->mightBeType(MIRType::Boolean)) {
4407 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4408 return true;
4409 }
4410 break;
4411 case JSTYPE_NUMBER:
4412 if (!typeOf->input()->mightBeType(MIRType::Int32) &&
4413 !typeOf->input()->mightBeType(MIRType::Float32) &&
4414 !typeOf->input()->mightBeType(MIRType::Double)) {
4415 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4416 return true;
4417 }
4418 break;
4419 case JSTYPE_STRING:
4420 if (!typeOf->input()->mightBeType(MIRType::String)) {
4421 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4422 return true;
4423 }
4424 break;
4425 case JSTYPE_SYMBOL:
4426 if (!typeOf->input()->mightBeType(MIRType::Symbol)) {
4427 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4428 return true;
4429 }
4430 break;
4431 case JSTYPE_BIGINT:
4432 if (!typeOf->input()->mightBeType(MIRType::BigInt)) {
4433 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4434 return true;
4435 }
4436 break;
4437 case JSTYPE_OBJECT:
4438 if (!typeOf->input()->mightBeType(MIRType::Object) &&
4439 !typeOf->input()->mightBeType(MIRType::Null)) {
4440 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4441 return true;
4442 }
4443 break;
4444 case JSTYPE_UNDEFINED:
4445 if (!typeOf->input()->mightBeType(MIRType::Object) &&
4446 !typeOf->input()->mightBeType(MIRType::Undefined)) {
4447 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4448 return true;
4449 }
4450 break;
4451 case JSTYPE_FUNCTION:
4452 if (!typeOf->input()->mightBeType(MIRType::Object)) {
4453 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4454 return true;
4455 }
4456 break;
4457 case JSTYPE_LIMIT:
4458 *result = (jsop() == JSOp::StrictNe || jsop() == JSOp::Ne);
4459 return true;
4460#ifdef ENABLE_RECORD_TUPLE
4461 case JSTYPE_RECORD:
4462 case JSTYPE_TUPLE:
4463 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"
, 4463); AnnotateMozCrashReason("MOZ_CRASH(" "Records and Tuples are not supported yet."
")"); do { *((volatile int*)__null) = 4463; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4464#endif
4465 }
4466
4467 return false;
4468}
4469
4470bool MCompare::tryFold(bool* result) {
4471 JSOp op = jsop();
4472
4473 if (tryFoldEqualOperands(result)) {
4474 return true;
4475 }
4476
4477 if (tryFoldTypeOf(result)) {
4478 return true;
4479 }
4480
4481 if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) {
4482 // The LHS is the value we want to test against null or undefined.
4483 if (IsStrictEqualityOp(op)) {
4484 if (lhs()->type() == inputType()) {
4485 *result = (op == JSOp::StrictEq);
4486 return true;
4487 }
4488 if (!lhs()->mightBeType(inputType())) {
4489 *result = (op == JSOp::StrictNe);
4490 return true;
4491 }
4492 } else {
4493 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"
, 4493); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsLooseEqualityOp(op)"
")"); do { *((volatile int*)__null) = 4493; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4494 if (IsNullOrUndefined(lhs()->type())) {
4495 *result = (op == JSOp::Eq);
4496 return true;
4497 }
4498 if (!lhs()->mightBeType(MIRType::Null) &&
4499 !lhs()->mightBeType(MIRType::Undefined) &&
4500 !lhs()->mightBeType(MIRType::Object)) {
4501 *result = (op == JSOp::Ne);
4502 return true;
4503 }
4504 }
4505 return false;
4506 }
4507
4508 return false;
4509}
4510
4511template <typename T>
4512static bool FoldComparison(JSOp op, T left, T right) {
4513 switch (op) {
4514 case JSOp::Lt:
4515 return left < right;
4516 case JSOp::Le:
4517 return left <= right;
4518 case JSOp::Gt:
4519 return left > right;
4520 case JSOp::Ge:
4521 return left >= right;
4522 case JSOp::StrictEq:
4523 case JSOp::Eq:
4524 return left == right;
4525 case JSOp::StrictNe:
4526 case JSOp::Ne:
4527 return left != right;
4528 default:
4529 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4529); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 4529; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4530 }
4531}
4532
4533bool MCompare::evaluateConstantOperands(TempAllocator& alloc, bool* result) {
4534 if (type() != MIRType::Boolean && type() != MIRType::Int32) {
4535 return false;
4536 }
4537
4538 MDefinition* left = getOperand(0);
4539 MDefinition* right = getOperand(1);
4540
4541 if (compareType() == Compare_Double) {
4542 // Optimize "MCompare MConstant (MToDouble SomethingInInt32Range).
4543 // In most cases the MToDouble was added, because the constant is
4544 // a double.
4545 // e.g. v < 9007199254740991, where v is an int32 is always true.
4546 if (!lhs()->isConstant() && !rhs()->isConstant()) {
4547 return false;
4548 }
4549
4550 MDefinition* operand = left->isConstant() ? right : left;
4551 MConstant* constant =
4552 left->isConstant() ? left->toConstant() : right->toConstant();
4553 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"
, 4553); AnnotateMozCrashReason("MOZ_ASSERT" "(" "constant->type() == MIRType::Double"
")"); do { *((volatile int*)__null) = 4553; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4554 double cte = constant->toDouble();
4555
4556 if (operand->isToDouble() &&
4557 operand->getOperand(0)->type() == MIRType::Int32) {
4558 bool replaced = false;
4559 switch (jsop_) {
4560 case JSOp::Lt:
4561 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4562 *result = !((constant == lhs()) ^ (cte < INT32_MIN(-2147483647-1)));
4563 replaced = true;
4564 }
4565 break;
4566 case JSOp::Le:
4567 if (constant == lhs()) {
4568 if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) {
4569 *result = (cte <= INT32_MIN(-2147483647-1));
4570 replaced = true;
4571 }
4572 } else {
4573 if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4574 *result = (cte >= INT32_MIN(-2147483647-1));
4575 replaced = true;
4576 }
4577 }
4578 break;
4579 case JSOp::Gt:
4580 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4581 *result = !((constant == rhs()) ^ (cte < INT32_MIN(-2147483647-1)));
4582 replaced = true;
4583 }
4584 break;
4585 case JSOp::Ge:
4586 if (constant == lhs()) {
4587 if (cte >= INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4588 *result = (cte >= INT32_MAX(2147483647));
4589 replaced = true;
4590 }
4591 } else {
4592 if (cte > INT32_MAX(2147483647) || cte <= INT32_MIN(-2147483647-1)) {
4593 *result = (cte <= INT32_MIN(-2147483647-1));
4594 replaced = true;
4595 }
4596 }
4597 break;
4598 case JSOp::StrictEq: // Fall through.
4599 case JSOp::Eq:
4600 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4601 *result = false;
4602 replaced = true;
4603 }
4604 break;
4605 case JSOp::StrictNe: // Fall through.
4606 case JSOp::Ne:
4607 if (cte > INT32_MAX(2147483647) || cte < INT32_MIN(-2147483647-1)) {
4608 *result = true;
4609 replaced = true;
4610 }
4611 break;
4612 default:
4613 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4613); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 4613; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4614 }
4615 if (replaced) {
4616 MLimitedTruncate* limit = MLimitedTruncate::New(
4617 alloc, operand->getOperand(0), TruncateKind::NoTruncate);
4618 limit->setGuardUnchecked();
4619 block()->insertBefore(this, limit);
4620 return true;
4621 }
4622 }
4623
4624 // Optimize comparison against NaN.
4625 if (std::isnan(cte)) {
4626 switch (jsop_) {
4627 case JSOp::Lt:
4628 case JSOp::Le:
4629 case JSOp::Gt:
4630 case JSOp::Ge:
4631 case JSOp::Eq:
4632 case JSOp::StrictEq:
4633 *result = false;
4634 break;
4635 case JSOp::Ne:
4636 case JSOp::StrictNe:
4637 *result = true;
4638 break;
4639 default:
4640 MOZ_CRASH("Unexpected op.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected op."
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 4640); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected op."
")"); do { *((volatile int*)__null) = 4640; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
4641 }
4642 return true;
4643 }
4644 }
4645
4646 if (!left->isConstant() || !right->isConstant()) {
4647 return false;
4648 }
4649
4650 MConstant* lhs = left->toConstant();
4651 MConstant* rhs = right->toConstant();
4652
4653 // Fold away some String equality comparisons.
4654 if (lhs->type() == MIRType::String && rhs->type() == MIRType::String) {
4655 int32_t comp = 0; // Default to equal.
4656 if (left != right) {
4657 comp = CompareStrings(&lhs->toString()->asLinear(),
4658 &rhs->toString()->asLinear());
4659 }
4660 *result = FoldComparison(jsop_, comp, 0);
4661 return true;
4662 }
4663
4664 if (compareType_ == Compare_UInt32) {
4665 *result = FoldComparison(jsop_, uint32_t(lhs->toInt32()),
4666 uint32_t(rhs->toInt32()));
4667 return true;
4668 }
4669
4670 if (compareType_ == Compare_Int64) {
4671 *result = FoldComparison(jsop_, lhs->toInt64(), rhs->toInt64());
4672 return true;
4673 }
4674
4675 if (compareType_ == Compare_UInt64) {
4676 *result = FoldComparison(jsop_, uint64_t(lhs->toInt64()),
4677 uint64_t(rhs->toInt64()));
4678 return true;
4679 }
4680
4681 if (lhs->isTypeRepresentableAsDouble() &&
4682 rhs->isTypeRepresentableAsDouble()) {
4683 *result =
4684 FoldComparison(jsop_, lhs->numberToDouble(), rhs->numberToDouble());
4685 return true;
4686 }
4687
4688 return false;
4689}
4690
4691MDefinition* MCompare::tryFoldTypeOf(TempAllocator& alloc) {
4692 auto typeOfCompare = IsTypeOfCompare(this);
4693 if (!typeOfCompare) {
4694 return this;
4695 }
4696 auto* typeOf = typeOfCompare->typeOf;
4697 JSType type = typeOfCompare->type;
4698
4699 auto* input = typeOf->input();
4700 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"
, 4701); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object"
")"); do { *((volatile int*)__null) = 4701; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4701 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"
, 4701); AnnotateMozCrashReason("MOZ_ASSERT" "(" "input->type() == MIRType::Value || input->type() == MIRType::Object"
")"); do { *((volatile int*)__null) = 4701; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4702
4703 // Constant typeof folding handles the other cases.
4704 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"
, 4706); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
")"); do { *((volatile int*)__null) = 4706; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4705 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"
, 4706); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
")"); do { *((volatile int*)__null) = 4706; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
4706 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"
, 4706); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type == JSTYPE_UNDEFINED || type == JSTYPE_OBJECT || type == JSTYPE_FUNCTION"
")"); do { *((volatile int*)__null) = 4706; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4707
4708 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"
, 4708); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type != JSTYPE_LIMIT"
") (" "unknown typeof strings folded earlier" ")"); do { *((
volatile int*)__null) = 4708; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4709
4710 // If there's only a single use, assume this |typeof| is used in a simple
4711 // comparison context.
4712 //
4713 // if (typeof thing === "number") { ... }
4714 //
4715 // It'll be compiled into something similar to:
4716 //
4717 // if (IsNumber(thing)) { ... }
4718 //
4719 // This heuristic can go wrong when repeated |typeof| are used in consecutive
4720 // if-statements.
4721 //
4722 // if (typeof thing === "number") { ... }
4723 // else if (typeof thing === "string") { ... }
4724 // ... repeated for all possible types
4725 //
4726 // In that case it'd more efficient to emit MTypeOf compared to MTypeOfIs. We
4727 // don't yet handle that case, because it'd require a separate optimization
4728 // pass to correctly detect it.
4729 if (typeOfCompare->typeOfSide->hasOneUse()) {
4730 return MTypeOfIs::New(alloc, input, jsop(), type);
4731 }
4732
4733 if (typeOfCompare->isIntComparison) {
4734 // Already optimized.
4735 return this;
4736 }
4737
4738 MConstant* cst = MConstant::New(alloc, Int32Value(type));
4739 block()->insertBefore(this, cst);
4740
4741 return MCompare::New(alloc, typeOf, cst, jsop(), MCompare::Compare_Int32);
4742}
4743
4744MDefinition* MCompare::tryFoldCharCompare(TempAllocator& alloc) {
4745 if (compareType() != Compare_String) {
4746 return this;
4747 }
4748
4749 MDefinition* left = lhs();
4750 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"
, 4750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4750; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4751
4752 MDefinition* right = rhs();
4753 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"
, 4753); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4753; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4754
4755 // |str[i]| is compiled as |MFromCharCode(MCharCodeAt(str, i))|.
4756 // Out-of-bounds access is compiled as
4757 // |FromCharCodeEmptyIfNegative(CharCodeAtOrNegative(str, i))|.
4758 auto isCharAccess = [](MDefinition* ins) {
4759 if (ins->isFromCharCode()) {
4760 return ins->toFromCharCode()->code()->isCharCodeAt();
4761 }
4762 if (ins->isFromCharCodeEmptyIfNegative()) {
4763 auto* fromCharCode = ins->toFromCharCodeEmptyIfNegative();
4764 return fromCharCode->code()->isCharCodeAtOrNegative();
4765 }
4766 return false;
4767 };
4768
4769 auto charAccessCode = [](MDefinition* ins) {
4770 if (ins->isFromCharCode()) {
4771 return ins->toFromCharCode()->code();
4772 }
4773 return ins->toFromCharCodeEmptyIfNegative()->code();
4774 };
4775
4776 if (left->isConstant() || right->isConstant()) {
4777 // Try to optimize |MConstant(string) <compare> (MFromCharCode MCharCodeAt)|
4778 // as |MConstant(charcode) <compare> MCharCodeAt|.
4779 MConstant* constant;
4780 MDefinition* operand;
4781 if (left->isConstant()) {
4782 constant = left->toConstant();
4783 operand = right;
4784 } else {
4785 constant = right->toConstant();
4786 operand = left;
4787 }
4788
4789 if (constant->toString()->length() != 1 || !isCharAccess(operand)) {
4790 return this;
4791 }
4792
4793 char16_t charCode = constant->toString()->asLinear().latin1OrTwoByteChar(0);
4794 MConstant* charCodeConst = MConstant::New(alloc, Int32Value(charCode));
4795 block()->insertBefore(this, charCodeConst);
4796
4797 MDefinition* charCodeAt = charAccessCode(operand);
4798
4799 if (left->isConstant()) {
4800 left = charCodeConst;
4801 right = charCodeAt;
4802 } else {
4803 left = charCodeAt;
4804 right = charCodeConst;
4805 }
4806 } else if (isCharAccess(left) && isCharAccess(right)) {
4807 // Try to optimize |(MFromCharCode MCharCodeAt) <compare> (MFromCharCode
4808 // MCharCodeAt)| as |MCharCodeAt <compare> MCharCodeAt|.
4809
4810 left = charAccessCode(left);
4811 right = charAccessCode(right);
4812 } else {
4813 return this;
4814 }
4815
4816 return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32);
4817}
4818
4819MDefinition* MCompare::tryFoldStringCompare(TempAllocator& alloc) {
4820 if (compareType() != Compare_String) {
4821 return this;
4822 }
4823
4824 MDefinition* left = lhs();
4825 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"
, 4825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4825; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4826
4827 MDefinition* right = rhs();
4828 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"
, 4828); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4828; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4829
4830 if (!left->isConstant() && !right->isConstant()) {
4831 return this;
4832 }
4833
4834 // Try to optimize |string <compare> MConstant("")| as |MStringLength(string)
4835 // <compare> MConstant(0)|.
4836
4837 MConstant* constant =
4838 left->isConstant() ? left->toConstant() : right->toConstant();
4839 if (!constant->toString()->empty()) {
4840 return this;
4841 }
4842
4843 MDefinition* operand = left->isConstant() ? right : left;
4844
4845 auto* strLength = MStringLength::New(alloc, operand);
4846 block()->insertBefore(this, strLength);
4847
4848 auto* zero = MConstant::New(alloc, Int32Value(0));
4849 block()->insertBefore(this, zero);
4850
4851 if (left->isConstant()) {
4852 left = zero;
4853 right = strLength;
4854 } else {
4855 left = strLength;
4856 right = zero;
4857 }
4858
4859 return MCompare::New(alloc, left, right, jsop(), MCompare::Compare_Int32);
4860}
4861
4862MDefinition* MCompare::tryFoldStringSubstring(TempAllocator& alloc) {
4863 if (compareType() != Compare_String) {
4864 return this;
4865 }
4866 if (!IsEqualityOp(jsop())) {
4867 return this;
4868 }
4869
4870 auto* left = lhs();
4871 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"
, 4871); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4871; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4872
4873 auto* right = rhs();
4874 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"
, 4874); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::String"
")"); do { *((volatile int*)__null) = 4874; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4875
4876 // One operand must be a constant string.
4877 if (!left->isConstant() && !right->isConstant()) {
4878 return this;
4879 }
4880
4881 // The constant string must be non-empty.
4882 auto* constant =
4883 left->isConstant() ? left->toConstant() : right->toConstant();
4884 if (constant->toString()->empty()) {
4885 return this;
4886 }
4887
4888 // The other operand must be a substring operation.
4889 auto* operand = left->isConstant() ? right : left;
4890 if (!operand->isSubstr()) {
4891 return this;
4892 }
4893 auto* substr = operand->toSubstr();
4894
4895 static_assert(JSString::MAX_LENGTH < INT32_MAX(2147483647),
4896 "string length can be casted to int32_t");
4897
4898 if (!IsSubstrTo(substr, int32_t(constant->toString()->length()))) {
4899 return this;
4900 }
4901
4902 // Now fold code like |str.substring(0, 2) == "aa"| to |str.startsWith("aa")|.
4903
4904 auto* startsWith = MStringStartsWith::New(alloc, substr->string(), constant);
4905 if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) {
4906 return startsWith;
4907 }
4908
4909 // Invert for inequality.
4910 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"
, 4910); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe"
")"); do { *((volatile int*)__null) = 4910; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4911
4912 block()->insertBefore(this, startsWith);
4913 return MNot::New(alloc, startsWith);
4914}
4915
4916MDefinition* MCompare::tryFoldStringIndexOf(TempAllocator& alloc) {
4917 if (compareType() != Compare_Int32) {
4918 return this;
4919 }
4920 if (!IsEqualityOp(jsop())) {
4921 return this;
4922 }
4923
4924 auto* left = lhs();
4925 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"
, 4925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "left->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 4925; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4926
4927 auto* right = rhs();
4928 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"
, 4928); AnnotateMozCrashReason("MOZ_ASSERT" "(" "right->type() == MIRType::Int32"
")"); do { *((volatile int*)__null) = 4928; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4929
4930 // One operand must be a constant integer.
4931 if (!left->isConstant() && !right->isConstant()) {
4932 return this;
4933 }
4934
4935 // The constant must be zero.
4936 auto* constant =
4937 left->isConstant() ? left->toConstant() : right->toConstant();
4938 if (!constant->isInt32(0)) {
4939 return this;
4940 }
4941
4942 // The other operand must be an indexOf operation.
4943 auto* operand = left->isConstant() ? right : left;
4944 if (!operand->isStringIndexOf()) {
4945 return this;
4946 }
4947
4948 // Fold |str.indexOf(searchStr) == 0| to |str.startsWith(searchStr)|.
4949
4950 auto* indexOf = operand->toStringIndexOf();
4951 auto* startsWith =
4952 MStringStartsWith::New(alloc, indexOf->string(), indexOf->searchString());
4953 if (jsop() == JSOp::Eq || jsop() == JSOp::StrictEq) {
4954 return startsWith;
4955 }
4956
4957 // Invert for inequality.
4958 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"
, 4958); AnnotateMozCrashReason("MOZ_ASSERT" "(" "jsop() == JSOp::Ne || jsop() == JSOp::StrictNe"
")"); do { *((volatile int*)__null) = 4958; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4959
4960 block()->insertBefore(this, startsWith);
4961 return MNot::New(alloc, startsWith);
4962}
4963
4964MDefinition* MCompare::foldsTo(TempAllocator& alloc) {
4965 bool result;
4966
4967 if (tryFold(&result) || evaluateConstantOperands(alloc, &result)) {
4968 if (type() == MIRType::Int32) {
4969 return MConstant::New(alloc, Int32Value(result));
4970 }
4971
4972 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"
, 4972); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Boolean"
")"); do { *((volatile int*)__null) = 4972; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4973 return MConstant::New(alloc, BooleanValue(result));
4974 }
4975
4976 if (MDefinition* folded = tryFoldTypeOf(alloc); folded != this) {
4977 return folded;
4978 }
4979
4980 if (MDefinition* folded = tryFoldCharCompare(alloc); folded != this) {
4981 return folded;
4982 }
4983
4984 if (MDefinition* folded = tryFoldStringCompare(alloc); folded != this) {
4985 return folded;
4986 }
4987
4988 if (MDefinition* folded = tryFoldStringSubstring(alloc); folded != this) {
4989 return folded;
4990 }
4991
4992 if (MDefinition* folded = tryFoldStringIndexOf(alloc); folded != this) {
4993 return folded;
4994 }
4995
4996 return this;
4997}
4998
4999void MCompare::trySpecializeFloat32(TempAllocator& alloc) {
5000 if (AllOperandsCanProduceFloat32(this) && compareType_ == Compare_Double) {
5001 compareType_ = Compare_Float32;
5002 } else {
5003 ConvertOperandsToDouble(this, alloc);
5004 }
5005}
5006
5007MDefinition* MNot::foldsTo(TempAllocator& alloc) {
5008 // Fold if the input is constant
5009 if (MConstant* inputConst = input()->maybeConstantValue()) {
5010 bool b;
5011 if (inputConst->valueToBoolean(&b)) {
5012 if (type() == MIRType::Int32 || type() == MIRType::Int64) {
5013 return MConstant::New(alloc, Int32Value(!b));
5014 }
5015 return MConstant::New(alloc, BooleanValue(!b));
5016 }
5017 }
5018
5019 // If the operand of the Not is itself a Not, they cancel out. But we can't
5020 // always convert Not(Not(x)) to x because that may loose the conversion to
5021 // boolean. We can simplify Not(Not(Not(x))) to Not(x) though.
5022 MDefinition* op = getOperand(0);
5023 if (op->isNot()) {
5024 MDefinition* opop = op->getOperand(0);
5025 if (opop->isNot()) {
5026 return opop;
5027 }
5028 }
5029
5030 // Not of an undefined or null value is always true
5031 if (input()->type() == MIRType::Undefined ||
5032 input()->type() == MIRType::Null) {
5033 return MConstant::New(alloc, BooleanValue(true));
5034 }
5035
5036 // Not of a symbol is always false.
5037 if (input()->type() == MIRType::Symbol) {
5038 return MConstant::New(alloc, BooleanValue(false));
5039 }
5040
5041 return this;
5042}
5043
5044void MNot::trySpecializeFloat32(TempAllocator& alloc) {
5045 (void)EnsureFloatInputOrConvert(this, alloc);
5046}
5047
5048#ifdef JS_JITSPEW1
5049void MBeta::printOpcode(GenericPrinter& out) const {
5050 MDefinition::printOpcode(out);
5051
5052 out.printf(" ");
5053 comparison_->dump(out);
5054}
5055#endif
5056
5057AliasSet MCreateThis::getAliasSet() const {
5058 return AliasSet::Load(AliasSet::Any);
5059}
5060
5061bool MGetArgumentsObjectArg::congruentTo(const MDefinition* ins) const {
5062 if (!ins->isGetArgumentsObjectArg()) {
5063 return false;
5064 }
5065 if (ins->toGetArgumentsObjectArg()->argno() != argno()) {
5066 return false;
5067 }
5068 return congruentIfOperandsEqual(ins);
5069}
5070
5071AliasSet MGetArgumentsObjectArg::getAliasSet() const {
5072 return AliasSet::Load(AliasSet::Any);
5073}
5074
5075AliasSet MSetArgumentsObjectArg::getAliasSet() const {
5076 return AliasSet::Store(AliasSet::Any);
5077}
5078
5079MObjectState::MObjectState(MObjectState* state)
5080 : MVariadicInstruction(classOpcode),
5081 numSlots_(state->numSlots_),
5082 numFixedSlots_(state->numFixedSlots_) {
5083 // This instruction is only used as a summary for bailout paths.
5084 setResultType(MIRType::Object);
5085 setRecoveredOnBailout();
5086}
5087
5088MObjectState::MObjectState(JSObject* templateObject)
5089 : MObjectState(templateObject->as<NativeObject>().shape()) {}
5090
5091MObjectState::MObjectState(const Shape* shape)
5092 : MVariadicInstruction(classOpcode) {
5093 // This instruction is only used as a summary for bailout paths.
5094 setResultType(MIRType::Object);
5095 setRecoveredOnBailout();
5096
5097 numSlots_ = shape->asShared().slotSpan();
5098 numFixedSlots_ = shape->asShared().numFixedSlots();
5099}
5100
5101/* static */
5102JSObject* MObjectState::templateObjectOf(MDefinition* obj) {
5103 // MNewPlainObject uses a shape constant, not an object.
5104 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"
, 5104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!obj->isNewPlainObject()"
")"); do { *((volatile int*)__null) = 5104; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5105
5106 if (obj->isNewObject()) {
5107 return obj->toNewObject()->templateObject();
5108 } else if (obj->isNewCallObject()) {
5109 return obj->toNewCallObject()->templateObject();
5110 } else if (obj->isNewIterator()) {
5111 return obj->toNewIterator()->templateObject();
5112 }
5113
5114 MOZ_CRASH("unreachable")do { do { } while (false); MOZ_ReportCrash("" "unreachable", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5114); AnnotateMozCrashReason("MOZ_CRASH(" "unreachable" ")"
); do { *((volatile int*)__null) = 5114; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
5115}
5116
5117bool MObjectState::init(TempAllocator& alloc, MDefinition* obj) {
5118 if (!MVariadicInstruction::init(alloc, numSlots() + 1)) {
5119 return false;
5120 }
5121 // +1, for the Object.
5122 initOperand(0, obj);
5123 return true;
5124}
5125
5126void MObjectState::initFromTemplateObject(TempAllocator& alloc,
5127 MDefinition* undefinedVal) {
5128 if (object()->isNewPlainObject()) {
5129 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"
, 5130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()"
")"); do { *((volatile int*)__null) = 5130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5130 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"
, 5130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "object()->toNewPlainObject()->shape()->asShared().slotSpan() == numSlots()"
")"); do { *((volatile int*)__null) = 5130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5131 for (size_t i = 0; i < numSlots(); i++) {
5132 initSlot(i, undefinedVal);
5133 }
5134 return;
5135 }
5136
5137 JSObject* templateObject = templateObjectOf(object());
5138
5139 // Initialize all the slots of the object state with the value contained in
5140 // the template object. This is needed to account values which are baked in
5141 // the template objects and not visible in IonMonkey, such as the
5142 // uninitialized-lexical magic value of call objects.
5143
5144 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"
, 5144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject->is<NativeObject>()"
")"); do { *((volatile int*)__null) = 5144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5145 NativeObject& nativeObject = templateObject->as<NativeObject>();
5146 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"
, 5146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nativeObject.slotSpan() == numSlots()"
")"); do { *((volatile int*)__null) = 5146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5147
5148 for (size_t i = 0; i < numSlots(); i++) {
5149 Value val = nativeObject.getSlot(i);
5150 MDefinition* def = undefinedVal;
5151 if (!val.isUndefined()) {
5152 MConstant* ins = MConstant::New(alloc, val);
5153 block()->insertBefore(this, ins);
5154 def = ins;
5155 }
5156 initSlot(i, def);
5157 }
5158}
5159
5160MObjectState* MObjectState::New(TempAllocator& alloc, MDefinition* obj) {
5161 MObjectState* res;
5162 if (obj->isNewPlainObject()) {
5163 const Shape* shape = obj->toNewPlainObject()->shape();
5164 res = new (alloc) MObjectState(shape);
5165 } else {
5166 JSObject* templateObject = templateObjectOf(obj);
5167 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"
, 5167); AnnotateMozCrashReason("MOZ_ASSERT" "(" "templateObject"
") (" "Unexpected object creation." ")"); do { *((volatile int
*)__null) = 5167; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5168 res = new (alloc) MObjectState(templateObject);
5169 }
5170
5171 if (!res || !res->init(alloc, obj)) {
5172 return nullptr;
5173 }
5174 return res;
5175}
5176
5177MObjectState* MObjectState::Copy(TempAllocator& alloc, MObjectState* state) {
5178 MObjectState* res = new (alloc) MObjectState(state);
5179 if (!res || !res->init(alloc, state->object())) {
5180 return nullptr;
5181 }
5182 for (size_t i = 0; i < res->numSlots(); i++) {
5183 res->initSlot(i, state->getSlot(i));
5184 }
5185 return res;
5186}
5187
5188MArrayState::MArrayState(MDefinition* arr) : MVariadicInstruction(classOpcode) {
5189 // This instruction is only used as a summary for bailout paths.
5190 setResultType(MIRType::Object);
5191 setRecoveredOnBailout();
5192 if (arr->isNewArrayObject()) {
5193 numElements_ = arr->toNewArrayObject()->length();
5194 } else {
5195 numElements_ = arr->toNewArray()->length();
5196 }
5197}
5198
5199bool MArrayState::init(TempAllocator& alloc, MDefinition* obj,
5200 MDefinition* len) {
5201 if (!MVariadicInstruction::init(alloc, numElements() + 2)) {
5202 return false;
5203 }
5204 // +1, for the Array object.
5205 initOperand(0, obj);
5206 // +1, for the length value of the array.
5207 initOperand(1, len);
5208 return true;
5209}
5210
5211void MArrayState::initFromTemplateObject(TempAllocator& alloc,
5212 MDefinition* undefinedVal) {
5213 for (size_t i = 0; i < numElements(); i++) {
5214 initElement(i, undefinedVal);
5215 }
5216}
5217
5218MArrayState* MArrayState::New(TempAllocator& alloc, MDefinition* arr,
5219 MDefinition* initLength) {
5220 MArrayState* res = new (alloc) MArrayState(arr);
5221 if (!res || !res->init(alloc, arr, initLength)) {
5222 return nullptr;
5223 }
5224 return res;
5225}
5226
5227MArrayState* MArrayState::Copy(TempAllocator& alloc, MArrayState* state) {
5228 MDefinition* arr = state->array();
5229 MDefinition* len = state->initializedLength();
5230 MArrayState* res = new (alloc) MArrayState(arr);
5231 if (!res || !res->init(alloc, arr, len)) {
5232 return nullptr;
5233 }
5234 for (size_t i = 0; i < res->numElements(); i++) {
5235 res->initElement(i, state->getElement(i));
5236 }
5237 return res;
5238}
5239
5240MNewArray::MNewArray(uint32_t length, MConstant* templateConst,
5241 gc::Heap initialHeap, bool vmCall)
5242 : MUnaryInstruction(classOpcode, templateConst),
5243 length_(length),
5244 initialHeap_(initialHeap),
5245 vmCall_(vmCall) {
5246 setResultType(MIRType::Object);
5247}
5248
5249MDefinition::AliasType MLoadFixedSlot::mightAlias(
5250 const MDefinition* def) const {
5251 if (def->isStoreFixedSlot()) {
5252 const MStoreFixedSlot* store = def->toStoreFixedSlot();
5253 if (store->slot() != slot()) {
5254 return AliasType::NoAlias;
5255 }
5256 if (store->object() != object()) {
5257 return AliasType::MayAlias;
5258 }
5259 return AliasType::MustAlias;
5260 }
5261 return AliasType::MayAlias;
5262}
5263
5264MDefinition* MLoadFixedSlot::foldsTo(TempAllocator& alloc) {
5265 if (MDefinition* def = foldsToStore(alloc)) {
5266 return def;
5267 }
5268
5269 return this;
5270}
5271
5272MDefinition::AliasType MLoadFixedSlotAndUnbox::mightAlias(
5273 const MDefinition* def) const {
5274 if (def->isStoreFixedSlot()) {
5275 const MStoreFixedSlot* store = def->toStoreFixedSlot();
5276 if (store->slot() != slot()) {
5277 return AliasType::NoAlias;
5278 }
5279 if (store->object() != object()) {
5280 return AliasType::MayAlias;
5281 }
5282 return AliasType::MustAlias;
5283 }
5284 return AliasType::MayAlias;
5285}
5286
5287MDefinition* MLoadFixedSlotAndUnbox::foldsTo(TempAllocator& alloc) {
5288 if (MDefinition* def = foldsToStore(alloc)) {
5289 return def;
5290 }
5291
5292 return this;
5293}
5294
5295MDefinition* MWasmExtendU32Index::foldsTo(TempAllocator& alloc) {
5296 MDefinition* input = this->input();
5297 if (input->isConstant()) {
5298 return MConstant::NewInt64(
5299 alloc, int64_t(uint32_t(input->toConstant()->toInt32())));
5300 }
5301
5302 return this;
5303}
5304
5305MDefinition* MWasmWrapU32Index::foldsTo(TempAllocator& alloc) {
5306 MDefinition* input = this->input();
5307 if (input->isConstant()) {
5308 return MConstant::New(
5309 alloc, Int32Value(int32_t(uint32_t(input->toConstant()->toInt64()))));
5310 }
5311
5312 return this;
5313}
5314
5315// Some helpers for folding wasm and/or/xor on int32/64 values. Rather than
5316// duplicating these for 32 and 64-bit values, all folding is done on 64-bit
5317// values and masked for the 32-bit case.
5318
5319const uint64_t Low32Mask = uint64_t(0xFFFFFFFFULL);
5320
5321// Routines to check and disassemble values.
5322
5323static bool IsIntegralConstant(const MDefinition* def) {
5324 return def->isConstant() &&
5325 (def->type() == MIRType::Int32 || def->type() == MIRType::Int64);
5326}
5327
5328static uint64_t GetIntegralConstant(const MDefinition* def) {
5329 if (def->type() == MIRType::Int32) {
5330 return uint64_t(def->toConstant()->toInt32()) & Low32Mask;
5331 }
5332 return uint64_t(def->toConstant()->toInt64());
5333}
5334
5335static bool IsIntegralConstantZero(const MDefinition* def) {
5336 return IsIntegralConstant(def) && GetIntegralConstant(def) == 0;
5337}
5338
5339static bool IsIntegralConstantOnes(const MDefinition* def) {
5340 uint64_t ones = def->type() == MIRType::Int32 ? Low32Mask : ~uint64_t(0);
5341 return IsIntegralConstant(def) && GetIntegralConstant(def) == ones;
5342}
5343
5344// Routines to create values.
5345static MDefinition* ToIntegralConstant(TempAllocator& alloc, MIRType ty,
5346 uint64_t val) {
5347 switch (ty) {
5348 case MIRType::Int32:
5349 return MConstant::New(alloc,
5350 Int32Value(int32_t(uint32_t(val & Low32Mask))));
5351 case MIRType::Int64:
5352 return MConstant::NewInt64(alloc, int64_t(val));
5353 default:
5354 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5354); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 5354; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
5355 }
5356}
5357
5358static MDefinition* ZeroOfType(TempAllocator& alloc, MIRType ty) {
5359 return ToIntegralConstant(alloc, ty, 0);
5360}
5361
5362static MDefinition* OnesOfType(TempAllocator& alloc, MIRType ty) {
5363 return ToIntegralConstant(alloc, ty, ~uint64_t(0));
5364}
5365
5366MDefinition* MWasmBinaryBitwise::foldsTo(TempAllocator& alloc) {
5367 MOZ_ASSERT(op() == Opcode::WasmBinaryBitwise)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(op() == Opcode::WasmBinaryBitwise)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(op() == Opcode::WasmBinaryBitwise
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"op() == Opcode::WasmBinaryBitwise", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5367); AnnotateMozCrashReason("MOZ_ASSERT" "(" "op() == Opcode::WasmBinaryBitwise"
")"); do { *((volatile int*)__null) = 5367; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5368 MOZ_ASSERT(type() == MIRType::Int32 || type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(type() == MIRType::Int32 || type() == MIRType::Int64
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(type() == MIRType::Int32 || type() == MIRType::Int64
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"type() == MIRType::Int32 || type() == MIRType::Int64", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5368); AnnotateMozCrashReason("MOZ_ASSERT" "(" "type() == MIRType::Int32 || type() == MIRType::Int64"
")"); do { *((volatile int*)__null) = 5368; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5369
5370 MDefinition* argL = getOperand(0);
5371 MDefinition* argR = getOperand(1);
5372 MOZ_ASSERT(argL->type() == type() && argR->type() == type())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(argL->type() == type() && argR->type()
== type())>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(argL->type() == type() &&
argR->type() == type()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("argL->type() == type() && argR->type() == type()"
, "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "argL->type() == type() && argR->type() == type()"
")"); do { *((volatile int*)__null) = 5372; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5373
5374 // The args are the same (SSA name)
5375 if (argL == argR) {
5376 switch (subOpcode()) {
5377 case SubOpcode::And:
5378 case SubOpcode::Or:
5379 return argL;
5380 case SubOpcode::Xor:
5381 return ZeroOfType(alloc, type());
5382 default:
5383 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5383); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 5383; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
5384 }
5385 }
5386
5387 // Both args constant
5388 if (IsIntegralConstant(argL) && IsIntegralConstant(argR)) {
5389 uint64_t valL = GetIntegralConstant(argL);
5390 uint64_t valR = GetIntegralConstant(argR);
5391 uint64_t val = valL;
5392 switch (subOpcode()) {
5393 case SubOpcode::And:
5394 val &= valR;
5395 break;
5396 case SubOpcode::Or:
5397 val |= valR;
5398 break;
5399 case SubOpcode::Xor:
5400 val ^= valR;
5401 break;
5402 default:
5403 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5403); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 5403; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
5404 }
5405 return ToIntegralConstant(alloc, type(), val);
5406 }
5407
5408 // Left arg is zero
5409 if (IsIntegralConstantZero(argL)) {
5410 switch (subOpcode()) {
5411 case SubOpcode::And:
5412 return ZeroOfType(alloc, type());
5413 case SubOpcode::Or:
5414 case SubOpcode::Xor:
5415 return argR;
5416 default:
5417 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5417); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 5417; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
5418 }
5419 }
5420
5421 // Right arg is zero
5422 if (IsIntegralConstantZero(argR)) {
5423 switch (subOpcode()) {
5424 case SubOpcode::And:
5425 return ZeroOfType(alloc, type());
5426 case SubOpcode::Or:
5427 case SubOpcode::Xor:
5428 return argL;
5429 default:
5430 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5430); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 5430; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
5431 }
5432 }
5433
5434 // Left arg is ones
5435 if (IsIntegralConstantOnes(argL)) {
5436 switch (subOpcode()) {
5437 case SubOpcode::And:
5438 return argR;
5439 case SubOpcode::Or:
5440 return OnesOfType(alloc, type());
5441 case SubOpcode::Xor:
5442 return MBitNot::New(alloc, argR);
5443 default:
5444 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5444); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 5444; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
5445 }
5446 }
5447
5448 // Right arg is ones
5449 if (IsIntegralConstantOnes(argR)) {
5450 switch (subOpcode()) {
5451 case SubOpcode::And:
5452 return argL;
5453 case SubOpcode::Or:
5454 return OnesOfType(alloc, type());
5455 case SubOpcode::Xor:
5456 return MBitNot::New(alloc, argL);
5457 default:
5458 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5458); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 5458; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
5459 }
5460 }
5461
5462 return this;
5463}
5464
5465MDefinition* MWasmAddOffset::foldsTo(TempAllocator& alloc) {
5466 MDefinition* baseArg = base();
5467 if (!baseArg->isConstant()) {
5468 return this;
5469 }
5470
5471 if (baseArg->type() == MIRType::Int32) {
5472 CheckedInt<uint32_t> ptr = baseArg->toConstant()->toInt32();
5473 ptr += offset();
5474 if (!ptr.isValid()) {
5475 return this;
5476 }
5477 return MConstant::New(alloc, Int32Value(ptr.value()));
5478 }
5479
5480 MOZ_ASSERT(baseArg->type() == MIRType::Int64)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(baseArg->type() == MIRType::Int64)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(baseArg->type() == MIRType
::Int64))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("baseArg->type() == MIRType::Int64", "/var/lib/jenkins/workspace/firefox-scan-build/js/src/jit/MIR.cpp"
, 5480); AnnotateMozCrashReason("MOZ_ASSERT" "(" "baseArg->type() == MIRType::Int64"
")"); do { *((volatile int*)__null) = 5480; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5481 CheckedInt<uint64_t> ptr = baseArg->toConstant()->toInt64();
5482 ptr += offset();
5483 if (!ptr.isValid()) {
5484 return this;
5485 }
5486 return MConstant::NewInt64(alloc, ptr.value());
5487}
5488
5489bool MWasmAlignmentCheck::congruentTo(const MDefinition* ins) const {
5490 if (!ins->isWasmAlignmentCheck()) {
5491 return false;
5492 }
5493 const MWasmAlignmentCheck* check = ins->toWasmAlignmentCheck();
5494 return byteSize_ == check->byteSize() && congruentIfOperandsEqual(check);
5495}
5496
5497MDefinition::AliasType MAsmJSLoadHeap::mightAlias(
5498 const MDefinition* def) const {
5499 if (def->isAsmJSStoreHeap()) {
5500 const MAsmJSStoreHeap* store = def->toAsmJSStoreHeap();
5501 if (store->accessType() != accessType()) {
5502 return AliasType::MayAlias;
5503 }
5504 if (!base()->isConstant() || !store->base()->isConstant()) {
5505 return AliasType::MayAlias;
5506 }
5507 const MConstant* otherBase = store->base()->toConstant();
5508 if (base()->toConstant()->equals(otherBase)) {
5509 return AliasType::MayAlias;
5510 }
5511 return AliasType::NoAlias;
5512 }
5513 return AliasType::MayAlias;
5514}
5515
5516bool MAsmJSLoadHeap::congruentTo(const MDefinition* ins) const {
5517 if (!ins->isAsmJSLoadHeap()) {
5518 return false;
5519 }
5520 const MAsmJSLoadHeap* load = ins->toAsmJSLoadHeap();
5521 return load->accessType() == accessType() && congruentIfOperandsEqual(load);
5522}
5523
5524MDefinition::AliasType MWasmLoadInstanceDataField::mightAlias(
5525 const MDefinition* def) const {
5526 if (def->isWasmStoreInstanceDataField()) {
5527 const MWasmStoreInstanceDataField* store =
5528 def->toWasmStoreInstanceDataField();
5529 return store->instanceDataOffset() == instanceDataOffset_
5530 ? AliasType::MayAlias
5531 : AliasType::NoAlias;
5532 }
5533
5534 return AliasType::MayAlias;
5535}
5536
5537MDefinition::AliasType MWasmLoadGlobalCell::mightAlias(
5538 const MDefinition* def) const {
5539 if (def->isWasmStoreGlobalCell()) {
5540 // No globals of different type can alias. See bug 1467415 comment 3.
5541 if (type() != def->toWasmStoreGlobalCell()->value()->type()) {
5542 return AliasType::NoAlias;
5543 }
5544
5545 // We could do better here. We're dealing with two indirect globals.
5546 // If at at least one of them is created in this module, then they
5547 // can't alias -- in other words they can only alias if they are both
5548 // imported. That would require having a flag on globals to indicate
5549 // which are imported. See bug 1467415 comment 3, 4th rule.
5550 }
5551
5552 return AliasType::MayAlias;
5553}
5554
5555HashNumber MWasmLoadInstanceDataField::valueHash() const {
5556 // Same comment as in MWasmLoadInstanceDataField::congruentTo() applies here.
5557 HashNumber hash = MDefinition::valueHash();
5558 hash = addU32ToHash(hash, instanceDataOffset_);
5559 return hash;
5560}
5561
5562bool MWasmLoadInstanceDataField::congruentTo(const