Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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