Skip to content

Commit cba24af

Browse files
authored
Incorporate changes from Artifact Evaluation process (#7)
1 parent a01f6a8 commit cba24af

32 files changed

+548
-97
lines changed

ARTIFACT.md

+225
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# ICFP 2023 Artifact Instructions
2+
3+
Name: *Special Delivery: Programming with Mailbox Types*
4+
5+
## Artifact Instructions
6+
7+
This is the artifact for the paper "Special Delivery: Programming with Mailbox
8+
Types". The artifact consists of a QEMU image (based on the ICFP base image)
9+
containing the Pat typechecker and scripts to help evaluate the artifact.
10+
The typechecker is written in OCaml, and uses Z3 as a backend solver for
11+
Presburger formulae. Please see the "QEMU Instructions" section for instructions
12+
on how to boot the QEMU image.
13+
14+
## Credentials
15+
16+
* Username: artifact
17+
* Password: password
18+
19+
### Scope
20+
21+
The typechecker implements the bidirectional type system described in Section 4.
22+
In addition, it implements all of the extensions (products, sums, lambdas, and
23+
interfaces). The artifact will also allow you to generate the table from the
24+
Evaluation section of the paper; includes all of the examples from the paper and
25+
evaluation; and will allow you to test your own examples.
26+
27+
### Sample evaluation workflow
28+
29+
1. `cd mbcheck` into the project directory.
30+
2. Build the `mbcheck` binary by running `make`.
31+
2. Run the test suite by running `make test`.
32+
3. Try the examples from the paper (see the "Mapping to Paper" section)
33+
4. Generate the table from section 6 by running `./generate-table.py`. (Note,
34+
this is set to perform 100 iterations by default; you can change this by
35+
modifying the `REPETITIONS` parameter)
36+
5. Try your own examples, if you like! You can invoke the typechecker by
37+
`./mbcheck <name>`. It will exit silently if the example typechecks. If you
38+
would like to see the inferred and simplified patterns, use the `-v` option.
39+
6. Have a look at the salient parts of the implementation (see the "Navigating
40+
the source code" section)
41+
42+
### Tool options
43+
44+
Invoke `mbcheck` as `./mbcheck <options> filename`. The options are as follows:
45+
* `-v`: verbose mode; outputs program with solved constraints
46+
* `-d`: debug mode; outputs detailed information about pattern constraints
47+
* `-b <count>` or `--benchmark=<count>`: output mean time taken to typecheck
48+
file over `<count>` iterations
49+
* `--ir` prints the IR after translation
50+
* `--mode=MODE` where `MODE` is one of `strict`, `interface`, or `none`:
51+
defines alias checking mode. `strict` requires that no free names occur
52+
within a guard; `interface` (default) requires that received names have a
53+
different interface to the free names in a guard; and `none` (unsound)
54+
turns off alias checking
55+
56+
### Mapping to Paper
57+
58+
All Pat code snippets in the paper, along with all examples, are included in the
59+
artifact.
60+
61+
You can run all of these using the `./run-paper-examples.py` script.
62+
63+
* The Future example from the introduction can be found in
64+
`test/examples/de_liguoro_padovani/future.pat`. This should typecheck without
65+
error.
66+
* The use-after-free examples should all raise errors, and can be found as follows:
67+
- Fig 3(a): `test/errors/uaf1.pat`
68+
- Fig 3(b): `test/errors/uaf2.pat`
69+
- Fig 3(c): `test/errors/uaf3.pat`
70+
* Programs introducing the problem in "Aliasing through communication" should
71+
also raise errors, and can be found in:
72+
- `test/errors/alias_comm1.pat`
73+
- `test/errors/alias_comm2.pat`
74+
* The product example from Sec 5.1 can be found in `test/examples/product.pat`
75+
* The interface example from Sec 5.1 can be found in `test/examples/interfaces.pat`
76+
* The de'Liguoro & Padovani examples from Sec 6 can be found in
77+
`test/examples/de_liguoro_padovani`.
78+
* The Savina examples from Sec 6 can be found in `test/examples/savina`.
79+
* The Robots case study from Sec 6 can be found in `test/examples/robotsn.pat`.
80+
81+
### Language guide & build / installation instructions
82+
A guide to the language, as well as build and installation instructions, can be
83+
found in `mbcheck/README.md`.
84+
85+
### Difference between core calculus and concrete syntax
86+
87+
The implementation is fairly faithful to the syntax from Fig. 4, with the
88+
following syntactic modifications:
89+
90+
* Since we perform an A-normalisation step, it is possible to write nested
91+
expressions (i.e., `(1 + 2) + 3` rather than `let x = 1 + 2 in x + 3`).
92+
* It is not necessary to specify a pattern or usage when writing a mailbox
93+
type (you can see this, for example, in the Future example).
94+
- You can write `Future!` to mean a send mailbox with interface `Future`.
95+
- You can also ascribe a pattern to a mailbox type: for example, you could
96+
write `Future!Put` to denote a mailbox type with interface Future, which
97+
must send a Put message.
98+
- By default, send mailbox types are inferred as having a second-class
99+
usage, whereas receive mailbox types are inferred as being returnable.
100+
You can specify the usage explicitly using the `[U]` (for second-class)
101+
and `[R]` (for returnable) modifiers.
102+
So, to complete our example, a returnable output mailbox type for the Future
103+
interface which can send a Put message is `Future!Put[R]`
104+
* Messages are written with parentheses rather than braces (e.g., `x ! m(y)`
105+
rather than `x ! m[y]`).
106+
* We require interfaces as standard, so it's necessary to specify an interface
107+
name with `new`, i.e., `let x = new[Future] in ...`
108+
* Branches of case expressions are separated with a pipe (`|`) rather than a
109+
semicolon, i.e., `case V { inl x -> M | inr y -> N }`
110+
111+
### Navigating the source code
112+
113+
The source code can be found in the `mbcheck` directory. Salient code locations
114+
are as follows:
115+
116+
* `bin/main.ml`: main entry point / command line processing
117+
* `lib/common/sugar_ast.ml`: post-parsing AST
118+
* `lib/common/ir.ml`: explicitly-sequenced intermediate representation
119+
* `lib/frontend/parser.mly`: grammar
120+
* `lib/frontend/pipeline.ml`: desugaring / typechecking pipeline
121+
* `lib/frontend/sugar_to_ir.ml`: IR conversion, converting sugared AST
122+
to explicitly-sequenced representation
123+
* `lib/typecheck/pretypecheck.ml`: contextual typing pass to propagate
124+
interface information (sec 5)
125+
* `lib/typecheck/gen_constraints.ml`: backwards bidirectional type system
126+
described in section 4
127+
- `synthesise_val` and `synthesise_comp` correspond to the synthesis
128+
judgement `M =P=> t |> env; constrs`
129+
- `check_val` and `check_comp` correspond to the checking judgement
130+
`M <=P= t |> env; constrs`
131+
- `check_guard` corresponds to the guard checking judgement
132+
`{E} G <=P= t |> Phi; consts; F`
133+
* `lib/typecheck/ty_env.ml`: algorithmic type & environment joining / merging
134+
- `combine` corresponds to disjoint combination `t1 + t2 |> t; constrs`
135+
- `join` corresponds to sequential combination `t1 ; t2 |> t; constrs`
136+
- `intersect` corresponds to disjoint combination `t1 cap t2 |> t; constrs`
137+
* `lib/typecheck/solve_constraints.ml` converts pattern constraints into
138+
Presburger formulae to be solved by Z3
139+
* `lib/typecheck/z3_solver.ml` interfaces with the Z3 solver
140+
141+
## QEMU Instructions
142+
143+
The ICFP 2023 Artifact Evaluation Process is using a Debian QEMU image as a
144+
base for artifacts. The Artifact Evaluation Committee (AEC) will verify that
145+
this image works on their own machines before distributing it to authors.
146+
Authors are encouraged to extend the provided image instead of creating their
147+
own. If it is not practical for authors to use the provided image then please
148+
contact the AEC co-chairs before submission.
149+
150+
QEMU is a hosted virtual machine monitor that can emulate a host processor
151+
via dynamic binary translation. On common host platforms QEMU can also use
152+
a host provided virtualization layer, which is faster than dynamic binary
153+
translation.
154+
155+
QEMU homepage: https://www.qemu.org/
156+
157+
### Installation
158+
159+
#### OSX
160+
``brew install qemu``
161+
162+
#### Debian and Ubuntu Linux
163+
``sudo apt update``
164+
``sudo apt install qemu-system-x86``
165+
166+
On x86 laptops and server machines you may need to enable the
167+
"Intel Virtualization Technology" setting in your BIOS, as some manufacturers
168+
leave this disabled by default. See Debugging.md for details.
169+
170+
171+
#### Arch Linux
172+
173+
``pacman -Sy qemu``
174+
175+
See the [Arch wiki](https://wiki.archlinux.org/title/QEMU) for more info.
176+
177+
See Debugging.md if you have problems logging into the artifact via SSH.
178+
179+
180+
#### Windows 10
181+
182+
Download and install QEMU via the links at
183+
184+
https://www.qemu.org/download/#windows.
185+
186+
Ensure that `qemu-system-x86_64.exe` is in your path.
187+
188+
Start Bar -> Search -> "Windows Features"
189+
-> enable "Hyper-V" and "Windows Hypervisor Platform".
190+
191+
Restart your computer.
192+
193+
#### Windows 8
194+
195+
See Debugging.md for Windows 8 install instructions.
196+
197+
### Startup
198+
199+
The base artifact provides a `start.sh` script to start the VM on unix-like
200+
systems and `start.bat` for Windows. Running this script will open a graphical
201+
console on the host machine, and create a virtualized network interface.
202+
On Linux you may need to run with `sudo` to start the VM. If the VM does not
203+
start then check `Debugging.md`
204+
205+
Once the VM has started you can login to the guest system from the host.
206+
Whenever you are asked for a password, the answer is `password`. The default
207+
username is `artifact`.
208+
209+
```
210+
$ ssh -p 5555 artifact@localhost
211+
```
212+
213+
You can also copy files to and from the host using scp.
214+
215+
```
216+
$ scp -P 5555 artifact@localhost:somefile .
217+
```
218+
219+
### Shutdown
220+
221+
To shutdown the guest system cleanly, login to it via ssh and use
222+
223+
```
224+
$ sudo shutdown now
225+
```

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ all:
55

66
.PHONY: test
77
test:
8-
cd test && ./run-tests.py
8+
cd test && python3 run-tests.py
99

1010
.PHONY: pin
1111
pin:

bin/main.ml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
open Common
2-
open Typecheck
3-
42

53
let print_result (prog, prety, _ir, ty, _env, _constrs) =
64
let open Format in
@@ -18,18 +16,18 @@ let print_result (prog, prety, _ir, ty, _env, _constrs) =
1816

1917
(* for IR translation testing *)
2018
let print_ir (prog, _prety, ir, _ty, _env, _constrs) =
21-
let open Format in
2219
Format.printf
2320
"=== Resolved Program: ===\n%a\n\n"
2421
(Sugar_ast.pp_program) prog;
2522
Format.printf
2623
"=== Intermediate Representation: ===\n%a\n\n"
2724
(Ir.pp_program) ir
2825

29-
let process filename is_verbose is_debug is_ir mode () =
26+
let process filename is_verbose is_debug is_ir mode benchmark_count () =
3027
Settings.(set verbose is_verbose);
3128
Settings.(set debug is_debug);
3229
Settings.(set receive_typing_strategy mode);
30+
Settings.(set benchmark benchmark_count);
3331
try
3432
Frontend.Parse.parse_file filename ()
3533
|> Frontend.Pipeline.pipeline
@@ -49,6 +47,8 @@ let () =
4947
$ Arg.(value & flag & info ["ir"] ~doc:"print the parsed program and its IR translation")
5048
$ Arg.(value & opt (enum Settings.ReceiveTypingStrategy.enum) Settings.ReceiveTypingStrategy.Interface & info ["mode"]
5149
~docv:"MODE" ~doc:"typechecking mode for receive blocks (allowed: strict, interface, none)")
50+
$ Arg.(value & opt int (-1) & info ["b"; "benchmark"]
51+
~docv:"BENCHMARK" ~doc:"number of repetitions for benchmark; -1 (default) for no benchmarking")
5252
$ const ()) in
5353
let info = Cmd.info "mbcheck" ~doc:"Typechecker for mailbox calculus" in
5454
Cmd.v info mbcheck_t

dune

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
; w7: Overridden method (can't see how to do 'ancestors' in visitors without this off)
22
; w17: Virtual method unimplemented, incompatible with fold visitor
3+
; w21: non-returning statement
34
; w33: Unused open -- silly during dev
45
; w34: Unused type
6+
; w39: Unused rec vlag
57
; w26, w27, w32: Unused variable name -- will want eventually but not yet
68
(env
79
(dev
810
; (flags (:standard -w -7-17-32-33-27-26-34-39))
9-
(flags (:standard -g -w -7-17-21-33-34-39))
11+
; (flags (:standard -g -w -7-17-21-33-34-39))
12+
(flags (:standard -g -w -7-17))
1013
)
1114
)

generate-table.py

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/usr/bin/env python3
2+
import os
3+
import subprocess
4+
from tabulate import tabulate
5+
6+
REPETITIONS = 100
7+
8+
BENCHMARKS =\
9+
[
10+
("Lock", os.path.join("test", "examples", "de_liguoro_padovani", "lock.pat")),
11+
("Future", os.path.join("test", "examples", "de_liguoro_padovani", "future.pat")),
12+
("Account", os.path.join("test", "examples", "de_liguoro_padovani", "account.pat")),
13+
("AccountF", os.path.join("test", "examples", "de_liguoro_padovani", "account_future.pat")),
14+
("Master-Worker", os.path.join("test", "examples", "de_liguoro_padovani", "master_worker.pat")),
15+
("Session Types", os.path.join("test", "examples", "de_liguoro_padovani", "sessions.pat")),
16+
("Ping Pong", os.path.join("test", "examples", "savina", "ping_pong_strict.pat")),
17+
("Thread Ring", os.path.join("test", "examples", "savina", "thread_ring.pat")),
18+
("Counter", os.path.join("test", "examples", "savina", "count.pat")),
19+
("K-Fork", os.path.join("test", "examples", "savina", "kfork.pat")),
20+
("Fibonacci", os.path.join("test", "examples", "savina", "fib.pat")),
21+
("Big", os.path.join("test", "examples", "savina", "big.pat")),
22+
("Philosopher", os.path.join("test", "examples", "savina", "philosopher.pat")),
23+
("Smokers", os.path.join("test", "examples", "savina", "cig_smok.pat")),
24+
("Log Map", os.path.join("test", "examples", "savina", "log_map.pat")),
25+
("Transaction", os.path.join("test", "examples", "savina", "banking.pat"))
26+
]
27+
28+
# Tries to run in strict mode -- returns True if it works, False otherwise
29+
def try_strict(path):
30+
return subprocess.run(["./mbcheck", "--mode=strict", path],\
31+
capture_output=True).returncode == 0
32+
33+
def run_benchmark(name, path):
34+
print("Running example " + name)
35+
is_strict = try_strict(path)
36+
time = str(subprocess.run(["./mbcheck", "-b", str(REPETITIONS), path],\
37+
capture_output=True, text=True).stdout)
38+
return (name, is_strict, time)
39+
40+
def main():
41+
print("Generating table -- this may take some time.")
42+
results = [run_benchmark(name, path) for (name, path) in BENCHMARKS]
43+
print(tabulate(results, headers=["Name", "Strict", "Time (ms)"], tablefmt='grid'))
44+
45+
if __name__ == "__main__":
46+
main()

lib/common/settings.ml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ end
1010

1111
let verbose = ref false
1212
let debug = ref false
13+
let benchmark = ref (-1)
1314
let receive_typing_strategy = ref ReceiveTypingStrategy.Interface
1415

1516
let set : 'a setting -> 'a -> unit = fun setting value ->

lib/common/settings.mli

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ end
88

99
val verbose : bool setting
1010
val debug : bool setting
11+
val benchmark : int setting
1112
val receive_typing_strategy : ReceiveTypingStrategy.t setting
1213

1314
val set : 'a setting -> 'a -> unit

lib/frontend/benchmark.ml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
(* Utility functions used for benchmarking. *)
2+
3+
let time f =
4+
let start = Unix.gettimeofday () in
5+
let fxy = f () in
6+
let ms = (Unix.gettimeofday () -. start) *. 1000.0 in
7+
(ms, fxy)
8+
9+
let rec repeat n acc_ms f =
10+
if n <= 0 then (
11+
acc_ms
12+
)
13+
else (
14+
let (ms, _) = time f in
15+
(* Print.printf "Run #%d complete in %.2fms.\n" n ms; *)
16+
(* flush stdout; *)
17+
repeat (n - 1) (acc_ms +. ms) f
18+
)
19+
20+
let benchmark n f =
21+
(* Printf.printf "Starting benchmark with %d run(s)..\n" n; *)
22+
flush stdout;
23+
let total_ms = repeat n 0.0 f in
24+
Printf.printf "%.2f" (total_ms /. (float_of_int n))

lib/frontend/desugar_let_annotations.ml

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
let x: A = M in N --> let x = (M : (returnable(A))) in N
33
*)
44
open Common
5-
open Common_types
65

76
let visitor =
87
object(self)

0 commit comments

Comments
 (0)