Русский сайт

для тех, кто не читает по-английски

For clients

Project tasks and bug-tracking



Why a new OS?

General description

Operations →

Phantom OS FAQ



Copyright © 2009 Dmitry Zavalishin,
Contacts:
Dmitry Zavalishin
dz@dz.ru,
+7 (916) 690 3208

Digital Zone, Moscow, Russia
+7 (499) 973-23-80

Operations

Here are virtual machine instructions described on assembler (phantasm) language level. (Phantasm is not used anymore for system development, but is good to describe bytecode structure.)


Strange stuff

nop

No operation. This operation does completely nothing.

debug
debug; // just print stacks
debug “we’re busted”; // show message too
debug 33; // no meaning yet
debug 33 “we’re busted”; // together

Prints string argument (if any), and top values of integer and object stack. Integer argument (mode) is one byte and upper bit is used internally, so don’t pass anything > 0x7F or < 0 – will be stripped.

Bit 0 (& 0x01) of mode byte turns on debug instruction printing.
Bit 1 (& 0x02) turns it off.


Flow control

jmp
jmp label;
// code to jump around
label:

Unconditional jump.

djnz
const 10;
loop:
// do something 10 times
djnz loop;

Decrement top of int stack. If top of int stack is not zero — jump to label.

NB! This operation does not pop integer stack!

jz

repeat:
// calculate while condition
jz done;
// loop body
jmp repeat;
done:

While-style loop operator. Jump if top of int stack is zero.

NB! This operation does pop integer stack!

switch shift divisor label…

// calculate expression on int stack
switch 0 1 case1 case2 case3;
// here we’ll come on default (fall through) jmp out;
case1:
// if expression was 0 we’ll come here
jmp out;
case2:
// if expression was 1 we’ll come here
jmp out;
case3:
// if expression was 2 we’ll come here
jmp out;

out:

Top of int stack (popped) is diminished by shift (signed), divided by divisor (unsigned) and is used as offset into the jump address table. If result is out of bounds, operator falls through, else jumps to selected address.

ret
ret;

Top of object stack is popped and pushed on caller’s stack. If stack is empty null object is pushed to caller. All the exception catchers pushed in this call are discarded.

call methodIndex numberOfArgs
call 0 2;

Pops numberOfArgs arguments from object stack, than pops object to call method for. Calls selected method passing given number of args. Top of integer stack of called method will have number of arguments passed. After the return exactly one object (possibly null) will be on the object stack.

sys syscall_number
sys 0;

Executes this (and only this!) object’s embedded method. NB – it is not possible to execute sys for other object than this because it will render its specialness visible from outside.
This operation is valid for a very limited number of classes.

Nothing can be guaranteed about sys. As for now all of them return something, but it is not enforced by interpreter. Though, for normal operation sys must return some object.

It is possible to pass parameters to sys on int stack and receive some return there as well, which is differs from call, which passes data on object stack only. That is so because sys does not create a call frame and thus all the current stack data is available to its code.

Generally, sys is used as the only content of internal class methods.


Stack manipulations

os dup
is dup
os dup; // now we have one more whatever it was

Duplicate stack top – either object or int.

os drop
is drop
call 0 0;
os drop; // discard return value

Delete stack top.

os pull displacement
os pull 2;

Copy object displacement steps down from top of object stack on top of it. Pull 0 is equal to dup. NB! Deprecated!

load slot_num
load 3;

Load object reference from this object slot (field), push to top of stack.

save slot_num
save 3;

Pop object reference, store to selected slot (field) of this object.

get absolute_stack_position
get 0;

Load object from given position of object stack, push to top of stack.

set absolute_stack_position
set 0;

Pop object, store to selected position of object stack. These two are for local variables access.

compose n_objects
// code object on stack
summon “internal.class.interface”;
compose 1;
// interface object initialized with 1 code object
// is on stack

Top of stack is class object, initializers follow. New object of that class will be constructed, new object slots will be filled with n_objects objects from stack.

NB!! This operation must be available to objects of classes that permit it explicitly. Corresponding checks must be added.

NB!! It is better to kill it at all.

decompose
decompose;

Will store on stack all of the fields of top stack object. Number of objects will be pushed to integer stack.

NB!! This operation must be available to objects of classes that permit it explicitly. Corresponding checks must be added.

NB!! It is better to kill it at all.

new
new;

Create a new object of given (stack top) class. It does not call any constructor.

copy
copy;

Create a copy of top stack object. Same class, same slot values.

os eq
os eq;

Pop and compare two objects on object stack. If they are the same, push non-zero on integer stack, else push zero.

os neq
os neq;

Pop and compare two objects on object stack. If they are the same, push zero on integer stack, else push non-zero.

os isnull
os isnull;

Pop object. If it is a null, push non-zero on integer stack, else push zero.


Exceptions

push catcher label

summon “internal.class.string”;
push catcher string_thrown;
// code ret;
string_thrown:
// on exception of string type we’ll get here
// do cleanup
ret;

Top of stack contains class object. Exceptions of that class will be catched here and control will be passed to a label if such exception is thrown. Thrown object will be on stack top in this case. In general no other assumptions about stack state can be done.

pop catcher
pop catcher;

Last pushed catcher will be deleted.

throw
const “we have a problem here”;
throw;

Object on top of stack is thrown down. If stack is empty - will throw special system-wide object (null?), if already on top of call stack - will kill current thread in a bad way.


Constants

const
const “hi there”;
// top of object stack is string object now
const 32656;
// top of integer stack has 32656 now

Push constant on stack top. Special shortcuts for 0 and 1 exist. Strings are Unicode UTF-8. MUST BE PLAIN 2-BYTE UNICODE?


Summoning

summon this
summon this
// this object is on stack top now

Puts this object reference on stack.

summon thread
summon thread
// current thread object is on stack top now

Puts current thread object reference on stack.

summon null
summon null
// stack top has null object

Put null object on stack.

summon class_name
summon “internal.class.class”;
summon “internal.class.int”;
summon “internal.class.string”;
summon “internal.class.interface”;
summon “internal.class.code”;

Push corresponding class object on stack.
NB!! Define implementation! Must go through some thread specific class loader?


Integer stack operations

i2o
o2i
const 10;
i2o;
// object stack now has integer object
o2i;
// value of integer object moved to integer stack

These operations can be used to move data between integer and object stacks.
NB! What exception is thrown if it is not int?

iload slot_num
iload 3;

(Not implemented!) Load object from this object slot, push to top of integer stack.

isave slot_num
isave 3;

(Not implemented!) Pop value from integer stack, store to selected slot of this object.

isum
imul
const 10;
const 5;
isum;
// int stack has 15 on top
const 10;
imul;
// int stack has 150 on top

Addition and multiplication.

isubul
isublu
idivul
idivlu
const 10;
const 5; // top is 5
isubul; // upper from lower, 5 – 10
// here we have -5

const 10;
const 5; // top is 5
isublu; // lower from upper, 10 - 5
// here we have 5

const 5;
const 10; // top is 10
idivul // = 10 / 5

const 10;
const 5; // top is 5
idivlu // = 10 / 5

Integer subtraction and division.

ior
iand
ixor
inot

Bit wise operations on integer stack top.

||
&&
!

logical operations on integer stack top.


Not yet described codes

None at the moment.


Stuff to implement

int 64 bit
int variable length

It is possible that all integers and pointers will be 64 bit in phantom in a near future because persistent memory has to be as large as common hard disks are, and gigabytes are not of interest now, we need terabytes to be addressable.

float 32 bit (24+8)
float variable length (for now – up to 80 bit, future ext)