Skip to content

Commit 7c66f61

Browse files
Change parsing to unify indirect call signatures with the same structure
This is meant to implement the changes discussed in WebAssembly/design#452. This eliminates the need to declare an explicit type reference for indirectly-called functions, so I also tried to eliminate the redundancy and potential mismatch between a function's type reference and its directly declared parameters and result, so I made any function declaration implicitly introduce a type matching its directly declared parameters and result. But this approach makes an explicitly indexed type table much less useful, since you no longer have complete control over its contents. To resolve that, I removed the declarations, and references to, type table entries. The type table is created implicitly from the set of unique types used by func and call_indirect. I also made the syntax slightly more uniform by defining a func_type production in the form (func_type ...), and using it in both call_indirect and import. I did not change func to use it, but I will submit another PR if people like this change.
1 parent 8358778 commit 7c66f61

File tree

7 files changed

+43
-106
lines changed

7 files changed

+43
-106
lines changed

ml-proto/README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ expr:
131131
( tableswitch <var> <expr> <switch> <target> <case>* ) ;; = (label <var> (tableswitch <expr> <switch> <target> <case>*))
132132
( call <var> <expr>* )
133133
( call_import <var> <expr>* )
134-
( call_indirect <var> <expr> <expr>* )
134+
( call_indirect <func_type> <expr> <expr>* )
135135
( get_local <var> )
136136
( set_local <var> <expr> )
137137
( <type>.load((8|16)_<sign>)? <offset>? <align>? <expr> )
@@ -154,15 +154,14 @@ target:
154154
case:
155155
( case <var>? <expr>* ) ;; = (case <var>? (block <expr>*))
156156
157-
func: ( func <name>? <type>? <param>* <result>? <local>* <expr>* )
158-
type: ( type <var> )
157+
func: ( func <name>? <param>* <result>? <local>* <expr>* )
159158
param: ( param <type>* ) | ( param <name> <type> )
160159
result: ( result <type> )
161160
local: ( local <type>* ) | ( local <name> <type> )
162161
163162
module: ( module <type>* <func>* <global>* <import>* <export>* <table>* <memory>? )
164-
type: ( type <name>? ( func <param>* <result>? ) )
165-
import: ( import <name>? "<module_name>" "<func_name>" (param <type>* ) (result <type>)* )
163+
func_type: ( func_type <param>* <result>? )
164+
import: ( import <name>? "<module_name>" "<func_name>" <func_type> )
166165
export: ( export "<char>*" <var> )
167166
global: ( global <type>* ) | ( global <name> <type> )
168167
table: ( table <var>* )

ml-proto/host/lexer.mll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ rule token = parse
243243
| "grow_memory" { GROW_MEMORY }
244244
| "has_feature" { HAS_FEATURE }
245245

246-
| "type" { TYPE }
247246
| "func" { FUNC }
247+
| "func_type" { FUNC_TYPE }
248248
| "param" { PARAM }
249249
| "result" { RESULT }
250250
| "local" { LOCAL }

ml-proto/host/parser.mly

Lines changed: 14 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,6 @@ let label c x =
105105
try VarMap.find x.it c.labels
106106
with Not_found -> error x.at ("unknown label " ^ x.it)
107107

108-
let bind_type c x ty =
109-
if VarMap.mem x.it c.types.tmap then
110-
error x.at ("duplicate type " ^ x.it);
111-
c.types.tmap <- VarMap.add x.it (List.length c.types.tlist) c.types.tmap;
112-
c.types.tlist <- c.types.tlist @ [ty]
113-
114108
let bind category space x =
115109
if VarMap.mem x.it space.map then
116110
error x.at ("duplicate " ^ category ^ " " ^ x.it);
@@ -124,9 +118,6 @@ let bind_case c x = bind "case" c.cases x
124118
let bind_label c x =
125119
{c with labels = VarMap.add x.it 0 (VarMap.map ((+) 1) c.labels)}
126120

127-
let anon_type c ty =
128-
c.types.tlist <- c.types.tlist @ [ty]
129-
130121
let anon space n = space.count <- space.count + n
131122

132123
let anon_func c = anon c.funcs 1
@@ -137,19 +128,9 @@ let anon_label c = {c with labels = VarMap.map ((+) 1) c.labels}
137128

138129
let empty_type = {ins = []; out = None}
139130

140-
let explicit_decl c name t at =
141-
let x = name c type_ in
142-
if
143-
x.it < List.length c.types.tlist &&
144-
t <> empty_type &&
145-
t <> List.nth c.types.tlist x.it
146-
then
147-
error at "signature mismatch";
148-
x
149-
150-
let implicit_decl c t at =
131+
let lookup_type c t at =
151132
match Lib.List.index_of t c.types.tlist with
152-
| None -> let i = List.length c.types.tlist in anon_type c t; i @@ at
133+
| None -> let i = List.length c.types.tlist in c.types.tlist <- c.types.tlist @ [t]; i @@ at
153134
| Some i -> i @@ at
154135

155136
%}
@@ -159,7 +140,7 @@ let implicit_decl c t at =
159140
%token CALL CALL_IMPORT CALL_INDIRECT RETURN
160141
%token GET_LOCAL SET_LOCAL LOAD STORE LOAD_EXTEND STORE_WRAP OFFSET ALIGN
161142
%token CONST UNARY BINARY COMPARE CONVERT
162-
%token FUNC TYPE PARAM RESULT LOCAL
143+
%token FUNC FUNC_TYPE PARAM RESULT LOCAL
163144
%token MODULE MEMORY SEGMENT IMPORT EXPORT TABLE
164145
%token UNREACHABLE MEMORY_SIZE GROW_MEMORY HAS_FEATURE
165146
%token ASSERT_INVALID ASSERT_RETURN ASSERT_RETURN_NAN ASSERT_TRAP INVOKE
@@ -197,7 +178,7 @@ value_type_list :
197178
| /* empty */ { [] }
198179
| VALUE_TYPE value_type_list { $1 :: $2 }
199180
;
200-
func_type :
181+
signature :
201182
| /* empty */
202183
{ {ins = []; out = None} }
203184
| LPAR PARAM value_type_list RPAR
@@ -207,7 +188,9 @@ func_type :
207188
| LPAR RESULT VALUE_TYPE RPAR
208189
{ {ins = []; out = Some $3} }
209190
;
210-
191+
func_type :
192+
| LPAR FUNC_TYPE signature RPAR { $3 }
193+
;
211194

212195
/* Expressions */
213196

@@ -270,8 +253,9 @@ expr1 :
270253
tableswitch (l, e, $6 c'', $8 c'', es) }
271254
| CALL var expr_list { fun c -> call ($2 c func, $3 c) }
272255
| CALL_IMPORT var expr_list { fun c -> call_import ($2 c import, $3 c) }
273-
| CALL_INDIRECT var expr expr_list
274-
{ fun c -> call_indirect ($2 c type_, $3 c, $4 c) }
256+
| CALL_INDIRECT func_type expr expr_list
257+
{ let at = at () in
258+
fun c -> call_indirect (lookup_type c $2 at, $3 c, $4 c) }
275259
| GET_LOCAL var { fun c -> get_local ($2 c local) }
276260
| SET_LOCAL var expr { fun c -> set_local ($2 c local, $3 c) }
277261
| LOAD offset align expr
@@ -347,25 +331,14 @@ func_fields :
347331
fun c -> bind_local c $3; let f = (snd $6) c in
348332
{f with locals = $4 :: f.locals} }
349333
;
350-
type_use :
351-
| LPAR TYPE var RPAR { $3 }
352-
;
353334
func :
354-
| LPAR FUNC type_use func_fields RPAR
355-
{ let at = at () in
356-
fun c -> anon_func c; let t = explicit_decl c $3 (fst $4) at in
357-
fun () -> {((snd $4) (enter_func c)) with ftype = t} @@ at }
358-
| LPAR FUNC bind_var type_use func_fields RPAR /* Sugar */
359-
{ let at = at () in
360-
fun c -> bind_func c $3; let t = explicit_decl c $4 (fst $5) at in
361-
fun () -> {((snd $5) (enter_func c)) with ftype = t} @@ at }
362335
| LPAR FUNC func_fields RPAR /* Sugar */
363336
{ let at = at () in
364-
fun c -> anon_func c; let t = implicit_decl c (fst $3) at in
337+
fun c -> anon_func c; let t = lookup_type c (fst $3) at in
365338
fun () -> {((snd $3) (enter_func c)) with ftype = t} @@ at }
366339
| LPAR FUNC bind_var func_fields RPAR /* Sugar */
367340
{ let at = at () in
368-
fun c -> bind_func c $3; let t = implicit_decl c (fst $4) at in
341+
fun c -> bind_func c $3; let t = lookup_type c (fst $4) at in
369342
fun () -> {((snd $4) (enter_func c)) with ftype = t} @@ at }
370343
;
371344
@@ -390,34 +363,19 @@ memory :
390363
@@ at () }
391364
;
392365
393-
type_def :
394-
| LPAR TYPE LPAR FUNC func_type RPAR RPAR
395-
{ fun c -> anon_type c $5 }
396-
| LPAR TYPE bind_var LPAR FUNC func_type RPAR RPAR
397-
{ fun c -> bind_type c $3 $6 }
398-
;
399-
400366
table :
401367
| LPAR TABLE var_list RPAR
402368
{ fun c -> $3 c func }
403369
;
404370
405371
import :
406-
| LPAR IMPORT TEXT TEXT type_use RPAR
407-
{ let at = at () in
408-
fun c -> anon_import c; let itype = explicit_decl c $5 empty_type at in
409-
{itype; module_name = $3; func_name = $4} @@ at }
410-
| LPAR IMPORT bind_var TEXT TEXT type_use RPAR /* Sugar */
411-
{ let at = at () in
412-
fun c -> bind_import c $3; let itype = explicit_decl c $6 empty_type at in
413-
{itype; module_name = $4; func_name = $5} @@ at }
414372
| LPAR IMPORT TEXT TEXT func_type RPAR /* Sugar */
415373
{ let at = at () in
416-
fun c -> anon_import c; let itype = implicit_decl c $5 at in
374+
fun c -> anon_import c; let itype = lookup_type c $5 at in
417375
{itype; module_name = $3; func_name = $4} @@ at }
418376
| LPAR IMPORT bind_var TEXT TEXT func_type RPAR /* Sugar */
419377
{ let at = at () in
420-
fun c -> bind_import c $3; let itype = implicit_decl c $6 at in
378+
fun c -> bind_import c $3; let itype = lookup_type c $6 at in
421379
{itype; module_name = $4; func_name = $5} @@ at }
422380
;
423381
@@ -443,8 +401,6 @@ module_fields :
443401
| table module_fields
444402
{ fun c -> let m = $2 c in
445403
{m with table = ($1 c) @ m.table} }
446-
| type_def module_fields
447-
{ fun c -> $1 c; $2 c }
448404
| memory module_fields
449405
{ fun c -> let m = $2 c in
450406
match m.memory with

ml-proto/test/address.wast

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
(module
22
(memory 1024 (segment 0 "abcdefghijklmnopqrstuvwxyz"))
3-
(import $print "stdio" "print" (param i32))
3+
(import $print "stdio" "print" (func_type (param i32)))
44

55
(func $good (param $i i32)
66
(call_import $print (i32.load8_u offset=0 (get_local $i))) ;; 97 'a'

ml-proto/test/func_ptrs.wast

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,38 @@
11
(module
2-
(type (func)) ;; 0: void -> void
3-
(type $S (func)) ;; 1: void -> void
4-
(type (func (param))) ;; 2: void -> void
5-
(type (func (result i32))) ;; 3: void -> i32
6-
(type (func (param) (result i32))) ;; 4: void -> i32
7-
(type $T (func (param i32) (result i32))) ;; 5: i32 -> i32
8-
(type $U (func (param i32))) ;; 6: i32 -> void
9-
10-
(func (type 0))
11-
(func (type $S))
12-
13-
(func $one (type 4) (i32.const 13))
2+
(func $one (result i32) (i32.const 13))
143
(export "one" $one)
154

16-
(func $two (type $T) (i32.add (get_local 0) (i32.const 1)))
5+
(func $two (param i32) (result i32) (i32.add (get_local 0) (i32.const 1)))
176
(export "two" $two)
187

19-
;; Both signature and parameters are allowed (and required to match)
20-
;; since this allows the naming of parameters.
21-
(func $three (type $T) (param $a i32) (result i32) (i32.sub (get_local 0) (i32.const 2)))
8+
(func $three (param $a i32) (result i32) (i32.sub (get_local 0) (i32.const 2)))
229
(export "three" $three)
2310

24-
(import $print "stdio" "print" (type 6))
25-
(func $four (type $U) (call_import $print (get_local 0)))
11+
(import $print "stdio" "print" (func_type (param i32)))
12+
(func $four (param i32) (call_import $print (get_local 0)))
2613
(export "four" $four)
2714
)
2815
(assert_return (invoke "one") (i32.const 13))
2916
(assert_return (invoke "two" (i32.const 13)) (i32.const 14))
3017
(assert_return (invoke "three" (i32.const 13)) (i32.const 11))
3118
(invoke "four" (i32.const 83))
3219

33-
(assert_invalid (module (func (type 42))) "unknown function type 42")
34-
(assert_invalid (module (import "stdio" "print" (type 43))) "unknown function type 43")
35-
3620
(module
37-
(type $T (func (param) (result i32)))
38-
(type $U (func (param) (result i32)))
3921
(table $t1 $t2 $t3 $u1 $u2 $t1 $t3)
4022

41-
(func $t1 (type $T) (i32.const 1))
42-
(func $t2 (type $T) (i32.const 2))
43-
(func $t3 (type $T) (i32.const 3))
44-
(func $u1 (type $U) (i32.const 4))
45-
(func $u2 (type $U) (i32.const 5))
23+
(func $t1 (result i32) (i32.const 1))
24+
(func $t2 (result i32) (i32.const 2))
25+
(func $t3 (result i32) (i32.const 3))
26+
(func $u1 (result i64) (i64.const 4))
27+
(func $u2 (result i64) (i64.const 5))
4628

4729
(func $callt (param $i i32) (result i32)
48-
(call_indirect $T (get_local $i))
30+
(call_indirect (func_type (param) (result i32)) (get_local $i))
4931
)
5032
(export "callt" $callt)
5133

52-
(func $callu (param $i i32) (result i32)
53-
(call_indirect $U (get_local $i))
34+
(func $callu (param $i i32) (result i64)
35+
(call_indirect (func_type (param) (result i64)) (get_local $i))
5436
)
5537
(export "callu" $callu)
5638
)
@@ -69,8 +51,8 @@
6951
(assert_trap (invoke "callu" (i32.const 0)) "indirect call signature mismatch")
7052
(assert_trap (invoke "callu" (i32.const 1)) "indirect call signature mismatch")
7153
(assert_trap (invoke "callu" (i32.const 2)) "indirect call signature mismatch")
72-
(assert_return (invoke "callu" (i32.const 3)) (i32.const 4))
73-
(assert_return (invoke "callu" (i32.const 4)) (i32.const 5))
54+
(assert_return (invoke "callu" (i32.const 3)) (i64.const 4))
55+
(assert_return (invoke "callu" (i32.const 4)) (i64.const 5))
7456
(assert_trap (invoke "callu" (i32.const 5)) "indirect call signature mismatch")
7557
(assert_trap (invoke "callu" (i32.const 6)) "indirect call signature mismatch")
7658
(assert_trap (invoke "callu" (i32.const 7)) "undefined table index 7")

ml-proto/test/imports.wast

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
(module
2-
(import $print_i32 "stdio" "print" (param i32))
3-
(import $print_i64 "stdio" "print" (param i64))
4-
(import $print_i32_f32 "stdio" "print" (param i32 f32))
5-
(import $print_i64_f64 "stdio" "print" (param i64 f64))
2+
(import $print_i32 "stdio" "print" (func_type (param i32)))
3+
(import $print_i64 "stdio" "print" (func_type (param i64)))
4+
(import $print_i32_f32 "stdio" "print" (func_type (param i32 f32)))
5+
(import $print_i64_f64 "stdio" "print" (func_type (param i64 f64)))
66
(func $print32 (param $i i32)
77
(call_import $print_i32 (get_local $i))
88
(call_import $print_i32_f32

ml-proto/test/store_retval.wast

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
(module
22
(memory 100)
33

4-
(import $print_i32 "stdio" "print" (param i32))
5-
(import $print_i64 "stdio" "print" (param i64))
6-
(import $print_f32 "stdio" "print" (param f32))
7-
(import $print_f64 "stdio" "print" (param f64))
4+
(import $print_i32 "stdio" "print" (func_type (param i32)))
5+
(import $print_i64 "stdio" "print" (func_type (param i64)))
6+
(import $print_f32 "stdio" "print" (func_type (param f32)))
7+
(import $print_f64 "stdio" "print" (func_type (param f64)))
88

99
(func $run
1010
(local $i32 i32) (local $i64 i64) (local $f32 f32) (local $f64 f64)

0 commit comments

Comments
 (0)