This commit is contained in:
Erik Dunteman
2024-07-05 21:15:30 -07:00
28 changed files with 483 additions and 133 deletions

View File

@@ -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)" `

View File

@@ -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()

Binary file not shown.

View File

@@ -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",

View File

@@ -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();

View File

@@ -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",

View File

@@ -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", <sha>
```

View File

@@ -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 <sys/uio.h>
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.

View File

@@ -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 <sys/syscall.h>
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();

View File

@@ -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; }

View File

@@ -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 <BaseTsd.h>
typedef SSIZE_T ssize_t;
#else
#include <stdalign.h>
#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);

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -461,10 +461,7 @@ static inline JSC::EncodedJSValue jsDOMFormDataPrototypeFunction_set2Body(JSC::J
auto name = convert<IDLUSVString>(*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<IDLUSVString>(*lexicalGlobalObject, argument2.value());
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
RefPtr<Blob> blobValue = nullptr;
if (argument1.value().inherits<JSBlob>()) {
@@ -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<IDLUSVString>(*lexicalGlobalObject, argument2.value());
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
RELEASE_AND_RETURN(throwScope, JSValue::encode(toJS<IDLUndefined>(*lexicalGlobalObject, throwScope, [&]() -> decltype(auto) { return impl.set(WTFMove(name), WTFMove(blobValue), WTFMove(filename)); })));
}

View File

@@ -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 },
});

View File

@@ -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("<r>${typeName}<d>.<r>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("<r>${typeName}<d>.<r>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("<r>${typeName}<d>.<r>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("<r>${typeName}<d>.<r>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.

View File

@@ -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 = {}) {

View File

@@ -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) },

View File

@@ -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 },
@@ -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 => {
@@ -2560,7 +2607,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 },
@@ -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;
}
}

View File

@@ -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 },

View File

@@ -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 },
});

View File

@@ -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 },

Binary file not shown.

View File

@@ -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 = [

View File

@@ -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);
});

View File

@@ -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);
});
});

View File

@@ -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",