├── 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_onego 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`sharedmemd 2 | helloWorld 3 |  AA*6A* -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------