Coverage Report

Created: 2025-01-23 14:27

/build/source/src/execution/mod.rs
Line
Count
Source (jump to first uncovered line)
1
use alloc::collections::btree_map::BTreeMap;
2
use alloc::string::{String, ToString};
3
use alloc::vec;
4
use alloc::vec::Vec;
5
6
use const_interpreter_loop::{run_const, run_const_span};
7
use execution_info::ExecutionInfo;
8
use function_ref::FunctionRef;
9
use interpreter_loop::run;
10
use locals::Locals;
11
use lut::Lut;
12
use store::{DataInst, ElemInst, ImportedFuncInst, LocalFuncInst, TableInst};
13
use value::{ExternAddr, FuncAddr, Ref};
14
use value_stack::Stack;
15
16
use crate::core::error::StoreInstantiationError;
17
use crate::core::reader::types::element::{ElemItems, ElemMode};
18
use crate::core::reader::types::export::ExportDesc;
19
use crate::core::reader::types::import::ImportDesc;
20
use crate::core::reader::WasmReader;
21
use crate::execution::assert_validated::UnwrapValidatedExt;
22
use crate::execution::hooks::{EmptyHookSet, HookSet};
23
use crate::execution::store::{FuncInst, GlobalInst, MemInst, Store};
24
use crate::execution::value::Value;
25
use crate::validation::code::read_declared_locals;
26
use crate::value::InteropValueList;
27
use crate::{RefType, Result as CustomResult, RuntimeError, ValType, ValidationInfo};
28
29
// TODO
30
pub(crate) mod assert_validated;
31
pub mod const_interpreter_loop;
32
pub(crate) mod execution_info;
33
pub mod function_ref;
34
pub mod hooks;
35
mod interpreter_loop;
36
pub(crate) mod locals;
37
pub(crate) mod lut;
38
pub(crate) mod store;
39
pub mod value;
40
pub mod value_stack;
41
42
/// The default module name if a [RuntimeInstance] was created using [RuntimeInstance::new].
43
pub const DEFAULT_MODULE: &str = "__interpreter_default__";
44
45
pub struct RuntimeInstance<'b, H = EmptyHookSet>
46
where
47
    H: HookSet,
48
{
49
    pub modules: Vec<ExecutionInfo<'b>>,
50
    module_map: BTreeMap<String, usize>,
51
    lut: Option<Lut>,
52
    pub hook_set: H,
53
}
54
55
impl<'b> RuntimeInstance<'b, EmptyHookSet> {
56
270
    pub fn new(validation_info: &'_ ValidationInfo<'b>) -> CustomResult<Self> {
57
270
        Self::new_with_hooks(DEFAULT_MODULE, validation_info, EmptyHookSet)
58
270
    }
59
60
4
    pub fn new_named(
61
4
        module_name: &str,
62
4
        validation_info: &'_ ValidationInfo<'b>,
63
4
    ) -> CustomResult<Self> {
64
4
        Self::new_with_hooks(module_name, validation_info, EmptyHookSet)
65
4
    }
66
}
67
68
impl<'b, H> RuntimeInstance<'b, H>
69
where
70
    H: HookSet,
71
{
72
274
    pub fn new_with_hooks(
73
274
        module_name: &str,
74
274
        validation_info: &'_ ValidationInfo<'b>,
75
274
        hook_set: H,
76
274
    ) -> CustomResult<Self> {
77
274
        trace!("Starting instantiation of bytecode");
78
79
274
        let mut instance = RuntimeInstance {
80
274
            modules: Vec::new(),
81
274
            module_map: BTreeMap::new(),
82
274
            lut: None,
83
274
            hook_set,
84
274
        };
85
274
        instance.add_module(module_name, validation_info)
?0
;
86
87
        // TODO: how do we handle the start function, if we don't have a LUT yet?
88
274
        if let Some(
start1
) = validation_info.start {
89
            // "start" is not always exported, so we need create a non-API exposed function reference.
90
            // Note: function name is not important here, as it is not used in the verification process.
91
1
            let start_fn = FunctionRef {
92
1
                module_name: module_name.to_string(),
93
1
                function_name: "start".to_string(),
94
1
                module_index: 0,
95
1
                function_index: start,
96
1
                exported: false,
97
1
            };
98
1
            instance.invoke::<(), ()>(&start_fn, ())
?0
;
99
273
        }
100
101
274
        Ok(instance)
102
274
    }
103
104
251
    pub fn get_function_by_name(
105
251
        &self,
106
251
        module_name: &str,
107
251
        function_name: &str,
108
251
    ) -> Result<FunctionRef, RuntimeError> {
109
251
        let (module_idx, func_idx) = self.get_indicies(module_name, function_name)
?0
;
110
111
251
        Ok(FunctionRef {
112
251
            module_name: module_name.to_string(),
113
251
            function_name: function_name.to_string(),
114
251
            module_index: module_idx,
115
251
            function_index: func_idx,
116
251
            exported: true,
117
251
        })
118
251
    }
119
120
1.32k
    pub fn get_function_by_index(
121
1.32k
        &self,
122
1.32k
        module_idx: usize,
123
1.32k
        function_idx: usize,
124
1.32k
    ) -> Result<FunctionRef, RuntimeError> {
125
1.32k
        let module = self
126
1.32k
            .modules
127
1.32k
            .get(module_idx)
128
1.32k
            .ok_or(RuntimeError::ModuleNotFound)
?0
;
129
130
1.32k
        let function_name = module
131
1.32k
            .store
132
1.32k
            .exports
133
1.32k
            .iter()
134
1.32k
            .find(|export| match &export.desc {
135
1.32k
                ExportDesc::FuncIdx(idx) => *idx == function_idx,
136
0
                _ => false,
137
1.32k
            })
138
1.32k
            .map(|export| export.name.clone())
139
1.32k
            .ok_or(RuntimeError::FunctionNotFound)
?0
;
140
141
1.32k
        Ok(FunctionRef {
142
1.32k
            module_name: module.name.clone(),
143
1.32k
            function_name,
144
1.32k
            module_index: module_idx,
145
1.32k
            function_index: function_idx,
146
1.32k
            exported: true,
147
1.32k
        })
148
1.32k
    }
149
150
278
    pub fn add_module(
151
278
        &mut self,
152
278
        module_name: &str,
153
278
        validation_info: &'_ ValidationInfo<'b>,
154
278
    ) -> CustomResult<()> {
155
278
        let store = Self::init_store(validation_info)
?0
;
156
278
        let exec_info = ExecutionInfo::new(
157
278
            module_name,
158
278
            validation_info.wasm,
159
278
            validation_info.types.clone(),
160
278
            store,
161
278
        );
162
278
163
278
        self.module_map
164
278
            .insert(module_name.to_string(), self.modules.len());
165
278
        self.modules.push(exec_info);
166
278
167
278
        self.lut = Lut::new(&self.modules, &self.module_map);
168
278
169
278
        Ok(())
170
278
    }
171
172
6.83k
    pub fn invoke<Param: InteropValueList, Returns: InteropValueList>(
173
6.83k
        &mut self,
174
6.83k
        function_ref: &FunctionRef,
175
6.83k
        params: Param,
176
6.83k
    ) -> Result<Returns, RuntimeError> {
177
        // First, verify that the function reference is valid
178
6.83k
        let (module_idx, func_idx) = self.verify_function_ref(function_ref)
?0
;
179
180
        // -=-= Verification =-=-
181
6.83k
        trace!("{:?}", self.modules[module_idx].store.funcs);
182
183
6.83k
        let func_inst = self.modules[module_idx]
184
6.83k
            .store
185
6.83k
            .funcs
186
6.83k
            .get(func_idx)
187
6.83k
            .ok_or(RuntimeError::FunctionNotFound)
?0
188
6.83k
            .try_into_local()
189
6.83k
            .ok_or(RuntimeError::FunctionNotFound)
?0
;
190
6.83k
        let func_ty = self.modules[module_idx]
191
6.83k
            .fn_types
192
6.83k
            .get(func_inst.ty)
193
6.83k
            .unwrap_validated();
194
6.83k
195
6.83k
        // Check correct function parameters and return types
196
6.83k
        if func_ty.params.valtypes != Param::TYS {
197
0
            panic!("Invalid `Param` generics");
198
6.83k
        }
199
6.83k
        if func_ty.returns.valtypes != Returns::TYS {
200
0
            panic!("Invalid `Returns` generics");
201
6.83k
        }
202
6.83k
203
6.83k
        // Prepare a new stack with the locals for the entry function
204
6.83k
        let mut stack = Stack::new();
205
6.83k
        let locals = Locals::new(
206
6.83k
            params.into_values().into_iter(),
207
6.83k
            func_inst.locals.iter().cloned(),
208
6.83k
        );
209
6.83k
210
6.83k
        // setting `usize::MAX` as return address for the outermost function ensures that we
211
6.83k
        // observably fail upon errornoeusly continuing execution after that function returns.
212
6.83k
        stack.push_stackframe(
213
6.83k
            module_idx,
214
6.83k
            func_idx,
215
6.83k
            func_ty,
216
6.83k
            locals,
217
6.83k
            usize::MAX,
218
6.83k
            usize::MAX,
219
6.83k
        );
220
6.83k
221
6.83k
        let mut current_module_idx = module_idx;
222
6.83k
        // Run the interpreter
223
6.83k
        run(
224
6.83k
            &mut self.modules,
225
6.83k
            &mut current_module_idx,
226
6.83k
            self.lut.as_ref().ok_or(RuntimeError::UnmetImport)
?2
,
227
6.83k
            &mut stack,
228
6.83k
            EmptyHookSet,
229
667
        )?;
230
231
        // Pop return values from stack
232
6.16k
        let return_values = Returns::TYS
233
6.16k
            .iter()
234
6.16k
            .map(|ty| 
stack.pop_value(*ty)6.09k
)
235
6.16k
            .collect::<Vec<Value>>();
236
6.16k
237
6.16k
        // Values are reversed because they were popped from stack one-by-one. Now reverse them back
238
6.16k
        let reversed_values = return_values.into_iter().rev();
239
6.16k
        let ret: Returns = Returns::from_values(reversed_values);
240
6.16k
        debug!("Successfully invoked function");
241
6.16k
        Ok(ret)
242
6.83k
    }
243
244
    /// Invokes a function with the given parameters, and return types which are not known at compile time.
245
2
    pub fn invoke_dynamic(
246
2
        &mut self,
247
2
        function_ref: &FunctionRef,
248
2
        params: Vec<Value>,
249
2
        ret_types: &[ValType],
250
2
    ) -> Result<Vec<Value>, RuntimeError> {
251
        // First, verify that the function reference is valid
252
2
        let (module_idx, func_idx) = self.verify_function_ref(function_ref)
?0
;
253
254
        // -=-= Verification =-=-
255
2
        let func_inst = self.modules[module_idx]
256
2
            .store
257
2
            .funcs
258
2
            .get(func_idx)
259
2
            .ok_or(RuntimeError::FunctionNotFound)
?0
260
2
            .try_into_local()
261
2
            .ok_or(RuntimeError::FunctionNotFound)
?0
;
262
2
        let func_ty = self.modules[module_idx]
263
2
            .fn_types
264
2
            .get(func_inst.ty)
265
2
            .unwrap_validated();
266
2
267
2
        // Verify that the given parameters match the function parameters
268
4
        let param_types = params.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
269
2
270
2
        if func_ty.params.valtypes != param_types {
271
0
            panic!("Invalid parameters for function");
272
2
        }
273
2
274
2
        // Verify that the given return types match the function return types
275
2
        if func_ty.returns.valtypes != ret_types {
276
0
            panic!("Invalid return types for function");
277
2
        }
278
2
279
2
        // Prepare a new stack with the locals for the entry function
280
2
        let mut stack = Stack::new();
281
2
        let locals = Locals::new(params.into_iter(), func_inst.locals.iter().cloned());
282
2
        stack.push_stackframe(module_idx, func_idx, func_ty, locals, 0, 0);
283
2
284
2
        let mut currrent_module_idx = module_idx;
285
2
        // Run the interpreter
286
2
        run(
287
2
            &mut self.modules,
288
2
            &mut currrent_module_idx,
289
2
            self.lut.as_ref().ok_or(RuntimeError::UnmetImport)
?0
,
290
2
            &mut stack,
291
2
            EmptyHookSet,
292
0
        )?;
293
294
2
        let func_inst = self.modules[module_idx]
295
2
            .store
296
2
            .funcs
297
2
            .get(func_idx)
298
2
            .ok_or(RuntimeError::FunctionNotFound)
?0
299
2
            .try_into_local()
300
2
            .ok_or(RuntimeError::FunctionNotFound)
?0
;
301
2
        let func_ty = self.modules[module_idx]
302
2
            .fn_types
303
2
            .get(func_inst.ty)
304
2
            .unwrap_validated();
305
2
306
2
        // Pop return values from stack
307
2
        let return_values = func_ty
308
2
            .returns
309
2
            .valtypes
310
2
            .iter()
311
2
            .map(|ty| stack.pop_value(*ty))
312
2
            .collect::<Vec<Value>>();
313
2
314
2
        // Values are reversed because they were popped from stack one-by-one. Now reverse them back
315
2
        let reversed_values = return_values.into_iter().rev();
316
2
        let ret = reversed_values.collect();
317
2
        debug!("Successfully invoked function");
318
2
        Ok(ret)
319
2
    }
320
321
    /// Get the indicies of a module and function by their names.
322
    ///
323
    /// # Arguments
324
    /// - `module_name`: The module in which to find the function.
325
    /// - `function_name`: The name of the function to find inside the module. The function must be a local function and
326
    ///   not an import.
327
    ///
328
    /// # Returns
329
    /// - `Ok((module_idx, func_idx))`, where `module_idx` is the internal index of the module inside the
330
    ///   [RuntimeInstance], and `func_idx` is the internal index of the function inside the module.
331
    /// - `Err(RuntimeError::ModuleNotFound)`, if the module is not found.
332
    /// - `Err(RuntimeError::FunctionNotFound`, if the function is not found within the module.
333
7.09k
    fn get_indicies(
334
7.09k
        &self,
335
7.09k
        module_name: &str,
336
7.09k
        function_name: &str,
337
7.09k
    ) -> Result<(usize, usize), RuntimeError> {
338
7.09k
        let module_idx = *self
339
7.09k
            .module_map
340
7.09k
            .get(module_name)
341
7.09k
            .ok_or(RuntimeError::ModuleNotFound)
?0
;
342
343
7.09k
        let func_idx = self.modules[module_idx]
344
7.09k
            .store
345
7.09k
            .exports
346
7.09k
            .iter()
347
25.5k
            .find_map(|export| {
348
25.5k
                if export.name == function_name {
349
7.09k
                    match export.desc {
350
7.09k
                        ExportDesc::FuncIdx(func_idx) => Some(func_idx),
351
0
                        _ => None,
352
                    }
353
                } else {
354
18.4k
                    None
355
                }
356
25.5k
            })
357
7.09k
            .ok_or(RuntimeError::FunctionNotFound)
?0
;
358
359
7.09k
        Ok((module_idx, func_idx))
360
7.09k
    }
361
362
    /// Verify that the function reference is still valid. A function reference may be invalid if it created from
363
    /// another [RuntimeInstance] or the modules inside the instance have been changed in a way that the indicies inside
364
    /// the [FunctionRef] would be invalid.
365
    ///
366
    /// Note: this function ensures that making an unchecked indexation will not cause a panic.
367
    ///
368
    /// # Returns
369
    /// - `Ok((function_ref.module_idx, function_ref.func_idx))`
370
    /// - `Err(RuntimeError::FunctionNotFound)`, or `Err(RuntimeError::ModuleNotFound)` if the function is not valid.
371
    ///
372
    /// # Implementation details
373
    /// For an exported function (i.e. created by the same [RuntimeInstance]), the names are re-resolved using
374
    /// [RuntimeInstance::get_indicies], and the indicies are compared with the indicies in the [FunctionRef].
375
    ///
376
    /// For a [FunctionRef] with the [export](FunctionRef::exported) flag set to `false`, the indicies are checked to be
377
    /// in-bounds, and that the module name matches the module name in the [FunctionRef]. The function name is ignored.
378
6.84k
    fn verify_function_ref(
379
6.84k
        &self,
380
6.84k
        function_ref: &FunctionRef,
381
6.84k
    ) -> Result<(usize, usize), RuntimeError> {
382
6.84k
        if function_ref.exported {
383
6.83k
            let (module_idx, func_idx) =
384
6.83k
                self.get_indicies(&function_ref.module_name, &function_ref.function_name)
?0
;
385
386
            // TODO: figure out errors :)
387
6.83k
            if module_idx != function_ref.module_index {
388
0
                return Err(RuntimeError::ModuleNotFound);
389
6.83k
            }
390
6.83k
            if func_idx != function_ref.function_index {
391
0
                return Err(RuntimeError::FunctionNotFound);
392
6.83k
            }
393
6.83k
394
6.83k
            Ok((module_idx, func_idx))
395
        } else {
396
1
            let (module_idx, func_idx) = (function_ref.module_index, function_ref.function_index);
397
398
1
            let module = self
399
1
                .modules
400
1
                .get(module_idx)
401
1
                .ok_or(RuntimeError::ModuleNotFound)
?0
;
402
403
1
            if module.name != function_ref.module_name {
404
0
                return Err(RuntimeError::ModuleNotFound);
405
1
            }
406
1
407
1
            // Sanity check that the function index is at least in the bounds of the store, though this doesn't mean
408
1
            // that it's a valid function.
409
1
            module
410
1
                .store
411
1
                .funcs
412
1
                .get(func_idx)
413
1
                .ok_or(RuntimeError::FunctionNotFound)
?0
;
414
415
1
            Ok((module_idx, func_idx))
416
        }
417
6.84k
    }
418
419
278
    fn init_store(validation_info: &ValidationInfo) -> CustomResult<Store> {
420
278
        use StoreInstantiationError::*;
421
278
        let function_instances: Vec<FuncInst> = {
422
278
            let mut wasm_reader = WasmReader::new(validation_info.wasm);
423
278
424
278
            let functions = validation_info.functions.iter();
425
278
            let func_blocks = validation_info.func_blocks.iter();
426
278
427
710
            let local_function_inst = functions.zip(func_blocks).map(|(ty, (func, sidetable))| {
428
710
                wasm_reader
429
710
                    .move_start_to(*func)
430
710
                    .expect("function index to be in the bounds of the WASM binary");
431
710
432
710
                let (locals, bytes_read) = wasm_reader
433
710
                    .measure_num_read_bytes(read_declared_locals)
434
710
                    .unwrap_validated();
435
710
436
710
                let code_expr = wasm_reader
437
710
                    .make_span(func.len() - bytes_read)
438
710
                    .expect("TODO remove this expect");
439
710
440
710
                FuncInst::Local(LocalFuncInst {
441
710
                    ty: *ty,
442
710
                    locals,
443
710
                    code_expr,
444
710
                    // TODO fix this ugly clone
445
710
                    sidetable: sidetable.clone(),
446
710
                })
447
710
            });
448
278
449
278
            let imported_function_inst =
450
278
                validation_info
451
278
                    .imports
452
278
                    .iter()
453
278
                    .filter_map(|import| 
match &import.desc8
{
454
7
                        ImportDesc::Func(type_idx) => Some(FuncInst::Imported(ImportedFuncInst {
455
7
                            ty: *type_idx,
456
7
                            module_name: import.module_name.clone(),
457
7
                            function_name: import.name.clone(),
458
7
                        })),
459
1
                        _ => None,
460
278
                    
}8
);
461
278
462
278
            imported_function_inst.chain(local_function_inst).collect()
463
278
        };
464
278
465
278
        // https://webassembly.github.io/spec/core/exec/modules.html#tables
466
278
        let mut tables: Vec<TableInst> = validation_info
467
278
            .tables
468
278
            .iter()
469
278
            .map(|ty| 
TableInst::new(*ty)84
)
470
278
            .collect();
471
278
472
278
        let mut passive_elem_indexes: Vec<usize> = vec![];
473
278
        // https://webassembly.github.io/spec/core/syntax/modules.html#element-segments
474
278
        let elements: Vec<ElemInst> = validation_info
475
278
            .elements
476
278
            .iter()
477
278
            .enumerate()
478
278
            .filter_map(|(i, elem)| {
479
181
                trace!("Instantiating element {:#?}", elem);
480
481
181
                let offsets = match &elem.init {
482
123
                    ElemItems::Exprs(_ref_type, init_exprs) => init_exprs
483
123
                        .iter()
484
330
                        .map(|expr| {
485
330
                            get_address_offset(
486
330
                                run_const_span(validation_info.wasm, expr, ()).unwrap_validated(),
487
330
                            )
488
330
                        })
489
123
                        .collect::<Vec<Option<u32>>>(),
490
58
                    ElemItems::RefFuncs(indicies) => {
491
58
                        // This branch gets taken when the elements are direct function references (i32 values), so we just return the indices
492
58
                        indicies
493
58
                            .iter()
494
242
                            .map(|el| Some(*el))
495
58
                            .collect::<Vec<Option<u32>>>()
496
                    }
497
                };
498
499
181
                let references: Vec<Ref> = offsets
500
181
                    .iter()
501
572
                    .map(|offset| {
502
572
                        let offset = offset.as_ref().map(|offset| *offset as usize);
503
572
                        match elem.ty() {
504
572
                            RefType::FuncRef => Ref::Func(FuncAddr::new(offset)),
505
0
                            RefType::ExternRef => Ref::Extern(ExternAddr::new(offset)),
506
                        }
507
572
                    })
508
181
                    .collect();
509
181
510
181
                let instance = ElemInst {
511
181
                    ty: elem.ty(),
512
181
                    references,
513
181
                };
514
181
515
181
                match &elem.mode {
516
                    // As per https://webassembly.github.io/spec/core/syntax/modules.html#element-segments
517
                    // A declarative element segment is not available at runtime but merely serves to forward-declare
518
                    //  references that are formed in code with instructions like `ref.func`
519
520
                    // Also, the answer given by Andreas Rossberg (the editor of the WASM Spec - Release 2.0)
521
                    // Per https://stackoverflow.com/questions/78672934/what-is-the-purpose-of-a-wasm-declarative-element-segment
522
                    // "[...] The reason Wasm requires this (admittedly ugly) forward declaration is to support streaming compilation [...]"
523
1
                    ElemMode::Declarative => None,
524
                    ElemMode::Passive => {
525
124
                        passive_elem_indexes.push(i);
526
124
                        Some(instance)
527
                    }
528
56
                    ElemMode::Active(active_elem) => {
529
56
                        let table_idx = active_elem.table_idx as usize;
530
531
56
                        let offset =
532
56
                            match run_const_span(validation_info.wasm, &active_elem.init_expr, ())
533
56
                                .unwrap_validated()
534
                            {
535
56
                                Value::I32(offset) => offset as usize,
536
                                // We are already asserting that on top of the stack there is an I32 at validation time
537
0
                                _ => unreachable!(),
538
                            };
539
540
56
                        let table = &mut tables[table_idx];
541
56
                        // This can't be verified at validation-time because we don't keep track of actual values when validating expressions
542
56
                        //  we only keep track of the type of the values. As such we can't pop the exact value of an i32 from the validation stack
543
56
                        assert!(table.len() >= (offset + instance.len()));
544
545
56
                        table.elem[offset..offset + instance.references.len()]
546
56
                            .copy_from_slice(&instance.references);
547
56
548
56
                        Some(instance)
549
                    }
550
                }
551
278
            
}181
)
552
278
            .collect();
553
278
554
278
        let mut memory_instances: Vec<MemInst> = validation_info
555
278
            .memories
556
278
            .iter()
557
278
            .map(|ty| 
MemInst::new(*ty)47
)
558
278
            .collect();
559
560
278
        let data_sections: Vec<DataInst> = validation_info
561
278
            .data
562
278
            .iter()
563
278
            .map(|d| 
{45
564
                use crate::core::reader::types::data::DataMode;
565
                use crate::NumType;
566
45
                if let DataMode::Active(
active_data33
) = d.mode.clone() {
567
33
                    let mem_idx = active_data.memory_idx;
568
33
                    if mem_idx != 0 {
569
0
                        todo!("Active data has memory_idx different than 0");
570
33
                    }
571
33
                    assert!(memory_instances.len() > mem_idx);
572
573
33
                    let boxed_value = {
574
33
                        let mut wasm = WasmReader::new(validation_info.wasm);
575
33
                        wasm.move_start_to(active_data.offset).unwrap_validated();
576
33
                        let mut stack = Stack::new();
577
33
                        run_const(wasm, &mut stack, ());
578
33
                        stack.pop_value(ValType::NumType(NumType::I32))
579
                        // stack.peek_unknown_value().ok_or(MissingValueOnTheStack)?
580
                    };
581
582
                    // TODO: this shouldn't be a simple value, should it? I mean it can't be, but it can also be any type of ValType
583
                    // TODO: also, do we need to forcefully make it i32?
584
33
                    let offset: u32 = match boxed_value {
585
33
                        Value::I32(val) => val,
586
                        // Value::I64(val) => {
587
                        //     if val > u32::MAX as u64 {
588
                        //         return Err(I64ValueOutOfReach("data segment".to_owned()));
589
                        //     }
590
                        //     val as u32
591
                        // }
592
                        // TODO: implement all value types
593
0
                        _ => todo!(),
594
                    };
595
596
33
                    let mem_inst = memory_instances.get_mut(mem_idx).unwrap();
597
33
598
33
                    let len = mem_inst.data.len();
599
33
                    if offset as usize + d.init.len() > len {
600
0
                        return Err(ActiveDataWriteOutOfBounds);
601
33
                    }
602
33
                    let data = mem_inst
603
33
                        .data
604
33
                        .get_mut(offset as usize..offset as usize + d.init.len())
605
33
                        .unwrap();
606
33
                    data.copy_from_slice(&d.init);
607
12
                }
608
45
                Ok(DataInst {
609
45
                    data: d.init.clone(),
610
45
                })
611
278
            
}45
)
612
278
            .collect::<Result<Vec<DataInst>, StoreInstantiationError>>()
?0
;
613
614
278
        let global_instances: Vec<GlobalInst> = validation_info
615
278
            .globals
616
278
            .iter()
617
278
            .map({
618
278
                let mut stack = Stack::new();
619
278
                move |global| {
620
4
                    let mut wasm = WasmReader::new(validation_info.wasm);
621
4
                    // The place we are moving the start to should, by all means, be inside the wasm bytecode.
622
4
                    wasm.move_start_to(global.init_expr).unwrap_validated();
623
4
                    // We shouldn't need to clear the stack. If validation is correct, it will remain empty after execution.
624
4
625
4
                    run_const(wasm, &mut stack, ());
626
4
                    let value = stack.pop_value(global.ty.ty);
627
4
628
4
                    GlobalInst {
629
4
                        global: *global,
630
4
                        value,
631
4
                    }
632
278
                }
633
278
            })
634
278
            .collect();
635
278
636
278
        let exports = validation_info.exports.clone();
637
278
        Ok(Store {
638
278
            funcs: function_instances,
639
278
            mems: memory_instances,
640
278
            globals: global_instances,
641
278
            data: data_sections,
642
278
            tables,
643
278
            elements,
644
278
            passive_elem_indexes,
645
278
            exports,
646
278
        })
647
278
    }
648
}
649
650
/// Used for getting the offset of an address.
651
///
652
/// Related to the Active Elements
653
///
654
/// <https://webassembly.github.io/spec/core/syntax/modules.html#element-segments>
655
///
656
/// Since active elements need an offset given by a constant expression, in this case
657
/// they can only be an i32 (which can be understood from either a [`Value::I32`] - but
658
/// since we don't unbox the address of the reference, for us also a [`Value::Ref`] -
659
/// or from a Global)
660
330
fn get_address_offset(value: Value) -> Option<u32> {
661
330
    match value {
662
0
        Value::I32(val) => Some(val),
663
330
        Value::Ref(rref) => match rref {
664
0
            Ref::Extern(_) => todo!("Not yet implemented"),
665
            // TODO: fix
666
330
            Ref::Func(func_addr) => func_addr.addr.map(|addr| addr as u32),
667
        },
668
        // INFO: from wasmtime - implement only global
669
0
        _ => unreachable!(),
670
    }
671
330
}