mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 13:58:49 +00:00
Support DataView on shared array buffers
This commit is contained in:
@@ -66,6 +66,23 @@ assertEq(sharedTracking.length, 8);
|
||||
sharedTracking[6] = 33;
|
||||
assertEq(new Uint8Array(gsab)[6], 33);
|
||||
|
||||
var sharedDv = new DataView(gsab);
|
||||
assertEq(sharedDv.buffer, gsab);
|
||||
assertEq(sharedDv.byteOffset, 0);
|
||||
assertEq(sharedDv.byteLength, 8);
|
||||
sharedDv.setUint8(7, 99);
|
||||
assertEq(sharedTracking[7], 99);
|
||||
gsab.grow(12);
|
||||
assertEq(sharedDv.byteLength, 12);
|
||||
assertEq(sharedDv.getUint8(7), 99);
|
||||
|
||||
var fixedSharedDv = new DataView(gsab, 4, 2);
|
||||
assertEq(fixedSharedDv.byteOffset, 4);
|
||||
assertEq(fixedSharedDv.byteLength, 2);
|
||||
gsab.grow(16);
|
||||
assertEq(fixedSharedDv.byteOffset, 4);
|
||||
assertEq(fixedSharedDv.byteLength, 2);
|
||||
|
||||
function readLength(view) {
|
||||
return view.length;
|
||||
}
|
||||
|
||||
@@ -1474,7 +1474,7 @@ ArrayBufferObject::createEmpty(JSContext* cx)
|
||||
bool
|
||||
ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
|
||||
MOZ_ASSERT(IsAnyArrayBuffer(args.thisv()));
|
||||
|
||||
/*
|
||||
* This method is only called for |DataView(alienBuf, ...)| which calls
|
||||
@@ -1487,7 +1487,8 @@ ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args
|
||||
uint32_t byteOffset = args[0].toPrivateUint32();
|
||||
uint32_t byteLength = args[1].toPrivateUint32();
|
||||
bool lengthTracking = args[3].toBoolean();
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &args.thisv().toObject().as<ArrayBufferObject>());
|
||||
Rooted<ArrayBufferObjectMaybeShared*> buffer(cx,
|
||||
&args.thisv().toObject().as<ArrayBufferObjectMaybeShared>());
|
||||
|
||||
/*
|
||||
* Pop off the passed-along prototype and delegate to normal DataViewObject
|
||||
@@ -1505,7 +1506,7 @@ bool
|
||||
ArrayBufferObject::createDataViewForThis(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
|
||||
return CallNonGenericMethod<IsAnyArrayBuffer, createDataViewForThisImpl>(cx, args);
|
||||
}
|
||||
|
||||
/* static */ ArrayBufferObject::BufferContents
|
||||
@@ -1926,6 +1927,8 @@ ArrayBufferViewObject::dataPointerUnshared(const JS::AutoRequireNoGC& nogc)
|
||||
bool
|
||||
ArrayBufferViewObject::isSharedMemory()
|
||||
{
|
||||
if (is<DataViewObject>())
|
||||
return as<DataViewObject>().isSharedMemory();
|
||||
if (is<TypedArrayObject>())
|
||||
return as<TypedArrayObject>().isSharedMemory();
|
||||
return false;
|
||||
@@ -1957,7 +1960,7 @@ ArrayBufferViewObject::bufferObject(JSContext* cx, Handle<ArrayBufferViewObject*
|
||||
return thisObject->as<TypedArrayObject>().bufferEither();
|
||||
}
|
||||
MOZ_ASSERT(thisObject->is<DataViewObject>());
|
||||
return &thisObject->as<DataViewObject>().arrayBuffer();
|
||||
return &thisObject->as<DataViewObject>().arrayBufferEither();
|
||||
}
|
||||
|
||||
/* JS Friend API */
|
||||
@@ -2208,7 +2211,7 @@ JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoChe
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
if (obj->is<DataViewObject>()) {
|
||||
*isSharedMemory = false;
|
||||
*isSharedMemory = obj->as<DataViewObject>().isSharedMemory();
|
||||
return obj->as<DataViewObject>().dataPointer();
|
||||
}
|
||||
TypedArrayObject& ta = obj->as<TypedArrayObject>();
|
||||
@@ -2278,7 +2281,7 @@ js::GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSha
|
||||
: obj->as<TypedArrayObject>().byteLength();
|
||||
|
||||
if (obj->is<DataViewObject>()) {
|
||||
*isSharedMemory = false;
|
||||
*isSharedMemory = obj->as<DataViewObject>().isSharedMemory();
|
||||
*data = static_cast<uint8_t*>(obj->as<DataViewObject>().dataPointer());
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -82,7 +82,7 @@ ArrayBufferObjectMaybeShared& AsAnyArrayBuffer(HandleValue val);
|
||||
class ArrayBufferObjectMaybeShared : public NativeObject
|
||||
{
|
||||
public:
|
||||
uint32_t byteLength() {
|
||||
uint32_t byteLength() const {
|
||||
return AnyArrayBufferByteLength(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "builtin/MapObject.h"
|
||||
#include "js/Date.h"
|
||||
#include "js/GCHashTable.h"
|
||||
#include "vm/ArrayBufferObject-inl.h"
|
||||
#include "vm/SavedFrame.h"
|
||||
#include "vm/SharedArrayObject.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
||||
@@ -1874,7 +1874,7 @@ DataViewNewObjectKind(JSContext* cx, uint32_t byteLength, JSObject* proto)
|
||||
|
||||
DataViewObject*
|
||||
DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
Handle<ArrayBufferObject*> arrayBuffer, JSObject* protoArg,
|
||||
Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, JSObject* protoArg,
|
||||
bool lengthTracking)
|
||||
{
|
||||
if (arrayBuffer->isDetached()) {
|
||||
@@ -1885,7 +1885,6 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
MOZ_ASSERT(byteOffset <= INT32_MAX);
|
||||
MOZ_ASSERT(byteLength <= INT32_MAX);
|
||||
MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX);
|
||||
MOZ_ASSERT(!arrayBuffer || !arrayBuffer->is<SharedArrayBufferObject>());
|
||||
|
||||
RootedObject proto(cx, protoArg);
|
||||
RootedObject obj(cx);
|
||||
@@ -1921,18 +1920,25 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
Int32Value(lengthTracking ? TypedArrayObject::LENGTH_TRACKING
|
||||
: int32_t(byteLength)));
|
||||
dvobj.setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*arrayBuffer));
|
||||
dvobj.initPrivate(arrayBuffer->dataPointer() + byteOffset);
|
||||
auto dataPointer = arrayBuffer->dataPointerEither();
|
||||
dvobj.initPrivate((dataPointer + byteOffset).unwrap(/*safe - stored as private data*/));
|
||||
|
||||
// Include a barrier if the data view's data pointer is in the nursery, as
|
||||
// is done for typed arrays.
|
||||
if (!IsInsideNursery(obj) && cx->runtime()->gc.nursery.isInside(arrayBuffer->dataPointer()))
|
||||
if (arrayBuffer->is<ArrayBufferObject>() &&
|
||||
!IsInsideNursery(obj) &&
|
||||
cx->runtime()->gc.nursery.isInside(dataPointer))
|
||||
{
|
||||
cx->runtime()->gc.storeBuffer.putWholeCell(obj);
|
||||
}
|
||||
|
||||
// Verify that the private slot is at the expected place
|
||||
MOZ_ASSERT(dvobj.numFixedSlots() == TypedArrayObject::DATA_SLOT);
|
||||
|
||||
if (!arrayBuffer->addView(cx, &dvobj))
|
||||
return nullptr;
|
||||
if (arrayBuffer->is<ArrayBufferObject>()) {
|
||||
if (!arrayBuffer->as<ArrayBufferObject>().addView(cx, &dvobj))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &dvobj;
|
||||
}
|
||||
@@ -1942,28 +1948,35 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons
|
||||
uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr,
|
||||
bool* lengthTrackingPtr)
|
||||
{
|
||||
if (!IsArrayBuffer(bufobj)) {
|
||||
if (!IsAnyArrayBuffer(bufobj)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
|
||||
"DataView", "ArrayBuffer", bufobj->getClass()->name);
|
||||
"DataView", "ArrayBuffer or SharedArrayBuffer",
|
||||
bufobj->getClass()->name);
|
||||
return false;
|
||||
}
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
|
||||
Rooted<ArrayBufferObjectMaybeShared*> buffer(cx, &bufobj->as<ArrayBufferObjectMaybeShared>());
|
||||
uint32_t byteOffset = 0;
|
||||
uint32_t byteLength = buffer->byteLength();
|
||||
bool lengthTracking = buffer->isResizable() && !args.hasDefined(2);
|
||||
bool isResizableOrGrowable =
|
||||
(buffer->is<ArrayBufferObject>() && buffer->as<ArrayBufferObject>().isResizable()) ||
|
||||
(buffer->is<SharedArrayBufferObject>() &&
|
||||
buffer->as<SharedArrayBufferObject>().isGrowable());
|
||||
bool lengthTracking = isResizableOrGrowable && !args.hasDefined(2);
|
||||
|
||||
if (args.length() > 1) {
|
||||
if (!ToUint32(cx, args[1], &byteOffset))
|
||||
uint64_t offset;
|
||||
if (!ToIndex(cx, args[1], &offset))
|
||||
return false;
|
||||
if (byteOffset > INT32_MAX) {
|
||||
if (offset > INT32_MAX) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
|
||||
"1");
|
||||
return false;
|
||||
}
|
||||
byteOffset = uint32_t(offset);
|
||||
}
|
||||
|
||||
if (buffer->isDetached()) {
|
||||
if (buffer->is<ArrayBufferObject>() && buffer->as<ArrayBufferObject>().isDetached()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return false;
|
||||
}
|
||||
@@ -1977,16 +1990,18 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons
|
||||
|
||||
if (args.get(2).isUndefined()) {
|
||||
byteLength -= byteOffset;
|
||||
lengthTracking = buffer->isResizable();
|
||||
lengthTracking = isResizableOrGrowable;
|
||||
} else {
|
||||
if (!ToUint32(cx, args[2], &byteLength))
|
||||
uint64_t viewByteLength;
|
||||
if (!ToIndex(cx, args[2], &viewByteLength))
|
||||
return false;
|
||||
lengthTracking = false;
|
||||
if (byteLength > INT32_MAX) {
|
||||
if (viewByteLength > INT32_MAX) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
|
||||
return false;
|
||||
}
|
||||
byteLength = uint32_t(viewByteLength);
|
||||
|
||||
MOZ_ASSERT(byteOffset + byteLength >= byteOffset,
|
||||
"can't overflow: both numbers are less than INT32_MAX");
|
||||
@@ -2026,7 +2041,7 @@ DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, con
|
||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
||||
return false;
|
||||
|
||||
Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
|
||||
Rooted<ArrayBufferObjectMaybeShared*> buffer(cx, &bufobj->as<ArrayBufferObjectMaybeShared>());
|
||||
JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto,
|
||||
lengthTracking);
|
||||
if (!obj)
|
||||
@@ -2226,7 +2241,7 @@ DataViewObject::read(JSContext* cx, Handle<DataViewObject*> obj,
|
||||
bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]);
|
||||
|
||||
// Steps 6-7.
|
||||
if (obj->arrayBuffer().isDetached()) {
|
||||
if (obj->arrayBufferEither().isDetached()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return false;
|
||||
}
|
||||
@@ -2325,7 +2340,7 @@ DataViewObject::write(JSContext* cx, Handle<DataViewObject*> obj,
|
||||
bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]);
|
||||
|
||||
// Steps 7-8.
|
||||
if (obj->arrayBuffer().isDetached()) {
|
||||
if (obj->arrayBufferEither().isDetached()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -532,7 +532,7 @@ class DataViewObject : public NativeObject
|
||||
friend bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args);
|
||||
static DataViewObject*
|
||||
create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength,
|
||||
Handle<ArrayBufferObject*> arrayBuffer, JSObject* proto,
|
||||
Handle<ArrayBufferObjectMaybeShared*> arrayBuffer, JSObject* proto,
|
||||
bool lengthTracking = false);
|
||||
|
||||
public:
|
||||
@@ -560,12 +560,18 @@ class DataViewObject : public NativeObject
|
||||
if (isOutOfBounds())
|
||||
return 0;
|
||||
if (isLengthTracking())
|
||||
return arrayBuffer().byteLength() - byteOffsetMaybeOutOfBounds();
|
||||
return arrayBufferEither().byteLength() - byteOffsetMaybeOutOfBounds();
|
||||
return fixedByteLengthMaybeOutOfBounds();
|
||||
}
|
||||
|
||||
ArrayBufferObject& arrayBuffer() const {
|
||||
return bufferValue(const_cast<DataViewObject*>(this)).toObject().as<ArrayBufferObject>();
|
||||
ArrayBufferObjectMaybeShared& arrayBufferEither() const {
|
||||
return bufferValue(const_cast<DataViewObject*>(this)).
|
||||
toObject().as<ArrayBufferObjectMaybeShared>();
|
||||
}
|
||||
|
||||
bool isSharedMemory() const {
|
||||
return bufferValue(const_cast<DataViewObject*>(this)).
|
||||
toObject().is<SharedArrayBufferObject>();
|
||||
}
|
||||
|
||||
void* dataPointer() const {
|
||||
@@ -590,7 +596,7 @@ class DataViewObject : public NativeObject
|
||||
}
|
||||
|
||||
bool isOutOfBounds() const {
|
||||
const ArrayBufferObject& buffer = arrayBuffer();
|
||||
const ArrayBufferObjectMaybeShared& buffer = arrayBufferEither();
|
||||
if (buffer.isDetached())
|
||||
return true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user