On Tue, 21 Oct 2003, Leopold Toetsch wrote:

> Dan Sugalski <[EMAIL PROTECTED]> wrote:
> > Since this has come up again, ...
>
> [ FYI: I was starting implementing this, based on a general traverse
>        vtable with callback functions. Two patches got backed out by
>        Dan after some discussion in PM ]

Right, because you'd implemented some stuff I'd specifically said we
weren't doing, and didn't back them out any of the times I asked...

> > ... and it's apparent that the last time around
> > I wasn't sufficiently clear, it's time to go through this again, and for
> > the final time.
>
> I'd be really happy, if you could go through my concerns mentioned in
> the summary in the thread:

That's why I did this, in part. It's the plan, until declared otherwise.

> >   PMC *thaw(interpreter, STRING *)
>
> This should IMHO be able to create constant PMCs out of metadata, e.g.
> for subroutine objects. So there should be some means to tell thaw() to
> create PMC(s) in the constant_pmc_pool.

There should be a way to put PMCs in the constant pool in general. I was
thinking a constant op would work--something like

   constant Ix, [SP]y

to make the string or PMC Y a constant at slot X in the constant pool.
Passing in the PMC header to be filled in also works, though both fail if
you want full PMC trees marked as constants since thawing out a PMC stream
may involve creating multiple PMCs. (In which case we might be better
temporarily switching allocation pools at constant creation time, rather
than passing in PMCs)

> > 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)

> >   1) Freezing at the destruction level may *not* use any additional memory
> >      for object traversal
>
> What is "Freezing at the destruction level"? Is this anyhow related to
> destruction ordering?

No. There are some valid cases where an object, after having been declared
dead by the DOD, wants to serialize itself. Persistent object stores
apparently do this, and it makes a certain amount of sense--when the
object goes out of scope the current state is flushed to disk.

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.

> > Note that I do *not* want to have multiple object traversal systems in
> > parrot! We have one for DOD, and proposals have ranged upwards from there.
> > No. That is *not* happening--the chance for error is significant, the
> > side-effects of the error annoying and tough to track down for complex
> > cases (akin to the trouble with tracking down GC issues), and just not
> > necessary. (Perhaps desirable for speed/space reasons, but desirable
> > isn't necessary)
>
> DOD's mark() routine has different requirements then a general
> traverse() for freeze(), chill(), clone(), and destruction ordering.
> Using just mark() will have these side effects that you want to avoid.

The only thing that mark does that the general traversal doesn't, in the
abstract, is flip the object's live flag. Everything else is an
optimization of code which we can, if we need, discard.

> 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.

> mark() is called permanently in a running interpreter, that does non
> trivial things. There are shortcuts for scalars, DOD is highly optimized
> not to destroy cache coherency. Using mark() also implies to back out
> my small PMC patches. All the advantages of smaller scalars are gone
> then.

All of this stuff for freezing is going to end up killing the small PMC
patch anyway, unfortunately, since we're going to have to be able to
traverse PMCs in the destruction phase, which means we have to have the
means of traversal at hand as we can't guarantee that we can allocate more
PMCs or resize the PMCs ext data.

> 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.

> > ... This is something that's hidden under a number of layers
> > of API, so regardless of the outcome it doesn't affect the assembly, PMC,
> > or runtime API.
>
> So when its hidden, I really don't understand, why you are insisting on
> an (IMHO) suboptimal design.

YHO, in this case, turns out to not consider all the issues involved.
Either way, we do it this way for now. Once the implementation of the
specified API is in, we can fight over reworking the internals.

                                        Dan

Reply via email to