Summary
Mango's source compiles to WASM cleanly (no compile-time errors) but the produced .wasm is rejected by V8 at instantiation time:
Boot error: CompileError: WebAssembly.instantiate(): Compiling function #1174 failed: expected 1 elements on the stack for return, found 0 @+1652382
This is invalid WASM — a function declared to return a value, but its body falls through to return without pushing the value first. The validator catches it; instantiation fails; the app never boots.
Environment
- Perry: 0.5.1008
- Target:
--target web
- Mango source:
https://github.com/MangoQuery/app at commit 2863473
- Browser: Chrome (V8) headless
--headless=new
- macOS arm64, host is also where the build was produced
Reproducing
git clone https://github.com/MangoQuery/app
cd app
PERRY_ALLOW_PERRY_FEATURES=1 PERRY_ALLOW_DYNAMIC_STDLIB=1 \
perry compile src/app.ts --target web -o dist/mango.html
# Serve and load in Chrome (any HTTP server, file:// also reproduces in
# permissive contexts). Console + DevTools shows the CompileError above.
The Mango source is ~5000 lines and uses: async functions extensively, perry/ui widgets including Toggle/Picker/SecureField/ZStack/SplitView/ProgressView, perry/thread, perry/system Keychain, better-sqlite3 (gated to native via __platform__), @perryts/mongodb (also native-only), and a generated DOM bridge via the web target's WASM<->JS shim.
Minimal repro doesn't trigger it
A small test app does compile + run successfully:
import { App, VStack, Text, Button } from 'perry/ui';
const b = Button('Hi', () => { console.log('clicked'); });
App({ title: 'Tiny', width: 400, height: 300,
body: VStack(0, [Text('Hello'), b]) });
Compiles to a 203 KB self-contained HTML; loads cleanly in headless Chrome; body renders "Hello\nHi"; no console errors. So the bug isn't in the runtime trampoline or general control-flow emission — it's something pattern-specific in Mango's source.
What function #1174 might be
Without symbols on the wasm side I can't tell which JS function maps to #1174. Notable patterns in Mango that might be involved (educated guesses, not validated):
-
restoreLastSession is split into a sync entry + an async tail specifically to dodge a different Perry async-codegen bug (CFTimer-driven promise-resolution spin at 100% CPU). The sync wrapper looks like:
function restoreLastSession(): void {
const lastUri = getState('lastConnUri');
const lastName = getState('lastConnName');
const lastId = getState('lastConnId');
if (!lastUri) return;
restoreLastSessionAsync(lastUri, lastName, lastId);
}
Early-return-without-value in a function whose call site doesn't use the return value.
-
Many handlers shaped async () => { ... await ... ... if (!ok) return; ... } — early returns inside async closures.
-
Recursive renderJsonNode(value, label, path, depth) that returns a Widget and has a branch that returns headBtn (single value) and another branch that returns VStack(0, [headBtn, childStack]) — both branches return values, but Perry's inference might be losing track in one branch.
-
Generator-like state machines aren't used, no try/finally without explicit return.
Happy to bisect if helpful — let me know what shape of repro would land best (e.g. a stripped-down branch that still triggers it).
Related
Summary
Mango's source compiles to WASM cleanly (no compile-time errors) but the produced
.wasmis rejected by V8 at instantiation time:This is invalid WASM — a function declared to return a value, but its body falls through to
returnwithout pushing the value first. The validator catches it; instantiation fails; the app never boots.Environment
--target webhttps://github.com/MangoQuery/appat commit2863473--headless=newReproducing
The Mango source is ~5000 lines and uses: async functions extensively, perry/ui widgets including Toggle/Picker/SecureField/ZStack/SplitView/ProgressView, perry/thread, perry/system Keychain, better-sqlite3 (gated to native via
__platform__), @perryts/mongodb (also native-only), and a generated DOM bridge via the web target's WASM<->JS shim.Minimal repro doesn't trigger it
A small test app does compile + run successfully:
Compiles to a 203 KB self-contained HTML; loads cleanly in headless Chrome; body renders "Hello\nHi"; no console errors. So the bug isn't in the runtime trampoline or general control-flow emission — it's something pattern-specific in Mango's source.
What function #1174 might be
Without symbols on the wasm side I can't tell which JS function maps to #1174. Notable patterns in Mango that might be involved (educated guesses, not validated):
restoreLastSessionis split into a sync entry + an async tail specifically to dodge a different Perry async-codegen bug (CFTimer-driven promise-resolution spin at 100% CPU). The sync wrapper looks like:Early-return-without-value in a function whose call site doesn't use the return value.
Many handlers shaped
async () => { ... await ... ... if (!ok) return; ... }— early returns inside async closures.Recursive
renderJsonNode(value, label, path, depth)that returns aWidgetand has a branch that returnsheadBtn(single value) and another branch that returnsVStack(0, [headBtn, childStack])— both branches return values, but Perry's inference might be losing track in one branch.Generator-like state machines aren't used, no try/finally without explicit return.
Happy to bisect if helpful — let me know what shape of repro would land best (e.g. a stripped-down branch that still triggers it).
Related
sheetCreateblank body (CLOSED, fixed in 0.5.1008) — same family of "dispatch vs runtime shape" issues per the v0.5.345 audit note. This new one is different (WASM validator vs runtime arg shape) but the v0.5.345 paragraph mentionedPicker,tabbarAddTab,frameSplitCreate,TextAreaconstructor as still-unaligned — Mango uses Picker and TextArea, may be a downstream symptom of one of those.