At 07:34 PM 3/29/00 -0800, Dan Ingalls wrote:
... If we are talking about putting contexts in the hardware stack, I did this half a decade earlier. Smalltalk-78 ran on a 4MHz 8086(*). The VM was 6K of code. And it put its contexts right in the hardware stack. I also used the trick of overlapping adjacent contexts so there was no need to transfer arguments (Ian and I have been discussing doing this for Squeak -- it requires pushing the receiver last instead of first). ...
Pat Caudill and I did something similar in Tektronix Smalltalk but did not have to change the push order. Probably the most interesting aspect of this implementation was that we used two stacks to cache the active contexts. One stack (the "object stack")contained the args/temps/evaluation-stack and the other stack (the "control stack") contains the control data (IP, method pointer, home pointer, etc.). The object stack used overlapping stack frames and only contained oops. The control stack only contained machine addresses. Object stack frames are variable sized, control stack frames are fixed size. The control stack state was design such that it could address into either the object stack or into a heap allocated context object in a manner that was transparent to the bytecode implementations. Thus there was no need to re-cache a context if it had been flushed to the heap.
The use of the two stacks eliminates almost all of the complexity of "parsing the stack" by the GC or when reifying the stack. In general we have been very happy with the two stack model. Subsequent to the Tektronix implementation we have used it with success in all of our VM designs as well as a Java runtime environment that we designed.
Much of the complexity of context caching schemes arises because in the most general case a Smalltalk-80 context aggregates into a single object entities with inherently different lifetime extents. Some entities("the activation record") have LIFO extents others ("block objects", variables referenced from blocks, etc.) have indefinite ("heap") extents. Things get much simpler if the architecture explicitly separates the entities with different life cycles into separate objects. For example, the Smalltalk compiler can easily identify which local variables are solely referenced from within a single activation and which are "captured" by a block with indefinite extent. With this knowledge it is possible to place the captured variables in a heap allocated "environment" object while placing all other local variables in a stack allocated activation record. Different bytecodes are then used to distinguish between accesses to "stack" or "heap" allocated variables.
All of the Digitalk Smalltalk virtual machines used architecturally explicit stacks in this manner. One of last of these designs is documented at: http://www.smalltalksystems.com/publications/avmarch.pdf.
Allen_Wirfs-Brock@instantiations.com
squeak-dev@lists.squeakfoundation.org