diff options
author | 2022-12-20 22:05:47 -0800 | |
---|---|---|
committer | 2022-12-20 22:05:47 -0800 | |
commit | a98e0adc7dda63600ff811fc6928c69879334dc5 (patch) | |
tree | 7e8c0911f3cb4493b43300811bad3c6a4f50a970 /src/bun.js | |
parent | 06487ef64f6968c411420f3e8347144f3885d2ef (diff) | |
download | bun-a98e0adc7dda63600ff811fc6928c69879334dc5.tar.gz bun-a98e0adc7dda63600ff811fc6928c69879334dc5.tar.zst bun-a98e0adc7dda63600ff811fc6928c69879334dc5.zip |
[web] Support multiple arguments in `setTimeout`, `setInterval`, and `setImmediate`
Diffstat (limited to 'src/bun.js')
-rw-r--r-- | src/bun.js/api/bun.zig | 63 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 67 | ||||
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 11 | ||||
-rw-r--r-- | src/bun.js/bindings/headers-cpp.h | 2 | ||||
-rw-r--r-- | src/bun.js/bindings/headers.h | 6 |
5 files changed, 139 insertions, 10 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index 7d7c0ec7a..eb235da2f 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -2340,6 +2340,7 @@ pub const Timer = struct { ref: JSC.Ref = JSC.Ref.init(), globalThis: *JSC.JSGlobalObject, callback: JSC.Strong = .{}, + arguments: JSC.Strong = .{}, repeat: bool = false, pub const Task = JSC.AnyTask.New(CallbackJob, perform); @@ -2369,6 +2370,7 @@ pub const Timer = struct { pub fn deinit(this: *CallbackJob) void { this.callback.deinit(); + this.arguments.deinit(); this.ref.unref(this.globalThis.bunVM()); bun.default_allocator.destroy(this); } @@ -2395,9 +2397,34 @@ pub const Timer = struct { } } + var args_buf: [8]JSC.JSValue = undefined; + var args: []JSC.JSValue = &.{}; + var args_needs_deinit = false; + defer if (args_needs_deinit) bun.default_allocator.free(args); + const callback = this.callback.get() orelse @panic("Expected CallbackJob to have a callback function"); + if (this.arguments.trySwap()) |arguments| { + const count = arguments.getLengthOfArray(globalThis); + if (count > 0) { + if (count > args_buf.len) { + args = bun.default_allocator.alloc(JSC.JSValue, count) catch unreachable; + args_needs_deinit = true; + } else { + args = args_buf[0..count]; + } + var arg = args.ptr; + var i: u32 = 0; + while (i < count) : (i += 1) { + arg[0] = JSC.JSObject.getIndex(arguments, globalThis, @truncate(u32, i)); + arg += 1; + } + } + } - const result = callback.call(globalThis, &.{}); + const result = callback.callWithGlobalThis( + globalThis, + args, + ); if (result.isEmptyOrUndefinedOrNull() or !result.isCell()) { this.deinit(); @@ -2435,6 +2462,7 @@ pub const Timer = struct { globalThis: *JSC.JSGlobalObject, timer: *uws.Timer, poll_ref: JSC.PollRef = JSC.PollRef.init(), + arguments: JSC.Strong = .{}, // this is sized to be the same as one pointer pub const ID = extern struct { @@ -2478,6 +2506,21 @@ pub const Timer = struct { ) else this.callback, + .arguments = if (repeats and this.arguments.has()) + JSC.Strong.create( + this.arguments.get() orelse { + // if the arguments freed, that's an error + if (comptime Environment.allow_assert) + unreachable; + + this.deinit(); + _ = map.swapRemove(timer_id.id); + return; + }, + globalThis, + ) + else + this.arguments, .globalThis = globalThis, .id = timer_id.id, .repeat = timer_id.repeat > 0, @@ -2488,6 +2531,7 @@ pub const Timer = struct { // - reuse the JSC.Strong if (!repeats) { this.callback = .{}; + this.arguments = .{}; map.put(vm.allocator, timer_id.id, null) catch unreachable; this.deinit(); } @@ -2507,9 +2551,11 @@ pub const Timer = struct { JSC.markBinding(@src()); var vm = this.globalThis.bunVM(); + this.poll_ref.unref(vm); this.timer.deinit(); this.callback.deinit(); + this.arguments.deinit(); } }; @@ -2518,6 +2564,7 @@ pub const Timer = struct { globalThis: *JSGlobalObject, callback: JSValue, countdown: JSValue, + arguments_array_or_zero: JSValue, repeat: bool, ) !void { JSC.markBinding(@src()); @@ -2545,6 +2592,10 @@ pub const Timer = struct { .repeat = false, }; + if (arguments_array_or_zero != .zero) { + cb.arguments = JSC.Strong.create(arguments_array_or_zero, globalThis); + } + var job = vm.allocator.create(CallbackJob) catch @panic( "Out of memory while allocating Timeout", ); @@ -2570,6 +2621,10 @@ pub const Timer = struct { ), }; + if (arguments_array_or_zero != .zero) { + timeout.arguments = JSC.Strong.create(arguments_array_or_zero, globalThis); + } + timeout.poll_ref.ref(vm); map.put(vm.allocator, id, timeout) catch unreachable; @@ -2588,12 +2643,13 @@ pub const Timer = struct { globalThis: *JSGlobalObject, callback: JSValue, countdown: JSValue, + arguments: JSValue, ) callconv(.C) JSValue { JSC.markBinding(@src()); const id = globalThis.bunVM().timer.last_id; globalThis.bunVM().timer.last_id +%= 1; - Timer.set(id, globalThis, callback, countdown, false) catch + Timer.set(id, globalThis, callback, countdown, arguments, false) catch return JSValue.jsUndefined(); return JSValue.jsNumberWithType(i32, id); @@ -2602,12 +2658,13 @@ pub const Timer = struct { globalThis: *JSGlobalObject, callback: JSValue, countdown: JSValue, + arguments: JSValue, ) callconv(.C) JSValue { JSC.markBinding(@src()); const id = globalThis.bunVM().timer.last_id; globalThis.bunVM().timer.last_id +%= 1; - Timer.set(id, globalThis, callback, countdown, true) catch + Timer.set(id, globalThis, callback, countdown, arguments, true) catch return JSValue.jsUndefined(); return JSValue.jsNumberWithType(i32, id); diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index e8ee74943..7b5490a0b 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -762,7 +762,27 @@ static JSC_DEFINE_HOST_FUNCTION(functionSetTimeout, } JSC::JSValue num = callFrame->argument(1); - return Bun__Timer__setTimeout(globalObject, JSC::JSValue::encode(job), JSC::JSValue::encode(num)); + JSC::JSValue arguments = {}; + size_t argumentCount = callFrame->argumentCount() - 2; + if (argumentCount > 0) { + JSC::ObjectInitializationScope initializationScope(globalObject->vm()); + JSC::JSArray* argumentsArray = argumentsArray = JSC::JSArray::tryCreateUninitializedRestricted( + initializationScope, nullptr, + globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous), + argumentCount); + + if (!argumentsArray) { + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + JSC::throwOutOfMemoryError(globalObject, scope); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + for (size_t i = 0; i < argumentCount; i++) { + argumentsArray->putDirectIndex(globalObject, i, callFrame->uncheckedArgument(i + 2)); + } + arguments = JSValue(argumentsArray); + } + return Bun__Timer__setTimeout(globalObject, JSC::JSValue::encode(job), JSC::JSValue::encode(num), JSValue::encode(arguments)); } static JSC_DEFINE_HOST_FUNCTION(functionSetInterval, @@ -785,8 +805,29 @@ static JSC_DEFINE_HOST_FUNCTION(functionSetInterval, } JSC::JSValue num = callFrame->argument(1); + + JSC::JSValue arguments = {}; + size_t argumentCount = callFrame->argumentCount() - 2; + if (argumentCount > 0) { + JSC::ObjectInitializationScope initializationScope(globalObject->vm()); + JSC::JSArray* argumentsArray = argumentsArray = JSC::JSArray::tryCreateUninitializedRestricted( + initializationScope, nullptr, + globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous), + argumentCount); + + if (!argumentsArray) { + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + JSC::throwOutOfMemoryError(globalObject, scope); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + for (size_t i = 0; i < argumentCount; i++) { + argumentsArray->putDirectIndex(globalObject, i, callFrame->uncheckedArgument(i + 2)); + } + arguments = JSValue(argumentsArray); + } return Bun__Timer__setInterval(globalObject, JSC::JSValue::encode(job), - JSC::JSValue::encode(num)); + JSC::JSValue::encode(num), JSValue::encode(arguments)); } static JSC_DEFINE_HOST_FUNCTION(functionClearInterval, @@ -2753,7 +2794,27 @@ static JSC_DEFINE_HOST_FUNCTION(functionSetImmediate, return JSC::JSValue::encode(JSC::JSValue {}); } - return Bun__Timer__setTimeout(globalObject, JSC::JSValue::encode(job), JSC::JSValue::encode(jsNumber(0))); + JSC::JSValue arguments = {}; + size_t argumentCount = callFrame->argumentCount() - 1; + if (argumentCount > 0) { + JSC::ObjectInitializationScope initializationScope(globalObject->vm()); + JSC::JSArray* argumentsArray = argumentsArray = JSC::JSArray::tryCreateUninitializedRestricted( + initializationScope, nullptr, + globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous), + argumentCount); + + if (!argumentsArray) { + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + JSC::throwOutOfMemoryError(globalObject, scope); + return JSC::JSValue::encode(JSC::JSValue {}); + } + + for (size_t i = 0; i < argumentCount; i++) { + argumentsArray->putDirectIndex(globalObject, i, callFrame->uncheckedArgument(i + 1)); + } + arguments = JSValue(argumentsArray); + } + return Bun__Timer__setTimeout(globalObject, JSC::JSValue::encode(job), JSC::JSValue::encode(jsNumber(0)), JSValue::encode(arguments)); } JSC_DEFINE_CUSTOM_GETTER(JSModuleLoader_getter, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName)) diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index add89ea77..1ce48da90 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -2427,6 +2427,17 @@ pub const JSValue = enum(JSValueReprInt) { return callWithThis(this, globalThis, JSC.JSValue.jsUndefined(), args); } + pub fn callWithGlobalThis(this: JSValue, globalThis: *JSGlobalObject, args: []const JSC.JSValue) JSC.JSValue { + JSC.markBinding(@src()); + return JSC.C.JSObjectCallAsFunctionReturnValue( + globalThis, + this.asObjectRef(), + @ptrCast(JSC.C.JSValueRef, globalThis), + args.len, + @ptrCast(?[*]const JSC.C.JSValueRef, args.ptr), + ); + } + pub fn callWithThis(this: JSValue, globalThis: *JSGlobalObject, thisValue: JSC.JSValue, args: []const JSC.JSValue) JSC.JSValue { JSC.markBinding(@src()); return JSC.C.JSObjectCallAsFunctionReturnValue( diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h index b8bf7c300..0e43e86de 100644 --- a/src/bun.js/bindings/headers-cpp.h +++ b/src/bun.js/bindings/headers-cpp.h @@ -1,4 +1,4 @@ -//-- AUTOGENERATED FILE -- 1671319165 +//-- AUTOGENERATED FILE -- 1671518642 // clang-format off #pragma once diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index f29395eff..31f5dc22a 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -1,5 +1,5 @@ // clang-format off -//-- AUTOGENERATED FILE -- 1671319165 +//-- AUTOGENERATED FILE -- 1671518642 #pragma once #include <stddef.h> @@ -726,8 +726,8 @@ ZIG_DECL void Zig__ConsoleClient__timeStamp(void* arg0, JSC__JSGlobalObject* arg ZIG_DECL JSC__JSValue Bun__Timer__clearInterval(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1); ZIG_DECL JSC__JSValue Bun__Timer__clearTimeout(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1); ZIG_DECL int32_t Bun__Timer__getNextID(); -ZIG_DECL JSC__JSValue Bun__Timer__setInterval(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, JSC__JSValue JSValue2); -ZIG_DECL JSC__JSValue Bun__Timer__setTimeout(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, JSC__JSValue JSValue2); +ZIG_DECL JSC__JSValue Bun__Timer__setInterval(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, JSC__JSValue JSValue2, JSC__JSValue JSValue3); +ZIG_DECL JSC__JSValue Bun__Timer__setTimeout(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, JSC__JSValue JSValue2, JSC__JSValue JSValue3); #endif |