git » jacl.git » commit 32d03dc

paper

author Alan Dipert
2020-02-20 21:21:01 UTC
committer Alan Dipert
2020-02-20 21:21:01 UTC
parent c422152dacf0bc8b3d83f4a6515cc05799192103

paper

paper/jacl-els-2020.tex +78 -44

diff --git a/paper/jacl-els-2020.tex b/paper/jacl-els-2020.tex
index 041db8a..218b248 100644
--- a/paper/jacl-els-2020.tex
+++ b/paper/jacl-els-2020.tex
@@ -490,65 +490,71 @@ Clojure's \texttt{..} macro. \texttt{JACL:\textbackslash.} expands to
 zero or more nested \texttt{JACL:\%DOT} or \texttt{JACL:\%CALL}
 forms. Here is an example of a \texttt{JACL:\textbackslash.} form ---
 equivalent to the JavaScript expression
-\texttt{(123).toString().length} --- and its expansion:
+\texttt{(123).toString().length} --- and its corresponding expansion:
 
 \begin{verbatim}
 (\. 123 (|toString|) |length|)
-(%DOT (%CALL 123 |toString|) |length|) ; 3
+(%DOT (%CALL 123 |toString|) |length|)
 \end{verbatim}
 
 Note that JavaScript identifiers are case sensitive, and so
 case-preserving, pipe-delimited Lisp symbols must be used to refer to
-field and method names. The dot macro also can also recognize Lisp or
+field and method names. The dot macro also recognizes Lisp or
 JavaScript strings as JavaScript identifiers.
 
 \subsubsection{\texttt{TAGBODY} compilation strategy}
 
-JSCL implements \texttt{TAGBODY} as the combination of:
+JSCL, the existing Lisp closest to JACL, implements \texttt{TAGBODY}
+through the combination of:
 
 \begin{itemize}
+  \item Generating a unique identifier, the \texttt{tbidx}, for each
+    \texttt{TAGBODY} encountered during compilation.
   \item A local JavaScript \texttt{branch} variable containing the tag
     of the next branch to execute.
-  \item A labeled \texttt{while(true) { ... }} loop containing a
+  \item Labeled \texttt{while(true) { ... }} loops each containing a
     \texttt{try/catch} statement. The \texttt{catch} arm of the
     \texttt{try/catch} inspects the type of thrown exception, and if
-    it is of the marker type \texttt{TagNLX}, \texttt{branch} is set
-    to the tag carried by the \texttt{TagNLX} object. The \texttt{try}
-    arm of the \texttt{try/catch} contains a \texttt{switch} statement
-    that dispatches on \texttt{branch}. Each arm of the
-    \texttt{switch} corresponds to code associated with a \texttt{GO}
+    it is of the marker type \texttt{TagNLX} and corresponds to the
+    current \texttt{TAGBODY}, \texttt{branch} is set to the tag
+    carried by the \texttt{TagNLX} object. The \texttt{try} arm of the
+    \texttt{try/catch} contains a \texttt{switch} statement that
+    dispatches on \texttt{branch}. Each labeled block of the
+    \texttt{switch} corresponds to the code succeeding a \texttt{GO}
     tag. The \texttt{switch} falls through to a \texttt{break} to the
     enclosing labeled \texttt{while} loop, concluding execution of the
     \texttt{TAGBODY}.
   \item An implementation of \texttt{GO} that throws a JavaScript
-    exception of type \texttt{TagNLX} that contains the target tag.
+    exception of type \texttt{TagNLX} that contains \texttt{tbidx} and
+    target \texttt{branch} values.
 \end{itemize}
 
-This mechanism is ingenious and general. Unfortunately, every jump
+This mechanism is ingenious and general, and it's roughly how JACL
+also currently implements \texttt{TAGBODY}. Unfortunately, every jump
 requires a JavaScript exception be thrown, severely penalizing nearly
-every iteration construct in JSCL. Fortunately, a slight improvement
-in the \texttt{GO} compilation strategy can yield a tremendous
-performance benefit. The improvement follows from the observation that
-any \emph{local jump} --- such as from a \texttt{GO} form to its
-relevant \texttt{TAGBODY}, with no lexically-intervening
+every iteration construct. Fortunately, a slight improvement in the
+\texttt{GO} compilation strategy can yield a tremendous performance
+benefit. The improvement follows from the observation that any
+\emph{local jump} --- such as that from a \texttt{GO} to its relevant
+enclosing \texttt{TAGBODY}, with no lexically-intervening
 \texttt{LAMBDA} forms --- may rely on JavaScript's
-\texttt{continue}\cite{MozLabel} operator with a label argument
-instead of on throwing an exception in order to transfer control.
-
-JACL's rich AST will facilitate the identification of usages of
-\texttt{GO} that are amenable to improvement. The availability of a
-high-level AST will also facilitate further optimizations, such as
-\texttt{GO} tag escape\footnote{Such as by use within a
-  \texttt{LAMBDA} form that is assigned as the value of a global
-  variable or passed to a function} analysis. It should be possible to
-identify \texttt{TAGBODY}s that consist only of local jumps, and to
-avoid generating \texttt{try/catch} boilerplate for them, thereby
-reducing generated code size.
+\texttt{continue}\cite{MozLabel} operator with a label argument for
+control transfer, instead of on throwing an exception.
+
+JACL's high-level AST will facilitate the identification of usages of
+\texttt{GO} that are amenable to the aforementioned optimization. The
+availability of a high-level AST will also facilitate other related
+optimizations, such as \texttt{GO} tag escape\footnote{Such as by use
+  within a \texttt{LAMBDA} form that is assigned as the value of a
+  global variable or passed to a function} analysis. It should be
+possible to identify \texttt{TAGBODY}s that consist only of local
+jumps, and to avoid generating \texttt{try/catch} boilerplate for
+them, thereby reducing generated code size.
 
 Code generated for \texttt{TAGBODY} in JACL will still generally
 require a \texttt{switch}, and so a slowdown relative to hand-coded
 JavaScript loops would not be unexpected. However, preliminary
-benchmarking \ref{appendix:benchmarks} of a factorial function on a
+benchmarking \ref{appendix:hypothetical} of a factorial function on a
 recent version of Google Chrome revealed only a very small discrepancy
 between JACL's proposed approach and a hand-coded JavaScript
 \texttt{while} loop-based approach.
@@ -647,7 +653,13 @@ beautiful wife, Sandra Dipert, for her skillful editing.
 \appendix
 
 \section{Loop Performance Benchmarks}
-\label{appendix:benchmarks}
+
+\subsection{JavaScript Baseline}
+
+This is a simple JavaScript function for computing the factorial of a
+positive integer as efficiently as possible. Its performance is
+considered baseline for the purposes of benchmarking JACL's
+\texttt{TAGBODY}.
 
 \begin{verbatim}
 function fact1(n) {
@@ -656,6 +668,39 @@ function fact1(n) {
   return prod;
 }
 
+var start = performance.now();
+for (var i = 0; i < 1e8; i++) fact1(20);
+console.log("fact1", performance.now() - start);
+// fact1 1860.9749999595806
+\end{verbatim}
+
+\subsection{Equivalent Lisp}
+
+The following is an analagous Common Lisp factorial
+function. \texttt{TAGBODY} is the means of iteration. This function
+cannot currently be compiled by JACL because \texttt{SETF},
+\texttt{DECF}, and \texttt{RETURN-FROM} are not yet implemented.
+
+\begin{verbatim}
+(defun fact2 (n &aux (prod 1))
+  (tagbody
+    start
+    (when (zerop n) (go done))
+    (setf prod (* prod n))
+    (decf n)
+    (go start)
+    done
+    (return-from fact2 prod)))
+\end{verbatim}
+
+\subsection{Hypothetical Generated Code}
+\label{appendix:hypothetical}
+
+The following is the hypothetical output for a future version of the
+JACL compiler that implements a \texttt{continue}-based strategy for
+efficient control transfer.
+
+\begin{verbatim}
 function GoTag(tag) {
   this.tag = tag;
   return this;
@@ -688,19 +733,8 @@ function fact2(n) {
   }
 }
 
-var start;
-
-start = performance.now();
-for (var i = 0; i < 1e8; i++) {
-  fact1(20);
-}
-console.log("fact1", performance.now() - start);
-// fact1 1860.9749999595806
-
-start = performance.now();
-for (var i = 0; i < 1e8; i++) {
-  fact2(20);
-}
+var start = performance.now();
+for (var i = 0; i < 1e8; i++) fact2(20);
 console.log("fact2", performance.now() - start);
 // fact2 1981.7150000017136
 \end{verbatim}