On Tue, 21 Oct 2003, Juergen Boemmels wrote:

> Dan Sugalski <[EMAIL PROTECTED]> writes:
>
> [...]
>
> > > > The chill and warm runtime methods take a PMC or a frozen representation
> > > > of a PMC (respectively) and provide a human readable version of that PMC.
> > >
> > > I dunno, why chill() is superior to dump() or pretty_print(), but the
> > > name doesn't really matter.
> >
> > The important thing is that it's not a vtable method. It's a function that
> > belongs in the freeze/thaw API as it's just an alternate encoding or
> > decoding. (Arguably it ought not be a separate API entry at all and just
> > another encoding scheme, but that requires transcoding serialization
> > forms, and I'd rather not get into that)
>
> This is really just a naming problem. Dan wants to call the
> vtable-function freeze and have different encodings for all kinds of
> dumping/pretty_printing/marking. Leo calls the function traverse and
> controlls it by callbacks.

It's more than just a naming issue (or if it is, then traverse is the
wrong name). The traversal must be done externally, since we can't be
recursive.

Mark puts a PMC on the list of PMCs to be frozen. Freeze dumps the
PMC being frozen (and *only* that PMC) to the stream. The freeze routine
for a PMC must mark (generally indirectly by calling the "add this pmc to
the stream" api function) any PMCs that it needs to be in the stream.

The external function that traverses this list of PMCs to be dumped is
responsible for making sure there are no duplicates--the easiest way is to
do what the DOD sweep does and note that a PMC has already been put on the
list and thus not mark it.

Mark and freeze are separate, though related by the subsystems that use
them.

> This is a question of what is allowed at destruction time. You don't
> want to allow memory allocation, but allow freezing. That gets hard,
> because you need at least allocate the STRING where you want to put
> your frozen stream.

It's more a question of what we we require the engine to do, vs what user
code is allowed to do. A user program is allowed to write code that can
fail at destroy time, however the infrastructure we provide (including, in
this case, freezing--while I don't like it there's no choice) can't fail
that way. It's the reason the DOD and GC systems don't allocate memory (or
didn't--they shouldn't) when they run. The engine's not allowed to have
failure modes in critical sections.

Basically the engine may fail because of user code, but user code can't
fail because of the engine. It makes some things annoyingly restrictive,
but some problems are inherently annoyingly restrictive.

> > It puts a number of unpleasant constraints on the core freeze routines.
> > User code can violate them and take the consequences, but we can't.
>
> We can call (hopefully) arbitary user code in destruction routines. So
> this argument does not count

See above. User code can fail, we can't.

> >> A general traverse() can be depth first of breadth first, mark() isn't
> >> required do have any specific ordering as long as it sets live bits
> >> everywhere.
> >
> > I'm pretty sure that with a singly linked list we can get a generally
> > properly-ordered flattened tree without having to do an insane number of
> > passes across the dead object store. I may be incorrect in this, but I
> > don't think so, and for our purposes the live bit can be safely ignored if
> > we end up setting it, though potentially with another pass over the dead
> > store, which may end up prohibitively expensive. We'll see.
>
> I'm pretty sure that a singly linked list is not enough. I had done
> some experiments with this. One pass my be enough, but you need to
> keep track of the tree-traversal and of the partial ordered
> list. These to things don't play well together. Maybe this can be cut
> down to two lists, or one list and one bit per pmc.

There may be a little more infrastructure--I've not dug out the algorithms
books and gone hunting. The common algorithms tend to cheat by just
dodging the whole problem. :)

> Destruction ordering just enforces that small PMCs can't have
> destructors. If they have destructors they must be big, big enough to
> construct the ordered list of objects without allocating any memory.

Can't have destructors *or* refer to PMCs that may either have a
destructor or (indirectly) refer to a PMC that has a destructor.

If we have 2 PMCs with destructors they may be connected by a chain of 100
PMCs that don't, but we still need to walk that chain.

> If you think about it: The call to the destructors is done after
> free_unused_pobjects completed. The memory of the objects without
> destructors is already freed.

Then we reorder. This can't happen, and it didn't used to happen--if
that's how it works now then there's a bug in the DOD system. *All*
destructors *must* be called before any headers are collected.

> >> While freeze() and friends have to pull in each PMC into the cache, just
> >> setting the live bit on a PMC hasn't. Further: Lukes proposal for
> >> speeding up timely destruction puts objects either in front or at the
> >> end of the next_for_GC chain. This IMHO implies that mark() is unusable
> >> as your general and solely iterator.
> >
> > We may end up playing macro games with the code. I can live with multiple
> > instantiations of the code, but I want only a single chunk of source to be
> > maintained.
>
> You know we already have two versions of pobject_lives lying around.

Then we need to fix that, too.

                                                Dan

Reply via email to