wasmer_interface_types_fl/interpreter/instructions/
mod.rs

1mod argument_get;
2mod arrays;
3mod byte_arrays;
4mod call_core;
5mod dup;
6pub(self) mod lilo;
7mod numbers;
8mod push;
9mod records;
10mod strings;
11mod swap2;
12
13use crate::errors::{
14    InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError,
15};
16use crate::interpreter::wasm;
17use crate::IType;
18use crate::IValue;
19use crate::NEVec;
20
21pub(crate) use argument_get::argument_get;
22pub(crate) use arrays::*;
23pub(crate) use byte_arrays::*;
24pub(crate) use call_core::call_core;
25pub(crate) use dup::dup;
26pub(crate) use numbers::*;
27pub(crate) use push::*;
28pub(crate) use records::*;
29pub(crate) use strings::*;
30pub(crate) use swap2::swap2;
31
32use fluence_it_types::NativeType;
33use serde::Deserialize;
34use serde::Serialize;
35
36use std::convert::TryFrom;
37
38pub(self) const ALLOCATE_FUNC_INDEX: u32 = 0;
39
40/// Represents all the possible WIT instructions.
41#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
42pub enum Instruction {
43    /// The `arg.get` instruction.
44    ArgumentGet {
45        /// The argument index.
46        index: u32,
47    },
48
49    /// The `call-core` instruction.
50    CallCore {
51        /// The function index.
52        function_index: u32,
53    },
54
55    /// The bool.from_i32` instruction.
56    BoolFromI32,
57
58    /// The `s8.from_i32` instruction.
59    S8FromI32,
60
61    /// The `s8.from_i64` instruction.
62    S8FromI64,
63
64    /// The `s16.from_i32` instruction.
65    S16FromI32,
66
67    /// The `s16.from_i64` instruction.
68    S16FromI64,
69
70    /// The `s32.from_i32` instruction.
71    S32FromI32,
72
73    /// The `s32.from_i64` instruction.
74    S32FromI64,
75
76    /// The `s64.from_i32` instruction.
77    S64FromI32,
78
79    /// The `s64.from_i64` instruction.
80    S64FromI64,
81
82    /// The i32.from_bool instruction.
83    I32FromBool,
84
85    /// The `i32.from_s8` instruction.
86    I32FromS8,
87
88    /// The `i32.from_s16` instruction.
89    I32FromS16,
90
91    /// The `i32.from_s32` instruction.
92    I32FromS32,
93
94    /// The `i32.from_s64` instruction.
95    I32FromS64,
96
97    /// The `i64.from_s8` instruction.
98    I64FromS8,
99
100    /// The `i64.from_s16` instruction.
101    I64FromS16,
102
103    /// The `i64.from_s32` instruction.
104    I64FromS32,
105
106    /// The `i64.from_s64` instruction.
107    I64FromS64,
108
109    /// The `u8.from_i32` instruction.
110    U8FromI32,
111
112    /// The `u8.from_i64` instruction.
113    U8FromI64,
114
115    /// The `u16.from_i32` instruction.
116    U16FromI32,
117
118    /// The `u16.from_i64` instruction.
119    U16FromI64,
120
121    /// The `u32.from_i32` instruction.
122    U32FromI32,
123
124    /// The `u32.from_i64` instruction.
125    U32FromI64,
126
127    /// The `u64.from_i32` instruction.
128    U64FromI32,
129
130    /// The `u64.from_i64` instruction.
131    U64FromI64,
132
133    /// The `i32.from_u8` instruction.
134    I32FromU8,
135
136    /// The `i32.from_u16` instruction.
137    I32FromU16,
138
139    /// The `i32.from_u32` instruction.
140    I32FromU32,
141
142    /// The `i32.from_u64` instruction.
143    I32FromU64,
144
145    /// The `i64.from_u8` instruction.
146    I64FromU8,
147
148    /// The `i64.from_u16` instruction.
149    I64FromU16,
150
151    /// The `i64.from_u32` instruction.
152    I64FromU32,
153
154    /// The `i64.from_u64` instruction.
155    I64FromU64,
156
157    /// The `string.lift_memory` instruction.
158    StringLiftMemory,
159
160    /// The `string.lower_memory` instruction.
161    StringLowerMemory,
162
163    /// The `byte_array.size` instruction.
164    ByteArraySize,
165
166    /// The `byte_array.lift_memory` instruction.
167    ByteArrayLiftMemory,
168
169    /// The `byte_array.lower_memory` instruction.
170    ByteArrayLowerMemory,
171
172    /// The `string.size` instruction.
173    StringSize,
174
175    /// The `array.lift_memory` instruction.
176    ArrayLiftMemory {
177        /// Array value type.
178        value_type: IType,
179    },
180
181    /// The `array.lower_memory` instruction.
182    ArrayLowerMemory {
183        /// Array value type.
184        value_type: IType,
185    },
186
187    /// The `record.lift_memory` instruction.
188    RecordLiftMemory {
189        /// The type index of the record.
190        record_type_id: u32,
191    },
192
193    /// The `record.lower_memory` instruction.
194    RecordLowerMemory {
195        /// The type index of the record.
196        record_type_id: u32,
197    },
198
199    /// The `i32.push` instruction.
200    PushI32 {
201        /// The value that should be pushed on the stack.
202        value: i32,
203    },
204
205    /// The `i64.push` instruction.
206    PushI64 {
207        /// The value that should be pushed on the stack.
208        value: i64,
209    },
210
211    /// The `dup` instructions.
212    Dup,
213
214    /// The `swap` instructions.
215    Swap2,
216}
217
218/// Just a short helper to map the error of a cast from an
219/// `IValue` to a native value.
220pub(crate) fn to_native<'a, T>(wit_value: IValue, instruction: Instruction) -> InstructionResult<T>
221where
222    T: NativeType + TryFrom<IValue, Error = WasmValueNativeCastError>,
223{
224    T::try_from(wit_value).map_err(|error| {
225        InstructionError::from_error_kind(instruction, InstructionErrorKind::ToNative(error))
226    })
227}
228
229pub(crate) fn check_function_signature<
230    'instance,
231    Instance,
232    Export,
233    LocalImport,
234    Memory,
235    MemoryView,
236    Store,
237>(
238    instance: &'instance Instance,
239    local_import: &LocalImport,
240    values: &[IValue],
241) -> Result<(), InstructionErrorKind>
242where
243    Export: wasm::structures::Export + 'instance,
244    LocalImport: wasm::structures::LocalImport<Store> + 'instance,
245    Memory: wasm::structures::Memory<MemoryView, Store> + 'instance,
246    MemoryView: wasm::structures::MemoryView<Store>,
247    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
248    Store: wasm::structures::Store,
249{
250    let func_inputs = local_import.arguments();
251
252    for (func_input_arg, value) in func_inputs.iter().zip(values.iter()) {
253        is_value_compatible_to_type(instance, &func_input_arg.ty, value)?;
254    }
255
256    Ok(())
257}
258
259/// Check whether the provided value could be a value of the provided type.
260pub(crate) fn is_value_compatible_to_type<
261    'instance,
262    Instance,
263    Export,
264    LocalImport,
265    Memory,
266    MemoryView,
267    Store,
268>(
269    instance: &'instance Instance,
270    interface_type: &IType,
271    interface_value: &IValue,
272) -> Result<(), InstructionErrorKind>
273where
274    Export: wasm::structures::Export + 'instance,
275    LocalImport: wasm::structures::LocalImport<Store> + 'instance,
276    Memory: wasm::structures::Memory<MemoryView, Store> + 'instance,
277    MemoryView: wasm::structures::MemoryView<Store>,
278    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
279    Store: wasm::structures::Store,
280{
281    match (&interface_type, interface_value) {
282        (IType::Boolean, IValue::Boolean(_)) => Ok(()),
283        (IType::S8, IValue::S8(_)) => Ok(()),
284        (IType::S16, IValue::S16(_)) => Ok(()),
285        (IType::S32, IValue::S32(_)) => Ok(()),
286        (IType::S64, IValue::S64(_)) => Ok(()),
287        (IType::U8, IValue::U8(_)) => Ok(()),
288        (IType::U16, IValue::U16(_)) => Ok(()),
289        (IType::U32, IValue::U32(_)) => Ok(()),
290        (IType::U64, IValue::U64(_)) => Ok(()),
291        (IType::I32, IValue::I32(_)) => Ok(()),
292        (IType::I64, IValue::I64(_)) => Ok(()),
293        (IType::F32, IValue::F32(_)) => Ok(()),
294        (IType::F64, IValue::F64(_)) => Ok(()),
295        (IType::String, IValue::String(_)) => Ok(()),
296        (IType::ByteArray, IValue::ByteArray(_)) => Ok(()),
297        (IType::Array(ty), IValue::Array(values)) => {
298            for value in values {
299                is_value_compatible_to_type(instance, ty, value)?
300            }
301
302            Ok(())
303        }
304        (IType::ByteArray, IValue::Array(values)) => {
305            for value in values {
306                is_value_compatible_to_type(instance, &IType::U8, value)?
307            }
308
309            Ok(())
310        }
311        (IType::Array(ty), IValue::ByteArray(_)) => {
312            if ty.as_ref() == &IType::U8 {
313                return Ok(());
314            }
315
316            Err(InstructionErrorKind::InvalidValueOnTheStack {
317                expected_type: interface_type.clone(),
318                received_value: interface_value.clone(),
319            })
320        }
321        (IType::Record(ref record_type_id), IValue::Record(record_fields)) => {
322            is_record_fields_compatible_to_type(instance, *record_type_id, record_fields)?;
323
324            Ok(())
325        }
326        _ => Err(InstructionErrorKind::InvalidValueOnTheStack {
327            expected_type: interface_type.clone(),
328            received_value: interface_value.clone(),
329        }),
330    }
331}
332
333pub(crate) fn is_record_fields_compatible_to_type<
334    'instance,
335    Instance,
336    Export,
337    LocalImport,
338    Memory,
339    MemoryView,
340    Store,
341>(
342    instance: &'instance Instance,
343    record_type_id: u64,
344    record_fields: &[IValue],
345) -> Result<(), InstructionErrorKind>
346where
347    Export: wasm::structures::Export + 'instance,
348    LocalImport: wasm::structures::LocalImport<Store> + 'instance,
349    Memory: wasm::structures::Memory<MemoryView, Store> + 'instance,
350    MemoryView: wasm::structures::MemoryView<Store>,
351    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
352    Store: wasm::structures::Store,
353{
354    let record_type = instance
355        .wit_record_by_id(record_type_id)
356        .ok_or(InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id })?;
357
358    if record_fields.len() != record_type.fields.len() {
359        return Err(InstructionErrorKind::InvalidValueOnTheStack {
360            expected_type: IType::Record(record_type_id),
361            // unwrap is safe here - len's been already checked
362            received_value: IValue::Record(NEVec::new(record_fields.to_vec()).unwrap()),
363        });
364    }
365
366    for (record_type_field, record_value_field) in
367        record_type.fields.iter().zip(record_fields.iter())
368    {
369        is_value_compatible_to_type(instance, &record_type_field.ty, record_value_field)?;
370    }
371
372    Ok(())
373}
374
375#[cfg(test)]
376pub(crate) mod tests {
377    use crate::{ast::*, interpreter::wasm, types::*, values::*};
378    use std::{cell::Cell, collections::HashMap, convert::TryInto, ops::Deref, rc::Rc};
379
380    pub(crate) struct Export {
381        pub(crate) inputs: Vec<IType>,
382        pub(crate) outputs: Vec<IType>,
383        pub(crate) function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, ()>,
384    }
385
386    impl wasm::structures::Export for Export {
387        fn inputs_cardinality(&self) -> usize {
388            self.inputs.len() as usize
389        }
390
391        fn outputs_cardinality(&self) -> usize {
392            self.outputs.len()
393        }
394
395        fn arguments(&self) -> &[IType] {
396            &self.inputs
397        }
398
399        fn outputs(&self) -> &[IType] {
400            &self.outputs
401        }
402
403        fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
404            (self.function)(arguments)
405        }
406    }
407
408    pub(crate) struct LocalImport {
409        pub(crate) inputs: Vec<IType>,
410        pub(crate) outputs: Vec<IType>,
411        pub(crate) function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, ()>,
412    }
413
414    impl wasm::structures::LocalImport for LocalImport {
415        fn inputs_cardinality(&self) -> usize {
416            self.inputs.len()
417        }
418
419        fn outputs_cardinality(&self) -> usize {
420            self.outputs.len()
421        }
422
423        fn arguments(&self) -> &[IType] {
424            &self.inputs
425        }
426
427        fn outputs(&self) -> &[IType] {
428            &self.outputs
429        }
430
431        fn call(&self, arguments: &[IValue]) -> Result<Vec<IValue>, ()> {
432            (self.function)(arguments)
433        }
434    }
435
436    #[derive(Default, Clone)]
437    pub(crate) struct MemoryView(Rc<Vec<Cell<u8>>>);
438
439    impl wasm::structures::MemoryView for MemoryView {}
440
441    impl Deref for MemoryView {
442        type Target = [Cell<u8>];
443
444        fn deref(&self) -> &Self::Target {
445            self.0.as_slice()
446        }
447    }
448
449    #[derive(Default)]
450    pub(crate) struct Memory {
451        pub(crate) view: MemoryView,
452    }
453
454    impl Memory {
455        pub(crate) fn new(data: Vec<Cell<u8>>) -> Self {
456            Self {
457                view: MemoryView(Rc::new(data)),
458            }
459        }
460    }
461
462    impl wasm::structures::Memory<MemoryView, Store> for Memory {
463        fn view(&self) -> MemoryView {
464            self.view.clone()
465        }
466    }
467
468    #[derive(Default)]
469    pub(crate) struct Instance {
470        pub(crate) exports: HashMap<String, Export>,
471        pub(crate) locals_or_imports: HashMap<usize, LocalImport>,
472        pub(crate) memory: Memory,
473        pub(crate) wit_types: Vec<Type>,
474    }
475
476    impl Instance {
477        pub(crate) fn new() -> Self {
478            Self {
479                exports: {
480                    let mut hashmap = HashMap::new();
481                    hashmap.insert(
482                        "sum".into(),
483                        Export {
484                            inputs: vec![IType::I32, IType::I32],
485                            outputs: vec![IType::I32],
486                            function: |arguments: &[IValue]| {
487                                let a: i32 = (&arguments[0]).try_into().unwrap();
488                                let b: i32 = (&arguments[1]).try_into().unwrap();
489
490                                Ok(vec![IValue::I32(a + b)])
491                            },
492                        },
493                    );
494
495                    hashmap
496                },
497                locals_or_imports: {
498                    let mut hashmap = HashMap::new();
499                    // sum
500                    hashmap.insert(
501                        42,
502                        LocalImport {
503                            inputs: vec![IType::I32, IType::I32],
504                            outputs: vec![IType::I32],
505                            function: |arguments: &[IValue]| {
506                                let a: i32 = (&arguments[0]).try_into().unwrap();
507                                let b: i32 = (&arguments[1]).try_into().unwrap();
508
509                                Ok(vec![IValue::I32(a * b)])
510                            },
511                        },
512                    );
513                    // string allocator
514                    hashmap.insert(
515                        43,
516                        LocalImport {
517                            inputs: vec![IType::I32],
518                            outputs: vec![IType::I32],
519                            function: |arguments: &[IValue]| {
520                                let _size: i32 = (&arguments[0]).try_into().unwrap();
521
522                                Ok(vec![IValue::I32(0)])
523                            },
524                        },
525                    );
526
527                    hashmap
528                },
529                memory: Memory::new(vec![Cell::new(0); 128]),
530                wit_types: vec![Type::Record(RecordType {
531                    name: String::from("RecordType0"),
532                    fields: vec1![
533                        RecordFieldType {
534                            name: String::from("field_0"),
535                            ty: IType::I32,
536                        },
537                        RecordFieldType {
538                            name: String::from("field_1"),
539                            ty: IType::Record(RecordType {
540                                name: String::from("RecordType1"),
541                                fields: vec1![
542                                    RecordFieldType {
543                                        name: String::from("field_0"),
544                                        ty: IType::String,
545                                    },
546                                    RecordFieldType {
547                                        name: String::from("field1"),
548                                        ty: IType::F32
549                                    }
550                                ],
551                            }),
552                        },
553                        RecordFieldType {
554                            name: String::from("field_2"),
555                            ty: IType::I64,
556                        }
557                    ],
558                })],
559            }
560        }
561    }
562
563    impl wasm::structures::Instance<Export, LocalImport, Memory, MemoryView> for Instance {
564        fn export(&self, export_name: &str) -> Option<&Export> {
565            self.exports.get(export_name)
566        }
567
568        fn local_or_import<I: wasm::structures::TypedIndex + wasm::structures::LocalImportIndex>(
569            &mut self,
570            index: I,
571        ) -> Option<&LocalImport> {
572            self.locals_or_imports.get(&index.index())
573        }
574
575        fn memory(&self, _index: usize) -> Option<&Memory> {
576            Some(&self.memory)
577        }
578
579        fn wit_type_by_id(&self, index: u32) -> Option<&Type> {
580            self.wit_types.get(index as usize)
581        }
582
583        fn wit_record_by_id(&self, index: u64) -> Option<&RecordType> {
584            self.wit_types.get(index as _)
585        }
586    }
587}