Documentation / Runtime model

A practical overview of virtual-machine architecture.

This guide introduces the ideas behind a shared bytecode runtime: software CPUs, register frames, low-level operations, abstract values, behavior tables, string handling, and frozen bytecode files.

On this page

Start with the execution model.

The original technical notes are organized here as a readable path from the interpreter itself to the data structures and file formats it uses.

01 / Interpreter

A shared target for language front ends.

A virtual machine provides a common execution target. Compilers and language front ends can translate their programs into an intermediate instruction model while the runtime supplies execution services.

What the runtime provides

The interpreter is best understood as a software CPU: it reads encoded operations, locates their operands, and advances through a bytecode stream.

Its design aims to keep low-level execution separate from the language-specific rules that define how values behave.

execution-model.pcodeillustrative
# A compact register instruction stream
set  r0, 21
set  r1, 2
mul  r2, r0, r1
print r2
halt

02 / Software CPU

Registers make the execution state explicit.

Instead of placing every operand on a stack, a register-oriented design gives instructions named locations for their inputs and results.

A / REG

Typed register groups

Separate groups can hold integers, floating-point values, strings, and abstract runtime objects.

B / FRAME

Scoped register frames

Subroutines and blocks can receive their own frame, which is pushed and released as execution enters and leaves a scope.

C / COST

Fewer operand moves

Keeping intermediate values in registers can reduce repeated stack pushes and pops in non-JIT execution.

03 / Operations

Small instructions form the bytecode language.

Operations use compact arguments and return the location of the next instruction. This keeps the execution loop predictable while allowing higher-level compilers to target a stable low-level vocabulary.

Opcode organization

Each operation has a numeric identity followed by arguments whose types depend on the instruction. Register references are commonly encoded as integer indexes, while constants use the value type expected by the operation.

Opcode tables may be shared globally or defined for a particular compilation unit, allowing specialized operations without changing the entire runtime.

From source to machine code

A language front end can first produce a medium-level representation, then lower it into the runtime’s instruction set. This separates language syntax and semantics from the mechanics of dispatch.

Detailed instruction references belong beside the source and implementation records so that examples can be compared with the runtime behavior they describe.

04 / Abstract values

One value interface, many language behaviors.

A portable runtime needs a way to represent values whose meaning can vary between languages. Abstract containers provide that boundary.

Data behind a stable API

An abstract value may represent a number, string, object, code reference, collection, or language-specific structure. Instructions can ask it to convert, measure, combine, or otherwise respond without knowing every internal detail.

Language-specific semantics

The same bytecode operation can produce different results when the value supplies different language rules. This makes it possible to share execution infrastructure while preserving the behavior expected by each front end.

05 / Vtables

Behavior is selected through function slots.

A behavior table connects an abstract value to the operations it supports. The runtime follows the relevant slot, passing the value as the receiver.

dispatch.cconceptual
/* behavior selected by the value */
result = value->vtable->length(value);

/* the same slot may vary by type */
if (value->kind == STRING)
    use_string_length(value);

Why this boundary matters

Common operations such as addition, length, and concatenation can be dispatched through a shared interface. A string, array, or language object can implement the slot according to its own semantics.

Tables can also be assembled dynamically, which lets runtime extensions introduce new value behavior without rewriting the instruction dispatcher.

06 / Strings

Encoding belongs in the runtime layer.

String services hide allocation, character indexing, length calculation, and conversion details from the code that uses text.

01 / MEMORY

Managed storage

The string subsystem handles allocation and expansion as values change size.

02 / TEXT

Character-aware access

Length and offsets can be defined in characters rather than raw storage units.

03 / ENCODING

Transcoding paths

Encoding implementations can convert directly or use a common Unicode representation.

07 / Bytecode format

A loadable file is organized in runtime segments.

A frozen bytecode file contains the information needed to identify the program, restore its data, and prepare the interpreter for execution.

01 / HEADER

Magic identifier

The opening marker identifies the file as bytecode for the expected runtime.

02 / FIXUP

References to restore

Loader-managed pointers are resolved against memory allocated by the running instance.

03 / CONSTANTS

Strings and values

Stored constants are reconstructed before instructions refer to them.

04 / OPS

Instruction segment

The operation stream and its arguments form the executable core of the file.

05 / DEBUG

Optional source record

A trailing code segment can preserve information useful for debugging.

06 / TRACE

Follow the loader

Studying the loading sequence connects the file format to the interpreter’s live state.

FAQ

Questions about the model.

What is a virtual machine in this context?

It is a software execution environment that reads an instruction stream and provides the registers, values, memory services, and dispatch rules needed to run it.

Why use registers instead of a stack?

Registers make operands explicit and can avoid repeated pushes and pops when intermediate values are used several times.

What is an abstract value?

It is a runtime-managed value whose concrete representation and behavior can vary while presenting a common interface to bytecode operations.

What does a vtable do?

A vtable maps supported operations to function implementations for a particular value, allowing dispatch to follow the value’s semantics.

Where does string encoding belong?

The string subsystem is the appropriate boundary for allocation, character indexing, length calculations, and transcoding.

What should I read next?

Use the examples directory to trace a small program, then consult the source and languages sections to connect execution concepts with implementation work.

About this document

PCode Vault overview

This page presents a refreshed, resource-oriented explanation of virtual-machine concepts originally documented in the overview material. It is intended as a technical orientation, not a claim that historical implementation details describe current software. Questions or corrections can be sent to info@pcodevault.en-html.com.