Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 29 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ on:
permissions:
contents: write

# A repeated tag event must verify the first publication, not race its upload.
concurrency:
group: runtime-release-${{ github.ref }}
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -52,11 +57,30 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
release_flags=()
prerelease=false
if [[ "$GITHUB_REF_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+- ]]; then
prerelease=true
release_flags+=(--prerelease --latest=false)
fi
gh release create "$GITHUB_REF_NAME" artifacts/* \
--verify-tag \
--title "PolkaVM Host Runtime $GITHUB_REF_NAME" \
--generate-notes \
"${release_flags[@]}"
if state="$(gh release view "$GITHUB_REF_NAME" \
--json isDraft,isPrerelease --jq '[.isDraft,.isPrerelease] | @tsv')"; then
[[ "$state" == $'false\t'"$prerelease" ]] || {
echo "existing release has unexpected draft/prerelease state" >&2
exit 1
}
published="$(mktemp -d)"
trap 'rm -rf "$published"' EXIT
gh release download "$GITHUB_REF_NAME" --dir "$published"
# Compare the complete inventory and every byte, including provenance.
# Never overwrite a release or accept a partial previous publication.
diff -r -- artifacts "$published"
echo "Existing immutable release exactly matches the rebuilt artifacts."
else
# Creation remains fail-closed if lookup failed for any other reason,
# or another publisher created the tag's release in the meantime.
gh release create "$GITHUB_REF_NAME" artifacts/* \
--verify-tag \
--title "PolkaVM Host Runtime $GITHUB_REF_NAME" \
--generate-notes \
"${release_flags[@]}"
fi
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ checksum and embedded copy, with no extra files or symlinks.
Generate and review assets and embedded Rust digests before preparing the tagged
source commit. The manifest command only verifies them; it does not repair
release inputs. Output belongs in ignored `artifacts/`, not the tagged source.
The `0.3.2-rc.6` candidate aligns the workspace, all Rust crates, browser package,
The `0.3.2-rc.7` candidate aligns the workspace, all Rust crates, browser package,
and npm lockfile. Regenerate attribution after updating `Cargo.lock`, then build
the browser distribution and refresh embedded assets and their Rust digests before
committing and tagging. SemVer prerelease tags are published with
Expand Down
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ members = [
]

[workspace.package]
version = "0.3.2-rc.6"
version = "0.3.2-rc.7"
edition = "2021"
license = "MPL-2.0"
repository = "https://github.com/paritytech/polkavm-host-runtime"
Expand Down
23 changes: 15 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,19 +300,26 @@ A release is identified by one source commit and records:

Release tags use `v<version>`. Moving branch references are not release inputs.

The workspace, Rust crates, and browser package are aligned at `0.3.2-rc.6`.
This candidate is `0.3.2-rc.5` plus the compiler correction for heap-backed
fiber stacks: SP-relative loads and stores use the same guest-address mapping
as other dynamic accesses, rather than assuming SP always points into the
reserved stack segment. This lets OpenHV's managed fibers use the compiled
browser backend. The 32-bit and 64-bit regression compares heap-backed and
reserved-stack accesses with the interpreter.
The workspace, Rust crates, and browser package are aligned at `0.3.2-rc.7`.
This candidate adds exact binary32 add/multiply intrinsics, accepting and returning
raw IEEE-754 bits. Native execution, browser fallback and translated Wasm preserve
round-to-nearest-even, subnormals, signed zero, and the documented NaN payload/sign
rules. The bounded intrinsics consume guest gas without consuming Host I/O quotas.
Translated float calls continue directly into the next block when it belongs to
the same generated function; gas checks and real Host-call suspension are retained.
No sustained application FPS improvement is claimed by this release.

The candidate retains `0.3.2-rc.6`'s correction for heap-backed fiber stacks:
SP-relative loads and stores use the same guest-address mapping as other dynamic
accesses, rather than assuming SP always points into the reserved stack segment.
The 32-bit and 64-bit regression compares heap-backed and reserved-stack accesses
with the interpreter.
The candidate retains the surface-resize fix: offscreen passes retain their
resources across resize, stale default-surface passes report error `4` with
the offending command index, and offscreen/resource-only work does not count
as a presented frame. It retains PolkaVM engine
`642fa95a6f1df85612bdbd0a7e4353a2aa4dc9b5` and the prior translated-dispatch
optimization, without adding the unfinished binary32 or checkpoint changes.
optimization, without adding the unfinished checkpoint changes.
It remains a prerelease, not a stable compatibility promise. The release generator
deliberately refuses inconsistent versions, dirty or untagged source, stale embedded
files, or mismatched compiler/engine provenance.
Expand Down
4 changes: 4 additions & 0 deletions docs/adr/0002-runtime-distribution-channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ allowlist entry for this repository to `paritytech/npm_publish_automation`.
and attaches all three to the tagged GitHub release. That tarball is the
artifact downstream Hosts vendor, recorded by upstream revision in their own
lockfiles.
- Repeated tag events are serialized. Retrying publication accepts an existing
non-draft release only when its prerelease flag, complete asset inventory and
every artifact byte (including the provenance manifest) match the rebuilt
release. Missing or differing assets fail; the workflow never replaces them.
- A Host that wants the package from a registry gets it through the
useragent-kit distribution, which owns that publication and its versioning.
- Changing the distribution channel is an organisational decision, not a
Expand Down
56 changes: 53 additions & 3 deletions docs/runtime/polkavm-app-abi-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,56 @@ only while the execution is in the foreground and MUST stop physical sensor
acquisition when the execution loses the foreground, closes, or loses
authorization. The application MUST handle `-1` and `-2`.

### Exact binary32 arithmetic

```text
host_f32_add(a: u32, b: u32) -> u32
host_f32_mul(a: u32, b: u32) -> u32
```

These optional imports interpret both arguments and the result as raw IEEE-754
binary32 bits, not integer values or pointers. Addition and multiplication MUST
round to nearest, ties to even, with gradual underflow (no flushing subnormals
to zero), signed zeros, and signed infinities. Each operation rounds once to
binary32; it MUST NOT be fused with another operation.

NaN propagation is explicit and matches the guest soft-float implementation,
independently of the Host's native floating-point NaN conventions:

- If either argument is a NaN, select the first NaN in argument order `a`, `b`.
- Addition returns `(selected & 0x7fffffff) | 0x00400000`: preserve the payload,
quiet signaling NaNs, and clear the sign.
- Multiplication returns `selected | 0x00400000`: preserve the payload and
sign, and quiet signaling NaNs.
- With no NaN operand, opposite-signed infinities added together or zero
multiplied by infinity return the positive canonical NaN `0x7fc00000`,
regardless of operand order or signs.

Subtraction uses `host_f32_add(a, b ^ 0x80000000)`; there is no separate
subtraction import.

These are pure, fixed-cost arithmetic operations: they access no guest memory,
allocate no per-operation storage, and perform no IO. Their guest instructions
remain gas-metered, including import calls. Hosts MUST NOT charge them against
Host IO call-count or byte budgets; this exemption does not apply to any other
Host import.

Existing guests that do not import these symbols are unchanged. Guests that
import them require an updated runtime providing this exact contract; an
unsupported Host MUST reject the import rather than silently substitute an
approximation or a fallback implementation.

The browser Wasm translator lowers these imports directly to binary32
arithmetic without a JavaScript hostcall. It checks the result for NaN and
repairs exceptional results from the original integer operand bits; non-NaN
results need no operand checks. This lowering preserves the register and gas
contract above, including when execution resumes after gas exhaustion.
When the arithmetic continuation is the adjacent block in the same generated
function, execution falls through without re-entering the group dispatcher.
The translator still records the continuation PC and retains its gas checks.
Continuations across function/module boundaries retain tail-call dispatch,
and ordinary Host imports still yield to the Host.

### Time

```text
Expand Down Expand Up @@ -1252,9 +1302,9 @@ asset files 2,048
one asset 128 MiB
all assets 256 MiB
one asset read 16 MiB
Host-call bytes per init/update 32 MiB
Host calls during init 131,072
Host calls during update 65,536
Host IO call bytes per init/update 32 MiB
Host IO calls during init 131,072
Host IO calls during update 65,536
sleep during init 100 ms
sleep during update 50 ms
audio samples per submission 96,000
Expand Down
2 changes: 1 addition & 1 deletion js/packages/polkavm-browser-runtime/SOURCE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
PolkaVM App v2 browser runtime
Source repository: https://github.com/paritytech/polkavm-host-runtime
Release tag: v0.3.2-rc.6
Release tag: v0.3.2-rc.7
Rust crate: rust/crates/polkavm-host-runtime
GPU wire crate: rust/crates/polkavm-gpu-wire
PolkaVM native revision: 642fa95a6f1df85612bdbd0a7e4353a2aa4dc9b5
Expand Down
2 changes: 1 addition & 1 deletion js/packages/polkavm-browser-runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@parity/polkavm-browser-runtime",
"version": "0.3.2-rc.6",
"version": "0.3.2-rc.7",
"description": "Host-neutral PolkaVM App v2 browser runtime artifacts",
"license": "MPL-2.0",
"type": "module",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,26 @@
const CORE_STATUS_INVALID = -3;
const CORE_STATUS_DENIED = -5;
const CORE_STATUS_LIMIT = -6;
// Also serve modules compiled without arithmetic lowering. Views are reused;
// the synchronous pure operation cannot overlap another instance's call.
const floatBits = new Uint32Array(2);
const floatValues = new Float32Array(floatBits.buffer);

function float32Arithmetic(name, a, b) {
const multiply = name === "host_f32_mul";
if ((a & 0x7fffffff) > 0x7f800000 || (b & 0x7fffffff) > 0x7f800000) {
const bits = (a & 0x7fffffff) > 0x7f800000 ? a : b;
return ((multiply ? bits : bits & 0x7fffffff) | 0x00400000) >>> 0;
}
floatBits[0] = a;
floatBits[1] = b;
floatValues[0] = multiply
? floatValues[0] * floatValues[1]
: floatValues[0] + floatValues[1];
const result = floatBits[0];
return (result & 0x7fffffff) > 0x7f800000 ? 0x7fc00000 : result;
}

const INPUT_EVENT_BYTES = 8;
const MOTION_SAMPLE_BYTES = 48;
const MOTION_STATUS_UNAVAILABLE = 0;
Expand Down Expand Up @@ -2085,6 +2105,14 @@
`translated PolkaVM called unknown import ${importIndex}`,
);
}
if (name === "host_f32_add" || name === "host_f32_mul") {
this.#setReg(
7,
float32Arithmetic(name, this.#u32(this.#reg(7)), this.#u32(this.#reg(8))),
);
status = this.pvm.pvm_resume();
continue;
}
this.hostcalls--;
const yielded = this.coreVm
? this.#handleCoreVmCall(name)
Expand Down
2 changes: 1 addition & 1 deletion licenses/THIRD_PARTY_LICENSES.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
THIRD-PARTY LICENSES AND NOTICES

Generated by scripts/generate-third-party-notices.mjs. See THIRD_PARTY_NOTICES.md.
Cargo.lock SHA-256: 03b8161d54ecd1854fe55e1eb2ac5501fb6db36cf29299da265114745be033cd
Cargo.lock SHA-256: 58aeed4b348b2b9bab144eaee514aa96825e7650a0409f2fc2e98be9f27134bb
Rust: rustc 1.97.1 (8bab26f4f 2026-07-14)

SCOPE: browser-default/runtime = normal browser dependency path; browser-default/build = build/proc-macro path.
Expand Down
2 changes: 1 addition & 1 deletion licenses/dependency-inventory.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"cargoLockSha256": "03b8161d54ecd1854fe55e1eb2ac5501fb6db36cf29299da265114745be033cd",
"cargoLockSha256": "58aeed4b348b2b9bab144eaee514aa96825e7650a0409f2fc2e98be9f27134bb",
"rustToolchain": "rustc 1.97.1 (8bab26f4f 2026-07-14)",
"browser": {
"root": "polkavm-host-runtime",
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "polkavm-host-runtime-workspace",
"private": true,
"version": "0.3.2-rc.6",
"version": "0.3.2-rc.7",
"description": "Host-neutral PolkaVM application runtime workspace",
"license": "MPL-2.0",
"type": "module",
Expand Down
4 changes: 2 additions & 2 deletions rust/crates/polkavm-assets-export/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "polkavm-assets-export"
version = "0.3.2-rc.6"
version = "0.3.2-rc.7"
edition = "2021"
description = "Exports host-neutral PolkaVM browser runtime assets"
license = "MPL-2.0"
Expand All @@ -11,4 +11,4 @@ publish = false
workspace = true

[dependencies]
polkavm-host-runtime-assets = { version = "0.3.2-rc.6", path = "../polkavm-host-runtime-assets" }
polkavm-host-runtime-assets = { version = "0.3.2-rc.7", path = "../polkavm-host-runtime-assets" }
2 changes: 1 addition & 1 deletion rust/crates/polkavm-gpu-wire/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "polkavm-gpu-wire"
version = "0.3.2-rc.6"
version = "0.3.2-rc.7"
edition = "2021"
description = "Bounded host-neutral Tri2D and WebGPU wire protocols for PolkaVM applications"
license = "MPL-2.0"
Expand Down
2 changes: 1 addition & 1 deletion rust/crates/polkavm-host-runtime-assets/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "polkavm-host-runtime-assets"
version = "0.3.2-rc.6"
version = "0.3.2-rc.7"
edition = "2021"
description = "Source-built browser assets for the host-neutral PolkaVM runtime"
license = "MPL-2.0"
Expand Down
8 changes: 4 additions & 4 deletions rust/crates/polkavm-host-runtime-assets/assets/SHA256SUMS
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
96a71c73bb3bff63209c4ca0355175fbe32ee5561296b1fe18be244914503097 polkavm-browser-runtime.wasm
0fbb81d3a5705bde006bdbe24f1c5256cbac47f02dc623224a5b1c07627fb32c polkavm-worker.js
820a2c074f9c66593f92b95ef10277cbdad77156fd85b63ef26e92af7cd37340 polkavm-browser-runtime.wasm
593d88c72873a9eb2bd9fde2059928cacbbf02165c29dc27620ba91fb93f5855 polkavm-worker.js
d82122ed55f389f00808e11b1bbe36195e5b711035ca887f33e79aa6cbf01e60 polkavm-gpu-worker.js
0e180d6044be0fde18fbcfda4e7ba26e669a98cf6d92471f77310c5360973e0b polkavm-wasm-translated.js
470140632156f45b9c671582b0daaf8bbc1f5f1ea1bc4365355bbaec145be7f6 polkavm-wasm-translated.js
5b0b9a6909716a65099fa45b80b9e802fc4b10a4300b3a429bd1ed88ec49e5bd polkavm-runtime-core.js
fa600faff369b09eae5a50dd4b08445b7762d89d6db269b70230ad5a8bf67951 polkavm-wasm-worker-entry.js
edb78a7e5973b92c36231e1383fb384f400ba277e9158e5228f39b7234ad4e29 polkavm-computer.js
Expand All @@ -11,4 +11,4 @@ caa19c63fae1fd4efd59b9b49f9fbd8425cebc8d744d6512f1d92fae24a96943 session.js
f72633219f482e458a1420f60ecc84d638d12d5389173fb6c7db85ed4447667f file-input-router.d.ts
4b89d4518bd135ab4ee154a7bce722246b57a98c3d7efc1a09409898160c2bd1 LICENSE-MPL-2.0
9c0e912f1ba2853c28497f21c6bed1aa17dd11939d01cd3d59656bec5fa32ce1 THIRD_PARTY_NOTICES.md
060bcb670693a049cd0eba3483b8265d73ec1266f04dfcd7e44a9c9f599fbbeb THIRD_PARTY_LICENSES.txt
3743334b17709c9a6295e708e637015bc1c1c8def5845865f25b42385fbdf0e7 THIRD_PARTY_LICENSES.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
THIRD-PARTY LICENSES AND NOTICES

Generated by scripts/generate-third-party-notices.mjs. See THIRD_PARTY_NOTICES.md.
Cargo.lock SHA-256: 03b8161d54ecd1854fe55e1eb2ac5501fb6db36cf29299da265114745be033cd
Cargo.lock SHA-256: 58aeed4b348b2b9bab144eaee514aa96825e7650a0409f2fc2e98be9f27134bb
Rust: rustc 1.97.1 (8bab26f4f 2026-07-14)

SCOPE: browser-default/runtime = normal browser dependency path; browser-default/build = build/proc-macro path.
Expand Down
Binary file not shown.
Loading
Loading