diff options
Diffstat (limited to 'js/src/jit/MIR.h')
-rw-r--r-- | js/src/jit/MIR.h | 213 |
1 files changed, 150 insertions, 63 deletions
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 07701847eb..d882665a65 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -421,10 +421,13 @@ class AliasSet { // The generation counter associated with the global object GlobalGenerationCounter = 1 << 26, - Last = GlobalGenerationCounter, + // The SharedArrayRawBuffer::length field. + SharedArrayRawBufferLength = 1 << 27, + + Last = SharedArrayRawBufferLength, Any = Last | (Last - 1), - NumCategories = 27, + NumCategories = 28, // Indicates load or store. Store_ = 1 << 31 @@ -657,7 +660,13 @@ class MDefinition : public MNode { virtual HashNumber valueHash() const; virtual bool congruentTo(const MDefinition* ins) const { return false; } const MDefinition* skipObjectGuards() const; + + // Note that, for a call `congruentIfOperandsEqual(ins)` inside some class + // MFoo, if `true` is returned then we are ensured that `ins` is also an + // MFoo, so it is safe to do `ins->toMFoo()` without first checking whether + // `ins->isMFoo()`. bool congruentIfOperandsEqual(const MDefinition* ins) const; + virtual MDefinition* foldsTo(TempAllocator& alloc); virtual void analyzeEdgeCasesForward(); virtual void analyzeEdgeCasesBackward(); @@ -1277,6 +1286,35 @@ class MVariadicT : public T { // initializes the operands_ array and must be checked for OOM. using MVariadicInstruction = MVariadicT<MInstruction>; +// All barriered operations: +// - MCompareExchangeTypedArrayElement +// - MExchangeTypedArrayElement +// - MAtomicTypedArrayElementBinop +// - MGrowableSharedArrayBufferByteLength +// +// And operations which are optionally barriered: +// - MLoadUnboxedScalar +// - MStoreUnboxedScalar +// - MResizableTypedArrayLength +// - MResizableDataViewByteLength +// +// Must have the following attributes: +// +// - Not movable +// - Not removable +// - Not congruent with any other instruction +// - Effectful (they alias every TypedArray store) +// +// The intended effect of those constraints is to prevent all loads and stores +// preceding the barriered operation from being moved to after the barriered +// operation, and vice versa, and to prevent the barriered operation from being +// removed or hoisted. + +enum class MemoryBarrierRequirement : bool { + NotRequired, + Required, +}; + MIR_OPCODE_CLASS_GENERATED // Truncation barrier. This is intended for protecting its input against @@ -7040,44 +7078,22 @@ class MArrayPopShift : public MUnaryInstruction, ALLOW_CLONE(MArrayPopShift) }; -// All barriered operations - MCompareExchangeTypedArrayElement, -// MExchangeTypedArrayElement, and MAtomicTypedArrayElementBinop, as -// well as MLoadUnboxedScalar and MStoreUnboxedScalar when they are -// marked as requiring a memory barrer - have the following -// attributes: -// -// - Not movable -// - Not removable -// - Not congruent with any other instruction -// - Effectful (they alias every TypedArray store) -// -// The intended effect of those constraints is to prevent all loads -// and stores preceding the barriered operation from being moved to -// after the barriered operation, and vice versa, and to prevent the -// barriered operation from being removed or hoisted. - -enum MemoryBarrierRequirement { - DoesNotRequireMemoryBarrier, - DoesRequireMemoryBarrier -}; - -// Also see comments at MMemoryBarrierRequirement, above. - // Load an unboxed scalar value from an array buffer view or other object. class MLoadUnboxedScalar : public MBinaryInstruction, public NoTypePolicy::Data { int32_t offsetAdjustment_ = 0; Scalar::Type storageType_; - bool requiresBarrier_; + MemoryBarrierRequirement requiresBarrier_; - MLoadUnboxedScalar( - MDefinition* elements, MDefinition* index, Scalar::Type storageType, - MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier) + MLoadUnboxedScalar(MDefinition* elements, MDefinition* index, + Scalar::Type storageType, + MemoryBarrierRequirement requiresBarrier = + MemoryBarrierRequirement::NotRequired) : MBinaryInstruction(classOpcode, elements, index), storageType_(storageType), - requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier) { + requiresBarrier_(requiresBarrier) { setResultType(MIRType::Value); - if (requiresBarrier_) { + if (requiresBarrier_ == MemoryBarrierRequirement::Required) { setGuard(); // Not removable or movable } else { setMovable(); @@ -7097,7 +7113,7 @@ class MLoadUnboxedScalar : public MBinaryInstruction, // Bailout if the result does not fit in an int32. return storageType_ == Scalar::Uint32 && type() == MIRType::Int32; } - bool requiresMemoryBarrier() const { return requiresBarrier_; } + auto requiresMemoryBarrier() const { return requiresBarrier_; } int32_t offsetAdjustment() const { return offsetAdjustment_; } void setOffsetAdjustment(int32_t offsetAdjustment) { offsetAdjustment_ = offsetAdjustment; @@ -7105,14 +7121,14 @@ class MLoadUnboxedScalar : public MBinaryInstruction, AliasSet getAliasSet() const override { // When a barrier is needed make the instruction effectful by // giving it a "store" effect. - if (requiresBarrier_) { + if (requiresBarrier_ == MemoryBarrierRequirement::Required) { return AliasSet::Store(AliasSet::UnboxedElement); } return AliasSet::Load(AliasSet::UnboxedElement); } bool congruentTo(const MDefinition* ins) const override { - if (requiresBarrier_) { + if (requiresBarrier_ == MemoryBarrierRequirement::Required) { return false; } if (!ins->isLoadUnboxedScalar()) { @@ -7198,26 +7214,29 @@ class MLoadDataViewElement : public MTernaryInstruction, }; // Load a value from a typed array. Out-of-bounds accesses are handled in-line. -class MLoadTypedArrayElementHole : public MBinaryInstruction, - public SingleObjectPolicy::Data { +class MLoadTypedArrayElementHole : public MTernaryInstruction, + public NoTypePolicy::Data { Scalar::Type arrayType_; bool forceDouble_; - MLoadTypedArrayElementHole(MDefinition* object, MDefinition* index, - Scalar::Type arrayType, bool forceDouble) - : MBinaryInstruction(classOpcode, object, index), + MLoadTypedArrayElementHole(MDefinition* elements, MDefinition* index, + MDefinition* length, Scalar::Type arrayType, + bool forceDouble) + : MTernaryInstruction(classOpcode, elements, index, length), arrayType_(arrayType), forceDouble_(forceDouble) { setResultType(MIRType::Value); setMovable(); + MOZ_ASSERT(elements->type() == MIRType::Elements); MOZ_ASSERT(index->type() == MIRType::IntPtr); + MOZ_ASSERT(length->type() == MIRType::IntPtr); MOZ_ASSERT(arrayType >= 0 && arrayType < Scalar::MaxTypedArrayViewType); } public: INSTRUCTION_HEADER(LoadTypedArrayElementHole) TRIVIAL_NEW_WRAPPERS - NAMED_OPERANDS((0, object), (1, index)) + NAMED_OPERANDS((0, elements), (1, index), (2, length)) Scalar::Type arrayType() const { return arrayType_; } bool forceDouble() const { return forceDouble_; } @@ -7239,8 +7258,7 @@ class MLoadTypedArrayElementHole : public MBinaryInstruction, return congruentIfOperandsEqual(other); } AliasSet getAliasSet() const override { - return AliasSet::Load(AliasSet::UnboxedElement | AliasSet::ObjectFields | - AliasSet::ArrayBufferViewLengthOrOffset); + return AliasSet::Load(AliasSet::UnboxedElement); } bool canProduceFloat32() const override { return arrayType_ == Scalar::Float32; @@ -7280,16 +7298,16 @@ class StoreUnboxedScalarBase { class MStoreUnboxedScalar : public MTernaryInstruction, public StoreUnboxedScalarBase, public StoreUnboxedScalarPolicy::Data { - bool requiresBarrier_; + MemoryBarrierRequirement requiresBarrier_; - MStoreUnboxedScalar( - MDefinition* elements, MDefinition* index, MDefinition* value, - Scalar::Type storageType, - MemoryBarrierRequirement requiresBarrier = DoesNotRequireMemoryBarrier) + MStoreUnboxedScalar(MDefinition* elements, MDefinition* index, + MDefinition* value, Scalar::Type storageType, + MemoryBarrierRequirement requiresBarrier = + MemoryBarrierRequirement::NotRequired) : MTernaryInstruction(classOpcode, elements, index, value), StoreUnboxedScalarBase(storageType), - requiresBarrier_(requiresBarrier == DoesRequireMemoryBarrier) { - if (requiresBarrier_) { + requiresBarrier_(requiresBarrier) { + if (requiresBarrier_ == MemoryBarrierRequirement::Required) { setGuard(); // Not removable or movable } MOZ_ASSERT(elements->type() == MIRType::Elements); @@ -7305,7 +7323,7 @@ class MStoreUnboxedScalar : public MTernaryInstruction, AliasSet getAliasSet() const override { return AliasSet::Store(AliasSet::UnboxedElement); } - bool requiresMemoryBarrier() const { return requiresBarrier_; } + auto requiresMemoryBarrier() const { return requiresBarrier_; } TruncateKind operandTruncateKind(size_t index) const override; bool canConsumeFloat32(MUse* use) const override { @@ -8997,6 +9015,55 @@ class MGuardToClass : public MUnaryInstruction, } }; +class MGuardToEitherClass : public MUnaryInstruction, + public SingleObjectPolicy::Data { + const JSClass* class1_; + const JSClass* class2_; + + MGuardToEitherClass(MDefinition* object, const JSClass* clasp1, + const JSClass* clasp2) + : MUnaryInstruction(classOpcode, object), + class1_(clasp1), + class2_(clasp2) { + MOZ_ASSERT(object->type() == MIRType::Object); + MOZ_ASSERT(clasp1 != clasp2, "Use MGuardToClass instead"); + MOZ_ASSERT(!clasp1->isJSFunction(), "Use MGuardToFunction instead"); + MOZ_ASSERT(!clasp2->isJSFunction(), "Use MGuardToFunction instead"); + setResultType(MIRType::Object); + setMovable(); + + // We will bail out if the class type is incorrect, so we need to ensure we + // don't eliminate this instruction + setGuard(); + } + + public: + INSTRUCTION_HEADER(GuardToEitherClass) + TRIVIAL_NEW_WRAPPERS + NAMED_OPERANDS((0, object)) + + const JSClass* getClass1() const { return class1_; } + const JSClass* getClass2() const { return class2_; } + + MDefinition* foldsTo(TempAllocator& alloc) override; + AliasSet getAliasSet() const override { return AliasSet::None(); } + bool congruentTo(const MDefinition* ins) const override { + if (!ins->isGuardToEitherClass()) { + return false; + } + const auto* other = ins->toGuardToEitherClass(); + if (getClass1() != other->getClass1() && + getClass1() != other->getClass2()) { + return false; + } + if (getClass2() != other->getClass1() && + getClass2() != other->getClass2()) { + return false; + } + return congruentIfOperandsEqual(ins); + } +}; + class MGuardToFunction : public MUnaryInstruction, public SingleObjectPolicy::Data { explicit MGuardToFunction(MDefinition* object) @@ -9337,6 +9404,23 @@ class MObjectToIterator : public MUnaryInstruction, void setWantsIndices(bool value) { wantsIndices_ = value; } }; +class MPostIntPtrConversion : public MUnaryInstruction, + public NoTypePolicy::Data { + explicit MPostIntPtrConversion(MDefinition* input) + : MUnaryInstruction(classOpcode, input) { + // Passes through the input. + setResultType(input->type()); + + // Note: Must be non-movable so we can attach a resume point. + } + + public: + INSTRUCTION_HEADER(PostIntPtrConversion) + TRIVIAL_NEW_WRAPPERS + + AliasSet getAliasSet() const override { return AliasSet::None(); } +}; + // Flips the input's sign bit, independently of the rest of the number's // payload. Note this is different from multiplying by minus-one, which has // side-effects for e.g. NaNs. @@ -10808,6 +10892,8 @@ class MWasmReinterpret : public MUnaryInstruction, public NoTypePolicy::Data { AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { + // No need to check type() here, because congruentIfOperandsEqual will + // check it. return congruentIfOperandsEqual(ins); } @@ -10867,7 +10953,8 @@ class MWasmTernarySimd128 : public MTernaryInstruction, AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { - return congruentIfOperandsEqual(ins); + return congruentIfOperandsEqual(ins) && + simdOp() == ins->toWasmTernarySimd128()->simdOp(); } #ifdef ENABLE_WASM_SIMD MDefinition* foldsTo(TempAllocator& alloc) override; @@ -10908,8 +10995,8 @@ class MWasmBinarySimd128 : public MBinaryInstruction, AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { - return ins->toWasmBinarySimd128()->simdOp() == simdOp_ && - congruentIfOperandsEqual(ins); + return congruentIfOperandsEqual(ins) && + ins->toWasmBinarySimd128()->simdOp() == simdOp_; } #ifdef ENABLE_WASM_SIMD MDefinition* foldsTo(TempAllocator& alloc) override; @@ -10945,8 +11032,8 @@ class MWasmBinarySimd128WithConstant : public MUnaryInstruction, AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { - return ins->toWasmBinarySimd128WithConstant()->simdOp() == simdOp_ && - congruentIfOperandsEqual(ins) && + return congruentIfOperandsEqual(ins) && + ins->toWasmBinarySimd128WithConstant()->simdOp() == simdOp_ && rhs_.bitwiseEqual(ins->toWasmBinarySimd128WithConstant()->rhs()); } @@ -10978,9 +11065,9 @@ class MWasmReplaceLaneSimd128 : public MBinaryInstruction, AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { - return ins->toWasmReplaceLaneSimd128()->simdOp() == simdOp_ && - ins->toWasmReplaceLaneSimd128()->laneIndex() == laneIndex_ && - congruentIfOperandsEqual(ins); + return congruentIfOperandsEqual(ins) && + ins->toWasmReplaceLaneSimd128()->simdOp() == simdOp_ && + ins->toWasmReplaceLaneSimd128()->laneIndex() == laneIndex_; } uint32_t laneIndex() const { return laneIndex_; } @@ -11006,8 +11093,8 @@ class MWasmScalarToSimd128 : public MUnaryInstruction, AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { - return ins->toWasmScalarToSimd128()->simdOp() == simdOp_ && - congruentIfOperandsEqual(ins); + return congruentIfOperandsEqual(ins) && + ins->toWasmScalarToSimd128()->simdOp() == simdOp_; } #ifdef ENABLE_WASM_SIMD MDefinition* foldsTo(TempAllocator& alloc) override; @@ -11036,9 +11123,9 @@ class MWasmReduceSimd128 : public MUnaryInstruction, public NoTypePolicy::Data { AliasSet getAliasSet() const override { return AliasSet::None(); } bool congruentTo(const MDefinition* ins) const override { - return ins->toWasmReduceSimd128()->simdOp() == simdOp_ && - ins->toWasmReduceSimd128()->imm() == imm_ && - congruentIfOperandsEqual(ins); + return congruentIfOperandsEqual(ins) && + ins->toWasmReduceSimd128()->simdOp() == simdOp_ && + ins->toWasmReduceSimd128()->imm() == imm_; } #ifdef ENABLE_WASM_SIMD MDefinition* foldsTo(TempAllocator& alloc) override; |