pr1.7
This commit is contained in:
parent
6d875784ea
commit
a5daebd849
127
crates/console/prometeu-bytecode/tests/roundtrip.rs
Normal file
127
crates/console/prometeu-bytecode/tests/roundtrip.rs
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
use prometeu_bytecode::decode_next;
|
||||||
|
use prometeu_bytecode::isa::core::{CoreOpCode, CoreOpCodeSpecExt};
|
||||||
|
|
||||||
|
fn encode_instr(op: CoreOpCode, imm: Option<&[u8]>) -> Vec<u8> {
|
||||||
|
let mut out = Vec::new();
|
||||||
|
let code = op as u16;
|
||||||
|
out.extend_from_slice(&code.to_le_bytes());
|
||||||
|
let spec = op.spec();
|
||||||
|
let need = spec.imm_bytes as usize;
|
||||||
|
match (need, imm) {
|
||||||
|
(0, None) => {}
|
||||||
|
(n, Some(bytes)) if bytes.len() == n => out.extend_from_slice(bytes),
|
||||||
|
(n, Some(bytes)) => panic!("immediate size mismatch for {:?}: expected {}, got {}", op, n, bytes.len()),
|
||||||
|
(n, None) => panic!("missing immediate for {:?}: need {} bytes", op, n),
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disasm(bytes: &[u8]) -> String {
|
||||||
|
// Minimal test-only disasm: NAME [operands]
|
||||||
|
let mut pc = 0usize;
|
||||||
|
let mut lines = Vec::new();
|
||||||
|
while pc < bytes.len() {
|
||||||
|
match decode_next(pc, bytes) {
|
||||||
|
Ok(instr) => {
|
||||||
|
let name = instr.opcode.spec().name;
|
||||||
|
let mut line = String::from(name);
|
||||||
|
let imm_len = instr.opcode.spec().imm_bytes as usize;
|
||||||
|
if imm_len > 0 {
|
||||||
|
// Heuristic formatting based on known op immediates
|
||||||
|
line.push(' ');
|
||||||
|
let s = match instr.opcode {
|
||||||
|
CoreOpCode::Jmp | CoreOpCode::JmpIfFalse | CoreOpCode::JmpIfTrue => {
|
||||||
|
format!("{}", instr.imm_u32().unwrap())
|
||||||
|
}
|
||||||
|
CoreOpCode::PushI64 => format!("{}", instr.imm_i64().unwrap()),
|
||||||
|
CoreOpCode::PushF64 => format!("{}", instr.imm_f64().unwrap()),
|
||||||
|
CoreOpCode::PushBool => format!("{}", instr.imm_u8().unwrap()),
|
||||||
|
CoreOpCode::PushI32 => format!("{}", instr.imm_i32().unwrap()),
|
||||||
|
CoreOpCode::PopN | CoreOpCode::PushConst | CoreOpCode::PushBounded => {
|
||||||
|
format!("{}", instr.imm_u32().unwrap())
|
||||||
|
}
|
||||||
|
_ => format!("0x{}", hex::encode(instr.imm)),
|
||||||
|
};
|
||||||
|
line.push_str(&s);
|
||||||
|
}
|
||||||
|
lines.push(line);
|
||||||
|
pc = instr.next_pc;
|
||||||
|
}
|
||||||
|
Err(_) => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lines.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encode_decode_roundtrip_preserves_structure() {
|
||||||
|
// Program: PUSH_I32 42; PUSH_I32 100; ADD; PUSH_BOOL 1; JMP 12; NOP; HALT
|
||||||
|
let mut prog = Vec::new();
|
||||||
|
prog.extend(encode_instr(CoreOpCode::PushI32, Some(&42i32.to_le_bytes())));
|
||||||
|
prog.extend(encode_instr(CoreOpCode::PushI32, Some(&100i32.to_le_bytes())));
|
||||||
|
prog.extend(encode_instr(CoreOpCode::Add, None));
|
||||||
|
prog.extend(encode_instr(CoreOpCode::PushBool, Some(&[1u8])));
|
||||||
|
// Jump to the HALT (compute absolute PC within this byte slice)
|
||||||
|
// Current pc after previous: 2+4 + 2+4 + 2 + 2+1 = 17 bytes
|
||||||
|
// Next we place: JMP (2+4), NOP (2), HALT (2)
|
||||||
|
// We want JMP target to land at the HALT's pc
|
||||||
|
let jmp_target: u32 = 17 + 2 + 4 + 2; // pc where HALT starts
|
||||||
|
prog.extend(encode_instr(CoreOpCode::Jmp, Some(&jmp_target.to_le_bytes())));
|
||||||
|
prog.extend(encode_instr(CoreOpCode::Nop, None));
|
||||||
|
prog.extend(encode_instr(CoreOpCode::Halt, None));
|
||||||
|
|
||||||
|
// Decode sequentially and check opcodes and immediates
|
||||||
|
let mut pc = 0usize;
|
||||||
|
let mut seen = Vec::new();
|
||||||
|
while pc < prog.len() {
|
||||||
|
let instr = decode_next(pc, &prog).expect("decode ok");
|
||||||
|
seen.push(instr);
|
||||||
|
pc = instr.next_pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(seen.len(), 7);
|
||||||
|
assert_eq!(seen[0].opcode, CoreOpCode::PushI32);
|
||||||
|
assert_eq!(seen[0].imm_i32().unwrap(), 42);
|
||||||
|
assert_eq!(seen[1].opcode, CoreOpCode::PushI32);
|
||||||
|
assert_eq!(seen[1].imm_i32().unwrap(), 100);
|
||||||
|
assert_eq!(seen[2].opcode, CoreOpCode::Add);
|
||||||
|
assert_eq!(seen[3].opcode, CoreOpCode::PushBool);
|
||||||
|
assert_eq!(seen[3].imm_u8().unwrap(), 1);
|
||||||
|
assert_eq!(seen[4].opcode, CoreOpCode::Jmp);
|
||||||
|
assert_eq!(seen[4].imm_u32().unwrap(), jmp_target);
|
||||||
|
assert_eq!(seen[5].opcode, CoreOpCode::Nop);
|
||||||
|
assert_eq!(seen[6].opcode, CoreOpCode::Halt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn disasm_contains_expected_mnemonics_and_operands() {
|
||||||
|
// Tiny deterministic sample: NOP; PUSH_I32 -7; PUSH_BOOL 0; ADD; HALT
|
||||||
|
let mut prog = Vec::new();
|
||||||
|
prog.extend(encode_instr(CoreOpCode::Nop, None));
|
||||||
|
prog.extend(encode_instr(CoreOpCode::PushI32, Some(&(-7i32).to_le_bytes())));
|
||||||
|
prog.extend(encode_instr(CoreOpCode::PushBool, Some(&[0u8])));
|
||||||
|
prog.extend(encode_instr(CoreOpCode::Add, None));
|
||||||
|
prog.extend(encode_instr(CoreOpCode::Halt, None));
|
||||||
|
|
||||||
|
let text = disasm(&prog);
|
||||||
|
|
||||||
|
// Must contain stable opcode names and operand text
|
||||||
|
assert!(text.contains("NOP"));
|
||||||
|
assert!(text.contains("PUSH_I32 -7"));
|
||||||
|
assert!(text.contains("PUSH_BOOL 0"));
|
||||||
|
assert!(text.contains("ADD"));
|
||||||
|
assert!(text.contains("HALT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimal hex helper to avoid extra deps in tests
|
||||||
|
mod hex {
|
||||||
|
pub fn encode(bytes: &[u8]) -> String {
|
||||||
|
let mut s = String::with_capacity(bytes.len() * 2);
|
||||||
|
const HEX: &[u8; 16] = b"0123456789abcdef";
|
||||||
|
for &b in bytes {
|
||||||
|
s.push(HEX[(b >> 4) as usize] as char);
|
||||||
|
s.push(HEX[(b & 0x0f) as usize] as char);
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
301
files/TODOs.md
301
files/TODOs.md
@ -1,31 +1,302 @@
|
|||||||
# PR-1.7 — Bytecode Roundtrip Tests (Encode/Decode/Disasm Sanity)
|
# PR-2.1 — Remove ScopeFrame and HIP Runtime Structures
|
||||||
|
|
||||||
### Briefing
|
### Briefing
|
||||||
|
|
||||||
Before touching VM behavior, we want confidence that the bytecode toolchain is coherent after the ISA reset.
|
The new architecture removes HIP, borrow/mutate/peek semantics, and any gate-based lifetime tracking. The VM must no longer depend on `ScopeFrame` or related structures.
|
||||||
|
|
||||||
### Target
|
### Target
|
||||||
|
|
||||||
* Add roundtrip tests that validate:
|
* Remove `ScopeFrame` and any HIP-related runtime data structures.
|
||||||
|
* Ensure the VM compiles and runs without any scope/gate logic.
|
||||||
* Encode → decode preserves structure.
|
|
||||||
* Disasm prints stable, readable output.
|
|
||||||
|
|
||||||
### Work items
|
### Work items
|
||||||
|
|
||||||
* Add a small set of “known-good” bytecode samples built using the new minimal ISA.
|
* Delete `scope_frame.rs` and any modules dedicated to HIP or gate lifetimes.
|
||||||
* Implement tests:
|
* Remove fields in VM state that track scope frames, gates, or borrow state.
|
||||||
|
* Update the main VM execution loop to no longer push/pop scope frames.
|
||||||
* Encode then decode equals original structure.
|
* Remove any trap logic that references scope or gate violations.
|
||||||
* Disasm output contains expected instruction names and operands.
|
|
||||||
* Keep samples intentionally tiny and deterministic.
|
|
||||||
|
|
||||||
### Acceptance checklist
|
### Acceptance checklist
|
||||||
|
|
||||||
* [ ] Roundtrip tests exist and pass.
|
* [ ] `ScopeFrame` and related modules are fully removed.
|
||||||
* [ ] Samples do not depend on legacy semantics.
|
* [ ] VM compiles without scope/gate concepts.
|
||||||
|
* [ ] No HIP-related symbols remain in the VM crate.
|
||||||
* [ ] `cargo test` passes.
|
* [ ] `cargo test` passes.
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
* New unit tests for encode/decode/disasm roundtrip.
|
* Existing tests only.
|
||||||
|
|
||||||
|
### Junie instructions
|
||||||
|
|
||||||
|
**You MAY:**
|
||||||
|
|
||||||
|
* Delete scope/gate-related modules and fields.
|
||||||
|
* Update code to remove references to them.
|
||||||
|
|
||||||
|
**You MUST NOT:**
|
||||||
|
|
||||||
|
* Introduce new lifetime or ownership systems.
|
||||||
|
* Replace scope frames with another architecture.
|
||||||
|
* Add compatibility layers.
|
||||||
|
|
||||||
|
**If unclear:**
|
||||||
|
|
||||||
|
* Ask for clarification instead of inventing new runtime concepts.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# PR-2.2 — Simplify VM Execution Loop (Pure Stack Machine)
|
||||||
|
|
||||||
|
### Briefing
|
||||||
|
|
||||||
|
The VM should operate as a simple stack-based interpreter with a clear fetch–decode–execute loop, without hidden side channels or legacy behaviors.
|
||||||
|
|
||||||
|
### Target
|
||||||
|
|
||||||
|
* Normalize the VM main loop to a clean stack-machine structure.
|
||||||
|
* Remove any legacy control paths tied to HIP/RC behavior.
|
||||||
|
|
||||||
|
### Work items
|
||||||
|
|
||||||
|
* Refactor the main interpreter loop to:
|
||||||
|
|
||||||
|
* Fetch instruction at PC.
|
||||||
|
* Decode opcode.
|
||||||
|
* Execute operation on stack/frames.
|
||||||
|
* Remove any conditional logic that depends on HIP/RC state.
|
||||||
|
* Ensure PC advancement is canonical and centralized.
|
||||||
|
|
||||||
|
### Acceptance checklist
|
||||||
|
|
||||||
|
* [ ] VM loop is structurally simple and readable.
|
||||||
|
* [ ] No HIP/RC conditionals remain.
|
||||||
|
* [ ] VM compiles and runs basic programs.
|
||||||
|
* [ ] `cargo test` passes.
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
* Existing tests only.
|
||||||
|
|
||||||
|
### Junie instructions
|
||||||
|
|
||||||
|
**You MAY:**
|
||||||
|
|
||||||
|
* Refactor the interpreter loop for clarity.
|
||||||
|
* Remove legacy conditionals.
|
||||||
|
|
||||||
|
**You MUST NOT:**
|
||||||
|
|
||||||
|
* Change opcode semantics.
|
||||||
|
* Introduce GC, closures, or coroutines here.
|
||||||
|
* Redesign the instruction set.
|
||||||
|
|
||||||
|
**If unclear:**
|
||||||
|
|
||||||
|
* Ask before modifying control flow assumptions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# PR-2.3 — Normalize Value Model (Stack vs Heap References)
|
||||||
|
|
||||||
|
### Briefing
|
||||||
|
|
||||||
|
The VM must use a clear value model: primitives and tuples on the stack, heap objects referenced through opaque handles. This PR prepares the VM for the GC-based heap.
|
||||||
|
|
||||||
|
### Target
|
||||||
|
|
||||||
|
* Define a single `Value` representation that distinguishes:
|
||||||
|
|
||||||
|
* Immediate primitives.
|
||||||
|
* Heap references (opaque handles).
|
||||||
|
* Remove any gate-based or borrow-based value types.
|
||||||
|
|
||||||
|
### Work items
|
||||||
|
|
||||||
|
* Review the `Value` or equivalent enum/struct.
|
||||||
|
* Remove variants related to gates, borrows, or HIP.
|
||||||
|
* Ensure only the following categories remain:
|
||||||
|
|
||||||
|
* Primitives (int, bool, etc.).
|
||||||
|
* Tuples or small aggregates.
|
||||||
|
* Heap reference handle (placeholder for future GC objects).
|
||||||
|
* Update stack operations accordingly.
|
||||||
|
|
||||||
|
### Acceptance checklist
|
||||||
|
|
||||||
|
* [ ] `Value` type has no HIP/gate-related variants.
|
||||||
|
* [ ] All stack operations compile with the new value model.
|
||||||
|
* [ ] No borrow/mutate semantics remain.
|
||||||
|
* [ ] `cargo test` passes.
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
* Existing tests only.
|
||||||
|
|
||||||
|
### Junie instructions
|
||||||
|
|
||||||
|
**You MAY:**
|
||||||
|
|
||||||
|
* Simplify the `Value` enum/struct.
|
||||||
|
* Remove legacy variants and adjust matches.
|
||||||
|
|
||||||
|
**You MUST NOT:**
|
||||||
|
|
||||||
|
* Design the GC handle layout.
|
||||||
|
* Introduce new object systems.
|
||||||
|
* Change instruction semantics beyond type cleanup.
|
||||||
|
|
||||||
|
**If unclear:**
|
||||||
|
|
||||||
|
* Ask what the intended value shape should be.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# PR-2.4 — Consolidate Trap and Error Surface
|
||||||
|
|
||||||
|
### Briefing
|
||||||
|
|
||||||
|
With HIP removed, the runtime trap surface must be simplified and aligned with the new stack+heap model.
|
||||||
|
|
||||||
|
### Target
|
||||||
|
|
||||||
|
* Define a minimal, coherent set of runtime traps.
|
||||||
|
* Remove traps that only existed for HIP/RC semantics.
|
||||||
|
|
||||||
|
### Work items
|
||||||
|
|
||||||
|
* Audit the VM’s trap/error enums.
|
||||||
|
* Remove HIP/RC-related traps.
|
||||||
|
* Keep only traps that remain meaningful, such as:
|
||||||
|
|
||||||
|
* Illegal instruction.
|
||||||
|
* Stack underflow/overflow.
|
||||||
|
* Invalid jump target.
|
||||||
|
* Out-of-bounds memory access.
|
||||||
|
* Ensure trap handling paths are consistent and deterministic.
|
||||||
|
|
||||||
|
### Acceptance checklist
|
||||||
|
|
||||||
|
* [ ] Trap enum contains only relevant traps.
|
||||||
|
* [ ] No HIP/RC trap names remain.
|
||||||
|
* [ ] VM compiles and tests pass.
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
* Adjust any tests expecting removed trap codes.
|
||||||
|
|
||||||
|
### Junie instructions
|
||||||
|
|
||||||
|
**You MAY:**
|
||||||
|
|
||||||
|
* Delete unused trap variants.
|
||||||
|
* Refactor match statements accordingly.
|
||||||
|
|
||||||
|
**You MUST NOT:**
|
||||||
|
|
||||||
|
* Add new trap categories without approval.
|
||||||
|
* Change the meaning of existing non-legacy traps.
|
||||||
|
|
||||||
|
**If unclear:**
|
||||||
|
|
||||||
|
* Ask before modifying trap semantics.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# PR-2.5 — Prepare Call Frame Structure for Closures and Coroutines
|
||||||
|
|
||||||
|
### Briefing
|
||||||
|
|
||||||
|
Before introducing closures and coroutines, the call frame structure must be neutral and future-proof, without HIP-specific fields.
|
||||||
|
|
||||||
|
### Target
|
||||||
|
|
||||||
|
* Simplify the call frame to a minimal, generic structure.
|
||||||
|
* Remove any HIP/borrow/gate-related fields.
|
||||||
|
|
||||||
|
### Work items
|
||||||
|
|
||||||
|
* Review the call frame struct.
|
||||||
|
* Remove fields tied to scope frames, borrow state, or gates.
|
||||||
|
* Ensure the frame contains only:
|
||||||
|
|
||||||
|
* Function identifier.
|
||||||
|
* Program counter.
|
||||||
|
* Base stack pointer.
|
||||||
|
* Locals or register area (if applicable).
|
||||||
|
* Keep the structure simple and extensible.
|
||||||
|
|
||||||
|
### Acceptance checklist
|
||||||
|
|
||||||
|
* [ ] Call frame struct has no HIP-related fields.
|
||||||
|
* [ ] VM call/return paths compile and work.
|
||||||
|
* [ ] `cargo test` passes.
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
* Existing call-related tests must still pass.
|
||||||
|
|
||||||
|
### Junie instructions
|
||||||
|
|
||||||
|
**You MAY:**
|
||||||
|
|
||||||
|
* Remove unused fields from the frame.
|
||||||
|
* Refactor call/return code to match the new structure.
|
||||||
|
|
||||||
|
**You MUST NOT:**
|
||||||
|
|
||||||
|
* Introduce closure or coroutine logic yet.
|
||||||
|
* Redesign the call stack architecture.
|
||||||
|
|
||||||
|
**If unclear:**
|
||||||
|
|
||||||
|
* Ask before changing frame responsibilities.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# PR-2.6 — Remove Dead Runtime Modules and Symbols
|
||||||
|
|
||||||
|
### Briefing
|
||||||
|
|
||||||
|
After the VM reset, there will be leftover modules, helpers, or symbols that are no longer referenced. This PR performs a final cleanup pass.
|
||||||
|
|
||||||
|
### Target
|
||||||
|
|
||||||
|
* Remove dead or unreachable runtime code.
|
||||||
|
* Ensure the VM crate has a minimal, clean surface.
|
||||||
|
|
||||||
|
### Work items
|
||||||
|
|
||||||
|
* Use compiler warnings and search tools to find:
|
||||||
|
|
||||||
|
* Unused modules.
|
||||||
|
* Unused structs/enums/functions.
|
||||||
|
* Legacy HIP/RC terminology.
|
||||||
|
* Remove dead code.
|
||||||
|
* Update module trees and public exports.
|
||||||
|
|
||||||
|
### Acceptance checklist
|
||||||
|
|
||||||
|
* [ ] No dead modules remain.
|
||||||
|
* [ ] No HIP/RC terminology found in the VM crate.
|
||||||
|
* [ ] `cargo test` passes.
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
* Existing tests only.
|
||||||
|
|
||||||
|
### Junie instructions
|
||||||
|
|
||||||
|
**You MAY:**
|
||||||
|
|
||||||
|
* Remove unused code and modules.
|
||||||
|
* Update `mod.rs` and exports.
|
||||||
|
|
||||||
|
**You MUST NOT:**
|
||||||
|
|
||||||
|
* Remove code that is still referenced.
|
||||||
|
* Replace deleted modules with new experimental ones.
|
||||||
|
|
||||||
|
**If unclear:**
|
||||||
|
|
||||||
|
* Ask before deleting anything that looks structurally important.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user