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
|
||||
|
||||
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
|
||||
|
||||
* Add roundtrip tests that validate:
|
||||
|
||||
* Encode → decode preserves structure.
|
||||
* Disasm prints stable, readable output.
|
||||
* Remove `ScopeFrame` and any HIP-related runtime data structures.
|
||||
* Ensure the VM compiles and runs without any scope/gate logic.
|
||||
|
||||
### Work items
|
||||
|
||||
* Add a small set of “known-good” bytecode samples built using the new minimal ISA.
|
||||
* Implement tests:
|
||||
|
||||
* Encode then decode equals original structure.
|
||||
* Disasm output contains expected instruction names and operands.
|
||||
* Keep samples intentionally tiny and deterministic.
|
||||
* Delete `scope_frame.rs` and any modules dedicated to HIP or gate lifetimes.
|
||||
* 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.
|
||||
* Remove any trap logic that references scope or gate violations.
|
||||
|
||||
### Acceptance checklist
|
||||
|
||||
* [ ] Roundtrip tests exist and pass.
|
||||
* [ ] Samples do not depend on legacy semantics.
|
||||
* [ ] `ScopeFrame` and related modules are fully removed.
|
||||
* [ ] VM compiles without scope/gate concepts.
|
||||
* [ ] No HIP-related symbols remain in the VM crate.
|
||||
* [ ] `cargo test` passes.
|
||||
|
||||
### 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