2009/11/7 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Ah, I forgot to say that if you recompile the methodClass, it won't trigger recompilation of those unregistered methods. Some actions like removing an inst var can then trigger very bad things when you try to execute those unregistered methods, like corrupting memory.
A security in the class builder would be to: - mutate all unregistered CompiledMethod pointing to this methodClass  before the oldClass becomeForward: newClass
Then, a security in the VM should prevent those CompiledMethod mutant to be executed. (or maybe the mutant could simply be modified to send a message like self mustBeRecompiled).
What do you think of this one ?
I would just throw an error and prevent (oldClass becomeForward: newClass) before any unregistered methods is removed from system, or .. skip mutating (oldClass becomeForward: newClass) if such methods hanging around, to avoid possible problems, and let user to deal with obsolete classes. The less magic we have, the more predicatable system will be.
2009/11/6 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
Most CompiledMethod are registered in a methodDictionary. But some are not.
(CompiledMethod allInstances reject: [:e | e methodClass ~~ nil and: [e selector ~~ nil and: [e == (e methodClass methodDictionary at: e selector ifAbsent: [nil])]]]) size
This is often because a BlockClosure has been registered somewhere in a registry (a ServiceRegistry for example). The objects pointers chain is something like: a SeviceRegistry -> a ServiceAction -> a BlockClosure -> a MethodContext -> a CompiledMethod...
Another source of MethodContext instances is a concurrent Process running in the image.
If ever recompiled, a new instance of the CompiledMethod is installed in the methodDictionary. But the old CompiledMethod is still there, being pointed to by above chains. The old CompiledMethod has a source code pointer pointing to sourceCode somewhere in the change Log, and so far it's fine.
But what if you compress the change log ? The registered CompiledMethod all get a valid new pointer to the new source location. But the unregistered ones retain their old pointer now pointing randomly in the change file. This is bad.
(CompiledMethod allInstances select: [:e | e selector = #id:text:button:description:action: and: [(e methodClass methodDictionary at: e selector ifAbsent: [nil]) ~~ e]]) anyOne getSource
Now if you try to decompile the method, either there is an Error like here, or unfortunately the random sourceCode is valid a valid chunk of Smalltalk and you open the door to potentially strange things... It could be misleading if you try to understand what the hell this SeviceAction could be doing.
If you try to decompile the BlockClosure, and getSource does not point to valid code, it doesn't work, you get nil... This is another bug, because #decompile should revert to homeMethod decompile decompileString...
I propose that #condenseChanges and the like, anihilate source code pointers of unregistered CompiledMethod. This should solve the issue. What do you think ?
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
-- Best regards, Igor Stasenko AKA sig.