Compiler Construction
Mayer Goldberg \ Ben-Gurion University Wednesday 22nd January, 2020
Mayer Goldberg \ Ben-Gurion University Compiler Construction 1 / 87
Compiler Construction Compiler Construction 1 / 87 Mayer Goldberg \ - - PowerPoint PPT Presentation
Compiler Construction Compiler Construction 1 / 87 Mayer Goldberg \ Ben-Gurion University Wednesday 22 nd January, 2020 Mayer Goldberg \ Ben-Gurion University Chapter 10 Goals Compiler Construction 2 / 87 Asynchronous Computing
Mayer Goldberg \ Ben-Gurion University Compiler Construction 1 / 87
▶ Coroutines, Threads & processes ▶ Context switching & tail-position ▶ The two-thread architecture
Mayer Goldberg \ Ben-Gurion University Compiler Construction 2 / 87
▶ α- — the prefjx “not”, “un-” ▶ σῠν- — the prefjx “with”, “together” ▶ χρόνος — the Greek God of time; time ▶ συνχρόνος — in time, in order, in phase, in step ▶ Synchronous computing means sequential computing ▶ Asynchronous computing means non-sequential computing, or
Mayer Goldberg \ Ben-Gurion University Compiler Construction 3 / 87
▶ True asynchronous computing requires truly independent
▶ Asynchronous computing is often simulated or augmented
Mayer Goldberg \ Ben-Gurion University Compiler Construction 4 / 87
▶ We begin with several, independent computations:
Mayer Goldberg \ Ben-Gurion University Compiler Construction 5 / 87
▶ Each computation is split into small, sequential chunks:
Mayer Goldberg \ Ben-Gurion University Compiler Construction 6 / 87
▶ The chunks of the difgerent computations are interleaved, and
Mayer Goldberg \ Ben-Gurion University Compiler Construction 7 / 87
▶ Under coöperative multitasking, each task must relinquish
▶ If it fails to do so, either by design or because of a bug, the
▶ Coöperative multitasking was used in Mac OS, the operating
Mayer Goldberg \ Ben-Gurion University Compiler Construction 8 / 87
▶ Special hardware (e.g., a timer-interrupt facility) is used to wrest
▶ No coöperation is required of the current task ▶ Generally, this kind of task-switching cannot be prevented ▶ This is how task-switching is implemented on modern operating
▶ The opposite of pre-emptive multitasking is non-pre-emptive
Mayer Goldberg \ Ben-Gurion University Compiler Construction 9 / 87
▶ Instrumentation means that the code is
▶ As with preemption, instrumented code cannot afgect or prevent
▶ We show how to do it manually ▶ Since the transformation is algorithmic, it can be done
Mayer Goldberg \ Ben-Gurion University Compiler Construction 10 / 87
▶ Context switching & tail-position ▶ The two-thread architecture
Mayer Goldberg \ Ben-Gurion University Compiler Construction 11 / 87
▶ Coroutines: All coroutines share the same stack and the same
▶ Threads: Each thread has its own stack, but all threads share
▶ Processes: Each process has its own stack & heap
Mayer Goldberg \ Ben-Gurion University Compiler Construction 12 / 87
▶ The two-thread architecture
Mayer Goldberg \ Ben-Gurion University Compiler Construction 13 / 87
▶ Each thread may consist of procedures calling each other, and
▶ Since each thread comes with its own stack, the activation
▶ Rather than implement several stacks, we require that all
▶ We use the CPS-transformation to convert all user-defjned code
▶ By applying the CPS-transformation, the thread-specifjc stack
▶ Because of lexical scope, one thread cannot access the
Mayer Goldberg \ Ben-Gurion University Compiler Construction 14 / 87
▶ Instrumenting code for the 2-thread architecture ▶ Racing & termination ▶ Detecting circularity ▶ Prioritization ▶ Threads & Types in Ocaml Mayer Goldberg \ Ben-Gurion University Compiler Construction 15 / 87
▶ We present a very simple, 2-thread architecture, that we are
▶ The name “2-thread architecture” refers to the API, and is not
▶ A thread is implemented as a procedure that takes a single
▶ The thread performs some simple, atomic operation, after
▶ The thread variable t is always used as a parameter
▶ Each procedure & continuation takes a thread as an additional
Mayer Goldberg \ Ben-Gurion University Compiler Construction 16 / 87
▶ Racing & termination ▶ Detecting circularity ▶ Prioritization ▶ Threads & Types in Ocaml Mayer Goldberg \ Ben-Gurion University Compiler Construction 17 / 87
▶ The code is just the instrumented code ▶ It does not come with any code to invoke it ▶ Later, after we are profjcient in converting Scheme source code
Mayer Goldberg \ Ben-Gurion University Compiler Construction 18 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 19 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 20 / 87
▶ As before, we convert the code to CPS ▶ We choose, arbitrarily, to start with the application (g x)
Mayer Goldberg \ Ben-Gurion University Compiler Construction 21 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 22 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 23 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 24 / 87
▶ Starting with the program in direct style, we convert it to CPS ▶ We then instrument the CPS version to run as a thread ▶ After all the procedures have been converted to threads, we
Mayer Goldberg \ Ben-Gurion University Compiler Construction 25 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 26 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 27 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 28 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 29 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 30 / 87
(define t$fib$ (lambda (n k t) (t (lambda (t) (if (< n 2) (t (lambda (t) (k n t))) (t (lambda (t) (t$fib$ (- n 1) (lambda (fib-1 t) (t (lambda (t) (t$fib$ (- n 2) (lambda (fib-2 t) (t (lambda (t) (k (+ fib-1 fib-2) t)))) t)))) t))))))))
Mayer Goldberg \ Ben-Gurion University Compiler Construction 31 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 32 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 33 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 34 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 35 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 36 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 37 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 38 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 39 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 40 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 41 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 42 / 87
▶ If we wish to map procedures in CPS over a list, we need
▶ Good for general programming in CPS
▶ If we wish to create a safe version of map, one that generates an
Mayer Goldberg \ Ben-Gurion University Compiler Construction 43 / 87
▶ Detecting circularity ▶ Prioritization ▶ Threads & Types in Ocaml Mayer Goldberg \ Ben-Gurion University Compiler Construction 44 / 87
▶ We know that our naïve, recursive defjnition of the Fibonacci
▶ We also know that the computational complexity of Ackermann’s
▶ We wish to write a function that takes 3 natural numbers a, b,
▶ One obvious stipulation is that our function should fail only
▶ This problem is a race to the fjnish. We are not concerned by
Mayer Goldberg \ Ben-Gurion University Compiler Construction 45 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 46 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 47 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 48 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 49 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 50 / 87
▶ For Ackermann: (lambda (x t) `((ack ,a ,b) ==> ,x)) ▶ For Fibonacci: (lambda (x t) `((fib ,c) ==> ,x)) ▶ Notice how each initial continuation ignores the tread it
▶ The thread received by the initial continuation for Ackermann
▶ The thread received by the initial continuation for Fibonacci
Mayer Goldberg \ Ben-Gurion University Compiler Construction 51 / 87
▶ Prioritization ▶ Threads & Types in Ocaml Mayer Goldberg \ Ben-Gurion University Compiler Construction 52 / 87
▶ For circular structures, e.g., #0=(moshe . #0#), length enters
▶ In Chez Scheme, length detects circularity in such situations,
▶ This means that the implementation of length is not the naïve
Mayer Goldberg \ Ben-Gurion University Compiler Construction 53 / 87
▶ In principle, we can have all procedures in Scheme that compute
Mayer Goldberg \ Ben-Gurion University Compiler Construction 54 / 87
▶ The classical algorithm for detecting circularity is known as the
▶ A slow pointer (tortoise) that proceeds one cdr down the list
▶ A fast pointer (hare) that proceeds two cdr-s down the list at
▶ If the pointers are ever equal again then the list is circular
Mayer Goldberg \ Ben-Gurion University Compiler Construction 55 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 56 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 57 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 58 / 87
▶ We are not interested in the return value ▶ We could have skipped the else-clause in run altogether, but
▶ The behavior of die-if-circular is a bit difgerent than of
Mayer Goldberg \ Ben-Gurion University Compiler Construction 59 / 87
▶ Currently, we return the void object ▶ In a multi-threaded context, we would just want to continue
▶ Our architecture is committed to running two threads ▶ Welcome to the do-nothing thread:
▶ Running t$do-nothing concurrently with another thread, just
Mayer Goldberg \ Ben-Gurion University Compiler Construction 60 / 87
▶ If this change makes you uncomfortable or insecure, then just
Mayer Goldberg \ Ben-Gurion University Compiler Construction 61 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 62 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 63 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 64 / 87
▶ It is straightforward to combine t$die-if-circular with other
Mayer Goldberg \ Ben-Gurion University Compiler Construction 65 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 66 / 87
▶ Threads & Types in Ocaml Mayer Goldberg \ Ben-Gurion University Compiler Construction 67 / 87
▶ If we think of access to the CPU as a resource, then
▶ Important or urgent tasks are assigned higher priority, and this
▶ Ideally, the priority of a task is something users should be able to
▶ with high resolution ▶ during run-time
▶ Our 2-thread architecture is not as fmexible
▶ We can lower the priority of a task by adding more indirections
Mayer Goldberg \ Ben-Gurion University Compiler Construction 68 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 69 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 70 / 87
▶ The double-dispatch involved in lowering the priority of a task is
▶ De-facto, most lists in Scheme are non-circular
▶ It might be more performant to detect circularity with an
Mayer Goldberg \ Ben-Gurion University Compiler Construction 71 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 72 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 73 / 87
▶ It is straightforward to encode t$fact$, t$fib$, and other
▶ Threads are applied to each other ▶ This means that the type of a thread must be a subtype of of
▶ The self-applicator cannot be typed directly in ocaml: ▶ (lambda (x) (x x) : τ → σ, therefore ▶ x : τ, and ▶ (x x) : σ, from which we get that x has type ▶ x : τ → σ, ▶ Attempting to unify x : τ and x : τ → σ gives us an infjnite
▶ We can encode such a type using either recursive types or
Mayer Goldberg \ Ben-Gurion University Compiler Construction 74 / 87
▶ The Hindley-Milner type system used in ocaml does not support
▶ Ergo, (fun x -> x x) does not have a type in ocaml:
Mayer Goldberg \ Ben-Gurion University Compiler Construction 75 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 76 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 77 / 87
▶ If we were to name 'a circular' as 'b, we would get the type
Mayer Goldberg \ Ben-Gurion University Compiler Construction 78 / 87
▶ Even though the ocaml type system does not permit general
Mayer Goldberg \ Ben-Gurion University Compiler Construction 79 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 80 / 87
let rec t_fib n k (Thr t) = t (Thr (fun (Thr t) -> if n < 2 then t (Thr (fun (Thr t) -> k n (Thr t))) else t (Thr (fun (Thr t) -> t_fib (n - 1) (fun r1 (Thr t) -> t (Thr (fun (Thr t) -> t_fib (n - 2) (fun r2 (Thr t) -> t (Thr (fun (Thr t) -> k (r1 + r2) (Thr t)) )) (Thr t)))) (Thr t)))));;
Mayer Goldberg \ Ben-Gurion University Compiler Construction 81 / 87
let rec t_ack a b k (Thr t) = t (Thr (fun (Thr t) -> if a = 0 then t (Thr (fun (Thr t) -> k (b + 1) (Thr t))) else t (Thr (fun (Thr t) -> if b = 0 then t (Thr (fun (Thr t) -> t_ack (a - 1) 1 k (Thr t))) else t (Thr (fun (Thr t) -> t_ack a (b - 1) (fun r (Thr t) -> t (Thr (fun (Thr t) -> t_ack (a - 1) r k (Thr t) ))) (Thr t)))))));;
Mayer Goldberg \ Ben-Gurion University Compiler Construction 82 / 87
let ack_vs_fib a b c = let thread_ack = Thr(fun (Thr t) -> t_ack a b (fun x (Thr t) -> Printf.sprintf "ack %d %d = %d" a b x) (Thr t)) in let thread_fib = Thr(fun (Thr t) -> t_fib c (fun x (Thr t) -> Printf.sprintf "fib %d = %d" b x) (Thr t)) in (fun (Thr t) -> t thread_fib)(thread_ack);;
Mayer Goldberg \ Ben-Gurion University Compiler Construction 83 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 84 / 87
▶ CPS can be used to slice computation into small, sequential
▶ The code can be instrumented for task switching, by taking a
▶ Uninstrumented code forms a critical section: An area of code
▶ Double-dispatching or gratuitous task-switching is used to
Mayer Goldberg \ Ben-Gurion University Compiler Construction 85 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 86 / 87
Mayer Goldberg \ Ben-Gurion University Compiler Construction 87 / 87