diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp index 6e80e67e3d..d2bc5c7a98 100644 --- a/src/bun.js/bindings/JSBuffer.cpp +++ b/src/bun.js/bindings/JSBuffer.cpp @@ -2450,6 +2450,16 @@ EncodedJSValue constructBufferFromArrayBuffer(JSC::ThrowScope& throwScope, JSGlo if (length > byteLength - offset) return Bun::ERR::BUFFER_OUT_OF_BOUNDS(throwScope, lexicalGlobalObject, "length"_s); } + auto isResizableOrGrowableShared = jsBuffer->isResizableOrGrowableShared(); + if (isResizableOrGrowableShared) { + auto* subclassStructure = globalObject->JSResizableOrGrowableSharedBufferSubclassStructure(); + auto* uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, WTFMove(buffer), offset, std::nullopt); + if (UNLIKELY(!uint8Array)) { + throwOutOfMemoryError(globalObject, throwScope); + return {}; + } + RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(uint8Array)); + } auto* subclassStructure = globalObject->JSBufferSubclassStructure(); auto* uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, WTFMove(buffer), offset, length); if (UNLIKELY(!uint8Array)) { diff --git a/src/bun.js/bindings/SQLClient.cpp b/src/bun.js/bindings/SQLClient.cpp index eddfe794c8..9df7cf2f8e 100644 --- a/src/bun.js/bindings/SQLClient.cpp +++ b/src/bun.js/bindings/SQLClient.cpp @@ -197,7 +197,7 @@ static JSC::JSValue toJS(JSC::VM& vm, JSC::JSGlobalObject* globalObject, DataCel uint32_t length = cell.value.typed_array.length; switch (type) { case JSC::JSType::Int32ArrayType: { - JSC::JSInt32Array* array = JSC::JSInt32Array::createUninitialized(globalObject, globalObject->typedArrayStructure(TypedArrayType::TypeInt32, false), length); + JSC::JSInt32Array* array = JSC::JSInt32Array::createUninitialized(globalObject, globalObject->typedArrayStructureWithTypedArrayType(), length); if (UNLIKELY(array == nullptr)) { return {}; } @@ -209,7 +209,7 @@ static JSC::JSValue toJS(JSC::VM& vm, JSC::JSGlobalObject* globalObject, DataCel return array; } case JSC::JSType::Uint32ArrayType: { - JSC::JSUint32Array* array = JSC::JSUint32Array::createUninitialized(globalObject, globalObject->typedArrayStructure(TypedArrayType::TypeUint32, false), length); + JSC::JSUint32Array* array = JSC::JSUint32Array::createUninitialized(globalObject, globalObject->typedArrayStructureWithTypedArrayType(), length); if (UNLIKELY(array == nullptr)) { return {}; } @@ -220,7 +220,7 @@ static JSC::JSValue toJS(JSC::VM& vm, JSC::JSGlobalObject* globalObject, DataCel return array; } case JSC::JSType::Int16ArrayType: { - JSC::JSInt16Array* array = JSC::JSInt16Array::createUninitialized(globalObject, globalObject->typedArrayStructure(TypedArrayType::TypeInt16, false), length); + JSC::JSInt16Array* array = JSC::JSInt16Array::createUninitialized(globalObject, globalObject->typedArrayStructureWithTypedArrayType(), length); if (UNLIKELY(array == nullptr)) { return {}; } @@ -232,7 +232,7 @@ static JSC::JSValue toJS(JSC::VM& vm, JSC::JSGlobalObject* globalObject, DataCel return array; } case JSC::JSType::Uint16ArrayType: { - JSC::JSUint16Array* array = JSC::JSUint16Array::createUninitialized(globalObject, globalObject->typedArrayStructure(TypedArrayType::TypeUint16, false), length); + JSC::JSUint16Array* array = JSC::JSUint16Array::createUninitialized(globalObject, globalObject->typedArrayStructureWithTypedArrayType(), length); if (UNLIKELY(array == nullptr)) { return {}; } @@ -243,7 +243,7 @@ static JSC::JSValue toJS(JSC::VM& vm, JSC::JSGlobalObject* globalObject, DataCel return array; } case JSC::JSType::Float16ArrayType: { - JSC::JSFloat16Array* array = JSC::JSFloat16Array::createUninitialized(globalObject, globalObject->typedArrayStructure(TypedArrayType::TypeFloat16, false), length); + JSC::JSFloat16Array* array = JSC::JSFloat16Array::createUninitialized(globalObject, globalObject->typedArrayStructureWithTypedArrayType(), length); if (UNLIKELY(array == nullptr)) { return {}; } @@ -254,7 +254,7 @@ static JSC::JSValue toJS(JSC::VM& vm, JSC::JSGlobalObject* globalObject, DataCel return array; } case JSC::JSType::Float32ArrayType: { - JSC::JSFloat32Array* array = JSC::JSFloat32Array::createUninitialized(globalObject, globalObject->typedArrayStructure(TypedArrayType::TypeFloat32, false), length); + JSC::JSFloat32Array* array = JSC::JSFloat32Array::createUninitialized(globalObject, globalObject->typedArrayStructureWithTypedArrayType(), length); if (UNLIKELY(array == nullptr)) { return {}; } @@ -265,7 +265,7 @@ static JSC::JSValue toJS(JSC::VM& vm, JSC::JSGlobalObject* globalObject, DataCel return array; } case JSC::JSType::Float64ArrayType: { - JSC::JSFloat64Array* array = JSC::JSFloat64Array::createUninitialized(globalObject, globalObject->typedArrayStructure(TypedArrayType::TypeFloat64, false), length); + JSC::JSFloat64Array* array = JSC::JSFloat64Array::createUninitialized(globalObject, globalObject->typedArrayStructureWithTypedArrayType(), length); if (UNLIKELY(array == nullptr)) { return {}; } diff --git a/src/bun.js/bindings/Uint8Array.cpp b/src/bun.js/bindings/Uint8Array.cpp index 62d43612dd..11d53e87fb 100644 --- a/src/bun.js/bindings/Uint8Array.cpp +++ b/src/bun.js/bindings/Uint8Array.cpp @@ -15,9 +15,9 @@ extern "C" JSC::EncodedJSValue JSUint8Array__fromDefaultAllocator(JSC::JSGlobalO mi_free(p); })); - uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::TypeUint8, false), WTFMove(buffer), 0, length); + uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructureWithTypedArrayType(), WTFMove(buffer), 0, length); } else { - uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructure(JSC::TypeUint8, false), 0); + uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, lexicalGlobalObject->typedArrayStructureWithTypedArrayType(), 0); } return JSC::JSValue::encode(uint8Array); diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 0bb72daecb..60ee9f261e 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -1867,10 +1867,8 @@ extern "C" JSC__JSValue Bun__createUint8ArrayForCopy(JSC::JSGlobalObject* global VM& vm = globalObject->vm(); auto scope = DECLARE_THROW_SCOPE(vm); - JSC::JSUint8Array* array = JSC::JSUint8Array::createUninitialized( - globalObject, - isBuffer ? reinterpret_cast(globalObject)->JSBufferSubclassStructure() : globalObject->typedArrayStructure(TypeUint8, false), - len); + auto* subclassStructure = isBuffer ? reinterpret_cast(globalObject)->JSBufferSubclassStructure() : globalObject->typedArrayStructureWithTypedArrayType(); + JSC::JSUint8Array* array = JSC::JSUint8Array::createUninitialized(globalObject, subclassStructure, len); if (UNLIKELY(!array)) { JSC::throwOutOfMemoryError(globalObject, scope); @@ -2940,8 +2938,14 @@ void GlobalObject::finishCreation(VM& vm) m_JSBufferSubclassStructure.initLater( [](const Initializer& init) { auto* globalObject = reinterpret_cast(init.owner); - - auto* baseStructure = globalObject->typedArrayStructure(JSC::TypeUint8, false); + auto* baseStructure = globalObject->typedArrayStructureWithTypedArrayType(); + JSC::Structure* subclassStructure = JSC::InternalFunction::createSubclassStructure(globalObject, globalObject->JSBufferConstructor(), baseStructure); + init.set(subclassStructure); + }); + m_JSResizableOrGrowableSharedBufferSubclassStructure.initLater( + [](const Initializer& init) { + auto* globalObject = reinterpret_cast(init.owner); + auto* baseStructure = globalObject->resizableOrGrowableSharedTypedArrayStructureWithTypedArrayType(); JSC::Structure* subclassStructure = JSC::InternalFunction::createSubclassStructure(globalObject, globalObject->JSBufferConstructor(), baseStructure); init.set(subclassStructure); }); @@ -3288,7 +3292,7 @@ void GlobalObject::finishCreation(VM& vm) m_JSBufferClassStructure.initLater( [](LazyClassStructure::Initializer& init) { - auto prototype = WebCore::createBufferPrototype(init.vm, init.global); + auto* prototype = WebCore::createBufferPrototype(init.vm, init.global); auto* structure = WebCore::createBufferStructure(init.vm, init.global, JSValue(prototype)); auto* constructor = WebCore::createBufferConstructor(init.vm, init.global, jsCast(prototype)); init.setPrototype(prototype); @@ -3877,6 +3881,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_JSBufferClassStructure.visit(visitor); thisObject->m_JSBufferListClassStructure.visit(visitor); thisObject->m_JSBufferSubclassStructure.visit(visitor); + thisObject->m_JSResizableOrGrowableSharedBufferSubclassStructure.visit(visitor); thisObject->m_JSCryptoKey.visit(visitor); thisObject->m_lazyStackCustomGetterSetter.visit(visitor); thisObject->m_JSDOMFileConstructor.visit(visitor); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index b34cb5aec5..fc00caeb1f 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -193,6 +193,7 @@ public: JSC::JSObject* JSBufferConstructor() const { return m_JSBufferClassStructure.constructorInitializedOnMainThread(this); } JSC::JSValue JSBufferPrototype() const { return m_JSBufferClassStructure.prototypeInitializedOnMainThread(this); } JSC::Structure* JSBufferSubclassStructure() const { return m_JSBufferSubclassStructure.getInitializedOnMainThread(this); } + JSC::Structure* JSResizableOrGrowableSharedBufferSubclassStructure() const { return m_JSResizableOrGrowableSharedBufferSubclassStructure.getInitializedOnMainThread(this); } JSC::Structure* JSCryptoKeyStructure() const { return m_JSCryptoKey.getInitializedOnMainThread(this); } @@ -567,6 +568,7 @@ public: LazyProperty m_subtleCryptoObject; LazyProperty m_JSHTTPResponseController; LazyProperty m_JSBufferSubclassStructure; + LazyProperty m_JSResizableOrGrowableSharedBufferSubclassStructure; LazyProperty m_vmModuleContextMap; LazyProperty m_lazyRequireCacheObject; LazyProperty m_lazyTestModuleObject; diff --git a/src/bun.js/bindings/webcore/ReadableStreamDefaultController.cpp b/src/bun.js/bindings/webcore/ReadableStreamDefaultController.cpp index c601884eae..ca3e35b2ba 100644 --- a/src/bun.js/bindings/webcore/ReadableStreamDefaultController.cpp +++ b/src/bun.js/bindings/webcore/ReadableStreamDefaultController.cpp @@ -143,7 +143,7 @@ bool ReadableStreamDefaultController::enqueue(RefPtr&& buffer) JSC::JSLockHolder lock(vm); auto scope = DECLARE_CATCH_SCOPE(vm); auto length = buffer->byteLength(); - auto value = JSC::JSUint8Array::create(&lexicalGlobalObject, lexicalGlobalObject.typedArrayStructure(JSC::TypeUint8, true), WTFMove(buffer), 0, length); + auto value = JSC::JSUint8Array::create(&lexicalGlobalObject, lexicalGlobalObject.typedArrayStructureWithTypedArrayType(), WTFMove(buffer), 0, length); EXCEPTION_ASSERT(!scope.exception() || vm.hasPendingTerminationException()); RETURN_IF_EXCEPTION(scope, false); diff --git a/src/bun.js/bindings/webcore/WebSocket.cpp b/src/bun.js/bindings/webcore/WebSocket.cpp index df421e74c1..0cc2fe3ea7 100644 --- a/src/bun.js/bindings/webcore/WebSocket.cpp +++ b/src/bun.js/bindings/webcore/WebSocket.cpp @@ -1141,12 +1141,8 @@ void WebSocket::didReceiveBinaryData(const AtomString& eventName, const std::spa context->postTask([name = eventName, buffer = WTFMove(arrayBuffer), protectedThis = Ref { *this }](ScriptExecutionContext& context) { size_t length = buffer->byteLength(); auto* globalObject = context.jsGlobalObject(); - JSUint8Array* uint8array = JSUint8Array::create( - globalObject, - reinterpret_cast(globalObject)->JSBufferSubclassStructure(), - buffer.copyRef(), - 0, - length); + auto* subclassStructure = reinterpret_cast(globalObject)->JSBufferSubclassStructure(); + JSUint8Array* uint8array = JSUint8Array::create(globalObject, subclassStructure, buffer.copyRef(), 0, length); JSC::EnsureStillAliveScope ensureStillAlive(uint8array); MessageEvent::Init init; init.data = uint8array; diff --git a/src/bun.js/modules/BunJSCModule.h b/src/bun.js/modules/BunJSCModule.h index ce6c5a8491..27898ed14b 100644 --- a/src/bun.js/modules/BunJSCModule.h +++ b/src/bun.js/modules/BunJSCModule.h @@ -1,3 +1,4 @@ +#include "root.h" #include "_NativeModule.h" #include "ExceptionOr.h" @@ -796,9 +797,8 @@ JSC_DEFINE_HOST_FUNCTION(functionSerialize, if (asNodeBuffer) { size_t byteLength = arrayBuffer->byteLength(); - JSC::JSUint8Array* uint8Array = JSC::JSUint8Array::create( - lexicalGlobalObject, globalObject->JSBufferSubclassStructure(), - WTFMove(arrayBuffer), 0, byteLength); + auto* subclassStructure = globalObject->JSBufferSubclassStructure(); + JSC::JSUint8Array* uint8Array = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, WTFMove(arrayBuffer), 0, byteLength); return JSValue::encode(uint8Array); } diff --git a/test/js/node/test/parallel/test-buffer-resizable.js b/test/js/node/test/parallel/test-buffer-resizable.js new file mode 100644 index 0000000000..6c31ba5ec8 --- /dev/null +++ b/test/js/node/test/parallel/test-buffer-resizable.js @@ -0,0 +1,42 @@ +// Flags: --no-warnings +'use strict'; + +require('../common'); +const { Buffer } = require('node:buffer'); +const { strictEqual } = require('node:assert'); + +{ + { + const ab = new ArrayBuffer(10, { maxByteLength: 20 }); + const buffer = Buffer.from(ab, 1); + strictEqual(ab.byteLength, 10); + strictEqual(buffer.buffer.byteLength, 10); + strictEqual(buffer.byteLength, 9); + ab.resize(15); + strictEqual(ab.byteLength, 15); + strictEqual(buffer.buffer.byteLength, 15); + strictEqual(buffer.byteLength, 14); + ab.resize(5); + strictEqual(ab.byteLength, 5); + strictEqual(buffer.buffer.byteLength, 5); + strictEqual(buffer.byteLength, 4); + } +} + +{ + { + const ab = new ArrayBuffer(10, { maxByteLength: 20 }); + const buffer = new Buffer(ab, 1); + strictEqual(ab.byteLength, 10); + strictEqual(buffer.buffer.byteLength, 10); + strictEqual(buffer.byteLength, 9); + ab.resize(15); + strictEqual(ab.byteLength, 15); + strictEqual(buffer.buffer.byteLength, 15); + strictEqual(buffer.byteLength, 14); + ab.resize(5); + strictEqual(ab.byteLength, 5); + strictEqual(buffer.buffer.byteLength, 5); + strictEqual(buffer.byteLength, 4); + } +}