Environment:** Elements 13.0.0.3081 and 13.0.0.3123 (develop), Island-WebAssembly (wasm32), SDK WebAssembly 1.1, Windows x86_64, Oxygene, tested in Chromium.
Summary: A dynamic-typed property read/write intermittently traps with unreachable inside DynamicHelpers.GetMember/SetMember, killing the WASM instance. Same code, same input, usually works then traps — not tied to a specific property, object shape, or call site. DevTools shows only a truncated top frame; capturing via window.addEventListener('error', ...) gives the real stack:
RuntimeError: unreachable
at ElementsRaiseException
at ExternalCalls.RaiseException
at DynamicHelpers.GetMember
at <application code — one dynamic .property read>
...
at System.Reflection.MethodInfo.Invoke
Most reliable repro pattern: WebSocket app, JSON response parsed and read via dynamic. First request/response cycle in a session succeeds ~every time; the second cycle traps ~every time (7/7 fails vs. 0/10 fails across trials).
Ruled out (each tested over multiple trials): raw dynamic.property vs. a JS helper wrapper — same result; bumping initial WASM memory ~300× to prevent memory.grow() — no change; forcing BoehmGCExt.Collect(0) before the access — no change; releasing retained view/data state between the two cycles — no change; switching to the RTL’s typed WebSocket/[DynamicInterface] interop instead of raw dynamic — trap still reproduces via the same __island_call_delegate path (rules out reflection-invoke as the cause), though extracting .data off the native MessageEvent this way was separately unreliable (nil instead of a trap).
Ask: Known issue with DynamicHelpers/the Boehm GC WASM port? Any way to disable/suspend GC around a critical section (only Collect/SuppressFinalize are public)? Happy to put together a minimal repro if useful.
Most likely this is an ordinary managed exception being rendered as unreachable, not the primary fault.
The current WASM RTL explicitly calls llvm.trap for every unhandled exception unless Wasm EH is enabled. Check the app’s .elements first:
<EnableWasmExceptions>True</EnableWasmExceptions>
That setting defaults to false, while the non-EH path logs “Fatal exception in WebAssembly!” and traps. With it enabled in Chromium, the second-cycle failure should expose its real exception rather than killing the instance at DynamicHelpers.GetMember.
DynamicHelpers is probably just the visible call site: it dispatches an IDynamicObject, and EcmaScriptObject.GetMember then calls the JS glue’s __island_get. That glue blindly evaluates handletable[thisval][property]; a freed/stale handle, null receiver, or a throwing JS getter would all appear as this stack.
That was it — thank you. Added EnableWasmExceptions, rebuilt (linker picked up IslandEH.fx as expected), and the trap is gone: the previous ~7/7-failing repro (login → first load_layout → second load_layout) now runs clean across 5/5 fresh-tab trials, no trapped instance, no dropped socket.
Underlying bug is still there, just non-fatal now — we get a real, catchable exception instead:
NullReferenceException: Member access on null reference
Narrowed it down: it fires when a dynamic value is passed across a JS call boundary if that value’s object graph contains a genuine JS array anywhere in it (nested is fine — doesn’t have to be the top-level value). In our case: a WS message envelope {action, status, payload: {..., data: [...]}} — just reading action/status off the envelope (not the array itself) throws. Tried both raw dot-access (msg.action) and our usual bridge helper (dwin.someJsFn(msg, 'action'), a plain JS function taking msg as an arg) — both fail identically, so it’s not an access-syntax thing, it’s the marshaling of the containing object itself.
Bug, not testcase. Reasoning: same failure via raw dot-access and a plain JS helper function (rules out an access-syntax issue), and it fires reading unrelated keys without ever touching the array.
Update since my last reply: the “needs a JS array in the object” theory was actually wrong. Shipped the same data as a JSON string instead (parsed separately, no array anywhere in the message) — still fails, same exception, same line. Also sent the exact same array-free payload twice in a row — the second one fails identically. So it’s not about arrays or payload shape at all.
Attached is a much smaller repro (no business-specific code, just the WebSocket/message-bus/router/small-layout-engine shape). It fails on the very first load_layout in a fresh page load — no second round-trip needed. One thing worth flagging: our full app fails reliably on the second call, but this smaller version fails on the first — so “second call” isn’t a fixed trigger condition either. Whatever it actually is seems to depend on something about the compiled binary or accumulated runtime state, not a simple call count. README in the zip has more detail.