Virtual machine layout and interface definition

Virtual machine layout and interface definition


Document formatted by vherva at Fri Apr 24 11:23:56 1998 on the host schemestation. This document is produced by the SchemeStation project during the Tik-76.115 course.

1 Introduction

The VM consists of

  1. Instruction fetcher & decoder
  2. Instruction selector (/executor)
  3. Exception handler
  4. Individual instructions

The purpose of this structure is to make VM as modular and as simple as possible. It is especially important to be able to add/change individual instructions by changing only the instruction module.

2 The functions of module VM external interface

File vm.h

C-functions:

  • Status make_instruction(INOUT unsigned char *buf, INOUT int *instruction_size, IN Vm_instruction instruction, IN uint64 *args)
    Description: Create an encoded byte code instruction number 'instruction' to * BUF and return the length of the instruction in bytes in INSTRUCTION_SIZE. Instrument args are stored in the array ARGS in the following way: register numbers are stored as uint64s, constant table entries as uint64s (offsets to a constants table) and labels in the same way. If BUF is NULL return length but do not write the actual encoding anywhere. INSTRUCTION_SIZE may not be NULL.

  • Status reverse_map_instruction(IN int instr_num, OUT const char **nameptr, OUT const char **argsptr)
    Description: Map instruction numbers to their names and arguments specification

  • Status vm_execute(IN Heap heap, IN Registerset *registers, IN Bytecode *byte_code, INOUT uint64 *instr_count, OUT Vm_status *status)
    Description: Execution of virtual machine instructions int32 vm_execute(IN Heap heap, IN Registerset *registers, IN Bytecode *byte_code, IN int64 code_offset, INOUT int64 *instr_count, OUT Vm_status *status); PRECOND(NULL != registers); PRECOND(NULL != byte_code); PRECOND(NULL != status); POSTCOND(IN(*instr_count) >= OUT(*instr_count)); The VM acts like a library; it has no internal state that persist across calls to vm_execute() (or vm_message()). Therefore the parameters specify the heap to be used, current register set, instructions (bytecode) and the number of instructions to be executed with this call. vm_execute() return the number of instructions executed (it can (and in many cases will!) be different from the number requested) and the status after the current instruction. The status values include: - VM_STATUS_OK VM state normal - VM_STATUS_BLOCKING VM is blocking; this happens when waiting for messages to arrive to the message queue - VM_STATUS_FAIL VM state violation (illegal instruction, jump out of code, invalid heap access, etc) - VM_STATUS_HALT VM_INSTR_HALT exected (or similar condition)

  • Status vm_message(IN Heap heap, IN Registerset *registers, IN LinearizedHeap message, OUT Vm_status *status)
    Description: Messages to actors Status vm_message(IN Heap heap, IN Registerset *registers, IN LinearizedHeap message, OUT Vm_status *status); PRECOND(NULL != registers); PRECOND(NULL != message); PRECOND(NULL != status); The message delivery to the VM is handled here; the internal exception mechanism is used to notify the bytecode program of the arrival of a message. Incoming messages are serialized so that the VM does not explicitly have to keep queues for incoming messages. However, it is likely that the program running on the VM is using a queue like mechanism if it does not handle the messages within the exception handler. The idea of the implementation is to place the message (linearized heap) into the exception handler's parameter (delinearized heap), then the exception mechanism is started by modifying the stack & PC to start the exception handler iediately. It is assumed that the exceptions are enabled when entering this function; if they are not, the function returns with *status == VM_STATUS_BLOCKING.

  • Status vm_send_message_out(uchar *address, LinearizedHeap heap, uint64 data_length)
    Description: This function is NOT implemented in the library, but needs to be implemented elsewhere in a program using the virtual machine library. The virtual machine calls it when it wants to send a message out. ADDRESS is the address where the message should be sent; it will be a 256-bit actor address. DATA contains the data (actually a linearized heap). DATA_LENGTH is the length of the linearized heap. Both ADDRESS and DATA are dynamically allocated. vm_send_message_out or some other external procedure should free them when needed. The function must return STATUS_OK.


File vm_debug.h

C-functions:

  • Status vm_debug_print_ops(IN Vm_decoded_instr *decoded)
    Description: * vm_debug_print_ops() * * Print out the decoded operands of an instruction *


File vm_encode.h

C-functions:


File vm_instr.h

C-functions:

3 Internal interfaces

This internal interface definition specifies the current implementation decisions of the SCHEMESTATION VM.

3.1 Instruction encoding & decoding

With each instruction (VM_INSTR_*) there is an association to instruction encoder and decoder functions. The purpose of the instruction decoding phase is to pick out the operands of the instruction and place them to a structure that holds all possible operand combinations. This structure can then be passed to individual instruction function. The encoder is placed here for convenience; the assembler uses the encoder to produce the binary from instructions and their operands.

Each decoder instruction is implemented as a function that has the following fingerprint:

Vm_status vm_decoder_*(IN uint32 instr, /* Instruction item to be decoded */
                       IN Heap heap, /* Constants are located here */
                       IN uint64 *imm_offset, /* IMM_EXTEND support */
                       OUT Vm_decoded_instr *decoded); /* The final result */

Encoder function fingerprint:

Vm_status vm_encoder_*(IN Vm_instruction instr, /* The instruction */
                       OUT unsigned char *buf, /* Output buffer */
                       OUT int *instr_size, /* Size of the encoded instruction */
                       IN uint64 *args); /* Operand vector */

3.2 Instruction selection and individual instructions

Instructions are associated to an instruction function and using a table of associations, the particular instruction function for an instruction is selected. Each instruction is implemented as a function that has the following fingerprint:

Vm_status vm_operator_*(INOUT Heap heap,
                        INOUT Registerset *registers,
                        IN Vm_decoded_instr *instr);

If instruction return status is different from VM_STATUS_OK, some decisions has to be made: either the VM exception mechanism can handle the situation and continue execution or the status value will be passed to the external interface of the VM and the instruction scheduling discontinued.

3.3 Exceptions

The exception mechanism is based on the register VM_REG_EXCEPTION which contains the address of the user-defined exception handler. If this register contains NIL, it means that the exceptions are disabled; if an exception should occur whenever exceptions are disabled, the VM acts like VM_INSTR_HALT would have been executed (the program dies). When an exception is raised, the following instructions are executed internally:

VM_INSTR_SAVE_IMMEDIATE    VM_REG_STACK, B1111111111110111 ; save registers except VM_REG_MSG_QUEUE
VM_INSTR_JUMP              VM_REG_EXCEPTION ; jump to the exception handler
VM_INSTR_LOAD_NULL         VM_REG_EXCEPTION ; set the exception handler to NIL -> exceptions disabled

After that, the parameter is placed to VM_REG_R2 and the execution can continue. This implies that whenever the instruction VM_INSTR_RESTORE_IMMEDIATE, VM_REG_STACK, B11111111111111 is executed, it has the effect of returning from the exception handler and continuing the execution from the point where the exception occurred. Note that the register VM_REG_MSG_QUEUE is not saved or restored.

NOTE: Current implementation does not generate fatal exceptions, as there are no defined semantics to handle them - instead, the program that generated the exception is terminated.

3.4 VM and asynchronous messages

vm_message() interface invokes the exception handling facility which passes the message to the exception handler of this particular bytecode instance. This message delinearizes the message (a linearized heap, formed as a list of parameters, where the first parameter is a bitstring identifying the message) and passes it to the program as the parameter of the exception handler.

NOTE: It is assumed that the exception mechanism (once defined) will be using this kind of parameter passing - that is, exceptions behave like "out of band" messages, and they can be recognized just like normal messages.


© SchemeStation project 1997-1998 [Back to the document index]