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

Commit 891253c

Browse files
yuri91rossberg
andauthored
[interpreter] Handle custom sections and annotations (#17)
* [interpreter] Handle custom sections and annotations Co-authored-by: Yuri Iozzelli <[email protected]> * Fix merge conflict * Fix lexer priorities * Fix wast.ml * Oops * Update wast.ml --------- Co-authored-by: Andreas Rossberg <[email protected]>
1 parent 09c8953 commit 891253c

30 files changed

+1180
-172
lines changed

interpreter/Makefile

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ ZIP = $(NAME).zip
1717
JSLIB = wast
1818
WINMAKE = winmake.bat
1919

20-
DIRS = util syntax binary text valid runtime exec script host main tests
20+
DIRS = util syntax binary text valid runtime exec custom script host main tests
2121
LIBS =
2222
FLAGS = -lexflags -ml -cflags '-w +a-4-27-42-44-45-70 -warn-error +a-3'
2323
OCBA = ocamlbuild $(FLAGS) $(DIRS:%=-I %)
@@ -37,10 +37,10 @@ unopt: $(UNOPT)
3737
libopt: _build/$(LIB).cmx _build/$(LIB).cmxa
3838
libunopt: _build/$(LIB).cmo _build/$(LIB).cma
3939
jslib: $(JSLIB).js
40-
all: unopt opt libunopt libopt test
40+
all: unopt opt libunopt libopt alltest
41+
alltest: unittest test customtest
4142
land: $(WINMAKE) all
4243
zip: $(ZIP)
43-
smallint: smallint.native
4444
ci: land wast.js dunebuild
4545

4646
dunebuild:
@@ -135,21 +135,18 @@ $(WINMAKE): clean
135135
>>$@
136136
137137
138-
# Executing test suite
138+
# Executing core test suite
139139
140140
TESTDIR = ../test/core
141-
# Skip _output directory, since that's a tmp directory, and list all other wast files.
142141
TESTFILES = $(shell cd $(TESTDIR); ls *.wast; ls [a-z]*/*.wast)
143142
TESTS = $(TESTFILES:%.wast=%)
144143
145-
.PHONY: test debugtest partest dune-test
144+
.PHONY: test debugtest partest dune-test quiettest
146145
147-
test: $(OPT) smallint
146+
test: $(OPT)
148147
$(TESTDIR)/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',)
149-
./smallint.native
150-
debugtest: $(UNOPT) smallint
148+
debugtest: $(UNOPT)
151149
$(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) $(if $(JS),--js '$(JS)',)
152-
./smallint.native
153150
154151
test/%: $(OPT)
155152
$(TESTDIR)/run.py --wasm `pwd`/$(OPT) $(if $(JS),--js '$(JS)',) $(TESTDIR)/$*.wast
@@ -171,9 +168,52 @@ quiettest/%: $(OPT)
171168
) || \
172169
cat $(@F).out || rm $(@F).out || exit 1
173170
174-
smallinttest: smallint
171+
172+
# Executing custom test suite
173+
174+
CUSTOMTESTDIR = ../test/custom
175+
CUSTOMTESTDIRS = $(shell cd $(CUSTOMTESTDIR); ls -d [a-z]*)
176+
CUSTOMTESTFILES = $(shell cd $(CUSTOMTESTDIR); ls [a-z]*/*.wast)
177+
CUSTOMTESTS = $(CUSTOMTESTFILES:%.wast=%)
178+
CUSTOMOPTS = -c custom $(CUSTOMTESTDIRS:%=-c %)
179+
180+
.PHONY: customtest customdebugtest custompartest customquiettest
181+
182+
customtest: $(OPT)
183+
$(TESTDIR)/run.py --wasm `pwd`/$(OPT) --opts '$(CUSTOMOPTS)' $(if $(JS),--js '$(JS)',) $(CUSTOMTESTFILES:%=$(CUSTOMTESTDIR)/%)
184+
customdebugtest: $(UNOPT)
185+
$(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) --opts '$(CUSTOMOPTS)' $(if $(JS),--js '$(JS)',) $(CUSTOMTESTFILES:%=$(CUSTOMTESTDIR)/%)
186+
187+
customtest/%: $(OPT)
188+
$(TESTDIR)/run.py --wasm `pwd`/$(OPT) --opts '$(CUSTOMOPTS) ' $(if $(JS),--js '$(JS)',) $(CUSTOMTESTDIR)/$*.wast
189+
customdebugtest/%: $(UNOPT)
190+
$(TESTDIR)/run.py --wasm `pwd`/$(UNOPT) --opts '$(CUSTOMOPTS)' $(if $(JS),--js '$(JS)',) $(CUSTOMTESTDIR)/$*.wast
191+
192+
customrun/%: $(OPT)
193+
./$(OPT) $(CUSTOMOPTS) $(CUSTOMTESTDIR)/$*.wast
194+
customdebug/%: $(UNOPT)
195+
./$(UNOPT) $(CUSTOMOPTS) $(CUSTOMTESTDIR)/$*.wast
196+
197+
custompartest: $(CUSTOMTESTS:%=customquiettest/%)
198+
@echo All custom tests passed.
199+
200+
customquiettest/%: $(OPT)
201+
@ ( \
202+
$(TESTDIR)/run.py 2>$(@F).out --wasm `pwd`/$(OPT) --opts '$(CUSTOMOPTS)' $(if $(JS),--js '$(JS)',) $(TESTDIR)/$*.wast && \
203+
rm $(@F).out \
204+
) || \
205+
cat $(@F).out || rm $(@F).out || exit 1
206+
207+
208+
# Executing unit tests
209+
210+
.PHONY: unittest
211+
212+
unittest: smallint
175213
@./smallint.native
176214
215+
smallint: smallint.native
216+
177217
dunetest:
178218
dune test
179219

interpreter/binary/decode.ml

Lines changed: 85 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -798,19 +798,19 @@ let id s =
798798
let bo = peek s in
799799
Lib.Option.map
800800
(function
801-
| 0 -> `CustomSection
802-
| 1 -> `TypeSection
803-
| 2 -> `ImportSection
804-
| 3 -> `FuncSection
805-
| 4 -> `TableSection
806-
| 5 -> `MemorySection
807-
| 6 -> `GlobalSection
808-
| 7 -> `ExportSection
809-
| 8 -> `StartSection
810-
| 9 -> `ElemSection
811-
| 10 -> `CodeSection
812-
| 11 -> `DataSection
813-
| 12 -> `DataCountSection
801+
| 0 -> Custom.Custom
802+
| 1 -> Custom.Type
803+
| 2 -> Custom.Import
804+
| 3 -> Custom.Func
805+
| 4 -> Custom.Table
806+
| 5 -> Custom.Memory
807+
| 6 -> Custom.Global
808+
| 7 -> Custom.Export
809+
| 8 -> Custom.Start
810+
| 9 -> Custom.Elem
811+
| 10 -> Custom.Code
812+
| 11 -> Custom.Data
813+
| 12 -> Custom.DataCount
814814
| _ -> error s (pos s) "malformed section id"
815815
) bo
816816

@@ -828,7 +828,7 @@ let section tag f default s =
828828
let type_ s = at func_type s
829829

830830
let type_section s =
831-
section `TypeSection (vec type_) [] s
831+
section Custom.Type (vec type_) [] s
832832

833833

834834
(* Import section *)
@@ -848,13 +848,13 @@ let import s =
848848
{module_name; item_name; idesc}
849849

850850
let import_section s =
851-
section `ImportSection (vec (at import)) [] s
851+
section Custom.Import (vec (at import)) [] s
852852

853853

854854
(* Function section *)
855855

856856
let func_section s =
857-
section `FuncSection (vec (at var)) [] s
857+
section Custom.Func (vec (at var)) [] s
858858

859859

860860
(* Table section *)
@@ -864,7 +864,7 @@ let table s =
864864
{ttype}
865865

866866
let table_section s =
867-
section `TableSection (vec (at table)) [] s
867+
section Custom.Table (vec (at table)) [] s
868868

869869

870870
(* Memory section *)
@@ -874,7 +874,7 @@ let memory s =
874874
{mtype}
875875

876876
let memory_section s =
877-
section `MemorySection (vec (at memory)) [] s
877+
section Custom.Memory (vec (at memory)) [] s
878878

879879

880880
(* Global section *)
@@ -885,7 +885,7 @@ let global s =
885885
{gtype; ginit}
886886

887887
let global_section s =
888-
section `GlobalSection (vec (at global)) [] s
888+
section Custom.Global (vec (at global)) [] s
889889

890890

891891
(* Export section *)
@@ -904,7 +904,7 @@ let export s =
904904
{name; edesc}
905905

906906
let export_section s =
907-
section `ExportSection (vec (at export)) [] s
907+
section Custom.Export (vec (at export)) [] s
908908

909909

910910
(* Start section *)
@@ -914,7 +914,7 @@ let start s =
914914
{sfunc}
915915

916916
let start_section s =
917-
section `StartSection (opt (at start) true) None s
917+
section Custom.Start (opt (at start) true) None s
918918

919919

920920
(* Code section *)
@@ -939,7 +939,7 @@ let code _ s =
939939
{locals; body; ftype = -1l @@ no_region}
940940

941941
let code_section s =
942-
section `CodeSection (vec (at (sized code))) [] s
942+
section Custom.Code (vec (at (sized code))) [] s
943943

944944

945945
(* Element section *)
@@ -1012,7 +1012,7 @@ let elem s =
10121012
| _ -> error s (pos s - 1) "malformed elements segment kind"
10131013

10141014
let elem_section s =
1015-
section `ElemSection (vec (at elem)) [] s
1015+
section Custom.Elem (vec (at elem)) [] s
10161016

10171017

10181018
(* Data section *)
@@ -1034,7 +1034,7 @@ let data s =
10341034
| _ -> error s (pos s - 1) "malformed data segment kind"
10351035

10361036
let data_section s =
1037-
section `DataSection (vec (at data)) [] s
1037+
section Custom.Data (vec (at data)) [] s
10381038

10391039

10401040
(* DataCount section *)
@@ -1043,62 +1043,64 @@ let data_count s =
10431043
Some (u32 s)
10441044

10451045
let data_count_section s =
1046-
section `DataCountSection data_count None s
1046+
section Custom.DataCount data_count None s
10471047

10481048

10491049
(* Custom section *)
10501050

1051-
let custom size s =
1051+
let custom place size s =
10521052
let start = pos s in
1053-
let id = name s in
1054-
let bs = get_string (size - (pos s - start)) s in
1055-
Some (id, bs)
1053+
let name = name s in
1054+
let content = get_string (size - (pos s - start)) s in
1055+
Custom.{name; content; place}
10561056

1057-
let custom_section s =
1058-
section_with_size `CustomSection custom None s
1057+
let some_custom place size s =
1058+
Some (at (custom place size) s)
10591059

1060-
let non_custom_section s =
1061-
match id s with
1062-
| None | Some `CustomSection -> None
1063-
| _ -> skip 1 s; sized skip s; Some ()
1060+
let custom_section place s =
1061+
section_with_size Custom.Custom (some_custom place) None s
10641062

10651063

10661064
(* Modules *)
10671065

1068-
let rec iterate f s = if f s <> None then iterate f s
1066+
let rec iterate f s =
1067+
match f s with
1068+
| None -> []
1069+
| Some x -> x :: iterate f s
10691070

10701071
let magic = 0x6d736100l
10711072

10721073
let module_ s =
1074+
let open Custom in
10731075
let header = word32 s in
10741076
require (header = magic) s 0 "magic header not detected";
10751077
let version = word32 s in
10761078
require (version = Encode.version) s 4 "unknown binary version";
1077-
iterate custom_section s;
1079+
let customs = iterate (custom_section (Before Type)) s in
10781080
let types = type_section s in
1079-
iterate custom_section s;
1081+
let customs = customs @ iterate (custom_section (After Type)) s in
10801082
let imports = import_section s in
1081-
iterate custom_section s;
1083+
let customs = customs @ iterate (custom_section (After Import)) s in
10821084
let func_types = func_section s in
1083-
iterate custom_section s;
1085+
let customs = customs @ iterate (custom_section (After Func)) s in
10841086
let tables = table_section s in
1085-
iterate custom_section s;
1087+
let customs = customs @ iterate (custom_section (After Table)) s in
10861088
let memories = memory_section s in
1087-
iterate custom_section s;
1089+
let customs = customs @ iterate (custom_section (After Memory)) s in
10881090
let globals = global_section s in
1089-
iterate custom_section s;
1091+
let customs = customs @ iterate (custom_section (After Global)) s in
10901092
let exports = export_section s in
1091-
iterate custom_section s;
1093+
let customs = customs @ iterate (custom_section (After Export)) s in
10921094
let start = start_section s in
1093-
iterate custom_section s;
1095+
let customs = customs @ iterate (custom_section (After Start)) s in
10941096
let elems = elem_section s in
1095-
iterate custom_section s;
1097+
let customs = customs @ iterate (custom_section (After Elem)) s in
10961098
let data_count = data_count_section s in
1097-
iterate custom_section s;
1099+
let customs = customs @ iterate (custom_section (After DataCount)) s in
10981100
let func_bodies = code_section s in
1099-
iterate custom_section s;
1101+
let customs = customs @ iterate (custom_section (After Code)) s in
11001102
let datas = data_section s in
1101-
iterate custom_section s;
1103+
let customs = customs @ iterate (custom_section (After Data)) s in
11021104
require (pos s = len s) s (len s) "unexpected content after last section";
11031105
require (List.length func_types = List.length func_bodies)
11041106
s (len s) "function and code section have inconsistent lengths";
@@ -1108,23 +1110,37 @@ let module_ s =
11081110
List.for_all Free.(fun f -> (func f).datas = Set.empty) func_bodies)
11091111
s (len s) "data count section required";
11101112
let funcs =
1111-
List.map2 (fun t f -> {f.it with ftype = t} @@ f.at) func_types func_bodies
1112-
in {types; tables; memories; globals; funcs; imports; exports; elems; datas; start}
1113-
1114-
1115-
let decode name bs = at module_ (stream name bs)
1116-
1117-
let all_custom tag s =
1118-
let header = word32 s in
1119-
require (header = magic) s 0 "magic header not detected";
1120-
let version = word32 s in
1121-
require (version = Encode.version) s 4 "unknown binary version";
1122-
let rec collect () =
1123-
iterate non_custom_section s;
1124-
match custom_section s with
1125-
| None -> []
1126-
| Some (n, s) when n = tag -> s :: collect ()
1127-
| Some _ -> collect ()
1128-
in collect ()
1129-
1130-
let decode_custom tag name bs = all_custom tag (stream name bs)
1113+
List.map2 Source.(fun t f -> {f.it with ftype = t} @@ f.at)
1114+
func_types func_bodies
1115+
in
1116+
{types; tables; memories; globals; funcs; imports; exports; elems; datas; start},
1117+
customs
1118+
1119+
1120+
let decode_custom m bs custom =
1121+
let open Source in
1122+
let Custom.{name; content; place} = custom.it in
1123+
match Custom.handler name, Custom.handler (Utf8.decode "custom") with
1124+
| Some (module Handler), _ ->
1125+
let fmt = Handler.decode m bs custom in
1126+
let module S = struct module Handler = Handler let it = fmt end in
1127+
[(module S : Custom.Section)]
1128+
| None, Some (module Handler') ->
1129+
let fmt = Handler'.decode m bs custom in
1130+
let module S = struct module Handler = Handler' let it = fmt end in
1131+
[(module S : Custom.Section)]
1132+
| None, None ->
1133+
if !Flags.custom_reject then
1134+
raise (Custom.Code (custom.at,
1135+
"unknown custom section \"" ^ Utf8.encode name ^ "\""))
1136+
else
1137+
[]
1138+
1139+
let decode_with_custom name bs =
1140+
let m_cs = at module_ (stream name bs) in
1141+
let open Source in
1142+
let m', cs = m_cs.it in
1143+
let m = m' @@ m_cs.at in
1144+
m, List.flatten (List.map (decode_custom m bs) cs)
1145+
1146+
let decode name bs = fst (decode_with_custom name bs)

interpreter/binary/decode.mli

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
exception Code of Source.region * string
22

33
val decode : string -> string -> Ast.module_ (* raises Code *)
4-
5-
val decode_custom : Ast.name -> string -> string -> string list (* raises Code *)
4+
val decode_with_custom : string -> string -> Ast.module_ * Custom.section list (* raises Code *)

0 commit comments

Comments
 (0)