From fad58168d28f38ad31a1e9a0eaa6a760bc149296 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 4 Jul 2024 16:20:18 -0700 Subject: [PATCH 01/10] Configure LTO on Windows (#12290) --- .github/workflows/build-windows.yml | 5 +++++ CMakeLists.txt | 13 +++++++------ scripts/env.ps1 | 18 ++++++++++++++++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 6f452ccd9c..11710ea952 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -36,6 +36,7 @@ env: BUN_GARBAGE_COLLECTOR_LEVEL: 1 BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: 1 CI: true + USE_LTO: 1 jobs: build-submodules: @@ -87,6 +88,7 @@ jobs: env: CPU_TARGET: ${{ inputs.cpu }} CCACHE_DIR: ccache + USE_LTO: 1 run: | .\scripts\env.ps1 ${{ contains(inputs.tag, '-baseline') && '-Baseline' || '' }} choco install -y nasm --version=2.16.01 @@ -172,6 +174,7 @@ jobs: env: CPU_TARGET: ${{ inputs.cpu }} CCACHE_DIR: ccache + USE_LTO: 1 run: | # $CANARY_REVISION = if (Test-Path build/.canary_revision) { Get-Content build/.canary_revision } else { "0" } $CANARY_REVISION = 0 @@ -181,6 +184,7 @@ jobs: cd build cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release ` -DNO_CODEGEN=1 ` + -DUSE_LTO=1 ` -DNO_CONFIGURE_DEPENDS=1 ` "-DCANARY=${CANARY_REVISION}" ` -DBUN_CPP_ONLY=1 ${{ contains(inputs.tag, '-baseline') && '-DUSE_BASELINE_BUILD=1' || '' }} @@ -276,6 +280,7 @@ jobs: -DNO_CONFIGURE_DEPENDS=1 ` "-DCANARY=${CANARY_REVISION}" ` -DBUN_LINK_ONLY=1 ` + -DUSE_LTO=1 ` "-DBUN_DEPS_OUT_DIR=$(Resolve-Path ../bun-deps)" ` "-DBUN_CPP_ARCHIVE=$(Resolve-Path ../bun-cpp/bun-cpp-objects.a)" ` "-DBUN_ZIG_OBJ_DIR=$(Resolve-Path ../bun-zig)" ` diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c2ac0d231..fdceab1972 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,8 +15,6 @@ set(CMAKE_C_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) - # Should not start with v # Used in process.version, process.versions.node, napi, and elsewhere set(REPORTED_NODEJS_VERSION "22.3.0") @@ -324,6 +322,11 @@ option(USE_STATIC_LIBATOMIC "Statically link libatomic, requires the presence of option(USE_LTO "Enable Link-Time Optimization" ${DEFAULT_LTO}) +if(WIN32 AND USE_LTO) + set(CMAKE_LINKER_TYPE LLD) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) +endif() + option(BUN_TIDY_ONLY "Only run clang-tidy" OFF) option(BUN_TIDY_ONLY_EXTRA " Only run clang-tidy, with extra checks for local development" OFF) @@ -1080,6 +1083,8 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release") set(LTO_LINK_FLAG "") if(USE_LTO) + target_compile_options(${bun} PUBLIC -Xclang -emit-llvm-bc) + # -emit-llvm seems to not be supported or under a different name on Windows. list(APPEND LTO_FLAG "-flto=full") list(APPEND LTO_LINK_FLAG "/LTCG") @@ -1120,10 +1125,6 @@ if(WIN32) # set_property(TARGET ${bun} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded") set_property(TARGET ${bun} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") - if(USE_LTO) - target_compile_options(${bun} PUBLIC "-Xclang -emit-llvm-bc") - endif() - target_compile_options(${bun} PUBLIC "/EHsc" "/GR-") target_link_options(${bun} PUBLIC "/STACK:0x1200000,0x100000" "/DEF:${BUN_SRC}/symbols.def" "/errorlimit:0") else() diff --git a/scripts/env.ps1 b/scripts/env.ps1 index c88271c4d2..d91dfedadf 100755 --- a/scripts/env.ps1 +++ b/scripts/env.ps1 @@ -52,11 +52,16 @@ $CPUS = if ($env:CPUS) { $env:CPUS } else { (Get-CimInstance -Class Win32_Proces $CC = "clang-cl" $CXX = "clang-cl" -$CFLAGS = '/O2 /Zi' +$CFLAGS = '/O2 /Zi ' # $CFLAGS = '/O2 /Z7 /MT' -$CXXFLAGS = '/O2 /Zi' +$CXXFLAGS = '/O2 /Zi ' # $CXXFLAGS = '/O2 /Z7 /MT' +if ($env:USE_LTO -eq "1") { + $CXXFLAGS += " -fuse-ld=lld -flto -Xclang -emit-llvm-bc " + $CFLAGS += " -fuse-ld=lld -flto -Xclang -emit-llvm-bc " +} + $CPU_NAME = if ($Baseline) { "nehalem" } else { "haswell" }; $env:CPU_TARGET = $CPU_NAME @@ -71,6 +76,15 @@ $CMAKE_FLAGS = @( "-DCMAKE_C_FLAGS=$CFLAGS", "-DCMAKE_CXX_FLAGS=$CXXFLAGS" ) + +if ($env:USE_LTO -eq "1") { + if (Get-Command lld-lib -ErrorAction SilentlyContinue) { + $AR = Get-Command lld-lib -ErrorAction SilentlyContinue + $env:AR = $AR + $CMAKE_FLAGS += "-DCMAKE_AR=$AR" + } +} + $env:CC = "clang-cl" $env:CXX = "clang-cl" $env:CFLAGS = $CFLAGS From 4f3ef07455c81de9ad264e060cbbbee917d5decb Mon Sep 17 00:00:00 2001 From: Vadzim Date: Fri, 5 Jul 2024 01:20:59 +0200 Subject: [PATCH 02/10] Fix crash on aborted timer (#12348) --- src/js/node/timers.promises.ts | 14 +++-- .../timers.promises/timers.promises.test.ts | 52 +++++++++++++++++++ 2 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 test/js/node/timers.promises/timers.promises.test.ts diff --git a/src/js/node/timers.promises.ts b/src/js/node/timers.promises.ts index eb171941a5..e9b8a290af 100644 --- a/src/js/node/timers.promises.ts +++ b/src/js/node/timers.promises.ts @@ -84,10 +84,9 @@ function setTimeoutPromise(after = 1, value, options = {}) { signal.addEventListener("abort", onCancel); } }); - if (typeof onCancel !== "undefined") { - returnValue.finally(() => signal.removeEventListener("abort", onCancel)); - } - return returnValue; + return typeof onCancel !== "undefined" + ? returnValue.finally(() => signal.removeEventListener("abort", onCancel)) + : returnValue; } function setImmediatePromise(value, options = {}) { @@ -124,10 +123,9 @@ function setImmediatePromise(value, options = {}) { signal.addEventListener("abort", onCancel); } }); - if (typeof onCancel !== "undefined") { - returnValue.finally(() => signal.removeEventListener("abort", onCancel)); - } - return returnValue; + return typeof onCancel !== "undefined" + ? returnValue.finally(() => signal.removeEventListener("abort", onCancel)) + : returnValue; } function setIntervalPromise(after = 1, value, options = {}) { diff --git a/test/js/node/timers.promises/timers.promises.test.ts b/test/js/node/timers.promises/timers.promises.test.ts new file mode 100644 index 0000000000..7550c94864 --- /dev/null +++ b/test/js/node/timers.promises/timers.promises.test.ts @@ -0,0 +1,52 @@ +import { describe, test, it, expect } from "bun:test"; +import { setTimeout, setImmediate } from "node:timers/promises"; + +describe("setTimeout", () => { + it("abort() does not emit global error", async () => { + let unhandledRejectionCaught = false; + + const catchUnhandledRejection = () => { + unhandledRejectionCaught = true; + }; + process.on('unhandledRejection', catchUnhandledRejection); + + const c = new AbortController(); + + global.setTimeout(() => c.abort()); + + await setTimeout(100, undefined, { signal: c.signal }).catch(() => "aborted"); + + // let unhandledRejection to be fired + await setTimeout(100) + + process.off('unhandledRejection', catchUnhandledRejection); + + expect(c.signal.aborted).toBe(true); + expect(unhandledRejectionCaught).toBe(false); + }); +}); + +describe("setImmediate", () => { + it("abort() does not emit global error", async () => { + let unhandledRejectionCaught = false; + + const catchUnhandledRejection = () => { + unhandledRejectionCaught = true; + }; + process.on('unhandledRejection', catchUnhandledRejection); + + const c = new AbortController(); + + global.setImmediate(() => c.abort()); + + await setImmediate(undefined, { signal: c.signal }).catch(() => "aborted"); + + // let unhandledRejection to be fired + await setTimeout(100) + + process.off('unhandledRejection', catchUnhandledRejection); + + expect(c.signal.aborted).toBe(true); + expect(unhandledRejectionCaught).toBe(false); + }); +}); From ee256181971857082889a895b64ab8c4dff46c68 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Thu, 4 Jul 2024 23:05:51 -0700 Subject: [PATCH 03/10] Use `bun.ComptimeStringMap` instead of `std.StaticStringMap` (#12351) Co-authored-by: Jarred-Sumner --- src/bun.js/ipc.zig | 2 +- src/js_lexer_tables.zig | 17 ++++++++-------- src/js_parser.zig | 4 ++-- src/open.zig | 2 +- src/options.zig | 4 ++-- src/resolver/tsconfig_json.zig | 2 +- .../timers.promises/timers.promises.test.ts | 20 +++++++++---------- 7 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/bun.js/ipc.zig b/src/bun.js/ipc.zig index 1816ddca5f..d19004bcdc 100644 --- a/src/bun.js/ipc.zig +++ b/src/bun.js/ipc.zig @@ -23,7 +23,7 @@ pub const Mode = enum { /// This must match the behavior of node.js, and supports bun <--> node.js/etc communication. json, - const Map = std.StaticStringMap(Mode).initComptime(.{ + const Map = bun.ComptimeStringMap(Mode, .{ .{ "advanced", .advanced }, .{ "json", .json }, }); diff --git a/src/js_lexer_tables.zig b/src/js_lexer_tables.zig index c9107f1ab8..bc87fb0e60 100644 --- a/src/js_lexer_tables.zig +++ b/src/js_lexer_tables.zig @@ -7,6 +7,7 @@ const unicode = std.unicode; const default_allocator = bun.default_allocator; const string = @import("string_types.zig").string; const CodePoint = @import("string_types.zig").CodePoint; +const ComptimeStringMap = bun.ComptimeStringMap; pub const T = enum(u8) { t_end_of_file, @@ -159,7 +160,7 @@ pub const T = enum(u8) { } }; -pub const Keywords = std.StaticStringMap(T).initComptime(.{ +pub const Keywords = ComptimeStringMap(T, .{ .{ "break", .t_break }, .{ "case", .t_case }, .{ "catch", .t_catch }, @@ -198,7 +199,7 @@ pub const Keywords = std.StaticStringMap(T).initComptime(.{ .{ "with", .t_with }, }); -pub const StrictModeReservedWords = std.StaticStringMap(void).initComptime(.{ +pub const StrictModeReservedWords = ComptimeStringMap(void, .{ .{ "implements", {} }, .{ "interface", {} }, .{ "let", {} }, @@ -210,7 +211,7 @@ pub const StrictModeReservedWords = std.StaticStringMap(void).initComptime(.{ .{ "yield", {} }, }); -pub const StrictModeReservedWordsRemap = std.StaticStringMap(string).initComptime(.{ +pub const StrictModeReservedWordsRemap = ComptimeStringMap(string, .{ .{ "implements", "_implements" }, .{ "interface", "_interface" }, .{ "let", "_let" }, @@ -235,7 +236,7 @@ pub const PropertyModifierKeyword = enum { p_set, p_static, - pub const List = std.StaticStringMap(PropertyModifierKeyword).initComptime(.{ + pub const List = ComptimeStringMap(PropertyModifierKeyword, .{ .{ "abstract", .p_abstract }, .{ "async", .p_async }, .{ "declare", .p_declare }, @@ -250,7 +251,7 @@ pub const PropertyModifierKeyword = enum { }); }; -pub const TypeScriptAccessibilityModifier = std.StaticStringMap(void).initComptime(.{ +pub const TypeScriptAccessibilityModifier = ComptimeStringMap(void, .{ .{ "override", void }, .{ "private", void }, .{ "protected", void }, @@ -519,7 +520,7 @@ pub const TypescriptStmtKeyword = enum { ts_stmt_global, ts_stmt_declare, - pub const List = std.StaticStringMap(TypescriptStmtKeyword).initComptime(.{ + pub const List = ComptimeStringMap(TypescriptStmtKeyword, .{ .{ "type", TypescriptStmtKeyword.ts_stmt_type, @@ -552,7 +553,7 @@ pub const TypescriptStmtKeyword = enum { }; // Error: meta is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`. -pub const ChildlessJSXTags = std.StaticStringMap(void).initComptime(.{ +pub const ChildlessJSXTags = ComptimeStringMap(void, .{ .{ "area", void }, .{ "base", void }, .{ "br", void }, @@ -572,7 +573,7 @@ pub const ChildlessJSXTags = std.StaticStringMap(void).initComptime(.{ }); // In a microbenchmark, this outperforms -pub const jsxEntity = std.StaticStringMap(CodePoint).initComptime(.{ +pub const jsxEntity = ComptimeStringMap(CodePoint, .{ .{ "Aacute", @as(CodePoint, 0x00C1) }, .{ "aacute", @as(CodePoint, 0x00E1) }, .{ "Acirc", @as(CodePoint, 0x00C2) }, diff --git a/src/js_parser.zig b/src/js_parser.zig index ac6c5a6959..42f3599a96 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -1013,7 +1013,7 @@ pub const TypeScript = struct { else => return null, } } - pub const IMap = std.StaticStringMap(Kind).initComptime(.{ + pub const IMap = bun.ComptimeStringMap(Kind, .{ .{ "unique", .unique }, .{ "abstract", .abstract }, .{ "asserts", .asserts }, @@ -2560,7 +2560,7 @@ const AsyncPrefixExpression = enum(u2) { is_async, is_await, - const map = std.StaticStringMap(AsyncPrefixExpression).initComptime(.{ + const map = bun.ComptimeStringMap(AsyncPrefixExpression, .{ .{ "yield", .is_yield }, .{ "await", .is_await }, .{ "async", .is_async }, diff --git a/src/open.zig b/src/open.zig index 3c867f9026..bb83d9b60d 100644 --- a/src/open.zig +++ b/src/open.zig @@ -66,7 +66,7 @@ pub const Editor = enum(u8) { const StringMap = std.EnumMap(Editor, string); const StringArrayMap = std.EnumMap(Editor, []const [:0]const u8); - const name_map = std.StaticStringMap(Editor).initComptime(.{ + const name_map = bun.ComptimeStringMap(Editor, .{ .{ "sublime", .sublime }, .{ "subl", .sublime }, .{ "vscode", .vscode }, diff --git a/src/options.zig b/src/options.zig index 67fbd950f0..9a8293b7c0 100644 --- a/src/options.zig +++ b/src/options.zig @@ -298,7 +298,7 @@ pub const ExternalModules = struct { "zlib", }; - pub const NodeBuiltinsMap = std.StaticStringMap(void).initComptime(.{ + pub const NodeBuiltinsMap = bun.ComptimeStringMap(void, .{ .{ "_http_agent", {} }, .{ "_http_client", {} }, .{ "_http_common", {} }, @@ -370,7 +370,7 @@ pub const ModuleType = enum { cjs, esm, - pub const List = std.StaticStringMap(ModuleType).initComptime(.{ + pub const List = bun.ComptimeStringMap(ModuleType, .{ .{ "commonjs", ModuleType.cjs }, .{ "module", ModuleType.esm }, }); diff --git a/src/resolver/tsconfig_json.zig b/src/resolver/tsconfig_json.zig index bc4c96927f..f5a61a0dee 100644 --- a/src/resolver/tsconfig_json.zig +++ b/src/resolver/tsconfig_json.zig @@ -67,7 +67,7 @@ pub const TSConfigJSON = struct { remove, invalid, - pub const List = std.StaticStringMap(ImportsNotUsedAsValue).initComptime(.{ + pub const List = bun.ComptimeStringMap(ImportsNotUsedAsValue, .{ .{ "preserve", .preserve }, .{ "error", .err }, .{ "remove", .remove }, diff --git a/test/js/node/timers.promises/timers.promises.test.ts b/test/js/node/timers.promises/timers.promises.test.ts index 7550c94864..56e057cf9c 100644 --- a/test/js/node/timers.promises/timers.promises.test.ts +++ b/test/js/node/timers.promises/timers.promises.test.ts @@ -5,11 +5,11 @@ describe("setTimeout", () => { it("abort() does not emit global error", async () => { let unhandledRejectionCaught = false; - const catchUnhandledRejection = () => { + const catchUnhandledRejection = () => { unhandledRejectionCaught = true; }; - process.on('unhandledRejection', catchUnhandledRejection); - + process.on("unhandledRejection", catchUnhandledRejection); + const c = new AbortController(); global.setTimeout(() => c.abort()); @@ -17,9 +17,9 @@ describe("setTimeout", () => { await setTimeout(100, undefined, { signal: c.signal }).catch(() => "aborted"); // let unhandledRejection to be fired - await setTimeout(100) + await setTimeout(100); - process.off('unhandledRejection', catchUnhandledRejection); + process.off("unhandledRejection", catchUnhandledRejection); expect(c.signal.aborted).toBe(true); expect(unhandledRejectionCaught).toBe(false); @@ -30,11 +30,11 @@ describe("setImmediate", () => { it("abort() does not emit global error", async () => { let unhandledRejectionCaught = false; - const catchUnhandledRejection = () => { + const catchUnhandledRejection = () => { unhandledRejectionCaught = true; }; - process.on('unhandledRejection', catchUnhandledRejection); - + process.on("unhandledRejection", catchUnhandledRejection); + const c = new AbortController(); global.setImmediate(() => c.abort()); @@ -42,9 +42,9 @@ describe("setImmediate", () => { await setImmediate(undefined, { signal: c.signal }).catch(() => "aborted"); // let unhandledRejection to be fired - await setTimeout(100) + await setTimeout(100); - process.off('unhandledRejection', catchUnhandledRejection); + process.off("unhandledRejection", catchUnhandledRejection); expect(c.signal.aborted).toBe(true); expect(unhandledRejectionCaught).toBe(false); From 71c223e1112c30ca807a5cb3f3bdac6e0950fd8d Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 5 Jul 2024 15:40:10 -0700 Subject: [PATCH 04/10] Handle EINTR in usockets (#12357) Co-authored-by: Jarred-Sumner --- packages/bun-usockets/src/bsd.c | 98 +++++++++++---- .../bun-usockets/src/eventing/epoll_kqueue.c | 119 ++++++++++++++---- packages/bun-usockets/src/eventing/libuv.c | 2 +- packages/bun-usockets/src/internal/internal.h | 19 ++- .../src/internal/networking/bsd.h | 6 +- 5 files changed, 186 insertions(+), 58 deletions(-) diff --git a/packages/bun-usockets/src/bsd.c b/packages/bun-usockets/src/bsd.c index 582aafbe9e..b736a340a0 100644 --- a/packages/bun-usockets/src/bsd.c +++ b/packages/bun-usockets/src/bsd.c @@ -42,6 +42,7 @@ #define HAS_MSGX #endif + /* We need to emulate sendmmsg, recvmmsg on platform who don't have it */ int bsd_sendmmsg(LIBUS_SOCKET_DESCRIPTOR fd, struct udp_sendbuf* sendbuf, int flags) { #if defined(_WIN32)// || defined(__APPLE__) @@ -397,7 +398,9 @@ int bsd_addr_get_port(struct bsd_addr_t *addr) { // called by dispatch_ready_poll LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) { LIBUS_SOCKET_DESCRIPTOR accepted_fd; - addr->len = sizeof(addr->mem); + + while (1) { + addr->len = sizeof(addr->mem); #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) // Linux, FreeBSD @@ -405,12 +408,18 @@ LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd #else // Windows, OS X accepted_fd = accept(fd, (struct sockaddr *) addr, &addr->len); - #endif - /* We cannot rely on addr since it is not initialized if failed */ - if (accepted_fd == LIBUS_SOCKET_ERROR) { - return LIBUS_SOCKET_ERROR; + if (UNLIKELY(IS_EINTR(accepted_fd))) { + continue; + } + + /* We cannot rely on addr since it is not initialized if failed */ + if (accepted_fd == LIBUS_SOCKET_ERROR) { + return LIBUS_SOCKET_ERROR; + } + + break; } internal_finalize_bsd_addr(addr); @@ -423,14 +432,22 @@ LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd #endif } -int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) { - return recv(fd, buf, length, flags); +ssize_t bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) { + while (1) { + ssize_t ret = recv(fd, buf, length, flags); + + if (UNLIKELY(IS_EINTR(ret))) { + continue; + } + + return ret; + } } #if !defined(_WIN32) #include -int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length) { +ssize_t bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length) { struct iovec chunks[2]; chunks[0].iov_base = (char *)header; @@ -438,13 +455,21 @@ int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length chunks[1].iov_base = (char *)payload; chunks[1].iov_len = payload_length; - return writev(fd, chunks, 2); + while (1) { + ssize_t written = writev(fd, chunks, 2); + + if (UNLIKELY(IS_EINTR(written))) { + continue; + } + + return written; + } } #else -int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length) { - int written = bsd_send(fd, header, header_length, 0); +ssize_t bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length) { + ssize_t written = bsd_send(fd, header, header_length, 0); if (written == header_length) { - int second_write = bsd_send(fd, payload, payload_length, 0); + ssize_t second_write = bsd_send(fd, payload, payload_length, 0); if (second_write > 0) { written += second_write; } @@ -453,26 +478,28 @@ int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length } #endif -int bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more) { - +ssize_t bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more) { + while (1) { // MSG_MORE (Linux), MSG_PARTIAL (Windows), TCP_NOPUSH (BSD) #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif -#ifdef MSG_MORE + #ifdef MSG_MORE + // for Linux we do not want signals + ssize_t rc = send(fd, buf, length, ((msg_more != 0) * MSG_MORE) | MSG_NOSIGNAL | MSG_DONTWAIT); + #else + // use TCP_NOPUSH + ssize_t rc = send(fd, buf, length, MSG_NOSIGNAL | MSG_DONTWAIT); + #endif - // for Linux we do not want signals - return send(fd, buf, length, ((msg_more != 0) * MSG_MORE) | MSG_NOSIGNAL | MSG_DONTWAIT); + if (UNLIKELY(IS_EINTR(rc))) { + continue; + } -#else - - // use TCP_NOPUSH - - return send(fd, buf, length, MSG_NOSIGNAL | MSG_DONTWAIT); - -#endif + return rc; + } } int bsd_would_block() { @@ -483,6 +510,23 @@ int bsd_would_block() { #endif } +static int us_internal_bind_and_listen(LIBUS_SOCKET_DESCRIPTOR listenFd, struct sockaddr *listenAddr, socklen_t listenAddrLength, int backlog) { + int result; + do + result = bind(listenFd, listenAddr, listenAddrLength); + while (IS_EINTR(result)); + + if (result == -1) { + return -1; + } + + do + result = listen(listenFd, backlog); + while (IS_EINTR(result)); + + return result; +} + inline __attribute__((always_inline)) LIBUS_SOCKET_DESCRIPTOR bsd_bind_listen_fd( LIBUS_SOCKET_DESCRIPTOR listenFd, struct addrinfo *listenAddr, @@ -512,7 +556,7 @@ inline __attribute__((always_inline)) LIBUS_SOCKET_DESCRIPTOR bsd_bind_listen_fd setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &disabled, sizeof(disabled)); #endif - if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen) || listen(listenFd, 512)) { + if (us_internal_bind_and_listen(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen, 512)) { return LIBUS_SOCKET_ERROR; } @@ -690,7 +734,7 @@ static LIBUS_SOCKET_DESCRIPTOR internal_bsd_create_listen_socket_unix(const char unlink(path); #endif - if (bind(listenFd, (struct sockaddr *)server_address, addrlen) || listen(listenFd, 512)) { + if (us_internal_bind_and_listen(listenFd, (struct sockaddr *) server_address, (socklen_t) addrlen, 512)) { #if defined(_WIN32) int shouldSimulateENOENT = WSAGetLastError() == WSAENETDOWN; #endif @@ -925,7 +969,7 @@ static int bsd_do_connect_raw(LIBUS_SOCKET_DESCRIPTOR fd, struct sockaddr *addr, do { errno = 0; r = connect(fd, (struct sockaddr *)addr, namelen); - } while (r == -1 && errno == EINTR); + } while (IS_EINTR(r)); // connect() can return -1 with an errno of 0. // the errno is the correct one in that case. diff --git a/packages/bun-usockets/src/eventing/epoll_kqueue.c b/packages/bun-usockets/src/eventing/epoll_kqueue.c index 192d0972fa..374e9ce809 100644 --- a/packages/bun-usockets/src/eventing/epoll_kqueue.c +++ b/packages/bun-usockets/src/eventing/epoll_kqueue.c @@ -109,6 +109,51 @@ struct us_loop_t *us_timer_loop(struct us_timer_t *t) { return internal_cb->loop; } + +#if defined(LIBUS_USE_EPOLL) + +#include +static int has_epoll_pwait2 = -1; + +#ifndef SYS_epoll_pwait2 +// It's consistent on multiple architectures +// https://github.com/torvalds/linux/blob/9d1ddab261f3e2af7c384dc02238784ce0cf9f98/include/uapi/asm-generic/unistd.h#L795 +// https://github.com/google/gvisor/blob/master/test/syscalls/linux/epoll.cc#L48C1-L50C7 +#define SYS_epoll_pwait2 441 +#endif + +static ssize_t sys_epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout, const sigset_t *sigmask, size_t sigsetsize) { + return syscall(SYS_epoll_pwait2, epfd, events, maxevents, timeout, sigmask, sigsetsize); +} + +static int bun_epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout) { + int ret; + if (has_epoll_pwait2 != 0) { + do { + ret = sys_epoll_pwait2(epfd, events, maxevents, timeout, NULL, 0); + } while (IS_EINTR(ret)); + + if (LIKELY(ret != -1 || errno != ENOSYS)) { + return ret; + } + + has_epoll_pwait2 = 0; + } + + int timeoutMs = -1; + if (timeout) { + timeoutMs = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000; + } + + do { + ret = epoll_wait(epfd, events, maxevents, timeoutMs); + } while (IS_EINTR(ret)); + + return ret; +} + +#endif + /* Loop */ struct us_loop_t *us_create_loop(void *hint, void (*wakeup_cb)(struct us_loop_t *loop), void (*pre_cb)(struct us_loop_t *loop), void (*post_cb)(struct us_loop_t *loop), unsigned int ext_size) { struct us_loop_t *loop = (struct us_loop_t *) us_calloc(1, sizeof(struct us_loop_t) + ext_size); @@ -139,9 +184,11 @@ void us_loop_run(struct us_loop_t *loop) { /* Fetch ready polls */ #ifdef LIBUS_USE_EPOLL - loop->num_ready_polls = epoll_wait(loop->fd, loop->ready_polls, 1024, -1); + loop->num_ready_polls = bun_epoll_pwait2(loop->fd, loop->ready_polls, 1024, NULL); #else - loop->num_ready_polls = kevent64(loop->fd, NULL, 0, loop->ready_polls, 1024, 0, NULL); + do { + loop->num_ready_polls = kevent64(loop->fd, NULL, 0, loop->ready_polls, 1024, 0, NULL); + } while (IS_EINTR(loop->num_ready_polls)); #endif /* Iterate ready polls, dispatching them by type */ @@ -183,12 +230,6 @@ void us_loop_run(struct us_loop_t *loop) { } } -#if defined(LIBUS_USE_EPOLL) - -// static int has_epoll_pwait2 = 0; -// TODO: - -#endif void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout) { if (loop->num_polls == 0) @@ -207,13 +248,12 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout /* Fetch ready polls */ #ifdef LIBUS_USE_EPOLL - int timeoutMs = -1; - if (timeout) { - timeoutMs = timeout->tv_sec * 1000 + timeout->tv_nsec / 1000000; - } - loop->num_ready_polls = epoll_wait(loop->fd, loop->ready_polls, 1024, timeoutMs); + + loop->num_ready_polls = bun_epoll_pwait2(loop->fd, loop->ready_polls, 1024, timeout); #else - loop->num_ready_polls = kevent64(loop->fd, NULL, 0, loop->ready_polls, 1024, 0, timeout); + do { + loop->num_ready_polls = kevent64(loop->fd, NULL, 0, loop->ready_polls, 1024, 0, timeout); + } while (IS_EINTR(loop->num_ready_polls)); #endif /* Iterate ready polls, dispatching them by type */ @@ -296,7 +336,10 @@ int kqueue_change(int kqfd, int fd, int old_events, int new_events, void *user_d EV_SET64(&change_list[change_length++], fd, EVFILT_WRITE, (new_events & LIBUS_SOCKET_WRITABLE) ? EV_ADD : EV_DELETE, 0, 0, (uint64_t)(void*)user_data, 0, 0); } - int ret = kevent64(kqfd, change_list, change_length, change_list, change_length, KEVENT_FLAG_ERROR_EVENTS, NULL); + int ret; + do { + ret = kevent64(kqfd, change_list, change_length, change_list, change_length, KEVENT_FLAG_ERROR_EVENTS, NULL); + } while (IS_EINTR(ret)); // ret should be 0 in most cases (not guaranteed when removing async) @@ -332,7 +375,10 @@ void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events) { struct epoll_event event; event.events = events; event.data.ptr = p; - epoll_ctl(loop->fd, EPOLL_CTL_ADD, p->state.fd, &event); + int ret; + do { + ret = epoll_ctl(loop->fd, EPOLL_CTL_ADD, p->state.fd, &event); + } while (IS_EINTR(ret)); #else kqueue_change(loop->fd, p->state.fd, 0, events, p); #endif @@ -348,7 +394,10 @@ void us_poll_change(struct us_poll_t *p, struct us_loop_t *loop, int events) { struct epoll_event event; event.events = events; event.data.ptr = p; - epoll_ctl(loop->fd, EPOLL_CTL_MOD, p->state.fd, &event); + int rc; + do { + rc = epoll_ctl(loop->fd, EPOLL_CTL_MOD, p->state.fd, &event); + } while (IS_EINTR(rc)); #else kqueue_change(loop->fd, p->state.fd, old_events, events, p); #endif @@ -362,7 +411,10 @@ void us_poll_stop(struct us_poll_t *p, struct us_loop_t *loop) { int new_events = 0; #ifdef LIBUS_USE_EPOLL struct epoll_event event; - epoll_ctl(loop->fd, EPOLL_CTL_DEL, p->state.fd, &event); + int rc; + do { + rc = epoll_ctl(loop->fd, EPOLL_CTL_DEL, p->state.fd, &event); + } while (IS_EINTR(rc)); #else if (old_events) { kqueue_change(loop->fd, p->state.fd, old_events, new_events, NULL); @@ -373,12 +425,14 @@ void us_poll_stop(struct us_poll_t *p, struct us_loop_t *loop) { us_internal_loop_update_pending_ready_polls(loop, p, 0, old_events, new_events); } -unsigned int us_internal_accept_poll_event(struct us_poll_t *p) { +size_t us_internal_accept_poll_event(struct us_poll_t *p) { #ifdef LIBUS_USE_EPOLL int fd = us_poll_fd(p); uint64_t buf; - int read_length = read(fd, &buf, 8); - (void)read_length; + ssize_t read_length = 0; + do { + read_length = read(fd, &buf, 8); + } while (IS_EINTR(read_length)); return buf; #else /* Kqueue has no underlying FD for timers or user events */ @@ -467,7 +521,11 @@ void us_timer_close(struct us_timer_t *timer, int fallthrough) { struct kevent64_s event; EV_SET64(&event, (uint64_t) (void*) internal_cb, EVFILT_TIMER, EV_DELETE, 0, 0, (uint64_t)internal_cb, 0, 0); - kevent64(internal_cb->loop->fd, &event, 1, &event, 1, KEVENT_FLAG_ERROR_EVENTS, NULL); + int ret; + do { + ret = kevent64(internal_cb->loop->fd, &event, 1, &event, 1, KEVENT_FLAG_ERROR_EVENTS, NULL); + } while (IS_EINTR(ret)); + /* (regular) sockets are the only polls which are not freed immediately */ if(fallthrough){ @@ -486,7 +544,11 @@ void us_timer_set(struct us_timer_t *t, void (*cb)(struct us_timer_t *t), int ms struct kevent64_s event; uint64_t ptr = (uint64_t)(void*)internal_cb; EV_SET64(&event, ptr, EVFILT_TIMER, EV_ADD | (repeat_ms ? 0 : EV_ONESHOT), 0, ms, (uint64_t)internal_cb, 0, 0); - kevent64(internal_cb->loop->fd, &event, 1, &event, 1, KEVENT_FLAG_ERROR_EVENTS, NULL); + + int ret; + do { + ret = kevent64(internal_cb->loop->fd, &event, 1, &event, 1, KEVENT_FLAG_ERROR_EVENTS, NULL); + } while (IS_EINTR(ret)); } #endif @@ -581,7 +643,11 @@ void us_internal_async_close(struct us_internal_async *a) { struct kevent64_s event; uint64_t ptr = (uint64_t)(void*)internal_cb; EV_SET64(&event, ptr, EVFILT_MACHPORT, EV_DELETE, 0, 0, (uint64_t)(void*)internal_cb, 0,0); - kevent64(internal_cb->loop->fd, &event, 1, &event, 1, KEVENT_FLAG_ERROR_EVENTS, NULL); + + int ret; + do { + ret = kevent64(internal_cb->loop->fd, &event, 1, &event, 1, KEVENT_FLAG_ERROR_EVENTS, NULL); + } while (IS_EINTR(ret)); mach_port_deallocate(mach_task_self(), internal_cb->port); us_free(internal_cb->machport_buf); @@ -609,7 +675,10 @@ void us_internal_async_set(struct us_internal_async *a, void (*cb)(struct us_int event.ext[1] = MACHPORT_BUF_LEN; event.udata = (uint64_t)(void*)internal_cb; - int ret = kevent64(internal_cb->loop->fd, &event, 1, &event, 1, KEVENT_FLAG_ERROR_EVENTS, NULL); + int ret; + do { + ret = kevent64(internal_cb->loop->fd, &event, 1, &event, 1, KEVENT_FLAG_ERROR_EVENTS, NULL); + } while (IS_EINTR(ret)); if (UNLIKELY(ret == -1)) { abort(); diff --git a/packages/bun-usockets/src/eventing/libuv.c b/packages/bun-usockets/src/eventing/libuv.c index 242cd2eb66..b808795ef0 100644 --- a/packages/bun-usockets/src/eventing/libuv.c +++ b/packages/bun-usockets/src/eventing/libuv.c @@ -125,7 +125,7 @@ int us_poll_events(struct us_poll_t *p) { ((p->poll_type & POLL_TYPE_POLLING_OUT) ? LIBUS_SOCKET_WRITABLE : 0); } -unsigned int us_internal_accept_poll_event(struct us_poll_t *p) { return 0; } +size_t us_internal_accept_poll_event(struct us_poll_t *p) { return 0; } int us_internal_poll_type(struct us_poll_t *p) { return p->poll_type & POLL_TYPE_KIND_MASK; } diff --git a/packages/bun-usockets/src/internal/internal.h b/packages/bun-usockets/src/internal/internal.h index f875bb9a3f..f0a34a823d 100644 --- a/packages/bun-usockets/src/internal/internal.h +++ b/packages/bun-usockets/src/internal/internal.h @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +#pragma once #ifndef INTERNAL_H #define INTERNAL_H @@ -22,6 +22,10 @@ #ifndef __cplusplus #define alignas(x) __declspec(align(x)) #endif + +#include +typedef SSIZE_T ssize_t; + #else #include #endif @@ -52,6 +56,17 @@ void us_internal_loop_update_pending_ready_polls(struct us_loop_t *loop, #include "internal/eventing/libuv.h" #endif +#ifndef LIKELY +#define LIKELY(cond) __builtin_expect((_Bool)(cond), 1) +#define UNLIKELY(cond) __builtin_expect((_Bool)(cond), 0) +#endif + +#ifdef _WIN32 +#define IS_EINTR(rc) (rc == SOCKET_ERROR && WSAGetLastError() == WSAEINTR) +#else +#define IS_EINTR(rc) (rc == -1 && errno == EINTR) +#endif + /* Poll type and what it polls for */ enum { /* Three first bits */ @@ -118,7 +133,7 @@ void us_internal_async_set(struct us_internal_async *a, void us_internal_async_wakeup(struct us_internal_async *a); /* Eventing related */ -unsigned int us_internal_accept_poll_event(struct us_poll_t *p); +size_t us_internal_accept_poll_event(struct us_poll_t *p); int us_internal_poll_type(struct us_poll_t *p); void us_internal_poll_set_type(struct us_poll_t *p, int poll_type); diff --git a/packages/bun-usockets/src/internal/networking/bsd.h b/packages/bun-usockets/src/internal/networking/bsd.h index d3bc65e16d..9e9b421011 100644 --- a/packages/bun-usockets/src/internal/networking/bsd.h +++ b/packages/bun-usockets/src/internal/networking/bsd.h @@ -134,9 +134,9 @@ int bsd_addr_get_port(struct bsd_addr_t *addr); // called by dispatch_ready_poll LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr); -int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags); -int bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more); -int bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length); +ssize_t bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags); +ssize_t bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more); +ssize_t bsd_write2(LIBUS_SOCKET_DESCRIPTOR fd, const char *header, int header_length, const char *payload, int payload_length); int bsd_would_block(); // return LIBUS_SOCKET_ERROR or the fd that represents listen socket From bbc621adff90d8786f2dab4415ba0d2bf97a5006 Mon Sep 17 00:00:00 2001 From: Zach Olivare Date: Fri, 5 Jul 2024 16:05:12 -0700 Subject: [PATCH 05/10] docs(argv): Correct cli file name (#12373) --- docs/guides/process/argv.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/process/argv.md b/docs/guides/process/argv.md index 7804f5b621..3acb68e52f 100644 --- a/docs/guides/process/argv.md +++ b/docs/guides/process/argv.md @@ -13,7 +13,7 @@ console.log(Bun.argv); Running this file with arguments results in the following: ```sh -$ bun run cli.tsx --flag1 --flag2 value +$ bun run cli.ts --flag1 --flag2 value [ '/path/to/bun', '/path/to/cli.ts', '--flag1', '--flag2', 'value' ] ``` @@ -47,7 +47,7 @@ console.log(positionals); then it outputs ``` -$ bun run cli.tsx --flag1 --flag2 value +$ bun run cli.ts --flag1 --flag2 value { flag1: true, flag2: "value", From 6f52b649dacf424925bc2a74eb467aab5c4be878 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 5 Jul 2024 17:28:48 -0700 Subject: [PATCH 06/10] Make debug log more useful --- src/codegen/generate-classes.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/codegen/generate-classes.ts b/src/codegen/generate-classes.ts index 64d9beeba9..63efacf89b 100644 --- a/src/codegen/generate-classes.ts +++ b/src/codegen/generate-classes.ts @@ -1828,7 +1828,7 @@ pub const ${className(typeName)} = struct { /// Return the pointer to the wrapped object. /// If the object does not match the type, return null. pub fn fromJS(value: JSC.JSValue) ?*${typeName} { - JSC.markBinding(@src()); + if (comptime Environment.enable_logs) zig("${typeName}.fromJS", .{}); return ${symbolName(typeName, "fromJS")}(value); } @@ -1837,7 +1837,7 @@ pub const ${className(typeName)} = struct { /// If the object is a subclass of the type or has mutated the structure, return null. /// Note: this may return null for direct instances of the type if the user adds properties to the object. pub fn fromJSDirect(value: JSC.JSValue) ?*${typeName} { - JSC.markBinding(@src()); + if (comptime Environment.enable_logs) zig("${typeName}.fromJSDirect", .{}); return ${symbolName(typeName, "fromJSDirect")}(value); } @@ -1849,7 +1849,7 @@ pub const ${className(typeName)} = struct { /// Get the ${typeName} constructor value. /// This loads lazily from the global object. pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue { - JSC.markBinding(@src()); + if (comptime Environment.enable_logs) zig("${typeName}.getConstructor", .{}); return ${symbolName(typeName, "getConstructor")}(globalObject); } ` @@ -1861,7 +1861,7 @@ pub const ${className(typeName)} = struct { ? ` /// Create a new instance of ${typeName} pub fn toJS(this: *${typeName}, globalObject: *JSC.JSGlobalObject) JSC.JSValue { - JSC.markBinding(@src()); + if (comptime Environment.enable_logs) zig("${typeName}.toJS", .{}); if (comptime Environment.allow_assert) { const value__ = ${symbolName(typeName, "create")}(globalObject, this); @import("root").bun.assert(value__.as(${typeName}).? == this); // If this fails, likely a C ABI issue. From 050a4b5c7196b506f8b8ec9a66b70ef1b553fb39 Mon Sep 17 00:00:00 2001 From: Andrew Johnston Date: Fri, 5 Jul 2024 18:29:12 -0700 Subject: [PATCH 07/10] fix(formdata): handle file names correctly when setting on formdata (#12379) Co-authored-by: Andrew Johnston --- src/bun.js/bindings/webcore/JSDOMFormData.cpp | 8 +-- test/js/bun/http/form-data-set-append.test.js | 63 +++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 test/js/bun/http/form-data-set-append.test.js diff --git a/src/bun.js/bindings/webcore/JSDOMFormData.cpp b/src/bun.js/bindings/webcore/JSDOMFormData.cpp index bb55ecd069..755944a96b 100644 --- a/src/bun.js/bindings/webcore/JSDOMFormData.cpp +++ b/src/bun.js/bindings/webcore/JSDOMFormData.cpp @@ -461,10 +461,7 @@ static inline JSC::EncodedJSValue jsDOMFormDataPrototypeFunction_set2Body(JSC::J auto name = convert(*lexicalGlobalObject, argument0.value()); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); EnsureStillAliveScope argument1 = callFrame->uncheckedArgument(1); - EnsureStillAliveScope argument2 = callFrame->argument(2); - auto filename = argument2.value().isUndefined() ? String() : convert(*lexicalGlobalObject, argument2.value()); - RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); RefPtr blobValue = nullptr; if (argument1.value().inherits()) { @@ -473,8 +470,11 @@ static inline JSC::EncodedJSValue jsDOMFormDataPrototypeFunction_set2Body(JSC::J if (!blobValue) { throwTypeError(lexicalGlobalObject, throwScope, "Expected argument to be a Blob."_s); - RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); } + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); + + auto filename = argument2.value().isUndefined() ? Blob__getFileNameString(blobValue->impl()).toWTFString(BunString::ZeroCopy) : convert(*lexicalGlobalObject, argument2.value()); + RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.set(WTFMove(name), WTFMove(blobValue), WTFMove(filename)); }))); } diff --git a/test/js/bun/http/form-data-set-append.test.js b/test/js/bun/http/form-data-set-append.test.js new file mode 100644 index 0000000000..7123dd3468 --- /dev/null +++ b/test/js/bun/http/form-data-set-append.test.js @@ -0,0 +1,63 @@ +import { expect, test } from "bun:test"; + +// https://github.com/oven-sh/bun/issues/12325 + +test("formdata set with File works as expected", async () => { + const expected = ["617580375", "text-notes1.txt"]; + + using server = Bun.serve({ + port: 0, + fetch: async req => { + const data = await req.formData(); + const chat_id = data.get("chat_id"); + const document = data.get("document"); + expect(chat_id).toEqual(expected[0]); + expect(document.name).toEqual(expected[1]); + return new Response(""); + }, + }); + + async function sendDocument(body) { + const response = await fetch(server.url, { + method: "POST", + body: body, + }); + const text = await response.text(); + return text; + } + + const formDataSet = new FormData(); + formDataSet.set("chat_id", expected[0]); + formDataSet.set("document", new File(["some text notes 1"], expected[1])); + await sendDocument(formDataSet); +}); + +test("formdata apppend with File works as expected", async () => { + const expected = ["617580376", "text-notes2.txt"]; + + using server = Bun.serve({ + port: 0, + fetch: async req => { + const data = await req.formData(); + const chat_id = data.get("chat_id"); + const document = data.get("document"); + expect(chat_id).toEqual(expected[0]); + expect(document.name).toEqual(expected[1]); + return new Response(""); + }, + }); + + async function sendDocument(body) { + const response = await fetch(server.url, { + method: "POST", + body: body, + }); + const text = await response.text(); + return text; + } + + const formDataSet = new FormData(); + formDataSet.append("chat_id", expected[0]); + formDataSet.append("document", new File(["some text notes 2"], expected[1])); + await sendDocument(formDataSet); +}); From da1b3d2007f2dcbdc73e7d0d723abe1d54f6727b Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 5 Jul 2024 18:33:00 -0700 Subject: [PATCH 08/10] Check that ccache points to a regular file instead of a non-empty string (#12382) --- scripts/env.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/env.sh b/scripts/env.sh index d4a26b5434..278ce207c0 100755 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -43,7 +43,7 @@ export CMAKE_FLAGS=( ) CCACHE=$(which ccache || which sccache || echo "") -if [ -n "$CCACHE" ]; then +if [ -f "$CCACHE" ]; then CMAKE_FLAGS+=( -DCMAKE_C_COMPILER_LAUNCHER="$CCACHE" -DCMAKE_CXX_COMPILER_LAUNCHER="$CCACHE" From 80bbad6568322528e1b8a8d308e0b4113bfa3e2d Mon Sep 17 00:00:00 2001 From: Noah Friedman Date: Fri, 5 Jul 2024 21:54:53 -0400 Subject: [PATCH 09/10] `setup-bun` action bumped to v2 in docs (#12315) --- docs/guides/runtime/cicd.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/runtime/cicd.md b/docs/guides/runtime/cicd.md index c6d6a36a3b..b94d22140a 100644 --- a/docs/guides/runtime/cicd.md +++ b/docs/guides/runtime/cicd.md @@ -13,7 +13,7 @@ jobs: steps: # ... - uses: actions/checkout@v4 -+ - uses: oven-sh/setup-bun@v1 ++ - uses: oven-sh/setup-bun@v2 # run any `bun` or `bunx` command + - run: bun install @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-latest steps: # ... - - uses: oven-sh/setup-bun@v1 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.0.11 # or "latest", "canary", ``` From 749c51d71ab0607d16af0fff87e3b6b28a6bf5b5 Mon Sep 17 00:00:00 2001 From: dave caruso Date: Fri, 5 Jul 2024 20:20:45 -0700 Subject: [PATCH 10/10] simpler version of `simplifyUnusedExpr` rewrite (#12384) --- bench/bun.lockb | Bin 69389 -> 69762 bytes bench/package.json | 1 + bench/snippets/transpiler-2.mjs | 14 +++ src/js_parser.zig | 126 +++++++++++++++++++------- test/bun.lockb | Bin 318401 -> 325027 bytes test/bundler/bundler_edgecase.test.ts | 8 ++ test/package.json | 1 + 7 files changed, 119 insertions(+), 31 deletions(-) create mode 100644 bench/snippets/transpiler-2.mjs diff --git a/bench/bun.lockb b/bench/bun.lockb index 78eea70b0ef1beb98f2becda86abc2eff95d0c4f..679ce8aba1293d97e0f346c0c8f47166adddff39 100755 GIT binary patch delta 9831 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 diff --git a/bench/package.json b/bench/package.json index 761fa8936e..6ea67f5c99 100644 --- a/bench/package.json +++ b/bench/package.json @@ -3,6 +3,7 @@ "dependencies": { "@babel/core": "^7.16.10", "@babel/preset-react": "^7.16.7", + "@babel/standalone": "^7.24.7", "@swc/core": "^1.2.133", "benchmark": "^2.1.4", "braces": "^3.0.2", diff --git a/bench/snippets/transpiler-2.mjs b/bench/snippets/transpiler-2.mjs new file mode 100644 index 0000000000..702fda9d18 --- /dev/null +++ b/bench/snippets/transpiler-2.mjs @@ -0,0 +1,14 @@ +import { bench, run } from "mitata"; +import { join } from "path"; + +const code = require("fs").readFileSync( + process.argv[2] || join(import.meta.dir, "../node_modules/@babel/standalone/babel.min.js"), +); + +const transpiler = new Bun.Transpiler({ minify: true }); + +bench("transformSync", () => { + transpiler.transformSync(code); +}); + +await run(); diff --git a/src/js_parser.zig b/src/js_parser.zig index 42f3599a96..300ee19232 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -1859,7 +1859,7 @@ pub const SideEffects = enum(u1) { }; } - pub fn simpifyUnusedExpr(p: anytype, expr: Expr) ?Expr { + pub fn simplifyUnusedExpr(p: anytype, expr: Expr) ?Expr { if (!p.options.features.dead_code_elimination) return expr; switch (expr.data) { .e_null, @@ -1894,12 +1894,12 @@ pub const SideEffects = enum(u1) { } }, .e_if => |__if__| { - __if__.yes = simpifyUnusedExpr(p, __if__.yes) orelse __if__.yes.toEmpty(); - __if__.no = simpifyUnusedExpr(p, __if__.no) orelse __if__.no.toEmpty(); + __if__.yes = simplifyUnusedExpr(p, __if__.yes) orelse __if__.yes.toEmpty(); + __if__.no = simplifyUnusedExpr(p, __if__.no) orelse __if__.no.toEmpty(); // "foo() ? 1 : 2" => "foo()" if (__if__.yes.isEmpty() and __if__.no.isEmpty()) { - return simpifyUnusedExpr(p, __if__.test_); + return simplifyUnusedExpr(p, __if__.test_); } // "foo() ? 1 : bar()" => "foo() || bar()" @@ -1927,7 +1927,7 @@ pub const SideEffects = enum(u1) { // such as "toString" or "valueOf". They must also never throw any exceptions. switch (un.op) { .un_void, .un_not => { - return simpifyUnusedExpr(p, un.value); + return simplifyUnusedExpr(p, un.value); }, .un_typeof => { // "typeof x" must not be transformed into if "x" since doing so could @@ -1937,7 +1937,7 @@ pub const SideEffects = enum(u1) { return null; } - return simpifyUnusedExpr(p, un.value); + return simplifyUnusedExpr(p, un.value); }, else => {}, @@ -1950,7 +1950,7 @@ pub const SideEffects = enum(u1) { // can be removed. The annotation causes us to ignore the target. if (call.can_be_unwrapped_if_unused) { if (call.args.len > 0) { - return Expr.joinAllWithCommaCallback(call.args.slice(), @TypeOf(p), p, comptime simpifyUnusedExpr, p.allocator); + return Expr.joinAllWithCommaCallback(call.args.slice(), @TypeOf(p), p, comptime simplifyUnusedExpr, p.allocator); } } }, @@ -1959,13 +1959,10 @@ pub const SideEffects = enum(u1) { switch (bin.op) { // These operators must not have any type conversions that can execute code // such as "toString" or "valueOf". They must also never throw any exceptions. - .bin_strict_eq, .bin_strict_ne, .bin_comma => { - return Expr.joinWithComma( - simpifyUnusedExpr(p, bin.left) orelse bin.left.toEmpty(), - simpifyUnusedExpr(p, bin.right) orelse bin.right.toEmpty(), - p.allocator, - ); - }, + .bin_strict_eq, + .bin_strict_ne, + .bin_comma, + => return simplifyUnusedBinaryCommaExpr(p, expr), // We can simplify "==" and "!=" even though they can call "toString" and/or // "valueOf" if we can statically determine that the types of both sides are @@ -1975,18 +1972,18 @@ pub const SideEffects = enum(u1) { .bin_loose_ne, => { if (isPrimitiveWithSideEffects(bin.left.data) and isPrimitiveWithSideEffects(bin.right.data)) { - return Expr.joinWithComma(simpifyUnusedExpr(p, bin.left) orelse bin.left.toEmpty(), simpifyUnusedExpr(p, bin.right) orelse bin.right.toEmpty(), p.allocator); + return Expr.joinWithComma(simplifyUnusedExpr(p, bin.left) orelse bin.left.toEmpty(), simplifyUnusedExpr(p, bin.right) orelse bin.right.toEmpty(), p.allocator); } }, .bin_logical_and, .bin_logical_or, .bin_nullish_coalescing => { - bin.right = simpifyUnusedExpr(p, bin.right) orelse bin.right.toEmpty(); + bin.right = simplifyUnusedExpr(p, bin.right) orelse bin.right.toEmpty(); // Preserve short-circuit behavior: the left expression is only unused if // the right expression can be completely removed. Otherwise, the left // expression is important for the branch. if (bin.right.isEmpty()) - return simpifyUnusedExpr(p, bin.left); + return simplifyUnusedExpr(p, bin.left); }, else => {}, @@ -2006,7 +2003,7 @@ pub const SideEffects = enum(u1) { for (properties_slice) |prop_| { var prop = prop_; if (prop_.kind != .spread) { - const value = simpifyUnusedExpr(p, prop.value.?); + const value = simplifyUnusedExpr(p, prop.value.?); if (value != null) { prop.value = value; } else if (!prop.flags.contains(.is_computed)) { @@ -2046,7 +2043,7 @@ pub const SideEffects = enum(u1) { ); } result = result.joinWithComma( - simpifyUnusedExpr(p, prop.value.?) orelse prop.value.?.toEmpty(), + simplifyUnusedExpr(p, prop.value.?) orelse prop.value.?.toEmpty(), p.allocator, ); } @@ -2078,7 +2075,7 @@ pub const SideEffects = enum(u1) { items, @TypeOf(p), p, - comptime simpifyUnusedExpr, + comptime simplifyUnusedExpr, p.allocator, ); }, @@ -2092,7 +2089,7 @@ pub const SideEffects = enum(u1) { call.args.slice(), @TypeOf(p), p, - comptime simpifyUnusedExpr, + comptime simplifyUnusedExpr, p.allocator, ); } @@ -2106,6 +2103,56 @@ pub const SideEffects = enum(u1) { return expr; } + const BinaryExpressionSimplifyVisitor = struct { + bin: *E.Binary, + }; + + /// + fn simplifyUnusedBinaryCommaExpr(p: anytype, expr: Expr) ?Expr { + if (Environment.allow_assert) { + assert(expr.data == .e_binary); + assert(switch (expr.data.e_binary.op) { + .bin_strict_eq, + .bin_strict_ne, + .bin_comma, + => true, + else => false, + }); + } + const stack: *std.ArrayList(BinaryExpressionSimplifyVisitor) = &p.binary_expression_simplify_stack; + const stack_bottom = stack.items.len; + defer stack.shrinkRetainingCapacity(stack_bottom); + + stack.append(.{ .bin = expr.data.e_binary }) catch bun.outOfMemory(); + + // Build stack up of expressions + var left: Expr = expr.data.e_binary.left; + while (left.data.as(.e_binary)) |left_bin| { + switch (left_bin.op) { + .bin_strict_eq, + .bin_strict_ne, + .bin_comma, + => { + stack.append(.{ .bin = left_bin }) catch bun.outOfMemory(); + left = left_bin.left; + }, + else => break, + } + } + + // Ride the stack downwards + var i = stack.items.len; + var result = simplifyUnusedExpr(p, left) orelse Expr.empty; + while (i > stack_bottom) { + i -= 1; + const top = stack.items[i]; + const visited_right = simplifyUnusedExpr(p, top.bin.right) orelse Expr.empty; + result = result.joinWithComma(visited_right, p.allocator); + } + + return if (result.isMissing()) Expr.empty else result; + } + fn findIdentifiers(binding: Binding, decls: *std.ArrayList(G.Decl)) void { switch (binding.data) { .b_identifier => { @@ -3340,10 +3387,25 @@ pub const Parser = struct { defer p.lexer.deinit(); - var binary_expression_stack_heap = std.heap.stackFallback(1024, bun.default_allocator); - p.binary_expression_stack = std.ArrayList(ParserType.BinaryExpressionVisitor).init(binary_expression_stack_heap.get()); + var binary_expression_stack_heap = std.heap.stackFallback(42 * @sizeOf(ParserType.BinaryExpressionVisitor), bun.default_allocator); + p.binary_expression_stack = std.ArrayList(ParserType.BinaryExpressionVisitor).initCapacity( + binary_expression_stack_heap.get(), + 41, // one less in case of unlikely alignment between the stack buffer and reality + ) catch unreachable; // stack allocation cannot fail defer p.binary_expression_stack.clearAndFree(); + var binary_expression_simplify_stack_heap = std.heap.stackFallback(48 * @sizeOf(SideEffects.BinaryExpressionSimplifyVisitor), bun.default_allocator); + p.binary_expression_simplify_stack = std.ArrayList(SideEffects.BinaryExpressionSimplifyVisitor).initCapacity( + binary_expression_simplify_stack_heap.get(), + 47, + ) catch unreachable; // stack allocation cannot fail + defer p.binary_expression_simplify_stack.clearAndFree(); + + if (Environment.allow_assert) { + bun.assert(binary_expression_stack_heap.fixed_buffer_allocator.ownsPtr(@ptrCast(p.binary_expression_stack.items))); + bun.assert(binary_expression_simplify_stack_heap.fixed_buffer_allocator.ownsPtr(@ptrCast(p.binary_expression_simplify_stack.items))); + } + // defer { // if (p.allocated_names_pool) |pool| { // pool.data = p.allocated_names; @@ -5218,7 +5280,9 @@ fn NewParser_( const_values: js_ast.Ast.ConstValuesMap = .{}, - binary_expression_stack: std.ArrayList(BinaryExpressionVisitor) = undefined, + // These are backed by stack fallback allocators in _parse, and are uninitialized until then. + binary_expression_stack: ListManaged(BinaryExpressionVisitor) = undefined, + binary_expression_simplify_stack: ListManaged(SideEffects.BinaryExpressionSimplifyVisitor) = undefined, /// We build up enough information about the TypeScript namespace hierarchy to /// be able to resolve scope lookups and property accesses for TypeScript enum @@ -7444,7 +7508,7 @@ fn NewParser_( // "(1, 2)" => "2" // "(sideEffects(), 2)" => "(sideEffects(), 2)" if (p.options.features.minify_syntax) { - e_.left = SideEffects.simpifyUnusedExpr(p, e_.left) orelse return e_.right; + e_.left = SideEffects.simplifyUnusedExpr(p, e_.left) orelse return e_.right; } }, .bin_loose_eq => { @@ -17327,7 +17391,7 @@ fn NewParser_( p.is_control_flow_dead = old; if (side_effects.side_effects == .could_have_side_effects) { - return Expr.joinWithComma(SideEffects.simpifyUnusedExpr(p, e_.test_) orelse p.newExpr(E.Missing{}, e_.test_.loc), e_.yes, p.allocator); + return Expr.joinWithComma(SideEffects.simplifyUnusedExpr(p, e_.test_) orelse p.newExpr(E.Missing{}, e_.test_.loc), e_.yes, p.allocator); } // "(1 ? fn : 2)()" => "fn()" @@ -17348,7 +17412,7 @@ fn NewParser_( // "(a, false) ? b : c" => "a, c" if (side_effects.side_effects == .could_have_side_effects) { - return Expr.joinWithComma(SideEffects.simpifyUnusedExpr(p, e_.test_) orelse p.newExpr(E.Missing{}, e_.test_.loc), e_.no, p.allocator); + return Expr.joinWithComma(SideEffects.simplifyUnusedExpr(p, e_.test_) orelse p.newExpr(E.Missing{}, e_.test_.loc), e_.no, p.allocator); } // "(1 ? fn : 2)()" => "fn()" @@ -18671,7 +18735,7 @@ fn NewParser_( for (props) |prop| { const key = prop.key.?.data.e_string.string(p.allocator) catch unreachable; const visited_value = p.visitExpr(prop.value.?); - const value = SideEffects.simpifyUnusedExpr(p, visited_value) orelse visited_value; + const value = SideEffects.simplifyUnusedExpr(p, visited_value) orelse visited_value; // We are doing `module.exports = { ... }` // lets rewrite it to a series of what will become export assignments @@ -19481,7 +19545,7 @@ fn NewParser_( } // simplify unused - data.value = SideEffects.simpifyUnusedExpr(p, data.value) orelse return; + data.value = SideEffects.simplifyUnusedExpr(p, data.value) orelse return; if (comptime FeatureFlags.unwrap_commonjs_to_esm) { if (is_top_level) { @@ -19693,7 +19757,7 @@ fn NewParser_( if (data.no == null or !SideEffects.shouldKeepStmtInDeadControlFlow(p, data.no.?, p.allocator)) { if (effects.side_effects == .could_have_side_effects) { // Keep the condition if it could have side effects (but is still known to be truthy) - if (SideEffects.simpifyUnusedExpr(p, data.test_)) |test_| { + if (SideEffects.simplifyUnusedExpr(p, data.test_)) |test_| { stmts.append(p.s(S.SExpr{ .value = test_ }, test_.loc)) catch unreachable; } } @@ -19707,7 +19771,7 @@ fn NewParser_( if (!SideEffects.shouldKeepStmtInDeadControlFlow(p, data.yes, p.allocator)) { if (effects.side_effects == .could_have_side_effects) { // Keep the condition if it could have side effects (but is still known to be truthy) - if (SideEffects.simpifyUnusedExpr(p, data.test_)) |test_| { + if (SideEffects.simplifyUnusedExpr(p, data.test_)) |test_| { stmts.append(p.s(S.SExpr{ .value = test_ }, test_.loc)) catch unreachable; } } diff --git a/test/bun.lockb b/test/bun.lockb index fc1f73cf79e9171f016edeb0648110f9969ae33b..b3cdc087159e70e93276956dad549dbec48565c4 100755 GIT binary patch delta 49980 zcmeEvcX*UV_x3)!S;#|&AOQk|&^rVYHX)Ers8T{ldI=$fKuD(q2uT3xAozfz(u>li zN(@LB1r!14QUs9~LAqE%{qFmj*^t*4y?lS)@4K$=5BK8iJ?G4sGc#w-v}bq2zD$o5 zKY7flQ{Df?kw7P(VA>fekq}qdH!lS+ePb;T@%)bj?kiP-z^z%3%dY(Q3O(mWN zPkUQ|Fqxhl9v?n1CNj+u1_2GM1hV37@D1@D@T_nekOl?;SwRe(O8-OvF-AFj50$?H zgG4tKDkt^c0dF=0$c~N#(oQqz=d+|)(uYS6kE}gtprsK6H0Y}^a%5y|GUE3H27m@e zMaK+^2u~b@-X}AR-z_gI=;kByhegK@svS4j(h@v75Sagh5#eZLJA^8ECy54qNQ#a!_2)oNJ7s}va5|7)omEdZOs)$U z&cw*@h~(PQNx@KX^^`qH1YZaR+5qW^kouC3i5n5m{Da_44&*FZ^jdP7Uu zrrtnCWLqEyur`n$-e`oodj_6vA={A>9upId{VaUwNCXK&ri1LVYuzj#CiSu*XX*CF zX7{RT6FSLYN&&Jr@d_i9ydAI*Q7VLh}igOhJLEz6IGct=qAg4 z1!Rcj>1{mL%ccF?TZ$8s=m#tjeWb@v0ojHxfNVozU#S-jWZ!o~PW)Km*nYAv_kr9% zqk)W(sJQq+w0jYJaqykd99Ew&z${-neTYn?506Y95;rKx5*`r|8IKjZm$5mYcW4O= zFNqp5=co~p-Ww8=4Oq1ecqLb@eEYrcWmWoD7e(&m6qooTxfUI-*P&teq&|((@hsici zG4|#6tnRXPH%68U9xiiTHjjg+!+i~{fM?nSXmLUe2Qs{S0_lg>fee)(Acv(cumG?U zkfZCWdk=a<_q!%qM1pK%PaxYiFd{J}K6z-;0;M+^NV|=J=wVv=NW=pLCx9$~rO(93 z*oe46(XmlqVL&MFk}R>@2w7orB3D9-S zBdd^isV#5HQTpTZGsAdLsBZO3Q)GRSSWMZ6q>+&^$&nUIAGNq%nJVQWM(e`fp|08; z(_|~E06C!Ouem<_*?GOo3>j&Lv8J$h+NzndZ?2`wwQx?DC9S&7wGGh*&VhBaC8hz( zfM1~aO>fEYSPG=xD2_c|wN=|M&ylS=4W!S;&o#%xnx15|F5+G4kLT1_oMc#hhmldl zvvs|B(rAhy8yf-Si% zzzXj8aegiqvFG{DO%#A zYA2_}M`yScbz6y9+)(E-uD0K-$fh-bGdL z!nj(jsupPI9?rn&8>I22n`C3&0&7a zvBe4lKTR$)a#f$gI z23-VC#ght88%1C9PP@KO#?+TU&ZbNtqh%$K=A8#*er+H(xW+wW8(NiAoHQACeGbxre$~Zts^COI_Yv-$tSi1d+hnz(8OvU_pgf zk4SzWusr0$<6@)YaMN9NOiu3!$7O@g06DGyY=<_WPtQ8Pkqw>)EMROX;gxm68*^dLyvDy!$ONyVB`NJa< zqay2DEZa~nKgS?CsdiLM+(63<2(W#_o+SseoVZ(s* z!(#XVj!HlDz4T8?IM0cAM#qOQz>I5B{soZM5`px~Zlxa`6&sfb#lcCnBS$AEhFh;o zy`f2QvAm8&gv;%9E%Xs0Y3Wmur~m`8K+eiHfF*(RQ5i>groxs#${4H#q+T(F**9b? zUQu`m$nu*Mz6bOKKM`007zbo*;`D`vV?dmDWUzZHd~sXy-vhZveh%bTv;tTWI0?wD zD^g)AU^(zLfYdJnWCI`mB;|3ah#@(^tPpxXOFQ|1<3)er~ zxvj0=;{v<7&)?i{QC!QeCmIcZJG8&EmD{=n_pa3s$=~QqD`Um>i5I*|-e?`)etVs- zhxNX3tMliF&qaPXv~TKK|DNLuRCs!}jkQJBucx*>u=;esm64ZceRw6?XYX&PS5ymM zGBNN=-$euU^pM+|TW79#KCJTd;`%o|U+c2)>CEvSTRYaTX4NJdDSl4vdm{_)6^(4X zcQFF}o!TBF#owvhZ5B&obkS~P_&fAaaBqOK8KFHLx&Rjp&fVlrgKGoMYV7lKXx>Iv zL#H0;X0ZgA`kFJq9ZY>wouG#?0N1b-1IMDu(cU-Awh$Ni9dJvnhLo zR6nM)&PGZTr?%P1!ut+%|YAIh|vk8Rp4*N)OjVZTpL8_6daho!! z0oPPB0$V$^EF-10Q}-z+b2J9I*4M~J&Qc?=jZ=GQq~JZ!$in+bBfE`L-+(2JaciZ| zv>QfBTa+&k*Fq+p-p$B{Y&m3f5%kc9Z^6|w>()XYdOjanA7UDL1Hm!sZD#E&jleLc z{w-wmfYk_X>Cnqpa7`n&uZNKxX11@rQ@d)Uw0G(qDqvu9fR5(9G3<-tC7P#4O|B!wRMnwPRU_mN`PB6i={oo z%)SAsri@hm9#SE)G4N#F>MlPqNTa~XPG}t*`Ui@`dK2c*3)FB`xbIYe8yVAZJW?&0 z(hndd2L%yswbwMp_y_BuHC-O#xQzuzM__484{!q$U^eNdQp#)kr(!Kx1TJsS&lr3>h83A)wWn#8>x+gv_VE-52v=(Na^9!-Rq*Orav_JxIZ`!l!b$+y=MgW zbn3?-YXKQT7SpD zyO&dc2QvEJ3<~=pa7|1bb_j!*(%Ku@y`7q21om<2-#|*g$bc%|z-1j_YM%_Qo$0;r zkm7`Z5866(4cGr2Qkw?px9mLXoa4L8M9C|e*RUK&CU~nyEjcD6?aB_}u0lsUb40PHZ@VV(qJrOB78}XN7mSn$r|yZ7W=)t1107g`vmrAelQy+C1Kh#L#U`|mL#tq94RYFxHQ|ie zH7Lj)j#QYL`Y0#$Bq#McS}k+uBh}W_yMk0}GgaN`N+sr`cIKqqFwdl3SWfDloYZ$Y zscNAXODoe}Tuy3xPU=}ssyTYp!ql6VllnR*<}kp2czZA>|5)2E7)t5%-Y2nsX$`ymB)ptW2k z7K2j*>hG|h0f&Q1qaeLB3`sfXPG@lS%+eE(f*VkG=$QaFFn(s$*0!!`%JWjNkrnUM z;~}G4kZKsiq_X0-XXs6!03)VDe6sP{QtL%cs*q7wc+jNuTE=P18IJs(Rqa5~&;4q@Yg7orlxTYzV z3~iv1HO8s0fb8W`aTOfhCp+rZUG@Z4G1a>mS!12{NsxsYyF!BOpCJ`&?E1a2dk>e| zzFPrqU>ch76OR;^66^|19fH~VZ)|rfE4*N`S zA*PA1km6Eej*M>Uvf&sZZM>0^=G1l>S!qtaSZ}Fku3CC$Z~?FZuDQcL z9bA3$y!xq;mG0D^gQpd^5i49{BQV3MkLcs72kz6q2PZeOQ0&rG`{uYX!J(&ud+EHL z;H2}oBm9!X!Lq$>KjazD+6U>gkwPHS#h9Y*{c+lt93pD~IL-mt-}T_?nH+j(zX%Se ze4L7F4RFmPoEx+;M%E;!z6~t;$w+zAsSgU5r7#?Q9Qsml^sHQN zPJxp(VV&3A21*Y5PpShSp=M2X>gkYi${MCI64CzK#fPi$?hO- zb>C>$)MtQa zz;PiokK=laVXkoF!il@kY^S!@NSW=_e?|_DJG_EsIP`a8WSixX{RWN$jy5-gmxkxq zfSad-V-HX@PB)jqH3ui>bcNWQ0FHO)gTSeQ$G$ZWoSbf4<_>}DYSzHPDieomBsd)S zV;p)cI625X;Oqv+-kHH?b&oe5&kfew#>*yI%oEWJaGWU^)X4#EV6gsSMY1QzI^=4X z4h{<**1mm{9rlypaG4DV(!7i;13O@%Ya+7+Z-K*BCD%#qoRKomsh3NVu^_EY0r%49 z7r@cyc?@k1;%L4TXWgv%I9(>^o)+ILPTmOWjgZsPJQwQYz}15VbSTWBtv9mYaat`S zjYc9^Z$DD@&dzg^J`)_Pk`6xvj?19A2U^`n8I9fz)_abU>pCJ}Ec_0ROO)JzzB01k zb?R=TT}F5i>jF+LE!gk%S>QOmu{piz&<`lhf@YMwP@1Uj5c>JPQ%f|m-goL@V`S?w z0Lud0!EiQX)k}5gyA%g=-5vI4;OZEu*d=R@m8&wsJi=k`4h~lj+-Vje#r|Qqn>h6I z;M#+epay=%wHEO&uW>~Pk2ttOGoWmEu;j~I_w0YlH;?$ZO*-M=ItTc>lkzVuvG>utc%A}YmQXsQvo3_BKNjm>jUkqkKoa1%~oZNPDkq0yMpi@`NFInIag z!Kuc#ci2l$fD?>e!9jW-q&UAY2AE%Sz_G;`1i0}qIL>vntGh#g46c!x7YfdAq8x8H z94pdLa1P|<7mM&RmD>`6i>q=EmCGNLl67=Yyx8 z;mb(@?qKK;I12}oVpAAld>j*Eq^x#o$wt;{r+p2ic>I$Zq~AnJ#sfRyKUEsS+`@4x z!N^+U)IWrb?m=W?C~heYcQfYNOq2R@_n!=oE|(Fw16)I%R_*tZs%JbKiB)^Lv?Xt6 zy%dLK4)>^e;JAdK-I#Wl!7-2uGdy&U8M2k;^Fcid9J>oH)L~sQ!@Q1v2VqCE_`ah7 z?lUbGCzyQZQ=+lpYJoG|uWwPDxwPn)6^BI#{m(ZmC(OaU4vsySgE#}6TnISZ_NhE` z9_dfOsR0lU-7!07=SACh=5YHG9Cq7V7E3n{o!$c}4rv}9D((Bh$?I~VIZ}=>Xynk| zFakF_^#zcrmSD2nGqNBHoa-8weVZNn3~)iPhF<-K0NUcTKZgVt6+FIZ__iDugvU~Z zG&qK)Jhf+nYYq-83WEO$IL40jR0BhXAc788t4ZLfi5?^P4}qgMFikKepM#@Kb4}(Q zW1CY?ntSCyHhXtj+Eh? zgC4X7$Eg8*tf493Ld|~eKuX3Rj}Lc^tW2jp-+T1yuFN3&8%VV`Q!A0e@h3A#%Qmt; zaq0o@%hn@``#9`F!F6S>z8k3s)Fb2BXMuU3fjk8%oNko-3OKU{z1BjDrFV{e3b>A@ zowG>cK&kW_E^^5yBlS{#9h|h|yEvB}eI~fRuG0EVaN#b_-e!rbPwyht*{tmrQe0Ru ztHK=iYD>{KqltfzeK1nEOiT*Ww;{!mL_9QdSZ&LUM!WGiYngN&hO1S8+j4w+!F&!< zZ-qQFL;PES8yHh;{~oE%RIvN4_h$9k+SAr5QvkBmm4!TJOU zl`EWhq@_5ybU##_c^0$R*a$C}E$@fa%LQQ>I8MC0=EJfRIa>Bja&qJ5jD~FkM<>e* zi`!<`vX13XZx61y>^%JYw&Kuea6jba@%mD2i>w(tFP7T@;OH2P1Zr3gt^qi?o1a#i zX29zOx5{M^{lfiX2)H)T#HUg?M{Y4vj^aZk$hhUn8%U#VGOl#94g6lbj540|KLyAB z${qf;%0utr;%XmD%h-glKPQ5F9hzt@HjW+Og23U45!&zzI4<7u4pn!%?3b)P3LMWD z#mp<)7vN|`_OfuM>t?|L9srJEBe%{qiomZ8uST>YGK?}KXz z4w`7^@8IZFX|qw5YvDk&>!ZQ>A`g8S<Px`+ndNu{bl-!O7#s!+ zPe{6g!!;Mr0@fhKy08Nt44{%Uz)j0%ujCMsh~(aiL(dvI?DN54HsLUT7%9dRW*MT` zzE4h4GyxH=?RQnWFD$?f46b9?yXPat$%M7KxdY#KO!*d%tqw?so6C~E5nPC=0W=SS%d;Mgqa?{;W!87Y^Y`Vq)NA(O|8{Dwcz)IQm|WZCNvr&Ei)A44Fx9x(Df3kYX9M1JPaNqzpT_7MoNs zIWy8?kZKAo$^+cM;4`D%L3-X((yL|7!cD=k*(PUy8(b4=X;+M_8~Et+wA`SInMe3u z;21IRFAnsF!Et59p4q`+FLVZZ=A?QZDL+$-U7rk&TIeh`V=(NUyzQ1fE6qtibO*;` z=y_9|e!+2O%Jt$fxQ5`&;L-JS(j@$jhgL1XIgMxU2I&H+2Bw8joS%~{J0w*7lE=7u~Ct?&23I7Goj7qJtk#*Z?@AIvB7`q*0UyBrua!CD}lWKaw zC7Yd-`WC4+re39sobW6Wlatz(lX{wyYJSP3H!~-7DkoLuvMYBGQaIwWEjg+CIjM%< zxpK!L)!fwEo0D?8;*!0dlbVSXo-{WN()Jr!51qPpRqkTgW%0Zjzj6E7sZWDU1|ybR z?WmFUv$J4{@8ztvS}c}%hOb{uBi_$l{{~XdTl0EWu<$i?8;1^#HjSiC2&DC)gPDF6 z0}QS)I2p7j!I|GN&^>;TBO)&bJ;6~+2E}}E3=sqc;}2XQxcuhoROq^DmwBFO4=w^geCWGU2K`7wi?RIcniNGQ6Ik*UL@~jd5FF9?^GgQ%S;5so6{U9Adf2*>;R{IU( z@z255z#B%RN5S@pAI-0ZJPNY!L#l_-1gTOtU8w}5a1wsh*v(8d`L(gzEnY~dm5`G< zh!nnP0-5JeyiPC`g%qxkkAn2ANIA_`YAXZW@5mbib_>juz5mAf+|8Xg0bFmh7&R|} z>zTtfyeIEG(#j%m{d4l3{u|f(zPztU%}>C+wCV8xx8Iy{L%{XT;SPf1;92q;RJ|>S#`?`Y+}k1+s}bsY^)Vo&lNv zuk-z^uffTa1@lTjmPQav*Z}*03o%Vnb0Ii}9RmA8fcAKPBQ033@kAc8 z%|p6%#FP0uAUp(NGbp-q3$Ryz$`zR(Tnt8vd#$;K>8rp|tC*27&0)RuR6N$SV0+7F z=B#cOWF7ZRjInCL*4@v<4y)EE4ND=HLrY!|W~%whjW$R^KpF_On6Li^S-v@l*a}2D z=&p&a&963sL4w}_v~&lR1jT{)BIXgPWi{_KmK#MGUavyV!xRwf83*Ev=nk3$V*X^1 z8)!Pn4tfj37m;!U#Cqm|_#);3y^k+qnhJ}-(9lv4UrWvRe@Eso2N74Q{M^U}u2OO$ zD_pH`jgk|ow_eFN@VLVkZdQUVK)(JC+Qg-Dnr9l-w}V(;CKFIG(RMI`^L zWKHxz+7rr@n-%^6X{R*b6w*KZu?exf#v8Xxhz&4j%?`=#Q!V+(^-Jyb({Rd?L%8R(vkBS~T&D?O@h9l}}`S-zom@AXTp@ zeIo1oLGiiK8*&?*$t*WIRbnGo;y;jv+?C?1u%Nh9S*vTd-&3jm6|!IDl-{eb0P<@f zpY5xu^oVRmUBwfb^i@2tsac>t1XOIOGKdTmeBH%-y$YEhg8V$UKWnblF{{}s|+7w9pr`YQcbpq#p|$Ure!kY)ShjRpq->8J>0@KwmHNW9T6(LnY$ z7D#zK-xN|l!s;arj#L>$CP(v4+^MR0cVc~GRQ9WoOW&KS*c2e^ouTxJZ1-%%6E%@q zP4gC?7Sh~v-inxRn5(pito3ammxuQizd+@`3fY^bDxXOH10Y4K@J4&96~9*T>lCiH zVg*Oq@)6(ufQ(=M`5YS9uJT`ntZ=8we-$!om&*T7ME_aAZlyph4*na(6PbS!NYQB} z|DPbo;~dKCz^g#o{l0)Q_&v}n!iuPc^190Zm%s83C`zoJE{hxuX z?~#)K17YZ;V4bj%G%J6T>@T-tn*(#sN20aC`LC=63K`VtOR+Jew2v~+cd*O>n zJ}-HZT2!qd`Be6+km?1H&y}DAkPa-Z^oh(bqj(~d-iptS)bmmKm4Iw_Wg9}5FC_j0 zxnaX-1N{>iKHCB9Mo2=gy&|ok!IA>Y_$+rTs=bcmm zA{)?I@wt)ZdaC?hDxb&-`z!eXB`4BOc$!KKR2jLE4HyJDv!Yb~Um*<+QF=rk*TyS8 zH&V}4uXxu(>mx4KR#%6~Nvtl;W$9f$@nlkfrp9 zjNCm+zE|NsARTr9$k(fo4f#yv1Jn3JOUrR3AX4Fk!f${K@iU4)3*?K)iq0!OH!>10 zL(Z(LO7EJ|BeL9e#b37tfl~rj{4b^OqrzKC@l{wrq?XX|7kf}Fn`&YaSks?RRq5xd zbZ(^j3&`m|JNm}vHjxa4CVb)d4D(5PlFAWAtGDeSn)(QELiccLgt64d?Ke<7?3^hsN}Cgmh0>W z1x=K#uWp>(l>Yw>a>?tX?EDv4AH`%rPNBgtzy=OcI8+%VQXWHIT&k}kC{AVPMye%1 zPCq0o9HsP#OpaCZ@j#A48ijvAPLN5E)81s2Po(}7H;Y(MO4H3So~AN$BbBBruR^?8p{1dKm%MrLTl;SDH6Y1hJivK&vAv_CxhUHaN?vI%EN5Ox? z(<673;r}7l`CA6qle?%$7aPiGUSe+<+*khU&CPV{6O>>R^V0Kw6X|1J>Hi(1etzh) zg#{EAv}3npbQDpBaw8RsLeBi+D*um&Ec0o9Lm(HW+)w(MN1o+FK(rSM;_D?w{88|q zJPkAl5nF+1=yipyfqW7FdE#%etTDYIk^Wi_qQCxm;;$TW2*?+aQ{o62ymBKQ_wq@< znGGJ&f1dbDr~N8@^3M~0_~D-?{<%Mr;9B#~6MuREuYaES|MSG3aq!O*f9$mXJn=U_ z3E)BcRZsdECzSI{@}E!onM=8PmhsOMf9ViB=$F^xf1dbDhj`*CjtLF@#l(?`xAkGp7@)K?<=18JIrM}_mh75jy&hp zpFi=R@_s`t^Zka_19?N5Y^Z)H80Nj_ zXw~)ZBfD0))oM<@3!m27H+pEo;f7Yv8~(A6hyUQYCG@@1eMfq^?RinPMY`rVb8eXrNLRAgQw-`C1N8xR%n>3}yEw5f6HGyhzM-Ew;(YG=Cx zeKv%RO_{x-Ou&oTP0!9d-FsHeGk)LxG;Q0;H2*fwcg;%9SEEp$Xe81k$waz90vyRS^D^DGN9(F8qXS&FcBW5+wg1GWrVe&)wVH9qotZ$X7}^{2O( zGOg93H%rv?%l>8Pj^^*>YH;4%c7N!z;n>5PLk`_qmG{zj)5={qaI$OKq4P86Zm*Y} zow;?=)$7)dXP>&|*%>!~Ufb`E@8134-XDtHKHO;6g#wFbhmZZ?Y5!b?-E$ib9`OC; z+xh;L5ZkZZ*@A)H7S$g6*}R>*hCiNuboYUAefE4d|MT*r9pydJrqrJMMqq6775!TV zEZTWK--fheX+h18>=~4q%dno?@Pq}e{M~)ZpTGG0(dQMyiUo9f(|=r0R?)7t3M?|cf zHtEB(>xa(`F~Wy-K3ZVKTF(L#^FIFRREM6MqAHYr_}13XMjp(V5dGzn?}DeFo-pxP z|AwjGEr}Ra^|Dc;Z!W|6a~obz@0&gozxA{?+chWenkC)lfBNRNTB7Ck#})1;-yC*q zV4G=O?|d>hwL`Giv*C~1_`Q*sb}(b``}zDXj;K)h(8_lP_GppIFu(ccdb#cWa`E|E zpOmzBF_xG4{+n)zqb?1-xAcqfs$Sc6f1;Jk_McW_S-`+IXI*>n)VIR5tN+q#7F~K_ zP0xKh+!j|H=*ZLYW-hx0bJn`>h$mDd_Tu)(O1t(e}8}BvZ0?>J(GI($^L7;hyBtzEbyu|U~ItoYqyTB z9Z@@Ya=`-+(}x958e6+gF2jX$8?LgZ#qr?aqP>?cjO}YZ(6j#P*oz}}j`0u+=1pwi z;nnB(S0nc&ukz|x?ZgSOXzS??11IeJ*N|RaGkjLW7SW$HZO{MO#ns>Su*NO?v3Gfg-3B|=`!fQeg0hAEo1W%DgC@G4D0!oQ!LTRy&;3Y~m1(Xp9gtFo= zp`7q(2JjXs0I|BY6<-2xW^Jqai0aKDuOKoA6~%c%CE?owP+3ePR1sGRRYhP+Ks7O! zP+i;vh>~G26xIrcYKr$-L0(HdAk-GEUkB6?%LsKvHld#A)EeL`))49otqq`o=m`*0 zJHpVeHZbHb^tKQLbb?@bTL>H?i-I31DBBK#KoQ*zf_FPZaFl`|Q7R0k8jA!%6LFXj zEPUDnoFat~B2ExOMfDDVrXqvTOq?e)7rq?6HX^h$ zpl#-Rovo|1vZFDEc$AucANw`FE|Ja~mh1o2yq(#%tMx5STP^N%vsSgo6@g0TgVEOh zHvE{>?KRi`z!(t|U1w;LyqvAboZHhXH2awfFe}2lTE|kg;LnxhU+vFZ8Gp4u6XNa~ z<@&?wveu`fY+vg=?Yt=1&l*&4P3@O$S)SRgpEXXif71Y8lgjiNh&G!g^VO06zd#L< z8g31;9}iUZIhp&;K&$&}r}66oe1vcI$o1bncxILzX#G;N_h^Q8uz8uLF@D0NLv>Q- z=0R4QX8)`Wdy4G5W@X~j{#JMG8*y~7b*r{CGb75nE}xI=8SFu$Fcn`fMwzkvhZRys8G8kO+6 zqh!2cmo_ExyZN-mk1MJw**&GlZ%Pixro7eE%l0%>u5v6LB<(No^45?(7P;}=Rdu^?W&5m4p<+QP4M^M&KQ zDdf*DwksJ=;#8!Y-%v6hqM5{mvpA73y#%D5CrAykg(pGk@yE-}n81r?BI=a_HCM7U z9%v}!xYb9RW5cruWmpL;4U{5}5tNkyRaUYhN>&y!*GaCZl9hwZ^@F@(O6CpO7#QJD zdq`QDr97DNN?2Se`am`bGQM7ejP9=hnxc4bbvCh_7l&h7Hg17{pmnLm8}#wAlgxe_TO3^+4{*U@ax%Oe&yc zwUvxBX#j|?I!cy?U6y|x&wTOM87$)mYA8jPdXTY!oO0M-&EM}ZPAH?!SBP{@KR;F0 zf%H)&FvpALWw|M)|5^ULJ`OOVoQjI;)W zoL2lv2rJBzM3dmFwzHU1g~Hq8|?%gQL+&JjD*4v&`~Ai6r#aU(AP@FDMVRQ z&@Lt86r!vdXt$EJP_pKbwMLp#vZa!>K$^Yhlx(GBEg63-#5wu861GB`z323!5mxd# zh-1d-*G9=&Bh9JG>DN}t+91u9jjwh}#^F7vWMN9y4zepSoK^{m_DUFr^brU-T{QhP{5enr_#c!kUFi)1 z9}41h&QP*Qq?;<)1jx)U#Sey{8Hlfm5YmNFASa0P{!LYQ2+}Rw@P^l9C5uM7Eo7X! zt{)o>MY^4mO;visAmeX9_?o8bh++S~1;f`2r8pev3raRq$zmb9h%_5COUdGpzNGYK zD_J~brHoP(m;{!;)nvrK4H@&3K_4Q)h@YqQMj#yt z83S*=l8r=q2n*o#4rKUe{!x%crUd(f(i;taJ&41~&ri+$Ck4zl&_K`vr8oxZJD>>A zLM0oEG#3#L*CHhwhjdFNTdZWM;M>F19EK%IHXiAGkZ~B6DjE82Nz1RsWEq6)Ksu

X>C9{3@W|AN1Hxcw1y3-lA{Hs}uM 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 yeXPTF;D6**>R)* delta 45980 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 diff --git a/test/bundler/bundler_edgecase.test.ts b/test/bundler/bundler_edgecase.test.ts index d30276f8ec..4baa0d9186 100644 --- a/test/bundler/bundler_edgecase.test.ts +++ b/test/bundler/bundler_edgecase.test.ts @@ -1301,6 +1301,14 @@ describe("bundler", () => { "-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 /* g */", ], }); + // Stack overflow possibility + itBundled("edgecase/AwsCdkLib", { + files: { + "entry.js": `import * as aws from ${JSON.stringify(require.resolve("aws-cdk-lib"))}; aws;`, + }, + target: "bun", + run: true, + }); // TODO(@paperdave): test every case of this. I had already tested it manually, but it may break later const requireTranspilationListESM = [ diff --git a/test/package.json b/test/package.json index 57edda9e72..3008ded2ec 100644 --- a/test/package.json +++ b/test/package.json @@ -14,6 +14,7 @@ "@resvg/resvg-js": "2.4.1", "@swc/core": "1.3.38", "@types/ws": "8.5.10", + "aws-cdk-lib": "2.148.0", "axios": "1.6.8", "body-parser": "1.20.2", "comlink": "4.4.1",