use super::*;
use crate::class_file::ClassFile;
use crate::memory::{StackFrame, Value};
fn create_interpreter() -> Interpreter {
Interpreter::new()
}
fn create_minimal_class() -> ClassFile {
ClassFile {
magic: 0xCAFEBABE,
minor_version: 0,
major_version: 52,
constant_pool: vec![],
access_flags: 0x0021,
this_class: 1,
super_class: 2,
interfaces: vec![],
fields: vec![],
methods: vec![],
attributes: vec![],
}
}
fn run_instruction(
opcode: u8,
operands: &[u8],
stack: Vec<Value>,
locals: Vec<Value>,
) -> (StackFrame, Result<bool, JvmError>) {
let mut interp = create_interpreter();
let class = create_minimal_class();
let mut frame = StackFrame::new(10, 10, "test".to_string());
frame.stack = stack;
if !locals.is_empty() {
for (i, val) in locals.into_iter().enumerate() {
frame.locals[i] = val;
}
}
let mut code = vec![opcode];
code.extend_from_slice(operands);
frame.pc = 1;
let result = interp.dispatch_instruction(&class, &code, &mut frame, opcode);
(frame, result)
}
#[test]
fn test_stack_pop2() {
let (frame, res) = run_instruction(0x58, &[], vec![Value::Int(1), Value::Int(2)], vec![]);
assert!(res.is_ok());
assert!(frame.stack.is_empty());
let (frame, res) = run_instruction(0x58, &[], vec![Value::Long(123)], vec![]);
assert!(res.is_ok());
assert!(frame.stack.is_empty());
}
#[test]
fn test_stack_dup2_x2() {
let initial_stack = vec![
Value::Int(4), Value::Int(3), Value::Int(2), Value::Int(1), ];
let (frame, res) = run_instruction(0x5e, &[], initial_stack, vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack.len(), 6);
assert_eq!(frame.stack[0], Value::Int(2)); assert_eq!(frame.stack[1], Value::Int(1)); assert_eq!(frame.stack[2], Value::Int(4));
assert_eq!(frame.stack[3], Value::Int(3));
assert_eq!(frame.stack[4], Value::Int(2));
assert_eq!(frame.stack[5], Value::Int(1));
let initial_stack = vec![
Value::Int(3), Value::Int(2), Value::Long(1), ];
let (frame, res) = run_instruction(0x5e, &[], initial_stack, vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack.len(), 4);
assert_eq!(frame.stack[0], Value::Long(1)); assert_eq!(frame.stack[1], Value::Int(3));
assert_eq!(frame.stack[2], Value::Int(2));
assert_eq!(frame.stack[3], Value::Long(1));
let initial_stack = vec![
Value::Long(3), Value::Int(2), Value::Int(1), ];
let (frame, res) = run_instruction(0x5e, &[], initial_stack, vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack.len(), 5);
assert_eq!(frame.stack[0], Value::Int(2)); assert_eq!(frame.stack[1], Value::Int(1)); assert_eq!(frame.stack[2], Value::Long(3));
assert_eq!(frame.stack[3], Value::Int(2));
assert_eq!(frame.stack[4], Value::Int(1));
let initial_stack = vec![
Value::Long(2), Value::Long(1), ];
let (frame, res) = run_instruction(0x5e, &[], initial_stack, vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack.len(), 3);
assert_eq!(frame.stack[0], Value::Long(1)); assert_eq!(frame.stack[1], Value::Long(2));
assert_eq!(frame.stack[2], Value::Long(1));
}
#[test]
fn test_control_flow_if_acmpeq() {
let (mut frame, res) =
run_instruction(0xa5, &[0x00, 0x05], vec![Value::Null, Value::Null], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (mut frame, res) = run_instruction(
0xa5,
&[0x00, 0x05],
vec![Value::Null, Value::Reference(1)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.pc, 3);
}
#[test]
fn test_control_flow_jsr_ret() {
let (mut frame, res) = run_instruction(0xa8, &[0x00, 0x05], vec![], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let ret_val = frame.pop().unwrap();
if let Value::ReturnAddress(addr) = ret_val {
assert_eq!(addr, 3);
} else {
panic!("Expected ReturnAddress, got {:?}", ret_val);
}
let mut interp = create_interpreter();
let class = create_minimal_class();
let mut frame = StackFrame::new(10, 10, "test".to_string());
frame.locals[1] = Value::ReturnAddress(10);
let code = vec![0xa9, 0x01];
frame.pc = 1; interp
.dispatch_instruction(&class, &code, &mut frame, 0xa9)
.unwrap();
assert_eq!(frame.pc, 10);
}
#[test]
fn test_control_flow_tableswitch() {
let mut code = vec![0xaa];
code.extend_from_slice(&[0, 0, 0]);
code.extend_from_slice(&[0, 0, 0, 0x64]);
code.extend_from_slice(&[0, 0, 0, 1]);
code.extend_from_slice(&[0, 0, 0, 2]);
code.extend_from_slice(&[0, 0, 0, 0x14]);
code.extend_from_slice(&[0, 0, 0, 0x1e]);
let mut interp = create_interpreter();
let class = create_minimal_class();
let mut frame = StackFrame::new(10, 10, "test".to_string());
frame.push(Value::Int(1)).unwrap();
frame.pc = 1;
interp
.dispatch_instruction(&class, &code, &mut frame, 0xaa)
.unwrap();
assert_eq!(frame.pc, 20);
let mut frame = StackFrame::new(10, 10, "test".to_string());
frame.push(Value::Int(2)).unwrap();
frame.pc = 1;
interp
.dispatch_instruction(&class, &code, &mut frame, 0xaa)
.unwrap();
assert_eq!(frame.pc, 30);
let mut frame = StackFrame::new(10, 10, "test".to_string());
frame.push(Value::Int(3)).unwrap(); frame.pc = 1;
interp
.dispatch_instruction(&class, &code, &mut frame, 0xaa)
.unwrap();
assert_eq!(frame.pc, 100); }
#[test]
fn test_arithmetic_lcmp() {
let (frame, res) = run_instruction(0x94, &[], vec![Value::Long(10), Value::Long(5)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(1));
let (frame, res) = run_instruction(0x94, &[], vec![Value::Long(5), Value::Long(10)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(-1));
let (frame, res) = run_instruction(0x94, &[], vec![Value::Long(10), Value::Long(10)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(0));
}
#[test]
fn test_arithmetic_fcmpl() {
let (frame, res) = run_instruction(
0x95,
&[],
vec![Value::Float(f32::NAN), Value::Float(1.0)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(-1));
let (frame, res) = run_instruction(
0x95,
&[],
vec![Value::Float(1.0), Value::Float(0.5)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(1));
}
#[test]
fn test_conversion_i2x() {
let (frame, res) = run_instruction(0x85, &[], vec![Value::Int(10)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(10));
let (frame, res) = run_instruction(0x86, &[], vec![Value::Int(10)], vec![]);
assert!(res.is_ok());
match frame.stack[0] {
Value::Float(f) => assert_eq!(f, 10.0),
_ => panic!("Expected Float"),
}
let (frame, res) = run_instruction(0x87, &[], vec![Value::Int(10)], vec![]);
assert!(res.is_ok());
match frame.stack[0] {
Value::Double(d) => assert_eq!(d, 10.0),
_ => panic!("Expected Double"),
}
let (frame, res) = run_instruction(0x91, &[], vec![Value::Int(128)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(-128));
let (frame, res) = run_instruction(0x92, &[], vec![Value::Int(-1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(65535));
let (frame, res) = run_instruction(0x93, &[], vec![Value::Int(32768)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(-32768));
}
#[test]
fn test_conversion_l2x() {
let (frame, res) = run_instruction(0x88, &[], vec![Value::Long(0xFFFFFFFF)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(-1));
let (frame, res) = run_instruction(0x89, &[], vec![Value::Long(10)], vec![]);
assert!(res.is_ok());
match frame.stack[0] {
Value::Float(f) => assert_eq!(f, 10.0),
_ => panic!("Expected Float"),
}
let (frame, res) = run_instruction(0x8a, &[], vec![Value::Long(10)], vec![]);
assert!(res.is_ok());
match frame.stack[0] {
Value::Double(d) => assert_eq!(d, 10.0),
_ => panic!("Expected Double"),
}
}
#[test]
fn test_conversion_f2x() {
let (frame, res) = run_instruction(0x8b, &[], vec![Value::Float(2.5)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(2));
let (frame, res) = run_instruction(0x8b, &[], vec![Value::Float(f32::NAN)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(0));
let (frame, res) = run_instruction(0x8b, &[], vec![Value::Float(f32::INFINITY)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(i32::MAX));
let (frame, res) = run_instruction(0x8c, &[], vec![Value::Float(2.5)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(2));
let (frame, res) = run_instruction(0x8d, &[], vec![Value::Float(2.5)], vec![]);
assert!(res.is_ok());
match frame.stack[0] {
Value::Double(d) => assert_eq!(d, 2.5),
_ => panic!("Expected Double"),
}
}
#[test]
fn test_conversion_d2x() {
let (frame, res) = run_instruction(0x8e, &[], vec![Value::Double(2.5)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(2));
let (frame, res) = run_instruction(0x8e, &[], vec![Value::Double(f64::NAN)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(0));
let (frame, res) = run_instruction(0x8f, &[], vec![Value::Double(2.5)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(2));
let (frame, res) = run_instruction(0x90, &[], vec![Value::Double(2.5)], vec![]);
assert!(res.is_ok());
match frame.stack[0] {
Value::Float(f) => assert_eq!(f, 2.5),
_ => panic!("Expected Float"),
}
}
#[test]
fn test_control_flow_lookupswitch() {
let mut operands = vec![0, 0, 0]; operands.extend_from_slice(&20i32.to_be_bytes()); operands.extend_from_slice(&2i32.to_be_bytes());
operands.extend_from_slice(&10i32.to_be_bytes()); operands.extend_from_slice(&30i32.to_be_bytes());
operands.extend_from_slice(&20i32.to_be_bytes()); operands.extend_from_slice(&40i32.to_be_bytes());
let (frame, res) = run_instruction(0xab, &operands, vec![Value::Int(10)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 30);
let (frame, res) = run_instruction(0xab, &operands, vec![Value::Int(20)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 40);
let (frame, res) = run_instruction(0xab, &operands, vec![Value::Int(5)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 20);
}
#[test]
fn test_arithmetic_f_ops() {
let (frame, res) = run_instruction(
0x62,
&[],
vec![Value::Float(1.5), Value::Float(2.5)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Float(f) => assert_eq!(f, 4.0),
_ => panic!("Expected Float"),
}
let (frame, res) = run_instruction(
0x66,
&[],
vec![Value::Float(2.5), Value::Float(1.5)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Float(f) => assert_eq!(f, 1.0),
_ => panic!("Expected Float"),
}
let (frame, res) = run_instruction(
0x6a,
&[],
vec![Value::Float(2.0), Value::Float(3.0)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Float(f) => assert_eq!(f, 6.0),
_ => panic!("Expected Float"),
}
let (frame, res) = run_instruction(
0x6e,
&[],
vec![Value::Float(6.0), Value::Float(2.0)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Float(f) => assert_eq!(f, 3.0),
_ => panic!("Expected Float"),
}
let (frame, res) = run_instruction(
0x72,
&[],
vec![Value::Float(5.5), Value::Float(2.0)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Float(f) => assert_eq!(f, 1.5),
_ => panic!("Expected Float"),
}
let (frame, res) = run_instruction(0x76, &[], vec![Value::Float(1.5)], vec![]);
assert!(res.is_ok());
match frame.stack[0] {
Value::Float(f) => assert_eq!(f, -1.5),
_ => panic!("Expected Float"),
}
}
#[test]
fn test_arithmetic_d_ops() {
let (frame, res) = run_instruction(
0x63,
&[],
vec![Value::Double(1.5), Value::Double(2.5)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Double(d) => assert_eq!(d, 4.0),
_ => panic!("Expected Double"),
}
let (frame, res) = run_instruction(
0x67,
&[],
vec![Value::Double(2.5), Value::Double(1.5)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Double(d) => assert_eq!(d, 1.0),
_ => panic!("Expected Double"),
}
let (frame, res) = run_instruction(
0x6b,
&[],
vec![Value::Double(2.0), Value::Double(3.0)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Double(d) => assert_eq!(d, 6.0),
_ => panic!("Expected Double"),
}
let (frame, res) = run_instruction(
0x6f,
&[],
vec![Value::Double(6.0), Value::Double(2.0)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Double(d) => assert_eq!(d, 3.0),
_ => panic!("Expected Double"),
}
let (frame, res) = run_instruction(
0x73,
&[],
vec![Value::Double(5.5), Value::Double(2.0)],
vec![],
);
assert!(res.is_ok());
match frame.stack[0] {
Value::Double(d) => assert_eq!(d, 1.5),
_ => panic!("Expected Double"),
}
let (frame, res) = run_instruction(0x77, &[], vec![Value::Double(1.5)], vec![]);
assert!(res.is_ok());
match frame.stack[0] {
Value::Double(d) => assert_eq!(d, -1.5),
_ => panic!("Expected Double"),
}
}
#[test]
fn test_arithmetic_l_ops() {
let (frame, res) = run_instruction(0x61, &[], vec![Value::Long(10), Value::Long(20)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(30));
let (frame, res) = run_instruction(0x65, &[], vec![Value::Long(20), Value::Long(10)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(10));
let (frame, res) = run_instruction(0x69, &[], vec![Value::Long(10), Value::Long(20)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(200));
let (frame, res) = run_instruction(0x6d, &[], vec![Value::Long(20), Value::Long(10)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(2));
let (frame, res) = run_instruction(0x71, &[], vec![Value::Long(10), Value::Long(3)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(1));
let (frame, res) = run_instruction(0x75, &[], vec![Value::Long(10)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(-10));
let (frame, res) = run_instruction(0x79, &[], vec![Value::Long(1), Value::Int(1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(2));
let (frame, res) = run_instruction(0x7b, &[], vec![Value::Long(-2), Value::Int(1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(-1));
let (frame, res) = run_instruction(0x7d, &[], vec![Value::Long(-2), Value::Int(1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(i64::MAX));
let (frame, res) = run_instruction(
0x7f,
&[],
vec![Value::Long(0b1100), Value::Long(0b1010)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(0b1000));
let (frame, res) = run_instruction(
0x81,
&[],
vec![Value::Long(0b1100), Value::Long(0b1010)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(0b1110));
let (frame, res) = run_instruction(
0x83,
&[],
vec![Value::Long(0b1100), Value::Long(0b1010)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Long(0b0110));
}
#[test]
fn test_comparison_fcmp_dcmp() {
let (frame, res) = run_instruction(
0x96,
&[],
vec![Value::Float(f32::NAN), Value::Float(1.0)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(1));
let (frame, res) = run_instruction(
0x97,
&[],
vec![Value::Double(f64::NAN), Value::Double(1.0)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(-1));
let (frame, res) = run_instruction(
0x98,
&[],
vec![Value::Double(f64::NAN), Value::Double(1.0)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.stack[0], Value::Int(1));
}
#[test]
fn test_control_flow_if_cond() {
let (frame, res) = run_instruction(0x99, &[0x00, 0x05], vec![Value::Int(0)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(0x99, &[0x00, 0x05], vec![Value::Int(1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 3);
let (frame, res) = run_instruction(0x9a, &[0x00, 0x05], vec![Value::Int(1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(0x9b, &[0x00, 0x05], vec![Value::Int(-1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(0x9c, &[0x00, 0x05], vec![Value::Int(0)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(0x9d, &[0x00, 0x05], vec![Value::Int(1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(0x9e, &[0x00, 0x05], vec![Value::Int(0)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
}
#[test]
fn test_control_flow_if_icmp() {
let (frame, res) = run_instruction(
0x9f,
&[0x00, 0x05],
vec![Value::Int(10), Value::Int(10)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(
0xa0,
&[0x00, 0x05],
vec![Value::Int(10), Value::Int(11)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(
0xa1,
&[0x00, 0x05],
vec![Value::Int(9), Value::Int(10)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(
0xa2,
&[0x00, 0x05],
vec![Value::Int(10), Value::Int(10)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(
0xa3,
&[0x00, 0x05],
vec![Value::Int(11), Value::Int(10)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (frame, res) = run_instruction(
0xa4,
&[0x00, 0x05],
vec![Value::Int(10), Value::Int(10)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
}
#[test]
fn test_control_flow_if_acmpne() {
let (mut frame, res) = run_instruction(
0xa6,
&[0x00, 0x05],
vec![Value::Null, Value::Reference(1)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (mut frame, res) =
run_instruction(0xa6, &[0x00, 0x05], vec![Value::Null, Value::Null], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 3);
let (mut frame, res) = run_instruction(
0xa6,
&[0x00, 0x05],
vec![Value::Reference(1), Value::Reference(1)],
vec![],
);
assert!(res.is_ok());
assert_eq!(frame.pc, 3);
}
#[test]
fn test_control_flow_goto() {
let (mut frame, res) = run_instruction(0xa7, &[0x00, 0x0a], vec![], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 10);
}
#[test]
fn test_control_flow_goto_w() {
let mut code = vec![0xc8];
code.extend_from_slice(&0x00000100i32.to_be_bytes());
let mut interp = create_interpreter();
let class = create_minimal_class();
let mut frame = StackFrame::new(10, 10, "test".to_string());
frame.pc = 1;
interp
.dispatch_instruction(&class, &code, &mut frame, 0xc8)
.unwrap();
assert_eq!(frame.pc, 256);
}
#[test]
fn test_control_flow_jsr_w() {
let mut code = vec![0xc9];
code.extend_from_slice(&0x00000010i32.to_be_bytes());
let mut interp = create_interpreter();
let class = create_minimal_class();
let mut frame = StackFrame::new(10, 10, "test".to_string());
frame.pc = 1;
interp
.dispatch_instruction(&class, &code, &mut frame, 0xc9)
.unwrap();
assert_eq!(frame.pc, 16);
let ret_val = frame.pop().unwrap();
if let Value::ReturnAddress(addr) = ret_val {
assert_eq!(addr, 5);
} else {
panic!("Expected ReturnAddress, got {:?}", ret_val);
}
}
#[test]
fn test_control_flow_ifnull_ifnonnull() {
let (mut frame, res) = run_instruction(0xc6, &[0x00, 0x05], vec![Value::Null], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (mut frame, res) = run_instruction(0xc6, &[0x00, 0x05], vec![Value::Reference(1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 3);
let (mut frame, res) = run_instruction(0xc7, &[0x00, 0x05], vec![Value::Reference(1)], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 5);
let (mut frame, res) = run_instruction(0xc7, &[0x00, 0x05], vec![Value::Null], vec![]);
assert!(res.is_ok());
assert_eq!(frame.pc, 3);
}