v149 · WebAssembly

WebAssembly Custom Descriptors

WasmGC structs can now carry a custom descriptor — a companion type whose first field becomes the struct's JavaScript prototype. Call wasmObj.myMethod() directly, with no hand-written wrapper class, and share type metadata across all instances instead of storing it per-object.

concepts

  1. Prototype Bridge

    Side-by-side comparison: the old pattern (JS wrapper class around raw Wasm exports) versus the new pattern (Wasm struct whose descriptor wires up the prototype automatically). Live code editor lets you call methods on both and see the difference.

  2. Type-Safe Objects

    Custom descriptors introduce exact types — a Counter descriptor cannot be applied to a Queue struct. Explore how the type boundary is enforced and why it matters for safe multi-type Wasm modules.

  3. Method Dispatch Bench

    Benchmark three dispatch patterns: JS wrapper class, per-object closures, and shared prototype (simulating custom descriptor). Side-by-side timing shows why the shared-prototype approach wins on both speed and memory — and how the real WasmGC custom descriptor takes it even further.

  4. JS Interop Explorer

    Live REPL with two sandboxed contexts — the old per-closure Counter class and a new CounterProto that simulates the custom descriptor pattern. Evaluate arbitrary expressions, use preset snippets for instanceof, prototype chain checks, and method calls, and see the outputs side by side.

  5. Memory Footprint Demo

    Sliders for object count (10–5000) and methods per type (1–20) drive a live memory model comparing three allocation patterns: per-instance closures, JS wrapper class, and custom descriptor. Instance layout visualisation shows exactly which fields each approach stores per object.

  6. Descriptor vs Wrapper Comparison

    Step through six stages of the object lifecycle — module instantiation, object creation, method call, instanceof check, prototype chain traversal, and memory layout — for both the legacy JS wrapper class and the new custom descriptor pattern. A side-by-side annotated code view and a live simulation that runs both patterns measure creation time and method-call throughput.

    Step-through Prototype chain Memory

why it shipped

WasmGC structs have long been a mismatch with JavaScript's object model: every time you wanted to call a method, you either exported a free function (counter_get(ptr)) or built a hand-written JS proxy class that duplicated the type hierarchy. Custom descriptors let the Wasm module itself declare which JS prototype its struct objects should inherit, eliminating the boilerplate entirely and reducing per-instance memory (the descriptor object is shared at the type level, not copied per instance). The j2cl Java-to-Wasm compiler is the first major toolchain to use this to expose compiled Java classes with natural JS method-call syntax.

references

implementation reference

Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗