Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  DataViewObject.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "builtin/DataViewObject.h"

#include "mozilla/Casting.h"
#include "mozilla/EndianUtils.h"
#include "mozilla/IntegerTypeTraits.h"
#include "mozilla/WrappingOperations.h"

#include <algorithm>
#include <string.h>
#include <type_traits>

#include "jsnum.h"

#include "jit/AtomicOperations.h"
#include "jit/InlinableNatives.h"
#include "js/Conversions.h"
#include "js/experimental/TypedData.h"  // JS_NewDataView
#include "js/friend/ErrorMessages.h"    // js::GetErrorMessage, JSMSG_*
#include "js/PropertySpec.h"
#include "js/Wrapper.h"
#include "util/DifferentialTesting.h"
#include "vm/ArrayBufferObject.h"
#include "vm/Compartment.h"
#include "vm/Float16.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
#include "vm/JSContext.h"
#include "vm/JSObject.h"
#include "vm/SharedMem.h"
#include "vm/Uint8Clamped.h"
#include "vm/WrapperObject.h"

#include "vm/ArrayBufferObject-inl.h"
#include "vm/NativeObject-inl.h"

using namespace js;

using JS::CanonicalizeNaN;
using JS::ToInt32;
using mozilla::WrapToSigned;

static bool IsDataView(HandleValue v) {
  return v.isObject() && v.toObject().is<DataViewObject>();
}

DataViewObject* DataViewObject::create(
    JSContext* cx, size_t byteOffset, size_t byteLength,
    Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto) {
  MOZ_ASSERT(!arrayBuffer->isResizable());
  MOZ_ASSERT(!arrayBuffer->isDetached());

  auto* obj = NewObjectWithClassProto<FixedLengthDataViewObject>(cx, proto);
  if (!obj || !obj->init(cx, arrayBuffer, byteOffset, byteLength,
                         /* bytesPerElement = */ 1)) {
    return nullptr;
  }

  return obj;
}

ResizableDataViewObject* ResizableDataViewObject::create(
    JSContext* cx, size_t byteOffset, size_t byteLength, AutoLength autoLength,
    Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, HandleObject proto) {
  MOZ_ASSERT(arrayBuffer->isResizable());
  MOZ_ASSERT(!arrayBuffer->isDetached());
  MOZ_ASSERT(autoLength == AutoLength::No || byteLength == 0,
             "byte length is zero for 'auto' length views");

  auto* obj = NewObjectWithClassProto<ResizableDataViewObject>(cx, proto);
  if (!obj || !obj->initResizable(cx, arrayBuffer, byteOffset, byteLength,
                                  /* bytesPerElement = */ 1, autoLength)) {
    return nullptr;
  }

  return obj;
}

// ES2017 draft rev 931261ecef9b047b14daacf82884134da48dfe0f
// 24.3.2.1 DataView (extracted part of the main algorithm)
bool DataViewObject::getAndCheckConstructorArgs(
    JSContext* cx, HandleObject bufobj, const CallArgs& args,
    size_t* byteOffsetPtr, size_t* byteLengthPtr, AutoLength* autoLengthPtr) {
  // Step 3.
  if (!bufobj->is<ArrayBufferObjectMaybeShared>()) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_NOT_EXPECTED_TYPE, "DataView",
                              "ArrayBuffer", bufobj->getClass()->name);
    return false;
  }
  auto buffer = bufobj.as<ArrayBufferObjectMaybeShared>();

  // Step 4.
  uint64_t offset;
  if (!ToIndex(cx, args.get(1), &offset)) {
    return false;
  }

  // Step 5.
  if (buffer->isDetached()) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_TYPED_ARRAY_DETACHED);
    return false;
  }

  // Step 6.
  size_t bufferByteLength = buffer->byteLength();

  // Step 7.
  if (offset > bufferByteLength) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_OFFSET_OUT_OF_BUFFER);
    return false;
  }
  MOZ_ASSERT(offset <= ArrayBufferObject::ByteLengthLimit);

  uint64_t viewByteLength = 0;
  auto autoLength = AutoLength::No;
  if (!args.hasDefined(2)) {
    if (buffer->isResizable()) {
      autoLength = AutoLength::Yes;
    } else {
      // Step 8.a
      viewByteLength = bufferByteLength - offset;
    }
  } else {
    // Step 9.a.
    if (!ToIndex(cx, args.get(2), &viewByteLength)) {
      return false;
    }

    MOZ_ASSERT(offset + viewByteLength >= offset,
               "can't overflow: both numbers are less than "
               "DOUBLE_INTEGRAL_PRECISION_LIMIT");

    // Step 9.b.
    if (offset + viewByteLength > bufferByteLength) {
      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                JSMSG_INVALID_DATA_VIEW_LENGTH);
      return false;
    }
  }
  MOZ_ASSERT(viewByteLength <= ArrayBufferObject::ByteLengthLimit);

  *byteOffsetPtr = offset;
  *byteLengthPtr = viewByteLength;
  *autoLengthPtr = autoLength;
  return true;
}

static bool CheckConstructorArgs(JSContext* cx,
                                 Handle<ArrayBufferObjectMaybeShared*> buffer,
                                 size_t byteOffset, size_t byteLength) {
  if (buffer->isDetached()) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_TYPED_ARRAY_DETACHED);
    return false;
  }

  if (buffer->isResizable()) {
    size_t bufferByteLength = buffer->byteLength();
    if (byteOffset + byteLength > bufferByteLength) {
      JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                JSMSG_OFFSET_OUT_OF_BUFFER);
      return false;
    }
  }

  return true;
}

bool DataViewObject::constructSameCompartment(JSContext* cx,
                                              HandleObject bufobj,
                                              const CallArgs& args) {
  MOZ_ASSERT(args.isConstructing());
  cx->check(bufobj);

  size_t byteOffset = 0;
  size_t byteLength = 0;
  auto autoLength = AutoLength::No;
  if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength,
                                  &autoLength)) {
    return false;
  }

  RootedObject proto(cx);
  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
    return false;
  }

  auto buffer = bufobj.as<ArrayBufferObjectMaybeShared>();

  // GetPrototypeFromBuiltinConstructor may have detached or resized the buffer,
  // so we have to revalidate the arguments.
  if (!CheckConstructorArgs(cx, buffer, byteOffset, byteLength)) {
    return false;
  }

  DataViewObject* obj;
  if (!buffer->isResizable()) {
    obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto);
  } else {
    obj = ResizableDataViewObject::create(cx, byteOffset, byteLength,
                                          autoLength, buffer, proto);
  }
  if (!obj) {
    return false;
  }
  args.rval().setObject(*obj);
  return true;
}

// Create a DataView object in another compartment.
//
// ES6 supports creating a DataView in global A (using global A's DataView
// constructor) backed by an ArrayBuffer created in global B.
//
// Our DataViewObject implementation doesn't support a DataView in
// compartment A backed by an ArrayBuffer in compartment B. So in this case,
// we create the DataView in B (!) and return a cross-compartment wrapper.
//
// Extra twist: the spec says the new DataView's [[Prototype]] must be
// A's DataView.prototype. So even though we're creating the DataView in B,
// its [[Prototype]] must be (a cross-compartment wrapper for) the
// DataView.prototype in A.
bool DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj,
                                      const CallArgs& args) {
  MOZ_ASSERT(args.isConstructing());
  MOZ_ASSERT(bufobj->is<WrapperObject>());

  RootedObject unwrapped(cx, CheckedUnwrapStatic(bufobj));
  if (!unwrapped) {
    ReportAccessDenied(cx);
    return false;
  }

  // NB: This entails the IsArrayBuffer check
  size_t byteOffset = 0;
  size_t byteLength = 0;
  auto autoLength = AutoLength::No;
  if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength,
                                  &autoLength)) {
    return false;
  }

  // Make sure to get the [[Prototype]] for the created view from this
  // compartment.
  RootedObject proto(cx);
  if (!GetPrototypeFromBuiltinConstructor(cx, args, JSProto_DataView, &proto)) {
    return false;
  }

  auto unwrappedBuffer = unwrapped.as<ArrayBufferObjectMaybeShared>();

  // GetPrototypeFromBuiltinConstructor may have detached or resized the buffer,
  // so we have to revalidate the arguments.
  if (!CheckConstructorArgs(cx, unwrappedBuffer, byteOffset, byteLength)) {
    return false;
  }

  Rooted<GlobalObject*> global(cx, cx->realm()->maybeGlobal());
  if (!proto) {
    proto = GlobalObject::getOrCreateDataViewPrototype(cx, global);
    if (!proto) {
      return false;
    }
  }

  RootedObject dv(cx);
  {
    JSAutoRealm ar(cx, unwrapped);

    RootedObject wrappedProto(cx, proto);
    if (!cx->compartment()->wrap(cx, &wrappedProto)) {
      return false;
    }

    if (!unwrappedBuffer->isResizable()) {
      dv = DataViewObject::create(cx, byteOffset, byteLength, unwrappedBuffer,
                                  wrappedProto);
    } else {
      dv = ResizableDataViewObject::create(cx, byteOffset, byteLength,
                                           autoLength, unwrappedBuffer,
                                           wrappedProto);
    }
    if (!dv) {
      return false;
    }
  }

  if (!cx->compartment()->wrap(cx, &dv)) {
    return false;
  }

  args.rval().setObject(*dv);
  return true;
}

bool DataViewObject::construct(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);

  if (!ThrowIfNotConstructing(cx, args, "DataView")) {
    return false;
  }

  RootedObject bufobj(cx);
  if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj)) {
    return false;
  }

  if (bufobj->is<WrapperObject>()) {
    return constructWrapped(cx, bufobj, args);
  }
  return constructSameCompartment(cx, bufobj, args);
}

template <typename NativeType>
SharedMem<uint8_t*> DataViewObject::getDataPointer(uint64_t offset,
                                                   size_t length,
                                                   bool* isSharedMemory) {
  MOZ_ASSERT(length <= *byteLength());
  MOZ_ASSERT(offsetIsInBounds<NativeType>(offset, length));

  MOZ_ASSERT(offset < SIZE_MAX);
  *isSharedMemory = this->isSharedMemory();
  return dataPointerEither().cast<uint8_t*>() + size_t(offset);
}

static void ReportOutOfBounds(JSContext* cx, DataViewObject* dataView) {
  if (dataView->hasDetachedBuffer()) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_TYPED_ARRAY_DETACHED);
  } else {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_TYPED_ARRAY_RESIZED_BOUNDS);
  }
}

template <typename T>
static inline std::enable_if_t<sizeof(T) != 1> SwapBytes(T* value,
                                                         bool isLittleEndian) {
  if (isLittleEndian) {
    mozilla::NativeEndian::swapToLittleEndianInPlace(value, 1);
  } else {
    mozilla::NativeEndian::swapToBigEndianInPlace(value, 1);
  }
}

template <typename T>
static inline std::enable_if_t<sizeof(T) == 1> SwapBytes(T* value,
                                                         bool isLittleEndian) {
  // mozilla::NativeEndian doesn't support int8_t/uint8_t types.
}

static inline void Memcpy(uint8_t* dest, uint8_t* src, size_t nbytes) {
  memcpy(dest, src, nbytes);
}

static inline void Memcpy(uint8_t* dest, SharedMem<uint8_t*> src,
                          size_t nbytes) {
  jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes);
}

static inline void Memcpy(SharedMem<uint8_t*> dest, uint8_t* src,
                          size_t nbytes) {
  jit::AtomicOperations::memcpySafeWhenRacy(dest, src, nbytes);
}

template <typename DataType, typename BufferPtrType>
struct DataViewIO {
  using ReadWriteType =
      typename mozilla::UnsignedStdintTypeForSize<sizeof(DataType)>::Type;

  static constexpr auto alignMask =
      std::min<size_t>(alignof(void*), sizeof(DataType)) - 1;

  static void fromBuffer(DataType* dest, BufferPtrType unalignedBuffer,
                         bool isLittleEndian) {
    MOZ_ASSERT((reinterpret_cast<uintptr_t>(dest) & alignMask) == 0);
    Memcpy((uint8_t*)dest, unalignedBuffer, sizeof(ReadWriteType));
    ReadWriteType* rwDest = reinterpret_cast<ReadWriteType*>(dest);
    SwapBytes(rwDest, isLittleEndian);
  }

  static void toBuffer(BufferPtrType unalignedBuffer, const DataType* src,
                       bool isLittleEndian) {
    MOZ_ASSERT((reinterpret_cast<uintptr_t>(src) & alignMask) == 0);
    ReadWriteType temp = *reinterpret_cast<const ReadWriteType*>(src);
    SwapBytes(&temp, isLittleEndian);
    Memcpy(unalignedBuffer, (uint8_t*)&temp, sizeof(ReadWriteType));
  }
};

template <typename NativeType>
NativeType DataViewObject::read(uint64_t offset, size_t length,
                                bool isLittleEndian) {
  bool isSharedMemory;
  SharedMem<uint8_t*> data =
      getDataPointer<NativeType>(offset, length, &isSharedMemory);
  MOZ_ASSERT(data);

  NativeType val{};
  if (isSharedMemory) {
    DataViewIO<NativeType, SharedMem<uint8_t*>>::fromBuffer(&val, data,
                                                            isLittleEndian);
  } else {
    DataViewIO<NativeType, uint8_t*>::fromBuffer(&val, data.unwrapUnshared(),
                                                 isLittleEndian);
  }

  return val;
}

template uint32_t DataViewObject::read(uint64_t offset, size_t length,
                                       bool isLittleEndian);

// https://tc39.github.io/ecma262/#sec-getviewvalue
// GetViewValue ( view, requestIndex, isLittleEndian, type )
template <typename NativeType>
/* static */
bool DataViewObject::read(JSContext* cx, Handle<DataViewObject*> obj,
                          const CallArgs& args, NativeType* val) {
  // Step 1. done by the caller
  // Step 2. unnecessary assert

  // Step 3.
  uint64_t getIndex;
  if (!ToIndex(cx, args.get(0), &getIndex)) {
    return false;
  }

  // Step 4.
  bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]);

  // Steps 5-6.
  auto viewSize = obj->byteLength();
  if (MOZ_UNLIKELY(!viewSize)) {
    ReportOutOfBounds(cx, obj);
    return false;
  }

  // Steps 7-10.
  if (!offsetIsInBounds<NativeType>(getIndex, *viewSize)) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_OFFSET_OUT_OF_DATAVIEW);
    return false;
  }

  // Steps 11-12.
  *val = obj->read<NativeType>(getIndex, *viewSize, isLittleEndian);
  return true;
}

template <typename T>
static inline T WrappingConvert(int32_t value) {
  if (std::is_unsigned_v<T>) {
    return static_cast<T>(value);
  }

  return WrapToSigned(static_cast<typename std::make_unsigned_t<T>>(value));
}

template <typename NativeType>
static inline bool WebIDLCast(JSContext* cx, HandleValue value,
                              NativeType* out) {
  int32_t i;
  if (!ToInt32(cx, value, &i)) {
    return false;
  }

  *out = WrappingConvert<NativeType>(i);
  return true;
}

template <>
inline bool WebIDLCast<int64_t>(JSContext* cx, HandleValue value,
                                int64_t* out) {
  BigInt* bi = ToBigInt(cx, value);
  if (!bi) {
    return false;
  }
  *out = BigInt::toInt64(bi);
  return true;
}

template <>
inline bool WebIDLCast<uint64_t>(JSContext* cx, HandleValue value,
                                 uint64_t* out) {
  BigInt* bi = ToBigInt(cx, value);
  if (!bi) {
    return false;
  }
  *out = BigInt::toUint64(bi);
  return true;
}

template <>
inline bool WebIDLCast<float16>(JSContext* cx, HandleValue value,
                                float16* out) {
  double temp;
  if (!ToNumber(cx, value, &temp)) {
    return false;
  }
  *out = float16(temp);
  return true;
}

template <>
inline bool WebIDLCast<float>(JSContext* cx, HandleValue value, float* out) {
  double temp;
  if (!ToNumber(cx, value, &temp)) {
    return false;
  }
  *out = static_cast<float>(temp);
  return true;
}

template <>
inline bool WebIDLCast<double>(JSContext* cx, HandleValue value, double* out) {
  return ToNumber(cx, value, out);
}

// https://tc39.github.io/ecma262/#sec-setviewvalue
// SetViewValue ( view, requestIndex, isLittleEndian, type, value )
template <typename NativeType>
/* static */
bool DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj,
                           const CallArgs& args) {
  // Step 1. done by the caller
  // Step 2. unnecessary assert

  // Step 3.
  uint64_t getIndex;
  if (!ToIndex(cx, args.get(0), &getIndex)) {
    return false;
  }

  // Steps 4-5. Call ToBigInt(value) or ToNumber(value) depending on the type.
  NativeType value;
  if (!WebIDLCast(cx, args.get(1), &value)) {
    return false;
  }

  // See the comment in ElementSpecific::doubleToNative.
  if constexpr (!std::numeric_limits<NativeType>::is_integer) {
    if (js::SupportDifferentialTesting()) {
      value = JS::CanonicalizeNaN(static_cast<double>(value));
    }
  }

  // Step 6.
  bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);

  // Steps 7-8.
  auto viewSize = obj->byteLength();
  if (MOZ_UNLIKELY(!viewSize)) {
    ReportOutOfBounds(cx, obj);
    return false;
  }

  // Steps 9-12.
  if (!offsetIsInBounds<NativeType>(getIndex, *viewSize)) {
    JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                              JSMSG_OFFSET_OUT_OF_DATAVIEW);
    return false;
  }

  // Steps 13-14.
  bool isSharedMemory;
  SharedMem<uint8_t*> data =
      obj->getDataPointer<NativeType>(getIndex, *viewSize, &isSharedMemory);
  MOZ_ASSERT(data);

  if (isSharedMemory) {
    DataViewIO<NativeType, SharedMem<uint8_t*>>::toBuffer(data, &value,
                                                          isLittleEndian);
  } else {
    DataViewIO<NativeType, uint8_t*>::toBuffer(data.unwrapUnshared(), &value,
                                               isLittleEndian);
  }
  return true;
}

bool DataViewObject::getInt8Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  int8_t val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }
  args.rval().setInt32(val);
  return true;
}

bool DataViewObject::fun_getInt8(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getInt8Impl>(cx, args);
}

bool DataViewObject::getUint8Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  uint8_t val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }
  args.rval().setInt32(val);
  return true;
}

bool DataViewObject::fun_getUint8(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getUint8Impl>(cx, args);
}

bool DataViewObject::getInt16Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  int16_t val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }
  args.rval().setInt32(val);
  return true;
}

bool DataViewObject::fun_getInt16(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getInt16Impl>(cx, args);
}

bool DataViewObject::getUint16Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  uint16_t val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }
  args.rval().setInt32(val);
  return true;
}

bool DataViewObject::fun_getUint16(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getUint16Impl>(cx, args);
}

bool DataViewObject::getInt32Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  int32_t val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }
  args.rval().setInt32(val);
  return true;
}

bool DataViewObject::fun_getInt32(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getInt32Impl>(cx, args);
}

bool DataViewObject::getUint32Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  uint32_t val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }
  args.rval().setNumber(val);
  return true;
}

bool DataViewObject::fun_getUint32(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getUint32Impl>(cx, args);
}

// BigInt proposal 7.26
// DataView.prototype.getBigInt64 ( byteOffset [ , littleEndian ] )
bool DataViewObject::getBigInt64Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  int64_t val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }

  BigInt* bi = BigInt::createFromInt64(cx, val);
  if (!bi) {
    return false;
  }
  args.rval().setBigInt(bi);
  return true;
}

bool DataViewObject::fun_getBigInt64(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getBigInt64Impl>(cx, args);
}

// BigInt proposal 7.27
// DataView.prototype.getBigUint64 ( byteOffset [ , littleEndian ] )
bool DataViewObject::getBigUint64Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  int64_t val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }

  BigInt* bi = BigInt::createFromUint64(cx, val);
  if (!bi) {
    return false;
  }
  args.rval().setBigInt(bi);
  return true;
}

bool DataViewObject::fun_getBigUint64(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getBigUint64Impl>(cx, args);
}

bool DataViewObject::getFloat16Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  float16 val{};
  if (!read(cx, thisView, args, &val)) {
    return false;
  }

  args.rval().setDouble(CanonicalizeNaN(static_cast<double>(val)));
  return true;
}

bool DataViewObject::fun_getFloat16(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getFloat16Impl>(cx, args);
}

bool DataViewObject::getFloat32Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  float val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }

  args.rval().setDouble(CanonicalizeNaN(val));
  return true;
}

bool DataViewObject::fun_getFloat32(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getFloat32Impl>(cx, args);
}

bool DataViewObject::getFloat64Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  double val;
  if (!read(cx, thisView, args, &val)) {
    return false;
  }

  args.rval().setDouble(CanonicalizeNaN(val));
  return true;
}

bool DataViewObject::fun_getFloat64(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, getFloat64Impl>(cx, args);
}

bool DataViewObject::setInt8Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<int8_t>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setInt8(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setInt8Impl>(cx, args);
}

bool DataViewObject::setUint8Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<uint8_t>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setUint8(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setUint8Impl>(cx, args);
}

bool DataViewObject::setInt16Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<int16_t>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setInt16(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setInt16Impl>(cx, args);
}

bool DataViewObject::setUint16Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<uint16_t>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setUint16(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setUint16Impl>(cx, args);
}

bool DataViewObject::setInt32Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<int32_t>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setInt32(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setInt32Impl>(cx, args);
}

bool DataViewObject::setUint32Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<uint32_t>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setUint32(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setUint32Impl>(cx, args);
}

// BigInt proposal 7.28
// DataView.prototype.setBigInt64 ( byteOffset, value [ , littleEndian ] )
bool DataViewObject::setBigInt64Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<int64_t>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setBigInt64(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setBigInt64Impl>(cx, args);
}

// BigInt proposal 7.29
// DataView.prototype.setBigUint64 ( byteOffset, value [ , littleEndian ] )
bool DataViewObject::setBigUint64Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<uint64_t>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setBigUint64(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setBigUint64Impl>(cx, args);
}

bool DataViewObject::setFloat16Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<float16>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setFloat16(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setFloat16Impl>(cx, args);
}

bool DataViewObject::setFloat32Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<float>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setFloat32(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setFloat32Impl>(cx, args);
}

bool DataViewObject::setFloat64Impl(JSContext* cx, const CallArgs& args) {
  MOZ_ASSERT(IsDataView(args.thisv()));

  Rooted<DataViewObject*> thisView(
      cx, &args.thisv().toObject().as<DataViewObject>());

  if (!write<double>(cx, thisView, args)) {
    return false;
  }
  args.rval().setUndefined();
  return true;
}

bool DataViewObject::fun_setFloat64(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, setFloat64Impl>(cx, args);
}

bool DataViewObject::bufferGetterImpl(JSContext* cx, const CallArgs& args) {
  auto* thisView = &args.thisv().toObject().as<DataViewObject>();
  args.rval().set(thisView->bufferValue());
  return true;
}

bool DataViewObject::bufferGetter(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, bufferGetterImpl>(cx, args);
}

bool DataViewObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args) {
  auto* thisView = &args.thisv().toObject().as<DataViewObject>();

  // Step 6.
  auto byteLength = thisView->byteLength();
  if (MOZ_UNLIKELY(!byteLength)) {
    ReportOutOfBounds(cx, thisView);
    return false;
  }

  // Step 7.
  args.rval().set(NumberValue(*byteLength));
  return true;
}

bool DataViewObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, byteLengthGetterImpl>(cx, args);
}

bool DataViewObject::byteOffsetGetterImpl(JSContext* cx, const CallArgs& args) {
  auto* thisView = &args.thisv().toObject().as<DataViewObject>();

  // Step 6.
  auto byteOffset = thisView->byteOffset();
  if (MOZ_UNLIKELY(!byteOffset)) {
    ReportOutOfBounds(cx, thisView);
    return false;
  }

  // Step 7.
  args.rval().set(NumberValue(*byteOffset));
  return true;
}

bool DataViewObject::byteOffsetGetter(JSContext* cx, unsigned argc, Value* vp) {
  CallArgs args = CallArgsFromVp(argc, vp);
  return CallNonGenericMethod<IsDataView, byteOffsetGetterImpl>(cx, args);
}

static const JSClassOps DataViewObjectClassOps = {
    nullptr,                       // addProperty
    nullptr,                       // delProperty
    nullptr,                       // enumerate
    nullptr,                       // newEnumerate
    nullptr,                       // resolve
    nullptr,                       // mayResolve
    nullptr,                       // finalize
    nullptr,                       // call
    nullptr,                       // construct
    ArrayBufferViewObject::trace,  // trace
};

static JSObject* CreateDataViewPrototype(JSContext* cx, JSProtoKey key) {
  return GlobalObject::createBlankPrototype(cx, cx->global(),
                                            &DataViewObject::protoClass_);
}

const ClassSpec DataViewObject::classSpec_ = {
    GenericCreateConstructor<DataViewObject::construct, 1,
                             gc::AllocKind::FUNCTION>,
    CreateDataViewPrototype,
    nullptr,
    nullptr,
    DataViewObject::methods,
    DataViewObject::properties,
};

const JSClass FixedLengthDataViewObject::class_ = {
    "DataView",
    JSCLASS_HAS_RESERVED_SLOTS(FixedLengthDataViewObject::RESERVED_SLOTS) |
        JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
    &DataViewObjectClassOps,
    &DataViewObject::classSpec_,
};

const JSClass ResizableDataViewObject::class_ = {
    "DataView",
    JSCLASS_HAS_RESERVED_SLOTS(ResizableDataViewObject::RESERVED_SLOTS) |
        JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
    &DataViewObjectClassOps,
    &DataViewObject::classSpec_,
};

const JSClass* const JS::DataView::FixedLengthClassPtr =
    &FixedLengthDataViewObject::class_;
const JSClass* const JS::DataView::ResizableClassPtr =
    &ResizableDataViewObject::class_;

const JSClass DataViewObject::protoClass_ = {
    "DataView.prototype",
    JSCLASS_HAS_CACHED_PROTO(JSProto_DataView),
    JS_NULL_CLASS_OPS,
    &DataViewObject::classSpec_,
};

const JSFunctionSpec DataViewObject::methods[] = {
    JS_INLINABLE_FN("getInt8", DataViewObject::fun_getInt8, 1, 0,
                    DataViewGetInt8),
    JS_INLINABLE_FN("getUint8", DataViewObject::fun_getUint8, 1, 0,
                    DataViewGetUint8),
    JS_INLINABLE_FN("getInt16", DataViewObject::fun_getInt16, 1, 0,
                    DataViewGetInt16),
    JS_INLINABLE_FN("getUint16", DataViewObject::fun_getUint16, 1, 0,
                    DataViewGetUint16),
    JS_INLINABLE_FN("getInt32", DataViewObject::fun_getInt32, 1, 0,
                    DataViewGetInt32),
    JS_INLINABLE_FN("getUint32", DataViewObject::fun_getUint32, 1, 0,
                    DataViewGetUint32),
    JS_INLINABLE_FN("getFloat16", DataViewObject::fun_getFloat16, 1, 0,
                    DataViewGetFloat16),
    JS_INLINABLE_FN("getFloat32", DataViewObject::fun_getFloat32, 1, 0,
                    DataViewGetFloat32),
    JS_INLINABLE_FN("getFloat64", DataViewObject::fun_getFloat64, 1, 0,
                    DataViewGetFloat64),
    JS_INLINABLE_FN("getBigInt64", DataViewObject::fun_getBigInt64, 1, 0,
                    DataViewGetBigInt64),
    JS_INLINABLE_FN("getBigUint64", DataViewObject::fun_getBigUint64, 1, 0,
                    DataViewGetBigUint64),
    JS_INLINABLE_FN("setInt8", DataViewObject::fun_setInt8, 2, 0,
                    DataViewSetInt8),
    JS_INLINABLE_FN("setUint8", DataViewObject::fun_setUint8, 2, 0,
                    DataViewSetUint8),
    JS_INLINABLE_FN("setInt16", DataViewObject::fun_setInt16, 2, 0,
                    DataViewSetInt16),
    JS_INLINABLE_FN("setUint16", DataViewObject::fun_setUint16, 2, 0,
                    DataViewSetUint16),
    JS_INLINABLE_FN("setInt32", DataViewObject::fun_setInt32, 2, 0,
                    DataViewSetInt32),
    JS_INLINABLE_FN("setUint32", DataViewObject::fun_setUint32, 2, 0,
                    DataViewSetUint32),
    JS_INLINABLE_FN("setFloat16", DataViewObject::fun_setFloat16, 2, 0,
                    DataViewSetFloat16),
    JS_INLINABLE_FN("setFloat32", DataViewObject::fun_setFloat32, 2, 0,
                    DataViewSetFloat32),
    JS_INLINABLE_FN("setFloat64", DataViewObject::fun_setFloat64, 2, 0,
                    DataViewSetFloat64),
    JS_INLINABLE_FN("setBigInt64", DataViewObject::fun_setBigInt64, 2, 0,
                    DataViewSetBigInt64),
    JS_INLINABLE_FN("setBigUint64", DataViewObject::fun_setBigUint64, 2, 0,
                    DataViewSetBigUint64),
    JS_FS_END,
};

const JSPropertySpec DataViewObject::properties[] = {
    JS_PSG("buffer", DataViewObject::bufferGetter, 0),
    JS_PSG("byteLength", DataViewObject::byteLengthGetter, 0),
    JS_PSG("byteOffset", DataViewObject::byteOffsetGetter, 0),
    JS_STRING_SYM_PS(toStringTag, "DataView", JSPROP_READONLY),
    JS_PS_END,
};

JS_PUBLIC_API JSObject* JS_NewDataView(JSContext* cx, HandleObject buffer,
                                       size_t byteOffset, size_t byteLength) {
  JSProtoKey key = JSProto_DataView;
  RootedObject constructor(cx, GlobalObject::getOrCreateConstructor(cx, key));
  if (!constructor) {
    return nullptr;
  }

  FixedConstructArgs<3> cargs(cx);

  cargs[0].setObject(*buffer);
  cargs[1].setNumber(byteOffset);
  cargs[2].setNumber(byteLength);

  RootedValue fun(cx, ObjectValue(*constructor));
  RootedObject obj(cx);
  if (!Construct(cx, fun, cargs, fun, &obj)) {
    return nullptr;
  }
  return obj;
}

JSObject* js::NewDataView(JSContext* cx, HandleObject buffer,
                          size_t byteOffset) {
  JSProtoKey key = JSProto_DataView;
  RootedObject constructor(cx, GlobalObject::getOrCreateConstructor(cx, key));
  if (!constructor) {
    return nullptr;
  }

  FixedConstructArgs<2> cargs(cx);

  cargs[0].setObject(*buffer);
  cargs[1].setNumber(byteOffset);

  RootedValue fun(cx, ObjectValue(*constructor));
  RootedObject obj(cx);
  if (!Construct(cx, fun, cargs, fun, &obj)) {
    return nullptr;
  }
  return obj;
}

Messung V0.5
C=90 H=98 G=94

¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge