ported from UXP: Implement ES2024 ArrayBuffer transfer APIs (3be309fa)

This commit is contained in:
2026-05-20 09:52:18 +08:00
parent 5ea63a6333
commit 25d353174e
4 changed files with 428 additions and 10 deletions
@@ -0,0 +1,68 @@
// |reftest| skip-if(!ArrayBuffer.prototype.transfer)
var fixed = new ArrayBuffer(4);
assertEq(fixed.byteLength, 4);
assertEq(fixed.maxByteLength, 4);
assertEq(fixed.resizable, false);
assertEq(fixed.detached, false);
assertThrowsInstanceOf(() => fixed.resize(2), TypeError);
assertEq(ArrayBuffer.prototype.transfer.length, 0);
assertEq(ArrayBuffer.prototype.transferToFixedLength.length, 0);
var resizeArgumentConverted = false;
assertThrowsInstanceOf(() => fixed.resize({ valueOf() { resizeArgumentConverted = true; return 1; } }),
TypeError);
assertEq(resizeArgumentConverted, false);
var resizable = new ArrayBuffer(4, { maxByteLength: 8 });
assertEq(resizable.byteLength, 4);
assertEq(resizable.maxByteLength, 8);
assertEq(resizable.resizable, true);
var bytes = new Uint8Array(resizable);
bytes[0] = 11;
bytes[3] = 44;
resizable.resize(6);
assertEq(resizable.byteLength, 6);
assertEq(new Uint8Array(resizable)[0], 11);
assertEq(new Uint8Array(resizable)[3], 44);
assertEq(new Uint8Array(resizable)[4], 0);
assertThrowsInstanceOf(() => resizable.resize(9), RangeError);
var source = new ArrayBuffer(4);
var sourceBytes = new Uint8Array(source);
sourceBytes[0] = 1;
sourceBytes[1] = 2;
var sourceView = new Uint8Array(source);
var moved = source.transfer(6);
assertEq(source.detached, true);
assertEq(source.byteLength, 0);
assertEq(source.maxByteLength, 0);
assertEq(sourceView.length, 0);
assertEq(moved.byteLength, 6);
assertEq(moved.resizable, false);
assertEq(moved.maxByteLength, 6);
assertEq(new Uint8Array(moved)[0], 1);
assertEq(new Uint8Array(moved)[1], 2);
assertEq(new Uint8Array(moved)[4], 0);
var resizableSource = new ArrayBuffer(4, { maxByteLength: 8 });
new Uint8Array(resizableSource)[0] = 7;
var resizableMoved = resizableSource.transfer();
assertEq(resizableSource.detached, true);
assertEq(resizableSource.resizable, true);
assertEq(resizableMoved.byteLength, 4);
assertEq(resizableMoved.maxByteLength, 8);
assertEq(resizableMoved.resizable, true);
assertEq(new Uint8Array(resizableMoved)[0], 7);
var fixedMoved = resizableMoved.transferToFixedLength(10);
assertEq(resizableMoved.detached, true);
assertEq(fixedMoved.byteLength, 10);
assertEq(fixedMoved.maxByteLength, 10);
assertEq(fixedMoved.resizable, false);
assertEq(new Uint8Array(fixedMoved)[0], 7);
assertThrowsInstanceOf(() => new ArrayBuffer(4, { maxByteLength: 3 }), RangeError);
if (typeof reportCompare === "function")
reportCompare(0, 0);
+326 -6
View File
@@ -22,6 +22,7 @@
# include <valgrind/memcheck.h>
#endif
#include <algorithm>
#include "jsapi.h"
#include "jsarray.h"
#include "jscntxt.h"
@@ -44,6 +45,7 @@
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
#include "vm/SharedArrayObject.h"
#include "vm/TypedArrayObject.h"
#include "vm/WrapperObject.h"
#include "wasm/WasmSignalHandlers.h"
#include "wasm/WasmTypes.h"
@@ -131,12 +133,18 @@ static const JSPropertySpec static_properties[] = {
static const JSFunctionSpec prototype_functions[] = {
JS_FN("resize", ArrayBufferObject::fun_resize, 1, 0),
JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0),
JS_FN("transfer", ArrayBufferObject::fun_transfer, 0, 0),
JS_FN("transferToFixedLength", ArrayBufferObject::fun_transferToFixedLength, 0, 0),
JS_FS_END
};
static const JSPropertySpec prototype_properties[] = {
JS_PSG("byteLength", ArrayBufferObject::byteLengthGetter, 0),
JS_PSG("detached", ArrayBufferObject::detachedGetter, 0),
JS_PSG("maxByteLength", ArrayBufferObject::maxByteLengthGetter, 0),
JS_PSG("resizable", ArrayBufferObject::resizableGetter, 0),
JS_STRING_SYM_PS(toStringTag, "ArrayBuffer", JSPROP_READONLY),
JS_PS_END
};
@@ -252,6 +260,52 @@ ArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
return CallNonGenericMethod<IsArrayBuffer, byteLengthGetterImpl>(cx, args);
}
MOZ_ALWAYS_INLINE bool
ArrayBufferObject::detachedGetterImpl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
args.rval().setBoolean(args.thisv().toObject().as<ArrayBufferObject>().isDetached());
return true;
}
bool
ArrayBufferObject::detachedGetter(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsArrayBuffer, detachedGetterImpl>(cx, args);
}
MOZ_ALWAYS_INLINE bool
ArrayBufferObject::maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
ArrayBufferObject& buffer = args.thisv().toObject().as<ArrayBufferObject>();
args.rval().setInt32(buffer.isDetached() ? 0 : int32_t(buffer.maxByteLength()));
return true;
}
bool
ArrayBufferObject::maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsArrayBuffer, maxByteLengthGetterImpl>(cx, args);
}
MOZ_ALWAYS_INLINE bool
ArrayBufferObject::resizableGetterImpl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
args.rval().setBoolean(args.thisv().toObject().as<ArrayBufferObject>().isResizable());
return true;
}
bool
ArrayBufferObject::resizableGetter(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsArrayBuffer, resizableGetterImpl>(cx, args);
}
/*
* ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
*/
@@ -264,6 +318,39 @@ ArrayBufferObject::fun_isView(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
GetArrayBufferMaxByteLengthOption(JSContext* cx, HandleValue options,
uint32_t byteLength, uint32_t* maxByteLength,
bool* resizable)
{
*maxByteLength = byteLength;
*resizable = false;
if (!options.isObject())
return true;
RootedObject opts(cx, &options.toObject());
RootedValue maxByteLengthValue(cx);
if (!GetProperty(cx, opts, opts, cx->names().maxByteLength, &maxByteLengthValue))
return false;
if (maxByteLengthValue.isUndefined())
return true;
uint64_t max;
if (!ToIndex(cx, maxByteLengthValue, &max))
return false;
if (max > INT32_MAX || max < byteLength) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
*maxByteLength = uint32_t(max);
*resizable = true;
return true;
}
// ES2017 draft 24.1.2.1
bool
ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
@@ -280,6 +367,15 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
return false;
// Step 3.
uint32_t maxByteLength;
bool resizable;
if (!GetArrayBufferMaxByteLengthOption(cx, args.get(1), uint32_t(byteLength),
&maxByteLength, &resizable))
{
return false;
}
// Step 4.
RootedObject proto(cx);
RootedObject newTarget(cx, &args.newTarget().toObject());
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
@@ -293,7 +389,8 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
}
// 24.1.1.1, steps 1 and 4-6.
JSObject* bufobj = create(cx, uint32_t(byteLength), proto);
JSObject* bufobj = create(cx, uint32_t(byteLength), BufferContents::createPlain(nullptr),
OwnsData, proto, GenericObject, maxByteLength, resizable);
if (!bufobj)
return false;
args.rval().setObject(*bufobj);
@@ -303,13 +400,57 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp)
static ArrayBufferObject::BufferContents
AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes)
{
uint8_t* p = cx->runtime()->pod_callocCanGC<uint8_t>(nbytes);
uint8_t* p = cx->runtime()->pod_callocCanGC<uint8_t>(nbytes ? nbytes : 1);
if (!p)
ReportOutOfMemory(cx);
return ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN>(p);
}
static bool
ReportArrayBufferNotResizable(JSContext* cx)
{
JS_ReportErrorASCII(cx, "ArrayBuffer is not resizable");
return false;
}
static bool
ReportArrayBufferCannotDetach(JSContext* cx)
{
JS_ReportErrorASCII(cx, "ArrayBuffer cannot be detached");
return false;
}
static bool
ReportArrayBufferLengthOutOfRange(JSContext* cx)
{
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
return false;
}
static bool
ArrayBufferViewFits(ArrayBufferViewObject* view, uint32_t newByteLength)
{
if (view->is<DataViewObject>()) {
DataViewObject& dataView = view->as<DataViewObject>();
uint32_t byteOffset = dataView.byteOffset();
uint32_t byteLength = dataView.byteLength();
return byteOffset <= newByteLength && byteLength <= newByteLength - byteOffset;
}
if (view->is<TypedArrayObject>()) {
TypedArrayObject& typedArray = view->as<TypedArrayObject>();
if (typedArray.isSharedMemory())
return true;
uint32_t byteOffset = typedArray.byteOffset();
uint32_t byteLength = typedArray.byteLength();
return byteOffset <= newByteLength && byteLength <= newByteLength - byteOffset;
}
// Outline typed objects don't have a recoverable fixed byte range here.
return false;
}
static void
NoteViewBufferWasDetached(ArrayBufferViewObject* view,
ArrayBufferObject::BufferContents newContents,
@@ -435,6 +576,173 @@ ArrayBufferObject::changeContents(JSContext* cx, BufferContents newContents,
changeViewContents(cx, firstView(), oldDataPointer, newContents);
}
void
ArrayBufferObject::changeContentsForResize(JSContext* cx, BufferContents newContents,
OwnsState ownsState, uint32_t newByteLength)
{
MOZ_RELEASE_ASSERT(!isWasm());
MOZ_ASSERT(!forInlineTypedObject());
uint8_t* oldDataPointer = dataPointer();
setNewData(cx->runtime()->defaultFreeOp(), newContents, ownsState);
auto& innerViews = cx->compartment()->innerViews.get();
if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
for (size_t i = 0; i < views->length(); i++) {
ArrayBufferViewObject* view = (*views)[i];
if (ArrayBufferViewFits(view, newByteLength))
changeViewContents(cx, view, oldDataPointer, newContents);
else
NoteViewBufferWasDetached(view, newContents, cx);
}
}
if (firstView()) {
if (ArrayBufferViewFits(firstView(), newByteLength))
changeViewContents(cx, firstView(), oldDataPointer, newContents);
else
NoteViewBufferWasDetached(firstView(), newContents, cx);
}
setByteLength(newByteLength);
}
static bool
ResizeArrayBuffer(JSContext* cx, Handle<ArrayBufferObject*> buffer, uint32_t newByteLength)
{
if (!buffer->isResizable())
return ReportArrayBufferNotResizable(cx);
if (buffer->isDetached()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
return false;
}
if (newByteLength > buffer->maxByteLength())
return ReportArrayBufferLengthOutOfRange(cx);
if (!buffer->isPlain() || buffer->isPreparedForAsmJS() || buffer->forInlineTypedObject())
return ReportArrayBufferCannotDetach(cx);
if (newByteLength == buffer->byteLength())
return true;
ArrayBufferObject::BufferContents newContents = AllocateArrayBufferContents(cx, newByteLength);
if (!newContents)
return false;
uint32_t copyLength = std::min(newByteLength, buffer->byteLength());
if (copyLength > 0)
memcpy(newContents.data(), buffer->dataPointer(), copyLength);
buffer->changeContentsForResize(cx, newContents, ArrayBufferObject::OwnsData, newByteLength);
return true;
}
bool
ArrayBufferObject::fun_resize_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
Rooted<ArrayBufferObject*> buffer(cx, &args.thisv().toObject().as<ArrayBufferObject>());
if (!buffer->isResizable())
return ReportArrayBufferNotResizable(cx);
uint64_t newByteLength;
if (!ToIndex(cx, args.get(0), &newByteLength))
return false;
if (newByteLength > INT32_MAX)
return ReportArrayBufferLengthOutOfRange(cx);
if (!ResizeArrayBuffer(cx, buffer, uint32_t(newByteLength)))
return false;
args.rval().setUndefined();
return true;
}
bool
ArrayBufferObject::fun_resize(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsArrayBuffer, fun_resize_impl>(cx, args);
}
static bool
ArrayBufferTransfer(JSContext* cx, const CallArgs& args, bool preserveResizability)
{
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
Rooted<ArrayBufferObject*> buffer(cx, &args.thisv().toObject().as<ArrayBufferObject>());
uint32_t newByteLength = buffer->byteLength();
if (args.hasDefined(0)) {
uint64_t newLength;
if (!ToIndex(cx, args.get(0), &newLength))
return false;
if (newLength > INT32_MAX)
return ReportArrayBufferLengthOutOfRange(cx);
newByteLength = uint32_t(newLength);
}
if (buffer->isDetached()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
return false;
}
if (buffer->isWasm() || buffer->isPreparedForAsmJS())
return ReportArrayBufferCannotDetach(cx);
bool newResizable = preserveResizability && buffer->isResizable();
uint32_t newMaxByteLength = newResizable ? buffer->maxByteLength() : newByteLength;
if (newResizable && newByteLength > newMaxByteLength)
return ReportArrayBufferLengthOutOfRange(cx);
Rooted<ArrayBufferObject*> newBuffer(cx,
ArrayBufferObject::create(cx, newByteLength, ArrayBufferObject::BufferContents::createPlain(nullptr),
ArrayBufferObject::OwnsData, nullptr, GenericObject,
newMaxByteLength, newResizable));
if (!newBuffer)
return false;
uint32_t copyLength = std::min(newByteLength, buffer->byteLength());
if (copyLength > 0)
memcpy(newBuffer->dataPointer(), buffer->dataPointer(), copyLength);
ArrayBufferObject::BufferContents detachedContents =
buffer->hasStealableContents() ? ArrayBufferObject::BufferContents::createPlain(nullptr)
: buffer->contents();
ArrayBufferObject::detach(cx, buffer, detachedContents);
args.rval().setObject(*newBuffer);
return true;
}
bool
ArrayBufferObject::fun_transfer_impl(JSContext* cx, const CallArgs& args)
{
return ArrayBufferTransfer(cx, args, true);
}
bool
ArrayBufferObject::fun_transfer(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsArrayBuffer, fun_transfer_impl>(cx, args);
}
bool
ArrayBufferObject::fun_transferToFixedLength_impl(JSContext* cx, const CallArgs& args)
{
return ArrayBufferTransfer(cx, args, false);
}
bool
ArrayBufferObject::fun_transferToFixedLength(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsArrayBuffer, fun_transferToFixedLength_impl>(cx, args);
}
/*
* Wasm Raw Buf Linear Memory Structure
*
@@ -888,6 +1196,14 @@ ArrayBufferObject::byteLength() const
return getSlot(BYTE_LENGTH_SLOT).toInt32();
}
uint32_t
ArrayBufferObject::maxByteLength() const
{
if (!isResizable())
return byteLength();
return getSlot(MAX_BYTE_LENGTH_SLOT).toInt32();
}
void
ArrayBufferObject::setByteLength(uint32_t length)
{
@@ -1036,9 +1352,12 @@ ArrayBufferObject*
ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents contents,
OwnsState ownsState /* = OwnsData */,
HandleObject proto /* = nullptr */,
NewObjectKind newKind /* = GenericObject */)
NewObjectKind newKind /* = GenericObject */,
uint32_t maxByteLength /* = 0 */,
bool resizable /* = false */)
{
MOZ_ASSERT_IF(contents.kind() == MAPPED, contents);
MOZ_ASSERT_IF(resizable, maxByteLength >= nbytes);
// 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
// Refuse to allocate too large buffers, currently limited to ~2 GiB.
@@ -1069,7 +1388,7 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content
MOZ_ASSERT(ownsState == OwnsData);
size_t usableSlots = NativeObject::MAX_FIXED_SLOTS - reservedSlots;
if (nbytes <= usableSlots * sizeof(Value)) {
int newSlots = (nbytes - 1) / sizeof(Value) + 1;
int newSlots = nbytes == 0 ? 0 : (nbytes - 1) / sizeof(Value) + 1;
MOZ_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value)));
nslots = reservedSlots + newSlots;
contents = BufferContents::createPlain(nullptr);
@@ -1099,9 +1418,10 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content
if (!contents) {
void* data = obj->inlineDataPointer();
memset(data, 0, nbytes);
obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData);
obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData,
maxByteLength, resizable);
} else {
obj->initialize(nbytes, contents, ownsState);
obj->initialize(nbytes, contents, ownsState, maxByteLength, resizable);
}
return obj;
+33 -4
View File
@@ -128,15 +128,22 @@ typedef MutableHandle<ArrayBufferObjectMaybeShared*> MutableHandleArrayBufferObj
class ArrayBufferObject : public ArrayBufferObjectMaybeShared
{
static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args);
static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args);
static bool resizableGetterImpl(JSContext* cx, const CallArgs& args);
static bool detachedGetterImpl(JSContext* cx, const CallArgs& args);
static bool fun_slice_impl(JSContext* cx, const CallArgs& args);
static bool fun_resize_impl(JSContext* cx, const CallArgs& args);
static bool fun_transfer_impl(JSContext* cx, const CallArgs& args);
static bool fun_transferToFixedLength_impl(JSContext* cx, const CallArgs& args);
public:
static const uint8_t DATA_SLOT = 0;
static const uint8_t BYTE_LENGTH_SLOT = 1;
static const uint8_t FIRST_VIEW_SLOT = 2;
static const uint8_t FLAGS_SLOT = 3;
static const uint8_t MAX_BYTE_LENGTH_SLOT = 4;
static const uint8_t RESERVED_SLOTS = 4;
static const uint8_t RESERVED_SLOTS = 5;
static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
@@ -189,7 +196,11 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
// This PLAIN or WASM buffer has been prepared for asm.js and cannot
// henceforth be transferred/detached.
FOR_ASMJS = 0x40
FOR_ASMJS = 0x40,
// This buffer was created with [[ArrayBufferMaxByteLength]] and can
// be resized up to that maximum.
RESIZABLE = 0x80
};
static_assert(JS_ARRAYBUFFER_DETACHED_FLAG == DETACHED,
@@ -231,8 +242,14 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
static const Class protoClass_;
static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
static bool maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp);
static bool resizableGetter(JSContext* cx, unsigned argc, Value* vp);
static bool detachedGetter(JSContext* cx, unsigned argc, Value* vp);
static bool fun_slice(JSContext* cx, unsigned argc, Value* vp);
static bool fun_resize(JSContext* cx, unsigned argc, Value* vp);
static bool fun_transfer(JSContext* cx, unsigned argc, Value* vp);
static bool fun_transferToFixedLength(JSContext* cx, unsigned argc, Value* vp);
static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);
@@ -244,7 +261,9 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
BufferContents contents,
OwnsState ownsState = OwnsData,
HandleObject proto = nullptr,
NewObjectKind newKind = GenericObject);
NewObjectKind newKind = GenericObject,
uint32_t maxByteLength = 0,
bool resizable = false);
static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes,
HandleObject proto = nullptr,
NewObjectKind newKind = GenericObject);
@@ -291,6 +310,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
void setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState);
void changeContents(JSContext* cx, BufferContents newContents, OwnsState ownsState);
void changeContentsForResize(JSContext* cx, BufferContents newContents,
OwnsState ownsState, uint32_t newByteLength);
// Detach this buffer from its original memory. (This necessarily makes
// views of this buffer unusable for modifying that original memory.)
@@ -308,6 +329,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
uint8_t* dataPointer() const;
SharedMem<uint8_t*> dataPointerShared() const;
uint32_t byteLength() const;
uint32_t maxByteLength() const;
BufferContents contents() const {
return BufferContents(dataPointer(), bufferKind());
@@ -331,6 +353,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
bool isWasm() const { return bufferKind() == WASM; }
bool isMapped() const { return bufferKind() == MAPPED; }
bool isDetached() const { return flags() & DETACHED; }
bool isResizable() const { return flags() & RESIZABLE; }
bool isPreparedForAsmJS() const { return flags() & FOR_ASMJS; }
// WebAssembly support:
@@ -388,12 +411,17 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
void setIsDetached() { setFlags(flags() | DETACHED); }
void setIsPreparedForAsmJS() { setFlags(flags() | FOR_ASMJS); }
void setIsResizable() { setFlags(flags() | RESIZABLE); }
void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) {
void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState,
uint32_t maxByteLength = 0, bool resizable = false) {
setByteLength(byteLength);
setFlags(0);
setFixedSlot(MAX_BYTE_LENGTH_SLOT, Int32Value(maxByteLength ? maxByteLength : byteLength));
setFirstView(nullptr);
setDataPointer(contents, ownsState);
if (resizable)
setIsResizable();
}
// Note: initialize() may be called after initEmpty(); initEmpty() must
@@ -401,6 +429,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared
void initEmpty() {
setByteLength(0);
setFlags(0);
setFixedSlot(MAX_BYTE_LENGTH_SLOT, Int32Value(0));
setFirstView(nullptr);
setDataPointer(BufferContents::createPlain(nullptr), DoesntOwnData);
}
+1
View File
@@ -247,6 +247,7 @@
macro(lookupSetter, lookupSetter, "__lookupSetter__") \
macro(MapConstructorInit, MapConstructorInit, "MapConstructorInit") \
macro(MapIterator, MapIterator, "Map Iterator") \
macro(maxByteLength, maxByteLength, "maxByteLength") \
macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \
macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \
macro(message, message, "message") \