Piers Cawley wrote:
> 
> The Perl 6 Summary for the week ending 20030601
>     Another Monday, another Perl 6 Summary. Does this man never take a
>     holiday? (Yes, but only to go to Perl conferences this year, how did
>     that happen?)
> 
>     We start with the internals list as usual.
> 
>   More on timely destruction
>     The discussion of how to get timely destruction with Parrot's Garbage
>     Collection system continued. Last week Dan announced that, for languages
>     that make commitments to call destructors as soon as a thing goes out of
>     scope, there would be a set of helpful ops to allow languages to trigger
>     conditional DOD (Dead Object Detection) runs at appropriate times.
>     People weren't desperately keen on the performance hit that this entails
>     (though the performance hit involved with reference counting is pretty
>     substantial...) but we didn't manage to come up with a better solution
>     to the issue.
> 
>     http://xrl.us/iu5

I'd like to reiterate (and clarify) my idea, of a hybrid scheme
combining refcounting and DoD.

All values needing timely destruction would inherit from a class
RefCounted.  They should (in the normal scheme of things) be stored in
variables with an "is refcounted" trait (or a trait which inherits or
includes that trait, if that's possible).

Hopefully, only a *small* number of objects in a system need timely
destruction, and (for best performance) all variables which will hold
those objects will have the "is refcounted" trait set on them.

(If most or all objects needed timely destruction, then we wouldn't be
moving away from perl5's pure-refcount GC, would we?)

All operations on a variable or variables having the "is refcounted"
trait result in opcodes to call the refcount(inc|dec) method(s) of the
values in those variables.

Under normal circumstances, when a refcounted value's refcount goes
to zero, it self destructs^W^W cleans itself up.

This is quite perl5-esque, and of course slower than simply letting
the DoD-GC handle everything, BUT, in the absence of circular reference
loops, it does produce timely cleanup of those objects which need it,
which pure-DoD wouldn't, and DOESN'T result in numerous, and thus
expensive, requests for full DoD runs.

For all of the other schemes, full DoD runs would be run on every scope
exit, even if there's only one single variable in scope which needs
timely destruction.

Here's where the non-normal circumstances are described, and how they're
handled:

It's legal for a refcounted value to end up referenced by a non-
refcounted variable.  This has to be so, since adding the "is refcounted"
trait everywhere would get cumbersome; also we may sometimes *need*, for
one reason or another, to store refcounted values in the same containers
which also hold non-refcounted values.

Thus, if a refcounted value gets stored in a non-refcounted variable,
then that value could quite easily still be reachable when it's refcount
goes to zero.  Obviously, when this is the case, we need to avoid a
premature cleanup.

To avoid premature cleanup, any time that the contents of a
refcounted variable is assigned to a non-refcounted variable, an opcode
to set a "reachable by non-refcounted variable" flag on the value
precedes the assignment.  If a refcounted values's refcount goes to
zero, and it has this flag set, it does NOT self-destruct[*].

A global counter keeps track of how many values have a refcount of zero
and have this flag set.

>From here, we are in a similar situation as other proposals -- for the
timeliest possible destruction, then on every single scope exit, we
check if this global counter is nonzero, and if so, do a DoD run.

For potentially less timely destruction, we do this check whenever we
leave a scope where a refcounted variable was declared, but not when
we leave other scopes.

Which of these two is done is a choice of the language designer, but
might possibly be controlled by a pragma.

Note that in the absence of marking any variables with the "is refcounted"
trait, and with the use of the first option here (at every scope exit,
check the counter and maybe do DoD), this scheme behaves *identically*
with one of the other schemes proposed.

It would be *no* slower at run time, since the refcount(inc|dec) methods
are only called when doing operations dealing with variables with the
"is refcounted" trait, and if noone uses that trait, there's no extra
work.  DoD would be a tiny bit slower with my scheme than the other,
due to the extra flag checking, but (assuming that *most* code with
objects needing timely destruction properly marks it's variables with
the necessary "is refcounted" trait) that's a small price to pay for
doing fewer DoD runs.

[*] How does this flag get cleared, you might ask?

Simplest would be to not clear it at all.  This would be mostly harmless
in terms of when objects get destructed, but would probably result in
more DoD runs than we really need -- blech. [**]

A more "proper" solution would be to clear it during/after each DoD run.

During the course of a DoD run, when we look for what PMCs are reachable,
we keep track of what each thing was reachable *from*.

If a PMC was found to be reachable through a non-refcounted variable,
then we set a flag saying so.  At the end of DoD, every reachable refcounted
value which has the first flag set, but this other flag not set, gets it's
first flag cleared.

[**] Please note:  Never doing any checking or attempting to clear this
flag (and not adding any "is refcounted" traits to variables) would
result in my scheme having the EXACT same performance as the other
proposed scheme, and not be a single bit slower.

-- 
$a=24;split//,240513;s/\B/ => /for@@=qw(ac ab bc ba cb ca
);{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print "[EMAIL PROTECTED]
]\n";((6<=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))&&redo;}

Reply via email to