wasmer_interface_types_fl/interpreter/instructions/
byte_arrays.rs1use super::to_native;
2use crate::instr_error;
3use crate::IType;
4use crate::IValue;
5use crate::{
6 errors::{InstructionError, InstructionErrorKind, InstructionResult},
7 interpreter::stack::Stackable,
8 interpreter::Instruction,
9 interpreter::Runtime,
10};
11
12use it_lilo::traits::DEFAULT_MEMORY_INDEX;
13
14use futures::future::BoxFuture;
15use futures::FutureExt;
16
17struct ByteArrayLiftMemoryAsync {
18 instruction: Instruction,
19}
20
21impl_async_executable_instruction!(
22 byte_array_lift_memory(instruction: Instruction) -> _ {
23 Box::new(ByteArrayLiftMemoryAsync{instruction})
24 }
25 ByteArrayLiftMemoryAsync {
26 fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>)
27 -> BoxFuture<InstructionResult<()>> {
28 async move {
29 let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
30 InstructionError::from_error_kind(
31 self.instruction.clone(),
32 InstructionErrorKind::StackIsTooSmall { needed: 2 },
33 )
34 })?;
35
36 let memory_index = DEFAULT_MEMORY_INDEX;
37 let memory = runtime
38 .wasm_instance
39 .memory(memory_index)
40 .ok_or_else(|| {
41 InstructionError::from_error_kind(
42 self.instruction.clone(),
43 InstructionErrorKind::MemoryIsMissing { memory_index },
44 )
45 })?;
46
47 let pointer = to_native::<i32>(inputs.remove(0), self.instruction.clone())? as u32;
48 let length = to_native::<i32>(inputs.remove(0), self.instruction.clone())? as u32;
49
50 let memory_view = memory.view();
51
52 if length == 0 {
53 runtime.stack.push(IValue::ByteArray(vec![]));
54
55 return Ok(())
56 }
57
58 memory_view
59 .check_bounds(runtime.store, pointer, length)
60 .map_err(|e| InstructionError::from_memory_access(self.instruction.clone(), e))?;
61
62 let data = memory_view.read_vec(runtime.store, pointer, length);
63
64 log::debug!("byte_array.lift_memory: pushing {:?} on the stack", data);
65 runtime.stack.push(IValue::ByteArray(data));
66
67 Ok(())
68 }.boxed()
69 }
70 }
71);
72
73struct ByteArrayLowerMemoryAsync {
74 instruction: Instruction,
75}
76
77impl_async_executable_instruction!(
78 byte_array_lower_memory(instruction: Instruction) -> _ {
79 Box::new(ByteArrayLowerMemoryAsync{instruction})
80 }
81
82 ByteArrayLowerMemoryAsync {
83 fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>) -> BoxFuture<InstructionResult<()>> {
84 async move {
85 let instruction = &self.instruction;
86 let mut inputs = runtime.stack.pop(2).ok_or_else(|| {
87 InstructionError::from_error_kind(
88 instruction.clone(),
89 InstructionErrorKind::StackIsTooSmall { needed: 2 },
90 )
91 })?;
92
93 let array_pointer = to_native::<i32>(inputs.remove(0), instruction.clone())? as u32;
94 let array: Vec<u8> = to_native(inputs.remove(0), instruction.clone())?;
95 let length = array.len() as u32;
96
97 let instance = &mut runtime.wasm_instance;
98 let memory_index = DEFAULT_MEMORY_INDEX;
99 let memory_view = instance
100 .memory(memory_index)
101 .ok_or_else(|| {
102 InstructionError::from_error_kind(
103 instruction.clone(),
104 InstructionErrorKind::MemoryIsMissing { memory_index },
105 )
106 })?
107 .view();
108
109 memory_view
110 .check_bounds(runtime.store, array_pointer, array.len() as u32)
111 .map_err(|e| InstructionError::from_memory_access(instruction.clone(), e))?;
112
113 memory_view.write_bytes(runtime.store, array_pointer, &array);
114
115 log::debug!("string.lower_memory: pushing {}, {} on the stack", array_pointer, length);
116 runtime.stack.push(IValue::I32(array_pointer as i32));
117 runtime.stack.push(IValue::I32(length as i32));
118
119 Ok(())
120 }.boxed()
121 }
122 }
123);
124
125struct ByteArraySizeAsync {
126 instruction: Instruction,
127}
128
129impl_async_executable_instruction!(
130 byte_array_size(instruction: Instruction) -> _ {
131 Box::new(ByteArraySizeAsync{instruction})
132 }
133
134 ByteArraySizeAsync {
135 fn execute<'args>(&'args self, runtime: &'args mut Runtime<Instance, Export, LocalImport, Memory, MemoryView, Store>) -> BoxFuture<InstructionResult<()>> {
136 async move {
137 let instruction = &self.instruction;
138 match runtime.stack.pop1() {
139 Some(IValue::ByteArray(array)) => {
140 let length = array.len() as i32;
141
142 log::debug!("byte_array.size: pushing {} on the stack", length);
143 runtime.stack.push(IValue::I32(length));
144
145 Ok(())
146 },
147
148 Some(IValue::Array(array)) => {
149 let array = check_array_type(array, &instruction)?;
150
151 let length = array.len() as i32;
152
153 log::debug!("byte_array.size: pushing {} on the stack", length);
154 runtime.stack.push(IValue::I32(length));
155
156 Ok(())
157 },
158
159 Some(value) => instr_error!(
160 instruction.clone(),
161 InstructionErrorKind::InvalidValueOnTheStack {
162 expected_type: IType::ByteArray,
163 received_value: (&value).clone(),
164 }
165 ),
166
167 None => instr_error!(
168 instruction.clone(),
169 InstructionErrorKind::StackIsTooSmall { needed: 1 }
170 ),
171 }
172 }.boxed()
173 }
174 }
175);
176
177fn check_array_type(
178 ivalues: Vec<IValue>,
179 instruction: &Instruction,
180) -> Result<Vec<IValue>, InstructionError> {
181 if ivalues.is_empty() {
182 return Ok(ivalues);
183 }
184
185 match &ivalues[0] {
186 IValue::U8(_) => Ok(ivalues),
187 _ => instr_error!(
188 instruction.clone(),
189 InstructionErrorKind::InvalidValueOnTheStack {
190 expected_type: IType::ByteArray,
191 received_value: IValue::Array(ivalues),
192 }
193 ),
194 }
195}