LCOV - code coverage report
Current view: top level - js/src/vm - UnboxedObject-inl.h (source / functions) Hit Total Coverage
Test: output.info Lines: 108 300 36.0 %
Date: 2017-07-14 16:53:18 Functions: 27 150 18.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_inl_h
       8             : #define vm_UnboxedObject_inl_h
       9             : 
      10             : #include "vm/UnboxedObject.h"
      11             : 
      12             : #include "gc/StoreBuffer-inl.h"
      13             : #include "vm/ArrayObject-inl.h"
      14             : #include "vm/NativeObject-inl.h"
      15             : 
      16             : namespace js {
      17             : 
      18             : static inline Value
      19        3899 : GetUnboxedValue(uint8_t* p, JSValueType type, bool maybeUninitialized)
      20             : {
      21        3899 :     switch (type) {
      22             :       case JSVAL_TYPE_BOOLEAN:
      23        2572 :         return BooleanValue(*p != 0);
      24             : 
      25             :       case JSVAL_TYPE_INT32:
      26           0 :         return Int32Value(*reinterpret_cast<int32_t*>(p));
      27             : 
      28             :       case JSVAL_TYPE_DOUBLE: {
      29             :         // During unboxed plain object creation, non-GC thing properties are
      30             :         // left uninitialized. This is normally fine, since the properties will
      31             :         // be filled in shortly, but if they are read before that happens we
      32             :         // need to make sure that doubles are canonical.
      33           0 :         double d = *reinterpret_cast<double*>(p);
      34           0 :         if (maybeUninitialized)
      35           0 :             return DoubleValue(JS::CanonicalizeNaN(d));
      36           0 :         return DoubleValue(d);
      37             :       }
      38             : 
      39             :       case JSVAL_TYPE_STRING:
      40           7 :         return StringValue(*reinterpret_cast<JSString**>(p));
      41             : 
      42             :       case JSVAL_TYPE_OBJECT:
      43        1320 :         return ObjectOrNullValue(*reinterpret_cast<JSObject**>(p));
      44             : 
      45             :       default:
      46           0 :         MOZ_CRASH("Invalid type for unboxed value");
      47             :     }
      48             : }
      49             : 
      50             : static inline void
      51           0 : SetUnboxedValueNoTypeChange(JSObject* unboxedObject,
      52             :                             uint8_t* p, JSValueType type, const Value& v,
      53             :                             bool preBarrier)
      54             : {
      55           0 :     switch (type) {
      56             :       case JSVAL_TYPE_BOOLEAN:
      57           0 :         *p = v.toBoolean();
      58           0 :         return;
      59             : 
      60             :       case JSVAL_TYPE_INT32:
      61           0 :         *reinterpret_cast<int32_t*>(p) = v.toInt32();
      62           0 :         return;
      63             : 
      64             :       case JSVAL_TYPE_DOUBLE:
      65           0 :         *reinterpret_cast<double*>(p) = v.toNumber();
      66           0 :         return;
      67             : 
      68             :       case JSVAL_TYPE_STRING: {
      69           0 :         MOZ_ASSERT(!IsInsideNursery(v.toString()));
      70           0 :         JSString** np = reinterpret_cast<JSString**>(p);
      71           0 :         if (preBarrier)
      72           0 :             JSString::writeBarrierPre(*np);
      73           0 :         *np = v.toString();
      74           0 :         return;
      75             :       }
      76             : 
      77             :       case JSVAL_TYPE_OBJECT: {
      78           0 :         JSObject** np = reinterpret_cast<JSObject**>(p);
      79             : 
      80             :         // Manually trigger post barriers on the whole object. If we treat
      81             :         // the pointer as a HeapPtrObject we will get confused later if the
      82             :         // object is converted to its native representation.
      83           0 :         JSObject* obj = v.toObjectOrNull();
      84           0 :         if (IsInsideNursery(obj) && !IsInsideNursery(unboxedObject))
      85           0 :             unboxedObject->zone()->group()->storeBuffer().putWholeCell(unboxedObject);
      86             : 
      87           0 :         if (preBarrier)
      88           0 :             JSObject::writeBarrierPre(*np);
      89           0 :         *np = obj;
      90           0 :         return;
      91             :       }
      92             : 
      93             :       default:
      94           0 :         MOZ_CRASH("Invalid type for unboxed value");
      95             :     }
      96             : }
      97             : 
      98             : static inline bool
      99        1003 : SetUnboxedValue(JSContext* cx, JSObject* unboxedObject, jsid id,
     100             :                 uint8_t* p, JSValueType type, const Value& v, bool preBarrier)
     101             : {
     102        1003 :     switch (type) {
     103             :       case JSVAL_TYPE_BOOLEAN:
     104         464 :         if (v.isBoolean()) {
     105         464 :             *p = v.toBoolean();
     106         464 :             return true;
     107             :         }
     108           0 :         return false;
     109             : 
     110             :       case JSVAL_TYPE_INT32:
     111           0 :         if (v.isInt32()) {
     112           0 :             *reinterpret_cast<int32_t*>(p) = v.toInt32();
     113           0 :             return true;
     114             :         }
     115           0 :         return false;
     116             : 
     117             :       case JSVAL_TYPE_DOUBLE:
     118           0 :         if (v.isNumber()) {
     119           0 :             *reinterpret_cast<double*>(p) = v.toNumber();
     120           0 :             return true;
     121             :         }
     122           0 :         return false;
     123             : 
     124             :       case JSVAL_TYPE_STRING:
     125         126 :         if (v.isString()) {
     126         125 :             MOZ_ASSERT(!IsInsideNursery(v.toString()));
     127         125 :             JSString** np = reinterpret_cast<JSString**>(p);
     128         125 :             if (preBarrier)
     129         125 :                 JSString::writeBarrierPre(*np);
     130         125 :             *np = v.toString();
     131         125 :             return true;
     132             :         }
     133           1 :         return false;
     134             : 
     135             :       case JSVAL_TYPE_OBJECT:
     136         413 :         if (v.isObjectOrNull()) {
     137         410 :             JSObject** np = reinterpret_cast<JSObject**>(p);
     138             : 
     139             :             // Update property types when writing object properties. Types for
     140             :             // other properties were captured when the unboxed layout was
     141             :             // created.
     142         410 :             AddTypePropertyId(cx, unboxedObject, id, v);
     143             : 
     144             :             // As above, trigger post barriers on the whole object.
     145         410 :             JSObject* obj = v.toObjectOrNull();
     146         410 :             if (IsInsideNursery(v.toObjectOrNull()) && !IsInsideNursery(unboxedObject))
     147         134 :                 unboxedObject->zone()->group()->storeBuffer().putWholeCell(unboxedObject);
     148             : 
     149         410 :             if (preBarrier)
     150         410 :                 JSObject::writeBarrierPre(*np);
     151         410 :             *np = obj;
     152         410 :             return true;
     153             :         }
     154           3 :         return false;
     155             : 
     156             :       default:
     157           0 :         MOZ_CRASH("Invalid type for unboxed value");
     158             :     }
     159             : }
     160             : 
     161             : /////////////////////////////////////////////////////////////////////
     162             : // UnboxedPlainObject
     163             : /////////////////////////////////////////////////////////////////////
     164             : 
     165             : inline const UnboxedLayout&
     166       14341 : UnboxedPlainObject::layout() const
     167             : {
     168       14341 :     return group()->unboxedLayout();
     169             : }
     170             : 
     171             : /////////////////////////////////////////////////////////////////////
     172             : // UnboxedArrayObject
     173             : /////////////////////////////////////////////////////////////////////
     174             : 
     175             : inline const UnboxedLayout&
     176           0 : UnboxedArrayObject::layout() const
     177             : {
     178           0 :     return group()->unboxedLayout();
     179             : }
     180             : 
     181             : inline void
     182           0 : UnboxedArrayObject::setLength(JSContext* cx, uint32_t length)
     183             : {
     184           0 :     if (length > INT32_MAX) {
     185             :         // Track objects with overflowing lengths in type information.
     186           0 :         MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW);
     187             :     }
     188             : 
     189           0 :     length_ = length;
     190           0 : }
     191             : 
     192             : inline void
     193           0 : UnboxedArrayObject::setInitializedLength(uint32_t initlen)
     194             : {
     195           0 :     if (initlen < initializedLength()) {
     196           0 :         switch (elementType()) {
     197             :           case JSVAL_TYPE_STRING:
     198           0 :             for (size_t i = initlen; i < initializedLength(); i++)
     199           0 :                 triggerPreBarrier<JSVAL_TYPE_STRING>(i);
     200           0 :             break;
     201             :           case JSVAL_TYPE_OBJECT:
     202           0 :             for (size_t i = initlen; i < initializedLength(); i++)
     203           0 :                 triggerPreBarrier<JSVAL_TYPE_OBJECT>(i);
     204           0 :             break;
     205             :           default:
     206           0 :             MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(elementType()));
     207             :         }
     208             :     }
     209           0 :     setInitializedLengthNoBarrier(initlen);
     210           0 : }
     211             : 
     212             : template <JSValueType Type>
     213             : inline bool
     214           0 : UnboxedArrayObject::setElementSpecific(JSContext* cx, size_t index, const Value& v)
     215             : {
     216           0 :     MOZ_ASSERT(index < initializedLength());
     217           0 :     MOZ_ASSERT(Type == elementType());
     218           0 :     uint8_t* p = elements() + index * UnboxedTypeSize(Type);
     219           0 :     return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true);
     220             : }
     221             : 
     222             : template <JSValueType Type>
     223             : inline void
     224           0 : UnboxedArrayObject::setElementNoTypeChangeSpecific(size_t index, const Value& v)
     225             : {
     226           0 :     MOZ_ASSERT(index < initializedLength());
     227           0 :     MOZ_ASSERT(Type == elementType());
     228           0 :     uint8_t* p = elements() + index * UnboxedTypeSize(Type);
     229           0 :     return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ true);
     230             : }
     231             : 
     232             : template <JSValueType Type>
     233             : inline bool
     234           0 : UnboxedArrayObject::initElementSpecific(JSContext* cx, size_t index, const Value& v)
     235             : {
     236           0 :     MOZ_ASSERT(index < initializedLength());
     237           0 :     MOZ_ASSERT(Type == elementType());
     238           0 :     uint8_t* p = elements() + index * UnboxedTypeSize(Type);
     239           0 :     return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false);
     240             : }
     241             : 
     242             : template <JSValueType Type>
     243             : inline void
     244           0 : UnboxedArrayObject::initElementNoTypeChangeSpecific(size_t index, const Value& v)
     245             : {
     246           0 :     MOZ_ASSERT(index < initializedLength());
     247           0 :     MOZ_ASSERT(Type == elementType());
     248           0 :     uint8_t* p = elements() + index * UnboxedTypeSize(Type);
     249           0 :     return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false);
     250             : }
     251             : 
     252             : template <JSValueType Type>
     253             : inline Value
     254           0 : UnboxedArrayObject::getElementSpecific(size_t index)
     255             : {
     256           0 :     MOZ_ASSERT(index < initializedLength());
     257           0 :     MOZ_ASSERT(Type == elementType());
     258           0 :     uint8_t* p = elements() + index * UnboxedTypeSize(Type);
     259           0 :     return GetUnboxedValue(p, Type, /* maybeUninitialized = */ false);
     260             : }
     261             : 
     262             : template <JSValueType Type>
     263             : inline void
     264           0 : UnboxedArrayObject::triggerPreBarrier(size_t index)
     265             : {
     266           0 :     MOZ_ASSERT(UnboxedTypeNeedsPreBarrier(Type));
     267             : 
     268           0 :     uint8_t* p = elements() + index * UnboxedTypeSize(Type);
     269             : 
     270             :     switch (Type) {
     271             :       case JSVAL_TYPE_STRING: {
     272           0 :         JSString** np = reinterpret_cast<JSString**>(p);
     273           0 :         JSString::writeBarrierPre(*np);
     274           0 :         break;
     275             :       }
     276             : 
     277             :       case JSVAL_TYPE_OBJECT: {
     278           0 :         JSObject** np = reinterpret_cast<JSObject**>(p);
     279           0 :         JSObject::writeBarrierPre(*np);
     280           0 :         break;
     281             :       }
     282             : 
     283             :       default:
     284           0 :         MOZ_CRASH("Bad type");
     285             :     }
     286           0 : }
     287             : 
     288             : /////////////////////////////////////////////////////////////////////
     289             : // Combined methods for NativeObject and UnboxedArrayObject accesses.
     290             : /////////////////////////////////////////////////////////////////////
     291             : 
     292             : static inline bool
     293        3417 : HasAnyBoxedOrUnboxedDenseElements(JSObject* obj)
     294             : {
     295        3417 :     return obj->isNative() || obj->is<UnboxedArrayObject>();
     296             : }
     297             : 
     298             : static inline size_t
     299        6069 : GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj)
     300             : {
     301        6069 :     if (obj->isNative())
     302        6058 :         return obj->as<NativeObject>().getDenseInitializedLength();
     303          11 :     if (obj->is<UnboxedArrayObject>())
     304           0 :         return obj->as<UnboxedArrayObject>().initializedLength();
     305          11 :     return 0;
     306             : }
     307             : 
     308             : static inline size_t
     309             : GetAnyBoxedOrUnboxedCapacity(JSObject* obj)
     310             : {
     311             :     if (obj->isNative())
     312             :         return obj->as<NativeObject>().getDenseCapacity();
     313             :     if (obj->is<UnboxedArrayObject>())
     314             :         return obj->as<UnboxedArrayObject>().capacity();
     315             :     return 0;
     316             : }
     317             : 
     318             : static inline Value
     319        2711 : GetAnyBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
     320             : {
     321        2711 :     if (obj->isNative())
     322        2711 :         return obj->as<NativeObject>().getDenseElement(index);
     323           0 :     return obj->as<UnboxedArrayObject>().getElement(index);
     324             : }
     325             : 
     326             : static inline size_t
     327         776 : GetAnyBoxedOrUnboxedArrayLength(JSObject* obj)
     328             : {
     329         776 :     if (obj->is<ArrayObject>())
     330         776 :         return obj->as<ArrayObject>().length();
     331           0 :     return obj->as<UnboxedArrayObject>().length();
     332             : }
     333             : 
     334             : static inline void
     335           4 : SetAnyBoxedOrUnboxedArrayLength(JSContext* cx, JSObject* obj, size_t length)
     336             : {
     337           4 :     if (obj->is<ArrayObject>()) {
     338           4 :         MOZ_ASSERT(length >= obj->as<ArrayObject>().length());
     339           4 :         obj->as<ArrayObject>().setLength(cx, length);
     340             :     } else {
     341           0 :         MOZ_ASSERT(length >= obj->as<UnboxedArrayObject>().length());
     342           0 :         obj->as<UnboxedArrayObject>().setLength(cx, length);
     343             :     }
     344           4 : }
     345             : 
     346             : static inline bool
     347           3 : SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
     348             : {
     349           3 :     if (obj->isNative()) {
     350           3 :         obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
     351           3 :         return true;
     352             :     }
     353           0 :     return obj->as<UnboxedArrayObject>().setElement(cx, index, value);
     354             : }
     355             : 
     356             : static inline bool
     357             : InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
     358             : {
     359             :     if (obj->isNative()) {
     360             :         obj->as<NativeObject>().initDenseElementWithType(cx, index, value);
     361             :         return true;
     362             :     }
     363             :     return obj->as<UnboxedArrayObject>().initElement(cx, index, value);
     364             : }
     365             : 
     366             : /////////////////////////////////////////////////////////////////////
     367             : // Template methods for NativeObject and UnboxedArrayObject accesses.
     368             : /////////////////////////////////////////////////////////////////////
     369             : 
     370             : static inline JSValueType
     371        3417 : GetBoxedOrUnboxedType(JSObject* obj)
     372             : {
     373        3417 :     if (obj->isNative())
     374        3417 :         return JSVAL_TYPE_MAGIC;
     375           0 :     return obj->as<UnboxedArrayObject>().elementType();
     376             : }
     377             : 
     378             : template <JSValueType Type>
     379             : static inline bool
     380          32 : HasBoxedOrUnboxedDenseElements(JSObject* obj)
     381             : {
     382             :     if (Type == JSVAL_TYPE_MAGIC)
     383          32 :         return obj->isNative();
     384           0 :     return obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().elementType() == Type;
     385             : }
     386             : 
     387             : template <JSValueType Type>
     388             : static inline size_t
     389         459 : GetBoxedOrUnboxedInitializedLength(JSObject* obj)
     390             : {
     391             :     if (Type == JSVAL_TYPE_MAGIC)
     392         459 :         return obj->as<NativeObject>().getDenseInitializedLength();
     393           0 :     return obj->as<UnboxedArrayObject>().initializedLength();
     394             : }
     395             : 
     396             : template <JSValueType Type>
     397             : static inline DenseElementResult
     398          26 : SetBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen)
     399             : {
     400          26 :     size_t oldInitlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
     401             :     if (Type == JSVAL_TYPE_MAGIC) {
     402          26 :         obj->as<NativeObject>().setDenseInitializedLength(initlen);
     403          26 :         if (initlen < oldInitlen)
     404           2 :             obj->as<NativeObject>().shrinkElements(cx, initlen);
     405             :     } else {
     406           0 :         obj->as<UnboxedArrayObject>().setInitializedLength(initlen);
     407           0 :         if (initlen < oldInitlen)
     408           0 :             obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen);
     409             :     }
     410          26 :     return DenseElementResult::Success;
     411             : }
     412             : 
     413             : template <JSValueType Type>
     414             : static inline size_t
     415           6 : GetBoxedOrUnboxedCapacity(JSObject* obj)
     416             : {
     417             :     if (Type == JSVAL_TYPE_MAGIC)
     418           6 :         return obj->as<NativeObject>().getDenseCapacity();
     419           0 :     return obj->as<UnboxedArrayObject>().capacity();
     420             : }
     421             : 
     422             : template <JSValueType Type>
     423             : static inline Value
     424        1939 : GetBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
     425             : {
     426             :     if (Type == JSVAL_TYPE_MAGIC)
     427        1939 :         return obj->as<NativeObject>().getDenseElement(index);
     428           0 :     return obj->as<UnboxedArrayObject>().getElementSpecific<Type>(index);
     429             : }
     430             : 
     431             : template <JSValueType Type>
     432             : static inline void
     433           0 : SetBoxedOrUnboxedDenseElementNoTypeChange(JSObject* obj, size_t index, const Value& value)
     434             : {
     435             :     if (Type == JSVAL_TYPE_MAGIC)
     436           0 :         obj->as<NativeObject>().setDenseElement(index, value);
     437             :     else
     438           0 :         obj->as<UnboxedArrayObject>().setElementNoTypeChangeSpecific<Type>(index, value);
     439           0 : }
     440             : 
     441             : template <JSValueType Type>
     442             : static inline bool
     443             : SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
     444             : {
     445             :     if (Type == JSVAL_TYPE_MAGIC) {
     446             :         obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
     447             :         return true;
     448             :     }
     449             :     return obj->as<UnboxedArrayObject>().setElementSpecific<Type>(cx, index, value);
     450             : }
     451             : 
     452             : template <JSValueType Type>
     453             : static inline DenseElementResult
     454           0 : EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count)
     455             : {
     456             :     if (Type == JSVAL_TYPE_MAGIC) {
     457           0 :         if (!obj->as<ArrayObject>().ensureElements(cx, count))
     458           0 :             return DenseElementResult::Failure;
     459             :     } else {
     460           0 :         if (obj->as<UnboxedArrayObject>().capacity() < count) {
     461           0 :             if (!obj->as<UnboxedArrayObject>().growElements(cx, count))
     462           0 :                 return DenseElementResult::Failure;
     463             :         }
     464             :     }
     465           0 :     return DenseElementResult::Success;
     466             : }
     467             : 
     468             : template <JSValueType Type>
     469             : static inline DenseElementResult
     470        2944 : SetOrExtendBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
     471             :                                        uint32_t start, const Value* vp, uint32_t count,
     472             :                                        ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update)
     473             : {
     474             :     if (Type == JSVAL_TYPE_MAGIC) {
     475        2944 :         NativeObject* nobj = &obj->as<NativeObject>();
     476             : 
     477        2944 :         if (nobj->denseElementsAreFrozen())
     478           0 :             return DenseElementResult::Incomplete;
     479             : 
     480        8832 :         if (obj->is<ArrayObject>() &&
     481        2944 :             !obj->as<ArrayObject>().lengthIsWritable() &&
     482           0 :             start + count >= obj->as<ArrayObject>().length())
     483             :         {
     484           0 :             return DenseElementResult::Incomplete;
     485             :         }
     486             : 
     487        2944 :         DenseElementResult result = nobj->ensureDenseElements(cx, start, count);
     488        2944 :         if (result != DenseElementResult::Success)
     489           0 :             return result;
     490             : 
     491        2944 :         if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length())
     492        2943 :             obj->as<ArrayObject>().setLengthInt32(start + count);
     493             : 
     494        2944 :         if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) {
     495         876 :             nobj->copyDenseElements(start, vp, count);
     496             :         } else {
     497        4243 :             for (size_t i = 0; i < count; i++)
     498        2175 :                 nobj->setDenseElementWithType(cx, start + i, vp[i]);
     499             :         }
     500             : 
     501        2944 :         return DenseElementResult::Success;
     502             :     }
     503             : 
     504           0 :     UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
     505             : 
     506           0 :     if (start > nobj->initializedLength())
     507           0 :         return DenseElementResult::Incomplete;
     508             : 
     509           0 :     if (start + count >= UnboxedArrayObject::MaximumCapacity)
     510           0 :         return DenseElementResult::Incomplete;
     511             : 
     512           0 :     if (start + count > nobj->capacity() && !nobj->growElements(cx, start + count))
     513           0 :         return DenseElementResult::Failure;
     514             : 
     515           0 :     size_t oldInitlen = nobj->initializedLength();
     516             : 
     517             :     // Overwrite any existing elements covered by the new range. If we fail
     518             :     // after this point due to some incompatible type being written to the
     519             :     // object's elements, afterwards the contents will be different from when
     520             :     // we started. The caller must retry the operation using a generic path,
     521             :     // which will overwrite the already-modified elements as well as the ones
     522             :     // that were left alone.
     523           0 :     size_t i = 0;
     524           0 :     if (updateTypes == ShouldUpdateTypes::DontUpdate) {
     525           0 :         for (size_t j = start; i < count && j < oldInitlen; i++, j++)
     526           0 :             nobj->setElementNoTypeChangeSpecific<Type>(j, vp[i]);
     527             :     } else {
     528           0 :         for (size_t j = start; i < count && j < oldInitlen; i++, j++) {
     529           0 :             if (!nobj->setElementSpecific<Type>(cx, j, vp[i]))
     530           0 :                 return DenseElementResult::Incomplete;
     531             :         }
     532             :     }
     533             : 
     534           0 :     if (i != count) {
     535           0 :         obj->as<UnboxedArrayObject>().setInitializedLength(start + count);
     536           0 :         if (updateTypes == ShouldUpdateTypes::DontUpdate) {
     537           0 :             for (; i < count; i++)
     538           0 :                 nobj->initElementNoTypeChangeSpecific<Type>(start + i, vp[i]);
     539             :         } else {
     540           0 :             for (; i < count; i++) {
     541           0 :                 if (!nobj->initElementSpecific<Type>(cx, start + i, vp[i])) {
     542           0 :                     nobj->setInitializedLengthNoBarrier(oldInitlen);
     543           0 :                     return DenseElementResult::Incomplete;
     544             :                 }
     545             :             }
     546             :         }
     547             :     }
     548             : 
     549           0 :     if (start + count >= nobj->length())
     550           0 :         nobj->setLength(cx, start + count);
     551             : 
     552           0 :     return DenseElementResult::Success;
     553             : }
     554             : 
     555             : template <JSValueType Type>
     556             : static inline DenseElementResult
     557          20 : MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart,
     558             :                                 uint32_t length)
     559             : {
     560          20 :     MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj));
     561             : 
     562             :     if (Type == JSVAL_TYPE_MAGIC) {
     563          20 :         if (obj->as<NativeObject>().denseElementsAreFrozen())
     564           0 :             return DenseElementResult::Incomplete;
     565             : 
     566          20 :         if (!obj->as<NativeObject>().maybeCopyElementsForWrite(cx))
     567           0 :             return DenseElementResult::Failure;
     568          20 :         obj->as<NativeObject>().moveDenseElements(dstStart, srcStart, length);
     569             :     } else {
     570           0 :         uint8_t* data = obj->as<UnboxedArrayObject>().elements();
     571           0 :         size_t elementSize = UnboxedTypeSize(Type);
     572             : 
     573           0 :         if (UnboxedTypeNeedsPreBarrier(Type) &&
     574           0 :             JS::shadow::Zone::asShadowZone(obj->zone())->needsIncrementalBarrier())
     575             :         {
     576             :             // Trigger pre barriers on any elements we are overwriting. See
     577             :             // NativeObject::moveDenseElements. No post barrier is needed as
     578             :             // only whole cell post barriers are used with unboxed objects.
     579           0 :             for (size_t i = 0; i < length; i++)
     580           0 :                 obj->as<UnboxedArrayObject>().triggerPreBarrier<Type>(dstStart + i);
     581             :         }
     582             : 
     583           0 :         memmove(data + dstStart * elementSize,
     584           0 :                 data + srcStart * elementSize,
     585             :                 length * elementSize);
     586             :     }
     587             : 
     588          20 :     return DenseElementResult::Success;
     589             : }
     590             : 
     591             : template <JSValueType DstType, JSValueType SrcType>
     592             : static inline DenseElementResult
     593           6 : CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
     594             :                                 uint32_t dstStart, uint32_t srcStart, uint32_t length)
     595             : {
     596           6 :     MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<SrcType>(src));
     597           6 :     MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<DstType>(dst));
     598           6 :     MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(dst) == dstStart);
     599           6 :     MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<SrcType>(src) >= srcStart + length);
     600           6 :     MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length);
     601             : 
     602           6 :     SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length);
     603             : 
     604             :     if (DstType == JSVAL_TYPE_MAGIC) {
     605             :         if (SrcType == JSVAL_TYPE_MAGIC) {
     606           6 :             const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart;
     607           6 :             dst->as<NativeObject>().initDenseElements(dstStart, vp, length);
     608             :         } else {
     609           0 :             for (size_t i = 0; i < length; i++) {
     610           0 :                 Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
     611           0 :                 dst->as<NativeObject>().initDenseElement(dstStart + i, v);
     612             :             }
     613             :         }
     614             :     } else if (DstType == SrcType) {
     615           0 :         uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
     616           0 :         uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
     617           0 :         size_t elementSize = UnboxedTypeSize(DstType);
     618             : 
     619           0 :         memcpy(dstData + dstStart * elementSize,
     620           0 :                srcData + srcStart * elementSize,
     621             :                length * elementSize);
     622             : 
     623             :         // Add a store buffer entry if we might have copied a nursery pointer to dst.
     624           0 :         if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst))
     625           0 :             dst->zone()->group()->storeBuffer().putWholeCell(dst);
     626             :     } else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) {
     627           0 :         uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
     628           0 :         uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
     629             : 
     630           0 :         for (size_t i = 0; i < length; i++) {
     631           0 :             int32_t v = *reinterpret_cast<int32_t*>(srcData + (srcStart + i) * sizeof(int32_t));
     632           0 :             *reinterpret_cast<double*>(dstData + (dstStart + i) * sizeof(double)) = v;
     633             :         }
     634             :     } else {
     635           0 :         for (size_t i = 0; i < length; i++) {
     636           0 :             Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
     637           0 :             dst->as<UnboxedArrayObject>().initElementNoTypeChangeSpecific<DstType>(dstStart + i, v);
     638             :         }
     639             :     }
     640             : 
     641           6 :     return DenseElementResult::Success;
     642             : }
     643             : 
     644             : /////////////////////////////////////////////////////////////////////
     645             : // Dispatch to specialized methods based on the type of an object.
     646             : /////////////////////////////////////////////////////////////////////
     647             : 
     648             : // Goop to fix MSVC. See DispatchTraceKindTyped in TraceKind.h.
     649             : // The clang-cl front end defines _MSC_VER, but still requires the explicit
     650             : // template declaration, so we must test for __clang__ here as well.
     651             : #if defined(_MSC_VER) && !defined(__clang__)
     652             : # define DEPENDENT_TEMPLATE_HINT
     653             : #else
     654             : # define DEPENDENT_TEMPLATE_HINT template
     655             : #endif
     656             : 
     657             : // Function to dispatch a method specialized to whatever boxed or unboxed dense
     658             : // elements which an input object has.
     659             : template <typename F>
     660             : DenseElementResult
     661        3405 : CallBoxedOrUnboxedSpecialization(F f, JSObject* obj)
     662             : {
     663        3405 :     if (!HasAnyBoxedOrUnboxedDenseElements(obj))
     664           0 :         return DenseElementResult::Incomplete;
     665        3405 :     switch (GetBoxedOrUnboxedType(obj)) {
     666             :       case JSVAL_TYPE_MAGIC:
     667        3405 :         return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>();
     668             :       case JSVAL_TYPE_BOOLEAN:
     669           0 :         return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>();
     670             :       case JSVAL_TYPE_INT32:
     671           0 :         return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>();
     672             :       case JSVAL_TYPE_DOUBLE:
     673           0 :         return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>();
     674             :       case JSVAL_TYPE_STRING:
     675           0 :         return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>();
     676             :       case JSVAL_TYPE_OBJECT:
     677           0 :         return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>();
     678             :       default:
     679           0 :         MOZ_CRASH();
     680             :     }
     681             : }
     682             : 
     683             : // As above, except the specialization can reflect the unboxed type of two objects.
     684             : template <typename F>
     685             : DenseElementResult
     686           6 : CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2)
     687             : {
     688           6 :     if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2))
     689           0 :         return DenseElementResult::Incomplete;
     690             : 
     691             : #define SPECIALIZE_OBJ2(TYPE)                                                     \
     692             :     switch (GetBoxedOrUnboxedType(obj2)) {                                        \
     693             :       case JSVAL_TYPE_MAGIC:                                                      \
     694             :         return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_MAGIC>();   \
     695             :       case JSVAL_TYPE_BOOLEAN:                                                    \
     696             :         return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_BOOLEAN>(); \
     697             :       case JSVAL_TYPE_INT32:                                                      \
     698             :         return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_INT32>();   \
     699             :       case JSVAL_TYPE_DOUBLE:                                                     \
     700             :         return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_DOUBLE>();  \
     701             :       case JSVAL_TYPE_STRING:                                                     \
     702             :         return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_STRING>();  \
     703             :       case JSVAL_TYPE_OBJECT:                                                     \
     704             :         return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_OBJECT>();  \
     705             :       default:                                                                    \
     706             :         MOZ_CRASH();                                                              \
     707             :     }
     708             : 
     709           6 :     switch (GetBoxedOrUnboxedType(obj1)) {
     710             :       case JSVAL_TYPE_MAGIC:
     711           6 :         SPECIALIZE_OBJ2(JSVAL_TYPE_MAGIC)
     712             :       case JSVAL_TYPE_BOOLEAN:
     713           0 :         SPECIALIZE_OBJ2(JSVAL_TYPE_BOOLEAN)
     714             :       case JSVAL_TYPE_INT32:
     715           0 :         SPECIALIZE_OBJ2(JSVAL_TYPE_INT32)
     716             :       case JSVAL_TYPE_DOUBLE:
     717           0 :         SPECIALIZE_OBJ2(JSVAL_TYPE_DOUBLE)
     718             :       case JSVAL_TYPE_STRING:
     719           0 :         SPECIALIZE_OBJ2(JSVAL_TYPE_STRING)
     720             :       case JSVAL_TYPE_OBJECT:
     721           0 :         SPECIALIZE_OBJ2(JSVAL_TYPE_OBJECT)
     722             :       default:
     723           0 :         MOZ_CRASH();
     724             :     }
     725             : 
     726             : #undef SPECIALIZE_OBJ2
     727             : }
     728             : 
     729             : #undef DEPENDENT_TEMPLATE_HINT
     730             : 
     731             : #define DefineBoxedOrUnboxedFunctor1(Signature, A)                      \
     732             : struct Signature ## Functor {                                           \
     733             :     A a;                                                                \
     734             :     explicit Signature ## Functor(A a)                                  \
     735             :       : a(a)                                                            \
     736             :     {}                                                                  \
     737             :     template <JSValueType Type>                                         \
     738             :     DenseElementResult operator()() {                                   \
     739             :         return Signature<Type>(a);                                      \
     740             :     }                                                                   \
     741             : }
     742             : 
     743             : #define DefineBoxedOrUnboxedFunctor3(Signature, A, B, C)                \
     744             : struct Signature ## Functor {                                           \
     745             :     A a; B b; C c;                                                      \
     746             :     Signature ## Functor(A a, B b, C c)                                 \
     747             :       : a(a), b(b), c(c)                                                \
     748             :     {}                                                                  \
     749             :     template <JSValueType Type>                                         \
     750             :     DenseElementResult operator()() {                                   \
     751             :         return Signature<Type>(a, b, c);                                \
     752             :     }                                                                   \
     753             : }
     754             : 
     755             : #define DefineBoxedOrUnboxedFunctor4(Signature, A, B, C, D)             \
     756             : struct Signature ## Functor {                                           \
     757             :     A a; B b; C c; D d;                                                 \
     758             :     Signature ## Functor(A a, B b, C c, D d)                            \
     759             :       : a(a), b(b), c(c), d(d)                                          \
     760             :     {}                                                                  \
     761             :     template <JSValueType Type>                                         \
     762             :     DenseElementResult operator()() {                                   \
     763             :         return Signature<Type>(a, b, c, d);                             \
     764             :     }                                                                   \
     765             : }
     766             : 
     767             : #define DefineBoxedOrUnboxedFunctorPair4(Signature, A, B, C, D)         \
     768             : struct Signature ## Functor {                                           \
     769             :     A a; B b; C c; D d;                                                 \
     770             :     Signature ## Functor(A a, B b, C c, D d)                            \
     771             :       : a(a), b(b), c(c), d(d)                                          \
     772             :     {}                                                                  \
     773             :     template <JSValueType TypeOne, JSValueType TypeTwo>                 \
     774             :     DenseElementResult operator()() {                                   \
     775             :         return Signature<TypeOne, TypeTwo>(a, b, c, d);                 \
     776             :     }                                                                   \
     777             : }
     778             : 
     779             : #define DefineBoxedOrUnboxedFunctor5(Signature, A, B, C, D, E)          \
     780             : struct Signature ## Functor {                                           \
     781             :     A a; B b; C c; D d; E e;                                            \
     782             :     Signature ## Functor(A a, B b, C c, D d, E e)                       \
     783             :       : a(a), b(b), c(c), d(d), e(e)                                    \
     784             :     {}                                                                  \
     785             :     template <JSValueType Type>                                         \
     786             :     DenseElementResult operator()() {                                   \
     787             :         return Signature<Type>(a, b, c, d, e);                          \
     788             :     }                                                                   \
     789             : }
     790             : 
     791             : #define DefineBoxedOrUnboxedFunctor6(Signature, A, B, C, D, E, F)       \
     792             : struct Signature ## Functor {                                           \
     793             :     A a; B b; C c; D d; E e; F f;                                       \
     794             :     Signature ## Functor(A a, B b, C c, D d, E e, F f)                  \
     795             :       : a(a), b(b), c(c), d(d), e(e), f(f)                              \
     796             :     {}                                                                  \
     797             :     template <JSValueType Type>                                         \
     798             :     DenseElementResult operator()() {                                   \
     799             :         return Signature<Type>(a, b, c, d, e, f);                       \
     800             :     }                                                                   \
     801             : }
     802             : 
     803             : #define DefineBoxedOrUnboxedFunctorPair6(Signature, A, B, C, D, E, F)   \
     804             : struct Signature ## Functor {                                           \
     805             :     A a; B b; C c; D d; E e; F f;                                       \
     806             :     Signature ## Functor(A a, B b, C c, D d, E e, F f)                  \
     807             :       : a(a), b(b), c(c), d(d), e(e), f(f)                              \
     808             :     {}                                                                  \
     809             :     template <JSValueType TypeOne, JSValueType TypeTwo>                 \
     810             :     DenseElementResult operator()() {                                   \
     811             :         return Signature<TypeOne, TypeTwo>(a, b, c, d, e, f);           \
     812             :     }                                                                   \
     813             : }
     814             : 
     815             : DenseElementResult
     816             : SetOrExtendAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
     817             :                                           uint32_t start, const Value* vp, uint32_t count,
     818             :                                           ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
     819             : 
     820             : DenseElementResult
     821             : MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
     822             :                                    uint32_t dstStart, uint32_t srcStart, uint32_t length);
     823             : 
     824             : DenseElementResult
     825             : CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
     826             :                                    uint32_t dstStart, uint32_t srcStart, uint32_t length);
     827             : 
     828             : void
     829             : SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen);
     830             : 
     831             : DenseElementResult
     832             : EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count);
     833             : 
     834             : } // namespace js
     835             : 
     836             : #endif // vm_UnboxedObject_inl_h

Generated by: LCOV version 1.13