> 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