tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DataViewObject.cpp (39378B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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/EndianUtils.h"
     10 #include "mozilla/IntegerTypeTraits.h"
     11 #include "mozilla/WrappingOperations.h"
     12 
     13 #include <algorithm>
     14 #include <string.h>
     15 #include <type_traits>
     16 
     17 #include "jsnum.h"
     18 
     19 #include "jit/AtomicOperations.h"
     20 #include "jit/InlinableNatives.h"
     21 #include "js/Conversions.h"
     22 #include "js/experimental/TypedData.h"  // JS_NewDataView
     23 #include "js/friend/ErrorMessages.h"    // js::GetErrorMessage, JSMSG_*
     24 #include "js/PropertySpec.h"
     25 #include "js/Wrapper.h"
     26 #include "util/DifferentialTesting.h"
     27 #include "vm/ArrayBufferObject.h"
     28 #include "vm/Compartment.h"
     29 #include "vm/Float16.h"
     30 #include "vm/GlobalObject.h"
     31 #include "vm/Interpreter.h"
     32 #include "vm/JSContext.h"
     33 #include "vm/JSObject.h"
     34 #include "vm/SharedMem.h"
     35 #include "vm/Uint8Clamped.h"
     36 #include "vm/WrapperObject.h"
     37 
     38 #include "vm/ArrayBufferObject-inl.h"
     39 #include "vm/NativeObject-inl.h"
     40 
     41 using namespace js;
     42 
     43 using JS::CanonicalizeNaN;
     44 using JS::ToInt32;
     45 using mozilla::WrapToSigned;
     46 
     47 static bool IsDataView(HandleValue v) {
     48  return v.isObject() && v.toObject().is<DataViewObject>();
     49 }
     50 
     51 DataViewObject* DataViewObject::create(
     52    JSContext* cx, size_t byteOffset, size_t byteLength,
     53    Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto) {
     54  MOZ_ASSERT(!arrayBuffer->isResizable());
     55  MOZ_ASSERT(!arrayBuffer->isDetached());
     56  MOZ_ASSERT(!arrayBuffer->isImmutable());
     57 
     58  auto* obj = NewObjectWithClassProto<FixedLengthDataViewObject>(cx, proto);
     59  if (!obj || !obj->init(cx, arrayBuffer, byteOffset, byteLength,
     60                         /* bytesPerElement = */ 1)) {
     61    return nullptr;
     62  }
     63 
     64  return obj;
     65 }
     66 
     67 ResizableDataViewObject* ResizableDataViewObject::create(
     68    JSContext* cx, size_t byteOffset, size_t byteLength, AutoLength autoLength,
     69    Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto) {
     70  MOZ_ASSERT(arrayBuffer->isResizable());
     71  MOZ_ASSERT(!arrayBuffer->isDetached());
     72  MOZ_ASSERT(!arrayBuffer->isImmutable());
     73  MOZ_ASSERT(autoLength == AutoLength::No || byteLength == 0,
     74             "byte length is zero for 'auto' length views");
     75 
     76  auto* obj = NewObjectWithClassProto<ResizableDataViewObject>(cx, proto);
     77  if (!obj || !obj->initResizable(cx, arrayBuffer, byteOffset, byteLength,
     78                                  /* bytesPerElement = */ 1, autoLength)) {
     79    return nullptr;
     80  }
     81 
     82  return obj;
     83 }
     84 
     85 ImmutableDataViewObject* ImmutableDataViewObject::create(
     86    JSContext* cx, size_t byteOffset, size_t byteLength,
     87    Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto) {
     88  MOZ_ASSERT(!arrayBuffer->isResizable());
     89  MOZ_ASSERT(!arrayBuffer->isDetached());
     90  MOZ_ASSERT(arrayBuffer->isImmutable());
     91 
     92  auto* obj = NewObjectWithClassProto<ImmutableDataViewObject>(cx, proto);
     93  if (!obj || !obj->init(cx, arrayBuffer, byteOffset, byteLength,
     94                         /* bytesPerElement = */ 1)) {
     95    return nullptr;
     96  }
     97 
     98  return obj;
     99 }
    100 
    101 // ES2017 draft rev 931261ecef9b047b14daacf82884134da48dfe0f
    102 // 24.3.2.1 DataView (extracted part of the main algorithm)
    103 bool DataViewObject::getAndCheckConstructorArgs(
    104    JSContext* cx, HandleObject bufobj, const CallArgs& args,
    105    size_t* byteOffsetPtr, size_t* byteLengthPtr, AutoLength* autoLengthPtr) {
    106  // Step 3.
    107  if (!bufobj->is<ArrayBufferObjectMaybeShared>()) {
    108    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    109                              JSMSG_NOT_EXPECTED_TYPE, "DataView",
    110                              "ArrayBuffer", bufobj->getClass()->name);
    111    return false;
    112  }
    113  auto buffer = bufobj.as<ArrayBufferObjectMaybeShared>();
    114 
    115  // Step 4.
    116  uint64_t offset;
    117  if (!ToIndex(cx, args.get(1), &offset)) {
    118    return false;
    119  }
    120 
    121  // Step 5.
    122  if (buffer->isDetached()) {
    123    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    124                              JSMSG_TYPED_ARRAY_DETACHED);
    125    return false;
    126  }
    127 
    128  // Step 6.
    129  size_t bufferByteLength = buffer->byteLength();
    130 
    131  // Step 7.
    132  if (offset > bufferByteLength) {
    133    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    134                              JSMSG_OFFSET_OUT_OF_BUFFER);
    135    return false;
    136  }
    137  MOZ_ASSERT(offset <= ArrayBufferObject::ByteLengthLimit);
    138 
    139  uint64_t viewByteLength = 0;
    140  auto autoLength = AutoLength::No;
    141  if (!args.hasDefined(2)) {
    142    if (buffer->isResizable()) {
    143      autoLength = AutoLength::Yes;
    144    } else {
    145      // Step 8.a
    146      viewByteLength = bufferByteLength - offset;
    147    }
    148  } else {
    149    // Step 9.a.
    150    if (!ToIndex(cx, args.get(2), &viewByteLength)) {
    151      return false;
    152    }
    153 
    154    MOZ_ASSERT(offset + viewByteLength >= offset,
    155               "can't overflow: both numbers are less than "
    156               "DOUBLE_INTEGRAL_PRECISION_LIMIT");
    157 
    158    // Step 9.b.
    159    if (offset + viewByteLength > bufferByteLength) {
    160      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    161                                JSMSG_INVALID_DATA_VIEW_LENGTH);
    162      return false;
    163    }
    164  }
    165  MOZ_ASSERT(viewByteLength <= ArrayBufferObject::ByteLengthLimit);
    166 
    167  *byteOffsetPtr = offset;
    168  *byteLengthPtr = viewByteLength;
    169  *autoLengthPtr = autoLength;
    170  return true;
    171 }
    172 
    173 static bool CheckConstructorArgs(JSContext* cx,
    174                                 Handle<ArrayBufferObjectMaybeShared*> buffer,
    175                                 size_t byteOffset, size_t byteLength) {
    176  if (buffer->isDetached()) {
    177    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    178                              JSMSG_TYPED_ARRAY_DETACHED);
    179    return false;
    180  }
    181 
    182  if (buffer->isResizable()) {
    183    size_t bufferByteLength = buffer->byteLength();
    184    if (byteOffset + byteLength > bufferByteLength) {
    185      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    186                                JSMSG_OFFSET_OUT_OF_BUFFER);
    187      return false;
    188    }
    189  }
    190 
    191  return true;
    192 }
    193 
    194 bool DataViewObject::constructSameCompartment(JSContext* cx,
    195                                              HandleObject bufobj,
    196                                              const CallArgs& args) {
    197  MOZ_ASSERT(args.isConstructing());
    198  cx->check(bufobj);
    199 
    200  size_t byteOffset = 0;
    201  size_t byteLength = 0;
    202  auto autoLength = AutoLength::No;
    203  if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength,
    204                                  &autoLength)) {
    205    return false;
    206  }
    207 
    208  RootedObject proto(cx);
    209  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
    210    return false;
    211  }
    212 
    213  auto buffer = bufobj.as<ArrayBufferObjectMaybeShared>();
    214 
    215  // GetPrototypeFromBuiltinConstructor may have detached or resized the buffer,
    216  // so we have to revalidate the arguments.
    217  if (!CheckConstructorArgs(cx, buffer, byteOffset, byteLength)) {
    218    return false;
    219  }
    220 
    221  DataViewObject* obj;
    222  if (buffer->isResizable()) {
    223    obj = ResizableDataViewObject::create(cx, byteOffset, byteLength,
    224                                          autoLength, buffer, proto);
    225  } else if (buffer->isImmutable()) {
    226    obj = ImmutableDataViewObject::create(cx, byteOffset, byteLength, buffer,
    227                                          proto);
    228  } else {
    229    obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
    230  }
    231  if (!obj) {
    232    return false;
    233  }
    234  args.rval().setObject(*obj);
    235  return true;
    236 }
    237 
    238 // Create a DataView object in another compartment.
    239 //
    240 // ES6 supports creating a DataView in global A (using global A's DataView
    241 // constructor) backed by an ArrayBuffer created in global B.
    242 //
    243 // Our DataViewObject implementation doesn't support a DataView in
    244 // compartment A backed by an ArrayBuffer in compartment B. So in this case,
    245 // we create the DataView in B (!) and return a cross-compartment wrapper.
    246 //
    247 // Extra twist: the spec says the new DataView's [[Prototype]] must be
    248 // A's DataView.prototype. So even though we're creating the DataView in B,
    249 // its [[Prototype]] must be (a cross-compartment wrapper for) the
    250 // DataView.prototype in A.
    251 bool DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj,
    252                                      const CallArgs& args) {
    253  MOZ_ASSERT(args.isConstructing());
    254  MOZ_ASSERT(bufobj->is<WrapperObject>());
    255 
    256  RootedObject unwrapped(cx, CheckedUnwrapStatic(bufobj));
    257  if (!unwrapped) {
    258    ReportAccessDenied(cx);
    259    return false;
    260  }
    261 
    262  // NB: This entails the IsArrayBuffer check
    263  size_t byteOffset = 0;
    264  size_t byteLength = 0;
    265  auto autoLength = AutoLength::No;
    266  if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength,
    267                                  &autoLength)) {
    268    return false;
    269  }
    270 
    271  // Make sure to get the [[Prototype]] for the created view from this
    272  // compartment.
    273  RootedObject proto(cx);
    274  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
    275    return false;
    276  }
    277 
    278  auto unwrappedBuffer = unwrapped.as<ArrayBufferObjectMaybeShared>();
    279 
    280  // GetPrototypeFromBuiltinConstructor may have detached or resized the buffer,
    281  // so we have to revalidate the arguments.
    282  if (!CheckConstructorArgs(cx, unwrappedBuffer, byteOffset, byteLength)) {
    283    return false;
    284  }
    285 
    286  Rooted<GlobalObject*> global(cx, cx->realm()->maybeGlobal());
    287  if (!proto) {
    288    proto = GlobalObject::getOrCreateDataViewPrototype(cx, global);
    289    if (!proto) {
    290      return false;
    291    }
    292  }
    293 
    294  RootedObject dv(cx);
    295  {
    296    JSAutoRealm ar(cx, unwrapped);
    297 
    298    RootedObject wrappedProto(cx, proto);
    299    if (!cx->compartment()->wrap(cx, &wrappedProto)) {
    300      return false;
    301    }
    302 
    303    if (unwrappedBuffer->isResizable()) {
    304      dv = ResizableDataViewObject::create(cx, byteOffset, byteLength,
    305                                           autoLength, unwrappedBuffer,
    306                                           wrappedProto);
    307    } else if (unwrappedBuffer->isImmutable()) {
    308      dv = ImmutableDataViewObject::create(cx, byteOffset, byteLength,
    309                                           unwrappedBuffer, wrappedProto);
    310    } else {
    311      dv = DataViewObject::create(cx, byteOffset, byteLength, unwrappedBuffer,
    312                                  wrappedProto);
    313    }
    314    if (!dv) {
    315      return false;
    316    }
    317  }
    318 
    319  if (!cx->compartment()->wrap(cx, &dv)) {
    320    return false;
    321  }
    322 
    323  args.rval().setObject(*dv);
    324  return true;
    325 }
    326 
    327 bool DataViewObject::construct(JSContext* cx, unsigned argc, Value* vp) {
    328  CallArgs args = CallArgsFromVp(argc, vp);
    329 
    330  if (!ThrowIfNotConstructing(cx, args, "DataView")) {
    331    return false;
    332  }
    333 
    334  RootedObject bufobj(cx);
    335  if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj)) {
    336    return false;
    337  }
    338 
    339  if (bufobj->is<WrapperObject>()) {
    340    return constructWrapped(cx, bufobj, args);
    341  }
    342  return constructSameCompartment(cx, bufobj, args);
    343 }
    344 
    345 template <typename NativeType>
    346 SharedMem<uint8_t*> DataViewObject::getDataPointer(uint64_t offset,
    347                                                   size_t length,
    348                                                   bool* isSharedMemory) {
    349  MOZ_ASSERT(length <= *byteLength());
    350  MOZ_ASSERT(offsetIsInBounds<NativeType>(offset, length));
    351 
    352  MOZ_ASSERT(offset < SIZE_MAX);
    353  *isSharedMemory = this->isSharedMemory();
    354  return dataPointerEither().cast<uint8_t*>() + size_t(offset);
    355 }
    356 
    357 static void ReportOutOfBounds(JSContext* cx, DataViewObject* dataView) {
    358  if (dataView->hasDetachedBuffer()) {
    359    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    360                              JSMSG_TYPED_ARRAY_DETACHED);
    361  } else {
    362    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    363                              JSMSG_TYPED_ARRAY_RESIZED_BOUNDS);
    364  }
    365 }
    366 
    367 template <typename T>
    368 static inline std::enable_if_t<sizeof(T) != 1> SwapBytes(T* value,
    369                                                         bool isLittleEndian) {
    370  if (isLittleEndian) {
    371    mozilla::NativeEndian::swapToLittleEndianInPlace(value, 1);
    372  } else {
    373    mozilla::NativeEndian::swapToBigEndianInPlace(value, 1);
    374  }
    375 }
    376 
    377 template <typename T>
    378 static inline std::enable_if_t<sizeof(T) == 1> SwapBytes(T* value,
    379                                                         bool isLittleEndian) {
    380  // mozilla::NativeEndian doesn't support int8_t/uint8_t types.
    381 }
    382 
    383 static inline void Memcpy(uint8_t* dest, uint8_t* src, size_t nbytes) {
    384  memcpy(dest, src, nbytes);
    385 }
    386 
    387 static inline void Memcpy(uint8_t* dest, SharedMem<uint8_t*> src,
    388                          size_t nbytes) {
    389  jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes);
    390 }
    391 
    392 static inline void Memcpy(SharedMem<uint8_t*> dest, uint8_t* src,
    393                          size_t nbytes) {
    394  jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes);
    395 }
    396 
    397 template <typename DataType, typename BufferPtrType>
    398 struct DataViewIO {
    399  using ReadWriteType =
    400      typename mozilla::UnsignedStdintTypeForSize<sizeof(DataType)>::Type;
    401 
    402  static constexpr auto alignMask =
    403      std::min<size_t>(alignof(void*), sizeof(DataType)) - 1;
    404 
    405  static void fromBuffer(DataType* dest, BufferPtrType unalignedBuffer,
    406                         bool isLittleEndian) {
    407    MOZ_ASSERT((reinterpret_cast<uintptr_t>(dest) & alignMask) == 0);
    408    Memcpy((uint8_t*)dest, unalignedBuffer, sizeof(ReadWriteType));
    409    ReadWriteType* rwDest = reinterpret_cast<ReadWriteType*>(dest);
    410    SwapBytes(rwDest, isLittleEndian);
    411  }
    412 
    413  static void toBuffer(BufferPtrType unalignedBuffer, const DataType* src,
    414                       bool isLittleEndian) {
    415    MOZ_ASSERT((reinterpret_cast<uintptr_t>(src) & alignMask) == 0);
    416    ReadWriteType temp = *reinterpret_cast<const ReadWriteType*>(src);
    417    SwapBytes(&temp, isLittleEndian);
    418    Memcpy(unalignedBuffer, (uint8_t*)&temp, sizeof(ReadWriteType));
    419  }
    420 };
    421 
    422 template <typename NativeType>
    423 NativeType DataViewObject::read(uint64_t offset, size_t length,
    424                                bool isLittleEndian) {
    425  bool isSharedMemory;
    426  SharedMem<uint8_t*> data =
    427      getDataPointer<NativeType>(offset, length, &isSharedMemory);
    428  MOZ_ASSERT(data);
    429 
    430  NativeType val{};
    431  if (isSharedMemory) {
    432    DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(&val, data,
    433                                                            isLittleEndian);
    434  } else {
    435    DataViewIO<NativeType, uint8_t*>::fromBuffer(&val, data.unwrapUnshared(),
    436                                                 isLittleEndian);
    437  }
    438 
    439  return val;
    440 }
    441 
    442 template uint32_t DataViewObject::read(uint64_t offset, size_t length,
    443                                       bool isLittleEndian);
    444 
    445 // https://tc39.github.io/ecma262/#sec-getviewvalue
    446 // GetViewValue ( view, requestIndex, isLittleEndian, type )
    447 template <typename NativeType>
    448 /* static */
    449 bool DataViewObject::read(JSContext* cx, Handle<DataViewObject*> obj,
    450                          const CallArgs& args, NativeType* val) {
    451  // Step 1. done by the caller
    452  // Step 2. unnecessary assert
    453 
    454  // Step 3.
    455  uint64_t getIndex;
    456  if (!ToIndex(cx, args.get(0), &getIndex)) {
    457    return false;
    458  }
    459 
    460  // Step 4.
    461  bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
    462 
    463  // Steps 5-6.
    464  auto viewSize = obj->byteLength();
    465  if (MOZ_UNLIKELY(!viewSize)) {
    466    ReportOutOfBounds(cx, obj);
    467    return false;
    468  }
    469 
    470  // Steps 7-10.
    471  if (!offsetIsInBounds<NativeType>(getIndex, *viewSize)) {
    472    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    473                              JSMSG_OFFSET_OUT_OF_DATAVIEW);
    474    return false;
    475  }
    476 
    477  // Steps 11-12.
    478  *val = obj->read<NativeType>(getIndex, *viewSize, isLittleEndian);
    479  return true;
    480 }
    481 
    482 template <typename T>
    483 static inline T WrappingConvert(int32_t value) {
    484  if (std::is_unsigned_v<T>) {
    485    return static_cast<T>(value);
    486  }
    487 
    488  return WrapToSigned(static_cast<typename std::make_unsigned_t<T>>(value));
    489 }
    490 
    491 template <typename NativeType>
    492 static inline bool WebIDLCast(JSContext* cx, HandleValue value,
    493                              NativeType* out) {
    494  int32_t i;
    495  if (!ToInt32(cx, value, &i)) {
    496    return false;
    497  }
    498 
    499  *out = WrappingConvert<NativeType>(i);
    500  return true;
    501 }
    502 
    503 template <>
    504 inline bool WebIDLCast<int64_t>(JSContext* cx, HandleValue value,
    505                                int64_t* out) {
    506  BigInt* bi = ToBigInt(cx, value);
    507  if (!bi) {
    508    return false;
    509  }
    510  *out = BigInt::toInt64(bi);
    511  return true;
    512 }
    513 
    514 template <>
    515 inline bool WebIDLCast<uint64_t>(JSContext* cx, HandleValue value,
    516                                 uint64_t* out) {
    517  BigInt* bi = ToBigInt(cx, value);
    518  if (!bi) {
    519    return false;
    520  }
    521  *out = BigInt::toUint64(bi);
    522  return true;
    523 }
    524 
    525 template <>
    526 inline bool WebIDLCast<float16>(JSContext* cx, HandleValue value,
    527                                float16* out) {
    528  double temp;
    529  if (!ToNumber(cx, value, &temp)) {
    530    return false;
    531  }
    532  *out = float16(temp);
    533  return true;
    534 }
    535 
    536 template <>
    537 inline bool WebIDLCast<float>(JSContext* cx, HandleValue value, float* out) {
    538  double temp;
    539  if (!ToNumber(cx, value, &temp)) {
    540    return false;
    541  }
    542  *out = static_cast<float>(temp);
    543  return true;
    544 }
    545 
    546 template <>
    547 inline bool WebIDLCast<double>(JSContext* cx, HandleValue value, double* out) {
    548  return ToNumber(cx, value, out);
    549 }
    550 
    551 // https://tc39.github.io/ecma262/#sec-setviewvalue
    552 // SetViewValue ( view, requestIndex, isLittleEndian, type, value )
    553 template <typename NativeType>
    554 /* static */
    555 bool DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj,
    556                           const CallArgs& args) {
    557  // Step 1. done by the caller
    558  // Step 2. unnecessary assert
    559 
    560  // Additional step from Immutable ArrayBuffer proposal.
    561  if (obj->is<ImmutableDataViewObject>()) {
    562    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    563                              JSMSG_ARRAYBUFFER_IMMUTABLE);
    564    return false;
    565  }
    566 
    567  // Step 3.
    568  uint64_t getIndex;
    569  if (!ToIndex(cx, args.get(0), &getIndex)) {
    570    return false;
    571  }
    572 
    573  // Steps 4-5. Call ToBigInt(value) or ToNumber(value) depending on the type.
    574  NativeType value;
    575  if (!WebIDLCast(cx, args.get(1), &value)) {
    576    return false;
    577  }
    578 
    579  // See the comment in ElementSpecific::doubleToNative.
    580  if constexpr (!std::numeric_limits<NativeType>::is_integer) {
    581    if (js::SupportDifferentialTesting()) {
    582      value = JS::CanonicalizeNaN(static_cast<double>(value));
    583    }
    584  }
    585 
    586  // Step 6.
    587  bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
    588 
    589  // Steps 7-8.
    590  auto viewSize = obj->byteLength();
    591  if (MOZ_UNLIKELY(!viewSize)) {
    592    ReportOutOfBounds(cx, obj);
    593    return false;
    594  }
    595 
    596  // Steps 9-12.
    597  if (!offsetIsInBounds<NativeType>(getIndex, *viewSize)) {
    598    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
    599                              JSMSG_OFFSET_OUT_OF_DATAVIEW);
    600    return false;
    601  }
    602 
    603  // Steps 13-14.
    604  bool isSharedMemory;
    605  SharedMem<uint8_t*> data =
    606      obj->getDataPointer<NativeType>(getIndex, *viewSize, &isSharedMemory);
    607  MOZ_ASSERT(data);
    608 
    609  if (isSharedMemory) {
    610    DataViewIO<NativeType, SharedMem<uint8_t*>>::toBuffer(data, &value,
    611                                                          isLittleEndian);
    612  } else {
    613    DataViewIO<NativeType, uint8_t*>::toBuffer(data.unwrapUnshared(), &value,
    614                                               isLittleEndian);
    615  }
    616  return true;
    617 }
    618 
    619 bool DataViewObject::getInt8Impl(JSContext* cx, const CallArgs& args) {
    620  MOZ_ASSERT(IsDataView(args.thisv()));
    621 
    622  Rooted<DataViewObject*> thisView(
    623      cx, &args.thisv().toObject().as<DataViewObject>());
    624 
    625  int8_t val;
    626  if (!read(cx, thisView, args, &val)) {
    627    return false;
    628  }
    629  args.rval().setInt32(val);
    630  return true;
    631 }
    632 
    633 bool DataViewObject::fun_getInt8(JSContext* cx, unsigned argc, Value* vp) {
    634  CallArgs args = CallArgsFromVp(argc, vp);
    635  return CallNonGenericMethod<IsDataView, getInt8Impl>(cx, args);
    636 }
    637 
    638 bool DataViewObject::getUint8Impl(JSContext* cx, const CallArgs& args) {
    639  MOZ_ASSERT(IsDataView(args.thisv()));
    640 
    641  Rooted<DataViewObject*> thisView(
    642      cx, &args.thisv().toObject().as<DataViewObject>());
    643 
    644  uint8_t val;
    645  if (!read(cx, thisView, args, &val)) {
    646    return false;
    647  }
    648  args.rval().setInt32(val);
    649  return true;
    650 }
    651 
    652 bool DataViewObject::fun_getUint8(JSContext* cx, unsigned argc, Value* vp) {
    653  CallArgs args = CallArgsFromVp(argc, vp);
    654  return CallNonGenericMethod<IsDataView, getUint8Impl>(cx, args);
    655 }
    656 
    657 bool DataViewObject::getInt16Impl(JSContext* cx, const CallArgs& args) {
    658  MOZ_ASSERT(IsDataView(args.thisv()));
    659 
    660  Rooted<DataViewObject*> thisView(
    661      cx, &args.thisv().toObject().as<DataViewObject>());
    662 
    663  int16_t val;
    664  if (!read(cx, thisView, args, &val)) {
    665    return false;
    666  }
    667  args.rval().setInt32(val);
    668  return true;
    669 }
    670 
    671 bool DataViewObject::fun_getInt16(JSContext* cx, unsigned argc, Value* vp) {
    672  CallArgs args = CallArgsFromVp(argc, vp);
    673  return CallNonGenericMethod<IsDataView, getInt16Impl>(cx, args);
    674 }
    675 
    676 bool DataViewObject::getUint16Impl(JSContext* cx, const CallArgs& args) {
    677  MOZ_ASSERT(IsDataView(args.thisv()));
    678 
    679  Rooted<DataViewObject*> thisView(
    680      cx, &args.thisv().toObject().as<DataViewObject>());
    681 
    682  uint16_t val;
    683  if (!read(cx, thisView, args, &val)) {
    684    return false;
    685  }
    686  args.rval().setInt32(val);
    687  return true;
    688 }
    689 
    690 bool DataViewObject::fun_getUint16(JSContext* cx, unsigned argc, Value* vp) {
    691  CallArgs args = CallArgsFromVp(argc, vp);
    692  return CallNonGenericMethod<IsDataView, getUint16Impl>(cx, args);
    693 }
    694 
    695 bool DataViewObject::getInt32Impl(JSContext* cx, const CallArgs& args) {
    696  MOZ_ASSERT(IsDataView(args.thisv()));
    697 
    698  Rooted<DataViewObject*> thisView(
    699      cx, &args.thisv().toObject().as<DataViewObject>());
    700 
    701  int32_t val;
    702  if (!read(cx, thisView, args, &val)) {
    703    return false;
    704  }
    705  args.rval().setInt32(val);
    706  return true;
    707 }
    708 
    709 bool DataViewObject::fun_getInt32(JSContext* cx, unsigned argc, Value* vp) {
    710  CallArgs args = CallArgsFromVp(argc, vp);
    711  return CallNonGenericMethod<IsDataView, getInt32Impl>(cx, args);
    712 }
    713 
    714 bool DataViewObject::getUint32Impl(JSContext* cx, const CallArgs& args) {
    715  MOZ_ASSERT(IsDataView(args.thisv()));
    716 
    717  Rooted<DataViewObject*> thisView(
    718      cx, &args.thisv().toObject().as<DataViewObject>());
    719 
    720  uint32_t val;
    721  if (!read(cx, thisView, args, &val)) {
    722    return false;
    723  }
    724  args.rval().setNumber(val);
    725  return true;
    726 }
    727 
    728 bool DataViewObject::fun_getUint32(JSContext* cx, unsigned argc, Value* vp) {
    729  CallArgs args = CallArgsFromVp(argc, vp);
    730  return CallNonGenericMethod<IsDataView, getUint32Impl>(cx, args);
    731 }
    732 
    733 // BigInt proposal 7.26
    734 // DataView.prototype.getBigInt64 ( byteOffset [ , littleEndian ] )
    735 bool DataViewObject::getBigInt64Impl(JSContext* cx, const CallArgs& args) {
    736  MOZ_ASSERT(IsDataView(args.thisv()));
    737 
    738  Rooted<DataViewObject*> thisView(
    739      cx, &args.thisv().toObject().as<DataViewObject>());
    740 
    741  int64_t val;
    742  if (!read(cx, thisView, args, &val)) {
    743    return false;
    744  }
    745 
    746  BigInt* bi = BigInt::createFromInt64(cx, val);
    747  if (!bi) {
    748    return false;
    749  }
    750  args.rval().setBigInt(bi);
    751  return true;
    752 }
    753 
    754 bool DataViewObject::fun_getBigInt64(JSContext* cx, unsigned argc, Value* vp) {
    755  CallArgs args = CallArgsFromVp(argc, vp);
    756  return CallNonGenericMethod<IsDataView, getBigInt64Impl>(cx, args);
    757 }
    758 
    759 // BigInt proposal 7.27
    760 // DataView.prototype.getBigUint64 ( byteOffset [ , littleEndian ] )
    761 bool DataViewObject::getBigUint64Impl(JSContext* cx, const CallArgs& args) {
    762  MOZ_ASSERT(IsDataView(args.thisv()));
    763 
    764  Rooted<DataViewObject*> thisView(
    765      cx, &args.thisv().toObject().as<DataViewObject>());
    766 
    767  int64_t val;
    768  if (!read(cx, thisView, args, &val)) {
    769    return false;
    770  }
    771 
    772  BigInt* bi = BigInt::createFromUint64(cx, val);
    773  if (!bi) {
    774    return false;
    775  }
    776  args.rval().setBigInt(bi);
    777  return true;
    778 }
    779 
    780 bool DataViewObject::fun_getBigUint64(JSContext* cx, unsigned argc, Value* vp) {
    781  CallArgs args = CallArgsFromVp(argc, vp);
    782  return CallNonGenericMethod<IsDataView, getBigUint64Impl>(cx, args);
    783 }
    784 
    785 bool DataViewObject::getFloat16Impl(JSContext* cx, const CallArgs& args) {
    786  MOZ_ASSERT(IsDataView(args.thisv()));
    787 
    788  Rooted<DataViewObject*> thisView(
    789      cx, &args.thisv().toObject().as<DataViewObject>());
    790 
    791  float16 val{};
    792  if (!read(cx, thisView, args, &val)) {
    793    return false;
    794  }
    795 
    796  args.rval().setDouble(CanonicalizeNaN(static_cast<double>(val)));
    797  return true;
    798 }
    799 
    800 bool DataViewObject::fun_getFloat16(JSContext* cx, unsigned argc, Value* vp) {
    801  CallArgs args = CallArgsFromVp(argc, vp);
    802  return CallNonGenericMethod<IsDataView, getFloat16Impl>(cx, args);
    803 }
    804 
    805 bool DataViewObject::getFloat32Impl(JSContext* cx, const CallArgs& args) {
    806  MOZ_ASSERT(IsDataView(args.thisv()));
    807 
    808  Rooted<DataViewObject*> thisView(
    809      cx, &args.thisv().toObject().as<DataViewObject>());
    810 
    811  float val;
    812  if (!read(cx, thisView, args, &val)) {
    813    return false;
    814  }
    815 
    816  args.rval().setDouble(CanonicalizeNaN(val));
    817  return true;
    818 }
    819 
    820 bool DataViewObject::fun_getFloat32(JSContext* cx, unsigned argc, Value* vp) {
    821  CallArgs args = CallArgsFromVp(argc, vp);
    822  return CallNonGenericMethod<IsDataView, getFloat32Impl>(cx, args);
    823 }
    824 
    825 bool DataViewObject::getFloat64Impl(JSContext* cx, const CallArgs& args) {
    826  MOZ_ASSERT(IsDataView(args.thisv()));
    827 
    828  Rooted<DataViewObject*> thisView(
    829      cx, &args.thisv().toObject().as<DataViewObject>());
    830 
    831  double val;
    832  if (!read(cx, thisView, args, &val)) {
    833    return false;
    834  }
    835 
    836  args.rval().setDouble(CanonicalizeNaN(val));
    837  return true;
    838 }
    839 
    840 bool DataViewObject::fun_getFloat64(JSContext* cx, unsigned argc, Value* vp) {
    841  CallArgs args = CallArgsFromVp(argc, vp);
    842  return CallNonGenericMethod<IsDataView, getFloat64Impl>(cx, args);
    843 }
    844 
    845 bool DataViewObject::setInt8Impl(JSContext* cx, const CallArgs& args) {
    846  MOZ_ASSERT(IsDataView(args.thisv()));
    847 
    848  Rooted<DataViewObject*> thisView(
    849      cx, &args.thisv().toObject().as<DataViewObject>());
    850 
    851  if (!write<int8_t>(cx, thisView, args)) {
    852    return false;
    853  }
    854  args.rval().setUndefined();
    855  return true;
    856 }
    857 
    858 bool DataViewObject::fun_setInt8(JSContext* cx, unsigned argc, Value* vp) {
    859  CallArgs args = CallArgsFromVp(argc, vp);
    860  return CallNonGenericMethod<IsDataView, setInt8Impl>(cx, args);
    861 }
    862 
    863 bool DataViewObject::setUint8Impl(JSContext* cx, const CallArgs& args) {
    864  MOZ_ASSERT(IsDataView(args.thisv()));
    865 
    866  Rooted<DataViewObject*> thisView(
    867      cx, &args.thisv().toObject().as<DataViewObject>());
    868 
    869  if (!write<uint8_t>(cx, thisView, args)) {
    870    return false;
    871  }
    872  args.rval().setUndefined();
    873  return true;
    874 }
    875 
    876 bool DataViewObject::fun_setUint8(JSContext* cx, unsigned argc, Value* vp) {
    877  CallArgs args = CallArgsFromVp(argc, vp);
    878  return CallNonGenericMethod<IsDataView, setUint8Impl>(cx, args);
    879 }
    880 
    881 bool DataViewObject::setInt16Impl(JSContext* cx, const CallArgs& args) {
    882  MOZ_ASSERT(IsDataView(args.thisv()));
    883 
    884  Rooted<DataViewObject*> thisView(
    885      cx, &args.thisv().toObject().as<DataViewObject>());
    886 
    887  if (!write<int16_t>(cx, thisView, args)) {
    888    return false;
    889  }
    890  args.rval().setUndefined();
    891  return true;
    892 }
    893 
    894 bool DataViewObject::fun_setInt16(JSContext* cx, unsigned argc, Value* vp) {
    895  CallArgs args = CallArgsFromVp(argc, vp);
    896  return CallNonGenericMethod<IsDataView, setInt16Impl>(cx, args);
    897 }
    898 
    899 bool DataViewObject::setUint16Impl(JSContext* cx, const CallArgs& args) {
    900  MOZ_ASSERT(IsDataView(args.thisv()));
    901 
    902  Rooted<DataViewObject*> thisView(
    903      cx, &args.thisv().toObject().as<DataViewObject>());
    904 
    905  if (!write<uint16_t>(cx, thisView, args)) {
    906    return false;
    907  }
    908  args.rval().setUndefined();
    909  return true;
    910 }
    911 
    912 bool DataViewObject::fun_setUint16(JSContext* cx, unsigned argc, Value* vp) {
    913  CallArgs args = CallArgsFromVp(argc, vp);
    914  return CallNonGenericMethod<IsDataView, setUint16Impl>(cx, args);
    915 }
    916 
    917 bool DataViewObject::setInt32Impl(JSContext* cx, const CallArgs& args) {
    918  MOZ_ASSERT(IsDataView(args.thisv()));
    919 
    920  Rooted<DataViewObject*> thisView(
    921      cx, &args.thisv().toObject().as<DataViewObject>());
    922 
    923  if (!write<int32_t>(cx, thisView, args)) {
    924    return false;
    925  }
    926  args.rval().setUndefined();
    927  return true;
    928 }
    929 
    930 bool DataViewObject::fun_setInt32(JSContext* cx, unsigned argc, Value* vp) {
    931  CallArgs args = CallArgsFromVp(argc, vp);
    932  return CallNonGenericMethod<IsDataView, setInt32Impl>(cx, args);
    933 }
    934 
    935 bool DataViewObject::setUint32Impl(JSContext* cx, const CallArgs& args) {
    936  MOZ_ASSERT(IsDataView(args.thisv()));
    937 
    938  Rooted<DataViewObject*> thisView(
    939      cx, &args.thisv().toObject().as<DataViewObject>());
    940 
    941  if (!write<uint32_t>(cx, thisView, args)) {
    942    return false;
    943  }
    944  args.rval().setUndefined();
    945  return true;
    946 }
    947 
    948 bool DataViewObject::fun_setUint32(JSContext* cx, unsigned argc, Value* vp) {
    949  CallArgs args = CallArgsFromVp(argc, vp);
    950  return CallNonGenericMethod<IsDataView, setUint32Impl>(cx, args);
    951 }
    952 
    953 // BigInt proposal 7.28
    954 // DataView.prototype.setBigInt64 ( byteOffset, value [ , littleEndian ] )
    955 bool DataViewObject::setBigInt64Impl(JSContext* cx, const CallArgs& args) {
    956  MOZ_ASSERT(IsDataView(args.thisv()));
    957 
    958  Rooted<DataViewObject*> thisView(
    959      cx, &args.thisv().toObject().as<DataViewObject>());
    960 
    961  if (!write<int64_t>(cx, thisView, args)) {
    962    return false;
    963  }
    964  args.rval().setUndefined();
    965  return true;
    966 }
    967 
    968 bool DataViewObject::fun_setBigInt64(JSContext* cx, unsigned argc, Value* vp) {
    969  CallArgs args = CallArgsFromVp(argc, vp);
    970  return CallNonGenericMethod<IsDataView, setBigInt64Impl>(cx, args);
    971 }
    972 
    973 // BigInt proposal 7.29
    974 // DataView.prototype.setBigUint64 ( byteOffset, value [ , littleEndian ] )
    975 bool DataViewObject::setBigUint64Impl(JSContext* cx, const CallArgs& args) {
    976  MOZ_ASSERT(IsDataView(args.thisv()));
    977 
    978  Rooted<DataViewObject*> thisView(
    979      cx, &args.thisv().toObject().as<DataViewObject>());
    980 
    981  if (!write<uint64_t>(cx, thisView, args)) {
    982    return false;
    983  }
    984  args.rval().setUndefined();
    985  return true;
    986 }
    987 
    988 bool DataViewObject::fun_setBigUint64(JSContext* cx, unsigned argc, Value* vp) {
    989  CallArgs args = CallArgsFromVp(argc, vp);
    990  return CallNonGenericMethod<IsDataView, setBigUint64Impl>(cx, args);
    991 }
    992 
    993 bool DataViewObject::setFloat16Impl(JSContext* cx, const CallArgs& args) {
    994  MOZ_ASSERT(IsDataView(args.thisv()));
    995 
    996  Rooted<DataViewObject*> thisView(
    997      cx, &args.thisv().toObject().as<DataViewObject>());
    998 
    999  if (!write<float16>(cx, thisView, args)) {
   1000    return false;
   1001  }
   1002  args.rval().setUndefined();
   1003  return true;
   1004 }
   1005 
   1006 bool DataViewObject::fun_setFloat16(JSContext* cx, unsigned argc, Value* vp) {
   1007  CallArgs args = CallArgsFromVp(argc, vp);
   1008  return CallNonGenericMethod<IsDataView, setFloat16Impl>(cx, args);
   1009 }
   1010 
   1011 bool DataViewObject::setFloat32Impl(JSContext* cx, const CallArgs& args) {
   1012  MOZ_ASSERT(IsDataView(args.thisv()));
   1013 
   1014  Rooted<DataViewObject*> thisView(
   1015      cx, &args.thisv().toObject().as<DataViewObject>());
   1016 
   1017  if (!write<float>(cx, thisView, args)) {
   1018    return false;
   1019  }
   1020  args.rval().setUndefined();
   1021  return true;
   1022 }
   1023 
   1024 bool DataViewObject::fun_setFloat32(JSContext* cx, unsigned argc, Value* vp) {
   1025  CallArgs args = CallArgsFromVp(argc, vp);
   1026  return CallNonGenericMethod<IsDataView, setFloat32Impl>(cx, args);
   1027 }
   1028 
   1029 bool DataViewObject::setFloat64Impl(JSContext* cx, const CallArgs& args) {
   1030  MOZ_ASSERT(IsDataView(args.thisv()));
   1031 
   1032  Rooted<DataViewObject*> thisView(
   1033      cx, &args.thisv().toObject().as<DataViewObject>());
   1034 
   1035  if (!write<double>(cx, thisView, args)) {
   1036    return false;
   1037  }
   1038  args.rval().setUndefined();
   1039  return true;
   1040 }
   1041 
   1042 bool DataViewObject::fun_setFloat64(JSContext* cx, unsigned argc, Value* vp) {
   1043  CallArgs args = CallArgsFromVp(argc, vp);
   1044  return CallNonGenericMethod<IsDataView, setFloat64Impl>(cx, args);
   1045 }
   1046 
   1047 bool DataViewObject::bufferGetterImpl(JSContext* cx, const CallArgs& args) {
   1048  auto* thisView = &args.thisv().toObject().as<DataViewObject>();
   1049  args.rval().set(thisView->bufferValue());
   1050  return true;
   1051 }
   1052 
   1053 bool DataViewObject::bufferGetter(JSContext* cx, unsigned argc, Value* vp) {
   1054  CallArgs args = CallArgsFromVp(argc, vp);
   1055  return CallNonGenericMethod<IsDataView, bufferGetterImpl>(cx, args);
   1056 }
   1057 
   1058 bool DataViewObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args) {
   1059  auto* thisView = &args.thisv().toObject().as<DataViewObject>();
   1060 
   1061  // Step 6.
   1062  auto byteLength = thisView->byteLength();
   1063  if (MOZ_UNLIKELY(!byteLength)) {
   1064    ReportOutOfBounds(cx, thisView);
   1065    return false;
   1066  }
   1067 
   1068  // Step 7.
   1069  args.rval().set(NumberValue(*byteLength));
   1070  return true;
   1071 }
   1072 
   1073 bool DataViewObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp) {
   1074  CallArgs args = CallArgsFromVp(argc, vp);
   1075  return CallNonGenericMethod<IsDataView, byteLengthGetterImpl>(cx, args);
   1076 }
   1077 
   1078 bool DataViewObject::byteOffsetGetterImpl(JSContext* cx, const CallArgs& args) {
   1079  auto* thisView = &args.thisv().toObject().as<DataViewObject>();
   1080 
   1081  // Step 6.
   1082  auto byteOffset = thisView->byteOffset();
   1083  if (MOZ_UNLIKELY(!byteOffset)) {
   1084    ReportOutOfBounds(cx, thisView);
   1085    return false;
   1086  }
   1087 
   1088  // Step 7.
   1089  args.rval().set(NumberValue(*byteOffset));
   1090  return true;
   1091 }
   1092 
   1093 bool DataViewObject::byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp) {
   1094  CallArgs args = CallArgsFromVp(argc, vp);
   1095  return CallNonGenericMethod<IsDataView, byteOffsetGetterImpl>(cx, args);
   1096 }
   1097 
   1098 static const JSClassOps DataViewObjectClassOps = {
   1099    nullptr,                       // addProperty
   1100    nullptr,                       // delProperty
   1101    nullptr,                       // enumerate
   1102    nullptr,                       // newEnumerate
   1103    nullptr,                       // resolve
   1104    nullptr,                       // mayResolve
   1105    nullptr,                       // finalize
   1106    nullptr,                       // call
   1107    nullptr,                       // construct
   1108    ArrayBufferViewObject::trace,  // trace
   1109 };
   1110 
   1111 static JSObject* CreateDataViewPrototype(JSContext* cx, JSProtoKey key) {
   1112  return GlobalObject::createBlankPrototype(cx, cx->global(),
   1113                                            &DataViewObject::protoClass_);
   1114 }
   1115 
   1116 const ClassSpec DataViewObject::classSpec_ = {
   1117    GenericCreateConstructor<DataViewObject::construct, 1,
   1118                             gc::AllocKind::FUNCTION>,
   1119    CreateDataViewPrototype,
   1120    nullptr,
   1121    nullptr,
   1122    DataViewObject::methods,
   1123    DataViewObject::properties,
   1124 };
   1125 
   1126 const JSClass FixedLengthDataViewObject::class_ = {
   1127    "DataView",
   1128    JSCLASS_HAS_RESERVED_SLOTS(FixedLengthDataViewObject::RESERVED_SLOTS) |
   1129        JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
   1130    &DataViewObjectClassOps,
   1131    &DataViewObject::classSpec_,
   1132 };
   1133 
   1134 const JSClass ResizableDataViewObject::class_ = {
   1135    "DataView",
   1136    JSCLASS_HAS_RESERVED_SLOTS(ResizableDataViewObject::RESERVED_SLOTS) |
   1137        JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
   1138    &DataViewObjectClassOps,
   1139    &DataViewObject::classSpec_,
   1140 };
   1141 
   1142 const JSClass ImmutableDataViewObject::class_ = {
   1143    "DataView",
   1144    JSCLASS_HAS_RESERVED_SLOTS(ImmutableDataViewObject::RESERVED_SLOTS) |
   1145        JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
   1146    &DataViewObjectClassOps,
   1147    &DataViewObject::classSpec_,
   1148 };
   1149 
   1150 const JSClass* const JS::DataView::FixedLengthClassPtr =
   1151    &FixedLengthDataViewObject::class_;
   1152 const JSClass* const JS::DataView::ResizableClassPtr =
   1153    &ResizableDataViewObject::class_;
   1154 const JSClass* const JS::DataView::ImmutableClassPtr =
   1155    &ImmutableDataViewObject::class_;
   1156 
   1157 const JSClass DataViewObject::protoClass_ = {
   1158    "DataView.prototype",
   1159    JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
   1160    JS_NULL_CLASS_OPS,
   1161    &DataViewObject::classSpec_,
   1162 };
   1163 
   1164 const JSFunctionSpec DataViewObject::methods[] = {
   1165    JS_INLINABLE_FN("getInt8", DataViewObject::fun_getInt8, 1, 0,
   1166                    DataViewGetInt8),
   1167    JS_INLINABLE_FN("getUint8", DataViewObject::fun_getUint8, 1, 0,
   1168                    DataViewGetUint8),
   1169    JS_INLINABLE_FN("getInt16", DataViewObject::fun_getInt16, 1, 0,
   1170                    DataViewGetInt16),
   1171    JS_INLINABLE_FN("getUint16", DataViewObject::fun_getUint16, 1, 0,
   1172                    DataViewGetUint16),
   1173    JS_INLINABLE_FN("getInt32", DataViewObject::fun_getInt32, 1, 0,
   1174                    DataViewGetInt32),
   1175    JS_INLINABLE_FN("getUint32", DataViewObject::fun_getUint32, 1, 0,
   1176                    DataViewGetUint32),
   1177    JS_INLINABLE_FN("getFloat16", DataViewObject::fun_getFloat16, 1, 0,
   1178                    DataViewGetFloat16),
   1179    JS_INLINABLE_FN("getFloat32", DataViewObject::fun_getFloat32, 1, 0,
   1180                    DataViewGetFloat32),
   1181    JS_INLINABLE_FN("getFloat64", DataViewObject::fun_getFloat64, 1, 0,
   1182                    DataViewGetFloat64),
   1183    JS_INLINABLE_FN("getBigInt64", DataViewObject::fun_getBigInt64, 1, 0,
   1184                    DataViewGetBigInt64),
   1185    JS_INLINABLE_FN("getBigUint64", DataViewObject::fun_getBigUint64, 1, 0,
   1186                    DataViewGetBigUint64),
   1187    JS_INLINABLE_FN("setInt8", DataViewObject::fun_setInt8, 2, 0,
   1188                    DataViewSetInt8),
   1189    JS_INLINABLE_FN("setUint8", DataViewObject::fun_setUint8, 2, 0,
   1190                    DataViewSetUint8),
   1191    JS_INLINABLE_FN("setInt16", DataViewObject::fun_setInt16, 2, 0,
   1192                    DataViewSetInt16),
   1193    JS_INLINABLE_FN("setUint16", DataViewObject::fun_setUint16, 2, 0,
   1194                    DataViewSetUint16),
   1195    JS_INLINABLE_FN("setInt32", DataViewObject::fun_setInt32, 2, 0,
   1196                    DataViewSetInt32),
   1197    JS_INLINABLE_FN("setUint32", DataViewObject::fun_setUint32, 2, 0,
   1198                    DataViewSetUint32),
   1199    JS_INLINABLE_FN("setFloat16", DataViewObject::fun_setFloat16, 2, 0,
   1200                    DataViewSetFloat16),
   1201    JS_INLINABLE_FN("setFloat32", DataViewObject::fun_setFloat32, 2, 0,
   1202                    DataViewSetFloat32),
   1203    JS_INLINABLE_FN("setFloat64", DataViewObject::fun_setFloat64, 2, 0,
   1204                    DataViewSetFloat64),
   1205    JS_INLINABLE_FN("setBigInt64", DataViewObject::fun_setBigInt64, 2, 0,
   1206                    DataViewSetBigInt64),
   1207    JS_INLINABLE_FN("setBigUint64", DataViewObject::fun_setBigUint64, 2, 0,
   1208                    DataViewSetBigUint64),
   1209    JS_FS_END,
   1210 };
   1211 
   1212 const JSPropertySpec DataViewObject::properties[] = {
   1213    JS_PSG("buffer", DataViewObject::bufferGetter, 0),
   1214    JS_INLINABLE_PSG("byteLength", DataViewObject::byteLengthGetter, 0,
   1215                     DataViewByteLength),
   1216    JS_INLINABLE_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0,
   1217                     DataViewByteOffset),
   1218    JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY),
   1219    JS_PS_END,
   1220 };
   1221 
   1222 JS_PUBLIC_API JSObject* JS_NewDataView(JSContext* cx, HandleObject buffer,
   1223                                       size_t byteOffset, size_t byteLength) {
   1224  JSProtoKey key = JSProto_DataView;
   1225  RootedObject constructor(cx, GlobalObject::getOrCreateConstructor(cx, key));
   1226  if (!constructor) {
   1227    return nullptr;
   1228  }
   1229 
   1230  FixedConstructArgs<3> cargs(cx);
   1231 
   1232  cargs[0].setObject(*buffer);
   1233  cargs[1].setNumber(byteOffset);
   1234  cargs[2].setNumber(byteLength);
   1235 
   1236  RootedValue fun(cx, ObjectValue(*constructor));
   1237  RootedObject obj(cx);
   1238  if (!Construct(cx, fun, cargs, fun, &obj)) {
   1239    return nullptr;
   1240  }
   1241  return obj;
   1242 }
   1243 
   1244 JSObject* js::NewDataView(JSContext* cx, HandleObject buffer,
   1245                          size_t byteOffset) {
   1246  JSProtoKey key = JSProto_DataView;
   1247  RootedObject constructor(cx, GlobalObject::getOrCreateConstructor(cx, key));
   1248  if (!constructor) {
   1249    return nullptr;
   1250  }
   1251 
   1252  FixedConstructArgs<2> cargs(cx);
   1253 
   1254  cargs[0].setObject(*buffer);
   1255  cargs[1].setNumber(byteOffset);
   1256 
   1257  RootedValue fun(cx, ObjectValue(*constructor));
   1258  RootedObject obj(cx);
   1259  if (!Construct(cx, fun, cargs, fun, &obj)) {
   1260    return nullptr;
   1261  }
   1262  return obj;
   1263 }