I'm stuck at a fork in terms of how to fix this particular GC problem. First, I changed all the direct vtable changes to use morph(). Morph does a: destroy(), vtable change, and an init(). This is required because some PMCs require GC-related initiailization, such as PerlStrings, which need to stick a String in the data pointer, and set the buffer_pointer flag.
Now take 'concat P0, P0, P0', where P0 is a PerlString. It needs to be implemented as: dest->vtable->morph(interpreter,dest,enum_class_PerlString); dest->data = string_concat(interpreter, pmc->data, value->vtable->get_string(interpreter, value), 0 ); The problem with this, is that by the time it goes to concat, the string has been lost due to morph'ings init(). The hack fix to solve this is to store the result of the concat in a temp variable, morph dest, and then set its data field. But this could cause problems where the temp var gets GC'ed during the morphing init(). Immortal/immune could be of help here, but I don't think this is heading in the right direction, since it's just making the programmer's life too confusing. A second approach is to throw out this weird transmogrifying class stuff, and just construct a new PMC of the appropriate type to put into the destination register. Why would we *ever* care what's in the destination register, since it never gets it's vtable methods called. We just go in and blow it's data away anyway. With the GC system we have now, we can leave PMC headers sitting on the wayside, and it will get collected. So if we construct a new PMC of the appropriate type to store into the destination register, it becomes GC-safe, easier to program, and we don't need to 'set' a new PMC into the dest register before we operate on it. I'm not sure what the original reasoning was for the way things are now, but I didn't want to go through and change the way the things worked without checking to be sure it's the right thing to do. Anyone have any objections to changing around the perl* classes to work this way? Mike Lambert