LCOV - code coverage report
Current view: top level - js/src/vm - NativeObject-inl.h (source / functions) Hit Total Coverage
Test: output.info Lines: 298 383 77.8 %
Date: 2017-07-14 16:53:18 Functions: 35 42 83.3 %
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_NativeObject_inl_h
       8             : #define vm_NativeObject_inl_h
       9             : 
      10             : #include "vm/NativeObject.h"
      11             : 
      12             : #include "jscntxt.h"
      13             : 
      14             : #include "builtin/TypedObject.h"
      15             : #include "proxy/Proxy.h"
      16             : #include "vm/ProxyObject.h"
      17             : #include "vm/TypedArrayObject.h"
      18             : 
      19             : #include "jsobjinlines.h"
      20             : 
      21             : #include "gc/Heap-inl.h"
      22             : 
      23             : namespace js {
      24             : 
      25             : inline uint8_t*
      26           0 : NativeObject::fixedData(size_t nslots) const
      27             : {
      28           0 :     MOZ_ASSERT(ClassCanHaveFixedData(getClass()));
      29           0 :     MOZ_ASSERT(nslots == numFixedSlots() + (hasPrivate() ? 1 : 0));
      30           0 :     return reinterpret_cast<uint8_t*>(&fixedSlots()[nslots]);
      31             : }
      32             : 
      33             : inline void
      34          39 : NativeObject::removeLastProperty(JSContext* cx)
      35             : {
      36          39 :     MOZ_ASSERT(canRemoveLastProperty());
      37          39 :     JS_ALWAYS_TRUE(setLastProperty(cx, lastProperty()->previous()));
      38          39 : }
      39             : 
      40             : inline bool
      41          79 : NativeObject::canRemoveLastProperty()
      42             : {
      43             :     /*
      44             :      * Check that the information about the object stored in the last
      45             :      * property's base shape is consistent with that stored in the previous
      46             :      * shape. If not consistent, then the last property cannot be removed as it
      47             :      * will induce a change in the object itself, and the object must be
      48             :      * converted to dictionary mode instead. See BaseShape comment in jsscope.h
      49             :      */
      50          79 :     MOZ_ASSERT(!inDictionaryMode());
      51          79 :     Shape* previous = lastProperty()->previous().get();
      52          79 :     return previous->getObjectFlags() == lastProperty()->getObjectFlags();
      53             : }
      54             : 
      55             : inline void
      56           0 : NativeObject::setShouldConvertDoubleElements()
      57             : {
      58           0 :     MOZ_ASSERT(is<ArrayObject>() && !hasEmptyElements());
      59           0 :     getElementsHeader()->setShouldConvertDoubleElements();
      60           0 : }
      61             : 
      62             : inline void
      63             : NativeObject::clearShouldConvertDoubleElements()
      64             : {
      65             :     MOZ_ASSERT(is<ArrayObject>() && !hasEmptyElements());
      66             :     getElementsHeader()->clearShouldConvertDoubleElements();
      67             : }
      68             : 
      69             : inline void
      70        9006 : NativeObject::setDenseElementWithType(JSContext* cx, uint32_t index, const Value& val)
      71             : {
      72             :     // Avoid a slow AddTypePropertyId call if the type is the same as the type
      73             :     // of the previous element.
      74        9006 :     TypeSet::Type thisType = TypeSet::GetValueType(val);
      75        9006 :     if (index == 0 || TypeSet::GetValueType(elements_[index - 1]) != thisType)
      76        3812 :         AddTypePropertyId(cx, this, JSID_VOID, thisType);
      77        9006 :     setDenseElementMaybeConvertDouble(index, val);
      78        9006 : }
      79             : 
      80             : inline void
      81           0 : NativeObject::initDenseElementWithType(JSContext* cx, uint32_t index, const Value& val)
      82             : {
      83           0 :     MOZ_ASSERT(!shouldConvertDoubleElements());
      84           0 :     if (val.isMagic(JS_ELEMENTS_HOLE))
      85           0 :         markDenseElementsNotPacked(cx);
      86             :     else
      87           0 :         AddTypePropertyId(cx, this, JSID_VOID, val);
      88           0 :     initDenseElement(index, val);
      89           0 : }
      90             : 
      91             : inline void
      92           0 : NativeObject::setDenseElementHole(JSContext* cx, uint32_t index)
      93             : {
      94           0 :     MarkObjectGroupFlags(cx, this, OBJECT_FLAG_NON_PACKED);
      95           0 :     setDenseElement(index, MagicValue(JS_ELEMENTS_HOLE));
      96           0 : }
      97             : 
      98             : /* static */ inline void
      99          98 : NativeObject::removeDenseElementForSparseIndex(JSContext* cx,
     100             :                                                HandleNativeObject obj, uint32_t index)
     101             : {
     102          98 :     MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_NON_PACKED | OBJECT_FLAG_SPARSE_INDEXES);
     103          98 :     if (obj->containsDenseElement(index))
     104           0 :         obj->setDenseElementUnchecked(index, MagicValue(JS_ELEMENTS_HOLE));
     105          98 : }
     106             : 
     107             : inline bool
     108        8210 : NativeObject::writeToIndexWouldMarkNotPacked(uint32_t index)
     109             : {
     110        8210 :     return getElementsHeader()->initializedLength < index;
     111             : }
     112             : 
     113             : inline void
     114          41 : NativeObject::markDenseElementsNotPacked(JSContext* cx)
     115             : {
     116          41 :     MOZ_ASSERT(isNative());
     117          41 :     MarkObjectGroupFlags(cx, this, OBJECT_FLAG_NON_PACKED);
     118          41 : }
     119             : 
     120             : inline void
     121        3183 : NativeObject::elementsRangeWriteBarrierPost(uint32_t start, uint32_t count)
     122             : {
     123       13611 :     for (size_t i = 0; i < count; i++) {
     124       10649 :         const Value& v = elements_[start + i];
     125       10649 :         if (v.isObject() && IsInsideNursery(&v.toObject())) {
     126         442 :             zone()->group()->storeBuffer().putSlot(this, HeapSlot::Element,
     127         221 :                                                    unshiftedIndex(start + i),
     128         442 :                                                    count - i);
     129         221 :             return;
     130             :         }
     131             :     }
     132             : }
     133             : 
     134             : inline void
     135         876 : NativeObject::copyDenseElements(uint32_t dstStart, const Value* src, uint32_t count)
     136             : {
     137         876 :     MOZ_ASSERT(dstStart + count <= getDenseCapacity());
     138         876 :     MOZ_ASSERT(!denseElementsAreCopyOnWrite());
     139         876 :     MOZ_ASSERT(!denseElementsAreFrozen());
     140             : #ifdef DEBUG
     141        2003 :     for (uint32_t i = 0; i < count; ++i)
     142        1127 :         checkStoredValue(src[i]);
     143             : #endif
     144         876 :     if (JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()) {
     145           3 :         uint32_t numShifted = getElementsHeader()->numShiftedElements();
     146          17 :         for (uint32_t i = 0; i < count; ++i) {
     147          14 :             elements_[dstStart + i].set(this, HeapSlot::Element,
     148          14 :                                         dstStart + i + numShifted,
     149          28 :                                         src[i]);
     150             :         }
     151             :     } else {
     152         873 :         memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot));
     153         873 :         elementsRangeWriteBarrierPost(dstStart, count);
     154             :     }
     155         876 : }
     156             : 
     157             : inline void
     158        2280 : NativeObject::initDenseElements(uint32_t dstStart, const Value* src, uint32_t count)
     159             : {
     160        2280 :     MOZ_ASSERT(dstStart + count <= getDenseCapacity());
     161        2280 :     MOZ_ASSERT(!denseElementsAreCopyOnWrite());
     162        2280 :     MOZ_ASSERT(!denseElementsAreFrozen());
     163             : #ifdef DEBUG
     164       11823 :     for (uint32_t i = 0; i < count; ++i)
     165        9543 :         checkStoredValue(src[i]);
     166             : #endif
     167        2280 :     memcpy(&elements_[dstStart], src, count * sizeof(HeapSlot));
     168        2280 :     elementsRangeWriteBarrierPost(dstStart, count);
     169        2280 : }
     170             : 
     171             : inline bool
     172           7 : NativeObject::tryShiftDenseElements(uint32_t count)
     173             : {
     174           7 :     ObjectElements* header = getElementsHeader();
     175          21 :     if (header->initializedLength == count ||
     176           7 :         count > ObjectElements::MaxShiftedElements ||
     177          14 :         header->isCopyOnWrite() ||
     178          21 :         header->isFrozen() ||
     179           7 :         header->hasNonwritableArrayLength())
     180             :     {
     181           0 :         return false;
     182             :     }
     183             : 
     184           7 :     shiftDenseElementsUnchecked(count);
     185           7 :     return true;
     186             : }
     187             : 
     188             : inline void
     189           7 : NativeObject::shiftDenseElementsUnchecked(uint32_t count)
     190             : {
     191           7 :     ObjectElements* header = getElementsHeader();
     192           7 :     MOZ_ASSERT(count > 0);
     193           7 :     MOZ_ASSERT(count < header->initializedLength);
     194             : 
     195           7 :     if (MOZ_UNLIKELY(header->numShiftedElements() + count > ObjectElements::MaxShiftedElements)) {
     196           0 :         moveShiftedElements();
     197           0 :         header = getElementsHeader();
     198             :     }
     199             : 
     200           7 :     prepareElementRangeForOverwrite(0, count);
     201           7 :     header->addShiftedElements(count);
     202             : 
     203           7 :     elements_ += count;
     204           7 :     ObjectElements* newHeader = getElementsHeader();
     205           7 :     memmove(newHeader, header, sizeof(ObjectElements));
     206           7 : }
     207             : 
     208             : inline void
     209          34 : NativeObject::moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count)
     210             : {
     211          34 :     MOZ_ASSERT(dstStart + count <= getDenseCapacity());
     212          34 :     MOZ_ASSERT(srcStart + count <= getDenseInitializedLength());
     213          34 :     MOZ_ASSERT(!denseElementsAreCopyOnWrite());
     214          34 :     MOZ_ASSERT(!denseElementsAreFrozen());
     215             : 
     216             :     /*
     217             :      * Using memmove here would skip write barriers. Also, we need to consider
     218             :      * an array containing [A, B, C], in the following situation:
     219             :      *
     220             :      * 1. Incremental GC marks slot 0 of array (i.e., A), then returns to JS code.
     221             :      * 2. JS code moves slots 1..2 into slots 0..1, so it contains [B, C, C].
     222             :      * 3. Incremental GC finishes by marking slots 1 and 2 (i.e., C).
     223             :      *
     224             :      * Since normal marking never happens on B, it is very important that the
     225             :      * write barrier is invoked here on B, despite the fact that it exists in
     226             :      * the array before and after the move.
     227             :      */
     228          34 :     if (JS::shadow::Zone::asShadowZone(zone())->needsIncrementalBarrier()) {
     229           4 :         uint32_t numShifted = getElementsHeader()->numShiftedElements();
     230           4 :         if (dstStart < srcStart) {
     231           0 :             HeapSlot* dst = elements_ + dstStart;
     232           0 :             HeapSlot* src = elements_ + srcStart;
     233           0 :             for (uint32_t i = 0; i < count; i++, dst++, src++)
     234           0 :                 dst->set(this, HeapSlot::Element, dst - elements_ + numShifted, *src);
     235             :         } else {
     236           4 :             HeapSlot* dst = elements_ + dstStart + count - 1;
     237           4 :             HeapSlot* src = elements_ + srcStart + count - 1;
     238          19 :             for (uint32_t i = 0; i < count; i++, dst--, src--)
     239          15 :                 dst->set(this, HeapSlot::Element, dst - elements_ + numShifted, *src);
     240             :         }
     241             :     } else {
     242          30 :         memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(HeapSlot));
     243          30 :         elementsRangeWriteBarrierPost(dstStart, count);
     244             :     }
     245          34 : }
     246             : 
     247             : inline void
     248           0 : NativeObject::moveDenseElementsNoPreBarrier(uint32_t dstStart, uint32_t srcStart, uint32_t count)
     249             : {
     250           0 :     MOZ_ASSERT(!shadowZone()->needsIncrementalBarrier());
     251             : 
     252           0 :     MOZ_ASSERT(dstStart + count <= getDenseCapacity());
     253           0 :     MOZ_ASSERT(srcStart + count <= getDenseCapacity());
     254           0 :     MOZ_ASSERT(!denseElementsAreCopyOnWrite());
     255           0 :     MOZ_ASSERT(!denseElementsAreFrozen());
     256             : 
     257           0 :     memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(Value));
     258           0 :     elementsRangeWriteBarrierPost(dstStart, count);
     259           0 : }
     260             : 
     261             : inline void
     262        8180 : NativeObject::ensureDenseInitializedLengthNoPackedCheck(JSContext* cx, uint32_t index,
     263             :                                                         uint32_t extra)
     264             : {
     265        8180 :     MOZ_ASSERT(!denseElementsAreCopyOnWrite());
     266        8180 :     MOZ_ASSERT(!denseElementsAreFrozen());
     267             : 
     268             :     /*
     269             :      * Ensure that the array's contents have been initialized up to index, and
     270             :      * mark the elements through 'index + extra' as initialized in preparation
     271             :      * for a write.
     272             :      */
     273        8180 :     MOZ_ASSERT(index + extra <= getDenseCapacity());
     274        8180 :     uint32_t& initlen = getElementsHeader()->initializedLength;
     275             : 
     276        8180 :     if (initlen < index + extra) {
     277        7772 :         uint32_t numShifted = getElementsHeader()->numShiftedElements();
     278        7772 :         size_t offset = initlen;
     279       17607 :         for (HeapSlot* sp = elements_ + initlen;
     280       17607 :              sp != elements_ + (index + extra);
     281             :              sp++, offset++)
     282             :         {
     283        9835 :             sp->init(this, HeapSlot::Element, offset + numShifted, MagicValue(JS_ELEMENTS_HOLE));
     284             :         }
     285        7772 :         initlen = index + extra;
     286             :     }
     287        8180 : }
     288             : 
     289             : inline void
     290           0 : NativeObject::ensureDenseInitializedLength(JSContext* cx, uint32_t index, uint32_t extra)
     291             : {
     292           0 :     if (writeToIndexWouldMarkNotPacked(index))
     293           0 :         markDenseElementsNotPacked(cx);
     294           0 :     ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
     295           0 : }
     296             : 
     297             : DenseElementResult
     298          93 : NativeObject::extendDenseElements(JSContext* cx,
     299             :                                   uint32_t requiredCapacity, uint32_t extra)
     300             : {
     301          93 :     MOZ_ASSERT(!denseElementsAreCopyOnWrite());
     302          93 :     MOZ_ASSERT(!denseElementsAreFrozen());
     303             : 
     304             :     /*
     305             :      * Don't grow elements for non-extensible objects or watched objects. Dense
     306             :      * elements can be added/written with no extensible or watchpoint checks as
     307             :      * long as there is capacity for them.
     308             :      */
     309          93 :     if (!nonProxyIsExtensible() || watched()) {
     310           0 :         MOZ_ASSERT(getDenseCapacity() == 0);
     311           0 :         return DenseElementResult::Incomplete;
     312             :     }
     313             : 
     314             :     /*
     315             :      * Don't grow elements for objects which already have sparse indexes.
     316             :      * This avoids needing to count non-hole elements in willBeSparseElements
     317             :      * every time a new index is added.
     318             :      */
     319          93 :     if (isIndexed())
     320          29 :         return DenseElementResult::Incomplete;
     321             : 
     322             :     /*
     323             :      * We use the extra argument also as a hint about number of non-hole
     324             :      * elements to be inserted.
     325             :      */
     326          65 :     if (requiredCapacity > MIN_SPARSE_INDEX &&
     327           1 :         willBeSparseElements(requiredCapacity, extra)) {
     328           1 :         return DenseElementResult::Incomplete;
     329             :     }
     330             : 
     331          63 :     if (!growElements(cx, requiredCapacity))
     332           0 :         return DenseElementResult::Failure;
     333             : 
     334          63 :     return DenseElementResult::Success;
     335             : }
     336             : 
     337             : inline DenseElementResult
     338        8210 : NativeObject::ensureDenseElements(JSContext* cx, uint32_t index, uint32_t extra)
     339             : {
     340        8210 :     MOZ_ASSERT(isNative());
     341             : 
     342        8210 :     if (writeToIndexWouldMarkNotPacked(index))
     343          41 :         markDenseElementsNotPacked(cx);
     344             : 
     345        8210 :     if (!maybeCopyElementsForWrite(cx))
     346           0 :         return DenseElementResult::Failure;
     347             : 
     348        8210 :     uint32_t currentCapacity = getDenseCapacity();
     349             : 
     350             :     uint32_t requiredCapacity;
     351        8210 :     if (extra == 1) {
     352             :         /* Optimize for the common case. */
     353        7283 :         if (index < currentCapacity) {
     354        7191 :             ensureDenseInitializedLengthNoPackedCheck(cx, index, 1);
     355        7191 :             return DenseElementResult::Success;
     356             :         }
     357          92 :         requiredCapacity = index + 1;
     358          92 :         if (requiredCapacity == 0) {
     359             :             /* Overflow. */
     360           0 :             return DenseElementResult::Incomplete;
     361             :         }
     362             :     } else {
     363         927 :         requiredCapacity = index + extra;
     364         927 :         if (requiredCapacity < index) {
     365             :             /* Overflow. */
     366           0 :             return DenseElementResult::Incomplete;
     367             :         }
     368         927 :         if (requiredCapacity <= currentCapacity) {
     369         926 :             ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
     370         926 :             return DenseElementResult::Success;
     371             :         }
     372             :     }
     373             : 
     374          93 :     DenseElementResult result = extendDenseElements(cx, requiredCapacity, extra);
     375          93 :     if (result != DenseElementResult::Success)
     376          30 :         return result;
     377             : 
     378          63 :     ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
     379          63 :     return DenseElementResult::Success;
     380             : }
     381             : 
     382             : inline Value
     383        3633 : NativeObject::getDenseOrTypedArrayElement(uint32_t idx)
     384             : {
     385        3633 :     if (is<TypedArrayObject>())
     386           0 :         return as<TypedArrayObject>().getElement(idx);
     387        3633 :     return getDenseElement(idx);
     388             : }
     389             : 
     390             : /* static */ inline NativeObject*
     391             : NativeObject::copy(JSContext* cx, gc::AllocKind kind, gc::InitialHeap heap,
     392             :                    HandleNativeObject templateObject)
     393             : {
     394             :     RootedShape shape(cx, templateObject->lastProperty());
     395             :     RootedObjectGroup group(cx, templateObject->group());
     396             :     MOZ_ASSERT(!templateObject->denseElementsAreCopyOnWrite());
     397             : 
     398             :     JSObject* baseObj;
     399             :     JS_TRY_VAR_OR_RETURN_NULL(cx, baseObj, create(cx, kind, heap, shape, group));
     400             : 
     401             :     NativeObject* obj = &baseObj->as<NativeObject>();
     402             : 
     403             :     size_t span = shape->slotSpan();
     404             :     if (span) {
     405             :         uint32_t numFixed = templateObject->numFixedSlots();
     406             :         const Value* fixed = &templateObject->getSlot(0);
     407             :         // Only copy elements which are registered in the shape, even if the
     408             :         // number of fixed slots is larger.
     409             :         if (span < numFixed)
     410             :             numFixed = span;
     411             :         obj->copySlotRange(0, fixed, numFixed);
     412             : 
     413             :         if (numFixed < span) {
     414             :             uint32_t numSlots = span - numFixed;
     415             :             const Value* slots = &templateObject->getSlot(numFixed);
     416             :             obj->copySlotRange(numFixed, slots, numSlots);
     417             :         }
     418             :     }
     419             : 
     420             :     return obj;
     421             : }
     422             : 
     423             : MOZ_ALWAYS_INLINE void
     424      115087 : NativeObject::setSlotWithType(JSContext* cx, Shape* shape,
     425             :                               const Value& value, bool overwriting)
     426             : {
     427      115087 :     setSlot(shape->slot(), value);
     428             : 
     429      115087 :     if (overwriting)
     430        2306 :         shape->setOverwritten();
     431             : 
     432      115087 :     AddTypePropertyId(cx, this, shape->propid(), value);
     433      115084 : }
     434             : 
     435             : inline void
     436       18577 : NativeObject::updateShapeAfterMovingGC()
     437             : {
     438       18577 :     Shape* shape = shape_;
     439       18577 :     if (IsForwarded(shape))
     440           0 :         shape_.unsafeSet(Forwarded(shape));
     441       18577 : }
     442             : 
     443             : inline bool
     444           0 : NativeObject::isInWholeCellBuffer() const
     445             : {
     446           0 :     const gc::TenuredCell* cell = &asTenured();
     447           0 :     gc::ArenaCellSet* cells = cell->arena()->bufferedCells();
     448           0 :     return cells && cells->hasCell(cell);
     449             : }
     450             : 
     451             : /* static */ inline JS::Result<NativeObject*, JS::OOM&>
     452      131350 : NativeObject::create(JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
     453             :                      js::HandleShape shape, js::HandleObjectGroup group)
     454             : {
     455      131350 :     debugCheckNewObject(group, shape, kind, heap);
     456             : 
     457      131352 :     const js::Class* clasp = group->clasp();
     458      131352 :     MOZ_ASSERT(clasp->isNative());
     459             : 
     460      131352 :     size_t nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
     461             : 
     462      131351 :     JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
     463      131353 :     if (!obj)
     464           0 :         return cx->alreadyReportedOOM();
     465             : 
     466      131353 :     NativeObject* nobj = static_cast<NativeObject*>(obj);
     467      131353 :     nobj->group_.init(group);
     468      131353 :     nobj->initShape(shape);
     469             : 
     470             :     // Note: slots are created and assigned internally by Allocate<JSObject>.
     471      131353 :     nobj->setInitialElementsMaybeNonNative(js::emptyObjectElements);
     472             : 
     473      131353 :     if (clasp->hasPrivate())
     474        8061 :         nobj->privateRef(shape->numFixedSlots()) = nullptr;
     475             : 
     476      131353 :     if (size_t span = shape->slotSpan())
     477       15348 :         nobj->initializeSlotRange(0, span);
     478             : 
     479             :     // JSFunction's fixed slots expect POD-style initialization.
     480      131353 :     if (clasp->isJSFunction()) {
     481       95396 :         MOZ_ASSERT(kind == js::gc::AllocKind::FUNCTION ||
     482             :                    kind == js::gc::AllocKind::FUNCTION_EXTENDED);
     483             :         size_t size =
     484       95396 :             kind == js::gc::AllocKind::FUNCTION ? sizeof(JSFunction) : sizeof(js::FunctionExtended);
     485       95396 :         memset(nobj->as<JSFunction>().fixedSlots(), 0, size - sizeof(js::NativeObject));
     486       95396 :         if (kind == js::gc::AllocKind::FUNCTION_EXTENDED) {
     487             :             // SetNewObjectMetadata may gc, which will be unhappy if flags &
     488             :             // EXTENDED doesn't match the arena's AllocKind.
     489       43426 :             nobj->as<JSFunction>().setFlags(JSFunction::EXTENDED);
     490             :         }
     491             :     }
     492             : 
     493      131353 :     if (clasp->shouldDelayMetadataBuilder())
     494         139 :         cx->compartment()->setObjectPendingMetadata(cx, nobj);
     495             :     else
     496      131214 :         nobj = SetNewObjectMetadata(cx, nobj);
     497             : 
     498      131353 :     js::gc::TraceCreateObject(nobj);
     499             : 
     500      131353 :     return nobj;
     501             : }
     502             : 
     503             : MOZ_ALWAYS_INLINE uint32_t
     504     2374296 : NativeObject::numDynamicSlots() const
     505             : {
     506     2374296 :     return dynamicSlotsCount(numFixedSlots(), slotSpan(), getClass());
     507             : }
     508             : 
     509             : /* static */ MOZ_ALWAYS_INLINE uint32_t
     510     2769934 : NativeObject::dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class* clasp)
     511             : {
     512     2769934 :     if (span <= nfixed)
     513      962799 :         return 0;
     514     1807135 :     span -= nfixed;
     515             : 
     516             :     // Increase the slots to SLOT_CAPACITY_MIN to decrease the likelihood
     517             :     // the dynamic slots need to get increased again. ArrayObjects ignore
     518             :     // this because slots are uncommon in that case.
     519     1807135 :     if (clasp != &ArrayObject::class_ && span <= SLOT_CAPACITY_MIN)
     520      350239 :         return SLOT_CAPACITY_MIN;
     521             : 
     522     1456896 :     uint32_t slots = mozilla::RoundUpPow2(span);
     523     1456987 :     MOZ_ASSERT(slots >= span);
     524     1456987 :     return slots;
     525             : }
     526             : 
     527             : /* static */ MOZ_ALWAYS_INLINE uint32_t
     528         668 : NativeObject::dynamicSlotsCount(Shape* shape)
     529             : {
     530         668 :     return dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), shape->getObjectClass());
     531             : }
     532             : 
     533             : MOZ_ALWAYS_INLINE bool
     534      129656 : NativeObject::updateSlotsForSpan(JSContext* cx, size_t oldSpan, size_t newSpan)
     535             : {
     536      129656 :     MOZ_ASSERT(oldSpan != newSpan);
     537             : 
     538      129656 :     size_t oldCount = dynamicSlotsCount(numFixedSlots(), oldSpan, getClass());
     539      129656 :     size_t newCount = dynamicSlotsCount(numFixedSlots(), newSpan, getClass());
     540             : 
     541      129657 :     if (oldSpan < newSpan) {
     542      129641 :         if (oldCount < newCount && !growSlots(cx, oldCount, newCount))
     543           0 :             return false;
     544             : 
     545      129641 :         if (newSpan == oldSpan + 1)
     546      125300 :             initSlotUnchecked(oldSpan, UndefinedValue());
     547             :         else
     548        4341 :             initializeSlotRange(oldSpan, newSpan - oldSpan);
     549             :     } else {
     550             :         /* Trigger write barriers on the old slots before reallocating. */
     551          16 :         prepareSlotRangeForOverwrite(newSpan, oldSpan);
     552          16 :         invalidateSlotRange(newSpan, oldSpan - newSpan);
     553             : 
     554          16 :         if (oldCount > newCount)
     555           0 :             shrinkSlots(cx, oldCount, newCount);
     556             :     }
     557             : 
     558      129656 :     return true;
     559             : }
     560             : 
     561             : MOZ_ALWAYS_INLINE bool
     562      145282 : NativeObject::setLastProperty(JSContext* cx, Shape* shape)
     563             : {
     564      145282 :     MOZ_ASSERT(!inDictionaryMode());
     565      145282 :     MOZ_ASSERT(!shape->inDictionary());
     566      145282 :     MOZ_ASSERT(shape->zone() == zone());
     567      145281 :     MOZ_ASSERT(shape->numFixedSlots() == numFixedSlots());
     568      145281 :     MOZ_ASSERT(shape->getObjectClass() == getClass());
     569             : 
     570      145281 :     size_t oldSpan = lastProperty()->slotSpan();
     571      145280 :     size_t newSpan = shape->slotSpan();
     572             : 
     573      145281 :     if (oldSpan == newSpan) {
     574       17564 :         shape_ = shape;
     575       17564 :         return true;
     576             :     }
     577             : 
     578      127717 :     if (MOZ_UNLIKELY(!updateSlotsForSpan(cx, oldSpan, newSpan)))
     579           0 :         return false;
     580             : 
     581      127717 :     shape_ = shape;
     582      127717 :     return true;
     583             : }
     584             : 
     585             : /* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
     586             : static inline PlainObject*
     587        3725 : CopyInitializerObject(JSContext* cx, HandlePlainObject baseobj, NewObjectKind newKind = GenericObject)
     588             : {
     589        3725 :     MOZ_ASSERT(!baseobj->inDictionaryMode());
     590             : 
     591        3725 :     gc::AllocKind allocKind = gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots());
     592        3725 :     allocKind = gc::GetBackgroundAllocKind(allocKind);
     593        3725 :     MOZ_ASSERT_IF(baseobj->isTenured(), allocKind == baseobj->asTenured().getAllocKind());
     594        7450 :     RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx, allocKind, newKind));
     595        3725 :     if (!obj)
     596           0 :         return nullptr;
     597             : 
     598        3725 :     if (!obj->setLastProperty(cx, baseobj->lastProperty()))
     599           0 :         return nullptr;
     600             : 
     601        3725 :     return obj;
     602             : }
     603             : 
     604             : inline NativeObject*
     605             : NewNativeObjectWithGivenTaggedProto(JSContext* cx, const Class* clasp,
     606             :                                     Handle<TaggedProto> proto,
     607             :                                     gc::AllocKind allocKind, NewObjectKind newKind)
     608             : {
     609             :     return MaybeNativeObject(NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind,
     610             :                                                            newKind));
     611             : }
     612             : 
     613             : inline NativeObject*
     614             : NewNativeObjectWithGivenTaggedProto(JSContext* cx, const Class* clasp,
     615             :                                     Handle<TaggedProto> proto,
     616             :                                     NewObjectKind newKind = GenericObject)
     617             : {
     618             :     return MaybeNativeObject(NewObjectWithGivenTaggedProto(cx, clasp, proto, newKind));
     619             : }
     620             : 
     621             : inline NativeObject*
     622             : NewNativeObjectWithGivenProto(JSContext* cx, const Class* clasp,
     623             :                               HandleObject proto,
     624             :                               gc::AllocKind allocKind, NewObjectKind newKind)
     625             : {
     626             :     return MaybeNativeObject(NewObjectWithGivenProto(cx, clasp, proto, allocKind, newKind));
     627             : }
     628             : 
     629             : inline NativeObject*
     630        1133 : NewNativeObjectWithGivenProto(JSContext* cx, const Class* clasp,
     631             :                               HandleObject proto,
     632             :                               NewObjectKind newKind = GenericObject)
     633             : {
     634        1133 :     return MaybeNativeObject(NewObjectWithGivenProto(cx, clasp, proto, newKind));
     635             : }
     636             : 
     637             : inline NativeObject*
     638             : NewNativeObjectWithClassProto(JSContext* cx, const Class* clasp, HandleObject proto,
     639             :                               gc::AllocKind allocKind,
     640             :                               NewObjectKind newKind = GenericObject)
     641             : {
     642             :     return MaybeNativeObject(NewObjectWithClassProto(cx, clasp, proto, allocKind, newKind));
     643             : }
     644             : 
     645             : inline NativeObject*
     646           4 : NewNativeObjectWithClassProto(JSContext* cx, const Class* clasp, HandleObject proto,
     647             :                               NewObjectKind newKind = GenericObject)
     648             : {
     649           4 :     return MaybeNativeObject(NewObjectWithClassProto(cx, clasp, proto, newKind));
     650             : }
     651             : 
     652             : /*
     653             :  * Call obj's resolve hook.
     654             :  *
     655             :  * cx and id are the parameters initially passed to the ongoing lookup;
     656             :  * propp and recursedp are its out parameters.
     657             :  *
     658             :  * There are four possible outcomes:
     659             :  *
     660             :  *   - On failure, report an error or exception and return false.
     661             :  *
     662             :  *   - If we are already resolving a property of obj, set *recursedp = true,
     663             :  *     and return true.
     664             :  *
     665             :  *   - If the resolve hook finds or defines the sought property, set propp
     666             :  *      appropriately, set *recursedp = false, and return true.
     667             :  *
     668             :  *   - Otherwise no property was resolved. Set propp to nullptr and
     669             :  *     *recursedp = false and return true.
     670             :  */
     671             : static MOZ_ALWAYS_INLINE bool
     672       57467 : CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id,
     673             :               MutableHandle<PropertyResult> propp, bool* recursedp)
     674             : {
     675             :     // Avoid recursion on (obj, id) already being resolved on cx.
     676      114934 :     AutoResolving resolving(cx, obj, id);
     677       57467 :     if (resolving.alreadyStarted()) {
     678             :         // Already resolving id in obj, suppress recursion.
     679           0 :         *recursedp = true;
     680           0 :         return true;
     681             :     }
     682       57467 :     *recursedp = false;
     683             : 
     684       57467 :     bool resolved = false;
     685       57467 :     if (!obj->getClass()->getResolve()(cx, obj, id, &resolved))
     686           0 :         return false;
     687             : 
     688       57467 :     if (!resolved)
     689       51947 :         return true;
     690             : 
     691             :     // Assert the mayResolve hook, if there is one, returns true for this
     692             :     // property.
     693        5520 :     MOZ_ASSERT_IF(obj->getClass()->getMayResolve(),
     694             :                   obj->getClass()->getMayResolve()(cx->names(), id, obj));
     695             : 
     696        5520 :     if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
     697           0 :         propp.setDenseOrTypedArrayElement();
     698           0 :         return true;
     699             :     }
     700             : 
     701        5520 :     MOZ_ASSERT(!obj->is<TypedArrayObject>());
     702             : 
     703       11040 :     RootedShape shape(cx, obj->lookup(cx, id));
     704        5520 :     if (shape)
     705        5520 :         propp.setNativeProperty(shape);
     706             :     else
     707           0 :         propp.setNotFound();
     708             : 
     709        5520 :     return true;
     710             : }
     711             : 
     712             : template <AllowGC allowGC>
     713             : static MOZ_ALWAYS_INLINE bool
     714      310347 : LookupOwnPropertyInline(JSContext* cx,
     715             :                         typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
     716             :                         typename MaybeRooted<jsid, allowGC>::HandleType id,
     717             :                         typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp,
     718             :                         bool* donep)
     719             : {
     720             :     // Check for a native dense element.
     721      310347 :     if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
     722        4267 :         propp.setDenseOrTypedArrayElement();
     723        4267 :         *donep = true;
     724        4267 :         return true;
     725             :     }
     726             : 
     727             :     // Check for a typed array element. Integer lookups always finish here
     728             :     // so that integer properties on the prototype are ignored even for out
     729             :     // of bounds accesses.
     730      306080 :     if (obj->template is<TypedArrayObject>()) {
     731             :         uint64_t index;
     732           0 :         if (IsTypedArrayIndex(id, &index)) {
     733           0 :             if (index < obj->template as<TypedArrayObject>().length())
     734           0 :                 propp.setDenseOrTypedArrayElement();
     735             :             else
     736           0 :                 propp.setNotFound();
     737           0 :             *donep = true;
     738           0 :             return true;
     739             :         }
     740             :     }
     741             : 
     742             :     // Check for a native property. Call Shape::search directly (instead of
     743             :     // NativeObject::lookup) because it's inlined.
     744      306080 :     if (Shape* shape = obj->lastProperty()->search(cx, id)) {
     745       85880 :         propp.setNativeProperty(shape);
     746       85880 :         *donep = true;
     747       85880 :         return true;
     748             :     }
     749             : 
     750             :     // id was not found in obj. Try obj's resolve hook, if any.
     751      220199 :     if (obj->getClass()->getResolve()) {
     752       58274 :         MOZ_ASSERT(!cx->helperThread());
     753             :         if (!allowGC)
     754        6327 :             return false;
     755             : 
     756             :         bool recursed;
     757       57467 :         if (!CallResolveOp(cx,
     758             :                            MaybeRooted<NativeObject*, allowGC>::toHandle(obj),
     759             :                            MaybeRooted<jsid, allowGC>::toHandle(id),
     760             :                            MaybeRooted<PropertyResult, allowGC>::toMutableHandle(propp),
     761             :                            &recursed))
     762             :         {
     763           0 :             return false;
     764             :         }
     765             : 
     766       57467 :         if (recursed) {
     767           0 :             propp.setNotFound();
     768           0 :             *donep = true;
     769           0 :             return true;
     770             :         }
     771             : 
     772       57467 :         if (propp) {
     773        5520 :             *donep = true;
     774        5520 :             return true;
     775             :         }
     776             :     }
     777             : 
     778      213872 :     propp.setNotFound();
     779      213872 :     *donep = false;
     780      213872 :     return true;
     781             : }
     782             : 
     783             : /*
     784             :  * Simplified version of LookupOwnPropertyInline that doesn't call resolve
     785             :  * hooks.
     786             :  */
     787             : static inline void
     788       14774 : NativeLookupOwnPropertyNoResolve(JSContext* cx, HandleNativeObject obj, HandleId id,
     789             :                                  MutableHandle<PropertyResult> result)
     790             : {
     791             :     // Check for a native dense element.
     792       14774 :     if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
     793           0 :         result.setDenseOrTypedArrayElement();
     794           0 :         return;
     795             :     }
     796             : 
     797             :     // Check for a typed array element.
     798       14774 :     if (obj->is<TypedArrayObject>()) {
     799             :         uint64_t index;
     800           0 :         if (IsTypedArrayIndex(id, &index)) {
     801           0 :             if (index < obj->as<TypedArrayObject>().length())
     802           0 :                 result.setDenseOrTypedArrayElement();
     803             :             else
     804           0 :                 result.setNotFound();
     805           0 :             return;
     806             :         }
     807             :     }
     808             : 
     809             :     // Check for a native property.
     810       14774 :     if (Shape* shape = obj->lookup(cx, id))
     811          14 :         result.setNativeProperty(shape);
     812             :     else
     813       14760 :         result.setNotFound();
     814             : }
     815             : 
     816             : template <AllowGC allowGC>
     817             : static MOZ_ALWAYS_INLINE bool
     818       44965 : LookupPropertyInline(JSContext* cx,
     819             :                      typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
     820             :                      typename MaybeRooted<jsid, allowGC>::HandleType id,
     821             :                      typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
     822             :                      typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp)
     823             : {
     824             :     /* Search scopes starting with obj and following the prototype link. */
     825       59093 :     typename MaybeRooted<NativeObject*, allowGC>::RootType current(cx, obj);
     826             : 
     827       11182 :     while (true) {
     828             :         bool done;
     829       56147 :         if (!LookupOwnPropertyInline<allowGC>(cx, current, id, propp, &done))
     830       19850 :             return false;
     831       55494 :         if (done) {
     832       18147 :             if (propp)
     833       18147 :                 objp.set(current);
     834             :             else
     835           0 :                 objp.set(nullptr);
     836       18147 :             return true;
     837             :         }
     838             : 
     839       48529 :         typename MaybeRooted<JSObject*, allowGC>::RootType proto(cx, current->staticPrototype());
     840             : 
     841       37347 :         if (!proto)
     842       25768 :             break;
     843       11579 :         if (!proto->isNative()) {
     844         397 :             MOZ_ASSERT(!cx->helperThread());
     845             :             if (!allowGC)
     846           0 :                 return false;
     847         794 :             return LookupProperty(cx,
     848             :                                   MaybeRooted<JSObject*, allowGC>::toHandle(proto),
     849             :                                   MaybeRooted<jsid, allowGC>::toHandle(id),
     850             :                                   MaybeRooted<JSObject*, allowGC>::toMutableHandle(objp),
     851         397 :                                   MaybeRooted<PropertyResult, allowGC>::toMutableHandle(propp));
     852             :         }
     853             : 
     854       11182 :         current = &proto->template as<NativeObject>();
     855             :     }
     856             : 
     857       25768 :     objp.set(nullptr);
     858       25768 :     propp.setNotFound();
     859       25768 :     return true;
     860             : }
     861             : 
     862             : inline bool
     863         569 : ThrowIfNotConstructing(JSContext *cx, const CallArgs &args, const char *builtinName)
     864             : {
     865         569 :     if (args.isConstructing())
     866         569 :         return true;
     867             :     return JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
     868           0 :                                              JSMSG_BUILTIN_CTOR_NO_NEW, builtinName);
     869             : }
     870             : 
     871             : inline bool
     872         350 : IsPackedArray(JSObject* obj)
     873             : {
     874         968 :     return obj->is<ArrayObject>() && !obj->hasLazyGroup() &&
     875         957 :            !obj->group()->hasAllFlags(OBJECT_FLAG_NON_PACKED) &&
     876         648 :            obj->as<ArrayObject>().getDenseInitializedLength() == obj->as<ArrayObject>().length();
     877             : }
     878             : 
     879             : } // namespace js
     880             : 
     881             : #endif /* vm_NativeObject_inl_h */

Generated by: LCOV version 1.13