pr3.3
This commit is contained in:
parent
650f1e0716
commit
46146993aa
74
crates/console/prometeu-vm/src/heap.rs
Normal file
74
crates/console/prometeu-vm/src/heap.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use crate::{ObjectHeader, ObjectKind};
|
||||
use prometeu_bytecode::HeapRef;
|
||||
|
||||
/// Internal stored object: header plus opaque payload bytes.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StoredObject {
|
||||
pub header: ObjectHeader,
|
||||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Simple vector-backed heap. No GC or compaction.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Heap {
|
||||
objects: Vec<StoredObject>,
|
||||
}
|
||||
|
||||
impl Heap {
|
||||
pub fn new() -> Self { Self { objects: Vec::new() } }
|
||||
|
||||
/// Allocate a new object with the given kind and raw payload bytes.
|
||||
/// Returns an opaque `HeapRef` handle.
|
||||
pub fn allocate_object(&mut self, kind: ObjectKind, payload: &[u8]) -> HeapRef {
|
||||
let header = ObjectHeader::new(kind, payload.len() as u32);
|
||||
let obj = StoredObject { header, payload: payload.to_vec() };
|
||||
let idx = self.objects.len();
|
||||
self.objects.push(obj);
|
||||
HeapRef(idx as u32)
|
||||
}
|
||||
|
||||
/// Returns true if this handle refers to an allocated object.
|
||||
pub fn is_valid(&self, r: HeapRef) -> bool {
|
||||
(r.0 as usize) < self.objects.len()
|
||||
}
|
||||
|
||||
/// Get immutable access to an object's header by handle.
|
||||
pub fn header(&self, r: HeapRef) -> Option<&ObjectHeader> {
|
||||
self.objects.get(r.0 as usize).map(|o| &o.header)
|
||||
}
|
||||
|
||||
/// Current number of allocated objects.
|
||||
pub fn len(&self) -> usize { self.objects.len() }
|
||||
pub fn is_empty(&self) -> bool { self.objects.is_empty() }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn basic_allocation_returns_valid_refs() {
|
||||
let mut heap = Heap::new();
|
||||
|
||||
let r1 = heap.allocate_object(ObjectKind::String, b"hello");
|
||||
let r2 = heap.allocate_object(ObjectKind::Bytes, &[1, 2, 3, 4]);
|
||||
let r3 = heap.allocate_object(ObjectKind::Array, &[]);
|
||||
|
||||
assert!(heap.is_valid(r1));
|
||||
assert!(heap.is_valid(r2));
|
||||
assert!(heap.is_valid(r3));
|
||||
assert_eq!(heap.len(), 3);
|
||||
|
||||
let h1 = heap.header(r1).unwrap();
|
||||
assert_eq!(h1.kind, ObjectKind::String);
|
||||
assert_eq!(h1.payload_len, 5);
|
||||
|
||||
let h2 = heap.header(r2).unwrap();
|
||||
assert_eq!(h2.kind, ObjectKind::Bytes);
|
||||
assert_eq!(h2.payload_len, 4);
|
||||
|
||||
let h3 = heap.header(r3).unwrap();
|
||||
assert_eq!(h3.kind, ObjectKind::Array);
|
||||
assert_eq!(h3.payload_len, 0);
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,9 @@ pub mod verifier;
|
||||
mod virtual_machine;
|
||||
pub mod vm_init_error;
|
||||
pub mod object;
|
||||
pub mod heap;
|
||||
|
||||
pub use prometeu_hal::{HostContext, HostReturn, NativeInterface, SyscallId};
|
||||
pub use virtual_machine::{BudgetReport, LogicalFrameEndingReason, VirtualMachine};
|
||||
pub use object::{object_flags, ObjectHeader, ObjectKind};
|
||||
pub use heap::{Heap, StoredObject};
|
||||
|
||||
@ -5,6 +5,7 @@ use crate::{HostContext, NativeInterface};
|
||||
use prometeu_bytecode::isa::core::CoreOpCode as OpCode;
|
||||
use prometeu_bytecode::ProgramImage;
|
||||
use prometeu_bytecode::Value;
|
||||
use crate::heap::Heap;
|
||||
use prometeu_bytecode::{
|
||||
TRAP_BAD_RET_SLOTS, TRAP_DIV_ZERO, TRAP_INVALID_FUNC, TRAP_INVALID_SYSCALL, TRAP_OOB,
|
||||
TRAP_STACK_UNDERFLOW, TRAP_TYPE, TrapInfo,
|
||||
@ -83,7 +84,7 @@ pub struct VirtualMachine {
|
||||
/// The loaded executable (Bytecode + Constant Pool), that is the ROM translated.
|
||||
pub program: ProgramImage,
|
||||
/// Heap Memory: Dynamic allocation pool.
|
||||
pub heap: Vec<Value>,
|
||||
pub heap: Heap,
|
||||
/// Total virtual cycles consumed since the VM started.
|
||||
pub cycles: u64,
|
||||
/// Stop flag: true if a `HALT` opcode was encountered.
|
||||
@ -114,7 +115,7 @@ impl VirtualMachine {
|
||||
None,
|
||||
std::collections::HashMap::new(),
|
||||
),
|
||||
heap: Vec::new(),
|
||||
heap: Heap::new(),
|
||||
cycles: 0,
|
||||
halted: false,
|
||||
breakpoints: std::collections::HashSet::new(),
|
||||
@ -135,7 +136,7 @@ impl VirtualMachine {
|
||||
self.operand_stack.clear();
|
||||
self.call_stack.clear();
|
||||
self.globals.clear();
|
||||
self.heap.clear();
|
||||
self.heap = Heap::new();
|
||||
self.cycles = 0;
|
||||
self.halted = true; // execution is impossible until a successful load
|
||||
|
||||
|
||||
100
files/TODOs.md
100
files/TODOs.md
@ -1,103 +1,3 @@
|
||||
# PR-3.3 — Implement Basic Heap Allocator (No GC Yet)
|
||||
|
||||
### Briefing
|
||||
|
||||
We need a simple heap allocator that can store objects and return handles. This PR introduces a minimal allocator without garbage collection.
|
||||
|
||||
### Target
|
||||
|
||||
* Create a heap structure that stores objects.
|
||||
* Return `HeapRef` handles for allocated objects.
|
||||
|
||||
### Work items
|
||||
|
||||
* Implement a `Heap` struct.
|
||||
* Store objects in a vector or arena-like container.
|
||||
* Provide methods such as:
|
||||
|
||||
* `allocate_object(kind, payload)`.
|
||||
* Return a `HeapRef` handle.
|
||||
* Integrate heap into VM state.
|
||||
|
||||
### Acceptance checklist
|
||||
|
||||
* [ ] Heap exists and can allocate objects.
|
||||
* [ ] VM can hold a heap instance.
|
||||
* [ ] Allocation returns valid `HeapRef`.
|
||||
* [ ] `cargo test` passes.
|
||||
|
||||
### Tests
|
||||
|
||||
* Add a unit test allocating a few objects and verifying handles are valid.
|
||||
|
||||
### Junie instructions
|
||||
|
||||
**You MAY:**
|
||||
|
||||
* Use a simple vector-backed heap.
|
||||
* Implement minimal allocation logic.
|
||||
|
||||
**You MUST NOT:**
|
||||
|
||||
* Implement garbage collection here.
|
||||
* Add compaction or generational strategies.
|
||||
|
||||
**If unclear:**
|
||||
|
||||
* Ask before choosing allocation layout.
|
||||
|
||||
---
|
||||
|
||||
# PR-3.4 — Define GC Root Set (Stack, Frames, Globals)
|
||||
|
||||
### Briefing
|
||||
|
||||
The GC must know where roots are located. This PR defines the root set abstraction without running a full GC yet.
|
||||
|
||||
### Target
|
||||
|
||||
* Identify and enumerate all GC roots.
|
||||
* Provide a mechanism to iterate them.
|
||||
|
||||
### Work items
|
||||
|
||||
* Define a root traversal interface or helper.
|
||||
* Enumerate roots from:
|
||||
|
||||
* Value stack.
|
||||
* Call frames.
|
||||
* Globals or constant pools if applicable.
|
||||
* Provide a function like `visit_roots(visitor)`.
|
||||
|
||||
### Acceptance checklist
|
||||
|
||||
* [ ] Root set traversal exists.
|
||||
* [ ] Stack and frames are included as roots.
|
||||
* [ ] Code compiles.
|
||||
* [ ] `cargo test` passes.
|
||||
|
||||
### Tests
|
||||
|
||||
* Add a test that inserts a `HeapRef` in the stack and confirms it is visited by root traversal.
|
||||
|
||||
### Junie instructions
|
||||
|
||||
**You MAY:**
|
||||
|
||||
* Add root iteration helpers.
|
||||
* Traverse stack and frames.
|
||||
|
||||
**You MUST NOT:**
|
||||
|
||||
* Implement marking logic yet.
|
||||
* Change frame or stack architecture.
|
||||
|
||||
**If unclear:**
|
||||
|
||||
* Ask which structures must be roots.
|
||||
|
||||
---
|
||||
|
||||
# PR-3.5 — Implement Mark Phase (Reachability Traversal)
|
||||
|
||||
### Briefing
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user