wingo pushed a commit to branch wip-whippet
in repository guile.

commit 5c5b8674554faf44df36b65907b9ba3c108b0087
Author: Andy Wingo <wi...@pobox.com>
AuthorDate: Wed Jun 11 21:59:58 2025 +0200

    Turn boot closures into subrs
    
    * libguile/eval.c: Instead of applicable smobs, boot closures are subrs.
    This gives better JIT and no shuffling in the VM.
    (is_boot_closure):
    (boot_closure_code):
    (boot_closure_env):
    (boot_closure_body):
    (boot_closure_num_required_args):
    (boot_closure_is_fixed):
    (boot_closure_has_rest_args):
    (boot_closure_is_rest): Inline functions instead of macros.
    (eval): Create boot closures as programs, not smobs.
    (prepare_boot_closure_env_for_apply):
    (prepare_boot_closure_env_for_eval): Adapt to lower-casing of boot
    closure inline functions.
    (apply_boot_closure): Rename from boot_closure_apply.
    (boot_closure_print): Remove.
    (scm_init_eval): Update.
---
 libguile/eval.c | 173 +++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 103 insertions(+), 70 deletions(-)

diff --git a/libguile/eval.c b/libguile/eval.c
index 32e76fe3f..a93c5a41f 100644
--- a/libguile/eval.c
+++ b/libguile/eval.c
@@ -40,7 +40,7 @@
 #include "frames.h"
 #include "fluids.h"
 #include "goops.h"
-#include "gsubr.h"
+#include "gsubr-internal.h"
 #include "hash.h"
 #include "hashtab.h"
 #include "keywords.h"
@@ -55,7 +55,6 @@
 #include "private-options.h"
 #include "procprop.h"
 #include "programs.h"
-#include "smob.h"
 #include "stackchk.h"
 #include "strings.h"
 #include "symbols.h"
@@ -71,6 +70,21 @@
 
 
 
+#define CAR(x)   SCM_CAR(x)
+#define CDR(x)   SCM_CDR(x)
+#define CAAR(x)  SCM_CAAR(x)
+#define CADR(x)  SCM_CADR(x)
+#define CDAR(x)  SCM_CDAR(x)
+#define CDDR(x)  SCM_CDDR(x)
+#define CADDR(x) SCM_CADDR(x)
+#define CDDDR(x) SCM_CDDDR(x)
+
+#define VECTOR_REF(v, i) (SCM_SIMPLE_VECTOR_REF (v, i))
+#define VECTOR_SET(v, i, x) (SCM_SIMPLE_VECTOR_SET (v, i, x))
+#define VECTOR_LENGTH(v) (SCM_SIMPLE_VECTOR_LENGTH (v))
+
+
+
 /* We have three levels of EVAL here:
 
    - eval (exp, env)
@@ -104,20 +118,59 @@
    eval.scm is in the house, closures are standard VM closures.
  */
 
-static scm_t_bits scm_tc16_boot_closure;
-#define RETURN_BOOT_CLOSURE(code, env) \
-  SCM_RETURN_NEWSMOB2 (scm_tc16_boot_closure, SCM_UNPACK (code), SCM_UNPACK 
(env))
-#define BOOT_CLOSURE_P(obj) SCM_TYP16_PREDICATE (scm_tc16_boot_closure, (obj))
-#define BOOT_CLOSURE_CODE(x) SCM_SMOB_OBJECT (x)
-#define BOOT_CLOSURE_ENV(x) SCM_SMOB_OBJECT_2 (x)
-#define BOOT_CLOSURE_BODY(x) CAR (BOOT_CLOSURE_CODE (x))
-#define BOOT_CLOSURE_NUM_REQUIRED_ARGS(x) (SCM_I_INUM (CADDR 
(BOOT_CLOSURE_CODE (x))))
-#define BOOT_CLOSURE_IS_FIXED(x)  (scm_is_null (CDDDR (BOOT_CLOSURE_CODE (x))))
+static const uint32_t *apply_boot_closure_code;
+
+static inline int
+is_boot_closure (SCM obj)
+{
+  return scm_is_program (obj) &&
+    scm_program_code (scm_to_program (obj)) == apply_boot_closure_code;
+}
+
+static inline SCM
+boot_closure_code (SCM clo)
+{
+  return scm_program_free_variable_ref (scm_to_program (clo), 0);
+}
+
+static inline SCM
+boot_closure_env (SCM clo)
+{
+  return scm_program_free_variable_ref (scm_to_program (clo), 1);
+}
+
+static inline SCM
+boot_closure_body (SCM clo)
+{
+  return CAR (boot_closure_code (clo));
+}
+
+static inline int
+boot_closure_num_required_args (SCM clo)
+{
+  return SCM_I_INUM (CADDR (boot_closure_code (clo)));
+}
+
+static inline int
+boot_closure_is_fixed (SCM clo)
+{
+  return scm_is_null (CDDDR (boot_closure_code (clo)));
+}
+
 /* NB: One may only call the following accessors if the closure is not FIXED. 
*/
-#define BOOT_CLOSURE_HAS_REST_ARGS(x) scm_is_true (CADDR (SCM_CDR 
(BOOT_CLOSURE_CODE (x))))
-#define BOOT_CLOSURE_IS_REST(x) scm_is_null (SCM_CDR (CDDDR (BOOT_CLOSURE_CODE 
(x))))
-/* NB: One may only call the following accessors if the closure is not REST. */
-#define BOOT_CLOSURE_IS_FULL(x) (1)
+static inline int
+boot_closure_has_rest_args (SCM clo)
+{
+  return scm_is_true (CADDR (SCM_CDR (boot_closure_code (clo))));
+}
+
+static inline int
+boot_closure_is_rest (SCM clo)
+{
+  return scm_is_null (SCM_CDR (CDDDR (boot_closure_code (clo))));
+}
+
+/* NB: One may only call the following accessor if the closure is not REST. */
 #define 
BOOT_CLOSURE_PARSE_FULL(fu_,body,nargs,rest,nopt,kw,ninits,unbound,alt) \
   do { SCM fu = fu_;                                            \
     body = CAR (fu); fu = CDDR (fu);                            \
@@ -140,6 +193,7 @@ static scm_t_bits scm_tc16_boot_closure;
           }                                                     \
       }                                                         \
   } while (0)
+
 static void prepare_boot_closure_env_for_apply (SCM proc, SCM args,
                                                 SCM *out_body, SCM *out_env);
 static void prepare_boot_closure_env_for_eval (SCM proc, unsigned int argc,
@@ -147,19 +201,6 @@ static void prepare_boot_closure_env_for_eval (SCM proc, 
unsigned int argc,
                                                SCM *inout_env);
 
 
-#define CAR(x)   SCM_CAR(x)
-#define CDR(x)   SCM_CDR(x)
-#define CAAR(x)  SCM_CAAR(x)
-#define CADR(x)  SCM_CADR(x)
-#define CDAR(x)  SCM_CDAR(x)
-#define CDDR(x)  SCM_CDDR(x)
-#define CADDR(x) SCM_CADDR(x)
-#define CDDDR(x) SCM_CDDDR(x)
-
-#define VECTOR_REF(v, i) (SCM_SIMPLE_VECTOR_REF (v, i))
-#define VECTOR_SET(v, i, x) (SCM_SIMPLE_VECTOR_SET (v, i, x))
-#define VECTOR_LENGTH(v) (SCM_SIMPLE_VECTOR_LENGTH (v))
-
 static SCM
 make_env (int n, SCM init, SCM next)
 {
@@ -286,7 +327,16 @@ eval (SCM x, SCM env)
       }
           
     case SCM_M_LAMBDA:
-      RETURN_BOOT_CLOSURE (mx, env);
+      {
+        struct scm_program *ret =
+          scm_make_subr_from_code (SCM_I_CURRENT_THREAD,
+                                   apply_boot_closure_code,
+                                   SCM_F_PROGRAM_IS_PRIMITIVE,
+                                   2);
+        scm_program_free_variable_set_x (ret, 0, mx);
+        scm_program_free_variable_set_x (ret, 1, env);
+        return scm_from_program (ret);
+      }
 
     case SCM_M_CAPTURE_ENV:
       {
@@ -325,7 +375,7 @@ eval (SCM x, SCM env)
     apply_proc:
       /* Go here to tail-apply a procedure.  PROC is the procedure and
        * ARGS is the list of arguments. */
-      if (BOOT_CLOSURE_P (proc))
+      if (is_boot_closure (proc))
         {
           prepare_boot_closure_env_for_apply (proc, args, &x, &env);
           goto loop;
@@ -339,7 +389,7 @@ eval (SCM x, SCM env)
       argc = scm_ilength (CDR (mx));
       mx = CDR (mx);
 
-      if (BOOT_CLOSURE_P (proc))
+      if (is_boot_closure (proc))
         {
           prepare_boot_closure_env_for_eval (proc, argc, mx, &x, &env);
           goto loop;
@@ -733,13 +783,13 @@ static void
 prepare_boot_closure_env_for_apply (SCM proc, SCM args,
                                     SCM *out_body, SCM *out_env)
 {
-  int nreq = BOOT_CLOSURE_NUM_REQUIRED_ARGS (proc);
-  SCM env = BOOT_CLOSURE_ENV (proc);
+  int nreq = boot_closure_num_required_args (proc);
+  SCM env = boot_closure_env (proc);
   int i;
 
-  if (BOOT_CLOSURE_IS_FIXED (proc)
-      || (BOOT_CLOSURE_IS_REST (proc)
-          && !BOOT_CLOSURE_HAS_REST_ARGS (proc)))
+  if (boot_closure_is_fixed (proc)
+      || (boot_closure_is_rest (proc)
+          && !boot_closure_has_rest_args (proc)))
     {
       if (SCM_UNLIKELY (scm_ilength (args) != nreq))
         scm_wrong_num_args (proc);
@@ -747,10 +797,10 @@ prepare_boot_closure_env_for_apply (SCM proc, SCM args,
       env = make_env (nreq, SCM_UNDEFINED, env);
       for (i = 0; i < nreq; args = CDR (args), i++)
         env_set (env, 0, i, CAR (args));
-      *out_body = BOOT_CLOSURE_BODY (proc);
+      *out_body = boot_closure_body (proc);
       *out_env = env;
     }
-  else if (BOOT_CLOSURE_IS_REST (proc))
+  else if (boot_closure_is_rest (proc))
     {
       if (SCM_UNLIKELY (scm_ilength (args) < nreq))
         scm_wrong_num_args (proc);
@@ -760,14 +810,14 @@ prepare_boot_closure_env_for_apply (SCM proc, SCM args,
         env_set (env, 0, i, CAR (args));
       env_set (env, 0, i++, args);
 
-      *out_body = BOOT_CLOSURE_BODY (proc);
+      *out_body = boot_closure_body (proc);
       *out_env = env;
     }
   else
     {
       int i, argc, nreq, nopt, ninits, nenv;
       SCM body, rest, kw, unbound, alt;
-      SCM mx = BOOT_CLOSURE_CODE (proc);
+      SCM mx = boot_closure_code (proc);
       
     loop:
       BOOT_CLOSURE_PARSE_FULL (mx, body, nargs, rest, nopt, kw,
@@ -896,11 +946,11 @@ static void
 prepare_boot_closure_env_for_eval (SCM proc, unsigned int argc,
                                    SCM exps, SCM *out_body, SCM *inout_env)
 {
-  int nreq = BOOT_CLOSURE_NUM_REQUIRED_ARGS (proc);
-  SCM new_env = BOOT_CLOSURE_ENV (proc);
-  if ((BOOT_CLOSURE_IS_FIXED (proc)
-       || (BOOT_CLOSURE_IS_REST (proc)
-           && !BOOT_CLOSURE_HAS_REST_ARGS (proc)))
+  int nreq = boot_closure_num_required_args (proc);
+  SCM new_env = boot_closure_env (proc);
+  if ((boot_closure_is_fixed (proc)
+       || (boot_closure_is_rest (proc)
+           && !boot_closure_has_rest_args (proc)))
       && nreq == argc)
     {
       int i;
@@ -909,11 +959,11 @@ prepare_boot_closure_env_for_eval (SCM proc, unsigned int 
argc,
       for (i = 0; i < nreq; exps = CDR (exps), i++)
         env_set (new_env, 0, i, EVAL1 (CAR (exps), *inout_env));
 
-      *out_body = BOOT_CLOSURE_BODY (proc);
+      *out_body = boot_closure_body (proc);
       *inout_env = new_env;
     }
-  else if (!BOOT_CLOSURE_IS_FIXED (proc) &&
-           BOOT_CLOSURE_IS_REST (proc) && argc >= nreq)
+  else if (!boot_closure_is_fixed (proc) &&
+           boot_closure_is_rest (proc) && argc >= nreq)
     {
       SCM rest;
       int i;
@@ -925,7 +975,7 @@ prepare_boot_closure_env_for_eval (SCM proc, unsigned int 
argc,
         rest = scm_cons (EVAL1 (CAR (exps), *inout_env), rest);
       env_set (new_env, 0, i++, scm_reverse_x (rest, SCM_UNDEFINED));
 
-      *out_body = BOOT_CLOSURE_BODY (proc);
+      *out_body = boot_closure_body (proc);
       *inout_env = new_env;
     }
   else
@@ -939,30 +989,13 @@ prepare_boot_closure_env_for_eval (SCM proc, unsigned int 
argc,
 }
 
 static SCM
-boot_closure_apply (SCM closure, SCM args)
+apply_boot_closure (SCM closure, SCM args)
 {
   SCM body, env;
   prepare_boot_closure_env_for_apply (closure, args, &body, &env);
   return eval (body, env);
 }
 
-static int
-boot_closure_print (SCM closure, SCM port, scm_print_state *pstate)
-{
-  SCM args;
-  scm_puts ("#<boot-closure ", port);
-  scm_uintprint (SCM_UNPACK (closure), 16, port);
-  scm_putc (' ', port);
-  args = scm_make_list (scm_from_int (BOOT_CLOSURE_NUM_REQUIRED_ARGS 
(closure)),
-                        scm_from_latin1_symbol ("_"));
-  if (!BOOT_CLOSURE_IS_FIXED (closure) && BOOT_CLOSURE_HAS_REST_ARGS (closure))
-    args = scm_cons_star (scm_from_latin1_symbol ("_"), args);
-  /* FIXME: optionals and rests */
-  scm_display (args, port);
-  scm_putc ('>', port);
-  return 1;
-}
-
 void 
 scm_init_eval ()
 {
@@ -970,9 +1003,9 @@ scm_init_eval ()
 
   f_apply = scm_c_define_gsubr ("apply", 2, 0, 1, scm_apply);
 
-  scm_tc16_boot_closure = scm_make_smob_type ("boot-closure", 0);
-  scm_set_smob_apply (scm_tc16_boot_closure, boot_closure_apply, 0, 0, 1);
-  scm_set_smob_print (scm_tc16_boot_closure, boot_closure_print);
+  apply_boot_closure_code =
+    scm_allocate_subr_code (scm_from_utf8_symbol ("boot-closure"), 0, 0, 1,
+                            apply_boot_closure, SCM_F_SUBR_CLOSURE);
 
   primitive_eval = scm_c_make_gsubr ("primitive-eval", 1, 0, 0,
                                      scm_c_primitive_eval);

Reply via email to