wasmer_interface_types_fl/interpreter/instructions/
byte_arrays.rs

1use 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}