1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::interpreter::wasm;
use crate::interpreter::wasm::structures::FunctionIndex;
use crate::IValue;

use it_lilo::traits::Allocatable;
use it_lilo::traits::AllocatableError;
use it_lilo::traits::DEFAULT_MEMORY_INDEX;

use std::marker::PhantomData;

pub struct LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView, Store>
where
    Export: wasm::structures::Export + 'i,
    LocalImport: wasm::structures::LocalImport<Store> + 'i,
    Memory: wasm::structures::Memory<MemoryView, Store> + 'i,
    MemoryView: wasm::structures::MemoryView<Store>,
    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
    Store: wasm::structures::Store,
{
    pub(crate) instance: &'i Instance,
    _export: PhantomData<Export>,
    _local_import: PhantomData<LocalImport>,
    _memory: PhantomData<Memory>,
    _memory_view: PhantomData<MemoryView>,
    _store: PhantomData<Store>,
}

impl<'i, Instance, Export, LocalImport, Memory, MemoryView, Store>
    LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView, Store>
where
    Export: wasm::structures::Export + 'i,
    LocalImport: wasm::structures::LocalImport<Store> + 'i,
    Memory: wasm::structures::Memory<MemoryView, Store> + 'i,
    MemoryView: wasm::structures::MemoryView<Store>,
    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
    Store: wasm::structures::Store,
{
    pub(crate) fn new(instance: &'i Instance) -> Self {
        Self {
            instance,
            _export: PhantomData,
            _local_import: PhantomData,
            _memory: PhantomData,
            _memory_view: PhantomData,
            _store: PhantomData,
        }
    }
}

impl<'i, Instance, Export, LocalImport, Memory, MemoryView, Store> Allocatable<MemoryView, Store>
    for LoHelper<'i, Instance, Export, LocalImport, Memory, MemoryView, Store>
where
    Export: wasm::structures::Export + 'i,
    LocalImport: wasm::structures::LocalImport<Store> + 'i,
    Memory: wasm::structures::Memory<MemoryView, Store> + 'i,
    MemoryView: wasm::structures::MemoryView<Store>,
    Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView, Store>,
    Store: wasm::structures::Store,
{
    fn allocate(
        &mut self,
        store: &mut <Store as wasm::structures::Store>::ActualStore<'_>,
        size: u32,
        type_tag: u32,
    ) -> Result<(u32, MemoryView), AllocatableError> {
        use AllocatableError::*;

        use crate::interpreter::instructions::ALLOCATE_FUNC_INDEX;
        use crate::interpreter::wasm::structures::TypedIndex;

        let index = FunctionIndex::new(ALLOCATE_FUNC_INDEX as usize);
        let local_or_import =
            self.instance
                .local_or_import(index)
                .ok_or(AllocateFuncIsMissing {
                    function_index: ALLOCATE_FUNC_INDEX,
                })?;

        let inputs = vec![IValue::I32(size as _), IValue::I32(type_tag as _)];
        // TODO: we could check it only once on the module startup or memorize check result
        crate::interpreter::instructions::check_function_signature(
            self.instance,
            local_or_import,
            &inputs,
        )
        .map_err(|_| AllocateFuncIncompatibleSignature)?;

        let outcome = local_or_import
            .call(store, &inputs)
            .map_err(|_| AllocateCallFailed)?;

        if outcome.len() != 1 {
            return Err(AllocateFuncIncompatibleOutput);
        }

        match outcome[0] {
            IValue::I32(offset) => {
                let view =
                    self.instance
                        .memory_view(DEFAULT_MEMORY_INDEX)
                        .ok_or(MemoryIsMissing {
                            memory_index: DEFAULT_MEMORY_INDEX,
                        })?;

                Ok((offset as _, view))
            }
            _ => Err(AllocateFuncIncompatibleOutput),
        }
    }
}