pr 00.1 change run budget to remove hardware constraints

This commit is contained in:
bQUARKz 2026-02-03 18:59:48 +00:00
parent aab53d30be
commit 90095bb21e
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
9 changed files with 142 additions and 133 deletions

1
Cargo.lock generated
View File

@ -2238,6 +2238,7 @@ dependencies = [
"prometeu-bytecode", "prometeu-bytecode",
"serde", "serde",
"serde_json", "serde_json",
"url",
] ]
[[package]] [[package]]

View File

@ -71,9 +71,10 @@ fn test_integration_test01_link() {
let mut native = SimpleNative; let mut native = SimpleNative;
let mut hw = SimpleHardware::new(); let mut hw = SimpleHardware::new();
let mut ctx = HostContext::new(Some(&mut hw));
// Run for a bit // 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. // It should not trap. test01 might loop or return.
if let LogicalFrameEndingReason::Trap(t) = report.reason { if let LogicalFrameEndingReason::Trap(t) = report.reason {

View File

@ -9,3 +9,4 @@ serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149" serde_json = "1.0.149"
prometeu-bytecode = { path = "../prometeu-bytecode" } prometeu-bytecode = { path = "../prometeu-bytecode" }
prometeu-abi = { path = "../prometeu-abi" } prometeu-abi = { path = "../prometeu-abi" }
url = "2.5.8"

View File

@ -181,7 +181,8 @@ impl PrometeuOS {
/// Executes a single VM instruction (Debug). /// Executes a single VM instruction (Debug).
pub fn debug_step_instruction(&mut self, vm: &mut VirtualMachine, hw: &mut dyn HardwareBridge) -> Option<String> { pub fn debug_step_instruction(&mut self, vm: &mut VirtualMachine, hw: &mut dyn HardwareBridge) -> Option<String> {
match vm.step(self, hw) { let mut ctx = HostContext::new(Some(hw));
match vm.step(self, &mut ctx) {
Ok(_) => None, Ok(_) => None,
Err(e) => { Err(e) => {
let err_msg = format!("PVM Fault during Step: {:?}", e); let err_msg = format!("PVM Fault during Step: {:?}", e);
@ -235,7 +236,10 @@ impl PrometeuOS {
// 3. VM Execution // 3. VM Execution
if budget > 0 { if budget > 0 {
// Run the VM until the budget is hit or FRAME_SYNC is reached. // 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 { match run_result {
Ok(run) => { Ok(run) => {

View File

@ -18,3 +18,14 @@ impl<'a> HostContext<'a> {
} }
} }
} }
pub trait HostContextProvider {
fn make_ctx<'a>(&'a mut self) -> HostContext<'a>;
}
impl<T: HardwareBridge> HostContextProvider for T {
#[inline]
fn make_ctx<'a>(&'a mut self) -> HostContext<'a> {
HostContext::new(Some(self))
}
}

View File

@ -8,7 +8,7 @@ pub mod opcode_spec;
pub mod bytecode; pub mod bytecode;
pub mod verifier; pub mod verifier;
pub use host_context::HostContext; pub use host_context::{HostContext, HostContextProvider};
pub use program::ProgramImage; pub use program::ProgramImage;
pub use prometeu_bytecode::abi::TrapInfo; pub use prometeu_bytecode::abi::TrapInfo;
pub use prometeu_bytecode::opcode::OpCode; pub use prometeu_bytecode::opcode::OpCode;

View File

@ -238,7 +238,7 @@ impl VirtualMachine {
&mut self, &mut self,
budget: u64, budget: u64,
native: &mut dyn NativeInterface, native: &mut dyn NativeInterface,
hw: &mut dyn HardwareBridge, ctx: &mut HostContext,
) -> Result<BudgetReport, String> { ) -> Result<BudgetReport, String> {
let start_cycles = self.cycles; let start_cycles = self.cycles;
let mut steps_executed = 0; let mut steps_executed = 0;
@ -281,7 +281,7 @@ impl VirtualMachine {
} }
// Execute a single step (Fetch-Decode-Execute) // 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); ending_reason = Some(reason);
break; break;
} }
@ -331,7 +331,11 @@ impl VirtualMachine {
/// 1. Fetch: Read the opcode from memory. /// 1. Fetch: Read the opcode from memory.
/// 2. Decode: Identify what operation to perform. /// 2. Decode: Identify what operation to perform.
/// 3. Execute: Perform the operation, updating stacks, memory, or calling peripherals. /// 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() { if self.halted || self.pc >= self.program.rom.len() {
return Ok(()); return Ok(());
} }
@ -843,8 +847,7 @@ impl VirtualMachine {
let stack_height_before = self.operand_stack.len(); let stack_height_before = self.operand_stack.len();
let mut ret = crate::virtual_machine::HostReturn::new(&mut self.operand_stack); 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, ctx).map_err(|fault| match fault {
native.syscall(id, &args, &mut ret, &mut 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::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::Panic(msg) => LogicalFrameEndingReason::Panic(msg),
crate::virtual_machine::VmFault::Unavailable => LogicalFrameEndingReason::Panic("Host feature unavailable".into()), 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 crate::virtual_machine::{expect_int, HostReturn, Value, VmFault};
use prometeu_bytecode::abi::SourceSpan; use prometeu_bytecode::abi::SourceSpan;
use prometeu_bytecode::FunctionMeta; use prometeu_bytecode::FunctionMeta;
use url::Host;
struct MockNative; struct MockNative;
impl NativeInterface for 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] #[test]
fn test_arithmetic_chain() { fn test_arithmetic_chain() {
let mut native = MockNative; 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 // (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. // 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()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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)); assert_eq!(vm.pop().unwrap(), Value::Int32(0));
} }
@ -988,7 +978,7 @@ mod tests {
#[test] #[test]
fn test_div_by_zero_trap() { fn test_div_by_zero_trap() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
let mut rom = Vec::new(); let mut rom = Vec::new();
rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); 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()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -1013,7 +1003,7 @@ mod tests {
#[test] #[test]
fn test_int_to_bound_checked_trap() { fn test_int_to_bound_checked_trap() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
let mut rom = Vec::new(); let mut rom = Vec::new();
rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); 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()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -1036,7 +1026,7 @@ mod tests {
#[test] #[test]
fn test_bounded_add_overflow_trap() { fn test_bounded_add_overflow_trap() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
let mut rom = Vec::new(); let mut rom = Vec::new();
rom.extend_from_slice(&(OpCode::PushBounded as u16).to_le_bytes()); 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()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -1061,7 +1051,7 @@ mod tests {
#[test] #[test]
fn test_comparisons_polymorphic() { fn test_comparisons_polymorphic() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// 10 < 20.5 (true) // 10 < 20.5 (true)
let mut rom = Vec::new(); let mut rom = Vec::new();
@ -1073,7 +1063,7 @@ mod tests {
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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)); 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 vm = new_test_vm(rom.clone(), vec![]);
let mut native = MockNative; 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)); 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 vm = new_test_vm(rom.clone(), vec![]);
let mut native = MockNative; 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)); 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 vm = new_test_vm(rom.clone(), vec![]);
let mut native = MockNative; 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)); 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)); assert_eq!(vm.peek().unwrap(), &Value::Boolean(false));
} }
@ -1138,9 +1128,9 @@ mod tests {
let cp = vec![Value::String("hello".into())]; let cp = vec![Value::String("hello".into())];
let mut vm = VirtualMachine::new(rom, cp); let mut vm = VirtualMachine::new(rom, cp);
let mut native = MockNative; 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())); assert_eq!(vm.peek().unwrap(), &Value::String("hello".into()));
} }
@ -1199,12 +1189,12 @@ mod tests {
}; };
vm.prepare_call("0"); vm.prepare_call("0");
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// Run until Halt // Run until Halt
let mut steps = 0; let mut steps = 0;
while !vm.halted && steps < 100 { while !vm.halted && steps < 100 {
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
steps += 1; steps += 1;
} }
@ -1244,10 +1234,10 @@ mod tests {
}; };
vm.prepare_call("0"); vm.prepare_call("0");
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
vm.step(&mut native, &mut hw).unwrap(); // CALL vm.step(&mut native, &mut ctx).unwrap(); // CALL
let res = vm.step(&mut native, &mut hw); // RET -> should fail let res = vm.step(&mut native, &mut ctx); // RET -> should fail
assert!(res.is_err()); assert!(res.is_err());
match res.unwrap_err() { match res.unwrap_err() {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -1282,9 +1272,9 @@ mod tests {
..Default::default() ..Default::default()
}; };
vm2.prepare_call("0"); vm2.prepare_call("0");
vm2.step(&mut native, &mut hw).unwrap(); // CALL vm2.step(&mut native, &mut ctx).unwrap(); // CALL
vm2.step(&mut native, &mut hw).unwrap(); // PUSH_I64 vm2.step(&mut native, &mut ctx).unwrap(); // PUSH_I64
vm2.step(&mut native, &mut hw).unwrap(); // RET vm2.step(&mut native, &mut ctx).unwrap(); // RET
assert_eq!(vm2.operand_stack.len(), 1); assert_eq!(vm2.operand_stack.len(), 1);
assert_eq!(vm2.pop().unwrap(), Value::Int64(123)); 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 vm = new_test_vm(rom.clone(), vec![]);
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// Execute step by step and check stack // 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); 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.len(), 1);
assert_eq!(vm.scope_stack.last().unwrap().scope_stack_base, 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); 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.len(), 2);
assert_eq!(vm.scope_stack.last().unwrap().scope_stack_base, 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); 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.scope_stack.len(), 1);
assert_eq!(vm.operand_stack.len(), 2); assert_eq!(vm.operand_stack.len(), 2);
assert_eq!(vm.operand_stack.last().unwrap(), &Value::Int64(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.scope_stack.len(), 0);
assert_eq!(vm.operand_stack.len(), 1); assert_eq!(vm.operand_stack.len(), 1);
assert_eq!(vm.operand_stack.last().unwrap(), &Value::Int64(1)); assert_eq!(vm.operand_stack.last().unwrap(), &Value::Int64(1));
@ -1392,11 +1382,11 @@ mod tests {
}; };
vm.prepare_call("0"); vm.prepare_call("0");
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
let mut steps = 0; let mut steps = 0;
while !vm.halted && steps < 100 { while !vm.halted && steps < 100 {
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
steps += 1; steps += 1;
} }
@ -1415,16 +1405,16 @@ mod tests {
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
let mut native = MockNative; 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)); assert_eq!(vm.peek().unwrap(), &Value::Int32(42));
} }
#[test] #[test]
fn test_bitwise_promotion() { fn test_bitwise_promotion() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// i32 & i32 -> i32 // i32 & i32 -> i32
let mut rom = Vec::new(); let mut rom = Vec::new();
@ -1436,9 +1426,9 @@ mod tests {
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
assert_eq!(vm.pop().unwrap(), Value::Int32(0)); assert_eq!(vm.pop().unwrap(), Value::Int32(0));
// i32 | i64 -> i64 // i32 | i64 -> i64
@ -1451,16 +1441,16 @@ mod tests {
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
assert_eq!(vm.pop().unwrap(), Value::Int64(0xFF)); assert_eq!(vm.pop().unwrap(), Value::Int64(0xFF));
} }
#[test] #[test]
fn test_comparisons_lte_gte() { fn test_comparisons_lte_gte() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// 10 <= 20 (true) // 10 <= 20 (true)
let mut rom = Vec::new(); let mut rom = Vec::new();
@ -1472,9 +1462,9 @@ mod tests {
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
assert_eq!(vm.pop().unwrap(), Value::Boolean(true)); assert_eq!(vm.pop().unwrap(), Value::Boolean(true));
// 20 >= 20 (true) // 20 >= 20 (true)
@ -1487,16 +1477,16 @@ mod tests {
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
assert_eq!(vm.pop().unwrap(), Value::Boolean(true)); assert_eq!(vm.pop().unwrap(), Value::Boolean(true));
} }
#[test] #[test]
fn test_negation() { fn test_negation() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
let mut rom = Vec::new(); let mut rom = Vec::new();
rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); 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()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
vm.step(&mut native, &mut hw).unwrap(); vm.step(&mut native, &mut ctx).unwrap();
assert_eq!(vm.pop().unwrap(), Value::Int32(-42)); assert_eq!(vm.pop().unwrap(), Value::Int32(-42));
} }
#[test] #[test]
fn test_jmp_if_true() { fn test_jmp_if_true() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// Corrected Calculations: // Corrected Calculations:
// 0-1: PushBool // 0-1: PushBool
@ -1536,17 +1526,17 @@ mod tests {
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
vm.step(&mut native, &mut hw).unwrap(); // PushBool vm.step(&mut native, &mut ctx).unwrap(); // PushBool
vm.step(&mut native, &mut hw).unwrap(); // JmpIfTrue vm.step(&mut native, &mut ctx).unwrap(); // JmpIfTrue
assert_eq!(vm.pc, 11); 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)); assert_eq!(vm.pop().unwrap(), Value::Int32(100));
} }
#[test] #[test]
fn test_trap_opcode() { fn test_trap_opcode() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
let mut rom = Vec::new(); let mut rom = Vec::new();
rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); 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()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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!(report.reason, LogicalFrameEndingReason::Breakpoint);
assert_eq!(vm.pc, 8); // PushI32 (6 bytes) + Trap (2 bytes) assert_eq!(vm.pc, 8); // PushI32 (6 bytes) + Trap (2 bytes)
@ -1565,7 +1555,7 @@ mod tests {
#[test] #[test]
fn test_pop_n_opcode() { fn test_pop_n_opcode() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
let mut rom = Vec::new(); let mut rom = Vec::new();
rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes()); 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()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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_eq!(vm.pop().unwrap(), Value::Int32(1));
assert!(vm.pop().is_err()); // Stack should be empty assert!(vm.pop().is_err()); // Stack should be empty
@ -1588,7 +1578,7 @@ mod tests {
#[test] #[test]
fn test_hip_traps_oob() { fn test_hip_traps_oob() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// ALLOC int, 1 -> Gate(0) // ALLOC int, 1 -> Gate(0)
// GATE_LOAD 1 -> TRAP_OOB (size is 1, offset 1 is invalid) // 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()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -1616,7 +1606,7 @@ mod tests {
#[test] #[test]
fn test_hip_traps_type() { fn test_hip_traps_type() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// PUSH_I32 42 // PUSH_I32 42
// GATE_LOAD 0 -> TRAP_TYPE (Expected gate handle, got Int32) // 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()); rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -1654,7 +1644,7 @@ mod tests {
code_len: rom.len() as u32, code_len: rom.len() as u32,
..Default::default() ..Default::default()
}]); }]);
let mut hw = crate::Hardware::new(); let mut ctx = HostContext::new(None);
struct TestNative; struct TestNative;
impl NativeInterface for TestNative { impl NativeInterface for TestNative {
fn syscall(&mut self, _id: u32, _args: &[Value], _ret: &mut HostReturn, _ctx: &mut HostContext) -> Result<(), VmFault> { Ok(()) } 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; let mut native = TestNative;
vm.prepare_call("0"); 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); assert_eq!(result.reason, LogicalFrameEndingReason::EndOfRom);
} }
@ -1690,10 +1680,10 @@ mod tests {
..Default::default() ..Default::default()
}]); }]);
let mut native = MultiReturnNative; let mut native = MultiReturnNative;
let mut hw = crate::Hardware::new(); let mut ctx = HostContext::new(None);
vm.prepare_call("0"); 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::Bounded(255));
assert_eq!(vm.pop().unwrap(), Value::Int64(42)); assert_eq!(vm.pop().unwrap(), Value::Int64(42));
@ -1721,11 +1711,11 @@ mod tests {
..Default::default() ..Default::default()
}]); }]);
let mut native = VoidReturnNative; let mut native = VoidReturnNative;
let mut hw = crate::Hardware::new(); let mut ctx = HostContext::new(None);
vm.prepare_call("0"); vm.prepare_call("0");
vm.operand_stack.push(Value::Int32(100)); 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_eq!(vm.pop().unwrap(), Value::Int32(100));
assert!(vm.operand_stack.is_empty()); assert!(vm.operand_stack.is_empty());
@ -1756,10 +1746,10 @@ mod tests {
..Default::default() ..Default::default()
}]); }]);
let mut native = ArgCheckNative; let mut native = ArgCheckNative;
let mut hw = crate::Hardware::new(); let mut ctx = HostContext::new(None);
vm.prepare_call("0"); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -1778,10 +1768,10 @@ mod tests {
]; ];
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
vm.prepare_call("0"); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -1803,10 +1793,10 @@ mod tests {
]; ];
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
vm.prepare_call("0"); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -1840,10 +1830,10 @@ mod tests {
let mut vm = new_test_vm(rom.clone(), vec![]); let mut vm = new_test_vm(rom.clone(), vec![]);
let mut native = BadNative; let mut native = BadNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
vm.prepare_call("0"); 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 { match report.reason {
LogicalFrameEndingReason::Panic(msg) => assert!(msg.contains("results mismatch")), LogicalFrameEndingReason::Panic(msg) => assert!(msg.contains("results mismatch")),
_ => panic!("Expected Panic, got {:?}", report.reason), _ => panic!("Expected Panic, got {:?}", report.reason),
@ -1933,7 +1923,7 @@ mod tests {
#[test] #[test]
fn test_calling_convention_add() { fn test_calling_convention_add() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// F0 (entry): // F0 (entry):
// PUSH_I32 10 // PUSH_I32 10
@ -1985,7 +1975,7 @@ mod tests {
]); ]);
vm.prepare_call("0"); 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!(report.reason, LogicalFrameEndingReason::Halted);
assert_eq!(vm.operand_stack.last().unwrap(), &Value::Int32(30)); assert_eq!(vm.operand_stack.last().unwrap(), &Value::Int32(30));
} }
@ -1993,7 +1983,7 @@ mod tests {
#[test] #[test]
fn test_calling_convention_multi_slot_return() { fn test_calling_convention_multi_slot_return() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// F0: // F0:
// CALL 1 // CALL 1
@ -2037,7 +2027,7 @@ mod tests {
]); ]);
vm.prepare_call("0"); 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!(report.reason, LogicalFrameEndingReason::Halted);
// Stack should be [100, 200] // Stack should be [100, 200]
assert_eq!(vm.operand_stack.len(), 2); assert_eq!(vm.operand_stack.len(), 2);
@ -2048,7 +2038,7 @@ mod tests {
#[test] #[test]
fn test_calling_convention_void_call() { fn test_calling_convention_void_call() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// F0: // F0:
// PUSH_I32 42 // PUSH_I32 42
@ -2088,7 +2078,7 @@ mod tests {
]); ]);
vm.prepare_call("0"); 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!(report.reason, LogicalFrameEndingReason::Halted);
assert_eq!(vm.operand_stack.len(), 0); assert_eq!(vm.operand_stack.len(), 0);
} }
@ -2096,7 +2086,7 @@ mod tests {
#[test] #[test]
fn test_trap_invalid_func() { fn test_trap_invalid_func() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// CALL 99 (invalid) // CALL 99 (invalid)
let mut rom = Vec::new(); let mut rom = Vec::new();
@ -2104,7 +2094,7 @@ mod tests {
rom.extend_from_slice(&99u32.to_le_bytes()); rom.extend_from_slice(&99u32.to_le_bytes());
let mut vm = new_test_vm(rom.clone(), vec![]); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -2118,7 +2108,7 @@ mod tests {
#[test] #[test]
fn test_trap_bad_ret_slots() { fn test_trap_bad_ret_slots() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// F0: CALL 1; HALT // F0: CALL 1; HALT
// F1: PUSH_I32 42; RET (expected 0 slots) // F1: PUSH_I32 42; RET (expected 0 slots)
@ -2153,7 +2143,7 @@ mod tests {
]); ]);
vm.prepare_call("0"); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -2167,7 +2157,7 @@ mod tests {
#[test] #[test]
fn test_locals_round_trip() { fn test_locals_round_trip() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// PUSH_I32 42 // PUSH_I32 42
// SET_LOCAL 0 // SET_LOCAL 0
@ -2196,7 +2186,7 @@ mod tests {
}]); }]);
vm.prepare_call("0"); 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); 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). // 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)]); assert_eq!(vm.operand_stack, vec![Value::Int32(42)]);
@ -2205,7 +2195,7 @@ mod tests {
#[test] #[test]
fn test_locals_per_call_isolation() { fn test_locals_per_call_isolation() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// Function 0 (entry): // Function 0 (entry):
// CALL 1 // CALL 1
@ -2257,7 +2247,7 @@ mod tests {
]); ]);
vm.prepare_call("0"); 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!(report.reason, LogicalFrameEndingReason::Halted);
// The last value on stack is the return of the second CALL 1, // The last value on stack is the return of the second CALL 1,
@ -2268,7 +2258,7 @@ mod tests {
#[test] #[test]
fn test_invalid_local_index_traps() { fn test_invalid_local_index_traps() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// Function with 0 params, 1 local. // Function with 0 params, 1 local.
// GET_LOCAL 1 (OOB) // GET_LOCAL 1 (OOB)
@ -2286,7 +2276,7 @@ mod tests {
}]); }]);
vm.prepare_call("0"); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
@ -2301,7 +2291,7 @@ mod tests {
#[test] #[test]
fn test_nested_if() { fn test_nested_if() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// if (true) { // if (true) {
// if (false) { // if (false) {
@ -2361,14 +2351,14 @@ mod tests {
}]); }]);
vm.prepare_call("0"); 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)); assert_eq!(vm.pop().unwrap(), Value::Int32(2));
} }
#[test] #[test]
fn test_if_with_empty_branches() { fn test_if_with_empty_branches() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// PUSH_BOOL true // PUSH_BOOL true
// JMP_IF_FALSE -> ELSE (offset 15) // JMP_IF_FALSE -> ELSE (offset 15)
@ -2399,7 +2389,7 @@ mod tests {
}]); }]);
vm.prepare_call("0"); 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!(report.reason, LogicalFrameEndingReason::Halted);
assert_eq!(vm.operand_stack.len(), 0); assert_eq!(vm.operand_stack.len(), 0);
} }
@ -2407,7 +2397,7 @@ mod tests {
#[test] #[test]
fn test_jmp_if_non_boolean_trap() { fn test_jmp_if_non_boolean_trap() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
// PUSH_I32 1 // PUSH_I32 1
// JMP_IF_TRUE 9 // JMP_IF_TRUE 9
@ -2427,7 +2417,7 @@ mod tests {
}]); }]);
vm.prepare_call("0"); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
assert_eq!(trap.code, TRAP_TYPE); assert_eq!(trap.code, TRAP_TYPE);
@ -2471,10 +2461,10 @@ mod tests {
}; };
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
vm.prepare_call("0"); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
assert_eq!(trap.code, TRAP_DIV_ZERO); assert_eq!(trap.code, TRAP_DIV_ZERO);
@ -2518,10 +2508,10 @@ mod tests {
}; };
let mut native = MockNative; let mut native = MockNative;
let mut hw = MockHardware; let mut ctx = HostContext::new(None);
vm.prepare_call("0"); 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 { match report.reason {
LogicalFrameEndingReason::Trap(trap) => { LogicalFrameEndingReason::Trap(trap) => {
assert_eq!(trap.code, TRAP_DIV_ZERO); assert_eq!(trap.code, TRAP_DIV_ZERO);

View File

@ -47,9 +47,10 @@ fn test_canonical_cartridge_heartbeat() {
let mut native = MockNative; let mut native = MockNative;
let mut hw = Hardware::new(); let mut hw = Hardware::new();
let mut ctx = HostContext::new(Some(&mut hw));
// Run for a reasonable budget // 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: // Acceptance criteria:
// 1. No traps // 1. No traps