Repository navigation
Conversation
|
Updated 3:48 PM PT - Oct 31st, 2026
✅ @robobun, your commit 0ae6b714b51df7bfb1cf27b061a0af7324e671f3 passed in 🧪 To try this PR locally: bunx bun-pr 47538That installs a local version of the PR into your bun-47538 --bun |
|
Status: reproduced on bun The engine fix landed on oven-sh/WebKit This pull request is now tests only. Its |
…ettles Eight programs for `bun build --compile --aot`. A `require()` or an `import()` runs an ES module that imports another one, and a module that it requires calls `import()` on it while it runs. The promise settles when the first module has run, in the same job as under plain Bun. - import-of-required-module-with-import-settles: the `.then` form - import-of-required-module-with-import-awaited: the `await` form - import-of-required-module-with-import-rejects: the module throws - import-of-required-module-with-import-job: the job of the fulfilment - import-of-required-module-with-import-again: a later `import()` inside another `require()` - import-of-imported-module-with-import-settles: the root of an `import()` - imports-of-nested-required-modules-settle: two nested roots, CommonJS entry point - import-of-required-cycle-root-settles: the root of an import cycle
The AOT run time fulfils an `import()` of a module that a `require()` or an `import()` is still evaluating, where the module keeps its status in the table of status bytes.
… code, and the records - import-of-required-module-with-import-settles counts one module with a start of its own (`// STATISTIC: ModulesWithState = 1`): without that start the program passes on any engine. - import-of-required-module-with-import-job: the imported module queues jobs too, so its importer keeps the start. - import-of-imported-module-with-import-job: the job of the fulfilment where an `import()` is the root. No synchronous queue is open there. - import-of-required-module-without-code-settles: the required module has no code of its own and gets no start. - imports-of-nested-required-modules-settle starts from an ES module. - a-module-that-has-run-keeps-no-record.test.ts: a sixth shape. While the promise of such an `import()` is pending no record goes (240 records behind 120 modules).
…nge leaves as they are - import-again-of-cycle-member-imported-while-it-runs: a later `import()` of a member of a cycle gets the promise that an earlier one left pending. - import-of-member-of-cycle-that-fails-is-rejected: the executable fulfils an `import()` of a member whose body has ended when its cycle fails. - import-by-name-of-entry-point-require-runs-settles: with no `import()` in compiled code the `require()` is a call of the start of the module, and an `import()` from text that the build did not read stays pending.
858d546 to
0ae6b71
Compare
--aot settles an import() of a module that a require() still evaluatesimport() of a module that a require() still evaluates settles
Problem
bun build --compile --aot, animport()of an ES module that arequire()is still evaluating never settled. No.thencallback ran, and a top-levelawaitof it never ended.bun runfulfils it.main: AOT: follow-up to #982: 48 fixes WebKit#983 (Modules::evaluateWithOwnStack,aot/runtime/AOTModuleEvaluation.cpp).mainhere does not pin an engine with it yet, and has no test for these cases.Fix
test/aot/parallel/modules/and one row ofa-module-that-has-run-keeps-no-record.test.ts. Each must print and exit as plain Bun does.WEBKIT_VERSIONcommit is temporary. It pins a preview build with the same engine change on the commit thatmainpins, so that the programs pass today. It goes away whenmainpins oven-sh/WebKitb83d8a12aeor later.mainatb83d8a12ae(Notes).Background
--aotcompiles the modules of a program to machine code. The engine half of that compiler and its run time are in oven-sh/WebKit.WEBKIT_VERSION(scripts/build/deps/webkit.ts) names the oven-sh/WebKit release that the build links.autobuild-preview-pr-<n>-<sha>is the build of a pull request there.// Todo:for imports that stay wrong in an executable, on thatmaintoo (Notes).Downsides
Notes
The report
@sosukesuzuki, bun
1.4.4-canary.1+da867c60b, linux-x64, every run.a.mjsrequiresc.mjs.c.mjsimportsd.mjsand requiresx.mjs.x.mjscallsimport("./c.mjs").then(..).bun a.mjsprints the line of the.thencallback, the executable does not. Without the import ofd.mjsthe executable is right, whichmodules/import-of-module-require-running-settlesalready covers.The programs
Each is a folder under
test/aot/parallel/modules/.run-parallel.tsbuilds it with--compile --aotand compares what the executable prints with plain Bun. "Fails" is without the engine change.import-of-required-module-with-import-settles.then. It also counts one module with a start of its own (// STATISTIC: ModulesWithState = 1): without that start it passes on any engineimport-of-required-module-with-import-awaitedimport()import-of-required-module-with-import-rejectsrequire: the promise is rejected with the same errorimport-of-required-module-with-import-jobimport-of-imported-module-with-import-jobimport()is the root, where no synchronous queue of arequire()takes the jobs of the loaderimport-of-required-module-with-import-againimport()of the module inside anotherrequire()import-of-imported-module-with-import-settlesimport(), not of arequireimport-of-required-module-without-code-settlesimports-of-nested-required-modules-settleimport-of-required-cycle-root-settlesThe row of
a-module-that-has-run-keeps-no-record.test.ts: while the promise of such animport()is pending, the run time retires no record. Without the engine change the executable holds 240 records behind 120 modules.Programs marked
// Todo:They print something else than plain Bun before and after the engine change, also on oven-sh/WebKit
mainatb83d8a12ae.run-parallel.tsreports them as skipped, and fails them when they pass.import-by-name-of-entry-point-require-runs-settles: noimport()is compiled, so the build makes therequire()a call of the start of the module. Animport()of it from text that the build did not read stays pending. That needs a second engine change, incallModules.import-again-of-cycle-member-imported-while-it-runs: a laterimport()of a member of a cycle gets the promise that an earlier one left pending.import-of-member-of-cycle-that-fails-is-rejected: the executable fulfils animport()of a member whose body has ended when its cycle fails.How it was run
mainatb83d8a12ae(AOT: follow-up to #982: 48 fixes WebKit#983), release build with assertions. The Bun tree was AOT: hangs, wrong answers, failed builds;bun test --aotfollows #44833's mocks #47605 (22621ef913), with three lines ofsrc/aot/engine.rsstubbed locally for an option that this engine no longer has.run-parallel.tspasses the ten programs and skips the three// Todo:programs. The six rows of the test pass.bun test --aotfollows #44833's mocks #47605 (64ddaea8aa) with the engine at oven-sh/WebKitmain(115632d802) plus the change, release build with assertions.run-parallel.tspasses the ten programs and skips the three// Todo:programs. The six rows of the test pass.1.4.4-canary.1+0ae6b714b), with the engine built from source at the commit of [JSC] AOT: settle the import() of a module that a require() still evaluates WebKit#961 (fedb2feecd):run-parallel.tspasses the ten programs and skips the three// Todo:programs. All six rows ofa-module-that-has-run-keeps-no-record.test.tspass. Of the 434 programs oftest/aot/parallel/modules, 427 pass, 6 are skipped by their// Todo:line and 1 fails: plain Bun with assertions aborts onreassigned-functions-in-cycles, with and without the engine change.bun bdon this pin:run-parallel.tsskips every program on a debug build (only a canary build of Bun reads BUN_AOT_START_AT). So each program was built withbun-debug build --compile --aot, run, and compared withBUN_FEATURE_FLAG_DISABLE_ASYNC_TRANSPILER=1 bun-debug main.*. The ten programs print the same, and the three// Todo:programs do not. The six rows of the test pass.f7607a3d35with the engine at8c6c963e3c, and Bun at AOT: bun test --aot on large suites, module loading fixes, fuzzer fixes #47316 (8aea497349) with the engine at oven-sh/WebKitmain(4d45755fed). 9 programs and the row fail without it, 10 programs and the row pass with it, and the three// Todo:programs are skipped in all four.8c6c963e3calso ran the other 4538 programs oftest/aot/parallel: no program changed its result.The pin
autobuild-preview-pr-961-fedb2feeis oven-sh/WebKitmainat4d45755fed, whichmainpins since #47316, plus the engine change as oven-sh/WebKit#961 had it. That pull request is closed, and the release stays. The pin is temporary: see Fix.What does not change
An
import()of a module that is a dependency of the running evaluation, not its root, stays pending in plain Bun and in an executable. Node.js v26.3.0 fulfils it. oven-sh/WebKit#871 is a draft for that.no test proof · iteration 2 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/aot/a-module-that-has-run-keeps-no-record.test.ts