diff options
Diffstat (limited to 'src')
11 files changed, 379 insertions, 31 deletions
diff --git a/src/javascript/jsc/bindings/ReadableByteStreamInternalsBuiltins.cpp b/src/javascript/jsc/bindings/ReadableByteStreamInternalsBuiltins.cpp index 123874f1b..a1df2da1b 100644 --- a/src/javascript/jsc/bindings/ReadableByteStreamInternalsBuiltins.cpp +++ b/src/javascript/jsc/bindings/ReadableByteStreamInternalsBuiltins.cpp @@ -366,7 +366,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerPullC const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerShouldCallPullCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerShouldCallPullCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerShouldCallPullCodeLength = 872; +const int s_readableByteStreamInternalsReadableByteStreamControllerShouldCallPullCodeLength = 873; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerShouldCallPullCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerShouldCallPullCode = "(function (controller)\n" \ @@ -381,7 +381,8 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerShoul " return false;\n" \ " if (!@getByIdDirectPrivate(controller, \"started\"))\n" \ " return false;\n" \ - " const reader = @getByIdDirectPrivate(stream, \"reader\");\n" \ + " const reader = @getByIdDirectPrivate(stream, \"reader\");\n" \ + " \n" \ " if (reader && (@getByIdDirectPrivate(reader, \"readRequests\")?.isNotEmpty() || !!@getByIdDirectPrivate(reader, \"bunNativePtr\")))\n" \ " return true;\n" \ " if (@readableStreamHasBYOBReader(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readIntoRequests\")?.isNotEmpty())\n" \ diff --git a/src/javascript/jsc/bindings/ReadableStreamBuiltins.cpp b/src/javascript/jsc/bindings/ReadableStreamBuiltins.cpp index c7d9470c2..6db3451d3 100644 --- a/src/javascript/jsc/bindings/ReadableStreamBuiltins.cpp +++ b/src/javascript/jsc/bindings/ReadableStreamBuiltins.cpp @@ -119,7 +119,7 @@ const char* const s_readableStreamInitializeReadableStreamCode = const JSC::ConstructAbility s_readableStreamReadableStreamToArrayCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamReadableStreamToArrayCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamReadableStreamToArrayCodeLength = 884; +const int s_readableStreamReadableStreamToArrayCodeLength = 883; static const JSC::Intrinsic s_readableStreamReadableStreamToArrayCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamReadableStreamToArrayCode = "(function (stream) {\n" \ @@ -129,7 +129,6 @@ const char* const s_readableStreamReadableStreamToArrayCode = " return null;\n" \ " }\n" \ " var reader = stream.getReader();\n" \ - "\n" \ " var manyResult = reader.readMany();\n" \ " \n" \ " async function processManyResult(result) {\n" \ @@ -166,6 +165,60 @@ const char* const s_readableStreamReadableStreamToArrayCode = "})\n" \ ; +const JSC::ConstructAbility s_readableStreamReadableStreamToTextCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; +const JSC::ConstructorKind s_readableStreamReadableStreamToTextCodeConstructorKind = JSC::ConstructorKind::None; +const int s_readableStreamReadableStreamToTextCodeLength = 215; +static const JSC::Intrinsic s_readableStreamReadableStreamToTextCodeIntrinsic = JSC::NoIntrinsic; +const char* const s_readableStreamReadableStreamToTextCode = + "(function (stream) {\n" \ + " \"use strict\";\n" \ + "\n" \ + " //\n" \ + " return globalThis.Bun.readableStreamToArrayBuffer(stream).@then(function(arrayBuffer) {\n" \ + " return new globalThis.TextDecoder().decode(arrayBuffer);\n" \ + " });\n" \ + "})\n" \ +; + +const JSC::ConstructAbility s_readableStreamReadableStreamToJSONCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; +const JSC::ConstructorKind s_readableStreamReadableStreamToJSONCodeConstructorKind = JSC::ConstructorKind::None; +const int s_readableStreamReadableStreamToJSONCodeLength = 238; +static const JSC::Intrinsic s_readableStreamReadableStreamToJSONCodeIntrinsic = JSC::NoIntrinsic; +const char* const s_readableStreamReadableStreamToJSONCode = + "(function (stream) {\n" \ + " \"use strict\";\n" \ + "\n" \ + " //\n" \ + " return globalThis.Bun.readableStreamToArrayBuffer(stream).@then(function(arrayBuffer) {\n" \ + " return globalThis.JSON.parse(new globalThis.TextDecoder().decode(arrayBuffer));\n" \ + " });\n" \ + "})\n" \ +; + +const JSC::ConstructAbility s_readableStreamReadableStreamToBlobCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; +const JSC::ConstructorKind s_readableStreamReadableStreamToBlobCodeConstructorKind = JSC::ConstructorKind::None; +const int s_readableStreamReadableStreamToBlobCodeLength = 367; +static const JSC::Intrinsic s_readableStreamReadableStreamToBlobCodeIntrinsic = JSC::NoIntrinsic; +const char* const s_readableStreamReadableStreamToBlobCode = + "(function (stream) {\n" \ + " \"use strict\";\n" \ + "\n" \ + " \n" \ + " const array = @readableStreamToArray(stream);\n" \ + " if (array === null) {\n" \ + " return new globalThis.Blob();\n" \ + " }\n" \ + "\n" \ + " return array.@then(function(chunks) {\n" \ + " if (chunks === null || chunks.length === 0) {\n" \ + " return new globalThis.Blob();\n" \ + " }\n" \ + "\n" \ + " return new globalThis.Blob(chunks);\n" \ + " });\n" \ + "})\n" \ +; + const JSC::ConstructAbility s_readableStreamReadableStreamToArrayPublicCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamReadableStreamToArrayPublicCodeConstructorKind = JSC::ConstructorKind::None; const int s_readableStreamReadableStreamToArrayPublicCodeLength = 841; diff --git a/src/javascript/jsc/bindings/ReadableStreamBuiltins.h b/src/javascript/jsc/bindings/ReadableStreamBuiltins.h index 7733d4d0c..d009f8560 100644 --- a/src/javascript/jsc/bindings/ReadableStreamBuiltins.h +++ b/src/javascript/jsc/bindings/ReadableStreamBuiltins.h @@ -55,6 +55,18 @@ extern const char* const s_readableStreamReadableStreamToArrayCode; extern const int s_readableStreamReadableStreamToArrayCodeLength; extern const JSC::ConstructAbility s_readableStreamReadableStreamToArrayCodeConstructAbility; extern const JSC::ConstructorKind s_readableStreamReadableStreamToArrayCodeConstructorKind; +extern const char* const s_readableStreamReadableStreamToTextCode; +extern const int s_readableStreamReadableStreamToTextCodeLength; +extern const JSC::ConstructAbility s_readableStreamReadableStreamToTextCodeConstructAbility; +extern const JSC::ConstructorKind s_readableStreamReadableStreamToTextCodeConstructorKind; +extern const char* const s_readableStreamReadableStreamToJSONCode; +extern const int s_readableStreamReadableStreamToJSONCodeLength; +extern const JSC::ConstructAbility s_readableStreamReadableStreamToJSONCodeConstructAbility; +extern const JSC::ConstructorKind s_readableStreamReadableStreamToJSONCodeConstructorKind; +extern const char* const s_readableStreamReadableStreamToBlobCode; +extern const int s_readableStreamReadableStreamToBlobCodeLength; +extern const JSC::ConstructAbility s_readableStreamReadableStreamToBlobCodeConstructAbility; +extern const JSC::ConstructorKind s_readableStreamReadableStreamToBlobCodeConstructorKind; extern const char* const s_readableStreamReadableStreamToArrayPublicCode; extern const int s_readableStreamReadableStreamToArrayPublicCodeLength; extern const JSC::ConstructAbility s_readableStreamReadableStreamToArrayPublicCodeConstructAbility; @@ -99,6 +111,9 @@ extern const JSC::ConstructorKind s_readableStreamLockedCodeConstructorKind; #define WEBCORE_FOREACH_READABLESTREAM_BUILTIN_DATA(macro) \ macro(initializeReadableStream, readableStreamInitializeReadableStream, 2) \ macro(readableStreamToArray, readableStreamReadableStreamToArray, 1) \ + macro(readableStreamToText, readableStreamReadableStreamToText, 1) \ + macro(readableStreamToJSON, readableStreamReadableStreamToJSON, 1) \ + macro(readableStreamToBlob, readableStreamReadableStreamToBlob, 1) \ macro(readableStreamToArrayPublic, readableStreamReadableStreamToArrayPublic, 1) \ macro(consumeReadableStream, readableStreamConsumeReadableStream, 3) \ macro(createEmptyReadableStream, readableStreamCreateEmptyReadableStream, 0) \ @@ -112,6 +127,9 @@ extern const JSC::ConstructorKind s_readableStreamLockedCodeConstructorKind; #define WEBCORE_BUILTIN_READABLESTREAM_INITIALIZEREADABLESTREAM 1 #define WEBCORE_BUILTIN_READABLESTREAM_READABLESTREAMTOARRAY 1 +#define WEBCORE_BUILTIN_READABLESTREAM_READABLESTREAMTOTEXT 1 +#define WEBCORE_BUILTIN_READABLESTREAM_READABLESTREAMTOJSON 1 +#define WEBCORE_BUILTIN_READABLESTREAM_READABLESTREAMTOBLOB 1 #define WEBCORE_BUILTIN_READABLESTREAM_READABLESTREAMTOARRAYPUBLIC 1 #define WEBCORE_BUILTIN_READABLESTREAM_CONSUMEREADABLESTREAM 1 #define WEBCORE_BUILTIN_READABLESTREAM_CREATEEMPTYREADABLESTREAM 1 @@ -126,6 +144,9 @@ extern const JSC::ConstructorKind s_readableStreamLockedCodeConstructorKind; #define WEBCORE_FOREACH_READABLESTREAM_BUILTIN_CODE(macro) \ macro(readableStreamInitializeReadableStreamCode, initializeReadableStream, ASCIILiteral(), s_readableStreamInitializeReadableStreamCodeLength) \ macro(readableStreamReadableStreamToArrayCode, readableStreamToArray, ASCIILiteral(), s_readableStreamReadableStreamToArrayCodeLength) \ + macro(readableStreamReadableStreamToTextCode, readableStreamToText, ASCIILiteral(), s_readableStreamReadableStreamToTextCodeLength) \ + macro(readableStreamReadableStreamToJSONCode, readableStreamToJSON, ASCIILiteral(), s_readableStreamReadableStreamToJSONCodeLength) \ + macro(readableStreamReadableStreamToBlobCode, readableStreamToBlob, ASCIILiteral(), s_readableStreamReadableStreamToBlobCodeLength) \ macro(readableStreamReadableStreamToArrayPublicCode, readableStreamToArrayPublic, ASCIILiteral(), s_readableStreamReadableStreamToArrayPublicCodeLength) \ macro(readableStreamConsumeReadableStreamCode, consumeReadableStream, ASCIILiteral(), s_readableStreamConsumeReadableStreamCodeLength) \ macro(readableStreamCreateEmptyReadableStreamCode, createEmptyReadableStream, ASCIILiteral(), s_readableStreamCreateEmptyReadableStreamCodeLength) \ @@ -149,6 +170,9 @@ extern const JSC::ConstructorKind s_readableStreamLockedCodeConstructorKind; macro(pipeTo) \ macro(readableStreamToArray) \ macro(readableStreamToArrayPublic) \ + macro(readableStreamToBlob) \ + macro(readableStreamToJSON) \ + macro(readableStreamToText) \ macro(tee) \ #define DECLARE_BUILTIN_GENERATOR(codeName, functionName, overriddenName, argumentCount) \ diff --git a/src/javascript/jsc/bindings/ReadableStreamDefaultReaderBuiltins.cpp b/src/javascript/jsc/bindings/ReadableStreamDefaultReaderBuiltins.cpp index 839550857..91689fb13 100644 --- a/src/javascript/jsc/bindings/ReadableStreamDefaultReaderBuiltins.cpp +++ b/src/javascript/jsc/bindings/ReadableStreamDefaultReaderBuiltins.cpp @@ -89,7 +89,7 @@ const char* const s_readableStreamDefaultReaderCancelCode = const JSC::ConstructAbility s_readableStreamDefaultReaderReadManyCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamDefaultReaderReadManyCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamDefaultReaderReadManyCodeLength = 2683; +const int s_readableStreamDefaultReaderReadManyCodeLength = 3235; static const JSC::Intrinsic s_readableStreamDefaultReaderReadManyCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamDefaultReaderReadManyCode = "(function ()\n" \ @@ -121,6 +121,12 @@ const char* const s_readableStreamDefaultReaderReadManyCode = " \n" \ "\n" \ " if (length > 0) {\n" \ + " for (var i = 0; i < values.length; i++) {\n" \ + " const buf = values[i];\n" \ + " if (!(@ArrayBuffer.@isView(buf) || buf instanceof @ArrayBuffer)) {\n" \ + " values[i] = new @Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n" \ + " }\n" \ + " }\n" \ " \n" \ " @resetQueue(@getByIdDirectPrivate(controller, \"queue\"));\n" \ "\n" \ @@ -143,6 +149,13 @@ const char* const s_readableStreamDefaultReaderReadManyCode = " \n" \ " var queue = @getByIdDirectPrivate(controller, \"queue\");\n" \ " var value = [result.value].concat(queue.content.toArray(false));\n" \ + " for (var i = 0; i < value.length; i++) {\n" \ + " const buf = value[i];\n" \ + " if (!(@ArrayBuffer.@isView(buf) || buf instanceof @ArrayBuffer)) {\n" \ + " value[i] = new @Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n" \ + " }\n" \ + " }\n" \ + "\n" \ " var size = queue.size;\n" \ " @resetQueue(queue);\n" \ "\n" \ diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp index 3282370bd..f0fb661a4 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp +++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp @@ -886,6 +886,19 @@ static JSC_DEFINE_HOST_FUNCTION(functionReportError, return JSC::JSValue::encode(JSC::jsUndefined()); } +extern "C" JSC__JSValue Bun__createUninitializedArrayBuffer(JSC::JSGlobalObject* globalObject, const void* ptr, size_t len) +{ + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + auto arrayBuffer = JSC::ArrayBuffer::tryCreateUninitialized(len, 1); + + if (UNLIKELY(!arrayBuffer)) { + JSC::throwOutOfMemoryError(globalObject, scope); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + RELEASE_AND_RETURN(scope, JSValue::encode(JSC::JSArrayBuffer::create(globalObject->vm(), globalObject->arrayBufferStructure(JSC::ArrayBufferSharingMode::Default), WTFMove(arrayBuffer)))); +} + JSC_DECLARE_HOST_FUNCTION(functionCreateUninitializedArrayBuffer); JSC_DEFINE_HOST_FUNCTION(functionCreateUninitializedArrayBuffer, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) @@ -1273,12 +1286,9 @@ extern "C" int32_t ReadableStreamTag__tagged(Zig::GlobalObject* globalObject, JS auto* readableStream = jsCast<JSReadableStream*>(object); auto& vm = globalObject->vm(); auto& builtinNames = WebCore::clientData(vm)->builtinNames(); - - JSValue numberValue = readableStream->getDirect(vm, builtinNames.bunNativeTypePrivateName()); - int32_t num = numberValue.toInt32(globalObject); - if (numberValue.isUndefined() || num == 0) { - *ptr = JSC::JSValue(); - return 0; + int32_t num = 0; + if (JSValue numberValue = readableStream->getDirect(vm, builtinNames.bunNativeTypePrivateName())) { + num = numberValue.toInt32(globalObject); } // If this type is outside the expected range, it means something is wrong. @@ -1533,6 +1543,78 @@ extern "C" JSC__JSValue ZigGlobalObject__readableStreamToArrayBuffer(Zig::Global return ZigGlobalObject__readableStreamToArrayBufferBody(reinterpret_cast<Zig::GlobalObject*>(globalObject), readableStreamValue); } +extern "C" JSC__JSValue ZigGlobalObject__readableStreamToText(Zig::GlobalObject* globalObject, JSC__JSValue readableStreamValue); +extern "C" JSC__JSValue ZigGlobalObject__readableStreamToText(Zig::GlobalObject* globalObject, JSC__JSValue readableStreamValue) +{ + auto& vm = globalObject->vm(); + + auto clientData = WebCore::clientData(vm); + auto& builtinNames = WebCore::builtinNames(vm); + + JSC::JSFunction* function = nullptr; + if (auto readableStreamToText = globalObject->m_readableStreamToText.get()) { + function = readableStreamToText; + } else { + function = JSFunction::create(vm, static_cast<JSC::FunctionExecutable*>(readableStreamReadableStreamToTextCodeGenerator(vm)), globalObject); + + globalObject->m_readableStreamToText.set(vm, globalObject, function); + } + + JSC::MarkedArgumentBuffer arguments = JSC::MarkedArgumentBuffer(); + arguments.append(JSValue::decode(readableStreamValue)); + + auto callData = JSC::getCallData(function); + return JSC::JSValue::encode(call(globalObject, function, callData, JSC::jsUndefined(), arguments)); +} + +extern "C" JSC__JSValue ZigGlobalObject__readableStreamToJSON(Zig::GlobalObject* globalObject, JSC__JSValue readableStreamValue); +extern "C" JSC__JSValue ZigGlobalObject__readableStreamToJSON(Zig::GlobalObject* globalObject, JSC__JSValue readableStreamValue) +{ + auto& vm = globalObject->vm(); + + auto clientData = WebCore::clientData(vm); + auto& builtinNames = WebCore::builtinNames(vm); + + JSC::JSFunction* function = nullptr; + if (auto readableStreamToJSON = globalObject->m_readableStreamToJSON.get()) { + function = readableStreamToJSON; + } else { + function = JSFunction::create(vm, static_cast<JSC::FunctionExecutable*>(readableStreamReadableStreamToJSONCodeGenerator(vm)), globalObject); + + globalObject->m_readableStreamToJSON.set(vm, globalObject, function); + } + + JSC::MarkedArgumentBuffer arguments = JSC::MarkedArgumentBuffer(); + arguments.append(JSValue::decode(readableStreamValue)); + + auto callData = JSC::getCallData(function); + return JSC::JSValue::encode(call(globalObject, function, callData, JSC::jsUndefined(), arguments)); +} + +extern "C" JSC__JSValue ZigGlobalObject__readableStreamToBlob(Zig::GlobalObject* globalObject, JSC__JSValue readableStreamValue); +extern "C" JSC__JSValue ZigGlobalObject__readableStreamToBlob(Zig::GlobalObject* globalObject, JSC__JSValue readableStreamValue) +{ + auto& vm = globalObject->vm(); + + auto clientData = WebCore::clientData(vm); + auto& builtinNames = WebCore::builtinNames(vm); + + JSC::JSFunction* function = nullptr; + if (auto readableStreamToBlob = globalObject->m_readableStreamToBlob.get()) { + function = readableStreamToBlob; + } else { + function = JSFunction::create(vm, static_cast<JSC::FunctionExecutable*>(readableStreamReadableStreamToBlobCodeGenerator(vm)), globalObject); + + globalObject->m_readableStreamToBlob.set(vm, globalObject, function); + } + + JSC::MarkedArgumentBuffer arguments = JSC::MarkedArgumentBuffer(); + arguments.append(JSValue::decode(readableStreamValue)); + + auto callData = JSC::getCallData(function); + return JSC::JSValue::encode(call(globalObject, function, callData, JSC::jsUndefined(), arguments)); +} + JSC_DECLARE_HOST_FUNCTION(functionReadableStreamToArrayBuffer); JSC_DEFINE_HOST_FUNCTION(functionReadableStreamToArrayBuffer, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { @@ -1772,6 +1854,24 @@ void GlobalObject::installAPIGlobals(JSClassRef* globals, int count, JSC::VM& vm } { + JSC::Identifier identifier = JSC::Identifier::fromString(vm, "readableStreamToText"_s); + object->putDirectBuiltinFunction(vm, this, identifier, readableStreamReadableStreamToTextCodeGenerator(vm), + JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + } + + { + JSC::Identifier identifier = JSC::Identifier::fromString(vm, "readableStreamToBlob"_s); + object->putDirectBuiltinFunction(vm, this, identifier, readableStreamReadableStreamToBlobCodeGenerator(vm), + JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + } + + { + JSC::Identifier identifier = JSC::Identifier::fromString(vm, "readableStreamToJSON"_s); + object->putDirectBuiltinFunction(vm, this, identifier, readableStreamReadableStreamToJSONCodeGenerator(vm), + JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); + } + + { JSC::Identifier identifier = JSC::Identifier::fromString(vm, "concatArrayBuffers"_s); object->putDirectNativeFunction(vm, this, identifier, 1, functionConcatTypedArrays, NoIntrinsic, JSC::PropertyAttribute::Function | JSC::PropertyAttribute::DontDelete | 0); @@ -1871,7 +1971,9 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) thisObject->m_builtinInternalFunctions.visit(visitor); thisObject->m_JSFFIFunctionStructure.visit(visitor); visitor.append(thisObject->m_readableStreamToArrayBufferResolve); - visitor.append(thisObject->m_readableStreamToTextResolve); + visitor.append(thisObject->m_readableStreamToText); + visitor.append(thisObject->m_readableStreamToJSON); + visitor.append(thisObject->m_readableStreamToBlob); ScriptExecutionContext* context = thisObject->scriptExecutionContext(); visitor.addOpaqueRoot(context); } diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.h b/src/javascript/jsc/bindings/ZigGlobalObject.h index ffed48909..54d511c94 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.h +++ b/src/javascript/jsc/bindings/ZigGlobalObject.h @@ -153,7 +153,9 @@ public: bool isThreadLocalDefaultGlobalObject = false; mutable WriteBarrier<JSFunction> m_readableStreamToArrayBufferResolve; - mutable WriteBarrier<JSFunction> m_readableStreamToTextResolve; + mutable WriteBarrier<JSFunction> m_readableStreamToText; + mutable WriteBarrier<JSFunction> m_readableStreamToBlob; + mutable WriteBarrier<JSFunction> m_readableStreamToJSON; private: void addBuiltinGlobals(JSC::VM&); diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig index 4a01c702f..31f9b497d 100644 --- a/src/javascript/jsc/bindings/bindings.zig +++ b/src/javascript/jsc/bindings/bindings.zig @@ -1620,12 +1620,30 @@ pub const JSGlobalObject = extern struct { } extern fn ZigGlobalObject__readableStreamToArrayBuffer(*JSGlobalObject, JSValue) JSValue; + extern fn ZigGlobalObject__readableStreamToText(*JSGlobalObject, JSValue) JSValue; + extern fn ZigGlobalObject__readableStreamToJSON(*JSGlobalObject, JSValue) JSValue; + extern fn ZigGlobalObject__readableStreamToBlob(*JSGlobalObject, JSValue) JSValue; pub fn readableStreamToArrayBuffer(this: *JSGlobalObject, value: JSValue) JSValue { if (comptime is_bindgen) unreachable; return ZigGlobalObject__readableStreamToArrayBuffer(this, value); } + pub fn readableStreamToText(this: *JSGlobalObject, value: JSValue) JSValue { + if (comptime is_bindgen) unreachable; + return ZigGlobalObject__readableStreamToText(this, value); + } + + pub fn readableStreamToJSON(this: *JSGlobalObject, value: JSValue) JSValue { + if (comptime is_bindgen) unreachable; + return ZigGlobalObject__readableStreamToJSON(this, value); + } + + pub fn readableStreamToBlob(this: *JSGlobalObject, value: JSValue) JSValue { + if (comptime is_bindgen) unreachable; + return ZigGlobalObject__readableStreamToBlob(this, value); + } + pub const Extern = [_][]const u8{ "bunVM", "putCachedObject", diff --git a/src/javascript/jsc/bindings/builtins/js/ReadableStream.js b/src/javascript/jsc/bindings/builtins/js/ReadableStream.js index 9695b0d82..4874067c3 100644 --- a/src/javascript/jsc/bindings/builtins/js/ReadableStream.js +++ b/src/javascript/jsc/bindings/builtins/js/ReadableStream.js @@ -96,7 +96,6 @@ function readableStreamToArray(stream) { return null; } var reader = stream.getReader(); - var manyResult = reader.readMany(); async function processManyResult(result) { @@ -133,6 +132,45 @@ function readableStreamToArray(stream) { } @globalPrivate +function readableStreamToText(stream) { + "use strict"; + + // TODO: optimize this to skip the extra ArrayBuffer + return globalThis.Bun.readableStreamToArrayBuffer(stream).@then(function(arrayBuffer) { + return new globalThis.TextDecoder().decode(arrayBuffer); + }); +} + +@globalPrivate +function readableStreamToJSON(stream) { + "use strict"; + + // TODO: optimize this to skip the extra ArrayBuffer + return globalThis.Bun.readableStreamToArrayBuffer(stream).@then(function(arrayBuffer) { + return globalThis.JSON.parse(new globalThis.TextDecoder().decode(arrayBuffer)); + }); +} + +@globalPrivate +function readableStreamToBlob(stream) { + "use strict"; + + + const array = @readableStreamToArray(stream); + if (array === null) { + return new globalThis.Blob(); + } + + return array.@then(function(chunks) { + if (chunks === null || chunks.length === 0) { + return new globalThis.Blob(); + } + + return new globalThis.Blob(chunks); + }); +} + +@globalPrivate function readableStreamToArrayPublic(stream) { "use strict"; diff --git a/src/javascript/jsc/bindings/builtins/js/ReadableStreamDefaultReader.js b/src/javascript/jsc/bindings/builtins/js/ReadableStreamDefaultReader.js index 118376ffb..bdeaf1919 100644 --- a/src/javascript/jsc/bindings/builtins/js/ReadableStreamDefaultReader.js +++ b/src/javascript/jsc/bindings/builtins/js/ReadableStreamDefaultReader.js @@ -80,6 +80,12 @@ function readMany() if (length > 0) { + for (var i = 0; i < values.length; i++) { + const buf = values[i]; + if (!(@ArrayBuffer.@isView(buf) || buf instanceof @ArrayBuffer)) { + values[i] = new @Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); + } + } @resetQueue(@getByIdDirectPrivate(controller, "queue")); @@ -102,6 +108,13 @@ function readMany() var queue = @getByIdDirectPrivate(controller, "queue"); var value = [result.value].concat(queue.content.toArray(false)); + for (var i = 0; i < value.length; i++) { + const buf = value[i]; + if (!(@ArrayBuffer.@isView(buf) || buf instanceof @ArrayBuffer)) { + value[i] = new @Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); + } + } + var size = queue.size; @resetQueue(queue); diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig index 19134b357..8d585f93c 100644 --- a/src/javascript/jsc/webcore/response.zig +++ b/src/javascript/jsc/webcore/response.zig @@ -3811,7 +3811,7 @@ pub const Body = struct { pub const PendingValue = struct { promise: ?JSValue = null, - readable: JSValue = JSValue.zero, + stream: ?JSC.WebCore.ReadableStream = null, global: *JSGlobalObject, task: ?*anyopaque = null, @@ -3825,14 +3825,47 @@ pub const Body = struct { pub fn setPromise(value: *PendingValue, globalThis: *JSC.JSGlobalObject, action: Action) JSValue { value.action = action; - var promise = JSC.JSPromise.create(globalThis); - const promise_value = promise.asValue(globalThis); - value.promise = promise_value; - if (value.onPull) |onPull| { - value.onPull = null; - onPull(value.task.?); + + if (value.stream) |*stream| { + // switch (stream.ptr) { + // .JavaScript + // } + switch (action) { + .getText, .getJSON, .getBlob, .getArrayBuffer => { + switch (stream.ptr) { + .Blob => unreachable, + else => {}, + } + value.promise = switch (action) { + .getJSON => globalThis.readableStreamToJSON(stream.value), + .getArrayBuffer => globalThis.readableStreamToArrayBuffer(stream.value), + .getText => globalThis.readableStreamToText(stream.value), + .getBlob => globalThis.readableStreamToBlob(stream.value), + else => unreachable, + }; + value.promise.?.ensureStillAlive(); + stream.value.unprotect(); + + // js now owns the memory + value.stream = null; + + return value.promise.?; + }, + .none => {}, + } + } + + { + var promise = JSC.JSPromise.create(globalThis); + const promise_value = promise.asValue(globalThis); + value.promise = promise_value; + + if (value.onPull) |onPull| { + value.onPull = null; + onPull(value.task.?); + } + return promise_value; } - return promise_value; } pub const Action = enum { @@ -3861,9 +3894,28 @@ pub const Body = struct { pub const empty = Value{ .Empty = .{} }; + pub fn fromReadableStream(stream: JSC.WebCore.ReadableStream, globalThis: *JSGlobalObject) Value { + if (stream.isLocked(globalThis)) { + return .{ .Error = ZigString.init("Cannot use a locked ReadableStream").toErrorInstance(globalThis) }; + } + + stream.value.protect(); + return .{ + .Locked = .{ + .stream = stream, + .global = globalThis, + }, + }; + } + pub fn resolve(this: *Value, new: *Value, global: *JSGlobalObject) void { if (this.* == .Locked) { - var locked = this.Locked; + var locked = &this.Locked; + if (locked.stream) |stream| { + stream.done(); + locked.stream = null; + } + if (locked.callback) |callback| { locked.callback = null; callback(locked.task.?, new); @@ -3936,6 +3988,11 @@ pub const Body = struct { locked.promise = null; } + if (locked.stream) |stream| { + stream.done(); + locked.stream = null; + } + this.* = .{ .Error = error_instance }; if (locked.callback) |callback| { locked.callback = null; @@ -3967,6 +4024,10 @@ pub const Body = struct { pub fn deinit(this: *Value) void { const tag = @as(Tag, this.*); if (tag == .Locked) { + if (this.Locked.stream) |*stream| { + stream.done(); + } + this.Locked.deinit = true; return; } @@ -4051,10 +4112,28 @@ pub const Body = struct { } else |_| {} } - // if (value.as(JSC.WebCore.ReadableStream)) |readable| { - // body.value = Body.Value.fromReadableStream(ctx, readable); - // return body; - // } + if (JSC.WebCore.ReadableStream.fromJS(value, ctx)) |readable| { + switch (readable.ptr) { + .Blob => |blob| { + body.value = .{ + .Blob = Blob.initWithStore(blob.store, ctx), + }; + blob.store.ref(); + + readable.done(); + + if (!blob.done) { + blob.done = true; + blob.deinit(); + } + return body; + }, + else => {}, + } + + body.value = Body.Value.fromReadableStream(readable, ctx); + return body; + } body.value = .{ .Blob = Blob.fromJS(ctx.ptr(), value, true, false) catch |err| { @@ -4451,7 +4530,7 @@ fn BlobInterface(comptime Type: type) type { _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { - var value = this.getBodyValue(); + var value: *Body.Value = this.getBodyValue(); if (value.* == .Locked) { return value.Locked.setPromise(ctx.ptr(), .getText).asObjectRef(); } @@ -4468,7 +4547,7 @@ fn BlobInterface(comptime Type: type) type { _: []const js.JSValueRef, exception: js.ExceptionRef, ) js.JSValueRef { - var value = this.getBodyValue(); + var value: *Body.Value = this.getBodyValue(); if (value.* == .Locked) { return value.Locked.setPromise(ctx.ptr(), .getJSON).asObjectRef(); } @@ -4484,7 +4563,7 @@ fn BlobInterface(comptime Type: type) type { _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { - var value = this.getBodyValue(); + var value: *Body.Value = this.getBodyValue(); if (value.* == .Locked) { return value.Locked.setPromise(ctx.ptr(), .getArrayBuffer).asObjectRef(); @@ -4502,7 +4581,8 @@ fn BlobInterface(comptime Type: type) type { _: []const js.JSValueRef, _: js.ExceptionRef, ) js.JSValueRef { - var value = this.getBodyValue(); + var value: *Body.Value = this.getBodyValue(); + if (value.* == .Locked) { return value.Locked.setPromise(ctx.ptr(), .getBlob).asObjectRef(); } diff --git a/src/javascript/jsc/webcore/streams.zig b/src/javascript/jsc/webcore/streams.zig index fea962e1e..bd0cfb133 100644 --- a/src/javascript/jsc/webcore/streams.zig +++ b/src/javascript/jsc/webcore/streams.zig @@ -51,6 +51,10 @@ pub const ReadableStream = struct { value: JSValue, ptr: Handle, + pub fn done(this: *const ReadableStream) void { + this.value.unprotect(); + } + pub const Tag = enum(i32) { Invalid = -1, |