From 1fcb573e6ba3c40ce7a6c017883d6cdc1b04a6da Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 21 Nov 2023 10:29:23 -0800 Subject: [PATCH] Implement ArrayBuffer.prototype.transfer (#101) --- quickjs.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test262.conf | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/quickjs.c b/quickjs.c index 948e75f..9e8d7f9 100644 --- a/quickjs.c +++ b/quickjs.c @@ -47253,6 +47253,18 @@ static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx) return JS_ThrowTypeError(ctx, "ArrayBuffer is detached"); } +// #sec-get-arraybuffer.prototype.detached +static JSValue js_array_buffer_get_detached(JSContext *ctx, + JSValueConst this_val) +{ + JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER); + if (!abuf) + return JS_EXCEPTION; + if (abuf->shared) + return JS_ThrowTypeError(ctx, "detached called on SharedArrayBuffer"); + return JS_NewBool(ctx, abuf->detached); +} + static JSValue js_array_buffer_get_byteLength(JSContext *ctx, JSValueConst this_val, int class_id) @@ -47325,6 +47337,52 @@ uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj) return NULL; } +// ES #sec-arraybuffer.prototype.transfer +static JSValue js_array_buffer_transfer(JSContext *ctx, + JSValueConst this_val, + int argc, JSValueConst *argv) +{ + JSArrayBuffer *abuf; + uint64_t new_len, old_len; + uint8_t *bs, *new_bs; + + abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER); + if (!abuf) + return JS_EXCEPTION; + if (abuf->shared) + return JS_ThrowTypeError(ctx, "cannot transfer a SharedArrayBuffer"); + if (argc < 1 || JS_IsUndefined(argv[0])) + new_len = abuf->byte_length; + else if (JS_ToIndex(ctx, &new_len, argv[0])) + return JS_EXCEPTION; + if (abuf->detached) + return JS_ThrowTypeErrorDetachedArrayBuffer(ctx); + /* create an empty AB */ + if (new_len == 0) { + JS_DetachArrayBuffer(ctx, this_val); + return js_array_buffer_constructor2(ctx, JS_UNDEFINED, 0, JS_CLASS_ARRAY_BUFFER); + } + bs = abuf->data; + old_len = abuf->byte_length; + /* if length mismatch, realloc. Otherwise, use the same backing buffer. */ + if (new_len != old_len) { + new_bs = js_realloc(ctx, bs, new_len); + if (!new_bs) + return JS_EXCEPTION; + bs = new_bs; + if (new_len > old_len) + memset(bs + old_len, 0, new_len - old_len); + } + /* neuter the backing buffer */ + abuf->data = NULL; + abuf->byte_length = 0; + abuf->detached = TRUE; + return js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, + JS_CLASS_ARRAY_BUFFER, + bs, abuf->free_func, + NULL, FALSE); +} + static JSValue js_array_buffer_slice(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int class_id) @@ -47393,7 +47451,10 @@ static JSValue js_array_buffer_slice(JSContext *ctx, static const JSCFunctionListEntry js_array_buffer_proto_funcs[] = { JS_CGETSET_MAGIC_DEF("byteLength", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ), + JS_CGETSET_DEF("detached", js_array_buffer_get_detached, NULL ), JS_CFUNC_MAGIC_DEF("slice", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ), + JS_CFUNC_DEF("transfer", 0, js_array_buffer_transfer ), + JS_CFUNC_DEF("transferToFixedLength", 0, js_array_buffer_transfer ), JS_PROP_STRING_DEF("[Symbol.toStringTag]", "ArrayBuffer", JS_PROP_CONFIGURABLE ), }; diff --git a/test262.conf b/test262.conf index e726385..094ac3c 100644 --- a/test262.conf +++ b/test262.conf @@ -65,7 +65,7 @@ Array.prototype.flatten Array.prototype.includes Array.prototype.values ArrayBuffer -arraybuffer-transfer=skip +arraybuffer-transfer arrow-function async-functions async-iteration