commit
ab89f9067b
10 changed files with 1406 additions and 0 deletions
@ -0,0 +1 @@ |
|||
_build |
@ -0,0 +1 @@ |
|||
(lang dune 3.0) |
@ -0,0 +1,26 @@ |
|||
(rule |
|||
(target main.pdf) |
|||
(deps |
|||
;; tex |
|||
main.tex slides.tex |
|||
;; images |
|||
logo_lmf.svg |
|||
logo_ocp.png |
|||
ocaml_chain.png |
|||
;; generated images |
|||
figure_ocaml_bit1.mps |
|||
figure_ocaml_bit2.mps |
|||
figure_ocaml_bit3.mps |
|||
figure_type_hierarchy.mps |
|||
) |
|||
(action (run texfot xelatex -halt-on-error -shell-escape main.tex))) |
|||
|
|||
(rule |
|||
(targets figure_ocaml_bit1.mps figure_ocaml_bit2.mps figure_ocaml_bit3.mps) |
|||
(deps figures.ml) |
|||
(action (run mlpost %{deps}))) |
|||
|
|||
(rule |
|||
(targets figure_type_hierarchy.mps) |
|||
(deps figures2.ml) |
|||
(action (run mlpost %{deps}))) |
@ -0,0 +1,436 @@ |
|||
open Mlpost |
|||
open Box |
|||
|
|||
(* a named box intended to be used as a pointer which implies empty content *) |
|||
let named_ptr name = box ~fill:Color.lightgreen ~name (tex " ") |
|||
|
|||
(* a named scalar *) |
|||
let named_scalar ~name v = box ~fill:Color.lightcyan ~name (tex v) |
|||
|
|||
(* a named taggeg pointer *) |
|||
let named_tagged_ptr name = |
|||
hbox ~stroke:(Some Color.black) ~fill:Color.lightgreen |
|||
[ box ~stroke:None (tex "") ~name; tex ~fill:Color.lightred "" ] |
|||
|
|||
(* a named scalar *) |
|||
let named_tagged_scalar ~name v = |
|||
hbox ~stroke:(Some Color.black) ~fill:Color.lightcyan ~name |
|||
[ box ~stroke:None (tex v); tex ~fill:Color.lightmagenta "" ] |
|||
|
|||
let tagged_scalar v = |
|||
hbox ~stroke:(Some Color.black) ~fill:Color.lightcyan |
|||
[ box ~stroke:None (tex v); tex ~fill:Color.lightmagenta "" ] |
|||
|
|||
type scalar = |
|||
| Int of int |
|||
| Float of float |
|||
|
|||
let value_to_string = function |
|||
| Int n -> string_of_int n |
|||
| Float f -> string_of_float f |
|||
|
|||
let name_box name = tex (Format.sprintf "\\texttt{%s}:" name) |
|||
|
|||
module Stack = struct |
|||
type value = |
|||
| Unboxed_ptr of string |
|||
| Unboxed_scalar of string * scalar |
|||
| Tagged_ptr of string |
|||
| Tagged_scalar of string * scalar |
|||
|
|||
type t = value list |
|||
|
|||
let value_to_box = function |
|||
| Unboxed_ptr name -> hbox [ name_box name; named_ptr name ] |
|||
| Unboxed_scalar (name, v) -> |
|||
let scalar = value_to_string v in |
|||
hbox [ name_box name; named_scalar ~name scalar ] |
|||
| Tagged_ptr name -> hbox [ name_box name; named_tagged_ptr name ] |
|||
| Tagged_scalar (name, v) -> |
|||
let scalar = value_to_string v in |
|||
hbox [ name_box name; named_tagged_scalar ~name scalar ] |
|||
|
|||
let to_box l = |
|||
let l = List.map value_to_box l in |
|||
vbox ~padding:(Num.em 2.) [ tex "stack:"; vbox ~pos:`Right l ] |
|||
end |
|||
|
|||
(* a named box intended to be used as a block metadata containing scalar *) |
|||
let named_meta_scalar name = box ~name ~fill:Color.lightmagenta (tex "") |
|||
|
|||
(* a named box intended to be used as a block metadata containing ptr *) |
|||
let named_meta_ptr name = box ~name ~fill:Color.lightred (tex "") |
|||
|
|||
module Block = struct |
|||
type tagged = |
|||
| Tagged_scalar of int |
|||
| Tagged_ptr of string |
|||
|
|||
type t = |
|||
| Unboxed_ptr of string * string list |
|||
| Unboxed_scalar of string * scalar list |
|||
| Tagged of string * tagged list |
|||
| Untagged of string * string list |
|||
|
|||
let named_meta_tagged name = box ~name ~fill:Color.lightblue (tex "") |
|||
|
|||
let named_meta_untagged name = box ~name ~fill:Color.lightblue (tex "") |
|||
|
|||
let tagged = function |
|||
| Tagged_scalar n -> |
|||
let v = string_of_int n in |
|||
tagged_scalar v |
|||
| Tagged_ptr name -> hbox [ named_tagged_ptr name ] |
|||
|
|||
let untagged v = tex v |
|||
|
|||
let to_box = function |
|||
| Unboxed_ptr (name, v) -> |
|||
hblock (named_meta_ptr name :: List.map named_ptr v) |
|||
| Unboxed_scalar (name, v) -> |
|||
let v = List.map value_to_string v in |
|||
hblock (named_meta_scalar name :: List.map (tex ~fill:Color.lightcyan) v) |
|||
| Tagged (name, v) -> hblock (named_meta_tagged name :: List.map tagged v) |
|||
| Untagged (name, v) -> |
|||
hblock (named_meta_untagged name :: List.map untagged v) |
|||
|
|||
let unboxed_ptr name v = to_box @@ Unboxed_ptr (name, v) |
|||
|
|||
let unboxed_scalar name v = to_box @@ Unboxed_scalar (name, v) |
|||
|
|||
let tagged name v = to_box @@ Tagged (name, v) |
|||
|
|||
let untagged name v = to_box @@ Untagged (name, v) |
|||
end |
|||
|
|||
(* a named box intended to be used as a block metadata containing scalar *) |
|||
let named_meta_unboxed_float name = box ~name ~fill:Color.purple (tex "") |
|||
|
|||
(* a block of unboxed floats *) |
|||
let unboxed_floats_block name values = |
|||
hblock |
|||
@@ named_meta_unboxed_float name |
|||
:: List.map (tex ~fill:Color.lightcyan) values |
|||
|
|||
let scalar_array name values = |
|||
hblock ~name (List.map (tex ~fill:Color.lightcyan) values) |
|||
|
|||
let figure_python_layout = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ Unboxed_ptr "array1" |
|||
; Unboxed_ptr "array2" |
|||
; Unboxed_ptr "pair" |
|||
; Unboxed_ptr "x" |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" |
|||
; hbox ~padding:(Num.em 1.) |
|||
[ unboxed_scalar "1_meta" [ Int 1 ] |
|||
; unboxed_scalar "2_meta" [ Int 2 ] |
|||
; unboxed_scalar "3_meta" [ Int 3 ] |
|||
] |
|||
; unboxed_ptr "array1_meta" [ "array1_1"; "array1_2"; "array1_3" ] |
|||
; unboxed_ptr "pair_meta" [ "pair_1"; "pair_2" ] |
|||
; unboxed_ptr "array2_meta" [ "array2_1"; "array2_2"; "array2_3" ] |
|||
; hbox ~padding:(Num.em 1.) |
|||
[ unboxed_scalar "42_meta" [ Int 42 ] |
|||
; unboxed_scalar "99_meta" [ Int 99 ] |
|||
; unboxed_scalar "666_meta" [ Int 666 ] |
|||
] |
|||
] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure |
|||
; ptr "array1" "array1_meta" |
|||
; ptr "array1_1" "1_meta" |
|||
; ptr "array1_2" "2_meta" |
|||
; ptr "array1_3" "3_meta" |
|||
; ptr "array2" "array2_meta" |
|||
; ptr "array2_1" "42_meta" |
|||
; ptr "array2_2" "99_meta" |
|||
; ptr "array2_3" "666_meta" |
|||
; ptr "pair" "pair_meta" |
|||
; ptr "pair_1" "array1_meta" |
|||
; ptr "pair_2" "array2_meta" |
|||
; ptr "x" "42_meta" |
|||
] |
|||
|
|||
let figure_python_layout2 = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ Unboxed_ptr "array1" |
|||
; Unboxed_ptr "array2" |
|||
; Unboxed_ptr "pair" |
|||
; Unboxed_ptr "x" |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" |
|||
; unboxed_scalar "array1_meta" [ Int 1; Int 2; Int 3 ] |
|||
; unboxed_ptr "pair_meta" [ "pair_1"; "pair_2" ] |
|||
; unboxed_scalar "array2_meta" [ Int 42; Int 99; Int 666 ] |
|||
; unboxed_scalar "42_meta" [ Int 42 ] |
|||
] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure |
|||
; ptr "array1" "array1_meta" |
|||
; ptr "array2" "array2_meta" |
|||
; ptr "pair" "pair_meta" |
|||
; ptr "pair_1" "array1_meta" |
|||
; ptr "pair_2" "array2_meta" |
|||
; ptr "x" "42_meta" |
|||
] |
|||
|
|||
let figure_ocaml_layout = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ Tagged_ptr "array1" |
|||
; Tagged_ptr "array2" |
|||
; Tagged_ptr "pair" |
|||
; Tagged_scalar ("x", Int 42) |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" |
|||
; tagged "array1_meta" |
|||
[ Tagged_scalar 1; Tagged_scalar 2; Tagged_scalar 3 ] |
|||
; tagged "pair_meta" [ Tagged_ptr "pair_1"; Tagged_ptr "pair_2" ] |
|||
; tagged "array2_meta" |
|||
[ Tagged_scalar 42; Tagged_scalar 99; Tagged_scalar 666 ] |
|||
] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure |
|||
; ptr "array1" "array1_meta" |
|||
; ptr "array2" "array2_meta" |
|||
; ptr "pair" "pair_meta" |
|||
; ptr "pair_1" "array1_meta" |
|||
; ptr "pair_2" "array2_meta" |
|||
] |
|||
|
|||
let figure_java_layout = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ Unboxed_ptr "array1" |
|||
; Unboxed_ptr "array2" |
|||
; Unboxed_ptr "pair" |
|||
; Unboxed_scalar ("x", Int 42) |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" |
|||
; scalar_array "array1_array" [ "1"; "2"; "3" ] |
|||
; hbox ~padding:(Num.em 1.) |
|||
[ unboxed_scalar "1_meta" [ Int 1 ] |
|||
; unboxed_scalar "2_meta" [ Int 2 ] |
|||
; unboxed_scalar "3_meta" [ Int 3 ] |
|||
] |
|||
; unboxed_ptr "array1_meta" [ "array1_1"; "array1_2"; "array1_3" ] |
|||
; unboxed_ptr "pair_meta" [ "pair_1"; "pair_2" ] |
|||
; unboxed_ptr "array2_meta" [ "array2_1"; "array2_2"; "array2_3" ] |
|||
; hbox ~padding:(Num.em 1.) |
|||
[ unboxed_scalar "42_meta" [ Int 42 ] |
|||
; unboxed_scalar "99_meta" [ Int 99 ] |
|||
; unboxed_scalar "666_meta" [ Int 666 ] |
|||
] |
|||
] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure |
|||
; ptr "array1" "array1_array" |
|||
; ptr "array1_1" "1_meta" |
|||
; ptr "array1_2" "2_meta" |
|||
; ptr "array1_3" "3_meta" |
|||
; ptr "array2" "array2_meta" |
|||
; ptr "array2_1" "42_meta" |
|||
; ptr "array2_2" "99_meta" |
|||
; ptr "array2_3" "666_meta" |
|||
; ptr "pair" "pair_meta" |
|||
; ptr "pair_1" "array1_meta" |
|||
; ptr "pair_2" "array2_meta" |
|||
] |
|||
|
|||
let figure_ocaml_bit1 = |
|||
let figure = |
|||
hblock |
|||
[ tex "$b_{n - 1}$" |
|||
; tex "$b_{n - 2}$" |
|||
; tex "\\ldots" |
|||
; tex "$b_{1}$" |
|||
; tex ~fill:Color.lightblue "$b_{0}$" |
|||
] |
|||
in |
|||
Command.seq [ draw figure ] |
|||
|
|||
let figure_ocaml_bit2 = |
|||
let figure = |
|||
hbox ~padding:(Num.em 2.) |
|||
[ hblock |
|||
[ tex "$b_{n - 1}$" |
|||
; tex "$b_{n - 2}$" |
|||
; tex "\\ldots" |
|||
; tex "$b_{1}$" |
|||
; tex ~fill:Color.lightred "$0$" |
|||
] |
|||
; hblock |
|||
[ tex ~fill:Color.lightgreen "$b_{n - 1}$" |
|||
; tex ~fill:Color.lightgreen "$b_{n - 2}$" |
|||
; tex ~fill:Color.lightgreen "\\ldots" |
|||
; tex ~fill:Color.lightgreen "$b_{1}$" |
|||
; tex ~fill:Color.lightgreen "$0$" |
|||
] |
|||
] |
|||
in |
|||
Command.seq [ draw figure ] |
|||
|
|||
let figure_ocaml_bit3 = |
|||
let figure = |
|||
hbox ~padding:(Num.em 2.) |
|||
[ hblock |
|||
[ tex "$b_{n - 1}$" |
|||
; tex "$b_{n - 2}$" |
|||
; tex "\\ldots" |
|||
; tex "$b_{1}$" |
|||
; tex ~fill:Color.lightmagenta "$1$" |
|||
] |
|||
; hblock |
|||
[ tex ~fill:Color.lightcyan "$b_{n - 1}$" |
|||
; tex ~fill:Color.lightcyan "$b_{n - 2}$" |
|||
; tex ~fill:Color.lightcyan "\\ldots" |
|||
; tex ~fill:Color.lightcyan "$b_{1}$" |
|||
; tex ~fill:Color.lightmagenta "$1$" |
|||
] |
|||
] |
|||
in |
|||
Command.seq [ draw figure ] |
|||
|
|||
let figure_python_block1 = |
|||
let figure = |
|||
hblock |
|||
[ tex ~fill:Color.lightblue "$tag$" |
|||
; tex "$n$" |
|||
; tex ~fill:Color.lightyellow "$data_{0}$" |
|||
; tex ~fill:Color.lightyellow "\\ldots" |
|||
; tex ~fill:Color.lightyellow "$data_{n - 1}$" |
|||
] |
|||
in |
|||
Command.seq [ draw figure ] |
|||
|
|||
let figure_python_block2 = |
|||
let figure = |
|||
hbox ~padding:(Num.em 2.) |
|||
[ hblock |
|||
[ tex ~fill:Color.lightred "pointer" |
|||
; tex "$2$" |
|||
; tex ~fill:Color.lightgreen "0x\\ldots" |
|||
; tex ~fill:Color.lightgreen "0x\\ldots" |
|||
] |
|||
; hblock |
|||
[ tex ~fill:Color.lightmagenta "scalar" |
|||
; tex "$1$" |
|||
; tex ~fill:Color.lightcyan "$42$" |
|||
] |
|||
] |
|||
in |
|||
Command.seq [ draw figure ] |
|||
|
|||
let figure_ocaml_float1 = |
|||
let figure = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ untagged "meta_abc" [ "$12.13$" ] |
|||
; hbox ~padding:(Num.em 1.) |
|||
[ tagged "array" |
|||
[ Tagged_ptr "array_1" |
|||
; Tagged_ptr "array_2" |
|||
; Tagged_ptr "array_3" |
|||
] |
|||
; untagged "meta_pi" [ "$6.28318530717958623$" ] |
|||
] |
|||
; untagged "meta_42" [ "$42.0$" ] |
|||
] |
|||
in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure |
|||
; ptr "array_1" "meta_abc" |
|||
; ptr "array_2" "meta_42" |
|||
; ptr "array_3" "meta_pi" |
|||
] |
|||
|
|||
let figure_ocaml_float2 = |
|||
let figure = |
|||
unboxed_floats_block "meta_abc" |
|||
[ "$12.13$"; "$42.0$"; "$6.28318530717958623$" ] |
|||
in |
|||
Command.seq [ draw figure ] |
|||
|
|||
let figure_wasm_layout = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ Unboxed_ptr "array1" |
|||
; Unboxed_ptr "array2" |
|||
; Unboxed_ptr "pair" |
|||
; Unboxed_scalar ("x", Int 42) |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" |
|||
; unboxed_scalar "array1_meta" [ Int 1; Int 2; Int 3 ] |
|||
; unboxed_ptr "pair_meta" [ "pair_1"; "pair_2" ] |
|||
; unboxed_scalar "array2_meta" [ Int 42; Int 99; Int 666 ] |
|||
] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure |
|||
; ptr "array1" "array1_meta" |
|||
; ptr "array2" "array2_meta" |
|||
; ptr "pair" "pair_meta" |
|||
; ptr "pair_1" "array1_meta" |
|||
; ptr "pair_2" "array2_meta" |
|||
] |
|||
|
|||
let () = |
|||
Array.iter |
|||
(fun (name, figure) -> Metapost.emit name (Picture.scale (Num.em 1.) figure)) |
|||
[| ("figure_python_layout", figure_python_layout) |
|||
; ("figure_python_layout2", figure_python_layout2) |
|||
; ("figure_ocaml_layout", figure_ocaml_layout) |
|||
; ("figure_java_layout", figure_java_layout) |
|||
; ("figure_ocaml_bit1", figure_ocaml_bit1) |
|||
; ("figure_ocaml_bit2", figure_ocaml_bit2) |
|||
; ("figure_ocaml_bit3", figure_ocaml_bit3) |
|||
; ("figure_python_block1", figure_python_block1) |
|||
; ("figure_python_block2", figure_python_block2) |
|||
; ("figure_ocaml_float1", figure_ocaml_float1) |
|||
; ("figure_ocaml_float2", figure_ocaml_float2) |
|||
; ("figure_wasm_layout", figure_wasm_layout) |
|||
|] |
@ -0,0 +1,315 @@ |
|||
open Mlpost |
|||
open Box |
|||
|
|||
(* a named box intended to be used as a pointer which implies empty content *) |
|||
let named_ptr name = box ~fill:Color.lightgreen ~name (tex " ") |
|||
|
|||
(* a named scalar *) |
|||
let named_scalar ~name v = box ~fill:Color.lightcyan ~name (tex v) |
|||
|
|||
(* a named taggeg pointer *) |
|||
let named_tagged_ptr name = |
|||
hbox ~stroke:(Some Color.black) ~fill:Color.lightgreen |
|||
[ box ~stroke:None (tex "") ~name; tex ~fill:Color.lightred "" ] |
|||
|
|||
(* a named scalar *) |
|||
let named_tagged_scalar ~name v = |
|||
hbox ~stroke:(Some Color.black) ~fill:Color.lightcyan ~name |
|||
[ box ~stroke:None (tex v); tex ~fill:Color.lightmagenta "" ] |
|||
|
|||
let tagged_scalar v = |
|||
hbox ~stroke:(Some Color.black) ~fill:Color.lightcyan |
|||
[ box ~stroke:None (tex v); tex ~fill:Color.lightmagenta "" ] |
|||
|
|||
type scalar = |
|||
| Int of int |
|||
| Float of float |
|||
|
|||
let value_to_string = function |
|||
| Int n -> string_of_int n |
|||
| Float f -> string_of_float f |
|||
|
|||
let name_box name = tex (Format.sprintf "\\texttt{%s}:" name) |
|||
|
|||
module Stack = struct |
|||
type value = |
|||
| Unboxed_ptr of string |
|||
| Unboxed_scalar of string * scalar |
|||
| Tagged_ptr of string |
|||
| Tagged_scalar of string * scalar |
|||
|
|||
type t = value list |
|||
|
|||
let value_to_box = function |
|||
| Unboxed_ptr name -> hbox [ name_box name; named_ptr name ] |
|||
| Unboxed_scalar (name, v) -> |
|||
let scalar = value_to_string v in |
|||
hbox [ name_box name; named_scalar ~name scalar ] |
|||
| Tagged_ptr name -> hbox [ name_box name; named_tagged_ptr name ] |
|||
| Tagged_scalar (name, v) -> |
|||
let scalar = value_to_string v in |
|||
hbox [ name_box name; named_tagged_scalar ~name scalar ] |
|||
|
|||
let to_box l = |
|||
let l = List.map value_to_box l in |
|||
vbox ~padding:(Num.em 2.) [ tex "stack:"; vbox ~pos:`Right l ] |
|||
end |
|||
|
|||
(* a named box intended to be used as a block metadata containing scalar *) |
|||
let named_meta_scalar name = box ~name ~fill:Color.lightmagenta (tex "") |
|||
|
|||
(* a named box intended to be used as a block metadata containing ptr *) |
|||
let named_meta_ptr name = box ~name ~fill:Color.lightred (tex "") |
|||
|
|||
module Block = struct |
|||
type tagged = |
|||
| Tagged_scalar of int |
|||
| Tagged_ptr of string |
|||
|
|||
type t = |
|||
| Unboxed_ptr of string * string list |
|||
| Unboxed_scalar of string * scalar list |
|||
| Tagged of string * tagged list |
|||
| Untagged of string * string list |
|||
|
|||
let named_meta_tagged name = box ~name ~fill:Color.lightblue (tex "") |
|||
|
|||
let named_meta_untagged name = box ~name ~fill:Color.lightblue (tex "") |
|||
|
|||
let tagged = function |
|||
| Tagged_scalar n -> |
|||
let v = string_of_int n in |
|||
tagged_scalar v |
|||
| Tagged_ptr name -> hbox [ named_tagged_ptr name ] |
|||
|
|||
let untagged v = tex v |
|||
|
|||
let to_box = function |
|||
| Unboxed_ptr (name, v) -> |
|||
hblock (named_meta_ptr name :: List.map named_ptr v) |
|||
| Unboxed_scalar (name, v) -> |
|||
let v = List.map value_to_string v in |
|||
hblock (named_meta_scalar name :: List.map (tex ~fill:Color.lightcyan) v) |
|||
| Tagged (name, v) -> hblock (named_meta_tagged name :: List.map tagged v) |
|||
| Untagged (name, v) -> |
|||
hblock (named_meta_untagged name :: List.map untagged v) |
|||
|
|||
let unboxed_ptr name v = to_box @@ Unboxed_ptr (name, v) |
|||
|
|||
let unboxed_scalar name v = to_box @@ Unboxed_scalar (name, v) |
|||
|
|||
let tagged name v = to_box @@ Tagged (name, v) |
|||
|
|||
let untagged name v = to_box @@ Untagged (name, v) |
|||
end |
|||
|
|||
(* a named box intended to be used as a block metadata containing scalar *) |
|||
let named_meta_unboxed_float name = box ~name ~fill:Color.purple (tex "") |
|||
|
|||
(* a block of unboxed floats *) |
|||
let unboxed_floats_block name values = |
|||
hblock |
|||
@@ named_meta_unboxed_float name |
|||
:: List.map (tex ~fill:Color.lightcyan) values |
|||
|
|||
let scalar_array name values = |
|||
hblock ~name (List.map (tex ~fill:Color.lightcyan) values) |
|||
|
|||
|
|||
let figure_ocaml_boxed = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ Tagged_ptr "v" |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" |
|||
; tagged "v_meta" |
|||
[ Tagged_scalar 3 ] |
|||
] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure |
|||
; ptr "v" "v_meta" |
|||
] |
|||
|
|||
let figure_ocaml_boxed2 = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ Tagged_ptr "v" |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" |
|||
; tagged "v_meta" |
|||
[ Tagged_ptr "int_of_float" ] |
|||
] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure |
|||
; ptr "v" "v_meta" |
|||
] |
|||
|
|||
let figure_ocaml_unboxed = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ |
|||
Tagged_scalar ("tag", (Int 0)); |
|||
Tagged_scalar ("v", (Int 3)); |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" ] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
Command.seq |
|||
[ draw figure |
|||
] |
|||
|
|||
let figure_ocaml_unboxed2 = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ |
|||
Tagged_scalar ("tag", (Int 1)); |
|||
Tagged_ptr ("v"); |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" |
|||
; tagged "v_meta" |
|||
[ Tagged_ptr "int_of_float" ] |
|||
] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure; |
|||
ptr "v" "v_meta" |
|||
] |
|||
|
|||
let figure_ocaml_layout = |
|||
let stack = |
|||
let open Stack in |
|||
to_box |
|||
[ Tagged_ptr "array1" |
|||
; Tagged_ptr "array2" |
|||
; Tagged_ptr "pair" |
|||
; Tagged_scalar ("x", Int 42) |
|||
] |
|||
in |
|||
let heap = |
|||
let open Block in |
|||
vbox ~padding:(Num.em 2.) |
|||
[ tex "heap:" |
|||
; tagged "array1_meta" |
|||
[ Tagged_scalar 1; Tagged_scalar 2; Tagged_scalar 3 ] |
|||
; tagged "pair_meta" [ Tagged_ptr "pair_1"; Tagged_ptr "pair_2" ] |
|||
; tagged "array2_meta" |
|||
[ Tagged_scalar 42; Tagged_scalar 99; Tagged_scalar 666 ] |
|||
] |
|||
in |
|||
let figure = hbox ~padding:(Num.em 2.) [ stack; heap ] in |
|||
let ptr a b = Helpers.box_pointer_arrow (get a figure) (get b figure) in |
|||
Command.seq |
|||
[ draw figure |
|||
; ptr "array1" "array1_meta" |
|||
; ptr "array2" "array2_meta" |
|||
; ptr "pair" "pair_meta" |
|||
; ptr "pair_1" "array1_meta" |
|||
; ptr "pair_2" "array2_meta" |
|||
] |
|||
|
|||
let figure_ocaml_bit1 = |
|||
let figure = |
|||
hblock |
|||
[ tex "$b_{n - 1}$" |
|||
; tex "$b_{n - 2}$" |
|||
; tex "\\ldots" |
|||
; tex "$b_{1}$" |
|||
; tex ~fill:Color.lightblue "$b_{0}$" |
|||
] |
|||
in |
|||
Command.seq [ draw figure ] |
|||
|
|||
let figure_ocaml_bit2 = |
|||
let figure = |
|||
hbox ~padding:(Num.em 2.) |
|||
[ hblock |
|||
[ tex "$b_{n - 1}$" |
|||
; tex "$b_{n - 2}$" |
|||
; tex "\\ldots" |
|||
; tex "$b_{1}$" |
|||
; tex ~fill:Color.lightred "$0$" |
|||
] |
|||
; hblock |
|||
[ tex ~fill:Color.lightgreen "$b_{n - 1}$" |
|||
; tex ~fill:Color.lightgreen "$b_{n - 2}$" |
|||
; tex ~fill:Color.lightgreen "\\ldots" |
|||
; tex ~fill:Color.lightgreen "$b_{1}$" |
|||
; tex ~fill:Color.lightgreen "$0$" |
|||
] |
|||
] |
|||
in |
|||
Command.seq [ draw figure ] |
|||
|
|||
let figure_ocaml_bit3 = |
|||
let figure = |
|||
hbox ~padding:(Num.em 2.) |
|||
[ hblock |
|||
[ tex "$b_{n - 1}$" |
|||
; tex "$b_{n - 2}$" |
|||
; tex "\\ldots" |
|||
; tex "$b_{1}$" |
|||
; tex ~fill:Color.lightmagenta "$1$" |
|||
] |
|||
; hblock |
|||
[ tex ~fill:Color.lightcyan "$b_{n - 1}$" |
|||
; tex ~fill:Color.lightcyan "$b_{n - 2}$" |
|||
; tex ~fill:Color.lightcyan "\\ldots" |
|||
; tex ~fill:Color.lightcyan "$b_{1}$" |
|||
; tex ~fill:Color.lightmagenta "$1$" |
|||
] |
|||
] |
|||
in |
|||
Command.seq [ draw figure ] |
|||
|
|||
let figure_type_hierarchy = |
|||
let f = |
|||
let open Tree in |
|||
let leaf s = leaf (tex ~style:Rect s) in |
|||
let node s = node ~arrow_style:Undirected (tex ~style:Rect s) in |
|||
|
|||
let t = |
|||
(node "any" [node "eq" [leaf "i31"; leaf "struct"; leaf "array"]]) |
|||
in |
|||
hbox ~padding:(Num.em 2.) [ |
|||
to_box t; to_box @@ node "func" [] ; to_box @@ node "extern" [] |
|||
] |
|||
in |
|||
Command.seq [ draw f] |
|||
|
|||
let () = |
|||
Array.iter |
|||
(fun (name, figure) -> Metapost.emit name (Picture.scale (Num.em 1.) figure)) |
|||
[| ("figure_ocaml_boxed", figure_ocaml_boxed) |
|||
; ("figure_ocaml_boxed2", figure_ocaml_boxed2) |
|||
; ("figure_ocaml_unboxed", figure_ocaml_unboxed) |
|||
; ("figure_ocaml_unboxed2", figure_ocaml_unboxed2) |
|||
; ("figure_type_hierarchy", figure_type_hierarchy) |
|||
|] |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 132 KiB |
@ -0,0 +1,38 @@ |
|||
\documentclass[12pt]{beamer} |
|||
|
|||
\usetheme[]{metropolis} |
|||
|
|||
\usepackage{graphicx} % to include img |
|||
\usepackage[notransparent]{svg} % to include svg |
|||
\usepackage{minted} % source code highlighting |
|||
\setminted{autogobble=true} % remove unneeded indentation |
|||
|
|||
\setmainfont{Linux Libertine O} |
|||
\setsansfont{Linux Biolinum O} |
|||
\setmonofont{RobotoMono Nerd Font} |
|||
|
|||
\newcommand{\auth}[3]{#1 {\tiny{\texttt{<#2>}}}\textsuperscript{#3}} |
|||
|
|||
\title{Wasocaml: compiling OCaml to WebAssembly} |
|||
\author{\auth{Léo Andrès}{l@ndrs.fr}{1, 2}\\ |
|||
\auth{Pierre Chambart}{pierre.chambart@ocamlpro.com}{1}\\ |
|||
\auth{Jean-Christophe Filliâtre}{jean-christophe.filliatre@cnrs.fr}{2} |
|||
} |
|||
\date{August 2023 -- IFL'23 -- Braga} |
|||
\institute{1. OCamlPro\\ |
|||
2. Université Paris-Saclay, CNRS, ENS Paris-Saclay, Inria, Laboratoire Méthodes Formelles\\ |
|||
\\ |
|||
\includegraphics[width=16.5em]{logo_ocp.png} |
|||
\hspace{5em} |
|||
\includesvg[width=14.5em]{logo_lmf} |
|||
} |
|||
|
|||
\begin{document} |
|||
|
|||
\begin{frame} |
|||
\titlepage{} |
|||
\end{frame} |
|||
|
|||
\input{slides.tex} |
|||
|
|||
\end{document} |
After Width: | Height: | Size: 1.1 MiB |
@ -0,0 +1,319 @@ |
|||
\newcommand{\ocaml}[1]{\mintinline{ocaml}{#1}} |
|||
\newcommand{\wasm}[1]{\mintinline{wast}{#1}} |
|||
|
|||
% TODO: about part (me, ocp, lmf) ? |
|||
|
|||
% JavaScript / Wasm |
|||
|
|||
\begin{frame} |
|||
JavaScript: |
|||
\begin{itemize} |
|||
\item bad/unpredictable performances |
|||
\item unsafe |
|||
\end{itemize} |
|||
WebAssembly (Wasm) is safe and has good/predictable performances, used: |
|||
\begin{itemize} |
|||
\item on the Web: V8, SpiderMonkey |
|||
\item on the Cloud: Fastly, CloudFlare |
|||
\item as a portable binary format |
|||
\item to interface with C from other languages |
|||
\end{itemize} |
|||
|
|||
\end{frame} |
|||
|
|||
% Wasm1 |
|||
% TODO: talk about the embedder somewhere |
|||
|
|||
\begin{frame} |
|||
Wasm1: |
|||
\begin{itemize} |
|||
\item compact binary format (Wasm) and text format (Wat) |
|||
\item functions |
|||
\item stack machine (stack can not be inspected) |
|||
\item static verification and typecheck (few dynamic tests) |
|||
\item one \wasm{memory} per module |
|||
\item only scalar types: \wasm{i32}, \wasm{i64}, \wasm{f32}, \wasm{f64} |
|||
\item only exported items can be used by other modules |
|||
\item can be seen as a simplified C |
|||
\end{itemize} |
|||
\end{frame} |
|||
|
|||
\begin{frame}[fragile] |
|||
\begin{minted}{wast} |
|||
(func $fact (param $x i32) (result i32) |
|||
(if (i32.eq (local.get $x) (i32.const 0)) |
|||
(then (i32.const 1)) |
|||
(else |
|||
(i32.mul |
|||
(local.get $x) |
|||
(call $fact |
|||
(i32.sub |
|||
(local.get $x) |
|||
(i32.const 1))))))) |
|||
\end{minted} |
|||
\end{frame} |
|||
|
|||
\begin{frame}[fragile] |
|||
\begin{minted}{wast} |
|||
(func $fact (param $x i32) (result i32) |
|||
i32.const 0 |
|||
local.get $x |
|||
i32.eq |
|||
(if |
|||
(then i32.const 1) |
|||
(else |
|||
local.get $x |
|||
i32.const 1 |
|||
i32.sub |
|||
call $fact |
|||
local.get $x |
|||
i32.mul))) |
|||
\end{minted} |
|||
\end{frame} |
|||
|
|||
% C/C++/Rust to Wasm1 |
|||
|
|||
\begin{frame} |
|||
Compiling runtime-free languages such as C/C++/Rust to Wasm is straightforward.\\ |
|||
Some primitives such as \mintinline{c}{malloc} need to be rewritten in Wasm and provided by the compiler. |
|||
\end{frame} |
|||
|
|||
% TODO: how do GC work |
|||
|
|||
% GC languages to Wasm1 |
|||
|
|||
\begin{frame} |
|||
Compiling garbage-collected languages to Wasm1 is more involved: |
|||
\begin{itemize} |
|||
\item runtime must be rewritten, or compiled from C to Wasm: difficult because of Wasm safety properties |
|||
\item GC need to inspect the stack to find roots, not possible in Wasm, requires a shallow stack |
|||
\item interactions with the GC of the embedder are difficult (cycles can't be collected) |
|||
\end{itemize} |
|||
|
|||
Need for a proper GC in Wasm. |
|||
\end{frame} |
|||
|
|||
\begin{frame} |
|||
Requirements: |
|||
\begin{itemize} |
|||
\item safe and fast |
|||
\item do not make Wasm1 code slower |
|||
\item fit with many existing value representation strategies |
|||
\end{itemize} |
|||
\end{frame} |
|||
|
|||
% Flambda1 |
|||
|
|||
\begin{frame} |
|||
\includegraphics[width=25em]{ocaml_chain.png} |
|||
\end{frame} |
|||
|
|||
\begin{frame} |
|||
\begin{center} |
|||
\begin{description} |
|||
\item[Lambda] closures are still implicit, not optimised |
|||
\item[Bytecode] not enough optimised |
|||
\item[Clambda] code pointers and values mixed in closures |
|||
\item[Cmm] even more low-level (pointer arithmetic) |
|||
\item[Flambda] our choice for the first prototype |
|||
\item[Flambda2] our choice for the future |
|||
\end{description} |
|||
\end{center} |
|||
Flambda: |
|||
\begin{itemize} |
|||
\item ANF |
|||
\item explicit closures |
|||
\item high-level: works on abstract values and not directly on the actual memory layout (this is done by \texttt{Cmm}) |
|||
\end{itemize} |
|||
\end{frame} |
|||
|
|||
\begin{frame}[fragile] |
|||
\begin{minted}{ocaml} |
|||
let f = print_int |
|||
let rec iter f l = |
|||
match l with |
|||
| [] -> () |
|||
| hd :: tl -> |
|||
f hd; |
|||
iter f tl |
|||
let () = |
|||
let iter_print = iter f in |
|||
iter_print [2; 1] |
|||
\end{minted} |
|||
\end{frame} |
|||
|
|||
\begin{frame}[fragile] |
|||
\begin{minted}{ocaml} |
|||
let f = |
|||
let s = |
|||
make_closures |
|||
| cl_f { x } env -> print_int x |
|||
with vars |
|||
end |
|||
in |
|||
project_closure cl_f from s |
|||
in |
|||
|
|||
let iter = |
|||
let set = |
|||
make_closures |
|||
| cl_iter { f } env -> |
|||
let otherset = |
|||
make_closures |
|||
| cl_iter_f { l } envtwo -> |
|||
switch l |
|||
with int |
|||
| 0 -> const 0 |
|||
with tag |
|||
| 0 -> |
|||
let x = get_field 0 l in |
|||
let f = project_var f from envtwo in |
|||
let dummy = f x in |
|||
let tl = get_field 1 l in |
|||
envtwo tl |
|||
end |
|||
with vars |
|||
| f -> f |
|||
end |
|||
in |
|||
project_closure cl_iter_f from otherset |
|||
with vars |
|||
end |
|||
in |
|||
project_closure cl_iter from set |
|||
in |
|||
|
|||
let lempty = const 0 in |
|||
let one = const 1 in |
|||
let lone = make_block 0 one lempty in |
|||
let two = const 2 in |
|||
let ltwo = make_block 0 two lone in |
|||
let iter_print = iter f in |
|||
iter_print ltwo |
|||
\end{minted} |
|||
\end{frame} |
|||
|
|||
% Compiling Flambda1 to WasmGC |
|||
|
|||
\begin{frame} |
|||
Value representation strategies: |
|||
\begin{itemize} |
|||
\item monomorphisation (C++/Rust) |
|||
\item boxing everything (Python) |
|||
\item boxing only in polymorphic places (Java) |
|||
\item pointer-tagging: unboxing small scalars (OCaml) |
|||
\item tagged union (Lua) |
|||
% TODO: add it back ? |
|||
%\item type-passing (TIL, AliceML) |
|||
\item runtime monomorphisation (F\#) |
|||
\end{itemize} |
|||
\end{frame} |
|||
|
|||
\begin{frame} |
|||
uniform representation using a tagged single machine word: |
|||
\begin{center} |
|||
\includegraphics[width=10em]{figure_ocaml_bit1.mps} |
|||
\end{center} |
|||
if $b_{0} = 0$, the value is a pointer to a heap-allocated block: |
|||
\begin{center} |
|||
\includegraphics[width=20em]{figure_ocaml_bit2.mps} |
|||
\end{center} |
|||
if $b_{1} = 1$, the $n - 1$ most significant bits are a small scalar: |
|||
\begin{center} |
|||
\includegraphics[width=20em]{figure_ocaml_bit3.mps} |
|||
\end{center} |
|||
small scalars: \ocaml{bool}, \ocaml{char}, \ocaml{int}, constant constructors of ADTs |
|||
\end{frame} |
|||
|
|||
\begin{frame} |
|||
A type system to represent values from any kind of source language is too complex.\\ |
|||
Instead, WasmGC introduces reference types and a subtyping hierarchy: |
|||
\begin{center} |
|||
\includegraphics[width=20em]{figure_type_hierarchy.mps} |
|||
\end{center} |
|||
The hierarchy tells which casts are allowed.\\ |
|||
Upcasts are implicit.\\ |
|||
Downcasts are explicit and lead to runtime errors if incorrect.\\ |
|||
Casts are cheap.\\ |
|||
Possible to dynamically test for compatibility. |
|||
\end{frame} |
|||
|
|||
\begin{frame} |
|||
\begin{center} |
|||
\includegraphics[width=20em]{figure_type_hierarchy.mps} |
|||
\end{center} |
|||
Uniform representation through \wasm{eqref} (\ocaml{==} operator).\\ |
|||
Can't be more precise because of \ocaml{Obj.magic}, GADTs and types that have scalar/blocks values.\\ |
|||
Small scalars are \wasm{i31ref}.\\ |
|||
OCaml arrays are \wasm{array}.\\ |
|||
Others heap-allocated blocks are \wasm{struct} or \wasm{array}. |
|||
\end{frame} |
|||
|
|||
% TODO: example with i31 ? |
|||
|
|||
\begin{frame} |
|||
In \ocaml{get_field n x} the type of \ocaml{x} is unknown.\\ |
|||
Could propagate more types but breaks some optimisations.\\ |
|||
Not enough because of \ocaml{Obj.field}.\\ |
|||
All we know is that \ocaml{x} is a block of size $n + 1$ at least. |
|||
\end{frame} |
|||
|
|||
\begin{frame}[fragile] |
|||
Blocks as structs: |
|||
|
|||
\begin{minted}{wast} |
|||
(type $block1 (struct |
|||
(field $tag i8) |
|||
(field $field0 eqref))) |
|||
|
|||
(type $block2 (sub $block1) (struct |
|||
(field $tag i8) |
|||
(field $field0 eqref) |
|||
(field $field1 eqref))) |
|||
|
|||
;; and so on... |
|||
\end{minted} |
|||
|
|||
We cast \ocaml{x} to \wasm{$block}$(n+1)$. |
|||
\end{frame} |
|||
|
|||
\begin{frame}[fragile] |
|||
swrup/ocaml-emoji: |
|||
\setmonofont{Symbola} |
|||
\begin{minted}{ocaml} |
|||
let fox = "🦊" |
|||
let framed_picture = "🖼" |
|||
let free_button = "🆓" |
|||
let french_fries = "🍟" |
|||
let fried_shrimp = "🍤" |
|||
let frog = "🐸" |
|||
let front_facing_baby_chick = "🐥" |
|||
\end{minted} |
|||
\setmonofont{RobotoMono Nerd Font} |
|||
Modules represented as blocks: each toplevel value is a field. |
|||
\begin{center} |
|||
\emph{too long subtyping chain} ☹ |
|||
\end{center} |
|||
We have two variations to avoid this problem, not implemented yet. |
|||
% TODO: ^ split on many slides |
|||
\end{frame} |
|||
|
|||
\begin{frame} |
|||
Blocks as arrays: an array of \wasm{eqref} with the tag stored at position 0. |
|||
\end{frame} |
|||
|
|||
% Formalized compilation |
|||
|
|||
% Wasocaml |
|||
|
|||
% Benchmarks |
|||
|
|||
% FFI |
|||
|
|||
% Effects |
|||
|
|||
% Related works |
|||
|
|||
% Future works |
|||
|
|||
% Symbolic execution |
Loading…
Reference in new issue