Skip to content

Commit c884784

Browse files
committed
Add new AST for shakedown
1 parent 49a1d1f commit c884784

File tree

2 files changed

+293
-3
lines changed

2 files changed

+293
-3
lines changed

www/notes/shakedown.scrbl

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,121 @@ have to solve:
109109

110110

111111
@itemlist[
112+
@item{How do we represent this in our AST?}
112113
@item{How does our runtime system know where @tt{function_in_c} is?}
113114
@item{How do we `tell' @tt{function_in_c} that the argument is 3?}
114115
@item{How do we `get' the result from @tt{function_in_c}?}
115116
]
116117

117-
The first of these issues has to do with how we @emph{link} our program. In
118-
order to safely call (or jump to) @tt{function_is_c} we have to convince our
119-
assembler (NASM) and our linker that we know where @tt{function_in_c} is!
118+
@subsection[#:tag-prefix "shakedown"]{Representation Matters}
119+
120+
In addressing the first issue, we can create a new AST node for FFI calls:
121+
122+
@#reader scribble/comment-reader
123+
(racketblock
124+
(struct ccall-e (f es))
125+
)
126+
127+
There are other possible representations (treating it as a primitive, for
128+
example), but this representation will make the next step slightly easier.
129+
130+
@subsection[#:tag-prefix "shakedown"]{Who you gonna call?}
131+
132+
The second issue is a bit more intricate. It deals with how we @emph{link} our
133+
program. In order to safely call (or jump to) @tt{function_is_c} we have to
134+
convince our assembler (NASM) and our linker that we know where
135+
@tt{function_in_c} is!
136+
137+
Our assembler, @tt{nasm}, requires that we declare which symbols are not
138+
defined locally. This is so that the assembler can catch simple errors, like
139+
misspelling the target of a jump. Not all assemblers require this, but because
140+
@tt{nasm} does, we need to address accommodate it.
141+
142+
First we can collect all the uses of the @tt{ccall} construct that we are
143+
introducing. This is a straightforward traversal of the AST, keeping track of
144+
the symbols used for a @tt{ccall}.
145+
146+
@#reader scribble/comment-reader
147+
(racketblock
148+
;; LExpr -> (Listof Symbol)
149+
;; Extract all the calls to C Functions
150+
(define (ffi-calls e)
151+
(match e
152+
[(? imm? i) '()]
153+
[(var-e v) '()]
154+
[(prim-e p es) (apply append (map ffi-calls es))]
155+
[(if-e e0 e1 e2) (append (ffi-calls e0) (ffi-calls e1) (ffi-calls e2))]
156+
[(let-e (list (binding v def)) body)
157+
(append (ffi-calls def) (ffi-calls body))]
158+
[(letr-e bs body) (append (apply append (map ffi-calls (get-defs bs))) (ffi-calls body))]
159+
[(lam-e xs e0) (ffi-calls e0)]
160+
[(lam-t _ xs e0) (ffi-calls e0)]
161+
[(ccall-e f es) (cons f (apply append (map ffi-calls es)))]
162+
[(app-e f es) (append (ffi-calls f) (apply append (map ffi-calls es)))]))
163+
)
164+
165+
Once we've collected all the uses of @tt{ccall} we can adapt our
166+
@tt{compile-entry} function so that all of the external symbols are generated
167+
in our assembly file:
168+
169+
@#reader scribble/comment-reader
170+
(racketblock
171+
;; Expr -> Asm
172+
(define (compile-entry e)
173+
`(,@(make-externs (ffi-calls e))
174+
(section text)
175+
entry
176+
,@(compile-tail-e e '())
177+
ret
178+
,@(compile-λ-definitions (λs e))
179+
err
180+
(push rbp)
181+
(call error)
182+
ret))
183+
)
184+
185+
The addition of the @tt{(section text)} directive is something we were doing in
186+
our printer before, as part of the preamble for our generated code. Now that we
187+
are adding the @tt{extern} directives we need make the distinction between the
188+
preamble and the code itself (text stands for code in ASM).
189+
190+
The next two points are related by a single concept: Calling Conventions
191+
192+
193+
@section[#:tag-prefix "shakedown"]{Calling Conventions}
194+
195+
How functions accept their arguments and provide their results is known as a
196+
@emph{calling convention}. All of our languages since @secref["Iniquity"] have
197+
had calling conventions, but it's been mostly up to us (modulo the issue with
198+
moving @tt{rsp}. This has worked @emph{because} we haven't had to communicate
199+
with any other language, that expects its arguments to be provided in a
200+
specific manner.
201+
202+
The calling convention we are using the
203+
@link["https://uclibc.org/docs/psABI-x86_64.pdf"]{x86_64 System V Application
204+
Binary Interface (ABI)} (which means this may not work on Windows systems). The
205+
document is quite long (approximately 130 pages), so we will only focus on some
206+
of the basics. For every limitation that our implementation, the details on how
207+
we might address that limitation will be in that document. For example, we will
208+
only deal with integer arguments and results here, but the System V ABI also
209+
describes the convention for Floating Point arguments/results.
210+
211+
In short, a calling convention specifies @emph{at least} the following:
212+
213+
@itemlist[
214+
@item{How do you pass arguments?}
215+
@item{What things is the @emph{caller} responsible for keeping track of?}
216+
@item{What things is the @emph{callee} responsible for keeping track of?}
217+
]
218+
219+
220+
221+
222+
@subsection[#:tag-prefix "shakedown"]{Determining the point of the argument}
223+
224+
We can now discuss
225+
226+
@subsection[#:tag-prefix "shakedown"]{Securing the result}
120227

121228
@codeblock-include["shakedown/compile.rkt"]
122229

www/notes/shakedown/ast.rkt

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
#lang racket
2+
(provide (all-defined-out))
3+
4+
;; type Prog = [FunDef] Expr
5+
6+
;; type FunDef = Variable [Variable] Expr
7+
8+
;; type Expr =
9+
;; | Integer
10+
;; | Boolean
11+
;; | Character
12+
;; | Variable
13+
;; | Prim1 Expr
14+
;; | Prim2 Expr Expr
15+
;; | Lam Name [Variable] Expr <--- New for Loot
16+
;; | App Expr [Expr] <--- Changed for Loot
17+
;; | If Expr Expr Expr
18+
;; | Let (Binding list) Expr
19+
;; | LetRec (Binding list) Expr <--- New for Loot (See the lecture notes!)
20+
;; | Nil
21+
22+
;; Note: Fun and Call, from Knock, are gone!
23+
;; They have been made redundant by the combination
24+
;; of Lam (which is new) and App (which has been modified)
25+
26+
;; type Prim1 = 'add1 | 'sub1 | 'zero? | box | unbox | car | cdr
27+
;; type Prim2 = '+ | '- | cons
28+
29+
;; type Binding = Variable Expr
30+
31+
;; type Variable = Symbol (except 'add1 'sub1 'if, etc.)
32+
33+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34+
;;;;;; The represenation of top-level programs
35+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
36+
37+
(struct prog (ds e) #:transparent)
38+
39+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
40+
;;;;;; The represenation of a function definition
41+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
42+
43+
;; A FunDef has a symbol for the function's name,
44+
;; a list of symbols representing the names of the function's
45+
;; arguments, and one expression that forms the body of the function.
46+
(struct fundef (name args body) #:transparent)
47+
48+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
49+
;;;;;; The Expr data structure
50+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
51+
52+
;; An Expr can be viewed as having 'kinds' of nodes.
53+
;;
54+
;; * The nodes that represnt an expression themselves
55+
;;
56+
;; * The nodes that are part of an expression, but no an expression themselves
57+
58+
;; The below are the former:
59+
60+
(struct int-e (i) #:transparent)
61+
(struct bool-e (b) #:transparent)
62+
(struct char-e (c) #:transparent)
63+
(struct var-e (v) #:transparent)
64+
(struct prim-e (p es) #:transparent)
65+
(struct lam-e (vs es) #:transparent)
66+
(struct lam-t (n vs es) #:transparent)
67+
(struct app-e (f es) #:transparent)
68+
(struct ccall-e (f es) #:transparent) ; <- new for Shakedown
69+
(struct if-e (e t f) #:transparent)
70+
(struct let-e (bs b) #:transparent)
71+
(struct letr-e (bs b) #:transparent)
72+
(struct nil-e () #:transparent)
73+
74+
;; The next is the latter:
75+
76+
;; A binding holds a symbol representing the bound variable and
77+
;; Expr that represents the value that will be bound to that variable
78+
(struct binding (v e) #:transparent)
79+
80+
81+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
82+
;;;;;; AST nodes for closures (used for pedagogical purposes)
83+
;;;;;; (see interp-defun.rkt)
84+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
85+
86+
(struct closure (fs e env) #:transparent)
87+
(struct rec-closure (lam fenv) #:transparent)
88+
89+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
90+
;;;;;; AST utility functions (predicates)
91+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
92+
93+
(define unops '(add1 sub1 zero? box unbox empty? car cdr))
94+
(define biops '(+ - cons))
95+
96+
;; Any -> Boolean
97+
(define (prim? x)
98+
(and (symbol? x)
99+
(memq x (append unops biops))))
100+
101+
;; Any -> Boolean
102+
(define (biop? x)
103+
(and (symbol? x)
104+
(memq x biops)))
105+
106+
;; Any -> Boolean
107+
(define (unop? x)
108+
(and (symbol? x)
109+
(memq x unops)))
110+
111+
(define (value? v)
112+
(or (int-e? v)
113+
(bool-e? v)))
114+
115+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
116+
;;;;;; AST utility functions (getters)
117+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
118+
119+
;; It will sometimes be useful to get the list of all the variables that are
120+
;; introduced by a `let`
121+
;; [Binding] -> [Symbol]
122+
(define (get-vars bs)
123+
(match bs
124+
['() '()]
125+
[(cons (binding v _) bs) (cons v (get-vars bs))]))
126+
127+
;; Get all of the _definitions_ from a list of bindings
128+
;; [Binding] -> [Expr]
129+
(define (get-defs bs)
130+
(match bs
131+
['() '()]
132+
[(cons (binding _ def) bs) (cons def (get-defs bs))]))
133+
134+
135+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
136+
;;;;;; AST utility functions (maps)
137+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
138+
139+
(define (bindings-map-def f bs)
140+
(match bs
141+
['() '()]
142+
[(cons (binding n def) bs)
143+
(cons (binding n (f def)) (bindings-map-def f bs))]))
144+
145+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
146+
;;;;;; AST utility functions (printers)
147+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
148+
149+
;; We have switched to using `#:transparent` above, so this should only be
150+
;; necessary if you're desperate when debugging :'(
151+
152+
;; Given a Program, construct an sexpr that has the same shape
153+
(define (prog-debug p)
154+
(match p
155+
[(prog ds e) `(prog ,(map fundef-debug ds) ,(ast-debug e))]))
156+
157+
;; Given a FunDef, construct an sexpr that has the same shape
158+
(define (fundef-debug def)
159+
(match def
160+
[(fundef name args body) `(fundef ,name ,args ,(ast-debug body))]))
161+
162+
;; Given an AST, construct an sexpr that has the same shape
163+
(define (ast-debug a)
164+
(match a
165+
[(int-e i) `(int-e ,i)]
166+
[(bool-e b) `(bool-e ,b)]
167+
[(char-e c) `(char-e ,c)]
168+
[(var-e v) `(var-e ,v)]
169+
[(nil-e) ''()]
170+
[(prim-e p es) `(prim-e ,p ,@(map ast-debug es))]
171+
[(lam-t n vs e)`(lam-t ,n ,vs ,(ast-debug e))]
172+
[(lam-e vs e) `(lam-e ,vs ,(ast-debug e))]
173+
[(app-e f es) `(app-e ,(ast-debug f) ,@(map ast-debug es))]
174+
[(if-e e t f) `(if-e ,(ast-debug e)
175+
,(ast-debug t)
176+
,(ast-debug f))]
177+
[(let-e bs b) `(let-e ,(binding-debug bs) ,(ast-debug b))]
178+
[(letr-e bs b) `(letr-e ,(binding-debug bs) ,(ast-debug b))]))
179+
180+
(define (binding-debug bnds)
181+
(match bnds
182+
['() '()]
183+
[(cons (binding v e) bnds) `((,v ,(ast-debug e)) ,@(binding-debug bnds))]))

0 commit comments

Comments
 (0)