summaryrefslogtreecommitdiffstats
path: root/js/src/jit/MIR.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/MIR.h')
-rw-r--r--js/src/jit/MIR.h213
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;