|
@@ -4075,12 +4075,15 @@ and test your compiler using your previously created programs on the
|
|
|
|
|
|
\section{Patch Instructions}
|
|
|
|
|
|
+The second argument of the \key{cmpq} instruction must not be an
|
|
|
+immediate value (such as a literal integer). So if you are comparing
|
|
|
+two immediates, we recommend inserting a \key{movq} instruction to put
|
|
|
+the second argument in \key{rax}.
|
|
|
+%
|
|
|
+The second argument of the \key{movzbq} must be a register.
|
|
|
+%
|
|
|
There are no special restrictions on the x86 instructions
|
|
|
-\key{jmp-if}, \key{jmp}, and \key{label}, but there is an unusual
|
|
|
-restriction on \key{cmpq}. The second argument is not allowed to be an
|
|
|
-immediate value (such as a literal integer). If you are comparing two
|
|
|
-immediates, you must insert another \key{movq} instruction to put the
|
|
|
-second argument in \key{rax}.
|
|
|
+\key{jmp-if}, \key{jmp}, and \key{label}.
|
|
|
|
|
|
\begin{exercise}\normalfont
|
|
|
Update \code{patch-instructions} to handle the new x86 instructions.
|
|
@@ -4363,18 +4366,24 @@ UNDER CONSTRUCTION
|
|
|
In this chapter we study the implementation of mutable tuples (called
|
|
|
``vectors'' in Racket). This language feature is the first to use the
|
|
|
computer's \emph{heap} because the lifetime of a Racket tuple is
|
|
|
-indefinite, that is, a tuple does not follow a stack (FIFO) discipline
|
|
|
-but instead lives forever from the programmer's viewpoint. Of course,
|
|
|
-from an implementor's viewpoint, it is important to reclaim the space
|
|
|
-associated with tuples when they are no longer needed, which is why we
|
|
|
-also study \emph{garbage collection} techniques in this chapter.
|
|
|
+indefinite, that is, a tuple lives forever from the programmer's
|
|
|
+viewpoint. Of course, from an implementor's viewpoint, it is important
|
|
|
+to reclaim the space associated with a tuple when it is no longer
|
|
|
+needed, which is why we also study \emph{garbage collection}
|
|
|
+techniques in this chapter.
|
|
|
|
|
|
Section~\ref{sec:r3} introduces the $R_3$ language including its
|
|
|
interpreter and type checker. The $R_3$ language extends the $R_2$
|
|
|
-language of Chapter~\ref{ch:bool-types} with vectors and void values
|
|
|
-(because the \code{vector-set!} operation returns a void
|
|
|
-value). Section~\ref{sec:GC} describes a garbage collection algorithm
|
|
|
-based on copying live objects back and forth between two halves of the
|
|
|
+language of Chapter~\ref{ch:bool-types} with vectors and Racket's
|
|
|
+``void'' value. The reason for including the later is that the
|
|
|
+\code{vector-set!} operation returns a value of type
|
|
|
+\code{Void}\footnote{This may sound contradictory, but Racket's
|
|
|
+ \code{Void} type corresponds to what is more commonly called the
|
|
|
+ \code{Unit} type. This type is inhabited by a single value that is
|
|
|
+ usually written \code{unit} or \code{()}\citep{Pierce:2002hj}.}.
|
|
|
+
|
|
|
+Section~\ref{sec:GC} describes a garbage collection algorithm based on
|
|
|
+copying live objects back and forth between two halves of the
|
|
|
heap. The garbage collector requires coordination with the compiler so
|
|
|
that it can see all of the \emph{root} pointers, that is, pointers in
|
|
|
registers or on the procedure call stack.
|
|
@@ -4399,11 +4408,11 @@ $40$, to which we add the $2$, the element at index $0$ of the
|
|
|
|
|
|
\begin{figure}[tbp]
|
|
|
\begin{lstlisting}
|
|
|
- (let ([t (vector 40 #t (vector 2))])
|
|
|
- (if (vector-ref t 1)
|
|
|
- (+ (vector-ref t 0)
|
|
|
- (vector-ref (vector-ref t 2) 0))
|
|
|
- 44))
|
|
|
+ (let ([t (vector 40 #t (vector 2))])
|
|
|
+ (if (vector-ref t 1)
|
|
|
+ (+ (vector-ref t 0)
|
|
|
+ (vector-ref (vector-ref t 2) 0))
|
|
|
+ 44))
|
|
|
\end{lstlisting}
|
|
|
\caption{Example program that creates tuples and reads from them.}
|
|
|
\label{fig:vector-eg}
|
|
@@ -4446,10 +4455,10 @@ in which both \code{t1} and \code{t2} refer to the same tuple. Thus,
|
|
|
the mutation through \code{t2} is visible when referencing the tuple
|
|
|
from \code{t1}, so the result of this program is \code{42}.
|
|
|
\begin{lstlisting}
|
|
|
-(let ([t1 (vector 3 7)])
|
|
|
- (let ([t2 t1])
|
|
|
- (let ([_ (vector-set! t2 0 42)])
|
|
|
- (vector-ref t1 0))))
|
|
|
+ (let ([t1 (vector 3 7)])
|
|
|
+ (let ([t2 t1])
|
|
|
+ (let ([_ (vector-set! t2 0 42)])
|
|
|
+ (vector-ref t1 0))))
|
|
|
\end{lstlisting}
|
|
|
|
|
|
The next issue concerns the lifetime of tuples. Of course, they are
|
|
@@ -4460,10 +4469,10 @@ is not tied to any notion of static scoping. For example, the
|
|
|
following program returns \code{3} even though the variable \code{t}
|
|
|
goes out of scope prior to accessing the vector.
|
|
|
\begin{lstlisting}
|
|
|
-(vector-ref
|
|
|
- (let ([t (vector 3 7)])
|
|
|
- t)
|
|
|
- 0)
|
|
|
+ (vector-ref
|
|
|
+ (let ([t (vector 3 7)])
|
|
|
+ t)
|
|
|
+ 0)
|
|
|
\end{lstlisting}
|
|
|
From the perspective of programmer-observable behavior, tuples live
|
|
|
forever. Of course, if they really lived forever, then many programs
|
|
@@ -4481,13 +4490,13 @@ in Section~\ref{sec:GC}, we need to know which variables are pointers
|
|
|
into the heap, that is, which variables are vectors. Also, when
|
|
|
allocating a vector, we shall need to know which elements of the
|
|
|
vector are pointers. We can obtain this information during type
|
|
|
-checking and flattening. The type checker in
|
|
|
+checking and when we uncover local variables. The type checker in
|
|
|
Figure~\ref{fig:typecheck-R3} not only computes the type of an
|
|
|
expression, it also wraps every sub-expression $e$ with the form
|
|
|
$(\key{has-type}\; e\; T)$, where $T$ is $e$'s type. Subsequently, in
|
|
|
-the flatten pass (Section~\ref{sec:flatten-gc}) this type information is
|
|
|
-propagated to all variables (including temporaries generated during
|
|
|
-flattening).
|
|
|
+the \code{uncover-locals} pass (Section~\ref{sec:uncover-locals-gc})
|
|
|
+this type information is propagated to all variables (including the
|
|
|
+temporaries generated by \code{remove-complex-opera*}).
|
|
|
|
|
|
\begin{figure}[tbp]
|
|
|
\begin{lstlisting}
|
|
@@ -4512,7 +4521,6 @@ flattening).
|
|
|
\label{fig:interp-R3}
|
|
|
\end{figure}
|
|
|
|
|
|
-
|
|
|
\begin{figure}[tbp]
|
|
|
\begin{lstlisting}
|
|
|
(define (type-check-exp env)
|
|
@@ -4521,39 +4529,30 @@ flattening).
|
|
|
(match e
|
|
|
...
|
|
|
['(void) (values '(has-type (void) Void) 'Void)]
|
|
|
- [`(vector ,(app recur e* t*) ...)
|
|
|
+ [`(vector ,es ...)
|
|
|
+ (define-values (e* t*) (for/lists (e* t*) ([e es])
|
|
|
+ (recur e)))
|
|
|
(let ([t `(Vector ,@t*)])
|
|
|
+ (debug "vector/type-check-exp finished vector" t)
|
|
|
(values `(has-type (vector ,@e*) ,t) t))]
|
|
|
- [`(vector-ref ,(app recur e t) ,i)
|
|
|
+ [`(vector-ref ,e ,i)
|
|
|
+ (define-values (e^ t) (recur e))
|
|
|
(match t
|
|
|
[`(Vector ,ts ...)
|
|
|
- (unless (and (exact-nonnegative-integer? i)
|
|
|
- (i . < . (length ts)))
|
|
|
- (error 'type-check-exp "invalid index ~a" i))
|
|
|
+ (unless (and (exact-nonnegative-integer? i) (< i (length ts)))
|
|
|
+ (error 'type-check-exp "invalid index ~a" i))
|
|
|
(let ([t (list-ref ts i)])
|
|
|
- (values `(has-type (vector-ref ,e (has-type ,i Integer)) ,t)
|
|
|
+ (values `(has-type (vector-ref ,e^ (has-type ,i Integer)) ,t)
|
|
|
t))]
|
|
|
[else (error "expected a vector in vector-ref, not" t)])]
|
|
|
- [`(vector-set! ,(app recur e-vec t-vec) ,i
|
|
|
- ,(app recur e-arg t-arg))
|
|
|
- (match t-vec
|
|
|
- [`(Vector ,ts ...)
|
|
|
- (unless (and (exact-nonnegative-integer? i)
|
|
|
- (i . < . (length ts)))
|
|
|
- (error 'type-check-exp "invalid index ~a" i))
|
|
|
- (unless (equal? (list-ref ts i) t-arg)
|
|
|
- (error 'type-check-exp "type mismatch in vector-set! ~a ~a"
|
|
|
- (list-ref ts i) t-arg))
|
|
|
- (values `(has-type (vector-set! ,e-vec
|
|
|
- (has-type ,i Integer)
|
|
|
- ,e-arg) Void) 'Void)]
|
|
|
- [else (error 'type-check-exp
|
|
|
- "expected a vector in vector-set!, not ~a" t-vec)])]
|
|
|
- [`(eq? ,(app recur e1 t1) ,(app recur e2 t2))
|
|
|
+ [`(eq? ,arg1 ,arg2)
|
|
|
+ (define-values (e1 t1) (recur arg1))
|
|
|
+ (define-values (e2 t2) (recur arg2))
|
|
|
(match* (t1 t2)
|
|
|
[(`(Vector ,ts1 ...) `(Vector ,ts2 ...))
|
|
|
(values `(has-type (eq? ,e1 ,e2) Boolean) 'Boolean)]
|
|
|
[(other wise) ((super type-check-exp env) e)])]
|
|
|
+ ...
|
|
|
)))
|
|
|
\end{lstlisting}
|
|
|
\caption{Type checker for the $R_3$ language.}
|