refactor(rust): eliminate 57 borrowck-workaround allocs and unsafe launders
Bucket B of the reshaped for borrowck cleanup: 57 sites with simple local fixes (<10 lines each, no signature changes needed except one vestigial &mut, no new fields). Brings the count from 368 to 311.
What changed
Entry-API double-lookups (6 sites): get() + insert() collapsed into a single entry()/get_or_put() where the map API supports it (fold.rs both arms, snapshot.rs). Three sites (WorkspacePackageJSONCache, SavedSourceMap, runTasks:544) keep the two-step shape because an entry borrow cannot span the intervening read/parse/directory call; comment updated to say why.
Allocation drops (31 sites):
&[Chunk]instead of&mut [Chunk]forappend_isolated_hashes_for_imported_chunks(read-only recursion):LinkerContextboth loops become plain iteration- index + re-borrow per iteration instead of
.collect():computeChunks,yarn,PackageManagerEnqueue:111 mem::take+ restore instead of.clone()/.to_vec():computeCrossChunkDependencies,repl::handle_enter,IOReaderboth callbacks,server_bodysplit_at_mutinstead of prefix.to_vec():braces.rs×3- plain
&[u8]where the borrow was already disjoint:install_with_manager,patchPackage×2,bake/production×2,repl::handle_tab/arrow-keys,bundle_v2:2440 SmallVecwhere a snapshot is required but tiny:h2_frame_parser,IOWriter- inline the value instead of stashing in an owned local:
defines.rs,js_parser/lib.rs,dotenv/env_loader,seq.rs(also deletes the now-deadSeq::buffield),diff_match_patch BackRefinstead of.cloned():visit_stmt.rs(matches the existing pattern invisit/mod.rs)
Three sites keep their allocation because it is required for correctness, with the comment rewritten to explain the hazard instead of reshaped for borrowck:
css/properties/flex.rs:879: basis is emitted twice (shorthand + longhand)PackageManagerEnqueue.rs:995:string_bytesmay reallocate underget_or_put_resolved_package_with_find_resultfilesystem_router.rsbust_dir_cache: the recursive walk races the bundler thread on the process-global entry cache (thereload() while Bun.build()test SIGSEGV'd on aarch64 without the copy)
Raw-pointer launders rewritten to safe Rust (20 sites):
- statement reorder so borrows don't overlap:
BunObject,publish_command,VirtualMachine:4313 - disjoint field borrows:
VirtualMachine:5527,PostgresSQLConnection:2407,MySQLConnection:1705,PostgresSQLConnection:1743 scopeguard::guard(payload, ..)instead of sibling*mutcopy:js_bun_spawn_bindings×2,jsc_hooksusizeaddress-diff for offset math, derive the final pointer from the live slice:resolve_path×2match &mut reqinstead offrom_ref().cast_mut():server/modSmallVec<[u8; 64]>copy instead ofdetach_lifetimeon a package name:runTasks:347- two-step
get/putinstead of holding a*mut u32across&mut self:bundle_v2:2135 - safe loop-invariant hoist instead of
RawSlice:AsyncModule - borrow from the live
self.store()instead of a*const [u8]round-trip:Blob.rs - local-slice reuse instead of
StoreStrarena alloc:lexer.rs - comment-only (code was already idiomatic):
interpreter.rs,ConsoleObject.rs
Dead code: deleting the unused destination_dir binding in PackageInstaller.rs made LazyPackageDestinationDir dead (the remaining caller only ever constructs ::Dir(fd) and get_dir() is infallible for it). The enum and its impl are removed and the single use site reads destination_dir.fd() directly.
Already done on main: KEventWatcher.rs:130 and WindowsWatcher.rs:525 were handled by #35321.
Test: test/internal/source-lints/borrowck-reshape-markers.test.ts pins the marker count at 311 so it only moves down.
Why
Every site was code that paid a runtime cost (an extra heap allocation, a double hash lookup, or an unsafe block) purely to placate the borrow checker at porting time. Each prescribed rewrite here is the idiomatic-Rust shape the code would have been written in directly: disjoint borrows the compiler can already prove, or moving a value instead of cloning it. Net: the hot-path per-iteration allocations from the audit are gone, 20 unsafe launders are replaced with safe equivalents, and the marker comments are removed.
Verification
cargo check --workspaceandbun run rust:check-all(all 10 targets) cleancargo clippyon every touched crate cleanbun bdbuildsrg "reshaped for borrowck" --type rust | wc -l: 368 → 311- Test suites for touched areas pass with no new failures vs main:
brace.test.ts,seq.test.ts,filesystem_router.test.ts,repl.test.ts, node/path,console-table.test.ts,env.test.ts,bun-patch.test.ts, snapshot tests, bundler edgecase/minify/splitting/html/cjs2esm, shell suite
[review] gate passed · iteration 9 · 40 files touched
fails on main (without fix)
ASAN without fix: 1 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/internal/source-lints/borrowck-reshape-markers.test.ts
bun test v1.4.0 (c411f3108)
test/internal/source-lints/borrowck-reshape-markers.test.ts:
47 | throw new Error(
48 | `Found ${count} 'reshaped for borrowck' markers in src/**/*.rs, up from ${LIMIT}.\n` +
49 | `Prefer the idiomatic Rust form over adding a new workaround; if unavoidable, bump LIMIT in this file.\n` +
50 | `First ${sample.length}:\n` +
51 | sample.map(l => ` ${l}`).join("\n"),
52 | );
^
error: Found 342 'reshaped for borrowck' markers in src/**/*.rs, up from 293.
Prefer the idiomatic Rust form over adding a new workaround; if unavoidable, bump LIMIT in this file.
First 20:
src/bundler/bundle_v2.rs:1132
src/bundler/bundle_v2.rs:1265
src/bundler/bundle_v2.rs:1892
src/bundler/bundle_v2.rs:1901
src/bundler/bundle_v2.rs:1963
src/bundler/bundle_v2.rs:1968
src/bundler/bundle_v2.rs:1999
src/bundler/bundle_v2.rs:2070
src/bundler/bundle_v2.rs:2115
src/bundler/bundle_v2.rs:2135
src/bundler/bundle_v2.rs:22
... (truncated)
release without fix: 1 FAILED
bun test v1.4.0-canary.1 (1498d7b77)
test/internal/source-lints/borrowck-reshape-markers.test.ts:
47 | throw new Error(
48 | `Found ${count} 'reshaped for borrowck' markers in src/**/*.rs, up from ${LIMIT}.\n` +
49 | `Prefer the idiomatic Rust form over adding a new workaround; if unavoidable, bump LIMIT in this file.\n` +
50 | `First ${sample.length}:\n` +
51 | sample.map(l => ` ${l}`).join("\n"),
52 | );
^
error: Found 342 'reshaped for borrowck' markers in src/**/*.rs, up from 293.
Prefer the idiomatic Rust form over adding a new workaround; if unavoidable, bump LIMIT in this file.
First 20:
src/bundler/bundle_v2.rs:1132
src/bundler/bundle_v2.rs:1265
src/bundler/bundle_v2.rs:1892
src/bundler/bundle_v2.rs:1901
src/bundler/bundle_v2.rs:1963
src/bundler/bundle_v2.rs:1968
src/bundler/bundle_v2.rs:1999
src/bundler/bundle_v2.rs:2070
src/bundler/bundle_v2.rs:2115
src/bundler/bundle_v2.rs:2135
src/bundler/bundle_v2.rs:2249
src/bundler/bundle_v2.rs:2440
src/bundler/bundle_v2.rs:6455
src/bundler/Chunk.rs:306
src/bundler/entry_points.rs:158
src/bundler/entry_points.rs:195
src/bundler/linker_c
... (truncated)
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/internal/source-lints/borrowck-reshape-markers.test.ts
bun test v1.4.0 (c411f3108)
test/internal/source-lints/borrowck-reshape-markers.test.ts:
(pass) 'reshaped for borrowck' markers are at or below the ratchet (293) [11.31ms]
1 pass
0 fail
1 expect() calls
Ran 1 test across 1 file. [84.34s]
__F:0:S:0
release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped)
target linux-x64-gnu
build type Release
build dir ./build/release
revision c411f31081
features baseline
22 deps, 108 codegen, 1170 objects in 3739ms
ninja: Entering directory `/workspace/bun/build/release'
[1/1233] install /workspace/bun
bun install v1.4.0-canary.1 (1498d7b77)
Checked 124 installs across 170 packages (no changes) [85.00ms]
[2/1233] gen ErrorCode+*.h
[3/1233] gen ProcessBindingConstants.lut.h
Generating /workspace/bun/build/release/codegen/ProcessBindingConstants.lut.h from /workspace/bun/src/jsc/bindings/ProcessBindingConstants.cpp
[4/1233] install /workspace/bun/packages/bun-error
bun install v1.4.0-canary.1 (1498d7b77)
Checked 1 install across 2 packages (no changes) [2.00ms]
[5/1233] fetch zlib
[zlib] up to date
[6/1233] install /workspace/bun/src/node-fallbacks
bun install v1.4.0-canary.1 (1498d7b77)
Checked 129 installs across 147 packages (no changes) [21.00ms]
[7/1233] gen bindgenv2
[8/1233] fetch picohttpparser
[picohttpparser] up to date
[9/1233] fetch tinycc
[tinycc] up to date
[10/1233] subst deps/zlib/zconf.h
[11/1233] f
... (truncated)
diff hotspot
src/bundler/LinkerContext.rs | 122 +++++++++------------
src/bundler/bundle_v2.rs | 45 +++-----
src/bundler/linker_context/computeChunks.rs | 22 ++--
.../computeCrossChunkDependencies.rs | 7 +-
src/css/properties/flex.rs | 2 +-
src/dotenv/env_loader.rs | 6 +-
src/install/PackageInstaller.rs | 85 +-------------
.../PackageManager/PackageManagerEnqueue.rs | 8 --
.../PackageManager/WorkspacePackageJSONCache.rs | 6 +-
src/install/PackageManager/install_with_manager.rs | 6 +-
src/install/PackageManager/patchPackage.rs | 15 +--
src/install/PackageManager/runTasks.rs | 16 +--
src/js_parser/fold.rs | 65 +++++------
src/js_parser/lexer.rs | 13 +--
src/js_parser/visit/visit_stmt.rs | 14 ++-
src/jsc/AsyncModule.rs | 15 ++-
src/jsc/ConsoleObject.rs | 2 -
src/jsc/SavedSourceMap.rs | 4 -
src/jsc/VirtualMachine.rs | 16 +--
src/paths/resolve_path.rs | 20 +---
src/runtime/api/BunObject.rs | 15 +--
src/runtime/api/bun/h2_frame_parser.rs | 5 +-
src/runtime/api/bun/js_bun_spawn_bindings.rs | 28 ++---
src/runtime/api/filesystem_router.rs | 10 +-
src/runtime/bake/production.rs | 9 +-
src/runtime/cli/publish_command.rs | 22 ++--
src/runtime/cli/repl.rs | 19 ++--
src/runtime/jsc_hooks.rs | 61 +++--------
src/runtime/server/mod.rs | 10 +-
src/runtime/server/server_body.rs | 10 +-
src/runtime/shell/IOReader.rs | 5 +-
src/runtime/shell/IOWr
... (truncated)
gate history · 1 passed · 4 rejected · iteration 9
evidence per changed file
file reads edits tests
src/bundler/LinkerContext.rs 3 2 0
src/bundler/bundle_v2.rs 1 2 0
src/bundler/linker_context/computeChunks.rs 1 0 0
…bundler/linker_context/computeCrossChunkDependencies.rs 3 0 0
src/css/properties/flex.rs 0 0 0
src/dotenv/env_loader.rs 1 0 0
src/install/PackageInstaller.rs 3 3 0
src/install/PackageManager/PackageManagerEnqueue.rs 2 2 0
src/install/PackageManager/WorkspacePackageJSONCache.rs 0 0 0
src/install/PackageManager/install_with_manager.rs 0 0 0
src/install/PackageManager/patchPackage.rs 0 0 0
src/install/PackageManager/runTasks.rs 1 1 0
src/js_parser/fold.rs 1 1 0
src/js_parser/lexer.rs 2 2 0
src/js_parser/visit/visit_stmt.rs 0 0 0
src/jsc/AsyncModule.rs 0 0 0
(+ 24 more files)