LCOV - code coverage report
Current view: top level - js/src/vm - UnboxedObject.h (source / functions) Hit Total Coverage
Test: output.info Lines: 71 141 50.4 %
Date: 2017-07-14 16:53:18 Functions: 27 50 54.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef vm_UnboxedObject_h
       8             : #define vm_UnboxedObject_h
       9             : 
      10             : #include "jsgc.h"
      11             : #include "jsobj.h"
      12             : 
      13             : #include "gc/Zone.h"
      14             : #include "vm/Runtime.h"
      15             : #include "vm/TypeInference.h"
      16             : 
      17             : namespace js {
      18             : 
      19             : // Memory required for an unboxed value of a given type. Returns zero for types
      20             : // which can't be used for unboxed objects.
      21             : static inline size_t
      22         133 : UnboxedTypeSize(JSValueType type)
      23             : {
      24         133 :     switch (type) {
      25          75 :       case JSVAL_TYPE_BOOLEAN: return 1;
      26           0 :       case JSVAL_TYPE_INT32:   return 4;
      27           0 :       case JSVAL_TYPE_DOUBLE:  return 8;
      28          12 :       case JSVAL_TYPE_STRING:  return sizeof(void*);
      29          36 :       case JSVAL_TYPE_OBJECT:  return sizeof(void*);
      30          10 :       default:                 return 0;
      31             :     }
      32             : }
      33             : 
      34             : static inline bool
      35           3 : UnboxedTypeNeedsPreBarrier(JSValueType type)
      36             : {
      37           3 :     return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
      38             : }
      39             : 
      40             : static inline bool
      41          10 : UnboxedTypeNeedsPostBarrier(JSValueType type)
      42             : {
      43          10 :     return type == JSVAL_TYPE_OBJECT;
      44             : }
      45             : 
      46             : // Class tracking information specific to unboxed objects.
      47             : class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
      48             : {
      49             :   public:
      50             :     struct Property {
      51             :         PropertyName* name;
      52             :         uint32_t offset;
      53             :         JSValueType type;
      54             : 
      55          54 :         Property()
      56          54 :           : name(nullptr), offset(UINT32_MAX), type(JSVAL_TYPE_MAGIC)
      57          54 :         {}
      58             :     };
      59             : 
      60             :     typedef Vector<Property, 0, SystemAllocPolicy> PropertyVector;
      61             : 
      62             :   private:
      63             :     Zone* zone_;
      64             : 
      65             :     // If objects in this group have ever been converted to native objects,
      66             :     // these store the corresponding native group and initial shape for such
      67             :     // objects. Type information for this object is reflected in nativeGroup.
      68             :     GCPtrObjectGroup nativeGroup_;
      69             :     GCPtrShape nativeShape_;
      70             : 
      71             :     // Any script/pc which the associated group is created for.
      72             :     GCPtrScript allocationScript_;
      73             :     jsbytecode* allocationPc_;
      74             : 
      75             :     // If nativeGroup is set and this object originally had a TypeNewScript or
      76             :     // was keyed to an allocation site, this points to the group which replaced
      77             :     // this one. This link is only needed to keep the replacement group from
      78             :     // being GC'ed. If it were GC'ed and a new one regenerated later, that new
      79             :     // group might have a different allocation kind from this group.
      80             :     GCPtrObjectGroup replacementGroup_;
      81             : 
      82             :     // The following members are only used for unboxed plain objects.
      83             : 
      84             :     // All properties on objects with this layout, in enumeration order.
      85             :     PropertyVector properties_;
      86             : 
      87             :     // Byte size of the data for objects with this layout.
      88             :     size_t size_;
      89             : 
      90             :     // Any 'new' script information associated with this layout.
      91             :     TypeNewScript* newScript_;
      92             : 
      93             :     // List for use in tracing objects with this layout. This has the same
      94             :     // structure as the trace list on a TypeDescr.
      95             :     int32_t* traceList_;
      96             : 
      97             :     // If this layout has been used to construct script or JSON constant
      98             :     // objects, this code might be filled in to more quickly fill in objects
      99             :     // from an array of values.
     100             :     GCPtrJitCode constructorCode_;
     101             : 
     102             :     // The following members are only used for unboxed arrays.
     103             : 
     104             :     // The type of array elements.
     105             :     JSValueType elementType_;
     106             : 
     107             :   public:
     108          19 :     explicit UnboxedLayout(Zone* zone)
     109          19 :       : zone_(zone), nativeGroup_(nullptr), nativeShape_(nullptr),
     110             :         allocationScript_(nullptr), allocationPc_(nullptr), replacementGroup_(nullptr),
     111             :         size_(0), newScript_(nullptr), traceList_(nullptr), constructorCode_(nullptr),
     112          19 :         elementType_(JSVAL_TYPE_MAGIC)
     113          19 :     {}
     114             : 
     115             :     Zone* zone() const { return zone_; }
     116             : 
     117          19 :     bool initProperties(const PropertyVector& properties, size_t size) {
     118          19 :         size_ = size;
     119          19 :         return properties_.appendAll(properties);
     120             :     }
     121             : 
     122           0 :     void initArray(JSValueType elementType) {
     123           0 :         elementType_ = elementType;
     124           0 :     }
     125             : 
     126           0 :     ~UnboxedLayout() {
     127           0 :         if (newScript_)
     128           0 :             newScript_->clear();
     129           0 :         js_delete(newScript_);
     130           0 :         js_free(traceList_);
     131             : 
     132           0 :         nativeGroup_.init(nullptr);
     133           0 :         nativeShape_.init(nullptr);
     134           0 :         replacementGroup_.init(nullptr);
     135           0 :         constructorCode_.init(nullptr);
     136           0 :     }
     137             : 
     138          24 :     bool isArray() const {
     139          24 :         return elementType_ != JSVAL_TYPE_MAGIC;
     140             :     }
     141             : 
     142             :     void detachFromCompartment();
     143             : 
     144        2445 :     const PropertyVector& properties() const {
     145        2445 :         return properties_;
     146             :     }
     147             : 
     148           4 :     TypeNewScript* newScript() const {
     149           4 :         return newScript_;
     150             :     }
     151             : 
     152             :     void setNewScript(TypeNewScript* newScript, bool writeBarrier = true);
     153             : 
     154           8 :     JSScript* allocationScript() const {
     155           8 :         return allocationScript_;
     156             :     }
     157             : 
     158           4 :     jsbytecode* allocationPc() const {
     159           4 :         return allocationPc_;
     160             :     }
     161             : 
     162          19 :     void setAllocationSite(JSScript* script, jsbytecode* pc) {
     163          19 :         allocationScript_ = script;
     164          19 :         allocationPc_ = pc;
     165          19 :     }
     166             : 
     167         388 :     const int32_t* traceList() const {
     168         388 :         return traceList_;
     169             :     }
     170             : 
     171          19 :     void setTraceList(int32_t* traceList) {
     172          19 :         traceList_ = traceList;
     173          19 :     }
     174             : 
     175       11684 :     const Property* lookup(JSAtom* atom) const {
     176       30981 :         for (size_t i = 0; i < properties_.length(); i++) {
     177       27224 :             if (properties_[i].name == atom)
     178        7927 :                 return &properties_[i];
     179             :         }
     180        3757 :         return nullptr;
     181             :     }
     182             : 
     183       11684 :     const Property* lookup(jsid id) const {
     184       11684 :         if (JSID_IS_STRING(id))
     185       11684 :             return lookup(JSID_TO_ATOM(id));
     186           0 :         return nullptr;
     187             :     }
     188             : 
     189         545 :     size_t size() const {
     190         545 :         return size_;
     191             :     }
     192             : 
     193          19 :     ObjectGroup* nativeGroup() const {
     194          19 :         return nativeGroup_;
     195             :     }
     196             : 
     197           4 :     Shape* nativeShape() const {
     198           4 :         return nativeShape_;
     199             :     }
     200             : 
     201           0 :     jit::JitCode* constructorCode() const {
     202           0 :         return constructorCode_;
     203             :     }
     204             : 
     205           0 :     void setConstructorCode(jit::JitCode* code) {
     206           0 :         constructorCode_ = code;
     207           0 :     }
     208             : 
     209           0 :     JSValueType elementType() const {
     210           0 :         return elementType_;
     211             :     }
     212             : 
     213             :     inline gc::AllocKind getAllocKind() const;
     214             : 
     215             :     void trace(JSTracer* trc);
     216             : 
     217             :     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
     218             : 
     219             :     static bool makeNativeGroup(JSContext* cx, ObjectGroup* group);
     220             :     static bool makeConstructorCode(JSContext* cx, HandleObjectGroup group);
     221             : };
     222             : 
     223             : class UnboxedObject : public JSObject
     224             : {
     225             :   protected:
     226             :     static JS::Result<UnboxedObject*, JS::OOM&>
     227             :     createInternal(JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
     228             :                    js::HandleObjectGroup group);
     229             : };
     230             : 
     231             : // Class for expando objects holding extra properties given to an unboxed plain
     232             : // object. These objects behave identically to normal native plain objects, and
     233             : // have a separate Class to distinguish them for memory usage reporting.
     234             : class UnboxedExpandoObject : public NativeObject
     235             : {
     236             :   public:
     237             :     static const Class class_;
     238             : };
     239             : 
     240             : // Class for a plain object using an unboxed representation. The physical
     241             : // layout of these objects is identical to that of an InlineTypedObject, though
     242             : // these objects use an UnboxedLayout instead of a TypeDescr to keep track of
     243             : // how their properties are stored.
     244             : class UnboxedPlainObject : public UnboxedObject
     245             : {
     246             :     // Optional object which stores extra properties on this object. This is
     247             :     // not automatically barriered to avoid problems if the object is converted
     248             :     // to a native. See ensureExpando().
     249             :     UnboxedExpandoObject* expando_;
     250             : 
     251             :     // Start of the inline data, which immediately follows the group and extra properties.
     252             :     uint8_t data_[1];
     253             : 
     254             :   public:
     255             :     static const Class class_;
     256             : 
     257             :     static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
     258             :                                    HandleId id, MutableHandleObject objp,
     259             :                                    MutableHandle<PropertyResult> propp);
     260             : 
     261             :     static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
     262             :                                    Handle<PropertyDescriptor> desc,
     263             :                                    ObjectOpResult& result);
     264             : 
     265             :     static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
     266             : 
     267             :     static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
     268             :                                 HandleId id, MutableHandleValue vp);
     269             : 
     270             :     static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
     271             :                                 HandleValue receiver, ObjectOpResult& result);
     272             : 
     273             :     static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
     274             :                                              MutableHandle<PropertyDescriptor> desc);
     275             : 
     276             :     static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
     277             :                                    ObjectOpResult& result);
     278             : 
     279             :     static bool newEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
     280             :                              bool enumerableOnly);
     281             :     static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
     282             : 
     283             :     inline const UnboxedLayout& layout() const;
     284             : 
     285         228 :     const UnboxedLayout& layoutDontCheckGeneration() const {
     286         228 :         return group()->unboxedLayoutDontCheckGeneration();
     287             :     }
     288             : 
     289         590 :     uint8_t* data() {
     290         590 :         return &data_[0];
     291             :     }
     292             : 
     293        3986 :     UnboxedExpandoObject* maybeExpando() const {
     294        3986 :         return expando_;
     295             :     }
     296             : 
     297         432 :     void initExpando() {
     298         432 :         expando_ = nullptr;
     299         432 :     }
     300             : 
     301             :     // For use during GC.
     302         158 :     JSObject** addressOfExpando() {
     303         158 :         return reinterpret_cast<JSObject**>(&expando_);
     304             :     }
     305             : 
     306             :     bool containsUnboxedOrExpandoProperty(JSContext* cx, jsid id) const;
     307             : 
     308             :     static UnboxedExpandoObject* ensureExpando(JSContext* cx, Handle<UnboxedPlainObject*> obj);
     309             : 
     310             :     bool setValue(JSContext* cx, const UnboxedLayout::Property& property, const Value& v);
     311             :     Value getValue(const UnboxedLayout::Property& property, bool maybeUninitialized = false);
     312             : 
     313             :     static bool convertToNative(JSContext* cx, JSObject* obj);
     314             :     static UnboxedPlainObject* create(JSContext* cx, HandleObjectGroup group,
     315             :                                       NewObjectKind newKind);
     316             :     static JSObject* createWithProperties(JSContext* cx, HandleObjectGroup group,
     317             :                                           NewObjectKind newKind, IdValuePair* properties);
     318             : 
     319             :     void fillAfterConvert(JSContext* cx,
     320             :                           Handle<GCVector<Value>> values, size_t* valueCursor);
     321             : 
     322             :     static void trace(JSTracer* trc, JSObject* object);
     323             : 
     324          20 :     static size_t offsetOfExpando() {
     325          20 :         return offsetof(UnboxedPlainObject, expando_);
     326             :     }
     327             : 
     328         207 :     static size_t offsetOfData() {
     329         207 :         return offsetof(UnboxedPlainObject, data_[0]);
     330             :     }
     331             : };
     332             : 
     333             : // Try to construct an UnboxedLayout for each of the preliminary objects,
     334             : // provided they all match the template shape. If successful, converts the
     335             : // preliminary objects and their group to the new unboxed representation.
     336             : bool
     337             : TryConvertToUnboxedLayout(JSContext* cx, AutoEnterAnalysis& enter, Shape* templateShape,
     338             :                           ObjectGroup* group, PreliminaryObjectArray* objects);
     339             : 
     340             : inline gc::AllocKind
     341          56 : UnboxedLayout::getAllocKind() const
     342             : {
     343          56 :     MOZ_ASSERT(size());
     344          56 :     return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
     345             : }
     346             : 
     347             : // Class for an array object using an unboxed representation.
     348             : class UnboxedArrayObject : public UnboxedObject
     349             : {
     350             :     // Elements pointer for the object.
     351             :     uint8_t* elements_;
     352             : 
     353             :     // The nominal array length. This always fits in an int32_t.
     354             :     uint32_t length_;
     355             : 
     356             :     // Value indicating the allocated capacity and initialized length of the
     357             :     // array. The top CapacityBits bits are an index into CapacityArray, which
     358             :     // indicates the elements capacity. The low InitializedLengthBits store the
     359             :     // initialized length of the array.
     360             :     uint32_t capacityIndexAndInitializedLength_;
     361             : 
     362             :     // If the elements are inline, they will point here.
     363             :     uint8_t inlineElements_[1];
     364             : 
     365             :   public:
     366             :     static const uint32_t CapacityBits = 6;
     367             :     static const uint32_t CapacityShift = 26;
     368             : 
     369             :     static const uint32_t CapacityMask = uint32_t(-1) << CapacityShift;
     370             :     static const uint32_t InitializedLengthMask = (1 << CapacityShift) - 1;
     371             : 
     372             :     static const uint32_t MaximumCapacity = InitializedLengthMask;
     373             :     static const uint32_t MinimumDynamicCapacity = 8;
     374             : 
     375             :     static const uint32_t CapacityArray[];
     376             : 
     377             :     // Capacity index which indicates the array's length is also its capacity.
     378             :     static const uint32_t CapacityMatchesLengthIndex = 0;
     379             : 
     380             :   private:
     381           0 :     static inline uint32_t computeCapacity(uint32_t index, uint32_t length) {
     382           0 :         if (index == CapacityMatchesLengthIndex)
     383           0 :             return length;
     384           0 :         return CapacityArray[index];
     385             :     }
     386             : 
     387             :     static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length);
     388             :     static uint32_t exactCapacityIndex(uint32_t capacity);
     389             : 
     390             :   public:
     391             :     static const Class class_;
     392             : 
     393             :     static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
     394             :                                    HandleId id, MutableHandleObject objp,
     395             :                                    MutableHandle<PropertyResult> propp);
     396             : 
     397             :     static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
     398             :                                    Handle<PropertyDescriptor> desc,
     399             :                                    ObjectOpResult& result);
     400             : 
     401             :     static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
     402             : 
     403             :     static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
     404             :                                 HandleId id, MutableHandleValue vp);
     405             : 
     406             :     static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
     407             :                                 HandleValue receiver, ObjectOpResult& result);
     408             : 
     409             :     static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
     410             :                                              MutableHandle<PropertyDescriptor> desc);
     411             : 
     412             :     static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
     413             :                                    ObjectOpResult& result);
     414             : 
     415             :     static bool newEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
     416             :                              bool enumerableOnly);
     417             :     static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
     418             : 
     419             :     inline const UnboxedLayout& layout() const;
     420             : 
     421           0 :     const UnboxedLayout& layoutDontCheckGeneration() const {
     422           0 :         return group()->unboxedLayoutDontCheckGeneration();
     423             :     }
     424             : 
     425           0 :     JSValueType elementType() const {
     426           0 :         return layoutDontCheckGeneration().elementType();
     427             :     }
     428             : 
     429           0 :     uint32_t elementSize() const {
     430           0 :         return UnboxedTypeSize(elementType());
     431             :     }
     432             : 
     433             :     static bool convertToNative(JSContext* cx, JSObject* obj);
     434             :     static UnboxedArrayObject* create(JSContext* cx, HandleObjectGroup group,
     435             :                                       uint32_t length, NewObjectKind newKind,
     436             :                                       uint32_t maxLength = MaximumCapacity);
     437             : 
     438             :     static bool convertToNativeWithGroup(JSContext* cx, JSObject* obj,
     439             :                                          ObjectGroup* group, Shape* shape);
     440             :     bool convertInt32ToDouble(JSContext* cx, ObjectGroup* group);
     441             : 
     442             :     void fillAfterConvert(JSContext* cx,
     443             :                           Handle<GCVector<Value>> values, size_t* valueCursor);
     444             : 
     445             :     static void trace(JSTracer* trc, JSObject* object);
     446             :     static void objectMoved(JSObject* obj, const JSObject* old);
     447             :     static void finalize(FreeOp* fop, JSObject* obj);
     448             : 
     449             :     static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src,
     450             :                                            gc::AllocKind allocKind);
     451             : 
     452           0 :     uint8_t* elements() {
     453           0 :         return elements_;
     454             :     }
     455             : 
     456           0 :     bool hasInlineElements() const {
     457           0 :         return elements_ == &inlineElements_[0];
     458             :     }
     459             : 
     460           0 :     uint32_t length() const {
     461           0 :         return length_;
     462             :     }
     463             : 
     464           0 :     uint32_t initializedLength() const {
     465           0 :         return capacityIndexAndInitializedLength_ & InitializedLengthMask;
     466             :     }
     467             : 
     468           0 :     uint32_t capacityIndex() const {
     469           0 :         return (capacityIndexAndInitializedLength_ & CapacityMask) >> CapacityShift;
     470             :     }
     471             : 
     472           0 :     uint32_t capacity() const {
     473           0 :         return computeCapacity(capacityIndex(), length());
     474             :     }
     475             : 
     476             :     bool containsProperty(JSContext* cx, jsid id);
     477             : 
     478             :     bool setElement(JSContext* cx, size_t index, const Value& v);
     479             :     bool initElement(JSContext* cx, size_t index, const Value& v);
     480             :     void initElementNoTypeChange(size_t index, const Value& v);
     481             :     Value getElement(size_t index);
     482             : 
     483             :     template <JSValueType Type> inline bool setElementSpecific(JSContext* cx, size_t index,
     484             :                                                                const Value& v);
     485             :     template <JSValueType Type> inline void setElementNoTypeChangeSpecific(size_t index, const Value& v);
     486             :     template <JSValueType Type> inline bool initElementSpecific(JSContext* cx, size_t index,
     487             :                                                                 const Value& v);
     488             :     template <JSValueType Type> inline void initElementNoTypeChangeSpecific(size_t index, const Value& v);
     489             :     template <JSValueType Type> inline Value getElementSpecific(size_t index);
     490             :     template <JSValueType Type> inline void triggerPreBarrier(size_t index);
     491             : 
     492             :     bool growElements(JSContext* cx, size_t cap);
     493             :     void shrinkElements(JSContext* cx, size_t cap);
     494             : 
     495           0 :     static uint32_t offsetOfElements() {
     496           0 :         return offsetof(UnboxedArrayObject, elements_);
     497             :     }
     498           0 :     static uint32_t offsetOfLength() {
     499           0 :         return offsetof(UnboxedArrayObject, length_);
     500             :     }
     501           0 :     static uint32_t offsetOfCapacityIndexAndInitializedLength() {
     502           0 :         return offsetof(UnboxedArrayObject, capacityIndexAndInitializedLength_);
     503             :     }
     504           0 :     static uint32_t offsetOfInlineElements() {
     505           0 :         return offsetof(UnboxedArrayObject, inlineElements_);
     506             :     }
     507             : 
     508           0 :     void setLengthInt32(uint32_t length) {
     509           0 :         MOZ_ASSERT(length <= INT32_MAX);
     510           0 :         length_ = length;
     511           0 :     }
     512             : 
     513             :     inline void setLength(JSContext* cx, uint32_t len);
     514             :     inline void setInitializedLength(uint32_t initlen);
     515             : 
     516           0 :     inline void setInitializedLengthNoBarrier(uint32_t initlen) {
     517           0 :         MOZ_ASSERT(initlen <= InitializedLengthMask);
     518           0 :         capacityIndexAndInitializedLength_ =
     519           0 :             (capacityIndexAndInitializedLength_ & CapacityMask) | initlen;
     520           0 :     }
     521             : 
     522             :   private:
     523           0 :     void setInlineElements() {
     524           0 :         elements_ = &inlineElements_[0];
     525           0 :     }
     526             : 
     527           0 :     void setCapacityIndex(uint32_t index) {
     528           0 :         MOZ_ASSERT(index <= (CapacityMask >> CapacityShift));
     529           0 :         capacityIndexAndInitializedLength_ =
     530           0 :             (index << CapacityShift) | initializedLength();
     531           0 :     }
     532             : };
     533             : 
     534             : } // namespace js
     535             : 
     536             : namespace JS {
     537             : 
     538             : template <>
     539             : struct DeletePolicy<js::UnboxedLayout> : public js::GCManagedDeletePolicy<js::UnboxedLayout>
     540             : {};
     541             : 
     542             : } /* namespace JS */
     543             : 
     544             : #endif /* vm_UnboxedObject_h */

Generated by: LCOV version 1.13