\item The thread is preempted.
\end{itemize}
-A world-switch (i.e. when compiled code encounters interpreted code,
-and vice-versa) can happen in six ways:
-
-\begin{itemize}
-\item A GHC thread enters a Hugs-built thunk.
-\item A GHC thread calls a Hugs-compiled function.
-\item A GHC thread returns to a Hugs-compiled return address.
-\item A Hugs thread enters a GHC-built thunk.
-\item A Hugs thread calls a GHC-compiled function.
-\item A Hugs thread returns to a Hugs-compiled return address.
-\end{itemize}
-
A running system has a global state, consisting of
\begin{itemize}
\section{Evaluation}
+This section describes the framework in which compiled code evaluates
+expressions. Only at certain points will compiled code need to be
+able to talk to the interpreted world; these are discussed in Section
+\ref{sec:hugs-ghc-interaction}.
+
\subsection{Calling conventions}
\subsubsection{The call/return registers}
@
case x of (a,b) -> E
@
-In a stack-based evaluator such as the STG machine,
-a @case@ expression is evaluated by pushing a {\em return address} on the stack
-before evaluating the scrutinee (@x@ in this case). Once evaluation of the
-scrutinee is complete, execution resumes at the return address, which
-points to the code for the expression @E@.
+
+The code for a @case@ expression looks like this:
+
+\begin{itemize}
+\item Push the free variables of the branches on the stack (fv(@E@) in
+this case).
+\item Push a \emph{return address} on the stack.
+\item Evaluate the scrutinee (@x@ in this case).
+\end{itemize}
+
+Once evaluation of the scrutinee is complete, execution resumes at the
+return address, which points to the code for the expression @E@.
When execution resumes at the return point, there must be some {\em
return convention} that defines where the components of the pair, @a@
heap.
When passing an unboxed tuple to a function, the components are
-flattened out and passed on the stack/in registers as usual.
+flattened out and passed in \Arg{1} \ldots \Arg{n} as usual.
\end{itemize}
@
data Maybe a = Nothing | Just a
@
-How does the return convention encode which of the two constructors is being returned?
-A @case@ expression scrutinising a value of @Maybe@ type would look like this:
+How does the return convention encode which of the two constructors is
+being returned? A @case@ expression scrutinising a value of @Maybe@
+type would look like this:
@
case E of
Nothing -> ...
The code at the return address will test the tag and jump to the
appropriate code for the case branch.
-\ToDo{Decide whether it's better to load the tag into \Arg{2} or not.
-May be affected by whether \Arg{2} is a real register.}
-
The choice of whether to use a vectored return or a direct return is
made on a type-by-type basis --- up to a certain maximum number of
constructors imposed by the update mechanism
(section~\ref{sect:data-updates}).
+Single-constructor data types also use direct returns, although in
+that case there is no need to return a tag in \Arg{2}.
+
\ToDo{Say whether we pop the return address before returning}
+\ToDo{Stack stubbing?}
+
\subsection{Updates}
\label{sect:data-updates}
\item The update frame is still on the stack.
\end{itemize}
+We can safely share a single statically-compiled update function
+between all types. However, the code must be able to handle both
+vectored and direct-return datatypes. This is done by arranging that
+the update code looks like this:
+
+@
+ | ^ |
+ | return vector |
+ |---------------|
+ | fixed-size |
+ | info table |
+ |---------------| <- update code pointer
+ | update code |
+ | v |
+@
+
+Each entry in the return vector (which is large enough to cover the
+largest vectored-return type) points to the update code.
+
The update code:
\begin{itemize}
\item overwrites the {\em updatee} with an indirection to \Arg{1};
\item enters \Arg{1}.
\end{itemize}
-This update code is the same for all data types, and can therefore be
-compiled statically in the runtime system.
-
-Since Haskell is polymorphic, we sometimes have to compile code for
-updatable thunks without knowing the type that will be returned. In
-this case, the update frame must work for both direct and vectored
-returns. This requires that we generate an infotable containing both
-a valid direct return address (which will perform the update and then
-perform a direct return) and a valid return vector (each entry of
-which will perform the update and then perform a vectored return).
-
+We enter \Arg{1} again, having probably just come from there, because
+it knows whether to perform a direct or vectored return. This could
+be optimised by compiling special update code for each slot in the
+return vector, which performs the correct return.
\subsection{Semi-tagging}
\label{sect:semi-tagging}
May have to revert black holes - ouch!
@
+\section{Switching Worlds}
+\label{sect:switching-worlds}
+
+Because this is a combined compiled/interpreted system, the
+interpreter will sometimes encounter compiled code, and vice-versa.
+
+All world-switches go via the scheduler, ensuring that the world is in
+a known state ready to enter either compiled code or the interpreter.
+When a thread is run from the scheduler, the @whatNext@ field is
+checked to find out how to execute the thread.
+
+\begin{itemize}
+\item If @whatNext@ is set to @RunGHC@, we load up the required
+registers from the TSO and jump to the address at the top of the user
+stack.
+\item If @whatNext@ is set to @RunHugs@, we execute the byte-code
+object pointed to by the top word of the stack.
+\end{itemize}
+
+Sometimes instead of returning to the address at the top of the stack,
+we need to enter a closure instead. This is achieved by pushing a
+pointer to the closure to be entered on the stack, followed by a
+pointer to a canned code sequence called @ghc_entertop@, or the dual
+byte-code object @hugs_entertop@. Both code sequences do the following:
+
+\begin{itemize}
+\item pop the top word (either @ghc_entertop@ or @hugs_entertop@) from
+the stack.
+\item pop the next word off the stack and enter it.
+\end{itemize}
+
+There are six cases we need to consider:
+
+\begin{enumerate}
+\item A GHC thread enters a Hugs-built closure.
+\item A GHC thread calls a Hugs-compiled function.
+\item A GHC thread returns to a Hugs-compiled return address.
+\item A Hugs thread enters a GHC-built closure.
+\item A Hugs thread calls a GHC-compiled function.
+\item A Hugs thread returns to a Hugs-compiled return address.
+\end{enumerate}
+
+We now examine the various cases one by one and describe how the
+switch happens in each situation.
+
+\subsection{A GHC thread enters a Hugs-built closure}
+
+All Hugs-built closures look like this:
+
+\begin{center}
+\begin{tabular}{|l|l|}
+\hline
+\emph{Hugs} & \emph{Hugs-specific payload} \\
+\hline
+\end{tabular}
+\end{center}
+
+\noindent where \emph{Hugs} is a pointer to a small statically
+compiled-piece of code that does the following:
+
+\begin{itemize}
+\item Push the address of this thunk on the stack.
+\item Push @hugs_entertop@ on the stack.
+\item Save the current state of the thread in the TSO.
+\item Return to the scheduler, with @whatNext@ set to @RunHugs@.
+\end{itemize}
+
+\ToDo{What about static thunks? If all code lives on the heap, we'll
+need an extra level of indirection for GHC references to Hugs
+closures.}
+
+\subsection{A GHC thread calls a Hugs-compiled function}
+
+In order to call the fast entry point for a function, GHC needs arity
+information from the defining module's interface file. Hugs doesn't
+supply this information, so GHC will always call the slow entry point
+for functions in Hugs-compiled modules.
+
+When a GHC module is linked into a running system, the calls to
+external Hugs-compiled functions will be resolved to point to
+dynamically-generated code that does the following:
+
+\begin{itemize}
+\item Push a pointer to the Hugs byte code object for the function on
+the stack.
+\item Push @hugs_entertop@ on the stack.
+\item Save the current thread state in the TSO.
+\item Return to the scheduler with @whatNext@ set to @RunHugs@
+\end{itemize}
+
+Ok, but how does Hugs find the byte code object for the function?
+These live on the heap, and can therefore move around. One solution
+is to use a jump table, where each element in the table has two
+elements:
+
+\begin{itemize}
+\item A call instruction pointing to the code fragment above.
+\item A pointer to the byte-code object for the function.
+\end{itemize}
+
+When GHC jumps to the address in the jump table, the call takes it to
+the statically-compiled code fragment, leaving a pointer to a pointer
+to the byte-code object on the C stack, which can then be retrieved.
+
+\subsection{A GHC thread returns to a Hugs-compiled return address}
+
+When Hugs pushes return addresses on the stack, they look like this:
+
+@
+ | |
+ |_______________|
+ | | -----> bytecode object
+ |_______________|
+ | | _____
+ |_______________| |
+ | _____
+ | | | Info Table
+ | | |
+ |_____\ |____| hugs_return
+ / . .
+ . . Code
+ . .
+@
+
+If GHC is returning, it will return to the address at the top of the
+stack. This address a pointer to a statically compiled code fragment
+called @hugs_return@, which:
+
+\begin{itemize}
+\item pops the return address off the user stack.
+\item saves the thread state in the TSO
+\item returns to the scheduler with @whatNext@ set to @RunHugs@.
+\end{itemize}
+
+\subsection{A Hugs thread enters a GHC-compiled closure}
+
+When Hugs is called on to enter a GHC closure (these are recognisable
+by the lack of a \emph{Hugs} pointer at the front), the following
+sequence of instructions is executed:
+
+\begin{itemize}
+\item Push the address of the thunk on the stack.
+\item Push @ghc_entertop@ on the stack.
+\item Save the current state of the thread in the TSO.
+\item Return to the scheduler, with the @whatNext@ field set to
+@RunGHC@.
+\end{itemize}
+
+\subsection{A Hugs thread calls a GHC-compiled function}
+
+Hugs never calls GHC-functions directly, it only enters closures
+(which point to the slow entry point for the function). Hence in this
+case, we just push the arguments on the stack and proceed as above.
+
+\subsection{A Hugs thread returns to a GHC-compiled return address}
+
+The return address at the top of the stack is recognisable as a
+GHC-return address by virtue of not being @hugs_return@. In this
+case, hugs recognises that it needs to do a world-switch and performs
+the following sequence:
+
+\begin{itemize}
+\item save the state of the thread in the TSO.
+\item return to the scheduler, setting @whatNext@ to @RunGHC@.
+\end{itemize}
\section{Heap objects}
\label{sect:fixed-header}