If there is interest, I may write a detailed description of how the current Evlan implementation works. Such documentation would of course be necessary to allow people other than me to work on the source code. However, I believe that the current prototype implementation is, for the most part, done. Any future production implementation should probably be started from scratch, as the prototype code makes far too many assumptions which wouldn't be acceptable. (For example, none of the prototype code is thread-safe, as it assumes that the VM is single-threaded.)
For the time being, here are some key implementation details:
-
Code is not compiled to native machine instructions. However, it is compiled down to a relatively small assembly-like instruction set, which is then interpreted. In theory, these instructions could trivially be translated to machine code, although in practice I do not believe it is worth the effort to implement this for the prototype.
-
The garbage collector is custom-written and based on generational garbage collection. It runs once for every 64k of allocation (not including large array allocations), sweeping two generations at a time (generation zero plus one other).
-
Arrays of homogeneous primitives (i.e. arrays of all integers, all characters, etc.) are packed efficiently. In particular, character arrays will be packed using 8-bit, 16-bit, or 32-bit elements as necessary. Unless packed, however, values are represented using a 12-byte union (on 32-bit machines; will be 24-byte on 64-bit systems if they are ever supported).
-
Each time the persistent state is saved, all data which has changed since the last save is added to the end of the state file. Data already in the state file is not modified. The data written during one save is called a "frame". A separate file is kept along side the state file which contains an index of these frames. Thus, when Evlan starts up, it can restore any point in the state file's history, not just the last one. This also makes Evlan's state files are fault-tolerant; if a crash occurs while writing an update to the state file, the file remains usable.
-
The virtual machine runs in a single thread and uses event-driven I/O, including asynchronous file I/O where available. Evlan uses WSAAsyncSelect and overlapped file I/O on Windows. On FreeBSD and MacOSX, kqueue() and AIO are fully utilized. Linux, on the other hand, did not have support for AIO until late 2004 (many years later than most OS's). Because this functionality in Linux is not yet proven, and because most people don't have it anyway, the Evlan prototype will use blocking file I/O on Linux for the foreseeable future. This means that Evlan will have scalability problems on Linux, although it is only a prototype anyway, so you probably don't care. (This is why the evlan.org server runs FreeBSD, not Linux.)
The current implementation consists of some reasonably well-organized, well-designed code (mostly in the "compiler" package) and some messy, ad hoc code (mostly in the "vm" package). I apologize for the messy, ad-hoc code. But, again, it's a prototype, and was never really intended to be worked on by anyone other than myself.