\section{Garbage Collection Safety}
\subsection{Motivation}
   High level languages such as SML make use of garbage collectors
to reclaim unused storage at runtime.   For generality, I assume that
a precise, compacting garbage collector is used.  In general, 
low-level optimizations that reorder instructions 
pass \newdef{gc safepoints}, when applied naively, 
are not safe.  In general, two general classes of safety issues can be identified:
\begin{description}
 \item[derived values] 
A derived value $x$ is a value that are
dependent on the addresses of one of more heap allocated objects
$a1,a2,a3,\ldots$ and/or the recent branch history.
When these allocated objects $a1,a2,a3,\ldots$
are moved by the garbage collector, $x$
has to be adjusted accordingly.  

For example, inductive variable elimination may transformed an array
indexing into a running pointer to the middle of an array object.
Such running pointer is a derived value and is dependent on the 
starting address of the array. 

The main difficulty in handling a derived value $x$ 
during garbage collection is that sometimes it is impossible or 
counter-productive to recompute from $a1,a2,a3,\ldots$.
For example, when the recent branch history is unknown, or when the
precise relationship between $x$ and $a1,a2,a3,\ldots$ cannot
be inferred from context.  
We call these \newdef{unrecoverable} derived values.  
  \item[incomplete allocation]
   If heap allocation is performed inlined, then code motion may 
render some allocation incomplete at a gc safepoint.  In general, incomplete
allocation has to be completed, or rolled backed and then reexecuted
after garbage collection, when the source language semantics allow it.
\end{description}

Typically, two gc safepoints cannot be separated by an unbounded
number of allocations, which implies that in general, optimizations that move
instructions between basic blocks are unsafe when naively applied,
which greatly limits the class of optimizations in such an environment
to trivial basic block level optimizations. 
framework is a necessity.


\subsection{Safety Framework}
  MLRISC contains a gc-safety framework 
for performing aggressive machine level optimizations, including SSA-based
scalar optimizations, global instruction scheduling, and global
register allocation.  Unlike previous work in this area, phases that
perform optimizations and phases that maintain and update 
garbage collection information are completely separate, and the optimizer
is constructed in a fully modular manner.  In particular,
gc-types and safety constraints 
are \emph{parameterizable} 
by the source language semantics, the object representation, 
and the target architectures.  

This framework has the following overall structure:
\begin{description}
\item[Garbage collection invariants annotation]
The front-end client is responsible for annotating each 
value in the program with a \newdef{gc type}, which is 
used to specify the abstract object representation, 
and the constraints on code motion that may be applied to such a value.
The front-end uses an architecture independent \href{mltree.html}{RTL} 
language for representing the program, thus this annotation 
phase is portable between target architectures. 
\item[GC constraints propagation]
    After instruction selection, gc constraint are propagated throughout
the machine level program representation.  Again, for portability, gc typing
rules are specified in terms of the \href{mltree.html}{ RTL } of
the machine instructions.  In this phase, unsafe code motions which
exposes unrecoverable derived values to gc safepoints are automatically 
identified.   (Pseudo) control dependence and anti-control dependence 
constraints are then added the  program representation to prohibit all
gc-unsafe code motions.
\item[Machine level optimizations]
    After constraints propagation, traditional 
machine level optimizations such as
SSA optimizations and/or global scheduling are applied, without regard
to gc information.  This is safe because 
all gc safety constraints have been translated into the appropriate 
code motion constraints. 
\item[GC type propagation and gc code generation]
    GC type inference is performed when all optimizations
have been performed.  GC safepoints are then
identified and the root sets are determined.  In addition, compensation
code are inserted at gc points for repairing recoverable derived values.
\end{description}
\subsection{Concurrency Safety}
 In the presence of \newdef{concurrency}, i.e. multiple threads
of control that communicate via a shared heap, the above framework
will have to slightly extended.  As in before, we assume that
context switching can only occur at well-defined 
\emph{safepoints}.
The crucial aspect is that values that are live at safepoints must be
classified as \newdef{local} or \newdef{global}.
Local values are only observable from
the local thread, while global values are potentially observable and mutable
from other threads.  The invariants to maintain are as follows:
\begin{itemize}
 \item Only local and recoverable derived values may be live at a safepoint,  
 \item Only local and recoverable allocation may be incomplete at a safepoint
\end{itemize}
