├── experiments
├── wasm-hello-world
│ ├── dune-project
│ ├── dune
│ ├── README.adoc
│ ├── .gitignore
│ ├── index.html
│ └── main.ml
├── wasm-dynamic-linking
│ ├── m3.wasm
│ ├── m2.wasm
│ ├── m1.wasm
│ ├── m3.wat
│ ├── m1.wat
│ ├── m2.wat
│ └── index.html
├── cmm
│ ├── a01_closures.ml
│ ├── a03_fibonacci.ml
│ ├── a04_factorial.ml
│ ├── c01_while.ml
│ ├── a02_match.ml
│ ├── .gitignore
│ └── Makefile
├── wasm-performance
│ ├── test.wasm
│ ├── index.html
│ └── test.wat
└── spidermonkey-wasmTextToBinary
│ ├── m1.wat
│ ├── README.adoc
│ └── test.js
├── .gitignore
├── linking.adoc
├── compiler.adoc
├── WASM-EXTENSIONS.adoc
└── README.adoc
/experiments/wasm-hello-world/dune-project:
--------------------------------------------------------------------------------
1 | (lang dune 1.11)
2 |
--------------------------------------------------------------------------------
/experiments/wasm-hello-world/dune:
--------------------------------------------------------------------------------
1 | (executable
2 | (name main)
3 | (libraries wasm))
4 |
--------------------------------------------------------------------------------
/experiments/wasm-dynamic-linking/m3.wasm:
--------------------------------------------------------------------------------
1 | asm ` m2add_one go
2 |
--------------------------------------------------------------------------------
/experiments/wasm-dynamic-linking/m2.wasm:
--------------------------------------------------------------------------------
1 | asm ` m1
2 | helloWorld add_one
3 | Aj
--------------------------------------------------------------------------------
/experiments/cmm/a01_closures.ml:
--------------------------------------------------------------------------------
1 | let f (a : int) (b: int -> int -> int) (c:int) = b (a + 13)
2 |
3 | let g = f 42 (+)
--------------------------------------------------------------------------------
/experiments/wasm-dynamic-linking/m1.wasm:
--------------------------------------------------------------------------------
1 | asm ` sharedmem d
2 | helloWorld
3 |
A A*6 A*
--------------------------------------------------------------------------------
/experiments/wasm-performance/test.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sabine/ocaml-to-wasm-overview/HEAD/experiments/wasm-performance/test.wasm
--------------------------------------------------------------------------------
/experiments/cmm/a03_fibonacci.ml:
--------------------------------------------------------------------------------
1 | let rec fibonacci n =
2 | if n < 3 then
3 | 1
4 | else
5 | fibonacci (n-1) + fibonacci (n-2)
6 |
7 |
--------------------------------------------------------------------------------
/experiments/spidermonkey-wasmTextToBinary/m1.wat:
--------------------------------------------------------------------------------
1 | (module
2 | (func (result i32)
3 | (i32.const 42)
4 | )
5 | (export "helloWorld" (func 0))
6 | )
7 |
--------------------------------------------------------------------------------
/experiments/cmm/a04_factorial.ml:
--------------------------------------------------------------------------------
1 |
2 | let rec fac n =
3 | if n > 1 then n * fac (n-1) else 1
4 |
5 | let rec fac_tr n acc =
6 | if n > 1 then fac_tr (n-1) (acc*n) else 1
7 |
8 |
--------------------------------------------------------------------------------
/experiments/cmm/c01_while.ml:
--------------------------------------------------------------------------------
1 | let b = ref 10
2 |
3 | let _ = while !b > 0 do
4 | b := !b - 1
5 | done
6 |
7 | let a = while !b > 0 do
8 | b := !b - 1
9 | done
10 |
11 |
--------------------------------------------------------------------------------
/experiments/wasm-hello-world/README.adoc:
--------------------------------------------------------------------------------
1 | ....
2 | dune exec ./main.exe
3 |
4 | python -m SimpleHTTPServer 8000
5 | ....
6 |
7 | Open in Browser, see in console that 42, the result of calling the function `helloWorld`, is displayed.
8 |
9 |
--------------------------------------------------------------------------------
/experiments/wasm-dynamic-linking/m3.wat:
--------------------------------------------------------------------------------
1 | (module
2 | (type $t (func (result i32)))
3 | (import "m2" "add_one" (func $m2.add_one (type $t)))
4 |
5 |
6 | (func $go (result i32)
7 | (call $m2.add_one)
8 | )
9 |
10 | (export "go" (func $go))
11 | )
12 |
--------------------------------------------------------------------------------
/experiments/wasm-dynamic-linking/m1.wat:
--------------------------------------------------------------------------------
1 | (module
2 | (import "shared" "mem" (memory $mem 100))
3 | (func (result i32)
4 | (i32.const 0)
5 | (i32.const 42)
6 | (i32.store)
7 |
8 | (i32.const 42)
9 | )
10 | (export "helloWorld" (func 0))
11 | )
12 |
--------------------------------------------------------------------------------
/experiments/cmm/a02_match.ml:
--------------------------------------------------------------------------------
1 | type fruit =
2 | | Apple
3 | | Orange
4 | | Kiwi
5 |
6 |
7 | let f (a : int) (b: int -> string) (c:int) = b (a + 13)
8 |
9 | let g = f 42
10 |
11 | let e x = match x with
12 | | Apple -> f 100
13 | | Orange -> f 200
14 | | Kiwi -> f 300
15 |
16 |
--------------------------------------------------------------------------------
/experiments/wasm-dynamic-linking/m2.wat:
--------------------------------------------------------------------------------
1 | (module
2 | (type $t (func (result i32)))
3 | (import "m1" "helloWorld" (func $m1.helloWorld $t)))
4 |
5 | (func $add_one (result i32)
6 | (call $m1.helloWorld)
7 | (i32.const 1)
8 | (i32.add)
9 | )
10 |
11 | (export "add_one" (func $add_one))
12 | )
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.annot
2 | *.cmo
3 | *.cma
4 | *.cmi
5 | *.a
6 | *.o
7 | *.cmx
8 | *.cmxs
9 | *.cmxa
10 |
11 | # ocamlbuild working directory
12 | _build/
13 |
14 | # ocamlbuild targets
15 | *.byte
16 | *.native
17 |
18 | # oasis generated files
19 | setup.data
20 | setup.log
21 |
22 | # Merlin configuring file for Vim and Emacs
23 | .merlin
24 |
--------------------------------------------------------------------------------
/experiments/spidermonkey-wasmTextToBinary/README.adoc:
--------------------------------------------------------------------------------
1 | Download the latest version of the Spidermonkey js-shell here:
2 |
3 | ```
4 | https://archive.mozilla.org/pub/firefox/nightly/latest-mozilla-central/
5 | ```
6 |
7 | In browsers, as of Apr 19, 2020, wasmTextToBinary does not work, but in the js shell, you can use it as a quick way to run `.wat` files.
8 |
--------------------------------------------------------------------------------
/experiments/spidermonkey-wasmTextToBinary/test.js:
--------------------------------------------------------------------------------
1 | function loadWat(fileName) {
2 | var t = read(fileName);
3 | console.log(t);
4 | var b = wasmTextToBinary(t);
5 | var module = new WebAssembly.Module(b);
6 | return new WebAssembly.Instance(module, {});
7 | };
8 |
9 | var instance = loadWat('m1.wat');
10 | console.log(instance.exports.helloWorld());
11 |
--------------------------------------------------------------------------------
/experiments/wasm-hello-world/.gitignore:
--------------------------------------------------------------------------------
1 | out.wasm
2 | *.annot
3 | *.cmo
4 | *.cma
5 | *.cmi
6 | *.a
7 | *.o
8 | *.cmx
9 | *.cmxs
10 | *.cmxa
11 |
12 | # ocamlbuild working directory
13 | _build/
14 |
15 | # ocamlbuild targets
16 | *.byte
17 | *.native
18 |
19 | # oasis generated files
20 | setup.data
21 | setup.log
22 |
23 | # Merlin configuring file for Vim and Emacs
24 | .merlin
25 |
26 | .wasm
27 |
--------------------------------------------------------------------------------
/experiments/cmm/.gitignore:
--------------------------------------------------------------------------------
1 | *.cmm
2 | *.clambda
3 | *.s
4 | *.annot
5 | *.cmo
6 | *.cma
7 | *.cmi
8 | *.a
9 | *.o
10 | *.cmx
11 | *.cmxs
12 | *.cmxa
13 |
14 | # ocamlbuild working directory
15 | _build/
16 |
17 | # ocamlbuild targets
18 | *.byte
19 | *.native
20 |
21 | # oasis generated files
22 | setup.data
23 | setup.log
24 |
25 | # Merlin configuring file for Vim and Emacs
26 | .merlin
27 |
28 | .wasm
29 |
--------------------------------------------------------------------------------
/experiments/cmm/Makefile:
--------------------------------------------------------------------------------
1 | files = a01_closures a02_match a03_fibonacci a04_factorial c01_while
2 |
3 | all: $(files:=.cmm) $(files:=.s) $(files:=.clambda)
4 | rm -rf *.cmx *.cmi *.o a.out
5 |
6 | %.cmm: %.ml
7 | ocamlopt $< -dcmm 2> $@
8 |
9 | %.s: %.ml
10 | ocamlopt $< -S -inline 0 -nodynlink
11 |
12 | %.clambda: %.ml
13 | ocamlopt $< -dclambda 2> $@
14 |
15 | clean:
16 | rm -rf *.cmx *.cmi *.o a.out *.cmm *.s *.clambda
17 |
18 |
--------------------------------------------------------------------------------
/linking.adoc:
--------------------------------------------------------------------------------
1 | # Linking of WebAssembly modules
2 |
3 | * Wat to Asm linker ? #1133 https://github.com/WebAssembly/wabt/issues/1133i
4 |
5 | Summary: There exists an unofficial specification for "wasm object files" which is implemented by LLVM's `wasm-ld` tool. This is using C linking conventions.
6 |
7 | * WebAssembly Object File Linking https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
8 |
9 |
10 | * In case of using the WebAssembly GC extension to represent values, linking might turn out to be as simple as concatenating several modules (and dropping all imports/exports that are resolved?).
11 |
12 |
--------------------------------------------------------------------------------
/experiments/wasm-hello-world/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WASM
7 |
8 |
9 |
10 | WASM
11 |
12 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/experiments/wasm-hello-world/main.ml:
--------------------------------------------------------------------------------
1 | let add_dummy_loc (x : 'a) : 'a Wasm.Source.phrase = Wasm.Source.(x @@ no_region)
2 |
3 | let fs = [
4 | add_dummy_loc {
5 | Wasm.Ast.ftype = add_dummy_loc 0l;
6 | Wasm.Ast.locals = [];
7 | Wasm.Ast.body = [add_dummy_loc (Wasm.Ast.Const (add_dummy_loc (Wasm.Values.I32 42l)))];
8 | }
9 | ]
10 |
11 | let f_type = Wasm.Types.FuncType ([], [Wasm.Types.I32Type])
12 |
13 | let f_export = {Wasm.Ast.name = Wasm.Utf8.decode "helloWorld";
14 | Wasm.Ast.edesc = add_dummy_loc (Wasm.Ast.FuncExport (add_dummy_loc 0l))}
15 |
16 | let x = add_dummy_loc {Wasm.Ast.empty_module with
17 | funcs = fs;
18 | types = [ add_dummy_loc f_type];
19 | exports = [ add_dummy_loc f_export ];
20 | }
21 |
22 | let () =
23 | let encoded = Wasm.Encode.encode x in
24 | let oc = open_out "out.wasm" in
25 | Printf.fprintf oc "%s" encoded;
26 | close_out oc;
27 | print_endline encoded
28 |
--------------------------------------------------------------------------------
/compiler.adoc:
--------------------------------------------------------------------------------
1 | # Notes on an OCaml to WASM Compiler
2 | :toc:
3 | :toclevels: 5
4 |
5 | Goals:::
6 | * bring the OCaml ecosystem to WASM
7 | * interoperate with some deliberately chosen other languages that compile to WASM (C would be a likely candidate, since interoperating with C seems to be common for OCaml code, but Rust might be interesting as well)
8 |
9 | ## Choices
10 |
11 | Note that some choices will not be compatible with each other. In the longer run, I want to turn this into a graph with all the combinations that could make sense together.
12 |
13 | Targets:::
14 | * Web browsers
15 | * WASM->native compilers
16 | * WASM PaaS
17 |
18 | Compilation output:::
19 | * Per-module compilation (needs a linker for the generated WASM modules)
20 | * monolithic binary (can potentially perform cross-module optimizations, if we even want that)
21 |
22 | Source language:::
23 | * Lambda
24 | * Clambda
25 | * Cmm
26 | * Mach
27 | * Bytecode
28 |
29 | Garbage collection:::
30 | * WASM GC
31 | * JavaScript GC
32 | * shipping our own GC as part of the runtime
33 |
34 | Exceptions:::
35 | * WASM exceptions extension
36 | * exception stack frames (bytecode)
37 | * WASM multi-return extension (return sucess or exception)
38 | * CPS transformation (passing continuation and exception handler through all function calls)
39 |
40 | ## Important Keywords
41 |
42 | * uniform value representation, boxed values, polymorphism, no monomorphization, no type argument passing
43 | * 31-bit tagged integers, garbage collector distinguishing unboxed integers and pointers (word-aligned)
44 |
45 |
46 |
--------------------------------------------------------------------------------
/experiments/wasm-dynamic-linking/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WASM
7 |
8 |
9 |
10 | WASM
11 |
12 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/experiments/wasm-performance/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WASM
7 |
8 |
9 |
10 | WASM
11 |
12 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/experiments/wasm-performance/test.wat:
--------------------------------------------------------------------------------
1 | (module
2 | (type $t (func))
3 | (type $load (func (result i32)))
4 | (type $store (func (param i32)))
5 | (import "imports" "sayHello" (func $imports.sayHello (type $t)))
6 | (import "imports" "loadArray" (func $imports.loadArray (type $load)))
7 | (import "imports" "storeArray" (func $imports.storeArray (type $store)))
8 |
9 | (global $g (mut i32) (i32.const 0))
10 |
11 | (func $noop (param $i i32)
12 | (get_local $i)
13 | (return)
14 | )
15 |
16 | (func $loop (param $i i32)
17 | (block
18 | (loop
19 | (get_local $i)
20 | (i32.const 1)
21 | (i32.sub)
22 | (set_local $i)
23 |
24 | (get_local $i)
25 | (i32.const 1)
26 | (i32.lt_s)
27 | (br_if 1)
28 | (br 0)
29 | ))
30 | )
31 |
32 | (func $callJS (param $i i32)
33 | (block
34 | (loop
35 | (block
36 | (get_local $i)
37 | (i32.const 1)
38 | (i32.sub)
39 | (set_local $i)
40 | )
41 |
42 | (call $imports.sayHello)
43 |
44 | (get_local $i)
45 | (i32.const 1)
46 | (i32.lt_s)
47 | (br_if 1)
48 | (br 0)
49 | ))
50 | )
51 |
52 | (func $storeAndLoadMem (param $i i32)
53 | (local $val i32)
54 |
55 | (block
56 | (loop
57 | (block
58 | (i32.const 22)
59 | (get_local $val)
60 | (i32.store)
61 |
62 | (get_local $i)
63 | (i32.const 1)
64 | (i32.sub)
65 | (set_local $i)
66 | )
67 |
68 | ;; (call $imports.sayHello)
69 |
70 | (block
71 | (i32.const 22)
72 | (i32.load)
73 | (i32.const 1)
74 | (i32.add)
75 | (set_local $val)
76 | )
77 |
78 | (get_local $i)
79 | (i32.const 1)
80 | (i32.lt_s)
81 | (br_if 1)
82 | (br 0)
83 | ))
84 | )
85 |
86 | (func $storeAndLoadLocal (param $i i32)
87 | (local $val i32)
88 | (local $x i32)
89 |
90 | (block
91 | (loop
92 | (block
93 | (get_local $val)
94 | (set_local $x)
95 |
96 | (get_local $i)
97 | (i32.const 1)
98 | (i32.sub)
99 | (set_local $i)
100 | )
101 |
102 | ;; (call $imports.sayHello)
103 |
104 | (block
105 | (get_local $x)
106 | (i32.const 1)
107 | (i32.add)
108 | (set_local $val)
109 | )
110 |
111 | (get_local $i)
112 | (i32.const 1)
113 | (i32.lt_s)
114 | (br_if 1)
115 | (br 0)
116 | ))
117 | )
118 |
119 | (func $storeAndLoadGlobal (param $i i32)
120 | (local $val i32)
121 |
122 | (block
123 | (loop
124 | (block
125 | (get_local $val)
126 | (set_global $g)
127 |
128 | (get_local $i)
129 | (i32.const 1)
130 | (i32.sub)
131 | (set_local $i)
132 | )
133 |
134 | ;; (call $imports.sayHello)
135 |
136 | (block
137 | (get_global $g)
138 | (i32.const 1)
139 | (i32.add)
140 | (set_local $val)
141 | )
142 |
143 | (get_local $i)
144 | (i32.const 1)
145 | (i32.lt_s)
146 | (br_if 1)
147 | (br 0)
148 | ))
149 | )
150 |
151 | (func $storeAndLoadJS (param $i i32)
152 | (local $val i32)
153 |
154 | (block
155 | (loop
156 | (block
157 | (get_local $val)
158 | (call $imports.storeArray)
159 |
160 | (get_local $i)
161 | (i32.const 1)
162 | (i32.sub)
163 | (set_local $i)
164 | )
165 |
166 | ;; (call $imports.sayHello)
167 |
168 | (block
169 | (call $imports.loadArray)
170 | (i32.const 1)
171 | (i32.add)
172 | (set_local $val)
173 | )
174 |
175 | (get_local $i)
176 | (i32.const 1)
177 | (i32.lt_s)
178 | (br_if 1)
179 | (br 0)
180 | ))
181 | )
182 |
183 | (export "noop" (func $noop))
184 | (export "loop" (func $loop))
185 | (export "callJS" (func $callJS))
186 | (export "storeAndLoadMem" (func $storeAndLoadMem))
187 | (export "storeAndLoadLocal" (func $storeAndLoadLocal))
188 | (export "storeAndLoadGlobal" (func $storeAndLoadGlobal))
189 | (export "storeAndLoadJS" (func $storeAndLoadJS))
190 |
191 | (memory $mem 20)
192 | (export "mem" (memory $mem))
193 |
194 | )
195 |
196 |
197 |
--------------------------------------------------------------------------------
/WASM-EXTENSIONS.adoc:
--------------------------------------------------------------------------------
1 | # WASM extensions that could be helpful
2 | :toc:
3 | :toclevels: 5
4 |
5 |
6 | ## Tail calls
7 |
8 | Proposal: https://github.com/WebAssembly/tail-call/blob/master/proposals/tail-call/Overview.md
9 |
10 | Formal spec: https://webassembly.github.io/tail-call/core/
11 |
12 | Status of proposal: Apr 4, 2018
13 |
14 | ### Interpreter
15 |
16 | In the master branch.
17 |
18 | Tests in `test/core/return_call_indirect.wast` and `test/core/return_call.wast`.
19 |
20 | ### Browser implementations
21 |
22 | The proposal is currently (August 2019) in phase 3 (implementation) of the WebAssembly standardization process.
23 |
24 | * https://bugzilla.mozilla.org/show_bug.cgi?id=1571996
25 | * https://www.chromestatus.com/feature/5423405012615168
26 |
27 | ### Interesting
28 |
29 | * Tail calls in Schism #5 https://github.com/WebAssembly/tail-call/issues/5
30 | * Including tail-callability in signatures #1 https://github.com/WebAssembly/tail-call/issues/1
31 | * Tail call optimization in js_of_ocaml https://ocsigen.org/js_of_ocaml/3.1.0/manual/tailcall
32 | * Continuations #1252 https://github.com/WebAssembly/design/issues/1252
33 |
34 | ## GC
35 |
36 | Proposal: https://github.com/WebAssembly/gc/blob/master/proposals/gc/Overview.md
37 |
38 | Status of proposal: **design is still in flux**, Jun 26, 2019
39 |
40 | Required Extensions: https://github.com/WebAssembly/reference-types
41 |
42 | ### Interpreter
43 |
44 | In the branch `interpreter.basics`.
45 |
46 | https://github.com/WebAssembly/gc/pull/6
47 |
48 | Tests for struct syntax in `test/core/struct.wast`.
49 |
50 | ### Browser implementations
51 |
52 | * https://bugzilla.mozilla.org/buglist.cgi?quicksearch=webassembly+gc
53 | * https://www.chromestatus.com/feature/6062715726462976
54 |
55 | ### Interesting
56 |
57 | * https://hg.mozilla.org/mozilla-central/file/tip/js/src/jit-test/tests/wasm/gc/
58 |
59 | * Efficient data representation
60 | in polymorphic languages. X. Leroy. https://xavierleroy.org/publi/data-representation-plilp.pdf
61 |
62 | * Unboxed Types for OCaml. Talk by Stephen Dolan. https://www.janestreet.com/tech-talks/unboxed-types-for-ocaml/
63 |
64 | * Value types rather than int31 #53 https://github.com/WebAssembly/gc/issues/53
65 |
66 | * Tagged GC Pointers #919 https://github.com/WebAssembly/design/issues/919
67 |
68 | * Priority: JavaScript-integrated GC or primitives for implementing GC in WASM #733 https://github.com/WebAssembly/design/issues/733
69 |
70 | * One does not need `i31ref` in order to have a uniform value representation. Instead, one can "allocate" integers in JavaScript to get an `anyref` into the WASM program. https://github.com/WebAssembly/gc/issues/53#issuecomment-545882853
71 |
72 | * Notes on https://github.com/RossTate/gc:
73 | +
74 | 1) Statically typed function pointers can be stored on the heap, i.e. there is no need for dynamic type checks when calling a function. However, in order to use that, we need to specify a type for every closure.
75 | +
76 | 2) Every heap value can have one array type field (this is nice).
77 | +
78 | 3) The engine decides whether to heap allocate or whether to use some pointer tagging technique to store stomething.
79 | +
80 | 4) There is a description of a uniform representation for values at https://github.com/RossTate/gc/blob/master/proposals/gc/TypedFun.md.
81 | +
82 | 5) Generally, it looks like the compiler needs to emit a lot of type declarations in order to use the WASM GC. Reason being that people want to allow WASM engines a lot of flexibility for their GC strategy by having an abstract model of the heap.
83 |
84 | ## Exceptions
85 |
86 | Proposal: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
87 |
88 | Formal spec: (sketch) https://github.com/WebAssembly/exception-handling/issues/87
89 |
90 | Status of proposal: Latest commit 7779599 on Jul 14, 2019
91 |
92 | Required Extensions: **reference types**
93 |
94 | ### Interpreter
95 |
96 | There is a partial implementation in this pull request: https://github.com/WebAssembly/exception-handling/pull/28.
97 |
98 | ### Browser implementations
99 |
100 | * https://www.chromestatus.com/feature/4756734233018368
101 | * https://bugzilla.mozilla.org/show_bug.cgi?id=1571689
102 |
103 | ## Algebraic effects
104 |
105 | Proposal: https://github.com/effect-handlers/wasm-effect-handlers
106 |
107 | Status of proposal: Latest commit c034db2 on Feb 17, 2019
108 |
109 | ### Interpreter
110 |
111 | There is some work in progress(?) in several branches with prefix `ex`. I opened an Issue in order to ask about the current status of interpreter implementations. https://github.com/effect-handlers/wasm-effect-handlers/issues/4
112 |
113 | ### Browser Implementations
114 |
115 | No browsers implement this, currently.
116 |
117 | ### Interesting
118 |
119 | Bibliography: https://github.com/effect-handlers/wasm-effect/blob/master/wasm-effect.bib
120 |
121 |
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | # Ocaml to WASM - an Overview
2 | :toc:
3 | :toclevels: 5
4 |
5 | This is a collection of links and ideas and notes on compiling OCaml to WASM.
6 |
7 | ## General Notes
8 |
9 | From http://caml.inria.fr/pub/ml-archives/caml-list/2009/03/3a77bfcca0f90b763d127d1581d6a2f1.en.html (Xavier Leroy, 2009):
10 | ....
11 | 3- A language implementation like OCaml breaks down in four big parts:
12 | 1- Front-end compiler
13 | 2- Back-end compiler and code emitter
14 | 3- Run-time system
15 | 4- OS interface
16 |
17 | [...]
18 |
19 | 6- Here is a schematic of the Caml compiler. (Use a fixed-width font.)
20 |
21 | |
22 | | parsing and preprocessing
23 | v
24 | Parsetree (untyped AST)
25 | |
26 | | type inference and checking
27 | v
28 | Typedtree (type-annotated AST)
29 | |
30 | | pattern-matching compilation, elimination of modules, classes
31 | v
32 | Lambda
33 | / \
34 | / \ closure conversion, inlining, uncurrying,
35 | v \ data representation strategy
36 | Bytecode \
37 | \
38 | Cmm
39 | |
40 | | code generation
41 | v
42 | Assembly code
43 | ....
44 |
45 |
46 | A more recent high-level view of the compilation pipeline (from https://ocamllabs.slack.com/archives/C0JCHGE78/p1568626615023800, Sep 16, 2019):
47 | ....
48 | Source code
49 | |
50 | | parsing
51 | v
52 | Parsetree
53 | |
54 | | typing
55 | v
56 | Typedtree
57 | |
58 | | desugar pattern matching, modules, objects, etc; erase types,
59 | | make explicit memory layout in terms of blocks and values
60 | |
61 | v
62 | Lambda (higher order lambda calculus based IR)
63 | |
64 | | make closure construction and usage explicit
65 | | perform inlining
66 | |
67 | v
68 | Clambda (like Lambda but with explicit closures, direct/indirect calls)
69 | |
70 | | make block/value manipulation explicit
71 | | make allocation explicit
72 | |
73 | v
74 | Cmm (tree-structured, explicit memory manipulation, C calls, etc)
75 | |
76 | | perform instruction selection,
77 | | sequentialization into basic blocks,
78 | | assignment of pseudo-registers
79 | |
80 | v
81 | Mach (block structured IR)
82 | |
83 | | liveness, register allocation, dead code elimination
84 | | are Mach -> Mach transformations
85 | |
86 | v
87 | Linear (linear sequence of abstract assembly instructions, explicit register assignments)
88 | |
89 | | this step is heavily backend-dependent, implemented in `emit.mlp`
90 | |
91 | v
92 | Textual assembly code
93 | ....
94 |
95 | ## Runtime / Garbage Collection
96 |
97 | Both OCaml bytecode and OCaml native code comes with a runtime that provides functions needed to run the compiled program.
98 |
99 | The runtime provides::
100 | * a copying garbage collector, the `caml_alloc`-functions
101 | * the `caml_apply`-functions that implement curried function application
102 | * binary and unary operations on tagged integers/floats
103 | * exception handling
104 |
105 | TODO: find out what else the runtime does.
106 |
107 | Dealing with OCaml values' lifetimes in WASM::
108 | * gc1) "Manual" garbage collection on the WASM linear memory, by maintaining a stack in WASM linear memory and porting the garbage collector to WASM
109 | +
110 | This is apparently what the https://docs.google.com/document/d/131vjr4DH6JFnb-blm_uRdaC0_Nv3OUwjEY5qVCxCup4/preview#heading=h.nrkaoiab5j18[WASM backend of the Go language] does.
111 |
112 | * gc2) Use the https://github.com/WebAssembly/gc[WASM garbage collector extension] to allocate and manage OCaml values
113 | +
114 | The WASM garbage collector specification is still at a very early stage, and it is not clear how exactly it will work. The only reasonable way, at this point in time, to attempt this is to prototype our own WASM GC extension.
115 | +
116 | What if, while browser support is not there yet, we could compile to WASM+GC and then compile WASM+GC to WASM?
117 |
118 | * gc3) Allocate heap objects on "the JavaScript side of the world" via https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md[Reference Types]
119 | +
120 | This is more or less a work-around for not having a WASM GC extension.
121 |
122 | * gc4) Create a version of OCaml that has static lifetimes, similar to Rust.
123 | +
124 | I will not do this, since pretty much all existing OCaml code would need to be rewritten in order to be compiled to WASM with this variant of the language. Also, this may be different enough to OCaml that this is essentially a new programming language.
125 |
126 | ## Paths to WASM
127 |
128 | Direct::
129 | * 1a) translate Lambda -> WASM
130 | * 1b) translate Cmm -> WASM
131 | * 1c) translate OCaml bytecode -> WASM
132 | * 1d) run a bytecode interpreter for OCaml in WASM
133 |
134 | Indirect::
135 | * 2a) Cmm -> LLVM -> WASM
136 | * 2b) OCaml bytecode -> LLVM -> WASM
137 | * 2c) Ocaml -> machine code -> WASM
138 |
139 | ## Direct Roads to WASM
140 |
141 | ### 1a) Lambda -> WASM
142 |
143 | While there are currently no projects that translate OCaml's lambda IR to WASM, there are these:
144 |
145 | * **[production-ready]** Bucklescript (Ocaml rawlambda) -> JavaScript: https://github.com/BuckleScript/bucklescript
146 | +
147 | This may or may not be helpful, I do not know.
148 | +
149 | From https://github.com/BuckleScript/bucklescript/blob/00ad78cbcfd1132d3a5931fe760706de35e480f6/site/docsource/Differences-from-js_of_ocaml.adoc:
150 | +
151 | "Js_of_ocaml focuses more on existing OCaml ecosystem(opam) while BuckleScript’s major goal is to target npm"
152 | +
153 | "Js_of_ocaml and BuckleScript have slightly different runtime encoding in several places, for example, BuckleScript encodes OCaml Array as JS Array while js_of_ocaml requires its index 0 to be of value 0."
154 | +
155 | Overview of the bucklescript compiler: https://github.com/BuckleScript/bucklescript/blob/00ad78cbcfd1132d3a5931fe760706de35e480f6/site/docsource/Compiler-overview.adoc
156 | +
157 | git compare of the bucklescript fork of the ocaml compiler to the official ocaml compiler: https://github.com/ocaml/ocaml/compare/4.02...BuckleScript:4.02.3+BS
158 |
159 | * the Grain Language -> WASM https://github.com/grain-lang/grain
160 | +
161 | Even though the source language used here is not OCaml, there might be some interesting observations in here about compiling a functional language to WASM.
162 | +
163 | "Low-level IR, suitable for direct translation into WASM": https://github.com/grain-lang/grain/blob/78dc08b2887226cf0b9f93357ca6fd689fcd1405/src/codegen/mashtree.ml
164 |
165 | ### 1b) Cmm -> WASM
166 |
167 | Starting from an already optimized version of the program is likely to result in a comparatively fast execution speed.
168 |
169 | Generally, it appears that Cmm is a good starting point when compiling to WASM without using the WASM GC extension, since the memory representation has already been flattened at the Cmm stage.
170 |
171 | * **[abandoned]** https://github.com/rolph-recto/ocaml-wasm/tree/wasm/wasmcomp
172 | +
173 | "first working version: compiles arith exprs only", latest commit Jul 27, 2018
174 |
175 | * **[WIP]** Ocaml Cmm -> WASM https://github.com/SanderSpies/ocaml/tree/manual_gc/asmcomp/wasm32
176 | +
177 | https://medium.com/@sanderspies/a-webassembly-backend-for-ocaml-b78e7eeea9d5
178 | +
179 | https://medium.com/@sanderspies/the-road-to-webassembly-gc-for-ocaml-bd44dc7f9a9d
180 | +
181 | Experiments on GC: https://github.com/SanderSpies/ocaml-wasm-gc-experimenting
182 | +
183 | I seems that this is based on the official WASM specification `ast.ml`, but copied and modified to use a symbol type, instead of string for function and variable identifiers: https://github.com/SanderSpies/ocaml/commit/60a0d4218b34a0ace29a39e925c12cb5a76a3c55
184 | +
185 | It also looks like there is a few (commmented-out) lines added for https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md[the upcoming WASM exception-handling feature].
186 |
187 | * **[WIP]** Haskell Cmm -> WASM https://github.com/tweag/asterius
188 | +
189 | "we implement the cmm-to-wasm code generator as yet another native backend, and any non-Haskell logic of the runtime is hand-written WebAssembly code, which means we're simulating various rts interfaces to the degree that a significant portion of vanilla Haskell code becomes runnable." (https://www.tweag.io/posts/2018-05-29-hello-asterius.html[see here])
190 | +
191 | Garbage collection: https://github.com/tweag/asterius/issues/52
192 |
193 | ### 1c) OCaml bytecode -> WASM
194 |
195 | I am not aware of any projects that attempt translating from OCaml bytecode to WASM. Please let me know if you are.
196 |
197 | An advantage is that the bytecode interpreter hardly ever changes at all (it is said to still be quite similar to what is laid out in https://caml.inria.fr/pub/papers/xleroy-zinc.pdf[the original report on ZINC]).
198 |
199 | There is no dependency on compiler internals, as we can work on the bytecode output of `ocamlc`.
200 |
201 | In the past, translating bytecode has proven to be a successful and maintainable strategy for compiling OCaml to different languages:
202 |
203 | * **[production-ready]** OCaml bytecode -> JavaScript: https://github.com/ocsigen/js_of_ocaml
204 | +
205 | https://www.irif.fr/~balat/publications/vouillon_balat-js_of_ocaml.pdf presents performance results from 2011: The code generated by `js_of_ocaml` running on the V8 JavaScript engine was faster than running the bytecode interpreter on the bytecode generated by `ocamlc`, and slower than the machine code generated by `ocamlopt`.
206 | Exceptions turned out to be very expensive.
207 | +
208 | `js_of_ocaml` is being used in production systems, as far as I know, it is currently the best tool to compile OCaml to JavaScript.
209 | +
210 | OCaml values are allocated on the JavaScript heap (**gc3**), thus, the calls to the garbage collector are just stubs: https://github.com/ocsigen/js_of_ocaml/blob/e7a34b8e0697a34b235ff121132c72121c16798d/runtime/gc.js
211 | +
212 | *Note:* It is unlikely, that exceptions will be an issue when compiling to WASM, since the exception mechanism in WASM will be different from the one in JavaScript.
213 |
214 |
215 | * **[inactive]** Ocaml bytecode -> C: https://github.com/bvaugon/ocamlcc
216 | +
217 | According to http://michel.mauny.net/data/papers/mauny-vaugon-ocamlcc-oud2012.pdf, performance in 2012 was better than running the bytecode interpreter, and worse than running the machine code generated by `ocamlopt`, which essentially was to be expected. However, this comes at the cost of having large executables, roughly up to twice the size of machine code in the considered examples.
218 | +
219 | I managed to compile this using an older version of the OCaml compiler.
220 | +
221 | I can compile trivial test programs to C.
222 | +
223 | Compiling that C code using Emscripten to WASM, I am stuck with this error on the JavaScript console:
224 | +
225 | ....
226 | exception thrown: RuntimeError: index out of bounds,_caml_page_table_modify@http://127.0.0.1:8000/output.js:45026:1
227 | _caml_page_table_add@http://127.0.0.1:8000/output.js:44203:1
228 | _caml_set_minor_heap_size@http://127.0.0.1:8000/output.js:89253:1
229 | _caml_init_gc@http://127.0.0.1:8000/output.js:90849:1
230 | _caml_main@http://127.0.0.1:8000/output.js:99291:1
231 | _main@http://127.0.0.1:8000/output.js:110038:1
232 | Module._main@http://127.0.0.1:8000/output.js:6717:10
233 | callMain@http://127.0.0.1:8000/output.js:7005:15
234 | doRun@http://127.0.0.1:8000/output.js:7064:23
235 | run/<@http://127.0.0.1:8000/output.js:7075:7
236 | ....
237 | +
238 | I'm having trouble debugging this because I don't have source maps for the C files where the `\_caml_`-functions come from. The reason seems to be that the files aren't actually included, only the headers. So I need to figure out what parameters to provide to emcc. In order to do that, I need to figure out what parameters ocamlcc uses to compile the code with gcc.
239 | +
240 | I was able to get the parameters from ocamlcc by using the -verbose option, now the error is this:
241 | +
242 | ....
243 | shared:ERROR: emcc: cannot find library "curses"
244 | ....
245 | +
246 | While I could continue here, I think that this is a dead end due to the large code size.
247 |
248 | ### 1d) bytecode interpreter in WASM
249 |
250 | * **[inactive]** https://github.com/sebmarkbage/ocamlrun-wasm
251 | +
252 | sebmarkbage compiled the OCaml bytecode interpreter, as well as the GC to WASM using emscripten. https://github.com/sebmarkbage/ocamlrun-wasm/commit/473580d7d2955ce254c2d0263383f7e251f6e497[Latest commit Mar 6, 2017]
253 | +
254 | I tried to compile this, but am stuck at the problem described in https://github.com/sebmarkbage/ocamlrun-wasm/issues/1[Issue 1]
255 |
256 | * https://github.com/vincentdchan/ocaml
257 | +
258 | same principle as sebmarkbage's approach, but adds support of libraries such as Unix library, Ctypes, Base, Core_kernel
259 |
260 |
261 | ## Indirect Roads to WASM
262 |
263 | If there was a compiler from OCaml to LLVM, it would immediately enable compilation to WASM.
264 |
265 | * **[discussion]** http://caml.inria.fr/pub/ml-archives/caml-list/2009/03/3a77bfcca0f90b763d127d1581d6a2f1.en.html
266 |
267 | * **[discussion]** https://discuss.ocaml.org/t/llvm-backend-for-ocaml/1132/5
268 |
269 | ### 2a) Cmm -> LLVM
270 |
271 | * **[abandoned]** Cmm -> LLVM https://github.com/whitequark/ocaml-llvm-ng/blob/master/lib/llvmcomp.ml
272 |
273 | ### 2b) OCaml bytecode -> LLVM
274 |
275 | * **[abandoned]** OCaml bytecode -> LLVM https://github.com/raph-amiard/CamllVM
276 | +
277 | "TLDR : In the end it is just not worth it to optimize this project for performance. A better approach would be to start from scratch and do a real OCaml -> LLVM compiler for ocamlopt, that would be able to use the full AST with type information." https://news.ycombinator.com/item?id=4798320
278 |
279 | ### 2c) machine code -> WASM
280 |
281 | For compiling machine code to WASM, there apparently do not currently exist any solutions.
282 |
283 | One would need to apply some kind of algorithm that transforms the control flow from a program-counter-based representation to the labeled continuations that can be seen in WASM, just like Emscripten's "Relooper" algorithm does for LLVM.
284 |
285 | If there is an architecture whose machine code can be translated to WASM in a reasonably efficient fashion, and it turns out that OCaml already compiles to this architecture, this could be interesting.
286 |
287 | If successful, this could, in the long run, help getting many other languages to compile to WASM as well.
288 |
289 | # My Collection of Links to Sort Through
290 |
291 | * wasm - https://opam.ocaml.org/packages/wasm/
292 | +
293 | "An OCaml library to read and write Web Assembly (wasm) files and manipulate their AST."
294 |
295 | * "Malfunctional Programming" (the author implemented an interpreter for lambda, which should be similar to one for Cmm) https://www.cl.cam.ac.uk/~sd601/papers/malfunction.pdf
296 |
297 | * "Caml Virtual Machine - Instruction set Document version: 1.4" http://cadmium.x9c.fr/distrib/caml-instructions.pdf
298 | +
299 | description of compiler version 3.11.2's bytecode
300 |
301 | * How to write programs that never allocate http://www.ocamlpro.com/2016/04/01/asm-ocaml/
302 |
303 | * loading `Cmm` in the interpreter:
304 | +
305 | ....
306 | #load "compiler-libs/ocamlcommon.cma";;
307 | #load "compiler-libs/ocamloptcomp.cma";;
308 | #require "compiler-libs.optcomp";;
309 | #show_module Cmm;;
310 | ....
311 |
312 | * A Scheme to WASM compiler - https://github.com/google/schism
313 | +
314 | Schism allocating values on the JS side: https://github.com/WebAssembly/tool-conventions/issues/122#issuecomment-520326189
315 |
316 | * WASM tail calls proposal - https://github.com/WebAssembly/tail-call/blob/125201ced9a0f158553d08d8a20b7152f3057367/proposals/tail-call/Overview.md
317 |
318 | * CakeML a verified ML compiler - https://cakeml.org/
319 | +
320 | Contains formal semantics for different intermediate representations in their compilation pipeline.
321 | +
322 | "A New Verified Compiler Backend for CakeML" (presentation of the overall structure and the intermediate languages of the CakeML compiler) https://cakeml.org/icfp16.pdf
323 | +
324 | CakeML to WebAssembly talk https://lorenz.leutgeb.xyz/paper/cakeml-wasm-viennajs-beam.pdf
325 |
326 | * How to Represent Elm functions in Web Assembly https://dev.to/briancarroll/elm-functions-in-webassembly-50ak
327 |
328 | * Solving the structured control flow problem (Improving on the Relooper algorithm) https://medium.com/leaningtech/solving-the-structured-control-flow-problem-once-and-for-all-5123117b1ee2
329 |
330 | * there is a parser for `.cmm` files in `testsuite/tools/parsecmm.mly` of the OCaml compiler
331 |
332 | * it is possible to generate a `.merlin` file for the compiler by, starting from a clean repository, running `./configure` and `dune build @world`. Even if the full build fails, the `.merlin` file will likely be there and useful.
333 |
334 | * How to explore Cmm semantics by looking at the generated x86 code (useful if you feel comfortable with assembly code):
335 | +
336 | ....
337 | ocamlopt test2.ml -S -inline 0 -nodynlink
338 | ocamlopt test2.ml -dcmm
339 | ....
340 | +
341 | One can then look at the Cmm and the generated `test2.s` side-by-side.
342 | +
343 | When compiling on an x86-64 Intel machine using Debian, one can look at the runtime functions in https://github.com/ocaml/ocaml/blob/5ad64306d36755b600f2556805effb73627508c8/runtime/amd64.S.
344 |
345 | * Talk on Rust, WebAssembly and JavaScript by Ashley Williams https://www.infoq.com/presentations/rust-webassembly-javascript/?utm_source=youtube&utm_medium=link&utm_campaign=qcontalks
346 |
347 | * IR for compiling WASM to Cmm https://github.com/SimonJF/cmm_of_wasm/blob/10fea570f80f91ee26c23a6cca48b29795c9967b/src/lib/ir/annotated.ml
348 |
349 | * Mozilla Garbage collector Info https://github.com/lars-t-hansen/moz-gc-experiments/
350 | +
351 | Some tests related to `anyref` and garbage collector:
352 | https://hg.mozilla.org/mozilla-central/file/tip/js/src/jit-test/tests/wasm/gc/
353 |
354 | * Web assembly meetings repository (last video call from July 23rd) https://github.com/WebAssembly/meetings
355 |
356 | * GC without a shadow stack in an "uncooperative environment"
357 | https://github.com/WebAssembly/gc/issues/36#issuecomment-406721705
358 | +
359 | As noted in a later comment, this technique becomes even more complex when the stack consists of both JavaScript and WASM frames. It doesn't look like a good idea to do that due to the increase in code size.
360 | +
361 | This later comment https://github.com/WebAssembly/gc/issues/36#issuecomment-461679185 proposes "making the execution stack visible" or implementing "an efficient user stack with a defined layout, including what gets put there when a function is called. Have a second instruction set that works with this stack: us.i32.const 50, us.i32.mul, etc".
362 | +
363 | If we had any possibility to inspect the WASM stack to discover the gc roots, this would be nice. However, in order for the OCaml GC to move blocks, we also need the ability to modify. A generic read/write feature for the WASM stack is not desirable due to security implications.
364 |
365 | * Paper: Accurate Garbage Collection in an Uncooperative Environment. Fergus Henderson. http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.87.3769&rep=rep1&type=pdf
366 |
367 | * Paper: Accurate Garbage Collection in Uncooperative Environments Revisited. J. Baker, A. Cunei, T. Kalibera, F. Pizlo, J. Vitek. http://www.filpizlo.com/papers/baker-ccpe09-accurate.pdf
368 |
369 | * sharing JS data structures with WASM in the absence of reference types https://github.com/WebAssembly/interface-types/issues/18#issuecomment-430605795
370 | +
371 | Inefficient but interesting workaround to use browser GC before a WASM GC appears: a) keep an Object that maps references (keys of the JavaScript Object) to arrays (representing the OCaml heap blocks), b) allocate by adding a new key to the Object, c) deallocate by deleting a key from the Object, d) provide functions to write/read the heap blocks from WASM. Clearly, the runtime performance here depends on: x) how fast function calls from WASM to JS are, y) how fast Object and array access is in JS. Note: if we had a way to read the WASM stack, we know the roots, and we can "deallocate" by removing unreachable keys from the Object. The actual garbage collection is done by the JavaScript GC. In WASM we only keep immutable handles to the data (the keys to the JS Object).
372 | +
373 | Performance will be worse than using a shadow stack with the OCaml gc compiled to WASM on the WASM linear memory. In order to be able to refer to any heap block by a reference, data will be "flattened" in the sense that every key maps to an array consisting of only numbers (primitives) and strings (references into the JS Object).
374 | +
375 | In this comment, the same approach is mentioned: https://www.reddit.com/r/ProgrammingLanguages/comments/bbhz69/wasm_reftypes_are_enabled_by_default_in_firefox/ekj4mhr/
376 | +
377 | With reftypes, the technique of using JavaScript values to represent OCaml heap blocks is simplified by not having to take the additional indirection through a JS Object - the references to JS data can be passed to WASM directly (which, I think, implies that the Browser GC is responsible for modifying moved references and for discovering its own GC roots). To model pointer values in OCaml heap blocks correctly, one would need to embed the data pointed to in the JavaScript array. So, we would have Arrays of numbers and arrays in JavaScript to model OCaml heap blocks. Performance now largely depends on the cost of array access and on the cost of function calls between WASM and JS.
378 | +
379 | Note that we don't ever need to inspect the WASM stack, we can store heap references in WASM local variables, and we don't need to keep a shadow stack, so the cost tradeoff would be between a) maintaining a shadow stack with OCaml's GC and b) modeling OCaml heap blocks via reftypes and JS arrays accessed by function calls with the JavaScript GC. Code size is likely smaller with the JS approach.
380 |
381 | * Note: We could avoid using local variables for OCaml values in WASM and instead use global variables as "registers". This means that compilation to WASM would not be very different from compilation to machine code (the main difference would be how control flow is compiled / register allocation works exactly as in compilation to native). However, currently this does not work since it is not possible to import/export global variables. See here: https://github.com/WebAssembly/mutable-global/blob/89e5be9d69f2afac7243b6d2ff36b9c8723efb77/proposals/mutable-global/Overview.md
382 |
383 | * WASM future features list https://github.com/WebAssembly/design/blob/master/FutureFeatures.md
384 |
385 | * LLVM WASM backend https://github.com/llvm/llvm-project/tree/6088f84398847152ad97eb1bc0b139a28e879b48/llvm/lib/Target/WebAssembly
386 | +
387 | "After register stackification and register coloring, convert non-stackified
388 | registers into locals, inserting explicit local.get and local.set
389 | instructions." https://github.com/llvm/llvm-project/blob/6088f84398847152ad97eb1bc0b139a28e879b48/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
390 |
391 | * `ocaml/runtime/globroots.c` I currently believe that the purpose is that you can use the OCaml `alloc` from other languages (e.g. C, Java) explicitly (so that you can deallocate eventually by removing from the global roots). This technique could be ported to WASM. `ocaml/runtime/roots_nat.c` scans the stack for gc roots, which is something that cannot be ported as-is to WASM.
392 |
393 | * An explanation of dynamic linking with LLD for WASM: https://iandouglasscott.com/2019/07/18/experimenting-with-webassembly-dynamic-linking-with-clang/
394 |
395 | * wasm-ld https://lld.llvm.org/WebAssembly.html
396 | +
397 | WASM tool conventions on linking https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
398 |
399 | * Notes on the background of WASI https://github.com/CraneStation/wasmtime/blob/3ae7c60b1395fe25971f683828241e7fac8cb40b/docs/WASI-background.md
400 |
401 | * Planning of reference types implementation in the Lucet WASM compiler https://github.com/fastly/lucet/issues/272
402 | +
403 | Using Lucet as a playground to prototype WASM implementations doesn't seem a good idea.
404 |
405 | * Multi-core ocaml compiler Wiki https://github.com/ocaml-multicore/ocaml-multicore/wiki
406 | +
407 | Garbage collector invariants, possibly helpful https://github.com/ocaml-multicore/ocaml-multicore/wiki/Garbage-collector-invariants
408 |
409 | * Boxing vs. tagging in the OCaml compiler
410 | +
411 | Boxing is the act of allocating a heap block to store a primitive value. This is done by using the appropriate heap block header for the type of the primitive value. Unboxing is the reverse operation, taking a heap-allocated primitive and returning just the primitive value.
412 | +
413 | Tagging is done with integers everywhere, in order to be able to store them unboxed on the heap without confusing the garbage collector (who scans the heap for pointers and will confuse integers ending with 0 with pointers)
414 |
415 | * Wouter van Oortmerssen — Bring your language to Wasm! https://github.com/sabine/ocaml-to-wasm-overview.git
416 | +
417 | Hands-on intro to how to generate WASM code. Also brief discussion of language features and tools that can be used.
418 |
419 | * "Run OCaml in the browser by WebAssembly
420 | " https://okcdz.medium.com/run-ocaml-in-the-browser-by-webassembly-31ce464594c6
421 | +
422 | Running OCaml in the browser by compiling the OCaml bytecode interpreter to WASM. Adding support of libraries such as Unix library, Ctypes, Base, Core_kernel.
423 | +
424 | https://github.com/vincentdchan/ocaml
425 |
426 | * binaryen_dsl package on opam https://opam.ocaml.org/packages/binaryen_dsl/
427 | +
428 | wrapper around Binaryen that allows to generate WAT and WASM files from a formalization of the Binaryen DSL. Not sure how complete it is, as it is a very new package.
429 |
--------------------------------------------------------------------------------