LCOV - code coverage report
Current view: top level - js/src/vm - TypedArrayObject.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 24 946 2.5 %
Date: 2017-07-14 16:53:18 Functions: 31 393 7.9 %
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             : #include "vm/TypedArrayObject-inl.h"
       8             : #include "vm/TypedArrayObject.h"
       9             : 
      10             : #include "mozilla/Alignment.h"
      11             : #include "mozilla/Casting.h"
      12             : #include "mozilla/FloatingPoint.h"
      13             : #include "mozilla/PodOperations.h"
      14             : 
      15             : #include <string.h>
      16             : #ifndef XP_WIN
      17             : # include <sys/mman.h>
      18             : #endif
      19             : 
      20             : #include "jsapi.h"
      21             : #include "jsarray.h"
      22             : #include "jscntxt.h"
      23             : #include "jscpucfg.h"
      24             : #include "jsnum.h"
      25             : #include "jsobj.h"
      26             : #include "jstypes.h"
      27             : #include "jsutil.h"
      28             : #ifdef XP_WIN
      29             : # include "jswin.h"
      30             : #endif
      31             : #include "jswrapper.h"
      32             : 
      33             : #include "builtin/DataViewObject.h"
      34             : #include "builtin/TypedObjectConstants.h"
      35             : #include "gc/Barrier.h"
      36             : #include "gc/Marking.h"
      37             : #include "jit/InlinableNatives.h"
      38             : #include "js/Conversions.h"
      39             : #include "vm/ArrayBufferObject.h"
      40             : #include "vm/GlobalObject.h"
      41             : #include "vm/Interpreter.h"
      42             : #include "vm/PIC.h"
      43             : #include "vm/SelfHosting.h"
      44             : #include "vm/SharedMem.h"
      45             : #include "vm/WrapperObject.h"
      46             : 
      47             : #include "jsatominlines.h"
      48             : 
      49             : #include "gc/Nursery-inl.h"
      50             : #include "gc/StoreBuffer-inl.h"
      51             : #include "vm/ArrayBufferObject-inl.h"
      52             : #include "vm/NativeObject-inl.h"
      53             : #include "vm/Shape-inl.h"
      54             : 
      55             : using namespace js;
      56             : using namespace js::gc;
      57             : 
      58             : using mozilla::AssertedCast;
      59             : using JS::CanonicalizeNaN;
      60             : using JS::ToInt32;
      61             : using JS::ToUint32;
      62             : 
      63             : /*
      64             :  * TypedArrayObject
      65             :  *
      66             :  * The non-templated base class for the specific typed implementations.
      67             :  * This class holds all the member variables that are used by
      68             :  * the subclasses.
      69             :  */
      70             : 
      71             : /* static */ int
      72           0 : TypedArrayObject::lengthOffset()
      73             : {
      74           0 :     return NativeObject::getFixedSlotOffset(LENGTH_SLOT);
      75             : }
      76             : 
      77             : /* static */ int
      78           0 : TypedArrayObject::dataOffset()
      79             : {
      80           0 :     return NativeObject::getPrivateDataOffset(DATA_SLOT);
      81             : }
      82             : 
      83             : void
      84           0 : TypedArrayObject::notifyBufferDetached(JSContext* cx, void* newData)
      85             : {
      86           0 :     MOZ_ASSERT(!isSharedMemory());
      87           0 :     setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(0));
      88           0 :     setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0));
      89             : 
      90             :     // If the object is in the nursery, the buffer will be freed by the next
      91             :     // nursery GC. Free the data slot pointer if the object has no inline data.
      92           0 :     Nursery& nursery = cx->nursery();
      93           0 :     if (isTenured() && !hasBuffer() && !hasInlineElements() &&
      94           0 :         !nursery.isInside(elements()))
      95             :     {
      96           0 :         js_free(elements());
      97             :     }
      98             : 
      99           0 :     setPrivate(newData);
     100           0 : }
     101             : 
     102             : /* static */ bool
     103           0 : TypedArrayObject::is(HandleValue v)
     104             : {
     105           0 :     return v.isObject() && v.toObject().is<TypedArrayObject>();
     106             : }
     107             : 
     108             : /* static */ bool
     109           0 : TypedArrayObject::ensureHasBuffer(JSContext* cx, Handle<TypedArrayObject*> tarray)
     110             : {
     111           0 :     if (tarray->hasBuffer())
     112           0 :         return true;
     113             : 
     114           0 :     Rooted<ArrayBufferObject*> buffer(cx, ArrayBufferObject::create(cx, tarray->byteLength()));
     115           0 :     if (!buffer)
     116           0 :         return false;
     117             : 
     118           0 :     if (!buffer->addView(cx, tarray))
     119           0 :         return false;
     120             : 
     121             :     // tarray is not shared, because if it were it would have a buffer.
     122           0 :     memcpy(buffer->dataPointer(), tarray->viewDataUnshared(), tarray->byteLength());
     123             : 
     124             :     // If the object is in the nursery, the buffer will be freed by the next
     125             :     // nursery GC. Free the data slot pointer if the object has no inline data.
     126           0 :     Nursery& nursery = cx->nursery();
     127           0 :     if (tarray->isTenured() && !tarray->hasInlineElements() &&
     128           0 :         !nursery.isInside(tarray->elements()))
     129             :     {
     130           0 :         js_free(tarray->elements());
     131             :     }
     132             : 
     133           0 :     tarray->setPrivate(buffer->dataPointer());
     134             : 
     135           0 :     tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*buffer));
     136             : 
     137             :     // Notify compiled jit code that the base pointer has moved.
     138           0 :     MarkObjectStateChange(cx, tarray);
     139             : 
     140           0 :     return true;
     141             : }
     142             : 
     143             : #ifdef DEBUG
     144             : void
     145           0 : TypedArrayObject::assertZeroLengthArrayData() const
     146             : {
     147           0 :     if (length() == 0 && !hasBuffer()) {
     148           0 :         uint8_t* end = fixedData(TypedArrayObject::FIXED_DATA_START);
     149           0 :         MOZ_ASSERT(end[0] == ZeroLengthArrayData);
     150             :     }
     151           0 : }
     152             : #endif
     153             : 
     154             : /* static */ void
     155           0 : TypedArrayObject::trace(JSTracer* trc, JSObject* objArg)
     156             : {
     157             :     // Handle all tracing required when the object has a buffer.
     158           0 :     ArrayBufferViewObject::trace(trc, objArg);
     159           0 : }
     160             : 
     161             : void
     162           0 : TypedArrayObject::finalize(FreeOp* fop, JSObject* obj)
     163             : {
     164           0 :     MOZ_ASSERT(!IsInsideNursery(obj));
     165           0 :     TypedArrayObject* curObj = &obj->as<TypedArrayObject>();
     166             : 
     167             :     // Template objects or discarded objects (which didn't have enough room
     168             :     // for inner elements). Don't have anything to free.
     169           0 :     if (!curObj->elementsRaw())
     170           0 :         return;
     171             : 
     172           0 :     curObj->assertZeroLengthArrayData();
     173             : 
     174             :     // Typed arrays with a buffer object do not need to be free'd
     175           0 :     if (curObj->hasBuffer())
     176           0 :         return;
     177             : 
     178             :     // Free the data slot pointer if it does not point into the old JSObject.
     179           0 :     if (!curObj->hasInlineElements())
     180           0 :         js_free(curObj->elements());
     181             : }
     182             : 
     183             : /* static */ void
     184           0 : TypedArrayObject::objectMoved(JSObject* obj, const JSObject* old)
     185             : {
     186           0 :     TypedArrayObject* newObj = &obj->as<TypedArrayObject>();
     187           0 :     const TypedArrayObject* oldObj = &old->as<TypedArrayObject>();
     188             : 
     189             :     // Typed arrays with a buffer object do not need an update.
     190           0 :     if (oldObj->hasBuffer())
     191           0 :         return;
     192             : 
     193             :     // Update the data slot pointer if it points to the old JSObject.
     194           0 :     if (oldObj->hasInlineElements())
     195           0 :         newObj->setInlineElements();
     196             : }
     197             : 
     198             : /* static */ size_t
     199           0 : TypedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* obj, const JSObject* old,
     200             :                                            gc::AllocKind newAllocKind)
     201             : {
     202           0 :     TypedArrayObject* newObj = &obj->as<TypedArrayObject>();
     203           0 :     const TypedArrayObject* oldObj = &old->as<TypedArrayObject>();
     204           0 :     MOZ_ASSERT(newObj->elementsRaw() == oldObj->elementsRaw());
     205           0 :     MOZ_ASSERT(obj->isTenured());
     206             : 
     207             :     // Typed arrays with a buffer object do not need an update.
     208           0 :     if (oldObj->hasBuffer())
     209           0 :         return 0;
     210             : 
     211           0 :     Nursery& nursery = obj->zone()->group()->nursery();
     212           0 :     void* buf = oldObj->elements();
     213             : 
     214           0 :     if (!nursery.isInside(buf)) {
     215           0 :         nursery.removeMallocedBuffer(buf);
     216           0 :         return 0;
     217             :     }
     218             : 
     219             :     // Determine if we can use inline data for the target array. If this is
     220             :     // possible, the nursery will have picked an allocation size that is large
     221             :     // enough.
     222           0 :     size_t nbytes = 0;
     223           0 :     switch (oldObj->type()) {
     224             : #define OBJECT_MOVED_TYPED_ARRAY(T, N) \
     225             :       case Scalar::N: \
     226             :         nbytes = oldObj->length() * sizeof(T); \
     227             :         break;
     228           0 : JS_FOR_EACH_TYPED_ARRAY(OBJECT_MOVED_TYPED_ARRAY)
     229             : #undef OBJECT_MOVED_TYPED_ARRAY
     230             :       default:
     231           0 :         MOZ_CRASH("Unsupported TypedArray type");
     232             :     }
     233             : 
     234           0 :     size_t headerSize = dataOffset() + sizeof(HeapSlot);
     235             : 
     236             :     // See AllocKindForLazyBuffer.
     237           0 :     MOZ_ASSERT_IF(nbytes == 0, headerSize + sizeof(uint8_t) <= GetGCKindBytes(newAllocKind));
     238             : 
     239           0 :     if (headerSize + nbytes <= GetGCKindBytes(newAllocKind)) {
     240           0 :         MOZ_ASSERT(oldObj->hasInlineElements());
     241             : #ifdef DEBUG
     242           0 :         if (nbytes == 0) {
     243           0 :             uint8_t* output = newObj->fixedData(TypedArrayObject::FIXED_DATA_START);
     244           0 :             output[0] = ZeroLengthArrayData;
     245             :         }
     246             : #endif
     247           0 :         newObj->setInlineElements();
     248             :     } else {
     249           0 :         MOZ_ASSERT(!oldObj->hasInlineElements());
     250           0 :         AutoEnterOOMUnsafeRegion oomUnsafe;
     251           0 :         nbytes = JS_ROUNDUP(nbytes, sizeof(Value));
     252           0 :         void* data = newObj->zone()->pod_malloc<uint8_t>(nbytes);
     253           0 :         if (!data)
     254           0 :             oomUnsafe.crash("Failed to allocate typed array elements while tenuring.");
     255           0 :         MOZ_ASSERT(!nursery.isInside(data));
     256           0 :         newObj->initPrivate(data);
     257             :     }
     258             : 
     259           0 :     mozilla::PodCopy(newObj->elements(), oldObj->elements(), nbytes);
     260             : 
     261             :     // Set a forwarding pointer for the element buffers in case they were
     262             :     // preserved on the stack by Ion.
     263           0 :     nursery.maybeSetForwardingPointer(trc, oldObj->elements(), newObj->elements(),
     264           0 :                                       /* direct = */nbytes >= sizeof(uintptr_t));
     265             : 
     266           0 :     return newObj->hasInlineElements() ? 0 : nbytes;
     267             : }
     268             : 
     269             : bool
     270           0 : TypedArrayObject::hasInlineElements() const
     271             : {
     272           0 :     return elements() == this->fixedData(TypedArrayObject::FIXED_DATA_START) &&
     273           0 :         byteLength() <= TypedArrayObject::INLINE_BUFFER_LIMIT;
     274             : }
     275             : 
     276             : void
     277           0 : TypedArrayObject::setInlineElements()
     278             : {
     279           0 :     char* dataSlot = reinterpret_cast<char*>(this) + this->dataOffset();
     280           0 :     *reinterpret_cast<void**>(dataSlot) = this->fixedData(TypedArrayObject::FIXED_DATA_START);
     281           0 : }
     282             : 
     283             : /* Helper clamped uint8_t type */
     284             : 
     285             : uint32_t JS_FASTCALL
     286           0 : js::ClampDoubleToUint8(const double x)
     287             : {
     288             :     // Not < so that NaN coerces to 0
     289           0 :     if (!(x >= 0))
     290           0 :         return 0;
     291             : 
     292           0 :     if (x > 255)
     293           0 :         return 255;
     294             : 
     295           0 :     double toTruncate = x + 0.5;
     296           0 :     uint8_t y = uint8_t(toTruncate);
     297             : 
     298             :     /*
     299             :      * now val is rounded to nearest, ties rounded up.  We want
     300             :      * rounded to nearest ties to even, so check whether we had a
     301             :      * tie.
     302             :      */
     303           0 :     if (y == toTruncate) {
     304             :         /*
     305             :          * It was a tie (since adding 0.5 gave us the exact integer
     306             :          * we want).  Since we rounded up, we either already have an
     307             :          * even number or we have an odd number but the number we
     308             :          * want is one less.  So just unconditionally masking out the
     309             :          * ones bit should do the trick to get us the value we
     310             :          * want.
     311             :          */
     312           0 :         return y & ~1;
     313             :     }
     314             : 
     315           0 :     return y;
     316             : }
     317             : 
     318             : template<typename ElementType>
     319             : static inline JSObject*
     320             : NewArray(JSContext* cx, uint32_t nelements);
     321             : 
     322             : namespace {
     323             : 
     324             : enum class SpeciesConstructorOverride {
     325             :     None,
     326             :     ArrayBuffer
     327             : };
     328             : 
     329             : template<typename NativeType>
     330             : class TypedArrayObjectTemplate : public TypedArrayObject
     331             : {
     332             :     friend class TypedArrayObject;
     333             : 
     334             :   public:
     335          60 :     static constexpr Scalar::Type ArrayTypeID() { return TypeIDOfType<NativeType>::id; }
     336           0 :     static bool ArrayTypeIsUnsigned() { return TypeIsUnsigned<NativeType>(); }
     337           0 :     static bool ArrayTypeIsFloatingPoint() { return TypeIsFloatingPoint<NativeType>(); }
     338             : 
     339             :     static const size_t BYTES_PER_ELEMENT = sizeof(NativeType);
     340             : 
     341             :     static JSObject*
     342          60 :     createPrototype(JSContext* cx, JSProtoKey key)
     343             :     {
     344          60 :         Handle<GlobalObject*> global = cx->global();
     345         120 :         RootedObject typedArrayProto(cx, GlobalObject::getOrCreateTypedArrayPrototype(cx, global));
     346          60 :         if (!typedArrayProto)
     347           0 :             return nullptr;
     348             : 
     349          60 :         const Class* clasp = TypedArrayObject::protoClassForType(ArrayTypeID());
     350          60 :         return GlobalObject::createBlankPrototypeInheriting(cx, global, clasp, typedArrayProto);
     351             :     }
     352             : 
     353             :     static JSObject*
     354          60 :     createConstructor(JSContext* cx, JSProtoKey key)
     355             :     {
     356          60 :         Handle<GlobalObject*> global = cx->global();
     357         120 :         RootedFunction ctorProto(cx, GlobalObject::getOrCreateTypedArrayConstructor(cx, global));
     358          60 :         if (!ctorProto)
     359           0 :             return nullptr;
     360             : 
     361         120 :         JSFunction* fun = NewFunctionWithProto(cx, class_constructor, 3,
     362             :                                                JSFunction::NATIVE_CTOR, nullptr,
     363             :                                                ClassName(key, cx),
     364             :                                                ctorProto, gc::AllocKind::FUNCTION,
     365          60 :                                                SingletonObject);
     366             : 
     367          60 :         if (fun)
     368          60 :             fun->setJitInfo(&jit::JitInfo_TypedArrayConstructor);
     369             : 
     370          60 :         return fun;
     371             :     }
     372             : 
     373           0 :     static inline const Class* instanceClass()
     374             :     {
     375           0 :         return TypedArrayObject::classForType(ArrayTypeID());
     376             :     }
     377             : 
     378             :     static bool is(HandleValue v) {
     379             :         return v.isObject() && v.toObject().hasClass(instanceClass());
     380             :     }
     381             : 
     382             :     static void
     383           0 :     setIndexValue(TypedArrayObject& tarray, uint32_t index, double d)
     384             :     {
     385             :         // If the array is an integer array, we only handle up to
     386             :         // 32-bit ints from this point on.  if we want to handle
     387             :         // 64-bit ints, we'll need some changes.
     388             : 
     389             :         // Assign based on characteristics of the destination type
     390           0 :         if (ArrayTypeIsFloatingPoint()) {
     391           0 :             setIndex(tarray, index, NativeType(d));
     392           0 :         } else if (ArrayTypeIsUnsigned()) {
     393           0 :             MOZ_ASSERT(sizeof(NativeType) <= 4);
     394           0 :             uint32_t n = ToUint32(d);
     395           0 :             setIndex(tarray, index, NativeType(n));
     396           0 :         } else if (ArrayTypeID() == Scalar::Uint8Clamped) {
     397             :             // The uint8_clamped type has a special rounding converter
     398             :             // for doubles.
     399           0 :             setIndex(tarray, index, NativeType(d));
     400             :         } else {
     401           0 :             MOZ_ASSERT(sizeof(NativeType) <= 4);
     402           0 :             int32_t n = ToInt32(d);
     403           0 :             setIndex(tarray, index, NativeType(n));
     404             :         }
     405           0 :     }
     406             : 
     407             :     static TypedArrayObject*
     408           0 :     makeProtoInstance(JSContext* cx, HandleObject proto, AllocKind allocKind)
     409             :     {
     410           0 :         MOZ_ASSERT(proto);
     411             : 
     412           0 :         JSObject* obj = NewObjectWithClassProto(cx, instanceClass(), proto, allocKind);
     413           0 :         return obj ? &obj->as<TypedArrayObject>() : nullptr;
     414             :     }
     415             : 
     416             :     static TypedArrayObject*
     417           0 :     makeTypedInstance(JSContext* cx, uint32_t len, gc::AllocKind allocKind)
     418             :     {
     419           0 :         const Class* clasp = instanceClass();
     420           0 :         if (len * sizeof(NativeType) >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
     421           0 :             JSObject* obj = NewBuiltinClassInstance(cx, clasp, allocKind, SingletonObject);
     422           0 :             if (!obj)
     423           0 :                 return nullptr;
     424           0 :             return &obj->as<TypedArrayObject>();
     425             :         }
     426             : 
     427             :         jsbytecode* pc;
     428           0 :         RootedScript script(cx, cx->currentScript(&pc));
     429           0 :         NewObjectKind newKind = GenericObject;
     430           0 :         if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, clasp))
     431           0 :             newKind = SingletonObject;
     432           0 :         RootedObject obj(cx, NewBuiltinClassInstance(cx, clasp, allocKind, newKind));
     433           0 :         if (!obj)
     434           0 :             return nullptr;
     435             : 
     436           0 :         if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj,
     437             :                                                                  newKind == SingletonObject))
     438             :         {
     439           0 :             return nullptr;
     440             :         }
     441             : 
     442           0 :         return &obj->as<TypedArrayObject>();
     443             :     }
     444             : 
     445             :     static TypedArrayObject*
     446           0 :     makeInstance(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> buffer, uint32_t byteOffset,
     447             :                  uint32_t len, HandleObject proto)
     448             :     {
     449           0 :         MOZ_ASSERT_IF(!buffer, byteOffset == 0);
     450           0 :         MOZ_ASSERT_IF(buffer, !buffer->isDetached());
     451           0 :         MOZ_ASSERT(len < INT32_MAX / sizeof(NativeType));
     452             : 
     453             :         gc::AllocKind allocKind = buffer
     454           0 :                                   ? GetGCObjectKind(instanceClass())
     455           0 :                                   : AllocKindForLazyBuffer(len * sizeof(NativeType));
     456             : 
     457             :         // Subclassing mandates that we hand in the proto every time. Most of
     458             :         // the time, though, that [[Prototype]] will not be interesting. If
     459             :         // it isn't, we can do some more TI optimizations.
     460           0 :         RootedObject checkProto(cx);
     461           0 :         if (proto && !GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &checkProto))
     462           0 :             return nullptr;
     463             : 
     464           0 :         AutoSetNewObjectMetadata metadata(cx);
     465           0 :         Rooted<TypedArrayObject*> obj(cx);
     466           0 :         if (proto && proto != checkProto)
     467           0 :             obj = makeProtoInstance(cx, proto, allocKind);
     468             :         else
     469           0 :             obj = makeTypedInstance(cx, len, allocKind);
     470           0 :         if (!obj)
     471           0 :             return nullptr;
     472             : 
     473           0 :         bool isSharedMemory = buffer && IsSharedArrayBuffer(buffer.get());
     474             : 
     475           0 :         obj->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectOrNullValue(buffer));
     476             :         // This is invariant.  Self-hosting code that sets BUFFER_SLOT
     477             :         // (if it does) must maintain it, should it need to.
     478           0 :         if (isSharedMemory)
     479           0 :             obj->setIsSharedMemory();
     480             : 
     481           0 :         if (buffer) {
     482           0 :             obj->initViewData(buffer->dataPointerEither() + byteOffset);
     483             : 
     484             :             // If the buffer is for an inline typed object, the data pointer
     485             :             // may be in the nursery, so include a barrier to make sure this
     486             :             // object is updated if that typed object moves.
     487           0 :             auto ptr = buffer->dataPointerEither();
     488           0 :             if (!IsInsideNursery(obj) && cx->nursery().isInside(ptr)) {
     489             :                 // Shared buffer data should never be nursery-allocated, so we
     490             :                 // need to fail here if isSharedMemory.  However, mmap() can
     491             :                 // place a SharedArrayRawBuffer up against the bottom end of a
     492             :                 // nursery chunk, and a zero-length buffer will erroneously be
     493             :                 // perceived as being inside the nursery; sidestep that.
     494           0 :                 if (isSharedMemory) {
     495           0 :                     MOZ_ASSERT(buffer->byteLength() == 0 &&
     496             :                                (uintptr_t(ptr.unwrapValue()) & gc::ChunkMask) == 0);
     497             :                 } else {
     498           0 :                     cx->zone()->group()->storeBuffer().putWholeCell(obj);
     499             :                 }
     500             :             }
     501             :         } else {
     502           0 :             void* data = obj->fixedData(FIXED_DATA_START);
     503           0 :             obj->initPrivate(data);
     504           0 :             memset(data, 0, len * sizeof(NativeType));
     505             : #ifdef DEBUG
     506           0 :             if (len == 0) {
     507           0 :                 uint8_t* elements = static_cast<uint8_t*>(data);
     508           0 :                 elements[0] = ZeroLengthArrayData;
     509             :             }
     510             : #endif
     511             :         }
     512             : 
     513           0 :         obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(len));
     514           0 :         obj->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
     515             : 
     516             : #ifdef DEBUG
     517           0 :         if (buffer) {
     518           0 :             uint32_t arrayByteLength = obj->byteLength();
     519           0 :             uint32_t arrayByteOffset = obj->byteOffset();
     520           0 :             uint32_t bufferByteLength = buffer->byteLength();
     521             :             // Unwraps are safe: both are for the pointer value.
     522           0 :             if (IsArrayBuffer(buffer.get())) {
     523           0 :                 MOZ_ASSERT_IF(!AsArrayBuffer(buffer.get()).isDetached(),
     524             :                               buffer->dataPointerEither().unwrap(/*safe*/) <= obj->viewDataEither().unwrap(/*safe*/));
     525             :             }
     526           0 :             MOZ_ASSERT(bufferByteLength - arrayByteOffset >= arrayByteLength);
     527           0 :             MOZ_ASSERT(arrayByteOffset <= bufferByteLength);
     528             :         }
     529             : 
     530             :         // Verify that the private slot is at the expected place
     531           0 :         MOZ_ASSERT(obj->numFixedSlots() == TypedArrayObject::DATA_SLOT);
     532             : #endif
     533             : 
     534             :         // ArrayBufferObjects track their views to support detaching.
     535           0 :         if (buffer && buffer->is<ArrayBufferObject>()) {
     536           0 :             if (!buffer->as<ArrayBufferObject>().addView(cx, obj))
     537           0 :                 return nullptr;
     538             :         }
     539             : 
     540           0 :         return obj;
     541             :     }
     542             : 
     543             :     static TypedArrayObject*
     544           0 :     makeTemplateObject(JSContext* cx, int32_t len)
     545             :     {
     546           0 :         MOZ_ASSERT(len >= 0);
     547             :         size_t nbytes;
     548           0 :         MOZ_ALWAYS_TRUE(CalculateAllocSize<NativeType>(len, &nbytes));
     549           0 :         MOZ_ASSERT(nbytes < TypedArrayObject::SINGLETON_BYTE_LENGTH);
     550           0 :         NewObjectKind newKind = TenuredObject;
     551           0 :         bool fitsInline = nbytes <= INLINE_BUFFER_LIMIT;
     552           0 :         const Class* clasp = instanceClass();
     553           0 :         gc::AllocKind allocKind = !fitsInline
     554           0 :                                   ? GetGCObjectKind(clasp)
     555           0 :                                   : AllocKindForLazyBuffer(nbytes);
     556           0 :         MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, clasp));
     557           0 :         allocKind = GetBackgroundAllocKind(allocKind);
     558             : 
     559           0 :         AutoSetNewObjectMetadata metadata(cx);
     560             :         jsbytecode* pc;
     561           0 :         RootedScript script(cx, cx->currentScript(&pc));
     562           0 :         if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, clasp))
     563           0 :             newKind = SingletonObject;
     564           0 :         JSObject* tmp = NewBuiltinClassInstance(cx, clasp, allocKind, newKind);
     565           0 :         if (!tmp)
     566           0 :             return nullptr;
     567             : 
     568           0 :         Rooted<TypedArrayObject*> tarray(cx, &tmp->as<TypedArrayObject>());
     569           0 :         initTypedArraySlots(cx, tarray, len);
     570             : 
     571             :         // Template objects do not need memory for its elements, since there
     572             :         // won't be any elements to store. Therefore, we set the pointer to
     573             :         // nullptr and avoid allocating memory that will never be used.
     574           0 :         tarray->initPrivate(nullptr);
     575             : 
     576           0 :         if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, tarray,
     577             :                                                                  newKind == SingletonObject))
     578             :         {
     579           0 :             return nullptr;
     580             :         }
     581             : 
     582           0 :         return tarray;
     583             :     }
     584             : 
     585             :     static void
     586           0 :     initTypedArraySlots(JSContext* cx, TypedArrayObject* tarray, int32_t len)
     587             :     {
     588           0 :         MOZ_ASSERT(len >= 0);
     589           0 :         tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT, NullValue());
     590           0 :         tarray->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(AssertedCast<int32_t>(len)));
     591           0 :         tarray->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0));
     592             : 
     593             :         // Verify that the private slot is at the expected place.
     594           0 :         MOZ_ASSERT(tarray->numFixedSlots() == TypedArrayObject::DATA_SLOT);
     595             : 
     596             : #ifdef DEBUG
     597           0 :         if (len == 0) {
     598           0 :             uint8_t* output = tarray->fixedData(TypedArrayObject::FIXED_DATA_START);
     599           0 :             output[0] = TypedArrayObject::ZeroLengthArrayData;
     600             :         }
     601             : #endif
     602           0 :     }
     603             : 
     604             :     static void
     605           0 :     initTypedArrayData(JSContext* cx, TypedArrayObject* tarray, int32_t len,
     606             :                        void* buf, AllocKind allocKind)
     607             :     {
     608           0 :         if (buf) {
     609             : #ifdef DEBUG
     610           0 :             Nursery& nursery = cx->nursery();
     611           0 :             MOZ_ASSERT_IF(!nursery.isInside(buf) && !tarray->hasInlineElements(),
     612             :                           tarray->isTenured());
     613             : #endif
     614           0 :             tarray->initPrivate(buf);
     615             :         } else {
     616           0 :             size_t nbytes = len * sizeof(NativeType);
     617             : #ifdef DEBUG
     618           0 :             size_t dataOffset = TypedArrayObject::dataOffset();
     619           0 :             size_t offset = dataOffset + sizeof(HeapSlot);
     620           0 :             MOZ_ASSERT(offset + nbytes <= GetGCKindBytes(allocKind));
     621             : #endif
     622             : 
     623           0 :             void* data = tarray->fixedData(FIXED_DATA_START);
     624           0 :             tarray->initPrivate(data);
     625           0 :             memset(data, 0, nbytes);
     626             :         }
     627           0 :     }
     628             : 
     629             :     static TypedArrayObject*
     630           0 :     makeTypedArrayWithTemplate(JSContext* cx, TypedArrayObject* templateObj, int32_t len)
     631             :     {
     632           0 :         if (len < 0 || uint32_t(len) >= INT32_MAX / sizeof(NativeType)) {
     633           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
     634           0 :             return nullptr;
     635             :         }
     636             : 
     637             :         size_t nbytes;
     638           0 :         MOZ_ALWAYS_TRUE(js::CalculateAllocSize<NativeType>(len, &nbytes));
     639             : 
     640           0 :         bool fitsInline = nbytes <= INLINE_BUFFER_LIMIT;
     641             : 
     642           0 :         AutoSetNewObjectMetadata metadata(cx);
     643             : 
     644           0 :         const Class* clasp = templateObj->group()->clasp();
     645           0 :         gc::AllocKind allocKind = !fitsInline
     646           0 :                                   ? GetGCObjectKind(clasp)
     647           0 :                                   : AllocKindForLazyBuffer(nbytes);
     648           0 :         MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, clasp));
     649           0 :         allocKind = GetBackgroundAllocKind(allocKind);
     650           0 :         RootedObjectGroup group(cx, templateObj->group());
     651             : 
     652           0 :         NewObjectKind newKind = TenuredObject;
     653             : 
     654           0 :         ScopedJSFreePtr<void> buf;
     655           0 :         if (!fitsInline && len > 0) {
     656           0 :             buf = cx->zone()->pod_malloc<uint8_t>(nbytes);
     657           0 :             if (!buf) {
     658           0 :                 ReportOutOfMemory(cx);
     659           0 :                 return nullptr;
     660             :             }
     661             : 
     662           0 :             memset(buf, 0, nbytes);
     663             :          }
     664             : 
     665           0 :         RootedObject tmp(cx, NewObjectWithGroup<TypedArrayObject>(cx, group, allocKind, newKind));
     666           0 :         if (!tmp)
     667           0 :             return nullptr;
     668             : 
     669           0 :         TypedArrayObject* obj = &tmp->as<TypedArrayObject>();
     670           0 :         initTypedArraySlots(cx, obj, len);
     671           0 :         initTypedArrayData(cx, obj, len, buf.forget(), allocKind);
     672             : 
     673           0 :         return obj;
     674             :     }
     675             : 
     676             :     // ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add
     677             :     // 22.2.4.1 TypedArray ( )
     678             :     // 22.2.4.2 TypedArray ( length )
     679             :     // 22.2.4.3 TypedArray ( typedArray )
     680             :     // 22.2.4.4 TypedArray ( object )
     681             :     // 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
     682             :     static bool
     683           0 :     class_constructor(JSContext* cx, unsigned argc, Value* vp)
     684             :     {
     685           0 :         CallArgs args = CallArgsFromVp(argc, vp);
     686             : 
     687             :         // Step 1 (22.2.4.1) or 2 (22.2.4.2-5).
     688           0 :         if (!ThrowIfNotConstructing(cx, args, "typed array"))
     689           0 :             return false;
     690             : 
     691           0 :         JSObject* obj = create(cx, args);
     692           0 :         if (!obj)
     693           0 :             return false;
     694           0 :         args.rval().setObject(*obj);
     695           0 :         return true;
     696             :     }
     697             : 
     698             :   private:
     699             :     static JSObject*
     700           0 :     create(JSContext* cx, const CallArgs& args)
     701             :     {
     702           0 :         MOZ_ASSERT(args.isConstructing());
     703           0 :         RootedObject newTarget(cx, &args.newTarget().toObject());
     704             : 
     705             :         // 22.2.4.1 TypedArray ( )
     706             :         // 22.2.4.2 TypedArray ( length )
     707           0 :         if (args.length() == 0 || !args[0].isObject()) {
     708             :             // 22.2.4.2, step 3.
     709             :             uint64_t len;
     710           0 :             if (!ToIndex(cx, args.get(0), JSMSG_BAD_ARRAY_LENGTH, &len))
     711           0 :                 return nullptr;
     712             : 
     713             :             // 22.2.4.1, step 3 and 22.2.4.2, step 5.
     714             :             // 22.2.4.2.1 AllocateTypedArray, step 1.
     715           0 :             RootedObject proto(cx);
     716           0 :             if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
     717           0 :                 return nullptr;
     718             : 
     719           0 :             return fromLength(cx, len, proto);
     720             :         }
     721             : 
     722           0 :         RootedObject dataObj(cx, &args[0].toObject());
     723             : 
     724             :         // 22.2.4.{3,4,5}, step 4.
     725             :         // 22.2.4.2.1 AllocateTypedArray, step 1.
     726           0 :         RootedObject proto(cx);
     727           0 :         if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
     728           0 :             return nullptr;
     729             : 
     730             :         // 22.2.4.3 TypedArray ( typedArray )
     731             :         // 22.2.4.4 TypedArray ( object )
     732           0 :         if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObjectMaybeShared>())
     733           0 :             return fromArray(cx, dataObj, proto);
     734             : 
     735             :         // 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
     736             : 
     737           0 :         uint64_t byteOffset = 0;
     738           0 :         if (args.hasDefined(1)) {
     739             :             // Step 6.
     740           0 :             if (!ToIndex(cx, args[1], &byteOffset))
     741           0 :                 return nullptr;
     742             : 
     743             :             // Step 7.
     744           0 :             if (byteOffset % sizeof(NativeType) != 0) {
     745           0 :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     746             :                                           JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
     747           0 :                 return nullptr;
     748             :             }
     749             :         }
     750             : 
     751           0 :         uint64_t length = UINT64_MAX;
     752           0 :         if (args.hasDefined(2)) {
     753             :             // Step 8.a.
     754           0 :             if (!ToIndex(cx, args[2], &length))
     755           0 :                 return nullptr;
     756             :         }
     757             : 
     758             :         // Steps 9-17.
     759           0 :         if (dataObj->is<ArrayBufferObjectMaybeShared>()) {
     760           0 :             HandleArrayBufferObjectMaybeShared buffer = dataObj.as<ArrayBufferObjectMaybeShared>();
     761           0 :             return fromBufferSameCompartment(cx, buffer, byteOffset, length, proto);
     762             :         }
     763           0 :         return fromBufferWrapped(cx, dataObj, byteOffset, length, proto);
     764             :     }
     765             : 
     766             :     // ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add
     767             :     // 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
     768             :     // Steps 9-12.
     769             :     static bool
     770           0 :     computeAndCheckLength(JSContext* cx, HandleArrayBufferObjectMaybeShared bufferMaybeUnwrapped,
     771             :                           uint64_t byteOffset, uint64_t lengthIndex, uint32_t* length)
     772             :     {
     773           0 :         MOZ_ASSERT(byteOffset % sizeof(NativeType) == 0);
     774           0 :         MOZ_ASSERT(byteOffset < uint64_t(DOUBLE_INTEGRAL_PRECISION_LIMIT));
     775           0 :         MOZ_ASSERT_IF(lengthIndex != UINT64_MAX,
     776             :                       lengthIndex < uint64_t(DOUBLE_INTEGRAL_PRECISION_LIMIT));
     777             : 
     778             :         // Step 9.
     779           0 :         if (bufferMaybeUnwrapped->isDetached()) {
     780           0 :            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
     781           0 :            return false;
     782             :         }
     783             : 
     784             :         // Step 10.
     785           0 :         uint32_t bufferByteLength = bufferMaybeUnwrapped->byteLength();
     786             : 
     787             :         uint32_t len;
     788           0 :         if (lengthIndex == UINT64_MAX) {
     789             :             // Steps 11.a, 11.c.
     790           0 :             if (bufferByteLength % sizeof(NativeType) != 0 || byteOffset > bufferByteLength) {
     791             :                 // The given byte array doesn't map exactly to
     792             :                 // |sizeof(NativeType) * N| or |byteOffset| is invalid.
     793           0 :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     794             :                                           JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
     795           0 :                 return false;
     796             :             }
     797             : 
     798             :             // Step 11.b.
     799           0 :             uint32_t newByteLength = bufferByteLength - uint32_t(byteOffset);
     800           0 :             len = newByteLength / sizeof(NativeType);
     801             :         } else {
     802             :             // Step 12.a.
     803           0 :             uint64_t newByteLength = lengthIndex * sizeof(NativeType);
     804             : 
     805             :             // Step 12.b.
     806           0 :             if (byteOffset + newByteLength > bufferByteLength) {
     807             :                 // |byteOffset + newByteLength| is too big for the arraybuffer
     808           0 :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     809             :                                           JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
     810           0 :                 return false;
     811             :             }
     812             : 
     813           0 :             len = uint32_t(lengthIndex);
     814             :         }
     815             : 
     816             :         // ArrayBuffer is too large for TypedArrays:
     817             :         // Standalone ArrayBuffers can hold up to INT32_MAX bytes, whereas
     818             :         // buffers in TypedArrays must have less than or equal to
     819             :         // |INT32_MAX - sizeof(NativeType) - INT32_MAX % sizeof(NativeType)|
     820             :         // bytes.
     821           0 :         if (len >= INT32_MAX / sizeof(NativeType)) {
     822           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     823             :                                       JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
     824           0 :             return false;
     825             :         }
     826           0 :         MOZ_ASSERT(byteOffset <= UINT32_MAX);
     827             : 
     828           0 :         *length = len;
     829           0 :         return true;
     830             :     }
     831             : 
     832             :     // ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add
     833             :     // 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )
     834             :     // Steps 9-17.
     835             :     static JSObject*
     836           0 :     fromBufferSameCompartment(JSContext* cx, HandleArrayBufferObjectMaybeShared buffer,
     837             :                               uint64_t byteOffset, uint64_t lengthIndex, HandleObject proto)
     838             :     {
     839             :         // Steps 9-12.
     840             :         uint32_t length;
     841           0 :         if (!computeAndCheckLength(cx, buffer, byteOffset, lengthIndex, &length))
     842           0 :             return nullptr;
     843             : 
     844             :         // Steps 13-17.
     845           0 :         return makeInstance(cx, buffer, uint32_t(byteOffset), length, proto);
     846             :     }
     847             : 
     848             :     // Create a TypedArray object in another compartment.
     849             :     //
     850             :     // ES6 supports creating a TypedArray in global A (using global A's
     851             :     // TypedArray constructor) backed by an ArrayBuffer created in global B.
     852             :     //
     853             :     // Our TypedArrayObject implementation doesn't support a TypedArray in
     854             :     // compartment A backed by an ArrayBuffer in compartment B. So in this
     855             :     // case, we create the TypedArray in B (!) and return a cross-compartment
     856             :     // wrapper.
     857             :     //
     858             :     // Extra twist: the spec says the new TypedArray's [[Prototype]] must be
     859             :     // A's TypedArray.prototype. So even though we're creating the TypedArray
     860             :     // in B, its [[Prototype]] must be (a cross-compartment wrapper for) the
     861             :     // TypedArray.prototype in A.
     862             :     static JSObject*
     863           0 :     fromBufferWrapped(JSContext* cx, HandleObject bufobj, uint64_t byteOffset,
     864             :                       uint64_t lengthIndex, HandleObject proto)
     865             :     {
     866           0 :         JSObject* unwrapped = CheckedUnwrap(bufobj);
     867           0 :         if (!unwrapped) {
     868           0 :             ReportAccessDenied(cx);
     869           0 :             return nullptr;
     870             :         }
     871             : 
     872           0 :         if (!unwrapped->is<ArrayBufferObjectMaybeShared>()) {
     873           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
     874           0 :             return nullptr;
     875             :         }
     876             : 
     877           0 :         RootedArrayBufferObjectMaybeShared unwrappedBuffer(cx);
     878           0 :         unwrappedBuffer = &unwrapped->as<ArrayBufferObjectMaybeShared>();
     879             : 
     880             :         uint32_t length;
     881           0 :         if (!computeAndCheckLength(cx, unwrappedBuffer, byteOffset, lengthIndex, &length))
     882           0 :             return nullptr;
     883             : 
     884             :         // Make sure to get the [[Prototype]] for the created typed array from
     885             :         // this compartment.
     886           0 :         RootedObject protoRoot(cx, proto);
     887           0 :         if (!protoRoot) {
     888           0 :             if (!GetBuiltinPrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()), &protoRoot))
     889           0 :                 return nullptr;
     890             :         }
     891             : 
     892           0 :         RootedObject typedArray(cx);
     893             :         {
     894           0 :             JSAutoCompartment ac(cx, unwrappedBuffer);
     895             : 
     896           0 :             RootedObject wrappedProto(cx, protoRoot);
     897           0 :             if (!cx->compartment()->wrap(cx, &wrappedProto))
     898           0 :                 return nullptr;
     899             : 
     900           0 :             typedArray =
     901           0 :                 makeInstance(cx, unwrappedBuffer, uint32_t(byteOffset), length, wrappedProto);
     902           0 :             if (!typedArray)
     903           0 :                 return nullptr;
     904             :         }
     905             : 
     906           0 :         if (!cx->compartment()->wrap(cx, &typedArray))
     907           0 :             return nullptr;
     908             : 
     909           0 :         return typedArray;
     910             :     }
     911             : 
     912             :   public:
     913             :     static JSObject*
     914           0 :     fromBuffer(JSContext* cx, HandleObject bufobj, uint32_t byteOffset, int32_t lengthInt)
     915             :     {
     916           0 :         if (byteOffset % sizeof(NativeType) != 0) {
     917           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     918             :                                       JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);
     919           0 :             return nullptr; // invalid byteOffset
     920             :         }
     921             : 
     922           0 :         uint64_t lengthIndex = lengthInt >= 0 ? uint64_t(lengthInt) : UINT64_MAX;
     923           0 :         if (bufobj->is<ArrayBufferObjectMaybeShared>()) {
     924           0 :             HandleArrayBufferObjectMaybeShared buffer = bufobj.as<ArrayBufferObjectMaybeShared>();
     925           0 :             return fromBufferSameCompartment(cx, buffer, byteOffset, lengthIndex, nullptr);
     926             :         }
     927           0 :         return fromBufferWrapped(cx, bufobj, byteOffset, lengthIndex, nullptr);
     928             :     }
     929             : 
     930             :     static bool
     931           0 :     maybeCreateArrayBuffer(JSContext* cx, uint32_t count, uint32_t unit,
     932             :                            HandleObject nonDefaultProto,
     933             :                            MutableHandle<ArrayBufferObject*> buffer)
     934             :     {
     935           0 :         if (count >= INT32_MAX / unit) {
     936           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
     937           0 :             return false;
     938             :         }
     939           0 :         uint32_t byteLength = count * unit;
     940             : 
     941           0 :         MOZ_ASSERT(byteLength < INT32_MAX);
     942             :         static_assert(INLINE_BUFFER_LIMIT % sizeof(NativeType) == 0,
     943             :                       "ArrayBuffer inline storage shouldn't waste any space");
     944             : 
     945           0 :         if (!nonDefaultProto && byteLength <= INLINE_BUFFER_LIMIT) {
     946             :             // The array's data can be inline, and the buffer created lazily.
     947           0 :             return true;
     948             :         }
     949             : 
     950           0 :         ArrayBufferObject* buf = ArrayBufferObject::create(cx, byteLength, nonDefaultProto);
     951           0 :         if (!buf)
     952           0 :             return false;
     953             : 
     954           0 :         buffer.set(buf);
     955           0 :         return true;
     956             :     }
     957             : 
     958             :     // 22.2.4.1 TypedArray ( )
     959             :     // 22.2.4.2 TypedArray ( length )
     960             :     static JSObject*
     961           0 :     fromLength(JSContext* cx, uint64_t nelements, HandleObject proto = nullptr)
     962             :     {
     963             :         // 22.2.4.1, step 1 and 22.2.4.2, steps 1-3 (performed in caller).
     964             :         // 22.2.4.1, step 2 and 22.2.4.2, step 4 (implicit).
     965             :         // 22.2.4.1, step 3 and 22.2.4.2, step 5 (call AllocateTypedArray).
     966             : 
     967           0 :         if (nelements > UINT32_MAX) {
     968           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
     969           0 :             return nullptr;
     970             :         }
     971             : 
     972           0 :         Rooted<ArrayBufferObject*> buffer(cx);
     973           0 :         if (!maybeCreateArrayBuffer(cx, uint32_t(nelements), BYTES_PER_ELEMENT, nullptr, &buffer))
     974           0 :             return nullptr;
     975             : 
     976           0 :         return makeInstance(cx, buffer, 0, uint32_t(nelements), proto);
     977             :     }
     978             : 
     979             :     static bool
     980             :     AllocateArrayBuffer(JSContext* cx, HandleValue ctor,
     981             :                         uint32_t count, uint32_t unit,
     982             :                         MutableHandle<ArrayBufferObject*> buffer);
     983             : 
     984             :     static bool
     985             :     CloneArrayBufferNoCopy(JSContext* cx, Handle<ArrayBufferObjectMaybeShared*> srcBuffer,
     986             :                            bool isWrapped, uint32_t srcByteOffset, uint32_t srcLength,
     987             :                            SpeciesConstructorOverride override,
     988             :                            MutableHandle<ArrayBufferObject*> buffer);
     989             : 
     990             :     static JSObject*
     991             :     fromArray(JSContext* cx, HandleObject other, HandleObject proto = nullptr);
     992             : 
     993             :     static JSObject*
     994             :     fromTypedArray(JSContext* cx, HandleObject other, bool isWrapped, HandleObject proto);
     995             : 
     996             :     static JSObject*
     997             :     fromObject(JSContext* cx, HandleObject other, HandleObject proto);
     998             : 
     999             :     static const NativeType
    1000           0 :     getIndex(JSObject* obj, uint32_t index)
    1001             :     {
    1002           0 :         TypedArrayObject& tarray = obj->as<TypedArrayObject>();
    1003           0 :         MOZ_ASSERT(index < tarray.length());
    1004           0 :         return jit::AtomicOperations::loadSafeWhenRacy(tarray.viewDataEither().cast<NativeType*>() + index);
    1005             :     }
    1006             : 
    1007             :     static void
    1008           0 :     setIndex(TypedArrayObject& tarray, uint32_t index, NativeType val)
    1009             :     {
    1010           0 :         MOZ_ASSERT(index < tarray.length());
    1011           0 :         jit::AtomicOperations::storeSafeWhenRacy(tarray.viewDataEither().cast<NativeType*>() + index, val);
    1012           0 :     }
    1013             : 
    1014             :     static Value getIndexValue(JSObject* tarray, uint32_t index);
    1015             : };
    1016             : 
    1017             : #define CREATE_TYPE_FOR_TYPED_ARRAY(T, N) \
    1018             :     typedef TypedArrayObjectTemplate<T> N##Array;
    1019             : JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPE_FOR_TYPED_ARRAY)
    1020             : #undef CREATE_TYPE_FOR_TYPED_ARRAY
    1021             : 
    1022             : } /* anonymous namespace */
    1023             : 
    1024             : TypedArrayObject*
    1025           0 : js::TypedArrayCreateWithTemplate(JSContext* cx, HandleObject templateObj, int32_t len)
    1026             : {
    1027           0 :     MOZ_ASSERT(templateObj->is<TypedArrayObject>());
    1028           0 :     TypedArrayObject* tobj = &templateObj->as<TypedArrayObject>();
    1029             : 
    1030           0 :     switch (tobj->type()) {
    1031             : #define CREATE_TYPED_ARRAY(T, N) \
    1032             :       case Scalar::N: \
    1033             :         return TypedArrayObjectTemplate<T>::makeTypedArrayWithTemplate(cx, tobj, len);
    1034           0 : JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARRAY)
    1035             : #undef CREATE_TYPED_ARRAY
    1036             :       default:
    1037           0 :         MOZ_CRASH("Unsupported TypedArray type");
    1038             :     }
    1039             : }
    1040             : 
    1041             : // ES 2016 draft Mar 25, 2016 24.1.1.1.
    1042             : // byteLength = count * unit
    1043             : template<typename T>
    1044             : /* static */ bool
    1045           0 : TypedArrayObjectTemplate<T>::AllocateArrayBuffer(JSContext* cx, HandleValue ctor,
    1046             :                                                  uint32_t count, uint32_t unit,
    1047             :                                                  MutableHandle<ArrayBufferObject*> buffer)
    1048             : {
    1049             :     // ES 2016 draft Mar 25, 2016 24.1.1.1 step 1 (partially).
    1050             :     // ES 2016 draft Mar 25, 2016 9.1.14 steps 1-2.
    1051           0 :     MOZ_ASSERT(ctor.isObject());
    1052           0 :     RootedObject proto(cx);
    1053           0 :     RootedObject ctorObj(cx, &ctor.toObject());
    1054           0 :     if (!GetPrototypeFromConstructor(cx, ctorObj, &proto))
    1055           0 :         return false;
    1056           0 :     JSObject* arrayBufferProto = GlobalObject::getOrCreateArrayBufferPrototype(cx, cx->global());
    1057           0 :     if (!arrayBufferProto)
    1058           0 :         return false;
    1059           0 :     if (proto == arrayBufferProto)
    1060           0 :         proto = nullptr;
    1061             : 
    1062             :     // ES 2016 draft Mar 25, 2016 24.1.1.1 steps 1 (remaining part), 2-6.
    1063           0 :     if (!maybeCreateArrayBuffer(cx, count, unit, proto, buffer))
    1064           0 :         return false;
    1065             : 
    1066           0 :     return true;
    1067             : }
    1068             : 
    1069             : static bool
    1070           0 : IsArrayBufferConstructor(const Value& v)
    1071             : {
    1072           0 :     return v.isObject() &&
    1073           0 :            v.toObject().is<JSFunction>() &&
    1074           0 :            v.toObject().as<JSFunction>().isNative() &&
    1075           0 :            v.toObject().as<JSFunction>().native() == ArrayBufferObject::class_constructor;
    1076             : }
    1077             : 
    1078             : static bool
    1079           0 : IsArrayBufferSpecies(JSContext* cx, HandleObject origBuffer)
    1080             : {
    1081           0 :     RootedValue ctor(cx);
    1082           0 :     if (!GetPropertyPure(cx, origBuffer, NameToId(cx->names().constructor), ctor.address()))
    1083           0 :         return false;
    1084             : 
    1085           0 :     if (!IsArrayBufferConstructor(ctor))
    1086           0 :         return false;
    1087             : 
    1088           0 :     RootedObject ctorObj(cx, &ctor.toObject());
    1089           0 :     RootedId speciesId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().species));
    1090             :     JSFunction* getter;
    1091           0 :     if (!GetGetterPure(cx, ctorObj, speciesId, &getter))
    1092           0 :         return false;
    1093             : 
    1094           0 :     if (!getter)
    1095           0 :         return false;
    1096             : 
    1097           0 :     return IsSelfHostedFunctionWithName(getter, cx->names().ArrayBufferSpecies);
    1098             : }
    1099             : 
    1100             : static bool
    1101           0 : GetSpeciesConstructor(JSContext* cx, HandleObject obj, bool isWrapped,
    1102             :                       SpeciesConstructorOverride override, MutableHandleValue ctor)
    1103             : {
    1104           0 :     if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_ArrayBuffer))
    1105           0 :         return false;
    1106           0 :     RootedValue defaultCtor(cx, cx->global()->getConstructor(JSProto_ArrayBuffer));
    1107             : 
    1108             :     // Use the current global's ArrayBuffer if the override is set.
    1109           0 :     if (override == SpeciesConstructorOverride::ArrayBuffer) {
    1110           0 :         ctor.set(defaultCtor);
    1111           0 :         return true;
    1112             :     }
    1113             : 
    1114           0 :     if (!isWrapped) {
    1115             :         // As an optimization, avoid calling into self-hosted code if |obj|'s
    1116             :         // constructor is the built-in ArrayBuffer and the constructor's
    1117             :         // species property is the original ArrayBuffer[@@species] function.
    1118           0 :         if (IsArrayBufferSpecies(cx, obj))
    1119           0 :             ctor.set(defaultCtor);
    1120           0 :         else if (!SpeciesConstructor(cx, obj, defaultCtor, ctor))
    1121           0 :             return false;
    1122             : 
    1123           0 :         return true;
    1124             :     }
    1125             : 
    1126           0 :     RootedObject wrappedObj(cx, obj);
    1127           0 :     if (!cx->compartment()->wrap(cx, &wrappedObj))
    1128           0 :         return false;
    1129             : 
    1130           0 :     if (!SpeciesConstructor(cx, wrappedObj, defaultCtor, ctor))
    1131           0 :         return false;
    1132             : 
    1133           0 :     return true;
    1134             : }
    1135             : 
    1136             : // ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 24.1.1.4.
    1137             : template<typename T>
    1138             : /* static */ bool
    1139           0 : TypedArrayObjectTemplate<T>::CloneArrayBufferNoCopy(JSContext* cx,
    1140             :                                                     Handle<ArrayBufferObjectMaybeShared*> srcBuffer,
    1141             :                                                     bool isWrapped, uint32_t srcByteOffset,
    1142             :                                                     uint32_t srcLength,
    1143             :                                                     SpeciesConstructorOverride override,
    1144             :                                                     MutableHandle<ArrayBufferObject*> buffer)
    1145             : {
    1146             :     // Step 1 (skipped).
    1147             : 
    1148             :     // Step 2.a.
    1149           0 :     RootedValue cloneCtor(cx);
    1150           0 :     if (!GetSpeciesConstructor(cx, srcBuffer, isWrapped, override, &cloneCtor))
    1151           0 :         return false;
    1152             : 
    1153             :     // Step 2.b.
    1154           0 :     if (srcBuffer->isDetached()) {
    1155           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
    1156           0 :         return false;
    1157             :     }
    1158             : 
    1159             :     // Steps 3-4 (skipped).
    1160             : 
    1161             :     // Steps 5.
    1162           0 :     if (!AllocateArrayBuffer(cx, cloneCtor, srcLength, 1, buffer))
    1163           0 :         return false;
    1164             : 
    1165             :     // Step 6.
    1166           0 :     if (srcBuffer->isDetached()) {
    1167           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
    1168           0 :         return false;
    1169             :     }
    1170             : 
    1171             :     // Steps 7-8 (done in caller).
    1172             : 
    1173             :     // Step 9.
    1174           0 :     return true;
    1175             : }
    1176             : 
    1177             : template<typename T>
    1178             : /* static */ JSObject*
    1179           0 : TypedArrayObjectTemplate<T>::fromArray(JSContext* cx, HandleObject other,
    1180             :                                        HandleObject proto /* = nullptr */)
    1181             : {
    1182             :     // Allow nullptr proto for FriendAPI methods, which don't care about
    1183             :     // subclassing.
    1184           0 :     if (other->is<TypedArrayObject>())
    1185           0 :         return fromTypedArray(cx, other, /* wrapped= */ false, proto);
    1186             : 
    1187           0 :     if (other->is<WrapperObject>() && UncheckedUnwrap(other)->is<TypedArrayObject>())
    1188           0 :         return fromTypedArray(cx, other, /* wrapped= */ true, proto);
    1189             : 
    1190           0 :     return fromObject(cx, other, proto);
    1191             : }
    1192             : 
    1193             : // ES2017 draft rev 6390c2f1b34b309895d31d8c0512eac8660a0210
    1194             : // 22.2.4.3 TypedArray ( typedArray )
    1195             : template<typename T>
    1196             : /* static */ JSObject*
    1197           0 : TypedArrayObjectTemplate<T>::fromTypedArray(JSContext* cx, HandleObject other, bool isWrapped,
    1198             :                                             HandleObject proto)
    1199             : {
    1200             :     // Step 1.
    1201           0 :     MOZ_ASSERT_IF(!isWrapped, other->is<TypedArrayObject>());
    1202           0 :     MOZ_ASSERT_IF(isWrapped,
    1203             :                   other->is<WrapperObject>() &&
    1204             :                   UncheckedUnwrap(other)->is<TypedArrayObject>());
    1205             : 
    1206             :     // Step 2 (Already performed in caller).
    1207             : 
    1208             :     // Step 4 (Allocation deferred until later).
    1209             : 
    1210             :     // Step 5.
    1211           0 :     Rooted<TypedArrayObject*> srcArray(cx);
    1212           0 :     if (!isWrapped) {
    1213           0 :         srcArray = &other->as<TypedArrayObject>();
    1214           0 :         if (!TypedArrayObject::ensureHasBuffer(cx, srcArray))
    1215           0 :             return nullptr;
    1216             :     } else {
    1217           0 :         RootedObject unwrapped(cx, CheckedUnwrap(other));
    1218           0 :         if (!unwrapped) {
    1219           0 :             ReportAccessDenied(cx);
    1220           0 :             return nullptr;
    1221             :         }
    1222             : 
    1223           0 :         JSAutoCompartment ac(cx, unwrapped);
    1224             : 
    1225           0 :         srcArray = &unwrapped->as<TypedArrayObject>();
    1226           0 :         if (!TypedArrayObject::ensureHasBuffer(cx, srcArray))
    1227           0 :             return nullptr;
    1228             :     }
    1229             : 
    1230             :     // Step 6.
    1231           0 :     Rooted<ArrayBufferObjectMaybeShared*> srcData(cx, srcArray->bufferEither());
    1232             : 
    1233             :     // Step 7.
    1234           0 :     if (srcData->isDetached()) {
    1235           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
    1236           0 :         return nullptr;
    1237             :     }
    1238             : 
    1239             :     // Step 9.
    1240           0 :     uint32_t elementLength = srcArray->length();
    1241             : 
    1242             :     // Steps 10-11.
    1243           0 :     Scalar::Type srcType = srcArray->type();
    1244             : 
    1245             :     // Step 12 (skipped).
    1246             : 
    1247             :     // Step 13.
    1248           0 :     uint32_t srcByteOffset = srcArray->byteOffset();
    1249             : 
    1250             :     // Steps 16-17.
    1251           0 :     bool isShared = srcArray->isSharedMemory();
    1252             :     SpeciesConstructorOverride override = isShared ? SpeciesConstructorOverride::ArrayBuffer
    1253           0 :                                                    : SpeciesConstructorOverride::None;
    1254             : 
    1255             :     // Steps 8, 16-17.
    1256           0 :     Rooted<ArrayBufferObject*> buffer(cx);
    1257           0 :     if (ArrayTypeID() == srcType) {
    1258             :         // Step 16.a.
    1259           0 :         uint32_t srcLength = srcArray->byteLength();
    1260             : 
    1261             :         // Steps 16.b-c.
    1262           0 :         if (!CloneArrayBufferNoCopy(cx, srcData, isWrapped, srcByteOffset, srcLength, override,
    1263             :                                     &buffer))
    1264             :         {
    1265           0 :             return nullptr;
    1266             :         }
    1267             :     } else {
    1268             :         // Steps 17.a-b.
    1269           0 :         RootedValue bufferCtor(cx);
    1270           0 :         if (!GetSpeciesConstructor(cx, srcData, isWrapped, override, &bufferCtor))
    1271           0 :             return nullptr;
    1272             : 
    1273             :         // Steps 14-15, 17.c.
    1274           0 :         if (!AllocateArrayBuffer(cx, bufferCtor, elementLength, BYTES_PER_ELEMENT, &buffer))
    1275           0 :             return nullptr;
    1276             : 
    1277             :         // Step 17.d.
    1278           0 :         if (srcArray->hasDetachedBuffer()) {
    1279           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
    1280           0 :             return nullptr;
    1281             :         }
    1282             :     }
    1283             : 
    1284             :     // Steps 3-4 (remaining part), 18-21.
    1285           0 :     Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, elementLength, proto));
    1286           0 :     if (!obj)
    1287           0 :         return nullptr;
    1288             : 
    1289             :     // Steps 17.e-h or 24.1.1.4 step 8.
    1290           0 :     MOZ_ASSERT(!obj->isSharedMemory());
    1291           0 :     if (isShared) {
    1292           0 :         if (!ElementSpecific<T, SharedOps>::setFromTypedArray(cx, obj, srcArray, 0))
    1293           0 :             return nullptr;
    1294             :     } else {
    1295           0 :         if (!ElementSpecific<T, UnsharedOps>::setFromTypedArray(cx, obj, srcArray, 0))
    1296           0 :             return nullptr;
    1297             :     }
    1298             : 
    1299             :     // Step 22.
    1300           0 :     return obj;
    1301             : }
    1302             : 
    1303             : static MOZ_ALWAYS_INLINE bool
    1304           0 : IsOptimizableInit(JSContext* cx, HandleObject iterable, bool* optimized)
    1305             : {
    1306           0 :     MOZ_ASSERT(!*optimized);
    1307             : 
    1308           0 :     if (!IsPackedArray(iterable))
    1309           0 :         return true;
    1310             : 
    1311           0 :     ForOfPIC::Chain* stubChain = ForOfPIC::getOrCreate(cx);
    1312           0 :     if (!stubChain)
    1313           0 :         return false;
    1314             : 
    1315           0 :     return stubChain->tryOptimizeArray(cx, iterable.as<ArrayObject>(), optimized);
    1316             : }
    1317             : 
    1318             : // ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e
    1319             : // 22.2.4.4 TypedArray ( object )
    1320             : template<typename T>
    1321             : /* static */ JSObject*
    1322           0 : TypedArrayObjectTemplate<T>::fromObject(JSContext* cx, HandleObject other, HandleObject proto)
    1323             : {
    1324             :     // Steps 1-2 (Already performed in caller).
    1325             : 
    1326             :     // Steps 3-4 (Allocation deferred until later).
    1327             : 
    1328           0 :     bool optimized = false;
    1329           0 :     if (!IsOptimizableInit(cx, other, &optimized))
    1330           0 :         return nullptr;
    1331             : 
    1332             :     // Fast path when iterable is a packed array using the default iterator.
    1333           0 :     if (optimized) {
    1334             :         // Step 6.a (We don't need to call IterableToList for the fast path).
    1335           0 :         RootedArrayObject array(cx, &other->as<ArrayObject>());
    1336             : 
    1337             :         // Step 6.b.
    1338           0 :         uint32_t len = array->getDenseInitializedLength();
    1339             : 
    1340             :         // Step 6.c.
    1341           0 :         Rooted<ArrayBufferObject*> buffer(cx);
    1342           0 :         if (!maybeCreateArrayBuffer(cx, len, BYTES_PER_ELEMENT, nullptr, &buffer))
    1343           0 :             return nullptr;
    1344             : 
    1345           0 :         Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
    1346           0 :         if (!obj)
    1347           0 :             return nullptr;
    1348             : 
    1349             :         // Steps 6.d-e.
    1350           0 :         MOZ_ASSERT(!obj->isSharedMemory());
    1351           0 :         if (!ElementSpecific<T, UnsharedOps>::initFromIterablePackedArray(cx, obj, array))
    1352           0 :             return nullptr;
    1353             : 
    1354             :         // Step 6.f (The assertion isn't applicable for the fast path).
    1355             : 
    1356             :         // Step 6.g.
    1357           0 :         return obj;
    1358             :     }
    1359             : 
    1360             :     // Step 5.
    1361           0 :     RootedValue callee(cx);
    1362           0 :     RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
    1363           0 :     if (!GetProperty(cx, other, other, iteratorId, &callee))
    1364           0 :         return nullptr;
    1365             : 
    1366             :     // Steps 6-8.
    1367           0 :     RootedObject arrayLike(cx);
    1368           0 :     if (!callee.isNullOrUndefined()) {
    1369             :         // Throw if other[Symbol.iterator] isn't callable.
    1370           0 :         if (!callee.isObject() || !callee.toObject().isCallable()) {
    1371           0 :             RootedValue otherVal(cx, ObjectValue(*other));
    1372           0 :             UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, otherVal, nullptr);
    1373           0 :             if (!bytes)
    1374           0 :                 return nullptr;
    1375           0 :             JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_ITERABLE,
    1376             :                                        bytes.get());
    1377           0 :             return nullptr;
    1378             :         }
    1379             : 
    1380           0 :         FixedInvokeArgs<2> args2(cx);
    1381           0 :         args2[0].setObject(*other);
    1382           0 :         args2[1].set(callee);
    1383             : 
    1384             :         // Step 6.a.
    1385           0 :         RootedValue rval(cx);
    1386           0 :         if (!CallSelfHostedFunction(cx, cx->names().IterableToList, UndefinedHandleValue, args2,
    1387             :                                     &rval))
    1388             :         {
    1389           0 :             return nullptr;
    1390             :         }
    1391             : 
    1392             :         // Steps 6.b-g (Implemented in steps 9-13 below).
    1393           0 :         arrayLike = &rval.toObject();
    1394             :     } else {
    1395             :         // Step 7 is an assertion: object is not an Iterator. Testing this is
    1396             :         // literally the very last thing we did, so we don't assert here.
    1397             : 
    1398             :         // Step 8.
    1399           0 :         arrayLike = other;
    1400             :     }
    1401             : 
    1402             :     // Step 9.
    1403             :     uint32_t len;
    1404           0 :     if (!GetLengthProperty(cx, arrayLike, &len))
    1405           0 :         return nullptr;
    1406             : 
    1407             :     // Step 10.
    1408           0 :     Rooted<ArrayBufferObject*> buffer(cx);
    1409           0 :     if (!maybeCreateArrayBuffer(cx, len, BYTES_PER_ELEMENT, nullptr, &buffer))
    1410           0 :         return nullptr;
    1411             : 
    1412           0 :     Rooted<TypedArrayObject*> obj(cx, makeInstance(cx, buffer, 0, len, proto));
    1413           0 :     if (!obj)
    1414           0 :         return nullptr;
    1415             : 
    1416             :     // Steps 11-12.
    1417           0 :     MOZ_ASSERT(!obj->isSharedMemory());
    1418           0 :     if (!ElementSpecific<T, UnsharedOps>::setFromNonTypedArray(cx, obj, arrayLike, len))
    1419           0 :         return nullptr;
    1420             : 
    1421             :     // Step 13.
    1422           0 :     return obj;
    1423             : }
    1424             : 
    1425             : bool
    1426           0 : TypedArrayConstructor(JSContext* cx, unsigned argc, Value* vp)
    1427             : {
    1428           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1429           0 :     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT,
    1430           0 :                               args.isConstructing() ? "construct" : "call");
    1431           0 :     return false;
    1432             : }
    1433             : 
    1434             : /* static */ bool
    1435         550 : TypedArrayObject::GetTemplateObjectForNative(JSContext* cx, Native native, uint32_t len,
    1436             :                                              MutableHandleObject res)
    1437             : {
    1438             : #define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
    1439             :     if (native == &TypedArrayObjectTemplate<T>::class_constructor) { \
    1440             :         size_t nbytes; \
    1441             :         if (!js::CalculateAllocSize<T>(len, &nbytes)) \
    1442             :             return true; \
    1443             :         \
    1444             :         if (nbytes < TypedArrayObject::SINGLETON_BYTE_LENGTH) { \
    1445             :             res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len)); \
    1446             :             return !!res; \
    1447             :         } \
    1448             :     }
    1449         550 : JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR)
    1450             : #undef CHECK_TYPED_ARRAY_CONSTRUCTOR
    1451         550 :     return true;
    1452             : }
    1453             : 
    1454             : /*
    1455             :  * These next 3 functions are brought to you by the buggy GCC we use to build
    1456             :  * B2G ICS. Older GCC versions have a bug in which they fail to compile
    1457             :  * reinterpret_casts of templated functions with the message: "insufficient
    1458             :  * contextual information to determine type". JS_PSG needs to
    1459             :  * reinterpret_cast<JSGetterOp>, so this causes problems for us here.
    1460             :  *
    1461             :  * We could restructure all this code to make this nicer, but since ICS isn't
    1462             :  * going to be around forever (and since this bug is fixed with the newer GCC
    1463             :  * versions we use on JB and KK), the workaround here is designed for ease of
    1464             :  * removal. When you stop seeing ICS Emulator builds on TBPL, remove these 3
    1465             :  * JSNatives and insert the templated callee directly into the JS_PSG below.
    1466             :  */
    1467             : static bool
    1468           0 : TypedArray_lengthGetter(JSContext* cx, unsigned argc, Value* vp)
    1469             : {
    1470           0 :     return TypedArrayObject::Getter<TypedArrayObject::lengthValue>(cx, argc, vp);
    1471             : }
    1472             : 
    1473             : static bool
    1474           0 : TypedArray_byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
    1475             : {
    1476           0 :     return TypedArrayObject::Getter<TypedArrayObject::byteLengthValue>(cx, argc, vp);
    1477             : }
    1478             : 
    1479             : static bool
    1480           0 : TypedArray_byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp)
    1481             : {
    1482           0 :     return TypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>(cx, argc, vp);
    1483             : }
    1484             : 
    1485             : bool
    1486           0 : BufferGetterImpl(JSContext* cx, const CallArgs& args)
    1487             : {
    1488           0 :     MOZ_ASSERT(TypedArrayObject::is(args.thisv()));
    1489           0 :     Rooted<TypedArrayObject*> tarray(cx, &args.thisv().toObject().as<TypedArrayObject>());
    1490           0 :     if (!TypedArrayObject::ensureHasBuffer(cx, tarray))
    1491           0 :         return false;
    1492           0 :     args.rval().set(TypedArrayObject::bufferValue(tarray));
    1493           0 :     return true;
    1494             : }
    1495             : 
    1496             : /*static*/ bool
    1497           0 : js::TypedArray_bufferGetter(JSContext* cx, unsigned argc, Value* vp)
    1498             : {
    1499           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1500           0 :     return CallNonGenericMethod<TypedArrayObject::is, BufferGetterImpl>(cx, args);
    1501             : }
    1502             : 
    1503             : /* static */ const JSPropertySpec
    1504             : TypedArrayObject::protoAccessors[] = {
    1505             :     JS_PSG("length", TypedArray_lengthGetter, 0),
    1506             :     JS_PSG("buffer", TypedArray_bufferGetter, 0),
    1507             :     JS_PSG("byteLength", TypedArray_byteLengthGetter, 0),
    1508             :     JS_PSG("byteOffset", TypedArray_byteOffsetGetter, 0),
    1509             :     JS_SELF_HOSTED_SYM_GET(toStringTag, "TypedArrayToStringTag", 0),
    1510             :     JS_PS_END
    1511             : };
    1512             : 
    1513             : template<typename T>
    1514             : static inline bool
    1515           0 : SetFromTypedArray(JSContext* cx, Handle<TypedArrayObject*> target,
    1516             :                   Handle<TypedArrayObject*> source, uint32_t offset)
    1517             : {
    1518             :     // WARNING: |source| may be an unwrapped typed array from a different
    1519             :     // compartment. Proceed with caution!
    1520             : 
    1521           0 :     if (target->isSharedMemory() || source->isSharedMemory())
    1522           0 :         return ElementSpecific<T, SharedOps>::setFromTypedArray(cx, target, source, offset);
    1523           0 :     return ElementSpecific<T, UnsharedOps>::setFromTypedArray(cx, target, source, offset);
    1524             : }
    1525             : 
    1526             : template<typename T>
    1527             : static inline bool
    1528           0 : SetFromNonTypedArray(JSContext* cx, Handle<TypedArrayObject*> target, HandleObject source,
    1529             :                      uint32_t len, uint32_t offset)
    1530             : {
    1531           0 :     MOZ_ASSERT(!source->is<TypedArrayObject>(), "use SetFromTypedArray");
    1532             : 
    1533           0 :     if (target->isSharedMemory())
    1534           0 :         return ElementSpecific<T, SharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
    1535           0 :     return ElementSpecific<T, UnsharedOps>::setFromNonTypedArray(cx, target, source, len, offset);
    1536             : }
    1537             : 
    1538             : // ES2017 draft rev c57ef95c45a371f9c9485bb1c3881dbdc04524a2
    1539             : // 22.2.3.23 %TypedArray%.prototype.set ( overloaded [ , offset ] )
    1540             : // 22.2.3.23.1 %TypedArray%.prototype.set ( array [ , offset ] )
    1541             : // 22.2.3.23.2 %TypedArray%.prototype.set( typedArray [ , offset ] )
    1542             : /* static */ bool
    1543           0 : TypedArrayObject::set_impl(JSContext* cx, const CallArgs& args)
    1544             : {
    1545           0 :     MOZ_ASSERT(TypedArrayObject::is(args.thisv()));
    1546             : 
    1547             :     // Steps 1-5 (Validation performed as part of CallNonGenericMethod).
    1548           0 :     Rooted<TypedArrayObject*> target(cx, &args.thisv().toObject().as<TypedArrayObject>());
    1549             : 
    1550             :     // Steps 6-7.
    1551           0 :     double targetOffset = 0;
    1552           0 :     if (args.length() > 1) {
    1553             :         // Step 6.
    1554           0 :         if (!ToInteger(cx, args[1], &targetOffset))
    1555           0 :             return false;
    1556             : 
    1557             :         // Step 7.
    1558           0 :         if (targetOffset < 0) {
    1559           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
    1560           0 :             return false;
    1561             :         }
    1562             :     }
    1563             : 
    1564             :     // Steps 8-9.
    1565           0 :     if (target->hasDetachedBuffer()) {
    1566           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
    1567           0 :         return false;
    1568             :     }
    1569             : 
    1570             :     // 22.2.3.23.1, step 15. (22.2.3.23.2 only applies if args[0] is a typed
    1571             :     // array, so it doesn't make a difference there to apply ToObject here.)
    1572           0 :     RootedObject src(cx, ToObject(cx, args.get(0)));
    1573           0 :     if (!src)
    1574           0 :         return false;
    1575             : 
    1576           0 :     Rooted<TypedArrayObject*> srcTypedArray(cx);
    1577             :     {
    1578           0 :         JSObject* obj = CheckedUnwrap(src);
    1579           0 :         if (!obj) {
    1580           0 :             ReportAccessDenied(cx);
    1581           0 :             return false;
    1582             :         }
    1583             : 
    1584           0 :         if (obj->is<TypedArrayObject>())
    1585           0 :             srcTypedArray = &obj->as<TypedArrayObject>();
    1586             :     }
    1587             : 
    1588           0 :     if (srcTypedArray) {
    1589             :         // Remaining steps of 22.2.3.23.2.
    1590             : 
    1591             :         // WARNING: |srcTypedArray| may be an unwrapped typed array from a
    1592             :         // different compartment. Proceed with caution!
    1593             : 
    1594             :         // Steps 11-12.
    1595           0 :         if (srcTypedArray->hasDetachedBuffer()) {
    1596           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
    1597           0 :             return false;
    1598             :         }
    1599             : 
    1600             :         // Step 10 (Reordered).
    1601           0 :         uint32_t targetLength = target->length();
    1602             : 
    1603             :         // Step 22 (Split into two checks to provide better error messages).
    1604           0 :         if (targetOffset > targetLength) {
    1605           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
    1606           0 :             return false;
    1607             :         }
    1608             : 
    1609             :         // Step 22 (Cont'd).
    1610           0 :         uint32_t offset = uint32_t(targetOffset);
    1611           0 :         if (srcTypedArray->length() > targetLength - offset) {
    1612           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
    1613           0 :             return false;
    1614             :         }
    1615             : 
    1616             :         // Steps 13-21, 23-28.
    1617           0 :         switch (target->type()) {
    1618             : #define SET_FROM_TYPED_ARRAY(T, N) \
    1619             :           case Scalar::N: \
    1620             :             if (!SetFromTypedArray<T>(cx, target, srcTypedArray, offset)) \
    1621             :                 return false; \
    1622             :             break;
    1623           0 : JS_FOR_EACH_TYPED_ARRAY(SET_FROM_TYPED_ARRAY)
    1624             : #undef SET_FROM_TYPED_ARRAY
    1625             :           default:
    1626           0 :             MOZ_CRASH("Unsupported TypedArray type");
    1627             :         }
    1628             :     } else {
    1629             :         // Remaining steps of 22.2.3.23.1.
    1630             : 
    1631             :         // Step 10.
    1632             :         // We can't reorder this step because side-effects in step 16 can
    1633             :         // detach the underlying array buffer from the typed array.
    1634           0 :         uint32_t targetLength = target->length();
    1635             : 
    1636             :         // Step 16.
    1637             :         uint32_t srcLength;
    1638           0 :         if (!GetLengthProperty(cx, src, &srcLength))
    1639           0 :             return false;
    1640             : 
    1641             :         // Step 17 (Split into two checks to provide better error messages).
    1642           0 :         if (targetOffset > targetLength) {
    1643           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX);
    1644           0 :             return false;
    1645             :         }
    1646             : 
    1647             :         // Step 17 (Cont'd).
    1648           0 :         uint32_t offset = uint32_t(targetOffset);
    1649           0 :         if (srcLength > targetLength - offset) {
    1650           0 :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
    1651           0 :             return false;
    1652             :         }
    1653             : 
    1654             :         // Steps 11-14, 18-21.
    1655           0 :         if (srcLength > 0) {
    1656             :             // GetLengthProperty in step 16 can lead to the execution of user
    1657             :             // code which may detach the buffer. Handle this case here to
    1658             :             // ensure SetFromNonTypedArray is never called with a detached
    1659             :             // buffer. We still need to execute steps 21.a-b for their
    1660             :             // possible side-effects.
    1661           0 :             if (target->hasDetachedBuffer()) {
    1662             :                 // Steps 21.a-b.
    1663           0 :                 RootedValue v(cx);
    1664           0 :                 if (!GetElement(cx, src, src, 0, &v))
    1665           0 :                    return false;
    1666             : 
    1667             :                 double unused;
    1668           0 :                 if (!ToNumber(cx, v, &unused))
    1669           0 :                     return false;
    1670             : 
    1671             :                 // Step 21.c.
    1672             :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1673           0 :                                           JSMSG_TYPED_ARRAY_DETACHED);
    1674           0 :                 return false;
    1675             :             }
    1676             : 
    1677           0 :             switch (target->type()) {
    1678             : #define SET_FROM_NON_TYPED_ARRAY(T, N) \
    1679             :               case Scalar::N: \
    1680             :                 if (!SetFromNonTypedArray<T>(cx, target, src, srcLength, offset)) \
    1681             :                     return false; \
    1682             :                 break;
    1683           0 : JS_FOR_EACH_TYPED_ARRAY(SET_FROM_NON_TYPED_ARRAY)
    1684             : #undef SET_FROM_NON_TYPED_ARRAY
    1685             :               default:
    1686           0 :                 MOZ_CRASH("Unsupported TypedArray type");
    1687             :             }
    1688             : 
    1689             :             // Step 21.c.
    1690             :             // SetFromNonTypedArray doesn't throw when the array buffer gets
    1691             :             // detached.
    1692           0 :             if (target->hasDetachedBuffer()) {
    1693             :                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    1694           0 :                                           JSMSG_TYPED_ARRAY_DETACHED);
    1695           0 :                 return false;
    1696             :             }
    1697             :         }
    1698             :     }
    1699             : 
    1700             :     // Step 29/22.
    1701           0 :     args.rval().setUndefined();
    1702           0 :     return true;
    1703             : }
    1704             : 
    1705             : /* static */ bool
    1706           0 : TypedArrayObject::set(JSContext* cx, unsigned argc, Value* vp)
    1707             : {
    1708           0 :     CallArgs args = CallArgsFromVp(argc, vp);
    1709           0 :     return CallNonGenericMethod<TypedArrayObject::is, TypedArrayObject::set_impl>(cx, args);
    1710             : }
    1711             : 
    1712             : /* static */ const JSFunctionSpec
    1713             : TypedArrayObject::protoFunctions[] = {
    1714             :     JS_SELF_HOSTED_FN("subarray", "TypedArraySubarray", 2, 0),
    1715             : #if 0 /* disabled until perf-testing is completed */
    1716             :     JS_SELF_HOSTED_FN("set", "TypedArraySet", 2, 0),
    1717             : #else
    1718             :     JS_FN("set", TypedArrayObject::set, 1, 0),
    1719             : #endif
    1720             :     JS_SELF_HOSTED_FN("copyWithin", "TypedArrayCopyWithin", 3, 0),
    1721             :     JS_SELF_HOSTED_FN("every", "TypedArrayEvery", 1, 0),
    1722             :     JS_SELF_HOSTED_FN("fill", "TypedArrayFill", 3, 0),
    1723             :     JS_SELF_HOSTED_FN("filter", "TypedArrayFilter", 1, 0),
    1724             :     JS_SELF_HOSTED_FN("find", "TypedArrayFind", 1, 0),
    1725             :     JS_SELF_HOSTED_FN("findIndex", "TypedArrayFindIndex", 1, 0),
    1726             :     JS_SELF_HOSTED_FN("forEach", "TypedArrayForEach", 1, 0),
    1727             :     JS_SELF_HOSTED_FN("indexOf", "TypedArrayIndexOf", 2, 0),
    1728             :     JS_SELF_HOSTED_FN("join", "TypedArrayJoin", 1, 0),
    1729             :     JS_SELF_HOSTED_FN("lastIndexOf", "TypedArrayLastIndexOf", 1, 0),
    1730             :     JS_SELF_HOSTED_FN("map", "TypedArrayMap", 1, 0),
    1731             :     JS_SELF_HOSTED_FN("reduce", "TypedArrayReduce", 1, 0),
    1732             :     JS_SELF_HOSTED_FN("reduceRight", "TypedArrayReduceRight", 1, 0),
    1733             :     JS_SELF_HOSTED_FN("reverse", "TypedArrayReverse", 0, 0),
    1734             :     JS_SELF_HOSTED_FN("slice", "TypedArraySlice", 2, 0),
    1735             :     JS_SELF_HOSTED_FN("some", "TypedArraySome", 1, 0),
    1736             :     JS_SELF_HOSTED_FN("sort", "TypedArraySort", 1, 0),
    1737             :     JS_SELF_HOSTED_FN("entries", "TypedArrayEntries", 0, 0),
    1738             :     JS_SELF_HOSTED_FN("keys", "TypedArrayKeys", 0, 0),
    1739             :     JS_SELF_HOSTED_FN("values", "TypedArrayValues", 0, 0),
    1740             :     JS_SELF_HOSTED_SYM_FN(iterator, "TypedArrayValues", 0, 0),
    1741             :     JS_SELF_HOSTED_FN("includes", "TypedArrayIncludes", 2, 0),
    1742             :     JS_SELF_HOSTED_FN("toString", "ArrayToString", 0, 0),
    1743             :     JS_SELF_HOSTED_FN("toLocaleString", "TypedArrayToLocaleString", 2, 0),
    1744             :     JS_FS_END
    1745             : };
    1746             : 
    1747             : /* static */ const JSFunctionSpec
    1748             : TypedArrayObject::staticFunctions[] = {
    1749             :     JS_SELF_HOSTED_FN("from", "TypedArrayStaticFrom", 3, 0),
    1750             :     JS_SELF_HOSTED_FN("of", "TypedArrayStaticOf", 0, 0),
    1751             :     JS_FS_END
    1752             : };
    1753             : 
    1754             : /* static */ const JSPropertySpec
    1755             : TypedArrayObject::staticProperties[] = {
    1756             :     JS_SELF_HOSTED_SYM_GET(species, "TypedArraySpecies", 0),
    1757             :     JS_PS_END
    1758             : };
    1759             : 
    1760             : static const ClassSpec
    1761             : TypedArrayObjectSharedTypedArrayPrototypeClassSpec = {
    1762             :     GenericCreateConstructor<TypedArrayConstructor, 0, gc::AllocKind::FUNCTION>,
    1763             :     GenericCreatePrototype,
    1764             :     TypedArrayObject::staticFunctions,
    1765             :     TypedArrayObject::staticProperties,
    1766             :     TypedArrayObject::protoFunctions,
    1767             :     TypedArrayObject::protoAccessors,
    1768             :     nullptr,
    1769             :     ClassSpec::DontDefineConstructor
    1770             : };
    1771             : 
    1772             : /* static */ const Class
    1773             : TypedArrayObject::sharedTypedArrayPrototypeClass = {
    1774             :     // Actually ({}).toString.call(%TypedArray%.prototype) should throw,
    1775             :     // because %TypedArray%.prototype lacks the the typed array internal
    1776             :     // slots.  (It's not clear this is desirable -- particularly applied to
    1777             :     // the actual typed array prototypes, see below -- but it's what ES6
    1778             :     // draft 20140824 requires.)  But this is about as much as we can do
    1779             :     // until we implement @@toStringTag.
    1780             :     "???",
    1781             :     JSCLASS_HAS_CACHED_PROTO(JSProto_TypedArray),
    1782             :     JS_NULL_CLASS_OPS,
    1783             :     &TypedArrayObjectSharedTypedArrayPrototypeClassSpec
    1784             : };
    1785             : 
    1786             : // this default implementation is only valid for integer types
    1787             : // less than 32-bits in size.
    1788             : template<typename NativeType>
    1789             : Value
    1790           0 : TypedArrayObjectTemplate<NativeType>::getIndexValue(JSObject* tarray, uint32_t index)
    1791             : {
    1792             :     static_assert(sizeof(NativeType) < 4,
    1793             :                   "this method must only handle NativeType values that are "
    1794             :                   "always exact int32_t values");
    1795             : 
    1796           0 :     return Int32Value(getIndex(tarray, index));
    1797             : }
    1798             : 
    1799             : namespace {
    1800             : 
    1801             : // and we need to specialize for 32-bit integers and floats
    1802             : template<>
    1803             : Value
    1804           0 : TypedArrayObjectTemplate<int32_t>::getIndexValue(JSObject* tarray, uint32_t index)
    1805             : {
    1806           0 :     return Int32Value(getIndex(tarray, index));
    1807             : }
    1808             : 
    1809             : template<>
    1810             : Value
    1811           0 : TypedArrayObjectTemplate<uint32_t>::getIndexValue(JSObject* tarray, uint32_t index)
    1812             : {
    1813           0 :     uint32_t val = getIndex(tarray, index);
    1814           0 :     return NumberValue(val);
    1815             : }
    1816             : 
    1817             : template<>
    1818             : Value
    1819           0 : TypedArrayObjectTemplate<float>::getIndexValue(JSObject* tarray, uint32_t index)
    1820             : {
    1821           0 :     float val = getIndex(tarray, index);
    1822           0 :     double dval = val;
    1823             : 
    1824             :     /*
    1825             :      * Doubles in typed arrays could be typed-punned arrays of integers. This
    1826             :      * could allow user code to break the engine-wide invariant that only
    1827             :      * canonical nans are stored into jsvals, which means user code could
    1828             :      * confuse the engine into interpreting a double-typed jsval as an
    1829             :      * object-typed jsval.
    1830             :      *
    1831             :      * This could be removed for platforms/compilers known to convert a 32-bit
    1832             :      * non-canonical nan to a 64-bit canonical nan.
    1833             :      */
    1834           0 :     return DoubleValue(CanonicalizeNaN(dval));
    1835             : }
    1836             : 
    1837             : template<>
    1838             : Value
    1839           0 : TypedArrayObjectTemplate<double>::getIndexValue(JSObject* tarray, uint32_t index)
    1840             : {
    1841           0 :     double val = getIndex(tarray, index);
    1842             : 
    1843             :     /*
    1844             :      * Doubles in typed arrays could be typed-punned arrays of integers. This
    1845             :      * could allow user code to break the engine-wide invariant that only
    1846             :      * canonical nans are stored into jsvals, which means user code could
    1847             :      * confuse the engine into interpreting a double-typed jsval as an
    1848             :      * object-typed jsval.
    1849             :      */
    1850           0 :     return DoubleValue(CanonicalizeNaN(val));
    1851             : }
    1852             : 
    1853             : } /* anonymous namespace */
    1854             : 
    1855             : Value
    1856           0 : TypedArrayObject::getElement(uint32_t index)
    1857             : {
    1858           0 :     switch (type()) {
    1859             :       case Scalar::Int8:
    1860           0 :         return Int8Array::getIndexValue(this, index);
    1861             :       case Scalar::Uint8:
    1862           0 :         return Uint8Array::getIndexValue(this, index);
    1863             :       case Scalar::Int16:
    1864           0 :         return Int16Array::getIndexValue(this, index);
    1865             :       case Scalar::Uint16:
    1866           0 :         return Uint16Array::getIndexValue(this, index);
    1867             :       case Scalar::Int32:
    1868           0 :         return Int32Array::getIndexValue(this, index);
    1869             :       case Scalar::Uint32:
    1870           0 :         return Uint32Array::getIndexValue(this, index);
    1871             :       case Scalar::Float32:
    1872           0 :         return Float32Array::getIndexValue(this, index);
    1873             :       case Scalar::Float64:
    1874           0 :         return Float64Array::getIndexValue(this, index);
    1875             :       case Scalar::Uint8Clamped:
    1876           0 :         return Uint8ClampedArray::getIndexValue(this, index);
    1877             :       case Scalar::Int64:
    1878             :       case Scalar::Float32x4:
    1879             :       case Scalar::Int8x16:
    1880             :       case Scalar::Int16x8:
    1881             :       case Scalar::Int32x4:
    1882             :       case Scalar::MaxTypedArrayViewType:
    1883           0 :         break;
    1884             :     }
    1885             : 
    1886           0 :     MOZ_CRASH("Unknown TypedArray type");
    1887             : }
    1888             : 
    1889             : void
    1890           0 : TypedArrayObject::setElement(TypedArrayObject& obj, uint32_t index, double d)
    1891             : {
    1892           0 :     MOZ_ASSERT(index < obj.length());
    1893             : 
    1894             : #ifdef JS_MORE_DETERMINISTIC
    1895             :     // See the comment in ElementSpecific::doubleToNative.
    1896             :     d = JS::CanonicalizeNaN(d);
    1897             : #endif
    1898             : 
    1899           0 :     switch (obj.type()) {
    1900             :       case Scalar::Int8:
    1901           0 :         Int8Array::setIndexValue(obj, index, d);
    1902           0 :         return;
    1903             :       case Scalar::Uint8:
    1904           0 :         Uint8Array::setIndexValue(obj, index, d);
    1905           0 :         return;
    1906             :       case Scalar::Uint8Clamped:
    1907           0 :         Uint8ClampedArray::setIndexValue(obj, index, d);
    1908           0 :         return;
    1909             :       case Scalar::Int16:
    1910           0 :         Int16Array::setIndexValue(obj, index, d);
    1911           0 :         return;
    1912             :       case Scalar::Uint16:
    1913           0 :         Uint16Array::setIndexValue(obj, index, d);
    1914           0 :         return;
    1915             :       case Scalar::Int32:
    1916           0 :         Int32Array::setIndexValue(obj, index, d);
    1917           0 :         return;
    1918             :       case Scalar::Uint32:
    1919           0 :         Uint32Array::setIndexValue(obj, index, d);
    1920           0 :         return;
    1921             :       case Scalar::Float32:
    1922           0 :         Float32Array::setIndexValue(obj, index, d);
    1923           0 :         return;
    1924             :       case Scalar::Float64:
    1925           0 :         Float64Array::setIndexValue(obj, index, d);
    1926           0 :         return;
    1927             :       case Scalar::Int64:
    1928             :       case Scalar::Float32x4:
    1929             :       case Scalar::Int8x16:
    1930             :       case Scalar::Int16x8:
    1931             :       case Scalar::Int32x4:
    1932             :       case Scalar::MaxTypedArrayViewType:
    1933           0 :         break;
    1934             :     }
    1935             : 
    1936           0 :     MOZ_CRASH("Unknown TypedArray type");
    1937             : }
    1938             : 
    1939             : /***
    1940             :  *** JS impl
    1941             :  ***/
    1942             : 
    1943             : /*
    1944             :  * TypedArrayObject boilerplate
    1945             :  */
    1946             : 
    1947             : #define IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Name,NativeType)                                    \
    1948             :   JS_FRIEND_API(JSObject*) JS_New ## Name ## Array(JSContext* cx, uint32_t nelements)           \
    1949             :   {                                                                                             \
    1950             :       return TypedArrayObjectTemplate<NativeType>::fromLength(cx, nelements);                   \
    1951             :   }                                                                                             \
    1952             :   JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayFromArray(JSContext* cx, HandleObject other)  \
    1953             :   {                                                                                             \
    1954             :       return TypedArrayObjectTemplate<NativeType>::fromArray(cx, other);                        \
    1955             :   }                                                                                             \
    1956             :   JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayWithBuffer(JSContext* cx,                     \
    1957             :                                HandleObject arrayBuffer, uint32_t byteOffset, int32_t length)   \
    1958             :   {                                                                                             \
    1959             :       return TypedArrayObjectTemplate<NativeType>::fromBuffer(cx, arrayBuffer, byteOffset,      \
    1960             :                                                               length);                          \
    1961             :   }                                                                                             \
    1962             :   JS_FRIEND_API(bool) JS_Is ## Name ## Array(JSObject* obj)                                     \
    1963             :   {                                                                                             \
    1964             :       if (!(obj = CheckedUnwrap(obj)))                                                          \
    1965             :           return false;                                                                         \
    1966             :       const Class* clasp = obj->getClass();                                                     \
    1967             :       return clasp == TypedArrayObjectTemplate<NativeType>::instanceClass();                    \
    1968             :   }                                                                                             \
    1969             :   JS_FRIEND_API(JSObject*) js::Unwrap ## Name ## Array(JSObject* obj)                           \
    1970             :   {                                                                                             \
    1971             :       obj = CheckedUnwrap(obj);                                                                 \
    1972             :       if (!obj)                                                                                 \
    1973             :           return nullptr;                                                                       \
    1974             :       const Class* clasp = obj->getClass();                                                     \
    1975             :       if (clasp == TypedArrayObjectTemplate<NativeType>::instanceClass())                       \
    1976             :           return obj;                                                                           \
    1977             :       return nullptr;                                                                           \
    1978             :   }                                                                                             \
    1979             :   const js::Class* const js::detail::Name ## ArrayClassPtr =                                    \
    1980             :       &js::TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()];
    1981             : 
    1982           0 : IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int8, int8_t)
    1983           0 : IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8, uint8_t)
    1984           0 : IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8Clamped, uint8_clamped)
    1985           0 : IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int16, int16_t)
    1986           0 : IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint16, uint16_t)
    1987           0 : IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int32, int32_t)
    1988           0 : IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint32, uint32_t)
    1989           0 : IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float32, float)
    1990           0 : IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double)
    1991             : 
    1992             : #define IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Name, ExternalType, InternalType)              \
    1993             :   JS_FRIEND_API(JSObject*) JS_GetObjectAs ## Name ## Array(JSObject* obj,                  \
    1994             :                                                             uint32_t* length,               \
    1995             :                                                             bool* isShared,                 \
    1996             :                                                             ExternalType** data)            \
    1997             :   {                                                                                         \
    1998             :       if (!(obj = CheckedUnwrap(obj)))                                                      \
    1999             :           return nullptr;                                                                   \
    2000             :                                                                                             \
    2001             :       const Class* clasp = obj->getClass();                                                 \
    2002             :       if (clasp != TypedArrayObjectTemplate<InternalType>::instanceClass())                 \
    2003             :           return nullptr;                                                                   \
    2004             :                                                                                             \
    2005             :       TypedArrayObject* tarr = &obj->as<TypedArrayObject>();                                \
    2006             :       *length = tarr->length();                                                             \
    2007             :       *isShared = tarr->isSharedMemory();                                                         \
    2008             :       *data = static_cast<ExternalType*>(tarr->viewDataEither().unwrap(/*safe - caller sees isShared flag*/)); \
    2009             :                                                                                             \
    2010             :       return obj;                                                                           \
    2011             :   }
    2012             : 
    2013           0 : IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int8, int8_t, int8_t)
    2014           0 : IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8, uint8_t, uint8_t)
    2015           0 : IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8Clamped, uint8_t, uint8_clamped)
    2016           0 : IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int16, int16_t, int16_t)
    2017           0 : IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint16, uint16_t, uint16_t)
    2018           0 : IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int32, int32_t, int32_t)
    2019           0 : IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint32, uint32_t, uint32_t)
    2020           0 : IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float32, float, float)
    2021           0 : IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
    2022             : 
    2023             : static const ClassOps TypedArrayClassOps = {
    2024             :     nullptr,                 /* addProperty */
    2025             :     nullptr,                 /* delProperty */
    2026             :     nullptr,                 /* getProperty */
    2027             :     nullptr,                 /* setProperty */
    2028             :     nullptr,                 /* enumerate   */
    2029             :     nullptr,                 /* newEnumerate */
    2030             :     nullptr,                 /* resolve     */
    2031             :     nullptr,                 /* mayResolve  */
    2032             :     TypedArrayObject::finalize, /* finalize    */
    2033             :     nullptr,                 /* call        */
    2034             :     nullptr,                 /* hasInstance */
    2035             :     nullptr,                 /* construct   */
    2036             :     TypedArrayObject::trace, /* trace  */
    2037             : };
    2038             : 
    2039             : static const ClassExtension TypedArrayClassExtension = {
    2040             :     nullptr,
    2041             :     TypedArrayObject::objectMoved,
    2042             : };
    2043             : 
    2044             : #define IMPL_TYPED_ARRAY_PROPERTIES(_type)                                     \
    2045             : {                                                                              \
    2046             : JS_INT32_PS("BYTES_PER_ELEMENT", _type##Array::BYTES_PER_ELEMENT,              \
    2047             :             JSPROP_READONLY | JSPROP_PERMANENT),                               \
    2048             : JS_PS_END                                                                      \
    2049             : }
    2050             : 
    2051             : static const JSPropertySpec static_prototype_properties[Scalar::MaxTypedArrayViewType][2] = {
    2052             :     IMPL_TYPED_ARRAY_PROPERTIES(Int8),
    2053             :     IMPL_TYPED_ARRAY_PROPERTIES(Uint8),
    2054             :     IMPL_TYPED_ARRAY_PROPERTIES(Int16),
    2055             :     IMPL_TYPED_ARRAY_PROPERTIES(Uint16),
    2056             :     IMPL_TYPED_ARRAY_PROPERTIES(Int32),
    2057             :     IMPL_TYPED_ARRAY_PROPERTIES(Uint32),
    2058             :     IMPL_TYPED_ARRAY_PROPERTIES(Float32),
    2059             :     IMPL_TYPED_ARRAY_PROPERTIES(Float64),
    2060             :     IMPL_TYPED_ARRAY_PROPERTIES(Uint8Clamped)
    2061           3 : };
    2062             : 
    2063             : #define IMPL_TYPED_ARRAY_CLASS_SPEC(_type)                                     \
    2064             : {                                                                              \
    2065             :     _type##Array::createConstructor,                                           \
    2066             :     _type##Array::createPrototype,                                             \
    2067             :     nullptr,                                                                   \
    2068             :     static_prototype_properties[Scalar::Type::_type],                          \
    2069             :     nullptr,                                                                   \
    2070             :     static_prototype_properties[Scalar::Type::_type],                          \
    2071             :     nullptr,                                                                   \
    2072             :     JSProto_TypedArray                                                         \
    2073             : }
    2074             : 
    2075             : static const ClassSpec TypedArrayObjectClassSpecs[Scalar::MaxTypedArrayViewType] = {
    2076             :     IMPL_TYPED_ARRAY_CLASS_SPEC(Int8),
    2077             :     IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8),
    2078             :     IMPL_TYPED_ARRAY_CLASS_SPEC(Int16),
    2079             :     IMPL_TYPED_ARRAY_CLASS_SPEC(Uint16),
    2080             :     IMPL_TYPED_ARRAY_CLASS_SPEC(Int32),
    2081             :     IMPL_TYPED_ARRAY_CLASS_SPEC(Uint32),
    2082             :     IMPL_TYPED_ARRAY_CLASS_SPEC(Float32),
    2083             :     IMPL_TYPED_ARRAY_CLASS_SPEC(Float64),
    2084             :     IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8Clamped)
    2085             : };
    2086             : 
    2087             : #define IMPL_TYPED_ARRAY_CLASS(_type)                                          \
    2088             : {                                                                              \
    2089             :     #_type "Array",                                                            \
    2090             :     JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) |             \
    2091             :     JSCLASS_HAS_PRIVATE |                                                      \
    2092             :     JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array) |                         \
    2093             :     JSCLASS_DELAY_METADATA_BUILDER |                                           \
    2094             :     JSCLASS_SKIP_NURSERY_FINALIZE |                                            \
    2095             :     JSCLASS_BACKGROUND_FINALIZE,                                               \
    2096             :     &TypedArrayClassOps,                                                       \
    2097             :     &TypedArrayObjectClassSpecs[Scalar::Type::_type],                          \
    2098             :     &TypedArrayClassExtension                                                  \
    2099             : }
    2100             : 
    2101             : const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
    2102             :     IMPL_TYPED_ARRAY_CLASS(Int8),
    2103             :     IMPL_TYPED_ARRAY_CLASS(Uint8),
    2104             :     IMPL_TYPED_ARRAY_CLASS(Int16),
    2105             :     IMPL_TYPED_ARRAY_CLASS(Uint16),
    2106             :     IMPL_TYPED_ARRAY_CLASS(Int32),
    2107             :     IMPL_TYPED_ARRAY_CLASS(Uint32),
    2108             :     IMPL_TYPED_ARRAY_CLASS(Float32),
    2109             :     IMPL_TYPED_ARRAY_CLASS(Float64),
    2110             :     IMPL_TYPED_ARRAY_CLASS(Uint8Clamped)
    2111             : };
    2112             : 
    2113             : // The various typed array prototypes are supposed to 1) be normal objects,
    2114             : // 2) stringify to "[object <name of constructor>]", and 3) (Gecko-specific)
    2115             : // be xrayable.  The first and second requirements mandate (in the absence of
    2116             : // @@toStringTag) a custom class.  The third requirement mandates that each
    2117             : // prototype's class have the relevant typed array's cached JSProtoKey in them.
    2118             : // Thus we need one class with cached prototype per kind of typed array, with a
    2119             : // delegated ClassSpec.
    2120             : #define IMPL_TYPED_ARRAY_PROTO_CLASS(_type) \
    2121             : { \
    2122             :     /*
    2123             :      * Actually ({}).toString.call(Uint8Array.prototype) should throw, because
    2124             :      * Uint8Array.prototype lacks the the typed array internal slots.  (Same as
    2125             :      * with %TypedArray%.prototype.)  It's not clear this is desirable (see
    2126             :      * above), but it's what we've always done, so keep doing it till we
    2127             :      * implement @@toStringTag or ES6 changes.
    2128             :      */ \
    2129             :     #_type "ArrayPrototype", \
    2130             :     JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array), \
    2131             :     JS_NULL_CLASS_OPS, \
    2132             :     &TypedArrayObjectClassSpecs[Scalar::Type::_type] \
    2133             : }
    2134             : 
    2135             : const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
    2136             :     IMPL_TYPED_ARRAY_PROTO_CLASS(Int8),
    2137             :     IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8),
    2138             :     IMPL_TYPED_ARRAY_PROTO_CLASS(Int16),
    2139             :     IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16),
    2140             :     IMPL_TYPED_ARRAY_PROTO_CLASS(Int32),
    2141             :     IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32),
    2142             :     IMPL_TYPED_ARRAY_PROTO_CLASS(Float32),
    2143             :     IMPL_TYPED_ARRAY_PROTO_CLASS(Float64),
    2144             :     IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Clamped)
    2145             : };
    2146             : 
    2147             : /* static */ bool
    2148           0 : TypedArrayObject::isOriginalLengthGetter(Native native)
    2149             : {
    2150           0 :     return native == TypedArray_lengthGetter;
    2151             : }
    2152             : 
    2153             : bool
    2154           0 : js::IsTypedArrayConstructor(HandleValue v, uint32_t type)
    2155             : {
    2156           0 :     switch (type) {
    2157             :       case Scalar::Int8:
    2158           0 :         return IsNativeFunction(v, Int8Array::class_constructor);
    2159             :       case Scalar::Uint8:
    2160           0 :         return IsNativeFunction(v, Uint8Array::class_constructor);
    2161             :       case Scalar::Int16:
    2162           0 :         return IsNativeFunction(v, Int16Array::class_constructor);
    2163             :       case Scalar::Uint16:
    2164           0 :         return IsNativeFunction(v, Uint16Array::class_constructor);
    2165             :       case Scalar::Int32:
    2166           0 :         return IsNativeFunction(v, Int32Array::class_constructor);
    2167             :       case Scalar::Uint32:
    2168           0 :         return IsNativeFunction(v, Uint32Array::class_constructor);
    2169             :       case Scalar::Float32:
    2170           0 :         return IsNativeFunction(v, Float32Array::class_constructor);
    2171             :       case Scalar::Float64:
    2172           0 :         return IsNativeFunction(v, Float64Array::class_constructor);
    2173             :       case Scalar::Uint8Clamped:
    2174           0 :         return IsNativeFunction(v, Uint8ClampedArray::class_constructor);
    2175             :       case Scalar::MaxTypedArrayViewType:
    2176           0 :         break;
    2177             :     }
    2178           0 :     MOZ_CRASH("unexpected typed array type");
    2179             : }
    2180             : 
    2181             : template <typename CharT>
    2182             : bool
    2183           0 : js::StringIsTypedArrayIndex(const CharT* s, size_t length, uint64_t* indexp)
    2184             : {
    2185           0 :     const CharT* end = s + length;
    2186             : 
    2187           0 :     if (s == end)
    2188           0 :         return false;
    2189             : 
    2190           0 :     bool negative = false;
    2191           0 :     if (*s == '-') {
    2192           0 :         negative = true;
    2193           0 :         if (++s == end)
    2194           0 :             return false;
    2195             :     }
    2196             : 
    2197           0 :     if (!JS7_ISDEC(*s))
    2198           0 :         return false;
    2199             : 
    2200           0 :     uint64_t index = 0;
    2201           0 :     uint32_t digit = JS7_UNDEC(*s++);
    2202             : 
    2203             :     /* Don't allow leading zeros. */
    2204           0 :     if (digit == 0 && s != end)
    2205           0 :         return false;
    2206             : 
    2207           0 :     index = digit;
    2208             : 
    2209           0 :     for (; s < end; s++) {
    2210           0 :         if (!JS7_ISDEC(*s))
    2211           0 :             return false;
    2212             : 
    2213           0 :         digit = JS7_UNDEC(*s);
    2214             : 
    2215             :         /* Watch for overflows. */
    2216           0 :         if ((UINT64_MAX - digit) / 10 < index)
    2217           0 :             index = UINT64_MAX;
    2218             :         else
    2219           0 :             index = 10 * index + digit;
    2220             :     }
    2221             : 
    2222           0 :     if (negative)
    2223           0 :         *indexp = UINT64_MAX;
    2224             :     else
    2225           0 :         *indexp = index;
    2226           0 :     return true;
    2227             : }
    2228             : 
    2229             : template bool
    2230             : js::StringIsTypedArrayIndex(const char16_t* s, size_t length, uint64_t* indexp);
    2231             : 
    2232             : template bool
    2233             : js::StringIsTypedArrayIndex(const Latin1Char* s, size_t length, uint64_t* indexp);
    2234             : 
    2235             : /* ES6 draft rev 34 (2015 Feb 20) 9.4.5.3 [[DefineOwnProperty]] step 3.c. */
    2236             : bool
    2237           0 : js::DefineTypedArrayElement(JSContext* cx, HandleObject obj, uint64_t index,
    2238             :                             Handle<PropertyDescriptor> desc, ObjectOpResult& result)
    2239             : {
    2240           0 :     MOZ_ASSERT(obj->is<TypedArrayObject>());
    2241             : 
    2242             :     // These are all substeps of 3.b.
    2243             : 
    2244             :     // Steps i-iii are handled by the caller.
    2245             : 
    2246             :     // Steps iv-v.
    2247             :     // We (wrongly) ignore out of range defines with a value.
    2248           0 :     uint32_t length = obj->as<TypedArrayObject>().length();
    2249           0 :     if (index >= length)
    2250           0 :         return result.succeed();
    2251             : 
    2252             :     // Step vi.
    2253           0 :     if (desc.isAccessorDescriptor())
    2254           0 :         return result.fail(JSMSG_CANT_REDEFINE_PROP);
    2255             : 
    2256             :     // Step vii.
    2257           0 :     if (desc.hasConfigurable() && desc.configurable())
    2258           0 :         return result.fail(JSMSG_CANT_REDEFINE_PROP);
    2259             : 
    2260             :     // Step viii.
    2261           0 :     if (desc.hasEnumerable() && !desc.enumerable())
    2262           0 :         return result.fail(JSMSG_CANT_REDEFINE_PROP);
    2263             : 
    2264             :     // Step ix.
    2265           0 :     if (desc.hasWritable() && !desc.writable())
    2266           0 :         return result.fail(JSMSG_CANT_REDEFINE_PROP);
    2267             : 
    2268             :     // Step x.
    2269           0 :     if (desc.hasValue()) {
    2270             :         // The following step numbers refer to 9.4.5.9
    2271             :         // IntegerIndexedElementSet.
    2272             : 
    2273             :         // Steps 1-2 are enforced by the caller.
    2274             : 
    2275             :         // Step 3.
    2276             :         double numValue;
    2277           0 :         if (!ToNumber(cx, desc.value(), &numValue))
    2278           0 :             return false;
    2279             : 
    2280             :         // Steps 4-5, 8-9.
    2281           0 :         if (obj->as<TypedArrayObject>().hasDetachedBuffer())
    2282           0 :             return result.fail(JSMSG_TYPED_ARRAY_DETACHED);
    2283             : 
    2284             :         // Steps 10-16.
    2285           0 :         TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, numValue);
    2286             :     }
    2287             : 
    2288             :     // Step xii.
    2289           0 :     return result.succeed();
    2290             : }
    2291             : 
    2292             : /* JS Friend API */
    2293             : 
    2294             : JS_FRIEND_API(bool)
    2295         145 : JS_IsTypedArrayObject(JSObject* obj)
    2296             : {
    2297         145 :     obj = CheckedUnwrap(obj);
    2298         145 :     return obj ? obj->is<TypedArrayObject>() : false;
    2299             : }
    2300             : 
    2301             : JS_FRIEND_API(uint32_t)
    2302           0 : JS_GetTypedArrayLength(JSObject* obj)
    2303             : {
    2304           0 :     obj = CheckedUnwrap(obj);
    2305           0 :     if (!obj)
    2306           0 :         return 0;
    2307           0 :     return obj->as<TypedArrayObject>().length();
    2308             : }
    2309             : 
    2310             : JS_FRIEND_API(uint32_t)
    2311           0 : JS_GetTypedArrayByteOffset(JSObject* obj)
    2312             : {
    2313           0 :     obj = CheckedUnwrap(obj);
    2314           0 :     if (!obj)
    2315           0 :         return 0;
    2316           0 :     return obj->as<TypedArrayObject>().byteOffset();
    2317             : }
    2318             : 
    2319             : JS_FRIEND_API(uint32_t)
    2320           0 : JS_GetTypedArrayByteLength(JSObject* obj)
    2321             : {
    2322           0 :     obj = CheckedUnwrap(obj);
    2323           0 :     if (!obj)
    2324           0 :         return 0;
    2325           0 :     return obj->as<TypedArrayObject>().byteLength();
    2326             : }
    2327             : 
    2328             : JS_FRIEND_API(bool)
    2329           0 : JS_GetTypedArraySharedness(JSObject* obj)
    2330             : {
    2331           0 :     obj = CheckedUnwrap(obj);
    2332           0 :     if (!obj)
    2333           0 :         return false;
    2334           0 :     return obj->as<TypedArrayObject>().isSharedMemory();
    2335             : }
    2336             : 
    2337             : JS_FRIEND_API(js::Scalar::Type)
    2338           0 : JS_GetArrayBufferViewType(JSObject* obj)
    2339             : {
    2340           0 :     obj = CheckedUnwrap(obj);
    2341           0 :     if (!obj)
    2342           0 :         return Scalar::MaxTypedArrayViewType;
    2343             : 
    2344           0 :     if (obj->is<TypedArrayObject>())
    2345           0 :         return obj->as<TypedArrayObject>().type();
    2346           0 :     if (obj->is<DataViewObject>())
    2347           0 :         return Scalar::MaxTypedArrayViewType;
    2348           0 :     MOZ_CRASH("invalid ArrayBufferView type");
    2349             : }
    2350             : 
    2351             : JS_FRIEND_API(int8_t*)
    2352           0 : JS_GetInt8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    2353             : {
    2354           0 :     obj = CheckedUnwrap(obj);
    2355           0 :     if (!obj)
    2356           0 :         return nullptr;
    2357           0 :     TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
    2358           0 :     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int8);
    2359           0 :     *isSharedMemory = tarr->isSharedMemory();
    2360           0 :     return static_cast<int8_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isShared*/));
    2361             : }
    2362             : 
    2363             : JS_FRIEND_API(uint8_t*)
    2364           0 : JS_GetUint8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    2365             : {
    2366           0 :     obj = CheckedUnwrap(obj);
    2367           0 :     if (!obj)
    2368           0 :         return nullptr;
    2369           0 :     TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
    2370           0 :     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8);
    2371           0 :     *isSharedMemory = tarr->isSharedMemory();
    2372           0 :     return static_cast<uint8_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
    2373             : }
    2374             : 
    2375             : JS_FRIEND_API(uint8_t*)
    2376           0 : JS_GetUint8ClampedArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    2377             : {
    2378           0 :     obj = CheckedUnwrap(obj);
    2379           0 :     if (!obj)
    2380           0 :         return nullptr;
    2381           0 :     TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
    2382           0 :     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8Clamped);
    2383           0 :     *isSharedMemory = tarr->isSharedMemory();
    2384           0 :     return static_cast<uint8_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
    2385             : }
    2386             : 
    2387             : JS_FRIEND_API(int16_t*)
    2388           0 : JS_GetInt16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    2389             : {
    2390           0 :     obj = CheckedUnwrap(obj);
    2391           0 :     if (!obj)
    2392           0 :         return nullptr;
    2393           0 :     TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
    2394           0 :     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int16);
    2395           0 :     *isSharedMemory = tarr->isSharedMemory();
    2396           0 :     return static_cast<int16_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
    2397             : }
    2398             : 
    2399             : JS_FRIEND_API(uint16_t*)
    2400           0 : JS_GetUint16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    2401             : {
    2402           0 :     obj = CheckedUnwrap(obj);
    2403           0 :     if (!obj)
    2404           0 :         return nullptr;
    2405           0 :     TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
    2406           0 :     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint16);
    2407           0 :     *isSharedMemory = tarr->isSharedMemory();
    2408           0 :     return static_cast<uint16_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
    2409             : }
    2410             : 
    2411             : JS_FRIEND_API(int32_t*)
    2412           0 : JS_GetInt32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    2413             : {
    2414           0 :     obj = CheckedUnwrap(obj);
    2415           0 :     if (!obj)
    2416           0 :         return nullptr;
    2417           0 :     TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
    2418           0 :     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int32);
    2419           0 :     *isSharedMemory = tarr->isSharedMemory();
    2420           0 :     return static_cast<int32_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
    2421             : }
    2422             : 
    2423             : JS_FRIEND_API(uint32_t*)
    2424           0 : JS_GetUint32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    2425             : {
    2426           0 :     obj = CheckedUnwrap(obj);
    2427           0 :     if (!obj)
    2428           0 :         return nullptr;
    2429           0 :     TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
    2430           0 :     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint32);
    2431           0 :     *isSharedMemory = tarr->isSharedMemory();
    2432           0 :     return static_cast<uint32_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
    2433             : }
    2434             : 
    2435             : JS_FRIEND_API(float*)
    2436           0 : JS_GetFloat32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    2437             : {
    2438           0 :     obj = CheckedUnwrap(obj);
    2439           0 :     if (!obj)
    2440           0 :         return nullptr;
    2441           0 :     TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
    2442           0 :     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float32);
    2443           0 :     *isSharedMemory = tarr->isSharedMemory();
    2444           0 :     return static_cast<float*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
    2445             : }
    2446             : 
    2447             : JS_FRIEND_API(double*)
    2448           0 : JS_GetFloat64ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    2449             : {
    2450           0 :     obj = CheckedUnwrap(obj);
    2451           0 :     if (!obj)
    2452           0 :         return nullptr;
    2453           0 :     TypedArrayObject* tarr = &obj->as<TypedArrayObject>();
    2454           0 :     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float64);
    2455           0 :     *isSharedMemory = tarr->isSharedMemory();
    2456           0 :     return static_cast<double*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));
    2457           9 : }

Generated by: LCOV version 1.13