Class side method is missing in obsolete class after the class is removed from system
Im writing some tests that needs to create classes dynamically. During the tearDown phase, i remove these classes using #removeFromSystem. I noticed that running these tests became more and more slower as i kept adding more tests. Using "Run Profiled" from Test Runner, i found out ChangesLog>>#logClassRemoved: was responsible of about 43% of the execution time: logClassRemoved: annoucement annoucement classRemoved acceptsLoggingOfCompilation ifTrue: [ self logChange: 'Smalltalk globals removeClassNamed: #', annoucement classRemoved name ]. Based on that, i overrided #acceptsLoggingOfCompilation on the new classes to avoid these changes being written down to disk (the classes are disposable after all), but ChangeSet kept doing it. I confirmed this by inspecting annoucement classRemoved acceptsLoggingOfCompilation which returns true, ignoring the overriding implementation i provided. #acceptsLoggingOfCompilation overriding implementation seems to be lost during the #removeFromSystem call. Specifically, during Behavior>>#obsolete, which is called during Class>>#obsolete "Change the receiver and all of its subclasses to an obsolete class." self == Object ifTrue: [^self error: 'Object is NOT obsolete']. self setName: 'AnObsolete' , self name. Object class instSize + 1 to: self classSide instSize do: [:i | self instVarAt: i put: nil]. "Store nil over class instVars." self classPool: nil. self sharedPools: nil. self hasClassSide ifTrue: [ self theMetaClass obsolete]. <======= HERE self propertyAt: #obsolete put: true. super obsolete. When i checked Behavior>>#obsolete, i found out the method dictionary is emptied, losing my implementation of #acceptsLoggingOfCompilation Behavior>>obsolete "Invalidate and recycle local methods, e.g., zap the method dictionary if can be done safely." self canZapMethodDictionary ifTrue: [self methodDict: self emptyMethodDictionary]. <======= HERE self hasTraitComposition ifTrue: [ self traitComposition traits do: [:each | each removeUser: self]] I don't know if this is by design or not, but it seems that the class that gets announced when removed, is not exactly the same as the original. Any thoughts/recommendations? -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
do you know that you can create class silently? so that you do not have to remove them from the log? Stef On Sat, Sep 23, 2017 at 10:33 PM, Nicolás Papagna Maldonado <nicolas.papagna@gmail.com> wrote:
Im writing some tests that needs to create classes dynamically. During the tearDown phase, i remove these classes using #removeFromSystem.
I noticed that running these tests became more and more slower as i kept adding more tests. Using "Run Profiled" from Test Runner, i found out ChangesLog>>#logClassRemoved: was responsible of about 43% of the execution time:
logClassRemoved: annoucement annoucement classRemoved acceptsLoggingOfCompilation ifTrue: [ self logChange: 'Smalltalk globals removeClassNamed: #', annoucement classRemoved name ].
Based on that, i overrided #acceptsLoggingOfCompilation on the new classes to avoid these changes being written down to disk (the classes are disposable after all), but ChangeSet kept doing it.
I confirmed this by inspecting annoucement classRemoved acceptsLoggingOfCompilation which returns true, ignoring the overriding implementation i provided.
#acceptsLoggingOfCompilation overriding implementation seems to be lost during the #removeFromSystem call. Specifically, during Behavior>>#obsolete, which is called during
Class>>#obsolete "Change the receiver and all of its subclasses to an obsolete class." self == Object ifTrue: [^self error: 'Object is NOT obsolete']. self setName: 'AnObsolete' , self name. Object class instSize + 1 to: self classSide instSize do: [:i | self instVarAt: i put: nil]. "Store nil over class instVars." self classPool: nil. self sharedPools: nil. self hasClassSide ifTrue: [ self theMetaClass obsolete]. <======= HERE self propertyAt: #obsolete put: true. super obsolete.
When i checked Behavior>>#obsolete, i found out the method dictionary is emptied, losing my implementation of #acceptsLoggingOfCompilation
Behavior>>obsolete "Invalidate and recycle local methods, e.g., zap the method dictionary if can be done safely." self canZapMethodDictionary ifTrue: [self methodDict: self emptyMethodDictionary]. <======= HERE self hasTraitComposition ifTrue: [ self traitComposition traits do: [:each | each removeUser: self]]
I don't know if this is by design or not, but it seems that the class that gets announced when removed, is not exactly the same as the original.
Any thoughts/recommendations?
-- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
Thanks Stef! I tried creating classes using SystemAnnouncer uniqueInstance suspendAllWhile: but this skips all subscribers, not only ChangeSet. That means that, say, RPackageTag instances won't contain the new class. Will use a workaround for now, as this is not the core of the thing im working on. -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
participants (2)
-
Nicolás Papagna Maldonado -
Stephane Ducasse