1use ivm_compile::byte_id;
2use ivm_compile::options::ProgramOptions;
3
4use crate::ivm_ext_x32::IvmX32ExternMap;
5
6pub mod ivm_ext_x32;
7
8pub struct StackElement {
10 pub bytes: Vec<u8>,
11}
12
13impl StackElement {
14 pub fn new(bytes: Vec<u8>) -> Self {
15 Self { bytes }
16 }
17}
18
19pub trait ExternMap {
20 fn handle(&mut self, call_id: usize, stack: &mut Vec<StackElement>) -> Result<(), String>;
21}
22
23pub struct VmInstance {
24 pub options: ProgramOptions,
25 pub mem_pool: Vec<u8>,
26 pub execution_index: usize,
27 pub extern_map: Box<dyn ExternMap>,
28 pub stack: Vec<StackElement>,
29}
30
31impl VmInstance {
32 pub fn introduce<I>(&mut self, bytes: I)
34 where
35 I: IntoIterator<Item = u8>,
36 {
37 self.mem_pool.extend(bytes);
38 }
39
40 fn handle_read_op(&self, mut index: usize) -> (Vec<u8>, usize) {
42 let identifier = self.mem_pool[index];
43 index += 1;
44
45 let arg = self.options.ptr_len.extract(index, &self.mem_pool);
46 index += self.options.ptr_len.get_span();
47
48 match identifier {
49 byte_id::RDOP_LOCAL => {
50 let data = &self.mem_pool[index..][..arg];
53 (data.to_vec(), 1 + self.options.ptr_len.get_span() + arg)
54 }
55
56 byte_id::RDOP_POINT => {
57 let rd_size = self.options.ptr_len.extract(arg, &self.mem_pool);
60 let data = &self.mem_pool[arg..][..rd_size];
61
62 (data.to_vec(), 1 + self.options.ptr_len.get_span())
63 }
64 _ => panic!("unrecognized read operation '{identifier:02x}'"),
65 }
66 }
67
68 pub fn continue_execution(&mut self) -> Result<(), String> {
69 while self.execution_index < self.mem_pool.len() {
70 let byte_instruction = self.mem_pool[self.execution_index];
71 self.execution_index += 1;
72
73 match byte_instruction {
74 byte_id::I_VISIT => {
75 self.execution_index = self
76 .options
77 .ptr_len
78 .extract(self.execution_index, &self.mem_pool)
79 }
80
81 byte_id::I_MUTATE => {
82 let dest = self
83 .options
84 .ptr_len
85 .extract(self.execution_index, &self.mem_pool);
86
87 self.execution_index += self.options.ptr_len.get_span();
88
89 let (data, skip) = self.handle_read_op(self.execution_index);
90 self.execution_index += skip;
91
92 for i in 0..data.len() {
93 self.mem_pool[dest + i] = data[i];
94 }
95 }
96
97 byte_id::I_PUSH => {
98 let (data, skip) = self.handle_read_op(self.execution_index);
99
100 self.stack.push(StackElement::new(data.to_vec()));
101 self.execution_index += skip;
102 }
103
104 byte_id::I_EXTERN_CALL => {
105 let call_id = self
106 .options
107 .ptr_len
108 .extract(self.execution_index, &self.mem_pool);
109
110 self.extern_map.handle(call_id, &mut self.stack)?;
111 self.execution_index += self.options.ptr_len.get_span();
112 }
113
114 _ => {
115 return Err(format!(
116 "unrecognized instruction (hex): {byte_instruction:02x}"
117 ))
118 }
119 }
120 }
121 Ok(())
122 }
123
124 pub fn from_raw(
125 program_options: ProgramOptions,
126 mem_pool: Vec<u8>,
127 ptr_index: usize,
128 extern_map: Box<dyn ExternMap>,
129 ) -> Self {
130 Self {
131 options: program_options,
132 mem_pool,
133 execution_index: ptr_index,
134 extern_map,
135 stack: Vec::new(),
136 }
137 }
138
139 pub fn init(program_options: ProgramOptions) -> Self {
143 Self::from_raw(
144 program_options,
145 Vec::with_capacity(128),
146 0,
147 Box::new(IvmX32ExternMap),
148 )
149 }
150}