deletions | additions
diff --git a/case-study.tex b/case-study.tex
index 464f33c..c3c9cc9 100644
--- a/case-study.tex
+++ b/case-study.tex
...
The source code of McVM is publicly available~\cite{mcvm}; after porting it from the LLVM legacy JIT to MCJIT, we have extended it with the following components to enable the optimization of \feval\ instructions:
\begin{enumerate}
\item An analysis pass to identify optimization opportunities for \feval\ instructions in the IIR
representation of a function
\item An extension for the IIR compiler to track the correspondence between IIR and IR objects at \feval\ sites
\item An inserter component to insert OSR points in the IR for IIR locations annotated during the analysis pass
\item An optimizer module triggered at OSR points, which in turn is made of:
...
The analysis pass is also able to determine whether the value of the argument can change across two executions of the same \feval\ instruction, thus discriminating when a run-time guard must be inserted during the run-time optimization phase. Compared to the OSR-based approach by Lameed and Hendren, our solution is cheaper because the types for the other arguments do not need to be cached or guarded: as we will see later on, the type inference engine will compute the most accurate yet sound type information in the analysis of the optimized IIR where direct calls are used.
When the IIR compiler processes an annotated \feval\ instruction, it
will store stores in the metadata of the function version being compiled
a copy of its the current variable map (i.e., a map between IIR and IR objects), the
current {\tt llvm::BasicBlock*} created for the
call \feval\ and the {\tt llvm::Value*} object corresponding to the first argument for the \feval. The last two objects are used by the inserter component as source label and
profiling value {\tt val} argument for inserting an open OSR
point, with the copy of the variable map being passed (along with other information) as {\tt extra} field. point. The open-OSR stub will in turn invoke the callback optimizer component we are about to
describe in the next subsection. present.
\subsection{Generating Optimized Code}
The core of our optimization pipeline is the
callback optimizer
component, module that is responsible for generating optimized code for the current function $f$ using
profiling (i.e., the
object containing run-time value of the first argument for
\feval) \feval and contextual information passed from the open-OSR stub. As a first step, the optimizer
will process the profiling object inspects {\tt val} to resolve the target of the call - which we call $g$ - and check whether a previously compiled optimized function is available from the code cache. If not, a new function $f_{opt}$ is generated by cloning the IIR representation $f^{IIR}$ of $f$ into
$f^{IIR}_{opt}$ and replacing all the \feval\ calls in the same group of the instrumented one with direct calls to $g$.
As a next step, the optimizer asks the IIR compiler to analyze $f^{IIR}_{opt}$ and generate optimized LLVM IR $f^{IR}_{opt}$, also making a copy of the variable map between IIR and IR objects when compiling the direct call corresponding to the \feval\ instruction that triggered the OSR.