diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /js/src/vm/UnboxedObject.h | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/vm/UnboxedObject.h')
-rw-r--r-- | js/src/vm/UnboxedObject.h | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h new file mode 100644 index 000000000..ecff8be5b --- /dev/null +++ b/js/src/vm/UnboxedObject.h @@ -0,0 +1,531 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef vm_UnboxedObject_h +#define vm_UnboxedObject_h + +#include "jsgc.h" +#include "jsobj.h" + +#include "vm/Runtime.h" +#include "vm/TypeInference.h" + +namespace js { + +// Memory required for an unboxed value of a given type. Returns zero for types +// which can't be used for unboxed objects. +static inline size_t +UnboxedTypeSize(JSValueType type) +{ + switch (type) { + case JSVAL_TYPE_BOOLEAN: return 1; + case JSVAL_TYPE_INT32: return 4; + case JSVAL_TYPE_DOUBLE: return 8; + case JSVAL_TYPE_STRING: return sizeof(void*); + case JSVAL_TYPE_OBJECT: return sizeof(void*); + default: return 0; + } +} + +static inline bool +UnboxedTypeNeedsPreBarrier(JSValueType type) +{ + return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT; +} + +static inline bool +UnboxedTypeNeedsPostBarrier(JSValueType type) +{ + return type == JSVAL_TYPE_OBJECT; +} + +// Class tracking information specific to unboxed objects. +class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout> +{ + public: + struct Property { + PropertyName* name; + uint32_t offset; + JSValueType type; + + Property() + : name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC) + {} + }; + + typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector; + + private: + // If objects in this group have ever been converted to native objects, + // these store the corresponding native group and initial shape for such + // objects. Type information for this object is reflected in nativeGroup. + GCPtrObjectGroup nativeGroup_; + GCPtrShape nativeShape_; + + // Any script/pc which the associated group is created for. + GCPtrScript allocationScript_; + jsbytecode* allocationPc_; + + // If nativeGroup is set and this object originally had a TypeNewScript or + // was keyed to an allocation site, this points to the group which replaced + // this one. This link is only needed to keep the replacement group from + // being GC'ed. If it were GC'ed and a new one regenerated later, that new + // group might have a different allocation kind from this group. + GCPtrObjectGroup replacementGroup_; + + // The following members are only used for unboxed plain objects. + + // All properties on objects with this layout, in enumeration order. + PropertyVector properties_; + + // Byte size of the data for objects with this layout. + size_t size_; + + // Any 'new' script information associated with this layout. + TypeNewScript* newScript_; + + // List for use in tracing objects with this layout. This has the same + // structure as the trace list on a TypeDescr. + int32_t* traceList_; + + // If this layout has been used to construct script or JSON constant + // objects, this code might be filled in to more quickly fill in objects + // from an array of values. + GCPtrJitCode constructorCode_; + + // The following members are only used for unboxed arrays. + + // The type of array elements. + JSValueType elementType_; + + public: + UnboxedLayout() + : nativeGroup_(nullptr), nativeShape_(nullptr), + allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr), + size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr), + elementType_(JSVAL_TYPE_MAGIC) + {} + + bool initProperties(const PropertyVector& properties, size_t size) { + size_ = size; + return properties_.appendAll(properties); + } + + void initArray(JSValueType elementType) { + elementType_ = elementType; + } + + ~UnboxedLayout() { + if (newScript_) + newScript_->clear(); + js_delete(newScript_); + js_free(traceList_); + + nativeGroup_.init(nullptr); + nativeShape_.init(nullptr); + replacementGroup_.init(nullptr); + constructorCode_.init(nullptr); + } + + bool isArray() const { + return elementType_ != JSVAL_TYPE_MAGIC; + } + + void detachFromCompartment(); + + const PropertyVector& properties() const { + return properties_; + } + + TypeNewScript* newScript() const { + return newScript_; + } + + void setNewScript(TypeNewScript* newScript, bool writeBarrier = true); + + JSScript* allocationScript() const { + return allocationScript_; + } + + jsbytecode* allocationPc() const { + return allocationPc_; + } + + void setAllocationSite(JSScript* script, jsbytecode* pc) { + allocationScript_ = script; + allocationPc_ = pc; + } + + const int32_t* traceList() const { + return traceList_; + } + + void setTraceList(int32_t* traceList) { + traceList_ = traceList; + } + + const Property* lookup(JSAtom* atom) const { + for (size_t i = 0; i < properties_.length(); i++) { + if (properties_[i].name == atom) + return &properties_[i]; + } + return nullptr; + } + + const Property* lookup(jsid id) const { + if (JSID_IS_STRING(id)) + return lookup(JSID_TO_ATOM(id)); + return nullptr; + } + + size_t size() const { + return size_; + } + + ObjectGroup* nativeGroup() const { + return nativeGroup_; + } + + Shape* nativeShape() const { + return nativeShape_; + } + + jit::JitCode* constructorCode() const { + return constructorCode_; + } + + void setConstructorCode(jit::JitCode* code) { + constructorCode_ = code; + } + + JSValueType elementType() const { + return elementType_; + } + + inline gc::AllocKind getAllocKind() const; + + void trace(JSTracer* trc); + + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); + + static bool makeNativeGroup(JSContext* cx, ObjectGroup* group); + static bool makeConstructorCode(JSContext* cx, HandleObjectGroup group); +}; + +// Class for expando objects holding extra properties given to an unboxed plain +// object. These objects behave identically to normal native plain objects, and +// have a separate Class to distinguish them for memory usage reporting. +class UnboxedExpandoObject : public NativeObject +{ + public: + static const Class class_; +}; + +// Class for a plain object using an unboxed representation. The physical +// layout of these objects is identical to that of an InlineTypedObject, though +// these objects use an UnboxedLayout instead of a TypeDescr to keep track of +// how their properties are stored. +class UnboxedPlainObject : public JSObject +{ + // Optional object which stores extra properties on this object. This is + // not automatically barriered to avoid problems if the object is converted + // to a native. See ensureExpando(). + UnboxedExpandoObject* expando_; + + // Start of the inline data, which immediately follows the group and extra properties. + uint8_t data_[1]; + + public: + static const Class class_; + + static bool obj_lookupProperty(JSContext* cx, HandleObject obj, + HandleId id, MutableHandleObject objp, + MutableHandleShape propp); + + static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, + Handle<PropertyDescriptor> desc, + ObjectOpResult& result); + + static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); + + static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, + HandleId id, MutableHandleValue vp); + + static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, + HandleValue receiver, ObjectOpResult& result); + + static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, + MutableHandle<PropertyDescriptor> desc); + + static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, + ObjectOpResult& result); + + static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, + bool enumerableOnly); + static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable); + + inline const UnboxedLayout& layout() const; + + const UnboxedLayout& layoutDontCheckGeneration() const { + return group()->unboxedLayoutDontCheckGeneration(); + } + + uint8_t* data() { + return &data_[0]; + } + + UnboxedExpandoObject* maybeExpando() const { + return expando_; + } + + void initExpando() { + expando_ = nullptr; + } + + // For use during GC. + JSObject** addressOfExpando() { + return reinterpret_cast<JSObject**>(&expando_); + } + + bool containsUnboxedOrExpandoProperty(ExclusiveContext* cx, jsid id) const; + + static UnboxedExpandoObject* ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj); + + bool setValue(ExclusiveContext* cx, const UnboxedLayout::Property& property, const Value& v); + Value getValue(const UnboxedLayout::Property& property, bool maybeUninitialized = false); + + static bool convertToNative(JSContext* cx, JSObject* obj); + static UnboxedPlainObject* create(ExclusiveContext* cx, HandleObjectGroup group, + NewObjectKind newKind); + static JSObject* createWithProperties(ExclusiveContext* cx, HandleObjectGroup group, + NewObjectKind newKind, IdValuePair* properties); + + void fillAfterConvert(ExclusiveContext* cx, + Handle<GCVector<Value>> values, size_t* valueCursor); + + static void trace(JSTracer* trc, JSObject* object); + + static size_t offsetOfExpando() { + return offsetof(UnboxedPlainObject, expando_); + } + + static size_t offsetOfData() { + return offsetof(UnboxedPlainObject, data_[0]); + } +}; + +// Try to construct an UnboxedLayout for each of the preliminary objects, +// provided they all match the template shape. If successful, converts the +// preliminary objects and their group to the new unboxed representation. +bool +TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Shape* templateShape, + ObjectGroup* group, PreliminaryObjectArray* objects); + +inline gc::AllocKind +UnboxedLayout::getAllocKind() const +{ + MOZ_ASSERT(size()); + return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size()); +} + +// Class for an array object using an unboxed representation. +class UnboxedArrayObject : public JSObject +{ + // Elements pointer for the object. + uint8_t* elements_; + + // The nominal array length. This always fits in an int32_t. + uint32_t length_; + + // Value indicating the allocated capacity and initialized length of the + // array. The top CapacityBits bits are an index into CapacityArray, which + // indicates the elements capacity. The low InitializedLengthBits store the + // initialized length of the array. + uint32_t capacityIndexAndInitializedLength_; + + // If the elements are inline, they will point here. + uint8_t inlineElements_[1]; + + public: + static const uint32_t CapacityBits = 6; + static const uint32_t CapacityShift = 26; + + static const uint32_t CapacityMask = uint32_t(-1) << CapacityShift; + static const uint32_t InitializedLengthMask = (1 << CapacityShift) - 1; + + static const uint32_t MaximumCapacity = InitializedLengthMask; + static const uint32_t MinimumDynamicCapacity = 8; + + static const uint32_t CapacityArray[]; + + // Capacity index which indicates the array's length is also its capacity. + static const uint32_t CapacityMatchesLengthIndex = 0; + + private: + static inline uint32_t computeCapacity(uint32_t index, uint32_t length) { + if (index == CapacityMatchesLengthIndex) + return length; + return CapacityArray[index]; + } + + static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length); + static uint32_t exactCapacityIndex(uint32_t capacity); + + public: + static const Class class_; + + static bool obj_lookupProperty(JSContext* cx, HandleObject obj, + HandleId id, MutableHandleObject objp, + MutableHandleShape propp); + + static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, + Handle<PropertyDescriptor> desc, + ObjectOpResult& result); + + static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); + + static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, + HandleId id, MutableHandleValue vp); + + static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, + HandleValue receiver, ObjectOpResult& result); + + static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, + MutableHandle<PropertyDescriptor> desc); + + static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, + ObjectOpResult& result); + + static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, + bool enumerableOnly); + static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable); + + inline const UnboxedLayout& layout() const; + + const UnboxedLayout& layoutDontCheckGeneration() const { + return group()->unboxedLayoutDontCheckGeneration(); + } + + JSValueType elementType() const { + return layoutDontCheckGeneration().elementType(); + } + + uint32_t elementSize() const { + return UnboxedTypeSize(elementType()); + } + + static bool convertToNative(JSContext* cx, JSObject* obj); + static UnboxedArrayObject* create(ExclusiveContext* cx, HandleObjectGroup group, + uint32_t length, NewObjectKind newKind, + uint32_t maxLength = MaximumCapacity); + + static bool convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj, + ObjectGroup* group, Shape* shape); + bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group); + + void fillAfterConvert(ExclusiveContext* cx, + Handle<GCVector<Value>> values, size_t* valueCursor); + + static void trace(JSTracer* trc, JSObject* object); + static void objectMoved(JSObject* obj, const JSObject* old); + static void finalize(FreeOp* fop, JSObject* obj); + + static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src, + gc::AllocKind allocKind); + + uint8_t* elements() { + return elements_; + } + + bool hasInlineElements() const { + return elements_ == &inlineElements_[0]; + } + + uint32_t length() const { + return length_; + } + + uint32_t initializedLength() const { + return capacityIndexAndInitializedLength_ & InitializedLengthMask; + } + + uint32_t capacityIndex() const { + return (capacityIndexAndInitializedLength_ & CapacityMask) >> CapacityShift; + } + + uint32_t capacity() const { + return computeCapacity(capacityIndex(), length()); + } + + bool containsProperty(ExclusiveContext* cx, jsid id); + + bool setElement(ExclusiveContext* cx, size_t index, const Value& v); + bool initElement(ExclusiveContext* cx, size_t index, const Value& v); + void initElementNoTypeChange(size_t index, const Value& v); + Value getElement(size_t index); + + template <JSValueType Type> inline bool setElementSpecific(ExclusiveContext* cx, size_t index, + const Value& v); + template <JSValueType Type> inline void setElementNoTypeChangeSpecific(size_t index, const Value& v); + template <JSValueType Type> inline bool initElementSpecific(ExclusiveContext* cx, size_t index, + const Value& v); + template <JSValueType Type> inline void initElementNoTypeChangeSpecific(size_t index, const Value& v); + template <JSValueType Type> inline Value getElementSpecific(size_t index); + template <JSValueType Type> inline void triggerPreBarrier(size_t index); + + bool growElements(ExclusiveContext* cx, size_t cap); + void shrinkElements(ExclusiveContext* cx, size_t cap); + + static uint32_t offsetOfElements() { + return offsetof(UnboxedArrayObject, elements_); + } + static uint32_t offsetOfLength() { + return offsetof(UnboxedArrayObject, length_); + } + static uint32_t offsetOfCapacityIndexAndInitializedLength() { + return offsetof(UnboxedArrayObject, capacityIndexAndInitializedLength_); + } + static uint32_t offsetOfInlineElements() { + return offsetof(UnboxedArrayObject, inlineElements_); + } + + void setLengthInt32(uint32_t length) { + MOZ_ASSERT(length <= INT32_MAX); + length_ = length; + } + + inline void setLength(ExclusiveContext* cx, uint32_t len); + inline void setInitializedLength(uint32_t initlen); + + inline void setInitializedLengthNoBarrier(uint32_t initlen) { + MOZ_ASSERT(initlen <= InitializedLengthMask); + capacityIndexAndInitializedLength_ = + (capacityIndexAndInitializedLength_ & CapacityMask) | initlen; + } + + private: + void setInlineElements() { + elements_ = &inlineElements_[0]; + } + + void setCapacityIndex(uint32_t index) { + MOZ_ASSERT(index <= (CapacityMask >> CapacityShift)); + capacityIndexAndInitializedLength_ = + (index << CapacityShift) | initializedLength(); + } +}; + +} // namespace js + +namespace JS { + +template <> +struct DeletePolicy<js::UnboxedLayout> : public js::GCManagedDeletePolicy<js::UnboxedLayout> +{}; + +} /* namespace JS */ + +#endif /* vm_UnboxedObject_h */ |