aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bun.js/api/server.zig6
-rw-r--r--src/bun.js/event_loop.zig236
-rw-r--r--src/bun.js/webcore/streams.zig21
-rw-r--r--src/bun_js.zig2
m---------src/deps/uws0
-rw-r--r--src/deps/uws.zig9
-rw-r--r--src/io/io_darwin.zig5
-rw-r--r--src/io/io_linux.zig8
-rw-r--r--test/apps/bun-install.sh5
-rw-r--r--test/bun.js/ffi.test.fixture.callback.c35
-rw-r--r--test/bun.js/ffi.test.fixture.receiver.c35
-rw-r--r--test/bun.js/serve.test.ts56
12 files changed, 230 insertions, 188 deletions
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index 12b383f05..2410b5e7c 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -2148,14 +2148,8 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
}
this.listener = socket;
- const needs_post_handler = this.vm.uws_event_loop == null;
this.vm.uws_event_loop = uws.Loop.get();
this.ref();
-
- if (needs_post_handler) {
- _ = this.vm.uws_event_loop.?.addPostHandler(*JSC.EventLoop, this.vm.eventLoop(), JSC.EventLoop.tick);
- _ = this.vm.uws_event_loop.?.addPreHandler(*JSC.EventLoop, this.vm.eventLoop(), JSC.EventLoop.tick);
- }
}
pub fn ref(this: *ThisServer) void {
diff --git a/src/bun.js/event_loop.zig b/src/bun.js/event_loop.zig
index 1907838d0..d4688beac 100644
--- a/src/bun.js/event_loop.zig
+++ b/src/bun.js/event_loop.zig
@@ -23,6 +23,7 @@ const js = JSC.C;
pub const WorkPool = @import("../work_pool.zig").WorkPool;
pub const WorkPoolTask = @import("../work_pool.zig").Task;
const NetworkThread = @import("http").NetworkThread;
+const uws = @import("uws");
pub fn ConcurrentPromiseTask(comptime Context: type) type {
return struct {
@@ -325,7 +326,6 @@ pub const EventLoop = struct {
// TODO: fix this technical debt
pub fn tick(this: *EventLoop) void {
- var poller = &this.virtual_machine.poller;
var ctx = this.virtual_machine;
this.tickConcurrent();
var global_vm = ctx.global.vm();
@@ -338,11 +338,13 @@ pub const EventLoop = struct {
this.tickConcurrent();
if (this.tasks.count > 0) continue;
}
+ break;
+ }
- this.global.vm().doWork();
- poller.tick();
+ this.global.vm().doWork();
- break;
+ while (this.tickWithCount() > 0) {
+ this.tickConcurrent();
}
this.global.handleRejectedPromises();
@@ -354,7 +356,7 @@ pub const EventLoop = struct {
ctx.global.vm().releaseWeakRefs();
ctx.global.vm().drainMicrotasks();
- if (ctx.us_loop_reference_count > 0 and !ctx.is_us_loop_entered and (ctx.uws_event_loop.?.num_polls > 0 or this.start_server_on_next_tick)) {
+ if (ctx.poller.loop != null and ctx.poller.loop.?.active > 0 or (ctx.us_loop_reference_count > 0 and !ctx.is_us_loop_entered and (ctx.uws_event_loop.?.num_polls > 0 or this.start_server_on_next_tick))) {
if (this.tickConcurrentWithCount() > 0) {
this.tick();
} else {
@@ -380,8 +382,6 @@ pub const EventLoop = struct {
if (promise.status(this.global.vm()) == .Pending) {
if (this.virtual_machine.uws_event_loop != null) {
this.runUSocketsLoop();
- } else if (this.waker) |*waker| {
- _ = waker.wait() catch 0;
}
}
}
@@ -411,8 +411,11 @@ pub const EventLoop = struct {
pub fn ensureWaker(this: *EventLoop) void {
JSC.markBinding();
- if (this.waker == null) {
- this.waker = AsyncIO.Waker.init(this.virtual_machine.allocator) catch unreachable;
+ if (this.virtual_machine.uws_event_loop == null) {
+ var actual = uws.Loop.get().?;
+ this.virtual_machine.uws_event_loop = actual;
+ _ = actual.addPostHandler(*JSC.EventLoop, this, JSC.EventLoop.tick);
+ _ = actual.addPreHandler(*JSC.VM, this.virtual_machine.global.vm(), JSC.VM.drainMicrotasks);
}
}
@@ -432,113 +435,143 @@ pub const EventLoop = struct {
loop.nextTick(*EventLoop, this, onDefer);
}
}
-
- if (this.waker) |*waker| {
- waker.wake() catch unreachable;
- }
}
};
pub const Poller = struct {
/// kqueue() or epoll()
/// 0 == unset
- watch_fd: i32 = 0,
- active: u32 = 0,
-
- pub const PlatformSpecificFlags = struct {};
+ loop: ?*uws.Loop = null,
- const Completion = fn (ctx: ?*anyopaque, sizeOrOffset: i64, flags: u16) void;
- const kevent64 = std.os.system.kevent64_s;
- pub fn dispatchKQueueEvent(kqueue_event: *const kevent64) void {
+ pub fn dispatchKQueueEvent(loop: *uws.Loop, kqueue_event: *const std.os.Kevent) void {
if (comptime !Environment.isMac) {
unreachable;
}
+ var ptr = Pollable.from(@intToPtr(?*anyopaque, kqueue_event.udata));
- const ptr = @intToPtr(?*anyopaque, kqueue_event.udata);
- const callback: Completion = @intToPtr(Completion, kqueue_event.ext[0]);
- callback(ptr, @bitCast(i64, kqueue_event.data), kqueue_event.flags);
+ switch (ptr.tag()) {
+ @field(Pollable.Tag, "FileBlobLoader") => {
+ var loader = ptr.as(FileBlobLoader);
+ loop.active -= 1;
+ loader.onPoll(@bitCast(i64, kqueue_event.data), kqueue_event.flags);
+ },
+ else => unreachable,
+ }
+ }
+
+ fn dispatchEpollEvent(loop: *uws.Loop, epoll_event: *linux.epoll_event) void {
+ var ptr = Pollable.from(@intToPtr(?*anyopaque, epoll_event.data.ptr));
+ switch (ptr.tag()) {
+ @field(Pollable.Tag, "FileBlobLoader") => {
+ var loader = ptr.as(FileBlobLoader);
+ loop.active -= 1;
+ loader.onPoll(0, 0);
+ },
+ else => unreachable,
+ }
}
const timeout = std.mem.zeroes(std.os.timespec);
+ const linux = std.os.linux;
+
+ const FileBlobLoader = JSC.WebCore.FileBlobLoader;
+
+ /// epoll only allows one pointer
+ /// We unfortunately need two pointers: one for a function call and one for the context
+ /// We use a tagged pointer union and then call the function with the context pointer
+ pub const Pollable = TaggedPointerUnion(.{
+ FileBlobLoader,
+ AsyncIO.Waker,
+ });
+ const Kevent = std.os.Kevent;
+ const kevent = std.c.kevent;
+
+ pub fn watch(this: *Poller, fd: JSC.Node.FileDescriptor, flag: Flag, comptime ContextType: type, ctx: *ContextType) JSC.Maybe(void) {
+ if (this.loop == null) {
+ this.loop = uws.Loop.get();
+ JSC.VirtualMachine.vm.uws_event_loop = this.loop.?;
+ }
+ const watcher_fd = this.loop.?.fd;
- pub fn watch(this: *Poller, fd: JSC.Node.FileDescriptor, flag: Flag, ctx: ?*anyopaque, completion: Completion) JSC.Maybe(void) {
if (comptime Environment.isLinux) {
- // std.debug.assert(this.watch_fd != 0);
- // TODO:
- return JSC.Maybe(void).success;
- } else if (comptime Environment.isMac) {
- if (this.watch_fd == 0) {
- this.watch_fd = std.c.kqueue();
- if (this.watch_fd == -1) {
- defer this.watch_fd = 0;
- return JSC.Maybe(void).errnoSys(this.watch_fd, .kqueue).?;
- }
+ const flags: u32 = switch (flag) {
+ .read => linux.EPOLL.IN | linux.EPOLL.HUP | linux.EPOLL.ONESHOT,
+ .write => linux.EPOLL.OUT | linux.EPOLL.HUP | linux.EPOLL.ERR | linux.EPOLL.ONESHOT,
+ };
+
+ var event = linux.epoll_event{ .events = flags, .data = .{ .u64 = @ptrToInt(Pollable.init(ctx).ptr()) } };
+
+ const ctl = linux.epoll_ctl(
+ watcher_fd,
+ linux.EPOLL.CTL_ADD,
+ fd,
+ &event,
+ );
+
+ if (JSC.Maybe(void).errnoSys(ctl, .epoll_ctl)) |errno| {
+ return errno;
}
- var events_list = std.mem.zeroes([2]kevent64);
- events_list[0] = switch (flag) {
+ this.loop.?.num_polls += 1;
+ this.loop.?.active += 1;
+ } else if (comptime Environment.isMac) {
+ var changelist = std.mem.zeroes([2]std.os.system.kevent64_s);
+ changelist[0] = switch (flag) {
.read => .{
.ident = @intCast(u64, fd),
.filter = std.os.system.EVFILT_READ,
.data = 0,
.fflags = 0,
- .udata = @ptrToInt(ctx),
+ .udata = @ptrToInt(Pollable.init(ctx).ptr()),
.flags = std.c.EV_ADD | std.c.EV_ENABLE | std.c.EV_ONESHOT,
- .ext = .{ @ptrToInt(completion), 0 },
+ .ext = .{ 0, 0 },
},
.write => .{
.ident = @intCast(u64, fd),
.filter = std.os.system.EVFILT_WRITE,
.data = 0,
.fflags = 0,
- .udata = @ptrToInt(ctx),
+ .udata = @ptrToInt(Pollable.init(ctx).ptr()),
.flags = std.c.EV_ADD | std.c.EV_ENABLE | std.c.EV_ONESHOT,
- .ext = .{ @ptrToInt(completion), 0 },
+ .ext = .{ 0, 0 },
},
};
+ // output events only include change errors
+ const KEVENT_FLAG_ERROR_EVENTS = 0x000002;
+
// The kevent() system call returns the number of events placed in
// the eventlist, up to the value given by nevents. If the time
// limit expires, then kevent() returns 0.
const rc = std.os.system.kevent64(
- this.watch_fd,
- &events_list,
+ watcher_fd,
+ &changelist,
1,
// The same array may be used for the changelist and eventlist.
- &events_list,
+ &changelist,
1,
- 0,
+ KEVENT_FLAG_ERROR_EVENTS,
&timeout,
);
-
// If an error occurs while
// processing an element of the changelist and there is enough room
// in the eventlist, then the event will be placed in the eventlist
// with EV_ERROR set in flags and the system error in data.
- if (events_list[0].flags == std.c.EV_ERROR) {
- return JSC.Maybe(void).errnoSys(events_list[0].data, .kevent).?;
+ if (changelist[0].flags == std.c.EV_ERROR) {
+ return JSC.Maybe(void).errnoSys(changelist[0].data, .kevent).?;
// Otherwise, -1 will be returned, and errno will be set to
// indicate the error condition.
}
- switch (rc) {
- std.math.minInt(@TypeOf(rc))...-1 => return JSC.Maybe(void).errnoSys(@enumToInt(std.c.getErrno(rc)), .kevent).?,
- 0 => {
- this.active += 1;
- return JSC.Maybe(void).success;
- },
- 1 => {
- // if we immediately get an event, we can skip the reference counting
- dispatchKQueueEvent(&events_list[0]);
- return JSC.Maybe(void).success;
- },
- 2 => {
- dispatchKQueueEvent(&events_list[0]);
+ const errno = std.c.getErrno(rc);
+ if (errno == .SUCCESS) {
+ this.loop.?.num_polls += 1;
+ this.loop.?.active += 1;
+ return JSC.Maybe(void).success;
+ }
- this.active -= 1;
- dispatchKQueueEvent(&events_list[1]);
- return JSC.Maybe(void).success;
- },
+ switch (rc) {
+ std.math.minInt(@TypeOf(rc))...-1 => return JSC.Maybe(void).errnoSys(@enumToInt(errno), .kevent).?,
else => unreachable,
}
} else {
@@ -546,67 +579,26 @@ pub const Poller = struct {
}
}
- const kqueue_events_ = std.mem.zeroes([4]kevent64);
pub fn tick(this: *Poller) void {
- if (comptime Environment.isMac) {
- if (this.active == 0) return;
-
- var events_list = kqueue_events_;
- // ub extern "c" fn kevent64(
- // kq: c_int,
- // changelist: [*]const kevent64_s,
- // nchanges: c_int,
- // eventlist: [*]kevent64_s,
- // nevents: c_int,
- // flags: c_uint,
- // timeout: ?*const timespec,
- // ) c_int;
- const rc = std.os.system.kevent64(
- this.watch_fd,
- &events_list,
- 0,
- // The same array may be used for the changelist and eventlist.
- &events_list,
- 4,
- 0,
- &timeout,
- );
+ var loop = this.loop orelse return;
+ if (loop.active == 0) return;
+ loop.tick();
+ }
- switch (rc) {
- std.math.minInt(@TypeOf(rc))...-1 => {
- // EINTR is fine
- switch (std.c.getErrno(rc)) {
- .INTR => return,
- else => |errno| std.debug.panic("kevent64() failed: {d}", .{errno}),
- }
- },
- 0 => {},
- 1 => {
- this.active -= 1;
- dispatchKQueueEvent(&events_list[0]);
- },
- 2 => {
- this.active -= 2;
- dispatchKQueueEvent(&events_list[0]);
- dispatchKQueueEvent(&events_list[1]);
- },
- 3 => {
- this.active -= 3;
- dispatchKQueueEvent(&events_list[0]);
- dispatchKQueueEvent(&events_list[1]);
- dispatchKQueueEvent(&events_list[2]);
- },
- 4 => {
- this.active -= 4;
- dispatchKQueueEvent(&events_list[0]);
- dispatchKQueueEvent(&events_list[1]);
- dispatchKQueueEvent(&events_list[2]);
- dispatchKQueueEvent(&events_list[3]);
- },
- else => unreachable,
- }
- }
+ pub fn onTick(loop: *uws.Loop, tagged_pointer: ?*anyopaque) callconv(.C) void {
+ _ = loop;
+ _ = tagged_pointer;
+ if (comptime Environment.isMac)
+ dispatchKQueueEvent(loop, &loop.ready_polls[@intCast(usize, loop.current_ready_poll)])
+ else if (comptime Environment.isLinux)
+ dispatchEpollEvent(loop, &loop.ready_polls[@intCast(usize, loop.current_ready_poll)]);
}
pub const Flag = enum { read, write };
+
+ comptime {
+ if (!JSC.is_bindgen) {
+ @export(onTick, .{ .name = "Bun__internal_dispatch_ready_poll" });
+ }
+ }
};
diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig
index 1158a8dd2..b7af9a8df 100644
--- a/src/bun.js/webcore/streams.zig
+++ b/src/bun.js/webcore/streams.zig
@@ -2328,9 +2328,13 @@ pub const FileBlobLoader = struct {
};
}
- pub fn watch(this: *FileReader) void {
- _ = JSC.VirtualMachine.vm.poller.watch(this.fd, .read, this, callback);
+ pub fn watch(this: *FileReader) ?JSC.Node.Syscall.Error {
+ switch (JSC.VirtualMachine.vm.poller.watch(this.fd, .read, FileBlobLoader, this)) {
+ .err => |err| return err,
+ else => {},
+ }
this.scheduled_count += 1;
+ return null;
}
const Concurrent = struct {
@@ -2658,7 +2662,8 @@ pub const FileBlobLoader = struct {
// this handles:
// - empty file
// - stream closed for some reason
- if ((result == 0 and remaining == 0)) {
+ // - FIFO returned EOF
+ if ((result == 0 and (remaining == 0 or std.os.S.ISFIFO(this.mode)))) {
this.finalize();
return .{ .done = {} };
}
@@ -2692,7 +2697,11 @@ pub const FileBlobLoader = struct {
this.protected_view = view;
this.protected_view.protect();
this.buf = read_buf;
- this.watch();
+ if (this.watch()) |watch_fail| {
+ this.finalize();
+ return .{ .err = watch_fail };
+ }
+
return .{
.pending = &this.pending,
};
@@ -2713,8 +2722,8 @@ pub const FileBlobLoader = struct {
}
}
- pub fn callback(task: ?*anyopaque, sizeOrOffset: i64, _: u16) void {
- var this: *FileReader = bun.cast(*FileReader, task.?);
+ /// Called from Poller
+ pub fn onPoll(this: *FileBlobLoader, sizeOrOffset: i64, _: u16) void {
std.debug.assert(this.started);
this.scheduled_count -= 1;
const protected_view = this.protected_view;
diff --git a/src/bun_js.zig b/src/bun_js.zig
index 118cf00f9..679576821 100644
--- a/src/bun_js.zig
+++ b/src/bun_js.zig
@@ -153,7 +153,7 @@ pub const Run = struct {
this.vm.active_tasks > 0)
{
this.vm.event_loop.ensureWaker();
- _ = this.vm.event_loop.waker.?.wait() catch 0;
+ _ = this.vm.uws_event_loop.?.run();
}
}
}
diff --git a/src/deps/uws b/src/deps/uws
-Subproject 1b46cf9ace5f55f713d55bb8c086f5878d13245
+Subproject d8ea7819243dba0d0201807a65556bb6db55baf
diff --git a/src/deps/uws.zig b/src/deps/uws.zig
index 353db4da9..b26020714 100644
--- a/src/deps/uws.zig
+++ b/src/deps/uws.zig
@@ -279,7 +279,10 @@ pub const Loop = extern struct {
current_ready_poll: c_int,
/// Loop's own file descriptor
- fd: c_int,
+ fd: i32,
+
+ /// Number of polls owned by Bun
+ active: u32 = 0,
/// The list of ready polls
ready_polls: [1024]EventType,
@@ -323,7 +326,7 @@ pub const Loop = extern struct {
}
pub fn tick(this: *Loop) void {
- us_loop_tick(this);
+ us_loop_run_bun_tick(this);
}
pub fn nextTick(this: *Loop, comptime UserType: type, user_data: UserType, comptime deferCallback: fn (ctx: UserType) void) void {
@@ -376,7 +379,7 @@ pub const Loop = extern struct {
extern fn us_loop_free(loop: ?*Loop) void;
extern fn us_loop_ext(loop: ?*Loop) ?*anyopaque;
extern fn us_loop_run(loop: ?*Loop) void;
- extern fn us_loop_tick(loop: ?*Loop) void;
+ extern fn us_loop_run_bun_tick(loop: ?*Loop) void;
extern fn us_wakeup_loop(loop: ?*Loop) void;
extern fn us_loop_integrate(loop: ?*Loop) void;
extern fn us_loop_iteration_number(loop: ?*Loop) c_longlong;
diff --git a/src/io/io_darwin.zig b/src/io/io_darwin.zig
index 78bf30290..f40ba60c7 100644
--- a/src/io/io_darwin.zig
+++ b/src/io/io_darwin.zig
@@ -545,7 +545,10 @@ pub const Waker = struct {
) bool;
pub fn init(allocator: std.mem.Allocator) !Waker {
- const kq = try os.kqueue();
+ return initWithFileDescriptor(allocator, try std.os.kqueue());
+ }
+
+ pub fn initWithFileDescriptor(allocator: std.mem.Allocator, kq: i32) !Waker {
assert(kq > -1);
var machport_buf = try allocator.alloc(u8, 1024);
const machport = io_darwin_create_machport(
diff --git a/src/io/io_linux.zig b/src/io/io_linux.zig
index d3af77d7c..00cc0c03e 100644
--- a/src/io/io_linux.zig
+++ b/src/io/io_linux.zig
@@ -987,9 +987,13 @@ pub const Completion = struct {
pub const Waker = struct {
fd: os.fd_t,
- pub fn init(_: std.mem.Allocator) !Waker {
+ pub fn init(allocator: std.mem.Allocator) !Waker {
+ return try initWithFileDescriptor(allocator, try std.os.eventfd(0, 0));
+ }
+
+ pub fn initWithFileDescriptor(_: std.mem.Allocator, fd: os.fd_t) Waker {
return Waker{
- .fd = try os.eventfd(0, 0),
+ .fd = fd,
};
}
diff --git a/test/apps/bun-install.sh b/test/apps/bun-install.sh
index af13f6fc3..78fcc2837 100644
--- a/test/apps/bun-install.sh
+++ b/test/apps/bun-install.sh
@@ -26,9 +26,10 @@ chmod +x index.js
JS_RUNTIME=${JS_RUNTIME:-"$(which bun)"}
# If this fails to run, it means we didn't link @babel/parser correctly
-realpath -e ./node_modules/.bin/parser
+$(which grealpath || which realpath) -e ./node_modules/.bin/parser >/dev/null
-# If this fails to run, it means we didn't link esbuild correctly
+# If this fails to run, it means we didn't link esbuild correctly or esbuild's install script broke
+# - https://github.com/evanw/esbuild/issues/2558
./node_modules/.bin/esbuild --version >/dev/null
if [ "$JS_RUNTIME" == "node" ]; then
diff --git a/test/bun.js/ffi.test.fixture.callback.c b/test/bun.js/ffi.test.fixture.callback.c
index 7de63120f..cb38eebe8 100644
--- a/test/bun.js/ffi.test.fixture.callback.c
+++ b/test/bun.js/ffi.test.fixture.callback.c
@@ -147,23 +147,39 @@ static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
}
+// JSValue numbers-as-pointers are represented as a 52-bit integer
+// Previously, the pointer was stored at the end of the 64-bit value
+// Now, they're stored at the beginning of the 64-bit value
+// This behavior change enables the JIT to handle it better
+// It also is better readability when console.log(myPtr)
static void* JSVALUE_TO_PTR(EncodedJSValue val) {
- // must be a double
if (val.asInt64 == TagValueNull)
return 0;
- return (void*)(val.asInt64 - DoubleEncodeOffset);
+ val.asInt64 -= DoubleEncodeOffset;
+ size_t ptr = (size_t)val.asDouble;
+ return (void*)ptr;
}
static EncodedJSValue PTR_TO_JSVALUE(void* ptr) {
EncodedJSValue val;
- if (ptr == 0) {
- val.asInt64 = TagValueNull;
- return val;
+ if (ptr == 0)
+ {
+ val.asInt64 = TagValueNull;
+ return val;
}
- val.asInt64 = (int64_t)ptr + DoubleEncodeOffset;
+
+ val.asDouble = (double)(size_t)ptr;
+ val.asInt64 += DoubleEncodeOffset;
return val;
}
+static EncodedJSValue DOUBLE_TO_JSVALUE(double val) {
+ EncodedJSValue res;
+ res.asDouble = val;
+ res.asInt64 += DoubleEncodeOffset;
+ return res;
+}
+
static int32_t JSVALUE_TO_INT32(EncodedJSValue val) {
return val.asInt64;
}
@@ -175,12 +191,7 @@ static EncodedJSValue INT32_TO_JSVALUE(int32_t val) {
}
-static EncodedJSValue DOUBLE_TO_JSVALUE(double val) {
- EncodedJSValue res;
- res.asDouble = val;
- res.asInt64 += DoubleEncodeOffset;
- return res;
-}
+
static EncodedJSValue FLOAT_TO_JSVALUE(float val) {
return DOUBLE_TO_JSVALUE((double)val);
diff --git a/test/bun.js/ffi.test.fixture.receiver.c b/test/bun.js/ffi.test.fixture.receiver.c
index 550d64b81..f8417805d 100644
--- a/test/bun.js/ffi.test.fixture.receiver.c
+++ b/test/bun.js/ffi.test.fixture.receiver.c
@@ -148,23 +148,39 @@ static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
}
+// JSValue numbers-as-pointers are represented as a 52-bit integer
+// Previously, the pointer was stored at the end of the 64-bit value
+// Now, they're stored at the beginning of the 64-bit value
+// This behavior change enables the JIT to handle it better
+// It also is better readability when console.log(myPtr)
static void* JSVALUE_TO_PTR(EncodedJSValue val) {
- // must be a double
if (val.asInt64 == TagValueNull)
return 0;
- return (void*)(val.asInt64 - DoubleEncodeOffset);
+ val.asInt64 -= DoubleEncodeOffset;
+ size_t ptr = (size_t)val.asDouble;
+ return (void*)ptr;
}
static EncodedJSValue PTR_TO_JSVALUE(void* ptr) {
EncodedJSValue val;
- if (ptr == 0) {
- val.asInt64 = TagValueNull;
- return val;
+ if (ptr == 0)
+ {
+ val.asInt64 = TagValueNull;
+ return val;
}
- val.asInt64 = (int64_t)ptr + DoubleEncodeOffset;
+
+ val.asDouble = (double)(size_t)ptr;
+ val.asInt64 += DoubleEncodeOffset;
return val;
}
+static EncodedJSValue DOUBLE_TO_JSVALUE(double val) {
+ EncodedJSValue res;
+ res.asDouble = val;
+ res.asInt64 += DoubleEncodeOffset;
+ return res;
+}
+
static int32_t JSVALUE_TO_INT32(EncodedJSValue val) {
return val.asInt64;
}
@@ -176,12 +192,7 @@ static EncodedJSValue INT32_TO_JSVALUE(int32_t val) {
}
-static EncodedJSValue DOUBLE_TO_JSVALUE(double val) {
- EncodedJSValue res;
- res.asDouble = val;
- res.asInt64 += DoubleEncodeOffset;
- return res;
-}
+
static EncodedJSValue FLOAT_TO_JSVALUE(float val) {
return DOUBLE_TO_JSVALUE((double)val);
diff --git a/test/bun.js/serve.test.ts b/test/bun.js/serve.test.ts
index 95428c028..317d94100 100644
--- a/test/bun.js/serve.test.ts
+++ b/test/bun.js/serve.test.ts
@@ -39,7 +39,9 @@ describe("streaming", () => {
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(
+ `http://${server.hostname}:${server.port}`
+ );
if (response.status > 0) {
expect(response.status).toBe(500);
expect(await response.text()).toBe("fail");
@@ -77,7 +79,9 @@ describe("streaming", () => {
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(
+ `http://${server.hostname}:${server.port}`
+ );
// connection terminated
if (response.status > 0) {
expect(response.status).toBe(200);
@@ -110,7 +114,7 @@ describe("streaming", () => {
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
const text = await response.text();
expect(text.length).toBe(textToExpect.length);
expect(text).toBe(textToExpect);
@@ -134,7 +138,7 @@ describe("streaming", () => {
);
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
@@ -157,8 +161,18 @@ describe("streaming", () => {
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
- expect(response.status).toBe(500);
+ var response;
+ try {
+ response = await fetch(`http://${server.hostname}:${server.port}`);
+ } catch (e) {
+ if (e.name !== "ConnectionClosed") {
+ throw e;
+ }
+ }
+
+ if (response) {
+ expect(response.status).toBe(500);
+ }
} catch (e) {
if (!e || !(e instanceof TestPass)) {
throw e;
@@ -191,7 +205,7 @@ describe("streaming", () => {
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(response.status).toBe(500);
expect(await response.text()).toBe("Fail");
expect(pass).toBe(true);
@@ -222,7 +236,7 @@ describe("streaming", () => {
);
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
@@ -244,7 +258,7 @@ describe("streaming", () => {
);
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
const text = await response.text();
expect(text).toBe(textToExpect);
server.stop();
@@ -270,7 +284,7 @@ describe("streaming", () => {
);
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
@@ -295,7 +309,7 @@ describe("streaming", () => {
);
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
@@ -324,7 +338,7 @@ describe("streaming", () => {
);
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
@@ -337,7 +351,7 @@ it("should work for a hello world", async () => {
return new Response(`Hello, world!`);
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe("Hello, world!");
server.stop();
});
@@ -352,7 +366,7 @@ it("should work for a blob", async () => {
return new Response(new Blob([textToExpect]));
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
@@ -367,7 +381,7 @@ it("should work for a blob stream", async () => {
return new Response(new Blob([textToExpect]).stream());
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
@@ -382,7 +396,7 @@ it("should work for a file", async () => {
return new Response(file(fixture));
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
@@ -397,7 +411,7 @@ it("should work for a file stream", async () => {
return new Response(file(fixture).stream());
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
server.stop();
});
@@ -416,7 +430,7 @@ it("fetch should work with headers", async () => {
});
},
});
- const response = await fetch(`http://127.0.0.1:${server.port}`, {
+ const response = await fetch(`http://${server.hostname}:${server.port}`, {
headers: {
"X-Foo": "bar",
},
@@ -444,7 +458,7 @@ it(`should work for a file ${count} times serial`, async () => {
// it's hard to say if this only happens here due to some weird stuff with the test runner
// or if it's "real" issue
for (let i = 0; i < count; i++) {
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
}
@@ -467,7 +481,7 @@ it(`should work for text ${count} times serial`, async () => {
// it's hard to say if this only happens here due to some weird stuff with the test runner
// or if it's "real" issue
for (let i = 0; i < count; i++) {
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
}
@@ -488,7 +502,7 @@ it(`should work for ArrayBuffer ${count} times serial`, async () => {
// it's hard to say if this only happens here due to some weird stuff with the test runner
// or if it's "real" issue
for (let i = 0; i < count; i++) {
- const response = await fetch(`http://127.0.0.1:${server.port}`);
+ const response = await fetch(`http://${server.hostname}:${server.port}`);
expect(await response.text()).toBe(textToExpect);
}