> Remember that the higher level (eg perl6) will expect to be able to find the
> PMC afterwards. For example:
>
> $foo = "abc";
> $bar = \$foo;
> print $$bar;
> $foo = 3;
> print $$bar;

This depends upon how variables and the registers interact. If, like a
real CPU, registers must be stored back into traditional memory as
variables, then there is no problem. Code looks something like:

#$foo = "abc";
new P0, PerlString
set P0, "abc"
stash_store P0, "foo";
#^ or however we store into the current stash, or global stash

#$bar = \$foo;
new P1, PerlRef
set P1, "foo"
#^ or whatever namespace we are in. it could also be a pointer
#to some particular point in the stash, or whatnot.

#print $$bar
deref P2, P1 #put the PMC pointed to by P1, into P2
print P2

#$foo = 3;
new P0, PerlInt
#^ not strictly necessary, but it makes a new PMC,
#which is necessary for this example
set P0, 3
stash_store P0, "foo";

#print $$bar
deref P2, P1
print P2

If instead, registers are aliased onto traditional memory variables, such
that a PMC pointed to by a register is *also* pointed to by a stash
somewhere, then it's a bit harder.

One approach that's an extension of my previous idea (where we obliterate
the destination PMC), is to change the PMC* of registers to PMC**. This
allows us to support the example you mentioned, and also allows us to
blindly obliterate whatever value is in the destination with our newly
constructed PMC, assued the old one will be properly GC'ed. This is
currently the approach I am leaning towards, if registers are aliased
onto variables. (Otherwise I prefer the approach mentioned above, which is
more inline with traditional register architectures.).

I thought about leaving PMC*'s and doing a memcpy over it, but that's a
'bad thing' in terms of support PMC-header custom DOD routines.

Another example of the ugliness in terms of supporting the GC for the
PMC's is:

STRING* s = string_copy(INTERP, (STRING*)SELF->cache.struct_val);
dest->cache.struct_val =
    string_concat(INTERP,
                  s,
                  value->vtable->get_string(INTERP, value),
                  0
                 );
/* don't destroy s, as it is dest->cache.struct_val */


What's the point of making a copy of that string? I don't really know,
and I don't see the point. The comment at the end doesn't help any, either
.. I'm hoping it's just code written under false assumptions.

Right now, it's not GC safe since 's' is not traceable, and if a dod run
occurs, s will be GC'ed. Same thing for the 'get_string' result, which is
also not traceable from the root set. To make this GC-safe, we need to:

a) store them all in temp variables
b) mark them as immortal/immune
c) operate on everything, get the result, and store it
d) unmark them

If we had C++, we could do all sorts of nice tricks with objects and
deterministic destruction at code block end. But we don't. This leads to
verbose code that's not easy or intuitive to write, with every PMC method
needing to do the above abcd logic to operate on variables.

Thoughts or comments?
Mike Lambert

PS: If you want, I can submit a patch that fixes the GC bugs in the
current system, leaving the semantics the same. It's just going to be
extremely ugly, verbose, and not nice to look at. (And not fun for me to
write, either.)

Reply via email to