Remove dead code from jsc FFI glue, C++ bindings, bun_core, http_types, and bunfig
Closed
RO
3mo ago+33+33+01234567890123456789-2622-2622-0123456789012345678901234567890123456789
Dead-code sweep across crates not covered by the other open dead-code PRs (#36237, #35775, #36970, #36115, #35437, #35880). Net -2419 lines. Every removal was verified to have zero references across src/, scripts/, and freshly regenerated build/debug/codegen output, then validated by cargo check on all 10 CI target triples and a full debug build.
Removed
bun_jsc FFI glue
DeprecatedStrong::unref: never called; the sole user (test_runner/Collection.rs) usesinit+ Drop only, per the file's own audit note- Unused extern "C" imports
JSCommonJSExtensions__{appendFunction,setFunction,swapRemove}in NodeModuleModule.rs: zero Rust call sites ZigString__free: exported fn whose only cross-reference was its prototype in headers-handwritten.h; no C++ caller (helpers.h frees viaZigString__freeGlobal, which stays)Zig__GlobalObject__reportUncaughtException: exported fn with no C++ caller; the internal safe wrapperreport_uncaught_exceptionstaysAbortSignal__Timeout__run: orphaned wrapper; AbortSignal.cpp calls only__create/__deinit, and the timeout actually fires through the Rust timer dispatch (EventLoopTimerTag::AbortSignalTimeout)Resolver__propForRequireMainPaths: no caller; removed together with its stale extern decl in JSCommonJSModule.cpp (getterPaths usesResolver__nodeModulePathsJSValue)
C++ bindings
- The
JSCommonJSExtensions::m_registeredFunctionsvector mechanism: with the Rust imports above gone, its three extern "C" writers had zero callers, so the member and its GC-visit loop were dead with them (custom require.extensions functions are stored in Rust-side Strongs) - Stale header prototypes for the removed exports in headers.h and headers-handwritten.h
bun_core
fmt::raw: shorthand constructor duplicatings(), zero callers (theRawstruct stays, it is constructed vias)- The
schemawrapper module in lib.rs: zero users; everyone imports the flattenedbun_core::StringPointer NAPI_MODULE_REGISTERfeature counter: never incremented, and bun_analytics has no mapping for it
bun_http_types
mime_type_list.txt(2309 lines): orphan data file fully duplicated by the hand-maintained table in mime_type_list_enum.rs; not read by any build step (absent from cargo dep-info), referenced only by two doc comments, both updatedFrameType::HTTP_FRAME_ALTSVC/HTTP_FRAME_ORIGIN: the enum is used only for outbound frame construction (inbound dispatch is on raw u8 per the file comment) and a client never sends these frames
websocket client
CompressError::OutOfMemory/DecompressError::OutOfMemory: never constructed (compress returns only DeflateFailed; decompress only InflateFailed/TooLarge), plus the unreachable match arm in websocket_client.rs
bun_runtime
ReadableStream::detach_if_possible: no-op vestige whose body was emptied in 85534281c6; removed with its sole call indone()image/mod.rs: trimmed the flattened re-export list to the two names actually addressed viacrate::image::(Image, AsyncImageTask)
options / bunfig
- The write-only
[bundle].packagescluster:BundlePackageenum,DebugOptions::package_bundle_map, the bunfig parse block that populated it, and two re-exports. The map had zero readers; the key is undocumented and now falls through bunfig's per-key lookup like any other unknown key
bun_perf
Timer::lap: existed only in the WASM stub impl; the real Timer never defined it, so no portable caller can exist
Verification
rg -wfor every symbol across src/, scripts/, cmake/, and regenerated build/debug/codegen: zero references outside the definition sitesbun run rust:check-all: 10/10 triples pass (this caught and reverted two candidates that grep missed: zig_hash_mapkeys/values_mutused inside the allow(dead_code) h2 file, andfile_poll::Pollableused by the darwin ParentDeathWatchdog path)- Full
bun bddebug build passes - Smoke tests pass: require-extensions (43), websocket permessage-deflate + abort (10), web streams (161), bunfig options (5)
Noted but not removed
- The legacy inbound half of h2_frame_parser.rs (~1770 lines) is provably unreachable, but the file header documents it as intentionally parked until the outbound h2 migration lands, so it is left for that migration to delete
DebugOptions::editorandDebugOptions::output_fileare write-only (bunfig[debug].editorand--output-fileparse into them, nothing reads them); they look like unported feature hooks rather than leftovers, so they are flagged here instead of deletedbun_resolver::Error::{MissingResolveDir,InvalidResolveDir}are never constructed, but the surrounding commented-out block is an intentional TODO referencing #8994
[review] gate passed · iteration 1 · 34 files touched
fails on main (without fix)
ASAN without fix: 3 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/dead-symbols-jsc-http-core.test.ts
bun test v1.4.0 (2b0a08d92)
test/internal/source-lints/dead-symbols-jsc-http-core.test.ts:
63 | ["src/jsc/JSGlobalObject.rs", /\bZig__GlobalObject__reportUncaughtException\b/],
64 | ["src/jsc/AbortSignal.rs", /\bAbortSignal__Timeout__run\b/],
65 | ["src/jsc/resolver_jsc.rs", /\bResolver__propForRequireMainPaths\b/],
66 | ];
67 | for (const [file, re] of checks) {
68 | expect(src(file)).not.toMatch(re);
^
error: expect(received).not.toMatch(expected)
Expected substring or pattern: not /pub fn unref\b/
Received: "#[cfg(debug_assertions)]\nuse core::mem::ManuallyDrop;\n#[cfg(debug_assertions)]\nuse core::ptr::NonNull;\n\nuse crate::JSValue;\n\n// Refcount contract (load-bearing): `ref()`/`unref()` calls must be balanced\n// in pairs; Drop is the release for the `init()` protect. In debug builds a\n// final `unref()` (ref_count 1 → 0) additionally frees the canary, zeroes\n// `raw`, and clears `_safety` so a subsequent Drop
... (truncated)
release without fix: 3 FAILED
bun test v1.4.0-canary.1 (830d03788)
test/internal/source-lints/dead-symbols-jsc-http-core.test.ts:
63 | ["src/jsc/JSGlobalObject.rs", /\bZig__GlobalObject__reportUncaughtException\b/],
64 | ["src/jsc/AbortSignal.rs", /\bAbortSignal__Timeout__run\b/],
65 | ["src/jsc/resolver_jsc.rs", /\bResolver__propForRequireMainPaths\b/],
66 | ];
67 | for (const [file, re] of checks) {
68 | expect(src(file)).not.toMatch(re);
^
error: expect(received).not.toMatch(expected)
Expected substring or pattern: not /pub fn unref\b/
Received: "#[cfg(debug_assertions)]\nuse core::mem::ManuallyDrop;\n#[cfg(debug_assertions)]\nuse core::ptr::NonNull;\n\nuse crate::JSValue;\n\n// Refcount contract (load-bearing): `ref()`/`unref()` calls must be balanced\n// in pairs; Drop is the release for the `init()` protect. In debug builds a\n// final `unref()` (ref_count 1 → 0) additionally frees the canary, zeroes\n// `raw`, and clears `_safety` so a subsequent Drop is a no-op. Release builds\n// have no ref_count, so an unref-used-as-release followed by Drop would\n// double-unprotect — callers must never use `unref()` as the release.\n// (Audite
... (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/dead-symbols-jsc-http-core.test.ts
bun test v1.4.0 (2b0a08d92)
test/internal/source-lints/dead-symbols-jsc-http-core.test.ts:
(pass) dead Rust symbols (bun_jsc FFI glue) do not reappear [18.97ms]
(pass) dead Rust symbols (bun_core, http_types, websocket, webcore, perf) do not reappear [13.21ms]
(pass) write-only [bundle].packages bunfig cluster does not reappear [6.77ms]
(pass) dead C++ symbols and stale header prototypes do not reappear (HEAD) [27.36ms]
(pass) orphan data file stays deleted (HEAD) [488.42ms]
5 pass
0 fail
24 expect() calls
Ran 5 tests across 1 file. [2.69s]
__F:0:S:0
release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 675ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[1/124] gen generated_host_exports.rs
generated_host_exports.rs: 92 exports (host=3, lazy=10, generic=79, rust=0); 238 extern-C blocks audited
[2/124] gen cpp.rs (cppbind)
[2/124] cargo bun_bin → libbun_rust.a (--target x86_64-unknown-linux-gnu)
nightly-2026-07-20-x86_64-unknown-linux-gnu unchanged - rustc 1.99.0-nightly (9f36de775 2026-07-19)
^[[1m^[[92m Compiling^[[0m bun_core v0.0.0 (/workspace/bun/src/bun_core)
^[[1m^[[92m Compiling^[[0m bun_errno v0.0.0 (/workspace/bun/src/errno)
^[[1m^[[92m Compiling^[[0m bun_ptr v0.0.0 (/workspace/bun/src/ptr)
^[[1m^[[92m Compiling^[[0m bun_boringssl_sys v0.0.0 (/workspace/bun/src/boringssl_sys)
^[[1m^[[92m Compiling^[[0m bun_safety v0.0.0 (/workspace/bun/src/safety)
^[[1m^[[92m Compiling^[[0m bun_zlib_sys v0.0.0 (/workspace/bun/src/zlib_sys)
^[[1m^[[92m Compiling^[[0m bun_cares_sys v0.0.0 (/workspace/bun/src/cares_sys)
^[[1m^[[92m Compiling^[[0m bun_zstd v0.0.0 (/workspace/bun/src/zstd)
^[[1m^[[92m Compiling^[[0m bun_picohttp v0.0.0 (/workspace/bun/src/picohttp)
^[[1m^[
... (truncated)
diff hotspot
src/bun_core/Global.rs | 2 +-
src/bun_core/fmt.rs | 8 +-
src/bun_core/lib.rs | 8 -
src/bundler/options.rs | 2 -
src/bunfig/bunfig.rs | 51 -
src/http_jsc/websocket_client.rs | 1 -
src/http_jsc/websocket_client/WebSocketDeflate.rs | 4 -
src/http_types/MimeType.rs | 3 +-
src/http_types/h2.rs | 4 -
src/http_types/mime_type_list.txt | 2310 --------------------
src/http_types/mime_type_list_enum.rs | 2 +-
src/jsc/AbortSignal.rs | 9 -
src/jsc/DeprecatedStrong.rs | 58 +-
src/jsc/JSGlobalObject.rs | 11 -
src/jsc/NodeModuleModule.rs | 18 -
src/jsc/ZigString.rs | 24 -
src/jsc/bindings/JSCommonJSExtensions.cpp | 47 -
src/jsc/bindings/JSCommonJSExtensions.h | 9 +-
src/jsc/bindings/JSCommonJSModule.cpp | 2 -
src/jsc/bindings/headers-handwritten.h | 2 -
src/jsc/bindings/headers.h | 1 -
src/jsc/resolver_jsc.rs | 8 -
src/options_types/bundle_enums.rs | 7 -
src/options_types/context.rs | 2 -
src/options_types/lib.rs | 4 +-
src/perf/system_timer.rs | 8 +-
src/resolver/resolver.rs | 3 +-
src/runtime/image/mod.rs | 5 +-
src/runtime/server/RequestContext.rs | 10 +-
src/runtime/webcore/Blob.rs | 4 +-
src/runtime/webcore/Body.rs | 2 +-
src/runtime/webcore/FileSink.rs | 6 +-
... (truncated)
gate history · 7 passed · 0 rejected · iteration 1
evidence per changed file
file reads edits tests
src/bun_core/Global.rs 1 1 0
src/bun_core/fmt.rs 2 3 0
src/bun_core/lib.rs 1 1 0
src/bundler/options.rs 1 1 0
src/bunfig/bunfig.rs 1 1 0
src/http_jsc/websocket_client.rs 1 2 0
src/http_jsc/websocket_client/WebSocketDeflate.rs 1 1 0
src/http_types/MimeType.rs 1 2 0
src/http_types/h2.rs 1 1 0
src/http_types/mime_type_list.txt 0 0 0
src/http_types/mime_type_list_enum.rs 1 1 0
src/jsc/AbortSignal.rs 1 1 0
src/jsc/DeprecatedStrong.rs 4 5 0
src/jsc/JSGlobalObject.rs 1 1 0
src/jsc/NodeModuleModule.rs 2 3 0
src/jsc/ZigString.rs 1 1 0
(+ 18 more files)