Merge pull request #2585 from alexcrichton/module-linking-update
Update support for the module linking proposal
This commit is contained in:
50
Cargo.lock
generated
50
Cargo.lock
generated
@@ -388,7 +388,7 @@ dependencies = [
|
|||||||
"souper-ir",
|
"souper-ir",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wast 29.0.0",
|
"wast 31.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1393,7 +1393,7 @@ dependencies = [
|
|||||||
"peepmatic-test-operator",
|
"peepmatic-test-operator",
|
||||||
"peepmatic-traits",
|
"peepmatic-traits",
|
||||||
"serde",
|
"serde",
|
||||||
"wast 29.0.0",
|
"wast 31.0.0",
|
||||||
"z3",
|
"z3",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1421,7 +1421,7 @@ dependencies = [
|
|||||||
"peepmatic-traits",
|
"peepmatic-traits",
|
||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"wast 29.0.0",
|
"wast 31.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1446,7 +1446,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_test",
|
"serde_test",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wast 29.0.0",
|
"wast 31.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1458,7 +1458,7 @@ dependencies = [
|
|||||||
"peepmatic",
|
"peepmatic",
|
||||||
"peepmatic-test-operator",
|
"peepmatic-test-operator",
|
||||||
"souper-ir",
|
"souper-ir",
|
||||||
"wast 29.0.0",
|
"wast 31.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1479,7 +1479,7 @@ version = "0.69.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"peepmatic-traits",
|
"peepmatic-traits",
|
||||||
"serde",
|
"serde",
|
||||||
"wast 29.0.0",
|
"wast 31.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2350,20 +2350,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-encoder"
|
name = "wasm-encoder"
|
||||||
version = "0.2.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed89eaf99e08b84f96e477a16588a07dd3b51dc5f07291c3706782f62a10a5e1"
|
checksum = "c75fa62cf1464aa6655479ae454202a159cc82b7b4d66e8f174409669c0654c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"leb128",
|
"leb128",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-smith"
|
name = "wasm-smith"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "509904d9c4c4659ac238a3f27c3656dd6d3931697eddd4b0f32e335769c298d0"
|
checksum = "0b9b9b796bf4da5eb0523b136d6f0cc9a59c16a66ece8e0d5a14a9cdccf2864e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arbitrary",
|
"arbitrary",
|
||||||
|
"indexmap",
|
||||||
"leb128",
|
"leb128",
|
||||||
"wasm-encoder",
|
"wasm-encoder",
|
||||||
]
|
]
|
||||||
@@ -2394,15 +2395,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmparser"
|
name = "wasmparser"
|
||||||
version = "0.71.0"
|
version = "0.72.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89a30c99437829ede826802bfcf28500cf58df00e66cb9114df98813bc145ff1"
|
checksum = "2cdf4d872d407f9fb44956e540582eeaf0dc4fb8142f1f0f64e2c37196bada01"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmprinter"
|
name = "wasmprinter"
|
||||||
version = "0.2.18"
|
version = "0.2.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0515db67c610037f3c53ec36976edfd1eb01bac6b1226914b17ce609480e729f"
|
checksum = "a0c139586e3b80b899f5aaaa3720c7a236ea9073e315292e01d099da12efacc5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
@@ -2754,7 +2755,7 @@ version = "0.22.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"wasmtime",
|
"wasmtime",
|
||||||
"wast 29.0.0",
|
"wast 31.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2790,29 +2791,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wast"
|
name = "wast"
|
||||||
version = "29.0.0"
|
version = "31.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dcf2268937131d63c3d833242bf5e075406f9ed868b4265f3280e15dac29ac18"
|
checksum = "9beb1f6b63f08c523a1e8e76fc70058af4d2a34ef1c504f56cdac7b6970228b9"
|
||||||
dependencies = [
|
|
||||||
"leb128",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wast"
|
|
||||||
version = "30.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b79907b22f740634810e882d8d1d9d0f9563095a8ab94e786e370242bff5cd2"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"leb128",
|
"leb128",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wat"
|
name = "wat"
|
||||||
version = "1.0.31"
|
version = "1.0.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a8279a02835bf12e61ed2b3c3cbc6ecf9918762fd97e036917c11a09ec20ca44"
|
checksum = "2a0b3044da73d3b84a822d955afad356759b2fee454b6882722008dace80b68e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wast 30.0.0",
|
"wast 31.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -38,12 +38,12 @@ anyhow = "1.0.19"
|
|||||||
target-lexicon = { version = "0.11.0", default-features = false }
|
target-lexicon = { version = "0.11.0", default-features = false }
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
file-per-thread-logger = "0.1.1"
|
file-per-thread-logger = "0.1.1"
|
||||||
wat = "1.0.30"
|
wat = "1.0.32"
|
||||||
libc = "0.2.60"
|
libc = "0.2.60"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rayon = "1.2.1"
|
rayon = "1.2.1"
|
||||||
humantime = "2.0.0"
|
humantime = "2.0.0"
|
||||||
wasmparser = "0.71.0"
|
wasmparser = "0.72.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.8.1"
|
env_logger = "0.8.1"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ peepmatic-traits = { path = "../peepmatic/crates/traits", optional = true, versi
|
|||||||
peepmatic-runtime = { path = "../peepmatic/crates/runtime", optional = true, version = "0.69.0" }
|
peepmatic-runtime = { path = "../peepmatic/crates/runtime", optional = true, version = "0.69.0" }
|
||||||
regalloc = { version = "0.0.31" }
|
regalloc = { version = "0.0.31" }
|
||||||
souper-ir = { version = "2.1.0", optional = true }
|
souper-ir = { version = "2.1.0", optional = true }
|
||||||
wast = { version = "29.0.0", optional = true }
|
wast = { version = "31.0.0", optional = true }
|
||||||
# It is a goal of the cranelift-codegen crate to have minimal external dependencies.
|
# It is a goal of the cranelift-codegen crate to have minimal external dependencies.
|
||||||
# Please don't add any unless they are essential to the task of creating binary
|
# Please don't add any unless they are essential to the task of creating binary
|
||||||
# machine code. Integration tests that need external dependencies can be
|
# machine code. Integration tests that need external dependencies can be
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ peepmatic-macro = { version = "0.69.0", path = "crates/macro" }
|
|||||||
peepmatic-runtime = { version = "0.69.0", path = "crates/runtime", features = ["construct"] }
|
peepmatic-runtime = { version = "0.69.0", path = "crates/runtime", features = ["construct"] }
|
||||||
peepmatic-traits = { version = "0.69.0", path = "crates/traits" }
|
peepmatic-traits = { version = "0.69.0", path = "crates/traits" }
|
||||||
serde = { version = "1.0.105", features = ["derive"] }
|
serde = { version = "1.0.105", features = ["derive"] }
|
||||||
wast = "29.0.0"
|
wast = "31.0.0"
|
||||||
z3 = { version = "0.7.1", features = ["static-link-z3"] }
|
z3 = { version = "0.7.1", features = ["static-link-z3"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ peepmatic-test-operator = { path = "../test-operator" }
|
|||||||
peepmatic-traits = { path = "../traits" }
|
peepmatic-traits = { path = "../traits" }
|
||||||
rand = { version = "0.7.3", features = ["small_rng"] }
|
rand = { version = "0.7.3", features = ["small_rng"] }
|
||||||
serde = "1.0.106"
|
serde = "1.0.106"
|
||||||
wast = "29.0.0"
|
wast = "31.0.0"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ peepmatic-automata = { version = "0.69.0", path = "../automata", features = ["se
|
|||||||
peepmatic-traits = { version = "0.69.0", path = "../traits" }
|
peepmatic-traits = { version = "0.69.0", path = "../traits" }
|
||||||
serde = { version = "1.0.105", features = ["derive"] }
|
serde = { version = "1.0.105", features = ["derive"] }
|
||||||
thiserror = "1.0.15"
|
thiserror = "1.0.15"
|
||||||
wast = { version = "29.0.0", optional = true }
|
wast = { version = "31.0.0", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
peepmatic-test-operator = { version = "0.69.0", path = "../test-operator" }
|
peepmatic-test-operator = { version = "0.69.0", path = "../test-operator" }
|
||||||
|
|||||||
@@ -16,4 +16,4 @@ log = "0.4.8"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
peepmatic = { path = "../..", version = "0.69.0" }
|
peepmatic = { path = "../..", version = "0.69.0" }
|
||||||
peepmatic-test-operator = { version = "0.69.0", path = "../test-operator" }
|
peepmatic-test-operator = { version = "0.69.0", path = "../test-operator" }
|
||||||
wast = "29.0.0"
|
wast = "31.0.0"
|
||||||
|
|||||||
@@ -11,4 +11,4 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
peepmatic-traits = { version = "0.69.0", path = "../traits" }
|
peepmatic-traits = { version = "0.69.0", path = "../traits" }
|
||||||
serde = { version = "1.0.105", features = ["derive"] }
|
serde = { version = "1.0.105", features = ["derive"] }
|
||||||
wast = "29.0.0"
|
wast = "31.0.0"
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ keywords = ["webassembly", "wasm"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmparser = { version = "0.71", default-features = false }
|
wasmparser = { version = "0.72", default-features = false }
|
||||||
cranelift-codegen = { path = "../codegen", version = "0.69.0", default-features = false }
|
cranelift-codegen = { path = "../codegen", version = "0.69.0", default-features = false }
|
||||||
cranelift-entity = { path = "../entity", version = "0.69.0" }
|
cranelift-entity = { path = "../entity", version = "0.69.0" }
|
||||||
cranelift-frontend = { path = "../frontend", version = "0.69.0", default-features = false }
|
cranelift-frontend = { path = "../frontend", version = "0.69.0", default-features = false }
|
||||||
|
|||||||
@@ -205,25 +205,34 @@ pub enum ReturnMode {
|
|||||||
|
|
||||||
/// An entry in the alias section of a wasm module (from the module linking
|
/// An entry in the alias section of a wasm module (from the module linking
|
||||||
/// proposal)
|
/// proposal)
|
||||||
pub enum Alias {
|
pub enum Alias<'a> {
|
||||||
/// A parent's module is being aliased into our own index space.
|
/// An outer module's module is being aliased into our own index space.
|
||||||
///
|
OuterModule {
|
||||||
/// Note that the index here is in the parent's index space, not our own.
|
/// The number of modules above us that we're referencing.
|
||||||
ParentModule(ModuleIndex),
|
relative_depth: u32,
|
||||||
|
/// The module index in the outer module's index space we're referencing.
|
||||||
|
index: ModuleIndex,
|
||||||
|
},
|
||||||
|
|
||||||
/// A parent's type is being aliased into our own index space
|
/// An outer module's type is being aliased into our own index space
|
||||||
///
|
///
|
||||||
/// Note that the index here is in the parent's index space, not our own.
|
/// Note that the index here is in the outer module's index space, not our
|
||||||
ParentType(TypeIndex),
|
/// own.
|
||||||
|
OuterType {
|
||||||
|
/// The number of modules above us that we're referencing.
|
||||||
|
relative_depth: u32,
|
||||||
|
/// The type index in the outer module's index space we're referencing.
|
||||||
|
index: TypeIndex,
|
||||||
|
},
|
||||||
|
|
||||||
/// A previously created instance is having one of its exports aliased into
|
/// A previously created instance is having one of its exports aliased into
|
||||||
/// our index space.
|
/// our index space.
|
||||||
Child {
|
InstanceExport {
|
||||||
/// The index we're aliasing.
|
/// The index we're aliasing.
|
||||||
instance: InstanceIndex,
|
instance: InstanceIndex,
|
||||||
/// The nth export that we're inserting into our own index space
|
/// The nth export that we're inserting into our own index space
|
||||||
/// locally.
|
/// locally.
|
||||||
export: usize,
|
export: &'a str,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,30 +1023,15 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
|
|||||||
drop(amount);
|
drop(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declares that a module will come later with the type signature provided.
|
|
||||||
fn declare_module(&mut self, ty: TypeIndex) -> WasmResult<()> {
|
|
||||||
drop(ty);
|
|
||||||
Err(WasmError::Unsupported("module linking".to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called at the beginning of translating a module.
|
/// Called at the beginning of translating a module.
|
||||||
///
|
///
|
||||||
/// The `index` argument is a monotonically increasing index which
|
|
||||||
/// corresponds to the nth module that's being translated. This is not the
|
|
||||||
/// 32-bit index in the current module's index space. For example the first
|
|
||||||
/// call to `module_start` will have index 0.
|
|
||||||
///
|
|
||||||
/// Note that for nested modules this may be called multiple times.
|
/// Note that for nested modules this may be called multiple times.
|
||||||
fn module_start(&mut self, index: usize) {
|
fn module_start(&mut self) {}
|
||||||
drop(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called at the end of translating a module.
|
/// Called at the end of translating a module.
|
||||||
///
|
///
|
||||||
/// Note that for nested modules this may be called multiple times.
|
/// Note that for nested modules this may be called multiple times.
|
||||||
fn module_end(&mut self, index: usize) {
|
fn module_end(&mut self) {}
|
||||||
drop(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicates that this module will have `amount` instances.
|
/// Indicates that this module will have `amount` instances.
|
||||||
fn reserve_instances(&mut self, amount: u32) {
|
fn reserve_instances(&mut self, amount: u32) {
|
||||||
@@ -1046,7 +1040,11 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
|
|||||||
|
|
||||||
/// Declares a new instance which this module will instantiate before it's
|
/// Declares a new instance which this module will instantiate before it's
|
||||||
/// instantiated.
|
/// instantiated.
|
||||||
fn declare_instance(&mut self, module: ModuleIndex, args: Vec<EntityIndex>) -> WasmResult<()> {
|
fn declare_instance(
|
||||||
|
&mut self,
|
||||||
|
module: ModuleIndex,
|
||||||
|
args: Vec<(&'data str, EntityIndex)>,
|
||||||
|
) -> WasmResult<()> {
|
||||||
drop((module, args));
|
drop((module, args));
|
||||||
Err(WasmError::Unsupported("wasm instance".to_string()))
|
Err(WasmError::Unsupported("wasm instance".to_string()))
|
||||||
}
|
}
|
||||||
@@ -1056,7 +1054,7 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
|
|||||||
/// The alias comes from the `instance` specified (or the parent if `None`
|
/// The alias comes from the `instance` specified (or the parent if `None`
|
||||||
/// is supplied) and the index is either in the module's own index spaces
|
/// is supplied) and the index is either in the module's own index spaces
|
||||||
/// for the parent or an index into the exports for nested instances.
|
/// for the parent or an index into the exports for nested instances.
|
||||||
fn declare_alias(&mut self, alias: Alias) -> WasmResult<()> {
|
fn declare_alias(&mut self, alias: Alias<'data>) -> WasmResult<()> {
|
||||||
drop(alias);
|
drop(alias);
|
||||||
Err(WasmError::Unsupported("wasm alias".to_string()))
|
Err(WasmError::Unsupported("wasm alias".to_string()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ use crate::environ::{ModuleEnvironment, WasmResult};
|
|||||||
use crate::sections_translator::{
|
use crate::sections_translator::{
|
||||||
parse_alias_section, parse_data_section, parse_element_section, parse_event_section,
|
parse_alias_section, parse_data_section, parse_element_section, parse_event_section,
|
||||||
parse_export_section, parse_function_section, parse_global_section, parse_import_section,
|
parse_export_section, parse_function_section, parse_global_section, parse_import_section,
|
||||||
parse_instance_section, parse_memory_section, parse_module_section, parse_name_section,
|
parse_instance_section, parse_memory_section, parse_name_section, parse_start_section,
|
||||||
parse_start_section, parse_table_section, parse_type_section,
|
parse_table_section, parse_type_section,
|
||||||
};
|
};
|
||||||
use crate::state::ModuleTranslationState;
|
use crate::state::ModuleTranslationState;
|
||||||
use cranelift_codegen::timing;
|
use cranelift_codegen::timing;
|
||||||
@@ -22,23 +22,16 @@ pub fn translate_module<'data>(
|
|||||||
let mut module_translation_state = ModuleTranslationState::new();
|
let mut module_translation_state = ModuleTranslationState::new();
|
||||||
let mut validator = Validator::new();
|
let mut validator = Validator::new();
|
||||||
validator.wasm_features(environ.wasm_features());
|
validator.wasm_features(environ.wasm_features());
|
||||||
let mut stack = Vec::new();
|
|
||||||
let mut modules = 1;
|
|
||||||
let mut cur_module = 0;
|
|
||||||
|
|
||||||
for payload in Parser::new(0).parse_all(data) {
|
for payload in Parser::new(0).parse_all(data) {
|
||||||
match payload? {
|
match payload? {
|
||||||
Payload::Version { num, range } => {
|
Payload::Version { num, range } => {
|
||||||
validator.version(num, &range)?;
|
validator.version(num, &range)?;
|
||||||
environ.module_start(cur_module);
|
environ.module_start();
|
||||||
}
|
}
|
||||||
Payload::End => {
|
Payload::End => {
|
||||||
validator.end()?;
|
validator.end()?;
|
||||||
environ.module_end(cur_module);
|
environ.module_end();
|
||||||
if let Some((other, other_index)) = stack.pop() {
|
|
||||||
validator = other;
|
|
||||||
cur_module = other_index;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Payload::TypeSection(types) => {
|
Payload::TypeSection(types) => {
|
||||||
@@ -111,10 +104,6 @@ pub fn translate_module<'data>(
|
|||||||
environ.reserve_passive_data(count)?;
|
environ.reserve_passive_data(count)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Payload::ModuleSection(s) => {
|
|
||||||
validator.module_section(&s)?;
|
|
||||||
parse_module_section(s, environ)?;
|
|
||||||
}
|
|
||||||
Payload::InstanceSection(s) => {
|
Payload::InstanceSection(s) => {
|
||||||
validator.instance_section(&s)?;
|
validator.instance_section(&s)?;
|
||||||
parse_instance_section(s, environ)?;
|
parse_instance_section(s, environ)?;
|
||||||
@@ -123,20 +112,17 @@ pub fn translate_module<'data>(
|
|||||||
validator.alias_section(&s)?;
|
validator.alias_section(&s)?;
|
||||||
parse_alias_section(s, environ)?;
|
parse_alias_section(s, environ)?;
|
||||||
}
|
}
|
||||||
Payload::ModuleCodeSectionStart {
|
Payload::ModuleSectionStart {
|
||||||
count,
|
count,
|
||||||
range,
|
range,
|
||||||
size: _,
|
size: _,
|
||||||
} => {
|
} => {
|
||||||
validator.module_code_section_start(count, &range)?;
|
validator.module_section_start(count, &range)?;
|
||||||
|
environ.reserve_modules(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
Payload::ModuleCodeSectionEntry { .. } => {
|
Payload::ModuleSectionEntry { .. } => {
|
||||||
let subvalidator = validator.module_code_section_entry();
|
validator.module_section_entry();
|
||||||
stack.push((validator, cur_module));
|
|
||||||
validator = subvalidator;
|
|
||||||
cur_module = modules;
|
|
||||||
modules += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Payload::CustomSection {
|
Payload::CustomSection {
|
||||||
|
|||||||
@@ -504,19 +504,6 @@ pub fn parse_name_section<'data>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the Module section of the wasm module.
|
|
||||||
pub fn parse_module_section<'data>(
|
|
||||||
section: wasmparser::ModuleSectionReader<'data>,
|
|
||||||
environ: &mut dyn ModuleEnvironment<'data>,
|
|
||||||
) -> WasmResult<()> {
|
|
||||||
environ.reserve_modules(section.get_count());
|
|
||||||
|
|
||||||
for module_ty in section {
|
|
||||||
environ.declare_module(TypeIndex::from_u32(module_ty?))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parses the Instance section of the wasm module.
|
/// Parses the Instance section of the wasm module.
|
||||||
pub fn parse_instance_section<'data>(
|
pub fn parse_instance_section<'data>(
|
||||||
section: wasmparser::InstanceSectionReader<'data>,
|
section: wasmparser::InstanceSectionReader<'data>,
|
||||||
@@ -530,20 +517,23 @@ pub fn parse_instance_section<'data>(
|
|||||||
let args = instance
|
let args = instance
|
||||||
.args()?
|
.args()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|result| {
|
.map(|arg| {
|
||||||
let (kind, idx) = result?;
|
let arg = arg?;
|
||||||
Ok(match kind {
|
let index = match arg.kind {
|
||||||
ExternalKind::Function => EntityIndex::Function(FuncIndex::from_u32(idx)),
|
ExternalKind::Function => EntityIndex::Function(FuncIndex::from_u32(arg.index)),
|
||||||
ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(idx)),
|
ExternalKind::Table => EntityIndex::Table(TableIndex::from_u32(arg.index)),
|
||||||
ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(idx)),
|
ExternalKind::Memory => EntityIndex::Memory(MemoryIndex::from_u32(arg.index)),
|
||||||
ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(idx)),
|
ExternalKind::Global => EntityIndex::Global(GlobalIndex::from_u32(arg.index)),
|
||||||
ExternalKind::Module => EntityIndex::Module(ModuleIndex::from_u32(idx)),
|
ExternalKind::Module => EntityIndex::Module(ModuleIndex::from_u32(arg.index)),
|
||||||
ExternalKind::Instance => EntityIndex::Instance(InstanceIndex::from_u32(idx)),
|
ExternalKind::Instance => {
|
||||||
|
EntityIndex::Instance(InstanceIndex::from_u32(arg.index))
|
||||||
|
}
|
||||||
ExternalKind::Event => unimplemented!(),
|
ExternalKind::Event => unimplemented!(),
|
||||||
|
|
||||||
// this won't pass validation
|
// this won't pass validation
|
||||||
ExternalKind::Type => unreachable!(),
|
ExternalKind::Type => unreachable!(),
|
||||||
})
|
};
|
||||||
|
Ok((arg.name, index))
|
||||||
})
|
})
|
||||||
.collect::<WasmResult<Vec<_>>>()?;
|
.collect::<WasmResult<Vec<_>>>()?;
|
||||||
environ.declare_instance(module, args)?;
|
environ.declare_instance(module, args)?;
|
||||||
@@ -557,19 +547,28 @@ pub fn parse_alias_section<'data>(
|
|||||||
environ: &mut dyn ModuleEnvironment<'data>,
|
environ: &mut dyn ModuleEnvironment<'data>,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
for alias in section {
|
for alias in section {
|
||||||
let alias = alias?;
|
let alias = match alias? {
|
||||||
let alias = match alias.instance {
|
wasmparser::Alias::OuterType {
|
||||||
wasmparser::AliasedInstance::Parent => {
|
relative_depth,
|
||||||
match alias.kind {
|
index,
|
||||||
ExternalKind::Module => Alias::ParentModule(ModuleIndex::from_u32(alias.index)),
|
} => Alias::OuterType {
|
||||||
ExternalKind::Type => Alias::ParentType(TypeIndex::from_u32(alias.index)),
|
relative_depth,
|
||||||
// shouldn't get past validation
|
index: TypeIndex::from_u32(index),
|
||||||
_ => unreachable!(),
|
},
|
||||||
}
|
wasmparser::Alias::OuterModule {
|
||||||
}
|
relative_depth,
|
||||||
wasmparser::AliasedInstance::Child(i) => Alias::Child {
|
index,
|
||||||
instance: InstanceIndex::from_u32(i),
|
} => Alias::OuterModule {
|
||||||
export: alias.index as usize,
|
relative_depth,
|
||||||
|
index: ModuleIndex::from_u32(index),
|
||||||
|
},
|
||||||
|
wasmparser::Alias::InstanceExport {
|
||||||
|
instance,
|
||||||
|
export,
|
||||||
|
kind: _,
|
||||||
|
} => Alias::InstanceExport {
|
||||||
|
instance: InstanceIndex::from_u32(instance),
|
||||||
|
export,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
environ.declare_alias(alias)?;
|
environ.declare_alias(alias)?;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gimli = "0.23.0"
|
gimli = "0.23.0"
|
||||||
wasmparser = "0.71"
|
wasmparser = "0.72"
|
||||||
object = { version = "0.22.0", default-features = false, features = ["read_core", "elf", "write"] }
|
object = { version = "0.22.0", default-features = false, features = ["read_core", "elf", "write"] }
|
||||||
wasmtime-environ = { path = "../environ", version = "0.22.0" }
|
wasmtime-environ = { path = "../environ", version = "0.22.0" }
|
||||||
target-lexicon = { version = "0.11.0", default-features = false }
|
target-lexicon = { version = "0.11.0", default-features = false }
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ anyhow = "1.0"
|
|||||||
cranelift-codegen = { path = "../../cranelift/codegen", version = "0.69.0", features = ["enable-serde"] }
|
cranelift-codegen = { path = "../../cranelift/codegen", version = "0.69.0", features = ["enable-serde"] }
|
||||||
cranelift-entity = { path = "../../cranelift/entity", version = "0.69.0", features = ["enable-serde"] }
|
cranelift-entity = { path = "../../cranelift/entity", version = "0.69.0", features = ["enable-serde"] }
|
||||||
cranelift-wasm = { path = "../../cranelift/wasm", version = "0.69.0", features = ["enable-serde"] }
|
cranelift-wasm = { path = "../../cranelift/wasm", version = "0.69.0", features = ["enable-serde"] }
|
||||||
wasmparser = "0.71"
|
wasmparser = "0.72"
|
||||||
indexmap = { version = "1.0.2", features = ["serde-1"] }
|
indexmap = { version = "1.0.2", features = ["serde-1"] }
|
||||||
thiserror = "1.0.4"
|
thiserror = "1.0.4"
|
||||||
serde = { version = "1.0.94", features = ["derive"] }
|
serde = { version = "1.0.94", features = ["derive"] }
|
||||||
|
|||||||
@@ -142,12 +142,6 @@ impl ModuleType {
|
|||||||
/// memory initializers.
|
/// memory initializers.
|
||||||
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
/// The parent index of this module, used for the module linking proposal.
|
|
||||||
///
|
|
||||||
/// This index is into the list of modules returned from compilation of a
|
|
||||||
/// single wasm file with nested modules.
|
|
||||||
pub parent: Option<usize>,
|
|
||||||
|
|
||||||
/// The name of this wasm module, often found in the wasm file.
|
/// The name of this wasm module, often found in the wasm file.
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
|
||||||
@@ -213,25 +207,26 @@ pub struct Module {
|
|||||||
pub enum Initializer {
|
pub enum Initializer {
|
||||||
/// An imported item is required to be provided.
|
/// An imported item is required to be provided.
|
||||||
Import {
|
Import {
|
||||||
/// Module name of this import
|
/// Name of this import
|
||||||
module: String,
|
name: String,
|
||||||
/// Optional field name of this import
|
/// The field name projection of this import. When module-linking is
|
||||||
|
/// enabled this is always `None`. Otherwise this is always `Some`.
|
||||||
field: Option<String>,
|
field: Option<String>,
|
||||||
/// Where this import will be placed, which also has type information
|
/// Where this import will be placed, which also has type information
|
||||||
/// about the import.
|
/// about the import.
|
||||||
index: EntityIndex,
|
index: EntityIndex,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// A module from the parent's declared modules is inserted into our own
|
/// An export from a previously defined instance is being inserted into our
|
||||||
/// index space.
|
/// index space.
|
||||||
AliasParentModule(ModuleIndex),
|
///
|
||||||
|
/// Note that when the module linking proposal is enabled two-level imports
|
||||||
/// A module from the parent's declared modules is inserted into our own
|
/// will implicitly desugar to this initializer.
|
||||||
/// index space.
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
AliasInstanceExport {
|
AliasInstanceExport {
|
||||||
|
/// The instance that we're referencing.
|
||||||
instance: InstanceIndex,
|
instance: InstanceIndex,
|
||||||
export: usize,
|
/// Which export is being inserted into our index space.
|
||||||
|
export: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// A module is being instantiated with previously configured intializers
|
/// A module is being instantiated with previously configured intializers
|
||||||
@@ -239,8 +234,9 @@ pub enum Initializer {
|
|||||||
Instantiate {
|
Instantiate {
|
||||||
/// The module that this instance is instantiating.
|
/// The module that this instance is instantiating.
|
||||||
module: ModuleIndex,
|
module: ModuleIndex,
|
||||||
/// The arguments provided to instantiation.
|
/// The arguments provided to instantiation, along with their name in
|
||||||
args: Vec<EntityIndex>,
|
/// the instance being instantiated.
|
||||||
|
args: IndexMap<String, EntityIndex>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// A module is defined into the module index space, and which module is
|
/// A module is defined into the module index space, and which module is
|
||||||
@@ -351,11 +347,9 @@ impl Module {
|
|||||||
/// module name, field name, and type that's being imported.
|
/// module name, field name, and type that's being imported.
|
||||||
pub fn imports(&self) -> impl Iterator<Item = (&str, Option<&str>, EntityType)> {
|
pub fn imports(&self) -> impl Iterator<Item = (&str, Option<&str>, EntityType)> {
|
||||||
self.initializers.iter().filter_map(move |i| match i {
|
self.initializers.iter().filter_map(move |i| match i {
|
||||||
Initializer::Import {
|
Initializer::Import { name, field, index } => {
|
||||||
module,
|
Some((name.as_str(), field.as_deref(), self.type_of(*index)))
|
||||||
field,
|
}
|
||||||
index,
|
|
||||||
} => Some((module.as_str(), field.as_deref(), self.type_of(*index))),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -389,16 +383,16 @@ pub struct TypeTables {
|
|||||||
/// The type signature of known modules.
|
/// The type signature of known modules.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ModuleSignature {
|
pub struct ModuleSignature {
|
||||||
/// All imports in this module, listed in order with their module/name and
|
/// All imports in this module, listed in order with their name and
|
||||||
/// what type they're importing.
|
/// what type they're importing.
|
||||||
pub imports: Vec<(String, Option<String>, EntityType)>,
|
pub imports: IndexMap<String, EntityType>,
|
||||||
/// Exports are what an instance type conveys, so we go through an
|
/// Exports are what an instance type conveys, so we go through an
|
||||||
/// indirection over there.
|
/// indirection over there.
|
||||||
pub exports: InstanceTypeIndex,
|
pub exports: InstanceTypeIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type signature of known instances.
|
/// The type signature of known instances.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
pub struct InstanceSignature {
|
pub struct InstanceSignature {
|
||||||
/// The name of what's being exported as well as its type signature.
|
/// The name of what's being exported as well as its type signature.
|
||||||
pub exports: IndexMap<String, EntityType>,
|
pub exports: IndexMap<String, EntityType>,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use cranelift_wasm::{
|
|||||||
WasmError, WasmFuncType, WasmResult,
|
WasmError, WasmFuncType, WasmResult,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::{hash_map::Entry, HashMap};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -31,6 +31,10 @@ pub struct ModuleEnvironment<'data> {
|
|||||||
/// the module linking proposal.
|
/// the module linking proposal.
|
||||||
results: Vec<ModuleTranslation<'data>>,
|
results: Vec<ModuleTranslation<'data>>,
|
||||||
|
|
||||||
|
/// Modules which are in-progress being translated, or otherwise also known
|
||||||
|
/// as the outer modules of the current module being processed.
|
||||||
|
in_progress: Vec<ModuleTranslation<'data>>,
|
||||||
|
|
||||||
/// How many modules that have not yet made their way into `results` which
|
/// How many modules that have not yet made their way into `results` which
|
||||||
/// are coming at some point.
|
/// are coming at some point.
|
||||||
modules_to_be: usize,
|
modules_to_be: usize,
|
||||||
@@ -38,13 +42,11 @@ pub struct ModuleEnvironment<'data> {
|
|||||||
/// Intern'd types for this entire translation, shared by all modules.
|
/// Intern'd types for this entire translation, shared by all modules.
|
||||||
types: TypeTables,
|
types: TypeTables,
|
||||||
|
|
||||||
/// Where our module will get pushed into `results` after it's finished.
|
|
||||||
cur: usize,
|
|
||||||
|
|
||||||
// Various bits and pieces of configuration
|
// Various bits and pieces of configuration
|
||||||
features: WasmFeatures,
|
features: WasmFeatures,
|
||||||
target_config: TargetFrontendConfig,
|
target_config: TargetFrontendConfig,
|
||||||
tunables: Tunables,
|
tunables: Tunables,
|
||||||
|
first_module: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of translating via `ModuleEnvironment`. Function bodies are not
|
/// The result of translating via `ModuleEnvironment`. Function bodies are not
|
||||||
@@ -72,15 +74,7 @@ pub struct ModuleTranslation<'data> {
|
|||||||
/// which function is currently being defined.
|
/// which function is currently being defined.
|
||||||
code_index: u32,
|
code_index: u32,
|
||||||
|
|
||||||
/// When local modules are declared an entry is pushed onto this list which
|
implicit_instances: HashMap<&'data str, InstanceIndex>,
|
||||||
/// indicates that the initializer at the specified position needs to be
|
|
||||||
/// rewritten with the module's final index in the global list of compiled
|
|
||||||
/// modules.
|
|
||||||
module_initializer_indexes: Vec<usize>,
|
|
||||||
|
|
||||||
/// Used as a pointer into the above list as the module code section is
|
|
||||||
/// parsed.
|
|
||||||
num_modules_defined: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains function data: byte code and its offset in the module.
|
/// Contains function data: byte code and its offset in the module.
|
||||||
@@ -142,12 +136,13 @@ impl<'data> ModuleEnvironment<'data> {
|
|||||||
Self {
|
Self {
|
||||||
result: ModuleTranslation::default(),
|
result: ModuleTranslation::default(),
|
||||||
results: Vec::with_capacity(1),
|
results: Vec::with_capacity(1),
|
||||||
|
in_progress: Vec::new(),
|
||||||
modules_to_be: 1,
|
modules_to_be: 1,
|
||||||
cur: 0,
|
|
||||||
types: Default::default(),
|
types: Default::default(),
|
||||||
target_config,
|
target_config,
|
||||||
tunables: tunables.clone(),
|
tunables: tunables.clone(),
|
||||||
features: *features,
|
features: *features,
|
||||||
|
first_module: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +158,8 @@ impl<'data> ModuleEnvironment<'data> {
|
|||||||
/// Note that for MVP modules this will always be a list with one element,
|
/// Note that for MVP modules this will always be a list with one element,
|
||||||
/// but with the module linking proposal this may have many elements.
|
/// but with the module linking proposal this may have many elements.
|
||||||
///
|
///
|
||||||
/// For the module linking proposal the top-level module is at index 0.
|
/// For the module linking proposal the top-level module is returned as the
|
||||||
|
/// first return value.
|
||||||
///
|
///
|
||||||
/// The `TypeTables` structure returned contains intern'd versions of types
|
/// The `TypeTables` structure returned contains intern'd versions of types
|
||||||
/// referenced from each module translation. This primarily serves as the
|
/// referenced from each module translation. This primarily serves as the
|
||||||
@@ -173,10 +169,10 @@ impl<'data> ModuleEnvironment<'data> {
|
|||||||
pub fn translate(
|
pub fn translate(
|
||||||
mut self,
|
mut self,
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
) -> WasmResult<(Vec<ModuleTranslation<'data>>, TypeTables)> {
|
) -> WasmResult<(usize, Vec<ModuleTranslation<'data>>, TypeTables)> {
|
||||||
translate_module(data, &mut self)?;
|
translate_module(data, &mut self)?;
|
||||||
assert!(self.results.len() > 0);
|
assert!(self.results.len() > 0);
|
||||||
Ok((self.results, self.types))
|
Ok((self.results.len() - 1, self.results, self.types))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_export(&mut self, export: EntityIndex, name: &str) -> WasmResult<()> {
|
fn declare_export(&mut self, export: EntityIndex, name: &str) -> WasmResult<()> {
|
||||||
@@ -224,6 +220,137 @@ impl<'data> ModuleEnvironment<'data> {
|
|||||||
dwarf.ranges = gimli::RangeLists::new(info.debug_ranges, info.debug_rnglists);
|
dwarf.ranges = gimli::RangeLists::new(info.debug_ranges, info.debug_rnglists);
|
||||||
dwarf.locations = gimli::LocationLists::new(info.debug_loc, info.debug_loclists);
|
dwarf.locations = gimli::LocationLists::new(info.debug_loc, info.debug_loclists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Declares a new import with the `module` and `field` names, importing the
|
||||||
|
/// `ty` specified.
|
||||||
|
///
|
||||||
|
/// Note that this method is somewhat tricky due to the implementation of
|
||||||
|
/// the module linking proposal. In the module linking proposal two-level
|
||||||
|
/// imports are recast as single-level imports of instances. That recasting
|
||||||
|
/// happens here by recording an import of an instance for the first time
|
||||||
|
/// we see a two-level import.
|
||||||
|
///
|
||||||
|
/// When the module linking proposal is disabled, however, disregard this
|
||||||
|
/// logic and instead work directly with two-level imports since no
|
||||||
|
/// instances are defined.
|
||||||
|
fn declare_import(&mut self, module: &'data str, field: Option<&'data str>, ty: EntityType) {
|
||||||
|
if !self.features.module_linking {
|
||||||
|
assert!(field.is_some());
|
||||||
|
let index = self.push_type(ty);
|
||||||
|
self.result.module.initializers.push(Initializer::Import {
|
||||||
|
name: module.to_owned(),
|
||||||
|
field: field.map(|s| s.to_string()),
|
||||||
|
index,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match field {
|
||||||
|
Some(field) => {
|
||||||
|
// If this is a two-level import then this is actually an
|
||||||
|
// implicit import of an instance, where each two-level import
|
||||||
|
// is an alias directive from the original instance. The first
|
||||||
|
// thing we do here is lookup our implicit instance, creating a
|
||||||
|
// blank one if it wasn't already created.
|
||||||
|
let instance = match self.result.implicit_instances.entry(module) {
|
||||||
|
Entry::Occupied(e) => *e.get(),
|
||||||
|
Entry::Vacant(v) => {
|
||||||
|
let ty = self
|
||||||
|
.types
|
||||||
|
.instance_signatures
|
||||||
|
.push(InstanceSignature::default());
|
||||||
|
let idx = self.result.module.instances.push(ty);
|
||||||
|
self.result.module.initializers.push(Initializer::Import {
|
||||||
|
name: module.to_owned(),
|
||||||
|
field: None,
|
||||||
|
index: EntityIndex::Instance(idx),
|
||||||
|
});
|
||||||
|
*v.insert(idx)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update the implicit instance's type signature with this new
|
||||||
|
// field and its type.
|
||||||
|
self.types.instance_signatures[self.result.module.instances[instance]]
|
||||||
|
.exports
|
||||||
|
.insert(field.to_string(), ty.clone());
|
||||||
|
|
||||||
|
// Record our implicit alias annotation which corresponds to
|
||||||
|
// this import that we're processing.
|
||||||
|
self.result
|
||||||
|
.module
|
||||||
|
.initializers
|
||||||
|
.push(Initializer::AliasInstanceExport {
|
||||||
|
instance,
|
||||||
|
export: field.to_string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// And then record the type information for the item that we're
|
||||||
|
// processing.
|
||||||
|
self.push_type(ty);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// Without a field then this is a single-level import (a feature
|
||||||
|
// of module linking) which means we're simply importing that
|
||||||
|
// name with the specified type. Record the type information and
|
||||||
|
// then the name that we're importing.
|
||||||
|
let index = self.push_type(ty);
|
||||||
|
self.result.module.initializers.push(Initializer::Import {
|
||||||
|
name: module.to_owned(),
|
||||||
|
field: None,
|
||||||
|
index,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_type(&mut self, ty: EntityType) -> EntityIndex {
|
||||||
|
match ty {
|
||||||
|
EntityType::Function(ty) => {
|
||||||
|
EntityIndex::Function(self.result.module.functions.push(ty))
|
||||||
|
}
|
||||||
|
EntityType::Table(ty) => {
|
||||||
|
let plan = TablePlan::for_table(ty, &self.tunables);
|
||||||
|
EntityIndex::Table(self.result.module.table_plans.push(plan))
|
||||||
|
}
|
||||||
|
EntityType::Memory(ty) => {
|
||||||
|
let plan = MemoryPlan::for_memory(ty, &self.tunables);
|
||||||
|
EntityIndex::Memory(self.result.module.memory_plans.push(plan))
|
||||||
|
}
|
||||||
|
EntityType::Global(ty) => EntityIndex::Global(self.result.module.globals.push(ty)),
|
||||||
|
EntityType::Instance(ty) => {
|
||||||
|
EntityIndex::Instance(self.result.module.instances.push(ty))
|
||||||
|
}
|
||||||
|
EntityType::Module(ty) => EntityIndex::Module(self.result.module.modules.push(ty)),
|
||||||
|
EntityType::Event(_) => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_type_of_module(&mut self, module: usize) -> ModuleTypeIndex {
|
||||||
|
let module = &self.results[module].module;
|
||||||
|
let imports = module
|
||||||
|
.imports()
|
||||||
|
.map(|(s, field, ty)| {
|
||||||
|
assert!(field.is_none());
|
||||||
|
(s.to_string(), ty)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let exports = module
|
||||||
|
.exports
|
||||||
|
.iter()
|
||||||
|
.map(|(name, idx)| (name.clone(), module.type_of(*idx)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// FIXME(#2469): this instance/module signature insertion should likely
|
||||||
|
// be deduplicated.
|
||||||
|
let exports = self
|
||||||
|
.types
|
||||||
|
.instance_signatures
|
||||||
|
.push(InstanceSignature { exports });
|
||||||
|
self.types
|
||||||
|
.module_signatures
|
||||||
|
.push(ModuleSignature { imports, exports })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'data> TargetEnvironment for ModuleEnvironment<'data> {
|
impl<'data> TargetEnvironment for ModuleEnvironment<'data> {
|
||||||
@@ -267,13 +394,29 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
|
|
||||||
fn declare_type_module(
|
fn declare_type_module(
|
||||||
&mut self,
|
&mut self,
|
||||||
imports: &[(&'data str, Option<&'data str>, EntityType)],
|
declared_imports: &[(&'data str, Option<&'data str>, EntityType)],
|
||||||
exports: &[(&'data str, EntityType)],
|
exports: &[(&'data str, EntityType)],
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
let imports = imports
|
let mut imports = indexmap::IndexMap::new();
|
||||||
.iter()
|
let mut instance_types = HashMap::new();
|
||||||
.map(|i| (i.0.to_string(), i.1.map(|s| s.to_string()), i.2.clone()))
|
for (module, field, ty) in declared_imports {
|
||||||
.collect();
|
match field {
|
||||||
|
Some(field) => {
|
||||||
|
let idx = *instance_types
|
||||||
|
.entry(module)
|
||||||
|
.or_insert_with(|| self.types.instance_signatures.push(Default::default()));
|
||||||
|
self.types.instance_signatures[idx]
|
||||||
|
.exports
|
||||||
|
.insert(field.to_string(), ty.clone());
|
||||||
|
if !imports.contains_key(*module) {
|
||||||
|
imports.insert(module.to_string(), EntityType::Instance(idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
imports.insert(module.to_string(), ty.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let exports = exports
|
let exports = exports
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| (e.0.to_string(), e.1.clone()))
|
.map(|e| (e.0.to_string(), e.1.clone()))
|
||||||
@@ -344,8 +487,8 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
fn declare_func_import(
|
fn declare_func_import(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: TypeIndex,
|
index: TypeIndex,
|
||||||
module: &str,
|
module: &'data str,
|
||||||
field: Option<&str>,
|
field: Option<&'data str>,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.result.module.functions.len(),
|
self.result.module.functions.len(),
|
||||||
@@ -353,12 +496,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
"Imported functions must be declared first"
|
"Imported functions must be declared first"
|
||||||
);
|
);
|
||||||
let sig_index = self.result.module.types[index].unwrap_function();
|
let sig_index = self.result.module.types[index].unwrap_function();
|
||||||
let func_index = self.result.module.functions.push(sig_index);
|
self.declare_import(module, field, EntityType::Function(sig_index));
|
||||||
self.result.module.initializers.push(Initializer::Import {
|
|
||||||
module: module.to_owned(),
|
|
||||||
field: field.map(|s| s.to_owned()),
|
|
||||||
index: EntityIndex::Function(func_index),
|
|
||||||
});
|
|
||||||
self.result.module.num_imported_funcs += 1;
|
self.result.module.num_imported_funcs += 1;
|
||||||
self.result.debuginfo.wasm_file.imported_func_count += 1;
|
self.result.debuginfo.wasm_file.imported_func_count += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -367,21 +505,15 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
fn declare_table_import(
|
fn declare_table_import(
|
||||||
&mut self,
|
&mut self,
|
||||||
table: Table,
|
table: Table,
|
||||||
module: &str,
|
module: &'data str,
|
||||||
field: Option<&str>,
|
field: Option<&'data str>,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.result.module.table_plans.len(),
|
self.result.module.table_plans.len(),
|
||||||
self.result.module.num_imported_tables,
|
self.result.module.num_imported_tables,
|
||||||
"Imported tables must be declared first"
|
"Imported tables must be declared first"
|
||||||
);
|
);
|
||||||
let plan = TablePlan::for_table(table, &self.tunables);
|
self.declare_import(module, field, EntityType::Table(table));
|
||||||
let table_index = self.result.module.table_plans.push(plan);
|
|
||||||
self.result.module.initializers.push(Initializer::Import {
|
|
||||||
module: module.to_owned(),
|
|
||||||
field: field.map(|s| s.to_owned()),
|
|
||||||
index: EntityIndex::Table(table_index),
|
|
||||||
});
|
|
||||||
self.result.module.num_imported_tables += 1;
|
self.result.module.num_imported_tables += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -389,8 +521,8 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
fn declare_memory_import(
|
fn declare_memory_import(
|
||||||
&mut self,
|
&mut self,
|
||||||
memory: Memory,
|
memory: Memory,
|
||||||
module: &str,
|
module: &'data str,
|
||||||
field: Option<&str>,
|
field: Option<&'data str>,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.result.module.memory_plans.len(),
|
self.result.module.memory_plans.len(),
|
||||||
@@ -400,13 +532,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
if memory.shared {
|
if memory.shared {
|
||||||
return Err(WasmError::Unsupported("shared memories".to_owned()));
|
return Err(WasmError::Unsupported("shared memories".to_owned()));
|
||||||
}
|
}
|
||||||
let plan = MemoryPlan::for_memory(memory, &self.tunables);
|
self.declare_import(module, field, EntityType::Memory(memory));
|
||||||
let memory_index = self.result.module.memory_plans.push(plan);
|
|
||||||
self.result.module.initializers.push(Initializer::Import {
|
|
||||||
module: module.to_owned(),
|
|
||||||
field: field.map(|s| s.to_owned()),
|
|
||||||
index: EntityIndex::Memory(memory_index),
|
|
||||||
});
|
|
||||||
self.result.module.num_imported_memories += 1;
|
self.result.module.num_imported_memories += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -414,20 +540,15 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
fn declare_global_import(
|
fn declare_global_import(
|
||||||
&mut self,
|
&mut self,
|
||||||
global: Global,
|
global: Global,
|
||||||
module: &str,
|
module: &'data str,
|
||||||
field: Option<&str>,
|
field: Option<&'data str>,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.result.module.globals.len(),
|
self.result.module.globals.len(),
|
||||||
self.result.module.num_imported_globals,
|
self.result.module.num_imported_globals,
|
||||||
"Imported globals must be declared first"
|
"Imported globals must be declared first"
|
||||||
);
|
);
|
||||||
let global_index = self.result.module.globals.push(global);
|
self.declare_import(module, field, EntityType::Global(global));
|
||||||
self.result.module.initializers.push(Initializer::Import {
|
|
||||||
module: module.to_owned(),
|
|
||||||
field: field.map(|s| s.to_owned()),
|
|
||||||
index: EntityIndex::Global(global_index),
|
|
||||||
});
|
|
||||||
self.result.module.num_imported_globals += 1;
|
self.result.module.num_imported_globals += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -439,12 +560,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
field: Option<&'data str>,
|
field: Option<&'data str>,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
let signature = self.type_to_module_type(ty_index)?;
|
let signature = self.type_to_module_type(ty_index)?;
|
||||||
let module_index = self.result.module.modules.push(signature);
|
self.declare_import(module, field, EntityType::Module(signature));
|
||||||
self.result.module.initializers.push(Initializer::Import {
|
|
||||||
module: module.to_owned(),
|
|
||||||
field: field.map(|s| s.to_owned()),
|
|
||||||
index: EntityIndex::Module(module_index),
|
|
||||||
});
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,12 +571,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
field: Option<&'data str>,
|
field: Option<&'data str>,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
let signature = self.type_to_instance_type(ty_index)?;
|
let signature = self.type_to_instance_type(ty_index)?;
|
||||||
let instance_index = self.result.module.instances.push(signature);
|
self.declare_import(module, field, EntityType::Instance(signature));
|
||||||
self.result.module.initializers.push(Initializer::Import {
|
|
||||||
module: module.to_owned(),
|
|
||||||
field: field.map(|s| s.to_owned()),
|
|
||||||
index: EntityIndex::Instance(instance_index),
|
|
||||||
});
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,62 +866,34 @@ and for re-adding support for interface types you can see this issue:
|
|||||||
self.result.module.initializers.reserve(amount as usize);
|
self.result.module.initializers.reserve(amount as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_module(&mut self, ty: TypeIndex) -> WasmResult<()> {
|
fn module_start(&mut self) {
|
||||||
// Record the type signature of this module ...
|
// If this is the first time this method is called, nothing to do.
|
||||||
let signature = self.type_to_module_type(ty)?;
|
if self.first_module {
|
||||||
self.result.module.modules.push(signature);
|
self.first_module = false;
|
||||||
|
return;
|
||||||
// ... and then record that in the initialization steps of this module
|
|
||||||
// we're inserting this module into the module index space. At this
|
|
||||||
// point we don't know the final index of the module we're defining, so
|
|
||||||
// we leave a placeholder to get rewritten later.
|
|
||||||
let loc = self.result.module.initializers.len();
|
|
||||||
self.result
|
|
||||||
.module
|
|
||||||
.initializers
|
|
||||||
.push(Initializer::DefineModule(usize::max_value()));
|
|
||||||
self.result.module_initializer_indexes.push(loc);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn module_start(&mut self, index: usize) {
|
|
||||||
// Reset the contents of `self.result` for a new module that's getting
|
|
||||||
// translataed.
|
|
||||||
let mut prev = mem::replace(&mut self.result, ModuleTranslation::default());
|
|
||||||
|
|
||||||
// If this is a nested submodule then we record the final destination of
|
|
||||||
// the child in parent (we store `index` into `prev`) in the appropriate
|
|
||||||
// initialization slot as dicated by `num_modules_defined` (our index of
|
|
||||||
// iteration through the code section).
|
|
||||||
// Record that the `num_modules_defined`-th module is defined at index
|
|
||||||
// by updating the initializer entry.
|
|
||||||
if index > 0 {
|
|
||||||
let initializer_idx = prev.module_initializer_indexes[prev.num_modules_defined];
|
|
||||||
prev.num_modules_defined += 1;
|
|
||||||
debug_assert!(match &prev.module.initializers[initializer_idx] {
|
|
||||||
Initializer::DefineModule(usize::MAX) => true,
|
|
||||||
_ => false,
|
|
||||||
});
|
|
||||||
prev.module.initializers[initializer_idx] = Initializer::DefineModule(index);
|
|
||||||
self.result.module.parent = Some(self.cur);
|
|
||||||
}
|
}
|
||||||
|
// Reset our internal state for a new module by saving the current
|
||||||
// Update our current index counter and save our parent's translation
|
// module in `results`.
|
||||||
// where this current translation will end up, which we'll swap back as
|
let in_progress = mem::replace(&mut self.result, ModuleTranslation::default());
|
||||||
// part of `module_end`.
|
self.in_progress.push(in_progress);
|
||||||
self.cur = index;
|
|
||||||
assert_eq!(index, self.results.len());
|
|
||||||
self.results.push(prev);
|
|
||||||
self.modules_to_be -= 1;
|
self.modules_to_be -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module_end(&mut self, index: usize) {
|
fn module_end(&mut self) {
|
||||||
assert!(self.result.num_modules_defined == self.result.module_initializer_indexes.len());
|
let (record_initializer, done) = match self.in_progress.pop() {
|
||||||
|
Some(m) => (true, mem::replace(&mut self.result, m)),
|
||||||
// Move our finished module into its final location, swapping it with
|
None => (false, mem::take(&mut self.result)),
|
||||||
// what was this module's parent.
|
};
|
||||||
self.cur = self.result.module.parent.unwrap_or(0);
|
self.results.push(done);
|
||||||
mem::swap(&mut self.result, &mut self.results[index]);
|
if record_initializer {
|
||||||
|
let index = self.results.len() - 1;
|
||||||
|
self.result
|
||||||
|
.module
|
||||||
|
.initializers
|
||||||
|
.push(Initializer::DefineModule(index));
|
||||||
|
let sig = self.gen_type_of_module(index);
|
||||||
|
self.result.module.modules.push(sig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reserve_instances(&mut self, amt: u32) {
|
fn reserve_instances(&mut self, amt: u32) {
|
||||||
@@ -818,7 +901,12 @@ and for re-adding support for interface types you can see this issue:
|
|||||||
self.result.module.initializers.reserve(amt as usize);
|
self.result.module.initializers.reserve(amt as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_instance(&mut self, module: ModuleIndex, args: Vec<EntityIndex>) -> WasmResult<()> {
|
fn declare_instance(
|
||||||
|
&mut self,
|
||||||
|
module: ModuleIndex,
|
||||||
|
args: Vec<(&'data str, EntityIndex)>,
|
||||||
|
) -> WasmResult<()> {
|
||||||
|
let args = args.into_iter().map(|(s, i)| (s.to_string(), i)).collect();
|
||||||
// Record the type of this instance with the type signature of the
|
// Record the type of this instance with the type signature of the
|
||||||
// module we're instantiating and then also add an initializer which
|
// module we're instantiating and then also add an initializer which
|
||||||
// records that we'll be adding to the instance index space here.
|
// records that we'll be adding to the instance index space here.
|
||||||
@@ -839,29 +927,32 @@ and for re-adding support for interface types you can see this issue:
|
|||||||
//
|
//
|
||||||
// Note that we don't add an initializer for this alias because
|
// Note that we don't add an initializer for this alias because
|
||||||
// we statically know where all types point to.
|
// we statically know where all types point to.
|
||||||
Alias::ParentType(parent_idx) => {
|
Alias::OuterType {
|
||||||
let ty = self.results[self.cur].module.types[parent_idx];
|
relative_depth,
|
||||||
|
index,
|
||||||
|
} => {
|
||||||
|
let module_idx = self.in_progress.len() - 1 - (relative_depth as usize);
|
||||||
|
let ty = self.in_progress[module_idx].module.types[index];
|
||||||
self.result.module.types.push(ty);
|
self.result.module.types.push(ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is similar to types in that it's easy for us to record the
|
// FIXME(WebAssembly/module-linking#28) unsure how to implement this
|
||||||
// type of the module that's being aliased, but we also need to add
|
// at this time, if we can alias imported modules it's a lot harder,
|
||||||
// an initializer so during instantiation we can prepare the index
|
// otherwise we'll need to figure out how to translate `index` to a
|
||||||
// space appropriately.
|
// `usize` for a defined module (creating Initializer::DefineModule)
|
||||||
Alias::ParentModule(parent_idx) => {
|
Alias::OuterModule {
|
||||||
let module_idx = self.results[self.cur].module.modules[parent_idx];
|
relative_depth,
|
||||||
self.result.module.modules.push(module_idx);
|
index,
|
||||||
self.result
|
} => {
|
||||||
.module
|
drop((relative_depth, index));
|
||||||
.initializers
|
unimplemented!()
|
||||||
.push(Initializer::AliasParentModule(parent_idx));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This case is slightly more involved, we'll be recording all the
|
// This case is slightly more involved, we'll be recording all the
|
||||||
// type information for each kind of entity, and then we also need
|
// type information for each kind of entity, and then we also need
|
||||||
// to record an initialization step to get the export from the
|
// to record an initialization step to get the export from the
|
||||||
// instance.
|
// instance.
|
||||||
Alias::Child { instance, export } => {
|
Alias::InstanceExport { instance, export } => {
|
||||||
let ty = self.result.module.instances[instance];
|
let ty = self.result.module.instances[instance];
|
||||||
match &self.types.instance_signatures[ty].exports[export] {
|
match &self.types.instance_signatures[ty].exports[export] {
|
||||||
EntityType::Global(g) => {
|
EntityType::Global(g) => {
|
||||||
@@ -894,7 +985,10 @@ and for re-adding support for interface types you can see this issue:
|
|||||||
self.result
|
self.result
|
||||||
.module
|
.module
|
||||||
.initializers
|
.initializers
|
||||||
.push(Initializer::AliasInstanceExport { instance, export })
|
.push(Initializer::AliasInstanceExport {
|
||||||
|
instance,
|
||||||
|
export: export.to_string(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ arbitrary = { version = "0.4.1", features = ["derive"] }
|
|||||||
env_logger = "0.8.1"
|
env_logger = "0.8.1"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rayon = "1.2.1"
|
rayon = "1.2.1"
|
||||||
wasmparser = "0.71"
|
wasmparser = "0.72"
|
||||||
wasmprinter = "0.2.17"
|
wasmprinter = "0.2.17"
|
||||||
wasmtime = { path = "../wasmtime" }
|
wasmtime = { path = "../wasmtime" }
|
||||||
wasmtime-wast = { path = "../wast" }
|
wasmtime-wast = { path = "../wast" }
|
||||||
wasm-encoder = "0.2"
|
wasm-encoder = "0.4"
|
||||||
wasm-smith = "0.3.0"
|
wasm-smith = "0.3.1"
|
||||||
wasmi = "0.7.0"
|
wasmi = "0.7.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ rayon = { version = "1.0", optional = true }
|
|||||||
region = "2.1.0"
|
region = "2.1.0"
|
||||||
thiserror = "1.0.4"
|
thiserror = "1.0.4"
|
||||||
target-lexicon = { version = "0.11.0", default-features = false }
|
target-lexicon = { version = "0.11.0", default-features = false }
|
||||||
wasmparser = "0.71"
|
wasmparser = "0.72"
|
||||||
more-asserts = "0.2.1"
|
more-asserts = "0.2.1"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
|
|||||||
@@ -105,8 +105,8 @@ impl CompilationArtifacts {
|
|||||||
pub fn build(
|
pub fn build(
|
||||||
compiler: &Compiler,
|
compiler: &Compiler,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Result<(Vec<CompilationArtifacts>, TypeTables), SetupError> {
|
) -> Result<(usize, Vec<CompilationArtifacts>, TypeTables), SetupError> {
|
||||||
let (translations, types) = ModuleEnvironment::new(
|
let (main_module, translations, types) = ModuleEnvironment::new(
|
||||||
compiler.frontend_config(),
|
compiler.frontend_config(),
|
||||||
compiler.tunables(),
|
compiler.tunables(),
|
||||||
compiler.features(),
|
compiler.features(),
|
||||||
@@ -166,6 +166,7 @@ impl CompilationArtifacts {
|
|||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, SetupError>>()?;
|
.collect::<Result<Vec<_>, SetupError>>()?;
|
||||||
Ok((
|
Ok((
|
||||||
|
main_module,
|
||||||
list,
|
list,
|
||||||
TypeTables {
|
TypeTables {
|
||||||
wasm_signatures: types.wasm_signatures,
|
wasm_signatures: types.wasm_signatures,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ more-asserts = "0.2.1"
|
|||||||
smallvec = "1.6.1"
|
smallvec = "1.6.1"
|
||||||
thiserror = "1.0.9"
|
thiserror = "1.0.9"
|
||||||
typemap = "0.3"
|
typemap = "0.3"
|
||||||
wasmparser = "0.71"
|
wasmparser = "0.72"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lazy_static = "1.2"
|
lazy_static = "1.2"
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lightbeam = { path = "..", version = "0.22.0" }
|
lightbeam = { path = "..", version = "0.22.0" }
|
||||||
wasmparser = "0.71"
|
wasmparser = "0.72"
|
||||||
cranelift-codegen = { path = "../../../cranelift/codegen", version = "0.69.0" }
|
cranelift-codegen = { path = "../../../cranelift/codegen", version = "0.69.0" }
|
||||||
wasmtime-environ = { path = "../../environ", version = "0.22.0" }
|
wasmtime-environ = { path = "../../environ", version = "0.22.0" }
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use crate::vmcontext::{
|
use crate::vmcontext::{
|
||||||
VMCallerCheckedAnyfunc, VMContext, VMGlobalDefinition, VMMemoryDefinition, VMTableDefinition,
|
VMCallerCheckedAnyfunc, VMContext, VMGlobalDefinition, VMMemoryDefinition, VMTableDefinition,
|
||||||
};
|
};
|
||||||
use crate::InstanceHandle;
|
use crate::RuntimeInstance;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use wasmtime_environ::wasm::Global;
|
use wasmtime_environ::wasm::Global;
|
||||||
use wasmtime_environ::{MemoryPlan, TablePlan};
|
use wasmtime_environ::{MemoryPlan, TablePlan};
|
||||||
|
|
||||||
/// The value of an export passed from one instance to another.
|
/// The value of an export passed from one instance to another.
|
||||||
pub enum Export<'a> {
|
pub enum Export {
|
||||||
/// A function export value.
|
/// A function export value.
|
||||||
Function(ExportFunction),
|
Function(ExportFunction),
|
||||||
|
|
||||||
@@ -22,10 +22,10 @@ pub enum Export<'a> {
|
|||||||
Global(ExportGlobal),
|
Global(ExportGlobal),
|
||||||
|
|
||||||
/// An instance
|
/// An instance
|
||||||
Instance(&'a InstanceHandle),
|
Instance(RuntimeInstance),
|
||||||
|
|
||||||
/// A module
|
/// A module
|
||||||
Module(&'a dyn Any),
|
Module(Box<dyn Any>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A function export value.
|
/// A function export value.
|
||||||
@@ -38,8 +38,8 @@ pub struct ExportFunction {
|
|||||||
pub anyfunc: NonNull<VMCallerCheckedAnyfunc>,
|
pub anyfunc: NonNull<VMCallerCheckedAnyfunc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<ExportFunction> for Export<'a> {
|
impl From<ExportFunction> for Export {
|
||||||
fn from(func: ExportFunction) -> Export<'a> {
|
fn from(func: ExportFunction) -> Export {
|
||||||
Export::Function(func)
|
Export::Function(func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,8 +55,8 @@ pub struct ExportTable {
|
|||||||
pub table: TablePlan,
|
pub table: TablePlan,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<ExportTable> for Export<'a> {
|
impl From<ExportTable> for Export {
|
||||||
fn from(func: ExportTable) -> Export<'a> {
|
fn from(func: ExportTable) -> Export {
|
||||||
Export::Table(func)
|
Export::Table(func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,8 +72,8 @@ pub struct ExportMemory {
|
|||||||
pub memory: MemoryPlan,
|
pub memory: MemoryPlan,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<ExportMemory> for Export<'a> {
|
impl From<ExportMemory> for Export {
|
||||||
fn from(func: ExportMemory) -> Export<'a> {
|
fn from(func: ExportMemory) -> Export {
|
||||||
Export::Memory(func)
|
Export::Memory(func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,8 +89,8 @@ pub struct ExportGlobal {
|
|||||||
pub global: Global,
|
pub global: Global,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<ExportGlobal> for Export<'a> {
|
impl From<ExportGlobal> for Export {
|
||||||
fn from(func: ExportGlobal) -> Export<'a> {
|
fn from(func: ExportGlobal) -> Export {
|
||||||
Export::Global(func)
|
Export::Global(func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport};
|
use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport};
|
||||||
use crate::InstanceHandle;
|
|
||||||
use std::any::Any;
|
|
||||||
use wasmtime_environ::entity::PrimaryMap;
|
|
||||||
use wasmtime_environ::wasm::{InstanceIndex, ModuleIndex};
|
|
||||||
|
|
||||||
/// Resolved import pointers.
|
/// Resolved import pointers.
|
||||||
///
|
///
|
||||||
@@ -28,15 +24,4 @@ pub struct Imports<'a> {
|
|||||||
|
|
||||||
/// Resolved addresses for imported globals.
|
/// Resolved addresses for imported globals.
|
||||||
pub globals: &'a [VMGlobalImport],
|
pub globals: &'a [VMGlobalImport],
|
||||||
|
|
||||||
/// Resolved imported instances.
|
|
||||||
pub instances: PrimaryMap<InstanceIndex, InstanceHandle>,
|
|
||||||
|
|
||||||
/// Resolved imported modules.
|
|
||||||
///
|
|
||||||
/// Note that `Box<Any>` here is chosen to allow the embedder of this crate
|
|
||||||
/// to pick an appropriate representation of what module type should be. For
|
|
||||||
/// example for the `wasmtime` crate it's `wasmtime::Module` but that's not
|
|
||||||
/// defined way down here in this low crate.
|
|
||||||
pub modules: PrimaryMap<ModuleIndex, Box<dyn Any>>,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use crate::vmcontext::{
|
|||||||
VMSharedSignatureIndex, VMTableDefinition, VMTableImport,
|
VMSharedSignatureIndex, VMTableDefinition, VMTableImport,
|
||||||
};
|
};
|
||||||
use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable};
|
use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable};
|
||||||
|
use indexmap::IndexMap;
|
||||||
use memoffset::offset_of;
|
use memoffset::offset_of;
|
||||||
use more_asserts::assert_lt;
|
use more_asserts::assert_lt;
|
||||||
use std::alloc::{self, Layout};
|
use std::alloc::{self, Layout};
|
||||||
@@ -22,17 +23,22 @@ use std::cell::RefCell;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{mem, ptr, slice};
|
use std::{mem, ptr, slice};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmtime_environ::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, PrimaryMap};
|
use wasmtime_environ::entity::{packed_option::ReservedValue, BoxedSlice, EntityRef, PrimaryMap};
|
||||||
use wasmtime_environ::wasm::{
|
use wasmtime_environ::wasm::{
|
||||||
DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
|
DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
|
||||||
ElemIndex, EntityIndex, FuncIndex, GlobalIndex, GlobalInit, InstanceIndex, MemoryIndex,
|
ElemIndex, EntityIndex, FuncIndex, GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex,
|
||||||
ModuleIndex, SignatureIndex, TableElementType, TableIndex, WasmType,
|
TableElementType, TableIndex, WasmType,
|
||||||
};
|
};
|
||||||
use wasmtime_environ::{ir, DataInitializer, Module, ModuleType, TableElements, VMOffsets};
|
use wasmtime_environ::{ir, DataInitializer, Module, ModuleType, TableElements, VMOffsets};
|
||||||
|
|
||||||
|
/// Runtime representation of an instance value, which erases all `Instance`
|
||||||
|
/// information since instances are just a collection of values.
|
||||||
|
pub type RuntimeInstance = Rc<IndexMap<String, Export>>;
|
||||||
|
|
||||||
/// A WebAssembly instance.
|
/// A WebAssembly instance.
|
||||||
///
|
///
|
||||||
/// This is repr(C) to ensure that the vmctx field is last.
|
/// This is repr(C) to ensure that the vmctx field is last.
|
||||||
@@ -50,15 +56,6 @@ pub(crate) struct Instance {
|
|||||||
/// WebAssembly table data.
|
/// WebAssembly table data.
|
||||||
tables: BoxedSlice<DefinedTableIndex, Table>,
|
tables: BoxedSlice<DefinedTableIndex, Table>,
|
||||||
|
|
||||||
/// Instances our module defined and their handles.
|
|
||||||
instances: PrimaryMap<InstanceIndex, InstanceHandle>,
|
|
||||||
|
|
||||||
/// Modules that are located in our index space.
|
|
||||||
///
|
|
||||||
/// For now these are `Box<Any>` so the caller can define the type of what a
|
|
||||||
/// module looks like.
|
|
||||||
modules: PrimaryMap<ModuleIndex, Box<dyn Any>>,
|
|
||||||
|
|
||||||
/// Passive elements in this instantiation. As `elem.drop`s happen, these
|
/// Passive elements in this instantiation. As `elem.drop`s happen, these
|
||||||
/// entries get removed. A missing entry is considered equivalent to an
|
/// entries get removed. A missing entry is considered equivalent to an
|
||||||
/// empty slice.
|
/// empty slice.
|
||||||
@@ -266,18 +263,8 @@ impl Instance {
|
|||||||
self.vmctx() as *const VMContext as *mut VMContext
|
self.vmctx() as *const VMContext as *mut VMContext
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup an export with the given name.
|
|
||||||
pub fn lookup(&self, field: &str) -> Option<Export> {
|
|
||||||
let export = if let Some(export) = self.module.exports.get(field) {
|
|
||||||
export.clone()
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
Some(self.lookup_by_declaration(&export))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lookup an export with the given export declaration.
|
/// Lookup an export with the given export declaration.
|
||||||
pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export<'_> {
|
pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export {
|
||||||
match export {
|
match export {
|
||||||
EntityIndex::Function(index) => {
|
EntityIndex::Function(index) => {
|
||||||
let anyfunc = self.get_caller_checked_anyfunc(*index).unwrap();
|
let anyfunc = self.get_caller_checked_anyfunc(*index).unwrap();
|
||||||
@@ -326,8 +313,9 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
|
||||||
EntityIndex::Instance(index) => Export::Instance(&self.instances[*index]),
|
EntityIndex::Instance(_) | EntityIndex::Module(_) => {
|
||||||
EntityIndex::Module(index) => Export::Module(&*self.modules[*index]),
|
panic!("can't use this api for modules/instances")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -855,8 +843,6 @@ impl InstanceHandle {
|
|||||||
passive_elements: Default::default(),
|
passive_elements: Default::default(),
|
||||||
passive_data,
|
passive_data,
|
||||||
host_state,
|
host_state,
|
||||||
instances: imports.instances,
|
|
||||||
modules: imports.modules,
|
|
||||||
vmctx: VMContext {},
|
vmctx: VMContext {},
|
||||||
};
|
};
|
||||||
let layout = instance.alloc_layout();
|
let layout = instance.alloc_layout();
|
||||||
@@ -1015,11 +1001,6 @@ impl InstanceHandle {
|
|||||||
self.instance().module()
|
self.instance().module()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup an export with the given name.
|
|
||||||
pub fn lookup(&self, field: &str) -> Option<Export> {
|
|
||||||
self.instance().lookup(field)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lookup an export with the given export declaration.
|
/// Lookup an export with the given export declaration.
|
||||||
pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export {
|
pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export {
|
||||||
self.instance().lookup_by_declaration(export)
|
self.instance().lookup_by_declaration(export)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub mod libcalls;
|
|||||||
pub use crate::export::*;
|
pub use crate::export::*;
|
||||||
pub use crate::externref::*;
|
pub use crate::externref::*;
|
||||||
pub use crate::imports::Imports;
|
pub use crate::imports::Imports;
|
||||||
pub use crate::instance::{InstanceHandle, InstantiationError, LinkError};
|
pub use crate::instance::{InstanceHandle, InstantiationError, LinkError, RuntimeInstance};
|
||||||
pub use crate::jit_int::GdbJitImageRegistration;
|
pub use crate::jit_int::GdbJitImageRegistration;
|
||||||
pub use crate::memory::{RuntimeLinearMemory, RuntimeMemoryCreator};
|
pub use crate::memory::{RuntimeLinearMemory, RuntimeMemoryCreator};
|
||||||
pub use crate::mmap::Mmap;
|
pub use crate::mmap::Mmap;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ wasmtime-jit = { path = "../jit", version = "0.22.0" }
|
|||||||
wasmtime-cache = { path = "../cache", version = "0.22.0", optional = true }
|
wasmtime-cache = { path = "../cache", version = "0.22.0", optional = true }
|
||||||
wasmtime-profiling = { path = "../profiling", version = "0.22.0" }
|
wasmtime-profiling = { path = "../profiling", version = "0.22.0" }
|
||||||
target-lexicon = { version = "0.11.0", default-features = false }
|
target-lexicon = { version = "0.11.0", default-features = false }
|
||||||
wasmparser = "0.71"
|
wasmparser = "0.72"
|
||||||
anyhow = "1.0.19"
|
anyhow = "1.0.19"
|
||||||
region = "2.2.0"
|
region = "2.2.0"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
|||||||
@@ -112,26 +112,25 @@ impl Extern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_wasmtime_export(
|
pub(crate) unsafe fn from_wasmtime_export(
|
||||||
wasmtime_export: wasmtime_runtime::Export,
|
wasmtime_export: &wasmtime_runtime::Export,
|
||||||
instance: StoreInstanceHandle,
|
store: &Store,
|
||||||
) -> Extern {
|
) -> Extern {
|
||||||
match wasmtime_export {
|
match wasmtime_export {
|
||||||
wasmtime_runtime::Export::Function(f) => {
|
wasmtime_runtime::Export::Function(f) => {
|
||||||
Extern::Func(Func::from_wasmtime_function(f, instance))
|
Extern::Func(Func::from_wasmtime_function(f, store))
|
||||||
}
|
}
|
||||||
wasmtime_runtime::Export::Memory(m) => {
|
wasmtime_runtime::Export::Memory(m) => {
|
||||||
Extern::Memory(Memory::from_wasmtime_memory(m, instance))
|
Extern::Memory(Memory::from_wasmtime_memory(m, store))
|
||||||
}
|
}
|
||||||
wasmtime_runtime::Export::Global(g) => {
|
wasmtime_runtime::Export::Global(g) => {
|
||||||
Extern::Global(Global::from_wasmtime_global(g, instance))
|
Extern::Global(Global::from_wasmtime_global(g, store))
|
||||||
}
|
}
|
||||||
wasmtime_runtime::Export::Table(t) => {
|
wasmtime_runtime::Export::Table(t) => {
|
||||||
Extern::Table(Table::from_wasmtime_table(t, instance))
|
Extern::Table(Table::from_wasmtime_table(t, store))
|
||||||
}
|
}
|
||||||
wasmtime_runtime::Export::Instance(i) => {
|
wasmtime_runtime::Export::Instance(i) => {
|
||||||
let handle = unsafe { instance.store.existing_instance_handle(i.clone()) };
|
Extern::Instance(Instance::from_wasmtime(i, store))
|
||||||
Extern::Instance(Instance::from_wasmtime(handle))
|
|
||||||
}
|
}
|
||||||
wasmtime_runtime::Export::Module(m) => {
|
wasmtime_runtime::Export::Module(m) => {
|
||||||
Extern::Module(m.downcast_ref::<Module>().unwrap().clone())
|
Extern::Module(m.downcast_ref::<Module>().unwrap().clone())
|
||||||
@@ -335,13 +334,13 @@ impl Global {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_wasmtime_global(
|
pub(crate) unsafe fn from_wasmtime_global(
|
||||||
wasmtime_export: wasmtime_runtime::ExportGlobal,
|
wasmtime_export: &wasmtime_runtime::ExportGlobal,
|
||||||
instance: StoreInstanceHandle,
|
store: &Store,
|
||||||
) -> Global {
|
) -> Global {
|
||||||
Global {
|
Global {
|
||||||
instance,
|
instance: store.existing_vmctx(wasmtime_export.vmctx),
|
||||||
wasmtime_export,
|
wasmtime_export: wasmtime_export.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,6 +353,10 @@ impl Global {
|
|||||||
from: self.wasmtime_export.definition,
|
from: self.wasmtime_export.definition,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::ExportGlobal {
|
||||||
|
&self.wasmtime_export
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A WebAssembly `table`, or an array of values.
|
/// A WebAssembly `table`, or an array of values.
|
||||||
@@ -576,13 +579,13 @@ impl Table {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_wasmtime_table(
|
pub(crate) unsafe fn from_wasmtime_table(
|
||||||
wasmtime_export: wasmtime_runtime::ExportTable,
|
wasmtime_export: &wasmtime_runtime::ExportTable,
|
||||||
instance: StoreInstanceHandle,
|
store: &Store,
|
||||||
) -> Table {
|
) -> Table {
|
||||||
Table {
|
Table {
|
||||||
instance,
|
instance: store.existing_vmctx(wasmtime_export.vmctx),
|
||||||
wasmtime_export,
|
wasmtime_export: wasmtime_export.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,6 +599,10 @@ impl Table {
|
|||||||
vmctx: self.wasmtime_export.vmctx,
|
vmctx: self.wasmtime_export.vmctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::ExportTable {
|
||||||
|
&self.wasmtime_export
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A WebAssembly linear memory.
|
/// A WebAssembly linear memory.
|
||||||
@@ -987,13 +994,13 @@ impl Memory {
|
|||||||
.ok_or_else(|| anyhow!("failed to grow memory"))
|
.ok_or_else(|| anyhow!("failed to grow memory"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_wasmtime_memory(
|
pub(crate) unsafe fn from_wasmtime_memory(
|
||||||
wasmtime_export: wasmtime_runtime::ExportMemory,
|
wasmtime_export: &wasmtime_runtime::ExportMemory,
|
||||||
instance: StoreInstanceHandle,
|
store: &Store,
|
||||||
) -> Memory {
|
) -> Memory {
|
||||||
Memory {
|
Memory {
|
||||||
instance,
|
instance: store.existing_vmctx(wasmtime_export.vmctx),
|
||||||
wasmtime_export,
|
wasmtime_export: wasmtime_export.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1007,6 +1014,10 @@ impl Memory {
|
|||||||
vmctx: self.wasmtime_export.vmctx,
|
vmctx: self.wasmtime_export.vmctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::ExportMemory {
|
||||||
|
&self.wasmtime_export
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A linear memory. This trait provides an interface for raw memory buffers which are used
|
/// A linear memory. This trait provides an interface for raw memory buffers which are used
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::store::StoreInner;
|
use crate::store::StoreInner;
|
||||||
use crate::trampoline::StoreInstanceHandle;
|
use crate::trampoline::StoreInstanceHandle;
|
||||||
use crate::{Extern, ExternRef, FuncType, Memory, Store, Trap, Val, ValType};
|
use crate::{Extern, ExternRef, FuncType, Store, Trap, Val, ValType};
|
||||||
use anyhow::{bail, ensure, Context as _, Result};
|
use anyhow::{bail, ensure, Context as _, Result};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
@@ -9,8 +9,9 @@ use std::mem;
|
|||||||
use std::panic::{self, AssertUnwindSafe};
|
use std::panic::{self, AssertUnwindSafe};
|
||||||
use std::ptr::{self, NonNull};
|
use std::ptr::{self, NonNull};
|
||||||
use std::rc::Weak;
|
use std::rc::Weak;
|
||||||
|
use wasmtime_environ::wasm::EntityIndex;
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
raise_user_trap, Export, InstanceHandle, VMContext, VMFunctionBody, VMSharedSignatureIndex,
|
raise_user_trap, InstanceHandle, VMContext, VMFunctionBody, VMSharedSignatureIndex,
|
||||||
VMTrampoline,
|
VMTrampoline,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -331,11 +332,8 @@ impl Func {
|
|||||||
debug_assert!(
|
debug_assert!(
|
||||||
anyfunc.as_ref().type_index != wasmtime_runtime::VMSharedSignatureIndex::default()
|
anyfunc.as_ref().type_index != wasmtime_runtime::VMSharedSignatureIndex::default()
|
||||||
);
|
);
|
||||||
|
|
||||||
let instance_handle = wasmtime_runtime::InstanceHandle::from_vmctx(anyfunc.as_ref().vmctx);
|
|
||||||
let export = wasmtime_runtime::ExportFunction { anyfunc };
|
let export = wasmtime_runtime::ExportFunction { anyfunc };
|
||||||
let instance = store.existing_instance_handle(instance_handle);
|
let f = Func::from_wasmtime_function(&export, store);
|
||||||
let f = Func::from_wasmtime_function(export, instance);
|
|
||||||
Some(f)
|
Some(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,8 +371,8 @@ impl Func {
|
|||||||
///
|
///
|
||||||
/// Finally you can also optionally take [`Caller`] as the first argument of
|
/// Finally you can also optionally take [`Caller`] as the first argument of
|
||||||
/// your closure. If inserted then you're able to inspect the caller's
|
/// your closure. If inserted then you're able to inspect the caller's
|
||||||
/// state, for example the [`Memory`] it has exported so you can read what
|
/// state, for example the [`Memory`](crate::Memory) it has exported so you
|
||||||
/// pointers point to.
|
/// can read what pointers point to.
|
||||||
///
|
///
|
||||||
/// Note that when using this API, the intention is to create as thin of a
|
/// Note that when using this API, the intention is to create as thin of a
|
||||||
/// layer as possible for when WebAssembly calls the function provided. With
|
/// layer as possible for when WebAssembly calls the function provided. With
|
||||||
@@ -649,24 +647,24 @@ impl Func {
|
|||||||
self.export.anyfunc
|
self.export.anyfunc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_wasmtime_function(
|
pub(crate) unsafe fn from_wasmtime_function(
|
||||||
export: wasmtime_runtime::ExportFunction,
|
export: &wasmtime_runtime::ExportFunction,
|
||||||
instance: StoreInstanceHandle,
|
store: &Store,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Each function signature in a module should have a trampoline stored
|
// Each function signature in a module should have a trampoline stored
|
||||||
// on that module as well, so unwrap the result here since otherwise
|
// on that module as well, so unwrap the result here since otherwise
|
||||||
// it's a bug in wasmtime.
|
// it's a bug in wasmtime.
|
||||||
let trampoline = instance
|
let anyfunc = export.anyfunc.as_ref();
|
||||||
.store
|
let trampoline = store
|
||||||
.signatures()
|
.signatures()
|
||||||
.borrow()
|
.borrow()
|
||||||
.lookup_shared(unsafe { export.anyfunc.as_ref().type_index })
|
.lookup_shared(anyfunc.type_index)
|
||||||
.expect("failed to retrieve trampoline from module")
|
.expect("failed to retrieve trampoline from module")
|
||||||
.1;
|
.1;
|
||||||
|
|
||||||
Func {
|
Func {
|
||||||
instance,
|
instance: store.existing_vmctx(anyfunc.vmctx),
|
||||||
export,
|
export: export.clone(),
|
||||||
trampoline,
|
trampoline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -807,6 +805,10 @@ impl Func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::ExportFunction {
|
||||||
|
&self.export
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Func {
|
impl fmt::Debug for Func {
|
||||||
@@ -1506,10 +1508,16 @@ impl Caller<'_> {
|
|||||||
debug_assert!(self.store.upgrade().is_some());
|
debug_assert!(self.store.upgrade().is_some());
|
||||||
let handle =
|
let handle =
|
||||||
Store::from_inner(self.store.upgrade()?).existing_instance_handle(instance);
|
Store::from_inner(self.store.upgrade()?).existing_instance_handle(instance);
|
||||||
let export = handle.lookup(name)?;
|
let index = handle.module().exports.get(name)?;
|
||||||
match export {
|
match index {
|
||||||
Export::Memory(m) => Some(Extern::Memory(Memory::from_wasmtime_memory(m, handle))),
|
// Only allow memory/functions for now to emulate what interface
|
||||||
Export::Function(f) => Some(Extern::Func(Func::from_wasmtime_function(f, handle))),
|
// types will once provide
|
||||||
|
EntityIndex::Memory(_) | EntityIndex::Function(_) => {
|
||||||
|
Some(Extern::from_wasmtime_export(
|
||||||
|
&handle.lookup_by_declaration(&index),
|
||||||
|
&handle.store,
|
||||||
|
))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
use crate::trampoline::StoreInstanceHandle;
|
|
||||||
use crate::types::matching;
|
use crate::types::matching;
|
||||||
use crate::{
|
use crate::{
|
||||||
Engine, Export, Extern, ExternType, Func, Global, InstanceType, Memory, Module, Store, Table,
|
Engine, Export, Extern, Func, Global, InstanceType, Memory, Module, Store, Table, Trap,
|
||||||
Trap,
|
|
||||||
};
|
};
|
||||||
use anyhow::{bail, Context, Error, Result};
|
use anyhow::{bail, Context, Error, Result};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::Arc;
|
use std::rc::Rc;
|
||||||
use wasmtime_environ::entity::PrimaryMap;
|
use wasmtime_environ::entity::PrimaryMap;
|
||||||
use wasmtime_environ::wasm::{
|
use wasmtime_environ::wasm::{
|
||||||
EntityIndex, EntityType, FuncIndex, GlobalIndex, InstanceIndex, MemoryIndex, ModuleIndex,
|
EntityIndex, FuncIndex, GlobalIndex, InstanceIndex, MemoryIndex, ModuleIndex, TableIndex,
|
||||||
TableIndex,
|
|
||||||
};
|
};
|
||||||
use wasmtime_environ::Initializer;
|
use wasmtime_environ::Initializer;
|
||||||
use wasmtime_jit::TypeTables;
|
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
Imports, InstanceHandle, InstantiationError, StackMapRegistry, VMContext,
|
Imports, InstantiationError, RuntimeInstance, StackMapRegistry, VMContext,
|
||||||
VMExternRefActivationsTable, VMFunctionBody, VMFunctionImport, VMGlobalImport, VMMemoryImport,
|
VMExternRefActivationsTable, VMFunctionBody, VMFunctionImport, VMGlobalImport, VMMemoryImport,
|
||||||
VMTableImport,
|
VMTableImport,
|
||||||
};
|
};
|
||||||
@@ -36,8 +32,6 @@ use wasmtime_runtime::{
|
|||||||
/// itself.
|
/// itself.
|
||||||
/// * `type` - the type tables produced during compilation which
|
/// * `type` - the type tables produced during compilation which
|
||||||
/// `compiled_module`'s metadata references.
|
/// `compiled_module`'s metadata references.
|
||||||
/// * `parent_modules` - this is the list of compiled modules the parent has.
|
|
||||||
/// This is only applicable on recursive instantiations.
|
|
||||||
/// * `define_import` - this function, like the name implies, defines an import
|
/// * `define_import` - this function, like the name implies, defines an import
|
||||||
/// into the provided builder. The expected entity that it's defining is also
|
/// into the provided builder. The expected entity that it's defining is also
|
||||||
/// passed in for the top-level case where type-checking is performed. This is
|
/// passed in for the top-level case where type-checking is performed. This is
|
||||||
@@ -45,9 +39,13 @@ use wasmtime_runtime::{
|
|||||||
fn instantiate(
|
fn instantiate(
|
||||||
store: &Store,
|
store: &Store,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
parent_modules: &PrimaryMap<ModuleIndex, Module>,
|
define_import: &mut dyn FnMut(
|
||||||
define_import: &mut dyn FnMut(&EntityIndex, &mut ImportsBuilder<'_>) -> Result<()>,
|
&str,
|
||||||
) -> Result<StoreInstanceHandle, Error> {
|
Option<&str>,
|
||||||
|
&EntityIndex,
|
||||||
|
&mut ImportsBuilder<'_>,
|
||||||
|
) -> Result<()>,
|
||||||
|
) -> Result<RuntimeInstance, Error> {
|
||||||
let compiled_module = module.compiled_module();
|
let compiled_module = module.compiled_module();
|
||||||
let env_module = compiled_module.module();
|
let env_module = compiled_module.module();
|
||||||
|
|
||||||
@@ -59,21 +57,9 @@ fn instantiate(
|
|||||||
// to fetching from the import list for the top-level module and
|
// to fetching from the import list for the top-level module and
|
||||||
// otherwise fetching from each nested instance's argument list for
|
// otherwise fetching from each nested instance's argument list for
|
||||||
// submodules.
|
// submodules.
|
||||||
Initializer::Import {
|
Initializer::Import { index, name, field } => {
|
||||||
index,
|
define_import(name, field.as_deref(), index, &mut imports)
|
||||||
module,
|
.with_context(|| format!("incompatible import type for `{}`", name))?;
|
||||||
field,
|
|
||||||
} => {
|
|
||||||
define_import(index, &mut imports).with_context(|| match field {
|
|
||||||
Some(name) => format!("incompatible import type for `{}::{}`", module, name),
|
|
||||||
None => format!("incompatible import type for `{}`", module),
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This one's pretty easy, we're just picking up our parent's module
|
|
||||||
// and putting it into our own index space.
|
|
||||||
Initializer::AliasParentModule(idx) => {
|
|
||||||
imports.modules.push(parent_modules[*idx].clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turns out defining any kind of module is pretty easy, we're just
|
// Turns out defining any kind of module is pretty easy, we're just
|
||||||
@@ -95,18 +81,8 @@ fn instantiate(
|
|||||||
// handle comes from our same store, but this should be true because
|
// handle comes from our same store, but this should be true because
|
||||||
// we acquired the handle from an instance in the store.
|
// we acquired the handle from an instance in the store.
|
||||||
Initializer::AliasInstanceExport { instance, export } => {
|
Initializer::AliasInstanceExport { instance, export } => {
|
||||||
let instance_ty = env_module.instances[*instance];
|
let export = &imports.instances[*instance][export];
|
||||||
let export_name = module.types().instance_signatures[instance_ty]
|
let item = unsafe { Extern::from_wasmtime_export(export, store) };
|
||||||
.exports
|
|
||||||
.get_index(*export)
|
|
||||||
.expect("validation bug - should be valid")
|
|
||||||
.0;
|
|
||||||
let handle = &imports.instances[*instance];
|
|
||||||
let entity_index = &handle.module().exports[export_name];
|
|
||||||
let item = Extern::from_wasmtime_export(
|
|
||||||
handle.lookup_by_declaration(entity_index),
|
|
||||||
unsafe { store.existing_instance_handle(handle.clone()) },
|
|
||||||
);
|
|
||||||
imports.push_extern(&item);
|
imports.push_extern(&item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,13 +103,13 @@ fn instantiate(
|
|||||||
// we're doing all of this in the context of our `Store` argument
|
// we're doing all of this in the context of our `Store` argument
|
||||||
// above so we should be safe here.
|
// above so we should be safe here.
|
||||||
Initializer::Instantiate { module, args } => {
|
Initializer::Instantiate { module, args } => {
|
||||||
let mut args = args.iter();
|
|
||||||
let handle = instantiate(
|
let handle = instantiate(
|
||||||
store,
|
store,
|
||||||
&imports.modules[*module],
|
&imports.modules[*module],
|
||||||
&imports.modules,
|
&mut |name, field, _, builder| {
|
||||||
&mut |_, builder| {
|
debug_assert!(field.is_none());
|
||||||
match *args.next().unwrap() {
|
let index = args.get(name).expect("should be present after validation");
|
||||||
|
match *index {
|
||||||
EntityIndex::Global(i) => {
|
EntityIndex::Global(i) => {
|
||||||
builder.globals.push(imports.globals[i]);
|
builder.globals.push(imports.globals[i]);
|
||||||
}
|
}
|
||||||
@@ -150,24 +126,17 @@ fn instantiate(
|
|||||||
builder.modules.push(imports.modules[i].clone());
|
builder.modules.push(imports.modules[i].clone());
|
||||||
}
|
}
|
||||||
EntityIndex::Instance(i) => {
|
EntityIndex::Instance(i) => {
|
||||||
builder
|
builder.instances.push(imports.instances[i].clone());
|
||||||
.instances
|
|
||||||
.push(unsafe { imports.instances[i].clone() });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
imports.instances.push(unsafe { (*handle).clone() });
|
imports.instances.push(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// With the above initialization done we've now acquired the final set of
|
|
||||||
// imports in all the right index spaces and everything. Time to carry on
|
|
||||||
// with the creation of our own instance.
|
|
||||||
let imports = imports.build();
|
|
||||||
|
|
||||||
// Register the module just before instantiation to ensure we have a
|
// Register the module just before instantiation to ensure we have a
|
||||||
// trampoline registered for every signature and to preserve the module's
|
// trampoline registered for every signature and to preserve the module's
|
||||||
// compiled JIT code within the `Store`.
|
// compiled JIT code within the `Store`.
|
||||||
@@ -176,11 +145,11 @@ fn instantiate(
|
|||||||
let config = store.engine().config();
|
let config = store.engine().config();
|
||||||
let instance = unsafe {
|
let instance = unsafe {
|
||||||
let instance = compiled_module.instantiate(
|
let instance = compiled_module.instantiate(
|
||||||
imports,
|
imports.build(),
|
||||||
&store.lookup_shared_signature(module.types()),
|
&store.lookup_shared_signature(module.types()),
|
||||||
config.memory_creator.as_ref().map(|a| a as _),
|
config.memory_creator.as_ref().map(|a| a as _),
|
||||||
store.interrupts(),
|
store.interrupts(),
|
||||||
Box::new(module.types().clone()),
|
Box::new(()),
|
||||||
store.externref_activations_table() as *const VMExternRefActivationsTable as *mut _,
|
store.externref_activations_table() as *const VMExternRefActivationsTable as *mut _,
|
||||||
store.stack_map_registry() as *const StackMapRegistry as *mut _,
|
store.stack_map_registry() as *const StackMapRegistry as *mut _,
|
||||||
)?;
|
)?;
|
||||||
@@ -233,7 +202,29 @@ fn instantiate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(instance)
|
let exports = instance
|
||||||
|
.handle
|
||||||
|
.module()
|
||||||
|
.exports
|
||||||
|
.iter()
|
||||||
|
.map(|(name, index)| {
|
||||||
|
// Note that instances and modules are not handled by
|
||||||
|
// `wasmtime_runtime`, they're handled by us in this crate. That
|
||||||
|
// means we need to handle that here, otherwise we defer to the
|
||||||
|
// instance to load the values.
|
||||||
|
let item = match index {
|
||||||
|
EntityIndex::Instance(i) => {
|
||||||
|
wasmtime_runtime::Export::Instance(imports.instances[*i].clone())
|
||||||
|
}
|
||||||
|
EntityIndex::Module(i) => {
|
||||||
|
wasmtime_runtime::Export::Module(Box::new(imports.modules[*i].clone()))
|
||||||
|
}
|
||||||
|
index => instance.handle.lookup_by_declaration(index),
|
||||||
|
};
|
||||||
|
(name.clone(), item)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Ok(Rc::new(exports))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An instantiated WebAssembly module.
|
/// An instantiated WebAssembly module.
|
||||||
@@ -254,7 +245,8 @@ fn instantiate(
|
|||||||
/// call any code or execute anything!
|
/// call any code or execute anything!
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
pub(crate) handle: StoreInstanceHandle,
|
pub(crate) store: Store,
|
||||||
|
pub(crate) items: RuntimeInstance,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
@@ -329,32 +321,26 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut imports = imports.iter();
|
let mut imports = imports.iter();
|
||||||
let handle = instantiate(store, module, &PrimaryMap::new(), &mut |idx, builder| {
|
let items = instantiate(store, module, &mut |_name, _field, idx, builder| {
|
||||||
let import = imports.next().expect("already checked the length");
|
let import = imports.next().expect("already checked the length");
|
||||||
builder.define_extern(idx, import)
|
builder.define_extern(idx, &import)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Instance { handle })
|
Ok(Instance::from_wasmtime(&items, store))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_wasmtime(handle: StoreInstanceHandle) -> Instance {
|
pub(crate) fn from_wasmtime(handle: &RuntimeInstance, store: &Store) -> Instance {
|
||||||
Instance { handle }
|
Instance {
|
||||||
|
items: handle.clone(),
|
||||||
|
store: store.clone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the type signature of this instance.
|
/// Returns the type signature of this instance.
|
||||||
pub fn ty(&self) -> InstanceType {
|
pub fn ty(&self) -> InstanceType {
|
||||||
let mut ty = InstanceType::new();
|
let mut ty = InstanceType::new();
|
||||||
let module = self.handle.module();
|
for export in self.exports() {
|
||||||
let types = self
|
ty.add_named_export(export.name(), export.ty());
|
||||||
.handle
|
|
||||||
.host_state()
|
|
||||||
.downcast_ref::<Arc<TypeTables>>()
|
|
||||||
.unwrap();
|
|
||||||
for (name, index) in module.exports.iter() {
|
|
||||||
ty.add_named_export(
|
|
||||||
name,
|
|
||||||
ExternType::from_wasmtime(types, &module.type_of(*index)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
@@ -364,16 +350,15 @@ impl Instance {
|
|||||||
/// This is the [`Store`] that generally serves as a sort of global cache
|
/// This is the [`Store`] that generally serves as a sort of global cache
|
||||||
/// for various instance-related things.
|
/// for various instance-related things.
|
||||||
pub fn store(&self) -> &Store {
|
pub fn store(&self) -> &Store {
|
||||||
&self.handle.store
|
&self.store
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of exported items from this [`Instance`].
|
/// Returns the list of exported items from this [`Instance`].
|
||||||
pub fn exports<'instance>(
|
pub fn exports<'instance>(
|
||||||
&'instance self,
|
&'instance self,
|
||||||
) -> impl ExactSizeIterator<Item = Export<'instance>> + 'instance {
|
) -> impl ExactSizeIterator<Item = Export<'instance>> + 'instance {
|
||||||
self.handle.exports().map(move |(name, entity_index)| {
|
self.items.iter().map(move |(name, item)| {
|
||||||
let export = self.handle.lookup_by_declaration(entity_index);
|
let extern_ = unsafe { Extern::from_wasmtime_export(item, &self.store) };
|
||||||
let extern_ = Extern::from_wasmtime_export(export, self.handle.clone());
|
|
||||||
Export::new(name, extern_)
|
Export::new(name, extern_)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -385,8 +370,8 @@ impl Instance {
|
|||||||
///
|
///
|
||||||
/// Returns `None` if there was no export named `name`.
|
/// Returns `None` if there was no export named `name`.
|
||||||
pub fn get_export(&self, name: &str) -> Option<Extern> {
|
pub fn get_export(&self, name: &str) -> Option<Extern> {
|
||||||
let export = self.handle.lookup(&name)?;
|
let export = self.items.get(name)?;
|
||||||
Some(Extern::from_wasmtime_export(export, self.handle.clone()))
|
Some(unsafe { Extern::from_wasmtime_export(export, &self.store) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Looks up an exported [`Func`] value by name.
|
/// Looks up an exported [`Func`] value by name.
|
||||||
@@ -427,7 +412,7 @@ struct ImportsBuilder<'a> {
|
|||||||
tables: PrimaryMap<TableIndex, VMTableImport>,
|
tables: PrimaryMap<TableIndex, VMTableImport>,
|
||||||
memories: PrimaryMap<MemoryIndex, VMMemoryImport>,
|
memories: PrimaryMap<MemoryIndex, VMMemoryImport>,
|
||||||
globals: PrimaryMap<GlobalIndex, VMGlobalImport>,
|
globals: PrimaryMap<GlobalIndex, VMGlobalImport>,
|
||||||
instances: PrimaryMap<InstanceIndex, InstanceHandle>,
|
instances: PrimaryMap<InstanceIndex, RuntimeInstance>,
|
||||||
modules: PrimaryMap<ModuleIndex, Module>,
|
modules: PrimaryMap<ModuleIndex, Module>,
|
||||||
|
|
||||||
module: &'a wasmtime_environ::Module,
|
module: &'a wasmtime_environ::Module,
|
||||||
@@ -452,36 +437,7 @@ impl<'a> ImportsBuilder<'a> {
|
|||||||
|
|
||||||
fn define_extern(&mut self, expected: &EntityIndex, actual: &Extern) -> Result<()> {
|
fn define_extern(&mut self, expected: &EntityIndex, actual: &Extern) -> Result<()> {
|
||||||
let expected_ty = self.module.type_of(*expected);
|
let expected_ty = self.module.type_of(*expected);
|
||||||
let compatible = match &expected_ty {
|
self.matcher.extern_(&expected_ty, actual)?;
|
||||||
EntityType::Table(i) => match actual {
|
|
||||||
Extern::Table(e) => self.matcher.table(i, e),
|
|
||||||
_ => bail!("expected table, but found {}", actual.desc()),
|
|
||||||
},
|
|
||||||
EntityType::Memory(i) => match actual {
|
|
||||||
Extern::Memory(e) => self.matcher.memory(i, e),
|
|
||||||
_ => bail!("expected memory, but found {}", actual.desc()),
|
|
||||||
},
|
|
||||||
EntityType::Global(i) => match actual {
|
|
||||||
Extern::Global(e) => self.matcher.global(i, e),
|
|
||||||
_ => bail!("expected global, but found {}", actual.desc()),
|
|
||||||
},
|
|
||||||
EntityType::Function(i) => match actual {
|
|
||||||
Extern::Func(e) => self.matcher.func(*i, e),
|
|
||||||
_ => bail!("expected func, but found {}", actual.desc()),
|
|
||||||
},
|
|
||||||
EntityType::Instance(i) => match actual {
|
|
||||||
Extern::Instance(e) => self.matcher.instance(*i, e),
|
|
||||||
_ => bail!("expected instance, but found {}", actual.desc()),
|
|
||||||
},
|
|
||||||
EntityType::Module(i) => match actual {
|
|
||||||
Extern::Module(e) => self.matcher.module(*i, e),
|
|
||||||
_ => bail!("expected module, but found {}", actual.desc()),
|
|
||||||
},
|
|
||||||
EntityType::Event(_) => unimplemented!(),
|
|
||||||
};
|
|
||||||
if !compatible {
|
|
||||||
bail!("{} types incompatible", actual.desc());
|
|
||||||
}
|
|
||||||
self.push_extern(actual);
|
self.push_extern(actual);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -502,7 +458,7 @@ impl<'a> ImportsBuilder<'a> {
|
|||||||
}
|
}
|
||||||
Extern::Instance(i) => {
|
Extern::Instance(i) => {
|
||||||
debug_assert!(Store::same(i.store(), self.matcher.store));
|
debug_assert!(Store::same(i.store(), self.matcher.store));
|
||||||
self.instances.push(unsafe { (*i.handle).clone() });
|
self.instances.push(i.items.clone());
|
||||||
}
|
}
|
||||||
Extern::Module(m) => {
|
Extern::Module(m) => {
|
||||||
self.modules.push(m.clone());
|
self.modules.push(m.clone());
|
||||||
@@ -516,11 +472,40 @@ impl<'a> ImportsBuilder<'a> {
|
|||||||
globals: self.globals.values().as_slice(),
|
globals: self.globals.values().as_slice(),
|
||||||
memories: self.memories.values().as_slice(),
|
memories: self.memories.values().as_slice(),
|
||||||
functions: self.functions.values().as_slice(),
|
functions: self.functions.values().as_slice(),
|
||||||
instances: mem::take(&mut self.instances),
|
}
|
||||||
modules: mem::take(&mut self.modules)
|
}
|
||||||
.into_iter()
|
}
|
||||||
.map(|(_, m)| Box::new(m) as Box<_>)
|
|
||||||
.collect(),
|
/// An internal structure to this crate to build an `Instance` from a list of
|
||||||
|
/// items with names. This is intended to stay private for now, it'll need an
|
||||||
|
/// audit of APIs if publicly exported.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(crate) struct InstanceBuilder {
|
||||||
|
items: RuntimeInstance,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstanceBuilder {
|
||||||
|
pub(crate) fn new() -> InstanceBuilder {
|
||||||
|
InstanceBuilder::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn insert(&mut self, name: &str, item: impl Into<Extern>) {
|
||||||
|
let items = Rc::get_mut(&mut self.items).unwrap();
|
||||||
|
let export = match item.into() {
|
||||||
|
Extern::Func(i) => wasmtime_runtime::Export::Function(i.wasmtime_export().clone()),
|
||||||
|
Extern::Memory(i) => wasmtime_runtime::Export::Memory(i.wasmtime_export().clone()),
|
||||||
|
Extern::Table(i) => wasmtime_runtime::Export::Table(i.wasmtime_export().clone()),
|
||||||
|
Extern::Global(i) => wasmtime_runtime::Export::Global(i.wasmtime_export().clone()),
|
||||||
|
Extern::Instance(i) => wasmtime_runtime::Export::Instance(i.items.clone()),
|
||||||
|
Extern::Module(i) => wasmtime_runtime::Export::Module(Box::new(i.clone())),
|
||||||
|
};
|
||||||
|
items.insert(name.to_string(), export);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn finish(self, store: &Store) -> Instance {
|
||||||
|
Instance {
|
||||||
|
store: store.clone(),
|
||||||
|
items: self.items,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::instance::InstanceBuilder;
|
||||||
use crate::{
|
use crate::{
|
||||||
Extern, ExternType, Func, FuncType, GlobalType, ImportType, Instance, IntoFunc, Module, Store,
|
Extern, ExternType, Func, FuncType, GlobalType, ImportType, Instance, IntoFunc, Module, Store,
|
||||||
Trap,
|
Trap,
|
||||||
@@ -654,7 +655,37 @@ impl Linker {
|
|||||||
},
|
},
|
||||||
kind: self.import_kind(import.ty()),
|
kind: self.import_kind(import.ty()),
|
||||||
};
|
};
|
||||||
self.map.get(&key).cloned()
|
if let Some(result) = self.map.get(&key).cloned() {
|
||||||
|
return Some(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a key location where the module linking proposal is
|
||||||
|
// implemented. This logic allows single-level imports of an instance to
|
||||||
|
// get satisfied by multiple definitions of items within this `Linker`.
|
||||||
|
//
|
||||||
|
// The instance being import is iterated over to load the names from
|
||||||
|
// this `Linker` (recursively calling `get`). If anything isn't defined
|
||||||
|
// we return `None` since the entire value isn't defined. Otherwise when
|
||||||
|
// all values are loaded it's assembled into an `Instance` and
|
||||||
|
// returned`.
|
||||||
|
//
|
||||||
|
// Note that this isn't exactly the speediest implementation in the
|
||||||
|
// world. Ideally we would pre-create the `Instance` instead of creating
|
||||||
|
// it each time a module is instantiated. For now though while the
|
||||||
|
// module linking proposal is under development this should hopefully
|
||||||
|
// suffice.
|
||||||
|
if let ExternType::Instance(t) = import.ty() {
|
||||||
|
if import.name().is_none() {
|
||||||
|
let mut builder = InstanceBuilder::new();
|
||||||
|
for export in t.exports() {
|
||||||
|
let item = self.get(&export.as_import(import.module()))?;
|
||||||
|
builder.insert(export.name(), item);
|
||||||
|
}
|
||||||
|
return Some(builder.finish(&self.store).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all items defined for the `module` and `name` pair.
|
/// Returns all items defined for the `module` and `name` pair.
|
||||||
|
|||||||
@@ -245,12 +245,14 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
|
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
|
||||||
#[cfg(feature = "cache")]
|
#[cfg(feature = "cache")]
|
||||||
let (artifacts, types) = ModuleCacheEntry::new("wasmtime", engine.cache_config())
|
let (main_module, artifacts, types) =
|
||||||
.get_data((engine.compiler(), binary), |(compiler, binary)| {
|
ModuleCacheEntry::new("wasmtime", engine.cache_config())
|
||||||
CompilationArtifacts::build(compiler, binary)
|
.get_data((engine.compiler(), binary), |(compiler, binary)| {
|
||||||
})?;
|
CompilationArtifacts::build(compiler, binary)
|
||||||
|
})?;
|
||||||
#[cfg(not(feature = "cache"))]
|
#[cfg(not(feature = "cache"))]
|
||||||
let (artifacts, types) = CompilationArtifacts::build(engine.compiler(), binary)?;
|
let (main_module, artifacts, types) =
|
||||||
|
CompilationArtifacts::build(engine.compiler(), binary)?;
|
||||||
|
|
||||||
let modules = CompiledModule::from_artifacts_list(
|
let modules = CompiledModule::from_artifacts_list(
|
||||||
artifacts,
|
artifacts,
|
||||||
@@ -261,7 +263,7 @@ impl Module {
|
|||||||
let types = Arc::new(types);
|
let types = Arc::new(types);
|
||||||
Ok(Module {
|
Ok(Module {
|
||||||
engine: engine.clone(),
|
engine: engine.clone(),
|
||||||
index: 0,
|
index: main_module,
|
||||||
data: Arc::new(ModuleData { types, modules }),
|
data: Arc::new(ModuleData { types, modules }),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ use std::sync::Arc;
|
|||||||
use wasmtime_environ::wasm;
|
use wasmtime_environ::wasm;
|
||||||
use wasmtime_jit::{CompiledModule, ModuleCode, TypeTables};
|
use wasmtime_jit::{CompiledModule, ModuleCode, TypeTables};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
InstanceHandle, RuntimeMemoryCreator, SignalHandler, StackMapRegistry, TrapInfo, VMExternRef,
|
InstanceHandle, RuntimeMemoryCreator, SignalHandler, StackMapRegistry, TrapInfo, VMContext,
|
||||||
VMExternRefActivationsTable, VMInterrupts, VMSharedSignatureIndex,
|
VMExternRef, VMExternRefActivationsTable, VMInterrupts, VMSharedSignatureIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A `Store` is a collection of WebAssembly instances and host-defined items.
|
/// A `Store` is a collection of WebAssembly instances and host-defined items.
|
||||||
@@ -234,6 +234,10 @@ impl Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn existing_vmctx(&self, cx: *mut VMContext) -> StoreInstanceHandle {
|
||||||
|
self.existing_instance_handle(InstanceHandle::from_vmctx(cx))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn weak(&self) -> Weak<StoreInner> {
|
pub(crate) fn weak(&self) -> Weak<StoreInner> {
|
||||||
Rc::downgrade(&self.inner)
|
Rc::downgrade(&self.inner)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
|
|||||||
module
|
module
|
||||||
.initializers
|
.initializers
|
||||||
.push(wasmtime_environ::Initializer::Import {
|
.push(wasmtime_environ::Initializer::Import {
|
||||||
module: "".into(),
|
name: "".into(),
|
||||||
field: None,
|
field: None,
|
||||||
index: wasm::EntityIndex::Function(func_index),
|
index: wasm::EntityIndex::Function(func_index),
|
||||||
});
|
});
|
||||||
@@ -80,7 +80,7 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<StoreIn
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Some(x) = externref_init {
|
if let Some(x) = externref_init {
|
||||||
match handle.lookup("").unwrap() {
|
match handle.lookup_by_declaration(&wasm::EntityIndex::Global(global_id)) {
|
||||||
wasmtime_runtime::Export::Global(g) => unsafe {
|
wasmtime_runtime::Export::Global(g) => unsafe {
|
||||||
*(*g.definition).as_externref_mut() = Some(x.inner);
|
*(*g.definition).as_externref_mut() = Some(x.inner);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use crate::{FuncType, GlobalType, MemoryType, Store, TableType, Trap, Val};
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use wasmtime_environ::wasm;
|
||||||
use wasmtime_runtime::{InstanceHandle, VMContext, VMFunctionBody, VMTrampoline};
|
use wasmtime_runtime::{InstanceHandle, VMContext, VMFunctionBody, VMTrampoline};
|
||||||
|
|
||||||
/// A wrapper around `wasmtime_runtime::InstanceHandle` which pairs it with the
|
/// A wrapper around `wasmtime_runtime::InstanceHandle` which pairs it with the
|
||||||
@@ -55,7 +56,8 @@ pub fn generate_func_export(
|
|||||||
VMTrampoline,
|
VMTrampoline,
|
||||||
)> {
|
)> {
|
||||||
let (instance, trampoline) = create_handle_with_function(ft, func, store)?;
|
let (instance, trampoline) = create_handle_with_function(ft, func, store)?;
|
||||||
match instance.lookup("").expect("trampoline export") {
|
let idx = wasm::EntityIndex::Function(wasm::FuncIndex::from_u32(0));
|
||||||
|
match instance.lookup_by_declaration(&idx) {
|
||||||
wasmtime_runtime::Export::Function(f) => Ok((instance, f, trampoline)),
|
wasmtime_runtime::Export::Function(f) => Ok((instance, f, trampoline)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -72,7 +74,8 @@ pub unsafe fn generate_raw_func_export(
|
|||||||
state: Box<dyn Any>,
|
state: Box<dyn Any>,
|
||||||
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportFunction)> {
|
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportFunction)> {
|
||||||
let instance = func::create_handle_with_raw_function(ft, func, trampoline, store, state)?;
|
let instance = func::create_handle_with_raw_function(ft, func, trampoline, store, state)?;
|
||||||
match instance.lookup("").expect("trampoline export") {
|
let idx = wasm::EntityIndex::Function(wasm::FuncIndex::from_u32(0));
|
||||||
|
match instance.lookup_by_declaration(&idx) {
|
||||||
wasmtime_runtime::Export::Function(f) => Ok((instance, f)),
|
wasmtime_runtime::Export::Function(f) => Ok((instance, f)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -84,7 +87,8 @@ pub fn generate_global_export(
|
|||||||
val: Val,
|
val: Val,
|
||||||
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportGlobal)> {
|
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportGlobal)> {
|
||||||
let instance = create_global(store, gt, val)?;
|
let instance = create_global(store, gt, val)?;
|
||||||
match instance.lookup("").expect("global export") {
|
let idx = wasm::EntityIndex::Global(wasm::GlobalIndex::from_u32(0));
|
||||||
|
match instance.lookup_by_declaration(&idx) {
|
||||||
wasmtime_runtime::Export::Global(g) => Ok((instance, g)),
|
wasmtime_runtime::Export::Global(g) => Ok((instance, g)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -95,7 +99,8 @@ pub fn generate_memory_export(
|
|||||||
m: &MemoryType,
|
m: &MemoryType,
|
||||||
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportMemory)> {
|
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportMemory)> {
|
||||||
let instance = create_handle_with_memory(store, m)?;
|
let instance = create_handle_with_memory(store, m)?;
|
||||||
match instance.lookup("").expect("memory export") {
|
let idx = wasm::EntityIndex::Memory(wasm::MemoryIndex::from_u32(0));
|
||||||
|
match instance.lookup_by_declaration(&idx) {
|
||||||
wasmtime_runtime::Export::Memory(m) => Ok((instance, m)),
|
wasmtime_runtime::Export::Memory(m) => Ok((instance, m)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -106,7 +111,8 @@ pub fn generate_table_export(
|
|||||||
t: &TableType,
|
t: &TableType,
|
||||||
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportTable)> {
|
) -> Result<(StoreInstanceHandle, wasmtime_runtime::ExportTable)> {
|
||||||
let instance = create_handle_with_table(store, t)?;
|
let instance = create_handle_with_table(store, t)?;
|
||||||
match instance.lookup("").expect("table export") {
|
let idx = wasm::EntityIndex::Table(wasm::TableIndex::from_u32(0));
|
||||||
|
match instance.lookup_by_declaration(&idx) {
|
||||||
wasmtime_runtime::Export::Table(t) => Ok((instance, t)),
|
wasmtime_runtime::Export::Table(t) => Ok((instance, t)),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result<Stor
|
|||||||
|
|
||||||
let table_plan = wasmtime_environ::TablePlan::for_table(table, &tunable);
|
let table_plan = wasmtime_environ::TablePlan::for_table(table, &tunable);
|
||||||
let table_id = module.table_plans.push(table_plan);
|
let table_id = module.table_plans.push(table_plan);
|
||||||
|
// TODO: can this `exports.insert` get removed?
|
||||||
module
|
module
|
||||||
.exports
|
.exports
|
||||||
.insert(String::new(), wasm::EntityIndex::Table(table_id));
|
.insert(String::new(), wasm::EntityIndex::Table(table_id));
|
||||||
|
|||||||
@@ -466,21 +466,21 @@ impl ModuleType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a new export to this `ModuleType`.
|
/// Adds a new export to this `ModuleType`.
|
||||||
pub fn add_named_export(&mut self, name: &str, ty: ExternType) {
|
pub(crate) fn add_named_export(&mut self, name: &str, ty: ExternType) {
|
||||||
self.exports.push((name.to_string(), ty));
|
self.exports.push((name.to_string(), ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a new import to this `ModuleType`.
|
/// Adds a new import to this `ModuleType`.
|
||||||
pub fn add_named_import(&mut self, module: &str, field: Option<&str>, ty: ExternType) {
|
pub(crate) fn add_named_import(&mut self, module: &str, field: Option<&str>, ty: ExternType) {
|
||||||
self.imports
|
self.imports
|
||||||
.push((module.to_string(), field.map(|f| f.to_string()), ty));
|
.push((module.to_string(), field.map(|f| f.to_string()), ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of imports associated with this module type.
|
/// Returns the list of imports associated with this module type.
|
||||||
pub fn imports(&self) -> impl ExactSizeIterator<Item = ImportType<'_>> {
|
pub fn imports(&self) -> impl ExactSizeIterator<Item = ImportType<'_>> {
|
||||||
self.imports.iter().map(|(module, name, ty)| ImportType {
|
self.imports.iter().map(|(name, field, ty)| ImportType {
|
||||||
module,
|
module: name,
|
||||||
name: name.as_deref(),
|
name: field.as_deref(),
|
||||||
ty: EntityOrExtern::Extern(ty),
|
ty: EntityOrExtern::Extern(ty),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -506,13 +506,7 @@ impl ModuleType {
|
|||||||
imports: ty
|
imports: ty
|
||||||
.imports
|
.imports
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(m, name, ty)| {
|
.map(|(m, ty)| (m.to_string(), None, ExternType::from_wasmtime(types, ty)))
|
||||||
(
|
|
||||||
m.to_string(),
|
|
||||||
name.as_ref().map(|n| n.to_string()),
|
|
||||||
ExternType::from_wasmtime(types, ty),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -615,8 +609,9 @@ impl<'module> ImportType<'module> {
|
|||||||
/// Returns the field name of the module that this import is expected to
|
/// Returns the field name of the module that this import is expected to
|
||||||
/// come from.
|
/// come from.
|
||||||
///
|
///
|
||||||
/// Note that the name can be `None` for the module linking proposal. If the
|
/// Note that this is optional due to the module linking proposal. If the
|
||||||
/// module linking proposal is not enabled it's safe to unwrap this.
|
/// module linking proposal is enabled this is always `None`, otherwise this
|
||||||
|
/// is always `Some`.
|
||||||
pub fn name(&self) -> Option<&'module str> {
|
pub fn name(&self) -> Option<&'module str> {
|
||||||
self.name
|
self.name
|
||||||
}
|
}
|
||||||
@@ -683,6 +678,17 @@ impl<'module> ExportType<'module> {
|
|||||||
EntityOrExtern::Extern(e) => (*e).clone(),
|
EntityOrExtern::Extern(e) => (*e).clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn as_import<'a>(&self, module: &'a str) -> ImportType<'a>
|
||||||
|
where
|
||||||
|
'module: 'a,
|
||||||
|
{
|
||||||
|
ImportType {
|
||||||
|
module,
|
||||||
|
name: Some(self.name),
|
||||||
|
ty: self.ty.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'module> fmt::Debug for ExportType<'module> {
|
impl<'module> fmt::Debug for ExportType<'module> {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::Store;
|
use crate::{Extern, Store};
|
||||||
use std::sync::Arc;
|
use anyhow::{bail, Context, Result};
|
||||||
use wasmtime_environ::wasm::{
|
use wasmtime_environ::wasm::{
|
||||||
EntityType, Global, InstanceTypeIndex, Memory, ModuleTypeIndex, SignatureIndex, Table,
|
EntityType, Global, InstanceTypeIndex, Memory, ModuleTypeIndex, SignatureIndex, Table,
|
||||||
};
|
};
|
||||||
@@ -11,22 +11,27 @@ pub struct MatchCx<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MatchCx<'_> {
|
impl MatchCx<'_> {
|
||||||
pub fn global(&self, expected: &Global, actual: &crate::Global) -> bool {
|
pub fn global(&self, expected: &Global, actual: &crate::Global) -> Result<()> {
|
||||||
self.global_ty(expected, actual.wasmtime_ty())
|
self.global_ty(expected, actual.wasmtime_ty())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_ty(&self, expected: &Global, actual: &Global) -> bool {
|
fn global_ty(&self, expected: &Global, actual: &Global) -> Result<()> {
|
||||||
expected.ty == actual.ty
|
if expected.ty == actual.ty
|
||||||
&& expected.wasm_ty == actual.wasm_ty
|
&& expected.wasm_ty == actual.wasm_ty
|
||||||
&& expected.mutability == actual.mutability
|
&& expected.mutability == actual.mutability
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
bail!("global types incompatible")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn table(&self, expected: &Table, actual: &crate::Table) -> bool {
|
pub fn table(&self, expected: &Table, actual: &crate::Table) -> Result<()> {
|
||||||
self.table_ty(expected, actual.wasmtime_ty())
|
self.table_ty(expected, actual.wasmtime_ty())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table_ty(&self, expected: &Table, actual: &Table) -> bool {
|
fn table_ty(&self, expected: &Table, actual: &Table) -> Result<()> {
|
||||||
expected.wasm_ty == actual.wasm_ty
|
if expected.wasm_ty == actual.wasm_ty
|
||||||
&& expected.ty == actual.ty
|
&& expected.ty == actual.ty
|
||||||
&& expected.minimum <= actual.minimum
|
&& expected.minimum <= actual.minimum
|
||||||
&& match expected.maximum {
|
&& match expected.maximum {
|
||||||
@@ -36,14 +41,19 @@ impl MatchCx<'_> {
|
|||||||
},
|
},
|
||||||
None => true,
|
None => true,
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
bail!("table types incompatible")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn memory(&self, expected: &Memory, actual: &crate::Memory) -> bool {
|
pub fn memory(&self, expected: &Memory, actual: &crate::Memory) -> Result<()> {
|
||||||
self.memory_ty(expected, actual.wasmtime_ty())
|
self.memory_ty(expected, actual.wasmtime_ty())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn memory_ty(&self, expected: &Memory, actual: &Memory) -> bool {
|
fn memory_ty(&self, expected: &Memory, actual: &Memory) -> Result<()> {
|
||||||
expected.shared == actual.shared
|
if expected.shared == actual.shared
|
||||||
&& expected.minimum <= actual.minimum
|
&& expected.minimum <= actual.minimum
|
||||||
&& match expected.maximum {
|
&& match expected.maximum {
|
||||||
Some(expected) => match actual.maximum {
|
Some(expected) => match actual.maximum {
|
||||||
@@ -52,10 +62,15 @@ impl MatchCx<'_> {
|
|||||||
},
|
},
|
||||||
None => true,
|
None => true,
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
bail!("memory types incompatible")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn func(&self, expected: SignatureIndex, actual: &crate::Func) -> bool {
|
pub fn func(&self, expected: SignatureIndex, actual: &crate::Func) -> Result<()> {
|
||||||
match self
|
let matches = match self
|
||||||
.store
|
.store
|
||||||
.signatures()
|
.signatures()
|
||||||
.borrow()
|
.borrow()
|
||||||
@@ -65,31 +80,50 @@ impl MatchCx<'_> {
|
|||||||
// If our expected signature isn't registered, then there's no way
|
// If our expected signature isn't registered, then there's no way
|
||||||
// that `actual` can match it.
|
// that `actual` can match it.
|
||||||
None => false,
|
None => false,
|
||||||
|
};
|
||||||
|
if matches {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
bail!("function types incompatible")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn instance(&self, expected: InstanceTypeIndex, actual: &crate::Instance) -> bool {
|
pub fn instance(&self, expected: InstanceTypeIndex, actual: &crate::Instance) -> Result<()> {
|
||||||
let module = actual.handle.module();
|
for (name, expected) in self.types.instance_signatures[expected].exports.iter() {
|
||||||
self.exports_match(
|
match actual.items.get(name) {
|
||||||
expected,
|
Some(item) => {
|
||||||
actual
|
let item = unsafe { Extern::from_wasmtime_export(item, self.store) };
|
||||||
.handle
|
self.extern_(expected, &item)
|
||||||
.host_state()
|
.with_context(|| format!("instance export {:?} incompatible", name))?;
|
||||||
.downcast_ref::<Arc<TypeTables>>()
|
}
|
||||||
.unwrap(),
|
None => bail!("instance type missing export {:?}", name),
|
||||||
|name| module.exports.get(name).map(|idx| module.type_of(*idx)),
|
}
|
||||||
)
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates that the type signature of `actual` matches the `expected`
|
/// Validates that the type signature of `actual` matches the `expected`
|
||||||
/// module type signature.
|
/// module type signature.
|
||||||
pub fn module(&self, expected: ModuleTypeIndex, actual: &crate::Module) -> bool {
|
pub fn module(&self, expected: ModuleTypeIndex, actual: &crate::Module) -> Result<()> {
|
||||||
|
// This should only ever be invoked with module linking, and this is an
|
||||||
|
// early check that our `field` assertion below should always work as
|
||||||
|
// well.
|
||||||
|
assert!(self.store.engine().config().features.module_linking);
|
||||||
|
|
||||||
let expected_sig = &self.types.module_signatures[expected];
|
let expected_sig = &self.types.module_signatures[expected];
|
||||||
let module = actual.compiled_module().module();
|
let module = actual.compiled_module().module();
|
||||||
self.imports_match(expected, actual.types(), module.imports())
|
self.imports_match(
|
||||||
&& self.exports_match(expected_sig.exports, actual.types(), |name| {
|
expected,
|
||||||
module.exports.get(name).map(|idx| module.type_of(*idx))
|
actual.types(),
|
||||||
})
|
module.imports().map(|(name, field, ty)| {
|
||||||
|
assert!(field.is_none()); // should be true if module linking is enabled
|
||||||
|
(name, ty)
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
self.exports_match(expected_sig.exports, actual.types(), |name| {
|
||||||
|
module.exports.get(name).map(|idx| module.type_of(*idx))
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates that the `actual_imports` list of module imports matches the
|
/// Validates that the `actual_imports` list of module imports matches the
|
||||||
@@ -100,19 +134,25 @@ impl MatchCx<'_> {
|
|||||||
&self,
|
&self,
|
||||||
expected: ModuleTypeIndex,
|
expected: ModuleTypeIndex,
|
||||||
actual_types: &TypeTables,
|
actual_types: &TypeTables,
|
||||||
mut actual_imports: impl Iterator<Item = (&'a str, Option<&'a str>, EntityType)>,
|
actual_imports: impl Iterator<Item = (&'a str, EntityType)>,
|
||||||
) -> bool {
|
) -> Result<()> {
|
||||||
|
// Imports match if all of the actual imports are satisfied by the
|
||||||
|
// expected set of imports. Note that we're reversing the order of the
|
||||||
|
// subtytpe matching here too.
|
||||||
let expected_sig = &self.types.module_signatures[expected];
|
let expected_sig = &self.types.module_signatures[expected];
|
||||||
for (_, _, expected) in expected_sig.imports.iter() {
|
for (name, actual_ty) in actual_imports {
|
||||||
let (_, _, ty) = match actual_imports.next() {
|
let expected_ty = match expected_sig.imports.get(name) {
|
||||||
Some(e) => e,
|
Some(ty) => ty,
|
||||||
None => return false,
|
None => bail!("expected type doesn't import {:?}", name),
|
||||||
};
|
};
|
||||||
if !self.extern_ty_matches(expected, &ty, actual_types) {
|
MatchCx {
|
||||||
return false;
|
types: actual_types,
|
||||||
|
store: self.store,
|
||||||
}
|
}
|
||||||
|
.extern_ty_matches(&actual_ty, expected_ty, self.types)
|
||||||
|
.with_context(|| format!("module import {:?} incompatible", name))?;
|
||||||
}
|
}
|
||||||
actual_imports.next().is_none()
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates that all exports in `expected` are defined by `lookup` within
|
/// Validates that all exports in `expected` are defined by `lookup` within
|
||||||
@@ -122,16 +162,19 @@ impl MatchCx<'_> {
|
|||||||
expected: InstanceTypeIndex,
|
expected: InstanceTypeIndex,
|
||||||
actual_types: &TypeTables,
|
actual_types: &TypeTables,
|
||||||
lookup: impl Fn(&str) -> Option<EntityType>,
|
lookup: impl Fn(&str) -> Option<EntityType>,
|
||||||
) -> bool {
|
) -> Result<()> {
|
||||||
// The `expected` type must be a subset of `actual`, meaning that all
|
// The `expected` type must be a subset of `actual`, meaning that all
|
||||||
// names in `expected` must be present in `actual`. Note that we do
|
// names in `expected` must be present in `actual`. Note that we do
|
||||||
// name-based lookup here instead of index-based lookup.
|
// name-based lookup here instead of index-based lookup.
|
||||||
self.types.instance_signatures[expected].exports.iter().all(
|
for (name, expected) in self.types.instance_signatures[expected].exports.iter() {
|
||||||
|(name, expected)| match lookup(name) {
|
match lookup(name) {
|
||||||
Some(ty) => self.extern_ty_matches(expected, &ty, actual_types),
|
Some(ty) => self
|
||||||
None => false,
|
.extern_ty_matches(expected, &ty, actual_types)
|
||||||
},
|
.with_context(|| format!("export {:?} incompatible", name))?,
|
||||||
)
|
None => bail!("failed to find export {:?}", name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates that the `expected` entity matches the `actual_ty` defined
|
/// Validates that the `expected` entity matches the `actual_ty` defined
|
||||||
@@ -141,34 +184,49 @@ impl MatchCx<'_> {
|
|||||||
expected: &EntityType,
|
expected: &EntityType,
|
||||||
actual_ty: &EntityType,
|
actual_ty: &EntityType,
|
||||||
actual_types: &TypeTables,
|
actual_types: &TypeTables,
|
||||||
) -> bool {
|
) -> Result<()> {
|
||||||
|
let actual_desc = match actual_ty {
|
||||||
|
EntityType::Global(_) => "global",
|
||||||
|
EntityType::Module(_) => "module",
|
||||||
|
EntityType::Memory(_) => "memory",
|
||||||
|
EntityType::Event(_) => "event",
|
||||||
|
EntityType::Instance(_) => "instance",
|
||||||
|
EntityType::Table(_) => "table",
|
||||||
|
EntityType::Function(_) => "function",
|
||||||
|
};
|
||||||
match expected {
|
match expected {
|
||||||
EntityType::Global(expected) => match actual_ty {
|
EntityType::Global(expected) => match actual_ty {
|
||||||
EntityType::Global(actual) => self.global_ty(expected, actual),
|
EntityType::Global(actual) => self.global_ty(expected, actual),
|
||||||
_ => false,
|
_ => bail!("expected global, but found {}", actual_desc),
|
||||||
},
|
},
|
||||||
EntityType::Table(expected) => match actual_ty {
|
EntityType::Table(expected) => match actual_ty {
|
||||||
EntityType::Table(actual) => self.table_ty(expected, actual),
|
EntityType::Table(actual) => self.table_ty(expected, actual),
|
||||||
_ => false,
|
_ => bail!("expected table, but found {}", actual_desc),
|
||||||
},
|
},
|
||||||
EntityType::Memory(expected) => match actual_ty {
|
EntityType::Memory(expected) => match actual_ty {
|
||||||
EntityType::Memory(actual) => self.memory_ty(expected, actual),
|
EntityType::Memory(actual) => self.memory_ty(expected, actual),
|
||||||
_ => false,
|
_ => bail!("expected memory, but found {}", actual_desc),
|
||||||
},
|
},
|
||||||
EntityType::Function(expected) => match *actual_ty {
|
EntityType::Function(expected) => match *actual_ty {
|
||||||
EntityType::Function(actual) => {
|
EntityType::Function(actual) => {
|
||||||
self.types.wasm_signatures[*expected] == actual_types.wasm_signatures[actual]
|
if self.types.wasm_signatures[*expected] == actual_types.wasm_signatures[actual]
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
bail!("function types incompatible")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => bail!("expected function, but found {}", actual_desc),
|
||||||
},
|
},
|
||||||
EntityType::Instance(expected) => match actual_ty {
|
EntityType::Instance(expected) => match actual_ty {
|
||||||
EntityType::Instance(actual) => {
|
EntityType::Instance(actual) => {
|
||||||
let sig = &actual_types.instance_signatures[*actual];
|
let sig = &actual_types.instance_signatures[*actual];
|
||||||
self.exports_match(*expected, actual_types, |name| {
|
self.exports_match(*expected, actual_types, |name| {
|
||||||
sig.exports.get(name).cloned()
|
sig.exports.get(name).cloned()
|
||||||
})
|
})?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => bail!("expected instance, but found {}", actual_desc),
|
||||||
},
|
},
|
||||||
EntityType::Module(expected) => match actual_ty {
|
EntityType::Module(expected) => match actual_ty {
|
||||||
EntityType::Module(actual) => {
|
EntityType::Module(actual) => {
|
||||||
@@ -180,14 +238,48 @@ impl MatchCx<'_> {
|
|||||||
self.imports_match(
|
self.imports_match(
|
||||||
*expected,
|
*expected,
|
||||||
actual_types,
|
actual_types,
|
||||||
actual_module_sig.imports.iter().map(|(module, field, ty)| {
|
actual_module_sig
|
||||||
(module.as_str(), field.as_deref(), ty.clone())
|
.imports
|
||||||
}),
|
.iter()
|
||||||
) && self.exports_match(expected_module_sig.exports, actual_types, |name| {
|
.map(|(module, ty)| (module.as_str(), ty.clone())),
|
||||||
|
)?;
|
||||||
|
self.exports_match(expected_module_sig.exports, actual_types, |name| {
|
||||||
actual_instance_sig.exports.get(name).cloned()
|
actual_instance_sig.exports.get(name).cloned()
|
||||||
})
|
})?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => bail!("expected module, but found {}", actual_desc),
|
||||||
|
},
|
||||||
|
EntityType::Event(_) => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validates that the `expected` type matches the type of `actual`
|
||||||
|
pub fn extern_(&self, expected: &EntityType, actual: &Extern) -> Result<()> {
|
||||||
|
match expected {
|
||||||
|
EntityType::Global(expected) => match actual {
|
||||||
|
Extern::Global(actual) => self.global(expected, actual),
|
||||||
|
_ => bail!("expected global, but found {}", actual.desc()),
|
||||||
|
},
|
||||||
|
EntityType::Table(expected) => match actual {
|
||||||
|
Extern::Table(actual) => self.table(expected, actual),
|
||||||
|
_ => bail!("expected table, but found {}", actual.desc()),
|
||||||
|
},
|
||||||
|
EntityType::Memory(expected) => match actual {
|
||||||
|
Extern::Memory(actual) => self.memory(expected, actual),
|
||||||
|
_ => bail!("expected memory, but found {}", actual.desc()),
|
||||||
|
},
|
||||||
|
EntityType::Function(expected) => match actual {
|
||||||
|
Extern::Func(actual) => self.func(*expected, actual),
|
||||||
|
_ => bail!("expected func, but found {}", actual.desc()),
|
||||||
|
},
|
||||||
|
EntityType::Instance(expected) => match actual {
|
||||||
|
Extern::Instance(actual) => self.instance(*expected, actual),
|
||||||
|
_ => bail!("expected instance, but found {}", actual.desc()),
|
||||||
|
},
|
||||||
|
EntityType::Module(expected) => match actual {
|
||||||
|
Extern::Module(actual) => self.module(*expected, actual),
|
||||||
|
_ => bail!("expected module, but found {}", actual.desc()),
|
||||||
},
|
},
|
||||||
EntityType::Event(_) => unimplemented!(),
|
EntityType::Event(_) => unimplemented!(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.19"
|
anyhow = "1.0.19"
|
||||||
wasmtime = { path = "../wasmtime", version = "0.22.0", default-features = false }
|
wasmtime = { path = "../wasmtime", version = "0.22.0", default-features = false }
|
||||||
wast = "29.0.0"
|
wast = "31.0.0"
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "actively-developed" }
|
maintenance = { status = "actively-developed" }
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ target-lexicon = "0.11"
|
|||||||
peepmatic-fuzzing = { path = "../cranelift/peepmatic/crates/fuzzing", optional = true }
|
peepmatic-fuzzing = { path = "../cranelift/peepmatic/crates/fuzzing", optional = true }
|
||||||
wasmtime = { path = "../crates/wasmtime" }
|
wasmtime = { path = "../crates/wasmtime" }
|
||||||
wasmtime-fuzzing = { path = "../crates/fuzzing" }
|
wasmtime-fuzzing = { path = "../crates/fuzzing" }
|
||||||
wasm-smith = "0.3.0"
|
wasm-smith = "0.3.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
experimental_x64 = ["wasmtime-fuzzing/experimental_x64"]
|
experimental_x64 = ["wasmtime-fuzzing/experimental_x64"]
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
|
|
||||||
use libfuzzer_sys::fuzz_target;
|
use libfuzzer_sys::fuzz_target;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use wasm_smith::{ConfiguredModule, SwarmConfig};
|
use wasm_smith::{Config, ConfiguredModule, SwarmConfig};
|
||||||
use wasmtime::Strategy;
|
use wasmtime::Strategy;
|
||||||
use wasmtime_fuzzing::oracles;
|
use wasmtime_fuzzing::oracles;
|
||||||
|
|
||||||
fuzz_target!(|module: ConfiguredModule<SwarmConfig>| {
|
fuzz_target!(|module: ConfiguredModule<SwarmConfig>| {
|
||||||
let mut cfg = wasmtime_fuzzing::fuzz_default_config(Strategy::Auto).unwrap();
|
let mut cfg = wasmtime_fuzzing::fuzz_default_config(Strategy::Auto).unwrap();
|
||||||
cfg.wasm_multi_memory(true);
|
cfg.wasm_multi_memory(true);
|
||||||
|
cfg.wasm_module_linking(module.config().module_linking_enabled());
|
||||||
oracles::instantiate_with_config(&module.to_bytes(), true, cfg, Some(Duration::from_secs(20)));
|
oracles::instantiate_with_config(&module.to_bytes(), true, cfg, Some(Duration::from_secs(20)));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ pub fn compile_to_obj(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let environ = ModuleEnvironment::new(compiler.isa().frontend_config(), &tunables, &features);
|
let environ = ModuleEnvironment::new(compiler.isa().frontend_config(), &tunables, &features);
|
||||||
let (mut translation, types) = environ
|
let (_main_module, mut translation, types) = environ
|
||||||
.translate(wasm)
|
.translate(wasm)
|
||||||
.context("failed to translate module")?;
|
.context("failed to translate module")?;
|
||||||
assert_eq!(translation.len(), 1);
|
assert_eq!(translation.len(), 1);
|
||||||
|
|||||||
@@ -105,8 +105,13 @@ fn imports_exports() -> Result<()> {
|
|||||||
assert_eq!(i.len(), 1);
|
assert_eq!(i.len(), 1);
|
||||||
let import = i.next().unwrap();
|
let import = i.next().unwrap();
|
||||||
assert_eq!(import.module(), "");
|
assert_eq!(import.module(), "");
|
||||||
assert_eq!(import.name(), Some("a"));
|
assert_eq!(import.name(), None);
|
||||||
let module_ty = match import.ty() {
|
let instance_ty = match import.ty() {
|
||||||
|
ExternType::Instance(t) => t,
|
||||||
|
_ => panic!("unexpected type"),
|
||||||
|
};
|
||||||
|
assert_eq!(instance_ty.exports().len(), 1);
|
||||||
|
let module_ty = match instance_ty.exports().next().unwrap().ty() {
|
||||||
ExternType::Module(m) => m,
|
ExternType::Module(m) => m,
|
||||||
_ => panic!("unexpected type"),
|
_ => panic!("unexpected type"),
|
||||||
};
|
};
|
||||||
@@ -148,8 +153,13 @@ fn imports_exports() -> Result<()> {
|
|||||||
assert_eq!(i.len(), 1);
|
assert_eq!(i.len(), 1);
|
||||||
let import = i.next().unwrap();
|
let import = i.next().unwrap();
|
||||||
assert_eq!(import.module(), "");
|
assert_eq!(import.module(), "");
|
||||||
assert_eq!(import.name(), Some("b"));
|
assert_eq!(import.name(), None);
|
||||||
let instance_ty = match import.ty() {
|
let instance_ty = match import.ty() {
|
||||||
|
ExternType::Instance(t) => t,
|
||||||
|
_ => panic!("unexpected type"),
|
||||||
|
};
|
||||||
|
assert_eq!(instance_ty.exports().len(), 1);
|
||||||
|
let instance_ty = match instance_ty.exports().next().unwrap().ty() {
|
||||||
ExternType::Instance(m) => m,
|
ExternType::Instance(m) => m,
|
||||||
_ => panic!("unexpected type"),
|
_ => panic!("unexpected type"),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
(instance $a (instantiate $m))
|
(instance $a (instantiate $m))
|
||||||
|
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
call $a.$foo)
|
call (func $a "foo"))
|
||||||
)
|
)
|
||||||
(assert_return (invoke "get") (i32.const 1))
|
(assert_return (invoke "get") (i32.const 1))
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
(instance $a (instantiate $m))
|
(instance $a (instantiate $m))
|
||||||
|
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
global.get $a.$g)
|
global.get (global $a "g"))
|
||||||
)
|
)
|
||||||
(assert_return (invoke "get") (i32.const 2))
|
(assert_return (invoke "get") (i32.const 2))
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
(data (i32.const 0) "\03\00\00\00")
|
(data (i32.const 0) "\03\00\00\00")
|
||||||
)
|
)
|
||||||
(instance $a (instantiate $m))
|
(instance $a (instantiate $m))
|
||||||
(alias (instance $a) (memory $m))
|
(alias $m (memory $a "m"))
|
||||||
|
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
i32.const 0
|
i32.const 0
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
|
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
i32.const 0
|
i32.const 0
|
||||||
call_indirect $a.$t (result i32))
|
call_indirect (table $a "t") (result i32))
|
||||||
)
|
)
|
||||||
(assert_return (invoke "get") (i32.const 4))
|
(assert_return (invoke "get") (i32.const 4))
|
||||||
|
|
||||||
@@ -62,11 +62,10 @@
|
|||||||
i32.const 5))
|
i32.const 5))
|
||||||
)
|
)
|
||||||
(instance $a (instantiate $m))
|
(instance $a (instantiate $m))
|
||||||
(instance $b (instantiate $a.$sub))
|
(instance $b (instantiate (module $a "module")))
|
||||||
(alias $b.$f (instance $b) (func 0))
|
|
||||||
|
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
call $b.$f)
|
call (func $b ""))
|
||||||
)
|
)
|
||||||
(assert_return (invoke "get") (i32.const 5))
|
(assert_return (invoke "get") (i32.const 5))
|
||||||
|
|
||||||
@@ -79,11 +78,9 @@
|
|||||||
(instance $i (export "") (instantiate $sub))
|
(instance $i (export "") (instantiate $sub))
|
||||||
)
|
)
|
||||||
(instance $a (instantiate $m))
|
(instance $a (instantiate $m))
|
||||||
(alias $a.$i (instance $a) (instance 0))
|
|
||||||
(alias $a.$i.$f (instance $a.$i) (func 0))
|
|
||||||
|
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
call $a.$i.$f)
|
call (func $a "" ""))
|
||||||
)
|
)
|
||||||
(assert_return (invoke "get") (i32.const 6))
|
(assert_return (invoke "get") (i32.const 6))
|
||||||
|
|
||||||
@@ -91,48 +88,51 @@
|
|||||||
(module
|
(module
|
||||||
(type $t (func))
|
(type $t (func))
|
||||||
(module $m
|
(module $m
|
||||||
(func $f (type $t))
|
(func $f (type outer 0 $t))
|
||||||
)
|
)
|
||||||
(instance $a (instantiate $m))
|
(instance $a (instantiate $m))
|
||||||
)
|
)
|
||||||
|
|
||||||
;; alias parent -- module
|
;; alias parent -- module
|
||||||
|
(; TODO
|
||||||
(module
|
(module
|
||||||
(module $a)
|
(module $a)
|
||||||
(module $m
|
(module $m
|
||||||
(instance (instantiate $a))
|
(instance (instantiate (module outer 0 $a)))
|
||||||
)
|
)
|
||||||
(instance (instantiate $m))
|
(instance (instantiate $m))
|
||||||
)
|
)
|
||||||
|
;)
|
||||||
|
|
||||||
;; The alias, import, type, module, and instance sections can all be interleaved
|
;; The alias, import, type, module, and instance sections can all be interleaved
|
||||||
(module
|
(module $ROOT
|
||||||
(module $a)
|
(module $a)
|
||||||
(type $t (func))
|
(type $t (func))
|
||||||
(module $m
|
(module $m
|
||||||
;; alias
|
;; alias
|
||||||
(alias $thunk parent (type $t))
|
(alias $thunk (type outer 0 $t))
|
||||||
;; import
|
;; import
|
||||||
(import "" "" (func (type $thunk)))
|
(import "" "" (func (type $thunk)))
|
||||||
;; module (referencing parent type)
|
;; module (referencing parent type)
|
||||||
(module
|
(module
|
||||||
(func (type $thunk))
|
(func (type outer $m $thunk))
|
||||||
|
(func (type outer $ROOT $t))
|
||||||
)
|
)
|
||||||
;; type
|
;; type
|
||||||
(type $thunk2 (func))
|
(type $thunk2 (func))
|
||||||
;; module (referencing previous alias)
|
;; module (referencing previous alias)
|
||||||
(module $m2
|
(module $m2
|
||||||
(func (export "") (type $thunk2))
|
(func (export "") (type outer $m $thunk2))
|
||||||
)
|
)
|
||||||
;; instance
|
;; instance
|
||||||
(instance $i (instantiate $m2))
|
(instance $i (instantiate $m2))
|
||||||
;; alias that instance
|
;; alias that instance
|
||||||
(alias $my_f (instance $i) (func 0))
|
(alias $my_f (func $i ""))
|
||||||
;; module
|
;; module
|
||||||
(module $m3
|
(module $m3
|
||||||
(import "" (func)))
|
(import "" (func)))
|
||||||
;; use our aliased function to create the module
|
;; use our aliased function to create the module
|
||||||
(instance $i2 (instantiate $m3 (func $my_f)))
|
(instance $i2 (instantiate $m3 "" (func $my_f)))
|
||||||
;; module
|
;; module
|
||||||
(module $m4
|
(module $m4
|
||||||
(import "" (func)))
|
(import "" (func)))
|
||||||
@@ -141,5 +141,5 @@
|
|||||||
;; instantiate the above module
|
;; instantiate the above module
|
||||||
(module $smol (func $f (export "")))
|
(module $smol (func $f (export "")))
|
||||||
(instance $smol (instantiate $smol))
|
(instance $smol (instantiate $smol))
|
||||||
(instance (instantiate $m (func $smol.$f)))
|
(instance (instantiate $m "" (instance $smol)))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,22 +9,36 @@
|
|||||||
|
|
||||||
(module
|
(module
|
||||||
(import "a" "m" (module))
|
(import "a" "m" (module))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "" (func))))
|
(import "a" "m" (module (export "" (func))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "a" (func))))
|
(import "a" "m" (module (export "a" (func))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "b" (global i32))))
|
(import "a" "m" (module (export "b" (global i32))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module
|
(import "a" "m" (module
|
||||||
(export "" (func))
|
(export "" (func))
|
||||||
(export "a" (func))
|
(export "a" (func))
|
||||||
))
|
))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module
|
(import "a" "m" (module
|
||||||
(export "a" (func))
|
(export "a" (func))
|
||||||
(export "" (func))
|
(export "" (func))
|
||||||
))
|
))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module
|
(import "a" "m" (module
|
||||||
(export "a" (func))
|
(export "a" (func))
|
||||||
(export "" (func))
|
(export "" (func))
|
||||||
(export "b" (global i32))
|
(export "b" (global i32))
|
||||||
))
|
))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module
|
(import "a" "m" (module
|
||||||
(export "b" (global i32))
|
(export "b" (global i32))
|
||||||
(export "a" (func))
|
(export "a" (func))
|
||||||
@@ -37,64 +51,60 @@
|
|||||||
(module (export "m")
|
(module (export "m")
|
||||||
(func (export ""))))
|
(func (export ""))))
|
||||||
|
|
||||||
(module
|
(module (import "a" "m" (module)))
|
||||||
(import "a" "m" (module))
|
(module (import "a" "m" (module (export "" (func)))))
|
||||||
(import "a" "m" (module (export "" (func))))
|
|
||||||
)
|
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (func (param i32))))))
|
(module (import "a" "m" (module (export "" (func (param i32))))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (func (result i32))))))
|
(module (import "a" "m" (module (export "" (func (result i32))))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (global i32)))))
|
(module (import "a" "m" (module (export "" (global i32)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (memory 1)))))
|
(module (import "a" "m" (module (export "" (memory 1)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (module)))))
|
(module (import "a" "m" (module (export "" (module)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (instance)))))
|
(module (import "a" "m" (module (export "" (instance)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
|
|
||||||
(module $a
|
(module $a
|
||||||
(module (export "m")
|
(module (export "m")
|
||||||
(global (export "") i32 (i32.const 0))))
|
(global (export "") i32 (i32.const 0))))
|
||||||
|
|
||||||
;; globals
|
;; globals
|
||||||
(module
|
(module (import "a" "m" (module)))
|
||||||
(import "a" "m" (module))
|
(module (import "a" "m" (module (export "" (global i32)))))
|
||||||
(import "a" "m" (module (export "" (global i32))))
|
|
||||||
)
|
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module
|
(module
|
||||||
(import "a" "m" (module (export "" (global (mut i32)))))
|
(import "a" "m" (module (export "" (global (mut i32)))))
|
||||||
)
|
)
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (global f32)))))
|
(module (import "a" "m" (module (export "" (global f32)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (func)))))
|
(module (import "a" "m" (module (export "" (func)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (memory 1)))))
|
(module (import "a" "m" (module (export "" (memory 1)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (module)))))
|
(module (import "a" "m" (module (export "" (module)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (instance)))))
|
(module (import "a" "m" (module (export "" (instance)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
|
|
||||||
;; tables
|
;; tables
|
||||||
(module $a
|
(module $a
|
||||||
@@ -105,40 +115,52 @@
|
|||||||
)
|
)
|
||||||
(module
|
(module
|
||||||
(import "a" "m" (module))
|
(import "a" "m" (module))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "" (table 1 funcref))))
|
(import "a" "m" (module (export "" (table 1 funcref))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "" (table 0 funcref))))
|
(import "a" "m" (module (export "" (table 0 funcref))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "max" (table 1 10 funcref))))
|
(import "a" "m" (module (export "max" (table 1 10 funcref))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "max" (table 0 10 funcref))))
|
(import "a" "m" (module (export "max" (table 0 10 funcref))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "max" (table 0 11 funcref))))
|
(import "a" "m" (module (export "max" (table 0 11 funcref))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "max" (table 0 funcref))))
|
(import "a" "m" (module (export "max" (table 0 funcref))))
|
||||||
)
|
)
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (global f32)))))
|
(module (import "a" "m" (module (export "" (global f32)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (func)))))
|
(module (import "a" "m" (module (export "" (func)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (table 2 funcref)))))
|
(module (import "a" "m" (module (export "" (table 2 funcref)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (table 1 10 funcref)))))
|
(module (import "a" "m" (module (export "" (table 1 10 funcref)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "max" (table 2 10 funcref)))))
|
(module (import "a" "m" (module (export "max" (table 2 10 funcref)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "max" (table 1 9 funcref)))))
|
(module (import "a" "m" (module (export "max" (table 1 9 funcref)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (memory 1)))))
|
(module (import "a" "m" (module (export "" (memory 1)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (module)))))
|
(module (import "a" "m" (module (export "" (module)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (instance)))))
|
(module (import "a" "m" (module (export "" (instance)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
|
|
||||||
;; memories
|
;; memories
|
||||||
(module $a
|
(module $a
|
||||||
@@ -149,40 +171,52 @@
|
|||||||
)
|
)
|
||||||
(module
|
(module
|
||||||
(import "a" "m" (module))
|
(import "a" "m" (module))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "" (memory 1))))
|
(import "a" "m" (module (export "" (memory 1))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "" (memory 0))))
|
(import "a" "m" (module (export "" (memory 0))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "max" (memory 1 10))))
|
(import "a" "m" (module (export "max" (memory 1 10))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "max" (memory 0 10))))
|
(import "a" "m" (module (export "max" (memory 0 10))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "max" (memory 0 11))))
|
(import "a" "m" (module (export "max" (memory 0 11))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "max" (memory 0))))
|
(import "a" "m" (module (export "max" (memory 0))))
|
||||||
)
|
)
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (global f32)))))
|
(module (import "a" "m" (module (export "" (global f32)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (func)))))
|
(module (import "a" "m" (module (export "" (func)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (memory 2)))))
|
(module (import "a" "m" (module (export "" (memory 2)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (memory 1 10)))))
|
(module (import "a" "m" (module (export "" (memory 1 10)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "max" (memory 2 10)))))
|
(module (import "a" "m" (module (export "max" (memory 2 10)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "max" (memory 2)))))
|
(module (import "a" "m" (module (export "max" (memory 2)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (module)))))
|
(module (import "a" "m" (module (export "" (module)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (instance)))))
|
(module (import "a" "m" (module (export "" (instance)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
|
|
||||||
;; modules
|
;; modules
|
||||||
(module $a
|
(module $a
|
||||||
@@ -206,72 +240,102 @@
|
|||||||
)
|
)
|
||||||
;; import a mixture
|
;; import a mixture
|
||||||
(module (export "e")
|
(module (export "e")
|
||||||
(import "" (func))
|
(import "a" (func))
|
||||||
(import "" (func))
|
(import "b" (func))
|
||||||
(import "" (global i32))
|
(import "c" (global i32))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
(module
|
(module
|
||||||
(import "a" "m" (module))
|
(import "a" "m" (module))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "a" (module))))
|
(import "a" "m" (module (export "a" (module))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "b" (module))))
|
(import "a" "m" (module (export "b" (module))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "b" (module (export "" (func))))))
|
(import "a" "m" (module (export "b" (module (export "" (func))))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "c" (module))))
|
(import "a" "m" (module (export "c" (module))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "c" (module
|
(import "a" "m" (module (export "c" (module
|
||||||
(export "a" (func))
|
(export "a" (func))
|
||||||
))))
|
))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "c" (module
|
(import "a" "m" (module (export "c" (module
|
||||||
(export "a" (func))
|
(export "a" (func))
|
||||||
(export "b" (func (result i32)))
|
(export "b" (func (result i32)))
|
||||||
))))
|
))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "c" (module
|
(import "a" "m" (module (export "c" (module
|
||||||
(export "c" (global i32))
|
(export "c" (global i32))
|
||||||
))))
|
))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "c" (module
|
(import "a" "m" (module (export "c" (module
|
||||||
(export "c" (global i32))
|
(export "c" (global i32))
|
||||||
(export "a" (func))
|
(export "a" (func))
|
||||||
))))
|
))))
|
||||||
|
)
|
||||||
;; for now import strings aren't matched at all, imports must simply pairwise
|
(module
|
||||||
;; line up
|
(import "a" "m" (module (export "d" (module
|
||||||
(import "a" "m" (module (export "d" (module (import "" (func))))))
|
(import "" (func))
|
||||||
(import "a" "m" (module (export "d" (module (import "x" (func))))))
|
|
||||||
(import "a" "m" (module (export "d" (module (import "x" "y" (func))))))
|
|
||||||
|
|
||||||
(import "a" "m" (module (export "e" (module
|
|
||||||
(import "x" "y" (func))
|
|
||||||
(import "a" (func))
|
(import "a" (func))
|
||||||
(import "z" (global i32))
|
))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
|
(import "a" "m" (module (export "d" (module (import "" (func))))))
|
||||||
|
)
|
||||||
|
(assert_unlinkable
|
||||||
|
(module
|
||||||
|
(import "a" "m" (module (export "d" (module (import "x" (func))))))
|
||||||
|
)
|
||||||
|
"incompatible import type for `a`")
|
||||||
|
(assert_unlinkable
|
||||||
|
(module
|
||||||
|
(import "a" "m" (module (export "d" (module (import "x" "y" (func))))))
|
||||||
|
)
|
||||||
|
"incompatible import type for `a`")
|
||||||
|
(module
|
||||||
|
(import "a" "m" (module (export "e" (module
|
||||||
|
(import "a" (func))
|
||||||
|
(import "b" (func))
|
||||||
|
(import "c" (global i32))
|
||||||
))))
|
))))
|
||||||
)
|
)
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (module (export "a" (func)))))))
|
(module (import "a" "m" (module (export "" (module (export "a" (func)))))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "d" (module)))))
|
(module (import "a" "m" (module (export "d" (module)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "d" (module (import "" (module)))))))
|
(module (import "a" "m" (module (export "d" (module (import "" (module)))))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (global f32)))))
|
(module (import "a" "m" (module (export "" (global f32)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (func)))))
|
(module (import "a" "m" (module (export "" (func)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (memory 2)))))
|
(module (import "a" "m" (module (export "" (memory 2)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (module (export "foo" (func)))))))
|
(module (import "a" "m" (module (export "" (module (export "foo" (func)))))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (instance)))))
|
(module (import "a" "m" (module (export "" (instance)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
|
|
||||||
;; instances
|
;; instances
|
||||||
(module $a
|
(module $a
|
||||||
@@ -303,46 +367,65 @@
|
|||||||
)
|
)
|
||||||
(module
|
(module
|
||||||
(import "a" "a" (instance))
|
(import "a" "a" (instance))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "b" (instance))
|
(import "a" "b" (instance))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "b" (instance (export "" (func))))
|
(import "a" "b" (instance (export "" (func))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "c" (instance))
|
(import "a" "c" (instance))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "c" (instance (export "a" (func))))
|
(import "a" "c" (instance (export "a" (func))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "c" (instance (export "b" (func (result i32)))))
|
(import "a" "c" (instance (export "b" (func (result i32)))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "c" (instance (export "c" (global i32))))
|
(import "a" "c" (instance (export "c" (global i32))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "c" (instance
|
(import "a" "c" (instance
|
||||||
(export "a" (func))
|
(export "a" (func))
|
||||||
(export "b" (func (result i32)))
|
(export "b" (func (result i32)))
|
||||||
(export "c" (global i32))
|
(export "c" (global i32))
|
||||||
))
|
))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "c" (instance
|
(import "a" "c" (instance
|
||||||
(export "c" (global i32))
|
(export "c" (global i32))
|
||||||
(export "a" (func))
|
(export "a" (func))
|
||||||
))
|
))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "i" (instance))))
|
(import "a" "m" (module (export "i" (instance))))
|
||||||
|
)
|
||||||
|
(module
|
||||||
(import "a" "m" (module (export "i" (instance (export "" (func))))))
|
(import "a" "m" (module (export "i" (instance (export "" (func))))))
|
||||||
)
|
)
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "a" (instance (export "" (global f32)))))
|
(module (import "a" "a" (instance (export "" (global f32)))))
|
||||||
"instance types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "i" (instance (export "x" (func)))))))
|
(module (import "a" "m" (module (export "i" (instance (export "x" (func)))))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (func)))))
|
(module (import "a" "m" (module (export "" (func)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
(module (import "a" "m" (module (export "" (table 1 funcref)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (memory 2)))))
|
(module (import "a" "m" (module (export "" (memory 2)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (memory 1 10)))))
|
(module (import "a" "m" (module (export "" (memory 1 10)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "max" (memory 2 10)))))
|
(module (import "a" "m" (module (export "max" (memory 2 10)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module (import "a" "m" (module (export "" (module)))))
|
(module (import "a" "m" (module (export "" (module)))))
|
||||||
"module types incompatible")
|
"incompatible import type for `a`")
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
(module
|
(module
|
||||||
(import "" (func))
|
(import "" (func))
|
||||||
(start 0))
|
(start 0))
|
||||||
(instance $a (instantiate 0 (func $set)))
|
(instance $a (instantiate 0 "" (func $set)))
|
||||||
)
|
)
|
||||||
|
|
||||||
(assert_return (invoke $a "get") (i32.const 1))
|
(assert_return (invoke $a "get") (i32.const 1))
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
global.set 0)
|
global.set 0)
|
||||||
(start 0))
|
(start 0))
|
||||||
|
|
||||||
(instance $a (instantiate 0 (global $g)))
|
(instance $a (instantiate 0 "" (global $g)))
|
||||||
)
|
)
|
||||||
(assert_return (invoke $a "get") (i32.const 2))
|
(assert_return (invoke $a "get") (i32.const 2))
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
call_indirect)
|
call_indirect)
|
||||||
(start 0))
|
(start 0))
|
||||||
|
|
||||||
(instance $a (instantiate 0 (table $t)))
|
(instance $a (instantiate 0 "" (table $t)))
|
||||||
)
|
)
|
||||||
(assert_return (invoke $a "get") (i32.const 3))
|
(assert_return (invoke $a "get") (i32.const 3))
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
i32.store)
|
i32.store)
|
||||||
(start 0))
|
(start 0))
|
||||||
|
|
||||||
(instance $a (instantiate 0 (memory $m)))
|
(instance $a (instantiate 0 "" (memory $m)))
|
||||||
)
|
)
|
||||||
(assert_return (invoke $a "load") (i32.const 100))
|
(assert_return (invoke $a "load") (i32.const 100))
|
||||||
|
|
||||||
@@ -88,13 +88,13 @@
|
|||||||
|
|
||||||
(module $m1
|
(module $m1
|
||||||
(import "" (instance (export "" (func))))
|
(import "" (instance (export "" (func))))
|
||||||
(alias (instance 0) (func 0))
|
(alias (func 0 ""))
|
||||||
(start 0))
|
(start 0))
|
||||||
|
|
||||||
(module $m2
|
(module $m2
|
||||||
(func (export "") (import "")))
|
(func (export "") (import "")))
|
||||||
(instance $i (instantiate $m2 (func $set)))
|
(instance $i (instantiate $m2 "" (func $set)))
|
||||||
(instance (instantiate $m1 (instance $i)))
|
(instance (instantiate $m1 "" (instance $i)))
|
||||||
)
|
)
|
||||||
(assert_return (invoke $a "get") (i32.const 4))
|
(assert_return (invoke $a "get") (i32.const 4))
|
||||||
|
|
||||||
@@ -106,14 +106,14 @@
|
|||||||
(import "" (module $m (export "" (func $f (result i32)))))
|
(import "" (module $m (export "" (func $f (result i32)))))
|
||||||
(instance $i (instantiate $m))
|
(instance $i (instantiate $m))
|
||||||
(func $get (export "") (result i32)
|
(func $get (export "") (result i32)
|
||||||
call $i.$f))
|
call (func $i "")))
|
||||||
|
|
||||||
(module $m2
|
(module $m2
|
||||||
(func (export "") (result i32)
|
(func (export "") (result i32)
|
||||||
i32.const 5))
|
i32.const 5))
|
||||||
(instance $i (instantiate $m1 (module $m2)))
|
(instance $i (instantiate $m1 "" (module $m2)))
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
call $i.$get)
|
call (func $i ""))
|
||||||
)
|
)
|
||||||
(assert_return (invoke "get") (i32.const 5))
|
(assert_return (invoke "get") (i32.const 5))
|
||||||
|
|
||||||
@@ -122,16 +122,16 @@
|
|||||||
(module $m
|
(module $m
|
||||||
(import "" (module $m (export "get" (func (result i32)))))
|
(import "" (module $m (export "get" (func (result i32)))))
|
||||||
(instance $i (instantiate $m))
|
(instance $i (instantiate $m))
|
||||||
(alias $f (instance $i) (func 0))
|
(alias $f (func $i "get"))
|
||||||
(export "" (func $f))
|
(export "" (func $f))
|
||||||
)
|
)
|
||||||
(module $m2
|
(module $m2
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
i32.const 6))
|
i32.const 6))
|
||||||
(instance $a (instantiate $m (module $m2)))
|
(instance $a (instantiate $m "" (module $m2)))
|
||||||
|
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
call $a.$f)
|
call (func $a ""))
|
||||||
)
|
)
|
||||||
(assert_return (invoke "get") (i32.const 6))
|
(assert_return (invoke "get") (i32.const 6))
|
||||||
|
|
||||||
@@ -143,10 +143,10 @@
|
|||||||
(import "a" "memory" (memory $m 1))
|
(import "a" "memory" (memory $m 1))
|
||||||
|
|
||||||
(module
|
(module
|
||||||
(import "" (memory 1))
|
(import "m" (memory 1))
|
||||||
(import "" (global (mut i32)))
|
(import "g" (global (mut i32)))
|
||||||
(import "" (table 1 funcref))
|
(import "t" (table 1 funcref))
|
||||||
(import "" (func))
|
(import "f" (func))
|
||||||
(func $start
|
(func $start
|
||||||
call 0
|
call 0
|
||||||
|
|
||||||
@@ -163,10 +163,10 @@
|
|||||||
|
|
||||||
(instance $a
|
(instance $a
|
||||||
(instantiate 0
|
(instantiate 0
|
||||||
(memory $m)
|
"m" (memory $m)
|
||||||
(global $g)
|
"g" (global $g)
|
||||||
(table $t)
|
"t" (table $t)
|
||||||
(func $f)
|
"f" (func $f)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -183,10 +183,10 @@
|
|||||||
(module $mt (import "" (table 1 funcref)))
|
(module $mt (import "" (table 1 funcref)))
|
||||||
(module $mg (import "" (global (mut i32))))
|
(module $mg (import "" (global (mut i32))))
|
||||||
|
|
||||||
(instance (instantiate $mm (memory $m)))
|
(instance (instantiate $mm "" (memory $m)))
|
||||||
(instance (instantiate $mf (func $f)))
|
(instance (instantiate $mf "" (func $f)))
|
||||||
(instance (instantiate $mt (table $t)))
|
(instance (instantiate $mt "" (table $t)))
|
||||||
(instance (instantiate $mg (global $g)))
|
(instance (instantiate $mg "" (global $g)))
|
||||||
)
|
)
|
||||||
|
|
||||||
;; instantiate nested
|
;; instantiate nested
|
||||||
@@ -204,13 +204,13 @@
|
|||||||
(import "" (func))
|
(import "" (func))
|
||||||
(start 0)
|
(start 0)
|
||||||
)
|
)
|
||||||
(instance (instantiate 0 (func 0)))
|
(instance (instantiate 0 "" (func 0)))
|
||||||
)
|
)
|
||||||
(instance (instantiate 0 (func 0)))
|
(instance (instantiate 0 "" (func 0)))
|
||||||
)
|
)
|
||||||
(instance (instantiate 0 (func 0)))
|
(instance (instantiate 0 "" (func 0)))
|
||||||
)
|
)
|
||||||
(instance (instantiate 0 (func 0)))
|
(instance (instantiate 0 "" (func 0)))
|
||||||
)
|
)
|
||||||
(assert_return (invoke $a "get") (i32.const 1))
|
(assert_return (invoke $a "get") (i32.const 1))
|
||||||
|
|
||||||
@@ -219,20 +219,14 @@
|
|||||||
(module (export "m"))
|
(module (export "m"))
|
||||||
(instance (export "i") (instantiate 0))
|
(instance (export "i") (instantiate 0))
|
||||||
)
|
)
|
||||||
(module
|
(module (import "b" "m" (module)))
|
||||||
(import "b" "m" (module))
|
(module (import "b" "m" (module (import "" (func)))))
|
||||||
(import "b" "i" (instance))
|
(module (import "b" "i" (instance)))
|
||||||
)
|
|
||||||
(assert_unlinkable
|
|
||||||
(module
|
|
||||||
(import "b" "m" (module (import "" (func))))
|
|
||||||
)
|
|
||||||
"module types incompatible")
|
|
||||||
(assert_unlinkable
|
(assert_unlinkable
|
||||||
(module
|
(module
|
||||||
(import "b" "i" (instance (export "" (func))))
|
(import "b" "i" (instance (export "" (func))))
|
||||||
)
|
)
|
||||||
"instance types incompatible")
|
"incompatible import type")
|
||||||
|
|
||||||
;; ensure we ignore other exported items
|
;; ensure we ignore other exported items
|
||||||
(module $b
|
(module $b
|
||||||
@@ -250,7 +244,7 @@
|
|||||||
))
|
))
|
||||||
|
|
||||||
(func (export "get") (result i32)
|
(func (export "get") (result i32)
|
||||||
global.get $i.$g)
|
global.get (global $i "g"))
|
||||||
)
|
)
|
||||||
(assert_return (invoke "get") (i32.const 0xfeed))
|
(assert_return (invoke "get") (i32.const 0xfeed))
|
||||||
|
|
||||||
@@ -270,15 +264,45 @@
|
|||||||
(module
|
(module
|
||||||
(import "b" "i" (instance $i
|
(import "b" "i" (instance $i
|
||||||
;; notice that this order is swapped
|
;; notice that this order is swapped
|
||||||
(export "g" (func $g (param i32) (result i32)))
|
(export "g" (func (param i32) (result i32)))
|
||||||
(export "f" (func $f (result i32)))
|
(export "f" (func (result i32)))
|
||||||
))
|
))
|
||||||
|
|
||||||
(func (export "f") (result i32)
|
(func (export "f") (result i32)
|
||||||
call $i.$f)
|
call (func $i "f"))
|
||||||
(func (export "g") (param i32) (result i32)
|
(func (export "g") (param i32) (result i32)
|
||||||
local.get 0
|
local.get 0
|
||||||
call $i.$g)
|
call (func $i "g"))
|
||||||
)
|
)
|
||||||
(assert_return (invoke "f") (i32.const 300))
|
(assert_return (invoke "f") (i32.const 300))
|
||||||
(assert_return (invoke "g" (i32.const 3000)) (i32.const 3100))
|
(assert_return (invoke "g" (i32.const 3000)) (i32.const 3100))
|
||||||
|
|
||||||
|
(module $a
|
||||||
|
(func (export "f")))
|
||||||
|
|
||||||
|
(module
|
||||||
|
(import "a" "f" (func))
|
||||||
|
|
||||||
|
(module $m1
|
||||||
|
(import "a" "f" (func)))
|
||||||
|
(instance (instantiate $m1 "a" (instance 0)))
|
||||||
|
)
|
||||||
|
|
||||||
|
(module
|
||||||
|
(import "a" "f" (func))
|
||||||
|
|
||||||
|
;; this module provides nothing
|
||||||
|
(module $m1)
|
||||||
|
|
||||||
|
;; this module imports a module which it says imports something
|
||||||
|
(module $m2
|
||||||
|
(module $a
|
||||||
|
(func (export "")))
|
||||||
|
(instance $i (instantiate $a))
|
||||||
|
(import "m" (module $b (import "" (func))))
|
||||||
|
(instance $b (instantiate $b "" (func $i ""))))
|
||||||
|
|
||||||
|
;; we should be able to instantiate m2 with m1 because m1 doesn't actually
|
||||||
|
;; import anything (always safe to remove imports!)
|
||||||
|
(instance (instantiate $m2 "m" (module $m1)))
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user