|
@@ -1236,7 +1236,7 @@ nonterminal has four alternatives, so the \code{match} has four
|
|
|
grammar rule. For example, the pattern \ADDP{\code{e1}}{\code{e2}}
|
|
|
corresponds to the right-hand side $\ADD{\Exp}{\Exp}$. When
|
|
|
translating from grammars to patterns, replace nonterminals such as
|
|
|
-$\Exp$ with pattern variables of your choice (e.g., \code{e1} and
|
|
|
+$\Exp$ with pattern variables of your choice (for example, \code{e1} and
|
|
|
\code{e2}).
|
|
|
|
|
|
|
|
@@ -3757,10 +3757,10 @@ recursively and then append the resulting instructions.
|
|
|
|
|
|
{\if\edition\pythonEd\pythonColor
|
|
|
We recommend that you use the function \code{utils.label\_name()} to
|
|
|
-transform a string into an label argument suitably suitable for, e.g.,
|
|
|
+transform strings into labels, for example, in
|
|
|
the target of the \code{callq} instruction. This practice makes your
|
|
|
-compiler portable across Linus and Mac OS X, which requires an underscore prefixed to
|
|
|
-all labels.
|
|
|
+compiler portable across Linus and Mac OS X, which requires an underscore
|
|
|
+prefixed to all labels.
|
|
|
\fi}
|
|
|
\begin{exercise}
|
|
|
\normalfont\normalsize
|
|
@@ -3973,7 +3973,7 @@ the rest of the program, as shown in figure~\ref{fig:p1-x86} and
|
|
|
discussed in section~\ref{sec:x86}.
|
|
|
|
|
|
When running on Mac OS X, your compiler should prefix an underscore to
|
|
|
-all labels (e.g., changing \key{main} to \key{\_main}).
|
|
|
+all labels (for example, changing \key{main} to \key{\_main}).
|
|
|
%
|
|
|
\racket{The Racket call \code{(system-type 'os)} is useful for
|
|
|
determining which operating system the compiler is running on. It
|
|
@@ -9359,8 +9359,8 @@ statements created by applying \code{create\_block} to the code
|
|
|
generated for the \code{thn} and \code{els} branches. Let us
|
|
|
illustrate this translation by returning to the program with an
|
|
|
\code{if} expression in tail position, shown next. We invoke
|
|
|
-\code{explicate\_pred} on its condition \racket{\code{(eq? x 0)}}
|
|
|
-\python{\code{x == 0}}.
|
|
|
+\code{explicate\_pred} on its condition
|
|
|
+\racket{\code{(eq? x 0)}}\python{\code{x == 0}}.
|
|
|
%
|
|
|
{\if\edition\racketEd
|
|
|
\begin{lstlisting}
|
|
@@ -10153,7 +10153,7 @@ conclusion:
|
|
|
\path[->,bend left=15] (Lif-2) edge [above] node {\ttfamily\footnotesize shrink} (Lif-3);
|
|
|
\path[->,bend left=15] (Lif-3) edge [above] node {\ttfamily\footnotesize uniquify} (Lif-4);
|
|
|
\path[->,bend left=15] (Lif-4) edge [above] node {\ttfamily\footnotesize remove\_complex\_operands} (Lif-5);
|
|
|
-\path[->,bend left=10] (Lif-5) edge [right] node {\ttfamily\footnotesize explicate\_control} (C1-1);
|
|
|
+\path[->,bend left=10] (Lif-5) edge [right] node {\ttfamily\footnotesize \ \ \ explicate\_control} (C1-1);
|
|
|
\path[->,bend right=15] (C1-1) edge [right] node {\ttfamily\footnotesize select\_instructions} (x86-2);
|
|
|
\path[->,bend left=15] (x86-2) edge [right] node {\ttfamily\footnotesize uncover\_live} (x86-2-1);
|
|
|
\path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize build\_interference} (x86-2-2);
|
|
@@ -10176,7 +10176,7 @@ conclusion:
|
|
|
|
|
|
\path[->,bend left=15] (Lif-1) edge [above] node {\ttfamily\footnotesize shrink} (Lif-2);
|
|
|
\path[->,bend left=15] (Lif-2) edge [above] node {\ttfamily\footnotesize remove\_complex\_operands} (Lif-3);
|
|
|
-\path[->,bend left=15] (Lif-3) edge [right] node {\ttfamily\footnotesize explicate\_control} (C-1);
|
|
|
+\path[->,bend left=15] (Lif-3) edge [right] node {\ttfamily\footnotesize \ \ explicate\_control} (C-1);
|
|
|
\path[->,bend right=15] (C-1) edge [right] node {\ttfamily\footnotesize select\_instructions} (x86-1);
|
|
|
\path[->,bend right=15] (x86-1) edge [below] node {\ttfamily\footnotesize assign\_homes} (x86-2);
|
|
|
\path[->,bend left=15] (x86-2) edge [above] node {\ttfamily\footnotesize patch\_instructions} (x86-3);
|
|
@@ -10204,7 +10204,7 @@ control-flow of the program.
|
|
|
The algorithm for \code{explicate\_control} that we discussed in
|
|
|
section~\ref{sec:explicate-control-Lif} sometimes generates too many
|
|
|
blocks. It creates a basic block whenever a continuation \emph{might}
|
|
|
-get used more than once (e.g., whenever the \code{cont} parameter is
|
|
|
+get used more than once (for example, whenever the \code{cont} parameter is
|
|
|
passed into two or more recursive calls). However, some continuation
|
|
|
arguments may not be used at all. For example, consider the case for
|
|
|
the constant \TRUE{} in \code{explicate\_pred}, in which we discard the
|
|
@@ -10696,7 +10696,7 @@ passing
|
|
|
style~\citep{Wijngaarden:1966,Fischer:1972,reynolds72:_def_interp,Plotkin:1975,Friedman:2001}.
|
|
|
%
|
|
|
The treatment of conditionals in the \code{explicate\_control} pass is
|
|
|
-similar to short-cut boolean
|
|
|
+similar to short-cut Boolean
|
|
|
evaluation~\citep{Logothetis:1981,Aho:2006wb,Clarke:1989,Danvy:2003fk}
|
|
|
and the case-of-case transformation~\citep{PeytonJones:1998}.
|
|
|
|
|
@@ -11130,8 +11130,7 @@ before register allocation.
|
|
|
block8:
|
|
|
movq $27, %rax
|
|
|
addq sum, %rax
|
|
|
- jmp mainconclusion
|
|
|
-)
|
|
|
+ jmp mainconclusion)
|
|
|
\end{lstlisting}
|
|
|
\end{minipage}
|
|
|
\fi}
|
|
@@ -11213,12 +11212,12 @@ For the second round, the live-after for \code{mainstart} is the
|
|
|
current live-before for \code{block5}, which is \code{\{i\}}. Therefore
|
|
|
the liveness analysis for \code{mainstart} computes the empty set. The
|
|
|
live-after for \code{block5} is the union of the live-before sets for
|
|
|
-\code{block7} and \code{block8}, which is \code{\{i , rsp, sum\}}.
|
|
|
-So the liveness analysis for \code{block5} computes \code{\{i , rsp,
|
|
|
+\code{block7} and \code{block8}, which is \code{\{i, rsp, sum\}}.
|
|
|
+So the liveness analysis for \code{block5} computes \code{\{i, rsp,
|
|
|
sum\}}. The live-after for \code{block7} is the live-before for
|
|
|
\code{block5} (from the previous iteration), which is \code{\{i\}}.
|
|
|
-So the liveness analysis for \code{block7} remains \code{\{i,
|
|
|
- sum\}}. Together these yield the following approximation $m_2$ of
|
|
|
+So the liveness analysis for \code{block7} remains \code{\{i, sum\}}.
|
|
|
+Together these yield the following approximation $m_2$ of
|
|
|
the live-before sets:
|
|
|
\begin{center}
|
|
|
\begin{lstlisting}
|
|
@@ -11379,7 +11378,7 @@ def analyze_dataflow(G, transfer, bottom, join):
|
|
|
\fi}
|
|
|
\end{tcolorbox}
|
|
|
|
|
|
-\caption{Generic work list algorithm for dataflow analysis}
|
|
|
+\caption{Generic work list algorithm for dataflow analysis.}
|
|
|
\label{fig:generic-dataflow}
|
|
|
\end{figure}
|
|
|
|
|
@@ -11449,7 +11448,7 @@ The temporary variable \code{t1} gets the value of \code{x} before the
|
|
|
the value of \code{x} after the \code{set!}, so it is \code{40}. We
|
|
|
do not generate a temporary variable for the occurrence of \code{y}
|
|
|
because it's an immutable variable. We want to avoid such unnecessary
|
|
|
-extra temporaries because they would needless increase the number of
|
|
|
+extra temporaries because they would needlessly increase the number of
|
|
|
variables, making it more likely for some of them to be spilled. The
|
|
|
result of this program is \code{42}, the same as the result prior to
|
|
|
\code{remove\_complex\_operands}.
|
|
@@ -11960,7 +11959,7 @@ Figure~\ref{fig:Lvec-concrete-syntax} shows the definition of the
|
|
|
concrete syntax for \LangVec{}, and figure~\ref{fig:Lvec-syntax} shows
|
|
|
the definition of the abstract syntax.
|
|
|
%
|
|
|
-\racket{The \LangVec{} language includes the forms: \code{vector} for
|
|
|
+\racket{The \LangVec{} language includes the forms \code{vector} for
|
|
|
creating a tuple, \code{vector-ref} for reading an element of a
|
|
|
tuple, \code{vector-set!} for writing to an element of a tuple, and
|
|
|
\code{vector-length} for obtaining the number of elements of a
|
|
@@ -12881,7 +12880,7 @@ the tuple, which is 8 for the tag plus \itm{len} times 8.
|
|
|
\end{center}
|
|
|
%
|
|
|
\noindent The sequencing of the initializing expressions
|
|
|
-$e_0,\ldots,e_{n-1}$ prior to the \code{allocate} is important, because
|
|
|
+$e_0,\ldots,e_{n-1}$ prior to the \code{allocate} is important because
|
|
|
they may trigger garbage collection and we cannot have an allocated
|
|
|
but uninitialized tuple on the heap during a collection.
|
|
|
|
|
@@ -13130,7 +13129,7 @@ section.
|
|
|
%% global (postpone)
|
|
|
|
|
|
In this pass we generate x86 code for most of the new operations that
|
|
|
-were needed to compile tuples, including \code{Allocate},
|
|
|
+are needed to compile tuples, including \code{Allocate},
|
|
|
\code{Collect}, and accessing tuple elements.
|
|
|
%
|
|
|
We compile \code{GlobalValue} to \code{Global} because the latter has a
|
|
@@ -13177,7 +13176,7 @@ movq |$\itm{rhs}'$|, |$8(n+1)$|(%r11)
|
|
|
are obtained by translating from \LangCVec{} to x86.
|
|
|
%
|
|
|
The move of $\itm{tup}'$ to
|
|
|
-register \code{r11} ensures that offset expression
|
|
|
+register \code{r11} ensures that the offset expression
|
|
|
\code{$8(n+1)$(\%r11)} contains a register operand. This requires
|
|
|
removing \code{r11} from consideration by the register allocating.
|
|
|
|
|
@@ -13195,7 +13194,7 @@ movq |$\itm{tup}'$|, %rax
|
|
|
movq |$\itm{rhs}'$|, %rax
|
|
|
movq %rax, |$8(n+1)$|(%rax)
|
|
|
\end{lstlisting}
|
|
|
-However, this sequence of instructions does not work, because we're
|
|
|
+However, this sequence of instructions does not work because we're
|
|
|
trying to use \code{rax} for two different values ($\itm{tup}'$ and
|
|
|
$\itm{rhs}'$) at the same time!
|
|
|
|
|
@@ -13750,7 +13749,7 @@ mark. The following example uses \code{set-point-x!} to change the
|
|
|
Create a type checker for \LangStruct{} by extending the type
|
|
|
checker for \LangVec{}. Extend your compiler with support for simple
|
|
|
structures, compiling \LangStruct{} to x86 assembly code. Create
|
|
|
- five new test cases that use structures and, test your compiler.
|
|
|
+ five new test cases that use structures, and test your compiler.
|
|
|
\end{exercise}
|
|
|
|
|
|
% TODO: create an interpreter for L_struct
|
|
@@ -13774,10 +13773,8 @@ sequence.
|
|
|
The Racket language does not distinguish between tuples and arrays;
|
|
|
they are both represented by vectors. However, Typed Racket
|
|
|
distinguishes between tuples and arrays: the \code{Vector} type is for
|
|
|
-tuples, and the \code{Vectorof} type is for arrays.}
|
|
|
-\python{
|
|
|
-Arrays correspond to the \code{list} type in Python language.
|
|
|
-}
|
|
|
+tuples, and the \code{Vectorof} type is for arrays.}%
|
|
|
+\python{Arrays correspond to the \code{list} type in Python language.}
|
|
|
|
|
|
Figure~\ref{fig:Lvecof-concrete-syntax} presents the definition of the
|
|
|
concrete syntax for \LangArray{}, and figure~\ref{fig:Lvecof-syntax}
|
|
@@ -13788,8 +13785,7 @@ with the \racket{\code{Vectorof}}\python{\code{list}} type and the
|
|
|
whose arguments are the length of the array and an initial value for
|
|
|
all the elements in the array.}
|
|
|
\python{bracket notation for creating an array literal.}
|
|
|
-\racket{
|
|
|
-The \code{vector-length},
|
|
|
+\racket{The \code{vector-length},
|
|
|
\code{vector-ref}, and \code{vector-ref!} operators that we defined
|
|
|
for tuples become overloaded for use with arrays.}
|
|
|
\python{
|
|
@@ -13800,7 +13796,7 @@ arbitrary expression and not just a constant integer.
|
|
|
The \code{len} function is also applicable to arrays.
|
|
|
}
|
|
|
%
|
|
|
-We include integer multiplication in \LangArray{}, because it is
|
|
|
+We include integer multiplication in \LangArray{} because it is
|
|
|
useful in many examples involving arrays such as computing the
|
|
|
inner product of two arrays (figure~\ref{fig:inner_product}).
|
|
|
|
|
@@ -14111,7 +14107,7 @@ figure~\ref{fig:interp-Lvecof}.
|
|
|
interpreted using Racket's \code{make-vector} function,
|
|
|
and multiplication is interpreted using \code{fx*},
|
|
|
which is multiplication for \code{fixnum} integers.
|
|
|
- In the \code{resolve} pass (Section~\ref{sec:array-resolution})
|
|
|
+ In the \code{resolve} pass (section~\ref{sec:array-resolution})
|
|
|
we translate array access operations
|
|
|
into \code{vectorof-ref} and \code{vectorof-set!} operations,
|
|
|
which we interpret using \code{vector} operations with additional
|
|
@@ -14399,7 +14395,7 @@ FromSpace and a ToSpace. The following is a sketch of how to adapt the
|
|
|
|
|
|
\begin{enumerate}
|
|
|
\item Copy the young generation's FromSpace to its ToSpace and then
|
|
|
- switch the role of the ToSpace and FromSpace
|
|
|
+ switch the role of the ToSpace and FromSpace.
|
|
|
\item If there is enough space for the requested number of bytes in
|
|
|
the young FromSpace, then return from \code{collect}.
|
|
|
\item If there is not enough space in the young FromSpace for the
|
|
@@ -14454,7 +14450,7 @@ from the set.
|
|
|
|
|
|
\section{Further Reading}
|
|
|
|
|
|
-\citet{Appel90} describes many data representation approaches,
|
|
|
+\citet{Appel90} describes many data representation approaches
|
|
|
including the ones used in the compilation of Standard ML.
|
|
|
|
|
|
There are many alternatives to copying collectors (and their bigger
|
|
@@ -14766,7 +14762,8 @@ this extended environment.
|
|
|
(cons x (box arg))))
|
|
|
(define new-env (append params-args fun-env))
|
|
|
((interp-exp new-env) body)]
|
|
|
- [else (error 'interp-exp "expected function, not ~a" fun-val)])]
|
|
|
+ [else
|
|
|
+ (error 'interp-exp "expected function, not ~a" fun-val)])]
|
|
|
[else ((super interp-exp env) e)]
|
|
|
))
|
|
|
|
|
@@ -15039,8 +15036,8 @@ the target. However, \code{callq} does not handle
|
|
|
\end{enumerate}
|
|
|
|
|
|
Regarding parameter passing, recall that the x86-64 calling
|
|
|
-convention for Unix-based system uses the following six registers to
|
|
|
-pass arguments to a function, in the given order.
|
|
|
+convention for Unix-based systems uses the following six registers to
|
|
|
+pass arguments to a function, in the given order:
|
|
|
\begin{lstlisting}
|
|
|
rdi rsi rdx rcx r8 r9
|
|
|
\end{lstlisting}
|
|
@@ -15352,7 +15349,7 @@ argument.\footnote{The implementation this pass can be postponed to
|
|
|
six or fewer parameters.}
|
|
|
|
|
|
Each function definition with seven or more parameters is transformed as
|
|
|
-follows.
|
|
|
+follows:
|
|
|
{\if\edition\racketEd
|
|
|
\begin{lstlisting}
|
|
|
(Def |$f$| ([|$x_1$|:|$T_1$|] |$\ldots$| [|$x_n$|:|$T_n$|]) |$T_r$| |$\itm{info}$| |$\itm{body}$|)
|
|
@@ -15423,11 +15420,11 @@ Call(|$e_0$|, [|$e_1,\ldots,e_5$|,Tuple([|$e_6,\ldots,e_n$|])])
|
|
|
|
|
|
The primary decisions to make for this pass are whether to classify
|
|
|
\code{FunRef} and \racket{\code{Apply}}\python{\code{Call}} as either
|
|
|
-atomic or complex expressions. Recall that an atomic expression will
|
|
|
-end up as an immediate argument of an x86 instruction. Function
|
|
|
-application will be translated to a sequence of instructions, so
|
|
|
+atomic or complex expressions. Recall that an atomic expression
|
|
|
+ends up as an immediate argument of an x86 instruction. Function
|
|
|
+application translates to a sequence of instructions, so
|
|
|
\racket{\code{Apply}}\python{\code{Call}} must be classified as
|
|
|
-complex expression. On the other hand, the arguments of
|
|
|
+a complex expression. On the other hand, the arguments of
|
|
|
\racket{\code{Apply}}\python{\code{Call}} should be atomic
|
|
|
expressions.
|
|
|
%
|
|
@@ -15889,7 +15886,7 @@ include all the caller-saved registers. Recall that the reason for
|
|
|
that is to force variables that are live across a function call to be assigned to callee-saved
|
|
|
registers or to be spilled to the stack.
|
|
|
|
|
|
-Regarding the set of read locations $R$, the arity field of
|
|
|
+Regarding the set of read locations $R$, the arity fields of
|
|
|
\code{TailJmp} and \code{IndirectCallq} determine how many of the
|
|
|
argument-passing registers should be considered as read by those
|
|
|
instructions. Also, the target field of \code{TailJmp} and
|
|
@@ -15909,10 +15906,10 @@ to our language, we need to revisit this issue. Functions that perform
|
|
|
allocation contain calls to the collector. Thus, we should not only
|
|
|
spill a tuple-typed variable when it is live during a call to
|
|
|
\code{collect}, but we should spill the variable if it is live during
|
|
|
-call to any user-defined function. Thus, in the
|
|
|
+a call to any user-defined function. Thus, in the
|
|
|
\code{build\_interference} pass, we recommend adding interference
|
|
|
edges between call-live tuple-typed variables and the callee-saved
|
|
|
-registers (in addition to the usual addition of edges between
|
|
|
+registers (in addition to creating edges between
|
|
|
call-live variables and the caller-saved registers).
|
|
|
|
|
|
|
|
@@ -15998,7 +15995,7 @@ compiling \LangFun{} to x86.
|
|
|
|
|
|
\begin{exercise}\normalfont\normalsize
|
|
|
Expand your compiler to handle \LangFun{} as outlined in this chapter.
|
|
|
-Create eight new programs that use functions, including examples that
|
|
|
+Create eight new programs that use functions including examples that
|
|
|
pass functions and return functions from other functions, recursive
|
|
|
functions, functions that create vectors, and functions that make tail
|
|
|
calls. Test your compiler on these new programs and all your
|
|
@@ -17092,12 +17089,12 @@ print( g(20) )
|
|
|
\end{lstlisting}
|
|
|
\fi}
|
|
|
%
|
|
|
-\noindent The variables \code{x} and \code{y} are assigned to. The
|
|
|
-variables \code{x} and \code{z} occur free inside the
|
|
|
-\code{lambda}. Thus, variable \code{x} needs to be boxed but not
|
|
|
-\code{y} or \code{z}. The boxing of \code{x} consists of three
|
|
|
-transformations: initialize \code{x} with a tuple whose elements are
|
|
|
-uninitialized, replace reads from \code{x} with tuple reads, and
|
|
|
+\noindent The variables \code{x} and \code{y} appear on the left-hand
|
|
|
+side of assignments. The variables \code{x} and \code{z} occur free
|
|
|
+inside the \code{lambda}. Thus, variable \code{x} needs to be boxed
|
|
|
+but not \code{y} or \code{z}. The boxing of \code{x} consists of
|
|
|
+three transformations: initialize \code{x} with a tuple whose elements
|
|
|
+are uninitialized, replace reads from \code{x} with tuple reads, and
|
|
|
replace each assignment to \code{x} with a tuple write. The output of
|
|
|
\code{convert\_assignments} for this example is as follows:
|
|
|
%
|
|
@@ -17406,7 +17403,7 @@ function definitions. To maintain a uniform translation of function
|
|
|
application, we turn function references into closures.
|
|
|
|
|
|
\begin{tabular}{lll}
|
|
|
-\begin{minipage}{0.3\textwidth}
|
|
|
+\begin{minipage}{0.2\textwidth}
|
|
|
{\if\edition\racketEd
|
|
|
\begin{lstlisting}
|
|
|
(FunRef |$f$| |$n$|)
|
|
@@ -17419,7 +17416,7 @@ FunRef(|$f$|, |$n$|)
|
|
|
\fi}
|
|
|
\end{minipage}
|
|
|
&
|
|
|
-$\Rightarrow$
|
|
|
+$\Rightarrow\qquad$
|
|
|
&
|
|
|
\begin{minipage}{0.5\textwidth}
|
|
|
{\if\edition\racketEd
|
|
@@ -17686,7 +17683,7 @@ $58$ from the tag.}
|
|
|
\path[->,bend left=15] (F1-6) edge [above] node
|
|
|
{\ttfamily\footnotesize explicate\_control} (C3-2);
|
|
|
\path[->] (C3-2) edge [right] node
|
|
|
- {\ttfamily\footnotesize select\_instructions} (x86-2);
|
|
|
+ {\ttfamily\footnotesize \ \ select\_instructions} (x86-2);
|
|
|
\path[->,bend right=15] (x86-2) edge [right] node
|
|
|
{\ttfamily\footnotesize uncover\_live} (x86-2-1);
|
|
|
\path[->,bend right=15] (x86-2-1) edge [below] node
|
|
@@ -17885,7 +17882,7 @@ need to perform closure conversion on the function.
|
|
|
of closure conversion that does not apply closure conversion to
|
|
|
global functions that do not escape but instead compiles them as
|
|
|
regular functions. Create several new test cases that check whether
|
|
|
- your compiler properly detect whether global functions escape or not.
|
|
|
+ your compiler properly detects whether global functions escape or not.
|
|
|
\end{exercise}
|
|
|
|
|
|
So far we have reduced the overhead of calling global functions, but
|
|
@@ -18000,7 +17997,7 @@ lists, so variable look-up was linear in the size of the
|
|
|
environment. \citet{Appel91} gives a detailed description of several
|
|
|
closure representations. In this chapter we represent environments
|
|
|
using flat closures, which were invented by
|
|
|
-\citet{Cardelli:1983aa,Cardelli:1984aa} for the purposes of compiling
|
|
|
+\citet{Cardelli:1983aa,Cardelli:1984aa} for the purpose of compiling
|
|
|
the ML language~\citep{Gordon:1978aa,Milner:1990fk}. With flat
|
|
|
closures, variable look-up is constant time but the time to create a
|
|
|
closure is proportional to the number of its free variables. Flat
|
|
@@ -18042,7 +18039,7 @@ are called \emph{polymorphic}, a word composed of the Greek roots
|
|
|
\emph{poly}, meaning \emph{many}, and \emph{morph}, meaning \emph{form}.
|
|
|
There are several kinds of polymorphism in programming languages, such as
|
|
|
subtype polymorphism and parametric polymorphism
|
|
|
-(aka. generics)~\citep{Cardelli:1985kx}. The kind of polymorphism that we
|
|
|
+(aka generics)~\citep{Cardelli:1985kx}. The kind of polymorphism that we
|
|
|
study in this chapter does not have a special name; it is the kind
|
|
|
that arises in dynamically typed languages.
|
|
|
|
|
@@ -18056,9 +18053,7 @@ given anything else it returns \FALSE{}.
|
|
|
Furthermore, even when primitive operations restrict their inputs to
|
|
|
values of a certain type, this restriction is enforced at runtime
|
|
|
instead of during compilation. For example, the tuple read
|
|
|
-operation
|
|
|
-\racket{\code{(vector-ref \#t 0)}}
|
|
|
-\python{\code{True[0]}}
|
|
|
+operation \racket{\code{(vector-ref \#t 0)}}\python{\code{True[0]}}
|
|
|
results in a runtime error because the first argument must
|
|
|
be a tuple, not a Boolean.
|
|
|
|
|
@@ -18194,10 +18189,8 @@ There is no type checker for \LangDyn{} because it checks types only
|
|
|
at runtime.
|
|
|
|
|
|
The definitional interpreter for \LangDyn{} is presented in
|
|
|
-\racket{figure~\ref{fig:interp-Ldyn}}
|
|
|
-\python{figures~\ref{fig:interp-Ldyn} and \ref{fig:interp-Ldyn-2}},
|
|
|
-and definitions of its auxiliary functions are shown in
|
|
|
-figure~\ref{fig:interp-Ldyn-aux}. Consider the match case for
|
|
|
+\racket{figure~\ref{fig:interp-Ldyn}}\python{figures~\ref{fig:interp-Ldyn} and \ref{fig:interp-Ldyn-2}}, and definitions of its auxiliary functions
|
|
|
+are shown in figure~\ref{fig:interp-Ldyn-aux}. Consider the match case for
|
|
|
\INT{n}. Instead of simply returning the integer \code{n} (as
|
|
|
in the interpreter for \LangVar{} in figure~\ref{fig:interp-Lvar}), the
|
|
|
interpreter for \LangDyn{} creates a \emph{tagged value}\index{subject}{tagged
|
|
@@ -18569,7 +18562,7 @@ type called \racket{\code{Any}}\python{\code{AnyType()}} and define
|
|
|
operations such as \code{Inject} and \code{Project} for creating and
|
|
|
using them, yielding the statically typed \LangAny{} intermediate
|
|
|
language. We describe how to compile \LangDyn{} to \LangAny{} in
|
|
|
-section~\ref{sec:compile-r7}; in th next section we describe the
|
|
|
+section~\ref{sec:compile-r7}; in the next section we describe the
|
|
|
\LangAny{} language in greater detail.
|
|
|
|
|
|
\section{The \LangAny{} Language}
|
|
@@ -19267,7 +19260,7 @@ Call(Name('any_tuple_load'),
|
|
|
\fi}
|
|
|
\end{tcolorbox}
|
|
|
|
|
|
- \caption{Cast insertion}
|
|
|
+ \caption{Cast insertion.}
|
|
|
\label{fig:compile-r7-Lany}
|
|
|
\end{figure}
|
|
|
|
|
@@ -19307,9 +19300,8 @@ the type checker.
|
|
|
%
|
|
|
\fi}
|
|
|
|
|
|
-
|
|
|
If the target type of the projection is \BOOLTY{} or \INTTY{}, then
|
|
|
-\code{Project} can be translated as follows.
|
|
|
+\code{Project} can be translated as follows:
|
|
|
\begin{center}
|
|
|
\begin{minipage}{1.0\textwidth}
|
|
|
{\if\edition\racketEd
|
|
@@ -19546,11 +19538,11 @@ of translating $e$ into an x86 argument:
|
|
|
We recommend compiling the
|
|
|
\racket{\code{make-any}}\python{\code{make\_any}} operation as follows
|
|
|
if the tag is for \INTTY{} or \BOOLTY{}. The \key{salq} instruction
|
|
|
-shifts the destination to the left by the number of bits specified its
|
|
|
+shifts the destination to the left by the number of bits specified by its
|
|
|
source argument (in this case three, the length of the tag), and it
|
|
|
preserves the sign of the integer. We use the \key{orq} instruction to
|
|
|
-combine the tag and the value to form the tagged value. \\
|
|
|
-%
|
|
|
+combine the tag and the value to form the tagged value.
|
|
|
+
|
|
|
{\if\edition\racketEd
|
|
|
\begin{lstlisting}
|
|
|
(Assign |\itm{lhs}| (Prim 'make-any (list |$e$| (Int |$\itm{tag}$|))))
|
|
@@ -19572,7 +19564,7 @@ orq $|$\itm{tag}$|, |\itm{lhs'}|
|
|
|
\fi}
|
|
|
%
|
|
|
The instruction selection for tuples and procedures is different
|
|
|
-because their is no need to shift them to the left. The rightmost 3
|
|
|
+because there is no need to shift them to the left. The rightmost 3
|
|
|
bits are already zeros, so we simply combine the value and the tag
|
|
|
using \key{orq}. \\
|
|
|
%
|
|
@@ -19971,7 +19963,7 @@ adding or removing type annotations on parameters and
|
|
|
variables~\citep{Anderson:2002kd,Siek:2006bh}.
|
|
|
|
|
|
The definition of the concrete syntax of \LangGrad{} is shown in
|
|
|
-figure~\ref{fig:Lgrad-concrete-syntax} and the definition of its
|
|
|
+figure~\ref{fig:Lgrad-concrete-syntax}, and the definition of its
|
|
|
abstract syntax is shown in figure~\ref{fig:Lgrad-syntax}. The main
|
|
|
syntactic difference between \LangLam{} and \LangGrad{} is that type
|
|
|
annotations are optional, which is specified in the grammar using the
|
|
@@ -20766,20 +20758,18 @@ defines a partially typed version of \code{map} whose parameter
|
|
|
\code{v} has type
|
|
|
\racket{\code{(Vector Any Any)}}\python{\code{list[Any]}}
|
|
|
and that updates \code{v} in place
|
|
|
-instead of returning a new tuple. So, we name this function
|
|
|
-\code{map\_inplace}. We apply \code{map\_inplace} to an
|
|
|
-\racket{tuple}\python{array} of integers, so the type checker inserts a
|
|
|
-cast from
|
|
|
+instead of returning a new tuple. We name this function
|
|
|
+\code{map\_inplace}. We apply \code{map\_inplace} to
|
|
|
+\racket{a tuple}\python{an array} of integers, so the type checker
|
|
|
+inserts a cast from
|
|
|
\racket{\code{(Vector Integer Integer)}}\python{\code{list[int]}}
|
|
|
to
|
|
|
\racket{\code{(Vector Any Any)}}\python{\code{list[Any]}}.
|
|
|
A naive way for the \LangCast{} interpreter to cast between
|
|
|
-\racket{tuple}\python{array} types would be a build a new
|
|
|
-\racket{tuple}\python{array}
|
|
|
-whose elements are the result
|
|
|
+\racket{tuple}\python{array} types would be to build a new
|
|
|
+\racket{tuple}\python{array} whose elements are the result
|
|
|
of casting each of the original elements to the appropriate target
|
|
|
-type.
|
|
|
-However, this approach is not valid for mutable data structures.
|
|
|
+type. However, this approach is not valid for mutable data structures.
|
|
|
In the example of figure~\ref{fig:map-bang},
|
|
|
if the cast created a new \racket{tuple}\python{array}, then the updates inside
|
|
|
\code{map\_inplace} would happen to the new \racket{tuple}\python{array} and not
|
|
@@ -20843,10 +20833,9 @@ from \CANYTY{} to \INTTY{}.
|
|
|
the proxy casts the tagged value from \CANYTY{} to \INTTY{}.
|
|
|
}
|
|
|
|
|
|
-The final category of cast that we need to consider consist of casts between
|
|
|
-the \CANYTY{} type and higher-order types such as functions and
|
|
|
-\racket{tuples}\python{lists}. Figure~\ref{fig:map-any} shows a
|
|
|
-variant of \code{map\_inplace} in which parameter \code{v} does not
|
|
|
+Finally we consider casts between the \CANYTY{} type and higher-order types
|
|
|
+such as functions and \racket{tuples}\python{lists}. Figure~\ref{fig:map-any}
|
|
|
+shows a variant of \code{map\_inplace} in which parameter \code{v} does not
|
|
|
have a type annotation, so it is given type \CANYTY{}. In the call to
|
|
|
\code{map\_inplace}, the \racket{tuple}\python{list} has type
|
|
|
\racket{\code{(Vector Integer Integer)}}\python{\code{list[int]}},
|
|
@@ -20890,7 +20879,7 @@ print( v[1] )
|
|
|
\fi}
|
|
|
\end{tcolorbox}
|
|
|
|
|
|
- \caption{Casting an \racket{tuple}\python{array} to \CANYTY{}.}
|
|
|
+ \caption{Casting \racket{a tuple}\python{an array} to \CANYTY{}.}
|
|
|
\label{fig:map-any}
|
|
|
\end{figure}
|
|
|
|
|
@@ -21126,7 +21115,7 @@ class InterpLcast(InterpLany):
|
|
|
|
|
|
Recall that when we added support for arrays in
|
|
|
section~\ref{sec:arrays}, the syntax for the array operations were the
|
|
|
-same as for tuple operations (e.g., accessing an element, getting the
|
|
|
+same as for tuple operations (for example, accessing an element, getting the
|
|
|
length). So we performed overload resolution, with a pass named
|
|
|
\code{resolve}, to separate the array and tuple operations. In
|
|
|
particular, we introduced the primitives \code{array\_load},
|
|
@@ -21163,7 +21152,7 @@ checker requires that the type of the left operand is consistent with
|
|
|
\INTTY{}. Thus, the \code{cast\_insert} pass should insert a
|
|
|
\code{Cast} around the left operand, converting from its type to
|
|
|
\INTTY{}. The story is similar for the right operand. It is not always
|
|
|
-necessary to insert a cast, e.g., if the left operand already has type
|
|
|
+necessary to insert a cast, for example, if the left operand already has type
|
|
|
\INTTY{} then there is no need for a \code{Cast}.
|
|
|
|
|
|
Some of the implicit casts are not as straightforward. One such case
|
|
@@ -21226,7 +21215,7 @@ type to another tuple type is accomplished by creating a proxy that
|
|
|
intercepts the operations on the underlying tuple. Here we make the
|
|
|
creation of the proxy explicit with the \code{vector-proxy} AST
|
|
|
node. It takes three arguments: the first is an expression for the
|
|
|
-tuple, the second is tuple of functions for casting an element that is
|
|
|
+tuple, the second is a tuple of functions for casting an element that is
|
|
|
being read from the tuple, and the third is a tuple of functions for
|
|
|
casting an element that is being written to the array. You can create
|
|
|
the functions for reading and writing using lambda expressions. Also,
|
|
@@ -21327,7 +21316,7 @@ by generating a \code{lambda} whose parameter and return types match
|
|
|
the target function type. The body of the \code{lambda} should cast
|
|
|
the parameters from the target type to the source type. (Yes,
|
|
|
backward! Functions are contravariant\index{subject}{contravariant}
|
|
|
-in the parameters.). Afterward, call the underlying function and then
|
|
|
+in the parameters.) Afterward, call the underlying function and then
|
|
|
cast the result from the source return type to the target return type.
|
|
|
Figure~\ref{fig:map-lower-cast} shows the output of the
|
|
|
\code{lower\_casts} pass on the \code{map} example give in
|
|
@@ -21667,7 +21656,7 @@ Recall that the \code{select\_instructions} pass is responsible for
|
|
|
lowering the primitive operations into x86 instructions. So, we need
|
|
|
to translate the new operations on \PTUPLETYNAME{} \python{and \PARRAYTYNAME{}}
|
|
|
to x86. To do so, the first question we need to answer is how to
|
|
|
-differentiate between tuple and tuples proxies\python{, and likewise for
|
|
|
+differentiate between tuple and tuple proxies\python{, and likewise for
|
|
|
arrays and array proxies}. We need just one bit to accomplish this;
|
|
|
we use the bit in position $63$ of the 64-bit tag at the front of
|
|
|
every tuple (see figure~\ref{fig:tuple-rep})\python{ or array
|
|
@@ -21758,6 +21747,7 @@ functions!), so here we simply need to translate these tuple
|
|
|
operations into the appropriate function call. For example, here is
|
|
|
the translation for
|
|
|
\racket{\code{proxy-vector-ref}}\python{\code{proxy\_tuple\_load}}.
|
|
|
+
|
|
|
{\if\edition\racketEd
|
|
|
\begin{minipage}{0.96\textwidth}
|
|
|
\begin{lstlisting}
|
|
@@ -21803,7 +21793,7 @@ array. But in the current setting, the underlying value is of type
|
|
|
functions to deal with this:
|
|
|
\code{proxy\_vector\_ref},
|
|
|
\code{proxy\_vector\_set}, and
|
|
|
-\code{proxy\_vector\_length}, that inspect bit $62$ of the tag
|
|
|
+\code{proxy\_vector\_length} that inspect bit $62$ of the tag
|
|
|
to determine whether the value is a proxy, and then
|
|
|
dispatches to the the appropriate code.
|
|
|
%
|
|
@@ -22338,7 +22328,7 @@ a function type.
|
|
|
|
|
|
The type checking of a function application is extended to handle the
|
|
|
case in which the operator expression is a generic function. In that case
|
|
|
-the type arguments are deduced by matching the type of the parameters
|
|
|
+the type arguments are deduced by matching the types of the parameters
|
|
|
with the types of the arguments.
|
|
|
%
|
|
|
The \code{match\_types} auxiliary function
|
|
@@ -22362,14 +22352,14 @@ The type checker extends type equality to handle the \code{All} type.
|
|
|
This is not quite as simple as for other types, such as function and
|
|
|
tuple types, because two \code{All} types can be syntactically
|
|
|
different even though they are equivalent. For example,
|
|
|
-%
|
|
|
-\racket{\code{(All (T) (T -> T))}}
|
|
|
-\python{\code{All[[T], Callable[[T], T]]}}
|
|
|
+\begin{center}
|
|
|
+\racket{\code{(All (T) (T -> T))}}\python{\code{All[[T], Callable[[T], T]]}}
|
|
|
+\end{center}
|
|
|
is equivalent to
|
|
|
-\racket{\code{(All (U) (U -> U))}}
|
|
|
-\python{\code{All[[U], Callable[[U], U]]}}.
|
|
|
-%
|
|
|
-Two generic types should be considered equal if they differ only in
|
|
|
+\begin{center}
|
|
|
+\racket{\code{(All (U) (U -> U))}}\python{\code{All[[U], Callable[[U], U]]}}.
|
|
|
+\end{center}
|
|
|
+Two generic types are equal if they differ only in
|
|
|
the choice of the names of the type parameters. The definition of type
|
|
|
equality shown in figure~\ref{fig:type-check-Lpoly-aux} renames the type
|
|
|
parameters in one type to match the type parameters of the other type.
|
|
@@ -22682,10 +22672,10 @@ follows:
|
|
|
producing type-specialized code. This approach results in the most
|
|
|
efficient code but requires whole-program compilation (no separate
|
|
|
compilation) and may increase code size. Unfortunately,
|
|
|
- monomorphization is incompatible with first-class generics, because
|
|
|
+ monomorphization is incompatible with first-class generics because
|
|
|
it is not always possible to determine which generic functions are
|
|
|
used with which type arguments during compilation. (It can be done
|
|
|
- at runtime, with just-in-time compilation.) Monomorphization is
|
|
|
+ at runtime with just-in-time compilation.) Monomorphization is
|
|
|
used to compile C++ templates~\citep{stroustrup88:_param_types} and
|
|
|
generic functions in NESL~\citep{Blelloch:1993aa} and
|
|
|
ML~\citep{Weeks:2006aa}.
|
|
@@ -22710,7 +22700,7 @@ follows:
|
|
|
function, using a boxed representation for type variables. However,
|
|
|
monomorphic code is compiled as usual (as in \LangLam{}), and
|
|
|
conversions are performed at the boundaries between monomorphic code
|
|
|
- and polymorphic code (e.g., when a generic function is instantiated
|
|
|
+ and polymorphic code (for example, when a generic function is instantiated
|
|
|
and called). This approach is compatible with separate compilation
|
|
|
and first-class generics and maintains efficiency in monomorphic
|
|
|
code. The trade-off is increased overhead at the boundary between
|
|
@@ -22828,7 +22818,7 @@ compiler.
|
|
|
The output of the \code{resolve} pass on the generic \code{map}
|
|
|
example is listed in figure~\ref{fig:map-resolve}. Note that the use
|
|
|
of \code{map} is wrapped in an \code{inst} node, with the parameter
|
|
|
-\code{T} chosen to be \racket{\code{Integer}} \python{\code{int}}.
|
|
|
+\code{T} chosen to be \racket{\code{Integer}}\python{\code{int}}.
|
|
|
|
|
|
\begin{figure}[tbp]
|
|
|
% poly_test_2.rkt
|
|
@@ -23014,9 +23004,8 @@ Regarding the translation of expressions, the case for \code{Inst} is
|
|
|
the interesting one. We translate it into a \code{Cast}, as shown
|
|
|
next.
|
|
|
The type of the subexpression $e$ is a generic type of the form
|
|
|
-\racket{$\LP\key{All}~\itm{xs}~T\RP$}
|
|
|
-\python{$\key{AllType}\LP\itm{xs}, T\RP$}. The source type of the
|
|
|
-cast is the erasure of $T$, the type $T_s$.
|
|
|
+\racket{$\LP\key{All}~\itm{xs}~T\RP$}\python{$\key{AllType}\LP\itm{xs}, T\RP$}.
|
|
|
+The source type of the cast is the erasure of $T$, the type $T_s$.
|
|
|
%
|
|
|
{\if\edition\racketEd
|
|
|
%
|
|
@@ -23241,10 +23230,10 @@ This function runs the compiler passes and the interpreters on each of
|
|
|
the specified tests to check whether each pass is correct. The
|
|
|
\key{interp-tests} function has the following parameters:
|
|
|
\begin{description}
|
|
|
-\item[name (a string)] A name to identify the compiler,
|
|
|
+\item[name (a string)] A name to identify the compiler.
|
|
|
\item[typechecker] A function of exactly one argument that either
|
|
|
raises an error using the \code{error} function when it encounters a
|
|
|
- type error or returns \code{\#f} when it encounters a type
|
|
|
+ type error, or returns \code{\#f} when it encounters a type
|
|
|
error. If there is no type error, the type checker returns the
|
|
|
program.
|
|
|
|
|
@@ -23358,7 +23347,7 @@ registers.
|
|
|
\texttt{subq} $A$, $B$ & $B - A \to B$\\
|
|
|
\texttt{imulq} $A$, $B$ & $A \times B \to B$\\
|
|
|
\texttt{callq} $L$ & Pushes the return address and jumps to label $L$ \\
|
|
|
-\texttt{callq} \texttt{*}$A$ & Calls the function at the address $A$. \\
|
|
|
+\texttt{callq} \texttt{*}$A$ & Calls the function at the address $A$ \\
|
|
|
%\texttt{leave} & $\texttt{ebp} \to \texttt{esp};$ \texttt{popl \%ebp} \\
|
|
|
\texttt{retq} & Pops the return address and jumps to it \\
|
|
|
\texttt{popq} $A$ & $*\mathtt{rsp} \to A; \mathtt{rsp} + 8 \to \mathtt{rsp}$ \\
|