diff options
Diffstat (limited to 'js/src/vm/UnboxedObject.h')
-rw-r--r-- | js/src/vm/UnboxedObject.h | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h new file mode 100644 index 000000000..ba66434bc --- /dev/null +++ b/js/src/vm/UnboxedObject.h @@ -0,0 +1,319 @@ +/* -*- 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_; + + public: + UnboxedLayout() + : nativeGroup_(nullptr), nativeShape_(nullptr), + allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr), + size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr) + {} + + bool initProperties(const PropertyVector& properties, size_t size) { + size_ = size; + return properties_.appendAll(properties); + } + + ~UnboxedLayout() { + if (newScript_) + newScript_->clear(); + js_delete(newScript_); + js_free(traceList_); + + nativeGroup_.init(nullptr); + nativeShape_.init(nullptr); + replacementGroup_.init(nullptr); + constructorCode_.init(nullptr); + } + + 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; + } + + 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]); + } +}; + +inline gc::AllocKind +UnboxedLayout::getAllocKind() const +{ + MOZ_ASSERT(size()); + return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size()); +} + +} // namespace js + +namespace JS { + +template <> +struct DeletePolicy<js::UnboxedLayout> : public js::GCManagedDeletePolicy<js::UnboxedLayout> +{}; + +} /* namespace JS */ + +#endif /* vm_UnboxedObject_h */ |