yet another smallest snapshot, and a visualization
craig at netjam.org
Sat Jan 21 01:01:04 UTC 2006
The short answer is that you can leave out a lot of things when you
know you're going to terminate within a few instructions. :)
> My crude unerstanding of Spoon is that many other objects are
> dynamically faulted into this tiny image at run-time (to do the 3+4),
> is this right?
This snapshot is not one that can grow into something more useful. It
was just an experiment to see how small a snapshot I could make, with
the new system tracer I wrote. I'm still working on a small growable
system (currently 162k uncompressed), which does operate as you say (in
addition to performing some other tricks).
When you run the 1337 snapshot, the virtual machine gets the object
address ("oop") for the special-objects array from the snapshot header
(first 60 bytes). Indirectly from that array (through the Processor and
its active process) it finds the active context and continues execution.
The instructions executed come from a method used by the context. The
instructions are: push (3), push (4), add, send (#quitPrimitive). The
send invokes >>quitPrimitive, another method. That method terminates the
virtual machine via a primitive. The virtual machine needs to look up
>>quitPrimitive in the method dictionary of the class of Smalltalk, a
literal association in the literal frame of the initial context.
In the above, we've touched the following objects from the snapshot
file, in the following order:
1. the special-objects array
2. the global Processor association
3. the Processor
4. the active Process
5. the active Process's suspended context
6. the now-active context's method
7. the symbol #quitPrimitive from the context's literal frame
8. the global Smalltalk association
9. the system dictionary (Smalltalk)
10. class SystemDictionary
11. SystemDictionary's method dictionary
12. SystemDictionary's method dictionary's association array
13. nil (touched during method lookup)
14. that array's association for key #quitPrimitive
15. the value for key #quitPrimitive (the second method)
The method dictionary of the first method is in there also, as is true
and false, making 18 objects. (The numbers 3 and 4 are immediates in the
first method's literal frame.) I could kill those last three, but I
declared victory when I got the thing under 1,337 bytes. :)
I did all this using a system tracer implemented as a specialization of
the virtual machine simulator. It's a simulator which keeps track of
every object it touches as it runs. At any point, you can stop it and
investigate the touched objects (read descriptions, follow pointers,
etc.). Their cached oops are properly remapped during garbage
collections. I used this information to guide a final garbage collection
with extremely aggressive mark phase (basically, only mark the touched
objects, and don't trace them), then just wrote a snapshot normally.
> To do 3+4, you have to send a message (#+)...
No, it has its own instruction ("bytecode").
> ...to an instance of SmallInteger (ok, maybe just the immediate
Right, small integers are immediate.
> Still, you have two CompiledMethods in there, so you have
> CompiledMethod class (but obviously not all of its superclasses).
> Classes have a lot of information, how can all this fit into 18
As you can see (hopefully) from the above, the only class we need is
the one for the method for the single message-send we're doing
(>>quitPrimitive). And the only one of its fields we need is the one for
its method dictionary.
> So are you able to measure how many objects are faulted [into the
> growable sytsem] at run-time?
> I just want to learn, thanks...
Thanks for asking! It was good to write this down.
improvisational musical informaticist
Smalltalkers do: [:it | All with: Class, (And love: it)]
More information about the Squeak-dev