diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 29293ea2..02d092f8 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -135,6 +135,9 @@ let sized f s = open Types +let zero s = expect 0x00 s "zero byte expected" +let var s = vu32 s + let num_type s = match vs7 s with | -0x01 -> I32Type @@ -189,17 +192,17 @@ let global_type s = let mut = mutability s in GlobalType (t, mut) +let event_type s = + zero s; at var s + (* Decode instructions *) open Ast open Operators -let var s = vu32 s - let op s = u8 s let end_ s = expect 0x0b s "END opcode expected" -let zero s = expect 0x00 s "zero byte expected" let memop s = let align = vu32 s in @@ -527,6 +530,7 @@ let id s = | 10 -> `CodeSection | 11 -> `DataSection | 12 -> `DataCountSection + | 13 -> `EventSection | _ -> error s (pos s) "malformed section id" ) bo @@ -555,6 +559,7 @@ let import_desc s = | 0x01 -> TableImport (table_type s) | 0x02 -> MemoryImport (memory_type s) | 0x03 -> GlobalImport (global_type s) + | 0x04 -> EventImport (event_type s) | _ -> error s (pos s - 1) "malformed import kind" let import s = @@ -592,6 +597,14 @@ let memory s = let memory_section s = section `MemorySection (vec (at memory)) [] s +(* Event section *) + +let event s = + let etype = event_type s in + {etype} + +let event_section s = + section `EventSection (vec (at event)) [] s (* Global section *) @@ -612,6 +625,7 @@ let export_desc s = | 0x01 -> TableExport (at var s) | 0x02 -> MemoryExport (at var s) | 0x03 -> GlobalExport (at var s) + | 0x04 -> EventExport (at var s) | _ -> error s (pos s - 1) "malformed export kind" let export s = @@ -787,6 +801,8 @@ let module_ s = iterate custom_section s; let memories = memory_section s in iterate custom_section s; + let events = event_section s in + iterate custom_section s; let globals = global_section s in iterate custom_section s; let exports = export_section s in @@ -812,7 +828,8 @@ let module_ s = let funcs = List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at) func_types func_bodies - in {types; tables; memories; globals; funcs; imports; exports; elems; datas; start} + in {types; tables; memories; events; globals; funcs; imports; exports; elems; + datas; start} let decode name bs = at module_ (stream name bs) diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 4485966b..a848a871 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -90,6 +90,9 @@ let encode m = (* Types *) open Types + open Source + + let var x = vu32 x.it let num_type = function | I32Type -> vs7 (-0x01) @@ -118,6 +121,8 @@ let encode m = let memory_type = function | MemoryType lim -> limits vu32 lim + let event_type x = vu32 0x00l; var x + let mutability = function | Immutable -> u8 0 | Mutable -> u8 1 @@ -127,7 +132,6 @@ let encode m = (* Expressions *) - open Source open Ast open Values @@ -136,8 +140,6 @@ let encode m = let memop {align; offset; _} = vu32 (Int32.of_int align); vu32 offset - let var x = vu32 x.it - let block_type = function | VarBlockType x -> vs33 x.it | ValBlockType None -> vs7 (-0x40) @@ -426,6 +428,7 @@ let encode m = | TableImport t -> u8 0x01; table_type t | MemoryImport t -> u8 0x02; memory_type t | GlobalImport t -> u8 0x03; global_type t + | EventImport t -> u8 0x04; event_type t let import im = let {module_name; item_name; idesc} = im.it in @@ -456,6 +459,12 @@ let encode m = let memory_section mems = section 5 (vec memory) mems (mems <> []) + (* Event section *) + let event (e : event) = u8 0x00; var e.it.etype + + let event_section es = + section 13 (vec event) es (es <> []) + (* Global section *) let global g = let {gtype; ginit} = g.it in @@ -471,6 +480,7 @@ let encode m = | TableExport x -> u8 1; var x | MemoryExport x -> u8 2; var x | GlobalExport x -> u8 3; var x + | EventExport x -> u8 4; var x let export ex = let {name = n; edesc} = ex.it in @@ -579,6 +589,7 @@ let encode m = func_section m.it.funcs; table_section m.it.tables; memory_section m.it.memories; + event_section m.it.events; global_section m.it.globals; export_section m.it.exports; start_section m.it.start; diff --git a/interpreter/exec/eval.ml b/interpreter/exec/eval.ml index 0db5a228..a3a06e32 100644 --- a/interpreter/exec/eval.ml +++ b/interpreter/exec/eval.ml @@ -85,6 +85,7 @@ let type_ (inst : module_inst) x = lookup "type" inst.types x let func (inst : module_inst) x = lookup "function" inst.funcs x let table (inst : module_inst) x = lookup "table" inst.tables x let memory (inst : module_inst) x = lookup "memory" inst.memories x +let event (inst : module_inst) x = lookup "event" inst.events x let global (inst : module_inst) x = lookup "global" inst.globals x let elem (inst : module_inst) x = lookup "element segment" inst.elems x let data (inst : module_inst) x = lookup "data segment" inst.datas x @@ -580,6 +581,9 @@ let create_memory (inst : module_inst) (mem : memory) : memory_inst = let {mtype} = mem.it in Memory.alloc mtype +let create_event (inst : module_inst) (e : event) : event_inst = + Event.alloc (type_ inst e.it.etype) + let create_global (inst : module_inst) (glob : global) : global_inst = let {gtype; ginit} = glob.it in let v = eval_const inst ginit in @@ -593,6 +597,7 @@ let create_export (inst : module_inst) (ex : export) : export_inst = | TableExport x -> ExternTable (table inst x) | MemoryExport x -> ExternMemory (memory inst x) | GlobalExport x -> ExternGlobal (global inst x) + | EventExport x -> ExternEvent (event inst x) in (name, ext) let create_elem (inst : module_inst) (seg : elem_segment) : elem_inst = @@ -612,6 +617,7 @@ let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst) | ExternFunc func -> {inst with funcs = func :: inst.funcs} | ExternTable tab -> {inst with tables = tab :: inst.tables} | ExternMemory mem -> {inst with memories = mem :: inst.memories} + | ExternEvent event -> {inst with events = event :: inst.events} | ExternGlobal glob -> {inst with globals = glob :: inst.globals} let init_func (inst : module_inst) (func : func_inst) = @@ -654,7 +660,7 @@ let run_start start = let init (m : module_) (exts : extern list) : module_inst = let - { imports; tables; memories; globals; funcs; types; + { imports; tables; memories; events; globals; funcs; types; exports; elems; datas; start } = m.it in @@ -670,6 +676,7 @@ let init (m : module_) (exts : extern list) : module_inst = { inst1 with tables = inst1.tables @ List.map (create_table inst1) tables; memories = inst1.memories @ List.map (create_memory inst1) memories; + events = inst1.events @ List.map (create_event inst1) events; globals = inst1.globals @ List.map (create_global inst1) globals; } in diff --git a/interpreter/runtime/event.ml b/interpreter/runtime/event.ml new file mode 100644 index 00000000..b3e1c816 --- /dev/null +++ b/interpreter/runtime/event.ml @@ -0,0 +1,10 @@ +open Types + +type event = {ty : func_type} +type t = event + +let alloc ty = + {ty} + +let type_of evt = + evt.ty diff --git a/interpreter/runtime/event.mli b/interpreter/runtime/event.mli new file mode 100644 index 00000000..42c24fb9 --- /dev/null +++ b/interpreter/runtime/event.mli @@ -0,0 +1,7 @@ +open Types + +type event = {ty : func_type} +type t = event + +val alloc : func_type -> event +val type_of : event -> func_type diff --git a/interpreter/runtime/instance.ml b/interpreter/runtime/instance.ml index efc230e0..e55f0a4f 100644 --- a/interpreter/runtime/instance.ml +++ b/interpreter/runtime/instance.ml @@ -6,6 +6,7 @@ type module_inst = funcs : func_inst list; tables : table_inst list; memories : memory_inst list; + events : event_inst list; globals : global_inst list; exports : export_inst list; elems : elem_inst list; @@ -15,6 +16,7 @@ type module_inst = and func_inst = module_inst ref Func.t and table_inst = Table.t and memory_inst = Memory.t +and event_inst = Event.t and global_inst = Global.t and export_inst = Ast.name * extern and elem_inst = Values.ref_ list ref @@ -24,6 +26,7 @@ and extern = | ExternFunc of func_inst | ExternTable of table_inst | ExternMemory of memory_inst + | ExternEvent of event_inst | ExternGlobal of global_inst @@ -47,14 +50,15 @@ let () = (* Auxiliary functions *) let empty_module_inst = - { types = []; funcs = []; tables = []; memories = []; globals = []; - exports = []; elems = []; datas = [] } + { types = []; funcs = []; tables = []; memories = []; events = []; + globals = []; exports = []; elems = []; datas = [] } let extern_type_of = function | ExternFunc func -> ExternFuncType (Func.type_of func) | ExternTable tab -> ExternTableType (Table.type_of tab) | ExternMemory mem -> ExternMemoryType (Memory.type_of mem) | ExternGlobal glob -> ExternGlobalType (Global.type_of glob) + | ExternEvent event -> ExternEventType (Event.type_of event) let export inst name = try Some (List.assoc name inst.exports) with Not_found -> None diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index 3eacacca..de589970 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -215,6 +215,7 @@ let print_import m im = | ExternFuncType t -> "func", string_of_func_type t | ExternTableType t -> "table", string_of_table_type t | ExternMemoryType t -> "memory", string_of_memory_type t + | ExternEventType t -> "event", string_of_func_type t | ExternGlobalType t -> "global", string_of_global_type t in Printf.printf " import %s \"%s\" \"%s\" : %s\n" @@ -228,6 +229,7 @@ let print_export m ex = | ExternFuncType t -> "func", string_of_func_type t | ExternTableType t -> "table", string_of_table_type t | ExternMemoryType t -> "memory", string_of_memory_type t + | ExternEventType t -> "event", string_of_func_type t | ExternGlobalType t -> "global", string_of_global_type t in Printf.printf " export %s \"%s\" : %s\n" diff --git a/interpreter/syntax/ast.ml b/interpreter/syntax/ast.ml index 38e55062..45dbd938 100644 --- a/interpreter/syntax/ast.ml +++ b/interpreter/syntax/ast.ml @@ -150,6 +150,13 @@ and memory' = mtype : memory_type; } +type event = event' Source.phrase +and event' = +{ + etype : var; +} + + type segment_mode = segment_mode' Source.phrase and segment_mode' = | Passive @@ -182,6 +189,7 @@ and export_desc' = | TableExport of var | MemoryExport of var | GlobalExport of var + | EventExport of var type export = export' Source.phrase and export' = @@ -196,6 +204,7 @@ and import_desc' = | TableImport of table_type | MemoryImport of memory_type | GlobalImport of global_type + | EventImport of var type import = import' Source.phrase and import' = @@ -212,6 +221,7 @@ and module_' = globals : global list; tables : table list; memories : memory list; + events : event list; funcs : func list; start : var option; elems : elem_segment list; @@ -229,6 +239,7 @@ let empty_module = globals = []; tables = []; memories = []; + events = []; funcs = []; start = None; elems = []; @@ -248,6 +259,7 @@ let import_type (m : module_) (im : import) : extern_type = | FuncImport x -> ExternFuncType (func_type_for m x) | TableImport t -> ExternTableType t | MemoryImport t -> ExternMemoryType t + | EventImport x -> ExternEventType (func_type_for m x) | GlobalImport t -> ExternGlobalType t let export_type (m : module_) (ex : export) : extern_type = @@ -268,6 +280,10 @@ let export_type (m : module_) (ex : export) : extern_type = | GlobalExport x -> let gts = globals its @ List.map (fun g -> g.it.gtype) m.it.globals in ExternGlobalType (nth gts x.it) + | EventExport x -> + let ets = + events its @ List.map (fun (e : event) -> func_type_for m e.it.etype) m.it.events + in ExternEventType (nth ets x.it) let string_of_name n = let b = Buffer.create 16 in diff --git a/interpreter/syntax/free.ml b/interpreter/syntax/free.ml index 33bfefc0..fa381d8d 100644 --- a/interpreter/syntax/free.ml +++ b/interpreter/syntax/free.ml @@ -9,6 +9,7 @@ type t = globals : Set.t; tables : Set.t; memories : Set.t; + events : Set.t; funcs : Set.t; elems : Set.t; datas : Set.t; @@ -22,6 +23,7 @@ let empty : t = globals = Set.empty; tables = Set.empty; memories = Set.empty; + events = Set.empty; funcs = Set.empty; elems = Set.empty; datas = Set.empty; @@ -35,6 +37,7 @@ let union (s1 : t) (s2 : t) : t = globals = Set.union s1.globals s2.globals; tables = Set.union s1.tables s2.tables; memories = Set.union s1.memories s2.memories; + events = Set.union s1.events s2.events; funcs = Set.union s1.funcs s2.funcs; elems = Set.union s1.elems s2.elems; datas = Set.union s1.datas s2.datas; @@ -46,6 +49,7 @@ let types s = {empty with types = s} let globals s = {empty with globals = s} let tables s = {empty with tables = s} let memories s = {empty with memories = s} +let events s = {empty with events = s} let funcs s = {empty with funcs = s} let elems s = {empty with elems = s} let datas s = {empty with datas = s} @@ -93,6 +97,7 @@ let global (g : global) = const g.it.ginit let func (f : func) = {(block f.it.body) with locals = Set.empty} let table (t : table) = empty let memory (m : memory) = empty +let event (e : event) = empty let segment_mode f (m : segment_mode) = match m.it with @@ -112,6 +117,7 @@ let export_desc (d : export_desc) = | FuncExport x -> funcs (var x) | TableExport x -> tables (var x) | MemoryExport x -> memories (var x) + | EventExport x -> events (var x) | GlobalExport x -> globals (var x) let import_desc (d : import_desc) = @@ -119,6 +125,7 @@ let import_desc (d : import_desc) = | FuncImport x -> types (var x) | TableImport tt -> empty | MemoryImport mt -> empty + | EventImport x -> types (var x) | GlobalImport gt -> empty let export (e : export) = export_desc e.it.edesc diff --git a/interpreter/syntax/free.mli b/interpreter/syntax/free.mli index dc01edc0..fa41783d 100644 --- a/interpreter/syntax/free.mli +++ b/interpreter/syntax/free.mli @@ -6,6 +6,7 @@ type t = globals : Set.t; tables : Set.t; memories : Set.t; + events : Set.t; funcs : Set.t; elems : Set.t; datas : Set.t; @@ -25,6 +26,7 @@ val global : Ast.global -> t val func : Ast.func -> t val table : Ast.table -> t val memory : Ast.memory -> t +val event : Ast.event -> t val elem : Ast.elem_segment -> t val data : Ast.data_segment -> t val export : Ast.export -> t diff --git a/interpreter/syntax/types.ml b/interpreter/syntax/types.ml index 6a80308e..db812957 100644 --- a/interpreter/syntax/types.ml +++ b/interpreter/syntax/types.ml @@ -8,13 +8,15 @@ type func_type = FuncType of stack_type * stack_type type 'a limits = {min : 'a; max : 'a option} type mutability = Immutable | Mutable -type table_type = TableType of Int32.t limits * ref_type -type memory_type = MemoryType of Int32.t limits +type table_type = TableType of int32 limits * ref_type +type memory_type = MemoryType of int32 limits +type event_type = EventType of int32 type global_type = GlobalType of value_type * mutability type extern_type = | ExternFuncType of func_type | ExternTableType of table_type | ExternMemoryType of memory_type + | ExternEventType of func_type | ExternGlobalType of global_type type pack_size = Pack8 | Pack16 | Pack32 @@ -51,6 +53,8 @@ let memories = Lib.List.map_filter (function ExternMemoryType t -> Some t | _ -> None) let globals = Lib.List.map_filter (function ExternGlobalType t -> Some t | _ -> None) +let events = + Lib.List.map_filter (function ExternEventType t -> Some t | _ -> None) (* Subtyping *) @@ -76,7 +80,8 @@ let match_global_type gt1 gt2 = let match_extern_type et1 et2 = match et1, et2 with - | ExternFuncType ft1, ExternFuncType ft2 -> match_func_type ft1 ft2 + | ExternFuncType ft1, ExternFuncType ft2 + | ExternEventType ft1, ExternEventType ft2 -> match_func_type ft1 ft2 | ExternTableType tt1, ExternTableType tt2 -> match_table_type tt1 tt2 | ExternMemoryType mt1, ExternMemoryType mt2 -> match_memory_type mt1 mt2 | ExternGlobalType gt1, ExternGlobalType gt2 -> match_global_type gt1 gt2 @@ -133,3 +138,4 @@ let string_of_extern_type = function | ExternTableType tt -> "table " ^ string_of_table_type tt | ExternMemoryType mt -> "memory " ^ string_of_memory_type mt | ExternGlobalType gt -> "global " ^ string_of_global_type gt + | ExternEventType ft -> "event " ^ string_of_func_type ft diff --git a/interpreter/text/arrange.ml b/interpreter/text/arrange.ml index 01e9c8ad..e421bec2 100644 --- a/interpreter/text/arrange.ml +++ b/interpreter/text/arrange.ml @@ -359,12 +359,23 @@ let data i seg = Node ("data $" ^ nat i, segment_mode "memory" dmode @ break_bytes dinit) +(* Events *) + +let event_with_name name (e : event) = + Node ("event" ^ name, + [Node ("type " ^ var (e.it.etype), [])] + ) + +let event_with_index off i e = + event_with_name (" $" ^ nat (off + i)) e + + (* Modules *) let typedef i ty = Node ("type $" ^ nat i, [struct_type ty.it]) -let import_desc fx tx mx gx d = +let import_desc fx tx mx ex gx d = match d.it with | FuncImport x -> incr fx; Node ("func $" ^ nat (!fx - 1), [Node ("type", [atom var x])]) @@ -374,11 +385,13 @@ let import_desc fx tx mx gx d = incr mx; memory 0 (!mx - 1) ({mtype = t} @@ d.at) | GlobalImport t -> incr gx; Node ("global $" ^ nat (!gx - 1), [global_type t]) + | EventImport x -> + incr ex; Node ("event $" ^ nat (!ex - 1), [Node ("type", [atom var x])]) -let import fx tx mx gx im = +let import fx tx mx ex gx im = let {module_name; item_name; idesc} = im.it in Node ("import", - [atom name module_name; atom name item_name; import_desc fx tx mx gx idesc] + [atom name module_name; atom name item_name; import_desc fx tx mx ex gx idesc] ) let export_desc d = @@ -386,6 +399,7 @@ let export_desc d = | FuncExport x -> Node ("func", [atom var x]) | TableExport x -> Node ("table", [atom var x]) | MemoryExport x -> Node ("memory", [atom var x]) + | EventExport x -> Node ("event", [atom var x]) | GlobalExport x -> Node ("global", [atom var x]) let export ex = @@ -407,13 +421,15 @@ let module_with_var_opt x_opt m = let fx = ref 0 in let tx = ref 0 in let mx = ref 0 in + let ex = ref 0 in let gx = ref 0 in - let imports = list (import fx tx mx gx) m.it.imports in + let imports = list (import fx tx mx ex gx) m.it.imports in Node ("module" ^ var_opt x_opt, listi typedef m.it.types @ imports @ listi (table !tx) m.it.tables @ listi (memory !mx) m.it.memories @ + listi (event_with_index !ex) m.it.events @ listi (global !gx) m.it.globals @ listi (func_with_index !fx) m.it.funcs @ list export m.it.exports @ diff --git a/interpreter/text/lexer.mll b/interpreter/text/lexer.mll index a4e91401..02376521 100644 --- a/interpreter/text/lexer.mll +++ b/interpreter/text/lexer.mll @@ -357,6 +357,7 @@ rule token = parse | "global" { GLOBAL } | "table" { TABLE } | "memory" { MEMORY } + | "event" { EVENT } | "elem" { ELEM } | "data" { DATA } | "declare" { DECLARE } diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index d423ee74..8ed472e3 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -72,14 +72,14 @@ let empty_types () = {space = empty (); list = []} type context = { types : types; tables : space; memories : space; - funcs : space; locals : space; globals : space; + events : space; funcs : space; locals : space; globals : space; datas : space; elems : 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 (); + events = empty (); funcs = empty (); locals = empty (); globals = empty (); datas = empty (); elems = empty (); labels = VarMap.empty; deferred_locals = ref [] } @@ -101,6 +101,7 @@ 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 +let event (c : context) x = lookup "event" c.events x let elem (c : context) x = lookup "elem segment" c.elems x let data (c : context) x = lookup "data segment" c.datas x let label (c : context) x = @@ -134,6 +135,7 @@ 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_event (c : context) x = bind "event" c.events x let bind_elem (c : context) x = bind "elem segment" c.elems x let bind_data (c : context) x = bind "data segment" c.datas x let bind_label (c : context) x = @@ -150,6 +152,7 @@ let anon_locals (c : context) lazy_ts = 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_event (c : context) = anon "event" c.events 1l let anon_elem (c : context) = anon "elem segment" c.elems 1l let anon_data (c : context) = anon "data segment" c.datas 1l let anon_label (c : context) = @@ -186,7 +189,7 @@ let inline_type_explicit (c : context) x ft at = %token CONST UNARY BINARY TEST COMPARE CONVERT %token REF_NULL REF_FUNC REF_EXTERN REF_IS_NULL %token FUNC START TYPE PARAM RESULT LOCAL GLOBAL -%token TABLE ELEM MEMORY DATA DECLARE OFFSET ITEM IMPORT EXPORT +%token TABLE ELEM MEMORY EVENT DATA DECLARE OFFSET ITEM IMPORT EXPORT %token MODULE BIN QUOTE %token SCRIPT REGISTER INVOKE GET %token ASSERT_MALFORMED ASSERT_INVALID ASSERT_SOFT_INVALID ASSERT_UNLINKABLE @@ -842,6 +845,48 @@ memory_fields : [{dinit = $3; dmode = Active {index = x; offset} @@ at} @@ at], [], [] } +event : + | LPAR EVENT bind_var_opt event_fields RPAR + { let at = at () in + fun c -> let x = $3 c anon_event bind_event @@ at in fun () -> $4 c x at } + +event_fields : + | type_use func_type + { fun c x at -> + let etype = inline_type_explicit c ($1 c type_) $2 at in + [{etype} @@ at], [], [] } + | func_type /* Sugar */ + { fun c x at -> + let etype = inline_type c $1 at in + [{etype} @@ at], [], [] } + | inline_import type_use event_fields_import /* Sugar */ + { fun c x at -> + let y = inline_type_explicit c ($2 c type_) $3 at in + [], + [{ module_name = fst $1; item_name = snd $1; + idesc = EventImport y @@ at } @@ at ], [] } + | inline_import event_fields_import /* Sugar */ + { fun c x at -> + let y = inline_type c $2 at in + [], + [{ module_name = fst $1; item_name = snd $1; + idesc = EventImport y @@ at } @@ at ], [] } + | inline_export event_fields /* Sugar */ + { fun c x at -> + let evs, ims, exs = $2 c x at in evs, ims, $1 (EventExport x) c :: exs } + +event_fields_import : /* Sugar */ + | event_fields_import_result { $1 } + | LPAR PARAM value_type_list RPAR event_fields_import + { let FuncType (ins, out) = $5 in FuncType ($3 @ ins, out) } + | LPAR PARAM bind_var value_type RPAR event_fields_import /* Sugar */ + { let FuncType (ins, out) = $6 in FuncType ($4 :: ins, out) } + +event_fields_import_result : /* Sugar */ + | /* empty */ { FuncType ([], []) } + | LPAR RESULT value_type_list RPAR event_fields_import_result + { let FuncType (ins, out) = $5 in FuncType (ins, $3 @ out) } + global : | LPAR GLOBAL bind_var_opt global_fields RPAR { let at = at () in @@ -877,6 +922,13 @@ import_desc : | LPAR MEMORY bind_var_opt memory_type RPAR { fun c -> ignore ($3 c anon_memory bind_memory); fun () -> MemoryImport $4 } + | LPAR EVENT bind_var_opt type_use RPAR + { fun c -> ignore ($3 c anon_event bind_event); + fun () -> EventImport ($4 c type_) } + | LPAR EVENT bind_var_opt func_type RPAR /* Sugar */ + { let at4 = ati 4 in + fun c -> ignore ($3 c anon_event bind_event); + fun () -> EventImport (inline_type c $4 at4) } | LPAR GLOBAL bind_var_opt global_type RPAR { fun c -> ignore ($3 c anon_global bind_global); fun () -> GlobalImport $4 } @@ -894,6 +946,7 @@ export_desc : | LPAR FUNC var RPAR { fun c -> FuncExport ($3 c func) } | LPAR TABLE var RPAR { fun c -> TableExport ($3 c table) } | LPAR MEMORY var RPAR { fun c -> MemoryExport ($3 c memory) } + | LPAR EVENT var RPAR { fun c -> EventExport ($3 c event) } | LPAR GLOBAL var RPAR { fun c -> GlobalExport ($3 c global) } export : @@ -950,6 +1003,13 @@ module_fields1 : error (List.hd m.imports).at "import after memory definition"; { m with memories = mems @ m.memories; datas = data @ m.datas; imports = ims @ m.imports; exports = exs @ m.exports } } + | event module_fields + { fun c -> let ef = $1 c in let mf = $2 c in + fun () -> let events, ims, exs = ef () in let m = mf () in + if events <> [] && m.imports <> [] then + error (List.hd m.imports).at "import after event definition"; + { m with events = events @ m.events; + imports = ims @ m.imports; exports = exs @ m.exports } } | func module_fields { fun c -> let ff = $1 c in let mf = $2 c in fun () -> let funcs, ims, exs = ff () in let m = mf () in diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index be8097ea..57a4a8fe 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -20,6 +20,7 @@ type context = funcs : func_type list; tables : table_type list; memories : memory_type list; + events : event_type list; globals : global_type list; elems : ref_type list; datas : unit list; @@ -31,7 +32,7 @@ type context = let empty_context = { types = []; funcs = []; tables = []; memories = []; - globals = []; elems = []; datas = []; + events = []; globals = []; elems = []; datas = []; locals = []; results = []; labels = []; refs = Free.empty } @@ -44,6 +45,7 @@ let type_ (c : context) x = lookup "type" c.types x let func (c : context) x = lookup "function" c.funcs x let table (c : context) x = lookup "table" c.tables x let memory (c : context) x = lookup "memory" c.memories x +let event (c : context) x = lookup "event" c.events x let global (c : context) x = lookup "global" c.globals x let elem (c : context) x = lookup "elem segment" c.elems x let data (c : context) x = lookup "data segment" c.datas x @@ -487,6 +489,10 @@ let check_func (c : context) (f : func) = let c' = {c with locals = ts1 @ locals; results = ts2; labels = [ts2]} in check_block c' body (FuncType ([], ts2)) f.at +let check_event (c : context) (e : event) = + match type_ c (e.it.etype) with + | FuncType (_, []) -> () + | FuncType _ -> error e.at "non-empty event result type" let is_const (c : context) (e : instr) = match e.it with @@ -568,6 +574,8 @@ let check_import (im : import) (c : context) : context = | GlobalImport gt -> check_global_type gt idesc.at; {c with globals = gt :: c.globals} + | EventImport x -> + {c with events = EventType x.it :: c.events} module NameSet = Set.Make(struct type t = Ast.name let compare = compare end) @@ -577,6 +585,7 @@ let check_export (c : context) (set : NameSet.t) (ex : export) : NameSet.t = | FuncExport x -> ignore (func c x) | TableExport x -> ignore (table c x) | MemoryExport x -> ignore (memory c x) + | EventExport x -> ignore (event c x) | GlobalExport x -> ignore (global c x) ); require (not (NameSet.mem name set)) ex.at "duplicate export name"; @@ -584,8 +593,8 @@ let check_export (c : context) (set : NameSet.t) (ex : export) : NameSet.t = let check_module (m : module_) = let - { types; imports; tables; memories; globals; funcs; start; elems; datas; - exports } = m.it + { types; imports; tables; memories; events; globals; funcs; start; elems; + datas; exports } = m.it in let c0 = List.fold_right check_import imports @@ -599,7 +608,8 @@ let check_module (m : module_) = funcs = c0.funcs @ List.map (fun f -> type_ c0 f.it.ftype) funcs; tables = c0.tables @ List.map (fun tab -> tab.it.ttype) tables; memories = c0.memories @ List.map (fun mem -> mem.it.mtype) memories; - elems = List.map (fun elem -> elem.it.etype) elems; + events = c0.events @ List.map (fun (ev : event) -> EventType ev.it.etype.it) events; + elems = List.map (fun (elem : elem_segment) -> elem.it.etype) elems; datas = List.map (fun _data -> ()) datas; } in @@ -610,6 +620,7 @@ let check_module (m : module_) = List.iter (check_global c1) globals; List.iter (check_table c1) tables; List.iter (check_memory c1) memories; + List.iter (check_event c1) events; List.iter (check_elem c1) elems; List.iter (check_data c1) datas; List.iter (check_func c) funcs; diff --git a/test/core/binary.wast b/test/core/binary.wast index d85c9685..b4f32c1d 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -45,7 +45,7 @@ (assert_malformed (module binary "\00asm\00\00\00\01") "unknown binary version") ;; Invalid section id. -(assert_malformed (module binary "\00asm" "\01\00\00\00" "\0d\00") "malformed section id") +(assert_malformed (module binary "\00asm" "\01\00\00\00" "\0e\00") "malformed section id") (assert_malformed (module binary "\00asm" "\01\00\00\00" "\7f\00") "malformed section id") (assert_malformed (module binary "\00asm" "\01\00\00\00" "\80\00\01\00") "malformed section id") (assert_malformed (module binary "\00asm" "\01\00\00\00" "\81\00\01\00") "malformed section id") @@ -1284,7 +1284,7 @@ "\02\04\01" ;; import section with single entry "\00" ;; string length 0 "\00" ;; string length 0 - "\04" ;; malformed import kind + "\05" ;; malformed import kind ) "malformed import kind" ) @@ -1294,7 +1294,7 @@ "\02\05\01" ;; import section with single entry "\00" ;; string length 0 "\00" ;; string length 0 - "\04" ;; malformed import kind + "\05" ;; malformed import kind "\00" ;; dummy byte ) "malformed import kind" diff --git a/test/core/event.wast b/test/core/event.wast new file mode 100644 index 00000000..4001fa78 --- /dev/null +++ b/test/core/event.wast @@ -0,0 +1,21 @@ +;; Test event section + +(module + (event) + (event (param i32)) + (event (export "e2") (param i32)) + (event $e3 (param i32 f32)) + (export "e3" (event 3)) +) + +(register "test") + +(module + (event $e0 (import "test" "e2") (param i32)) + (import "test" "e3" (event $e1 (param i32 f32))) +) + +(assert_invalid + (module (event (result i32))) + "non-empty event result type" +) diff --git a/test/core/imports.wast b/test/core/imports.wast index cfe79489..a9c017fe 100644 --- a/test/core/imports.wast +++ b/test/core/imports.wast @@ -16,6 +16,10 @@ (memory (export "memory-2-inf") 2) ;; Multiple memories are not yet supported ;; (memory (export "memory-2-4") 2 4) + (event (export "event")) + (event $event-i32 (param i32)) + (export "event-i32" (event $event-i32)) + (event (export "event-f32") (param f32)) ) (register "test") @@ -43,6 +47,9 @@ (func $print_f64-2 (import "spectest" "print_f64") (param f64)) (import "test" "func-i64->i64" (func $i64->i64 (param i64) (result i64))) + (event (import "test" "event-i32") (param i32)) + (import "test" "event-f32" (event (param f32))) + (func (export "p1") (import "spectest" "print_i32") (param i32)) (func $p (export "p2") (import "spectest" "print_i32") (param i32)) (func (export "p3") (export "p4") (import "spectest" "print_i32") (param i32)) @@ -191,6 +198,10 @@ (module (import "test" "memory-2-inf" (func))) "incompatible import type" ) +(assert_unlinkable + (module (import "test" "event" (func))) + "incompatible import type" +) (assert_unlinkable (module (import "spectest" "global_i32" (func))) "incompatible import type" @@ -204,6 +215,27 @@ "incompatible import type" ) +(assert_unlinkable + (module (event (import "test" "unknown"))) + "unknown import" +) +(assert_unlinkable + (module (event (import "test" "event") (param f32))) + "incompatible import type" +) +(assert_unlinkable + (module (event (import "test" "event-i32"))) + "incompatible import type" +) +(assert_unlinkable + (module (event (import "test" "event-i32") (param f32))) + "incompatible import type" +) +(assert_unlinkable + (module (event (import "test" "func-i32") (param f32))) + "incompatible import type" +) + ;; Globals