Squeak is basically an operating system. One difference is that Squeak brings all of its objects into virtual memory at once. This is not so bad since "virtual" means objects that aren't used can reside on disk. But imagine if Squeak were as big as Windows. Traditional virtual memory schemes would not be appropriate, some form of virtual object memory would be needed (ala LOOM). But until Squeak gets large, traditional virtual memory will suffice.
Just like you add updates or install new applications in traditional operating systems, you would do the same in Squeak. In Windows, updates and applications come in as files (.dll, .exe, .txt, .dat,...). In Squeak, everything is an object, so updates and applications can come in as image segments (object clusters).
Unlike files, segments have pointers to other segments. This is actually good because it makes dependencies explicit. Files have implicit dependencies that have be interpreted. When installing a segment, other segments that it points to can be automatically installed (or installed later on demand). Segments will have to be globally unique, globally accessible, and versioned.
A module and its variables form the root of a segment. A module is an object with a set of variables, and a set of imported modules. Variables are named classes, selectors, and global/pool/class vars. Imported modules are other modules whose variables are visible to this module.
Every method is defined in a module (rather than its class) and is associated with a local or imported class and a local or imported selector (one of them has to be local). Message sends are also associated with a local or imported selector. Method lookup looks in the module of the selector then the module of the class, for each class in the receiver's super chain, until a matching method is found. This lookup cost is not critical, thanks to the VM's method cache, and future inlining JIT compilers.
Defining methods by module allows us to add methods to imported classes easily, without the need for delta modules. Changing a method is another story. This requires versions.
As I said before, a module forms the root of a segment. It and all its variables are added to the roots array, then the normal algorithm for extracting a segment is followed. All objects that are only reachable from the roots are added to the segment. Pointer to objects outside of the segment form the out-pointers of the segment. Out-pointers to imported module variables are typical. Out-pointers to other objects will force each of those object to create its own segment, and so on, until all segments only point-out to other module variables.
Each segment has different versions. However, each version must contain the same roots (interface) so they are backwards and forward compatible. Out-pointers specify which other segments they point to, but not which version. The user determines which version to load. Segment versions can be maintained as deltas/layers, and viewed/edited without being installed, ala PIE. Each segment also keeps track of which other segment versions point to it. This is useful for finding users/senders of module variables.
When Squeak is saved, segments that have changed are written out as new versions. The VM can mark that a segment has changed during writes to old space objects. Segments can be loaded linearly into object memory, so you can tell which segment an object belongs to just by its address. Upon save, new objects added to each segment can be moved down next to its segment. More details are needed but this is the jist of it.
The fact that the interface is fixed means you can never add variables to a module, unless it has no users (no other segments point to it). Instead you have to create a new module for the new variables and import the original module. This is ok since all variables in the original module are accessible via the import.
I know this requires image format changes. But that is what VI4 is all about. I would definitely like to explore this in VI4 or VI5.
Cheers, Anthony
squeak-dev@lists.squeakfoundation.org