diff options
Diffstat (limited to 'js/src/jit/MIR.h')
-rw-r--r-- | js/src/jit/MIR.h | 340 |
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); |