Skip to content

Commit 73b18dc

Browse files
committed
Add note on RTS and unload/free for values project.
1 parent d5d9eed commit 73b18dc

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

www/project.scrbl

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#lang scribble/manual
2+
@(require (for-label (except-in racket compile ...) a86))
23
@(require "defns.rkt")
34
@(require "notes/ev.rkt")
5+
@(require "fancyverb.rkt")
46

57
@title[#:style '(unnumbered)]{Project}
68

@@ -279,6 +281,127 @@ to use @racket['rax] for the common case of a single result.) The
279281
solution for this problem with function parameters was to use the
280282
stack and a similar approach can work for results too.
281283

284+
285+
@subsection{Returning multiple values to the run-time system or @racket[asm-interp]}
286+
287+
In implementing @racket[values], there are two design decisions you
288+
have to make:
289+
290+
@itemlist[#:style 'ordered
291+
@item{How are values going to be represented during the execution of a program?}
292+
@item{How are values going to be communicated back to the run-time system and/or asm-interp when the program completes?}
293+
]
294+
295+
The answers to (1) and (2) don't necessarily have to be the same.
296+
297+
Note that you can go a long way working on (1) without making any
298+
changes to the run-time system or @tt{unload-bits-asm.rkt} (which is
299+
how the result of @racket[asm-interp] is converted back to a Racket
300+
value). You can basically punt on (2) and work on (1) by writing
301+
tests that use multiple values within a computation, but ultimately
302+
return a single value, e.g. @racket[(let-values ([(x y) (values 1 2)]
303+
(cons x y)))].
304+
305+
As for (2), here is a suggestion that you are free to adopt, although
306+
you can implement (2) however you'd like so long as when running an
307+
executable that returns multiple values it prints the results in a way
308+
consistent with how Racket prints and that if using
309+
@racket[asm-interp], your version of @racket[unload/free] produces
310+
multiple values whenever the program does.
311+
312+
You can return a vector of results at the end of @racket[entry]. This
313+
means after the instructions for the program, whatever values are
314+
produced are converted from the internal representation of values
315+
(i.e., your design for (1)) to a vector and the address (untagged) is
316+
put into @tt{rax} to be returned to the run-time system and/or
317+
@racket[asm-interp].
318+
319+
Now both the run-time system and @tt{unload-bits-asm.rkt} need to be
320+
updated to deal with this change in representation for the result.
321+
322+
In @tt{main.c}, the part that gets the result and prints it:
323+
324+
@fancy-c[
325+
#<<HERE
326+
val_t result = entry(heap);
327+
print_result(result);
328+
if (val_typeof(result) != T_VOID)
329+
putchar('\n');
330+
HERE
331+
]
332+
333+
can be changed to getting the vector and printing each element:
334+
335+
@fancy-c[
336+
#<<HERE
337+
val_vect_t *result = entry(heap);
338+
for (int i = 0; i < result->len; ++i) {
339+
print_result(result->elems[i]);
340+
if (val_typeof(result->elems[i]) != T_VOID)
341+
putchar('\n');
342+
}
343+
HERE
344+
]
345+
346+
You'll also need to update the signature of @racket[entry] in
347+
@tt{runtime.h} to:
348+
349+
@fancy-c[" val_vect_t* entry();"]
350+
351+
You'll also need to make a similar change to @racket[unload/free] in
352+
@tt{unload-bits-asm.rkt}, which plays the role of the run-time system
353+
when writing tests that use @racket[asm-interp].
354+
355+
Instead of:
356+
357+
@#reader scribble/comment-reader
358+
(racketblock
359+
;; Answer* -> Answer
360+
(define (unload/free a)
361+
(match a
362+
['err 'err]
363+
[(cons h v) (begin0 (unload-value v)
364+
(free h))]))
365+
)
366+
367+
You'll want:
368+
369+
@#reader scribble/comment-reader
370+
(racketblock
371+
;; Answer* -> Answer
372+
(define (unload/free a)
373+
(match a
374+
['err 'err]
375+
[(cons h vs) (begin0 (unload-values vs)
376+
(free h))]))
377+
378+
(define (unload-values vs)
379+
(let ((vec (unload-value (bitwise-xor vs type-vect))))
380+
(apply values (vector->list vec))))
381+
)
382+
383+
384+
385+
Let's say you make these changes to the run-time system and
386+
@racket[unload/free] before you make any changes to the compiler and
387+
now you want to adapt the compiler to work with the new set up (before
388+
trying to do anything with @racket[values]). You can add the following
389+
at the end of @racket[entry], just before the @racket[(Ret)]:
390+
391+
@#reader scribble/comment-reader
392+
(racketblock
393+
;; Create and return unary vector holding the result
394+
(Mov r8 1)
395+
(Mov (Offset rbx 0) r8) ; write size of vector, 1
396+
(Mov (Offset rbx 8) rax) ; write rax as single element of vector
397+
(Mov rax rbx) ; return the pointer to the vector
398+
)
399+
400+
In order to return more values, you'd construct a larger vector.
401+
402+
403+
404+
282405
@section{Exceptions and exception handling}
283406

284407
Exceptions and exception handling mechanisms are widely used in modern

0 commit comments

Comments
 (0)