Skip to content

Commit 61facdb

Browse files
feat: add embedder api for accessing imports/exports of a module
Signed-off-by: Florian Hartung <florian.hartung@dlr.de>
1 parent 5596ced commit 61facdb

File tree

4 files changed

+143
-6
lines changed

4 files changed

+143
-6
lines changed

src/execution/linker.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use alloc::{
2+
borrow::ToOwned,
23
collections::btree_map::{BTreeMap, Entry},
34
string::String,
45
vec::Vec,
@@ -138,10 +139,9 @@ impl Linker {
138139
validation_info: &ValidationInfo,
139140
) -> Result<Vec<ExternVal>, RuntimeError> {
140141
validation_info
141-
.imports
142-
.iter()
143-
.map(|import| {
144-
self.get_unchecked(import.module_name.clone(), import.name.clone())
142+
.imports()
143+
.map(|(module_name, name, _desc)| {
144+
self.get_unchecked(module_name.to_owned(), name.to_owned())
145145
.ok_or(RuntimeError::UnableToResolveExternLookup)
146146
})
147147
.collect()

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ extern crate log_wrapper;
1111

1212
pub use core::error::ValidationError;
1313
pub use core::reader::types::{
14-
export::ExportDesc, global::GlobalType, Limits, MemType, NumType, RefType, TableType, ValType,
14+
export::ExportDesc, global::GlobalType, ExternType, Limits, MemType, NumType, RefType, FuncType, ResultType,
15+
TableType, ValType,
1516
};
1617
pub use core::rw_spinlock;
1718
pub use execution::error::{RuntimeError, TrapError};

src/validation/mod.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use core::iter::Map;
2+
13
use alloc::collections::btree_set::{self, BTreeSet};
24
use alloc::vec::Vec;
35

@@ -9,7 +11,7 @@ use crate::core::reader::types::element::ElemType;
911
use crate::core::reader::types::export::Export;
1012
use crate::core::reader::types::global::{Global, GlobalType};
1113
use crate::core::reader::types::import::{Import, ImportDesc};
12-
use crate::core::reader::types::{FuncType, MemType, ResultType, TableType};
14+
use crate::core::reader::types::{ExternType, FuncType, MemType, ResultType, TableType};
1315
use crate::core::reader::WasmReader;
1416
use crate::core::sidetable::Sidetable;
1517
use crate::{ExportDesc, ValidationError};
@@ -480,3 +482,34 @@ fn handle_section<T, F: FnOnce(&mut WasmReader, SectionHeader) -> Result<T, Vali
480482
_ => Ok(None),
481483
}
482484
}
485+
486+
impl ValidationInfo<'_> {
487+
/// Returns the imports of this module as an iterator. Each import consist
488+
/// of a module name, a name and an extern type.
489+
///
490+
/// See: WebAssembly Specification 2.0 - 7.1.5 - module_imports
491+
pub fn imports<'a>(
492+
&'a self,
493+
) -> Map<core::slice::Iter<'a, Import>, impl FnMut(&'a Import) -> (&'a str, &'a str, ExternType)>
494+
{
495+
self.imports.iter().map(|import| {
496+
(
497+
&*import.module_name,
498+
&*import.name,
499+
import.desc.extern_type(self),
500+
)
501+
})
502+
}
503+
504+
/// Returns the exports of this module as an iterator. Each export consist
505+
/// of a name, and an extern type.
506+
///
507+
/// See: WebAssembly Specification 2.0 - 7.1.5 - module_exports
508+
pub fn exports<'a>(
509+
&'a self,
510+
) -> Map<core::slice::Iter<'a, Export>, impl FnMut(&'a Export) -> (&'a str, ExternType)> {
511+
self.exports
512+
.iter()
513+
.map(|export| (&*export.name, export.desc.extern_type(self)))
514+
}
515+
}

tests/module_imports_exports.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use wasm::{validate, ExternType, FuncType, GlobalType, NumType, ResultType, ValType};
2+
3+
#[test_log::test]
4+
fn empty_module() {
5+
const EMPTY_MODULE: &str = r#"
6+
(module)
7+
"#;
8+
let wasm_bytes = wat::parse_str(EMPTY_MODULE).unwrap();
9+
10+
let validation_info = validate(&wasm_bytes).unwrap();
11+
12+
assert_eq!(validation_info.imports().len(), 0);
13+
assert_eq!(validation_info.exports().len(), 0);
14+
}
15+
16+
#[test_log::test]
17+
fn imports() {
18+
const MODULE_WITH_IMPORTS: &str = r#"
19+
(module
20+
(import "foo" "baz" (func))
21+
(import "bar" "bat" (global (mut i64)))
22+
)
23+
"#;
24+
25+
let wasm_bytes = wat::parse_str(MODULE_WITH_IMPORTS).unwrap();
26+
27+
let validation_info = validate(&wasm_bytes).unwrap();
28+
29+
let imports: Vec<(&str, &str, ExternType)> = validation_info.imports().collect();
30+
31+
assert_eq!(
32+
&imports,
33+
&[
34+
(
35+
"foo",
36+
"baz",
37+
ExternType::Func(FuncType {
38+
params: ResultType {
39+
valtypes: Vec::new()
40+
},
41+
returns: ResultType {
42+
valtypes: Vec::new()
43+
},
44+
})
45+
),
46+
(
47+
"bar",
48+
"bat",
49+
ExternType::Global(GlobalType {
50+
ty: ValType::NumType(NumType::I64),
51+
is_mut: true,
52+
}),
53+
)
54+
]
55+
);
56+
57+
assert_eq!(validation_info.exports().len(), 0);
58+
}
59+
60+
#[test_log::test]
61+
fn exports() {
62+
const MODULE_WITH_EXPORTED_DEFINITIONS: &str = r#"
63+
(module
64+
(func $my_func (export "foo") (param i32) (result i64)
65+
local.get 0
66+
i64.extend_i32_u
67+
)
68+
(global $my_global (export "bar") (mut i32)
69+
i32.const 123
70+
)
71+
)
72+
"#;
73+
74+
let wasm_bytes = wat::parse_str(MODULE_WITH_EXPORTED_DEFINITIONS).unwrap();
75+
76+
let validation_info = validate(&wasm_bytes).unwrap();
77+
78+
let exports: Vec<(&str, ExternType)> = validation_info.exports().collect();
79+
80+
assert_eq!(
81+
&exports,
82+
&[
83+
(
84+
"foo",
85+
ExternType::Func(FuncType {
86+
params: ResultType {
87+
valtypes: vec![ValType::NumType(NumType::I32)]
88+
},
89+
returns: ResultType {
90+
valtypes: vec![ValType::NumType(NumType::I64)],
91+
}
92+
}),
93+
),
94+
(
95+
"bar",
96+
ExternType::Global(GlobalType {
97+
ty: ValType::NumType(NumType::I32),
98+
is_mut: true
99+
})
100+
)
101+
]
102+
)
103+
}

0 commit comments

Comments
 (0)