> I noticed that both Church-State and the current COLAs depend on
> Boehm's libgc for conservative collection.  I have long been pondering
> a design for an ultra-simple precise mark-sweep GC with an ABI and
> macros that don't put too much burden on a C programmer (since I am a
> C programmer, and will probably stay that way for a while).

> My design for Figure has been to create a meta-machine (I'm not sure I
> can call it a virtual machine), which is calling convention compatible
> with the platform's C environment.  The idea is to unify the language
> that describes low-level calls (i.e. any arbitrary C primitive or
> function call) with the language for high-level calls (prototype
> multiple dispatch).

It's not clear to me how you can distinguish between an object pointer
and an integer at garbage collection time? I assume your figure language
is not typed (doesn't have a type checker), unless you're able to use
the C type checker for that?

Besides the stack frames, can you distinguish between integers and
object pointers in heap allocated objects?

John

> In trying to reconcile these issues, I've been forced to make several
> mechanical transformations to my C sources, until I've evolutionarily
> discovered a style that supports the ABI.  That style includes
> reifying stack frames and a single return register, so that there is a
> clear path for the GC to trace.  The way I've chosen to do this is to
> pass a single pointer to every high-level call (and as much of the
> mid-level runtime as possible), without imposing any burden on
> functions that are called below.  This also means that there are no
> global variables in Figure (well, just one, but I'll get rid of that
> one after I finish writing this e-mail).
> 
> The ABI for a typical piece of code looks like this:
> 
> /* Think of Gut as the high-level object type system. */
> typedef void *Gut;
> 
> struct _Figure
> {
> [...]
>   KSFrame *frame;
>   /* This is the return pseudoregister.  Every function puts Gut
>      results in here so that the precise garbage collector can find
>      them, no matter what program state. */
>   union
>   {
>     /* This is a union only so the callee can avoid tedious
>        typecasting. */
>     ptrdiff_t i;
>     Gut p;
>     GutFun f;
>   } x;
>   /* This is nonzero iff X should be traced by the precise GC. */
>   int x_is_gcroot;
> };
> 
> Where KSFrame is:
> 
> struct _KSFrame
> {
>   KSFrame *caller;
> #ifndef NDEBUG
>   /* Current source location. */
>   char *file;
>   char *func;
>   int line;
> #endif
>   [more high-level call information, such as object states and selves...]
> };
> 
> I've annotated this function to try to explain better:
> 
> static void
> skin_parse(Figure *f, GushInput *in)
> {
>   int c;
>   /* Create a new frame, called "ks", and link it into Figure's call
>      stack (f->frame).  Declare "before" and "quote" as objects that
>      need to be traced by the precise GC. */
>   ks_enter(f, GushInput *before; Gut quote;);
>   /* Make a high-level call to skin_parse_spaces (imported into the
>      current module). */
>   gut_call(f, skinParseSpaces, in);
>   /* Clone the input stream. */
>   gut_clone(f, in);
>   /* Assign the cloned pointer to the "before" temporary. */
>   ks.before = f->x.p;
>   /* Read from the input stream. */
>   gut_call(f, read, in);
>   gut_raw_integer(f, f->x.p);
>   c = f->x.i;
>   if (c == '(')
>     gut_call(f, skinParseList, in);
>   else if (c == ')')
>     /* Signal a condition, which is a restartable exceptions. */
>     gush_error(f, ks.before, "skin", "too many close parentheses");
>   else if (c == '.')
>     gush_error(f, ks.before, "skin", "unexpected improper list separator");
>   else if (c == '"')
>     gut_call(f, skinParseString, in);
>   else if (c == '-' || isdigit(c))
>     {
>       /* Restore the state of the input stream from the cloned copy. */
>       *in = *ks.before;
>       /* Parse the number. */
>       gut_call(f, skinParseNumber, in);
>     }
>   else if (c == '\'')
>     {
>       /* Implement syntactic quote sugar. */
>       gut_name(f, "quote");
>       /* Save a reference to the "quote" symbol. */
>       ks.quote = f->x.p;
>       /* Parse the next object. */
>       gut_call(f, skinParse, in);
>       /* Create a pair out of that object and the empty list. */
>       gut_pair(f, f->x.p, f->gut->empty_list);
>       /* Add the quote symbol. */
>       gut_pair(f, ks.quote, f->x.p);
>     }
>   else
>     {
>       /* Restore the input state. */
>       *in = *ks.before;
>       /* Call the name parser. */
>       gut_call(f, skinParseName, in);
>     }
>   /* Pop the stack frame without modifying the return register.
>      (Take the result of the last call as the value. */
>   ks_leave(f);
> }
> 
> There are other ks_*leave* macros that allow setting of the return
> register, and marking it as a gc root or a raw value.
> 
> You can see that this creates a much more asm-like flow.  There are
> very few expressions, just statements (nearly every function returns
> void).
> 
> Next on my agenda is actually implementing the mark-sweep collector,
> and after that, multithreading!  Whoopie!
> 
> As usual, the state of things is at:
> 
> http://michael.fig.org/figure.c
> 
> Figure.sln and Figure.vcproj are also there for the VC++ enthusiasts
> (but not yet tested for this latest iteration).  There is only dlopen
> to port to new platforms, everything else is ANSI.
> 
> That's all for now,
> 


_______________________________________________
fonc mailing list
[email protected]
http://vpri.org/mailman/listinfo/fonc

Reply via email to