Hello,
In order to load muO in the latest Spur image, I had to reintroduce the
garbageCollect that has been deleted from method #update:to: in
ClassBuilder.
There is a verbose discussion in both the previous and current
implementations of this methods.
From nice 3/10/2013, we read (talking about the Smalltalk
garbageCollect bit):
"Warning: Read this before you even think about removing the GC. Yes,
it slows us down. Quite heavily if you have a large image. However,
there's no good and simple alternative here, since unfortunately,
#become: does change class pointers. What happens is that after the
above become all of the instances of the old class will have a class
pointer identifying them as instances of newClass. If we get our hands
on any of these instances we will break immediately since their expected
instance layout (that of its class, e.g., newClass) will not match their
actual instance layout (that of oldClass). And getting your hands on any
of those instances is really simple - just reshaping one class two times
in rapid succession will do it. Reflection techniques, interrupts, etc.
will only add to this problem. In the case of Metaclass things get even
worse since when we recompile the entire class hierarchy we will
recompile both, Metaclass and its instances (and some of its instances
will have the old and some the new layout).
The only easy solution to this problem would be to 'fix up' the class
pointers of the old instances to point to the old class (using
primitiveChangeClassTo:). But this won't work either - as we do a
one-way become we would have to search the entire object memory for the
oldClass and couldn't even clearly identify it unless we give it some
'special token' which sounds quite error-prone. If you really need to
get rid of the GC here are some alternatives:
On the image level, one could create a copy of the oldClass before
becoming it into the new class and, after becoming it, 'fix up' the old
instances. That would certainly work but it sounds quite complex, as we
need to make sure we're not breaking any of the superclass/subclass
meta/non-meta class variants.
Alternatively, fix up #becomeForward on the VM-level to 'dump the
source objects' of #become. This would be quite doable (just 'convert'
them into a well known special class such as bitmap) yet it has problems
if (accidentally or not) one of the objects in #become: appears on 'both
sides of the fence' (right now, this will work ... in a way ... even
though the consequences are unclear).
Another alternative is to provide a dedicated primitive for this
(instead of using it implicitly in become) which would allow us to dump
all the existing instances right here. This is equivalent to a more
general primitiveChangeClassTo: and might be worthwhile but it would
likely have to keep in mind the differences between bits and pointer
thingies etc.
Since all of the alternatives seem rather complex and magical compared
to a straight-forward GC it seems best to stick with the GC solution for
now. If someone has a real need to fix this problem, that person will
likely be motivated enough to check out the alternatives. Personally I'd
probably go for #1 (copy the old class and remap the instances to it)
since it's a solution that could be easily reverted from within the
image if there's any problem with it."
In the current version we read:
"eem 5/31/2014 07:22 At this point there used to be a garbage collect
whose purpose was to ensure no old instances existed after the
becomeForward:. Without the GC it was possible to resurrect old
instances using e.g. allInstancesDo:. This was because the
becomeForward: updated references from the old objects to new objects
but didn't destroy the old objects. But as of late 2013/early 2014
becomeForward: has been modified to free all the old objects."
This latest statement may not hold true, since I could not load muO due
to "Metaclasses can only have one instance" errors (originating in
ClassDescription>>#updateInstances:from:isMeta:.
Stef