Eventually Smalltalk will no longer be needed by Avail. The migration path is as follows:
Hybridize the Avail interpreter. The current system is already a hybrid. The Smalltalk implementation of the virtual machine is sufficient to do everything the hybrid virtual machine can do, but not as fast. The hybrid virtual machine is a mixture of Smalltalk and C++ code, where the C++ code is a mechanical translation of some of the Smalltalk code. The C++ part can be enabled or disabled with the flip of a switch. This greatly simplifies debugging, and allows all the usual prototyping ability of Smalltalk until an implementation crystallizes, at which point the C++ part can be flipped on for speed (approximately tenfold).
The hybrid currently relies on Smalltalk to implement some features. For example, Smalltalk is responsible for allocating large chunks of memory in which to allocate Avail objects. Also, the Avail module browser window is written entirely in Smalltalk. Many of these features will eventually be translated or reimplemented in C++ (for speed). There's no rush to abandon the flexibility of Smalltalk yet, and it seems likely I will want to be able to "fall back" on the Smalltalk implementation whenever the C++ version becomes unreliable. This gives me the IDE and prototyping power of Smalltalk with the speed of C++, all at the flip of a switch.
I will investigate the possibility of making the "glue" required for Avail exactly match the "glue" required for porting Squeak. That would make new Avail ports as ubiquitous as Squeak. Note that this has nothing to do with using the Squeak VM, just the platform-dependent files that the VM interfaces to (e.g., for accessing a machine's sound capability, file system, event stream, sockets, etc).
Write a Level Two interpreter. In 1997 I had an interpreter that dynamically translated the Avail nybblecodes into Smalltalk blocks. These blocks could then be executed by Smalltalk (duh) in place of the nybblecodes. This code was (permanently) disabled when hybridization was started in late 1997. This is because of the overhead and complexity of the C++ implementation of the interpreter loop calling back into Smalltalk just to run short Smalltalk blocks.
In late 1999 I wrote what I call the Level Two interpreter. It uses a register based instruction set instead of the stack based one found in the naive nybblecodes (called Level One). The Level Two instructions are more suitable for optimizations, and are expected to execute much faster than the stack-based instructions, but the real speed improvement comes from the optimizer. Level Two instructions are similar to machine language instructions, and can be optimized with traditional optimization techniques (e.g., constant folding, inlining, common subexpression elimination, loop unrolling). This was made to work in Smalltalk in November 1999, and as of March 2000 I am still struggling to find enough time to get this translated to C++ (sigh). At least I managed to convert the garbage collector to be incremental in February/March 2000. Eventually Avail will be useable as a game platform because of this, I hope. Regardless, why should developers get a lower quality experience than gamers? Anyhow, I will publish a new release of Avail when the level two interpreter is running in C++.
Eventually Level Two code can be translated directly to the machine language of each target platform for an additional boost, but I want these code generators to be written entirely in Avail.
The Level Two recompiler can gradually be translated into Avail itself. It will be triggered in an asynchronous Avail thread or maybe by a VM interrupt, whenever a method is being called for the Nth time (where N can be tuned). The recompiler will produce something suitable for the Level Two interpreter to execute (but semantically identical to the original Level One nybblecodes), or invoke a "back end" (also written in Avail) to produce native machine code. Execution will then continue in the Level One thread that triggered this reoptimization. This scheme would remove all dependence on Smalltalk and C++, other than compiling the virtual machine executable during porting. This can even be tried out in the hybrid environment - Smalltalk code (or Avail code) can create Level Two wordcodes in non-Smalltalk memory, and then execute it via either a Smalltalk or a C++ Level Two interpreter. Likewise, Smalltalk or Avail code could create native translations of this, and execute it through a thin C++ interface.
Going one step further would incorporate all the C++ source code for the VM inside Avail. One more step would be to translate a metacircular VM written in a special "pidgin" subset of Avail into C++. The final step would be to generate only a nanokernel as an executable, and then to bootstrap the rest of the VM via a "pidgin" Avail-to-native translator written in Avail. VM "safety" will drop when native code generation occurs in Avail (not that a code generator written in C is any safer, just less likely to be changed by hackers). Coming up with a way of delivering modules without source code would elegantly solve this last problem.
At this point, Avail could run anywhere. Since representation and execution policies reside entirely in the VM, even multiple ports per platform would be useful. Imagine a slow VM that runs highly compressed Level One code on a Palm Pilot, as well as a fast VM that generates 68000 code dynamically on the same Pilot (using much more RAM).
(This page was last updated March 26, 2000)