Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit 33d8b36

Browse files
authored
Merge pull request #339 from WebAssembly/final
Add `final` attribute
2 parents 0475570 + f9cf112 commit 33d8b36

File tree

20 files changed

+302
-83
lines changed

20 files changed

+302
-83
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
- run: pip install bikeshed && bikeshed update
6464
- run: pip install six
6565
- run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended
66-
- run: pip install sphinx==4.0.0
66+
- run: pip install sphinx==5.1.0
6767
- run: cd document/core && make all
6868
- uses: actions/upload-artifact@v2
6969
with:

interpreter/binary/decode.ml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,12 @@ let sub_type s =
256256
| Some i when i = -0x30 land 0x7f ->
257257
skip 1 s;
258258
let xs = vec (var_type u32) s in
259-
SubT (xs, str_type s)
260-
| _ -> SubT ([], str_type s)
259+
SubT (NoFinal, xs, str_type s)
260+
| Some i when i = -0x32 land 0x7f ->
261+
skip 1 s;
262+
let xs = vec (var_type u32) s in
263+
SubT (Final, xs, str_type s)
264+
| _ -> SubT (Final, [], str_type s)
261265

262266
let def_type s =
263267
match peek s with

interpreter/binary/encode.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,9 @@ struct
173173
| DefFuncT ft -> s7 (-0x20); func_type ft
174174

175175
let sub_type = function
176-
| SubT ([], st) -> str_type st
177-
| SubT (xs, st) -> s7 (-0x30); vec (var_type u32) xs; str_type st
176+
| SubT (Final, [], st) -> str_type st
177+
| SubT (Final, xs, st) -> s7 (-0x32); vec (var_type u32) xs; str_type st
178+
| SubT (NoFinal, xs, st) -> s7 (-0x30); vec (var_type u32) xs; str_type st
178179

179180
let def_type = function
180181
| RecT [st] -> sub_type st

interpreter/exec/eval.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ let rec step (c : config) : config =
244244
| CallIndirect (x, y), Num (I32 i) :: vs ->
245245
let f = func_ref c.frame.inst x i e.at in
246246
if
247-
Match.eq_var_type [] (DynX (type_ c.frame.inst y)) (DynX (Func.type_inst_of f))
247+
Match.match_var_type [] (DynX (Func.type_inst_of f)) (DynX (type_ c.frame.inst y))
248248
then
249249
vs, [Invoke f @@ e.at]
250250
else

interpreter/host/spectest.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ let memory =
2929

3030
let func f ft =
3131
let x = Types.alloc_uninit () in
32-
Types.init x (CtxT ([(DynX x, SubT ([], DefFuncT ft))], 0l));
32+
Types.init x (CtxT ([(DynX x, SubT (Final, [], DefFuncT ft))], 0l));
3333
ExternFunc (Func.alloc_host x (f ft))
3434

3535
let print_value v =

interpreter/script/js.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ let value v =
270270
| Ref _ -> assert false
271271

272272
let invoke ft vs at =
273-
let dt = RecT [SubT ([], DefFuncT ft)] in
273+
let dt = RecT [SubT (Final, [], DefFuncT ft)] in
274274
[dt @@ at], FuncImport (subject_type_idx @@ at) @@ at,
275275
List.concat (List.map value vs) @ [Call (subject_idx @@ at) @@ at]
276276

@@ -380,7 +380,8 @@ let assert_return ress ts at =
380380
let i32 = NumT I32T
381381
let anyref = RefT (Null, AnyHT)
382382
let eqref = RefT (Null, EqHT)
383-
let func_def_type ts1 ts2 at = RecT [SubT ([], DefFuncT (FuncT (ts1, ts2)))] @@ at
383+
let func_def_type ts1 ts2 at =
384+
RecT [SubT (Final, [], DefFuncT (FuncT (ts1, ts2)))] @@ at
384385

385386
let wrap item_name wrap_action wrap_assertion at =
386387
let itypes, idesc, action = wrap_action at in

interpreter/syntax/free.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ let str_type = function
107107
| DefFuncT ft -> func_type ft
108108

109109
let sub_type = function
110-
| SubT (xs, st) -> list var_type xs ++ str_type st
110+
| SubT (_fin, xs, st) -> list var_type xs ++ str_type st
111111

112112
let def_type = function
113113
| RecT sts -> list sub_type sts

interpreter/syntax/types.ml

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ type name = Utf8.unicode
77
type null = NoNull | Null
88
type mut = Cons | Var
99
type init = Set | Unset
10+
type final = NoFinal | Final
1011
type 'a limits = {min : 'a; max : 'a option}
1112

1213
type type_addr = ..
@@ -38,7 +39,7 @@ type str_type =
3839
| DefArrayT of array_type
3940
| DefFuncT of func_type
4041

41-
type sub_type = SubT of var list * str_type
42+
type sub_type = SubT of final * var list * str_type
4243
type def_type = RecT of sub_type list
4344
type ctx_type = CtxT of (var * sub_type) list * int32
4445

@@ -176,7 +177,11 @@ let string_of_null = function
176177
| NoNull -> ""
177178
| Null -> "null "
178179

179-
and string_of_mut s = function
180+
let string_of_final = function
181+
| NoFinal -> ""
182+
| Final -> " final"
183+
184+
let string_of_mut s = function
180185
| Cons -> s
181186
| Var -> "(mut " ^ s ^ ")"
182187

@@ -241,9 +246,10 @@ let string_of_str_type = function
241246
| DefFuncT ft -> "func " ^ string_of_func_type ft
242247

243248
let string_of_sub_type = function
244-
| SubT ([], st) -> string_of_str_type st
245-
| SubT (xs, st) ->
246-
String.concat " " ("sub" :: List.map string_of_var xs) ^
249+
| SubT (Final, [], st) -> string_of_str_type st
250+
| SubT (fin, xs, st) ->
251+
String.concat " "
252+
(("sub" ^ string_of_final fin) :: List.map string_of_var xs) ^
247253
" (" ^ string_of_str_type st ^ ")"
248254

249255
let string_of_def_type = function
@@ -355,7 +361,7 @@ let subst_str_type s = function
355361
| DefFuncT ft -> DefFuncT (subst_func_type s ft)
356362

357363
let subst_sub_type s = function
358-
| SubT (xs, st) -> SubT (List.map s xs, subst_str_type s st)
364+
| SubT (fin, xs, st) -> SubT (fin, List.map s xs, subst_str_type s st)
359365

360366
let subst_def_type s = function
361367
| RecT sts -> RecT (List.map (subst_sub_type s) sts)
@@ -413,7 +419,7 @@ let unroll_ctx_type (ct : ctx_type) : sub_type =
413419

414420
let expand_ctx_type (ct : ctx_type) : str_type =
415421
match unroll_ctx_type ct with
416-
| SubT (_, st) -> st
422+
| SubT (_, _, st) -> st
417423

418424

419425
(* Dynamic Types *)

interpreter/text/arrange.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ let null = function
8686
| NoNull -> ""
8787
| Null -> "null "
8888

89+
let final = function
90+
| NoFinal -> ""
91+
| Final -> " final"
92+
8993
let ref_type_raw (nul, t) =
9094
Atom (null nul ^ heap_type t)
9195

@@ -110,9 +114,10 @@ let str_type st =
110114
| DefFuncT ft -> func_type ft
111115

112116
let sub_type = function
113-
| SubT ([], st) -> str_type st
114-
| SubT (xs, st) ->
115-
Node (String.concat " " ("sub" :: List.map var_type xs), [str_type st])
117+
| SubT (Final, [], st) -> str_type st
118+
| SubT (fin, xs, st) ->
119+
Node (String.concat " "
120+
(("sub" ^ final fin ):: List.map var_type xs), [str_type st])
116121

117122
let def_type i j st =
118123
Node ("type $" ^ nat (i + j), [sub_type st])

interpreter/text/lexer.mll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ rule token = parse
175175
| "field" -> FIELD
176176
| "mut" -> MUT
177177
| "sub" -> SUB
178+
| "final" -> FINAL
178179
| "rec" -> REC
179180

180181
| "nop" -> NOP

interpreter/text/parser.mly

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ let anon_fields (c : context) n at = bind "field" c.fields n at
212212

213213

214214
let inline_func_type (c : context) ft at =
215-
let st = SubT ([], DefFuncT ft) in
215+
let st = SubT (Final, [], DefFuncT ft) in
216216
match
217217
Lib.List.index_where (function
218218
| CtxT ([(_, st')], 0l) -> st = st'
@@ -248,7 +248,7 @@ let inline_func_type_explicit (c : context) x ft at =
248248
%token ANYREF NULLREF EQREF I31REF STRUCTREF ARRAYREF
249249
%token FUNCREF NULLFUNCREF EXTERNREF NULLEXTERNREF
250250
%token ANY NONE EQ I31 REF NOFUNC EXTERN NOEXTERN NULL
251-
%token MUT FIELD STRUCT ARRAY SUB REC
251+
%token MUT FIELD STRUCT ARRAY SUB FINAL REC
252252
%token UNREACHABLE NOP DROP SELECT
253253
%token BLOCK END IF THEN ELSE LOOP
254254
%token BR BR_IF BR_TABLE BR_ON_NULL BR_ON_NON_NULL BR_ON_CAST BR_ON_CAST_FAIL
@@ -439,9 +439,11 @@ str_type :
439439
| LPAR FUNC func_type RPAR { fun c -> DefFuncT ($3 c) }
440440

441441
sub_type :
442-
| str_type { fun c -> SubT ([], $1 c) }
442+
| str_type { fun c -> SubT (Final, [], $1 c) }
443443
| LPAR SUB var_list str_type RPAR
444-
{ fun c -> SubT (List.map (fun x -> StatX x.it) ($3 c type_), $4 c) }
444+
{ fun c -> SubT (NoFinal, List.map (fun x -> StatX x.it) ($3 c type_), $4 c) }
445+
| LPAR SUB FINAL var_list str_type RPAR
446+
{ fun c -> SubT (Final, List.map (fun x -> StatX x.it) ($4 c type_), $5 c) }
445447

446448
table_type :
447449
| limits ref_type { fun c -> TableT ($1, $2 c) }

interpreter/valid/match.ml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ and eq_str_type c dt1 dt2 =
127127
| DefFuncT ft1, DefFuncT ft2 -> eq_func_type c ft1 ft2
128128
| _, _ -> false
129129

130-
and eq_sub_type c (SubT (xs1, st1)) (SubT (xs2, st2)) =
131-
eq_list eq_var_type c xs1 xs2 && eq_str_type c st1 st2
130+
and eq_sub_type c (SubT (fin1, xs1, st1)) (SubT (fin2, xs2, st2)) =
131+
fin1 = fin2 && eq_list eq_var_type c xs1 xs2 && eq_str_type c st1 st2
132132

133133
and eq_def_type c (RecT sts1) (RecT sts2) =
134134
eq_list eq_sub_type c sts1 sts2
@@ -261,10 +261,9 @@ and match_str_type c dt1 dt2 =
261261
and match_var_type c x1 x2 =
262262
eq_var x1 x2 ||
263263
not (is_rec_var x1 || is_rec_var x2) && eq_ctx_type c (lookup c x1) (lookup c x2) ||
264-
let SubT (xs, _) = unroll_ctx_type (lookup c x1) in
264+
let SubT (_fin, xs, _st) = unroll_ctx_type (lookup c x1) in
265265
List.exists (fun x -> match_var_type c x x2) xs
266266

267-
268267
let match_table_type c (TableT (lim1, t1)) (TableT (lim2, t2)) =
269268
match_limits c lim1 lim2 && eq_ref_type c t1 t2
270269

interpreter/valid/valid.ml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,16 @@ let check_str_type (c : context) (st : str_type) at =
170170
| DefFuncT ft -> check_func_type c ft at
171171

172172
let check_sub_type (c : context) (st : sub_type) x at =
173-
let SubT (xs, st) = st in
173+
let SubT (fin, xs, st) = st in
174174
check_str_type c st at;
175175
List.iter (fun xi ->
176176
let xi = as_stat_var xi in
177177
require (xi < x) at
178178
("forward use of type " ^ I32.to_string_u xi ^ " in sub type definition");
179-
require (match_str_type c.types st (expand_ctx_type (type_ c (xi @@ at)))) at
179+
let SubT (fini, _, sti) = unroll_ctx_type (type_ c (xi @@ at)) in
180+
require (fini = NoFinal) at
181+
("sub type " ^ I32.to_string_u x ^ " has final super type " ^ I32.to_string_u xi);
182+
require (match_str_type c.types st sti) at
180183
("sub type " ^ I32.to_string_u x ^ " does not match super type " ^ I32.to_string_u xi)
181184
) xs
182185

proposals/gc/MVP.md

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ New abbreviations are introduced for reference types in binary and text format,
111111
- Note that the number of type section entries is now the number of recursion groups rather than the number of individual types.
112112

113113
* `subtype` is a new category of type defining a single type, as a subtype of possible other types
114-
- `subtype ::= sub <typeidx>* <strtype>`
115-
- the preexisting syntax with no `sub` clause is redefined to be a shorthand for a `sub` clause with empty `typeidx` list: `<strtype> == sub () <strtype>`
114+
- `subtype ::= sub final? <typeidx>* <strtype>`
115+
- the preexisting syntax with no `sub` clause is redefined to be a shorthand for a `sub` clause with empty `typeidx` list: `<strtype> == sub final () <strtype>`
116116
- Note: This allows multiple supertypes. For the MVP, it is restricted to at most one supertype.
117117

118118
* `strtype` is a new category of types covering the different forms of concrete structural reference types
@@ -155,8 +155,13 @@ In the case of `C.funcs`, it is an invariant that all types [expand](#auxiliary-
155155

156156
* Expanding a type definition unrolls it and returns its plain definition
157157
- `expand($t) = expand(<ctxtype>)` iff `$t = <ctxtype>`
158-
- `expand(<ctxtype>) = <strtype>`
159-
- where `unroll(<ctxttype>) = sub x* <strtype>`
158+
- `expand(<ctxtype>) = <strtype>`
159+
- where `unroll(<ctxttype>) = sub final? x* <strtype>`
160+
161+
* Finality of a type just checks the flag
162+
- `final($t) = final(<ctxtype>)` iff `$t = <ctxtype>`
163+
- `final(<ctxtype>) = final? =/= empty`
164+
- where `unroll(<ctxttype>) = sub final? x* <strtype>`
160165

161166

162167
#### External Types
@@ -189,10 +194,11 @@ Some of the rules define a type as `ok` for a certain index, written `ok(x)`. Th
189194
- iff `<subtype0> ok($t)`
190195
- and `<subtype>* ok($t+1)`
191196

192-
* an individual subtype is valid if its definition is valid, matches every supertype, and no supertype has an index higher than its own
193-
- `sub $t* <strtype> ok($t')`
197+
* an individual subtype is valid if its definition is valid, matches every supertype, and no supertype is final or has an index higher than its own
198+
- `sub final? $t* <strtype> ok($t')`
194199
- iff `<strtype> ok`
195200
- and `(<strtype> <: expand($t))*`
201+
- and `(not final($t))*`
196202
- and `($t < $t')*`
197203
- Note: the upper bound on the supertype indices ensures that subtyping hierarchies are never circular, because definitions need to be ordered.
198204

@@ -253,10 +259,11 @@ With that:
253259
- iff `(<subtype> == <subtype'>)*`
254260
- Note: This rule is only used on types that have been tied, which prevents looping.
255261

256-
* notably, two subtypes are equivalent if their structure is equivalent and they have equivalent supertypes
257-
- `(sub $t* <strtype>) == (sub $t'* <strtype'>)`
262+
* notably, two subtypes are equivalent if their structure is equivalent, they have equivalent supertypes, and their finality flag matches
263+
- `(sub final1? $t* <strtype>) == (sub final2? $t'* <strtype'>)`
258264
- iff `<strtype> == <strtype'>`
259265
- and `($t == $t')*`
266+
- and `final1? = final2?`
260267

261268
Example: As explained above, the mutually recursive types
262269
```
@@ -311,7 +318,7 @@ In the [existing rules](https://github.com/WebAssembly/function-references/propo
311318
* Type indices are subtypes if they either define [equivalent](#type-equivalence) types or a suitable (direct or indirect) subtype relation has been declared
312319
- `$t <: $t'`
313320
- if `$t = <ctxtype>` and `$t' = <ctxtype'>` and `<ctxtype> == <ctxtype'>`
314-
- or `unroll($t) = sub $t1* $t'' $t2* strtype` and `$t'' <: $t'`
321+
- or `unroll($t) = sub final? $t1* $t'' $t2* strtype` and `$t'' <: $t'`
315322
- Note: This rule climbs the supertype hierarchy until an equivalent type has been found. Effectively, this means that subtyping is "nominal" modulo type canonicalisation.
316323

317324

@@ -446,7 +453,7 @@ Note: This assumes that there is at most one supertype. For hierarchies with mul
446453

447454
Example: Consider three types and corresponding RTTs:
448455
```
449-
(type $A (struct))
456+
(type $A (sub (struct)))
450457
(type $B (sub $A (struct (field i32))))
451458
(type $C (sub $B (struct (field i32 i64))))
452459
```
@@ -713,6 +720,7 @@ The opcode for heap types is encoded as an `s33`.
713720
| -0x21 | `struct ft*` | `ft* : vec(fieldtype)` | shorthand |
714721
| -0x22 | `array ft` | `ft : fieldtype` | shorthand |
715722
| -0x30 | `sub $t* st` | `$t* : vec(typeidx)`, `st : strtype` | |
723+
| -0x32 | `sub final $t* st` | `$t* : vec(typeidx)`, `st : strtype` | |
716724

717725
#### Defined Types
718726

@@ -722,6 +730,7 @@ The opcode for heap types is encoded as an `s33`.
722730
| -0x22 | `array ft` | `ft : fieldtype` | shorthand |
723731
| -0x30 | `sub $t* st` | `$t* : vec(typeidx)`, `st : strtype` | shorthand |
724732
| -0x31 | `rec dt*` | `dt* : vec(subtype)` | |
733+
| -0x32 | `sub final $t* st` | `$t* : vec(typeidx)`, `st : strtype` | shorthand |
725734

726735
#### Field Types
727736

@@ -830,9 +839,10 @@ C |- array ft ok
830839
```
831840
C |- st ok
832841
(C |- st <: expand(C(x)))*
842+
(not final(C(x)))*
833843
(x < x')*
834-
--------------------------
835-
C |- sub x* st ok(x')
844+
----------------------------
845+
C |- sub final? x* st ok(x')
836846
837847
C |- st ok(x)
838848
C |- st'* ok(x+1)
@@ -929,8 +939,9 @@ C |- array ft == array ft'
929939
```
930940
(C |- x == x')*
931941
C |- st == st'
932-
-----------------------------
933-
C |- sub x* st == sub x'* st'
942+
final1? = final2?
943+
---------------------------------------------
944+
C |- sub final1? x* st == sub final2? x'* st'
934945
```
935946

936947
### Subtyping
@@ -942,9 +953,9 @@ C |- x == x'
942953
------------
943954
C |- x <: x'
944955
945-
unroll(C(x)) = sub (x1* x'' x2*) st
956+
unroll(C(x)) = sub final? (x1* x'' x2*) st
946957
C |- x'' <: x'
947-
-----------------------------------
958+
------------------------------------------
948959
C |- x <: x'
949960
```
950961

test/core/gc/br_on_cast.wast

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
;; Concrete Types
8787

8888
(module
89-
(type $t0 (struct))
89+
(type $t0 (sub (struct)))
9090
(type $t1 (sub $t0 (struct (field i32))))
9191
(type $t1' (sub $t0 (struct (field i32))))
9292
(type $t2 (sub $t1 (struct (field i32 i32))))

test/core/gc/br_on_cast_fail.wast

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
;; Concrete Types
8787

8888
(module
89-
(type $t0 (struct))
89+
(type $t0 (sub (struct)))
9090
(type $t1 (sub $t0 (struct (field i32))))
9191
(type $t1' (sub $t0 (struct (field i32))))
9292
(type $t2 (sub $t1 (struct (field i32 i32))))

0 commit comments

Comments
 (0)