LCOV - code coverage report
Current view: top level - js/src/builtin - DataViewObject.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 5 445 1.1 %
Date: 2017-07-14 16:53:18 Functions: 2 123 1.6 %
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 "builtin/DataViewObject.h"
       8             : 
       9             : #include "mozilla/Alignment.h"
      10             : #include "mozilla/Casting.h"
      11             : 
      12             : #include <string.h>
      13             : 
      14             : #include "jsapi.h"
      15             : #include "jsarray.h"
      16             : #include "jscntxt.h"
      17             : #include "jsnum.h"
      18             : #include "jsobj.h"
      19             : #ifdef XP_WIN
      20             : # include "jswin.h"
      21             : #endif
      22             : #include "jswrapper.h"
      23             : 
      24             : #include "jit/AtomicOperations.h"
      25             : #include "js/Conversions.h"
      26             : #include "vm/ArrayBufferObject.h"
      27             : #include "vm/GlobalObject.h"
      28             : #include "vm/Interpreter.h"
      29             : #include "vm/SharedMem.h"
      30             : #include "vm/WrapperObject.h"
      31             : 
      32             : #include "gc/Nursery-inl.h"
      33             : #include "gc/StoreBuffer-inl.h"
      34             : #include "vm/ArrayBufferObject-inl.h"
      35             : #include "vm/NativeObject-inl.h"
      36             : 
      37             : using namespace js;
      38             : using namespace js::gc;
      39             : 
      40             : using mozilla::AssertedCast;
      41             : using JS::CanonicalizeNaN;
      42             : using JS::ToInt32;
      43             : using JS::ToUint32;
      44             : 
      45             : static NewObjectKind
      46           0 : DataViewNewObjectKind(JSContext* cx, uint32_t byteLength, JSObject* proto)
      47             : {
      48           0 :     if (!proto && byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH)
      49           0 :         return SingletonObject;
      50             :     jsbytecode* pc;
      51           0 :     JSScript* script = cx->currentScript(&pc);
      52           0 :     if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, &DataViewObject::class_))
      53           0 :         return SingletonObject;
      54           0 :     return GenericObject;
      55             : }
      56             : 
      57             : DataViewObject*
      58           0 : DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
      59             :                        Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, JSObject* protoArg)
      60             : {
      61           0 :     if (arrayBuffer->isDetached()) {
      62           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
      63           0 :         return nullptr;
      64             :     }
      65             : 
      66           0 :     MOZ_ASSERT(byteOffset <= INT32_MAX);
      67           0 :     MOZ_ASSERT(byteLength <= INT32_MAX);
      68           0 :     MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX);
      69             : 
      70           0 :     RootedObject proto(cx, protoArg);
      71           0 :     RootedObject obj(cx);
      72             : 
      73           0 :     NewObjectKind newKind = DataViewNewObjectKind(cx, byteLength, proto);
      74           0 :     obj = NewObjectWithClassProto(cx, &class_, proto, newKind);
      75           0 :     if (!obj)
      76           0 :         return nullptr;
      77             : 
      78           0 :     if (!proto) {
      79           0 :         if (byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH) {
      80           0 :             MOZ_ASSERT(obj->isSingleton());
      81             :         } else {
      82             :             jsbytecode* pc;
      83           0 :             RootedScript script(cx, cx->currentScript(&pc));
      84           0 :             if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, obj,
      85           0 :                                                                      newKind == SingletonObject))
      86             :             {
      87           0 :                 return nullptr;
      88             :             }
      89             :         }
      90             :     }
      91             : 
      92             :     // Caller should have established these preconditions, and no
      93             :     // (non-self-hosted) JS code has had an opportunity to run so nothing can
      94             :     // have invalidated them.
      95           0 :     MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength());
      96           0 :     MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
      97             : 
      98           0 :     DataViewObject& dvobj = obj->as<DataViewObject>();
      99             : 
     100             :     // The isSharedMemory property is invariant.  Self-hosting code that sets
     101             :     // BUFFER_SLOT or the private slot (if it does) must maintain it by always
     102             :     // setting those to reference shared memory.
     103           0 :     bool isSharedMemory = IsSharedArrayBuffer(arrayBuffer.get());
     104           0 :     if (isSharedMemory)
     105           0 :         dvobj.setIsSharedMemory();
     106             : 
     107           0 :     dvobj.setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset));
     108           0 :     dvobj.setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(byteLength));
     109           0 :     dvobj.setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*arrayBuffer));
     110             : 
     111           0 :     SharedMem<uint8_t*> ptr = arrayBuffer->dataPointerEither();
     112             :     // A pointer to raw shared memory is exposed through the private slot.  This
     113             :     // is safe so long as getPrivate() is not used willy-nilly.  It is wrapped in
     114             :     // other accessors in TypedArrayObject.h.
     115           0 :     dvobj.initPrivate(ptr.unwrap(/*safe - see above*/) + byteOffset);
     116             : 
     117             :     // Include a barrier if the data view's data pointer is in the nursery, as
     118             :     // is done for typed arrays.
     119           0 :     if (!IsInsideNursery(obj) && cx->nursery().isInside(ptr)) {
     120             :         // Shared buffer data should never be nursery-allocated, so we
     121             :         // need to fail here if isSharedMemory.  However, mmap() can
     122             :         // place a SharedArrayRawBuffer up against the bottom end of a
     123             :         // nursery chunk, and a zero-length buffer will erroneously be
     124             :         // perceived as being inside the nursery; sidestep that.
     125           0 :         if (isSharedMemory) {
     126           0 :             MOZ_ASSERT(arrayBuffer->byteLength() == 0 &&
     127             :                        (uintptr_t(ptr.unwrapValue()) & gc::ChunkMask) == 0);
     128             :         } else {
     129           0 :             cx->zone()->group()->storeBuffer().putWholeCell(obj);
     130             :         }
     131             :     }
     132             : 
     133             :     // Verify that the private slot is at the expected place
     134           0 :     MOZ_ASSERT(dvobj.numFixedSlots() == TypedArrayObject::DATA_SLOT);
     135             : 
     136           0 :     if (arrayBuffer->is<ArrayBufferObject>()) {
     137           0 :         if (!arrayBuffer->as<ArrayBufferObject>().addView(cx, &dvobj))
     138           0 :             return nullptr;
     139             :     }
     140             : 
     141           0 :     return &dvobj;
     142             : }
     143             : 
     144             : // ES2017 draft rev 931261ecef9b047b14daacf82884134da48dfe0f
     145             : // 24.3.2.1 DataView (extracted part of the main algorithm)
     146             : bool
     147           0 : DataViewObject::getAndCheckConstructorArgs(JSContext* cx, HandleObject bufobj, const CallArgs& args,
     148             :                                            uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr)
     149             : {
     150             :     // Step 3.
     151           0 :     if (!IsArrayBufferMaybeShared(bufobj)) {
     152             :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
     153           0 :                                   "DataView", "ArrayBuffer", bufobj->getClass()->name);
     154           0 :         return false;
     155             :     }
     156           0 :     Rooted<ArrayBufferObjectMaybeShared*> buffer(cx, &AsArrayBufferMaybeShared(bufobj));
     157             : 
     158             :     // Step 4.
     159             :     uint64_t offset;
     160           0 :     if (!ToIndex(cx, args.get(1), &offset))
     161           0 :         return false;
     162             : 
     163             :     // Step 5.
     164           0 :     if (buffer->isDetached()) {
     165           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
     166           0 :         return false;
     167             :     }
     168             : 
     169             :     // Step 6.
     170           0 :     uint32_t bufferByteLength = buffer->byteLength();
     171             : 
     172             :     // Step 7.
     173           0 :     if (offset > bufferByteLength) {
     174           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
     175           0 :         return false;
     176             :     }
     177           0 :     MOZ_ASSERT(offset <= INT32_MAX);
     178             : 
     179             :     // Step 8.a
     180           0 :     uint64_t viewByteLength = bufferByteLength - offset;
     181           0 :     if (args.hasDefined(2)) {
     182             :         // Step 9.a.
     183           0 :         if (!ToIndex(cx, args.get(2), &viewByteLength))
     184           0 :             return false;
     185             : 
     186             : 
     187           0 :         MOZ_ASSERT(offset + viewByteLength >= offset,
     188             :                    "can't overflow: both numbers are less than DOUBLE_INTEGRAL_PRECISION_LIMIT");
     189             : 
     190             :         // Step 9.b.
     191           0 :         if (offset + viewByteLength > bufferByteLength) {
     192             :             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
     193           0 :                                       JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
     194           0 :             return false;
     195             :         }
     196             :     }
     197           0 :     MOZ_ASSERT(viewByteLength <= INT32_MAX);
     198             : 
     199           0 :     *byteOffsetPtr = AssertedCast<uint32_t>(offset);
     200           0 :     *byteLengthPtr = AssertedCast<uint32_t>(viewByteLength);
     201           0 :     return true;
     202             : }
     203             : 
     204             : bool
     205           0 : DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args)
     206             : {
     207           0 :     MOZ_ASSERT(args.isConstructing());
     208           0 :     assertSameCompartment(cx, bufobj);
     209             : 
     210             :     uint32_t byteOffset, byteLength;
     211           0 :     if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength))
     212           0 :         return false;
     213             : 
     214           0 :     RootedObject proto(cx);
     215           0 :     if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
     216           0 :         return false;
     217             : 
     218           0 :     Rooted<ArrayBufferObjectMaybeShared*> buffer(cx, &AsArrayBufferMaybeShared(bufobj));
     219           0 :     JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
     220           0 :     if (!obj)
     221           0 :         return false;
     222           0 :     args.rval().setObject(*obj);
     223           0 :     return true;
     224             : }
     225             : 
     226             : // Create a DataView object in another compartment.
     227             : //
     228             : // ES6 supports creating a DataView in global A (using global A's DataView
     229             : // constructor) backed by an ArrayBuffer created in global B.
     230             : //
     231             : // Our DataViewObject implementation doesn't support a DataView in
     232             : // compartment A backed by an ArrayBuffer in compartment B. So in this case,
     233             : // we create the DataView in B (!) and return a cross-compartment wrapper.
     234             : //
     235             : // Extra twist: the spec says the new DataView's [[Prototype]] must be
     236             : // A's DataView.prototype. So even though we're creating the DataView in B,
     237             : // its [[Prototype]] must be (a cross-compartment wrapper for) the
     238             : // DataView.prototype in A.
     239             : bool
     240           0 : DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args)
     241             : {
     242           0 :     MOZ_ASSERT(args.isConstructing());
     243           0 :     MOZ_ASSERT(bufobj->is<WrapperObject>());
     244             : 
     245           0 :     RootedObject unwrapped(cx, CheckedUnwrap(bufobj));
     246           0 :     if (!unwrapped) {
     247           0 :         ReportAccessDenied(cx);
     248           0 :         return false;
     249             :     }
     250             : 
     251             :     // NB: This entails the IsArrayBuffer check
     252             :     uint32_t byteOffset, byteLength;
     253           0 :     if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength))
     254           0 :         return false;
     255             : 
     256             :     // Make sure to get the [[Prototype]] for the created view from this
     257             :     // compartment.
     258           0 :     RootedObject proto(cx);
     259           0 :     if (!GetPrototypeFromBuiltinConstructor(cx, args, &proto))
     260           0 :         return false;
     261             : 
     262           0 :     Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
     263           0 :     if (!proto) {
     264           0 :         proto = GlobalObject::getOrCreateDataViewPrototype(cx, global);
     265           0 :         if (!proto)
     266           0 :             return false;
     267             :     }
     268             : 
     269           0 :     RootedObject dv(cx);
     270             :     {
     271           0 :         JSAutoCompartment ac(cx, unwrapped);
     272             : 
     273           0 :         Rooted<ArrayBufferObjectMaybeShared*> buffer(cx);
     274           0 :         buffer = &unwrapped->as<ArrayBufferObjectMaybeShared>();
     275             : 
     276           0 :         RootedObject wrappedProto(cx, proto);
     277           0 :         if (!cx->compartment()->wrap(cx, &wrappedProto))
     278           0 :             return false;
     279             : 
     280           0 :         dv = DataViewObject::create(cx, byteOffset, byteLength, buffer, wrappedProto);
     281           0 :         if (!dv)
     282           0 :             return false;
     283             :     }
     284             : 
     285           0 :     if (!cx->compartment()->wrap(cx, &dv))
     286           0 :         return false;
     287             : 
     288           0 :     args.rval().setObject(*dv);
     289           0 :     return true;
     290             : }
     291             : 
     292             : bool
     293           0 : DataViewObject::construct(JSContext* cx, unsigned argc, Value* vp)
     294             : {
     295           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     296             : 
     297           0 :     if (!ThrowIfNotConstructing(cx, args, "DataView"))
     298           0 :         return false;
     299             : 
     300           0 :     RootedObject bufobj(cx);
     301           0 :     if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj))
     302           0 :         return false;
     303             : 
     304           0 :     if (bufobj->is<WrapperObject>())
     305           0 :         return constructWrapped(cx, bufobj, args);
     306           0 :     return constructSameCompartment(cx, bufobj, args);
     307             : }
     308             : 
     309             : template <typename NativeType>
     310             : /* static */ SharedMem<uint8_t*>
     311           0 : DataViewObject::getDataPointer(JSContext* cx, Handle<DataViewObject*> obj, uint64_t offset,
     312             :                                bool* isSharedMemory)
     313             : {
     314           0 :     const size_t TypeSize = sizeof(NativeType);
     315           0 :     if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) {
     316           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
     317             :                                   "1");
     318           0 :         return SharedMem<uint8_t*>::unshared(nullptr);
     319             :     }
     320             : 
     321           0 :     MOZ_ASSERT(offset < UINT32_MAX);
     322           0 :     *isSharedMemory = obj->isSharedMemory();
     323           0 :     return obj->dataPointerEither().cast<uint8_t*>() + uint32_t(offset);
     324             : }
     325             : 
     326             : static inline bool
     327           0 : needToSwapBytes(bool littleEndian)
     328             : {
     329             : #if MOZ_LITTLE_ENDIAN
     330           0 :     return !littleEndian;
     331             : #else
     332             :     return littleEndian;
     333             : #endif
     334             : }
     335             : 
     336             : static inline uint8_t
     337           0 : swapBytes(uint8_t x)
     338             : {
     339           0 :     return x;
     340             : }
     341             : 
     342             : static inline uint16_t
     343           0 : swapBytes(uint16_t x)
     344             : {
     345           0 :     return ((x & 0xff) << 8) | (x >> 8);
     346             : }
     347             : 
     348             : static inline uint32_t
     349           0 : swapBytes(uint32_t x)
     350             : {
     351           0 :     return ((x & 0xff) << 24) |
     352           0 :            ((x & 0xff00) << 8) |
     353           0 :            ((x & 0xff0000) >> 8) |
     354           0 :            ((x & 0xff000000) >> 24);
     355             : }
     356             : 
     357             : static inline uint64_t
     358           0 : swapBytes(uint64_t x)
     359             : {
     360           0 :     uint32_t a = x & UINT32_MAX;
     361           0 :     uint32_t b = x >> 32;
     362           0 :     return (uint64_t(swapBytes(a)) << 32) | swapBytes(b);
     363             : }
     364             : 
     365             : template <typename DataType> struct DataToRepType { typedef DataType result; };
     366             : template <> struct DataToRepType<int8_t>   { typedef uint8_t result; };
     367             : template <> struct DataToRepType<uint8_t>  { typedef uint8_t result; };
     368             : template <> struct DataToRepType<int16_t>  { typedef uint16_t result; };
     369             : template <> struct DataToRepType<uint16_t> { typedef uint16_t result; };
     370             : template <> struct DataToRepType<int32_t>  { typedef uint32_t result; };
     371             : template <> struct DataToRepType<uint32_t> { typedef uint32_t result; };
     372             : template <> struct DataToRepType<float>    { typedef uint32_t result; };
     373             : template <> struct DataToRepType<double>   { typedef uint64_t result; };
     374             : 
     375             : static inline void
     376           0 : Memcpy(uint8_t* dest, uint8_t* src, size_t nbytes)
     377             : {
     378           0 :     memcpy(dest, src, nbytes);
     379           0 : }
     380             : 
     381             : static inline void
     382           0 : Memcpy(uint8_t* dest, SharedMem<uint8_t*> src, size_t nbytes)
     383             : {
     384           0 :     jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes);
     385           0 : }
     386             : 
     387             : static inline void
     388           0 : Memcpy(SharedMem<uint8_t*> dest, uint8_t* src, size_t nbytes)
     389             : {
     390           0 :     jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes);
     391           0 : }
     392             : 
     393             : template <typename DataType, typename BufferPtrType>
     394             : struct DataViewIO
     395             : {
     396             :     typedef typename DataToRepType<DataType>::result ReadWriteType;
     397             : 
     398           0 :     static void fromBuffer(DataType* dest, BufferPtrType unalignedBuffer, bool wantSwap)
     399             :     {
     400           0 :         MOZ_ASSERT((reinterpret_cast<uintptr_t>(dest) & (Min<size_t>(MOZ_ALIGNOF(void*), sizeof(DataType)) - 1)) == 0);
     401           0 :         Memcpy((uint8_t*) dest, unalignedBuffer, sizeof(ReadWriteType));
     402           0 :         if (wantSwap) {
     403           0 :             ReadWriteType* rwDest = reinterpret_cast<ReadWriteType*>(dest);
     404           0 :             *rwDest = swapBytes(*rwDest);
     405             :         }
     406           0 :     }
     407             : 
     408           0 :     static void toBuffer(BufferPtrType unalignedBuffer, const DataType* src, bool wantSwap)
     409             :     {
     410           0 :         MOZ_ASSERT((reinterpret_cast<uintptr_t>(src) & (Min<size_t>(MOZ_ALIGNOF(void*), sizeof(DataType)) - 1)) == 0);
     411           0 :         ReadWriteType temp = *reinterpret_cast<const ReadWriteType*>(src);
     412           0 :         if (wantSwap)
     413           0 :             temp = swapBytes(temp);
     414           0 :         Memcpy(unalignedBuffer, (uint8_t*) &temp, sizeof(ReadWriteType));
     415           0 :     }
     416             : };
     417             : 
     418             : template<typename NativeType>
     419             : /* static */ bool
     420           0 : DataViewObject::read(JSContext* cx, Handle<DataViewObject*> obj, const CallArgs& args,
     421             :                      NativeType* val)
     422             : {
     423             :     // Steps 1-2. done by the caller
     424             :     // Step 3. unnecessary assert
     425             : 
     426             :     // Step 4.
     427             :     uint64_t getIndex;
     428           0 :     if (!ToIndex(cx, args.get(0), &getIndex))
     429           0 :         return false;
     430             : 
     431             :     // Step 5.
     432           0 :     bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
     433             : 
     434             :     // Steps 6-7.
     435           0 :     if (obj->arrayBufferEither().isDetached()) {
     436           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
     437           0 :         return false;
     438             :     }
     439             : 
     440             :     // Steps 8-12.
     441             :     bool isSharedMemory;
     442           0 :     SharedMem<uint8_t*> data = DataViewObject::getDataPointer<NativeType>(cx, obj, getIndex,
     443           0 :                                                                           &isSharedMemory);
     444           0 :     if (!data)
     445           0 :         return false;
     446             : 
     447             :     // Step 13.
     448           0 :     if (isSharedMemory) {
     449           0 :         DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(val, data,
     450           0 :                                                                 needToSwapBytes(isLittleEndian));
     451             :     } else {
     452           0 :         DataViewIO<NativeType, uint8_t*>::fromBuffer(val, data.unwrapUnshared(),
     453           0 :                                                      needToSwapBytes(isLittleEndian));
     454             :     }
     455           0 :     return true;
     456             : }
     457             : 
     458             : template <typename NativeType>
     459             : static inline bool
     460           0 : WebIDLCast(JSContext* cx, HandleValue value, NativeType* out)
     461             : {
     462             :     int32_t temp;
     463           0 :     if (!ToInt32(cx, value, &temp))
     464           0 :         return false;
     465             :     // Technically, the behavior of assigning an out of range value to a signed
     466             :     // variable is undefined. In practice, compilers seem to do what we want
     467             :     // without issuing any warnings.
     468           0 :     *out = static_cast<NativeType>(temp);
     469           0 :     return true;
     470             : }
     471             : 
     472             : template <>
     473             : inline bool
     474           0 : WebIDLCast<float>(JSContext* cx, HandleValue value, float* out)
     475             : {
     476             :     double temp;
     477           0 :     if (!ToNumber(cx, value, &temp))
     478           0 :         return false;
     479           0 :     *out = static_cast<float>(temp);
     480           0 :     return true;
     481             : }
     482             : 
     483             : template <>
     484             : inline bool
     485           0 : WebIDLCast<double>(JSContext* cx, HandleValue value, double* out)
     486             : {
     487           0 :     return ToNumber(cx, value, out);
     488             : }
     489             : 
     490             : template<typename NativeType>
     491             : /* static */ bool
     492           0 : DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj, const CallArgs& args)
     493             : {
     494             :     // Steps 1-2. done by the caller
     495             :     // Step 3. unnecessary assert
     496             : 
     497             :     // Step 4.
     498             :     uint64_t getIndex;
     499           0 :     if (!ToIndex(cx, args.get(0), &getIndex))
     500           0 :         return false;
     501             : 
     502             :     // Step 5. Should just call ToNumber (unobservable)
     503             :     NativeType value;
     504           0 :     if (!WebIDLCast(cx, args.get(1), &value))
     505           0 :         return false;
     506             : 
     507             : #ifdef JS_MORE_DETERMINISTIC
     508             :     // See the comment in ElementSpecific::doubleToNative.
     509             :     if (TypeIsFloatingPoint<NativeType>())
     510             :         value = JS::CanonicalizeNaN(value);
     511             : #endif
     512             : 
     513             :     // Step 6.
     514           0 :     bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
     515             : 
     516             :     // Steps 7-8.
     517           0 :     if (obj->arrayBufferEither().isDetached()) {
     518           0 :         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
     519           0 :         return false;
     520             :     }
     521             : 
     522             :     // Steps 9-13.
     523             :     bool isSharedMemory;
     524           0 :     SharedMem<uint8_t*> data = DataViewObject::getDataPointer<NativeType>(cx, obj, getIndex,
     525           0 :                                                                           &isSharedMemory);
     526           0 :     if (!data)
     527           0 :         return false;
     528             : 
     529             :     // Step 14.
     530           0 :     if (isSharedMemory) {
     531           0 :         DataViewIO<NativeType, SharedMem<uint8_t*>>::toBuffer(data, &value,
     532           0 :                                                               needToSwapBytes(isLittleEndian));
     533             :     } else {
     534           0 :         DataViewIO<NativeType, uint8_t*>::toBuffer(data.unwrapUnshared(), &value,
     535           0 :                                                    needToSwapBytes(isLittleEndian));
     536             :     }
     537           0 :     return true;
     538             : }
     539             : 
     540             : bool
     541           0 : DataViewObject::getInt8Impl(JSContext* cx, const CallArgs& args)
     542             : {
     543           0 :     MOZ_ASSERT(is(args.thisv()));
     544             : 
     545           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     546             : 
     547             :     int8_t val;
     548           0 :     if (!read(cx, thisView, args, &val))
     549           0 :         return false;
     550           0 :     args.rval().setInt32(val);
     551           0 :     return true;
     552             : }
     553             : 
     554             : bool
     555           0 : DataViewObject::fun_getInt8(JSContext* cx, unsigned argc, Value* vp)
     556             : {
     557           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     558           0 :     return CallNonGenericMethod<is, getInt8Impl>(cx, args);
     559             : }
     560             : 
     561             : bool
     562           0 : DataViewObject::getUint8Impl(JSContext* cx, const CallArgs& args)
     563             : {
     564           0 :     MOZ_ASSERT(is(args.thisv()));
     565             : 
     566           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     567             : 
     568             :     uint8_t val;
     569           0 :     if (!read(cx, thisView, args, &val))
     570           0 :         return false;
     571           0 :     args.rval().setInt32(val);
     572           0 :     return true;
     573             : }
     574             : 
     575             : bool
     576           0 : DataViewObject::fun_getUint8(JSContext* cx, unsigned argc, Value* vp)
     577             : {
     578           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     579           0 :     return CallNonGenericMethod<is, getUint8Impl>(cx, args);
     580             : }
     581             : 
     582             : bool
     583           0 : DataViewObject::getInt16Impl(JSContext* cx, const CallArgs& args)
     584             : {
     585           0 :     MOZ_ASSERT(is(args.thisv()));
     586             : 
     587           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     588             : 
     589             :     int16_t val;
     590           0 :     if (!read(cx, thisView, args, &val))
     591           0 :         return false;
     592           0 :     args.rval().setInt32(val);
     593           0 :     return true;
     594             : }
     595             : 
     596             : bool
     597           0 : DataViewObject::fun_getInt16(JSContext* cx, unsigned argc, Value* vp)
     598             : {
     599           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     600           0 :     return CallNonGenericMethod<is, getInt16Impl>(cx, args);
     601             : }
     602             : 
     603             : bool
     604           0 : DataViewObject::getUint16Impl(JSContext* cx, const CallArgs& args)
     605             : {
     606           0 :     MOZ_ASSERT(is(args.thisv()));
     607             : 
     608           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     609             : 
     610             :     uint16_t val;
     611           0 :     if (!read(cx, thisView, args, &val))
     612           0 :         return false;
     613           0 :     args.rval().setInt32(val);
     614           0 :     return true;
     615             : }
     616             : 
     617             : bool
     618           0 : DataViewObject::fun_getUint16(JSContext* cx, unsigned argc, Value* vp)
     619             : {
     620           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     621           0 :     return CallNonGenericMethod<is, getUint16Impl>(cx, args);
     622             : }
     623             : 
     624             : bool
     625           0 : DataViewObject::getInt32Impl(JSContext* cx, const CallArgs& args)
     626             : {
     627           0 :     MOZ_ASSERT(is(args.thisv()));
     628             : 
     629           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     630             : 
     631             :     int32_t val;
     632           0 :     if (!read(cx, thisView, args, &val))
     633           0 :         return false;
     634           0 :     args.rval().setInt32(val);
     635           0 :     return true;
     636             : }
     637             : 
     638             : bool
     639           0 : DataViewObject::fun_getInt32(JSContext* cx, unsigned argc, Value* vp)
     640             : {
     641           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     642           0 :     return CallNonGenericMethod<is, getInt32Impl>(cx, args);
     643             : }
     644             : 
     645             : bool
     646           0 : DataViewObject::getUint32Impl(JSContext* cx, const CallArgs& args)
     647             : {
     648           0 :     MOZ_ASSERT(is(args.thisv()));
     649             : 
     650           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     651             : 
     652             :     uint32_t val;
     653           0 :     if (!read(cx, thisView, args, &val))
     654           0 :         return false;
     655           0 :     args.rval().setNumber(val);
     656           0 :     return true;
     657             : }
     658             : 
     659             : bool
     660           0 : DataViewObject::fun_getUint32(JSContext* cx, unsigned argc, Value* vp)
     661             : {
     662           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     663           0 :     return CallNonGenericMethod<is, getUint32Impl>(cx, args);
     664             : }
     665             : 
     666             : bool
     667           0 : DataViewObject::getFloat32Impl(JSContext* cx, const CallArgs& args)
     668             : {
     669           0 :     MOZ_ASSERT(is(args.thisv()));
     670             : 
     671           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     672             : 
     673             :     float val;
     674           0 :     if (!read(cx, thisView, args, &val))
     675           0 :         return false;
     676             : 
     677           0 :     args.rval().setDouble(CanonicalizeNaN(val));
     678           0 :     return true;
     679             : }
     680             : 
     681             : bool
     682           0 : DataViewObject::fun_getFloat32(JSContext* cx, unsigned argc, Value* vp)
     683             : {
     684           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     685           0 :     return CallNonGenericMethod<is, getFloat32Impl>(cx, args);
     686             : }
     687             : 
     688             : bool
     689           0 : DataViewObject::getFloat64Impl(JSContext* cx, const CallArgs& args)
     690             : {
     691           0 :     MOZ_ASSERT(is(args.thisv()));
     692             : 
     693           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     694             : 
     695             :     double val;
     696           0 :     if (!read(cx, thisView, args, &val))
     697           0 :         return false;
     698             : 
     699           0 :     args.rval().setDouble(CanonicalizeNaN(val));
     700           0 :     return true;
     701             : }
     702             : 
     703             : bool
     704           0 : DataViewObject::fun_getFloat64(JSContext* cx, unsigned argc, Value* vp)
     705             : {
     706           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     707           0 :     return CallNonGenericMethod<is, getFloat64Impl>(cx, args);
     708             : }
     709             : 
     710             : bool
     711           0 : DataViewObject::setInt8Impl(JSContext* cx, const CallArgs& args)
     712             : {
     713           0 :     MOZ_ASSERT(is(args.thisv()));
     714             : 
     715           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     716             : 
     717           0 :     if (!write<int8_t>(cx, thisView, args))
     718           0 :         return false;
     719           0 :     args.rval().setUndefined();
     720           0 :     return true;
     721             : }
     722             : 
     723             : bool
     724           0 : DataViewObject::fun_setInt8(JSContext* cx, unsigned argc, Value* vp)
     725             : {
     726           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     727           0 :     return CallNonGenericMethod<is, setInt8Impl>(cx, args);
     728             : }
     729             : 
     730             : bool
     731           0 : DataViewObject::setUint8Impl(JSContext* cx, const CallArgs& args)
     732             : {
     733           0 :     MOZ_ASSERT(is(args.thisv()));
     734             : 
     735           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     736             : 
     737           0 :     if (!write<uint8_t>(cx, thisView, args))
     738           0 :         return false;
     739           0 :     args.rval().setUndefined();
     740           0 :     return true;
     741             : }
     742             : 
     743             : bool
     744           0 : DataViewObject::fun_setUint8(JSContext* cx, unsigned argc, Value* vp)
     745             : {
     746           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     747           0 :     return CallNonGenericMethod<is, setUint8Impl>(cx, args);
     748             : }
     749             : 
     750             : bool
     751           0 : DataViewObject::setInt16Impl(JSContext* cx, const CallArgs& args)
     752             : {
     753           0 :     MOZ_ASSERT(is(args.thisv()));
     754             : 
     755           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     756             : 
     757           0 :     if (!write<int16_t>(cx, thisView, args))
     758           0 :         return false;
     759           0 :     args.rval().setUndefined();
     760           0 :     return true;
     761             : }
     762             : 
     763             : bool
     764           0 : DataViewObject::fun_setInt16(JSContext* cx, unsigned argc, Value* vp)
     765             : {
     766           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     767           0 :     return CallNonGenericMethod<is, setInt16Impl>(cx, args);
     768             : }
     769             : 
     770             : bool
     771           0 : DataViewObject::setUint16Impl(JSContext* cx, const CallArgs& args)
     772             : {
     773           0 :     MOZ_ASSERT(is(args.thisv()));
     774             : 
     775           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     776             : 
     777           0 :     if (!write<uint16_t>(cx, thisView, args))
     778           0 :         return false;
     779           0 :     args.rval().setUndefined();
     780           0 :     return true;
     781             : }
     782             : 
     783             : bool
     784           0 : DataViewObject::fun_setUint16(JSContext* cx, unsigned argc, Value* vp)
     785             : {
     786           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     787           0 :     return CallNonGenericMethod<is, setUint16Impl>(cx, args);
     788             : }
     789             : 
     790             : bool
     791           0 : DataViewObject::setInt32Impl(JSContext* cx, const CallArgs& args)
     792             : {
     793           0 :     MOZ_ASSERT(is(args.thisv()));
     794             : 
     795           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     796             : 
     797           0 :     if (!write<int32_t>(cx, thisView, args))
     798           0 :         return false;
     799           0 :     args.rval().setUndefined();
     800           0 :     return true;
     801             : }
     802             : 
     803             : bool
     804           0 : DataViewObject::fun_setInt32(JSContext* cx, unsigned argc, Value* vp)
     805             : {
     806           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     807           0 :     return CallNonGenericMethod<is, setInt32Impl>(cx, args);
     808             : }
     809             : 
     810             : bool
     811           0 : DataViewObject::setUint32Impl(JSContext* cx, const CallArgs& args)
     812             : {
     813           0 :     MOZ_ASSERT(is(args.thisv()));
     814             : 
     815           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     816             : 
     817           0 :     if (!write<uint32_t>(cx, thisView, args))
     818           0 :         return false;
     819           0 :     args.rval().setUndefined();
     820           0 :     return true;
     821             : }
     822             : 
     823             : bool
     824           0 : DataViewObject::fun_setUint32(JSContext* cx, unsigned argc, Value* vp)
     825             : {
     826           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     827           0 :     return CallNonGenericMethod<is, setUint32Impl>(cx, args);
     828             : }
     829             : 
     830             : bool
     831           0 : DataViewObject::setFloat32Impl(JSContext* cx, const CallArgs& args)
     832             : {
     833           0 :     MOZ_ASSERT(is(args.thisv()));
     834             : 
     835           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     836             : 
     837           0 :     if (!write<float>(cx, thisView, args))
     838           0 :         return false;
     839           0 :     args.rval().setUndefined();
     840           0 :     return true;
     841             : }
     842             : 
     843             : bool
     844           0 : DataViewObject::fun_setFloat32(JSContext* cx, unsigned argc, Value* vp)
     845             : {
     846           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     847           0 :     return CallNonGenericMethod<is, setFloat32Impl>(cx, args);
     848             : }
     849             : 
     850             : bool
     851           0 : DataViewObject::setFloat64Impl(JSContext* cx, const CallArgs& args)
     852             : {
     853           0 :     MOZ_ASSERT(is(args.thisv()));
     854             : 
     855           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     856             : 
     857           0 :     if (!write<double>(cx, thisView, args))
     858           0 :         return false;
     859           0 :     args.rval().setUndefined();
     860           0 :     return true;
     861             : }
     862             : 
     863             : bool
     864           0 : DataViewObject::fun_setFloat64(JSContext* cx, unsigned argc, Value* vp)
     865             : {
     866           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     867           0 :     return CallNonGenericMethod<is, setFloat64Impl>(cx, args);
     868             : }
     869             : 
     870             : 
     871             : bool
     872           0 : DataViewObject::bufferGetterImpl(JSContext* cx, const CallArgs& args)
     873             : {
     874           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     875           0 :     args.rval().set(DataViewObject::bufferValue(thisView));
     876           0 :     return true;
     877             : }
     878             : 
     879             : bool
     880           0 : DataViewObject::bufferGetter(JSContext* cx, unsigned argc, Value* vp)
     881             : {
     882           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     883           0 :     return CallNonGenericMethod<is, bufferGetterImpl>(cx, args);
     884             : }
     885             : 
     886             : bool
     887           0 : DataViewObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args)
     888             : {
     889           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     890           0 :     args.rval().set(DataViewObject::byteLengthValue(thisView));
     891           0 :     return true;
     892             : }
     893             : 
     894             : bool
     895           0 : DataViewObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
     896             : {
     897           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     898           0 :     return CallNonGenericMethod<is, byteLengthGetterImpl>(cx, args);
     899             : }
     900             : 
     901             : bool
     902           0 : DataViewObject::byteOffsetGetterImpl(JSContext* cx, const CallArgs& args)
     903             : {
     904           0 :     Rooted<DataViewObject*> thisView(cx, &args.thisv().toObject().as<DataViewObject>());
     905           0 :     args.rval().set(DataViewObject::byteOffsetValue(thisView));
     906           0 :     return true;
     907             : }
     908             : 
     909             : bool
     910           0 : DataViewObject::byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp)
     911             : {
     912           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     913           0 :     return CallNonGenericMethod<is, byteOffsetGetterImpl>(cx, args);
     914             : }
     915             : 
     916             : const Class DataViewObject::protoClass_ = {
     917             :     js_Object_str,
     918             :     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
     919             :     JS_NULL_CLASS_OPS,
     920             :     &DataViewObject::classSpec_
     921             : };
     922             : 
     923             : JSObject*
     924           6 : DataViewObject::CreatePrototype(JSContext* cx, JSProtoKey key)
     925             : {
     926           6 :     return GlobalObject::createBlankPrototype(cx, cx->global(), &DataViewObject::protoClass_);
     927             : }
     928             : 
     929             : static const ClassOps DataViewObjectClassOps = {
     930             :     nullptr, /* addProperty */
     931             :     nullptr, /* delProperty */
     932             :     nullptr, /* getProperty */
     933             :     nullptr, /* setProperty */
     934             :     nullptr, /* enumerate */
     935             :     nullptr, /* newEnumerate */
     936             :     nullptr, /* resolve */
     937             :     nullptr, /* mayResolve */
     938             :     nullptr, /* finalize */
     939             :     nullptr, /* call */
     940             :     nullptr, /* hasInstance */
     941             :     nullptr, /* construct */
     942             :     ArrayBufferViewObject::trace
     943             : };
     944             : 
     945             : const ClassSpec DataViewObject::classSpec_ = {
     946             :     GenericCreateConstructor<DataViewObject::construct, 3, gc::AllocKind::FUNCTION>,
     947             :     DataViewObject::CreatePrototype,
     948             :     nullptr,
     949             :     nullptr,
     950             :     DataViewObject::methods,
     951             :     DataViewObject::properties,
     952             : };
     953             : 
     954             : const Class DataViewObject::class_ = {
     955             :     "DataView",
     956             :     JSCLASS_HAS_PRIVATE |
     957             :     JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) |
     958             :     JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
     959             :     &DataViewObjectClassOps,
     960             :     &DataViewObject::classSpec_
     961             : };
     962             : 
     963             : const JSFunctionSpec DataViewObject::methods[] = {
     964             :     JS_FN("getInt8",    DataViewObject::fun_getInt8,      1,0),
     965             :     JS_FN("getUint8",   DataViewObject::fun_getUint8,     1,0),
     966             :     JS_FN("getInt16",   DataViewObject::fun_getInt16,     1,0),
     967             :     JS_FN("getUint16",  DataViewObject::fun_getUint16,    1,0),
     968             :     JS_FN("getInt32",   DataViewObject::fun_getInt32,     1,0),
     969             :     JS_FN("getUint32",  DataViewObject::fun_getUint32,    1,0),
     970             :     JS_FN("getFloat32", DataViewObject::fun_getFloat32,   1,0),
     971             :     JS_FN("getFloat64", DataViewObject::fun_getFloat64,   1,0),
     972             :     JS_FN("setInt8",    DataViewObject::fun_setInt8,      2,0),
     973             :     JS_FN("setUint8",   DataViewObject::fun_setUint8,     2,0),
     974             :     JS_FN("setInt16",   DataViewObject::fun_setInt16,     2,0),
     975             :     JS_FN("setUint16",  DataViewObject::fun_setUint16,    2,0),
     976             :     JS_FN("setInt32",   DataViewObject::fun_setInt32,     2,0),
     977             :     JS_FN("setUint32",  DataViewObject::fun_setUint32,    2,0),
     978             :     JS_FN("setFloat32", DataViewObject::fun_setFloat32,   2,0),
     979             :     JS_FN("setFloat64", DataViewObject::fun_setFloat64,   2,0),
     980             :     JS_FS_END
     981             : };
     982             : 
     983             : const JSPropertySpec DataViewObject::properties[] = {
     984             :     JS_PSG("buffer", DataViewObject::bufferGetter, 0),
     985             :     JS_PSG("byteLength", DataViewObject::byteLengthGetter, 0),
     986             :     JS_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0),
     987             :     JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY),
     988             :     JS_PS_END
     989             : };
     990             : 
     991             : void
     992           0 : DataViewObject::notifyBufferDetached(void* newData)
     993             : {
     994           0 :     setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(0));
     995           0 :     setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0));
     996           0 :     setPrivate(newData);
     997           0 : }
     998             : 
     999             : JS_FRIEND_API(bool)
    1000         138 : JS_IsDataViewObject(JSObject* obj)
    1001             : {
    1002         138 :     obj = CheckedUnwrap(obj);
    1003         138 :     return obj ? obj->is<DataViewObject>() : false;
    1004             : }
    1005             : 
    1006             : JS_FRIEND_API(uint32_t)
    1007           0 : JS_GetDataViewByteOffset(JSObject* obj)
    1008             : {
    1009           0 :     obj = CheckedUnwrap(obj);
    1010           0 :     if (!obj)
    1011           0 :         return 0;
    1012           0 :     return obj->as<DataViewObject>().byteOffset();
    1013             : }
    1014             : 
    1015             : JS_FRIEND_API(void*)
    1016           0 : JS_GetDataViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&)
    1017             : {
    1018           0 :     obj = CheckedUnwrap(obj);
    1019           0 :     if (!obj)
    1020           0 :         return nullptr;
    1021           0 :     DataViewObject& dv = obj->as<DataViewObject>();
    1022           0 :     *isSharedMemory = dv.isSharedMemory();
    1023           0 :     return dv.dataPointerEither().unwrap(/*safe - caller sees isSharedMemory*/);
    1024             : }
    1025             : 
    1026             : JS_FRIEND_API(uint32_t)
    1027           0 : JS_GetDataViewByteLength(JSObject* obj)
    1028             : {
    1029           0 :     obj = CheckedUnwrap(obj);
    1030           0 :     if (!obj)
    1031           0 :         return 0;
    1032           0 :     return obj->as<DataViewObject>().byteLength();
    1033             : }
    1034             : 
    1035             : JS_FRIEND_API(JSObject*)
    1036           0 : JS_NewDataView(JSContext* cx, HandleObject buffer, uint32_t byteOffset, int32_t byteLength)
    1037             : {
    1038           0 :     RootedObject constructor(cx);
    1039           0 :     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(&DataViewObject::class_);
    1040           0 :     if (!GetBuiltinConstructor(cx, key, &constructor))
    1041           0 :         return nullptr;
    1042             : 
    1043           0 :     FixedConstructArgs<3> cargs(cx);
    1044             : 
    1045           0 :     cargs[0].setObject(*buffer);
    1046           0 :     cargs[1].setNumber(byteOffset);
    1047           0 :     cargs[2].setInt32(byteLength);
    1048             : 
    1049           0 :     RootedValue fun(cx, ObjectValue(*constructor));
    1050           0 :     RootedObject obj(cx);
    1051           0 :     if (!Construct(cx, fun, cargs, fun, &obj))
    1052           0 :         return nullptr;
    1053           0 :     return obj;
    1054             : }

Generated by: LCOV version 1.13