From 09277c852cdf68840a013bfbb541d6bbb389541c Mon Sep 17 00:00:00 2001 From: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> Date: Mon, 12 Feb 2024 02:18:02 -0800 Subject: [PATCH] fixup --- src/bun.js/bindings/bindings.cpp | 31 +++++++++++++++--- src/bun.js/bindings/bindings.zig | 2 +- src/bun.js/webcore/streams.zig | 38 ++++++++++++++-------- src/js/builtins/ReadableStreamInternals.ts | 8 ++--- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 44a6bb839c..0778950e86 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -5113,12 +5113,33 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC__JSGlobalObject* arg0 { Zig::GlobalObject* globalObject = reinterpret_cast(arg0); JSC::VM& vm = globalObject->vm(); - globalObject->queueMicrotask( - JSValue(globalObject->performMicrotaskFunction()), - JSC::JSValue::decode(JSValue1), + JSValue microtaskArgs[] = { + JSValue::decode(JSValue1), globalObject->m_asyncContextData.get()->getInternalField(0), - JSC::JSValue::decode(JSValue3), - JSC::JSValue::decode(JSValue4)); + JSValue::decode(JSValue3), + JSValue::decode(JSValue4) + }; + + ASSERT(microtaskArgs[0].isCallable()); + + if (microtaskArgs[1].isEmpty()) { + microtaskArgs[1] = jsUndefined(); + } + + if (microtaskArgs[2].isEmpty()) { + microtaskArgs[2] = jsUndefined(); + } + + if (microtaskArgs[3].isEmpty()) { + microtaskArgs[3] = jsUndefined(); + } + + globalObject->queueMicrotask( + globalObject->performMicrotaskFunction(), + WTFMove(microtaskArgs[0]), + WTFMove(microtaskArgs[1]), + WTFMove(microtaskArgs[2]), + WTFMove(microtaskArgs[3])); } extern "C" WebCore::AbortSignal* WebCore__AbortSignal__new(JSC__JSGlobalObject* globalObject) diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 0929c5fe99..808d27fc77 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -2830,7 +2830,7 @@ pub const JSGlobalObject = extern struct { pub fn queueMicrotask( this: *JSGlobalObject, function: JSValue, - args: []JSC.JSValue, + args: []const JSC.JSValue, ) void { this.queueMicrotaskJob( function, diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index 211ac634bf..923f104b61 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -2582,7 +2582,7 @@ pub fn ReadableStreamSource( pending_err: ?Syscall.Error = null, close_handler: ?*const fn (?*anyopaque) void = null, close_ctx: ?*anyopaque = null, - close_jsvalue: JSC.JSValue = .zero, + close_jsvalue: JSC.Strong = .{}, globalThis: *JSGlobalObject = undefined, this_jsvalue: JSC.JSValue = .zero, is_closed: bool = false, @@ -2665,6 +2665,7 @@ pub fn ReadableStreamSource( this.ref_count -= 1; if (this.ref_count == 0) { + this.close_jsvalue.deinit(); deinit_fn(&this.context); return 0; } @@ -2729,6 +2730,7 @@ pub fn ReadableStreamSource( const arguments = callFrame.arguments(2); const view = arguments.ptr[0]; view.ensureStillAlive(); + this.this_jsvalue = this_jsvalue; var buffer = view.asArrayBuffer(globalThis) orelse return JSC.JSValue.jsUndefined(); return processResult( this_jsvalue, @@ -2738,9 +2740,9 @@ pub fn ReadableStreamSource( ); } pub fn start(this: *ReadableStreamSourceType, globalThis: *JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { - _ = callFrame; // autofix JSC.markBinding(@src()); this.globalThis = globalThis; + this.this_jsvalue = callFrame.this(); switch (this.onStartFromJS()) { .empty => return JSValue.jsNumber(0), .ready => return JSValue.jsNumber(16384), @@ -2787,8 +2789,8 @@ pub fn ReadableStreamSource( } pub fn cancel(this: *ReadableStreamSourceType, globalObject: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { _ = globalObject; // autofix - _ = callFrame; // autofix JSC.markBinding(@src()); + this.this_jsvalue = callFrame.this(); this.cancel(); return JSC.JSValue.jsUndefined(); } @@ -2796,48 +2798,56 @@ pub fn ReadableStreamSource( JSC.markBinding(@src()); this.close_handler = JSReadableStreamSource.onClose; this.globalThis = globalObject; + + if (value.isUndefined()) { + this.close_jsvalue.deinit(); + return true; + } + if (!value.isCallable(globalObject.vm())) { globalObject.throwInvalidArgumentType("ReadableStreamSource", "onclose", "function"); return false; } const cb = value.withAsyncContextIfNeeded(globalObject); - this.close_jsvalue = cb; - ReadableStreamSourceType.onCloseCallbackSetCached(this.this_jsvalue, globalObject, cb); + this.close_jsvalue.set(globalObject, cb); return true; } pub fn getOnCloseFromJS(this: *ReadableStreamSourceType, globalObject: *JSC.JSGlobalObject) callconv(.C) JSC.JSValue { _ = globalObject; // autofix - JSC.markBinding(@src()); - if (this.close_jsvalue == .zero) { - return JSC.JSValue.jsUndefined(); - } - return this.close_jsvalue; + JSC.markBinding(@src()); + + return this.close_jsvalue.get() orelse .undefined; } pub fn updateRef(this: *ReadableStreamSourceType, globalObject: *JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { JSC.markBinding(@src()); + this.this_jsvalue = callFrame.this(); const ref_or_unref = callFrame.argument(0).toBooleanSlow(globalObject); this.setRef(ref_or_unref); + return JSC.JSValue.jsUndefined(); } fn onClose(ptr: ?*anyopaque) void { JSC.markBinding(@src()); var this = bun.cast(*ReadableStreamSourceType, ptr.?); - const loop = this.globalThis.bunVM().eventLoop(); - loop.runCallback(this.close_jsvalue, this.globalThis, if (this.this_jsvalue != .zero) this.this_jsvalue else .undefined, &.{}); - // this.closer + if (this.close_jsvalue.trySwap()) |cb| { + this.globalThis.queueMicrotask(cb, &.{}); + } + + this.close_jsvalue.deinit(); } pub fn finalize(this: *ReadableStreamSourceType) callconv(.C) void { + this.this_jsvalue = .zero; _ = this.decrementCount(); } pub fn drain(this: *ReadableStreamSourceType, globalThis: *JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSC.JSValue { - _ = callFrame; // autofix JSC.markBinding(@src()); + this.this_jsvalue = callFrame.this(); var list = this.drain(); if (list.len > 0) { return JSC.ArrayBuffer.fromBytes(list.slice(), .Uint8Array).toJS(globalThis, null); diff --git a/src/js/builtins/ReadableStreamInternals.ts b/src/js/builtins/ReadableStreamInternals.ts index aff5c443cd..157ce07283 100644 --- a/src/js/builtins/ReadableStreamInternals.ts +++ b/src/js/builtins/ReadableStreamInternals.ts @@ -1532,10 +1532,9 @@ export function lazyLoadStream(stream, autoAllocateChunkSize) { function callClose(controller) { try { const stream = $getByIdDirectPrivate(controller, "controlledReadableStream"); - $assert(stream, "stream is missing"); - if ($getByIdDirectPrivate(stream, "state") === $streamReadable) { - controller.close(); - } + if (!stream) return; + if ($getByIdDirectPrivate(stream, "state") !== $streamReadable) return; + controller.close(); } catch (e) { globalThis.reportError(e); } @@ -1588,7 +1587,6 @@ export function lazyLoadStream(stream, autoAllocateChunkSize) { this.pull = this.#pull.bind(this); this.cancel = this.#cancel.bind(this); this.autoAllocateChunkSize = autoAllocateChunkSize; - handle.updateRef(true); if (drainValue !== undefined) { this.start = controller => {