diff --git a/Cargo.lock b/Cargo.lock index 7f4f33f0..b933398f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2238,6 +2238,7 @@ dependencies = [ "prometeu-bytecode", "serde", "serde_json", + "url", ] [[package]] diff --git a/crates/prometeu-compiler/tests/link_integration.rs b/crates/prometeu-compiler/tests/link_integration.rs index 01569268..78b2546a 100644 --- a/crates/prometeu-compiler/tests/link_integration.rs +++ b/crates/prometeu-compiler/tests/link_integration.rs @@ -71,9 +71,10 @@ fn test_integration_test01_link() { let mut native = SimpleNative; let mut hw = SimpleHardware::new(); + let mut ctx = HostContext::new(Some(&mut hw)); // Run for a bit - let report = vm.run_budget(1000, &mut native, &mut hw).expect("VM execution failed"); + let report = vm.run_budget(1000, &mut native, &mut ctx).expect("VM execution failed"); // It should not trap. test01 might loop or return. if let LogicalFrameEndingReason::Trap(t) = report.reason { diff --git a/crates/prometeu-core/Cargo.toml b/crates/prometeu-core/Cargo.toml index 47fc58dc..1c4ef217 100644 --- a/crates/prometeu-core/Cargo.toml +++ b/crates/prometeu-core/Cargo.toml @@ -8,4 +8,5 @@ license.workspace = true serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" prometeu-bytecode = { path = "../prometeu-bytecode" } -prometeu-abi = { path = "../prometeu-abi" } \ No newline at end of file +prometeu-abi = { path = "../prometeu-abi" } +url = "2.5.8" \ No newline at end of file diff --git a/crates/prometeu-core/src/prometeu_os/prometeu_os.rs b/crates/prometeu-core/src/prometeu_os/prometeu_os.rs index d25af7a8..7fb6ec2d 100644 --- a/crates/prometeu-core/src/prometeu_os/prometeu_os.rs +++ b/crates/prometeu-core/src/prometeu_os/prometeu_os.rs @@ -181,7 +181,8 @@ impl PrometeuOS { /// Executes a single VM instruction (Debug). pub fn debug_step_instruction(&mut self, vm: &mut VirtualMachine, hw: &mut dyn HardwareBridge) -> Option { - match vm.step(self, hw) { + let mut ctx = HostContext::new(Some(hw)); + match vm.step(self, &mut ctx) { Ok(_) => None, Err(e) => { let err_msg = format!("PVM Fault during Step: {:?}", e); @@ -235,7 +236,10 @@ impl PrometeuOS { // 3. VM Execution if budget > 0 { // Run the VM until the budget is hit or FRAME_SYNC is reached. - let run_result = vm.run_budget(budget, self, hw); // internally dispatch to frame on SDK + let run_result = { + let mut ctx = HostContext::new(Some(hw)); + vm.run_budget(budget, self, &mut ctx) + }; // internally dispatch to frame on SDK match run_result { Ok(run) => { diff --git a/crates/prometeu-core/src/virtual_machine/host_context.rs b/crates/prometeu-core/src/virtual_machine/host_context.rs index 3841715c..7d6d288b 100644 --- a/crates/prometeu-core/src/virtual_machine/host_context.rs +++ b/crates/prometeu-core/src/virtual_machine/host_context.rs @@ -18,3 +18,14 @@ impl<'a> HostContext<'a> { } } } + +pub trait HostContextProvider { + fn make_ctx<'a>(&'a mut self) -> HostContext<'a>; +} + +impl HostContextProvider for T { + #[inline] + fn make_ctx<'a>(&'a mut self) -> HostContext<'a> { + HostContext::new(Some(self)) + } +} diff --git a/crates/prometeu-core/src/virtual_machine/mod.rs b/crates/prometeu-core/src/virtual_machine/mod.rs index 140ec66a..57016d26 100644 --- a/crates/prometeu-core/src/virtual_machine/mod.rs +++ b/crates/prometeu-core/src/virtual_machine/mod.rs @@ -8,7 +8,7 @@ pub mod opcode_spec; pub mod bytecode; pub mod verifier; -pub use host_context::HostContext; +pub use host_context::{HostContext, HostContextProvider}; pub use program::ProgramImage; pub use prometeu_bytecode::abi::TrapInfo; pub use prometeu_bytecode::opcode::OpCode; diff --git a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs index dcafa3d8..c0d747b0 100644 --- a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs +++ b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs @@ -238,7 +238,7 @@ impl VirtualMachine { &mut self, budget: u64, native: &mut dyn NativeInterface, - hw: &mut dyn HardwareBridge, + ctx: &mut HostContext, ) -> Result { let start_cycles = self.cycles; let mut steps_executed = 0; @@ -281,7 +281,7 @@ impl VirtualMachine { } // Execute a single step (Fetch-Decode-Execute) - if let Err(reason) = self.step(native, hw) { + if let Err(reason) = self.step(native, ctx) { ending_reason = Some(reason); break; } @@ -331,7 +331,11 @@ impl VirtualMachine { /// 1. Fetch: Read the opcode from memory. /// 2. Decode: Identify what operation to perform. /// 3. Execute: Perform the operation, updating stacks, memory, or calling peripherals. - pub fn step(&mut self, native: &mut dyn NativeInterface, hw: &mut dyn HardwareBridge) -> Result<(), LogicalFrameEndingReason> { + pub fn step(&mut self, native: &mut dyn NativeInterface, ctx: &mut HostContext) -> Result<(), LogicalFrameEndingReason> { + self.step_impl(native, ctx) + } + + fn step_impl(&mut self, native: &mut dyn NativeInterface, ctx: &mut HostContext) -> Result<(), LogicalFrameEndingReason> { if self.halted || self.pc >= self.program.rom.len() { return Ok(()); } @@ -843,8 +847,7 @@ impl VirtualMachine { let stack_height_before = self.operand_stack.len(); let mut ret = crate::virtual_machine::HostReturn::new(&mut self.operand_stack); - let mut ctx = HostContext::new(Some(hw)); - native.syscall(id, &args, &mut ret, &mut ctx).map_err(|fault| match fault { + native.syscall(id, &args, &mut ret, ctx).map_err(|fault| match fault { crate::virtual_machine::VmFault::Trap(code, msg) => self.trap(code, OpCode::Syscall as u16, msg, pc_at_syscall), crate::virtual_machine::VmFault::Panic(msg) => LogicalFrameEndingReason::Panic(msg), crate::virtual_machine::VmFault::Unavailable => LogicalFrameEndingReason::Panic("Host feature unavailable".into()), @@ -933,6 +936,7 @@ mod tests { use crate::virtual_machine::{expect_int, HostReturn, Value, VmFault}; use prometeu_bytecode::abi::SourceSpan; use prometeu_bytecode::FunctionMeta; + use url::Host; struct MockNative; impl NativeInterface for MockNative { @@ -941,24 +945,10 @@ mod tests { } } - struct MockHardware; - impl HardwareBridge for MockHardware { - fn gfx(&self) -> &crate::hardware::Gfx { todo!() } - fn gfx_mut(&mut self) -> &mut crate::hardware::Gfx { todo!() } - fn audio(&self) -> &crate::hardware::Audio { todo!() } - fn audio_mut(&mut self) -> &mut crate::hardware::Audio { todo!() } - fn pad(&self) -> &crate::hardware::Pad { todo!() } - fn pad_mut(&mut self) -> &mut crate::hardware::Pad { todo!() } - fn touch(&self) -> &crate::hardware::Touch { todo!() } - fn touch_mut(&mut self) -> &mut crate::hardware::Touch { todo!() } - fn assets(&self) -> &crate::hardware::AssetManager { todo!() } - fn assets_mut(&mut self) -> &mut crate::hardware::AssetManager { todo!() } - } - #[test] fn test_arithmetic_chain() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // (10 + 20) * 2 / 5 % 4 = 12 * 2 / 5 % 4 = 60 / 5 % 4 = 12 % 4 = 0 // wait: (10 + 20) = 30. 30 * 2 = 60. 60 / 5 = 12. 12 % 4 = 0. @@ -980,7 +970,7 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - vm.run_budget(100, &mut native, &mut hw).unwrap(); + vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Int32(0)); } @@ -988,7 +978,7 @@ mod tests { #[test] fn test_div_by_zero_trap() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); let mut rom = Vec::new(); rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); @@ -999,7 +989,7 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -1013,7 +1003,7 @@ mod tests { #[test] fn test_int_to_bound_checked_trap() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); let mut rom = Vec::new(); rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); @@ -1022,7 +1012,7 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -1036,7 +1026,7 @@ mod tests { #[test] fn test_bounded_add_overflow_trap() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); let mut rom = Vec::new(); rom.extend_from_slice(&(OpCode::PushBounded as u16).to_le_bytes()); @@ -1047,7 +1037,7 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -1061,7 +1051,7 @@ mod tests { #[test] fn test_comparisons_polymorphic() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // 10 < 20.5 (true) let mut rom = Vec::new(); @@ -1073,7 +1063,7 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - vm.run_budget(100, &mut native, &mut hw).unwrap(); + vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Boolean(true)); } @@ -1086,9 +1076,9 @@ mod tests { let mut vm = new_test_vm(rom.clone(), vec![]); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); assert_eq!(vm.peek().unwrap(), &Value::Int64(42)); } @@ -1101,9 +1091,9 @@ mod tests { let mut vm = new_test_vm(rom.clone(), vec![]); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); assert_eq!(vm.peek().unwrap(), &Value::Float(3.14)); } @@ -1120,11 +1110,11 @@ mod tests { let mut vm = new_test_vm(rom.clone(), vec![]); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); - vm.step(&mut native, &mut hw).unwrap(); // Push true + vm.step(&mut native, &mut ctx).unwrap(); // Push true assert_eq!(vm.peek().unwrap(), &Value::Boolean(true)); - vm.step(&mut native, &mut hw).unwrap(); // Push false + vm.step(&mut native, &mut ctx).unwrap(); // Push false assert_eq!(vm.peek().unwrap(), &Value::Boolean(false)); } @@ -1138,9 +1128,9 @@ mod tests { let cp = vec![Value::String("hello".into())]; let mut vm = VirtualMachine::new(rom, cp); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); assert_eq!(vm.peek().unwrap(), &Value::String("hello".into())); } @@ -1199,12 +1189,12 @@ mod tests { }; vm.prepare_call("0"); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // Run until Halt let mut steps = 0; while !vm.halted && steps < 100 { - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); steps += 1; } @@ -1244,10 +1234,10 @@ mod tests { }; vm.prepare_call("0"); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); - vm.step(&mut native, &mut hw).unwrap(); // CALL - let res = vm.step(&mut native, &mut hw); // RET -> should fail + vm.step(&mut native, &mut ctx).unwrap(); // CALL + let res = vm.step(&mut native, &mut ctx); // RET -> should fail assert!(res.is_err()); match res.unwrap_err() { LogicalFrameEndingReason::Trap(trap) => { @@ -1282,9 +1272,9 @@ mod tests { ..Default::default() }; vm2.prepare_call("0"); - vm2.step(&mut native, &mut hw).unwrap(); // CALL - vm2.step(&mut native, &mut hw).unwrap(); // PUSH_I64 - vm2.step(&mut native, &mut hw).unwrap(); // RET + vm2.step(&mut native, &mut ctx).unwrap(); // CALL + vm2.step(&mut native, &mut ctx).unwrap(); // PUSH_I64 + vm2.step(&mut native, &mut ctx).unwrap(); // RET assert_eq!(vm2.operand_stack.len(), 1); assert_eq!(vm2.pop().unwrap(), Value::Int64(123)); @@ -1316,32 +1306,32 @@ mod tests { let mut vm = new_test_vm(rom.clone(), vec![]); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // Execute step by step and check stack - vm.step(&mut native, &mut hw).unwrap(); // Push 1 + vm.step(&mut native, &mut ctx).unwrap(); // Push 1 assert_eq!(vm.operand_stack.len(), 1); - vm.step(&mut native, &mut hw).unwrap(); // PushScope 1 + vm.step(&mut native, &mut ctx).unwrap(); // PushScope 1 assert_eq!(vm.scope_stack.len(), 1); assert_eq!(vm.scope_stack.last().unwrap().scope_stack_base, 1); - vm.step(&mut native, &mut hw).unwrap(); // Push 2 + vm.step(&mut native, &mut ctx).unwrap(); // Push 2 assert_eq!(vm.operand_stack.len(), 2); - vm.step(&mut native, &mut hw).unwrap(); // PushScope 2 + vm.step(&mut native, &mut ctx).unwrap(); // PushScope 2 assert_eq!(vm.scope_stack.len(), 2); assert_eq!(vm.scope_stack.last().unwrap().scope_stack_base, 2); - vm.step(&mut native, &mut hw).unwrap(); // Push 3 + vm.step(&mut native, &mut ctx).unwrap(); // Push 3 assert_eq!(vm.operand_stack.len(), 3); - vm.step(&mut native, &mut hw).unwrap(); // PopScope 2 + vm.step(&mut native, &mut ctx).unwrap(); // PopScope 2 assert_eq!(vm.scope_stack.len(), 1); assert_eq!(vm.operand_stack.len(), 2); assert_eq!(vm.operand_stack.last().unwrap(), &Value::Int64(2)); - vm.step(&mut native, &mut hw).unwrap(); // PopScope 1 + vm.step(&mut native, &mut ctx).unwrap(); // PopScope 1 assert_eq!(vm.scope_stack.len(), 0); assert_eq!(vm.operand_stack.len(), 1); assert_eq!(vm.operand_stack.last().unwrap(), &Value::Int64(1)); @@ -1392,11 +1382,11 @@ mod tests { }; vm.prepare_call("0"); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); let mut steps = 0; while !vm.halted && steps < 100 { - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); steps += 1; } @@ -1415,16 +1405,16 @@ mod tests { let mut vm = new_test_vm(rom.clone(), vec![]); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); assert_eq!(vm.peek().unwrap(), &Value::Int32(42)); } #[test] fn test_bitwise_promotion() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // i32 & i32 -> i32 let mut rom = Vec::new(); @@ -1436,9 +1426,9 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - vm.step(&mut native, &mut hw).unwrap(); - vm.step(&mut native, &mut hw).unwrap(); - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Int32(0)); // i32 | i64 -> i64 @@ -1451,16 +1441,16 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - vm.step(&mut native, &mut hw).unwrap(); - vm.step(&mut native, &mut hw).unwrap(); - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Int64(0xFF)); } #[test] fn test_comparisons_lte_gte() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // 10 <= 20 (true) let mut rom = Vec::new(); @@ -1472,9 +1462,9 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - vm.step(&mut native, &mut hw).unwrap(); - vm.step(&mut native, &mut hw).unwrap(); - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Boolean(true)); // 20 >= 20 (true) @@ -1487,16 +1477,16 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - vm.step(&mut native, &mut hw).unwrap(); - vm.step(&mut native, &mut hw).unwrap(); - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Boolean(true)); } #[test] fn test_negation() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); let mut rom = Vec::new(); rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); @@ -1505,15 +1495,15 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - vm.step(&mut native, &mut hw).unwrap(); - vm.step(&mut native, &mut hw).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); + vm.step(&mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Int32(-42)); } #[test] fn test_jmp_if_true() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // Corrected Calculations: // 0-1: PushBool @@ -1536,17 +1526,17 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - vm.step(&mut native, &mut hw).unwrap(); // PushBool - vm.step(&mut native, &mut hw).unwrap(); // JmpIfTrue + vm.step(&mut native, &mut ctx).unwrap(); // PushBool + vm.step(&mut native, &mut ctx).unwrap(); // JmpIfTrue assert_eq!(vm.pc, 11); - vm.step(&mut native, &mut hw).unwrap(); // PushI32 + vm.step(&mut native, &mut ctx).unwrap(); // PushI32 assert_eq!(vm.pop().unwrap(), Value::Int32(100)); } #[test] fn test_trap_opcode() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); let mut rom = Vec::new(); rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); @@ -1555,7 +1545,7 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(report.reason, LogicalFrameEndingReason::Breakpoint); assert_eq!(vm.pc, 8); // PushI32 (6 bytes) + Trap (2 bytes) @@ -1565,7 +1555,7 @@ mod tests { #[test] fn test_pop_n_opcode() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); let mut rom = Vec::new(); rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); @@ -1579,7 +1569,7 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - vm.run_budget(100, &mut native, &mut hw).unwrap(); + vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Int32(1)); assert!(vm.pop().is_err()); // Stack should be empty @@ -1588,7 +1578,7 @@ mod tests { #[test] fn test_hip_traps_oob() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // ALLOC int, 1 -> Gate(0) // GATE_LOAD 1 -> TRAP_OOB (size is 1, offset 1 is invalid) @@ -1601,7 +1591,7 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -1616,7 +1606,7 @@ mod tests { #[test] fn test_hip_traps_type() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // PUSH_I32 42 // GATE_LOAD 0 -> TRAP_TYPE (Expected gate handle, got Int32) @@ -1628,7 +1618,7 @@ mod tests { rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -1654,7 +1644,7 @@ mod tests { code_len: rom.len() as u32, ..Default::default() }]); - let mut hw = crate::Hardware::new(); + let mut ctx = HostContext::new(None); struct TestNative; impl NativeInterface for TestNative { fn syscall(&mut self, _id: u32, _args: &[Value], _ret: &mut HostReturn, _ctx: &mut HostContext) -> Result<(), VmFault> { Ok(()) } @@ -1662,7 +1652,7 @@ mod tests { let mut native = TestNative; vm.prepare_call("0"); - let result = vm.run_budget(100, &mut native, &mut hw).expect("VM run failed"); + let result = vm.run_budget(100, &mut native, &mut ctx).expect("VM run failed"); assert_eq!(result.reason, LogicalFrameEndingReason::EndOfRom); } @@ -1690,10 +1680,10 @@ mod tests { ..Default::default() }]); let mut native = MultiReturnNative; - let mut hw = crate::Hardware::new(); + let mut ctx = HostContext::new(None); vm.prepare_call("0"); - vm.run_budget(100, &mut native, &mut hw).unwrap(); + vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Bounded(255)); assert_eq!(vm.pop().unwrap(), Value::Int64(42)); @@ -1721,11 +1711,11 @@ mod tests { ..Default::default() }]); let mut native = VoidReturnNative; - let mut hw = crate::Hardware::new(); + let mut ctx = HostContext::new(None); vm.prepare_call("0"); vm.operand_stack.push(Value::Int32(100)); - vm.run_budget(100, &mut native, &mut hw).unwrap(); + vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Int32(100)); assert!(vm.operand_stack.is_empty()); @@ -1756,10 +1746,10 @@ mod tests { ..Default::default() }]); let mut native = ArgCheckNative; - let mut hw = crate::Hardware::new(); + let mut ctx = HostContext::new(None); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -1778,10 +1768,10 @@ mod tests { ]; let mut vm = new_test_vm(rom.clone(), vec![]); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -1803,10 +1793,10 @@ mod tests { ]; let mut vm = new_test_vm(rom.clone(), vec![]); let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -1840,10 +1830,10 @@ mod tests { let mut vm = new_test_vm(rom.clone(), vec![]); let mut native = BadNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Panic(msg) => assert!(msg.contains("results mismatch")), _ => panic!("Expected Panic, got {:?}", report.reason), @@ -1933,7 +1923,7 @@ mod tests { #[test] fn test_calling_convention_add() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // F0 (entry): // PUSH_I32 10 @@ -1985,7 +1975,7 @@ mod tests { ]); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(report.reason, LogicalFrameEndingReason::Halted); assert_eq!(vm.operand_stack.last().unwrap(), &Value::Int32(30)); } @@ -1993,7 +1983,7 @@ mod tests { #[test] fn test_calling_convention_multi_slot_return() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // F0: // CALL 1 @@ -2037,7 +2027,7 @@ mod tests { ]); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(report.reason, LogicalFrameEndingReason::Halted); // Stack should be [100, 200] assert_eq!(vm.operand_stack.len(), 2); @@ -2048,7 +2038,7 @@ mod tests { #[test] fn test_calling_convention_void_call() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // F0: // PUSH_I32 42 @@ -2088,7 +2078,7 @@ mod tests { ]); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(report.reason, LogicalFrameEndingReason::Halted); assert_eq!(vm.operand_stack.len(), 0); } @@ -2096,7 +2086,7 @@ mod tests { #[test] fn test_trap_invalid_func() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // CALL 99 (invalid) let mut rom = Vec::new(); @@ -2104,7 +2094,7 @@ mod tests { rom.extend_from_slice(&99u32.to_le_bytes()); let mut vm = new_test_vm(rom.clone(), vec![]); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -2118,7 +2108,7 @@ mod tests { #[test] fn test_trap_bad_ret_slots() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // F0: CALL 1; HALT // F1: PUSH_I32 42; RET (expected 0 slots) @@ -2153,7 +2143,7 @@ mod tests { ]); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -2167,7 +2157,7 @@ mod tests { #[test] fn test_locals_round_trip() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // PUSH_I32 42 // SET_LOCAL 0 @@ -2196,7 +2186,7 @@ mod tests { }]); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(report.reason, LogicalFrameEndingReason::EndOfRom); // RET pops return values and pushes them back on the caller stack (which is the sentinel frame's stack here). assert_eq!(vm.operand_stack, vec![Value::Int32(42)]); @@ -2205,7 +2195,7 @@ mod tests { #[test] fn test_locals_per_call_isolation() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // Function 0 (entry): // CALL 1 @@ -2257,7 +2247,7 @@ mod tests { ]); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(report.reason, LogicalFrameEndingReason::Halted); // The last value on stack is the return of the second CALL 1, @@ -2268,7 +2258,7 @@ mod tests { #[test] fn test_invalid_local_index_traps() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // Function with 0 params, 1 local. // GET_LOCAL 1 (OOB) @@ -2286,7 +2276,7 @@ mod tests { }]); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { @@ -2301,7 +2291,7 @@ mod tests { #[test] fn test_nested_if() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // if (true) { // if (false) { @@ -2361,14 +2351,14 @@ mod tests { }]); vm.prepare_call("0"); - vm.run_budget(100, &mut native, &mut hw).unwrap(); + vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(vm.pop().unwrap(), Value::Int32(2)); } #[test] fn test_if_with_empty_branches() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // PUSH_BOOL true // JMP_IF_FALSE -> ELSE (offset 15) @@ -2399,7 +2389,7 @@ mod tests { }]); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); assert_eq!(report.reason, LogicalFrameEndingReason::Halted); assert_eq!(vm.operand_stack.len(), 0); } @@ -2407,7 +2397,7 @@ mod tests { #[test] fn test_jmp_if_non_boolean_trap() { let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); // PUSH_I32 1 // JMP_IF_TRUE 9 @@ -2427,7 +2417,7 @@ mod tests { }]); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { assert_eq!(trap.code, TRAP_TYPE); @@ -2471,10 +2461,10 @@ mod tests { }; let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { assert_eq!(trap.code, TRAP_DIV_ZERO); @@ -2518,10 +2508,10 @@ mod tests { }; let mut native = MockNative; - let mut hw = MockHardware; + let mut ctx = HostContext::new(None); vm.prepare_call("0"); - let report = vm.run_budget(100, &mut native, &mut hw).unwrap(); + let report = vm.run_budget(100, &mut native, &mut ctx).unwrap(); match report.reason { LogicalFrameEndingReason::Trap(trap) => { assert_eq!(trap.code, TRAP_DIV_ZERO); diff --git a/crates/prometeu-core/tests/heartbeat.rs b/crates/prometeu-core/tests/heartbeat.rs index 362f727a..56e38620 100644 --- a/crates/prometeu-core/tests/heartbeat.rs +++ b/crates/prometeu-core/tests/heartbeat.rs @@ -47,9 +47,10 @@ fn test_canonical_cartridge_heartbeat() { let mut native = MockNative; let mut hw = Hardware::new(); + let mut ctx = HostContext::new(Some(&mut hw)); // Run for a reasonable budget - let report = vm.run_budget(1000, &mut native, &mut hw).expect("VM failed to run"); + let report = vm.run_budget(1000, &mut native, &mut ctx).expect("VM failed to run"); // Acceptance criteria: // 1. No traps diff --git a/test-cartridges/canonical/golden/program.pbc b/test-cartridges/canonical/golden/program.pbc index b06b91ca..666448e9 100644 Binary files a/test-cartridges/canonical/golden/program.pbc and b/test-cartridges/canonical/golden/program.pbc differ