Remove dead code from jsc FFI glue, C++ bindings, bun_core, http_types, and bunfig

Closed
RO
3mo ago
+33-2622

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) uses init + 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 via ZigString__freeGlobal, which stays)
  • Zig__GlobalObject__reportUncaughtException: exported fn with no C++ caller; the internal safe wrapper report_uncaught_exception stays
  • AbortSignal__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 uses Resolver__nodeModulePathsJSValue)

C++ bindings

  • The JSCommonJSExtensions::m_registeredFunctions vector 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 duplicating s(), zero callers (the Raw struct stays, it is constructed via s)
  • The schema wrapper module in lib.rs: zero users; everyone imports the flattened bun_core::StringPointer
  • NAPI_MODULE_REGISTER feature 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 updated
  • FrameType::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 in done()
  • image/mod.rs: trimmed the flattened re-export list to the two names actually addressed via crate::image:: (Image, AsyncImageTask)

options / bunfig

  • The write-only [bundle].packages cluster: BundlePackage enum, 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 -w for every symbol across src/, scripts/, cmake/, and regenerated build/debug/codegen: zero references outside the definition sites
  • bun run rust:check-all: 10/10 triples pass (this caught and reverted two candidates that grep missed: zig_hash_map keys/values_mut used inside the allow(dead_code) h2 file, and file_poll::Pollable used by the darwin ParentDeathWatchdog path)
  • Full bun bd debug 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::editor and DebugOptions::output_file are write-only (bunfig [debug].editor and --output-file parse into them, nothing reads them); they look like unported feature hooks rather than leftovers, so they are flagged here instead of deleted
  • bun_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)