Skip to content

Commit ea16da7

Browse files
committed
Describe WebAssembly.setDescriptorPrototype
And add a full example with counters implemented in Wasm being accessed from JS.
1 parent 4288a69 commit ea16da7

File tree

1 file changed

+79
-1
lines changed

1 file changed

+79
-1
lines changed

proposals/custom-rtts/Overview.md

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,85 @@ C |- br_on_cast_rtt_fail l rt_1 rt_2 : t* rt_1 (ref null exact_1 y) -> t* rt_2
353353

354354
## JS Prototypes
355355

356-
TODO
356+
In JS engines,
357+
WebAssembly RTTs correspond to JS shape descriptors.
358+
Custom RTTs act as first-class handles to the engine-managed RTTs,
359+
so they can serve as extension points for the JS reflection of the Wasm objects they describe.
360+
361+
We introduce a new `WebAssembly.setDescriptorPrototype()` API
362+
that takes a custom RTT instance and a prototype object.
363+
The provided prototype will be attached to the custom RTT
364+
and will become the prototype for the JS reflection
365+
of all Wasm objects the custom RTT describes.
366+
367+
The following is a full example that uses `WebAssembly.setDescriptorPrototype()`
368+
to allow JS to call `get()` and `inc()` methods on counter objects implemented in
369+
WebAssembly.
370+
371+
> Note: If there is demand for it,
372+
> a similar API could configure property names that JS could use to access fields
373+
> of the described WebAssembly objects.
374+
375+
```wasm
376+
;; counter.wasm
377+
(module
378+
(rec
379+
(type $counter (struct (descriptor $counter.vtable (field $val i32))))
380+
(type $counter.vtable (struct
381+
(describes $counter)
382+
(field $get (ref $get_t))
383+
(field $inc (ref $inc_t))
384+
))
385+
(type $get_t (func (param (ref null $counter)) (result i32)))
386+
(type $inc_t (func (param (ref null $counter))))
387+
)
388+
389+
(elem declare func $counter.get $counter.inc)
390+
391+
(global $counter.vtable (export "counter.vtable") (ref exact $counter.vtable)
392+
(struct.new $counter.vtable
393+
(ref.func $counter.get)
394+
(ref.func $counter.inc)
395+
)
396+
)
397+
398+
(global $counter (export "counter") (ref $counter)
399+
(struct.new_default $counter
400+
(global.get $counter.vtable)
401+
)
402+
)
403+
404+
(func $counter.get (export "counter.get") (type $get_t) (param (ref null $counter)) (result i32)
405+
(struct.get $counter $val (local.get 0))
406+
)
407+
408+
(func $counter.inc (export "counter.inc") (type $inc_t) (param (ref null $counter))
409+
(struct.set $counter $val
410+
(local.get 0)
411+
(i32.add
412+
(struct.get $counter $val (local.get 0))
413+
(i32.const 1)
414+
)
415+
)
416+
)
417+
)
418+
```
419+
420+
```js
421+
// counter.js
422+
var {module, instance} = await WebAssembly.instantiateStreaming(fetch('counter.wasm'));
423+
424+
WebAssembly.setDescriptorPrototype(instance.exports['counter.vtable'], {
425+
get: function() { instance.exports['counter.get'](this); },
426+
inc: function() { return instance.exports['counter.get'](this); }
427+
});
428+
429+
var counter = instance.exports['counter'];
430+
431+
console.log(counter.get()); // 0
432+
counter.inc();
433+
console.log(counter.get()); // 1
434+
```
357435

358436
## Declarative Prototype Initialization
359437

0 commit comments

Comments
 (0)