[Top][All Lists]

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

towards a more unified procedure application mechanism

From: Andy Wingo
Subject: towards a more unified procedure application mechanism
Date: Sat, 29 Aug 2009 13:38:13 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.92 (gnu/linux)

Hey all,

I'm working on pulling dispatch of non-VM procedure applications into
the VM -- so invoking primitives written in C can happen quickly from
within the VM.

This is also a step along the path towards native compilation. Procedure
dispatch right now has so many cases -- it is feasible to inline all of
those cases into the VM, but once we generate native code, it would be
ludicrous to do so at all call sites.

One could trampoline out to an "apply" procedure, but that loses on tail
recursion in a number of important cases.

My approach is to start by listing all the different kinds of applicable
objects, and how the VM would apply them.

 scm_tc7_program            VM procedures
   - native support

 scm_tcs_closures           Interpreted procedures
   - Currently calls out to the interpreter, but in the future we will
     only see these during the first phase of bootstrapping, when eval.c
     is compiling eval.scm. This one should probably be moved to be a
     SMOB, because there is no need for code outside of eval.c to know
     about closures, and closures will only be live during the boot

 scm_tc7_subr_2o            SCM (*) () -- 0 arguments.
 scm_tc7_subr_1             SCM (*) (SCM) -- 1 argument.
 scm_tc7_subr_1o            SCM (*) (SCM) -- 1 optional argument.
 scm_tc7_subr_2o            SCM (*) (SCM, SCM) -- 2 required args.
 scm_tc7_subr_2o            SCM (*) (SCM, SCM) -- 2 optional args.
 scm_tc7_subr_3             SCM (*) (SCM, SCM, SCM) -- 3 required args.

 scm_tc7_lsubr              SCM (*) (SCM) -- list subrs
     All arguments are passed as a list.
 scm_tc7_lsubr_2            SCM (*) (SCM, SCM, SCM)
     A list subr with two required args.

 scm_tc7_dsubr              double (*) (double) -- double subrs
     Pretty much a bad non-optimization, IMO. Converts its argument to a
     double, calls the function, then converts the result double to a
     SCM -- dispatching to a generic if the ->double conversion didn't

 scm_tc7_cxr                c[da]+r
     Interprets the SUBR pointer as some kind of bit pattern for chasing
     car/cdr pairs. Only useful in the e.g. (map cddr ...) case, because
     otherwise cddr gets compiled better for the VM. And, in the future,
     map will do some inlining, so that even (map cddr ...) will compile

 scm_tc7_asubr              SCM (*) (SCM, SCM) -- "accumulating" subrs.
     With 0 arguments, returns subr (SCM_UNDEFINED, SCM_UNDEFINED).
     With 1 argument, returns subr (arg1, SCM_UNDEFINED).
     Otherwise returns subr (subr (arg1, arg2), arg3), ... -- like the
     semantics of +.

 scm_tc7_rpsubr             SCM (*) (SCM, SCM) -- predicate subrs.
     With 0 arguments, returns true.
     With 1 argument, returns subr (arg1, SCM_UNDEFINED).
     Otherwise, like an asubr, but returns SCM_BOOL_F if any subr
     invocation returns false. Otherwise returns SCM_BOOL_T.

 scm_tc7_smob               Applicable smobs
     Some smobs are applicable. Actually there are a number of smob
     apply procedures that one might choose to implement:
     SCM (*apply) ();
     SCM (*apply_0) (SCM);
     SCM (*apply_1) (SCM, SCM);
     SCM (*apply_2) (SCM, SCM, SCM);
     SCM (*apply_3) (SCM, SCM, SCM, SCM);
     In the apply_3 case, the last argument is a rest arg list.

 scm_tc7_gsubr              Generic subrs
     The is the base case in which you can have N required args, N
     optional args, and maybe rest args too. SCM_DEFINE produces
     gsubrs -- at least, it tries to. scm_c_define_gsubr actually
     returns e.g. scm_tc7_subr_1 for certain combinations of req, opt,
     and rest args; but we can change that.

 scm_tc7_pws                Procedures with setters
     Gets the procedure, and applies that. This needs to be inlined into
     the VM to preserve tail recursion.

 scm_tcs_struct             Applicable structs
     Currently, a struct needs one of two bits set for this to work:
     One case is if the procedure is a "pure generic", an instance of
     <generic> and not one of its subclasses, in which case we fetch or
     compute the effective method, and apply that.

     Actually it's worth mentioning here that for pure generics, the
     current GOOPS code returns an effective method that includes an
     address@hidden isym, to speed up dispatch in the interpreter. It
     actually mutates a cache inline to to the memoized effective

     Generics that are instances of subclasses of <generic> cannot
     currently be applied at all, due to limitations in Guile's
     implementation of the generics MOP. But now that we have compiled
     procedures, I think we can just require that the effective method
     of a generic be any kind of applicable object, but normally a
     closure, implementing the dispatch algorithm in Scheme. That should
     be sufficiently fast, and if we need VM ops for dispatch, well so
     be it. At least that way we move more to Scheme and handle tail
     recursion too. That would allow the generic function application
     MOP to be finished -- including advice, before/after/around
     methods, different dispatch algorithms, etc.

     The other case is if the struct is an "operator". I don't really
     understand what these are -- the comment in objects.h seems to
     suggest that operators were an optimization for applicable structs
     and the evaluator. But they do not appear to be used anywhere; I
     will be happy to remove them entirely.

     Pascal Constanza's R6RS enhancement request seems relevant:

     I think his applicable struct construct seems to be equivalent to
     GOOPS/objects.c's "entities". I prefer Constanza's name though.

That's all the cases, afaict. I'll reply to my message with a plan of


reply via email to

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