Skip to content

Benchmarks: pass -Xwasm-use-new-exception-proposal to Wasm linkTask - #5787

Merged
Oleksandr Karpovich (eymar) merged 1 commit into
JetBrains:masterfrom
danleh:wasm-linktask-exception-proposal
Nov 3, 2026
Merged

Oleksandr Karpovich (eymar) merged 1 commit into
JetBrains:masterfrom
danleh:wasm-linktask-exception-proposal

Conversation

@danleh

Copy link
Copy Markdown
Contributor

In #5359, -Xwasm-use-new-exception-proposal was added to compilation.compileTaskProvider in benchmarks/multiplatform/benchmarks/build.gradle.kts.

In the Kotlin Gradle plugin for wasmJs, compilation.compileTaskProvider (Kotlin2JsCompile) only compiles .kt sources into .klib archives. Lowering .klib IR into the final .wasm binary happens in binary.linkTask (KotlinJsIrLink, such as compileProductionExecutableKotlinWasmJs), which has its own compilerOptions block and does not inherit freeCompilerArgs from compileTaskProvider. As a result, compose-benchmarks-benchmarks.wasm was still being linked with the legacy Wasm exception handling instructions (try / catch).

Passing -Xwasm-use-new-exception-proposal to linkTask as well switches the generated .wasm binary to standard WebAssembly exnref (try_table).

We ran into this while updating the Kotlin-compose-wasm workload in WebKit/JetStream (WebKit/JetStream#277).

cc Zalim Bashorov (@bashor) Oleksandr Karpovich (@eymar) Konstantin (@terrakok)

Testing

Built :benchmarks:compileProductionExecutableKotlinWasmJs and verified with wasm-tools that the emitted compose-benchmarks-benchmarks.wasm uses try_table instead of legacy try/catch instructions.

Release Notes

N/A

In JetBrains#5359, -Xwasm-use-new-exception-proposal was added to compilation.compileTaskProvider, which only compiles .kt sources into .klib archives. Pass it to binary.linkTask (KotlinJsIrLink) as well so the linked .wasm binary uses standard WebAssembly exnref (try_table).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix!

@eymar
Oleksandr Karpovich (eymar) merged commit 1574503 into JetBrains:master Nov 3, 2026
4 checks passed
Daniel Lehmann (danleh) added a commit to danleh/JetStream that referenced this pull request Nov 3, 2026
Build the Compose Multiplatform benchmarks from upstream master (1574503571,
which includes JetBrains/compose-multiplatform#5787 passing
-Xwasm-use-new-exception-proposal to the Wasm linkTask) instead of the
JetStream 3.0 hotfix branch (ok/jetstream3_hotfix, 84dad4d3f6), overriding
compose.version to 1.13.0-beta01. This moves Kotlin from 2.2.20-Beta2 to
2.4.20 (stable), Compose from 1.8.2 to 1.13.0-beta01 (which includes the PR
#3411 fix for per-frame JobCancellationException/Error stack allocation in
RectManager and PR #3269/#3484 Skia wrapper reuse fixes), and Skiko from a
custom 0.9.4.3 build to 0.156.0, while emitting standard WebAssembly exnref
(try_table/throw_ref) with zero legacy try/catch instructions.

Compiler option added in compiler-options.patch (both on compile and
KotlinJsIrLink tasks):
- -Xwasm-kclass-fqn=false: Works around KT-91066, where Kotlin 2.3+'s
  KClassImpl.hashCode() allocates and hashes "$packageName.$typeName" on
  every call (triggered on every Compose modifier node lookup).

Removed workarounds:
- The hotfix branch and its custom Skiko build.
- use-beta-toolchain.patch: master uses a stable Kotlin (2.4.20).
- jstag-workaround.patch: Safari's WebAssembly.JSTag fixes have shipped.
- hook-print.patch: Kotlin's glue logs through console, and benchmark.js
  now silences console.log and console.warn unless verbose is set.
- The skipFunMain global in benchmark.js, which nothing reads.

Kept, rebased: empty-main-function.patch and
skiko-disable-instantiate.patch (updated for Skiko 0.156.0's
awaitSkikoCore). Also rewrite static imports in Kotlin 2.4's
compose-benchmarks-benchmarks.import-object.mjs via sed in build.sh,
instantiate compose-benchmarks-benchmarks.wasm directly in benchmark.js
(replacing compose-benchmarks-benchmarks.uninstantiated.mjs), and disable
window.caches in benchmark.js so Compose 1.12+'s ResourceWebCache uses the
in-memory preload fetch polyfill in browsers just as in JS shells.

TODOs once upstream updates ship:
- Update CMP_REV to a newer compose-multiplatform commit once Compose
  1.13.0 is stable (~mid-December 2026) and drop the explicit
  -Pcompose.version=1.13.0-beta01 override in build.sh.
- Remove compiler-options.patch (-Xwasm-kclass-fqn=false) once KT-91066 is
  fixed and backported.

Part of WebKit#277.
Daniel Lehmann (danleh) added a commit to danleh/JetStream that referenced this pull request Nov 3, 2026
Build the Compose Multiplatform benchmarks from upstream master (1574503571,
which includes JetBrains/compose-multiplatform#5787 passing
-Xwasm-use-new-exception-proposal to the Wasm linkTask) instead of the
JetStream 3.0 hotfix branch (ok/jetstream3_hotfix, 84dad4d3f6), overriding
compose.version to 1.13.0-beta01. This moves Kotlin from 2.2.20-Beta2 to
2.4.20 (stable), Compose from 1.8.2 to 1.13.0-beta01 (which includes the PR
#3411 fix for per-frame JobCancellationException/Error stack allocation in
RectManager and PR #3269/#3484 Skia wrapper reuse fixes), and Skiko from a
custom 0.9.4.3 build to 0.156.0, while emitting standard WebAssembly exnref
(try_table/throw_ref) with zero legacy try/catch instructions.

Compiler option added in compiler-options.patch (both on compile and
KotlinJsIrLink tasks):
- -Xwasm-kclass-fqn=false: Works around KT-91066, where Kotlin 2.3+'s
  KClassImpl.hashCode() allocates and hashes "$packageName.$typeName" on
  every call (triggered on every Compose modifier node lookup).

Removed workarounds:
- The hotfix branch and its custom Skiko build.
- use-beta-toolchain.patch: master uses a stable Kotlin (2.4.20).
- jstag-workaround.patch: Safari's WebAssembly.JSTag fixes have shipped.
- hook-print.patch: Kotlin's glue logs through console, and benchmark.js
  now silences console.log and console.warn unless verbose is set.
- The skipFunMain global in benchmark.js, which nothing reads.

Kept, rebased: empty-main-function.patch and
skiko-disable-instantiate.patch (updated for Skiko 0.156.0's
awaitSkikoCore). Also rewrite static imports in Kotlin 2.4's
compose-benchmarks-benchmarks.import-object.mjs via sed in build.sh,
instantiate compose-benchmarks-benchmarks.wasm directly in benchmark.js
(replacing compose-benchmarks-benchmarks.uninstantiated.mjs), and disable
window.caches in benchmark.js so Compose 1.12+'s ResourceWebCache uses the
in-memory preload fetch polyfill in browsers just as in JS shells.

TODOs once upstream updates ship:
- Update CMP_REV to a newer compose-multiplatform commit once Compose
  1.13.0 is stable (~mid-December 2026) and drop the explicit
  -Pcompose.version=1.13.0-beta01 override in build.sh.
- Remove compiler-options.patch (-Xwasm-kclass-fqn=false) once KT-91066 is
  fixed and backported.

Part of WebKit#277.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants