On Fri, Jan 10, 2003 at 01:05:05PM +0100, Leopold Toetsch wrote:

> >While I'd like no stack walking, as it's pricey, I'm not sure it's 
> >tenable. 
> 
> As the current clone changes does show, it's possible.
> 
> BTW current tests do succed w/o stackwalking - its disabled.
> 
> >... Skipping it makes things rather more fragile, as it means that 
> >any code that may potentially trigger a DOD run while holding an 
> >unrooted object needs to root it temporarily, and that's a lot of code. 
 
Without the stack/register examination the following can occur (though nothing
does this yet)

1) A PMC is accessible from the root set when a vtable is called. Either via a
reference or being a member of an aggregate.

2) A vtable function obtains a PMC* to that PMC.

3) The vtable calls some code deletes the reference to the PMC, which is now
no longer accessible from the root set. The vtable then attempts to allocate
some memory.

The vtable function will now contain the only remaining reference to the PMC,
but unless the vtable function has added that PMC to the root set somehow it
will be collected prematurely.

This means that even some would that are already rooted need to be treated
specially. From this example, any object in an aggregate.

On a related note, I have been looking at implementation techniques for
incremental/generational garbage collectors. A critical aspect of a
generational garbage collector is a write barrier, which records any pointer
writes that create references to a generation from an older generation.

In the context of parrot this means identifying every place that a PMC pointer
is updated. The only portable way to do this is by explicit checks in the
interpreter and code produced by the JIT. The current flexibility in parrot
allows C code to freely update PMC pointers, so such checks would have to be
manually inserted in so many places as to become untenable.

The non-portable techniques for implementing write barriers include marking
pages read-only and trapping SIGSEGV's on any write or using the hardware dirty
bits to find pages that have been written. Besides portability, these
techniques are not really well supported by the operating system and have their
own inefficiencies.

I believe the above considerations present some basic choices:

1) Create new conventions for manipulating the interpreter state from C code
that that make all PMC pointers immediately accesible to the garbage collector.
(The infant mortality issue has started movement in this direction)

This will make parrot slower in general (The C compiler will be unable to
perform register allocation of many PMC pointers in addition to the additional
overhead), but makes a stop the world collector faster and allows an
incremental collector which can shorten the pauses due to collector runs.  It
also makes for more rules for core programmers or extension writers to follow.

2) Rework the implementation so that the vtables or any other opcodes that may
callback into parrot are entirely/mostly implemented in parrot ops that can be
JIT compiled. This way we can still get optimized vtable code that allows an
incremental collector.

3) Give up on a portable incremental collector and stick with the current stop
the world collector. Parrot's basic execution speed will be unchanged. By
trading heap size against frequency of collector runs, one could amortize the
cost of running the collector. Extension and core code programmers would never
have to think about the garbage collector in order to write correct code.

-- 
Jason

Reply via email to