Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
c1ca51f
toml: the parser keeps tables and arrays as `StoreRef`
claude Oct 29, 2026
59c10e2
bun_core: remove `boxed_zeroed_unchecked`, `ZStr::boxed` and `Options…
claude Oct 29, 2026
a044535
xml: `Unit::from_u16` and `Unit::from_bytes` instead of casts
claude Oct 29, 2026
cc2d57e
crash_handler: `UNSUPPORTED_UV_FUNCTION` holds the name's bytes
claude Oct 29, 2026
2b35613
xml_index: `StructuralIndex::seek` and `at` read the window with `get`
claude Oct 29, 2026
3e7d3c9
collections: `HiveSlot` borrows its hive
claude Oct 29, 2026
dee9080
bun_core: `vec::extend_from_fn` is `Vec::extend`
claude Oct 29, 2026
a0c8cff
fmt: the shared temp buffer is an `Option<Box>`
claude Oct 29, 2026
ebc36f0
SmolStr: `Inlined::all_chars` views the `u128` with `bytes_of_mut`
claude Oct 29, 2026
a10a006
bun_core: `impl io::Write for Writer` calls the inherent methods
claude Oct 29, 2026
5e10673
atomic_cell: `unreachable!()` for the widths that `Atom` excludes
claude Oct 29, 2026
166a6d2
highway: `memmem` subtracts addresses
claude Oct 29, 2026
a3c759b
Check constant strings at compile time instead of `from_utf8_unchecked`
claude Oct 29, 2026
211f7e9
Call `gettid`, `getpid`, `alarm`, `_exit` and `raise` as `safe fn`
claude Oct 29, 2026
a920067
bun_core: `fd_path_raw_w` takes `&mut [u16]`
claude Oct 29, 2026
27e6eeb
output: `STDOUT_STREAM` and `STDERR_STREAM` are atomics
claude Oct 29, 2026
fe10856
resolver: `BrowserMapPath::map` is `&'static BrowserMap`
claude Oct 29, 2026
8c348de
resolver: keep the slot that `MaybeUninit::write` returns
claude Oct 29, 2026
0270bca
resolver: drop three lifetime casts that change nothing
claude Oct 29, 2026
24176a7
resolver: `RealFS::read_directory` and `EntryLookup` keep their `'sta…
claude Oct 29, 2026
5980510
http: `h3::ClientContext::get_or_create` reads the loop itself
claude Oct 29, 2026
80e3575
boringssl: `ssl_ctx_setup` takes `&OwnedSslCtx`
claude Oct 29, 2026
6319e52
sourcemap: `impl_pod!` for `SyncEntry` and `ObjectBrace`
claude Oct 29, 2026
8f2ec5d
sourcemap: `WindowReader<'a>` borrows the stream
claude Oct 29, 2026
e1644df
resolver: four `unsafe` blocks that plain borrows replace
claude Oct 29, 2026
895e0e0
resolver: `package_json` travels as `&'static PackageJSON`
claude Oct 29, 2026
160dad7
resolver: `load_tsconfig` keeps its boxes
claude Oct 29, 2026
00fc417
resolver: `BIN_FOLDERS` is initialised at compile time
claude Oct 29, 2026
3a7a349
standalone_graph: in `inject`, `zname` borrows `zname_owned`
claude Oct 29, 2026
6bf6c28
sourcemap: `ParsedSourceMap` holds the standalone graph's sources by …
claude Oct 29, 2026
4dea31f
http: `InitOpts::abs_ca_file_name` is a `&'static ZStr`
claude Oct 29, 2026
b0116e4
exe_format: `_mh_execute_header` is a `safe static`
claude Oct 29, 2026
91cb2a9
install: `init` reborrows the `&'static mut DirEntry` it matched on
claude Oct 29, 2026
2d599ab
install: `save_lockfile` uses `progress.root` instead of a stashed no…
claude Oct 29, 2026
f55e016
install: drop four raw-pointer and lifetime detours that borrowck doe…
claude Oct 29, 2026
dda35a9
install: `find_workspace_root_above` borrows `walk.path` for the sour…
claude Oct 29, 2026
2b5a192
install: `AutoInstaller::path_for_resolution` takes `&mut PathBuffer`
claude Oct 29, 2026
f14394f
install: `NetworkTask` reads its manager through the `ParentRef` it s…
claude Oct 29, 2026
663b8a5
install: remove three one-line `unsafe` blocks that have a safe spelling
claude Oct 29, 2026
129afdb
install: clear `root_lifecycle_scripts` with a `scopeguard` on `manager`
claude Oct 29, 2026
0dc4f19
semver: delete `query::Group.input`
claude Oct 29, 2026
44a3f88
install: `UpdateRequest.e_string` keeps the `StoreRef` it is made from
claude Oct 29, 2026
b1fc886
install: `TarballStream::init` returns a `Box` and `populate_result` …
claude Oct 29, 2026
6986eeb
install: the Windows hardlink task is passed and reclaimed as a `Box`
claude Oct 29, 2026
ba8ec80
install: the Windows `Hardlinker` keeps the cwd slice it gets
claude Oct 29, 2026
f418a47
install: `ROOT_PACKAGE_JSON_PATH` becomes `PackageManager::root_packa…
claude Oct 29, 2026
5dadab2
install: `Diff::generate` takes `to_update: bool` instead of the upda…
claude Oct 29, 2026
a7f1fa0
install: `Package::parse_from_real_manager` takes `&mut PackageManager`
claude Oct 29, 2026
12b39ec
install: in `init`, `original_cwd` borrows the boxed copy of the cwd
claude Oct 29, 2026
e31083d
install: remove two pieces of dead code that needed `unsafe`
claude Oct 29, 2026
5d85c2a
xml_index: `seek_refill` calls `at` for every index, as it did
claude Oct 29, 2026
0ce5584
resolver: `EntriesOption::try_entries_mut` returns the listing or the…
claude Oct 29, 2026
45884ed
test: `custom-accessor-reached-computed-key.ir` allows one more membe…
claude Oct 30, 2026
b9d7f3a
test: record the growth in memory of one shape of build-scaling, as #…
claude Oct 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions src/boringssl/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,17 @@ std::thread_local! {
}

/// Install the per-thread `CRYPTO_BUFFER_POOL`.
///
/// # Safety
/// `ctx` must be a live `SSL_CTX*`.
pub unsafe fn ssl_ctx_setup(ctx: *mut boring::SSL_CTX) {
pub fn ssl_ctx_setup(ctx: &boring::OwnedSslCtx) {
AUTO_CRYPTO_BUFFER_POOL.with(|pool| {
// SAFETY: caller guarantees `ctx` is a live `SSL_CTX*`; the pool pointer
// SAFETY: `ctx` owns a reference, so it is a live `SSL_CTX*`; the pool pointer
// is either freshly returned by `CRYPTO_BUFFER_POOL_new` or a previously
// stored thread-local pool.
// stored thread-local pool. The pool is never freed; `OwnedSslCtx` is
// `!Send + !Sync`, so no other thread reads `ctx->pool` during the store.
unsafe {
if pool.get().is_null() {
pool.set(CRYPTO_BUFFER_POOL_new());
}
SSL_CTX_set0_buffer_pool(ctx, pool.get());
SSL_CTX_set0_buffer_pool(ctx.as_ptr(), pool.get());
}
});
}
Expand Down
5 changes: 2 additions & 3 deletions src/bun_core/atomic_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,8 @@ macro_rules! size_dispatch {
let $a = unsafe { &*($p as *const $A) };
$body
}
// SAFETY: `unsafe_impl_atom!`'s `const _` assert rejected every
// other width at compile time.
_ => unsafe { ::core::hint::unreachable_unchecked() },
// `unsafe_impl_atom!`'s `const _` assert rejects every other width.
_ => unreachable!(),
}
};
}
Expand Down
12 changes: 8 additions & 4 deletions src/bun_core/bounded_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,7 @@ type Length = usize;

impl<T, const BUFFER_CAPACITY: usize> Default for BoundedArrayAligned<T, BUFFER_CAPACITY> {
fn default() -> Self {
Self {
buffer: [const { MaybeUninit::uninit() }; BUFFER_CAPACITY],
len: 0,
}
Self::new()
}
}

Expand All @@ -67,6 +64,13 @@ impl<T, const BUFFER_CAPACITY: usize> Drop for BoundedArrayAligned<T, BUFFER_CAP
}

impl<T, const BUFFER_CAPACITY: usize> BoundedArrayAligned<T, BUFFER_CAPACITY> {
pub const fn new() -> Self {
Self {
buffer: [const { MaybeUninit::uninit() }; BUFFER_CAPACITY],
len: 0,
}
}

/// Set the actual length of the slice.
/// Returns error.Overflow if it exceeds the length of the backing array.
pub(crate) fn init(len: usize) -> Result<Self, OverflowError> {
Expand Down
6 changes: 2 additions & 4 deletions src/bun_core/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,8 @@ impl MemoryAccessor {
match self.mem {
-2 => break,
-1 => {
// SAFETY: getpid has no preconditions. Don't cache across
// calls — it's served from the vDSO and a stale cache after
// fork() would target the wrong process.
let pid = unsafe { libc::getpid() };
// Not cached: after fork() a stale pid would target the wrong process.
let pid = crate::output::getpid();
let local = libc::iovec {
iov_base: buf.as_mut_ptr().cast(),
iov_len: buf.len(),
Expand Down
21 changes: 1 addition & 20 deletions src/bun_core/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub const SHOW_CRASH_TRACE: bool = IS_DEBUG || IS_TEST || ENABLE_ASAN;
pub const REPORTED_NODEJS_VERSION: &str = build_options::REPORTED_NODEJS_VERSION;
pub const GIT_SHA: &str = build_options::SHA;
pub const GIT_SHA_SHORT: &str = if !build_options::SHA.is_empty() {
const_str_slice(build_options::SHA, 0, 9)
build_options::SHA.split_at(9).0
} else {
""
};
Expand Down Expand Up @@ -209,22 +209,3 @@ pub const ARCH: Architecture = if IS_WASM {
} else {
panic!("Please add your architecture to the Architecture enum")
};

// Helper for const &str slicing (Rust stable lacks const range indexing on str).
const fn const_str_slice(s: &'static str, start: usize, end: usize) -> &'static str {
// `[u8]::split_at` and `str::from_utf8` are both `const` on stable, so the
// sub-slice + UTF-8 check happens entirely at compile time without raw
// pointer arithmetic.
//
// ALLOWED `core::str::from_utf8`: this is the ONE permitted call site in
// the codebase. simdutf is the runtime validator (`bun_core::strings::
// {is_valid_utf8, str_utf8}`); `const fn` cannot call FFI, and this body
// const-evals at compile time only (git-SHA slicing).
let (head, _) = s.as_bytes().split_at(end);
let (_, sub) = head.split_at(start);
match core::str::from_utf8(sub) {
Ok(s) => s,
// Unreachable for git-SHA inputs (hex ASCII); fail the const-eval if not.
Err(_) => panic!("const_str_slice: not at a UTF-8 boundary"),
}
}
184 changes: 65 additions & 119 deletions src/bun_core/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

use core::cell::Cell;
use core::fmt::{self, Display, Formatter, Write as _};
use core::ptr::NonNull;

use crate::output as Output;
// `strings` is the canonical `crate::strings` (lib.rs); `js_printer`/`js_lexer`
Expand Down Expand Up @@ -505,129 +504,76 @@ pub fn substitute_named(template: &[u8], args: &[(&[u8], &[u8])]) -> Vec<u8> {

type SharedTempBuffer = [u8; 32 * 1024];

struct SharedTempBufferSlot(Cell<Option<NonNull<SharedTempBuffer>>>);
impl Drop for SharedTempBufferSlot {
fn drop(&mut self) {
if let Some(p) = self.0.take() {
// SAFETY: produced by `heap::alloc_nn` in `SharedTempBufferBorrow::
// new` and parked here on borrow drop; the thread is exiting so no
// outstanding borrow holds it.
unsafe { crate::heap::destroy(p.as_ptr()) };
}
}
}
impl core::ops::Deref for SharedTempBufferSlot {
type Target = Cell<Option<NonNull<SharedTempBuffer>>>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
thread_local! {
static SHARED_TEMP_BUFFER_PTR: SharedTempBufferSlot =
const { SharedTempBufferSlot(Cell::new(None)) };
}

/// RAII borrow of the thread-local shared temp buffer.
///
/// On construction: takes (or allocates) the buffer and nulls the thread-local
/// cell so any recursive borrow allocates a fresh one instead of aliasing this
/// one. On drop: restores the buffer to the cell, or frees it if recursion has
/// already restored a different buffer.
struct SharedTempBufferBorrow {
ptr: NonNull<SharedTempBuffer>,
static SHARED_TEMP_BUFFER: Cell<Option<Box<SharedTempBuffer>>> = const { Cell::new(None) };
}

impl SharedTempBufferBorrow {
fn new() -> Self {
let ptr = SHARED_TEMP_BUFFER_PTR.with(|cell| {
cell.take()
.unwrap_or_else(|| crate::heap::alloc_nn([0u8; 32 * 1024]))
});
Self { ptr }
}

#[inline]
fn chunk(&mut self) -> &mut SharedTempBuffer {
// SAFETY: this borrow uniquely owns the buffer for its lifetime; the
// thread-local cell was nulled on construction so recursion cannot alias it.
unsafe { self.ptr.as_mut() }
}
}

impl Drop for SharedTempBufferBorrow {
fn drop(&mut self) {
SHARED_TEMP_BUFFER_PTR.with(|c| {
if let Some(existing) = c.get() {
if existing != self.ptr {
// Recursion restored a different buffer; free ours.
// SAFETY: ptr was allocated via heap::alloc_nn and is uniquely owned by self.
unsafe { crate::heap::destroy(self.ptr.as_ptr()) };
}
} else {
c.set(Some(self.ptr));
}
});
}
/// Lends `f` the thread's temp buffer. The cell is empty meanwhile, so a recursive call allocates its own.
fn with_shared_temp_buffer(f: impl FnOnce(&mut SharedTempBuffer) -> fmt::Result) -> fmt::Result {
let mut buffer = SHARED_TEMP_BUFFER
.with(|cell| cell.take())
.unwrap_or_else(crate::boxed_zeroed);
let result = f(&mut buffer);
// Frees the buffer that a recursive call has put back.
SHARED_TEMP_BUFFER.with(|cell| cell.set(Some(buffer)));
result
}

// ───────────────────────────────────────────────────────────────────────────
// UTF-16 formatting
// ───────────────────────────────────────────────────────────────────────────

pub fn format_utf16_type(slice_: &[u16], writer: &mut impl fmt::Write) -> fmt::Result {
let mut borrow = SharedTempBufferBorrow::new();
let chunk = borrow.chunk();

let mut slice = slice_;
with_shared_temp_buffer(|chunk| {
let mut slice = slice_;

while !slice.is_empty() {
let result = strings::copy_utf16_into_utf8(chunk, slice);
if result.read == 0 || result.written == 0 {
break;
while !slice.is_empty() {
let result = strings::copy_utf16_into_utf8(chunk, slice);
if result.read == 0 || result.written == 0 {
break;
}
write_bytes(writer, &chunk[..result.written])?;
slice = &slice[result.read..];
}
write_bytes(writer, &chunk[..result.written])?;
slice = &slice[result.read..];
}
Ok(())
Ok(())
})
}

pub(crate) fn format_utf16_type_with_path_options(
slice_: &[u16],
writer: &mut impl fmt::Write,
opts: PathFormatOptions,
) -> fmt::Result {
let mut borrow = SharedTempBufferBorrow::new();
let chunk = borrow.chunk();

let mut slice = slice_;
with_shared_temp_buffer(|chunk| {
let mut slice = slice_;

while !slice.is_empty() {
let result = strings::copy_utf16_into_utf8(chunk, slice);
if result.read == 0 || result.written == 0 {
break;
}
while !slice.is_empty() {
let result = strings::copy_utf16_into_utf8(chunk, slice);
if result.read == 0 || result.written == 0 {
break;
}

let to_write = &chunk[..result.written];
if !opts.escape_backslashes && opts.path_sep == PathSep::Any {
write_bytes(writer, to_write)?;
} else {
let mut ptr = to_write;
while let Some(i) = crate::strings::index_of_any(ptr, b"\\/") {
let sep = opts.path_sep.apply(ptr[i]);
write_bytes(writer, &ptr[..i])?;
writer.write_char(sep as char)?;
if opts.escape_backslashes && sep == b'\\' {
let to_write = &chunk[..result.written];
if !opts.escape_backslashes && opts.path_sep == PathSep::Any {
write_bytes(writer, to_write)?;
} else {
let mut ptr = to_write;
while let Some(i) = crate::strings::index_of_any(ptr, b"\\/") {
let sep = opts.path_sep.apply(ptr[i]);
write_bytes(writer, &ptr[..i])?;
writer.write_char(sep as char)?;
}
if opts.escape_backslashes && sep == b'\\' {
writer.write_char(sep as char)?;
}

ptr = &ptr[i + 1..];
ptr = &ptr[i + 1..];
}
write_bytes(writer, ptr)?;
}
write_bytes(writer, ptr)?;
slice = &slice[result.read..];
}
slice = &slice[result.read..];
}
Ok(())
Ok(())
})
}

#[inline]
Expand Down Expand Up @@ -1253,28 +1199,28 @@ pub fn parse_ascii<T: core::str::FromStr>(s: &[u8]) -> Option<T> {
// ───────────────────────────────────────────────────────────────────────────

pub fn format_latin1(slice_: &[u8], writer: &mut impl fmt::Write) -> fmt::Result {
let mut borrow = SharedTempBufferBorrow::new();
let chunk = borrow.chunk();
let mut slice = slice_;

while let Some(i) = crate::strings::first_non_ascii_usize(slice) {
if i > 0 {
write_bytes(writer, &slice[..i])?;
slice = &slice[i..];
}
let take = chunk.len().min(slice.len());
let result = strings::copy_latin1_into_utf8(chunk, &slice[..take]);
if result.read == 0 || result.written == 0 {
break;
with_shared_temp_buffer(|chunk| {
let mut slice = slice_;

while let Some(i) = crate::strings::first_non_ascii_usize(slice) {
if i > 0 {
write_bytes(writer, &slice[..i])?;
slice = &slice[i..];
}
let take = chunk.len().min(slice.len());
let result = strings::copy_latin1_into_utf8(chunk, &slice[..take]);
if result.read == 0 || result.written == 0 {
break;
}
write_bytes(writer, &chunk[..result.written])?;
slice = &slice[result.read..];
}
write_bytes(writer, &chunk[..result.written])?;
slice = &slice[result.read..];
}

if !slice.is_empty() {
write_bytes(writer, slice)?; // write the remaining bytes
}
Ok(())
if !slice.is_empty() {
write_bytes(writer, slice)?; // write the remaining bytes
}
Ok(())
})
}

// ───────────────────────────────────────────────────────────────────────────
Expand Down
Loading
Loading