The LSWVST Virtual-Machine ( LSWVST-VM ) is written in LSWAsm a proprietary stand-alone Assembler. The LSWVST-VM doesn't require any additional Libraries and can be reduced to a size of only 30 KB.
There exist several flavours of the VM ( in the subfolder of LSWVST installation directory Virtual-Machines:
Filename | Description | Size |
LSWVST-dev-W32-exe | full development VM including JIT-Engine | 130KB |
LSWVST-dev-vse-W32-exe | dev. VM + VSE Image, SLL & Primitive compatibility | 140 KB |
LSWVST-rtm-W32.exe | full runtime engine, excluding JIT-Engine & Development Primitives | 60 KB |
LSWVST-rtm-min-W32.exe | minimal runtime engine without Float Support & Startup-Support & Dump Support | 30KB |
LSWVST-dev-WCE.exe | full development VM including JIT-Engine for Windows CE | 130 KB |
LSWVST-rtm-WCE.exe | same as *-rtm-W32.exe for Windows CE | 60 KB |
LSWVST-rtm.min-WCE.exe | same as *-min.rtm-W32.exe for Windows CE | 112 KB |
LSWVST-dev-linux-ubuntu | full development VM including JIT-Engine for Linux/Ubuntu | 126 KB |
LSWVST-rtm-W32.dll | full runtime VM including JIT-Engine for DLL's | 50 KB |
LSWVST-rtm-WCE.dll | same as *-rtm-W32.dll for Windows CE | 50 KB |
LSWVST-rtm-W64.dll | same as *-rtm-W32.dll for Windows 64Bit | 80 KB |
LSWVST-rtm-W32.sys | full runtime VM including JIT-Engine for NT Driver's | 160 KB |
LSWVST-OS32.img | Experimental operating system including full development VM including LSWASM + Debugger , JIT-Engine for OS-Development and over 20000 Classes | 40 MB |
LSWVST-dev-W64.exe | full development VM including JIT-Engine for Windows 64Bit | 160 KB |
LSWVST VM's can be indiviually configured, it is possible for instance to take out the Float or threading-support. The JIT Engine can be configured to add ANC support which adds about 100 KB in size.
The LSWVST-Smalltalk-Object images can be stored within the Virtual-Machine executable.
In the days of .NET and managed-code it is not easy to rectify the development of an own virtual-machine. Our philosophy is to have the deepest operating-system-Integation of Smalltalk which is possible. The next operating-system from Microsoft - may expose some of its operating-system functionality only in form of managed-code. This means for a Language which relies on its own virtual-machine which traditionally includes a "Just-In-Time" compiler a serious integration problem.
There exist several options:
We decided for 2, 3, 4 and 5,8.
Our VM executes Bytecode with traditional JIT or adaptive compilation to Native Code, which is something similar to JIT. We don't call it JIT because there are some big technology differences between Just-in-Time compilation in Java or .NET and the ANC Compilation of our Smalltalk-VM. Bytecode is used at Development-time - which is translated on-the-fly to Native-Code. For a Production-Image we take out the Native-Code-Generation.
There are several options in our Virtual-Machine:
a) Traditional JIT of Bytecode - usually used in a Development-Scenario.
b) Compilation to Abstract-Assembly-Code which can be translated in Zero-Time to Machine-Code at Program-Load-Time.
c) Compilation to Pure-Assembly-Code
Option b and c gives Assembly-Code which is faster than C-Code.
We have an MSIL-Interpreter which executes MSIL which is loaded by our Reflection engine. Of course this is an order of Magnitude slower than execution on the .NET CLR. But it gives us the Opportunity to speed up development for .NET. Our .NET Code need to be recompiled if we change Classes add/remove Methods.
Our Native Callout Interface follows the accepted way found in other Dialects.
Look at the example of a Smalltalk-Method defined in the class UserDLL with a Resource statement ( < ... > ) in the body.
messageBeep: anInteger
<api: MessageBeep ulong boolean>
^self invalidCallout
We have added a new .NET Callout Interface to our Smalltalk. Look at the example of a Smalltalk-Method defined in the class SystemWindowsFormsAssemblyDLL with a Resource statement ( < ... > ) in the body.
messageBoxShow: messageString caption: captionString buttons: buttons
<.NET: DialogResult System.Windows.Forms.MessageBox.Show string string
MessageBoxButtons>
^self invalidCallout
Both forms of Callouts are heavily optmized. Callouts can be recursivley interrupted by means of Callins. A special form of a Callin is a WM_ message sent which will be handled by a NotificationStrategy object in the Process-Object receiving the WM_message.
Our carefully designed Virtual-machine is stateless and this means that the VM behaves as a "First-Class" Object in the sense of the Operating-System or the outside world.
It is very essential to have an opimized Callout Interface for overall execution speed of Smalltalk-programs in LSWVST. We tried to achieve almost the same speed for Callouts as Primitive calls.
Adaptive compilation to Native Code - in short ANC is a technique that goes beyond JIT - and we can beat C-Programs with execution speed. Why Smalltalk is said to loose speed - for instance because of its runtime type checking - why can be a technique which executes Smalltalk faster than C ?.
Compilation to Machine-Code for traditional Languages means traditionally Analysis ( Control-Flow, Data-Flow, Dependence and Alias Analysis ) , Optimization ( Register Allocation, Code-Scheduling, Control-Flow Optimization & more ). These complex techniques leads to highly optimized Native-Programs and it is evident that JIT cannot compete with these Compile-Time techniques. In Languages like LISP or Smalltalk, Java or C# most these techniques cannot be applied at all. But JIT can do better than traditional compilation in dynamic optimization because if we encounter an operation we now about how often it is already executed - we don't need much Analysis we can do Statistics. The drawback about JIT is that often it has to be reexecuted each time the program is invoked.
But again can we do better than JIT. Sure we can compile using Profiling information - that take statistic overhead out of JIT - allows to use many of global optimization techniques from traditional language compilation and leads to what we call "Adaptive Compilation".
Our Smalltalk-Compiler can produce Abstract-Native-Code which is transformed at Installation-Time to Real-Native-Code when we know on which Processor architecure we should run.
A big advantage of todays OO Languages are the automatic memory management features. A program - the Garbage collector which is executed "in parallel" takes care of memory occupied by objects which are no more referenced and recycles it automatically. Hardcoded mechanisms to avoid Garbage are available - e.g. Allocation of local variables and value types on the Stack instead of the Heap - which is maintained by the Garbage Collector.
We have decided to extend these mechansimns to allow full control by the programmer - we have added a number of MemoryManagement Strategy classes which can be used to allocate memory in a more controlled way - also an extended Collection framework is created to allow Collections of same or similar objects to be handled efficiently.
We call these technics Garbage avoidance supported by our Object memory recycling and Object lifetime management frameworks.
The collection framework of Smalltalk is very simple and powerful - but also inefficient. In Smalltalk everything is an Object and objects are boxed. For Isomorphic Collections - collections of objects of a known species we can make a lot of optimizations.
Primitives are methods executed by the VM. In Smalltalk they look like
SessionStrategy>>primSaveSessionToFile: sName
description: sDescription options: iOptions
<primitive: PrimitiveSaveSession>
^ self primitiveFailed
<PrimitiveSaveSession> is a constant from the Pool-Dictionary PrimitiveNumbers ( with the value 121).
The Primitive itself knows the number of Arguments. They are pushed from lowest to highest onto the stack. In case of success the Primitive removes the Arguments from the stack. Here comes another reason for having a Smalltalk - Specific debugger environment - to see the callstack the debugger must have knowledge which functions are smalltalk-primitives.