epsilon-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[epsilon-devel] [Patch] Integrating Jitter as a sub-package in Poke: fir


From: Luca Saiu
Subject: [epsilon-devel] [Patch] Integrating Jitter as a sub-package in Poke: first iteration
Date: Sun, 15 Sep 2019 20:34:12 +0200
User-agent: Gnus (Gnus v5.13), GNU Emacs 25.1.50.2, x86_64-unknown-linux-gnu

Hello José.

Last night I committed sub-package mode in Jitter, and rebased to
master:
  
http://ageinghacker.net/git/cgit.cgi/jitter/commit/?id=d2eb00486f118a60ce1677360237127d982cba00

As promised I ported Poke to the latest Jitter, switching from Jitter as
a dependency to Jitter as a sub-package.  You can find the first
iteration of the changes attached here.

Please tell me what you think, José.  Before going further and cleaning
up the changes with a ChangeLog entry, let me add a few remarks:

a) I have changed "program" to "routine" in the context of the Poke VM,
   whenever I came across to that in comments.  It could probably be
   done in a more systematic way; tell me if I should go ahead.
   I have updated HACKING to introduce the idea of non-executable and
   executable routine, which has become important now.

b) In this context, I had to make a choice in several data structures
   of yours which used to hold "program" pointers from an older Jitter.
   The old programs have turned into "routines", sometimes non-executable,
   sometimes executable.
   Non-executable routines are used at code generation time; from a
   non-executable routine you can obtain an executable routine (which
   can be no longer edited, but is in an efficient dispatch-dependent
   form suitable for, well, execution).
   Each non-executable routine has a field pointing to its executable
   counterpart, and vice-versa, so apart from efficiency, you could
   have both but keep a pointer to either one, in every context.
   Non-executable and executable routine can be destroyed independently,
   and the destruction functions provided by Jitter update the pointer
   fields as appropriate to avoid dangling references: for example if
   you destroy an executable routine when its non-executable version
   still exists, the pointer from non-executable to executable becomes
   NULL.
   You make an executable routine from a non-executable routine by using
   (with your VM prefix)
     pvm_make_executable_routine
   , which is the new name of
     pvm_specialize_program
   . The important API difference is that now this function has a
   result.
   Now, which kind of routine shall I use in your own data structures?
   I decided in favor of executable routines almost in every case, to
   avoid a pointer dereference before execution, which may or may not
   matter for performance.  The one exception is the Poke assembler.
   I think I have been consistent with variable and field names.

c) I have not carefully checked the build dependencies ensuring jitter
   (the code generator) is built.  An explicit
     $(MAKE) -C jitter/
   may be needed somewhere.

d) I have not touched the build system code selecting a Jitter dispatch;
   however this is no longer needed, and can be removed.

This is off-topic for the change set:

e) I really think you should keep your C files generated by Jitter into
   the source directory.  This will make cross-compilation easy.

f) I saw that you copied autoconf/jitter.a4 from the Jitter distribution
   into acinclude.m4 .  I updated your copy with the new version, however
   I think you should switch to using AC_CONFIG_MACRO_DIRS and distribute
   unrelated Autoconf macro sets in different files, as recommended by
   the Automake manual (§"Handling Local Macros").  This will make
   integration easier if you include other Autoconf macro files, or add
   your own.

In any case Poke's test suite passes with no failures.  I normally use a
separate build directory.

Incidentally, Jitter's test suite will run as a side effect of running
Poke's test suite.  I find this slightly annoying as Jitter's test suite
takes some time even with only one dispatch enabled, and I think I will
prevent this behavior by default.  This is a forthcoming change in
Jitter, which should not require any modification on your side.

Is all of this okay?


For any interested people who might not know the context of our private
sub-package discussion, this presentation introduces the problem:
  http://ageinghacker.net/talks/nesting-slides--saiu--ghm2019--2019-09-06.pdf

Regards,

-- 
Luca Saiu
* My personal web site:  http://ageinghacker.net
* GNU epsilon:           http://www.gnu.org/software/epsilon
* Jitter:                http://ageinghacker.net/projects/jitter

I support everyone's freedom of mocking any opinion or belief, no
matter how deeply held, with open disrespect and the same unrelented
enthusiasm of a toddler who has just learned the word "poo".
diff --git a/HACKING b/HACKING
index e65d6ed..146d481 100644
--- a/HACKING
+++ b/HACKING
@@ -58,7 +58,7 @@ along with GNU poke.  If not, see 
<https://www.gnu.org/licenses/>.
      7  Memory Management
        7.1  Using ASTREF
        7.2  Using ASTDEREF
-       7.3  PVM values in PVM programs
+       7.3  PVM values in PVM routines
        7.4  PVM values in AST nodes
      8  Debugging Poke
        8.1  Building with Debugging support
@@ -663,48 +663,64 @@ This works because ``pkl_ast_make_xxx`` does an 
``ASTREF`` to ``b``
 internally.  The final result is that the reference counter of ``b``
 doesn't change at all.
   
-PVM values in PVM programs
+PVM values in PVM routines
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The PVM programs (data structures of type ``pvm_program``) are
-allocated by Jitter, using ``malloc``.  Therefore, they are not
-traversed by the GC.
-
-Now, the instructions in a program can contain literal PVM values, and
+Jittery VMs represents code as sequences of assembly-like
+instructions called *routines*.  Routines exist in two forms:
+*non-executable routines* or simply *routines*, used at the time
+of code generation and optimization, and *executable routines*,
+meant for actual code execution.
+Each routine begins its life as non-executable, then is translated
+into a executable version, whose internal representation, meant
+for efficient execution, is dispatch- and usually also
+hardware-dependent.
+
+Non-executable routines can be destroyed after code generation,
+but Poke currently keeps them around to aid debugging.  Disassembly,
+in particular, relies on both forms being available.
+When a routine exists in both non-executable and executable form,
+it is always possible to reach one from the other.
+
+PVM executable routines (data structures of type
+``pvm_executable_routine``) are allocated by Jitter, using ``malloc``.
+Therefore, they are not traversed by the GC.
+
+Now, VM instructions in a routine can contain literal PVM values, and
 some of these values will be boxed.  For example, the following
-program contains a pointer to a ``pvm_val_box``::
+routine contains a pointer to a ``pvm_val_box``::
 
   ;; Initialize the element index to 0UL, and put it
   ;; in a local.
   push ulong<64>0
   regvar $eidx
 
-There are two places where PVM programs are stored in other data
+There are two places where PVM executable routines are stored in other data
 structures: in closures, and in the compiler.
 
 A closure is a kind of PVM value itself, and therefore allocated by
-the GC.  It is composed by a PVM program, a run-time environment and
-an entry point into the program::
+the GC.  It is composed by a PVM executable routine, a run-time
+environment and an entry point into the routine::
 
   struct pvm_cls
   {
-    struct jitter_program *program;
+    struct jitter_executable_routine *erout;
     const void *entry_point;
     struct pvm_env *env;
   };
 
-However, since ``program`` is malloc-allocated, the GC can't traverse
-it.  Consequently, the references to contained boxed values won't be
-accounted, and these values will be collected if there are no more
-refences to them!
+However each ``erout`` points to malloc-allocated memory which the GC
+cannot automaticall traverse.  Consequently, the references to contained
+boxed values won't be accounted for, and these values will be collected if
+there are no more refences to them!
 
 The solution, recommended by Luca Saiu, is to keep an array of
 pointers in the closure structure, containing the pointers to every
-boxed value used in ``program``::
+boxed value used in ``erout``::
 
   struct pvm_cls
   {
-    struct jitter_program *program;
+    struct jitter_executable_routine *erout;
     void **pointers;
     const void *entry_point;
     struct pvm_env *env;
@@ -715,12 +731,12 @@ macro-assembler in ``pkl-asm.c``.  ``pkl_asm_finish`` 
will return the
 array of pointers, and it is up to the caller (in the code generator)
 to install it the corresponding closure structure.
 
-The second place where a PVM program is stored in other data
+The second place where a PVM routine is stored in other data
 structures is the compiler functions ``pkl_compile_file`` and
-``pkl_compile_buffer``.  In both functions, the compiled PVM program
+``pkl_compile_buffer``.  In both functions, the compiled PVM routine
 is executed and then discarded.  However, it is still required to have
-the ``pointers`` array linked from the C stack, to avoid the GC to
-collect the values from the program.  That's the purpose of the weird
+the ``pointers`` array linked from the C stack, to prevent the GC from
+collecting the values from the routine.  That's the purpose of the weird
 local variables, which are set but never used::
 
   int
@@ -729,12 +745,12 @@ local variables, which are set but never used::
   {
     ...
     /* Note that the sole purpose of `pointers' is to serve as a root
-       (in the stack) for the GC, to prevent the boxed values in PROGRAM
+       (in the stack) for the GC, to prevent the boxed values in ROUTINE
        to be collected.  Ugly as shit, but conservative garbage
        collection doesn't really work.  */
     void *pointers;
     ...
-    program = rest_of_compilation (compiler, ast, &pointers);
+    routine = rest_of_compilation (compiler, ast, &pointers);
     ...
   }
 
diff --git a/Makefile.am b/Makefile.am
index 2e1f7b9..da23157 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,2 +1,2 @@
 ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = lib pickles src doc testsuite
+SUBDIRS = jitter lib pickles src doc testsuite
diff --git a/acinclude.m4 b/acinclude.m4
index ad0a10c..1c1fbbe 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -1,5 +1,5 @@
 # Autoconf macros for Jitter.
-# Copyright (C) 2017, 2018 Luca Saiu
+# Copyright (C) 2017, 2018, 2019 Luca Saiu
 # Written by Luca Saiu
 
 # This file is part of Jitter.
@@ -129,26 +129,73 @@ m4_define([jitter_flags],
 # This is only used internally.  If Automake is being used, then define
 # the shell variable ac_jitter_using_automake to "yes".
 AC_DEFUN([AC_JITTER_USING_AUTOMAKE], [
-# Define ac_jitter_using_automake to a non-empty iff the configuration system 
is
-# used Automake and well, and not just Autoconf.  I have found no documented 
way
-# of doing this, so I am relying on am__api_version being defined, which
-# happens, indirectly, when AM_INIT_AUTOMAKE is called.
+# Define ac_jitter_using_automake to a non-empty value iff the configuration
+# system is used Automake and well, and not just Autoconf.  I have found no
+# documented way of doing this, so I am relying on am__api_version being
+# defined, which happens, indirectly, when AM_INIT_AUTOMAKE is called.
 # This is not particularly related to Jitter but I found no predefined way
-# of doing it, and I'm adding the variable to the Jitter namespace just so as
-# not to pollute the generic ones.
+# of doing it, and I'm adding the variable to the AC_JITTER namespace just
+# to prevent conflicts.
 if test "x$am__api_version" != "x"; then
   ac_jitter_using_automake="yes"
 fi
 ]) # AC_JITTER_USING_AUTOMAKE
 
 
+# Sub-packages to be configured immediately, not on AC_OUTPUT.
+################################################################
+
+# AC_JITTER_CONFIG_SUBDIRS_NOW([dir ...])
+# ---------------------------------------
+# Behave like AC_CONFIG_SUBDIRS , but call the recursive configure immediately
+# rather that at the time of AC_OUTPUT.  A final explicit AC_OUTPUT call by
+# the user will still be required, as usual.
+#
+# Rationale: If the sub-package is configured immediately, the rest of
+# the outer package configure script can make its configuration depend
+# on the inner package.
+AC_DEFUN([AC_JITTER_CONFIG_SUBDIRS_NOW], [
+# Keep a backup of some shell variables used by configure at AC_OUTPUT time to
+# handle generated files and subdirectories.  Then clean up the current values
+# of these variables so that AC_OUTPUT *only* deals with the subpackage.
+jitter_ac_config_files_backup="${ac_config_files}"
+jitter_subdirs_backup="${subdirs}"
+ac_config_files=''
+subdirs=''
+# Add the sub-package the ordinary way, and output.  This has the effect of
+# configuring the sub-package.
+AC_CONFIG_SUBDIRS([$1])
+AC_MSG_NOTICE([recursively invoking configure in sub-package] [$1] [right now])
+# Here we could use AC_OUTPUT and then remove config.status , which should
+# not be generated here as that would introduce subtle bugs in case the user
+# forgot to call AC_OUTPUT at the end.
+# But instead of using AC_OUTPUT we can use its supposedly internal subroutine
+# _AC_OUTPUT_SUBDIRS, which *only* deals with sub-packages.  This is exactly
+# what we need.
+_AC_OUTPUT_SUBDIRS
+AC_MSG_NOTICE([back from the recursive configuration in] [$1])
+# Restore the shell variables we saved later, so that a user call to
+# AC_OUTPUT later will do its work.  The sub-package we have configured
+# already will not be configured again.
+ac_config_files="${jitter_ac_config_files_backup}"
+subdirs="${jitter_subdirs_backup}"
+]) # AC_JITTER_CONFIG_SUBDIRS_NOW
+
+
 # Jitter exported Autoconf macros.
 ################################################################
 
 # AC_JITTER_CONFIG
 # ----------------
-# Look for the jitter-config script, by default in $PATH or, if the option
-# --with-jitter="PREFIX" is given, in PREFIX/bin (only).
+# Look for the jitter-config script:
+# * if the option --with-jitter="PREFIX" is given, in PREFIX/bin (only);
+# * if the shell variable JITTER_SUBPACKAGE is defined as a non-empty
+#   value, in ${JITTER_SUBPACKAGE}/bin relative to the super-package
+#   build directory;
+# * otherwise, in $PATH;
+#
+# Choose the default dispatch, using --with-jitter-dispatch="DISPATCH" or
+# the best available dispatch if the option is not given.
 #
 # Define the substitution JITTER_CONFIG to either the full pathname of a
 # jitter-config script which appears to be working, or nothing in case of
@@ -163,12 +210,16 @@ fi
 #                               dashes separating words, one space separating
 #                               dispatch names);
 # * JITTER_BEST_DISPATCH       (the best dispatch in JITTER_DISPATCHES);
-# * for every dispatching model $D (in all caps, with underscores separating
-#   words):
-#   - JITTER_$D_CFLAGS         (CFLAGS for using $D);
-#   - JITTER_$D_CPPFLAGS       (CPPFLAGS for using $D);
-#   - JITTER_$D_LDADD          (LDADD for using $D);
-#   - JITTER_$D_LDFLAGS        (LDFLAGS for using $D).
+# * JITTER_DEFAULT_DISPATCH    (the dispatch chosen by default);
+# * JITTER_CFLAGS              (CFLAGS with the default dispatch);
+# * JITTER_CPPFLAGS            (CPPFLAGS with the default dispatch);
+# * JITTER_LDADD               (LDADD with the default dispatch);
+# * JITTER_LDFLAGS             (LDFLAGS with the default dispatch);
+# * for every dispatch $D (in all caps, with underscores separating words):
+#   - JITTER_$D_CFLAGS         (CFLAGS with dispatch $D);
+#   - JITTER_$D_CPPFLAGS       (CPPFLAGS with dispatch $D);
+#   - JITTER_$D_LDADD          (LDADD with dispatch $D);
+#   - JITTER_$D_LDFLAGS        (LDFLAGS with dispatch $D).
 #
 # When Automake is used, also define the following Automake conditionals
 # for each dispatching model $D (in all caps, with underscores separating
@@ -198,19 +249,52 @@ fi
 # path with "/bin" appended, or $PATH.
 AC_ARG_WITH([jitter],
             [AS_HELP_STRING([--with-jitter="PREFIX"],
-               [use the jitter program from the bin directory of the given
-                prefix instead of searching for it in $PATH])],
+               [use the jitter and jitter-config programs from the bin
+                directory of the given prefix instead of searching for
+                it in $PATH.
+                This is intended for using an installed Jitter as a
+                dependency; for a sub-package Jitter do not use this, and
+                instead just export and set the shell variable
+                JITTER_SUBPACKAGE to a non-empty value different
+                from "no" (this is normally done in the super-package via
+                the Autoconf macro provided with Jitter)])],
             [ac_jitter_path="$withval/bin"])
 
+# Define ac_jitter_path from JITTER_SUBPACKAGE, if Jitter is being
+# used in sub-package mode.  From the point of view of prefixes, this is
+# functionally equivalent to --with-jitter .
+if test "x$JITTER_SUBPACKAGE" != 'x' \
+   && test "x$JITTER_SUBPACKAGE" != 'xno'; then
+  if test "x$ac_jitter_path" != 'x'; then
+    # Using --with-jitter together with JITTER_SUBPACKAGE is a
+    # contradiction.
+    AC_MSG_ERROR([Enabling sub-package mode with JITTER_SUBPACKAGE is
+                  incompatible with the --with-jitter option])
+  else
+    # Using sub-package mode, when --with-jitter was not given.  Set the
+    # path variable.
+    # REMARK: ac_pwd is undocumented.  Is there a cleaner alternative to
+    #         find the build directory at configure time?
+    ac_jitter_path="${ac_pwd}/${JITTER_SUBPACKAGE}/bin"
+  fi
+fi
+
 # Search for the "jitter-config" script and perform the JITTER_CONFIG
 # substitution.
-AC_PATH_PROG([JITTER_CONFIG],
-             [jitter-config],
-             ,
-             [$ac_jitter_path])
+if test "x$ac_jitter_path" = 'x'; then
+  # Search in $PATH (only).
+  AC_PATH_PROG([JITTER_CONFIG],
+               [jitter-config])
+else
+  # Search in $ac_jitter_path (only).
+  AC_PATH_PROG([JITTER_CONFIG],
+               [jitter-config],
+               ,
+               [$ac_jitter_path])
+fi
 
 # However jitter-config was found, verify that it can be used; if not, unset 
the
-# JITTER_CONFIG variable (and substitution).
+# JITTER_CONFIG variable (and its substitution).
 AS_IF([test "x$JITTER_CONFIG" = "x"],
         [AC_MSG_NOTICE([can't find jitter-config])],
       [! test -r "$JITTER_CONFIG"],
@@ -223,6 +307,24 @@ AS_IF([test "x$JITTER_CONFIG" = "x"],
         [AC_MSG_WARN([non-working jitter-config at $JITTER_CONFIG])
          JITTER_CONFIG=""])
 
+# Provide an option for the user to explicitly choose a default dispatching
+# model.  Decide on the default dispatch at this point, either using the option
+# or choosing the best.
+# ac_jitter_default_dispatch will be defined as the dispatching model in lower
+# case with dashes separating words.  Default flag variables will refer to the
+# selected dispatching model.
+# If the requested dispatch is not avaiable the variable will be redefined 
later
+# to use the best, with a warning.
+AC_ARG_WITH([jitter-dispatch],
+            [AS_HELP_STRING([--with-jitter-dispatch="DISPATCH"],
+               [use the given dispatching model (either one given by
+                jitter-config --dispatches or "best", which is the default)
+                for the default jitter flag variables; if the requested
+                dispatch is not available in the current Jitter
+                configuration warn and use the best])],
+            [ac_jitter_default_dispatch="$withval"],
+            [ac_jitter_default_dispatch="best"])
+
 # Define the Automake conditional JITTER_HAVE_JITTER_CONFIG , if we are using
 # Automake.
 if test "x$ac_jitter_using_automake" != "x"; then
@@ -241,17 +343,34 @@ if test "x$JITTER_CONFIG" != "x"; then
   # Define the list of enabled dispatching models.
   AC_SUBST([JITTER_DISPATCHES],
            [$("$JITTER_CONFIG" --dispatches)])
-  AC_MSG_NOTICE([the available Jitter dispatching models are 
$JITTER_DISPATCHES])
+  AC_MSG_NOTICE([the available Jitter dispatches are $JITTER_DISPATCHES])
 
-  # Define the best dispatching model.
+  # Define the best available dispatching model.
   AC_SUBST([JITTER_BEST_DISPATCH],
            [$("$JITTER_CONFIG" --best-dispatch)])
-  AC_MSG_NOTICE([the best Jitter dispatching model is $JITTER_BEST_DISPATCH])
+  AC_MSG_NOTICE([the best available Jitter dispatch is 
\"$JITTER_BEST_DISPATCH\"])
+
+  # Define the default dispatching model.  In case "best" was requested, 
replace
+  # it with the actual name.  If the dispatching model selected as default is
+  # not available warn, and use the best available.
+  if test "x$ac_jitter_default_dispatch" = "xbest"; then
+    ac_jitter_default_dispatch="$JITTER_BEST_DISPATCH"
+  elif ! "$JITTER_CONFIG" --has-dispatch="$ac_jitter_default_dispatch"; then
+    AC_MSG_WARN([the requested Jitter dispatch \
+\"$ac_jitter_default_dispatch\" is not available: choosing the best available \
+\"$JITTER_BEST_DISPATCH\" instead])
+    ac_jitter_default_dispatch="$JITTER_BEST_DISPATCH"
+  fi
+  AC_SUBST([JITTER_DEFAULT_DISPATCH],
+           [$ac_jitter_default_dispatch])
+  AC_MSG_NOTICE([the default Jitter dispatching model used here will be \
+\"$JITTER_DEFAULT_DISPATCH\"])
 
-  # Define flags for the best dispatching model.
+  # Define flags for the default dispatching model.
   jitter_for_flag([a_flag],
     [AC_SUBST([JITTER_]jitter_tocpp(a_flag),
-              [$("$JITTER_CONFIG" --a_flag)])])
+              [$("$JITTER_CONFIG" --dispatch="$JITTER_DEFAULT_DISPATCH" \
+                 --a_flag)])])
 
   # For every dispatch and flag define a substitution JITTER_$dispatch_$flag .
   jitter_for_dispatch([a_dispatch],
@@ -280,8 +399,8 @@ AC_LANG_POP([C])
 
 # AC_JITTER_C_GENERATOR
 # ---------------------
-# Look for jitter, the C code generator program in $PATH if the option
-# --with-jitter="PREFIX" is given, in DIRECTORY/bin (only).
+# Look for jitter, the C code generator program in $PATH, or if the option
+# --with-jitter="PREFIX" is given in PREFIX/bin (only).
 #
 # Substitute:
 # * JITTER                            (the jitter program full path, or empty
@@ -300,13 +419,20 @@ AC_REQUIRE([AC_PROG_CC])
 AC_REQUIRE([AC_JITTER_USING_AUTOMAKE])
 
 # Search for the "jitter" program and perform the JITTER substitution.
-AC_PATH_PROG([JITTER],
-             [jitter],
-             ,
-             [$ac_jitter_path:$PATH])
+if test "x$ac_jitter_path" = 'x'; then
+  # Search in $PATH (only).
+  AC_PATH_PROG([JITTER],
+               [jitter])
+else
+  # Search in $ac_jitter_path (only).
+  AC_PATH_PROG([JITTER],
+               [jitter],
+               ,
+               [$ac_jitter_path])
+fi
 
 # However jitter was found, verify that it can be used; if not, unset the 
JITTER
-# variable (and substitution).
+# variable (and its substitution).
 AS_IF([test "x$JITTER" = "x"],
         [AC_MSG_NOTICE([can't find jitter])],
       [! test -r "$JITTER"],
@@ -360,3 +486,50 @@ $JITTER_CONFIG_VERSION) and $JITTER (version 
$JITTER_VERSION)])
   fi
 fi
 ]) # AC_JITTER
+
+
+# AC_JITTER_SUBPACKAGE([subdirectory])
+# ------------------------------------
+# Configure Jitter in sub-package mode, using the Jitter source directory
+# from the given subdirectory relative to the super-package source directory.
+AC_DEFUN([AC_JITTER_SUBPACKAGE], [
+
+# Print one explicit message about what is about to happen.  Even Autoconf
+# experts might be surprised by the unusual configuration order, and it is good
+# to be explicit in case something happens.
+AC_MSG_NOTICE([configuring Jitter as a sub-package in ./$1])
+
+# Make sure that Jitter will be configured in sub-package mode.  Jitter's
+# configure script checks for this environment variable, as it is inconvenient
+# to call it with an additional command-line option when invoked recursively
+# from a super-package configure script.
+# The variable must be set to the Jitter source subdirectory, relative to the
+# super-package source directory.
+JITTER_SUBPACKAGE="$1"
+export JITTER_SUBPACKAGE
+
+# Call Jitter's configure script recursively, right now.
+AC_JITTER_CONFIG_SUBDIRS_NOW([$1])
+
+# Check for jitter-config .  Do not check for the jitter C generator: it will
+# not normally be available at configuration time, but it will be built.
+AC_JITTER_CONFIG
+
+# Fail if we failed to find jitter-config; this should not happen in 
sub-package
+# mode, after Jitter's subdirectory has been configured with success.
+if test "x$JITTER_CONFIG" = 'x'; then
+  AC_MSG_ERROR([could not find jitter-config in Jitter sub-package within
+                $JITTER_CONFIG])
+fi
+
+# The "jitter" C generator may not exist yet, but it can be built and its 
future
+# full path is known.
+JITTER="$(echo $JITTER_CONFIG | sed 's/-config$//')$EXEEXT"
+AC_SUBST([JITTER], [$JITTER])
+AC_MSG_NOTICE([jitter may not exist yet, but it can be built at $JITTER])
+
+# The C generator will have the same version as the jitter-config script.
+JITTER_VERSION="$JITTER_CONFIG_VERSION"
+AC_SUBST([JITTER_VERSION], [$JITTER_VERSION])
+
+]) # AC_JITTER_SUBPACKAGE
diff --git a/configure.ac b/configure.ac
index 134612a..1ad29dc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -62,13 +62,7 @@ PKG_CHECK_MODULES(BDW_GC,[bdw-gc])
 
 dnl Jitter
 
-AC_JITTER
-if test "x$JITTER" = "x"; then
-   AC_MSG_WARN([you need Jitter to regenerate C files])
-fi
-if test "x$JITTER_CONFIG" = "x"; then
-   AC_MSG_ERROR([you need jitter-config to compile])
-fi
+AC_JITTER_SUBPACKAGE([jitter])
 
 dnl We need to determine the endianness of the host system.  The
 dnl following macro is also supposed to work when cross-compiling.
diff --git a/src/pk-cmd.c b/src/pk-cmd.c
index 680d5f6..4ed2fcd 100644
--- a/src/pk-cmd.c
+++ b/src/pk-cmd.c
@@ -345,16 +345,16 @@ pk_cmd_exec_1 (char *str, struct pk_trie *cmds_trie, char 
*prefix)
                 case 'e':
                   {
                     /* Compile a poke program.  */
-                    pvm_program prog;
+                    pvm_executable_routine erout;
                     char *end;
                     char *program_string;
 
                     program_string = p;
-                    prog = pkl_compile_expression (poke_compiler,
-                                                   program_string, &end);
-                    if (prog != NULL)
+                    erout = pkl_compile_expression (poke_compiler,
+                                                    program_string, &end);
+                    if (erout != NULL)
                       {
-                        argv[argc].val.prog = prog;
+                        argv[argc].val.erout = erout;
                         match = 1;
 
                         argv[argc].type = PK_CMD_ARG_EXP;
@@ -563,7 +563,12 @@ pk_cmd_exec_1 (char *str, struct pk_trie *cmds_trie, char 
*prefix)
       if (argv[i].type == PK_CMD_ARG_EXP
           || argv[i].type == PK_CMD_ARG_DEF
           || argv[i].type == PK_CMD_ARG_STMT)
-        pvm_destroy_program (argv[i].val.prog);
+        {
+          pvm_routine rout = argv[i].val.erout->routine;
+          if (rout != NULL)
+            pvm_destroy_routine (rout);
+          pvm_destroy_executable_routine (argv[i].val.erout);
+        }
     }
   
   return ret;
diff --git a/src/pk-cmd.h b/src/pk-cmd.h
index 640e2ca..ac0135f 100644
--- a/src/pk-cmd.h
+++ b/src/pk-cmd.h
@@ -21,7 +21,7 @@
 
 #include <config.h>
 
-#include "pvm.h" /* For pvm_program */
+#include "pvm.h" /* For pvm_routine */
 #include "ios.h"
 
 enum pk_cmd_arg_type
@@ -37,9 +37,9 @@ enum pk_cmd_arg_type
 };
 
 #define PK_CMD_ARG_TYPE(arg) ((arg).type)
-#define PK_CMD_ARG_EXP(arg) ((arg).val.prog)
-#define PK_CMD_ARG_DEF(arg) ((arg).val.prog)
-#define PK_CMD_ARG_STMT(arg) ((arg).val.prog)
+#define PK_CMD_ARG_EXP(arg) ((arg).val.erout)
+#define PK_CMD_ARG_DEF(arg) ((arg).val.erout)
+#define PK_CMD_ARG_STMT(arg) ((arg).val.erout)
 #define PK_CMD_ARG_INT(arg) ((arg).val.integer)
 #define PK_CMD_ARG_ADDR(arg) ((arg).val.addr)
 #define PK_CMD_ARG_STR(arg) ((arg).val.str)
@@ -50,7 +50,7 @@ struct pk_cmd_arg
   enum pk_cmd_arg_type type;
   union
   {
-    pvm_program prog;
+    pvm_executable_routine erout;
     int64_t integer;
     ios_off addr;
     char *str;
diff --git a/src/pk-print.c b/src/pk-print.c
index afc76bf..ea38434 100644
--- a/src/pk-print.c
+++ b/src/pk-print.c
@@ -36,7 +36,7 @@ pk_cmd_print (int argc, struct pk_cmd_arg argv[], uint64_t 
uflags)
 {
   /* print EXP */
 
-  pvm_program prog;
+  pvm_executable_routine erout;
   pvm_val val;
   int pvm_ret;
   int base;
@@ -45,7 +45,7 @@ pk_cmd_print (int argc, struct pk_cmd_arg argv[], uint64_t 
uflags)
   assert (argc == 1);
   assert (PK_CMD_ARG_TYPE (argv[0]) == PK_CMD_ARG_EXP);
 
-  prog = PK_CMD_ARG_EXP (argv[0]);
+  erout = PK_CMD_ARG_EXP (argv[0]);
 
   /* Numeration base to use while printing values.  Default is
      decimal.  Command flags can be used to change this.  */
@@ -68,7 +68,7 @@ pk_cmd_print (int argc, struct pk_cmd_arg argv[], uint64_t 
uflags)
   if (uflags & PK_PRINT_F_MAP)
     pflags |= PVM_PRINT_F_MAPS;
   
-  pvm_ret = pvm_run (poke_vm, prog, &val);
+  pvm_ret = pvm_run (poke_vm, erout, &val);
   if (pvm_ret != PVM_EXIT_OK)
     goto rterror;
 
diff --git a/src/pk-vm.c b/src/pk-vm.c
index 67569e4..2776bcc 100644
--- a/src/pk-vm.c
+++ b/src/pk-vm.c
@@ -31,18 +31,18 @@ pk_cmd_vm_disas_exp (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
 {
   /* disassemble expression EXP.  */
 
-  pvm_program prog;
-  
+  pvm_executable_routine erout;
+
   assert (argc == 1);
   assert (PK_CMD_ARG_TYPE (argv[0]) == PK_CMD_ARG_EXP);
 
-  prog = PK_CMD_ARG_EXP (argv[0]);
+  erout = PK_CMD_ARG_EXP (argv[0]);
 
   if (uflags & PK_VM_DIS_F_NAT)
-    pvm_disassemble_program (prog, true,
-                             JITTER_OBJDUMP, NULL);
+    pvm_disassemble_executable_routine (erout, true,
+                                        JITTER_OBJDUMP, NULL);
   else
-    pvm_print_program (stdout, prog);
+    pvm_print_routine (stdout, erout->routine);
 
   return 1;
 }
@@ -54,7 +54,7 @@ pk_cmd_vm_disas_fun (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
 
   const char *fname;
   pkl_ast_node decl;
-  pvm_program prog;
+  pvm_executable_routine erout;
   int back, over;
   pvm_val val;
 
@@ -83,13 +83,13 @@ pk_cmd_vm_disas_fun (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
   val = pvm_env_lookup (runtime_env, back, over);
   assert (val != PVM_NULL);
 
-  prog = PVM_VAL_CLS_PROGRAM (val);
+  erout = PVM_VAL_CLS_ROUTINE (val);
 
   if (uflags & PK_VM_DIS_F_NAT)
-    pvm_disassemble_program (prog, true,
-                             JITTER_OBJDUMP, NULL);
+    pvm_disassemble_executable_routine (erout, true,
+                                        JITTER_OBJDUMP, NULL);
   else
-    pvm_print_program (stdout, prog);
+    pvm_print_routine (stdout, erout->routine);
   
   return 1;
 }
@@ -101,13 +101,13 @@ pk_cmd_vm_disas_map (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
 
   pvm_val exp;
   pvm_val mapper;
-  pvm_program program;
+  pvm_executable_routine erout;
 
   assert (argc == 1);
   assert (PK_CMD_ARG_TYPE (argv[0]) == PK_CMD_ARG_EXP);
 
-  program = PK_CMD_ARG_EXP (argv[0]);
-  if (pvm_run (poke_vm, program, &exp) != PVM_EXIT_OK)
+  erout = PK_CMD_ARG_EXP (argv[0]);
+  if (pvm_run (poke_vm, erout, &exp) != PVM_EXIT_OK)
     return 0;
 
   mapper = pvm_val_mapper (exp);
@@ -117,13 +117,13 @@ pk_cmd_vm_disas_map (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
       return 0;
     }
 
-  program = PVM_VAL_CLS_PROGRAM (mapper);
+  erout = PVM_VAL_CLS_ROUTINE (mapper);
 
   if (uflags & PK_VM_DIS_F_NAT)
-    pvm_disassemble_program (program, true,
-                             JITTER_OBJDUMP, NULL);
+    pvm_disassemble_executable_routine (erout, true,
+                                        JITTER_OBJDUMP, NULL);
   else
-    pvm_print_program (stdout, program);
+    pvm_print_routine (stdout, erout->routine);
 
   return 1;
 }
@@ -135,13 +135,13 @@ pk_cmd_vm_disas_writ (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
 
   pvm_val exp;
   pvm_val writer;
-  pvm_program program;
+  pvm_executable_routine erout;
 
   assert (argc == 1);
   assert (PK_CMD_ARG_TYPE (argv[0]) == PK_CMD_ARG_EXP);
 
-  program = PK_CMD_ARG_EXP (argv[0]);
-  if (pvm_run (poke_vm, program, &exp) != PVM_EXIT_OK)
+  erout = PK_CMD_ARG_EXP (argv[0]);
+  if (pvm_run (poke_vm, erout, &exp) != PVM_EXIT_OK)
     return 0;
 
   writer = pvm_val_writer (exp);
@@ -151,13 +151,13 @@ pk_cmd_vm_disas_writ (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
       return 0;
     }
 
-  program = PVM_VAL_CLS_PROGRAM (writer);
+  erout = PVM_VAL_CLS_ROUTINE (writer);
   
   if (uflags & PK_VM_DIS_F_NAT)
-    pvm_disassemble_program (program, true,
-                             JITTER_OBJDUMP, NULL);
+    pvm_disassemble_executable_routine (erout, true,
+                                        JITTER_OBJDUMP, NULL);
   else
-    pvm_print_program (stdout, program);
+    pvm_print_routine (stdout, erout->routine);
 
   return 1;
 }
diff --git a/src/pkl-asm.c b/src/pkl-asm.c
index dbbea21..1448e97 100644
--- a/src/pkl-asm.c
+++ b/src/pkl-asm.c
@@ -91,12 +91,12 @@ struct pkl_asm_level
 
    COMPILER is the PKL compiler using the macro-assembler.
 
-   PROGRAM is the PVM program being assembled.
+   PROGRAM is the PVM routine being assembled.
 
    POINTERS is an array of pointers.  Pointers to literal boxed
    instruction arguments are collected and returned to the caller.
    This is to make it possible for callers to garbage-collect these
-   values in the entities containing pvm_programs (such as closures.)
+   values in the entities containing pvm_routines (such as closures.)
 
    NEXT_POINTER is the next available slot in POINTERS.
 
@@ -114,7 +114,7 @@ struct pkl_asm
 {
   pkl_compiler compiler;
 
-  pvm_program program;
+  pvm_routine rout;
   void **pointers;
   int next_pointer;
 
@@ -152,7 +152,7 @@ pkl_asm_poplevel (pkl_asm pasm)
 /* Append instructions to PROGRAM to push VAL into the stack.  */
 
 static inline void
-pkl_asm_push_val (pvm_program program, pvm_val val)
+pkl_asm_push_val (pvm_routine program, pvm_val val)
 {
 #if __WORDSIZE == 64
   PVM_APPEND_INSTRUCTION (program, push);
@@ -910,23 +910,23 @@ pkl_asm_insn_bnz (pkl_asm pasm,
 }
 
 /* Create a new instance of an assembler.  This initializes a new
-   program.  */
+   routine.  */
 
 pkl_asm
 pkl_asm_new (pkl_ast ast, pkl_compiler compiler,
              int prologue)
 {
   pkl_asm pasm = xmalloc (sizeof (struct pkl_asm));
-  pvm_program program;
+  pvm_routine rout;
 
   memset (pasm, 0, sizeof (struct pkl_asm));
   pkl_asm_pushlevel (pasm, PKL_ASM_ENV_NULL);
 
   pasm->compiler = compiler;
   pasm->ast = ast;
-  program = pvm_make_program ();
-  pasm->error_label = jitter_fresh_label (program);
-  pasm->program = program;
+  rout = pvm_make_routine ();
+  pasm->error_label = jitter_fresh_label (rout);
+  pasm->rout = rout;
 
   pasm->pointers = pvm_alloc (sizeof (void*) * PKL_AST_MAX_POINTERS);
   memset (pasm->pointers, 0, PKL_AST_MAX_POINTERS);
@@ -955,26 +955,26 @@ pkl_asm_new (pkl_ast ast, pkl_compiler compiler,
   return pasm;
 }
 
-/* Finish the assembly of the current program and return it.  This
+/* Finish the assembly of the current routine and return it.  This
    function frees all resources used by the assembler instance, and
    `pkl_asm_new' should be called again in order to assemble another
-   program.  */
+   routine.  */
 
-pvm_program
+pvm_routine
 pkl_asm_finish (pkl_asm pasm, int epilogue, void **pointers)
 {
-  pvm_program program = pasm->program;
+  pvm_routine rout = pasm->rout;
 
   if (epilogue)
     {
       pkl_asm_note (pasm, "#begin epilogue");
 
-      /* Successful program finalization.  */
+      /* Successful routine finalization.  */
       pkl_asm_insn (pasm, PKL_INSN_POPE);
       pkl_asm_insn (pasm, PKL_INSN_PUSH, pvm_make_int (PVM_EXIT_OK, 32));
       pkl_asm_insn (pasm, PKL_INSN_EXIT);      
 
-      pvm_append_label (pasm->program, pasm->error_label);
+      pvm_append_label (pasm->rout, pasm->error_label);
 
       /* Default exception handler.  If we are bootstrapping the
          compiler, then use a very simple one inlined here in
@@ -1004,13 +1004,13 @@ pkl_asm_finish (pkl_asm pasm, int epilogue, void 
**pointers)
   /* Free the first level.  */
   pkl_asm_poplevel (pasm);
   
-  /* Free the assembler instance and return the assembled program to
+  /* Free the assembler instance and return the assembled routine to
      the user.  */
   free (pasm);
-  return program;
+  return rout;
 }
 
-/* Assemble an instruction INSN and append it to the program being
+/* Assemble an instruction INSN and append it to the routine being
    assembled in PASM.  If the instruction takes any argument, they
    follow after INSN.  */
 
@@ -1050,7 +1050,7 @@ pkl_asm_insn (pkl_asm pasm, enum pkl_asm_insn insn, ...)
 
       /* Due to some jitter limitations, we have to do some additional
          work.  See the docstring for `pkl_asm_push_val' - above.  */
-      pkl_asm_push_val (pasm->program, val);
+      pkl_asm_push_val (pasm->rout, val);
     }
   else if (insn < PKL_INSN_MACRO)
     {
@@ -1060,7 +1060,7 @@ pkl_asm_insn (pkl_asm pasm, enum pkl_asm_insn insn, ...)
       const char *insn_name = insn_names[insn];
       const char *p;
 
-      pvm_append_instruction_name (pasm->program, insn_name);
+      pvm_append_instruction_name (pasm->rout, insn_name);
 
       va_start (valist, insn);
       for (p = insn_args[insn]; *p != '\0'; ++p)
@@ -1073,14 +1073,14 @@ pkl_asm_insn (pkl_asm pasm, enum pkl_asm_insn insn, ...)
               {
                 pvm_val val = va_arg (valist, pvm_val);
                 /* XXX: this doesn't work in 32-bit  */
-                pvm_append_unsigned_literal_parameter (pasm->program,
+                pvm_append_unsigned_literal_parameter (pasm->rout,
                                                        (jitter_uint) val);
                 break;
               }
             case 'n':
               {
                 jitter_uint n = va_arg (valist, jitter_uint);
-                pvm_append_unsigned_literal_parameter (pasm->program, n);
+                pvm_append_unsigned_literal_parameter (pasm->rout, n);
                 break;
               }
             case 'a':
@@ -1089,7 +1089,7 @@ pkl_asm_insn (pkl_asm pasm, enum pkl_asm_insn insn, ...)
             case 'l':
               {
                 jitter_label label = va_arg (valist, jitter_label);
-                pvm_append_label_parameter (pasm->program, label);
+                pvm_append_label_parameter (pasm->rout, label);
                 break;
               }
             case 'i':
@@ -1098,7 +1098,7 @@ pkl_asm_insn (pkl_asm pasm, enum pkl_asm_insn insn, ...)
             case 'r':
               {
                 jitter_uint reg = va_arg (valist, jitter_uint);
-                PVM_APPEND_REGISTER_PARAMETER (pasm->program, r, reg);
+                PVM_APPEND_REGISTER_PARAMETER (pasm->rout, r, reg);
                 break;
               }
             }
@@ -1379,8 +1379,8 @@ pkl_asm_if (pkl_asm pasm, pkl_ast_node exp)
 {
   pkl_asm_pushlevel (pasm, PKL_ASM_ENV_CONDITIONAL);
 
-  pasm->level->label1 = jitter_fresh_label (pasm->program);
-  pasm->level->label2 = jitter_fresh_label (pasm->program);
+  pasm->level->label1 = jitter_fresh_label (pasm->rout);
+  pasm->level->label2 = jitter_fresh_label (pasm->rout);
   pasm->level->node1 = ASTREF (exp);
 }
 
@@ -1402,7 +1402,7 @@ pkl_asm_else (pkl_asm pasm)
   assert (pasm->level->current_env == PKL_ASM_ENV_CONDITIONAL);
 
   pkl_asm_insn (pasm, PKL_INSN_BA, pasm->level->label2);
-  pvm_append_label (pasm->program, pasm->level->label1);
+  pvm_append_label (pasm->rout, pasm->level->label1);
   /* Pop the expression condition from the stack.  */
   pkl_asm_insn (pasm, PKL_INSN_DROP);
 }
@@ -1411,7 +1411,7 @@ void
 pkl_asm_endif (pkl_asm pasm)
 {
   assert (pasm->level->current_env == PKL_ASM_ENV_CONDITIONAL);
-  pvm_append_label (pasm->program, pasm->level->label2);
+  pvm_append_label (pasm->rout, pasm->level->label2);
   
   /* Cleanup and pop the current level.  */
   pkl_ast_node_free (pasm->level->node1);
@@ -1443,8 +1443,8 @@ pkl_asm_try (pkl_asm pasm, pkl_ast_node arg)
 
   if (arg)
     pasm->level->node1 = ASTREF (arg);
-  pasm->level->label1 = jitter_fresh_label (pasm->program);
-  pasm->level->label2 = jitter_fresh_label (pasm->program);
+  pasm->level->label1 = jitter_fresh_label (pasm->rout);
+  pasm->level->label2 = jitter_fresh_label (pasm->rout);
 
   /* pkl_asm_note (pasm, "PUSH-REGISTERS"); */
   pkl_asm_insn (pasm, PKL_INSN_PUSHE, pasm->level->label1);
@@ -1458,7 +1458,7 @@ pkl_asm_catch (pkl_asm pasm)
   pkl_asm_insn (pasm, PKL_INSN_POPE);
   /* XXX pkl_asm_note (pasm, "POP-REGISTERS"); */
   pkl_asm_insn (pasm, PKL_INSN_BA, pasm->level->label2);
-  pvm_append_label (pasm->program, pasm->level->label1);
+  pvm_append_label (pasm->rout, pasm->level->label1);
   
   /* At this point the exception number is at the top of the stack.
      If the catch block received an argument, push a new environment
@@ -1482,7 +1482,7 @@ pkl_asm_endtry (pkl_asm pasm)
   if (pasm->level->node1)
     pkl_asm_insn (pasm, PKL_INSN_POPF, 1);
 
-  pvm_append_label (pasm->program, pasm->level->label2);
+  pvm_append_label (pasm->rout, pasm->level->label2);
 
   /* Cleanup and pop the current level.  */
   pkl_ast_node_free (pasm->level->node1);
@@ -1509,11 +1509,11 @@ pkl_asm_while (pkl_asm pasm)
 {
   pkl_asm_pushlevel (pasm, PKL_ASM_ENV_LOOP);
 
-  pasm->level->label1 = jitter_fresh_label (pasm->program);
-  pasm->level->label2 = jitter_fresh_label (pasm->program);
-  pasm->level->break_label = jitter_fresh_label (pasm->program);
+  pasm->level->label1 = jitter_fresh_label (pasm->rout);
+  pasm->level->label2 = jitter_fresh_label (pasm->rout);
+  pasm->level->break_label = jitter_fresh_label (pasm->rout);
 
-  pvm_append_label (pasm->program, pasm->level->label1);
+  pvm_append_label (pasm->rout, pasm->level->label1);
 }
 
 void
@@ -1528,11 +1528,11 @@ void
 pkl_asm_endloop (pkl_asm pasm)
 {
   pkl_asm_insn (pasm, PKL_INSN_BA, pasm->level->label1);
-  pvm_append_label (pasm->program, pasm->level->label2);
+  pvm_append_label (pasm->rout, pasm->level->label2);
   /* Pop the loop condition from the stack.  */
   pkl_asm_insn (pasm, PKL_INSN_DROP);
 
-  pvm_append_label (pasm->program, pasm->level->break_label);
+  pvm_append_label (pasm->rout, pasm->level->break_label);
   
   /* Cleanup and pop the current level.  */
   pkl_asm_poplevel (pasm);
@@ -1599,10 +1599,10 @@ pkl_asm_for (pkl_asm pasm, int container_type,
 {
   pkl_asm_pushlevel (pasm, PKL_ASM_ENV_FOR_LOOP);
 
-  pasm->level->label1 = jitter_fresh_label (pasm->program);
-  pasm->level->label2 = jitter_fresh_label (pasm->program);
-  pasm->level->label3 = jitter_fresh_label (pasm->program);
-  pasm->level->break_label = jitter_fresh_label (pasm->program);
+  pasm->level->label1 = jitter_fresh_label (pasm->rout);
+  pasm->level->label2 = jitter_fresh_label (pasm->rout);
+  pasm->level->label3 = jitter_fresh_label (pasm->rout);
+  pasm->level->break_label = jitter_fresh_label (pasm->rout);
 
   if (selector)
     pasm->level->node1 = ASTREF (selector);
@@ -1614,7 +1614,7 @@ pkl_asm_for (pkl_asm pasm, int container_type,
 void
 pkl_asm_for_where (pkl_asm pasm)
 {
-  pvm_append_label (pasm->program, pasm->level->label1);
+  pvm_append_label (pasm->rout, pasm->level->label1);
 
   pkl_asm_insn (pasm, PKL_INSN_PUSHF);
   pkl_asm_insn (pasm, PKL_INSN_PUSH, PVM_NULL);
@@ -1624,7 +1624,7 @@ pkl_asm_for_where (pkl_asm pasm)
   pkl_asm_insn (pasm, PKL_INSN_SWAP);
   pkl_asm_insn (pasm, PKL_INSN_PUSH, PVM_NULL);
 
-  pvm_append_label (pasm->program, pasm->level->label2);
+  pvm_append_label (pasm->rout, pasm->level->label2);
 
   pkl_asm_insn (pasm, PKL_INSN_DROP);
   pkl_asm_insn (pasm, PKL_INSN_EQLU);
@@ -1669,12 +1669,12 @@ pkl_asm_for_endloop (pkl_asm pasm)
   pkl_asm_insn (pasm, PKL_INSN_PUSH, PVM_NULL);
   pkl_asm_insn (pasm, PKL_INSN_BA, pasm->level->label2);
 
-  pvm_append_label (pasm->program, pasm->level->label3);
+  pvm_append_label (pasm->rout, pasm->level->label3);
 
   /* Cleanup the stack, and pop the current frame from the
      environment.  */
   pkl_asm_insn (pasm, PKL_INSN_DROP);
-  pvm_append_label (pasm->program, pasm->level->break_label);
+  pvm_append_label (pasm->rout, pasm->level->break_label);
   pkl_asm_insn (pasm, PKL_INSN_DROP);
   pkl_asm_insn (pasm, PKL_INSN_DROP);
   pkl_asm_insn (pasm, PKL_INSN_DROP);
@@ -1725,11 +1725,11 @@ pkl_asm_break_label (pkl_asm pasm)
 jitter_label
 pkl_asm_fresh_label (pkl_asm pasm)
 {
-  return jitter_fresh_label (pasm->program);
+  return jitter_fresh_label (pasm->rout);
 }
 
 void
 pkl_asm_label (pkl_asm pasm, jitter_label label)
 {
-  pvm_append_label (pasm->program, label);
+  pvm_append_label (pasm->rout, label);
 }
diff --git a/src/pkl-asm.h b/src/pkl-asm.h
index 4b0c455..1ff0e5e 100644
--- a/src/pkl-asm.h
+++ b/src/pkl-asm.h
@@ -77,7 +77,7 @@ pkl_asm pkl_asm_new (pkl_ast ast, pkl_compiler compiler,
    If POINTERS is not NULL, then it is an array of pointers to boxed
    values stored in the returned program.  */
 
-pvm_program pkl_asm_finish (pkl_asm pasm, int epilogue,
+pvm_routine pkl_asm_finish (pkl_asm pasm, int epilogue,
                             void **pointers);
 
 /* Assemble an instruction INSN and append it to the program being
diff --git a/src/pkl-gen.c b/src/pkl-gen.c
index 9a15ec8..04f4062 100644
--- a/src/pkl-gen.c
+++ b/src/pkl-gen.c
@@ -252,14 +252,15 @@ PKL_PHASE_BEGIN_HANDLER (pkl_gen_ps_decl)
            with the current environment.  */
 
         void *pointers;
-        pvm_program program = pkl_asm_finish (PKL_GEN_ASM,
-                                              0 /* epilogue */,
-                                              &pointers);
+        pvm_routine rout = pkl_asm_finish (PKL_GEN_ASM,
+                                           0 /* epilogue */,
+                                           &pointers);
+        pvm_executable_routine erout;
         pvm_val closure;
 
         PKL_GEN_POP_ASM;
-        pvm_specialize_program (program);
-        closure = pvm_make_cls (program, pointers);
+        erout = pvm_make_executable_routine (rout);
+        closure = pvm_make_cls (erout, pointers);
 
         /*XXX*/
         /* pvm_print_program (stdout, program); */
@@ -1871,7 +1872,7 @@ PKL_PHASE_BEGIN_HANDLER (pkl_gen_pr_type_array)
       pkl_asm_insn (PKL_GEN_ASM, PKL_INSN_DROP);                  /* _ */
 
       /* XXX */
-      /* pvm_print_program (stdout, PVM_VAL_CLS_PROGRAM (bounder_closure)); */
+      /* pvm_print_program (stdout, PVM_VAL_CLS_ROUTINE (bounder_closure)); */
 
       PKL_AST_TYPE_A_BOUNDER (array_type) = bounder_closure;
       PKL_PASS_BREAK;
diff --git a/src/pkl-gen.h b/src/pkl-gen.h
index ab1e9c7..e05a71b 100644
--- a/src/pkl-gen.h
+++ b/src/pkl-gen.h
@@ -51,7 +51,7 @@
    CUR_PASM and CUR_PASM2 are the pointers to the top of PASM and
    PASM2, respectively.
 
-   PROGRAM is the main PVM program being compiled.  When the phase is
+   PROGRAM is the main PVM routine being compiled.  When the phase is
    completed, the program is "finished" (in jitter parlance) and ready
    to be used.
 
@@ -84,7 +84,7 @@ struct pkl_gen_payload
   pkl_asm pasm2[PKL_GEN_MAX_PASM];
   int cur_pasm;
   int cur_pasm2;
-  pvm_program program;
+  pvm_routine program;
   void *pointers;
   int in_struct_decl;
   int in_mapper;
diff --git a/src/pkl.c b/src/pkl.c
index 3380b6c..3abac3b 100644
--- a/src/pkl.c
+++ b/src/pkl.c
@@ -101,7 +101,7 @@ pkl_free (pkl_compiler compiler)
   free (compiler);
 }
 
-static pvm_program
+static pvm_routine
 rest_of_compilation (pkl_compiler compiler,
                      pkl_ast ast,
                      void **pointers)
@@ -240,12 +240,13 @@ pkl_compile_buffer (pkl_compiler compiler,
                     char *buffer, char **end)
 {
   pkl_ast ast = NULL;
-  pvm_program program;
+  pvm_routine rout;
+  pvm_executable_routine erout;
   int ret;
   pkl_env env = NULL;
 
   /* Note that the sole purpose of `pointers' is to serve as a root
-     (in the stack) for the GC, to prevent the boxed values in PROGRAM
+     (in the stack) for the GC, to prevent the boxed values in EROUT
      to be collected.  Ugly as shit, but conservative garbage
      collection doesn't really work.  */
   void *pointers;
@@ -264,11 +265,11 @@ pkl_compile_buffer (pkl_compiler compiler,
     /* Memory exhaustion.  */
     printf (_("out of memory\n"));
   
-  program = rest_of_compilation (compiler, ast, &pointers);
-  if (program == NULL)
+  rout = rest_of_compilation (compiler, ast, &pointers);
+  if (rout == NULL)
     goto error;
 
-  pvm_specialize_program (program);
+  erout = pvm_make_executable_routine (rout);
   /* XXX */
   /* pvm_print_program (stdout, program); */
 
@@ -276,13 +277,14 @@ pkl_compile_buffer (pkl_compiler compiler,
   {
     pvm_val val;
 
-    if (pvm_run (poke_vm, program, &val) != PVM_EXIT_OK)
+    if (pvm_run (poke_vm, erout, &val) != PVM_EXIT_OK)
       goto error;
 
     /* Discard the value.  */
   }
 
-  pvm_destroy_program (program);
+  pvm_destroy_routine (erout->routine);
+  pvm_destroy_executable_routine (erout);
   pkl_env_free (compiler->env);
   compiler->env = env;
   return 1;
@@ -298,12 +300,13 @@ pkl_compile_statement (pkl_compiler compiler,
                        pvm_val *val)
 {
   pkl_ast ast = NULL;
-  pvm_program program;
+  pvm_routine rout;
+  pvm_executable_routine erout;
   int ret;
   pkl_env env = NULL;
 
   /* Note that the sole purpose of `pointers' is to serve as a root
-     (in the stack) for the GC, to prevent the boxed values in PROGRAM
+     (in the stack) for the GC, to prevent the boxed values in EROUT
      to be collected.  Ugly as shit, but conservative garbage
      collection doesn't really work.  */
   void *pointers;
@@ -322,19 +325,20 @@ pkl_compile_statement (pkl_compiler compiler,
     /* Memory exhaustion.  */
     printf (_("out of memory\n"));
   
-  program = rest_of_compilation (compiler, ast, &pointers);
-  if (program == NULL)
+  rout = rest_of_compilation (compiler, ast, &pointers);
+  if (rout == NULL)
     goto error;
 
-  pvm_specialize_program (program);
+  erout = pvm_make_executable_routine (rout);
   /* XXX */
-  /* pvm_print_program (stdout, program); */
+  /* pvm_print_routine (stdout, rout); */
 
   /* Execute the program in the poke vm.  */
-  if (pvm_run (poke_vm, program, val) != PVM_EXIT_OK)
+  if (pvm_run (poke_vm, erout, val) != PVM_EXIT_OK)
     goto error;
 
-  pvm_destroy_program (program);
+  pvm_destroy_routine (erout->routine);
+  pvm_destroy_executable_routine (erout);
   pkl_env_free (compiler->env);
   compiler->env = env;
   return 1;
@@ -345,12 +349,13 @@ pkl_compile_statement (pkl_compiler compiler,
 }
 
 
-pvm_program
+pvm_executable_routine
 pkl_compile_expression (pkl_compiler compiler,
                         char *buffer, char **end)
 {
   pkl_ast ast = NULL;
-  pvm_program program;
+  pvm_routine rout;
+  pvm_executable_routine erout;
   int ret;
   pkl_env env = NULL;
 
@@ -374,16 +379,16 @@ pkl_compile_expression (pkl_compiler compiler,
     /* Memory exhaustion.  */
     printf (_("out of memory\n"));
   
-  program = rest_of_compilation (compiler, ast, &pointers);
-  if (program == NULL)
+  rout = rest_of_compilation (compiler, ast, &pointers);
+  if (rout == NULL)
     goto error;
 
   pkl_env_free (compiler->env);
   compiler->env = env;
-  pvm_specialize_program (program);
+  erout = pvm_make_executable_routine (rout);
   /* XXX */
-  /* pvm_print_program (stdout, program); */
-  return program;
+  /* pvm_print_routine (stdout, rout); */
+  return erout;
 
  error:
   pkl_env_free (env);
@@ -396,12 +401,13 @@ pkl_compile_file (pkl_compiler compiler, const char 
*fname)
 {
   int ret;
   pkl_ast ast = NULL;
-  pvm_program program;
+  pvm_routine rout;
+  pvm_executable_routine erout;
   FILE *fd;
   pkl_env env = NULL;
 
   /* Note that the sole purpose of `pointers' is to serve as a root
-     (in the stack) for the GC, to prevent the boxed values in PROGRAM
+     (in the stack) for the GC, to prevent the boxed values in ROUT
      to be collected.  Ugly as shit, but conservative garbage
      collection doesn't really work.  */
   void *pointers;
@@ -426,26 +432,27 @@ pkl_compile_file (pkl_compiler compiler, const char 
*fname)
       printf (_("out of memory\n"));
     }
 
-  program = rest_of_compilation (compiler, ast, &pointers);
-  if (program == NULL)
+  rout = rest_of_compilation (compiler, ast, &pointers);
+  if (rout == NULL)
     goto error;
 
-  pvm_specialize_program (program);
+  erout = pvm_make_executable_routine (rout);
   /* XXX */  
-  /* pvm_print_program (stdout, program); */
+  /* pvm_print_routine (stdout, rout); */
   fclose (fd);
 
   /* Execute the program in the poke vm.  */
   {
     pvm_val val;
 
-    if (pvm_run (poke_vm, program, &val) != PVM_EXIT_OK)
+    if (pvm_run (poke_vm, erout, &val) != PVM_EXIT_OK)
       goto error_no_close;
 
     /* Discard the value.  */
   }
 
-  pvm_destroy_program (program);
+  pvm_destroy_routine (rout);
+  pvm_destroy_executable_routine (erout);
   pkl_env_free (compiler->env);
   compiler->env = env;
   return 1;
diff --git a/src/pkl.h b/src/pkl.h
index 19b0963..66e7f05 100644
--- a/src/pkl.h
+++ b/src/pkl.h
@@ -48,9 +48,9 @@
    types, function etc from the user.
 
    At any point, the user can request to compile a poke expression
-   with `pkl_compile_expression'.  This returns a PVM program that,
-   can be executed in a virtual machine.  It is up to the user to free
-   the returned PVM program when it is not useful anymore.
+   with `pkl_compile_expression'.  This returns a PVM executable routine
+   that can be executed on a virtual machine.  It is up to the user to free
+   the returned routine when it is not useful anymore.
 
    `pkl_compile_buffer', `pkl_compile_file' and
    `pkl_compile_expression' can be called any number of times, in any
@@ -88,11 +88,11 @@ int pkl_compile_statement (pkl_compiler compiler, char 
*buffer, char **end,
 
 
 /* Like pkl_compile_buffer, but compile a Poke expression and return a
-   PVM program that evaluates to the expression.  In case of error
+   PVM routine that evaluates to the expression.  In case of error
    return NULL.  */
 
-pvm_program pkl_compile_expression (pkl_compiler compiler,
-                                    char *buffer, char **end);
+pvm_executable_routine pkl_compile_expression (pkl_compiler compiler,
+                                               char *buffer, char **end);
 
 /* Return the current compile-time environment in COMPILER.  */
 
diff --git a/src/pvm-alloc.c b/src/pvm-alloc.c
index b3c00a0..84019b7 100644
--- a/src/pvm-alloc.c
+++ b/src/pvm-alloc.c
@@ -36,7 +36,8 @@ static void
 pvm_alloc_finalize_closure (void *object, void *client_data)
 {
   pvm_cls cls = (pvm_cls) object;
-  pvm_destroy_program (cls->program);
+  pvm_destroy_routine (cls->erout->routine);
+  pvm_destroy_executable_routine (cls->erout);
 }
 
 void *
diff --git a/src/pvm-env.h b/src/pvm-env.h
index a129361..f3255d3 100644
--- a/src/pvm-env.h
+++ b/src/pvm-env.h
@@ -26,7 +26,7 @@
 
 /* The poke virtual machine (PVM) maintains a data structure called
    the run-time environment.  This structure contains run-time frames,
-   which in turn store the variables of PVM programs.
+   which in turn store the variables of PVM routines.
 
    A set of PVM instructions are provided to allow programs to
    manipulate the run-time environment.  These are implemented in
diff --git a/src/pvm-val.c b/src/pvm-val.c
index ccb7cba..9dd1131 100644
--- a/src/pvm-val.c
+++ b/src/pvm-val.c
@@ -268,14 +268,14 @@ pvm_make_closure_type (pvm_val rtype,
 }
 
 pvm_val
-pvm_make_cls (pvm_program program, void **pointers)
+pvm_make_cls (pvm_executable_routine erout, void **pointers)
 {
   pvm_val_box box = pvm_make_box (PVM_VAL_TAG_CLS);
   pvm_cls cls = pvm_alloc_cls ();
 
-  cls->program = program;
+  cls->erout = erout;
   cls->pointers = pointers;
-  cls->entry_point = PVM_PROGRAM_BEGINNING (program);
+  cls->entry_point = PVM_EXECUTABLE_ROUTINE_BEGINNING (erout);
   cls->env = NULL; /* This should be set by a PEC instruction before
                       using the closure.  */
 
diff --git a/src/pvm-val.h b/src/pvm-val.h
index d49774f..417787b 100644
--- a/src/pvm-val.h
+++ b/src/pvm-val.h
@@ -426,7 +426,7 @@ int pvm_type_equal (pvm_val type1, pvm_val type2);
 
 #define PVM_VAL_CLS(V) (PVM_VAL_BOX_CLS (PVM_VAL_BOX ((V))))
 
-#define PVM_VAL_CLS_PROGRAM(V) (PVM_VAL_CLS((V))->program)
+#define PVM_VAL_CLS_ROUTINE(V) (PVM_VAL_CLS((V))->erout)
 #define PVM_VAL_CLS_ENTRY_POINT(V) (PVM_VAL_CLS((V))->entry_point)
 #define PVM_VAL_CLS_ENV(V) (PVM_VAL_CLS((V))->env)
 
@@ -434,7 +434,7 @@ struct pvm_cls
 {
   /* Note we have to use explicit pointers here due to the include
      mess induced by jitter's combined header files :/ */
-  struct jitter_program *program;
+  struct jitter_executable_routine *erout;
   void **pointers;
   const void *entry_point;
   struct pvm_env *env;
@@ -442,7 +442,7 @@ struct pvm_cls
 
 typedef struct pvm_cls *pvm_cls;
 
-pvm_val pvm_make_cls (struct jitter_program *program,
+pvm_val pvm_make_cls (struct jitter_executable_routine *erout,
                       void **pointers);
 
 /* Offsets are boxed values.  */
diff --git a/src/pvm.c b/src/pvm.c
index 2ada27b..b5a892f 100644
--- a/src/pvm.c
+++ b/src/pvm.c
@@ -113,12 +113,12 @@ pvm_shutdown (pvm apvm)
 }
 
 enum pvm_exit_code
-pvm_run (pvm apvm, pvm_program prog, pvm_val *res)
+pvm_run (pvm apvm, pvm_executable_routine erout, pvm_val *res)
 {
   PVM_STATE_RESULT_VALUE (apvm) = PVM_NULL;
   PVM_STATE_EXIT_CODE (apvm) = PVM_EXIT_OK;
 
-  pvm_interpret (prog, &apvm->pvm_state);
+  pvm_execute_executable_routine (erout, &apvm->pvm_state);
 
   if (res != NULL)
     *res = PVM_STATE_RESULT_VALUE (apvm);
diff --git a/src/pvm.h b/src/pvm.h
index ca5c30f..a1dbe5b 100644
--- a/src/pvm.h
+++ b/src/pvm.h
@@ -62,11 +62,12 @@ enum pvm_exit_code
 
 typedef struct pvm *pvm;
 
-/* A PVM program can be executed in the virtual machine at any time.
-   The struct pvm_program is provided by Jitter, but we provide here
-   an opaque type to be used by the PVM users.  */
+/* A PVM routine can be executed in the virtual machine at any time.
+   Jitter defines struct pvm_routine and struct pvm_executable_routine,
+   but here we provide opaque types to be used by the PVM users.  */
 
-typedef struct pvm_program *pvm_program;
+typedef struct pvm_routine *pvm_routine;
+typedef struct pvm_executable_routine *pvm_executable_routine;
 
 /* Initialize a new Poke Virtual Machine and return it.  */
 
@@ -80,11 +81,11 @@ void pvm_shutdown (pvm pvm);
 
 pvm_env pvm_get_env (pvm pvm);
 
-/* Run a PVM program in a given Poke Virtual Machine.  Put the
+/* Run a PVM routine in a given Poke Virtual Machine.  Put the
    resulting value in RES, if any, and return an exit code.  */
 
 enum pvm_exit_code pvm_run (pvm pvm,
-                            pvm_program prog,
+                            pvm_executable_routine erout,
                             pvm_val *res);
 
 /* Get and set the current endianness and negative encoding for the
diff --git a/src/ras b/src/ras
index 9b148b4..a0538f1 100755
--- a/src/ras
+++ b/src/ras
@@ -78,8 +78,8 @@
 #
 # This translates into a C macro RAS_FUNCTION_NAME(CLOSURE), with a
 # single argument which should be an l-value.  The macro will compile
-# the function into a pvm_program, and install it into a PVM closure
-# value that is assigned to CLOSURE.
+# the function into a pvm_executable_routine, and install it into a
+# PVM closure value that is assigned to CLOSURE.
 #
 # Expanding Macros
 # ----------------
@@ -256,7 +256,7 @@
 # Another difficulty when dealing with lexical addresses is that
 # different addresses are required to refer to the same variable,
 # depending on the context.  For example, consider the following PVM
-# program:
+# routine:
 #
 # pushf
 # regvar        ; A
@@ -559,7 +559,7 @@ BEGIN {
 
     out("#define RAS_FUNCTION_" toupper($2) "(CLOSURE)  \\")
     out("\tdo {                                         \\")
-    out("\tpvm_program program;                         \\")
+    out("\tpvm_routine rout;                            \\")
     out("\t                                             \\")
     out("\tPKL_GEN_PUSH_ASM (pkl_asm_new (PKL_PASS_AST, \\")
     out("\t                               PKL_GEN_PAYLOAD->compiler, \\")
@@ -582,12 +582,13 @@ BEGIN {
     {
         out("\t{                                                       \\")
         out("\t  void *pointers;                                       \\")
-        out("\t  program = pkl_asm_finish (RAS_ASM,                    \\")
-        out("\t                            0 /* epilogue */,           \\")
-        out("\t                            &pointers);                 \\")
+        out("\t  pvm_executable_routine erout;                         \\")
+        out("\t  rout = pkl_asm_finish (RAS_ASM,                       \\")
+        out("\t                         0 /* epilogue */,              \\")
+        out("\t                         &pointers);                    \\")
         out("\t  PKL_GEN_POP_ASM;                                      \\")
-        out("\t  pvm_specialize_program (program);                     \\")
-        out("\t  (CLOSURE) = pvm_make_cls (program, pointers);         \\")
+        out("\t  erout = pvm_make_executable_routine (rout);           \\")
+        out("\t  (CLOSURE) = pvm_make_cls (erout, pointers);           \\")
         out("\t}                                                       \\")
     }
     out("\t} while (0)")

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]