diff options
author | 2022-06-02 03:00:45 -0700 | |
---|---|---|
committer | 2022-06-02 03:00:45 -0700 | |
commit | e5eabc0658d2133603596ec17a6e7c956c5fe28c (patch) | |
tree | 8e50a0bfa0ca9eba4145191720bb7d412bf8d26f | |
parent | 121c2960de87c53cc6bdd5f92fab627a74d21a2b (diff) | |
download | bun-e5eabc0658d2133603596ec17a6e7c956c5fe28c.tar.gz bun-e5eabc0658d2133603596ec17a6e7c956c5fe28c.tar.zst bun-e5eabc0658d2133603596ec17a6e7c956c5fe28c.zip |
Faster ReadableStream
26 files changed, 716 insertions, 645 deletions
diff --git a/src/global.zig b/src/global.zig index 868b0ad10..eb385537d 100644 --- a/src/global.zig +++ b/src/global.zig @@ -22,7 +22,7 @@ pub const auto_allocator: std.mem.Allocator = if (!use_mimalloc) else @import("./memory_allocator.zig").auto_allocator; -pub const huge_allocator_threshold = 1024 * 1024 * 2; +pub const huge_allocator_threshold: comptime_int = @import("./memory_allocator.zig").huge_threshold; pub const C = @import("c.zig"); diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig index 0b895ed82..777a5d6ef 100644 --- a/src/javascript/jsc/base.zig +++ b/src/javascript/jsc/base.zig @@ -2306,61 +2306,6 @@ pub const ArrayBuffer = extern struct { return this.toJSUnchecked(ctx, exception); } - pub fn toJSAutoAllocator(this: ArrayBuffer, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.JSValue { - if (!this.value.isEmpty()) { - return this.value; - } - - if (this.byte_len >= bun.huge_allocator_threshold) { - if (this.typed_array_type == .ArrayBuffer) { - return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy( - ctx, - this.ptr, - this.byte_len, - MmapArrayBuffer_deallocator, - @intToPtr(*anyopaque, this.byte_len), - exception, - )); - } - - return JSC.JSValue.fromRef(JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy( - ctx, - this.typed_array_type.toC(), - this.ptr, - this.byte_len, - MmapArrayBuffer_deallocator, - @intToPtr(*anyopaque, this.byte_len), - exception, - )); - } - - // If it's not a mimalloc heap buffer, we're not going to call a deallocator - if (!bun.Global.Mimalloc.mi_is_in_heap_region(this.ptr)) { - if (this.typed_array_type == .ArrayBuffer) { - return JSC.JSValue.fromRef(JSC.C.JSObjectMakeArrayBufferWithBytesNoCopy( - ctx, - this.ptr, - this.byte_len, - null, - null, - exception, - )); - } - - return JSC.JSValue.fromRef(JSC.C.JSObjectMakeTypedArrayWithBytesNoCopy( - ctx, - this.typed_array_type.toC(), - this.ptr, - this.byte_len, - null, - null, - exception, - )); - } - - return this.toJSUnchecked(ctx, exception); - } - pub fn toJSWithContext( this: ArrayBuffer, ctx: JSC.C.JSContextRef, @@ -2609,12 +2554,6 @@ pub export fn MarkedArrayBuffer_deallocator(bytes_: *anyopaque, _: *anyopaque) v mimalloc.mi_free(bytes_); } -pub export fn MmapArrayBuffer_deallocator(bytes: *anyopaque, length_as_ptr: *anyopaque) void { - const length = @ptrToInt(length_as_ptr); - var ptr = @ptrCast([*]u8, bytes); - - bun.auto_allocator.free(ptr[0..length]); -} pub export fn BlobArrayBuffer_deallocator(_: *anyopaque, blob: *anyopaque) void { // zig's memory allocator interface won't work here // mimalloc knows the size of things diff --git a/src/javascript/jsc/bindings/BunBuiltinNames.h b/src/javascript/jsc/bindings/BunBuiltinNames.h index 0acfb0bb5..e849f914d 100644 --- a/src/javascript/jsc/bindings/BunBuiltinNames.h +++ b/src/javascript/jsc/bindings/BunBuiltinNames.h @@ -67,8 +67,10 @@ using namespace JSC; macro(controlledReadableStream) \ macro(controller) \ macro(cork) \ - macro(createReadableStream) \ + macro(createFIFO) \ macro(createNativeReadableStream) \ + macro(createReadableStream) \ + macro(createUninitializedArrayBuffer) \ macro(createWritableStreamFromInternal) \ macro(cwd) \ macro(dataView) \ diff --git a/src/javascript/jsc/bindings/ReadableByteStreamControllerBuiltins.cpp b/src/javascript/jsc/bindings/ReadableByteStreamControllerBuiltins.cpp index 2532f608b..b09754494 100644 --- a/src/javascript/jsc/bindings/ReadableByteStreamControllerBuiltins.cpp +++ b/src/javascript/jsc/bindings/ReadableByteStreamControllerBuiltins.cpp @@ -131,7 +131,7 @@ const char* const s_readableByteStreamControllerCloseCode = const JSC::ConstructAbility s_readableByteStreamControllerByobRequestCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamControllerByobRequestCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamControllerByobRequestCodeLength = 759; +const int s_readableByteStreamControllerByobRequestCodeLength = 817; static const JSC::Intrinsic s_readableByteStreamControllerByobRequestCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamControllerByobRequestCode = "(function ()\n" \ @@ -141,12 +141,17 @@ const char* const s_readableByteStreamControllerByobRequestCode = " if (!@isReadableByteStreamController(this))\n" \ " throw @makeGetterTypeError(\"ReadableByteStreamController\", \"byobRequest\");\n" \ "\n" \ - " if (@getByIdDirectPrivate(this, \"byobRequest\") === @undefined && @getByIdDirectPrivate(this, \"pendingPullIntos\").length) {\n" \ - " const firstDescriptor = @getByIdDirectPrivate(this, \"pendingPullIntos\")[0];\n" \ - " const view = new @Uint8Array(firstDescriptor.buffer,\n" \ + " \n" \ + " var request = @getByIdDirectPrivate(this, \"byobRequest\");\n" \ + " if (request === @undefined) {\n" \ + " var pending = @getByIdDirectPrivate(this, \"pendingPullIntos\");\n" \ + " const firstDescriptor = pending.peek();\n" \ + " if (firstDescriptor) {\n" \ + " const view = new @Uint8Array(firstDescriptor.buffer,\n" \ " firstDescriptor.byteOffset + firstDescriptor.bytesFilled,\n" \ " firstDescriptor.byteLength - firstDescriptor.bytesFilled);\n" \ - " @putByIdDirectPrivate(this, \"byobRequest\", new @ReadableStreamBYOBRequest(this, view, @isReadableStream));\n" \ + " @putByIdDirectPrivate(this, \"byobRequest\", new @ReadableStreamBYOBRequest(this, view, @isReadableStream));\n" \ + " }\n" \ " }\n" \ "\n" \ " return @getByIdDirectPrivate(this, \"byobRequest\");\n" \ diff --git a/src/javascript/jsc/bindings/ReadableByteStreamInternalsBuiltins.cpp b/src/javascript/jsc/bindings/ReadableByteStreamInternalsBuiltins.cpp index f8faa0b4a..97dd3ba81 100644 --- a/src/javascript/jsc/bindings/ReadableByteStreamInternalsBuiltins.cpp +++ b/src/javascript/jsc/bindings/ReadableByteStreamInternalsBuiltins.cpp @@ -49,7 +49,7 @@ namespace WebCore { const JSC::ConstructAbility s_readableByteStreamInternalsPrivateInitializeReadableByteStreamControllerCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsPrivateInitializeReadableByteStreamControllerCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsPrivateInitializeReadableByteStreamControllerCodeLength = 2333; +const int s_readableByteStreamInternalsPrivateInitializeReadableByteStreamControllerCodeLength = 2344; static const JSC::Intrinsic s_readableByteStreamInternalsPrivateInitializeReadableByteStreamControllerCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsPrivateInitializeReadableByteStreamControllerCode = "(function (stream, underlyingByteSource, highWaterMark)\n" \ @@ -84,7 +84,7 @@ const char* const s_readableByteStreamInternalsPrivateInitializeReadableByteStre " @throwRangeError(\"autoAllocateChunkSize value is negative or equal to positive or negative infinity\");\n" \ " }\n" \ " @putByIdDirectPrivate(this, \"autoAllocateChunkSize\", autoAllocateChunkSize);\n" \ - " @putByIdDirectPrivate(this, \"pendingPullIntos\", []);\n" \ + " @putByIdDirectPrivate(this, \"pendingPullIntos\", @createFIFO());\n" \ "\n" \ " const controller = this;\n" \ " const startResult = @promiseInvokeOrNoopNoCatch(underlyingByteSource, \"start\", [this]).@then(() => {\n" \ @@ -166,7 +166,7 @@ const char* const s_readableByteStreamInternalsIsReadableStreamBYOBReaderCode = const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerCancelCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerCancelCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerCancelCodeLength = 392; +const int s_readableByteStreamInternalsReadableByteStreamControllerCancelCodeLength = 398; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerCancelCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerCancelCode = "(function (controller, reason)\n" \ @@ -174,8 +174,10 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerCance " \"use strict\";\n" \ "\n" \ " var pendingPullIntos = @getByIdDirectPrivate(controller, \"pendingPullIntos\");\n" \ - " if (pendingPullIntos.length > 0)\n" \ - " pendingPullIntos[0].bytesFilled = 0;\n" \ + " var first = pendingPullIntos.peek();\n" \ + " if (first)\n" \ + " first.bytesFilled = 0;\n" \ + "\n" \ " @putByIdDirectPrivate(controller, \"queue\", @newQueue());\n" \ " return @promiseInvokeOrNoop(@getByIdDirectPrivate(controller, \"underlyingByteSource\"), \"cancel\", [reason]);\n" \ "})\n" \ @@ -199,7 +201,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerError const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerCloseCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerCloseCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerCloseCodeLength = 848; +const int s_readableByteStreamInternalsReadableByteStreamControllerCloseCodeLength = 809; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerCloseCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerCloseCode = "(function (controller)\n" \ @@ -214,9 +216,9 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerClose " return;\n" \ " }\n" \ "\n" \ - " var pendingPullIntos = @getByIdDirectPrivate(controller, \"pendingPullIntos\");\n" \ - " if (pendingPullIntos.length > 0) {\n" \ - " if (pendingPullIntos[0].bytesFilled > 0) {\n" \ + " var first = @getByIdDirectPrivate(controller, \"pendingPullIntos\")?.peek();\n" \ + " if (first) {\n" \ + " if (first.bytesFilled > 0) {\n" \ " const e = @makeTypeError(\"Close requested while there remain pending bytes\");\n" \ " @readableByteStreamControllerError(controller, e);\n" \ " throw e;\n" \ @@ -229,7 +231,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerClose const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerClearPendingPullIntosCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerClearPendingPullIntosCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerClearPendingPullIntosCodeLength = 178; +const int s_readableByteStreamInternalsReadableByteStreamControllerClearPendingPullIntosCodeLength = 347; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerClearPendingPullIntosCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerClearPendingPullIntosCode = "(function (controller)\n" \ @@ -237,7 +239,12 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerClear " \"use strict\";\n" \ "\n" \ " @readableByteStreamControllerInvalidateBYOBRequest(controller);\n" \ - " @putByIdDirectPrivate(controller, \"pendingPullIntos\", []);\n" \ + " var existing = @getByIdDirectPrivate(controller, \"pendingPullIntos\");\n" \ + " if (existing !== @undefined) {\n" \ + " existing.clear();\n" \ + " } else {\n" \ + " @putByIdDirectPrivate(controller, \"pendingPullIntos\", @createFIFO());\n" \ + " }\n" \ "})\n" \ ; @@ -309,7 +316,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerHandl const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerPullCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerPullCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerPullCodeLength = 1701; +const int s_readableByteStreamInternalsReadableByteStreamControllerPullCodeLength = 1706; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerPullCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerPullCode = "(function (controller)\n" \ @@ -320,8 +327,8 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerPullC " @assert(@readableStreamHasDefaultReader(stream));\n" \ "\n" \ " if (@getByIdDirectPrivate(controller, \"queue\").size > 0) {\n" \ - " @assert(@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\").length === 0);\n" \ - " const entry = @getByIdDirectPrivate(controller, \"queue\").content.@shift();\n" \ + " @assert(@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\")?.isEmpty());\n" \ + " const entry = @getByIdDirectPrivate(controller, \"queue\").content.shift();\n" \ " @getByIdDirectPrivate(controller, \"queue\").size -= entry.byteLength;\n" \ " @readableByteStreamControllerHandleQueueDrain(controller);\n" \ " let view;\n" \ @@ -336,7 +343,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerPullC " if (@getByIdDirectPrivate(controller, \"autoAllocateChunkSize\") !== @undefined) {\n" \ " let buffer;\n" \ " try {\n" \ - " buffer = new @ArrayBuffer(@getByIdDirectPrivate(controller, \"autoAllocateChunkSize\"));\n" \ + " buffer = @createUninitializedArrayBuffer(@getByIdDirectPrivate(controller, \"autoAllocateChunkSize\"));\n" \ " } catch (error) {\n" \ " return @Promise.@reject(error);\n" \ " }\n" \ @@ -349,7 +356,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerPullC " ctor: @Uint8Array,\n" \ " readerType: 'default'\n" \ " };\n" \ - " @arrayPush(@getByIdDirectPrivate(controller, \"pendingPullIntos\"), pullIntoDescriptor);\n" \ + " @getByIdDirectPrivate(controller, \"pendingPullIntos\").push(pullIntoDescriptor);\n" \ " }\n" \ "\n" \ " const promise = @readableStreamAddReadRequest(stream);\n" \ @@ -360,7 +367,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 = 868; +const int s_readableByteStreamInternalsReadableByteStreamControllerShouldCallPullCodeLength = 874; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerShouldCallPullCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerShouldCallPullCode = "(function (controller)\n" \ @@ -375,9 +382,9 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerShoul " return false;\n" \ " if (!@getByIdDirectPrivate(controller, \"started\"))\n" \ " return false;\n" \ - " if (@readableStreamHasDefaultReader(stream) && (@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\").length > 0 || !!@getByIdDirectPrivate(reader, \"bunNativePtr\")))\n" \ + " if (@readableStreamHasDefaultReader(stream) && (@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\")?.isNotEmpty() || !!@getByIdDirectPrivate(reader, \"bunNativePtr\")))\n" \ " return true;\n" \ - " if (@readableStreamHasBYOBReader(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readIntoRequests\").length > 0)\n" \ + " if (@readableStreamHasBYOBReader(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readIntoRequests\")?.isNotEmpty())\n" \ " return true;\n" \ " if (@readableByteStreamControllerGetDesiredSize(controller) > 0)\n" \ " return true;\n" \ @@ -455,7 +462,7 @@ const char* const s_readableByteStreamInternalsReadableStreamReaderKindCode = const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerEnqueueCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerEnqueueCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerEnqueueCodeLength = 1642; +const int s_readableByteStreamInternalsReadableByteStreamControllerEnqueueCodeLength = 1649; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerEnqueueCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerEnqueueCode = "(function (controller, chunk)\n" \ @@ -471,10 +478,10 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerEnque " switch (reader ? @readableStreamReaderKind(reader) : 0) {\n" \ " \n" \ " case 1: {\n" \ - " if (!@getByIdDirectPrivate(reader, \"readRequests\").length)\n" \ + " if (!@getByIdDirectPrivate(reader, \"readRequests\")?.isNotEmpty())\n" \ " @readableByteStreamControllerEnqueueChunk(controller, @transferBufferToCurrentRealm(chunk.buffer), chunk.byteOffset, chunk.byteLength);\n" \ " else {\n" \ - " @assert(!@getByIdDirectPrivate(controller, \"queue\").content.length);\n" \ + " @assert(!@getByIdDirectPrivate(controller, \"queue\").content.size());\n" \ " const transferredView = chunk.constructor === @Uint8Array ? chunk : new @Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);\n" \ " @readableStreamFulfillReadRequest(stream, transferredView, false);\n" \ " }\n" \ @@ -506,14 +513,14 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerEnque const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerEnqueueChunkCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerEnqueueChunkCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerEnqueueChunkCodeLength = 310; +const int s_readableByteStreamInternalsReadableByteStreamControllerEnqueueChunkCodeLength = 303; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerEnqueueChunkCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerEnqueueChunkCode = "(function (controller, buffer, byteOffset, byteLength)\n" \ "{\n" \ " \"use strict\";\n" \ "\n" \ - " @arrayPush(@getByIdDirectPrivate(controller, \"queue\").content, {\n" \ + " @getByIdDirectPrivate(controller, \"queue\").content.push({\n" \ " buffer: buffer,\n" \ " byteOffset: byteOffset,\n" \ " byteLength: byteLength\n" \ @@ -524,17 +531,17 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerEnque const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerRespondWithNewViewCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerRespondWithNewViewCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerRespondWithNewViewCodeLength = 609; +const int s_readableByteStreamInternalsReadableByteStreamControllerRespondWithNewViewCodeLength = 619; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerRespondWithNewViewCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespondWithNewViewCode = "(function (controller, view)\n" \ "{\n" \ " \"use strict\";\n" \ "\n" \ - " @assert(@getByIdDirectPrivate(controller, \"pendingPullIntos\").length > 0);\n" \ - "\n" \ - " let firstDescriptor = @getByIdDirectPrivate(controller, \"pendingPullIntos\")[0];\n" \ + " @assert(@getByIdDirectPrivate(controller, \"pendingPullIntos\").isNotEmpty());\n" \ "\n" \ + " let firstDescriptor = @getByIdDirectPrivate(controller, \"pendingPullIntos\").peek();\n" \ + " \n" \ " if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset)\n" \ " @throwRangeError(\"Invalid value for view.byteOffset\");\n" \ "\n" \ @@ -548,7 +555,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespo const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerRespondCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerRespondCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerRespondCodeLength = 409; +const int s_readableByteStreamInternalsReadableByteStreamControllerRespondCodeLength = 411; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerRespondCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespondCode = "(function (controller, bytesWritten)\n" \ @@ -560,7 +567,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespo " if (@isNaN(bytesWritten) || bytesWritten === @Infinity || bytesWritten < 0 )\n" \ " @throwRangeError(\"bytesWritten has an incorrect value\");\n" \ "\n" \ - " @assert(@getByIdDirectPrivate(controller, \"pendingPullIntos\").length > 0);\n" \ + " @assert(@getByIdDirectPrivate(controller, \"pendingPullIntos\").isNotEmpty());\n" \ "\n" \ " @readableByteStreamControllerRespondInternal(controller, bytesWritten);\n" \ "})\n" \ @@ -568,14 +575,14 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespo const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerRespondInternalCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerRespondInternalCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerRespondInternalCodeLength = 708; +const int s_readableByteStreamInternalsReadableByteStreamControllerRespondInternalCodeLength = 712; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerRespondInternalCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespondInternalCode = "(function (controller, bytesWritten)\n" \ "{\n" \ " \"use strict\";\n" \ "\n" \ - " let firstDescriptor = @getByIdDirectPrivate(controller, \"pendingPullIntos\")[0];\n" \ + " let firstDescriptor = @getByIdDirectPrivate(controller, \"pendingPullIntos\").peek();\n" \ " let stream = @getByIdDirectPrivate(controller, \"controlledReadableStream\");\n" \ "\n" \ " if (@getByIdDirectPrivate(stream, \"state\") === @streamClosed) {\n" \ @@ -591,7 +598,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespo const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerRespondInReadableStateCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerRespondInReadableStateCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerRespondInReadableStateCodeLength = 1439; +const int s_readableByteStreamInternalsReadableByteStreamControllerRespondInReadableStateCodeLength = 1440; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerRespondInReadableStateCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespondInReadableStateCode = "(function (controller, bytesWritten, pullIntoDescriptor)\n" \ @@ -601,7 +608,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespo " if (pullIntoDescriptor.bytesFilled + bytesWritten > pullIntoDescriptor.byteLength)\n" \ " @throwRangeError(\"bytesWritten value is too great\");\n" \ "\n" \ - " @assert(@getByIdDirectPrivate(controller, \"pendingPullIntos\").length === 0 || @getByIdDirectPrivate(controller, \"pendingPullIntos\")[0] === pullIntoDescriptor);\n" \ + " @assert(@getByIdDirectPrivate(controller, \"pendingPullIntos\").isEmpty() || @getByIdDirectPrivate(controller, \"pendingPullIntos\").peek() === pullIntoDescriptor);\n" \ " @readableByteStreamControllerInvalidateBYOBRequest(controller);\n" \ " pullIntoDescriptor.bytesFilled += bytesWritten;\n" \ "\n" \ @@ -626,7 +633,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespo const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerRespondInClosedStateCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerRespondInClosedStateCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerRespondInClosedStateCodeLength = 727; +const int s_readableByteStreamInternalsReadableByteStreamControllerRespondInClosedStateCodeLength = 730; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerRespondInClosedStateCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespondInClosedStateCode = "(function (controller, firstDescriptor)\n" \ @@ -637,7 +644,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespo " @assert(firstDescriptor.bytesFilled === 0);\n" \ "\n" \ " if (@readableStreamHasBYOBReader(@getByIdDirectPrivate(controller, \"controlledReadableStream\"))) {\n" \ - " while (@getByIdDirectPrivate(@getByIdDirectPrivate(@getByIdDirectPrivate(controller, \"controlledReadableStream\"), \"reader\"), \"readIntoRequests\").length > 0) {\n" \ + " while (@getByIdDirectPrivate(@getByIdDirectPrivate(@getByIdDirectPrivate(controller, \"controlledReadableStream\"), \"reader\"), \"readIntoRequests\")?.isNotEmpty()) {\n" \ " let pullIntoDescriptor = @readableByteStreamControllerShiftPendingDescriptor(controller);\n" \ " @readableByteStreamControllerCommitDescriptor(@getByIdDirectPrivate(controller, \"controlledReadableStream\"), pullIntoDescriptor);\n" \ " }\n" \ @@ -647,7 +654,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerRespo const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerProcessPullDescriptorsCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerProcessPullDescriptorsCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerProcessPullDescriptorsCodeLength = 706; +const int s_readableByteStreamInternalsReadableByteStreamControllerProcessPullDescriptorsCodeLength = 712; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerProcessPullDescriptorsCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerProcessPullDescriptorsCode = "(function (controller)\n" \ @@ -655,10 +662,10 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerProce " \"use strict\";\n" \ "\n" \ " @assert(!@getByIdDirectPrivate(controller, \"closeRequested\"));\n" \ - " while (@getByIdDirectPrivate(controller, \"pendingPullIntos\").length > 0) {\n" \ + " while (@getByIdDirectPrivate(controller, \"pendingPullIntos\").isNotEmpty()) {\n" \ " if (@getByIdDirectPrivate(controller, \"queue\").size === 0)\n" \ " return;\n" \ - " let pullIntoDescriptor = @getByIdDirectPrivate(controller, \"pendingPullIntos\")[0];\n" \ + " let pullIntoDescriptor = @getByIdDirectPrivate(controller, \"pendingPullIntos\").peek();\n" \ " if (@readableByteStreamControllerFillDescriptorFromQueue(controller, pullIntoDescriptor)) {\n" \ " @readableByteStreamControllerShiftPendingDescriptor(controller);\n" \ " @readableByteStreamControllerCommitDescriptor(@getByIdDirectPrivate(controller, \"controlledReadableStream\"), pullIntoDescriptor);\n" \ @@ -669,7 +676,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerProce const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerFillDescriptorFromQueueCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerFillDescriptorFromQueueCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerFillDescriptorFromQueueCodeLength = 2355; +const int s_readableByteStreamInternalsReadableByteStreamControllerFillDescriptorFromQueueCodeLength = 2359; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerFillDescriptorFromQueueCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerFillDescriptorFromQueueCode = "(function (controller, pullIntoDescriptor)\n" \ @@ -690,7 +697,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerFillD " }\n" \ "\n" \ " while (totalBytesToCopyRemaining > 0) {\n" \ - " let headOfQueue = @getByIdDirectPrivate(controller, \"queue\").content[0];\n" \ + " let headOfQueue = @getByIdDirectPrivate(controller, \"queue\").content.peek();\n" \ " const bytesToCopy = totalBytesToCopyRemaining < headOfQueue.byteLength ? totalBytesToCopyRemaining : headOfQueue.byteLength;\n" \ " //\n" \ " //\n" \ @@ -701,14 +708,14 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerFillD " new @Uint8Array(pullIntoDescriptor.buffer).set(new @Uint8Array(headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy), destStart);\n" \ "\n" \ " if (headOfQueue.byteLength === bytesToCopy)\n" \ - " @getByIdDirectPrivate(controller, \"queue\").content.@shift();\n" \ + " @getByIdDirectPrivate(controller, \"queue\").content.shift();\n" \ " else {\n" \ " headOfQueue.byteOffset += bytesToCopy;\n" \ " headOfQueue.byteLength -= bytesToCopy;\n" \ " }\n" \ "\n" \ " @getByIdDirectPrivate(controller, \"queue\").size -= bytesToCopy;\n" \ - " @assert(@getByIdDirectPrivate(controller, \"pendingPullIntos\").length === 0 || @getByIdDirectPrivate(controller, \"pendingPullIntos\")[0] === pullIntoDescriptor);\n" \ + " @assert(@getByIdDirectPrivate(controller, \"pendingPullIntos\").isEmpty() || @getByIdDirectPrivate(controller, \"pendingPullIntos\").peek() === pullIntoDescriptor);\n" \ " @readableByteStreamControllerInvalidateBYOBRequest(controller);\n" \ " pullIntoDescriptor.bytesFilled += bytesToCopy;\n" \ " totalBytesToCopyRemaining -= bytesToCopy;\n" \ @@ -726,14 +733,14 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerFillD const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerShiftPendingDescriptorCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerShiftPendingDescriptorCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerShiftPendingDescriptorCodeLength = 223; +const int s_readableByteStreamInternalsReadableByteStreamControllerShiftPendingDescriptorCodeLength = 222; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerShiftPendingDescriptorCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerShiftPendingDescriptorCode = "(function (controller)\n" \ "{\n" \ " \"use strict\";\n" \ "\n" \ - " let descriptor = @getByIdDirectPrivate(controller, \"pendingPullIntos\").@shift();\n" \ + " let descriptor = @getByIdDirectPrivate(controller, \"pendingPullIntos\").shift();\n" \ " @readableByteStreamControllerInvalidateBYOBRequest(controller);\n" \ " return descriptor;\n" \ "})\n" \ @@ -800,13 +807,13 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerConve const JSC::ConstructAbility s_readableByteStreamInternalsReadableStreamFulfillReadIntoRequestCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableStreamFulfillReadIntoRequestCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableStreamFulfillReadIntoRequestCodeLength = 244; +const int s_readableByteStreamInternalsReadableStreamFulfillReadIntoRequestCodeLength = 243; static const JSC::Intrinsic s_readableByteStreamInternalsReadableStreamFulfillReadIntoRequestCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableStreamFulfillReadIntoRequestCode = "(function (stream, chunk, done)\n" \ "{\n" \ " \"use strict\";\n" \ - " const readIntoRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readIntoRequests\").@shift();\n" \ + " const readIntoRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readIntoRequests\").shift();\n" \ " @fulfillPromise(readIntoRequest, { value: chunk, done: done });\n" \ "})\n" \ ; @@ -833,7 +840,7 @@ const char* const s_readableByteStreamInternalsReadableStreamBYOBReaderReadCode const JSC::ConstructAbility s_readableByteStreamInternalsReadableByteStreamControllerPullIntoCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableByteStreamControllerPullIntoCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableByteStreamControllerPullIntoCodeLength = 2216; +const int s_readableByteStreamInternalsReadableByteStreamControllerPullIntoCodeLength = 2190; static const JSC::Intrinsic s_readableByteStreamInternalsReadableByteStreamControllerPullIntoCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableByteStreamControllerPullIntoCode = "(function (controller, view)\n" \ @@ -873,9 +880,10 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerPullI " readerType: 'byob'\n" \ " };\n" \ "\n" \ - " if (@getByIdDirectPrivate(controller, \"pendingPullIntos\").length) {\n" \ + " var pending = @getByIdDirectPrivate(controller, \"pendingPullIntos\");\n" \ + " if (pending?.isNotEmpty()) {\n" \ " pullIntoDescriptor.buffer = @transferBufferToCurrentRealm(pullIntoDescriptor.buffer);\n" \ - " @arrayPush(@getByIdDirectPrivate(controller, \"pendingPullIntos\"), pullIntoDescriptor);\n" \ + " pending.push(pullIntoDescriptor);\n" \ " return @readableStreamAddReadIntoRequest(stream);\n" \ " }\n" \ "\n" \ @@ -898,7 +906,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerPullI " }\n" \ "\n" \ " pullIntoDescriptor.buffer = @transferBufferToCurrentRealm(pullIntoDescriptor.buffer);\n" \ - " @arrayPush(@getByIdDirectPrivate(controller, \"pendingPullIntos\"), pullIntoDescriptor);\n" \ + " @getByIdDirectPrivate(controller, \"pendingPullIntos\").push(pullIntoDescriptor);\n" \ " const promise = @readableStreamAddReadIntoRequest(stream);\n" \ " @readableByteStreamControllerCallPullIfNeeded(controller);\n" \ " return promise;\n" \ @@ -907,7 +915,7 @@ const char* const s_readableByteStreamInternalsReadableByteStreamControllerPullI const JSC::ConstructAbility s_readableByteStreamInternalsReadableStreamAddReadIntoRequestCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableByteStreamInternalsReadableStreamAddReadIntoRequestCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableByteStreamInternalsReadableStreamAddReadIntoRequestCodeLength = 437; +const int s_readableByteStreamInternalsReadableStreamAddReadIntoRequestCodeLength = 430; static const JSC::Intrinsic s_readableByteStreamInternalsReadableStreamAddReadIntoRequestCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableByteStreamInternalsReadableStreamAddReadIntoRequestCode = "(function (stream)\n" \ @@ -918,7 +926,7 @@ const char* const s_readableByteStreamInternalsReadableStreamAddReadIntoRequestC " @assert(@getByIdDirectPrivate(stream, \"state\") === @streamReadable || @getByIdDirectPrivate(stream, \"state\") === @streamClosed);\n" \ "\n" \ " const readRequest = @newPromise();\n" \ - " @arrayPush(@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readIntoRequests\"), readRequest);\n" \ + " @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readIntoRequests\").push(readRequest);\n" \ "\n" \ " return readRequest;\n" \ "})\n" \ diff --git a/src/javascript/jsc/bindings/ReadableStreamBYOBReaderBuiltins.cpp b/src/javascript/jsc/bindings/ReadableStreamBYOBReaderBuiltins.cpp index c6514f616..81486dffe 100644 --- a/src/javascript/jsc/bindings/ReadableStreamBYOBReaderBuiltins.cpp +++ b/src/javascript/jsc/bindings/ReadableStreamBYOBReaderBuiltins.cpp @@ -49,7 +49,7 @@ namespace WebCore { const JSC::ConstructAbility s_readableStreamBYOBReaderInitializeReadableStreamBYOBReaderCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamBYOBReaderInitializeReadableStreamBYOBReaderCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamBYOBReaderInitializeReadableStreamBYOBReaderCodeLength = 574; +const int s_readableStreamBYOBReaderInitializeReadableStreamBYOBReaderCodeLength = 585; static const JSC::Intrinsic s_readableStreamBYOBReaderInitializeReadableStreamBYOBReaderCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamBYOBReaderInitializeReadableStreamBYOBReaderCode = "(function (stream)\n" \ @@ -64,7 +64,7 @@ const char* const s_readableStreamBYOBReaderInitializeReadableStreamBYOBReaderCo " @throwTypeError(\"ReadableStream is locked\");\n" \ "\n" \ " @readableStreamReaderGenericInitialize(this, stream);\n" \ - " @putByIdDirectPrivate(this, \"readIntoRequests\", []);\n" \ + " @putByIdDirectPrivate(this, \"readIntoRequests\", @createFIFO());\n" \ "\n" \ " return this;\n" \ "})\n" \ @@ -119,7 +119,7 @@ const char* const s_readableStreamBYOBReaderReadCode = const JSC::ConstructAbility s_readableStreamBYOBReaderReleaseLockCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamBYOBReaderReleaseLockCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamBYOBReaderReleaseLockCodeLength = 440; +const int s_readableStreamBYOBReaderReleaseLockCodeLength = 447; static const JSC::Intrinsic s_readableStreamBYOBReaderReleaseLockCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamBYOBReaderReleaseLockCode = "(function ()\n" \ @@ -132,7 +132,7 @@ const char* const s_readableStreamBYOBReaderReleaseLockCode = " if (!@getByIdDirectPrivate(this, \"ownerReadableStream\"))\n" \ " return;\n" \ "\n" \ - " if (@getByIdDirectPrivate(this, \"readIntoRequests\").length)\n" \ + " if (@getByIdDirectPrivate(this, \"readIntoRequests\")?.isNotEmpty())\n" \ " @throwTypeError(\"There are still pending read requests, cannot release the lock\");\n" \ "\n" \ " @readableStreamReaderGenericRelease(this);\n" \ diff --git a/src/javascript/jsc/bindings/ReadableStreamBuiltins.cpp b/src/javascript/jsc/bindings/ReadableStreamBuiltins.cpp index a268cf2ce..68155a460 100644 --- a/src/javascript/jsc/bindings/ReadableStreamBuiltins.cpp +++ b/src/javascript/jsc/bindings/ReadableStreamBuiltins.cpp @@ -119,82 +119,73 @@ const char* const s_readableStreamInitializeReadableStreamCode = const JSC::ConstructAbility s_readableStreamCreateNativeReadableStreamCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamCreateNativeReadableStreamCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamCreateNativeReadableStreamCodeLength = 2905; +const int s_readableStreamCreateNativeReadableStreamCodeLength = 3152; static const JSC::Intrinsic s_readableStreamCreateNativeReadableStreamCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamCreateNativeReadableStreamCode = - "(function (nativePtr, nativeType) {\n" \ + "(function (nativePtr, nativeType, autoAllocateChunkSize) {\n" \ " \"use strict\";\n" \ " var cached = globalThis[Symbol.for(\"Bun.nativeReadableStreamPrototype\")] ||= new @Map;\n" \ " var Prototype = cached.@get(nativeType);\n" \ " if (Prototype === @undefined) {\n" \ " var [pull, start, cancel, setClose, deinit] = globalThis[Symbol.for(\"Bun.lazy\")](nativeType);\n" \ " var closer = [false];\n" \ - "\n" \ + "var handleResult;\n" \ " function handleNativeReadableStreamPromiseResult(val) {\n" \ " \"use strict\";\n" \ - " var {r, c} = this;\n" \ - " this.r = @undefined;\n" \ + " var {c, v} = this;\n" \ " this.c = @undefined;\n" \ - " r(val, c);\n" \ + " this.v = @undefined;\n" \ + " closer[0] = false;\n" \ + " handleResult(val, c, v);\n" \ " }\n" \ " \n" \ - " function closeNativeReadableStreamOnNextTick(controller) {\n" \ - " \"use strict\";\n" \ - " controller.close();\n" \ - " controller = @undefined;\n" \ - " } \n" \ - "\n" \ - " var handleResult = function handleResult(result, controller) {\n" \ + " \n" \ + " handleResult = function handleResult(result, controller, view) {\n" \ " \"use strict\";\n" \ "\n" \ " if (result && @isPromise(result)) {\n" \ - " return result.then(handleNativeReadableStreamPromiseResult.bind({c: controller, r: handleResult}), controller.error);\n" \ + " return result.then(handleNativeReadableStreamPromiseResult.bind({c: controller, v: view}), (err) => controller.error(err));\n" \ " } else if (result !== false) {\n" \ - " controller.enqueue(result);\n" \ + " if (view && view.byteLength === result) {\n" \ + " controller.byobRequest.respondWithNewView(view);\n" \ + " } else {\n" \ + " controller.byobRequest.respond(result);\n" \ + " }\n" \ " }\n" \ "\n" \ " if (closer[0] || result === false) {\n" \ - " @enqueueJob(closeNativeReadableStreamOnNextTick, controller);\n" \ + " @enqueueJob(() => controller.close());\n" \ " closer[0] = false;\n" \ " }\n" \ - " }\n" \ + " };\n" \ "\n" \ " Prototype = class NativeReadableStreamSource {\n" \ - " constructor(tag) {\n" \ + " constructor(tag, autoAllocateChunkSize) {\n" \ " this.pull = this.pull_.bind(tag);\n" \ - " this.start = this.start_.bind(tag);\n" \ " this.cancel = this.cancel_.bind(tag);\n" \ + " this.autoAllocateChunkSize = autoAllocateChunkSize;\n" \ " }\n" \ "\n" \ " pull;\n" \ - " start;\n" \ " cancel;\n" \ - " \n" \ - " pull_(controller) {\n" \ - " closer[0] = false;\n" \ - " var result;\n" \ - "\n" \ - " try {\n" \ - " result = pull(this, closer);\n" \ - " } catch(err) {\n" \ - " return controller.error(err);\n" \ - " }\n" \ "\n" \ - " return handleResult(result, controller);\n" \ - " }\n" \ + " type = \"bytes\";\n" \ + " autoAllocateChunkSize = 0;\n" \ "\n" \ - " start_(controller) {\n" \ - " setClose(this, controller.close);\n" \ + " static startSync = start;\n" \ + " \n" \ + " pull_(controller) {\n" \ " closer[0] = false;\n" \ " var result;\n" \ "\n" \ + " const view = controller.byobRequest.view;\n" \ " try {\n" \ - " result = start(this, closer);\n" \ + " result = pull(this, view, closer);\n" \ " } catch(err) {\n" \ " return controller.error(err);\n" \ " }\n" \ "\n" \ - " return handleResult(result, controller);\n" \ + " return handleResult(result, controller, view);\n" \ " }\n" \ "\n" \ " cancel_(reason) {\n" \ @@ -206,7 +197,29 @@ const char* const s_readableStreamCreateNativeReadableStreamCode = " cached.@set(nativeType, Prototype);\n" \ " }\n" \ " \n" \ - " var instance = new Prototype(nativePtr);\n" \ + " //\n" \ + " //\n" \ + " //\n" \ + " const chunkSize = Prototype.startSync(nativePtr, autoAllocateChunkSize);\n" \ + "\n" \ + " //\n" \ + " if (chunkSize === 0) {\n" \ + " return new @ReadableStream({\n" \ + " start(controller) {\n" \ + " controller.close();\n" \ + " },\n" \ + "\n" \ + " pull() {\n" \ + "\n" \ + " },\n" \ + "\n" \ + " cancel() {\n" \ + "\n" \ + " },\n" \ + " });\n" \ + " }\n" \ + "\n" \ + " var instance = new Prototype(nativePtr, chunkSize);\n" \ " Prototype.registry.register(instance, nativePtr);\n" \ " var stream = new @ReadableStream(instance);\n" \ " @putByIdDirectPrivate(stream, \"bunNativeType\", nativeType);\n" \ diff --git a/src/javascript/jsc/bindings/ReadableStreamBuiltins.h b/src/javascript/jsc/bindings/ReadableStreamBuiltins.h index ccf3e9b7c..2cd7f6b6e 100644 --- a/src/javascript/jsc/bindings/ReadableStreamBuiltins.h +++ b/src/javascript/jsc/bindings/ReadableStreamBuiltins.h @@ -82,7 +82,7 @@ extern const JSC::ConstructorKind s_readableStreamLockedCodeConstructorKind; #define WEBCORE_FOREACH_READABLESTREAM_BUILTIN_DATA(macro) \ macro(initializeReadableStream, readableStreamInitializeReadableStream, 2) \ - macro(createNativeReadableStream, readableStreamCreateNativeReadableStream, 2) \ + macro(createNativeReadableStream, readableStreamCreateNativeReadableStream, 3) \ macro(cancel, readableStreamCancel, 1) \ macro(getReader, readableStreamGetReader, 1) \ macro(pipeThrough, readableStreamPipeThrough, 2) \ diff --git a/src/javascript/jsc/bindings/ReadableStreamDefaultReaderBuiltins.cpp b/src/javascript/jsc/bindings/ReadableStreamDefaultReaderBuiltins.cpp index e1933d425..f488ffea0 100644 --- a/src/javascript/jsc/bindings/ReadableStreamDefaultReaderBuiltins.cpp +++ b/src/javascript/jsc/bindings/ReadableStreamDefaultReaderBuiltins.cpp @@ -49,7 +49,7 @@ namespace WebCore { const JSC::ConstructAbility s_readableStreamDefaultReaderInitializeReadableStreamDefaultReaderCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamDefaultReaderInitializeReadableStreamDefaultReaderCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamDefaultReaderInitializeReadableStreamDefaultReaderCodeLength = 382; +const int s_readableStreamDefaultReaderInitializeReadableStreamDefaultReaderCodeLength = 393; static const JSC::Intrinsic s_readableStreamDefaultReaderInitializeReadableStreamDefaultReaderCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamDefaultReaderInitializeReadableStreamDefaultReaderCode = "(function (stream)\n" \ @@ -62,7 +62,7 @@ const char* const s_readableStreamDefaultReaderInitializeReadableStreamDefaultRe " @throwTypeError(\"ReadableStream is locked\");\n" \ "\n" \ " @readableStreamReaderGenericInitialize(this, stream);\n" \ - " @putByIdDirectPrivate(this, \"readRequests\", []);\n" \ + " @putByIdDirectPrivate(this, \"readRequests\", @createFIFO());\n" \ "\n" \ " return this;\n" \ "})\n" \ @@ -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 = 3797; +const int s_readableStreamDefaultReaderReadManyCodeLength = 2136; static const JSC::Intrinsic s_readableStreamDefaultReaderReadManyCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamDefaultReaderReadManyCode = "(function ()\n" \ @@ -111,30 +111,14 @@ const char* const s_readableStreamDefaultReaderReadManyCode = " throw @getByIdDirectPrivate(stream, \"storedError\");\n" \ " }\n" \ "\n" \ - " const controller = @getByIdDirectPrivate(stream, \"readableStreamController\");\n" \ + " var controller = @getByIdDirectPrivate(stream, \"readableStreamController\");\n" \ " \n" \ " const content = @getByIdDirectPrivate(controller, \"queue\").content;\n" \ " var size = @getByIdDirectPrivate(controller, \"queue\").size;\n" \ + " var values = content.toArray(false);\n" \ + " var length = values.length;\n" \ "\n" \ - " var values = new @Array(content.length);\n" \ - "\n" \ - " if (content.length > 0) {\n" \ - " if (\"buffer\" in content[0]) {\n" \ - " values[0] = new @Uint8Array(content[0].buffer, content[0].byteOffset, content[0].byteLength);\n" \ - " for (var i = 0; i < content.length; ++i) {\n" \ - " @putByValDirect(values, i+1, new @Uint8Array(content[i].buffer, content[i].byteOffset, content[i].byteLength));\n" \ - " }\n" \ - " } else if (typeof content[0] === 'object' && content[0] && \"byteLength\" in content[0]) {\n" \ - " size = 0;\n" \ - " for (var i = 0; i < content.length; ++i) {\n" \ - " @putByValDirect(values, i+1, content[i].value);\n" \ - " size += content[i].value.byteLength;\n" \ - " }\n" \ - " } else {\n" \ - " for (var i = 0; i < content.length; ++i) {\n" \ - " @putByValDirect(values, i+1, content[i].value);\n" \ - " }\n" \ - " }\n" \ + " if (length > 0) {\n" \ " @resetQueue(@getByIdDirectPrivate(controller, \"queue\"));\n" \ "\n" \ " if (@getByIdDirectPrivate(controller, \"closeRequested\"))\n" \ @@ -146,44 +130,23 @@ const char* const s_readableStreamDefaultReaderReadManyCode = " if (done) {\n" \ " return {value: [], size: 0, done: true};\n" \ " }\n" \ - "\n" \ - " const content = queue.content;\n" \ - " var values = new @Array(content.length + 1);\n" \ - " \n" \ + " var queue = @getByIdDirectPrivate(controller, \"queue\");\n" \ + " const content = [value].concat(queue.content.toArray(false));\n" \ " var size = queue.size;\n" \ - "\n" \ - " if (\"buffer\" in content[0]) {\n" \ - " values[0] = new @Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n" \ - " for (var i = 0; i < content.length; ++i) {\n" \ - " @putByValDirect(values, i+1, new @Uint8Array(content[i].buffer, content[i].byteOffset, content[i].byteLength));\n" \ - " }\n" \ - " size += value.byteLength;\n" \ - " } else if (typeof value === 'object' && value && \"byteLength\" in value) {\n" \ - " size += value.byteLength;\n" \ - " values[0] = value;\n" \ - " for (var i = 0; i < content.length; ++i) {\n" \ - " @putByValDirect(values, i+1, content[i].value);\n" \ - " size += content[i].value.byteLength;\n" \ - " }\n" \ - "\n" \ - " } else {\n" \ - " values[0] = value;\n" \ - " for (var i = 0; i < content.length; ++i) {\n" \ - " @putByValDirect(values, i+1, content[i].value);\n" \ - " }\n" \ - " }\n" \ - "\n" \ " @resetQueue(queue);\n" \ "\n" \ " if (@getByIdDirectPrivate(controller, \"closeRequested\"))\n" \ " @readableStreamClose(@getByIdDirectPrivate(controller, \"controlledReadableStream\"));\n" \ " else\n" \ " @readableStreamDefaultControllerCallPullIfNeeded(controller);\n" \ + " controller = @undefined;\n" \ "\n" \ " return {value: values, size: size, done: false};\n" \ " });\n" \ " }\n" \ "\n" \ + " controller = @undefined;\n" \ + "\n" \ " return {value: values, size, done: false};\n" \ "})\n" \ ; @@ -208,7 +171,7 @@ const char* const s_readableStreamDefaultReaderReadCode = const JSC::ConstructAbility s_readableStreamDefaultReaderReleaseLockCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamDefaultReaderReleaseLockCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamDefaultReaderReleaseLockCodeLength = 442; +const int s_readableStreamDefaultReaderReleaseLockCodeLength = 449; static const JSC::Intrinsic s_readableStreamDefaultReaderReleaseLockCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamDefaultReaderReleaseLockCode = "(function ()\n" \ @@ -221,7 +184,7 @@ const char* const s_readableStreamDefaultReaderReleaseLockCode = " if (!@getByIdDirectPrivate(this, \"ownerReadableStream\"))\n" \ " return;\n" \ "\n" \ - " if (@getByIdDirectPrivate(this, \"readRequests\").length)\n" \ + " if (@getByIdDirectPrivate(this, \"readRequests\")?.isNotEmpty())\n" \ " @throwTypeError(\"There are still pending read requests, cannot release the lock\");\n" \ "\n" \ " @readableStreamReaderGenericRelease(this);\n" \ diff --git a/src/javascript/jsc/bindings/ReadableStreamInternalsBuiltins.cpp b/src/javascript/jsc/bindings/ReadableStreamInternalsBuiltins.cpp index 99ef5176a..b7ae6f1df 100644 --- a/src/javascript/jsc/bindings/ReadableStreamInternalsBuiltins.cpp +++ b/src/javascript/jsc/bindings/ReadableStreamInternalsBuiltins.cpp @@ -688,7 +688,7 @@ const char* const s_readableStreamInternalsIsReadableStreamDefaultControllerCode const JSC::ConstructAbility s_readableStreamInternalsReadableStreamErrorCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamInternalsReadableStreamErrorCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamInternalsReadableStreamErrorCodeLength = 1283; +const int s_readableStreamInternalsReadableStreamErrorCodeLength = 1295; static const JSC::Intrinsic s_readableStreamInternalsReadableStreamErrorCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamInternalsReadableStreamErrorCode = "(function (stream, error)\n" \ @@ -707,15 +707,15 @@ const char* const s_readableStreamInternalsReadableStreamErrorCode = "\n" \ " if (@isReadableStreamDefaultReader(reader)) {\n" \ " const requests = @getByIdDirectPrivate(reader, \"readRequests\");\n" \ - " @putByIdDirectPrivate(reader, \"readRequests\", []);\n" \ - " for (let index = 0, length = requests.length; index < length; ++index)\n" \ - " @rejectPromise(requests[index], error);\n" \ + " @putByIdDirectPrivate(reader, \"readRequests\", @createFIFO());\n" \ + " for (var request = requests.shift(); request; request = requests.shift())\n" \ + " @rejectPromise(request, error);\n" \ " } else {\n" \ " @assert(@isReadableStreamBYOBReader(reader));\n" \ " const requests = @getByIdDirectPrivate(reader, \"readIntoRequests\");\n" \ - " @putByIdDirectPrivate(reader, \"readIntoRequests\", []);\n" \ - " for (let index = 0, length = requests.length; index < length; ++index)\n" \ - " @rejectPromise(requests[index], error);\n" \ + " @putByIdDirectPrivate(reader, \"readIntoRequests\", @createFIFO());\n" \ + " for (var request = requests.shift(); request; request = requests.shift())\n" \ + " @rejectPromise(request, error);\n" \ " }\n" \ "\n" \ " @getByIdDirectPrivate(reader, \"closedPromiseCapability\").@reject.@call(@undefined, error);\n" \ @@ -726,7 +726,7 @@ const char* const s_readableStreamInternalsReadableStreamErrorCode = const JSC::ConstructAbility s_readableStreamInternalsReadableStreamDefaultControllerShouldCallPullCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamInternalsReadableStreamDefaultControllerShouldCallPullCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamInternalsReadableStreamDefaultControllerShouldCallPullCodeLength = 652; +const int s_readableStreamInternalsReadableStreamDefaultControllerShouldCallPullCodeLength = 659; static const JSC::Intrinsic s_readableStreamInternalsReadableStreamDefaultControllerShouldCallPullCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamInternalsReadableStreamDefaultControllerShouldCallPullCode = "(function (controller)\n" \ @@ -737,7 +737,7 @@ const char* const s_readableStreamInternalsReadableStreamDefaultControllerShould " return false;\n" \ " if (!@getByIdDirectPrivate(controller, \"started\"))\n" \ " return false;\n" \ - " if ((!@isReadableStreamLocked(stream) || !@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\").length) && @readableStreamDefaultControllerGetDesiredSize(controller) <= 0)\n" \ + " if ((!@isReadableStreamLocked(stream) || !@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\")?.isNotEmpty()) && @readableStreamDefaultControllerGetDesiredSize(controller) <= 0)\n" \ " return false;\n" \ " const desiredSize = @readableStreamDefaultControllerGetDesiredSize(controller);\n" \ " @assert(desiredSize !== null);\n" \ @@ -747,7 +747,7 @@ const char* const s_readableStreamInternalsReadableStreamDefaultControllerShould const JSC::ConstructAbility s_readableStreamInternalsReadableStreamDefaultControllerCallPullIfNeededCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamInternalsReadableStreamDefaultControllerCallPullIfNeededCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamInternalsReadableStreamDefaultControllerCallPullIfNeededCodeLength = 1239; +const int s_readableStreamInternalsReadableStreamDefaultControllerCallPullIfNeededCodeLength = 1246; static const JSC::Intrinsic s_readableStreamInternalsReadableStreamDefaultControllerCallPullIfNeededCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamInternalsReadableStreamDefaultControllerCallPullIfNeededCode = "(function (controller)\n" \ @@ -761,7 +761,7 @@ const char* const s_readableStreamInternalsReadableStreamDefaultControllerCallPu " return;\n" \ " if (!@getByIdDirectPrivate(controller, \"started\"))\n" \ " return;\n" \ - " if ((!@isReadableStreamLocked(stream) || !@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\").length) && @readableStreamDefaultControllerGetDesiredSize(controller) <= 0)\n" \ + " if ((!@isReadableStreamLocked(stream) || !@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\")?.isNotEmpty()) && @readableStreamDefaultControllerGetDesiredSize(controller) <= 0)\n" \ " return;\n" \ "\n" \ " if (@getByIdDirectPrivate(controller, \"pulling\")) {\n" \ @@ -870,16 +870,17 @@ const char* const s_readableStreamInternalsReadableStreamDefaultControllerCancel const JSC::ConstructAbility s_readableStreamInternalsReadableStreamDefaultControllerPullCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamInternalsReadableStreamDefaultControllerPullCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamInternalsReadableStreamDefaultControllerPullCodeLength = 805; +const int s_readableStreamInternalsReadableStreamDefaultControllerPullCodeLength = 742; static const JSC::Intrinsic s_readableStreamInternalsReadableStreamDefaultControllerPullCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamInternalsReadableStreamDefaultControllerPullCode = "(function (controller)\n" \ "{\n" \ " \"use strict\";\n" \ "\n" \ - " if (@getByIdDirectPrivate(controller, \"queue\").content.length) {\n" \ - " const chunk = @dequeueValue(@getByIdDirectPrivate(controller, \"queue\"));\n" \ - " if (@getByIdDirectPrivate(controller, \"closeRequested\") && @getByIdDirectPrivate(controller, \"queue\").content.length === 0)\n" \ + " var queue = @getByIdDirectPrivate(controller, \"queue\");\n" \ + " if (queue.isNotEmpty()) {\n" \ + " const chunk = @dequeueValue(queue);\n" \ + " if (@getByIdDirectPrivate(controller, \"closeRequested\") && queue.isEmpty())\n" \ " @readableStreamClose(@getByIdDirectPrivate(controller, \"controlledReadableStream\"));\n" \ " else\n" \ " @readableStreamDefaultControllerCallPullIfNeeded(controller);\n" \ @@ -894,7 +895,7 @@ const char* const s_readableStreamInternalsReadableStreamDefaultControllerPullCo const JSC::ConstructAbility s_readableStreamInternalsReadableStreamDefaultControllerCloseCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamInternalsReadableStreamDefaultControllerCloseCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamInternalsReadableStreamDefaultControllerCloseCodeLength = 352; +const int s_readableStreamInternalsReadableStreamDefaultControllerCloseCodeLength = 346; static const JSC::Intrinsic s_readableStreamInternalsReadableStreamDefaultControllerCloseCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamInternalsReadableStreamDefaultControllerCloseCode = "(function (controller)\n" \ @@ -903,14 +904,14 @@ const char* const s_readableStreamInternalsReadableStreamDefaultControllerCloseC "\n" \ " @assert(@readableStreamDefaultControllerCanCloseOrEnqueue(controller));\n" \ " @putByIdDirectPrivate(controller, \"closeRequested\", true);\n" \ - " if (@getByIdDirectPrivate(controller, \"queue\").content.length === 0)\n" \ + " if (!@getByIdDirectPrivate(controller, \"queue\")?.isNotEmpty())\n" \ " @readableStreamClose(@getByIdDirectPrivate(controller, \"controlledReadableStream\"));\n" \ "})\n" \ ; const JSC::ConstructAbility s_readableStreamInternalsReadableStreamCloseCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamInternalsReadableStreamCloseCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamInternalsReadableStreamCloseCodeLength = 697; +const int s_readableStreamInternalsReadableStreamCloseCodeLength = 712; static const JSC::Intrinsic s_readableStreamInternalsReadableStreamCloseCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamInternalsReadableStreamCloseCode = "(function (stream)\n" \ @@ -926,9 +927,10 @@ const char* const s_readableStreamInternalsReadableStreamCloseCode = "\n" \ " if (@isReadableStreamDefaultReader(reader)) {\n" \ " const requests = @getByIdDirectPrivate(reader, \"readRequests\");\n" \ - " @putByIdDirectPrivate(reader, \"readRequests\", []);\n" \ - " for (let index = 0, length = requests.length; index < length; ++index)\n" \ - " @fulfillPromise(requests[index], { value: @undefined, done: true });\n" \ + " @putByIdDirectPrivate(reader, \"readRequests\", @createFIFO());\n" \ + " \n" \ + " for (var request = requests.shift(); request; request = requests.shift())\n" \ + " @fulfillPromise(request, { value: @undefined, done: true });\n" \ " }\n" \ "\n" \ " @getByIdDirectPrivate(reader, \"closedPromiseCapability\").@resolve.@call();\n" \ @@ -937,20 +939,20 @@ const char* const s_readableStreamInternalsReadableStreamCloseCode = const JSC::ConstructAbility s_readableStreamInternalsReadableStreamFulfillReadRequestCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamInternalsReadableStreamFulfillReadRequestCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamInternalsReadableStreamFulfillReadRequestCodeLength = 232; +const int s_readableStreamInternalsReadableStreamFulfillReadRequestCodeLength = 231; static const JSC::Intrinsic s_readableStreamInternalsReadableStreamFulfillReadRequestCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamInternalsReadableStreamFulfillReadRequestCode = "(function (stream, chunk, done)\n" \ "{\n" \ " \"use strict\";\n" \ - " const readRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\").@shift();\n" \ + " const readRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\").shift();\n" \ " @fulfillPromise(readRequest, { value: chunk, done: done });\n" \ "})\n" \ ; const JSC::ConstructAbility s_readableStreamInternalsReadableStreamDefaultControllerEnqueueCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamInternalsReadableStreamDefaultControllerEnqueueCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamInternalsReadableStreamDefaultControllerEnqueueCodeLength = 986; +const int s_readableStreamInternalsReadableStreamDefaultControllerEnqueueCodeLength = 990; static const JSC::Intrinsic s_readableStreamInternalsReadableStreamDefaultControllerEnqueueCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamInternalsReadableStreamDefaultControllerEnqueueCode = "(function (controller, chunk)\n" \ @@ -961,7 +963,7 @@ const char* const s_readableStreamInternalsReadableStreamDefaultControllerEnqueu " //\n" \ " @assert(@readableStreamDefaultControllerCanCloseOrEnqueue(controller));\n" \ "\n" \ - " if (@isReadableStreamLocked(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\").length) {\n" \ + " if (@isReadableStreamLocked(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\").isNotEmpty) {\n" \ " @readableStreamFulfillReadRequest(stream, chunk, false);\n" \ " @readableStreamDefaultControllerCallPullIfNeeded(controller);\n" \ " return;\n" \ @@ -1007,7 +1009,7 @@ const char* const s_readableStreamInternalsReadableStreamDefaultReaderReadCode = const JSC::ConstructAbility s_readableStreamInternalsReadableStreamAddReadRequestCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_readableStreamInternalsReadableStreamAddReadRequestCodeConstructorKind = JSC::ConstructorKind::None; -const int s_readableStreamInternalsReadableStreamAddReadRequestCodeLength = 375; +const int s_readableStreamInternalsReadableStreamAddReadRequestCodeLength = 373; static const JSC::Intrinsic s_readableStreamInternalsReadableStreamAddReadRequestCodeIntrinsic = JSC::NoIntrinsic; const char* const s_readableStreamInternalsReadableStreamAddReadRequestCode = "(function (stream)\n" \ @@ -1018,7 +1020,8 @@ const char* const s_readableStreamInternalsReadableStreamAddReadRequestCode = " @assert(@getByIdDirectPrivate(stream, \"state\") == @streamReadable);\n" \ "\n" \ " const readRequest = @newPromise();\n" \ - " @arrayPush(@getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\"), readRequest);\n" \ + " \n" \ + " @getByIdDirectPrivate(@getByIdDirectPrivate(stream, \"reader\"), \"readRequests\").push(readRequest);\n" \ "\n" \ " return readRequest;\n" \ "})\n" \ diff --git a/src/javascript/jsc/bindings/StreamInternalsBuiltins.cpp b/src/javascript/jsc/bindings/StreamInternalsBuiltins.cpp index 41b6a4532..2203ed2f2 100644 --- a/src/javascript/jsc/bindings/StreamInternalsBuiltins.cpp +++ b/src/javascript/jsc/bindings/StreamInternalsBuiltins.cpp @@ -183,29 +183,135 @@ const char* const s_streamInternalsValidateAndNormalizeQueuingStrategyCode = "})\n" \ ; +const JSC::ConstructAbility s_streamInternalsCreateFIFOCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; +const JSC::ConstructorKind s_streamInternalsCreateFIFOCodeConstructorKind = JSC::ConstructorKind::None; +const int s_streamInternalsCreateFIFOCodeLength = 2764; +static const JSC::Intrinsic s_streamInternalsCreateFIFOCodeIntrinsic = JSC::NoIntrinsic; +const char* const s_streamInternalsCreateFIFOCode = + "(function () {\n" \ + " \"use strict\";\n" \ + " class Denqueue {\n" \ + " constructor() {\n" \ + " this._head = 0;\n" \ + " this._tail = 0;\n" \ + " //\n" \ + " this._capacityMask = 0x3;\n" \ + " this._list = @newArrayWithSize(4);\n" \ + " }\n" \ + " \n" \ + " size() {\n" \ + " if (this._head === this._tail) return 0;\n" \ + " if (this._head < this._tail) return this._tail - this._head;\n" \ + " else return this._capacityMask + 1 - (this._head - this._tail);\n" \ + " }\n" \ + "\n" \ + " isEmpty() {\n" \ + " return this.size() == 0;\n" \ + " }\n" \ + "\n" \ + " isNotEmpty() {\n" \ + " return this.size() > 0;\n" \ + " }\n" \ + " \n" \ + " shift() {\n" \ + " var head = this._head;\n" \ + " if (head === this._tail) return @undefined;\n" \ + " var item = this._list[head];\n" \ + " @putByValDirect(this._list, head, @undefined);\n" \ + " this._head = (head + 1) & this._capacityMask;\n" \ + " if (head < 2 && this._tail > 10000 && this._tail <= this._list.length >>> 2) this._shrinkArray();\n" \ + " return item;\n" \ + " }\n" \ + "\n" \ + " peek() {\n" \ + " if (this._head === this._tail) return @undefined;\n" \ + " return this._list[this._head];\n" \ + " }\n" \ + " \n" \ + " push(item) {\n" \ + " var tail = this._tail;\n" \ + " @putByValDirect(this._list, tail, item);\n" \ + " this._tail = (tail + 1) & this._capacityMask;\n" \ + " if (this._tail === this._head) {\n" \ + " this._growArray();\n" \ + " }\n" \ + " //\n" \ + " //\n" \ + " //\n" \ + " }\n" \ + " \n" \ + " toArray(fullCopy) {\n" \ + " var list = this._list;\n" \ + " var len = @toLength(list.length);\n" \ + " \n" \ + " if (fullCopy || this._head > this._tail) {\n" \ + " var _head = @toLength(this._head);\n" \ + " var _tail = @toLength(this._tail);\n" \ + " var total = @toLength((len - _head) + _tail);\n" \ + " var array = @newArrayWithSize(total);\n" \ + " var j = 0;\n" \ + " for (var i = _head; i < len; i++) @putByValDirect(array, j++, list[i]);\n" \ + " for (var i = 0; i < _tail; i++) @putByValDirect(array, j++, list[i]);\n" \ + " return array;\n" \ + " } else {\n" \ + " return @Array.prototype.slice.@call(list, this._head, this._tail);\n" \ + " }\n" \ + " }\n" \ + " \n" \ + " clear() {\n" \ + " this._head = 0;\n" \ + " this._tail = 0;\n" \ + " this._list.fill(undefined);\n" \ + " }\n" \ + "\n" \ + " _growArray() {\n" \ + " if (this._head) {\n" \ + " //\n" \ + " this._list = this.toArray(true);\n" \ + " this._head = 0;\n" \ + " }\n" \ + " \n" \ + " //\n" \ + " this._tail = @toLength(this._list.length);\n" \ + " \n" \ + " this._list.length <<= 1;\n" \ + " this._capacityMask = (this._capacityMask << 1) | 1;\n" \ + " }\n" \ + " \n" \ + " shrinkArray() {\n" \ + " this._list.length >>>= 1;\n" \ + " this._capacityMask >>>= 1;\n" \ + " }\n" \ + " }\n" \ + "\n" \ + " \n" \ + " return new Denqueue();\n" \ + "})\n" \ +; + const JSC::ConstructAbility s_streamInternalsNewQueueCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_streamInternalsNewQueueCodeConstructorKind = JSC::ConstructorKind::None; -const int s_streamInternalsNewQueueCodeLength = 74; +const int s_streamInternalsNewQueueCodeLength = 85; static const JSC::Intrinsic s_streamInternalsNewQueueCodeIntrinsic = JSC::NoIntrinsic; const char* const s_streamInternalsNewQueueCode = "(function ()\n" \ "{\n" \ " \"use strict\";\n" \ "\n" \ - " return { content: [], size: 0 };\n" \ + " return { content: @createFIFO(), size: 0 };\n" \ "})\n" \ ; const JSC::ConstructAbility s_streamInternalsDequeueValueCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_streamInternalsDequeueValueCodeConstructorKind = JSC::ConstructorKind::None; -const int s_streamInternalsDequeueValueCodeLength = 196; +const int s_streamInternalsDequeueValueCodeLength = 195; static const JSC::Intrinsic s_streamInternalsDequeueValueCodeIntrinsic = JSC::NoIntrinsic; const char* const s_streamInternalsDequeueValueCode = "(function (queue)\n" \ "{\n" \ " \"use strict\";\n" \ "\n" \ - " const record = queue.content.@shift();\n" \ + " const record = queue.content.shift();\n" \ " queue.size -= record.size;\n" \ " //\n" \ " if (queue.size < 0)\n" \ @@ -216,7 +322,7 @@ const char* const s_streamInternalsDequeueValueCode = const JSC::ConstructAbility s_streamInternalsEnqueueValueWithSizeCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_streamInternalsEnqueueValueWithSizeCodeConstructorKind = JSC::ConstructorKind::None; -const int s_streamInternalsEnqueueValueWithSizeCodeLength = 250; +const int s_streamInternalsEnqueueValueWithSizeCodeLength = 248; static const JSC::Intrinsic s_streamInternalsEnqueueValueWithSizeCodeIntrinsic = JSC::NoIntrinsic; const char* const s_streamInternalsEnqueueValueWithSizeCode = "(function (queue, value, size)\n" \ @@ -226,29 +332,30 @@ const char* const s_streamInternalsEnqueueValueWithSizeCode = " size = @toNumber(size);\n" \ " if (!@isFinite(size) || size < 0)\n" \ " @throwRangeError(\"size has an incorrect value\");\n" \ - " @arrayPush(queue.content, { value, size });\n" \ + " \n" \ + " queue.content.push({ value, size });\n" \ " queue.size += size;\n" \ "})\n" \ ; const JSC::ConstructAbility s_streamInternalsPeekQueueValueCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_streamInternalsPeekQueueValueCodeConstructorKind = JSC::ConstructorKind::None; -const int s_streamInternalsPeekQueueValueCodeLength = 117; +const int s_streamInternalsPeekQueueValueCodeLength = 115; static const JSC::Intrinsic s_streamInternalsPeekQueueValueCodeIntrinsic = JSC::NoIntrinsic; const char* const s_streamInternalsPeekQueueValueCode = "(function (queue)\n" \ "{\n" \ " \"use strict\";\n" \ "\n" \ - " @assert(queue.content.length > 0);\n" \ + " @assert(queue.content.isNotEmpty());\n" \ "\n" \ - " return queue.content[0].value;\n" \ + " return queue.peek().value;\n" \ "})\n" \ ; const JSC::ConstructAbility s_streamInternalsResetQueueCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_streamInternalsResetQueueCodeConstructorKind = JSC::ConstructorKind::None; -const int s_streamInternalsResetQueueCodeLength = 149; +const int s_streamInternalsResetQueueCodeLength = 152; static const JSC::Intrinsic s_streamInternalsResetQueueCodeIntrinsic = JSC::NoIntrinsic; const char* const s_streamInternalsResetQueueCode = "(function (queue)\n" \ @@ -257,7 +364,7 @@ const char* const s_streamInternalsResetQueueCode = "\n" \ " @assert(\"content\" in queue);\n" \ " @assert(\"size\" in queue);\n" \ - " queue.content = [];\n" \ + " queue.content.clear();\n" \ " queue.size = 0;\n" \ "})\n" \ ; diff --git a/src/javascript/jsc/bindings/StreamInternalsBuiltins.h b/src/javascript/jsc/bindings/StreamInternalsBuiltins.h index 20c41ddb9..61fb36b0e 100644 --- a/src/javascript/jsc/bindings/StreamInternalsBuiltins.h +++ b/src/javascript/jsc/bindings/StreamInternalsBuiltins.h @@ -79,6 +79,10 @@ extern const char* const s_streamInternalsValidateAndNormalizeQueuingStrategyCod extern const int s_streamInternalsValidateAndNormalizeQueuingStrategyCodeLength; extern const JSC::ConstructAbility s_streamInternalsValidateAndNormalizeQueuingStrategyCodeConstructAbility; extern const JSC::ConstructorKind s_streamInternalsValidateAndNormalizeQueuingStrategyCodeConstructorKind; +extern const char* const s_streamInternalsCreateFIFOCode; +extern const int s_streamInternalsCreateFIFOCodeLength; +extern const JSC::ConstructAbility s_streamInternalsCreateFIFOCodeConstructAbility; +extern const JSC::ConstructorKind s_streamInternalsCreateFIFOCodeConstructorKind; extern const char* const s_streamInternalsNewQueueCode; extern const int s_streamInternalsNewQueueCodeLength; extern const JSC::ConstructAbility s_streamInternalsNewQueueCodeConstructAbility; @@ -129,6 +133,7 @@ extern const JSC::ConstructorKind s_streamInternalsToDictionaryCodeConstructorKi macro(promiseInvokeOrNoop, streamInternalsPromiseInvokeOrNoop, 3) \ macro(promiseInvokeOrFallbackOrNoop, streamInternalsPromiseInvokeOrFallbackOrNoop, 5) \ macro(validateAndNormalizeQueuingStrategy, streamInternalsValidateAndNormalizeQueuingStrategy, 2) \ + macro(createFIFO, streamInternalsCreateFIFO, 0) \ macro(newQueue, streamInternalsNewQueue, 0) \ macro(dequeueValue, streamInternalsDequeueValue, 1) \ macro(enqueueValueWithSize, streamInternalsEnqueueValueWithSize, 3) \ @@ -148,6 +153,7 @@ extern const JSC::ConstructorKind s_streamInternalsToDictionaryCodeConstructorKi #define WEBCORE_BUILTIN_STREAMINTERNALS_PROMISEINVOKEORNOOP 1 #define WEBCORE_BUILTIN_STREAMINTERNALS_PROMISEINVOKEORFALLBACKORNOOP 1 #define WEBCORE_BUILTIN_STREAMINTERNALS_VALIDATEANDNORMALIZEQUEUINGSTRATEGY 1 +#define WEBCORE_BUILTIN_STREAMINTERNALS_CREATEFIFO 1 #define WEBCORE_BUILTIN_STREAMINTERNALS_NEWQUEUE 1 #define WEBCORE_BUILTIN_STREAMINTERNALS_DEQUEUEVALUE 1 #define WEBCORE_BUILTIN_STREAMINTERNALS_ENQUEUEVALUEWITHSIZE 1 @@ -168,6 +174,7 @@ extern const JSC::ConstructorKind s_streamInternalsToDictionaryCodeConstructorKi macro(streamInternalsPromiseInvokeOrNoopCode, promiseInvokeOrNoop, ASCIILiteral(), s_streamInternalsPromiseInvokeOrNoopCodeLength) \ macro(streamInternalsPromiseInvokeOrFallbackOrNoopCode, promiseInvokeOrFallbackOrNoop, ASCIILiteral(), s_streamInternalsPromiseInvokeOrFallbackOrNoopCodeLength) \ macro(streamInternalsValidateAndNormalizeQueuingStrategyCode, validateAndNormalizeQueuingStrategy, ASCIILiteral(), s_streamInternalsValidateAndNormalizeQueuingStrategyCodeLength) \ + macro(streamInternalsCreateFIFOCode, createFIFO, ASCIILiteral(), s_streamInternalsCreateFIFOCodeLength) \ macro(streamInternalsNewQueueCode, newQueue, ASCIILiteral(), s_streamInternalsNewQueueCodeLength) \ macro(streamInternalsDequeueValueCode, dequeueValue, ASCIILiteral(), s_streamInternalsDequeueValueCodeLength) \ macro(streamInternalsEnqueueValueWithSizeCode, enqueueValueWithSize, ASCIILiteral(), s_streamInternalsEnqueueValueWithSizeCodeLength) \ @@ -180,6 +187,7 @@ extern const JSC::ConstructorKind s_streamInternalsToDictionaryCodeConstructorKi macro(streamInternalsToDictionaryCode, toDictionary, ASCIILiteral(), s_streamInternalsToDictionaryCodeLength) \ #define WEBCORE_FOREACH_STREAMINTERNALS_BUILTIN_FUNCTION_NAME(macro) \ + macro(createFIFO) \ macro(createFulfilledPromise) \ macro(dequeueValue) \ macro(enqueueValueWithSize) \ diff --git a/src/javascript/jsc/bindings/WritableStreamInternalsBuiltins.cpp b/src/javascript/jsc/bindings/WritableStreamInternalsBuiltins.cpp index 2e0a4b1df..98674f442 100644 --- a/src/javascript/jsc/bindings/WritableStreamInternalsBuiltins.cpp +++ b/src/javascript/jsc/bindings/WritableStreamInternalsBuiltins.cpp @@ -160,7 +160,7 @@ const char* const s_writableStreamInternalsCreateInternalWritableStreamFromUnder const JSC::ConstructAbility s_writableStreamInternalsInitializeWritableStreamSlotsCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_writableStreamInternalsInitializeWritableStreamSlotsCodeConstructorKind = JSC::ConstructorKind::None; -const int s_writableStreamInternalsInitializeWritableStreamSlotsCodeLength = 734; +const int s_writableStreamInternalsInitializeWritableStreamSlotsCodeLength = 745; static const JSC::Intrinsic s_writableStreamInternalsInitializeWritableStreamSlotsCodeIntrinsic = JSC::NoIntrinsic; const char* const s_writableStreamInternalsInitializeWritableStreamSlotsCode = "(function (stream, underlyingSink)\n" \ @@ -173,7 +173,7 @@ const char* const s_writableStreamInternalsInitializeWritableStreamSlotsCode = " @putByIdDirectPrivate(stream, \"closeRequest\", @undefined);\n" \ " @putByIdDirectPrivate(stream, \"inFlightCloseRequest\", @undefined);\n" \ " @putByIdDirectPrivate(stream, \"pendingAbortRequest\", @undefined);\n" \ - " @putByIdDirectPrivate(stream, \"writeRequests\", []);\n" \ + " @putByIdDirectPrivate(stream, \"writeRequests\", @createFIFO());\n" \ " @putByIdDirectPrivate(stream, \"backpressure\", false);\n" \ " @putByIdDirectPrivate(stream, \"underlyingSink\", underlyingSink);\n" \ "})\n" \ @@ -320,7 +320,7 @@ const char* const s_writableStreamInternalsWritableStreamCloseCode = const JSC::ConstructAbility s_writableStreamInternalsWritableStreamAddWriteRequestCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_writableStreamInternalsWritableStreamAddWriteRequestCodeConstructorKind = JSC::ConstructorKind::None; -const int s_writableStreamInternalsWritableStreamAddWriteRequestCodeLength = 379; +const int s_writableStreamInternalsWritableStreamAddWriteRequestCodeLength = 372; static const JSC::Intrinsic s_writableStreamInternalsWritableStreamAddWriteRequestCodeIntrinsic = JSC::NoIntrinsic; const char* const s_writableStreamInternalsWritableStreamAddWriteRequestCode = "(function (stream)\n" \ @@ -330,7 +330,7 @@ const char* const s_writableStreamInternalsWritableStreamAddWriteRequestCode = "\n" \ " const writePromiseCapability = @newPromiseCapability(@Promise);\n" \ " const writeRequests = @getByIdDirectPrivate(stream, \"writeRequests\");\n" \ - " @arrayPush(writeRequests, writePromiseCapability);\n" \ + " writeRequests.push(writePromiseCapability);\n" \ " return writePromiseCapability.@promise;\n" \ "})\n" \ ; @@ -366,7 +366,7 @@ const char* const s_writableStreamInternalsWritableStreamDealWithRejectionCode = const JSC::ConstructAbility s_writableStreamInternalsWritableStreamFinishErroringCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_writableStreamInternalsWritableStreamFinishErroringCodeConstructorKind = JSC::ConstructorKind::None; -const int s_writableStreamInternalsWritableStreamFinishErroringCodeLength = 1543; +const int s_writableStreamInternalsWritableStreamFinishErroringCodeLength = 1556; static const JSC::Intrinsic s_writableStreamInternalsWritableStreamFinishErroringCodeIntrinsic = JSC::NoIntrinsic; const char* const s_writableStreamInternalsWritableStreamFinishErroringCode = "(function (stream)\n" \ @@ -381,10 +381,11 @@ const char* const s_writableStreamInternalsWritableStreamFinishErroringCode = "\n" \ " const storedError = @getByIdDirectPrivate(stream, \"storedError\");\n" \ " const requests = @getByIdDirectPrivate(stream, \"writeRequests\");\n" \ - " for (let index = 0, length = requests.length; index < length; ++index)\n" \ - " requests[index].@reject.@call(@undefined, storedError);\n" \ + " for (var request = requests.shift(); request; request = requests.shift())\n" \ + " request.@reject.@call(@undefined, storedError);\n" \ "\n" \ - " @putByIdDirectPrivate(stream, \"writeRequests\", []);\n" \ + " //\n" \ + " @putByIdDirectPrivate(stream, \"writeRequests\", @createFIFO());\n" \ "\n" \ " const abortRequest = @getByIdDirectPrivate(stream, \"pendingAbortRequest\");\n" \ " if (abortRequest === @undefined) {\n" \ @@ -534,16 +535,16 @@ const char* const s_writableStreamInternalsWritableStreamMarkCloseRequestInFligh const JSC::ConstructAbility s_writableStreamInternalsWritableStreamMarkFirstWriteRequestInFlightCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_writableStreamInternalsWritableStreamMarkFirstWriteRequestInFlightCodeConstructorKind = JSC::ConstructorKind::None; -const int s_writableStreamInternalsWritableStreamMarkFirstWriteRequestInFlightCodeLength = 343; +const int s_writableStreamInternalsWritableStreamMarkFirstWriteRequestInFlightCodeLength = 344; static const JSC::Intrinsic s_writableStreamInternalsWritableStreamMarkFirstWriteRequestInFlightCodeIntrinsic = JSC::NoIntrinsic; const char* const s_writableStreamInternalsWritableStreamMarkFirstWriteRequestInFlightCode = "(function (stream)\n" \ "{\n" \ " const writeRequests = @getByIdDirectPrivate(stream, \"writeRequests\");\n" \ " @assert(@getByIdDirectPrivate(stream, \"inFlightWriteRequest\") === @undefined);\n" \ - " @assert(writeRequests.length > 0);\n" \ + " @assert(writeRequests.isNotEmpty());\n" \ "\n" \ - " const writeRequest = writeRequests.@shift();\n" \ + " const writeRequest = writeRequests.shift();\n" \ " @putByIdDirectPrivate(stream, \"inFlightWriteRequest\", writeRequest);\n" \ "})\n" \ ; @@ -869,7 +870,7 @@ const char* const s_writableStreamInternalsSetUpWritableStreamDefaultControllerF const JSC::ConstructAbility s_writableStreamInternalsWritableStreamDefaultControllerAdvanceQueueIfNeededCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_writableStreamInternalsWritableStreamDefaultControllerAdvanceQueueIfNeededCodeConstructorKind = JSC::ConstructorKind::None; -const int s_writableStreamInternalsWritableStreamDefaultControllerAdvanceQueueIfNeededCodeLength = 865; +const int s_writableStreamInternalsWritableStreamDefaultControllerAdvanceQueueIfNeededCodeLength = 872; static const JSC::Intrinsic s_writableStreamInternalsWritableStreamDefaultControllerAdvanceQueueIfNeededCodeIntrinsic = JSC::NoIntrinsic; const char* const s_writableStreamInternalsWritableStreamDefaultControllerAdvanceQueueIfNeededCode = "(function (controller)\n" \ @@ -890,7 +891,7 @@ const char* const s_writableStreamInternalsWritableStreamDefaultControllerAdvanc " return;\n" \ " }\n" \ "\n" \ - " if (@getByIdDirectPrivate(controller, \"queue\").content.length === 0)\n" \ + " if (@getByIdDirectPrivate(controller, \"queue\").content?.isEmpty() ?? false)\n" \ " return;\n" \ "\n" \ " const value = @peekQueueValue(@getByIdDirectPrivate(controller, \"queue\"));\n" \ @@ -1007,7 +1008,7 @@ const char* const s_writableStreamInternalsWritableStreamDefaultControllerGetDes const JSC::ConstructAbility s_writableStreamInternalsWritableStreamDefaultControllerProcessCloseCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_writableStreamInternalsWritableStreamDefaultControllerProcessCloseCodeConstructorKind = JSC::ConstructorKind::None; -const int s_writableStreamInternalsWritableStreamDefaultControllerProcessCloseCodeLength = 630; +const int s_writableStreamInternalsWritableStreamDefaultControllerProcessCloseCodeLength = 628; static const JSC::Intrinsic s_writableStreamInternalsWritableStreamDefaultControllerProcessCloseCodeIntrinsic = JSC::NoIntrinsic; const char* const s_writableStreamInternalsWritableStreamDefaultControllerProcessCloseCode = "(function (controller)\n" \ @@ -1017,7 +1018,7 @@ const char* const s_writableStreamInternalsWritableStreamDefaultControllerProces " @writableStreamMarkCloseRequestInFlight(stream);\n" \ " @dequeueValue(@getByIdDirectPrivate(controller, \"queue\"));\n" \ "\n" \ - " @assert(@getByIdDirectPrivate(controller, \"queue\").content.length === 0);\n" \ + " @assert(@getByIdDirectPrivate(controller, \"queue\").content?.isEmpty());\n" \ "\n" \ " const sinkClosePromise = @getByIdDirectPrivate(controller, \"closeAlgorithm\").@call();\n" \ " @writableStreamDefaultControllerClearAlgorithms(controller);\n" \ diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp index 8da658526..c3ba74cf4 100644 --- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp +++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp @@ -871,6 +871,22 @@ static JSC_DEFINE_HOST_FUNCTION(functionReportError, return JSC::JSValue::encode(JSC::jsUndefined()); } +JSC_DECLARE_HOST_FUNCTION(functionCreateUninitializedArrayBuffer); +JSC_DEFINE_HOST_FUNCTION(functionCreateUninitializedArrayBuffer, + (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + size_t len = static_cast<size_t>(JSC__JSValue__toInt64(JSC::JSValue::encode(callFrame->argument(0)))); + 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_DEFINE_HOST_FUNCTION(functionNoop, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); @@ -1250,7 +1266,7 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) auto& builtinNames = WebCore::builtinNames(vm); WTF::Vector<GlobalPropertyInfo> extraStaticGlobals; - extraStaticGlobals.reserveCapacity(26); + extraStaticGlobals.reserveCapacity(27); JSC::Identifier queueMicrotaskIdentifier = JSC::Identifier::fromString(vm, "queueMicrotask"_s); extraStaticGlobals.uncheckedAppend( @@ -1336,6 +1352,8 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) extraStaticGlobals.releaseBuffer(); + putDirectBuiltinFunction(vm, this, builtinNames.createFIFOPrivateName(), streamInternalsCreateFIFOCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + putDirectNativeFunction(vm, this, builtinNames.createUninitializedArrayBufferPrivateName(), 1, functionCreateUninitializedArrayBuffer, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function); putDirectBuiltinFunction(vm, this, builtinNames.createNativeReadableStreamPrivateName(), readableStreamCreateNativeReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "process"_s), JSC::CustomGetterSetter::create(vm, property_lazyProcessGetter, property_lazyProcessSetter), diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig index 1f4a62939..e421bfd89 100644 --- a/src/javascript/jsc/bindings/bindings.zig +++ b/src/javascript/jsc/bindings/bindings.zig @@ -2259,6 +2259,16 @@ pub const JSValue = enum(i64) { return JSC.GetJSPrivateData(ZigType, value.asObjectRef()); } + pub fn protect(this: JSValue) void { + if (this.isEmptyOrUndefinedOrNull() or this.isNumber()) return; + JSC.C.JSValueProtect(JSC.VirtualMachine.vm.global, this.asObjectRef()); + } + + pub fn unprotect(this: JSValue) void { + if (this.isEmptyOrUndefinedOrNull() or this.isNumber()) return; + JSC.C.JSValueUnprotect(JSC.VirtualMachine.vm.global, this.asObjectRef()); + } + /// Create an object with exactly two properties pub fn createObject2(global: *JSGlobalObject, key1: *const ZigString, key2: *const ZigString, value1: JSValue, value2: JSValue) JSValue { return cppFn("createObject2", .{ global, key1, key2, value1, value2 }); diff --git a/src/javascript/jsc/bindings/builtins/js/ReadableByteStreamController.js b/src/javascript/jsc/bindings/builtins/js/ReadableByteStreamController.js index fac5c864c..0b47d730c 100644 --- a/src/javascript/jsc/bindings/builtins/js/ReadableByteStreamController.js +++ b/src/javascript/jsc/bindings/builtins/js/ReadableByteStreamController.js @@ -89,12 +89,17 @@ function byobRequest() if (!@isReadableByteStreamController(this)) throw @makeGetterTypeError("ReadableByteStreamController", "byobRequest"); - if (@getByIdDirectPrivate(this, "byobRequest") === @undefined && @getByIdDirectPrivate(this, "pendingPullIntos").length) { - const firstDescriptor = @getByIdDirectPrivate(this, "pendingPullIntos")[0]; - const view = new @Uint8Array(firstDescriptor.buffer, + + var request = @getByIdDirectPrivate(this, "byobRequest"); + if (request === @undefined) { + var pending = @getByIdDirectPrivate(this, "pendingPullIntos"); + const firstDescriptor = pending.peek(); + if (firstDescriptor) { + const view = new @Uint8Array(firstDescriptor.buffer, firstDescriptor.byteOffset + firstDescriptor.bytesFilled, firstDescriptor.byteLength - firstDescriptor.bytesFilled); - @putByIdDirectPrivate(this, "byobRequest", new @ReadableStreamBYOBRequest(this, view, @isReadableStream)); + @putByIdDirectPrivate(this, "byobRequest", new @ReadableStreamBYOBRequest(this, view, @isReadableStream)); + } } return @getByIdDirectPrivate(this, "byobRequest"); diff --git a/src/javascript/jsc/bindings/builtins/js/ReadableByteStreamInternals.js b/src/javascript/jsc/bindings/builtins/js/ReadableByteStreamInternals.js index 45af990cd..5806ba48c 100644 --- a/src/javascript/jsc/bindings/builtins/js/ReadableByteStreamInternals.js +++ b/src/javascript/jsc/bindings/builtins/js/ReadableByteStreamInternals.js @@ -56,7 +56,7 @@ function privateInitializeReadableByteStreamController(stream, underlyingByteSou @throwRangeError("autoAllocateChunkSize value is negative or equal to positive or negative infinity"); } @putByIdDirectPrivate(this, "autoAllocateChunkSize", autoAllocateChunkSize); - @putByIdDirectPrivate(this, "pendingPullIntos", []); + @putByIdDirectPrivate(this, "pendingPullIntos", @createFIFO()); const controller = this; const startResult = @promiseInvokeOrNoopNoCatch(underlyingByteSource, "start", [this]).@then(() => { @@ -116,8 +116,10 @@ function readableByteStreamControllerCancel(controller, reason) "use strict"; var pendingPullIntos = @getByIdDirectPrivate(controller, "pendingPullIntos"); - if (pendingPullIntos.length > 0) - pendingPullIntos[0].bytesFilled = 0; + var first = pendingPullIntos.peek(); + if (first) + first.bytesFilled = 0; + @putByIdDirectPrivate(controller, "queue", @newQueue()); return @promiseInvokeOrNoop(@getByIdDirectPrivate(controller, "underlyingByteSource"), "cancel", [reason]); } @@ -144,9 +146,9 @@ function readableByteStreamControllerClose(controller) return; } - var pendingPullIntos = @getByIdDirectPrivate(controller, "pendingPullIntos"); - if (pendingPullIntos.length > 0) { - if (pendingPullIntos[0].bytesFilled > 0) { + var first = @getByIdDirectPrivate(controller, "pendingPullIntos")?.peek(); + if (first) { + if (first.bytesFilled > 0) { const e = @makeTypeError("Close requested while there remain pending bytes"); @readableByteStreamControllerError(controller, e); throw e; @@ -161,7 +163,12 @@ function readableByteStreamControllerClearPendingPullIntos(controller) "use strict"; @readableByteStreamControllerInvalidateBYOBRequest(controller); - @putByIdDirectPrivate(controller, "pendingPullIntos", []); + var existing = @getByIdDirectPrivate(controller, "pendingPullIntos"); + if (existing !== @undefined) { + existing.clear(); + } else { + @putByIdDirectPrivate(controller, "pendingPullIntos", @createFIFO()); + } } function readableByteStreamControllerGetDesiredSize(controller) @@ -214,8 +221,8 @@ function readableByteStreamControllerPull(controller) @assert(@readableStreamHasDefaultReader(stream)); if (@getByIdDirectPrivate(controller, "queue").size > 0) { - @assert(@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").length === 0); - const entry = @getByIdDirectPrivate(controller, "queue").content.@shift(); + @assert(@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests")?.isEmpty()); + const entry = @getByIdDirectPrivate(controller, "queue").content.shift(); @getByIdDirectPrivate(controller, "queue").size -= entry.byteLength; @readableByteStreamControllerHandleQueueDrain(controller); let view; @@ -230,7 +237,7 @@ function readableByteStreamControllerPull(controller) if (@getByIdDirectPrivate(controller, "autoAllocateChunkSize") !== @undefined) { let buffer; try { - buffer = new @ArrayBuffer(@getByIdDirectPrivate(controller, "autoAllocateChunkSize")); + buffer = @createUninitializedArrayBuffer(@getByIdDirectPrivate(controller, "autoAllocateChunkSize")); } catch (error) { return @Promise.@reject(error); } @@ -243,7 +250,7 @@ function readableByteStreamControllerPull(controller) ctor: @Uint8Array, readerType: 'default' }; - @arrayPush(@getByIdDirectPrivate(controller, "pendingPullIntos"), pullIntoDescriptor); + @getByIdDirectPrivate(controller, "pendingPullIntos").push(pullIntoDescriptor); } const promise = @readableStreamAddReadRequest(stream); @@ -263,9 +270,9 @@ function readableByteStreamControllerShouldCallPull(controller) return false; if (!@getByIdDirectPrivate(controller, "started")) return false; - if (@readableStreamHasDefaultReader(stream) && (@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").length > 0 || !!@getByIdDirectPrivate(reader, "bunNativePtr"))) + if (@readableStreamHasDefaultReader(stream) && (@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests")?.isNotEmpty() || !!@getByIdDirectPrivate(reader, "bunNativePtr"))) return true; - if (@readableStreamHasBYOBReader(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readIntoRequests").length > 0) + if (@readableStreamHasBYOBReader(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readIntoRequests")?.isNotEmpty()) return true; if (@readableByteStreamControllerGetDesiredSize(controller) > 0) return true; @@ -334,10 +341,10 @@ function readableByteStreamControllerEnqueue(controller, chunk) switch (reader ? @readableStreamReaderKind(reader) : 0) { /* default reader */ case 1: { - if (!@getByIdDirectPrivate(reader, "readRequests").length) + if (!@getByIdDirectPrivate(reader, "readRequests")?.isNotEmpty()) @readableByteStreamControllerEnqueueChunk(controller, @transferBufferToCurrentRealm(chunk.buffer), chunk.byteOffset, chunk.byteLength); else { - @assert(!@getByIdDirectPrivate(controller, "queue").content.length); + @assert(!@getByIdDirectPrivate(controller, "queue").content.size()); const transferredView = chunk.constructor === @Uint8Array ? chunk : new @Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength); @readableStreamFulfillReadRequest(stream, transferredView, false); } @@ -371,7 +378,7 @@ function readableByteStreamControllerEnqueueChunk(controller, buffer, byteOffset { "use strict"; - @arrayPush(@getByIdDirectPrivate(controller, "queue").content, { + @getByIdDirectPrivate(controller, "queue").content.push({ buffer: buffer, byteOffset: byteOffset, byteLength: byteLength @@ -383,10 +390,10 @@ function readableByteStreamControllerRespondWithNewView(controller, view) { "use strict"; - @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").length > 0); - - let firstDescriptor = @getByIdDirectPrivate(controller, "pendingPullIntos")[0]; + @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").isNotEmpty()); + let firstDescriptor = @getByIdDirectPrivate(controller, "pendingPullIntos").peek(); + if (firstDescriptor.byteOffset + firstDescriptor.bytesFilled !== view.byteOffset) @throwRangeError("Invalid value for view.byteOffset"); @@ -406,7 +413,7 @@ function readableByteStreamControllerRespond(controller, bytesWritten) if (@isNaN(bytesWritten) || bytesWritten === @Infinity || bytesWritten < 0 ) @throwRangeError("bytesWritten has an incorrect value"); - @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").length > 0); + @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").isNotEmpty()); @readableByteStreamControllerRespondInternal(controller, bytesWritten); } @@ -415,7 +422,7 @@ function readableByteStreamControllerRespondInternal(controller, bytesWritten) { "use strict"; - let firstDescriptor = @getByIdDirectPrivate(controller, "pendingPullIntos")[0]; + let firstDescriptor = @getByIdDirectPrivate(controller, "pendingPullIntos").peek(); let stream = @getByIdDirectPrivate(controller, "controlledReadableStream"); if (@getByIdDirectPrivate(stream, "state") === @streamClosed) { @@ -435,7 +442,7 @@ function readableByteStreamControllerRespondInReadableState(controller, bytesWri if (pullIntoDescriptor.bytesFilled + bytesWritten > pullIntoDescriptor.byteLength) @throwRangeError("bytesWritten value is too great"); - @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").length === 0 || @getByIdDirectPrivate(controller, "pendingPullIntos")[0] === pullIntoDescriptor); + @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").isEmpty() || @getByIdDirectPrivate(controller, "pendingPullIntos").peek() === pullIntoDescriptor); @readableByteStreamControllerInvalidateBYOBRequest(controller); pullIntoDescriptor.bytesFilled += bytesWritten; @@ -465,7 +472,7 @@ function readableByteStreamControllerRespondInClosedState(controller, firstDescr @assert(firstDescriptor.bytesFilled === 0); if (@readableStreamHasBYOBReader(@getByIdDirectPrivate(controller, "controlledReadableStream"))) { - while (@getByIdDirectPrivate(@getByIdDirectPrivate(@getByIdDirectPrivate(controller, "controlledReadableStream"), "reader"), "readIntoRequests").length > 0) { + while (@getByIdDirectPrivate(@getByIdDirectPrivate(@getByIdDirectPrivate(controller, "controlledReadableStream"), "reader"), "readIntoRequests")?.isNotEmpty()) { let pullIntoDescriptor = @readableByteStreamControllerShiftPendingDescriptor(controller); @readableByteStreamControllerCommitDescriptor(@getByIdDirectPrivate(controller, "controlledReadableStream"), pullIntoDescriptor); } @@ -478,10 +485,10 @@ function readableByteStreamControllerProcessPullDescriptors(controller) "use strict"; @assert(!@getByIdDirectPrivate(controller, "closeRequested")); - while (@getByIdDirectPrivate(controller, "pendingPullIntos").length > 0) { + while (@getByIdDirectPrivate(controller, "pendingPullIntos").isNotEmpty()) { if (@getByIdDirectPrivate(controller, "queue").size === 0) return; - let pullIntoDescriptor = @getByIdDirectPrivate(controller, "pendingPullIntos")[0]; + let pullIntoDescriptor = @getByIdDirectPrivate(controller, "pendingPullIntos").peek(); if (@readableByteStreamControllerFillDescriptorFromQueue(controller, pullIntoDescriptor)) { @readableByteStreamControllerShiftPendingDescriptor(controller); @readableByteStreamControllerCommitDescriptor(@getByIdDirectPrivate(controller, "controlledReadableStream"), pullIntoDescriptor); @@ -508,7 +515,7 @@ function readableByteStreamControllerFillDescriptorFromQueue(controller, pullInt } while (totalBytesToCopyRemaining > 0) { - let headOfQueue = @getByIdDirectPrivate(controller, "queue").content[0]; + let headOfQueue = @getByIdDirectPrivate(controller, "queue").content.peek(); const bytesToCopy = totalBytesToCopyRemaining < headOfQueue.byteLength ? totalBytesToCopyRemaining : headOfQueue.byteLength; // Copy appropriate part of pullIntoDescriptor.buffer to headOfQueue.buffer. // Remark: this implementation is not completely aligned on the definition of CopyDataBlockBytes @@ -519,14 +526,14 @@ function readableByteStreamControllerFillDescriptorFromQueue(controller, pullInt new @Uint8Array(pullIntoDescriptor.buffer).set(new @Uint8Array(headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy), destStart); if (headOfQueue.byteLength === bytesToCopy) - @getByIdDirectPrivate(controller, "queue").content.@shift(); + @getByIdDirectPrivate(controller, "queue").content.shift(); else { headOfQueue.byteOffset += bytesToCopy; headOfQueue.byteLength -= bytesToCopy; } @getByIdDirectPrivate(controller, "queue").size -= bytesToCopy; - @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").length === 0 || @getByIdDirectPrivate(controller, "pendingPullIntos")[0] === pullIntoDescriptor); + @assert(@getByIdDirectPrivate(controller, "pendingPullIntos").isEmpty() || @getByIdDirectPrivate(controller, "pendingPullIntos").peek() === pullIntoDescriptor); @readableByteStreamControllerInvalidateBYOBRequest(controller); pullIntoDescriptor.bytesFilled += bytesToCopy; totalBytesToCopyRemaining -= bytesToCopy; @@ -546,7 +553,7 @@ function readableByteStreamControllerShiftPendingDescriptor(controller) { "use strict"; - let descriptor = @getByIdDirectPrivate(controller, "pendingPullIntos").@shift(); + let descriptor = @getByIdDirectPrivate(controller, "pendingPullIntos").shift(); @readableByteStreamControllerInvalidateBYOBRequest(controller); return descriptor; } @@ -597,7 +604,7 @@ function readableByteStreamControllerConvertDescriptor(pullIntoDescriptor) function readableStreamFulfillReadIntoRequest(stream, chunk, done) { "use strict"; - const readIntoRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readIntoRequests").@shift(); + const readIntoRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readIntoRequests").shift(); @fulfillPromise(readIntoRequest, { value: chunk, done: done }); } @@ -652,9 +659,10 @@ function readableByteStreamControllerPullInto(controller, view) readerType: 'byob' }; - if (@getByIdDirectPrivate(controller, "pendingPullIntos").length) { + var pending = @getByIdDirectPrivate(controller, "pendingPullIntos"); + if (pending?.isNotEmpty()) { pullIntoDescriptor.buffer = @transferBufferToCurrentRealm(pullIntoDescriptor.buffer); - @arrayPush(@getByIdDirectPrivate(controller, "pendingPullIntos"), pullIntoDescriptor); + pending.push(pullIntoDescriptor); return @readableStreamAddReadIntoRequest(stream); } @@ -677,7 +685,7 @@ function readableByteStreamControllerPullInto(controller, view) } pullIntoDescriptor.buffer = @transferBufferToCurrentRealm(pullIntoDescriptor.buffer); - @arrayPush(@getByIdDirectPrivate(controller, "pendingPullIntos"), pullIntoDescriptor); + @getByIdDirectPrivate(controller, "pendingPullIntos").push(pullIntoDescriptor); const promise = @readableStreamAddReadIntoRequest(stream); @readableByteStreamControllerCallPullIfNeeded(controller); return promise; @@ -691,7 +699,7 @@ function readableStreamAddReadIntoRequest(stream) @assert(@getByIdDirectPrivate(stream, "state") === @streamReadable || @getByIdDirectPrivate(stream, "state") === @streamClosed); const readRequest = @newPromise(); - @arrayPush(@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readIntoRequests"), readRequest); + @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readIntoRequests").push(readRequest); return readRequest; } diff --git a/src/javascript/jsc/bindings/builtins/js/ReadableStream.js b/src/javascript/jsc/bindings/builtins/js/ReadableStream.js index 5a5ea4094..4d7113888 100644 --- a/src/javascript/jsc/bindings/builtins/js/ReadableStream.js +++ b/src/javascript/jsc/bindings/builtins/js/ReadableStream.js @@ -89,79 +89,69 @@ function initializeReadableStream(underlyingSource, strategy) } @globalPrivate -function createNativeReadableStream(nativePtr, nativeType) { +function createNativeReadableStream(nativePtr, nativeType, autoAllocateChunkSize) { "use strict"; var cached = globalThis[Symbol.for("Bun.nativeReadableStreamPrototype")] ||= new @Map; var Prototype = cached.@get(nativeType); if (Prototype === @undefined) { var [pull, start, cancel, setClose, deinit] = globalThis[Symbol.for("Bun.lazy")](nativeType); var closer = [false]; - +var handleResult; function handleNativeReadableStreamPromiseResult(val) { "use strict"; - var {r, c} = this; - this.r = @undefined; + var {c, v} = this; this.c = @undefined; - r(val, c); + this.v = @undefined; + handleResult(val, c, v); } - function closeNativeReadableStreamOnNextTick(controller) { - "use strict"; - controller.close(); - controller = @undefined; - } - - var handleResult = function handleResult(result, controller) { + + handleResult = function handleResult(result, controller, view) { "use strict"; if (result && @isPromise(result)) { - return result.then(handleNativeReadableStreamPromiseResult.bind({c: controller, r: handleResult}), controller.error); + return result.then(handleNativeReadableStreamPromiseResult.bind({c: controller, v: view}), (err) => controller.error(err)); } else if (result !== false) { - controller.enqueue(result); + if (view && view.byteLength === result) { + controller.byobRequest.respondWithNewView(view); + } else { + controller.byobRequest.respond(result); + } } if (closer[0] || result === false) { - @enqueueJob(closeNativeReadableStreamOnNextTick, controller); + @enqueueJob(() => controller.close()); closer[0] = false; } - } + }; Prototype = class NativeReadableStreamSource { - constructor(tag) { + constructor(tag, autoAllocateChunkSize) { this.pull = this.pull_.bind(tag); - this.start = this.start_.bind(tag); this.cancel = this.cancel_.bind(tag); + this.autoAllocateChunkSize = autoAllocateChunkSize; } pull; - start; cancel; - - pull_(controller) { - closer[0] = false; - var result; - - try { - result = pull(this, closer); - } catch(err) { - return controller.error(err); - } - return handleResult(result, controller); - } + type = "bytes"; + autoAllocateChunkSize = 0; - start_(controller) { - setClose(this, controller.close); + static startSync = start; + + pull_(controller) { closer[0] = false; var result; + const view = controller.byobRequest.view; try { - result = start(this, closer); + result = pull(this, view, closer); } catch(err) { return controller.error(err); } - return handleResult(result, controller); + return handleResult(result, controller, view); } cancel_(reason) { @@ -173,7 +163,29 @@ function createNativeReadableStream(nativePtr, nativeType) { cached.@set(nativeType, Prototype); } - var instance = new Prototype(nativePtr); + // either returns the chunk size + // or throws an error + // should never return a Promise + const chunkSize = Prototype.startSync(nativePtr, autoAllocateChunkSize); + + // empty file, no need for native back-and-forth on this + if (chunkSize === 0) { + return new @ReadableStream({ + start(controller) { + controller.close(); + }, + + pull() { + + }, + + cancel() { + + }, + }); + } + + var instance = new Prototype(nativePtr, chunkSize); Prototype.registry.register(instance, nativePtr); var stream = new @ReadableStream(instance); @putByIdDirectPrivate(stream, "bunNativeType", nativeType); diff --git a/src/javascript/jsc/bindings/builtins/js/ReadableStreamBYOBReader.js b/src/javascript/jsc/bindings/builtins/js/ReadableStreamBYOBReader.js index f4bc203c8..16e4ebce5 100644 --- a/src/javascript/jsc/bindings/builtins/js/ReadableStreamBYOBReader.js +++ b/src/javascript/jsc/bindings/builtins/js/ReadableStreamBYOBReader.js @@ -34,7 +34,7 @@ function initializeReadableStreamBYOBReader(stream) @throwTypeError("ReadableStream is locked"); @readableStreamReaderGenericInitialize(this, stream); - @putByIdDirectPrivate(this, "readIntoRequests", []); + @putByIdDirectPrivate(this, "readIntoRequests", @createFIFO()); return this; } @@ -84,7 +84,7 @@ function releaseLock() if (!@getByIdDirectPrivate(this, "ownerReadableStream")) return; - if (@getByIdDirectPrivate(this, "readIntoRequests").length) + if (@getByIdDirectPrivate(this, "readIntoRequests")?.isNotEmpty()) @throwTypeError("There are still pending read requests, cannot release the lock"); @readableStreamReaderGenericRelease(this); diff --git a/src/javascript/jsc/bindings/builtins/js/ReadableStreamDefaultReader.js b/src/javascript/jsc/bindings/builtins/js/ReadableStreamDefaultReader.js index 3e7438a62..9766d150e 100644 --- a/src/javascript/jsc/bindings/builtins/js/ReadableStreamDefaultReader.js +++ b/src/javascript/jsc/bindings/builtins/js/ReadableStreamDefaultReader.js @@ -33,7 +33,7 @@ function initializeReadableStreamDefaultReader(stream) @throwTypeError("ReadableStream is locked"); @readableStreamReaderGenericInitialize(this, stream); - @putByIdDirectPrivate(this, "readRequests", []); + @putByIdDirectPrivate(this, "readRequests", @createFIFO()); return this; } @@ -70,30 +70,14 @@ function readMany() throw @getByIdDirectPrivate(stream, "storedError"); } - const controller = @getByIdDirectPrivate(stream, "readableStreamController"); + var controller = @getByIdDirectPrivate(stream, "readableStreamController"); const content = @getByIdDirectPrivate(controller, "queue").content; var size = @getByIdDirectPrivate(controller, "queue").size; + var values = content.toArray(false); + var length = values.length; - var values = new @Array(content.length); - - if (content.length > 0) { - if ("buffer" in content[0]) { - values[0] = new @Uint8Array(content[0].buffer, content[0].byteOffset, content[0].byteLength); - for (var i = 0; i < content.length; ++i) { - @putByValDirect(values, i+1, new @Uint8Array(content[i].buffer, content[i].byteOffset, content[i].byteLength)); - } - } else if (typeof content[0] === 'object' && content[0] && "byteLength" in content[0]) { - size = 0; - for (var i = 0; i < content.length; ++i) { - @putByValDirect(values, i+1, content[i].value); - size += content[i].value.byteLength; - } - } else { - for (var i = 0; i < content.length; ++i) { - @putByValDirect(values, i+1, content[i].value); - } - } + if (length > 0) { @resetQueue(@getByIdDirectPrivate(controller, "queue")); if (@getByIdDirectPrivate(controller, "closeRequested")) @@ -105,44 +89,23 @@ function readMany() if (done) { return {value: [], size: 0, done: true}; } - - const content = queue.content; - var values = new @Array(content.length + 1); - + var queue = @getByIdDirectPrivate(controller, "queue"); + const content = [value].concat(queue.content.toArray(false)); var size = queue.size; - - if ("buffer" in content[0]) { - values[0] = new @Uint8Array(value.buffer, value.byteOffset, value.byteLength); - for (var i = 0; i < content.length; ++i) { - @putByValDirect(values, i+1, new @Uint8Array(content[i].buffer, content[i].byteOffset, content[i].byteLength)); - } - size += value.byteLength; - } else if (typeof value === 'object' && value && "byteLength" in value) { - size += value.byteLength; - values[0] = value; - for (var i = 0; i < content.length; ++i) { - @putByValDirect(values, i+1, content[i].value); - size += content[i].value.byteLength; - } - - } else { - values[0] = value; - for (var i = 0; i < content.length; ++i) { - @putByValDirect(values, i+1, content[i].value); - } - } - @resetQueue(queue); if (@getByIdDirectPrivate(controller, "closeRequested")) @readableStreamClose(@getByIdDirectPrivate(controller, "controlledReadableStream")); else @readableStreamDefaultControllerCallPullIfNeeded(controller); + controller = @undefined; return {value: values, size: size, done: false}; }); } + controller = @undefined; + return {value: values, size, done: false}; } @@ -168,7 +131,7 @@ function releaseLock() if (!@getByIdDirectPrivate(this, "ownerReadableStream")) return; - if (@getByIdDirectPrivate(this, "readRequests").length) + if (@getByIdDirectPrivate(this, "readRequests")?.isNotEmpty()) @throwTypeError("There are still pending read requests, cannot release the lock"); @readableStreamReaderGenericRelease(this); diff --git a/src/javascript/jsc/bindings/builtins/js/ReadableStreamInternals.js b/src/javascript/jsc/bindings/builtins/js/ReadableStreamInternals.js index 7c2384330..f441858cc 100644 --- a/src/javascript/jsc/bindings/builtins/js/ReadableStreamInternals.js +++ b/src/javascript/jsc/bindings/builtins/js/ReadableStreamInternals.js @@ -547,15 +547,15 @@ function readableStreamError(stream, error) if (@isReadableStreamDefaultReader(reader)) { const requests = @getByIdDirectPrivate(reader, "readRequests"); - @putByIdDirectPrivate(reader, "readRequests", []); - for (let index = 0, length = requests.length; index < length; ++index) - @rejectPromise(requests[index], error); + @putByIdDirectPrivate(reader, "readRequests", @createFIFO()); + for (var request = requests.shift(); request; request = requests.shift()) + @rejectPromise(request, error); } else { @assert(@isReadableStreamBYOBReader(reader)); const requests = @getByIdDirectPrivate(reader, "readIntoRequests"); - @putByIdDirectPrivate(reader, "readIntoRequests", []); - for (let index = 0, length = requests.length; index < length; ++index) - @rejectPromise(requests[index], error); + @putByIdDirectPrivate(reader, "readIntoRequests", @createFIFO()); + for (var request = requests.shift(); request; request = requests.shift()) + @rejectPromise(request, error); } @getByIdDirectPrivate(reader, "closedPromiseCapability").@reject.@call(@undefined, error); @@ -571,7 +571,7 @@ function readableStreamDefaultControllerShouldCallPull(controller) return false; if (!@getByIdDirectPrivate(controller, "started")) return false; - if ((!@isReadableStreamLocked(stream) || !@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").length) && @readableStreamDefaultControllerGetDesiredSize(controller) <= 0) + if ((!@isReadableStreamLocked(stream) || !@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests")?.isNotEmpty()) && @readableStreamDefaultControllerGetDesiredSize(controller) <= 0) return false; const desiredSize = @readableStreamDefaultControllerGetDesiredSize(controller); @assert(desiredSize !== null); @@ -589,7 +589,7 @@ function readableStreamDefaultControllerCallPullIfNeeded(controller) return; if (!@getByIdDirectPrivate(controller, "started")) return; - if ((!@isReadableStreamLocked(stream) || !@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").length) && @readableStreamDefaultControllerGetDesiredSize(controller) <= 0) + if ((!@isReadableStreamLocked(stream) || !@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests")?.isNotEmpty()) && @readableStreamDefaultControllerGetDesiredSize(controller) <= 0) return; if (@getByIdDirectPrivate(controller, "pulling")) { @@ -670,9 +670,10 @@ function readableStreamDefaultControllerPull(controller) { "use strict"; - if (@getByIdDirectPrivate(controller, "queue").content.length) { - const chunk = @dequeueValue(@getByIdDirectPrivate(controller, "queue")); - if (@getByIdDirectPrivate(controller, "closeRequested") && @getByIdDirectPrivate(controller, "queue").content.length === 0) + var queue = @getByIdDirectPrivate(controller, "queue"); + if (queue.isNotEmpty()) { + const chunk = @dequeueValue(queue); + if (@getByIdDirectPrivate(controller, "closeRequested") && queue.isEmpty()) @readableStreamClose(@getByIdDirectPrivate(controller, "controlledReadableStream")); else @readableStreamDefaultControllerCallPullIfNeeded(controller); @@ -690,7 +691,7 @@ function readableStreamDefaultControllerClose(controller) @assert(@readableStreamDefaultControllerCanCloseOrEnqueue(controller)); @putByIdDirectPrivate(controller, "closeRequested", true); - if (@getByIdDirectPrivate(controller, "queue").content.length === 0) + if (!@getByIdDirectPrivate(controller, "queue")?.isNotEmpty()) @readableStreamClose(@getByIdDirectPrivate(controller, "controlledReadableStream")); } @@ -707,9 +708,10 @@ function readableStreamClose(stream) if (@isReadableStreamDefaultReader(reader)) { const requests = @getByIdDirectPrivate(reader, "readRequests"); - @putByIdDirectPrivate(reader, "readRequests", []); - for (let index = 0, length = requests.length; index < length; ++index) - @fulfillPromise(requests[index], { value: @undefined, done: true }); + @putByIdDirectPrivate(reader, "readRequests", @createFIFO()); + + for (var request = requests.shift(); request; request = requests.shift()) + @fulfillPromise(request, { value: @undefined, done: true }); } @getByIdDirectPrivate(reader, "closedPromiseCapability").@resolve.@call(); @@ -718,7 +720,7 @@ function readableStreamClose(stream) function readableStreamFulfillReadRequest(stream, chunk, done) { "use strict"; - const readRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").@shift(); + const readRequest = @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").shift(); @fulfillPromise(readRequest, { value: chunk, done: done }); } @@ -730,7 +732,7 @@ function readableStreamDefaultControllerEnqueue(controller, chunk) // this is checked by callers @assert(@readableStreamDefaultControllerCanCloseOrEnqueue(controller)); - if (@isReadableStreamLocked(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").length) { + if (@isReadableStreamLocked(stream) && @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").isNotEmpty) { @readableStreamFulfillReadRequest(stream, chunk, false); @readableStreamDefaultControllerCallPullIfNeeded(controller); return; @@ -775,7 +777,8 @@ function readableStreamAddReadRequest(stream) @assert(@getByIdDirectPrivate(stream, "state") == @streamReadable); const readRequest = @newPromise(); - @arrayPush(@getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests"), readRequest); + + @getByIdDirectPrivate(@getByIdDirectPrivate(stream, "reader"), "readRequests").push(readRequest); return readRequest; } diff --git a/src/javascript/jsc/bindings/builtins/js/StreamInternals.js b/src/javascript/jsc/bindings/builtins/js/StreamInternals.js index 9c2103293..c2ca3f5b5 100644 --- a/src/javascript/jsc/bindings/builtins/js/StreamInternals.js +++ b/src/javascript/jsc/bindings/builtins/js/StreamInternals.js @@ -114,18 +114,119 @@ function validateAndNormalizeQueuingStrategy(size, highWaterMark) return { size: size, highWaterMark: newHighWaterMark }; } +@globalPrivate +function createFIFO() { + "use strict"; + class Denqueue { + constructor() { + this._head = 0; + this._tail = 0; + // this._capacity = 0; + this._capacityMask = 0x3; + this._list = @newArrayWithSize(4); + } + + size() { + if (this._head === this._tail) return 0; + if (this._head < this._tail) return this._tail - this._head; + else return this._capacityMask + 1 - (this._head - this._tail); + } + + isEmpty() { + return this.size() == 0; + } + + isNotEmpty() { + return this.size() > 0; + } + + shift() { + var head = this._head; + if (head === this._tail) return @undefined; + var item = this._list[head]; + @putByValDirect(this._list, head, @undefined); + this._head = (head + 1) & this._capacityMask; + if (head < 2 && this._tail > 10000 && this._tail <= this._list.length >>> 2) this._shrinkArray(); + return item; + } + + peek() { + if (this._head === this._tail) return @undefined; + return this._list[this._head]; + } + + push(item) { + var tail = this._tail; + @putByValDirect(this._list, tail, item); + this._tail = (tail + 1) & this._capacityMask; + if (this._tail === this._head) { + this._growArray(); + } + // if (this._capacity && this.size() > this._capacity) { + // this.shift(); + // } + } + + toArray(fullCopy) { + var list = this._list; + var len = @toLength(list.length); + + if (fullCopy || this._head > this._tail) { + var _head = @toLength(this._head); + var _tail = @toLength(this._tail); + var total = @toLength((len - _head) + _tail); + var array = @newArrayWithSize(total); + var j = 0; + for (var i = _head; i < len; i++) @putByValDirect(array, j++, list[i]); + for (var i = 0; i < _tail; i++) @putByValDirect(array, j++, list[i]); + return array; + } else { + return @Array.prototype.slice.@call(list, this._head, this._tail); + } + } + + clear() { + this._head = 0; + this._tail = 0; + this._list.fill(undefined); + } + + _growArray() { + if (this._head) { + // copy existing data, head to end, then beginning to tail. + this._list = this.toArray(true); + this._head = 0; + } + + // head is at 0 and array is now full, safe to extend + this._tail = @toLength(this._list.length); + + this._list.length <<= 1; + this._capacityMask = (this._capacityMask << 1) | 1; + } + + shrinkArray() { + this._list.length >>>= 1; + this._capacityMask >>>= 1; + } + } + + + return new Denqueue(); +} + function newQueue() { "use strict"; - return { content: [], size: 0 }; + return { content: @createFIFO(), size: 0 }; } function dequeueValue(queue) { "use strict"; - const record = queue.content.@shift(); + const record = queue.content.shift(); queue.size -= record.size; // As described by spec, below case may occur due to rounding errors. if (queue.size < 0) @@ -140,7 +241,8 @@ function enqueueValueWithSize(queue, value, size) size = @toNumber(size); if (!@isFinite(size) || size < 0) @throwRangeError("size has an incorrect value"); - @arrayPush(queue.content, { value, size }); + + queue.content.push({ value, size }); queue.size += size; } @@ -148,9 +250,9 @@ function peekQueueValue(queue) { "use strict"; - @assert(queue.content.length > 0); + @assert(queue.content.isNotEmpty()); - return queue.content[0].value; + return queue.peek().value; } function resetQueue(queue) @@ -159,7 +261,7 @@ function resetQueue(queue) @assert("content" in queue); @assert("size" in queue); - queue.content = []; + queue.content.clear(); queue.size = 0; } diff --git a/src/javascript/jsc/bindings/builtins/js/WritableStreamInternals.js b/src/javascript/jsc/bindings/builtins/js/WritableStreamInternals.js index 406b9ea48..6b2b3cf90 100644 --- a/src/javascript/jsc/bindings/builtins/js/WritableStreamInternals.js +++ b/src/javascript/jsc/bindings/builtins/js/WritableStreamInternals.js @@ -118,7 +118,7 @@ function initializeWritableStreamSlots(stream, underlyingSink) @putByIdDirectPrivate(stream, "closeRequest", @undefined); @putByIdDirectPrivate(stream, "inFlightCloseRequest", @undefined); @putByIdDirectPrivate(stream, "pendingAbortRequest", @undefined); - @putByIdDirectPrivate(stream, "writeRequests", []); + @putByIdDirectPrivate(stream, "writeRequests", @createFIFO()); @putByIdDirectPrivate(stream, "backpressure", false); @putByIdDirectPrivate(stream, "underlyingSink", underlyingSink); } @@ -233,7 +233,7 @@ function writableStreamAddWriteRequest(stream) const writePromiseCapability = @newPromiseCapability(@Promise); const writeRequests = @getByIdDirectPrivate(stream, "writeRequests"); - @arrayPush(writeRequests, writePromiseCapability); + writeRequests.push(writePromiseCapability); return writePromiseCapability.@promise; } @@ -266,10 +266,11 @@ function writableStreamFinishErroring(stream) const storedError = @getByIdDirectPrivate(stream, "storedError"); const requests = @getByIdDirectPrivate(stream, "writeRequests"); - for (let index = 0, length = requests.length; index < length; ++index) - requests[index].@reject.@call(@undefined, storedError); + for (var request = requests.shift(); request; request = requests.shift()) + request.@reject.@call(@undefined, storedError); - @putByIdDirectPrivate(stream, "writeRequests", []); + // TODO: is this still necessary? + @putByIdDirectPrivate(stream, "writeRequests", @createFIFO()); const abortRequest = @getByIdDirectPrivate(stream, "pendingAbortRequest"); if (abortRequest === @undefined) { @@ -384,9 +385,9 @@ function writableStreamMarkFirstWriteRequestInFlight(stream) { const writeRequests = @getByIdDirectPrivate(stream, "writeRequests"); @assert(@getByIdDirectPrivate(stream, "inFlightWriteRequest") === @undefined); - @assert(writeRequests.length > 0); + @assert(writeRequests.isNotEmpty()); - const writeRequest = writeRequests.@shift(); + const writeRequest = writeRequests.shift(); @putByIdDirectPrivate(stream, "inFlightWriteRequest", writeRequest); } @@ -649,7 +650,7 @@ function writableStreamDefaultControllerAdvanceQueueIfNeeded(controller) return; } - if (@getByIdDirectPrivate(controller, "queue").content.length === 0) + if (@getByIdDirectPrivate(controller, "queue").content?.isEmpty() ?? false) return; const value = @peekQueueValue(@getByIdDirectPrivate(controller, "queue")); @@ -722,7 +723,7 @@ function writableStreamDefaultControllerProcessClose(controller) @writableStreamMarkCloseRequestInFlight(stream); @dequeueValue(@getByIdDirectPrivate(controller, "queue")); - @assert(@getByIdDirectPrivate(controller, "queue").content.length === 0); + @assert(@getByIdDirectPrivate(controller, "queue").content?.isEmpty()); const sinkClosePromise = @getByIdDirectPrivate(controller, "closeAlgorithm").@call(); @writableStreamDefaultControllerClearAlgorithms(controller); diff --git a/src/javascript/jsc/event_loop.zig b/src/javascript/jsc/event_loop.zig index 88bc9af4e..209e9071d 100644 --- a/src/javascript/jsc/event_loop.zig +++ b/src/javascript/jsc/event_loop.zig @@ -19,8 +19,8 @@ const napi_async_work = JSC.napi.napi_async_work; const FetchTasklet = Fetch.FetchTasklet; const JSValue = JSC.JSValue; const js = JSC.C; -const WorkPool = @import("../../work_pool.zig").WorkPool; -const WorkPoolTask = @import("../../work_pool.zig").Task; +pub const WorkPool = @import("../../work_pool.zig").WorkPool; +pub const WorkPoolTask = @import("../../work_pool.zig").Task; const NetworkThread = @import("http").NetworkThread; pub fn ConcurrentPromiseTask(comptime Context: type) type { diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig index 137ce35b8..3e42c174a 100644 --- a/src/javascript/jsc/webcore/response.zig +++ b/src/javascript/jsc/webcore/response.zig @@ -1557,7 +1557,7 @@ pub const Blob = struct { is_all_ascii: ?bool = null, allocator: std.mem.Allocator, - // 8 MB ought to be enough + // 2 MB ought to be enough pub const max_chunk_size = 1024 * 1024 * 2; pub export fn BlobStore__ref(ptr: *anyopaque) void { @@ -4988,6 +4988,12 @@ pub const FetchEvent = struct { } }; +pub const StreamStart = union(enum) { + empty: void, + err: JSC.Node.Syscall.Error, + chunk_size: Blob.SizeType, +}; + pub const StreamResult = union(enum) { owned: bun.ByteList, owned_and_done: bun.ByteList, @@ -5000,8 +5006,8 @@ pub const StreamResult = union(enum) { done: void, pub const IntoArray = struct { - value: JSValue, - len: usize = std.math.maxInt(usize), + value: JSValue = JSValue.zero, + len: Blob.SizeType = std.math.maxInt(Blob.SizeType), }; pub const Pending = struct { @@ -5010,6 +5016,13 @@ pub const StreamResult = union(enum) { used: bool = false, }; + pub fn isDone(this: *const StreamResult) bool { + return switch (this.*) { + .owned_and_done, .temporary_and_done, .into_array_and_done, .done, .err => true, + else => false, + }; + } + fn toPromisedWrap(globalThis: *JSGlobalObject, promise: *JSPromise, pending: *Pending) void { suspend {} @@ -5038,10 +5051,10 @@ pub const StreamResult = union(enum) { pub fn toJS(this: *const StreamResult, globalThis: *JSGlobalObject) JSValue { switch (this.*) { .owned => |list| { - return JSC.ArrayBuffer.fromBytes(list.slice(), .Uint8Array).toJSAutoAllocator(globalThis.ref(), null); + return JSC.ArrayBuffer.fromBytes(list.slice(), .Uint8Array).toJS(globalThis.ref(), null); }, .owned_and_done => |list| { - return JSC.ArrayBuffer.fromBytes(list.slice(), .Uint8Array).toJSAutoAllocator(globalThis.ref(), null); + return JSC.ArrayBuffer.fromBytes(list.slice(), .Uint8Array).toJS(globalThis.ref(), null); }, .temporary => |temp| { var array = JSC.JSValue.createUninitializedUint8Array(globalThis, temp.len); @@ -5056,10 +5069,10 @@ pub const StreamResult = union(enum) { return array; }, .into_array => |array| { - return array.value; + return JSC.JSValue.jsNumberFromInt64(array.len); }, .into_array_and_done => |array| { - return array.value; + return JSC.JSValue.jsNumberFromInt64(array.len); }, .pending => |pending| { var promise = JSC.JSPromise.create(globalThis); @@ -5115,7 +5128,7 @@ pub fn WritableStreamSink( return onWrite(&this.context, bytes); } - pub fn start(this: *This) StreamResult { + pub fn start(this: *This) StreamStart { return onStart(&this.context); } @@ -5291,21 +5304,21 @@ pub fn ReadableStreamSource( const This = @This(); const ReadableStreamSourceType = @This(); - pub fn pull(this: *This) StreamResult { - return onPull(&this.context); + pub fn pull(this: *This, buf: []u8) StreamResult { + return onPull(&this.context, buf, JSValue.zero); } pub fn start( this: *This, - ) StreamResult { + ) StreamStart { return onStart(&this.context); } - pub fn pullFromJS(this: *This) StreamResult { - return onPull(&this.context); + pub fn pullFromJS(this: *This, buf: []u8, view: JSValue) StreamResult { + return onPull(&this.context, buf, view); } - pub fn startFromJS(this: *This) StreamResult { + pub fn startFromJS(this: *This) StreamStart { return onStart(&this.context); } @@ -5356,19 +5369,24 @@ pub fn ReadableStreamSource( pub fn pull(globalThis: *JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { var this = callFrame.argument(0).asPtr(ReadableStreamSourceType); + const view = callFrame.argument(1); + view.ensureStillAlive(); + var buffer = view.asArrayBuffer(globalThis) orelse return JSC.JSValue.jsUndefined(); return processResult( globalThis, callFrame, - this.pullFromJS(), + this.pullFromJS(buffer.slice(), view), ); } pub fn start(globalThis: *JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { var this = callFrame.argument(0).asPtr(ReadableStreamSourceType); - return processResult( - globalThis, - callFrame, - this.startFromJS(), - ); + switch (this.startFromJS()) { + .empty => return JSValue.jsNumber(0), + .chunk_size => |size| return JSValue.jsNumber(size), + .err => |err| { + return err.toJSC(globalThis); + }, + } } pub fn processResult(globalThis: *JSGlobalObject, callFrame: *JSC.CallFrame, result: StreamResult) JSC.JSValue { @@ -5475,30 +5493,35 @@ pub const ByteBlobLoader = struct { }; } - pub fn onStart(this: *ByteBlobLoader) StreamResult { - return this.onPull(); + pub fn onStart(this: *ByteBlobLoader) StreamStart { + return .{ .chunk_size = this.chunk_size }; } - pub fn onPull(this: *ByteBlobLoader) StreamResult { + pub fn onPull(this: *ByteBlobLoader, buffer: []u8, array: JSC.JSValue) StreamResult { if (this.done) { return .{ .done = {} }; } var temporary = this.store.sharedView(); temporary = temporary[this.offset..]; - temporary = temporary[0..@minimum(this.chunk_size, @minimum(temporary.len, this.remain))]; + + temporary = temporary[0..@minimum(buffer.len, @minimum(temporary.len, this.remain))]; if (temporary.len == 0) { this.store.deref(); this.done = true; return .{ .done = {} }; } - this.remain -|= @intCast(Blob.SizeType, temporary.len); - this.offset +|= @intCast(Blob.SizeType, temporary.len); + const copied = @intCast(Blob.SizeType, temporary.len); - return .{ - .temporary = bun.ByteList.init(temporary), - }; + this.remain -|= copied; + this.offset +|= copied; + @memcpy(temporary.ptr, buffer.ptr, temporary.len); + if (this.remain == 0) { + return .{ .into_array_and_done = .{ .value = array, .len = copied } }; + } + + return .{ .into_array = .{ .value = array, .len = copied } }; } pub fn onCancel(_: *ByteBlobLoader) void {} @@ -5517,7 +5540,7 @@ pub const ByteBlobLoader = struct { pub const FileBlobLoader = struct { buf: []u8 = &[_]u8{}, - uint8array: JSC.JSValue = JSC.JSValue.zero, + protected_view: JSC.JSValue = JSC.JSValue.zero, fd: JSC.Node.FileDescriptor = 0, auto_close: bool = false, loop: *JSC.EventLoop = undefined, @@ -5538,7 +5561,7 @@ pub const FileBlobLoader = struct { const FileReader = @This(); - const run_on_different_thread_size = 1024 * 512; + const run_on_different_thread_size = bun.huge_allocator_threshold; pub const tag = ReadableStream.Tag.File; @@ -5635,40 +5658,23 @@ pub const FileBlobLoader = struct { scheduleMainThreadTask(this); return; } + } - AsyncIO.global.read( - *FileBlobLoader, - this, - onRead, - &this.concurrent.completion, - this.fd, - this.buf[this.concurrent.read..], - null, - ); - - suspend { - var _frame = @frame(); - var this_frame = HTTPClient.getAllocator().create(std.meta.Child(@TypeOf(_frame))) catch unreachable; - this_frame.* = _frame.*; - this.concurrent.read_frame = this_frame; - } - } else { - AsyncIO.global.read( - *FileBlobLoader, - this, - onRead, - &this.concurrent.completion, - this.fd, - this.buf[this.concurrent.read..], - null, - ); + AsyncIO.global.read( + *FileBlobLoader, + this, + onRead, + &this.concurrent.completion, + this.fd, + this.buf[this.concurrent.read..], + null, + ); - suspend { - var _frame = @frame(); - var this_frame = HTTPClient.getAllocator().create(std.meta.Child(@TypeOf(_frame))) catch unreachable; - this_frame.* = _frame.*; - this.concurrent.read_frame = this_frame; - } + suspend { + var _frame = @frame(); + var this_frame = HTTPClient.getAllocator().create(std.meta.Child(@TypeOf(_frame))) catch unreachable; + this_frame.* = _frame.*; + this.concurrent.read_frame = this_frame; } scheduleMainThreadTask(this); @@ -5676,12 +5682,16 @@ pub const FileBlobLoader = struct { pub fn onJSThread(task_ctx: *anyopaque) void { var this: *FileBlobLoader = bun.cast(*FileBlobLoader, task_ctx); + const protected_view = this.protected_view; + defer protected_view.unprotect(); + this.protected_view = JSC.JSValue.zero; if (this.finalized and this.scheduled_count == 0) { if (!this.pending.used) { resume this.pending.frame; } this.scheduled_count -= 1; + this.deinit(); return; @@ -5702,9 +5712,12 @@ pub const FileBlobLoader = struct { return; } - this.pending.result = this.handleReadChunk(this.buf, @as(usize, this.concurrent.read)); + this.pending.result = this.handleReadChunk(@as(usize, this.concurrent.read)); resume this.pending.frame; this.scheduled_count -= 1; + if (this.pending.result.isDone()) { + this.finalize(); + } } pub fn scheduleMainThreadTask(this: *FileBlobLoader) void { @@ -5714,14 +5727,6 @@ pub const FileBlobLoader = struct { fn runAsync(this: *FileBlobLoader) void { this.concurrent.read = 0; - this.buf = bun.auto_allocator.alloc(u8, this.concurrent.chunk_size) catch { - this.pending.result = .{ .err = JSC.Node.Syscall.Error.oom }; - this.concurrent.read = 0; - scheduleMainThreadTask(this); - - return; - }; - _ = bun.C.posix_madvise(this.buf.ptr, this.buf.len, 2); Concurrent.scheduleRead(this); @@ -5742,7 +5747,7 @@ pub const FileBlobLoader = struct { const default_fifo_chunk_size = 1024; const default_file_chunk_size = 1024 * 1024 * 2; - pub fn onStart(this: *FileBlobLoader) StreamResult { + pub fn onStart(this: *FileBlobLoader) StreamStart { var file = &this.store.data.file; var file_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; var auto_close = this.auto_close; @@ -5800,15 +5805,6 @@ pub const FileBlobLoader = struct { return .{ .err = err }; } - // if (comptime Environment.isMac) { - // if (std.os.S.ISSOCK(stat.mode)) { - // // darwin doesn't support os.MSG.NOSIGNAL, - // // but instead a socket option to avoid SIGPIPE. - // const _bytes = &std.mem.toBytes(@as(c_int, 1)); - // _ = std.os.darwin.setsockopt(fd, std.os.SOL.SOCKET, std.os.SO.NOSIGPIPE, _bytes, @intCast(std.os.socklen_t, _bytes.len)); - // } - // } - file.seekable = std.os.S.ISREG(stat.mode); file.mode = @intCast(JSC.Node.Mode, stat.mode); this.mode = file.mode; @@ -5821,45 +5817,14 @@ pub const FileBlobLoader = struct { _ = JSC.Node.Syscall.close(fd); } this.deinit(); - return .{ .done = {} }; + return .{ .empty = {} }; } this.fd = fd; this.auto_close = auto_close; const chunk_size = this.calculateChunkSize(std.math.maxInt(usize)); - - if (chunk_size >= run_on_different_thread_size) { - // should never be reached - this.pending.result = .{ - .err = JSC.Node.Syscall.Error.todo, - }; - - this.scheduleAsync(@truncate(Blob.SizeType, chunk_size)); - - return .{ .pending = &this.pending }; - } - - if (this.allocateBuffer(chunk_size)) |err| { - this.deinit(); - return .{ .err = err }; - } - - return this.read(this.buf); - } - - // Disabled because it's not fully implemented - // Maybe we should allocate as an ArrayBuffer instead of a Uint8Array? - fn shouldUseJSCHeap(this: *const FileBlobLoader, chunk_size: Blob.SizeType) bool { - _ = this; - _ = chunk_size; - return false; - // const file = &this.store.data.file; - - // if (!(file.seekable orelse false)) - // return false; - - // return file.max_size - this.total_read >= chunk_size; + return .{ .chunk_size = @truncate(Blob.SizeType, chunk_size) }; } fn calculateChunkSize(this: *FileBlobLoader, available_to_read: usize) usize { @@ -5878,55 +5843,32 @@ pub const FileBlobLoader = struct { @minimum(available_to_read, chunk_size); } - fn allocateBuffer(this: *FileBlobLoader, chunk_size: usize) ?JSC.Node.Syscall.Error { - var file = &this.store.data.file; - - if (this.shouldUseJSCHeap(@intCast(Blob.SizeType, chunk_size))) { - this.uint8array = JSValue.createUninitializedUint8Array(this.loop.global, chunk_size); - this.uint8array.ensureStillAlive(); - this.buf = this.uint8array.asArrayBuffer(this.loop.global).?.slice(); - } else { - this.buf = bun.auto_allocator.alloc( - u8, - chunk_size, - ) catch { - this.maybeAutoClose(); - return JSC.Node.Syscall.Error.oom.withPath(if (file.pathlike.path.slice().len > 0) file.pathlike.path.slice() else ""); - }; - } - - return null; - } - - pub fn onPull(this: *FileBlobLoader) StreamResult { - if (this.buf.len == 0) { - const chunk_size = this.calculateChunkSize(std.math.maxInt(usize)); + pub fn onPull(this: *FileBlobLoader, buffer: []u8, view: JSC.JSValue) StreamResult { + const chunk_size = this.calculateChunkSize(std.math.maxInt(usize)); - switch (chunk_size) { - 0 => { - std.debug.assert(this.store.data.file.seekable orelse false); - this.finalize(); - return .{ .done = {} }; - }, - run_on_different_thread_size...std.math.maxInt(@TypeOf(chunk_size)) => { - // should never be reached - this.pending.result = .{ - .err = JSC.Node.Syscall.Error.todo, - }; + switch (chunk_size) { + 0 => { + std.debug.assert(this.store.data.file.seekable orelse false); + this.finalize(); + return .{ .done = {} }; + }, + run_on_different_thread_size...std.math.maxInt(@TypeOf(chunk_size)) => { + this.protected_view = view; + this.protected_view.protect(); + // should never be reached + this.pending.result = .{ + .err = JSC.Node.Syscall.Error.todo, + }; + this.buf = buffer; - this.scheduleAsync(@truncate(Blob.SizeType, chunk_size)); + this.scheduleAsync(@truncate(Blob.SizeType, chunk_size)); - return .{ .pending = &this.pending }; - }, - else => { - if (this.allocateBuffer(chunk_size)) |err| { - return .{ .err = err }; - } - }, - } + return .{ .pending = &this.pending }; + }, + else => {}, } - return this.read(this.buf); + return this.read(buffer, view); } fn maybeAutoClose(this: *FileBlobLoader) void { @@ -5936,7 +5878,7 @@ pub const FileBlobLoader = struct { } } - fn handleReadChunk(this: *FileBlobLoader, read_buf: []u8, result: usize) StreamResult { + fn handleReadChunk(this: *FileBlobLoader, result: usize) StreamResult { this.total_read += @intCast(Blob.SizeType, result); const remaining: Blob.SizeType = if (this.store.data.file.seekable orelse false) this.store.data.file.max_size -| this.total_read @@ -5954,52 +5896,16 @@ pub const FileBlobLoader = struct { const has_more = remaining > 0; if (!has_more) { - this.uint8array.ensureStillAlive(); - - defer { - this.uint8array.ensureStillAlive(); - this.buf = &.{}; - this.uint8array = JSValue.zero; - this.finalize(); - } - - if (this.uint8array.isEmpty()) { - return .{ - .owned_and_done = bun.ByteList.init(read_buf[0..result]), - }; - } else { - return .{ - .into_array_and_done = .{ - .value = this.uint8array, - .len = result, - }, - }; - } + return .{ .into_array_and_done = .{ .len = @truncate(Blob.SizeType, result) } }; } - if (this.uint8array.isEmpty()) { - defer this.buf = &.{}; - return .{ - .owned = bun.ByteList.init(read_buf[0..result]), - }; - } else { - defer { - this.buf = &.{}; - this.uint8array = JSValue.zero; - } - - return .{ - .into_array = .{ - .value = this.uint8array, - .len = result, - }, - }; - } + return .{ .into_array = .{ .len = @truncate(Blob.SizeType, result) } }; } pub fn read( this: *FileBlobLoader, read_buf: []u8, + view: JSC.JSValue, ) StreamResult { const rc = JSC.Node.Syscall.read(this.fd, read_buf); @@ -6013,6 +5919,9 @@ pub const FileBlobLoader = struct { switch (err.getErrno()) { retry => { + this.protected_view = view; + this.protected_view.protect(); + this.buf = read_buf; this.watch(); return .{ .pending = &this.pending, @@ -6029,7 +5938,7 @@ pub const FileBlobLoader = struct { return .{ .err = sys }; }, .result => |result| { - return this.handleReadChunk(read_buf, result); + return this.handleReadChunk(result); }, } } @@ -6037,6 +5946,9 @@ pub const FileBlobLoader = struct { pub fn callback(task: ?*anyopaque, sizeOrOffset: i64, _: u16) void { var this: *FileReader = bun.cast(*FileReader, task.?); this.scheduled_count -= 1; + const protected_view = this.protected_view; + defer protected_view.unprotect(); + this.protected_view = JSValue.zero; var available_to_read: usize = std.math.maxInt(usize); if (comptime Environment.isMac) { @@ -6064,16 +5976,12 @@ pub const FileBlobLoader = struct { return; if (this.buf.len == 0) { - if (this.allocateBuffer(available_to_read)) |err| { - this.pending.result = .{ .err = err }; - resume this.pending.frame; - return; - } + return; } else { this.buf.len = @minimum(this.buf.len, available_to_read); } - this.pending.result = this.read(this.buf); + this.pending.result = this.read(this.buf, this.protected_view); resume this.pending.frame; } @@ -6081,15 +5989,6 @@ pub const FileBlobLoader = struct { if (this.finalized) return; this.finalized = true; - if (this.buf.len > 0) { - if (this.uint8array.isEmpty()) { - bun.default_allocator.free(this.buf); - this.buf = &.{}; - } else { - this.buf = &.{}; - this.uint8array = JSValue.zero; - } - } this.maybeAutoClose(); diff --git a/src/memory_allocator.zig b/src/memory_allocator.zig index b6b9283fa..a8fbd116a 100644 --- a/src/memory_allocator.zig +++ b/src/memory_allocator.zig @@ -214,7 +214,6 @@ const z_allocator_vtable = Allocator.VTable{ .resize = ZAllocator.resize, .free = ZAllocator.free, }; - const HugeAllocator = struct { fn alloc( _: *anyopaque, @@ -272,6 +271,8 @@ const huge_allocator_vtable = Allocator.VTable{ .free = HugeAllocator.free, }; +pub const huge_threshold = 1024 * 256; + const AutoSizeAllocator = struct { fn alloc( _: *anyopaque, @@ -280,7 +281,7 @@ const AutoSizeAllocator = struct { len_align: u29, return_address: usize, ) error{OutOfMemory}![]u8 { - if (len > 1024 * 1024 * 2) { + if (len >= huge_threshold) { return huge_allocator.rawAlloc( len, alignment, @@ -314,7 +315,7 @@ const AutoSizeAllocator = struct { a: u29, b: usize, ) void { - if (buf.len > 1024 * 1024 * 2) { + if (buf.len >= huge_threshold) { return huge_allocator.rawFree( buf, a, |