Sfoglia il codice sorgente

revising tuples and GC

Jeremy Siek 3 anni fa
parent
commit
122c110ce0
3 ha cambiato i file con 145 aggiunte e 111 eliminazioni
  1. 18 0
      book.bib
  2. 126 111
      book.tex
  3. 1 0
      defs.tex

+ 18 - 0
book.bib

@@ -1,3 +1,21 @@
+@inproceedings{Dieckmann99,
+  author    = {Sylvia Dieckmann and Urs H{\"{o}}lzle},
+  editor    = {Rachid Guerraoui},
+  title     = {A Study of the Allocation Behavior of the SPECjvm98 Java Benchmark},
+  booktitle = {ECOOP'99 - Object-Oriented Programming, 13th European Conference,
+               Lisbon, Portugal, June 14-18, 1999, Proceedings},
+  series    = {Lecture Notes in Computer Science},
+  volume    = 1628,
+  pages     = {92--115},
+  publisher = {Springer},
+  year      = 1999,
+  url       = {https://doi.org/10.1007/3-540-48743-3\_5},
+  doi       = {10.1007/3-540-48743-3\_5},
+  timestamp = {Tue, 14 May 2019 10:00:54 +0200},
+  biburl    = {https://dblp.org/rec/conf/ecoop/DieckmannH99.bib},
+  bibsource = {dblp computer science bibliography, https://dblp.org}
+}
+
 @article{Pierce:2000,
 author = {Pierce, Benjamin C. and Turner, David N.},
 title = {Local Type Inference},

+ 126 - 111
book.tex

@@ -2413,10 +2413,12 @@ short). \index{subject}{stack}\index{subject}{procedure call stack}
 The stack consists of a separate \emph{frame}\index{subject}{frame}
 for each procedure call. The memory layout for an individual frame is
 shown in Figure~\ref{fig:frame}.  The register \key{rsp} is called the
-\emph{stack pointer}\index{subject}{stack pointer} and points to the
-item at the top of the stack. The stack grows downward in memory, so
-we increase the size of the stack by subtracting from the stack
-pointer.  In the context of a procedure call, the \emph{return
+\emph{stack pointer}\index{subject}{stack pointer} and it contains the
+address of the item at the top of the stack.  In general, we use the
+term \emph{pointer}\index{subject}{pointer} for something that
+contains an address. The stack grows downward in memory, so we
+increase the size of the stack by subtracting from the stack pointer.
+In the context of a procedure call, the \emph{return
 address}\index{subject}{return address} is the instruction after the
 call instruction on the caller side. The function call instruction,
 \code{callq}, pushes the return address onto the stack prior to
@@ -11166,57 +11168,62 @@ class TypeCheckLtup(TypeCheckLwhile):
 \label{sec:GC}
 
 Garbage collection is a runtime technique for reclaiming space on the
-heap that will not be used in the future by the executing
-program. Unfortunately, it is impossible to know precisely which heap
-allocated values, such as tuples, will be accessed in the
-future. Instead, garbage collectors overapproximate this set of values
-by identifying which of them are possible to access in the future. In
-particular, the \textbf{live}\index{subject}{live} values are those
-that are reachable from values in the registers or procedure call
-stack. Garbage collectors reclaim the space for those values that are
-no longer live.
-
-UNDER CONSTRUCTION
-
-These addresses are called the \emph{root
-  set}\index{subject}{root set}. In addition, a program could access any tuple that is
-transitively reachable from the root set. Thus, it is safe for the
-garbage collector to reclaim the tuples that are not reachable in this
-way.
+heap that will not be used in the future of the running program. We
+use the term \emph{object}\index{subject}{object} to refer to any
+value that is stored in the heap, which for now only includes
+tuples.%
+%
+\footnote{The term ``object'' as used in the context of
+object-oriented programming has a more specific meaning than how we
+are using the term here.}
+%
+Unfortunately, it is impossible to know precisely which objects will
+be accessed in the future and which will not.  Instead, garbage
+collectors overapproximate the set of objects that will be accessed by
+identifying which objects can possibly be accessed.  The running
+program can directly access objects that are in registers and on the
+procedure call stack. It can also transitively access the elements of
+tuples, starting with a tuple whose address is in a register or on the
+procedure call stack.  We define the \emph{root
+set}\index{subject}{root set} to be all the tuple addresses that are
+in registers or on the procedure call stack.  We define the \emph{live
+objects}\index{subject}{live objects} to be the objects that are
+reachable from the root set. Garbage collectors reclaim the space that
+is allocated to objects that are no longer live.  That means that some
+objects may not get reclaimed as soon as they could be, but at least
+garbage collectors do not reclaim the space dedicated to objects that
+will be accessed in the future! The programmer can influence which
+objects get reclaimed by causing them to become unreachable.
 
 So the goal of the garbage collector is twofold:
 \begin{enumerate}
-\item preserve all tuples that are reachable from the root set via a
-  path of pointers, that is, the \emph{live} tuples, and
-\item reclaim the memory of everything else, that is, the
-  \emph{garbage}.
+\item preserve all the live objects, and
+\item reclaim the memory of everything else, that is, the \emph{garbage}.
 \end{enumerate}
 
+\subsection{Two-Space Copying Collector}
 
 Here we study a relatively simple algorithm for garbage collection
-that is the basis of state-of-the-art garbage
+that is the basis of many state-of-the-art garbage
 collectors~\citep{Lieberman:1983aa,Ungar:1984aa,Jones:1996aa,Detlefs:2004aa,Dybvig:2006aa,Tene:2011kx}. In
 particular, we describe a two-space copying
 collector~\citep{Wilson:1992fk} that uses Cheney's algorithm to
-perform the
-copy~\citep{Cheney:1970aa}.
-\index{subject}{copying collector}
-\index{subject}{two-space copying collector}
-Figure~\ref{fig:copying-collector} gives a
-coarse-grained depiction of what happens in a two-space collector,
-showing two time steps, prior to garbage collection (on the top) and
-after garbage collection (on the bottom). In a two-space collector,
-the heap is divided into two parts named the FromSpace and the
-ToSpace. Initially, all allocations go to the FromSpace until there is
-not enough room for the next allocation request. At that point, the
-garbage collector goes to work to make more room.
-\index{subject}{ToSpace}
-\index{subject}{FromSpace}
-
-A copying collector accomplishes this by copying all of the live
-objects from the FromSpace into the ToSpace and then performs a
-sleight of hand, treating the ToSpace as the new FromSpace and the old
-FromSpace as the new ToSpace.  In the example of
+perform the copy~\citep{Cheney:1970aa}.  \index{subject}{copying
+  collector} \index{subject}{two-space copying collector}
+Figure~\ref{fig:copying-collector} gives a coarse-grained depiction of
+what happens in a two-space collector, showing two time steps, prior
+to garbage collection (on the top) and after garbage collection (on
+the bottom). In a two-space collector, the heap is divided into two
+parts named the FromSpace\index{subject}{FromSpace} and the
+ToSpace\index{subject}{ToSpace}.  Initially, all allocations go to the
+FromSpace until there is not enough room for the next allocation
+request. At that point, the garbage collector goes to work to room for
+the next allocation.
+
+A copying collector makes more room by copying all of the live objects
+from the FromSpace into the ToSpace and then performs a sleight of
+hand, treating the ToSpace as the new FromSpace and the old FromSpace
+as the new ToSpace.  In the example of
 Figure~\ref{fig:copying-collector}, there are three pointers in the
 root set, one in a register and two on the stack.  All of the live
 objects have been copied to the ToSpace (the right-hand side of
@@ -11228,9 +11235,9 @@ not get copied into the ToSpace.
 
 The exact situation in Figure~\ref{fig:copying-collector} cannot be
 created by a well-typed program in \LangVec{} because it contains a
-cycle. However, creating cycles will be possible once we get to \LangAny{}.
-We design the garbage collector to deal with cycles to begin with so
-we will not need to revisit this issue.
+cycle. However, creating cycles will be possible once we get to
+\LangDyn{}.  We design the garbage collector to deal with cycles to
+begin with so we will not need to revisit this issue.
 
 \begin{figure}[tbp]
 \centering
@@ -11240,27 +11247,6 @@ we will not need to revisit this issue.
 \label{fig:copying-collector}
 \end{figure}
 
-There are many alternatives to copying collectors (and their bigger
-siblings, the generational collectors) when its comes to garbage
-collection, such as mark-and-sweep~\citep{McCarthy:1960dz} and
-reference counting~\citep{Collins:1960aa}.  The strengths of copying
-collectors are that allocation is fast (just a comparison and pointer
-increment), there is no fragmentation, cyclic garbage is collected,
-and the time complexity of collection only depends on the amount of
-live data, and not on the amount of garbage~\citep{Wilson:1992fk}. The
-main disadvantages of a two-space copying collector is that it uses a
-lot of space and takes a long time to perform the copy, though these
-problems are ameliorated in generational collectors.  Racket and
-Scheme programs tend to allocate many small objects and generate a lot
-of garbage, so copying and generational collectors are a good fit.
-Garbage collection is an active research topic, especially concurrent
-garbage collection~\citep{Tene:2011kx}. Researchers are continuously
-developing new techniques and revisiting old
-trade-offs~\citep{Blackburn:2004aa,Jones:2011aa,Shahriyar:2013aa,Cutler:2015aa,Shidal:2015aa,Osterlund:2016aa,Jacek:2019aa,Gamari:2020aa}. Researchers
-meet every year at the International Symposium on Memory Management to
-present these findings.
-
-
 \subsection{Graph Copying via Cheney's Algorithm}
 \label{sec:cheney}
 \index{subject}{Cheney's algorithm}
@@ -11281,19 +11267,20 @@ and copying tuples into the ToSpace.
 Figure~\ref{fig:cheney} shows several snapshots of the ToSpace as the
 copy progresses. The queue is represented by a chunk of contiguous
 memory at the beginning of the ToSpace, using two pointers to track
-the front and the back of the queue. The algorithm starts by copying
-all tuples that are immediately reachable from the root set into the
-ToSpace to form the initial queue.  When we copy a tuple, we mark the
-old tuple to indicate that it has been visited. We discuss how this
-marking is accomplish in Section~\ref{sec:data-rep-gc}. Note that any
-pointers inside the copied tuples in the queue still point back to the
-FromSpace. Once the initial queue has been created, the algorithm
-enters a loop in which it repeatedly processes the tuple at the front
-of the queue and pops it off the queue.  To process a tuple, the
-algorithm copies all the tuple that are directly reachable from it to
-the ToSpace, placing them at the back of the queue. The algorithm then
-updates the pointers in the popped tuple so they point to the newly
-copied tuples.
+the front and the back of the queue, called the \emph{free pointer}
+and the \emph{scan pointer} respectively. The algorithm starts by
+copying all tuples that are immediately reachable from the root set
+into the ToSpace to form the initial queue.  When we copy a tuple, we
+mark the old tuple to indicate that it has been visited. We discuss
+how this marking is accomplish in Section~\ref{sec:data-rep-gc}. Note
+that any pointers inside the copied tuples in the queue still point
+back to the FromSpace. Once the initial queue has been created, the
+algorithm enters a loop in which it repeatedly processes the tuple at
+the front of the queue and pops it off the queue.  To process a tuple,
+the algorithm copies all the tuple that are directly reachable from it
+to the ToSpace, placing them at the back of the queue. The algorithm
+then updates the pointers in the popped tuple so they point to the
+newly copied tuples.
 
 \begin{figure}[tbp]
 \centering \includegraphics[width=0.9\textwidth]{figs/cheney}
@@ -11306,10 +11293,11 @@ tuple whose second element is $42$ to the back of the queue. The other
 pointer goes to a tuple that has already been copied, so we do not
 need to copy it again, but we do need to update the pointer to the new
 location. This can be accomplished by storing a \emph{forwarding
-pointer} to the new location in the old tuple, back when we initially
-copied the tuple into the ToSpace. This completes one step of the
-algorithm. The algorithm continues in this way until the front of the
-queue is empty, that is, until the front catches up with the back.
+pointer}\index{subect}{forwarding pointer} to the new location in the
+old tuple, back when we initially copied the tuple into the
+ToSpace. This completes one step of the algorithm. The algorithm
+continues in this way until the queue is empty, that is, when the scan
+pointer catches up with the free pointer.
 
 
 \subsection{Data Representation}
@@ -11317,8 +11305,8 @@ queue is empty, that is, until the front catches up with the back.
 
 The garbage collector places some requirements on the data
 representations used by our compiler. First, the garbage collector
-needs to distinguish between pointers and other kinds of data. There
-are several ways to accomplish this.
+needs to distinguish between pointers and other kinds of data such as
+integers. There are several ways to accomplish this.
 \begin{enumerate}
 \item Attached a tag to each object that identifies what type of
   object it is~\citep{McCarthy:1960dz}.
@@ -11336,23 +11324,23 @@ would be unfortunate to require tags on every object, especially small
 and pervasive objects like integers and Booleans.  Option 3 is the
 best-performing choice for statically typed languages, but comes with
 a relatively high implementation complexity. To keep this chapter
-within a 2-week time budget, we recommend a combination of options 1
-and 2, using separate strategies for the stack and the heap.
+within a reasonable time budget, we recommend a combination of options
+1 and 2, using separate strategies for the stack and the heap.
 
 Regarding the stack, we recommend using a separate stack for pointers,
-which we call a \emph{root stack}\index{subject}{root stack}
+which we call the \emph{root stack}\index{subject}{root stack}
 (a.k.a. ``shadow
 stack'')~\citep{Siebert:2001aa,Henderson:2002aa,Baker:2009aa}. That
 is, when a local variable needs to be spilled and is of type
 \racket{\code{Vector}}\python{\code{TupleType}}, then we put it on the
-root stack instead of the normal procedure call stack. Furthermore, we
-always spill tuple-typed variables if they are live during a call to
-the collector, thereby ensuring that no pointers are in registers
-during a collection. Figure~\ref{fig:shadow-stack} reproduces the
-example from Figure~\ref{fig:copying-collector} and contrasts it with
-the data layout using a root stack. The root stack contains the two
-pointers from the regular stack and also the pointer in the second
-register.
+root stack instead of putting it on the procedure call
+stack. Furthermore, we always spill tuple-typed variables if they are
+live during a call to the collector, thereby ensuring that no pointers
+are in registers during a collection. Figure~\ref{fig:shadow-stack}
+reproduces the example from Figure~\ref{fig:copying-collector} and
+contrasts it with the data layout using a root stack. The root stack
+contains the two pointers from the regular stack and also the pointer
+in the second register.
 
 \begin{figure}[tbp]
 \centering \includegraphics[width=0.60\textwidth]{figs/root-stack}
@@ -11372,16 +11360,20 @@ which corresponds to the direction of the x86 shifting instructions
 is dedicated to specifying which elements of the tuple are pointers,
 the part labeled ``pointer mask''. Within the pointer mask, a 1 bit
 indicates there is a pointer and a 0 bit indicates some other kind of
-data. The pointer mask starts at bit location 7. We have limited
-tuples to a maximum size of 50 elements, so we just need 50 bits for
-the pointer mask. The tag also contains two other pieces of
-information. The length of the tuple (number of elements) is stored in
-bits location 1 through 6. Finally, the bit at location 0 indicates
-whether the tuple has yet to be copied to the ToSpace.  If the bit has
-value 1, then this tuple has not yet been copied.  If the bit has
-value 0 then the entire tag is a forwarding pointer. (The lower 3 bits
-of a pointer are always zero anyways because our tuples are 8-byte
-aligned.)
+data. The pointer mask starts at bit location 7. We limit tuples to a
+maximum size of 50 elements, so we just need 50 bits for the pointer
+mask.%
+%
+\footnote{A production-quality compiler would handle
+arbitrary-sized tuples and use a more complex approach.}
+%
+The tag also contains two other pieces of information. The length of
+the tuple (number of elements) is stored in bits location 1 through
+6. Finally, the bit at location 0 indicates whether the tuple has yet
+to be copied to the ToSpace.  If the bit has value 1, then this tuple
+has not yet been copied.  If the bit has value 0 then the entire tag
+is a forwarding pointer. (The lower 3 bits of a pointer are always
+zero anyways because our tuples are 8-byte aligned.)
 
 \begin{figure}[tbp]
 \centering \includegraphics[width=0.8\textwidth]{figs/tuple-rep}
@@ -11531,7 +11523,8 @@ of tuple creation.
       &\MID& \key{collect}(\itm{int})
       \MID \key{allocate}(\itm{int},\itm{type})
       \MID \key{global\_value}(\itm{name}) \\
-      &\MID& \key{begin:} ~ \Stmt^{*} ~ \Exp
+      &\MID& \key{begin:} ~ \Stmt^{*} ~ \Exp \\
+   \Stmt &::= & \CASSIGN{\CPUT{\Exp}{\itm{int}}}{\Exp}
 \end{array}
 \]
 
@@ -12855,7 +12848,29 @@ from the set.
 
 \fi}
 
-% Further Reading
+\section{Further Reading}
+
+There are many alternatives to copying collectors (and their bigger
+siblings, the generational collectors) when its comes to garbage
+collection, such as mark-and-sweep~\citep{McCarthy:1960dz} and
+reference counting~\citep{Collins:1960aa}.  The strengths of copying
+collectors are that allocation is fast (just a comparison and pointer
+increment), there is no fragmentation, cyclic garbage is collected,
+and the time complexity of collection only depends on the amount of
+live data, and not on the amount of garbage~\citep{Wilson:1992fk}. The
+main disadvantages of a two-space copying collector is that it uses a
+lot of extra space and takes a long time to perform the copy, though
+these problems are ameliorated in generational collectors.
+\racket{Racket}\python{Object-oriented} programs tend to allocate many
+small objects and generate a lot of garbage, so copying and
+generational collectors are a good fit\python{~\citep{Dieckmann99}}.
+Garbage collection is an active research topic, especially concurrent
+garbage collection~\citep{Tene:2011kx}. Researchers are continuously
+developing new techniques and revisiting old
+trade-offs~\citep{Blackburn:2004aa,Jones:2011aa,Shahriyar:2013aa,Cutler:2015aa,Shidal:2015aa,Osterlund:2016aa,Jacek:2019aa,Gamari:2020aa}. Researchers
+meet every year at the International Symposium on Memory Management to
+present these findings.
+
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Functions}

+ 1 - 0
defs.tex

@@ -192,6 +192,7 @@
 \newcommand{\CLEN}[1]{\code{len}\LP #1 \RP}
 \newcommand{\LEN}[1]{\code{Call}\LP \code{Name('len')} \code{,} \LS #1 \RS \RP}
 \newcommand{\PUT}[2]{\key{Subscript}\LP #1 \code{,} #2 \code{,} \code{Store()} \RP}
+\newcommand{\CPUT}[2]{#1[#2]}
 \newcommand{\TUPLE}[1]{\key{Tuple}\LP #1 \code{,} \code{Load()} \RP}
 \newcommand{\BOOLOP}[3]{\key{BoolOp}\LP #1 \code{,} \LS #2 \code{,} #3 \RS \RP}
 \newcommand{\CMP}[3]{\key{Compare}\LP #1\code{,}\LS #2 \RS \code{,} \LS #3 \RS\RP}