Disclaimer: I am not experienced at this, so I might use the wrong
terminology, or have some totally stupid ideas. The point is to
learn by doing, and sometimes that involves failing and looking
Now having said that...
Last night I started working on a project that I've been toying with
the idea of for a while.
I want to make a virtual machine that meets all the following
Portable, with no weird dependencies. Should just compile with my
utilities library and standard C++. Should run on every platform
supported by C++.
Sandboxable. Should be able to run untrusted code. (Lua is not
built for this.)
Really fast. As fast as possible without just going and writing a
JIT. (Don't want to deal with individual platform weirdness just
Pause/resume capable. (Something DerpScript is not.)
Can save and restore VM state. (Something Lua cannot do with any
level of sanity.)
A new LLVM backend targeted to it, or an assembler that can read
LCC's intermediate assembly representation in a similar manner to
And for these goals:
Scripting for games, allowing fast iteration time and dynamic
reloading of game logic. The execution time must be fast to be
suitable for this.
User-programmable game scripts that can safely be run on a
multiplayer server, even though they're written by potentially
hostile players. We need sandboxing, suspend/resume support, and
the ability to take and restore state snapshots for this to work
General purpose scripting. Maybe get it integrated with that
texture generator tool I was working on. For this, it needs a sane
API and the ability to hold references to data outside of the VM.
I don't know how I'm going to handle the latter part, and the way
I did it in DerpScript isn't going to cut it.
So after one night of work I have the start of the VM, a mostly
complete assembler (not using LCC's assembly), and a disassembler.
At the moment it's possible to write some very simple assembly
programs and do basic flow control and memory access. Only the "add"
instruction has been implemented on the arithmetic side.
The specs of the VM are (right now):
No addressable general purpose registers. Everything is just
direct memory access. There's a program counter and stack pointer,
and that's it at the moment. So far there is no way to modify them
directly. Push/pop instructions exist as a way to modify the stack
pointer, with no direct access (yet). Jump and branch instructions
modify the program counter, but there's no way to read it (yet).
Three addressing modes: Immediate, direct memory, and indirect
with an immediate value as an offset from the stack pointer. There
are additional instructions for dereferencing pointers in memory.
(This could all change, because I'd rather have the
dereference-pointer ops be replaced with addressing modes built
into the opcodes.)
Memory is divided into 32-bit Words. Each instruction with encoded
addressing modes takes up exactly one Word, plus one Word per
parameter. This can change with a modification to a typedef to
change the meaning of Word, but there's a minimum usable size.
8-bit Words won't work just because the encoded instructions won't
fit in them.
That's all I have right now. I'll add more information as I piece it
together. I haven't done a good job of making the code presentable,
so no source code or example code yet. But maybe soon.