Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[interpreter] Fix symbolic local resolution with typeuse #1213

Merged
merged 1 commit into from
Aug 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions document/core/exec/runtime.rst
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,8 @@ and a reference to the function's own :ref:`module instance <syntax-moduleinst>`
The values of the locals are mutated by respective :ref:`variable instructions <syntax-instr-variable>`.


.. _exec-expand:

Conventions
...........

Expand Down
2 changes: 1 addition & 1 deletion document/core/util/macros.def
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,7 @@

.. Stack, meta functions

.. |expand| mathdef:: \xref{exec/runtime}{syntax-frame}{\F{expand}}
.. |expand| mathdef:: \xref{exec/runtime}{exec-expand}{\F{expand}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an unrelated change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha, yeah, I didn't notice I still had that in my tree. One could argue it's somewhat related to typeuse, though, since it expands type uses in block types. :)



.. Administrative Instructions, terminals
Expand Down
63 changes: 38 additions & 25 deletions interpreter/text/parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,19 @@ let empty_types () = {space = empty (); list = []}

type context =
{ types : types; tables : space; memories : space;
funcs : space; locals : space; globals : space; labels : int32 VarMap.t }
funcs : space; locals : space; globals : space;
labels : int32 VarMap.t; deferred_locals : (unit -> unit) list ref
}

let empty_context () =
{ types = empty_types (); tables = empty (); memories = empty ();
funcs = empty (); locals = empty (); globals = empty ();
labels = VarMap.empty }
labels = VarMap.empty; deferred_locals = ref []
}

let force_locals (c : context) =
List.fold_right Stdlib.(@@) !(c.deferred_locals) ();
c.deferred_locals := []

let enter_func (c : context) =
{c with labels = VarMap.empty; locals = empty ()}
Expand All @@ -88,7 +95,7 @@ let lookup category space x =

let type_ (c : context) x = lookup "type" c.types.space x
let func (c : context) x = lookup "function" c.funcs x
let local (c : context) x = lookup "local" c.locals x
let local (c : context) x = force_locals c; lookup "local" c.locals x
let global (c : context) x = lookup "global" c.globals x
let table (c : context) x = lookup "table" c.tables x
let memory (c : context) x = lookup "memory" c.memories x
Expand All @@ -101,53 +108,57 @@ let func_type (c : context) x =
with Failure _ -> error x.at ("unknown type " ^ Int32.to_string x.it)


let anon category space n =
let i = space.count in
space.count <- Int32.add i n;
if I32.lt_u space.count n then
error no_region ("too many " ^ category ^ " bindings");
i

let bind category space x =
let i = anon category space 1l in
if VarMap.mem x.it space.map then
error x.at ("duplicate " ^ category ^ " " ^ x.it);
let i = space.count in
space.map <- VarMap.add x.it space.count space.map;
space.count <- Int32.add space.count 1l;
if space.count = 0l then
error x.at ("too many " ^ category ^ " bindings");
space.map <- VarMap.add x.it i space.map;
i

let bind_type (c : context) x ty =
c.types.list <- c.types.list @ [ty];
bind "type" c.types.space x
let bind_func (c : context) x = bind "function" c.funcs x
let bind_local (c : context) x = bind "local" c.locals x
let bind_local (c : context) x = force_locals c; bind "local" c.locals x
let bind_global (c : context) x = bind "global" c.globals x
let bind_table (c : context) x = bind "table" c.tables x
let bind_memory (c : context) x = bind "memory" c.memories x
let bind_label (c : context) x =
{c with labels = VarMap.add x.it 0l (VarMap.map (Int32.add 1l) c.labels)}

let anon category space n =
let i = space.count in
space.count <- Int32.add space.count n;
if I32.lt_u space.count n then
error no_region ("too many " ^ category ^ " bindings");
i

let anon_type (c : context) ty =
c.types.list <- c.types.list @ [ty];
anon "type" c.types.space 1l
let anon_func (c : context) = anon "function" c.funcs 1l
let anon_locals (c : context) ts =
ignore (anon "local" c.locals (Lib.List32.length ts))
let anon_locals (c : context) lazy_ts =
let f () =
ignore (anon "local" c.locals (Lib.List32.length (Lazy.force lazy_ts)))
in c.deferred_locals := f :: !(c.deferred_locals)
let anon_global (c : context) = anon "global" c.globals 1l
let anon_table (c : context) = anon "table" c.tables 1l
let anon_memory (c : context) = anon "memory" c.memories 1l
let anon_label (c : context) =
{c with labels = VarMap.map (Int32.add 1l) c.labels}


let inline_type (c : context) ft at =
match Lib.List.index_where (fun ty -> ty.it = ft) c.types.list with
| Some i -> Int32.of_int i @@ at
| None -> anon_type c (ft @@ at) @@ at

let inline_type_explicit (c : context) x ft at =
if ft <> FuncType ([], []) && ft <> func_type c x then
if ft = FuncType ([], []) then
(* Laziness ensures that type lookup is only triggered when
symbolic identifiers are used, and not for desugared functions *)
anon_locals c (lazy (let FuncType (ts, _) = func_type c x in ts))
else if ft <> func_type c x then
error at "inline function type does not match explicit type";
x

Expand Down Expand Up @@ -536,12 +547,14 @@ func :
func_fields :
| type_use func_fields_body
{ fun c x at ->
let y = inline_type_explicit c ($1 c type_) (fst $2) at in
[{(snd $2 (enter_func c)) with ftype = y} @@ at], [], [] }
let c' = enter_func c in
let y = inline_type_explicit c' ($1 c' type_) (fst $2) at in
[{(snd $2 c') with ftype = y} @@ at], [], [] }
| func_fields_body /* Sugar */
{ fun c x at ->
let y = inline_type c (fst $1) at in
[{(snd $1 (enter_func c)) with ftype = y} @@ at], [], [] }
let c' = enter_func c in
let y = inline_type c' (fst $1) at in
[{(snd $1 c') with ftype = y} @@ at], [], [] }
| inline_import type_use func_fields_import /* Sugar */
{ fun c x at ->
let y = inline_type_explicit c ($2 c type_) $3 at in
Expand Down Expand Up @@ -575,7 +588,7 @@ func_fields_body :
| LPAR PARAM value_type_list RPAR func_fields_body
{ let FuncType (ins, out) = fst $5 in
FuncType ($3 @ ins, out),
fun c -> ignore (anon_locals c $3); snd $5 c }
fun c -> anon_locals c (lazy $3); snd $5 c }
| LPAR PARAM bind_var VALUE_TYPE RPAR func_fields_body /* Sugar */
{ let FuncType (ins, out) = fst $6 in
FuncType ($4 :: ins, out),
Expand All @@ -592,7 +605,7 @@ func_body :
{ fun c -> let c' = anon_label c in
{ftype = -1l @@ at(); locals = []; body = $1 c'} }
| LPAR LOCAL value_type_list RPAR func_body
{ fun c -> ignore (anon_locals c $3); let f = $5 c in
{ fun c -> anon_locals c (lazy $3); let f = $5 c in
{f with locals = $3 @ f.locals} }
| LPAR LOCAL bind_var VALUE_TYPE RPAR func_body /* Sugar */
{ fun c -> ignore (bind_local c $3); let f = $6 c in
Expand Down
40 changes: 40 additions & 0 deletions test/core/func.wast
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,46 @@
"unknown type"
)

(assert_malformed
(module quote
"(func $f (result f64) (f64.const 0))" ;; adds implicit type definition
"(func $g (param i32))" ;; reuses explicit type definition
"(func $h (result f64) (f64.const 1))" ;; reuses implicit type definition
"(type $t (func (param i32)))"

"(func (type 2) (param i32))" ;; does not exist
)
"unknown type"
)

(module
(type $proc (func (result i32)))
(type $sig (func (param i32) (result i32)))

(func (export "f") (type $sig)
(local $var i32)
(local.get $var)
)

(func $g (type $sig)
(local $var i32)
(local.get $var)
)
(func (export "g") (type $sig)
(call $g (local.get 0))
)

(func (export "p") (type $proc)
(local $var i32)
(local.set 0 (i32.const 42))
(local.get $var)
)
)

(assert_return (invoke "f" (i32.const 42)) (i32.const 0))
(assert_return (invoke "g" (i32.const 42)) (i32.const 0))
(assert_return (invoke "p") (i32.const 42))


(module
(type $sig (func))
Expand Down