Remove dead code from bun-uws, the native BufferList class, and built-in JS

Closed
RO
3mo ago
+26-2372

Problem

  • No user-visible behavior changes. About 2,058 lines across bun-uws, the native JSBufferList binding, the built-in JS modules and two Rust extern "C" exports have no remaining reference on main.
  • packages/bun-uws had never been swept: it is header templates, so the linker-based sweep in #37454 could not see members that are never instantiated.
  • Two bun-uws layoutAssert() helpers were never called, so their static_asserts never ran. The WebSocket one guards a layout that WebSocket::getContextData() really depends on.

Fix

  • Deletes the unreferenced headers, template members, JSBufferList, JS declarations and helpers, and the two Rust exports. The property to check: each removed item has zero references in src/, packages/, scripts/, test/ and codegen output, so nothing that runs today can change.
  • bun-uws members were checked by hand against every file that includes each header. The extern "C" candidates were also checked against vendor/ and the prebuilt WebKit symbol tables, which is what kept Bun__thisThreadHasVM and WTFTimer__* in place.
  • The WebSocket layout check becomes a RELEASE_ASSERT in WebSocketContext::create(), so it now runs once per context in every build. The HttpContext one guarded nothing and is dropped.
  • Verification: bun bd builds, the preprocessed PerMessageDeflate.h is byte-identical, the websocket, http, http3, quic, stream and repl tests pass (the few local failures fail the same way on main), and a new source lint fires on main for every removed file and symbol and passes here.

Background

  • packages/bun-uws is Bun's fork of uWebSockets, the C++ HTTP and WebSocket server behind Bun.serve. It is header templates; Bun reaches it through the C shim in src/uws_sys/ and a few bindings files, so those includers are the complete set of callers.
  • A member of a class template that is never called is never instantiated, so it is never compiled or linked. Linker-based dead-code tools cannot see it, and a static_assert inside it never runs.
  • WebSocket::getContextData() finds the context's data by pointer arithmetic from the socket group (group first, data immediately after) so that WebSocket.h need not include WebSocketContext.h. offsetof cannot express this because the struct is not standard-layout, hence a runtime assert.
  • JSBufferList was a native buffer list for Node-style streams; the JS streams implementation replaced it, and the only remaining mention is a comment.
  • test/internal/source-lints/ holds tests that read the source tree instead of the built binary. The new one lists every removed file and symbol, so a revert or a fresh upstream import shows up as a failing test.
Original description

Removes 2,050 lines of code that nothing references (plus the 322-line packages/bun-uws/misc/ directory of upstream README assets), with 26 lines added (one assertion, a rewritten import, comment fixes). No behavior change: every removed item is unreferenced today on main, and the build passes without it.

This run deliberately picked areas none of the 18 open dead-code PRs touch. packages/bun-uws had never been swept: it is header templates, so the recent linker-based sweep (#37454) could not see uninstantiated members, and each candidate below was checked by hand against every file that includes the header (the other bun-uws headers, src/uws_sys/libuwsockets*.cpp, and the eight bindings files that include App.h/Http3*.h). JSBufferList was noted as verified-dead but left for its own PR in #37181.

Removed

bun-uws (packages/bun-uws/src, -870)

  • Whole headers nothing includes: ClientApp.h, HttpError.h (superseded by HttpErrors.h), Multipart.h and MessageParser.h (its only includer), ProxyParser.h (only reachable under UWS_WITH_PROXY, which no build defines; verified against compile_commands.json and scripts/build), plus every #ifdef UWS_WITH_PROXY block and the reserved/proxyParser parameters whose only purpose was to carry the proxy parser into getHeaders()
  • WebSocketBehavior::subscription and subscriptionHandler: the only place a WebSocketBehavior is built (uws_ws() in the C shim) never sets it, so every dispatch site in WebSocket::end/subscribe/unsubscribe and WebSocketContext::onClose was unreachable; TopicTree::unsubscribe drops the newCount that only those sites read
  • HttpRequest: the per-route std::map of parameter offsets (setParameterOffsets, getParameter(name); every caller uses the index overload), getQuery() with no key, isShortRead, notFieldNameWord/hasMore/hasBetween (unused since the v20.62 parser upgrade), and the now unused <map> includes
  • HttpContext::HTTP_IDLE_TIMEOUT_S, HttpFlags::isAuthorized (the live flag is the per-socket one in AsyncSocketData), HttpResponse::getHttpResponseDataS, HttpResponse::endWithoutBody, HttpResponse::overrideWriteOffset (byte-identical to setWriteOffset, which is what the shim calls)
  • App: publish(unsigned char), listen(host, port, handler), listen(handler, path, options), the UWS_NO_ZLIB block; H3App: the two listen overloads the shim does not use; Http3Request::isAncient/getCaseSensitiveMethod; Http3Response::setWriteOffset/uncork/isCorked/close/getNativeHandle/isConnectRequest/setTimeout/resetTimeout/prepareForSendfile (the matching uws_h3_res_* shims are stubs that do not call them); the write-only Http3ResponseData::totalSize
  • Loop::integrate, Loop::setSilent and the LoopData::noMark flag it wrote, a stray us_timer_t forward declaration
  • PerMessageDeflate.h: the UWS_NO_ZLIB/UWS_MOCK_ZLIB mock streams and the UWS_USE_LIBDEFLATE guards (the macro is defined unconditionally three lines above its first use). The preprocessed output of the header is identical before and after.
  • HttpContext::layoutAssert() and WebSocketContext::layoutAssert() were never called, and as static members of class templates their static_asserts were never instantiated. Instantiating them does not compile either (offsetof on a non-standard-layout type is an error under -Werror). The HttpContext one guarded nothing (fromSocket round-trips the ext pointer), so it is simply removed; the WebSocketContext one guards the layout WebSocket::getContextData() really depends on, so it becomes a RELEASE_ASSERT in create() (the layout can differ per ABI and only debug/asan builds enable ASSERT; it runs once per context).
  • misc/ (READMORE.md, three PNGs, logo.svg, demo cert.pem/key.pem): referenced by nothing in the repo; also drops the .gitattributes line for a fuzzing/ directory that no longer exists

Native BufferList (src/jsc/bindings, -641)

  • JSBufferList.cpp/.h and their ZigGlobalObject lazy structure, the three accessors, and the DOMIsoSubspaces/DOMClientIsoSubspaces slots. The JS streams implementation replaced it long ago; the only remaining mention of "BufferList" in the tree is a comment in internal/streams/readable.ts.

Built-in JS (src/js, -520)

  • internal/util/inspect.d.ts (ambient types for node-inspect-extracted, which nothing imports; the one JSDoc @type referring to it in node/util.ts goes too) and src/js/.gitignore (ignores src/js/out, which codegen has not written to since the build moved under build/)
  • private.d.ts: the BunFS/BunFSWatcher types (Bun.fs() no longer exists), Bun.TOML, Bun.tty
  • QuicStream.prototype[kSendHeaders] and its symbol (the public header methods talk to the native handle directly), the unused get [kVerifyPeer] (the setter stays), colors.ts yellow/gray/clear/reset, the runtime SSLMode export in internal/sql/shared.ts (only imported as a type), the REPL_MODE_* re-exports of internal/repl/utils.js (repl.js takes them from internal/repl/mode), Dequeue#clear(), the Operation/Diff declarations in assertion_error.ts, and the write-only listeningId in net.ts

Rust (-18)

  • zig__ModuleInfo__destroy and zig_log in analyze_transpiled_module.rs: extern "C" exports that no C++ declares or calls (BunAnalyzeTranspiledModule.cpp frees through zig__ModuleInfoDeserialized__deinit), and that do not appear in vendor/ or in the prebuilt WebKit libraries

Verification

  • rg for every symbol across src/, packages/, scripts/, test/ and build/debug/codegen/; the extern "C" candidates were additionally checked against vendor/ and against both the undefined and the weak-defined symbols of the prebuilt libWTF.a/libJavaScriptCore.a. That check is what disqualified Bun__thisThreadHasVM (WTF ships a weak default that Bun overrides, so it shows up as neither a textual reference nor an undefined symbol; removing it trips RunLoopBun.cpp's assertion as soon as a Worker starts) and WTFTimer__deinit/__cancel (imported by libWTF.a). Both stay.
  • The preprocessed PerMessageDeflate.h is byte-for-byte identical before and after (one blank line aside).
  • bun bd passes. The only Rust file touched has no cfg gates, so the host cargo check covers every target. clang-format, prettier and oxlint are clean.
  • bun bd test passes on test/js/bun/websocket/websocket-server.test.ts (pub/sub, end(), close paths; the WebSocketContext::create assertion runs in every server test), test/js/web/websocket/websocket-permessage-deflate.test.ts, test/js/bun/http/bun-serve-routes.test.ts (route parameters), test/js/bun/http/serve-http3.test.ts, test/js/node/http/node-http.test.ts, test/js/node/quic/quic-stream.test.ts, test/js/node/assert/assert.test.cjs, test/js/node/stream/node-stream.test.js, test/js/bun/sqlite/sqlite.test.js, test/internal/fifo.test.ts (the one failure there is the large push/shift test timing out under a debug ASAN build, which it also does on main), and test/js/node/test/parallel/test-repl-definecommand.js. The few failures seen locally (a proxy test that needs network, two debug-build perf timeouts, and three Worker lifecycle tests) fail identically on an unmodified main debug build in the same container.
  • No open PR adds a caller of anything removed here (checked the diffs of the 60 open PRs that mention bun-uws, including the HTTP/2 server work in #36161, which defines its own Http2Response equivalents). The Http3ResponseData::totalSize hunk sits next to a hunk in #34385 and the ZigGlobalObject/DOMIsoSubspaces hunks next to ones in #37062/#37149/#37332; they delete different lines.

Rebase notes

Rebased onto main twice, on 2026-08-17 and 2026-08-21 (about 430 commits in total). Conflicts were mechanical: #39420 removed the JSMIMEBindings.h include next to the JSBufferList.h include this PR removes, and #39770 restructured the lazy-structure initializers in ZigGlobalObject.cpp and the slot declarations in DOMIsoSubspaces.h / DOMClientIsoSubspaces.h, so the BufferList entries were removed again in their new form (and the modified-on-main JSBufferList.cpp/.h stay deleted). Every removed symbol was re-checked against the new main after each rebase; nothing gained a caller.

The source lint that earlier revisions of this PR added is gone: main has since deleted the existing dead-symbols-* lints and test/internal/source-lints/CLAUDE.md asks for no more of them, so this PR now only deletes code (the source-lints workflow trigger change that existed for that lint is dropped too).

Left for follow-ups

  • Once #37181 lands (it removes the uws_* C wrappers), these bun-uws members lose their last caller and can go too: QueryParser.h as a whole with HttpRequest::getQuery(key) and Http3Request::getQuery/query, App::removeServerName/missingServerName/onMissingServerName and HttpContextData::missingServerNameHandler, App::getNativeHandle, H3App::constructorFailed/getNativeHandle, WebSocket::send{First,,Last}Fragment, AsyncSocket::getRemoteAddressAsText/addressAsText, HttpResponse::getWriteOffset/setWriteOffset/getSocketData, Http3Response::getWriteOffset/overrideWriteOffset/getSocketData and the never-written Http3ResponseData::socketData.
  • ChunkedEncoding.h's trailer flag is passed as false by all three ChunkIterator call sites, so its 4-byte-terminator branch is dead; removing it is a signature change through the parser rather than a deletion.
  • Http3Response::endWithoutBody's reportedContentLength is always std::nullopt (its one caller is in the shim file #37181 edits).
  • uWS::WebSocket/WebSocketContext/WebSocketProtocol are only ever instantiated with isServer = true (the only false use was in the deleted ClientApp.h), so the client-side masking branches in WebSocketProtocol.h are unreachable; dropping the parameter is a refactor.
  • Bun__Node__CAStore (cli/Arguments.rs) is a #[no_mangle] static that nothing native reads yet; the adjacent comment says native code is meant to migrate to it, so it is left alone.