Camil Demetrescu  over 8 years ago

Commit id: 07649654e2be396e5453654fd8ab2a8aac45e0c7

deletions | additions      

       

%The last two elements are then used by the inserter component as basic block and {\tt val} argument in the open-OSR stub that invokes the optimizer component.  \newcommand{\gBase}{$f$}  \newcommand{\gOpt}{$f_{opt}$}  \newcommand{\gIIR}{$f^{IIR}$}  \newcommand{\gIR}{$f^{IR}$}  \newcommand{\gOptIIR}{$f^{IIR}_{opt}$}  \newcommand{\gOptIR}{$f^{IR}_{opt}$} \newcommand{\fBase}{$f$}  \newcommand{\fOpt}{$f_{opt}$}  \newcommand{\fIIR}{$f^{IIR}$}  \newcommand{\fIR}{$f^{IR}$}  \newcommand{\fOptIIR}{$f^{IIR}_{opt}$}  \newcommand{\fOptIR}{$f^{IR}_{opt}$}  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%  \paragraph{Optimizer.}  The optimizer is called as {\tt gen} function in the open OSR stub (see \myfigure\ref{fi:overview-osr-open}) created by the OSR inserter. It receives the IR version \fIR\ of function $f$, the basic block of \fIR\ where the OSR was fired, and the native code address of the \feval\ target function $g$. As a first step, the optimizer looks up the IR code of $g$ by its address and checks whether a previously compiled version of \fBase\ specialized with $g$ was previously cached.  %The  core of our optimization pipeline is the optimizer module, which is responsible for generating optimized code for the running function \gBase\ \fBase\  using contextual information passed by an open-OSR stub. As a first step, the optimizer inspects {\tt val} to resolve the target $f$ $g$  of the \feval\ and checks whether a previously compiled version of \gBase\ \fBase\  optimized for $f$ is available from the cache. \ifdefined \fullver  If not, a new function \gOpt\ \fOptIIR\  is generated by cloning the IIR representation \gIIR\ \fIIR\  of \gBase\ into \gOptIIR\ \fBase\  and by  replacing all the \feval\ calls in the same group of the instrumented one with direct calls to $f$. \else  If not, a new function \gOpt\ \fOptIIR\  is generated by cloning the IIR representation \gIIR\ \fIIR\  of \gBase\ into \gOptIIR\ \fBase\  and by  replacing all \feval\ calls to $f$ $g$ in \fOptIIR\  with direct calls. \fi  As a next step, the optimizer asks the IIR compiler to process \gOptIIR\ \fOptIIR\  and generate optimized LLVM IR \gOptIR, \fOptIR,  also storing the variable map between IIR and IR objects when compiling the direct call corresponding to the \feval\ instruction that triggered the OSR. \ifdefined \fullver  \fi  This map is essential for the next step, which is constructing a state mapping between \gIR\ \fIR\  to \gOptIR, \fOptIR,  as it is compared against the corresponding map stored during the lowering of \gBase\ \fBase\  to determine whether for each value in \gOptIR\ \fOptIR\  live at the continuation block: \begin{itemize}  \item an {\tt llvm::Value*} from \gIR\ \fIR\  passed as argument at the OSR point can be used directly \item or, compensation code is required to reconstruct its value before jumping to the block.  \end{itemize}  \noindent In fact, since the type inference engine yields more accurate results for \gOptIIR\ \fOptIIR\  compared to \gIIR, \fIIR,  the IIR compiler can in turn generate efficient specialized IR code for representing and manipulating IIR variables, and compensation code is typically required to unbox or downcast some of the live values passed at the OSR point. \ifdefined \fullver  Compensation code might also be required to materialize an IR object for an IIR variable that were previously accessed through get/set methods from the environment. %TODO  \fi