Skip to content

Commit 6aab75a

Browse files
committed
Knock.
1 parent 874bdb0 commit 6aab75a

3 files changed

Lines changed: 91 additions & 3 deletions

File tree

www/notes.scrbl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
@include-section{notes/hustle.scrbl}
1717
@include-section{notes/iniquity.scrbl}
1818
@include-section{notes/jig.scrbl}
19+
@include-section{notes/knock.scrbl}
1920
@;{
2021
@include-section{notes/5.scrbl}
2122
@include-section{notes/6.scrbl}

www/notes/knock.scrbl

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,89 @@ a function value.
5656
We will end up eliminating them in future versions of the compiler;
5757
they are simply a crutch for now.
5858

59-
6059
@section[#:tag-prefix "knock"]{A Compiler with Function pointers}
6160

61+
The main idea in making functions into values is we will need to have
62+
a representation of functions. We will use a representation similar
63+
to boxes: functions will be heap allocated data structures. What will
64+
be stored in the heap? The address of the label of the function.
65+
66+
A function reference, @racket[(fun _f)], will allocate a 64-bit
67+
segment of the heap, store the location of the function's label,
68+
i.e. a pointer to the instructions for the function, and tag the
69+
pointer as a ``procedure value,'' which is new, disjoint kind of
70+
value.
71+
72+
@#reader scribble/comment-reader
73+
(racketblock
74+
;; Variable -> Asm
75+
(define (compile-fun f)
76+
`(; rax <- address of label f
77+
(lea rax (offset ,(symbol->label f) 0))
78+
; write in to heap
79+
(mov (offset rdi 0) rax)
80+
; rax <- pointer into heap
81+
(mov rax rdi)
82+
; tag as procedure pointer
83+
(or rax ,type-proc)
84+
; alloc
85+
(add rdi 8)))
86+
)
87+
88+
A function call, @racket[(call _e0 _es ...)] will evaluate on the
89+
subexpressions. The @racket[_e0] expression should produce a
90+
function, i.e. tagged pointer. We can erase the tag to compute the
91+
address in the heap. Dereferencing that location, gets us the label
92+
address, which can then jump to.
93+
94+
@#reader scribble/comment-reader
95+
(racketblock
96+
;; Expr (Listof Expr) CEnv -> Asm
97+
(define (compile-fun-call e0 es c)
98+
(let ((cs (compile-es es (cons #f c)))
99+
(c0 (compile-e e0 c))
100+
(i (- (add1 (length c))))
101+
(stack-size (* 8 (length c))))
102+
`(,@c0
103+
; save f in stack
104+
(mov (offset rsp ,i) rax)
105+
,@cs
106+
; restore f
107+
(mov rax (offset rsp ,i))
108+
,@assert-proc
109+
(sub rsp ,stack-size)
110+
(xor rax ,type-proc)
111+
; call f
112+
(call (offset rax 0))
113+
(add rsp ,stack-size))))
114+
)
115+
116+
A tail call version of the above can be defined as:
117+
118+
@#reader scribble/comment-reader
119+
(racketblock
120+
;; Expr (Listof Expr) CEnv -> Asm
121+
(define (compile-fun-tail-call e0 es c)
122+
(let ((cs (compile-es es (cons #f c)))
123+
(c0 (compile-e e0 c))
124+
(i (- (add1 (length c)))))
125+
`(,@c0
126+
(mov (offset rsp ,i) rax)
127+
,@cs
128+
(mov rax (offset rsp ,i))
129+
,@(move-args (length es) i)
130+
,@assert-proc
131+
(xor rax ,type-proc)
132+
(jmp (offset rax 0)))))
133+
)
134+
135+
The complete compiler:
136+
62137
@codeblock-include["knock/compile.rkt"]
63138

139+
We can verify that the compiler works for programs that use functions
140+
like before:
141+
64142
@ex[
65143
(asm-interp
66144
(compile '(begin (define (f x)
@@ -70,10 +148,19 @@ they are simply a crutch for now.
70148
(call (fun f) 10))))
71149
]
72150

151+
But it also works when functions are put in lists:
152+
153+
@ex[
154+
(asm-interp
155+
(compile '(begin (define (f x) x)
156+
(call (car (cons (fun f) '())) 7))))
157+
]
158+
159+
And functions that produce functions:
160+
73161
@ex[
74162
(asm-interp
75163
(compile '(begin (define (f x) (fun h))
76164
(define (h y) y)
77165
(call (call (fun f) 5) 9))))
78-
79166
]

www/notes/knock/compile.rkt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
(define type-box #b001)
1111
(define type-pair #b010)
1212
(define type-string #b011)
13-
(define type-proc #b100) ;; <-- NEW: procedure value: points to function label in memory
13+
(define type-proc #b100) ;; <-- NEW: procedure value
1414

1515
(define imm-shift (+ 2 result-shift))
1616
(define imm-type-mask (sub1 (arithmetic-shift 1 imm-shift)))

0 commit comments

Comments
 (0)