|Anonymous | Login||01-17-2021 02:41 UTC|
|Main | My View | View Issues | Change Log | Docs|
|Viewing Issue Advanced Details [ Jump to Notes ]||[ View Simple ] [ Issue History ] [ Print ]|
|ID||Category||Severity||Reproducibility||Date Submitted||Last Update|
|0007650||[Squeak] System||minor||always||06-16-11 14:18||07-20-11 06:08|
|ETA||none||Fixed in Version||Product Version||4.2|
|Summary||0007650: calling storeString on a compiledMethod freezes the image|
|Description||I printed 'Object methodDict values first storeString' in a Workspace.|
|Steps To Reproduce|
(0014147 - 1268 - 1436 - 1654 - 1654 - 1654 - 1654)
#storeString runs into infinite recursion if the object graph to be serialized has a loop. Object methodDict values first is #checkHaltCountExpired (in my image) which references Smalltalk. Smalltalk is a global variable, it's value is a SmalltalkImage. The SmalltalkImage's globals variable points to a SystemDictionary which contains all global variables, including Smalltalk itself.
You could say that ReadOnlyVariableBinding (the class whose instances are used by CompiledMethods to point to globals in literals) could have a better #storeString implementation, but this is not enough to avoid loops in the object graph. E.g. if you evaluate the following method at least once, then #storeString will run into infinite recursion no matter what you do:
Object >> recursiveObjectGraph
| foo |
foo := #(nil).
(foo at: 1) ifNil: [ foo at: 1 put: foo ].
The real solution is to use an object serializer instead of #storeString if you want to serialize a CompiledMethod, or just use the source code if you don't care about state stored by the methods. There are several "old" serializers, like SmartRefStream, ImageSegments or SIXX and we also have new tools, like Fuel (http://squeaksource.com/Fuel/ [^] ) and StOMP (http://squeaksource.com/STOMP/ [^] ).
(0014148 - 752 - 835 - 835 - 835 - 835 - 835)
StoreString should be implemented to at minimum throw an error for classes that would otherwise send it into an infinite loop. Or just return a string saying x is not storable.
Better would be to sort things out so it works in most cases.
Above all someone needs to document what storeString can be expected to do and not do.
What I expect to get when I ask for a store rather than a print string is a re-compilable object no more complicated than the initializing selector sent to the class . E. G. If I type ' storeString' I would expect '' in response.
For a compiled method maybe I would just want a [ :var1 :var2 | <current method source> ] version of the method for starters.
Yours in curiosity and service, --Jerome Peace
(0014165 - 776 - 794 - 794 - 794 - 794 - 794)
The rule is simple: #storeString works iff the receiver's graph is a tree. If it's a DAG and not a tree, then the image won't freeze, but evaluating the resulting code will yield a different object graph (with a tree structure). If the object graph has a loop, then #storeString will get into infinite recursion.
The only way to avoid the last two cases is to mark the visited objects and reference them instead of serializing them onto the stream again (like #veryDeepCopy does). It would also be a two pass algorithm.
Also note that storeString won't work for large graphs, because the VM has some limitations for executed code (number of temporaries, literals, bytecodes, etc).
So I think #storeString shouldn't be used without a priori knowledge about the object graph.
(0014166 - 1415 - 1499 - 1499 - 1499 - 1499 - 1499)
Thank you for your insight.
This still begs the question however. Plus objects are avoiding a responsibility.
First, each object should know if it can reliably respond to #storeString: and if not give an error message. Allowing a default method going into an infinite loop breaks protocol. The user should not have to know how each object will respond before sending the message. That breaks encapsulation.
Second each object that can print itself should have a way of storeStringing itself. The object class should discern the difference between state variables and cache variables. There is no need to store cache variables. In the case of Morphs they could usefully store themselves with out their owners if they would take responsibility for adding their sub morphs.
There are time and commitment constraints in finding programmers who will take responsibility for writing the proper code. So the resources might not be there to solve the problem completely. So the first step should happen first then the second step as resources permit.
The current practice of blindly saving all ivars by index has got to be abandoned IMO.
The other part of this is I really want a storeString that works for most objects. Squeak needs a way of writing itself out.
Good low hanging fruit would be to get a test that indicates if an object can be trusted to respond storeString w/o an infinite loop.
|06-16-11 14:18||Lars||New Issue|
|06-18-11 22:35||leves||Note Added: 0014147|
|06-22-11 05:50||wiz||Relationship added||child of 0007640|
|06-22-11 06:15||wiz||Note Added: 0014148|
|07-18-11 21:34||leves||Note Added: 0014165|
|07-20-11 06:08||wiz||Note Added: 0014166|
| Mantis 1.0.8[^]
Copyright © 2000 - 2007 Mantis Group
50 total queries executed.|
36 unique queries executed.