Remove dead code from the WebCore bindings, IDL converters, and Rust FFI wrappers

Closed
RO
3mo ago
+1-1501

Removes 1,501 lines of code nothing references (the one modified line is the tail of a macro list), across the WebCore/JSC C++ bindings, a few Rust FFI wrapper crates, and stale hawk.toml overrides. No behavior change: everything removed was either never compiled into anything, never instantiated, or written and never read.

How the candidates were found

  • Rust: the cross-crate hawk analysis configured in hawk.toml (release profile unioned over the 11 shipped targets) run against current main. Almost all of its 1218 dead_public findings sit in files that one of the open dead-code PRs already touches; those were left alone, and the remainder was re-checked with rg (hawk only analyzes the release profile, so e.g. ntstatus::ACCESS_DENIED, which has a debug-only reader, was kept).
  • C++: per-header pass over the bindings files not touched by any open dead-code PR, looking for the things the earlier linker-based sweep (#37454) cannot see: declarations without definitions, header-only templates and specializations nothing instantiates, enumerators, macros, and preprocessor branches that can never be taken. Every candidate was checked with rg across src/, packages/, scripts/, test/ and freshly regenerated build/debug/codegen/, and symbol by symbol against the diffs of the open PRs that touch the same files (no overlap; JSDOMConvert.h is also touched by #37062, on a different include line).
  • src/js/ was scanned as well and is clean (oxlint's unused checks keep it that way); nothing from there is in this PR.

Removed

ENABLE(BINDING_INTEGRITY) scaffolding in 19 generated-style bindings (536 lines)
JSAbortController, JSAbortSignal, JSBroadcastChannel, JSCloseEvent, JSCustomEvent, JSDOMFormData, JSDOMURL, JSMessageChannel, JSMessageEvent, JSMessagePort, JSPerformanceMark, JSPerformanceObserver, JSPerformanceObserverEntryList, JSPerformanceServerTiming, JSPerformanceTiming, JSTextEncoder, JSWebSocket, JSWorker, JSSubtleCrypto (.cpp). The RELEASE_ASSERT(actualVTablePointer == expectedVTablePointer) these blocks exist for has been commented out since the files were imported, so the file-scope block only declared an unused _ZTV... vtable symbol and the if constexpr (std::is_polymorphic_v<T>) body in toJSNewlyCreated was empty after preprocessing (its only remaining statement sits under PLATFORM(WIN), which is never true in a BUILDING_JSCONLY__ build). JSURLPattern.cpp still performs the check and is untouched; JSFetchHeaders.cpp / JSPerformance.cpp have the same blocks but are claimed by open PRs.

IDL conversion layer (webcore/JSDOMConvert*.h)

  • JSDOMConvertPromise.h (whole file) and its include in JSSubtleCrypto.cpp: every toJS<IDLPromise<...>> call there passes a void-returning functor, which JSDOMConvertBase.h short-circuits without instantiating the converter; Converter<IDLPromise> had no callers. Cascade: DOMPromise::create(), promise() and the constructor in JSDOMPromise.h (only the static whenPromiseIsSettled remains in use).
  • JSDOMConvertNull.h (whole file) and its includes in JSDOMConvert.h / JSDOMConvertUnion.h: no union names IDLNull, and ConditionalConverter<.., IDLNull, false> never touches the converter.
  • Converter/JSConverter for IDLFloat and IDLUnrestrictedFloat (codegen only emits the double variants), JSConverter<IDLByteString>, JSConverter<IDLObject>, JSConverter<IDLAtomStringAdaptor<T>>, both IDLRequiresExistingAtomStringAdaptor<T> converters, both IDLCallbackInterface<T> converters, JSConverter<IDLCallbackFunction<T>> and the two-argument Converter<IDLCallbackFunction<T>>::convert overload (the one live caller, JSPerformanceObserver.cpp, uses the global-object overload), the UncachedString / OwnedString overloads of the DOMString / USVString converters (nothing constructs those adaptors), and VariadicConverter<IDLAny> / VariadicConverter<IDLInterface<T>> (their consumer, convertVariadicArguments, lives in a header nothing includes).
  • CastedThisErrorBehavior::ReturnEarly (JSDOMCastThisValue.h).

Other JSC / WebCore binding helpers

  • WTF::EnumTraits<HTTPHeaderName> (98 lines) and EnumTraits<ExceptionCode>: EnumTraits<E>::values is only consumed by EnumeratedArray, OptionSet and isZeroBasedContiguousEnum, none of which is used with either enum.
  • ExceptionOr<T&> (never instantiated), the isolatedCopy(ExceptionOr<void>&&) / isolatedCopy(Exception&&) free functions (crossThreadCopy uses the member), ExceptionOr::m_wasReleased, Exception::extra().
  • Opaque roots: the ImplType* / ImplType& forwarding overloads of addWebCoreOpaqueRoot, all three containsWebCoreOpaqueRoot overloads, the nullptr_t constructor, and the root(MessagePort*) / root(CryptoKey*) functions only those overloads could reach (plus the includes / forward declarations that existed for them). The one live user, JSAbortController, passes a WebCoreOpaqueRoot value.
  • BunCommonStrings.h: ConnectionWasClosed, OperationFailed, OperationTimedOut, ec, ed25519, rsa, rsaPss, jwkDsa, jwkG, systemError, x25519 (each one expands to a LazyProperty, accessor, initializer and GC visit; the http* entries are reached via token pasting and stay).
  • EventLoopTask(Function<void()>&&) (every construction site passes a Function<void(ScriptExecutionContext&)>), m_bakeGetAsyncLocalStorage (initialized and visited, never read) and a duplicate LazyPropertyOfGlobalObject alias in BakeAdditionsToGlobalObject.h.
  • Enumerators nothing names: six of TaskSource (only PostedMessageQueue / WebSocket are used), eight of EventListener::Type (JSEventListener is the only subclass).
  • Branches that can never be taken: #if 1 ... #else in CryptoAlgorithmRSA_PSSOpenSSL.cpp, #if ENABLE(OFFSCREEN_CANVAS) / #if ENABLE(MEDIA_SOURCE) includes of headers that do not exist in this tree (JSEventTargetCustom.cpp, JSDOMURL.cpp).
  • Declarations with no definition: CryptoKeyOKP::platformExportSpki / platformExportPkcs8, SecretKeyJobCtx::result(), KeyPairJobCtx::deinit(), and the never-defined template<typename Visitor> visitChildren declarations next to DECLARE_VISIT_CHILDREN in JSNodePerformanceHooksHistogram.h and JSX509Certificate.h.
  • Unreferenced accessors / fields / macros: JSNodePerformanceHooksHistogram::histogram() (+ a commented-out declaration), NodeVMSourceTextModule::cachedExecutable(), Worker::isOnline(), OnLoadResult::wasMock and its one store, JSOneShotDirectSink::m_asUint8Array and its one store (the flag reaches JS through startOptions), expectedEnumerationValues<BufferEncodingType> (no IDLEnumeration<BufferEncodingType> anywhere), G_FALSE / G_TRUE in SecretsLinux.cpp, BUN_WRAP_FWD_VOID in workaround-missing-symbols.cpp.

Rust

  • bun_mimalloc_sys: Heap::malloc / calloc / realloc and the mi_heap_calloc / mi_heap_realloc imports only they used (callers go through the raw mi_heap_* functions with a *mut Heap; MimallocArena deliberately never hands out a &Heap).
  • bun_libdeflate_sys: Compressor::destroy / Decompressor::destroy (the RAII wrappers free directly).
  • bun_uws_sys: App::run, App::listen and the uws_app_run / uws_app_listen imports behind them (the server listens through listen_with_config), uws_app_listen_config_t::new, and a duplicate NewApp alias in App.rs (the live one is in lib.rs).
  • bun_css: DeclarationContext::Keyframes, and the empty generated_color_conversions marker module whose use no longer exists.

hawk.toml: 13 overrides for mysql::status_flags::StatusFlag::* variants that #37229 deleted; hawk now reports them as unknown_item. (The six bun_platform ones in the same state are removed by #37328.)

Verification

  • bun bd (full debug/ASAN build) passes with the removals; bun bd test test/internal/source-lints/ passes. (The branch briefly carried a source lint pinning the removed symbols; it was dropped in 791ffe9, so the PR is now the removals only.)
  • bun bd test passes on test/js/web/abort/abort.test.ts, workers/{message-channel,message-event,performance-observer-leak}.test.ts, encoding/text-encoder.test.js, html/FormData.test.ts, url/url.test.ts, broadcastchannel/broadcast-channel.test.ts, crypto/web-crypto.test.ts, streams/streams.test.js, test/js/node/perf_hooks/perf_hooks.test.ts, test/js/bun/perf_hooks/histogram.test.ts, test/js/node/crypto/x509.test.ts, test/js/node/zlib/zlib.test.js, test/js/bun/test/mock/mock-module.test.ts, and on everything in test/js/web/websocket/websocket.test.js, test/js/node/crypto/crypto.key-objects.test.ts, test/js/bun/css/color.test.ts and test/js/web/workers/worker.test.ts except for tests that need the public internet or that spawn subprocesses and time out at their 5 s budget on this (heavily loaded) machine; the seven worker.test.ts terminate() tests fail identically on a debug build with src/jsc reset to main, and the other timeouts hit a different subset on every run.
  • Rust: cargo check of the touched crates passes; the removed items had no readers in any cfg (hawk unions all 11 targets, and the rg checks are cfg-agnostic), so the per-target cargo check pass is left to CI.

Left alone on purpose (follow-ups, not in this diff)

  • WorkerMessagingProxy::isOnline() is now unreferenced, but that header is touched by #37332 on the neighbouring lines.
  • StringAdaptors.h (UncachedString / OwnedString) has no remaining construction sites, but IDLTypes.h (claimed by an open PR) still names the types.
  • The TextCodec::encode side of the text codecs (~700 lines across TextCodecCJK / TextCodecSingleByte / TextCodecUserDefined / UnencodableHandling.h) is only reachable from TextEncoding::encodeForURLParsing, which has no callers; TextEncoding.h/.cpp are claimed by #37332, so this should go in one piece once that lands.
  • DOMPromise / JSDOMPromise.cpp as a whole become dead once #37062 removes DeferredPromise::whenSettled.
  • hawk also flags bun_install::read_without_launch (the shell-side .bunx fast path, whose caller was not carried over in the Rust port), a handful of bun_jsc helpers added four days ago in 9d519e8ca9 (JSPromise settle_task / resolve_task, VM::has_termination_request, LoopHandle::accepting_work / ref_keep_alive / unref_keep_alive, job.rs accessors), and bun_sys::ErrorCase::LeakFdOnFail; these look like API surface still settling rather than leftovers, so they are not touched here.