Jeremy Siek 6 years ago
parent
commit
3aa14fd227
1 changed files with 53 additions and 54 deletions
  1. 53 54
      book.tex

+ 53 - 54
book.tex

@@ -4075,12 +4075,15 @@ and test your compiler using your previously created programs on the
 
 
 \section{Patch Instructions}
 \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
 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
 \begin{exercise}\normalfont
 Update \code{patch-instructions} to handle the new x86 instructions.
 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
 In this chapter we study the implementation of mutable tuples (called
 ``vectors'' in Racket). This language feature is the first to use the
 ``vectors'' in Racket). This language feature is the first to use the
 computer's \emph{heap} because the lifetime of a Racket tuple is
 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
 Section~\ref{sec:r3} introduces the $R_3$ language including its
 interpreter and type checker. The $R_3$ language extends the $R_2$
 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
 heap. The garbage collector requires coordination with the compiler so
 that it can see all of the \emph{root} pointers, that is, pointers in
 that it can see all of the \emph{root} pointers, that is, pointers in
 registers or on the procedure call stack.
 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{figure}[tbp]
 \begin{lstlisting}
 \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}
 \end{lstlisting}
 \caption{Example program that creates tuples and reads from them.}
 \caption{Example program that creates tuples and reads from them.}
 \label{fig:vector-eg}
 \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
 the mutation through \code{t2} is visible when referencing the tuple
 from \code{t1}, so the result of this program is \code{42}.
 from \code{t1}, so the result of this program is \code{42}.
 \begin{lstlisting}
 \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}
 \end{lstlisting}
 
 
 The next issue concerns the lifetime of tuples. Of course, they are
 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}
 following program returns \code{3} even though the variable \code{t}
 goes out of scope prior to accessing the vector.
 goes out of scope prior to accessing the vector.
 \begin{lstlisting}
 \begin{lstlisting}
-(vector-ref
-  (let ([t (vector 3 7)])
-    t)
-  0)
+    (vector-ref
+      (let ([t (vector 3 7)])
+        t)
+      0)
 \end{lstlisting}
 \end{lstlisting}
 From the perspective of programmer-observable behavior, tuples live
 From the perspective of programmer-observable behavior, tuples live
 forever. Of course, if they really lived forever, then many programs
 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
 into the heap, that is, which variables are vectors. Also, when
 allocating a vector, we shall need to know which elements of the
 allocating a vector, we shall need to know which elements of the
 vector are pointers. We can obtain this information during type
 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
 Figure~\ref{fig:typecheck-R3} not only computes the type of an
 expression, it also wraps every sub-expression $e$ with the form
 expression, it also wraps every sub-expression $e$ with the form
 $(\key{has-type}\; e\; T)$, where $T$ is $e$'s type. Subsequently, in
 $(\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{figure}[tbp]
 \begin{lstlisting}
 \begin{lstlisting}
@@ -4512,7 +4521,6 @@ flattening).
 \label{fig:interp-R3}
 \label{fig:interp-R3}
 \end{figure}
 \end{figure}
 
 
-
 \begin{figure}[tbp]
 \begin{figure}[tbp]
 \begin{lstlisting}
 \begin{lstlisting}
 (define (type-check-exp env)
 (define (type-check-exp env)
@@ -4521,39 +4529,30 @@ flattening).
     (match e
     (match e
       ...
       ...
       ['(void) (values '(has-type (void) Void) 'Void)]
       ['(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*)])
        (let ([t `(Vector ,@t*)])
+         (debug "vector/type-check-exp finished vector" t)
          (values `(has-type (vector ,@e*) ,t) 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
        (match t
          [`(Vector ,ts ...)
          [`(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)])
           (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))]
                     t))]
          [else (error "expected a vector in vector-ref, not" 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)
        (match* (t1 t2)
          [(`(Vector ,ts1 ...) `(Vector ,ts2 ...))
          [(`(Vector ,ts1 ...) `(Vector ,ts2 ...))
           (values `(has-type (eq? ,e1 ,e2) Boolean) 'Boolean)]
           (values `(has-type (eq? ,e1 ,e2) Boolean) 'Boolean)]
          [(other wise) ((super type-check-exp env) e)])]
          [(other wise) ((super type-check-exp env) e)])]
+      ...
       )))
       )))
 \end{lstlisting}
 \end{lstlisting}
 \caption{Type checker for the $R_3$ language.}
 \caption{Type checker for the $R_3$ language.}