Skip to content

Commit 351de2d

Browse files
authored
Add proposed binary format and initial prototype notes (#1)
With the intent to make the proposal concrete enough to implement.
1 parent ea16da7 commit 351de2d

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed

proposals/custom-rtts/Overview.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,3 +440,136 @@ TODO
440440
## Type Section Field Deduplication
441441

442442
TODO
443+
444+
## Binary Format
445+
446+
### Describes and Desciptor Clauses
447+
448+
In the formal syntax,
449+
we insert optional descriptor and describes clauses between `comptype`
450+
(or `sharecomptype` from shared-everything-threads)
451+
and `subtype`:
452+
453+
```
454+
descriptorcomptype ::=
455+
| 0x4D x:typeidx ct:sharecomptype => (descriptor x ct)
456+
| ct:sharecomptype => ct
457+
458+
describescomptype ::=
459+
| 0x4C x:typeidx ct:descriptorcomptype => (describes x ct)
460+
| ct:descriptorcomptype => ct
461+
462+
subtype ::=
463+
| 0x50 x*:vec(typeidx) ct:describescomptype => sub x* ct
464+
| 0x4F x*:vec(typeidx) ct:describescomptype => sub final x* ct
465+
| ct:describescomptype => sub final eps ct
466+
```
467+
468+
> TODO: Update the text format in the examples above to reflect this
469+
> factoring of the syntax.
470+
471+
### Exact Reference Types
472+
473+
Rather than use two new opcodes in the type opcode space
474+
to represent nullable and non-nullable exact reference types,
475+
we introduce just a single new prefix opcode that encode both:
476+
477+
```
478+
reftype :: ...
479+
| 0x62 0x64 ht:heaptype => ref exact ht
480+
| 0x62 0x63 ht:heaptype => ref null exact ht
481+
```
482+
483+
To make the most of the existing shorthands for nullable abstract heap types,
484+
we also allow using the exact prefix with those shorthands:
485+
486+
```
487+
reftype :: ...
488+
| 0x62 ht:absheaptype => ref null exact ht
489+
```
490+
491+
### Instructions
492+
493+
The existing `ref.test`, `ref.cast`, `br_on_cast` and `br_on_cast_fail` instructions
494+
need to be able to work with exact reference types.
495+
`ref.test` and `ref.cast` currently have two opcodes each:
496+
one for nullable target types and one for non-nullable target types.
497+
Rather than introducing two new opcodes for each of these instructions
498+
to allow for nullable exact and non-nullable exact target types,
499+
we introduce one new opcode for each that takes a full reference type
500+
rather than a heap type as its immediate.
501+
502+
```
503+
instr ::= ...
504+
| 0xFB 32:u32 rt:reftype => ref.test rt
505+
| 0xFB 33:u32 rt:reftype => ref.cast rt
506+
```
507+
508+
(`0xFB 31` is already used by `ref.i31_shared` in the shared-everything-threads proposal.)
509+
510+
Note that these new encodings can be used instead of the existing encodings
511+
to represent casts to inexact reference types.
512+
513+
> Note: We could alternatively restrict the new encoding to be usable only with exact types,
514+
> but this artificial restriction does not seem useful.
515+
516+
> Note: We could alternatively continue the existing encoding scheme,
517+
> at the cost of using 4 new opcodes instead of 2.
518+
519+
`br_on_cast` and `br_on_cast_fail` already encode the nullability of their
520+
input and output types in a "castflags" u8 immediate. Castflags is extended to encode
521+
exactness as well:
522+
523+
```
524+
castflags ::= ...
525+
| 4:u8 => (exact, eps)
526+
| 5:u8 => (null exact, eps)
527+
| 6:u8 => (exact, null)
528+
| 7:u8 => (null exact, null)
529+
| 8:u8 => (eps, exact)
530+
| 9:u8 => (null, exact)
531+
| 10:u8 => (eps, null exact)
532+
| 11:u8 => (null, null exact)
533+
| 12:u8 => (exact, exact)
534+
| 13:u8 => (null exact, exact)
535+
| 14:u8 => (exact, null exact)
536+
| 15:u8 => (null exact, null exact)
537+
```
538+
539+
Note that the bits now have the following meanings:
540+
541+
```
542+
bit 0: source nullability
543+
bit 1: target nullability
544+
bit 3: source exactness
545+
bit 4: target exactness
546+
```
547+
548+
The other new instructions are encoded as follows:
549+
550+
```
551+
instr ::= ...
552+
| 0xFB 34:u32 x:typeidx => ref.get_rtt x
553+
| 0xFB 35:u32 rt:reftype => ref.cast_rtt reftype
554+
| 0xFB 36:u32 (null_1? exact_1?, null_2? exact_2?):castflags
555+
l:labelidx ht_1:heaptype ht_2:heaptype =>
556+
br_on_cast_rtt l (ref null_1? exact_1? ht_1) (ref null_2? exact_2? ht_2)
557+
| 0xFB 37:u32 (null_1? exact_1?, null_2? exact_2?):castflags
558+
l:labelidx ht_1:heaptype ht_2:heaptype =>
559+
br_on_cast_rtt_fail l (ref null_1? exact_1? ht_1) (ref null_2? exact_2? ht_2)
560+
```
561+
562+
## Minimal Initial Prototyping for JS Interop
563+
564+
A truly minimal prototype for experimenting with JS interop can skip
565+
implementing most of the new features in this proposal:
566+
567+
- Arbitrary fields on custom RTTs.
568+
A minimal prototype can allow `descriptor` clauses only on empty structs.
569+
- Exact reference types.
570+
A minimal prototype can instead bake a custom RTT exactness check into the
571+
semantics of `struct.new` and `struct.new_default` to ensure soundness.
572+
- New instructions.
573+
A minimal prototype only needs to update `struct.new` and `struct.new_default`
574+
to take references to custom RTTs as necessary.
575+
It does not need to implement `ref.get_rtt` or any of the new RTT casts.

0 commit comments

Comments
 (0)