mirror of
https://github.com/aphrody-labs/deno.git
synced 2026-10-13 22:12:32 +00:00
## Why On `aarch64-apple-darwin`, the deno binary links 8 system frameworks — CoreFoundation, Foundation, Security, CoreServices, Metal, QuartzCore, CoreGraphics, MetalPerformanceShaders — but only touches them in rarely-hit paths (`fs.watch`/FSEvents, keychain, WebGPU). Even with the existing `-weak_framework` linkage, **dyld loads + initializes them at process launch** (weak only makes missing symbols non-fatal; the dylib is still loaded). That's pure startup cost paid on every `deno run`. `dyld_info -imports` shows deno imports only ~47 symbols from these frameworks; QuartzCore/CoreGraphics/MPS import **zero**. ## What [lzld](https://github.com/littledivy/lzld) is a thin `ld64.lld` wrapper that strips `-framework`/`-weak_framework` and links `liblzld` instead — a static shim that provides exactly the symbols deno imports, each `dlopen`-ing its framework on **first use**. Frameworks a given run never touches are never loaded. - Added as a git submodule at `tools/lzld`. - **CI builds the macOS aarch64 release binary through lzld by default** (`.github/workflows/ci.ts`): the release step inits the submodule, builds `liblzld`, and patches the linker before `cargo build --release`. Guarded to Darwin/arm64; other matrix entries skip it. - Opt-in build helper `tools/build_lzld.sh` for local use; the default `cargo build` is unchanged. - `.cargo/config.toml` is left untouched: `-fuse-ld` requires an *absolute* linker path (Apple clang rejects relative ones), computed at build time by both CI and the helper. ## `otool -L` — frameworks gone from the load commands **Before (shipping main):** 11 load commands, 8 frameworks loaded at launch ``` $ otool -L $(which deno) /System/Library/Frameworks/Security.framework/.../Security /System/Library/Frameworks/CoreFoundation.framework/.../CoreFoundation /usr/lib/libobjc.A.dylib /System/Library/Frameworks/CoreServices.framework/.../CoreServices /usr/lib/libSystem.B.dylib /System/Library/Frameworks/QuartzCore.framework/.../QuartzCore (weak) /System/Library/Frameworks/Metal.framework/.../Metal (weak) /System/Library/Frameworks/Foundation.framework/.../Foundation /usr/lib/libiconv.2.dylib /System/Library/Frameworks/MetalPerformanceShaders.framework/.../MetalPerformanceShaders (weak) /System/Library/Frameworks/CoreGraphics.framework/.../CoreGraphics (weak) ``` **After (lzld build):** 3 load commands, 0 frameworks ``` $ otool -L target/release/deno /usr/lib/libSystem.B.dylib /usr/lib/libobjc.A.dylib /usr/lib/libiconv.2.dylib $ otool -l target/release/deno | grep -iE 'Metal|CoreFoundation|Foundation|Security|QuartzCore|CoreServices|CoreGraphics' (none) ``` ## Results aarch64-macOS (Apple M4 Max, macOS 15.6), warm, lzld vs. stock main. Interleaved A/B, 80 rounds each (means). | invocation | main | lzld | Δ | |---|---|---|---| | `deno run empty.js` | 11.8 ms | 11.6 ms | −0.2 ms | | `deno task echo` | 7.1 ms | 6.7 ms | −0.4 ms (−6%) | | `deno --help` | 6.2 ms | 5.7 ms | −0.5 ms (−8%) | | `deno --version` | 5.2 ms | 4.8 ms | −0.4 ms (−7%) | | `LC_LOAD` dylibs | 11 | **3** | −8 | | frameworks loaded at launch | 8 | **0** | −8 | The saving is the framework load+init cost avoided at launch (~0.2–0.5 ms), consistent in direction; it's a larger fraction of the cheaper commands. (deno startup is much faster than when [#23716](https://github.com/denoland/deno/pull/23716) first proposed this, so the absolute headroom is smaller now.) ## Correctness The shim handles data constants that have no call to intercept (`kCFAllocatorDefault` = NULL sentinel; `kCFTypeArrayCallBacks`/`kCFRunLoopDefaultMode` substituted at the use site once their framework loads). Validated on a standalone test (CoreFoundation not loaded at startup, loads on first call, `CFArray`/`kCFTypeArrayCallBacks` paths correct) and `deno run`/`eval` work normally. ## Scope / caveats - aarch64-macOS only; other targets unaffected. - Symbol set is generated from `dyld_info -imports`; regenerate if deno's framework imports change (see `tools/lzld/README.md`).
21 lines
656 B
Plaintext
21 lines
656 B
Plaintext
[submodule "tests/util/std"]
|
|
path = tests/util/std
|
|
url = https://github.com/denoland/deno_std
|
|
shallow = true
|
|
[submodule "tests/wpt/suite"]
|
|
path = tests/wpt/suite
|
|
url = https://github.com/web-platform-tests/wpt.git
|
|
shallow = true
|
|
[submodule "tests/node_compat/runner/suite"]
|
|
path = tests/node_compat/runner/suite
|
|
url = https://github.com/denoland/node_test.git
|
|
shallow = true
|
|
ignore = untracked
|
|
[submodule "tests/bench/testdata/lsp_benchdata"]
|
|
path = tests/bench/testdata/lsp_benchdata
|
|
url = https://github.com/denoland/deno_lsp_benchdata.git
|
|
shallow = true
|
|
[submodule "tools/lzld"]
|
|
path = tools/lzld
|
|
url = https://github.com/littledivy/lzld
|