353 lines
5.6 KiB
Markdown
353 lines
5.6 KiB
Markdown
< [Back](chapter-2.md) | [Summary](table-of-contents.md) | [Next](chapter-4.md) >
|
|
|
|
# 🧠 **Memory Model**
|
|
|
|
This chapter defines the memory architecture of the Prometeu Virtual Machine (PVM). It describes the stack, heap, handles, object layout, garbage collection, and interaction with host-owned memory such as asset banks.
|
|
|
|
The memory model is designed to be:
|
|
|
|
* deterministic
|
|
* safe
|
|
* simple to verify
|
|
* suitable for real-time 2D games
|
|
|
|
---
|
|
|
|
## 1 Overview
|
|
|
|
The PVM uses a **split memory model**:
|
|
|
|
1. **Stack memory**
|
|
|
|
* used for temporary values
|
|
* function arguments
|
|
* multi-return tuples
|
|
2. **Heap memory**
|
|
|
|
* used for all user-defined objects
|
|
* accessed only through handles
|
|
3. **Host-owned memory**
|
|
|
|
* asset banks
|
|
* audio buffers
|
|
* framebuffers
|
|
* not part of the VM heap
|
|
|
|
---
|
|
|
|
## 2 Stack Memory
|
|
|
|
The stack is used for:
|
|
|
|
* primitive values
|
|
* built-in value types
|
|
* temporary results
|
|
* function arguments
|
|
* tuple returns
|
|
|
|
### Stack value types
|
|
|
|
| Type | Description |
|
|
| -------- | ------------------------ |
|
|
| `int` | 64-bit integer |
|
|
| `bool` | Boolean |
|
|
| `float` | 64-bit float |
|
|
| `vec2` | 2D vector |
|
|
| `color` | Packed color |
|
|
| `pixel` | Position + color |
|
|
| `handle` | Reference to heap object |
|
|
|
|
All stack values are:
|
|
|
|
* fixed-size
|
|
* copied by value
|
|
* never directly reference raw memory
|
|
|
|
### Stack properties
|
|
|
|
* Stack is bounded and verified.
|
|
* Stack depth must be consistent across all control paths.
|
|
* Stack never stores raw pointers.
|
|
|
|
---
|
|
|
|
## 3 Tuples (Stack-Only Aggregates)
|
|
|
|
Tuples are used for multi-value returns.
|
|
|
|
### Tuple rules
|
|
|
|
* Tuples exist only on the stack.
|
|
* Maximum tuple arity: **6 slots**.
|
|
* Tuples are not heap objects by default.
|
|
* To persist a tuple, it must be explicitly boxed into a heap object.
|
|
|
|
### Example
|
|
|
|
Function returning two values:
|
|
|
|
```
|
|
fn position(): (int, int)
|
|
```
|
|
|
|
At runtime:
|
|
|
|
```
|
|
stack top → [x, y]
|
|
```
|
|
|
|
---
|
|
|
|
## 4 Heap Memory
|
|
|
|
All user-defined objects live in the heap.
|
|
|
|
### Heap characteristics
|
|
|
|
* Linear slot-based storage.
|
|
* Objects are fixed-layout blocks.
|
|
* No raw pointer access.
|
|
* No inheritance at memory level.
|
|
|
|
Heap objects include:
|
|
|
|
* user structs/classes
|
|
* arrays
|
|
* strings
|
|
* closures
|
|
* boxed tuples (optional)
|
|
|
|
---
|
|
|
|
## 5 Handles and Gate Table
|
|
|
|
All heap objects are accessed via **handles**.
|
|
|
|
A handle is defined as:
|
|
|
|
```
|
|
handle = { index, generation }
|
|
```
|
|
|
|
The VM maintains a **gate table**:
|
|
|
|
```
|
|
GateEntry {
|
|
alive: bool
|
|
generation: u32
|
|
base: usize
|
|
slots: u32
|
|
type_id: u32
|
|
}
|
|
```
|
|
|
|
### Handle safety
|
|
|
|
When an object is freed:
|
|
|
|
* `alive` becomes false
|
|
* `generation` is incremented
|
|
|
|
When a handle is used:
|
|
|
|
* index must exist
|
|
* generation must match
|
|
|
|
Otherwise, the VM traps.
|
|
|
|
This prevents:
|
|
|
|
* use-after-free
|
|
* stale references
|
|
|
|
---
|
|
|
|
## 6 Object Layout
|
|
|
|
Heap objects have a simple, fixed layout:
|
|
|
|
```
|
|
Object {
|
|
type_id
|
|
field_0
|
|
field_1
|
|
...
|
|
}
|
|
```
|
|
|
|
Properties:
|
|
|
|
* Fields are stored in slot order.
|
|
* No hidden base classes.
|
|
* No pointer arithmetic.
|
|
|
|
Traits and method dispatch are resolved:
|
|
|
|
* statically by the compiler, or
|
|
* via vtable handles (if dynamic dispatch is used).
|
|
|
|
---
|
|
|
|
## 7 Closures
|
|
|
|
Closures are heap objects.
|
|
|
|
Layout:
|
|
|
|
```
|
|
Closure {
|
|
func_id
|
|
capture_count
|
|
captures[]
|
|
}
|
|
```
|
|
|
|
Captures may be:
|
|
|
|
* copied values
|
|
* handles to heap objects
|
|
|
|
Closure environments are part of the GC root set.
|
|
|
|
---
|
|
|
|
## 8 Coroutine Memory
|
|
|
|
Each coroutine owns its own stacks:
|
|
|
|
```
|
|
Coroutine {
|
|
call_stack
|
|
operand_stack
|
|
state
|
|
}
|
|
```
|
|
|
|
All coroutine stacks are included in the GC root set.
|
|
|
|
Coroutines do not share stacks or frames.
|
|
|
|
---
|
|
|
|
## 9 Garbage Collection
|
|
|
|
The PVM uses a **mark-sweep collector**.
|
|
|
|
### GC properties
|
|
|
|
* Non-moving (no compaction in v1).
|
|
* Runs only at **safepoints**.
|
|
* Primary safepoint: `FRAME_SYNC`.
|
|
|
|
### GC triggers
|
|
|
|
GC may run when:
|
|
|
|
* heap usage exceeds threshold
|
|
* allocation pressure is high
|
|
|
|
### Root set
|
|
|
|
The collector marks from:
|
|
|
|
* operand stack
|
|
* call stack frames
|
|
* global variables
|
|
* coroutine stacks
|
|
* closure environments
|
|
* host-held handles
|
|
|
|
---
|
|
|
|
## 10 Allocation and Deallocation
|
|
|
|
### Allocation
|
|
|
|
Heap allocation:
|
|
|
|
1. VM reserves a slot block.
|
|
2. A gate entry is created.
|
|
3. A handle is returned.
|
|
|
|
If allocation fails:
|
|
|
|
* VM may trigger GC.
|
|
* If still failing, a trap occurs.
|
|
|
|
### Deallocation
|
|
|
|
Objects are freed only by the GC.
|
|
|
|
When freed:
|
|
|
|
* gate is marked dead
|
|
* generation is incremented
|
|
* memory becomes available via free list
|
|
|
|
---
|
|
|
|
## 11 Host-Owned Memory (Asset Banks)
|
|
|
|
Asset memory is **not part of the VM heap**.
|
|
|
|
It is managed by the firmware.
|
|
|
|
Examples:
|
|
|
|
* tilebanks
|
|
* audio sample banks
|
|
* sprite sheets
|
|
|
|
### Properties
|
|
|
|
* VM cannot access asset memory directly.
|
|
* Access occurs only through syscalls.
|
|
* Asset memory is not scanned by GC.
|
|
|
|
---
|
|
|
|
## 12 Save Memory (MEMCARD)
|
|
|
|
Save memory is a host-managed persistent storage area.
|
|
|
|
Properties:
|
|
|
|
* fixed size
|
|
* accessed only via syscalls
|
|
* not part of the VM heap
|
|
* not scanned by GC
|
|
|
|
---
|
|
|
|
## 13 Memory Safety Rules
|
|
|
|
The VM enforces:
|
|
|
|
1. All heap access via handles.
|
|
2. Generation checks on every handle use.
|
|
3. Bounds checking on object fields.
|
|
4. No raw pointer arithmetic.
|
|
5. Verified stack discipline.
|
|
|
|
Any violation results in a trap.
|
|
|
|
---
|
|
|
|
## 14 Summary
|
|
|
|
The PVM memory model is based on:
|
|
|
|
* stack-only primitive and tuple values
|
|
* heap-only user objects
|
|
* generation-based handles
|
|
* deterministic GC at frame safepoints
|
|
* strict separation between VM heap and host memory
|
|
|
|
This design ensures:
|
|
|
|
* predictable performance
|
|
* memory safety
|
|
* simple verification
|
|
* suitability for real-time game workloads.
|
|
|
|
< [Back](chapter-2.md) | [Summary](table-of-contents.md) | [Next](chapter-4.md) > |