Skip to content

Commit

Permalink
Bug 1842773 - Part 8: Implement ArrayBuffer.prototype.resize method. …
Browse files Browse the repository at this point in the history
…r=sfink

Resizing simply adjusts the byte-length slot and sets the memory to
zero if the array is shrunk.

Differential Revision: https://phabricator.services.mozilla.com/D183324
  • Loading branch information
anba committed Jan 26, 2024
1 parent 8e6a95c commit df80812
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
81 changes: 81 additions & 0 deletions js/src/vm/ArrayBufferObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,9 @@ static const JSPropertySpec arraybuffer_properties[] = {

static const JSFunctionSpec arraybuffer_proto_functions[] = {
JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0),
#ifdef NIGHTLY_BUILD
JS_FN("resize", ArrayBufferObject::resize, 1, 0),
#endif
JS_FN("transfer", ArrayBufferObject::transfer, 0, 0),
JS_FN("transferToFixedLength", ArrayBufferObject::transferToFixedLength, 0,
0),
Expand Down Expand Up @@ -423,6 +426,12 @@ static bool IsArrayBuffer(HandleValue v) {
return v.isObject() && v.toObject().is<ArrayBufferObject>();
}

#ifdef NIGHTLY_BUILD
static bool IsResizableArrayBuffer(HandleValue v) {
return v.isObject() && v.toObject().is<ResizableArrayBufferObject>();
}
#endif

MOZ_ALWAYS_INLINE bool ArrayBufferObject::byteLengthGetterImpl(
JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsArrayBuffer(args.thisv()));
Expand Down Expand Up @@ -643,6 +652,58 @@ bool ArrayBufferObject::transferToFixedLength(JSContext* cx, unsigned argc,
args);
}

#ifdef NIGHTLY_BUILD
/**
* ArrayBuffer.prototype.resize ( newLength )
*
* https://tc39.es/ecma262/#sec-arraybuffer.prototype.resize
*/
bool ArrayBufferObject::resizeImpl(JSContext* cx, const CallArgs& args) {
MOZ_ASSERT(IsResizableArrayBuffer(args.thisv()));

Rooted<ResizableArrayBufferObject*> obj(
cx, &args.thisv().toObject().as<ResizableArrayBufferObject>());

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

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

// Step 6.
if (newByteLength > obj->maxByteLength()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_ARRAYBUFFER_LENGTH_LARGER_THAN_MAXIMUM);
return false;
}

// Steps 7-15.
obj->resize(size_t(newByteLength));

// Step 16.
args.rval().setUndefined();
return true;
}

/**
* ArrayBuffer.prototype.resize ( newLength )
*
* https://tc39.es/ecma262/#sec-arraybuffer.prototype.resize
*/
bool ArrayBufferObject::resize(JSContext* cx, unsigned argc, Value* vp) {
// Steps 1-3.
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsResizableArrayBuffer, resizeImpl>(cx, args);
}
#endif

/*
* ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1
*/
Expand Down Expand Up @@ -846,6 +907,26 @@ void ArrayBufferObject::detach(JSContext* cx,
}
}

void ResizableArrayBufferObject::resize(size_t newByteLength) {
MOZ_ASSERT(!isPreparedForAsmJS());
MOZ_ASSERT(!isWasm());
MOZ_ASSERT(!isDetached());
MOZ_ASSERT(isResizable());
MOZ_ASSERT(newByteLength <= maxByteLength());

// Clear the bytes between `data[newByteLength..oldByteLength]` when
// shrinking the buffer. We don't need to clear any bytes when growing the
// buffer, because the new space was either initialized to zero when creating
// the buffer, or a prior shrink zeroed it out here.
size_t oldByteLength = byteLength();
if (newByteLength < oldByteLength) {
size_t nbytes = oldByteLength - newByteLength;
memset(dataPointer() + newByteLength, 0, nbytes);
}

setByteLength(newByteLength);
}

/* clang-format off */
/*
* [SMDOC] WASM Linear Memory structure
Expand Down
6 changes: 6 additions & 0 deletions js/src/vm/ArrayBufferObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared {
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 resizeImpl(JSContext* cx, const CallArgs& args);
static bool transferImpl(JSContext* cx, const CallArgs& args);
static bool transferToFixedLengthImpl(JSContext* cx, const CallArgs& args);

Expand Down Expand Up @@ -372,6 +373,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared {

static bool fun_isView(JSContext* cx, unsigned argc, Value* vp);

static bool resize(JSContext* cx, unsigned argc, Value* vp);

static bool transfer(JSContext* cx, unsigned argc, Value* vp);

static bool transferToFixedLength(JSContext* cx, unsigned argc, Value* vp);
Expand Down Expand Up @@ -647,6 +650,9 @@ class ResizableArrayBufferObject : public ArrayBufferObject {
setDataPointer(contents);
}

// Resize this buffer.
void resize(size_t newByteLength);

public:
static const uint8_t MAX_BYTE_LENGTH_SLOT = ArrayBufferObject::RESERVED_SLOTS;

Expand Down

0 comments on commit df80812

Please sign in to comment.