Skip to content
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
8b43679
Bytecode cache: generate optimized bytecode for --compile --bytecode …
Jarred-Sumner Sep 8, 2026
99dc1b3
Faster startup for bun build --compile --bytecode executables
Jarred-Sumner Sep 8, 2026
214cd13
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 8, 2026
ff06991
test: compile+bytecode ESM module graph cases (cycles, star exports, …
Jarred-Sumner Sep 8, 2026
d1ed36c
Round 3: startup JIT deferral ends on first stdin data / stdout-or-tt…
Jarred-Sumner Sep 8, 2026
d5f65a1
Round 4: Bun.build optimize:{bytecode,prelinkModules,startupJITDeferr…
Jarred-Sumner Sep 8, 2026
e3242a4
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 8, 2026
f3b66ae
test: make the startup JIT deferral test independent of JSC log inter…
Jarred-Sumner Sep 8, 2026
a13558e
prelinked_module_graph: take the string table directly instead of clo…
Jarred-Sumner Sep 8, 2026
eecc87d
Use the WebKit prebuilt from oven-sh/WebKit#588 (preview tag)
Jarred-Sumner Sep 8, 2026
9f02b75
node_fs: scope the AtomicI32 import to the unix-only tty probe (fixes…
Jarred-Sumner Sep 8, 2026
7b49dbd
compile: lay out the embedded module payload in static evaluation order
Jarred-Sumner Sep 9, 2026
d39bbb7
Module registry: let JSModuleLoader::removeEntry take its own lock (f…
Jarred-Sumner Sep 9, 2026
f345a53
Module registry: same for Loader.registry.delete()
Jarred-Sumner Sep 9, 2026
e74de70
WebKit prebuilt b525829f; stack traces read function names via ecmaNa…
Jarred-Sumner Sep 9, 2026
91f7b49
Revert "compile: lay out the embedded module payload in static evalua…
Jarred-Sumner Sep 9, 2026
0c729b9
Bun.unsafe.setJITPolicy(scale) replaces endStartupJITDeferral(); drop…
Jarred-Sumner Sep 9, 2026
654cdc8
compile: jitPolicy is an opt-in scale only; prelinked graph always on…
Jarred-Sumner Sep 9, 2026
eb6a2df
JIT policy: opt-in tier-up threshold scale (compile.jitPolicy, --comp…
Jarred-Sumner Sep 9, 2026
7f1ec5d
test: update the bytecode-cache portability snapshot for cache format…
Jarred-Sumner Sep 9, 2026
1856016
Blob.rs: drop an unused helper left over from the removed deferral hooks
Jarred-Sumner Sep 9, 2026
bd326d2
WebKit prebuilt 4f033003 (VM::setStartupJITDeferralScale)
Jarred-Sumner Sep 9, 2026
9d965b8
Drop the embedded-bytecode integrity flag (JSC no longer checksums ca…
Jarred-Sumner Sep 9, 2026
4cfc3af
test: debugger, sampling profiler and heap snapshot on a --compile --…
Jarred-Sumner Sep 9, 2026
fcd00cf
Install the executable's bytecode string table on every VM (fixes ins…
Jarred-Sumner Sep 9, 2026
2754df2
test: bytecode portability snapshot for cache format revision 3 (no c…
Jarred-Sumner Sep 9, 2026
59806dc
WebKit prebuilt 9acf76c5 (no instrumentation, no cache checksum)
Jarred-Sumner Sep 9, 2026
4032782
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 9, 2026
fe71c36
Address review comments: removeEntry double lock, ensureRegistered ex…
Jarred-Sumner Sep 9, 2026
3d086e0
test: keep the inspector.open() pause case as todo (bytecode-cached f…
Jarred-Sumner Sep 9, 2026
f4d34ad
WebKit prebuilt fe7a6814
Jarred-Sumner Sep 9, 2026
63a6a97
Address review comments (round 2): don't fail output waits when the i…
Jarred-Sumner Sep 9, 2026
04da767
[autofix.ci] apply automated fixes
autofix-ci[bot] Sep 9, 2026
8b3b47d
WebKit prebuilt b0a89d60; portability snapshot for cache format revis…
Jarred-Sumner Sep 9, 2026
1986655
test: bytecode portability snapshot for cache format revision 4
Jarred-Sumner Sep 9, 2026
d9717da
Prelinked graph: register non-graph requests (builtins) through setIm…
Jarred-Sumner Sep 9, 2026
048ac39
Prelinked module graph v3: emit the per-module import hash index
Jarred-Sumner Sep 9, 2026
69391eb
test: fix stale header-layout comment
Jarred-Sumner Sep 9, 2026
2a2f110
Revert "Prelinked module graph v3: emit the per-module import hash in…
Jarred-Sumner Sep 9, 2026
4389fbd
WebKit prebuilt 00ff4355
Jarred-Sumner Sep 9, 2026
b4eaf7e
test: compile/prelinked/RegistryDelete — deleting a graph module's re…
Jarred-Sumner Sep 9, 2026
59a1421
WebKit prebuilt b3919f8e
Jarred-Sumner Sep 9, 2026
cbb83ca
test: regenerate the bytecode portability snapshot against a fresh fr…
Jarred-Sumner Sep 9, 2026
b62f223
test: RegistryDelete case finds the cache key separator-agnostically …
Jarred-Sumner Sep 9, 2026
fe61a72
Bump WebKit to dfd696443b9b
Jarred-Sumner Sep 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/bundler/executables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,25 @@ The `--sourcemap` argument embeds a sourcemap compressed with zstd, so that erro

The `--bytecode` argument enables bytecode compilation. Every time you run JavaScript code in Bun, JavaScriptCore (the engine) compiles your source code into bytecode. `--bytecode` moves that parsing work from runtime to bundle time, which shortens startup.

With `--bytecode`, JavaScriptCore's build-time optimization passes also run over the generated bytecode; `--no-optimize-bytecode` (`optimize: { bytecode: false }` in `Bun.build`) skips them.

### JIT policy

Code that only runs during startup rarely pays back the time the JIT spends compiling it. `--compile-jit-policy <n>` (`compile: { jitPolicy: n }` in `Bun.build`) starts the executable with JavaScriptCore's tier-up thresholds multiplied by `n`, so startup code stays in the interpreter longer. The default, `1`, is the normal JIT policy. The scale stays in effect until the program calls `Bun.unsafe.setJITPolicy(1)`, which it should do once it is interactive:

```ts build.ts icon="/icons/typescript.svg"
await Bun.build({
entrypoints: ["./app.ts"],
compile: { outfile: "./myapp", jitPolicy: 8 },
bytecode: true,
});
```

```ts app.ts icon="/icons/typescript.svg"
await renderFirstScreen();
Bun.unsafe.setJITPolicy(1); // back to the normal JIT policy
```

---

## Embedding runtime arguments
Expand Down Expand Up @@ -1216,6 +1235,7 @@ interface CompileBuildOptions {
autoloadPackageJson?: boolean; // Load package.json (default: false)
autoloadDotenv?: boolean; // Load .env files (default: true)
autoloadBunfig?: boolean; // Load bunfig.toml (default: true)
jitPolicy?: number; // JIT tier-up threshold scale at startup (default: 1 = normal)
windows?: {
icon?: string; // Path to .ico file
hideConsole?: boolean; // Hide console window
Expand Down
10 changes: 10 additions & 0 deletions docs/bundler/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1885,6 +1885,16 @@ interface BuildConfig {
* @default undefined (all nested functions)
*/
bytecodeDepth?: number;
/**
* Build-time optimizations for `bytecode` builds.
*/
optimize?: {
/**
* Run JavaScriptCore's build-time optimization passes over the generated bytecode.
* @default true
*/
bytecode?: boolean;
};
/**
* Add a banner to the bundled code such as "use client";
*/
Expand Down
9 changes: 9 additions & 0 deletions docs/snippets/cli/build.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ bun build <entry points>
How many levels of nested functions to compile to bytecode ahead of time (a non-negative integer). Defaults to all
</ParamField>

<ParamField path="--no-optimize-bytecode" type="boolean">
With <code>--bytecode</code>: skip the build-time bytecode optimization passes
</ParamField>

<ParamField path="--target" type="string" default="browser">
Intended execution environment for the bundle. One of <code>browser</code>, <code>bun</code>, or <code>node</code>
</ParamField>
Expand Down Expand Up @@ -189,6 +193,11 @@ bun build <entry points>
Prepend arguments to the standalone executable’s <code>execArgv</code>
</ParamField>

<ParamField path="--compile-jit-policy" type="number" default="1">
JIT tier-up threshold scale the executable starts with; <code>1</code> is the normal JIT policy. See
<code>Bun.unsafe.setJITPolicy</code>
</ParamField>

<ParamField path="--compile-autoload-dotenv" type="boolean" default="true">
Enable autoloading of <code>.env</code> files in the standalone executable
</ParamField>
Expand Down
38 changes: 38 additions & 0 deletions packages/bun-types/bun.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3423,6 +3423,18 @@ declare module "bun" {
*/
bytecodeDepth?: number;

/**
* Build-time optimizations for `bytecode` builds.
*/
optimize?: {
/**
* Run JavaScriptCore's build-time optimization passes over the generated
* bytecode. Only used when `bytecode: true`.
* @default true
*/
bytecode?: boolean;
};

/**
* Add a banner to the bundled code such as "use client";
*/
Expand Down Expand Up @@ -3720,6 +3732,17 @@ declare module "bun" {
* @default false
*/
autoloadPackageJson?: boolean;
/**
* The JIT policy the executable starts with (see {@link Bun.unsafe.setJITPolicy}).
* `1` is the normal policy. A value `> 1` multiplies JavaScriptCore's tier-up
* thresholds so code that only runs during startup stays in the interpreter
* longer; the app should call `Bun.unsafe.setJITPolicy(1)` once it is interactive.
*
* Equivalent CLI flag: `--compile-jit-policy <n>`
*
* @default 1
*/
jitPolicy?: number;
windows?: {
hideConsole?: boolean;
icon?: string;
Expand Down Expand Up @@ -5399,6 +5422,21 @@ declare module "bun" {
*/
function mimallocDump(): void;

/**
* Scale JavaScriptCore's JIT tier-up thresholds for the current thread's VM.
*
* `1` is the normal JIT policy. A value `> 1` makes the JIT that many times more
* reluctant to compile, e.g. during a burst of run-once startup code; it stays in
* effect until the next call. `bun build --compile` executables can start with a
* scale baked in (`compile.jitPolicy` / `--compile-jit-policy`) and call
* `setJITPolicy(1)` once interactive.
*
* @param scale a finite number `>= 1`
* @throws {TypeError} if `scale` is not a number
* @throws {RangeError} if `scale` is not finite or `< 1`
*/
function setJITPolicy(scale: number): void;

/**
* Accurate per-process memory footprint in bytes.
*
Expand Down
2 changes: 1 addition & 1 deletion scripts/build/deps/webkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* for local mode. Override via `--webkit-version=<hash>` to test a branch.
* From https://github.com/oven-sh/WebKit releases.
*/
export const WEBKIT_VERSION = "2e2aa2290fac856d6f451ceacb58f7f5b44dd057";
export const WEBKIT_VERSION = "autobuild-preview-pr-588-00ff4355";

/**
* WebKit (JavaScriptCore) — the JS engine.
Expand Down
1 change: 1 addition & 0 deletions scripts/verify-baseline-static/allowlist-x64-windows.txt
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@ bssl::BORINGSSL_keccak_squeeze_x4 [AVX, AVX2]
# MSVC STL vectorized algorithms. Gate: __isa_available.
# (15 symbols)
# ----------------------------------------------------------------------------
__std_min_element_d [AVX, AVX2]
__std_mismatch_1 [AVX, AVX2]
__std_reverse_copy_trivially_copyable_1 [AVX, AVX2]
__std_reverse_trivially_swappable_1 [AVX, AVX2]
Expand Down
2 changes: 2 additions & 0 deletions src/bundler/LinkerContext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,7 @@ pub struct LinkerOptions {
/// See `CompileTargetBuiltins::Target`.
pub(crate) target_builtins: Option<std::sync::Arc<[u8]>>,
pub(crate) bytecode_depth: u32,
pub(crate) optimize_bytecode: bool,
pub(crate) output_format: Format,
pub(crate) ignore_dce_annotations: bool,
pub(crate) emit_dce_annotations: bool,
Expand Down Expand Up @@ -1429,6 +1430,7 @@ impl Default for LinkerOptions {
generate_internal_module_bytecode: false,
target_builtins: None,
bytecode_depth: u32::MAX,
optimize_bytecode: true,
output_format: Format::Esm,
ignore_dce_annotations: false,
emit_dce_annotations: true,
Expand Down
5 changes: 5 additions & 0 deletions src/bundler/OutputFile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ pub struct OutputFile {
/// The chunk is in the entry point's static import closure, i.e. it loads
/// before the first `import()`.
pub loads_at_startup: bool,
/// This chunk's module index in the `OutputKind::PrelinkedModuleGraph` blob (see
/// `prelinked_module_graph::build`); `u32::MAX` when it is not an ES module of that graph.
pub prelinked_module_index: u32,
}

impl OutputFile {
Expand Down Expand Up @@ -66,6 +69,7 @@ impl OutputFile {
bake_extra: BakeExtra::default(),
load_order: u32::MAX,
loads_at_startup: false,
prelinked_module_index: u32::MAX,
}
}
}
Expand Down Expand Up @@ -215,6 +219,7 @@ impl OutputFile {
bake_extra: options.bake_extra,
load_order: u32::MAX,
loads_at_startup: false,
prelinked_module_index: u32::MAX,
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/bundler/analyze_transpiled_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,16 @@ impl ModuleInfoSlotTableBuilder {
}
ids
}
/// Interns one string (a module key the pre-resolved graph names); returns its table id.
pub fn intern(&mut self, s: &[u8], slot_for: impl Fn(&[u8]) -> u32) -> u32 {
if let Some(&id) = self.ids.get(s) {
return id;
}
let id = u32::try_from(self.slots.len()).expect("int cast");
self.slots.push(slot_for(s));
self.ids.insert(s.into(), id);
id
}
pub fn count(&self) -> u32 {
self.slots.len() as u32
}
Expand Down
12 changes: 12 additions & 0 deletions src/bundler/bundle_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,7 @@ pub mod bv2_impl {
source: &[u8],
source_provider_url: &bun_core::String,
depth: u32,
optimize: bool,
external_strings: Option<core::ptr::NonNull<EncoderStringTable>>,
) -> Option<Box<[u8]>>;

Expand Down Expand Up @@ -1445,6 +1446,14 @@ pub mod bv2_impl {
table: core::ptr::NonNull<EncoderStringTable>,
wtf8: &[u8],
) -> u32;
/// `WTF::StringImpl::hash()` of the string with these WTF-8 contents.
safe fn __bun_jsc_wtf_string_hash(wtf8: &[u8]) -> u32;
}

/// `WTF::StringImpl::hash()` of a WTF-8 string, as JSC hashes the atom it becomes at runtime.
#[inline]
pub(crate) fn wtf_string_hash(wtf8: &[u8]) -> u32 {
__bun_jsc_wtf_string_hash(wtf8)
}

unsafe extern "Rust" {
Expand Down Expand Up @@ -1483,6 +1492,7 @@ pub mod bv2_impl {
source: &[u8],
source_provider_url: &bun_core::String,
depth: u32,
optimize: bool,
external_strings: Option<core::ptr::NonNull<EncoderStringTable>>,
) -> Option<Box<[u8]>> {
// A CJS chunk is wrapped in `(function(exports, require, module, ...) {})`, so the module's top level is one function deep.
Expand All @@ -1495,6 +1505,7 @@ pub mod bv2_impl {
source,
source_provider_url,
depth,
optimize,
external_strings,
)
}
Expand Down Expand Up @@ -3068,6 +3079,7 @@ pub mod bv2_impl {
_ => None,
};
this.linker.options.bytecode_depth = this.transpiler.options.bytecode_depth;
this.linker.options.optimize_bytecode = this.transpiler.options.optimize_bytecode;
this.linker.options.compile_mode = this.transpiler.options.compile_mode;
this.linker.options.metafile = this.transpiler.options.metafile;
// SAFETY: same `'a`-owned `Transpiler` field as `banner` above.
Expand Down
6 changes: 6 additions & 0 deletions src/bundler/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub mod thread_pool;
pub(crate) mod AstBuilder;
pub mod analyze_transpiled_module;
pub mod bundled_ast;
pub mod prelinked_module_graph;
pub use bundled_ast::BundledAst;
pub mod barrel_imports;
#[path = "Chunk.rs"]
Expand Down Expand Up @@ -285,6 +286,10 @@ pub mod options {
/// The string table every chunk's `ModuleInfo` body indexes (`ModuleInfoStringTable::serialize`).
#[strum(serialize = "module-info-string-table")]
ModuleInfoStringTable,
/// The pre-resolved ES module graph of a --compile executable (`prelinked_module_graph::build`), consumed by
/// JSC's module loader (`JSC::PrelinkedModuleGraph`).
#[strum(serialize = "prelinked-module-graph")]
PrelinkedModuleGraph,
#[strum(serialize = "metafile-json")]
MetafileJson,
#[strum(serialize = "metafile-markdown")]
Expand All @@ -301,6 +306,7 @@ pub mod options {
| OutputKind::BuiltinBytecode
| OutputKind::BytecodeStringTable
| OutputKind::ModuleInfoStringTable
| OutputKind::PrelinkedModuleGraph
| OutputKind::MetafileJson
| OutputKind::MetafileMarkdown
)
Expand Down
Loading
Loading