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.h340
1 files changed, 318 insertions, 22 deletions
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 0c1e77f80..af0abc695 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -30,6 +30,7 @@
#include "vm/EnvironmentObject.h"
#include "vm/SharedMem.h"
#include "vm/TypedArrayCommon.h"
+#include "vm/UnboxedObject.h"
// Undo windows.h damage on Win64
#undef MemoryBarrier
@@ -375,7 +376,8 @@ class AliasSet {
Element = 1 << 1, // A Value member of obj->elements or
// a typed object.
UnboxedElement = 1 << 2, // An unboxed scalar or reference member of
- // typed object.
+ // a typed array, typed object, or unboxed
+ // object.
DynamicSlot = 1 << 3, // A Value member of obj->slots.
FixedSlot = 1 << 4, // A Value member of obj->fixedSlots().
DOMProperty = 1 << 5, // A DOM property
@@ -432,6 +434,9 @@ class AliasSet {
MOZ_ASSERT(flags && !(flags & Store_));
return AliasSet(flags | Store_);
}
+ static uint32_t BoxedOrUnboxedElements(JSValueType type) {
+ return (type == JSVAL_TYPE_MAGIC) ? Element : UnboxedElement;
+ }
};
typedef Vector<MDefinition*, 6, JitAllocPolicy> MDefinitionVector;
@@ -3758,9 +3763,14 @@ class MObjectState
{
private:
uint32_t numSlots_;
- uint32_t numFixedSlots_;
+ uint32_t numFixedSlots_; // valid if isUnboxed() == false.
+ OperandIndexMap* operandIndex_; // valid if isUnboxed() == true.
+
+ bool isUnboxed() const {
+ return operandIndex_ != nullptr;
+ }
- MObjectState(JSObject *templateObject);
+ MObjectState(JSObject *templateObject, OperandIndexMap* operandIndex);
explicit MObjectState(MObjectState* state);
MOZ_MUST_USE bool init(TempAllocator& alloc, MDefinition* obj);
@@ -3820,6 +3830,18 @@ class MObjectState
setSlot(slot + numFixedSlots(), def);
}
+ // Interface reserved for unboxed objects.
+ bool hasOffset(uint32_t offset) const {
+ MOZ_ASSERT(isUnboxed());
+ return offset < operandIndex_->map.length() && operandIndex_->map[offset] != 0;
+ }
+ MDefinition* getOffset(uint32_t offset) const {
+ return getOperand(operandIndex_->map[offset]);
+ }
+ void setOffset(uint32_t offset, MDefinition* def) {
+ replaceOperand(operandIndex_->map[offset], def);
+ }
+
MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
bool canRecoverOnBailout() const override {
return true;
@@ -8741,6 +8763,102 @@ class MSetInitializedLength
ALLOW_CLONE(MSetInitializedLength)
};
+// Load the length from an unboxed array.
+class MUnboxedArrayLength
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ explicit MUnboxedArrayLength(MDefinition* object)
+ : MUnaryInstruction(object)
+ {
+ setResultType(MIRType::Int32);
+ setMovable();
+ }
+
+ public:
+ INSTRUCTION_HEADER(UnboxedArrayLength)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, object))
+
+ bool congruentTo(const MDefinition* ins) const override {
+ return congruentIfOperandsEqual(ins);
+ }
+ AliasSet getAliasSet() const override {
+ return AliasSet::Load(AliasSet::ObjectFields);
+ }
+
+ ALLOW_CLONE(MUnboxedArrayLength)
+};
+
+// Load the initialized length from an unboxed array.
+class MUnboxedArrayInitializedLength
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ explicit MUnboxedArrayInitializedLength(MDefinition* object)
+ : MUnaryInstruction(object)
+ {
+ setResultType(MIRType::Int32);
+ setMovable();
+ }
+
+ public:
+ INSTRUCTION_HEADER(UnboxedArrayInitializedLength)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, object))
+
+ bool congruentTo(const MDefinition* ins) const override {
+ return congruentIfOperandsEqual(ins);
+ }
+ AliasSet getAliasSet() const override {
+ return AliasSet::Load(AliasSet::ObjectFields);
+ }
+
+ ALLOW_CLONE(MUnboxedArrayInitializedLength)
+};
+
+// Increment the initialized length of an unboxed array object.
+class MIncrementUnboxedArrayInitializedLength
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ explicit MIncrementUnboxedArrayInitializedLength(MDefinition* obj)
+ : MUnaryInstruction(obj)
+ {}
+
+ public:
+ INSTRUCTION_HEADER(IncrementUnboxedArrayInitializedLength)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, object))
+
+ AliasSet getAliasSet() const override {
+ return AliasSet::Store(AliasSet::ObjectFields);
+ }
+
+ ALLOW_CLONE(MIncrementUnboxedArrayInitializedLength)
+};
+
+// Set the initialized length of an unboxed array object.
+class MSetUnboxedArrayInitializedLength
+ : public MBinaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ explicit MSetUnboxedArrayInitializedLength(MDefinition* obj, MDefinition* length)
+ : MBinaryInstruction(obj, length)
+ {}
+
+ public:
+ INSTRUCTION_HEADER(SetUnboxedArrayInitializedLength)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, object), (1, length))
+
+ AliasSet getAliasSet() const override {
+ return AliasSet::Store(AliasSet::ObjectFields);
+ }
+
+ ALLOW_CLONE(MSetUnboxedArrayInitializedLength)
+};
+
// Load the array length from an elements header.
class MArrayLength
: public MUnaryInstruction,
@@ -9234,19 +9352,23 @@ class MLoadElement
ALLOW_CLONE(MLoadElement)
};
-// Load a value from the elements vector of a native object.
+// Load a value from the elements vector for a dense native or unboxed array.
// If the index is out-of-bounds, or the indexed slot has a hole, undefined is
// returned instead.
class MLoadElementHole
: public MTernaryInstruction,
public SingleObjectPolicy::Data
{
+ // Unboxed element type, JSVAL_TYPE_MAGIC for dense native elements.
+ JSValueType unboxedType_;
+
bool needsNegativeIntCheck_;
bool needsHoleCheck_;
MLoadElementHole(MDefinition* elements, MDefinition* index, MDefinition* initLength,
- bool needsHoleCheck)
+ JSValueType unboxedType, bool needsHoleCheck)
: MTernaryInstruction(elements, index, initLength),
+ unboxedType_(unboxedType),
needsNegativeIntCheck_(true),
needsHoleCheck_(needsHoleCheck)
{
@@ -9268,6 +9390,9 @@ class MLoadElementHole
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, elements), (1, index), (2, initLength))
+ JSValueType unboxedType() const {
+ return unboxedType_;
+ }
bool needsNegativeIntCheck() const {
return needsNegativeIntCheck_;
}
@@ -9278,6 +9403,8 @@ class MLoadElementHole
if (!ins->isLoadElementHole())
return false;
const MLoadElementHole* other = ins->toLoadElementHole();
+ if (unboxedType() != other->unboxedType())
+ return false;
if (needsHoleCheck() != other->needsHoleCheck())
return false;
if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
@@ -9285,7 +9412,7 @@ class MLoadElementHole
return congruentIfOperandsEqual(other);
}
AliasSet getAliasSet() const override {
- return AliasSet::Load(AliasSet::Element);
+ return AliasSet::Load(AliasSet::BoxedOrUnboxedElements(unboxedType()));
}
void collectRangeInfoPreTrunc() override;
@@ -9465,17 +9592,20 @@ class MStoreElement
ALLOW_CLONE(MStoreElement)
};
-// Like MStoreElement, but supports indexes >= initialized length. The downside
-// is that we cannot hoist the elements vector and bounds check, since this
-// instruction may update the (initialized) length and reallocate the elements
-// vector.
+// Like MStoreElement, but supports indexes >= initialized length, and can
+// handle unboxed arrays. The downside is that we cannot hoist the elements
+// vector and bounds check, since this instruction may update the (initialized)
+// length and reallocate the elements vector.
class MStoreElementHole
: public MAryInstruction<4>,
public MStoreElementCommon,
public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
{
+ JSValueType unboxedType_;
+
MStoreElementHole(MDefinition* object, MDefinition* elements,
- MDefinition* index, MDefinition* value)
+ MDefinition* index, MDefinition* value, JSValueType unboxedType)
+ : unboxedType_(unboxedType)
{
initOperand(0, object);
initOperand(1, elements);
@@ -9490,6 +9620,10 @@ class MStoreElementHole
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
+ JSValueType unboxedType() const {
+ return unboxedType_;
+ }
+
ALLOW_CLONE(MStoreElementHole)
};
@@ -9500,11 +9634,13 @@ class MFallibleStoreElement
public MStoreElementCommon,
public MixPolicy<SingleObjectPolicy, NoFloatPolicy<3> >::Data
{
+ JSValueType unboxedType_;
bool strict_;
MFallibleStoreElement(MDefinition* object, MDefinition* elements,
MDefinition* index, MDefinition* value,
- bool strict)
+ JSValueType unboxedType, bool strict)
+ : unboxedType_(unboxedType)
{
initOperand(0, object);
initOperand(1, elements);
@@ -9520,6 +9656,10 @@ class MFallibleStoreElement
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object), (1, elements), (2, index), (3, value))
+ JSValueType unboxedType() const {
+ return unboxedType_;
+ }
+
bool strict() const {
return strict_;
}
@@ -9610,6 +9750,59 @@ class MStoreUnboxedString
ALLOW_CLONE(MStoreUnboxedString)
};
+// Passes through an object, after ensuring it is converted from an unboxed
+// object to a native representation.
+class MConvertUnboxedObjectToNative
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ CompilerObjectGroup group_;
+
+ explicit MConvertUnboxedObjectToNative(MDefinition* obj, ObjectGroup* group)
+ : MUnaryInstruction(obj),
+ group_(group)
+ {
+ setGuard();
+ setMovable();
+ setResultType(MIRType::Object);
+ }
+
+ public:
+ INSTRUCTION_HEADER(ConvertUnboxedObjectToNative)
+ NAMED_OPERANDS((0, object))
+
+ static MConvertUnboxedObjectToNative* New(TempAllocator& alloc, MDefinition* obj,
+ ObjectGroup* group);
+
+ ObjectGroup* group() const {
+ return group_;
+ }
+ bool congruentTo(const MDefinition* ins) const override {
+ if (!congruentIfOperandsEqual(ins))
+ return false;
+ return ins->toConvertUnboxedObjectToNative()->group() == group();
+ }
+ AliasSet getAliasSet() const override {
+ // This instruction can read and write to all parts of the object, but
+ // is marked as non-effectful so it can be consolidated by LICM and GVN
+ // and avoid inhibiting other optimizations.
+ //
+ // This is valid to do because when unboxed objects might have a native
+ // group they can be converted to, we do not optimize accesses to the
+ // unboxed objects and do not guard on their group or shape (other than
+ // in this opcode).
+ //
+ // Later accesses can assume the object has a native representation
+ // and optimize accordingly. Those accesses cannot be reordered before
+ // this instruction, however. This is prevented by chaining this
+ // instruction with the object itself, in the same way as MBoundsCheck.
+ return AliasSet::None();
+ }
+ bool appendRoots(MRootList& roots) const override {
+ return roots.append(group_);
+ }
+};
+
// Array.prototype.pop or Array.prototype.shift on a dense array.
class MArrayPopShift
: public MUnaryInstruction,
@@ -9623,12 +9816,13 @@ class MArrayPopShift
private:
Mode mode_;
+ JSValueType unboxedType_;
bool needsHoleCheck_;
bool maybeUndefined_;
- MArrayPopShift(MDefinition* object, Mode mode,
+ MArrayPopShift(MDefinition* object, Mode mode, JSValueType unboxedType,
bool needsHoleCheck, bool maybeUndefined)
- : MUnaryInstruction(object), mode_(mode),
+ : MUnaryInstruction(object), mode_(mode), unboxedType_(unboxedType),
needsHoleCheck_(needsHoleCheck), maybeUndefined_(maybeUndefined)
{ }
@@ -9646,8 +9840,12 @@ class MArrayPopShift
bool mode() const {
return mode_;
}
+ JSValueType unboxedType() const {
+ return unboxedType_;
+ }
AliasSet getAliasSet() const override {
- return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
+ return AliasSet::Store(AliasSet::ObjectFields |
+ AliasSet::BoxedOrUnboxedElements(unboxedType()));
}
ALLOW_CLONE(MArrayPopShift)
@@ -9658,8 +9856,10 @@ class MArrayPush
: public MBinaryInstruction,
public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >::Data
{
- MArrayPush(MDefinition* object, MDefinition* value)
- : MBinaryInstruction(object, value)
+ JSValueType unboxedType_;
+
+ MArrayPush(MDefinition* object, MDefinition* value, JSValueType unboxedType)
+ : MBinaryInstruction(object, value), unboxedType_(unboxedType)
{
setResultType(MIRType::Int32);
}
@@ -9669,8 +9869,12 @@ class MArrayPush
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, object), (1, value))
+ JSValueType unboxedType() const {
+ return unboxedType_;
+ }
AliasSet getAliasSet() const override {
- return AliasSet::Store(AliasSet::ObjectFields | AliasSet::Element);
+ return AliasSet::Store(AliasSet::ObjectFields |
+ AliasSet::BoxedOrUnboxedElements(unboxedType()));
}
void computeRange(TempAllocator& alloc) override;
@@ -9684,13 +9888,15 @@ class MArraySlice
{
CompilerObject templateObj_;
gc::InitialHeap initialHeap_;
+ JSValueType unboxedType_;
MArraySlice(CompilerConstraintList* constraints, MDefinition* obj,
MDefinition* begin, MDefinition* end,
- JSObject* templateObj, gc::InitialHeap initialHeap)
+ JSObject* templateObj, gc::InitialHeap initialHeap, JSValueType unboxedType)
: MTernaryInstruction(obj, begin, end),
templateObj_(templateObj),
- initialHeap_(initialHeap)
+ initialHeap_(initialHeap),
+ unboxedType_(unboxedType)
{
setResultType(MIRType::Object);
}
@@ -9708,6 +9914,10 @@ class MArraySlice
return initialHeap_;
}
+ JSValueType unboxedType() const {
+ return unboxedType_;
+ }
+
bool possiblyCalls() const override {
return true;
}
@@ -10972,6 +11182,11 @@ class MGuardShape
setMovable();
setResultType(MIRType::Object);
setResultTypeSet(obj->resultTypeSet());
+
+ // Disallow guarding on unboxed object shapes. The group is better to
+ // guard on, and guarding on the shape can interact badly with
+ // MConvertUnboxedObjectToNative.
+ MOZ_ASSERT(shape->getObjectClass() != &UnboxedPlainObject::class_);
}
public:
@@ -11066,6 +11281,11 @@ class MGuardObjectGroup
setGuard();
setMovable();
setResultType(MIRType::Object);
+
+ // Unboxed groups which might be converted to natives can't be guarded
+ // on, due to MConvertUnboxedObjectToNative.
+ MOZ_ASSERT_IF(group->maybeUnboxedLayoutDontCheckGeneration(),
+ !group->unboxedLayoutDontCheckGeneration().nativeGroup());
}
public:
@@ -11174,6 +11394,73 @@ class MGuardClass
ALLOW_CLONE(MGuardClass)
};
+// Guard on the presence or absence of an unboxed object's expando.
+class MGuardUnboxedExpando
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ bool requireExpando_;
+ BailoutKind bailoutKind_;
+
+ MGuardUnboxedExpando(MDefinition* obj, bool requireExpando, BailoutKind bailoutKind)
+ : MUnaryInstruction(obj),
+ requireExpando_(requireExpando),
+ bailoutKind_(bailoutKind)
+ {
+ setGuard();
+ setMovable();
+ setResultType(MIRType::Object);
+ }
+
+ public:
+ INSTRUCTION_HEADER(GuardUnboxedExpando)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, object))
+
+ bool requireExpando() const {
+ return requireExpando_;
+ }
+ BailoutKind bailoutKind() const {
+ return bailoutKind_;
+ }
+ bool congruentTo(const MDefinition* ins) const override {
+ if (!congruentIfOperandsEqual(ins))
+ return false;
+ if (requireExpando() != ins->toGuardUnboxedExpando()->requireExpando())
+ return false;
+ return true;
+ }
+ AliasSet getAliasSet() const override {
+ return AliasSet::Load(AliasSet::ObjectFields);
+ }
+};
+
+// Load an unboxed plain object's expando.
+class MLoadUnboxedExpando
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ private:
+ explicit MLoadUnboxedExpando(MDefinition* object)
+ : MUnaryInstruction(object)
+ {
+ setResultType(MIRType::Object);
+ setMovable();
+ }
+
+ public:
+ INSTRUCTION_HEADER(LoadUnboxedExpando)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, object))
+
+ bool congruentTo(const MDefinition* ins) const override {
+ return congruentIfOperandsEqual(ins);
+ }
+ AliasSet getAliasSet() const override {
+ return AliasSet::Load(AliasSet::ObjectFields);
+ }
+};
+
// Load from vp[slot] (slots that are not inline in an object).
class MLoadSlot
: public MUnaryInstruction,
@@ -12076,13 +12363,15 @@ class MInArray
{
bool needsHoleCheck_;
bool needsNegativeIntCheck_;
+ JSValueType unboxedType_;
MInArray(MDefinition* elements, MDefinition* index,
MDefinition* initLength, MDefinition* object,
- bool needsHoleCheck)
+ bool needsHoleCheck, JSValueType unboxedType)
: MQuaternaryInstruction(elements, index, initLength, object),
needsHoleCheck_(needsHoleCheck),
- needsNegativeIntCheck_(true)
+ needsNegativeIntCheck_(true),
+ unboxedType_(unboxedType)
{
setResultType(MIRType::Boolean);
setMovable();
@@ -12102,6 +12391,9 @@ class MInArray
bool needsNegativeIntCheck() const {
return needsNegativeIntCheck_;
}
+ JSValueType unboxedType() const {
+ return unboxedType_;
+ }
void collectRangeInfoPreTrunc() override;
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::Element);
@@ -12114,6 +12406,8 @@ class MInArray
return false;
if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
return false;
+ if (unboxedType() != other->unboxedType())
+ return false;
return congruentIfOperandsEqual(other);
}
};
@@ -14014,6 +14308,8 @@ MDefinition::maybeConstantValue()
bool ElementAccessIsDenseNative(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id);
+JSValueType UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
+ MDefinition* id);
bool ElementAccessIsTypedArray(CompilerConstraintList* constraints,
MDefinition* obj, MDefinition* id,
Scalar::Type* arrayType);