Merge pull request #1781 from fitzgen/externref
Initial, partial support for `externref`
This commit is contained in:
23
Cargo.lock
generated
23
Cargo.lock
generated
@@ -579,7 +579,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wasmparser",
|
"wasmparser 0.57.0",
|
||||||
"wat",
|
"wat",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1114,7 +1114,7 @@ dependencies = [
|
|||||||
"staticvec",
|
"staticvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"typemap",
|
"typemap",
|
||||||
"wasmparser",
|
"wasmparser 0.57.0",
|
||||||
"wat",
|
"wat",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2151,6 +2151,12 @@ version = "0.55.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af931e2e1960c53f4a28b063fec4cacd036f35acbec8ff3a4739125b17382a87"
|
checksum = "af931e2e1960c53f4a28b063fec4cacd036f35acbec8ff3a4739125b17382a87"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasmparser"
|
||||||
|
version = "0.57.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32fddd575d477c6e9702484139cf9f23dcd554b06d185ed0f56c857dd3a47aa6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmprinter"
|
name = "wasmprinter"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
@@ -2158,7 +2164,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c93ba310101ec5ee980db66b47b3d276577c8310df1570e19994347137650454"
|
checksum = "c93ba310101ec5ee980db66b47b3d276577c8310df1570e19994347137650454"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"wasmparser",
|
"wasmparser 0.55.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2175,7 +2181,7 @@ dependencies = [
|
|||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"wasmparser",
|
"wasmparser 0.57.0",
|
||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
"wasmtime-jit",
|
"wasmtime-jit",
|
||||||
"wasmtime-profiling",
|
"wasmtime-profiling",
|
||||||
@@ -2211,6 +2217,7 @@ name = "wasmtime-cli"
|
|||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"env_logger 0.7.1",
|
||||||
"faerie",
|
"faerie",
|
||||||
"file-per-thread-logger",
|
"file-per-thread-logger",
|
||||||
"filecheck",
|
"filecheck",
|
||||||
@@ -2246,7 +2253,7 @@ dependencies = [
|
|||||||
"more-asserts",
|
"more-asserts",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wasmparser",
|
"wasmparser 0.57.0",
|
||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2277,7 +2284,7 @@ dependencies = [
|
|||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"toml",
|
"toml",
|
||||||
"wasmparser",
|
"wasmparser 0.57.0",
|
||||||
"winapi",
|
"winapi",
|
||||||
"zstd",
|
"zstd",
|
||||||
]
|
]
|
||||||
@@ -2306,7 +2313,7 @@ dependencies = [
|
|||||||
"env_logger 0.7.1",
|
"env_logger 0.7.1",
|
||||||
"log",
|
"log",
|
||||||
"rayon",
|
"rayon",
|
||||||
"wasmparser",
|
"wasmparser 0.57.0",
|
||||||
"wasmprinter",
|
"wasmprinter",
|
||||||
"wasmtime",
|
"wasmtime",
|
||||||
"wasmtime-wast",
|
"wasmtime-wast",
|
||||||
@@ -2330,7 +2337,7 @@ dependencies = [
|
|||||||
"region",
|
"region",
|
||||||
"target-lexicon",
|
"target-lexicon",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"wasmparser",
|
"wasmparser 0.57.0",
|
||||||
"wasmtime-debug",
|
"wasmtime-debug",
|
||||||
"wasmtime-environ",
|
"wasmtime-environ",
|
||||||
"wasmtime-profiling",
|
"wasmtime-profiling",
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ rayon = "1.2.1"
|
|||||||
humantime = "1.3.0"
|
humantime = "1.3.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
env_logger = "0.7.1"
|
||||||
filecheck = "0.5.0"
|
filecheck = "0.5.0"
|
||||||
more-asserts = "0.2.1"
|
more-asserts = "0.2.1"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|||||||
4
build.rs
4
build.rs
@@ -155,9 +155,10 @@ fn write_testsuite_tests(
|
|||||||
writeln!(out, "#[ignore]")?;
|
writeln!(out, "#[ignore]")?;
|
||||||
}
|
}
|
||||||
writeln!(out, "fn r#{}() {{", &testname)?;
|
writeln!(out, "fn r#{}() {{", &testname)?;
|
||||||
|
writeln!(out, " let _ = env_logger::try_init();")?;
|
||||||
writeln!(
|
writeln!(
|
||||||
out,
|
out,
|
||||||
"crate::wast::run_wast(r#\"{}\"#, crate::wast::Strategy::{}).unwrap();",
|
" crate::wast::run_wast(r#\"{}\"#, crate::wast::Strategy::{}).unwrap();",
|
||||||
path.display(),
|
path.display(),
|
||||||
strategy
|
strategy
|
||||||
)?;
|
)?;
|
||||||
@@ -205,6 +206,7 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
|
|||||||
|
|
||||||
// Still working on implementing these. See #929.
|
// Still working on implementing these. See #929.
|
||||||
("reference_types", "table_copy_on_imported_tables") => return false,
|
("reference_types", "table_copy_on_imported_tables") => return false,
|
||||||
|
("reference_types", "externref_id_function") => return false,
|
||||||
("reference_types", _) => return true,
|
("reference_types", _) => return true,
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
0
cranelift/peepmatic/crates/runtime/src/lib.rs
Executable file → Normal file
0
cranelift/peepmatic/crates/runtime/src/lib.rs
Executable file → Normal file
0
cranelift/peepmatic/src/lib.rs
Executable file → Normal file
0
cranelift/peepmatic/src/lib.rs
Executable file → Normal file
0
cranelift/src/clif-util.rs
Executable file → Normal file
0
cranelift/src/clif-util.rs
Executable file → Normal file
@@ -12,7 +12,7 @@ keywords = ["webassembly", "wasm"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasmparser = { version = "0.55.0", default-features = false }
|
wasmparser = { version = "0.57.0", default-features = false }
|
||||||
cranelift-codegen = { path = "../codegen", version = "0.63.0", default-features = false }
|
cranelift-codegen = { path = "../codegen", version = "0.63.0", default-features = false }
|
||||||
cranelift-entity = { path = "../entity", version = "0.63.0" }
|
cranelift-entity = { path = "../entity", version = "0.63.0" }
|
||||||
cranelift-frontend = { path = "../frontend", version = "0.63.0", default-features = false }
|
cranelift-frontend = { path = "../frontend", version = "0.63.0", default-features = false }
|
||||||
|
|||||||
@@ -1171,23 +1171,26 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
)?);
|
)?);
|
||||||
}
|
}
|
||||||
Operator::TableGrow { table } => {
|
Operator::TableGrow { table } => {
|
||||||
|
let table_index = TableIndex::from_u32(*table);
|
||||||
let delta = state.pop1();
|
let delta = state.pop1();
|
||||||
let init_value = state.pop1();
|
let init_value = state.pop1();
|
||||||
state.push1(environ.translate_table_grow(
|
state.push1(environ.translate_table_grow(
|
||||||
builder.cursor(),
|
builder.cursor(),
|
||||||
*table,
|
table_index,
|
||||||
delta,
|
delta,
|
||||||
init_value,
|
init_value,
|
||||||
)?);
|
)?);
|
||||||
}
|
}
|
||||||
Operator::TableGet { table } => {
|
Operator::TableGet { table } => {
|
||||||
|
let table_index = TableIndex::from_u32(*table);
|
||||||
let index = state.pop1();
|
let index = state.pop1();
|
||||||
state.push1(environ.translate_table_get(builder.cursor(), *table, index)?);
|
state.push1(environ.translate_table_get(builder.cursor(), table_index, index)?);
|
||||||
}
|
}
|
||||||
Operator::TableSet { table } => {
|
Operator::TableSet { table } => {
|
||||||
|
let table_index = TableIndex::from_u32(*table);
|
||||||
let value = state.pop1();
|
let value = state.pop1();
|
||||||
let index = state.pop1();
|
let index = state.pop1();
|
||||||
environ.translate_table_set(builder.cursor(), *table, value, index)?;
|
environ.translate_table_set(builder.cursor(), table_index, value, index)?;
|
||||||
}
|
}
|
||||||
Operator::TableCopy {
|
Operator::TableCopy {
|
||||||
dst_table: dst_table_index,
|
dst_table: dst_table_index,
|
||||||
@@ -1210,10 +1213,11 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Operator::TableFill { table } => {
|
Operator::TableFill { table } => {
|
||||||
|
let table_index = TableIndex::from_u32(*table);
|
||||||
let len = state.pop1();
|
let len = state.pop1();
|
||||||
let val = state.pop1();
|
let val = state.pop1();
|
||||||
let dest = state.pop1();
|
let dest = state.pop1();
|
||||||
environ.translate_table_fill(builder.cursor(), *table, dest, val, len)?;
|
environ.translate_table_fill(builder.cursor(), table_index, dest, val, len)?;
|
||||||
}
|
}
|
||||||
Operator::TableInit {
|
Operator::TableInit {
|
||||||
segment,
|
segment,
|
||||||
@@ -1561,6 +1565,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
| Operator::I32x4WidenHighI16x8U { .. } => {
|
| Operator::I32x4WidenHighI16x8U { .. } => {
|
||||||
return Err(wasm_unsupported!("proposed SIMD operator {:?}", op));
|
return Err(wasm_unsupported!("proposed SIMD operator {:?}", op));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Operator::ReturnCall { .. } | Operator::ReturnCallIndirect { .. } => {
|
||||||
|
return Err(wasm_unsupported!("proposed tail-call operator {:?}", op));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
//! [Wasmtime]: https://github.com/bytecodealliance/wasmtime
|
//! [Wasmtime]: https://github.com/bytecodealliance/wasmtime
|
||||||
|
|
||||||
use crate::environ::{
|
use crate::environ::{
|
||||||
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, WasmResult,
|
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment,
|
||||||
|
WasmFuncType, WasmResult,
|
||||||
};
|
};
|
||||||
use crate::func_translator::FuncTranslator;
|
use crate::func_translator::FuncTranslator;
|
||||||
use crate::state::ModuleTranslationState;
|
use crate::state::ModuleTranslationState;
|
||||||
@@ -433,7 +434,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
fn translate_table_grow(
|
fn translate_table_grow(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut pos: FuncCursor,
|
mut pos: FuncCursor,
|
||||||
_table_index: u32,
|
_table_index: TableIndex,
|
||||||
_delta: ir::Value,
|
_delta: ir::Value,
|
||||||
_init_value: ir::Value,
|
_init_value: ir::Value,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> WasmResult<ir::Value> {
|
||||||
@@ -443,7 +444,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
fn translate_table_get(
|
fn translate_table_get(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut pos: FuncCursor,
|
mut pos: FuncCursor,
|
||||||
_table_index: u32,
|
_table_index: TableIndex,
|
||||||
_index: ir::Value,
|
_index: ir::Value,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> WasmResult<ir::Value> {
|
||||||
Ok(pos.ins().null(self.reference_type()))
|
Ok(pos.ins().null(self.reference_type()))
|
||||||
@@ -452,7 +453,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
fn translate_table_set(
|
fn translate_table_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
_pos: FuncCursor,
|
_pos: FuncCursor,
|
||||||
_table_index: u32,
|
_table_index: TableIndex,
|
||||||
_value: ir::Value,
|
_value: ir::Value,
|
||||||
_index: ir::Value,
|
_index: ir::Value,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
@@ -476,7 +477,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
|||||||
fn translate_table_fill(
|
fn translate_table_fill(
|
||||||
&mut self,
|
&mut self,
|
||||||
_pos: FuncCursor,
|
_pos: FuncCursor,
|
||||||
_table_index: u32,
|
_table_index: TableIndex,
|
||||||
_dst: ir::Value,
|
_dst: ir::Value,
|
||||||
_val: ir::Value,
|
_val: ir::Value,
|
||||||
_len: ir::Value,
|
_len: ir::Value,
|
||||||
@@ -534,7 +535,7 @@ impl TargetEnvironment for DummyEnvironment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
||||||
fn declare_signature(&mut self, sig: ir::Signature) -> WasmResult<()> {
|
fn declare_signature(&mut self, _wasm: &WasmFuncType, sig: ir::Signature) -> WasmResult<()> {
|
||||||
self.info.signatures.push(sig);
|
self.info.signatures.push(sig);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,5 @@ mod spec;
|
|||||||
pub use crate::environ::dummy::DummyEnvironment;
|
pub use crate::environ::dummy::DummyEnvironment;
|
||||||
pub use crate::environ::spec::{
|
pub use crate::environ::spec::{
|
||||||
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, WasmError,
|
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, WasmError,
|
||||||
WasmResult,
|
WasmFuncType, WasmResult, WasmType,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,6 +22,13 @@ use thiserror::Error;
|
|||||||
use wasmparser::BinaryReaderError;
|
use wasmparser::BinaryReaderError;
|
||||||
use wasmparser::Operator;
|
use wasmparser::Operator;
|
||||||
|
|
||||||
|
// Re-export `wasmparser`'s function and value types so that consumers can
|
||||||
|
// associate this the original Wasm signature with each compiled function. This
|
||||||
|
// is often necessary because while each Wasm signature gets compiled down into
|
||||||
|
// a single native signature, multiple Wasm signatures might compile down into
|
||||||
|
// the same native signature.
|
||||||
|
pub use wasmparser::{FuncType as WasmFuncType, Type as WasmType};
|
||||||
|
|
||||||
/// The value of a WebAssembly global variable.
|
/// The value of a WebAssembly global variable.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum GlobalVariable {
|
pub enum GlobalVariable {
|
||||||
@@ -347,7 +354,7 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
fn translate_table_grow(
|
fn translate_table_grow(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: FuncCursor,
|
pos: FuncCursor,
|
||||||
table_index: u32,
|
table_index: TableIndex,
|
||||||
delta: ir::Value,
|
delta: ir::Value,
|
||||||
init_value: ir::Value,
|
init_value: ir::Value,
|
||||||
) -> WasmResult<ir::Value>;
|
) -> WasmResult<ir::Value>;
|
||||||
@@ -356,7 +363,7 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
fn translate_table_get(
|
fn translate_table_get(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: FuncCursor,
|
pos: FuncCursor,
|
||||||
table_index: u32,
|
table_index: TableIndex,
|
||||||
index: ir::Value,
|
index: ir::Value,
|
||||||
) -> WasmResult<ir::Value>;
|
) -> WasmResult<ir::Value>;
|
||||||
|
|
||||||
@@ -364,7 +371,7 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
fn translate_table_set(
|
fn translate_table_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: FuncCursor,
|
pos: FuncCursor,
|
||||||
table_index: u32,
|
table_index: TableIndex,
|
||||||
value: ir::Value,
|
value: ir::Value,
|
||||||
index: ir::Value,
|
index: ir::Value,
|
||||||
) -> WasmResult<()>;
|
) -> WasmResult<()>;
|
||||||
@@ -387,7 +394,7 @@ pub trait FuncEnvironment: TargetEnvironment {
|
|||||||
fn translate_table_fill(
|
fn translate_table_fill(
|
||||||
&mut self,
|
&mut self,
|
||||||
pos: FuncCursor,
|
pos: FuncCursor,
|
||||||
table_index: u32,
|
table_index: TableIndex,
|
||||||
dst: ir::Value,
|
dst: ir::Value,
|
||||||
val: ir::Value,
|
val: ir::Value,
|
||||||
len: ir::Value,
|
len: ir::Value,
|
||||||
@@ -472,7 +479,11 @@ pub trait ModuleEnvironment<'data>: TargetEnvironment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Declares a function signature to the environment.
|
/// Declares a function signature to the environment.
|
||||||
fn declare_signature(&mut self, sig: ir::Signature) -> WasmResult<()>;
|
fn declare_signature(
|
||||||
|
&mut self,
|
||||||
|
wasm_func_type: &WasmFuncType,
|
||||||
|
sig: ir::Signature,
|
||||||
|
) -> WasmResult<()>;
|
||||||
|
|
||||||
/// Provides the number of imports up front. By default this does nothing, but
|
/// Provides the number of imports up front. By default this does nothing, but
|
||||||
/// implementations can use this to preallocate memory if desired.
|
/// implementations can use this to preallocate memory if desired.
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ mod translation_utils;
|
|||||||
|
|
||||||
pub use crate::environ::{
|
pub use crate::environ::{
|
||||||
DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode,
|
DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode,
|
||||||
TargetEnvironment, WasmError, WasmResult,
|
TargetEnvironment, WasmError, WasmFuncType, WasmResult, WasmType,
|
||||||
};
|
};
|
||||||
pub use crate::func_translator::FuncTranslator;
|
pub use crate::func_translator::FuncTranslator;
|
||||||
pub use crate::module_translator::translate_module;
|
pub use crate::module_translator::translate_module;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use std::boxed::Box;
|
|||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use wasmparser::{
|
use wasmparser::{
|
||||||
self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems,
|
self, CodeSectionReader, Data, DataKind, DataSectionReader, Element, ElementItem, ElementItems,
|
||||||
ElementKind, ElementSectionReader, Export, ExportSectionReader, ExternalKind, FuncType,
|
ElementKind, ElementSectionReader, Export, ExportSectionReader, ExternalKind,
|
||||||
FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
|
FunctionSectionReader, GlobalSectionReader, GlobalType, ImportSectionEntryType,
|
||||||
ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, NamingReader,
|
ImportSectionReader, MemorySectionReader, MemoryType, NameSectionReader, Naming, NamingReader,
|
||||||
Operator, TableSectionReader, Type, TypeSectionReader,
|
Operator, TableSectionReader, Type, TypeSectionReader,
|
||||||
@@ -40,34 +40,22 @@ pub fn parse_type_section(
|
|||||||
environ.reserve_signatures(count)?;
|
environ.reserve_signatures(count)?;
|
||||||
|
|
||||||
for entry in types {
|
for entry in types {
|
||||||
match entry? {
|
let wasm_func_ty = entry?;
|
||||||
FuncType {
|
let mut sig = Signature::new(ModuleEnvironment::target_config(environ).default_call_conv);
|
||||||
form: wasmparser::Type::Func,
|
sig.params.extend(wasm_func_ty.params.iter().map(|ty| {
|
||||||
params,
|
|
||||||
returns,
|
|
||||||
} => {
|
|
||||||
let mut sig =
|
|
||||||
Signature::new(ModuleEnvironment::target_config(environ).default_call_conv);
|
|
||||||
sig.params.extend(params.iter().map(|ty| {
|
|
||||||
let cret_arg: ir::Type = type_to_type(*ty, environ)
|
let cret_arg: ir::Type = type_to_type(*ty, environ)
|
||||||
.expect("only numeric types are supported in function signatures");
|
.expect("only numeric types are supported in function signatures");
|
||||||
AbiParam::new(cret_arg)
|
AbiParam::new(cret_arg)
|
||||||
}));
|
}));
|
||||||
sig.returns.extend(returns.iter().map(|ty| {
|
sig.returns.extend(wasm_func_ty.returns.iter().map(|ty| {
|
||||||
let cret_arg: ir::Type = type_to_type(*ty, environ)
|
let cret_arg: ir::Type = type_to_type(*ty, environ)
|
||||||
.expect("only numeric types are supported in function signatures");
|
.expect("only numeric types are supported in function signatures");
|
||||||
AbiParam::new(cret_arg)
|
AbiParam::new(cret_arg)
|
||||||
}));
|
}));
|
||||||
environ.declare_signature(sig)?;
|
environ.declare_signature(&wasm_func_ty, sig)?;
|
||||||
module_translation_state.wasm_types.push((params, returns));
|
module_translation_state
|
||||||
}
|
.wasm_types
|
||||||
ty => {
|
.push((wasm_func_ty.params, wasm_func_ty.returns));
|
||||||
return Err(wasm_unsupported!(
|
|
||||||
"unsupported type in type section: {:?}",
|
|
||||||
ty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ pub fn declare_ref(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn #as_ref(a: &#ty) -> Box<crate::wasm_ref_t> {
|
pub extern fn #as_ref(a: &#ty) -> Box<crate::wasm_ref_t> {
|
||||||
let r = a.externref();
|
let r = Some(a.externref());
|
||||||
Box::new(crate::wasm_ref_t { r })
|
Box::new(crate::wasm_ref_t { r })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::wasm_config_t;
|
use crate::wasm_config_t;
|
||||||
use wasmtime::{Engine, HostRef};
|
use wasmtime::Engine;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasm_engine_t {
|
pub struct wasm_engine_t {
|
||||||
pub(crate) engine: HostRef<Engine>,
|
pub(crate) engine: Engine,
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmtime_c_api_macros::declare_own!(wasm_engine_t);
|
wasmtime_c_api_macros::declare_own!(wasm_engine_t);
|
||||||
@@ -22,7 +22,7 @@ pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
|||||||
drop(env_logger::try_init());
|
drop(env_logger::try_init());
|
||||||
|
|
||||||
Box::new(wasm_engine_t {
|
Box::new(wasm_engine_t {
|
||||||
engine: HostRef::new(Engine::default()),
|
engine: Engine::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +30,6 @@ pub extern "C" fn wasm_engine_new() -> Box<wasm_engine_t> {
|
|||||||
pub extern "C" fn wasm_engine_new_with_config(c: Box<wasm_config_t>) -> Box<wasm_engine_t> {
|
pub extern "C" fn wasm_engine_new_with_config(c: Box<wasm_config_t>) -> Box<wasm_engine_t> {
|
||||||
let config = c.config;
|
let config = c.config;
|
||||||
Box::new(wasm_engine_t {
|
Box::new(wasm_engine_t {
|
||||||
engine: HostRef::new(Engine::new(&config)),
|
engine: Engine::new(&config),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{wasm_name_t, wasm_trap_t};
|
use crate::{wasm_name_t, wasm_trap_t};
|
||||||
use anyhow::{anyhow, Error, Result};
|
use anyhow::{anyhow, Error, Result};
|
||||||
use wasmtime::Trap;
|
use wasmtime::{Store, Trap};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct wasmtime_error_t {
|
pub struct wasmtime_error_t {
|
||||||
@@ -10,8 +10,8 @@ pub struct wasmtime_error_t {
|
|||||||
wasmtime_c_api_macros::declare_own!(wasmtime_error_t);
|
wasmtime_c_api_macros::declare_own!(wasmtime_error_t);
|
||||||
|
|
||||||
impl wasmtime_error_t {
|
impl wasmtime_error_t {
|
||||||
pub(crate) fn to_trap(self) -> Box<wasm_trap_t> {
|
pub(crate) fn to_trap(self, store: &Store) -> Box<wasm_trap_t> {
|
||||||
Box::new(wasm_trap_t::new(Trap::from(self.error)))
|
Box::new(wasm_trap_t::new(store, Trap::from(self.error)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::wasm_externkind_t;
|
use crate::wasm_externkind_t;
|
||||||
use crate::{wasm_externtype_t, wasm_func_t, wasm_global_t, wasm_memory_t, wasm_table_t};
|
use crate::{wasm_externtype_t, wasm_func_t, wasm_global_t, wasm_memory_t, wasm_table_t};
|
||||||
use wasmtime::{ExternType, Func, Global, HostRef, Memory, Table};
|
use wasmtime::{ExternType, Func, Global, Memory, Table};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasm_extern_t {
|
pub struct wasm_extern_t {
|
||||||
@@ -18,12 +19,12 @@ pub(crate) enum ExternHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl wasm_extern_t {
|
impl wasm_extern_t {
|
||||||
fn externref(&self) -> wasmtime::ExternRef {
|
pub(crate) fn externref(&self) -> wasmtime::ExternRef {
|
||||||
match &self.which {
|
match &self.which {
|
||||||
ExternHost::Func(f) => f.externref(),
|
ExternHost::Func(f) => f.clone().into(),
|
||||||
ExternHost::Global(f) => f.externref(),
|
ExternHost::Global(f) => f.clone().into(),
|
||||||
ExternHost::Memory(f) => f.externref(),
|
ExternHost::Memory(f) => f.clone().into(),
|
||||||
ExternHost::Table(f) => f.externref(),
|
ExternHost::Table(f) => f.clone().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::{wasm_extern_t, wasm_functype_t, wasm_store_t, wasm_val_t};
|
use crate::{wasm_extern_t, wasm_functype_t, wasm_store_t, wasm_val_t};
|
||||||
use crate::{wasm_name_t, wasm_trap_t, wasmtime_error_t, ExternHost};
|
use crate::{wasm_name_t, wasm_trap_t, wasmtime_error_t, ExternHost};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
@@ -5,7 +6,7 @@ use std::ffi::c_void;
|
|||||||
use std::panic::{self, AssertUnwindSafe};
|
use std::panic::{self, AssertUnwindSafe};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::str;
|
use std::str;
|
||||||
use wasmtime::{Caller, Extern, Func, HostRef, Trap};
|
use wasmtime::{Caller, Extern, Func, Trap};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@@ -71,7 +72,7 @@ impl wasm_func_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn externref(&self) -> wasmtime::ExternRef {
|
fn externref(&self) -> wasmtime::ExternRef {
|
||||||
self.func().externref()
|
self.func().clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ fn create_function(
|
|||||||
ty: &wasm_functype_t,
|
ty: &wasm_functype_t,
|
||||||
func: impl Fn(Caller<'_>, *const wasm_val_t, *mut wasm_val_t) -> Option<Box<wasm_trap_t>> + 'static,
|
func: impl Fn(Caller<'_>, *const wasm_val_t, *mut wasm_val_t) -> Option<Box<wasm_trap_t>> + 'static,
|
||||||
) -> Box<wasm_func_t> {
|
) -> Box<wasm_func_t> {
|
||||||
let store = &store.store.borrow();
|
let store = &store.store;
|
||||||
let ty = ty.ty().ty.clone();
|
let ty = ty.ty().ty.clone();
|
||||||
let func = Func::new(store, ty, move |caller, params, results| {
|
let func = Func::new(store, ty, move |caller, params, results| {
|
||||||
let params = params
|
let params = params
|
||||||
@@ -107,7 +108,7 @@ fn create_function(
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
Box::new(HostRef::new(func).into())
|
Box::new(HostRef::new(store, func).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -182,7 +183,7 @@ pub unsafe extern "C" fn wasm_func_call(
|
|||||||
&mut trap,
|
&mut trap,
|
||||||
);
|
);
|
||||||
match error {
|
match error {
|
||||||
Some(err) => Box::into_raw(err.to_trap()),
|
Some(err) => Box::into_raw(err.to_trap(&wasm_func.ext.externref().store().unwrap())),
|
||||||
None => trap,
|
None => trap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,6 +211,7 @@ fn _wasmtime_func_call(
|
|||||||
results: &mut [wasm_val_t],
|
results: &mut [wasm_val_t],
|
||||||
trap_ptr: &mut *mut wasm_trap_t,
|
trap_ptr: &mut *mut wasm_trap_t,
|
||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
|
let store = &func.ext.externref().store().unwrap();
|
||||||
let func = func.func().borrow();
|
let func = func.func().borrow();
|
||||||
if results.len() != func.result_arity() {
|
if results.len() != func.result_arity() {
|
||||||
return Some(Box::new(anyhow!("wrong number of results provided").into()));
|
return Some(Box::new(anyhow!("wrong number of results provided").into()));
|
||||||
@@ -230,7 +232,7 @@ fn _wasmtime_func_call(
|
|||||||
}
|
}
|
||||||
Ok(Err(trap)) => match trap.downcast::<Trap>() {
|
Ok(Err(trap)) => match trap.downcast::<Trap>() {
|
||||||
Ok(trap) => {
|
Ok(trap) => {
|
||||||
*trap_ptr = Box::into_raw(Box::new(wasm_trap_t::new(trap)));
|
*trap_ptr = Box::into_raw(Box::new(wasm_trap_t::new(store, trap)));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(err) => Some(Box::new(err.into())),
|
Err(err) => Some(Box::new(err.into())),
|
||||||
@@ -243,7 +245,7 @@ fn _wasmtime_func_call(
|
|||||||
} else {
|
} else {
|
||||||
Trap::new("rust panic happened")
|
Trap::new("rust panic happened")
|
||||||
};
|
};
|
||||||
let trap = Box::new(wasm_trap_t::new(trap));
|
let trap = Box::new(wasm_trap_t::new(store, trap));
|
||||||
*trap_ptr = Box::into_raw(trap);
|
*trap_ptr = Box::into_raw(trap);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -277,11 +279,12 @@ pub unsafe extern "C" fn wasmtime_caller_export_get(
|
|||||||
) -> Option<Box<wasm_extern_t>> {
|
) -> Option<Box<wasm_extern_t>> {
|
||||||
let name = str::from_utf8(name.as_slice()).ok()?;
|
let name = str::from_utf8(name.as_slice()).ok()?;
|
||||||
let export = caller.caller.get_export(name)?;
|
let export = caller.caller.get_export(name)?;
|
||||||
|
let store = caller.caller.store();
|
||||||
let which = match export {
|
let which = match export {
|
||||||
Extern::Func(f) => ExternHost::Func(HostRef::new(f)),
|
Extern::Func(f) => ExternHost::Func(HostRef::new(&store, f)),
|
||||||
Extern::Global(g) => ExternHost::Global(HostRef::new(g)),
|
Extern::Global(g) => ExternHost::Global(HostRef::new(&store, g)),
|
||||||
Extern::Memory(m) => ExternHost::Memory(HostRef::new(m)),
|
Extern::Memory(m) => ExternHost::Memory(HostRef::new(&store, m)),
|
||||||
Extern::Table(t) => ExternHost::Table(HostRef::new(t)),
|
Extern::Table(t) => ExternHost::Table(HostRef::new(&store, t)),
|
||||||
};
|
};
|
||||||
Some(Box::new(wasm_extern_t { which }))
|
Some(Box::new(wasm_extern_t { which }))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::{handle_result, wasmtime_error_t};
|
use crate::{handle_result, wasmtime_error_t};
|
||||||
use crate::{wasm_extern_t, wasm_globaltype_t, wasm_store_t, wasm_val_t, ExternHost};
|
use crate::{wasm_extern_t, wasm_globaltype_t, wasm_store_t, wasm_val_t, ExternHost};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use wasmtime::{Global, HostRef};
|
use wasmtime::Global;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@@ -27,7 +28,7 @@ impl wasm_global_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn externref(&self) -> wasmtime::ExternRef {
|
fn externref(&self) -> wasmtime::ExternRef {
|
||||||
self.global().externref()
|
self.global().clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,11 +55,11 @@ pub extern "C" fn wasmtime_global_new(
|
|||||||
val: &wasm_val_t,
|
val: &wasm_val_t,
|
||||||
ret: &mut *mut wasm_global_t,
|
ret: &mut *mut wasm_global_t,
|
||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
let global = Global::new(&store.store.borrow(), gt.ty().ty.clone(), val.val());
|
let global = Global::new(&store.store, gt.ty().ty.clone(), val.val());
|
||||||
handle_result(global, |global| {
|
handle_result(global, |global| {
|
||||||
*ret = Box::into_raw(Box::new(wasm_global_t {
|
*ret = Box::into_raw(Box::new(wasm_global_t {
|
||||||
ext: wasm_extern_t {
|
ext: wasm_extern_t {
|
||||||
which: ExternHost::Global(HostRef::new(global)),
|
which: ExternHost::Global(HostRef::new(&store.store, global)),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
|
|||||||
101
crates/c-api/src/host_ref.rs
Normal file
101
crates/c-api/src/host_ref.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
use std::any::Any;
|
||||||
|
use std::cell::{self, RefCell};
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use wasmtime::{ExternRef, Store};
|
||||||
|
|
||||||
|
/// Represents a piece of data located in the host environment.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HostRef<T>
|
||||||
|
where
|
||||||
|
T: 'static + Any,
|
||||||
|
{
|
||||||
|
externref: ExternRef,
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> HostRef<T>
|
||||||
|
where
|
||||||
|
T: 'static + Any,
|
||||||
|
{
|
||||||
|
/// Creates a new `HostRef<T>` from `T`.
|
||||||
|
pub fn new(store: &Store, item: T) -> HostRef<T> {
|
||||||
|
HostRef {
|
||||||
|
externref: ExternRef::new(store, RefCell::new(item)),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Immutably borrows the wrapped data.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the value is currently mutably borrowed.
|
||||||
|
pub fn borrow(&self) -> cell::Ref<T> {
|
||||||
|
self.inner().borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutably borrows the wrapped data.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the `HostRef<T>` is already borrowed.
|
||||||
|
pub fn borrow_mut(&self) -> cell::RefMut<T> {
|
||||||
|
self.inner().borrow_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the two `HostRef<T>`'s point to the same value (not just
|
||||||
|
/// values that compare as equal).
|
||||||
|
pub fn ptr_eq(&self, other: &HostRef<T>) -> bool {
|
||||||
|
self.externref.ptr_eq(&other.externref)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inner(&self) -> &RefCell<T> {
|
||||||
|
self.externref
|
||||||
|
.data()
|
||||||
|
.downcast_ref::<RefCell<T>>()
|
||||||
|
.expect("`HostRef<T>`s always wrap an `ExternRef` of `RefCell<T>`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AsRef<ExternRef> for HostRef<T> {
|
||||||
|
fn as_ref(&self) -> &ExternRef {
|
||||||
|
&self.externref
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<HostRef<T>> for ExternRef
|
||||||
|
where
|
||||||
|
T: 'static + Any,
|
||||||
|
{
|
||||||
|
fn from(host: HostRef<T>) -> ExternRef {
|
||||||
|
host.externref
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TryFrom<ExternRef> for HostRef<T>
|
||||||
|
where
|
||||||
|
T: 'static + Any,
|
||||||
|
{
|
||||||
|
type Error = ExternRef;
|
||||||
|
|
||||||
|
fn try_from(externref: ExternRef) -> Result<Self, ExternRef> {
|
||||||
|
if externref.data().is::<RefCell<T>>() {
|
||||||
|
Ok(HostRef {
|
||||||
|
externref,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(externref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for HostRef<T> {
|
||||||
|
fn clone(&self) -> HostRef<T> {
|
||||||
|
HostRef {
|
||||||
|
externref: self.externref.clone(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t};
|
use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t};
|
||||||
use crate::{wasm_store_t, wasmtime_error_t, ExternHost};
|
use crate::{wasm_store_t, wasmtime_error_t, ExternHost};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use wasmtime::{Extern, HostRef, Instance, Store, Trap};
|
use wasmtime::{Extern, Instance, Store, Trap};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -16,14 +17,15 @@ wasmtime_c_api_macros::declare_ref!(wasm_instance_t);
|
|||||||
|
|
||||||
impl wasm_instance_t {
|
impl wasm_instance_t {
|
||||||
pub(crate) fn new(instance: Instance) -> wasm_instance_t {
|
pub(crate) fn new(instance: Instance) -> wasm_instance_t {
|
||||||
|
let store = instance.store().clone();
|
||||||
wasm_instance_t {
|
wasm_instance_t {
|
||||||
instance: HostRef::new(instance),
|
instance: HostRef::new(&store, instance),
|
||||||
exports_cache: RefCell::new(None),
|
exports_cache: RefCell::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn externref(&self) -> wasmtime::ExternRef {
|
fn externref(&self) -> wasmtime::ExternRef {
|
||||||
self.instance.externref()
|
self.instance.clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,12 +36,12 @@ pub unsafe extern "C" fn wasm_instance_new(
|
|||||||
imports: *const Box<wasm_extern_t>,
|
imports: *const Box<wasm_extern_t>,
|
||||||
result: Option<&mut *mut wasm_trap_t>,
|
result: Option<&mut *mut wasm_trap_t>,
|
||||||
) -> Option<Box<wasm_instance_t>> {
|
) -> Option<Box<wasm_instance_t>> {
|
||||||
let store = &store.store.borrow();
|
let store = &store.store;
|
||||||
let module = &wasm_module.module.borrow();
|
let module = &wasm_module.module.borrow();
|
||||||
if !Store::same(&store, module.store()) {
|
if !Store::same(&store, module.store()) {
|
||||||
if let Some(result) = result {
|
if let Some(result) = result {
|
||||||
let trap = Trap::new("wasm_store_t must match store in wasm_module_t");
|
let trap = Trap::new("wasm_store_t must match store in wasm_module_t");
|
||||||
let trap = Box::new(wasm_trap_t::new(trap));
|
let trap = Box::new(wasm_trap_t::new(store, trap));
|
||||||
*result = Box::into_raw(trap);
|
*result = Box::into_raw(trap);
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
@@ -58,7 +60,7 @@ pub unsafe extern "C" fn wasm_instance_new(
|
|||||||
assert!(trap.is_null());
|
assert!(trap.is_null());
|
||||||
assert!(instance.is_null());
|
assert!(instance.is_null());
|
||||||
if let Some(result) = result {
|
if let Some(result) = result {
|
||||||
*result = Box::into_raw(err.to_trap());
|
*result = Box::into_raw(err.to_trap(store));
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -111,10 +113,16 @@ fn _wasmtime_instance_new(
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let module = &module.module.borrow();
|
let module = &module.module.borrow();
|
||||||
handle_instantiate(Instance::new(module, &imports), instance_ptr, trap_ptr)
|
handle_instantiate(
|
||||||
|
module.store(),
|
||||||
|
Instance::new(module, &imports),
|
||||||
|
instance_ptr,
|
||||||
|
trap_ptr,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_instantiate(
|
pub fn handle_instantiate(
|
||||||
|
store: &Store,
|
||||||
instance: Result<Instance>,
|
instance: Result<Instance>,
|
||||||
instance_ptr: &mut *mut wasm_instance_t,
|
instance_ptr: &mut *mut wasm_instance_t,
|
||||||
trap_ptr: &mut *mut wasm_trap_t,
|
trap_ptr: &mut *mut wasm_trap_t,
|
||||||
@@ -130,7 +138,7 @@ pub fn handle_instantiate(
|
|||||||
}
|
}
|
||||||
Err(e) => match e.downcast::<Trap>() {
|
Err(e) => match e.downcast::<Trap>() {
|
||||||
Ok(trap) => {
|
Ok(trap) => {
|
||||||
write(trap_ptr, wasm_trap_t::new(trap));
|
write(trap_ptr, wasm_trap_t::new(store, trap));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(e) => Some(Box::new(e.into())),
|
Err(e) => Some(Box::new(e.into())),
|
||||||
@@ -146,10 +154,10 @@ pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wa
|
|||||||
instance
|
instance
|
||||||
.exports()
|
.exports()
|
||||||
.map(|e| match e.into_extern() {
|
.map(|e| match e.into_extern() {
|
||||||
Extern::Func(f) => ExternHost::Func(HostRef::new(f)),
|
Extern::Func(f) => ExternHost::Func(HostRef::new(instance.store(), f)),
|
||||||
Extern::Global(f) => ExternHost::Global(HostRef::new(f)),
|
Extern::Global(f) => ExternHost::Global(HostRef::new(instance.store(), f)),
|
||||||
Extern::Memory(f) => ExternHost::Memory(HostRef::new(f)),
|
Extern::Memory(f) => ExternHost::Memory(HostRef::new(instance.store(), f)),
|
||||||
Extern::Table(f) => ExternHost::Table(HostRef::new(f)),
|
Extern::Table(f) => ExternHost::Table(HostRef::new(instance.store(), f)),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ mod error;
|
|||||||
mod r#extern;
|
mod r#extern;
|
||||||
mod func;
|
mod func;
|
||||||
mod global;
|
mod global;
|
||||||
|
mod host_ref;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod linker;
|
mod linker;
|
||||||
mod memory;
|
mod memory;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::{bad_utf8, handle_result, wasmtime_error_t};
|
use crate::{bad_utf8, handle_result, wasmtime_error_t};
|
||||||
use crate::{wasm_extern_t, wasm_store_t, ExternHost};
|
use crate::{wasm_extern_t, wasm_store_t, ExternHost};
|
||||||
use crate::{wasm_func_t, wasm_instance_t, wasm_module_t, wasm_name_t, wasm_trap_t};
|
use crate::{wasm_func_t, wasm_instance_t, wasm_module_t, wasm_name_t, wasm_trap_t};
|
||||||
use std::str;
|
use std::str;
|
||||||
use wasmtime::{Extern, HostRef, Linker};
|
use wasmtime::{Extern, Linker};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct wasmtime_linker_t {
|
pub struct wasmtime_linker_t {
|
||||||
@@ -12,7 +13,7 @@ pub struct wasmtime_linker_t {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasmtime_linker_new(store: &wasm_store_t) -> Box<wasmtime_linker_t> {
|
pub extern "C" fn wasmtime_linker_new(store: &wasm_store_t) -> Box<wasmtime_linker_t> {
|
||||||
Box::new(wasmtime_linker_t {
|
Box::new(wasmtime_linker_t {
|
||||||
linker: Linker::new(&store.store.borrow()),
|
linker: Linker::new(&store.store),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ pub unsafe extern "C" fn wasmtime_linker_instantiate(
|
|||||||
trap_ptr: &mut *mut wasm_trap_t,
|
trap_ptr: &mut *mut wasm_trap_t,
|
||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
let result = linker.linker.instantiate(&module.module.borrow());
|
let result = linker.linker.instantiate(&module.module.borrow());
|
||||||
super::instance::handle_instantiate(result, instance_ptr, trap_ptr)
|
super::instance::handle_instantiate(linker.linker.store(), result, instance_ptr, trap_ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -116,6 +117,6 @@ pub unsafe extern "C" fn wasmtime_linker_get_default(
|
|||||||
Err(_) => return bad_utf8(),
|
Err(_) => return bad_utf8(),
|
||||||
};
|
};
|
||||||
handle_result(linker.get_default(name), |f| {
|
handle_result(linker.get_default(name), |f| {
|
||||||
*func = Box::into_raw(Box::new(HostRef::new(f).into()))
|
*func = Box::into_raw(Box::new(HostRef::new(linker.store(), f).into()))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::{wasm_extern_t, wasm_memorytype_t, wasm_store_t, ExternHost};
|
use crate::{wasm_extern_t, wasm_memorytype_t, wasm_store_t, ExternHost};
|
||||||
use wasmtime::{HostRef, Memory};
|
use wasmtime::Memory;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@@ -27,7 +28,7 @@ impl wasm_memory_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn externref(&self) -> wasmtime::ExternRef {
|
fn externref(&self) -> wasmtime::ExternRef {
|
||||||
self.memory().externref()
|
self.memory().clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ pub extern "C" fn wasm_memory_new(
|
|||||||
store: &wasm_store_t,
|
store: &wasm_store_t,
|
||||||
mt: &wasm_memorytype_t,
|
mt: &wasm_memorytype_t,
|
||||||
) -> Box<wasm_memory_t> {
|
) -> Box<wasm_memory_t> {
|
||||||
let memory = HostRef::new(Memory::new(&store.store.borrow(), mt.ty().ty.clone()));
|
let memory = HostRef::new(&store.store, Memory::new(&store.store, mt.ty().ty.clone()));
|
||||||
Box::new(wasm_memory_t {
|
Box::new(wasm_memory_t {
|
||||||
ext: wasm_extern_t {
|
ext: wasm_extern_t {
|
||||||
which: ExternHost::Memory(memory),
|
which: ExternHost::Memory(memory),
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::{handle_result, wasmtime_error_t};
|
use crate::{handle_result, wasmtime_error_t};
|
||||||
use crate::{wasm_byte_vec_t, wasm_exporttype_vec_t, wasm_importtype_vec_t};
|
use crate::{wasm_byte_vec_t, wasm_exporttype_vec_t, wasm_importtype_vec_t};
|
||||||
use crate::{wasm_exporttype_t, wasm_importtype_t, wasm_store_t};
|
use crate::{wasm_exporttype_t, wasm_importtype_t, wasm_store_t};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use wasmtime::{HostRef, Module};
|
use wasmtime::Module;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -16,7 +17,7 @@ wasmtime_c_api_macros::declare_ref!(wasm_module_t);
|
|||||||
|
|
||||||
impl wasm_module_t {
|
impl wasm_module_t {
|
||||||
fn externref(&self) -> wasmtime::ExternRef {
|
fn externref(&self) -> wasmtime::ExternRef {
|
||||||
self.module.externref()
|
self.module.clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ pub extern "C" fn wasmtime_module_new(
|
|||||||
ret: &mut *mut wasm_module_t,
|
ret: &mut *mut wasm_module_t,
|
||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
let binary = binary.as_slice();
|
let binary = binary.as_slice();
|
||||||
let store = &store.store.borrow();
|
let store = &store.store;
|
||||||
handle_result(Module::from_binary(store, binary), |module| {
|
handle_result(Module::from_binary(store, binary), |module| {
|
||||||
let imports = module
|
let imports = module
|
||||||
.imports()
|
.imports()
|
||||||
@@ -53,7 +54,7 @@ pub extern "C" fn wasmtime_module_new(
|
|||||||
.map(|e| wasm_exporttype_t::new(e.name().to_owned(), e.ty()))
|
.map(|e| wasm_exporttype_t::new(e.name().to_owned(), e.ty()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let module = Box::new(wasm_module_t {
|
let module = Box::new(wasm_module_t {
|
||||||
module: HostRef::new(module),
|
module: HostRef::new(store, module),
|
||||||
imports,
|
imports,
|
||||||
exports,
|
exports,
|
||||||
});
|
});
|
||||||
@@ -72,7 +73,7 @@ pub extern "C" fn wasmtime_module_validate(
|
|||||||
binary: &wasm_byte_vec_t,
|
binary: &wasm_byte_vec_t,
|
||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
let binary = binary.as_slice();
|
let binary = binary.as_slice();
|
||||||
let store = &store.store.borrow();
|
let store = &store.store;
|
||||||
handle_result(Module::validate(store, binary), |()| {})
|
handle_result(Module::validate(store, binary), |()| {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use wasmtime::ExternRef;
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasm_ref_t {
|
pub struct wasm_ref_t {
|
||||||
pub(crate) r: ExternRef,
|
pub(crate) r: Option<ExternRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmtime_c_api_macros::declare_own!(wasm_ref_t);
|
wasmtime_c_api_macros::declare_own!(wasm_ref_t);
|
||||||
@@ -17,7 +17,11 @@ pub extern "C" fn wasm_ref_copy(r: &wasm_ref_t) -> Box<wasm_ref_t> {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_ref_same(a: &wasm_ref_t, b: &wasm_ref_t) -> bool {
|
pub extern "C" fn wasm_ref_same(a: &wasm_ref_t, b: &wasm_ref_t) -> bool {
|
||||||
a.r.ptr_eq(&b.r)
|
match (a.r.as_ref(), b.r.as_ref()) {
|
||||||
|
(Some(a), Some(b)) => a.ptr_eq(b),
|
||||||
|
(None, None) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_host_info(r: &ExternRef) -> *mut c_void {
|
pub(crate) fn get_host_info(r: &ExternRef) -> *mut c_void {
|
||||||
@@ -25,6 +29,7 @@ pub(crate) fn get_host_info(r: &ExternRef) -> *mut c_void {
|
|||||||
Some(info) => info,
|
Some(info) => info,
|
||||||
None => return std::ptr::null_mut(),
|
None => return std::ptr::null_mut(),
|
||||||
};
|
};
|
||||||
|
let host_info = host_info.borrow();
|
||||||
match host_info.downcast_ref::<HostInfoState>() {
|
match host_info.downcast_ref::<HostInfoState>() {
|
||||||
Some(state) => state.info,
|
Some(state) => state.info,
|
||||||
None => std::ptr::null_mut(),
|
None => std::ptr::null_mut(),
|
||||||
@@ -33,7 +38,8 @@ pub(crate) fn get_host_info(r: &ExternRef) -> *mut c_void {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_ref_get_host_info(a: &wasm_ref_t) -> *mut c_void {
|
pub extern "C" fn wasm_ref_get_host_info(a: &wasm_ref_t) -> *mut c_void {
|
||||||
get_host_info(&a.r)
|
a.r.as_ref()
|
||||||
|
.map_or(std::ptr::null_mut(), |r| get_host_info(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_host_info(
|
pub(crate) fn set_host_info(
|
||||||
@@ -51,7 +57,7 @@ pub(crate) fn set_host_info(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_ref_set_host_info(a: &wasm_ref_t, info: *mut c_void) {
|
pub extern "C" fn wasm_ref_set_host_info(a: &wasm_ref_t, info: *mut c_void) {
|
||||||
set_host_info(&a.r, info, None)
|
a.r.as_ref().map(|r| set_host_info(r, info, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -60,5 +66,5 @@ pub extern "C" fn wasm_ref_set_host_info_with_finalizer(
|
|||||||
info: *mut c_void,
|
info: *mut c_void,
|
||||||
finalizer: Option<extern "C" fn(*mut c_void)>,
|
finalizer: Option<extern "C" fn(*mut c_void)>,
|
||||||
) {
|
) {
|
||||||
set_host_info(&a.r, info, finalizer)
|
a.r.as_ref().map(|r| set_host_info(r, info, finalizer));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::wasm_engine_t;
|
use crate::wasm_engine_t;
|
||||||
use wasmtime::{HostRef, InterruptHandle, Store};
|
use wasmtime::{InterruptHandle, Store};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasm_store_t {
|
pub struct wasm_store_t {
|
||||||
pub(crate) store: HostRef<Store>,
|
pub(crate) store: Store,
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmtime_c_api_macros::declare_own!(wasm_store_t);
|
wasmtime_c_api_macros::declare_own!(wasm_store_t);
|
||||||
@@ -13,7 +13,7 @@ wasmtime_c_api_macros::declare_own!(wasm_store_t);
|
|||||||
pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t> {
|
pub extern "C" fn wasm_store_new(engine: &wasm_engine_t) -> Box<wasm_store_t> {
|
||||||
let engine = &engine.engine;
|
let engine = &engine.engine;
|
||||||
Box::new(wasm_store_t {
|
Box::new(wasm_store_t {
|
||||||
store: HostRef::new(Store::new(&engine.borrow())),
|
store: Store::new(&engine),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ pub extern "C" fn wasmtime_interrupt_handle_new(
|
|||||||
store: &wasm_store_t,
|
store: &wasm_store_t,
|
||||||
) -> Option<Box<wasmtime_interrupt_handle_t>> {
|
) -> Option<Box<wasmtime_interrupt_handle_t>> {
|
||||||
Some(Box::new(wasmtime_interrupt_handle_t {
|
Some(Box::new(wasmtime_interrupt_handle_t {
|
||||||
handle: store.store.borrow().interrupt_handle().ok()?,
|
handle: store.store.interrupt_handle().ok()?,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::{handle_result, wasm_func_t, wasm_ref_t, wasmtime_error_t};
|
use crate::{handle_result, wasm_func_t, wasm_ref_t, wasmtime_error_t};
|
||||||
use crate::{wasm_extern_t, wasm_store_t, wasm_tabletype_t, ExternHost};
|
use crate::{wasm_extern_t, wasm_store_t, wasm_tabletype_t, ExternHost};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use wasmtime::{ExternRef, HostRef, Table, Val};
|
use wasmtime::{Table, Val};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@@ -29,7 +30,7 @@ impl wasm_table_t {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn externref(&self) -> wasmtime::ExternRef {
|
fn externref(&self) -> wasmtime::ExternRef {
|
||||||
self.table().externref()
|
self.table().clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,12 +42,12 @@ pub extern "C" fn wasm_table_new(
|
|||||||
) -> Option<Box<wasm_table_t>> {
|
) -> Option<Box<wasm_table_t>> {
|
||||||
let init: Val = match init {
|
let init: Val = match init {
|
||||||
Some(init) => init.r.into(),
|
Some(init) => init.r.into(),
|
||||||
None => Val::ExternRef(ExternRef::Null),
|
None => Val::ExternRef(None),
|
||||||
};
|
};
|
||||||
let table = Table::new(&store.store.borrow(), tt.ty().ty.clone(), init).ok()?;
|
let table = Table::new(&store.store, tt.ty().ty.clone(), init).ok()?;
|
||||||
Some(Box::new(wasm_table_t {
|
Some(Box::new(wasm_table_t {
|
||||||
ext: wasm_extern_t {
|
ext: wasm_extern_t {
|
||||||
which: ExternHost::Table(HostRef::new(table)),
|
which: ExternHost::Table(HostRef::new(&store.store, table)),
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -60,14 +61,14 @@ pub extern "C" fn wasmtime_funcref_table_new(
|
|||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
let init: Val = match init {
|
let init: Val = match init {
|
||||||
Some(val) => Val::FuncRef(val.func().borrow().clone()),
|
Some(val) => Val::FuncRef(val.func().borrow().clone()),
|
||||||
None => Val::ExternRef(ExternRef::Null),
|
None => Val::ExternRef(None),
|
||||||
};
|
};
|
||||||
handle_result(
|
handle_result(
|
||||||
Table::new(&store.store.borrow(), tt.ty().ty.clone(), init),
|
Table::new(&store.store, tt.ty().ty.clone(), init),
|
||||||
|table| {
|
|table| {
|
||||||
*out = Box::into_raw(Box::new(wasm_table_t {
|
*out = Box::into_raw(Box::new(wasm_table_t {
|
||||||
ext: wasm_extern_t {
|
ext: wasm_extern_t {
|
||||||
which: ExternHost::Table(HostRef::new(table)),
|
which: ExternHost::Table(HostRef::new(&store.store, table)),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
@@ -84,7 +85,7 @@ pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> {
|
|||||||
pub extern "C" fn wasm_table_get(t: &wasm_table_t, index: wasm_table_size_t) -> *mut wasm_ref_t {
|
pub extern "C" fn wasm_table_get(t: &wasm_table_t, index: wasm_table_size_t) -> *mut wasm_ref_t {
|
||||||
match t.table().borrow().get(index) {
|
match t.table().borrow().get(index) {
|
||||||
Some(val) => into_funcref(val),
|
Some(val) => into_funcref(val),
|
||||||
None => into_funcref(Val::ExternRef(ExternRef::Null)),
|
None => into_funcref(Val::ExternRef(None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,8 +99,14 @@ pub extern "C" fn wasmtime_funcref_table_get(
|
|||||||
Some(val) => {
|
Some(val) => {
|
||||||
*ptr = match val {
|
*ptr = match val {
|
||||||
// TODO: what do do about creating new `HostRef` handles here?
|
// TODO: what do do about creating new `HostRef` handles here?
|
||||||
Val::FuncRef(f) => Box::into_raw(Box::new(HostRef::new(f).into())),
|
Val::FuncRef(f) => {
|
||||||
Val::ExternRef(ExternRef::Null) => ptr::null_mut(),
|
let store = match t.table().as_ref().store() {
|
||||||
|
None => return false,
|
||||||
|
Some(store) => store,
|
||||||
|
};
|
||||||
|
Box::into_raw(Box::new(HostRef::new(&store, f).into()))
|
||||||
|
}
|
||||||
|
Val::ExternRef(None) => ptr::null_mut(),
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -127,13 +134,13 @@ pub extern "C" fn wasmtime_funcref_table_set(
|
|||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
let val = match val {
|
let val = match val {
|
||||||
Some(val) => Val::FuncRef(val.func().borrow().clone()),
|
Some(val) => Val::FuncRef(val.func().borrow().clone()),
|
||||||
None => Val::ExternRef(ExternRef::Null),
|
None => Val::ExternRef(None),
|
||||||
};
|
};
|
||||||
handle_result(t.table().borrow().set(index, val), |()| {})
|
handle_result(t.table().borrow().set(index, val), |()| {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_funcref(val: Val) -> *mut wasm_ref_t {
|
fn into_funcref(val: Val) -> *mut wasm_ref_t {
|
||||||
if let Val::ExternRef(ExternRef::Null) = val {
|
if let Val::ExternRef(None) = val {
|
||||||
return ptr::null_mut();
|
return ptr::null_mut();
|
||||||
}
|
}
|
||||||
let externref = match val.externref() {
|
let externref = match val.externref() {
|
||||||
@@ -148,7 +155,7 @@ unsafe fn from_funcref(r: *mut wasm_ref_t) -> Val {
|
|||||||
if !r.is_null() {
|
if !r.is_null() {
|
||||||
Box::from_raw(r).r.into()
|
Box::from_raw(r).r.into()
|
||||||
} else {
|
} else {
|
||||||
Val::ExternRef(ExternRef::Null)
|
Val::ExternRef(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +183,7 @@ pub extern "C" fn wasmtime_funcref_table_grow(
|
|||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
let val = match init {
|
let val = match init {
|
||||||
Some(val) => Val::FuncRef(val.func().borrow().clone()),
|
Some(val) => Val::FuncRef(val.func().borrow().clone()),
|
||||||
None => Val::ExternRef(ExternRef::Null),
|
None => Val::ExternRef(None),
|
||||||
};
|
};
|
||||||
handle_result(t.table().borrow().grow(delta, val), |prev| {
|
handle_result(t.table().borrow().grow(delta, val), |prev| {
|
||||||
if let Some(ptr) = prev_size {
|
if let Some(ptr) = prev_size {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
|
use crate::{wasm_frame_vec_t, wasm_instance_t, wasm_name_t, wasm_store_t};
|
||||||
use once_cell::unsync::OnceCell;
|
use once_cell::unsync::OnceCell;
|
||||||
use wasmtime::{HostRef, Trap};
|
use wasmtime::{Store, Trap};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -11,14 +12,14 @@ pub struct wasm_trap_t {
|
|||||||
wasmtime_c_api_macros::declare_ref!(wasm_trap_t);
|
wasmtime_c_api_macros::declare_ref!(wasm_trap_t);
|
||||||
|
|
||||||
impl wasm_trap_t {
|
impl wasm_trap_t {
|
||||||
pub(crate) fn new(trap: Trap) -> wasm_trap_t {
|
pub(crate) fn new(store: &Store, trap: Trap) -> wasm_trap_t {
|
||||||
wasm_trap_t {
|
wasm_trap_t {
|
||||||
trap: HostRef::new(trap),
|
trap: HostRef::new(store, trap),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn externref(&self) -> wasmtime::ExternRef {
|
fn externref(&self) -> wasmtime::ExternRef {
|
||||||
self.trap.externref()
|
self.trap.clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ pub type wasm_message_t = wasm_name_t;
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_trap_new(
|
pub extern "C" fn wasm_trap_new(
|
||||||
_store: &wasm_store_t,
|
store: &wasm_store_t,
|
||||||
message: &wasm_message_t,
|
message: &wasm_message_t,
|
||||||
) -> Box<wasm_trap_t> {
|
) -> Box<wasm_trap_t> {
|
||||||
let message = message.as_slice();
|
let message = message.as_slice();
|
||||||
@@ -46,7 +47,7 @@ pub extern "C" fn wasm_trap_new(
|
|||||||
}
|
}
|
||||||
let message = String::from_utf8_lossy(&message[..message.len() - 1]);
|
let message = String::from_utf8_lossy(&message[..message.len() - 1]);
|
||||||
Box::new(wasm_trap_t {
|
Box::new(wasm_trap_t {
|
||||||
trap: HostRef::new(Trap::new(message)),
|
trap: HostRef::new(&store.store, Trap::new(message)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//! The WASI embedding API definitions for Wasmtime.
|
//! The WASI embedding API definitions for Wasmtime.
|
||||||
|
use crate::host_ref::HostRef;
|
||||||
use crate::{wasm_extern_t, wasm_importtype_t, wasm_store_t, wasm_trap_t, ExternHost};
|
use crate::{wasm_extern_t, wasm_importtype_t, wasm_store_t, wasm_trap_t, ExternHost};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -12,7 +13,7 @@ use wasi_common::{
|
|||||||
old::snapshot_0::WasiCtxBuilder as WasiSnapshot0CtxBuilder, preopen_dir,
|
old::snapshot_0::WasiCtxBuilder as WasiSnapshot0CtxBuilder, preopen_dir,
|
||||||
WasiCtxBuilder as WasiPreview1CtxBuilder,
|
WasiCtxBuilder as WasiPreview1CtxBuilder,
|
||||||
};
|
};
|
||||||
use wasmtime::{HostRef, Linker, Store, Trap};
|
use wasmtime::{Linker, Store, Trap};
|
||||||
use wasmtime_wasi::{old::snapshot_0::Wasi as WasiSnapshot0, Wasi as WasiPreview1};
|
use wasmtime_wasi::{old::snapshot_0::Wasi as WasiSnapshot0, Wasi as WasiPreview1};
|
||||||
|
|
||||||
unsafe fn cstr_to_path<'a>(path: *const c_char) -> Option<&'a Path> {
|
unsafe fn cstr_to_path<'a>(path: *const c_char) -> Option<&'a Path> {
|
||||||
@@ -282,7 +283,7 @@ pub unsafe extern "C" fn wasi_instance_new(
|
|||||||
config: Box<wasi_config_t>,
|
config: Box<wasi_config_t>,
|
||||||
trap: &mut *mut wasm_trap_t,
|
trap: &mut *mut wasm_trap_t,
|
||||||
) -> Option<Box<wasi_instance_t>> {
|
) -> Option<Box<wasi_instance_t>> {
|
||||||
let store = &store.store.borrow();
|
let store = &store.store;
|
||||||
|
|
||||||
let result = match CStr::from_ptr(name).to_str().unwrap_or("") {
|
let result = match CStr::from_ptr(name).to_str().unwrap_or("") {
|
||||||
"wasi_snapshot_preview1" => create_preview1_instance(store, *config),
|
"wasi_snapshot_preview1" => create_preview1_instance(store, *config),
|
||||||
@@ -297,7 +298,7 @@ pub unsafe extern "C" fn wasi_instance_new(
|
|||||||
})),
|
})),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
*trap = Box::into_raw(Box::new(wasm_trap_t {
|
*trap = Box::into_raw(Box::new(wasm_trap_t {
|
||||||
trap: HostRef::new(Trap::new(e)),
|
trap: HostRef::new(store, Trap::new(e)),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
None
|
None
|
||||||
@@ -335,13 +336,14 @@ pub extern "C" fn wasi_instance_bind_import<'a>(
|
|||||||
if &export.ty() != import.ty.func()? {
|
if &export.ty() != import.ty.func()? {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let store = export.store();
|
||||||
|
|
||||||
let entry = instance
|
let entry = instance
|
||||||
.export_cache
|
.export_cache
|
||||||
.entry(name.to_string())
|
.entry(name.to_string())
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
Box::new(wasm_extern_t {
|
Box::new(wasm_extern_t {
|
||||||
which: ExternHost::Func(HostRef::new(export.clone())),
|
which: ExternHost::Func(HostRef::new(store, export.clone())),
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
Some(entry)
|
Some(entry)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gimli = "0.20.0"
|
gimli = "0.20.0"
|
||||||
wasmparser = "0.55.0"
|
wasmparser = "0.57.0"
|
||||||
faerie = "0.15.0"
|
faerie = "0.15.0"
|
||||||
wasmtime-environ = { path = "../environ", version = "0.16.0" }
|
wasmtime-environ = { path = "../environ", version = "0.16.0" }
|
||||||
target-lexicon = { version = "0.10.0", default-features = false }
|
target-lexicon = { version = "0.10.0", default-features = false }
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ anyhow = "1.0"
|
|||||||
cranelift-codegen = { path = "../../cranelift/codegen", version = "0.63.0", features = ["enable-serde"] }
|
cranelift-codegen = { path = "../../cranelift/codegen", version = "0.63.0", features = ["enable-serde"] }
|
||||||
cranelift-entity = { path = "../../cranelift/entity", version = "0.63.0", features = ["enable-serde"] }
|
cranelift-entity = { path = "../../cranelift/entity", version = "0.63.0", features = ["enable-serde"] }
|
||||||
cranelift-wasm = { path = "../../cranelift/wasm", version = "0.63.0", features = ["enable-serde"] }
|
cranelift-wasm = { path = "../../cranelift/wasm", version = "0.63.0", features = ["enable-serde"] }
|
||||||
wasmparser = "0.55.0"
|
wasmparser = "0.57.0"
|
||||||
lightbeam = { path = "../lightbeam", optional = true, version = "0.16.0" }
|
lightbeam = { path = "../lightbeam", optional = true, version = "0.16.0" }
|
||||||
indexmap = "1.0.2"
|
indexmap = "1.0.2"
|
||||||
rayon = "1.2.1"
|
rayon = "1.2.1"
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ fn compile(env: CompileEnv<'_>) -> Result<ModuleCacheDataTupleType, CompileError
|
|||||||
let func_index = env.local.func_index(*i);
|
let func_index = env.local.func_index(*i);
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
context.func.name = get_func_name(func_index);
|
context.func.name = get_func_name(func_index);
|
||||||
context.func.signature = env.local.func_signature(func_index).clone();
|
context.func.signature = env.local.native_func_signature(func_index).clone();
|
||||||
if env.tunables.debug_info {
|
if env.tunables.debug_info {
|
||||||
context.func.collect_debug_info();
|
context.func.collect_debug_info();
|
||||||
}
|
}
|
||||||
|
|||||||
2
crates/environ/src/data_structures.rs
Executable file → Normal file
2
crates/environ/src/data_structures.rs
Executable file → Normal file
@@ -24,6 +24,6 @@ pub mod wasm {
|
|||||||
pub use cranelift_wasm::{
|
pub use cranelift_wasm::{
|
||||||
get_vmctx_value_label, DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex,
|
get_vmctx_value_label, DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex,
|
||||||
DefinedTableIndex, ElemIndex, FuncIndex, Global, GlobalIndex, GlobalInit, Memory,
|
DefinedTableIndex, ElemIndex, FuncIndex, Global, GlobalIndex, GlobalInit, Memory,
|
||||||
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex,
|
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex, WasmFuncType, WasmType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -549,7 +549,7 @@ impl lightbeam::ModuleContext for FuncEnvironment<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self, index: u32) -> &Self::Signature {
|
fn signature(&self, index: u32) -> &Self::Signature {
|
||||||
&self.module.signatures[SignatureIndex::from_u32(index)]
|
&self.module.signatures[SignatureIndex::from_u32(index)].1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn defined_table_index(&self, table_index: u32) -> Option<u32> {
|
fn defined_table_index(&self, table_index: u32) -> Option<u32> {
|
||||||
@@ -658,6 +658,13 @@ impl<'module_environment> TargetEnvironment for FuncEnvironment<'module_environm
|
|||||||
fn target_config(&self) -> TargetFrontendConfig {
|
fn target_config(&self) -> TargetFrontendConfig {
|
||||||
self.target_config
|
self.target_config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reference_type(&self) -> ir::Type {
|
||||||
|
// For now, the only reference types we support are `externref`, which
|
||||||
|
// don't require tracing GC and stack maps. So we just use the target's
|
||||||
|
// pointer type. This will have to change once we move to tracing GC.
|
||||||
|
self.pointer_type()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> {
|
impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'module_environment> {
|
||||||
@@ -727,7 +734,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
|
|||||||
fn translate_table_grow(
|
fn translate_table_grow(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
||||||
_: u32,
|
_: TableIndex,
|
||||||
_: ir::Value,
|
_: ir::Value,
|
||||||
_: ir::Value,
|
_: ir::Value,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> WasmResult<ir::Value> {
|
||||||
@@ -739,7 +746,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
|
|||||||
fn translate_table_get(
|
fn translate_table_get(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
||||||
_: u32,
|
_: TableIndex,
|
||||||
_: ir::Value,
|
_: ir::Value,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> WasmResult<ir::Value> {
|
||||||
Err(WasmError::Unsupported(
|
Err(WasmError::Unsupported(
|
||||||
@@ -750,7 +757,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
|
|||||||
fn translate_table_set(
|
fn translate_table_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
||||||
_: u32,
|
_: TableIndex,
|
||||||
_: ir::Value,
|
_: ir::Value,
|
||||||
_: ir::Value,
|
_: ir::Value,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
@@ -762,7 +769,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
|
|||||||
fn translate_table_fill(
|
fn translate_table_fill(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
_: cranelift_codegen::cursor::FuncCursor<'_>,
|
||||||
_: u32,
|
_: TableIndex,
|
||||||
_: ir::Value,
|
_: ir::Value,
|
||||||
_: ir::Value,
|
_: ir::Value,
|
||||||
_: ir::Value,
|
_: ir::Value,
|
||||||
@@ -915,7 +922,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
|
|||||||
func: &mut ir::Function,
|
func: &mut ir::Function,
|
||||||
index: SignatureIndex,
|
index: SignatureIndex,
|
||||||
) -> WasmResult<ir::SigRef> {
|
) -> WasmResult<ir::SigRef> {
|
||||||
Ok(func.import_signature(self.module.signatures[index].clone()))
|
Ok(func.import_signature(self.module.signatures[index].1.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_direct_func(
|
fn make_direct_func(
|
||||||
@@ -923,7 +930,7 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
|
|||||||
func: &mut ir::Function,
|
func: &mut ir::Function,
|
||||||
index: FuncIndex,
|
index: FuncIndex,
|
||||||
) -> WasmResult<ir::FuncRef> {
|
) -> WasmResult<ir::FuncRef> {
|
||||||
let sig = self.module.func_signature(index);
|
let sig = self.module.native_func_signature(index);
|
||||||
let signature = func.import_signature(sig.clone());
|
let signature = func.import_signature(sig.clone());
|
||||||
let name = get_func_name(index);
|
let name = get_func_name(index);
|
||||||
Ok(func.import_function(ir::ExtFuncData {
|
Ok(func.import_function(ir::ExtFuncData {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use cranelift_entity::{EntityRef, PrimaryMap};
|
|||||||
use cranelift_wasm::{
|
use cranelift_wasm::{
|
||||||
DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
|
DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
|
||||||
ElemIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table,
|
ElemIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table,
|
||||||
TableIndex,
|
TableIndex, WasmFuncType,
|
||||||
};
|
};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use more_asserts::assert_ge;
|
use more_asserts::assert_ge;
|
||||||
@@ -181,7 +181,7 @@ pub struct Module {
|
|||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
pub struct ModuleLocal {
|
pub struct ModuleLocal {
|
||||||
/// Unprocessed signatures exactly as provided by `declare_signature()`.
|
/// Unprocessed signatures exactly as provided by `declare_signature()`.
|
||||||
pub signatures: PrimaryMap<SignatureIndex, ir::Signature>,
|
pub signatures: PrimaryMap<SignatureIndex, (WasmFuncType, ir::Signature)>,
|
||||||
|
|
||||||
/// Number of imported functions in the module.
|
/// Number of imported functions in the module.
|
||||||
pub num_imported_funcs: usize,
|
pub num_imported_funcs: usize,
|
||||||
@@ -332,8 +332,15 @@ impl ModuleLocal {
|
|||||||
index.index() < self.num_imported_globals
|
index.index() < self.num_imported_globals
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method for looking up the signature of a function.
|
/// Convenience method for looking up the native signature of a compiled
|
||||||
pub fn func_signature(&self, func_index: FuncIndex) -> &ir::Signature {
|
/// Wasm function.
|
||||||
&self.signatures[self.functions[func_index]]
|
pub fn native_func_signature(&self, func_index: FuncIndex) -> &ir::Signature {
|
||||||
|
&self.signatures[self.functions[func_index]].1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convenience method for looking up the original Wasm signature of a
|
||||||
|
/// function.
|
||||||
|
pub fn wasm_func_type(&self, func_index: FuncIndex) -> &WasmFuncType {
|
||||||
|
&self.signatures[self.functions[func_index]].0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use cranelift_entity::PrimaryMap;
|
|||||||
use cranelift_wasm::{
|
use cranelift_wasm::{
|
||||||
self, translate_module, DataIndex, DefinedFuncIndex, ElemIndex, FuncIndex, Global, GlobalIndex,
|
self, translate_module, DataIndex, DefinedFuncIndex, ElemIndex, FuncIndex, Global, GlobalIndex,
|
||||||
Memory, MemoryIndex, ModuleTranslationState, SignatureIndex, Table, TableIndex,
|
Memory, MemoryIndex, ModuleTranslationState, SignatureIndex, Table, TableIndex,
|
||||||
TargetEnvironment, WasmError, WasmResult,
|
TargetEnvironment, WasmError, WasmFuncType, WasmResult,
|
||||||
};
|
};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -92,6 +92,13 @@ impl<'data> TargetEnvironment for ModuleEnvironment<'data> {
|
|||||||
fn target_config(&self) -> TargetFrontendConfig {
|
fn target_config(&self) -> TargetFrontendConfig {
|
||||||
self.result.target_config
|
self.result.target_config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reference_type(&self) -> ir::Type {
|
||||||
|
// For now, the only reference types we support are `externref`, which
|
||||||
|
// don't require tracing GC and stack maps. So we just use the target's
|
||||||
|
// pointer type. This will have to change once we move to tracing GC.
|
||||||
|
self.pointer_type()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This trait is useful for `translate_module` because it tells how to translate
|
/// This trait is useful for `translate_module` because it tells how to translate
|
||||||
@@ -106,10 +113,14 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_signature(&mut self, sig: ir::Signature) -> WasmResult<()> {
|
fn declare_signature(&mut self, wasm: &WasmFuncType, sig: ir::Signature) -> WasmResult<()> {
|
||||||
let sig = translate_signature(sig, self.pointer_type());
|
let sig = translate_signature(sig, self.pointer_type());
|
||||||
// TODO: Deduplicate signatures.
|
// TODO: Deduplicate signatures.
|
||||||
self.result.module.local.signatures.push(sig);
|
self.result
|
||||||
|
.module
|
||||||
|
.local
|
||||||
|
.signatures
|
||||||
|
.push((wasm.clone(), sig));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -583,6 +583,14 @@ impl VMOffsets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Offsets for `VMExternData`.
|
||||||
|
impl VMOffsets {
|
||||||
|
/// Return the offset for `VMExternData::ref_count`.
|
||||||
|
pub fn vm_extern_data_ref_count() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Target specific type for shared signature index.
|
/// Target specific type for shared signature index.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct TargetSharedSignatureIndex(u32);
|
pub struct TargetSharedSignatureIndex(u32);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ binaryen = { version = "0.10.0", optional = true }
|
|||||||
env_logger = "0.7.1"
|
env_logger = "0.7.1"
|
||||||
log = "0.4.8"
|
log = "0.4.8"
|
||||||
rayon = "1.2.1"
|
rayon = "1.2.1"
|
||||||
wasmparser = "0.55.0"
|
wasmparser = "0.57.0"
|
||||||
wasmprinter = "0.2.5"
|
wasmprinter = "0.2.5"
|
||||||
wasmtime = { path = "../wasmtime" }
|
wasmtime = { path = "../wasmtime" }
|
||||||
wasmtime-wast = { path = "../wast" }
|
wasmtime-wast = { path = "../wast" }
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ wasmtime-profiling = { path = "../profiling", version = "0.16.0" }
|
|||||||
region = "2.0.0"
|
region = "2.0.0"
|
||||||
thiserror = "1.0.4"
|
thiserror = "1.0.4"
|
||||||
target-lexicon = { version = "0.10.0", default-features = false }
|
target-lexicon = { version = "0.10.0", default-features = false }
|
||||||
wasmparser = "0.55.0"
|
wasmparser = "0.57.0"
|
||||||
more-asserts = "0.2.1"
|
more-asserts = "0.2.1"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
cfg-if = "0.1.9"
|
cfg-if = "0.1.9"
|
||||||
|
|||||||
@@ -149,8 +149,10 @@ impl Compiler {
|
|||||||
let mut cx = FunctionBuilderContext::new();
|
let mut cx = FunctionBuilderContext::new();
|
||||||
let mut trampolines = HashMap::new();
|
let mut trampolines = HashMap::new();
|
||||||
let mut trampoline_relocations = HashMap::new();
|
let mut trampoline_relocations = HashMap::new();
|
||||||
for sig in translation.module.local.signatures.values() {
|
for (wasm_func_ty, native_sig) in translation.module.local.signatures.values() {
|
||||||
let index = self.signatures.register(sig);
|
let index = self
|
||||||
|
.signatures
|
||||||
|
.register(wasm_func_ty.clone(), native_sig.clone());
|
||||||
if trampolines.contains_key(&index) {
|
if trampolines.contains_key(&index) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -158,7 +160,7 @@ impl Compiler {
|
|||||||
&*self.isa,
|
&*self.isa,
|
||||||
&mut self.code_memory,
|
&mut self.code_memory,
|
||||||
&mut cx,
|
&mut cx,
|
||||||
sig,
|
native_sig,
|
||||||
std::mem::size_of::<u128>(),
|
std::mem::size_of::<u128>(),
|
||||||
)?;
|
)?;
|
||||||
trampolines.insert(index, trampoline);
|
trampolines.insert(index, trampoline);
|
||||||
@@ -167,7 +169,7 @@ impl Compiler {
|
|||||||
// show up be sure to log it in case anyone's listening and there's
|
// show up be sure to log it in case anyone's listening and there's
|
||||||
// an accidental bug.
|
// an accidental bug.
|
||||||
if relocations.len() > 0 {
|
if relocations.len() > 0 {
|
||||||
log::info!("relocations found in trampoline for {:?}", sig);
|
log::info!("relocations found in trampoline for {:?}", native_sig);
|
||||||
trampoline_relocations.insert(index, relocations);
|
trampoline_relocations.insert(index, relocations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ pub fn resolve_imports(
|
|||||||
|
|
||||||
match (import, &export) {
|
match (import, &export) {
|
||||||
(EntityIndex::Function(func_index), Some(Export::Function(f))) => {
|
(EntityIndex::Function(func_index), Some(Export::Function(f))) => {
|
||||||
let import_signature = module.local.func_signature(*func_index);
|
let import_signature = module.local.native_func_signature(*func_index);
|
||||||
let signature = signatures.lookup(f.signature).unwrap();
|
let signature = signatures.lookup_native(f.signature).unwrap();
|
||||||
if signature != *import_signature {
|
if signature != *import_signature {
|
||||||
// TODO: If the difference is in the calling convention,
|
// TODO: If the difference is in the calling convention,
|
||||||
// we could emit a wrapper function to fix it up.
|
// we could emit a wrapper function to fix it up.
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ impl<'data> RawCompiledModule<'data> {
|
|||||||
.local
|
.local
|
||||||
.signatures
|
.signatures
|
||||||
.values()
|
.values()
|
||||||
.map(|sig| signature_registry.register(sig))
|
.map(|(wasm, native)| signature_registry.register(wasm.clone(), native.clone()))
|
||||||
.collect::<PrimaryMap<_, _>>()
|
.collect::<PrimaryMap<_, _>>()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ smallvec = "1.0.0"
|
|||||||
staticvec = "0.9"
|
staticvec = "0.9"
|
||||||
thiserror = "1.0.9"
|
thiserror = "1.0.9"
|
||||||
typemap = "0.3"
|
typemap = "0.3"
|
||||||
wasmparser = "0.55.0"
|
wasmparser = "0.57.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lazy_static = "1.2"
|
lazy_static = "1.2"
|
||||||
|
|||||||
437
crates/runtime/src/externref.rs
Normal file
437
crates/runtime/src/externref.rs
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
//! # `VMExternRef`
|
||||||
|
//!
|
||||||
|
//! `VMExternRef` is a reference-counted box for any kind of data that is
|
||||||
|
//! external and opaque to running Wasm. Sometimes it might hold a Wasmtime
|
||||||
|
//! thing, other times it might hold something from a Wasmtime embedder and is
|
||||||
|
//! opaque even to us. It is morally equivalent to `Rc<dyn Any>` in Rust, but
|
||||||
|
//! additionally always fits in a pointer-sized word. `VMExternRef` is
|
||||||
|
//! non-nullable, but `Option<VMExternRef>` is a null pointer.
|
||||||
|
//!
|
||||||
|
//! The one part of `VMExternRef` that can't ever be opaque to us is the
|
||||||
|
//! reference count. Even when we don't know what's inside an `VMExternRef`, we
|
||||||
|
//! need to be able to manipulate its reference count as we add and remove
|
||||||
|
//! references to it. And we need to do this from compiled Wasm code, so it must
|
||||||
|
//! be `repr(C)`!
|
||||||
|
//!
|
||||||
|
//! ## Memory Layout
|
||||||
|
//!
|
||||||
|
//! `VMExternRef` itself is just a pointer to an `VMExternData`, which holds the
|
||||||
|
//! opaque, boxed value, its reference count, and its vtable pointer.
|
||||||
|
//!
|
||||||
|
//! The `VMExternData` struct is *preceded* by the dynamically-sized value boxed
|
||||||
|
//! up and referenced by one or more `VMExternRef`s:
|
||||||
|
//!
|
||||||
|
//! ```ignore
|
||||||
|
//! ,-------------------------------------------------------.
|
||||||
|
//! | |
|
||||||
|
//! V |
|
||||||
|
//! +----------------------------+-----------+-----------+ |
|
||||||
|
//! | dynamically-sized value... | ref_count | value_ptr |---'
|
||||||
|
//! +----------------------------+-----------+-----------+
|
||||||
|
//! | VMExternData |
|
||||||
|
//! +-----------------------+
|
||||||
|
//! ^
|
||||||
|
//! +-------------+ |
|
||||||
|
//! | VMExternRef |-------------------+
|
||||||
|
//! +-------------+ |
|
||||||
|
//! |
|
||||||
|
//! +-------------+ |
|
||||||
|
//! | VMExternRef |-------------------+
|
||||||
|
//! +-------------+ |
|
||||||
|
//! |
|
||||||
|
//! ... ===
|
||||||
|
//! |
|
||||||
|
//! +-------------+ |
|
||||||
|
//! | VMExternRef |-------------------'
|
||||||
|
//! +-------------+
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! The `value_ptr` member always points backwards to the start of the
|
||||||
|
//! dynamically-sized value (which is also the start of the heap allocation for
|
||||||
|
//! this value-and-`VMExternData` pair). Because it is a `dyn` pointer, it is
|
||||||
|
//! fat, and also points to the value's `Any` vtable.
|
||||||
|
//!
|
||||||
|
//! The boxed value and the `VMExternRef` footer are held a single heap
|
||||||
|
//! allocation. The layout described above is used to make satisfying the
|
||||||
|
//! value's alignment easy: we just need to ensure that the heap allocation used
|
||||||
|
//! to hold everything satisfies its alignment. It also ensures that we don't
|
||||||
|
//! need a ton of excess padding between the `VMExternData` and the value for
|
||||||
|
//! values with large alignment.
|
||||||
|
//!
|
||||||
|
//! ## Reference Counting Protocol and Wasm Functions
|
||||||
|
//!
|
||||||
|
//! Currently, `VMExternRef`s passed into compiled Wasm functions have move
|
||||||
|
//! semantics: the host code gives up ownership and does not decrement the
|
||||||
|
//! reference count. Similarly, `VMExternRef`s returned from compiled Wasm
|
||||||
|
//! functions also have move semantics: host code takes ownership and the
|
||||||
|
//! reference count is not incremented.
|
||||||
|
//!
|
||||||
|
//! This works well when a reference is passed into Wasm and then passed back
|
||||||
|
//! out again. However, if a reference is passed into Wasm, but not passed back
|
||||||
|
//! out, then the reference is leaked. This is only a temporary state, and
|
||||||
|
//! follow up work will leverage stack maps to fix this issue. Follow
|
||||||
|
//! https://github.com/bytecodealliance/wasmtime/issues/929 to keep an eye on
|
||||||
|
//! this.
|
||||||
|
|
||||||
|
use std::alloc::Layout;
|
||||||
|
use std::any::Any;
|
||||||
|
use std::cell::UnsafeCell;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::hash::Hasher;
|
||||||
|
use std::mem;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::ptr::{self, NonNull};
|
||||||
|
|
||||||
|
/// An external reference to some opaque data.
|
||||||
|
///
|
||||||
|
/// `VMExternRef`s dereference to their underlying opaque data as `dyn Any`.
|
||||||
|
///
|
||||||
|
/// Unlike the `externref` in the Wasm spec, `VMExternRef`s are non-nullable,
|
||||||
|
/// and always point to a valid value. You may use `Option<VMExternRef>` to
|
||||||
|
/// represent nullable references, and `Option<VMExternRef>` is guaranteed to
|
||||||
|
/// have the same size and alignment as a raw pointer, with `None` represented
|
||||||
|
/// with the null pointer.
|
||||||
|
///
|
||||||
|
/// `VMExternRef`s are reference counted, so cloning is a cheap, shallow
|
||||||
|
/// operation. It also means they are inherently shared, so you may not get a
|
||||||
|
/// mutable, exclusive reference to their inner contents, only a shared,
|
||||||
|
/// immutable reference. You may use interior mutability with `RefCell` or
|
||||||
|
/// `Mutex` to work around this restriction, if necessary.
|
||||||
|
///
|
||||||
|
/// `VMExternRef`s have pointer-equality semantics, not structural-equality
|
||||||
|
/// semantics. Given two `VMExternRef`s `a` and `b`, `a == b` only if `a` and
|
||||||
|
/// `b` point to the same allocation. `a` and `b` are considered not equal, even
|
||||||
|
/// if `a` and `b` are two different identical copies of the same data, if they
|
||||||
|
/// are in two different allocations. The hashing and ordering implementations
|
||||||
|
/// also only operate on the pointer.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn foo() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
/// use std::cell::RefCell;
|
||||||
|
/// use wasmtime_runtime::VMExternRef;
|
||||||
|
///
|
||||||
|
/// // Open a file. Wasm doesn't know about files, but we can let Wasm instances
|
||||||
|
/// // work with files via opaque `externref` handles.
|
||||||
|
/// let file = std::fs::File::create("some/file/path")?;
|
||||||
|
///
|
||||||
|
/// // Wrap the file up as an `VMExternRef` that can be passed to Wasm.
|
||||||
|
/// let extern_ref_to_file = VMExternRef::new(RefCell::new(file));
|
||||||
|
///
|
||||||
|
/// // `VMExternRef`s dereference to `dyn Any`, so you can use `Any` methods to
|
||||||
|
/// // perform runtime type checks and downcasts.
|
||||||
|
///
|
||||||
|
/// assert!(extern_ref_to_file.is::<RefCell<std::fs::File>>());
|
||||||
|
/// assert!(!extern_ref_to_file.is::<String>());
|
||||||
|
///
|
||||||
|
/// if let Some(file) = extern_ref_to_file.downcast_ref::<RefCell<std::fs::File>>() {
|
||||||
|
/// use std::io::Write;
|
||||||
|
/// let mut file = file.borrow_mut();
|
||||||
|
/// writeln!(&mut file, "Hello, `VMExternRef`!")?;
|
||||||
|
/// }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct VMExternRef(NonNull<VMExternData>);
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct VMExternData {
|
||||||
|
// Implicit, dynamically-sized member that always preceded an
|
||||||
|
// `VMExternData`.
|
||||||
|
//
|
||||||
|
// value: [u8],
|
||||||
|
//
|
||||||
|
/// The reference count for this `VMExternData` and value. When it reaches
|
||||||
|
/// zero, we can safely destroy the value and free this heap
|
||||||
|
/// allocation. This is an `UnsafeCell`, rather than plain `Cell`, because
|
||||||
|
/// it can be modified by compiled Wasm code.
|
||||||
|
///
|
||||||
|
/// Note: this field's offset must be kept in sync with
|
||||||
|
/// `wasmtime_environ::VMOffsets::vm_extern_data_ref_count()` which is
|
||||||
|
/// currently always zero.
|
||||||
|
ref_count: UnsafeCell<usize>,
|
||||||
|
|
||||||
|
/// Always points to the implicit, dynamically-sized `value` member that
|
||||||
|
/// precedes this `VMExternData`.
|
||||||
|
value_ptr: NonNull<dyn Any>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for VMExternRef {
|
||||||
|
#[inline]
|
||||||
|
fn clone(&self) -> VMExternRef {
|
||||||
|
self.extern_data().increment_ref_count();
|
||||||
|
VMExternRef(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for VMExternRef {
|
||||||
|
#[inline]
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let data = self.extern_data();
|
||||||
|
data.decrement_ref_count();
|
||||||
|
if data.get_ref_count() == 0 {
|
||||||
|
// Drop our live reference to `data` before we drop it itself.
|
||||||
|
drop(data);
|
||||||
|
unsafe {
|
||||||
|
VMExternData::drop_and_dealloc(self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VMExternData {
|
||||||
|
/// Get the `Layout` for a value with the given size and alignment, and the
|
||||||
|
/// offset within that layout where the `VMExternData` footer resides.
|
||||||
|
///
|
||||||
|
/// This doesn't take a `value: &T` because `VMExternRef::new_with` hasn't
|
||||||
|
/// constructed a `T` value yet, and it isn't generic over `T` because
|
||||||
|
/// `VMExternData::drop_and_dealloc` doesn't know what `T` to use, and has
|
||||||
|
/// to use `std::mem::{size,align}_of_val` instead.
|
||||||
|
unsafe fn layout_for(value_size: usize, value_align: usize) -> (Layout, usize) {
|
||||||
|
let extern_data_size = mem::size_of::<VMExternData>();
|
||||||
|
let extern_data_align = mem::align_of::<VMExternData>();
|
||||||
|
|
||||||
|
let value_and_padding_size = round_up_to_align(value_size, extern_data_align).unwrap();
|
||||||
|
|
||||||
|
let alloc_align = std::cmp::max(value_align, extern_data_align);
|
||||||
|
let alloc_size = value_and_padding_size + extern_data_size;
|
||||||
|
|
||||||
|
debug_assert!(Layout::from_size_align(alloc_size, alloc_align).is_ok());
|
||||||
|
(
|
||||||
|
Layout::from_size_align_unchecked(alloc_size, alloc_align),
|
||||||
|
value_and_padding_size,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Drop the inner value and then free this `VMExternData` heap allocation.
|
||||||
|
unsafe fn drop_and_dealloc(mut data: NonNull<VMExternData>) {
|
||||||
|
// Note: we introduce a block scope so that we drop the live
|
||||||
|
// reference to the data before we free the heap allocation it
|
||||||
|
// resides within after this block.
|
||||||
|
let (alloc_ptr, layout) = {
|
||||||
|
let data = data.as_mut();
|
||||||
|
debug_assert_eq!(data.get_ref_count(), 0);
|
||||||
|
|
||||||
|
// Same thing, but for the dropping the reference to `value` before
|
||||||
|
// we drop it itself.
|
||||||
|
let (layout, _) = {
|
||||||
|
let value = data.value_ptr.as_ref();
|
||||||
|
Self::layout_for(mem::size_of_val(value), mem::align_of_val(value))
|
||||||
|
};
|
||||||
|
|
||||||
|
ptr::drop_in_place(data.value_ptr.as_ptr());
|
||||||
|
let alloc_ptr = data.value_ptr.cast::<u8>();
|
||||||
|
|
||||||
|
(alloc_ptr, layout)
|
||||||
|
};
|
||||||
|
|
||||||
|
ptr::drop_in_place(data.as_ptr());
|
||||||
|
std::alloc::dealloc(alloc_ptr.as_ptr(), layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_ref_count(&self) -> usize {
|
||||||
|
unsafe { *self.ref_count.get() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn increment_ref_count(&self) {
|
||||||
|
unsafe {
|
||||||
|
let count = self.ref_count.get();
|
||||||
|
*count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn decrement_ref_count(&self) {
|
||||||
|
unsafe {
|
||||||
|
let count = self.ref_count.get();
|
||||||
|
*count -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn round_up_to_align(n: usize, align: usize) -> Option<usize> {
|
||||||
|
debug_assert!(align.is_power_of_two());
|
||||||
|
let align_minus_one = align - 1;
|
||||||
|
Some(n.checked_add(align_minus_one)? & !align_minus_one)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VMExternRef {
|
||||||
|
/// Wrap the given value inside an `VMExternRef`.
|
||||||
|
pub fn new<T>(value: T) -> VMExternRef
|
||||||
|
where
|
||||||
|
T: 'static + Any,
|
||||||
|
{
|
||||||
|
VMExternRef::new_with(|| value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct a new `VMExternRef` in place by invoking `make_value`.
|
||||||
|
pub fn new_with<T>(make_value: impl FnOnce() -> T) -> VMExternRef
|
||||||
|
where
|
||||||
|
T: 'static + Any,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let (layout, footer_offset) =
|
||||||
|
VMExternData::layout_for(mem::size_of::<T>(), mem::align_of::<T>());
|
||||||
|
|
||||||
|
let alloc_ptr = std::alloc::alloc(layout);
|
||||||
|
let alloc_ptr = NonNull::new(alloc_ptr).unwrap_or_else(|| {
|
||||||
|
std::alloc::handle_alloc_error(layout);
|
||||||
|
});
|
||||||
|
|
||||||
|
let value_ptr = alloc_ptr.cast::<T>();
|
||||||
|
ptr::write(value_ptr.as_ptr(), make_value());
|
||||||
|
|
||||||
|
let value_ref: &T = value_ptr.as_ref();
|
||||||
|
let value_ref: &dyn Any = value_ref as _;
|
||||||
|
let value_ptr: *const dyn Any = value_ref as _;
|
||||||
|
let value_ptr: *mut dyn Any = value_ptr as _;
|
||||||
|
let value_ptr = NonNull::new_unchecked(value_ptr);
|
||||||
|
|
||||||
|
let extern_data_ptr =
|
||||||
|
alloc_ptr.cast::<u8>().as_ptr().add(footer_offset) as *mut VMExternData;
|
||||||
|
ptr::write(
|
||||||
|
extern_data_ptr,
|
||||||
|
VMExternData {
|
||||||
|
ref_count: UnsafeCell::new(1),
|
||||||
|
value_ptr,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
VMExternRef(NonNull::new_unchecked(extern_data_ptr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Turn this `VMExternRef` into a raw, untyped pointer.
|
||||||
|
///
|
||||||
|
/// This forgets `self` and does *not* decrement the reference count on the
|
||||||
|
/// pointed-to data.
|
||||||
|
///
|
||||||
|
/// This `VMExternRef` may be recovered with `VMExternRef::from_raw`.
|
||||||
|
pub fn into_raw(self) -> *mut u8 {
|
||||||
|
let ptr = self.0.cast::<u8>().as_ptr();
|
||||||
|
mem::forget(self);
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `VMExternRef` from a pointer returned from a previous call to
|
||||||
|
/// `VMExternRef::into_raw`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Wildly unsafe to use with anything other than the result of a previous
|
||||||
|
/// `into_raw` call!
|
||||||
|
///
|
||||||
|
/// This method does *not* increment the reference count on the pointed-to
|
||||||
|
/// data, so `from_raw` must be called at most *once* on the result of a
|
||||||
|
/// previous `into_raw` call. (Ideally, every `into_raw` is later followed
|
||||||
|
/// by a `from_raw`, but it is technically memory safe to never call
|
||||||
|
/// `from_raw` after `into_raw`: it will leak the pointed-to value, which is
|
||||||
|
/// memory safe).
|
||||||
|
pub unsafe fn from_raw(ptr: *mut u8) -> Self {
|
||||||
|
debug_assert!(!ptr.is_null());
|
||||||
|
VMExternRef(NonNull::new_unchecked(ptr).cast())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn extern_data(&self) -> &VMExternData {
|
||||||
|
unsafe { self.0.as_ref() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Methods that would normally be trait implementations, but aren't to avoid
|
||||||
|
/// potential footguns around `VMExternRef`'s pointer-equality semantics.
|
||||||
|
///
|
||||||
|
/// Note that none of these methods are on `&self`, they all require a
|
||||||
|
/// fully-qualified `VMExternRef::foo(my_ref)` invocation.
|
||||||
|
impl VMExternRef {
|
||||||
|
/// Check whether two `VMExternRef`s point to the same inner allocation.
|
||||||
|
///
|
||||||
|
/// Note that this uses pointer-equality semantics, not structural-equality
|
||||||
|
/// semantics, and so only pointers are compared, and doesn't use any `Eq`
|
||||||
|
/// or `PartialEq` implementation of the pointed-to values.
|
||||||
|
#[inline]
|
||||||
|
pub fn eq(a: &Self, b: &Self) -> bool {
|
||||||
|
ptr::eq(a.0.as_ptr() as *const _, b.0.as_ptr() as *const _)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hash a given `VMExternRef`.
|
||||||
|
///
|
||||||
|
/// Note that this just hashes the pointer to the inner value, it does *not*
|
||||||
|
/// use the inner value's `Hash` implementation (if any).
|
||||||
|
#[inline]
|
||||||
|
pub fn hash<H>(externref: &Self, hasher: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
|
ptr::hash(externref.0.as_ptr() as *const _, hasher);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compare two `VMExternRef`s.
|
||||||
|
///
|
||||||
|
/// Note that this uses pointer-equality semantics, not structural-equality
|
||||||
|
/// semantics, and so only pointers are compared, and doesn't use any `Cmp`
|
||||||
|
/// or `PartialCmp` implementation of the pointed-to values.
|
||||||
|
#[inline]
|
||||||
|
pub fn cmp(a: &Self, b: &Self) -> Ordering {
|
||||||
|
let a = a.0.as_ptr() as usize;
|
||||||
|
let b = b.0.as_ptr() as usize;
|
||||||
|
a.cmp(&b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for VMExternRef {
|
||||||
|
type Target = dyn Any;
|
||||||
|
|
||||||
|
fn deref(&self) -> &dyn Any {
|
||||||
|
unsafe { self.extern_data().value_ptr.as_ref() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extern_ref_is_pointer_sized_and_aligned() {
|
||||||
|
assert_eq!(mem::size_of::<VMExternRef>(), mem::size_of::<*mut ()>());
|
||||||
|
assert_eq!(mem::align_of::<VMExternRef>(), mem::align_of::<*mut ()>());
|
||||||
|
assert_eq!(
|
||||||
|
mem::size_of::<Option<VMExternRef>>(),
|
||||||
|
mem::size_of::<*mut ()>()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
mem::align_of::<Option<VMExternRef>>(),
|
||||||
|
mem::align_of::<*mut ()>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ref_count_is_at_correct_offset() {
|
||||||
|
let s = "hi";
|
||||||
|
let s: &dyn Any = &s as _;
|
||||||
|
let s: *const dyn Any = s as _;
|
||||||
|
let s: *mut dyn Any = s as _;
|
||||||
|
|
||||||
|
let extern_data = VMExternData {
|
||||||
|
ref_count: UnsafeCell::new(0),
|
||||||
|
value_ptr: NonNull::new(s).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let extern_data_ptr = &extern_data as *const _;
|
||||||
|
let ref_count_ptr = &extern_data.ref_count as *const _;
|
||||||
|
|
||||||
|
let actual_offset = (ref_count_ptr as usize) - (extern_data_ptr as usize);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
wasmtime_environ::VMOffsets::vm_extern_data_ref_count(),
|
||||||
|
actual_offset.try_into().unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
mod export;
|
mod export;
|
||||||
|
mod externref;
|
||||||
mod imports;
|
mod imports;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod jit_int;
|
mod jit_int;
|
||||||
@@ -36,6 +37,7 @@ pub mod debug_builtins;
|
|||||||
pub mod libcalls;
|
pub mod libcalls;
|
||||||
|
|
||||||
pub use crate::export::*;
|
pub use crate::export::*;
|
||||||
|
pub use crate::externref::VMExternRef;
|
||||||
pub use crate::imports::Imports;
|
pub use crate::imports::Imports;
|
||||||
pub use crate::instance::{InstanceHandle, InstantiationError, LinkError};
|
pub use crate::instance::{InstanceHandle, InstantiationError, LinkError};
|
||||||
pub use crate::jit_int::GdbJitImageRegistration;
|
pub use crate::jit_int::GdbJitImageRegistration;
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
//! signature checking.
|
//! signature checking.
|
||||||
|
|
||||||
use crate::vmcontext::VMSharedSignatureIndex;
|
use crate::vmcontext::VMSharedSignatureIndex;
|
||||||
use more_asserts::{assert_lt, debug_assert_lt};
|
use more_asserts::assert_lt;
|
||||||
use std::collections::{hash_map, HashMap};
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use wasmtime_environ::ir;
|
use wasmtime_environ::{ir, wasm::WasmFuncType};
|
||||||
|
|
||||||
/// WebAssembly requires that the caller and callee signatures in an indirect
|
/// WebAssembly requires that the caller and callee signatures in an indirect
|
||||||
/// call must match. To implement this efficiently, keep a registry of all
|
/// call must match. To implement this efficiently, keep a registry of all
|
||||||
@@ -24,8 +24,13 @@ pub struct SignatureRegistry {
|
|||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct Inner {
|
struct Inner {
|
||||||
signature2index: HashMap<ir::Signature, VMSharedSignatureIndex>,
|
wasm2index: HashMap<WasmFuncType, VMSharedSignatureIndex>,
|
||||||
index2signature: HashMap<VMSharedSignatureIndex, ir::Signature>,
|
|
||||||
|
// Maps the index to the original Wasm signature.
|
||||||
|
index2wasm: HashMap<VMSharedSignatureIndex, WasmFuncType>,
|
||||||
|
|
||||||
|
// Maps the index to the native signature.
|
||||||
|
index2native: HashMap<VMSharedSignatureIndex, ir::Signature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignatureRegistry {
|
impl SignatureRegistry {
|
||||||
@@ -37,37 +42,42 @@ impl SignatureRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Register a signature and return its unique index.
|
/// Register a signature and return its unique index.
|
||||||
pub fn register(&self, sig: &ir::Signature) -> VMSharedSignatureIndex {
|
pub fn register(&self, wasm: WasmFuncType, native: ir::Signature) -> VMSharedSignatureIndex {
|
||||||
let mut inner = self.inner.write().unwrap();
|
let Inner {
|
||||||
let len = inner.signature2index.len();
|
wasm2index,
|
||||||
match inner.signature2index.entry(sig.clone()) {
|
index2wasm,
|
||||||
hash_map::Entry::Occupied(entry) => *entry.get(),
|
index2native,
|
||||||
hash_map::Entry::Vacant(entry) => {
|
} = &mut *self.inner.write().unwrap();
|
||||||
|
let len = wasm2index.len();
|
||||||
|
|
||||||
|
*wasm2index.entry(wasm.clone()).or_insert_with(|| {
|
||||||
// Keep `signature_hash` len under 2**32 -- VMSharedSignatureIndex::new(std::u32::MAX)
|
// Keep `signature_hash` len under 2**32 -- VMSharedSignatureIndex::new(std::u32::MAX)
|
||||||
// is reserved for VMSharedSignatureIndex::default().
|
// is reserved for VMSharedSignatureIndex::default().
|
||||||
debug_assert_lt!(
|
assert_lt!(
|
||||||
len,
|
len,
|
||||||
std::u32::MAX as usize,
|
std::u32::MAX as usize,
|
||||||
"Invariant check: signature_hash.len() < std::u32::MAX"
|
"Invariant check: signature_hash.len() < std::u32::MAX"
|
||||||
);
|
);
|
||||||
let sig_id = VMSharedSignatureIndex::new(u32::try_from(len).unwrap());
|
let index = VMSharedSignatureIndex::new(u32::try_from(len).unwrap());
|
||||||
entry.insert(sig_id);
|
index2wasm.insert(index, wasm);
|
||||||
inner.index2signature.insert(sig_id, sig.clone());
|
index2native.insert(index, native);
|
||||||
sig_id
|
index
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Looks up a shared signature index within this registry.
|
/// Looks up a shared native signature within this registry.
|
||||||
///
|
///
|
||||||
/// Note that for this operation to be semantically correct the `idx` must
|
/// Note that for this operation to be semantically correct the `idx` must
|
||||||
/// have previously come from a call to `register` of this same object.
|
/// have previously come from a call to `register` of this same object.
|
||||||
pub fn lookup(&self, idx: VMSharedSignatureIndex) -> Option<ir::Signature> {
|
pub fn lookup_native(&self, idx: VMSharedSignatureIndex) -> Option<ir::Signature> {
|
||||||
self.inner
|
self.inner.read().unwrap().index2native.get(&idx).cloned()
|
||||||
.read()
|
}
|
||||||
.unwrap()
|
|
||||||
.index2signature
|
/// Looks up a shared Wasm signature within this registry.
|
||||||
.get(&idx)
|
///
|
||||||
.cloned()
|
/// Note that for this operation to be semantically correct the `idx` must
|
||||||
|
/// have previously come from a call to `register` of this same object.
|
||||||
|
pub fn lookup_wasm(&self, idx: VMSharedSignatureIndex) -> Option<WasmFuncType> {
|
||||||
|
self.inner.read().unwrap().index2wasm.get(&idx).cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ wasmtime-runtime = { path = "../runtime", version = "0.16.0" }
|
|||||||
wasmtime-environ = { path = "../environ", version = "0.16.0" }
|
wasmtime-environ = { path = "../environ", version = "0.16.0" }
|
||||||
wasmtime-jit = { path = "../jit", version = "0.16.0" }
|
wasmtime-jit = { path = "../jit", version = "0.16.0" }
|
||||||
wasmtime-profiling = { path = "../profiling", version = "0.16.0" }
|
wasmtime-profiling = { path = "../profiling", version = "0.16.0" }
|
||||||
wasmparser = "0.55.0"
|
wasmparser = "0.57.0"
|
||||||
target-lexicon = { version = "0.10.0", default-features = false }
|
target-lexicon = { version = "0.10.0", default-features = false }
|
||||||
anyhow = "1.0.19"
|
anyhow = "1.0.19"
|
||||||
region = "2.0.0"
|
region = "2.0.0"
|
||||||
|
|||||||
@@ -244,9 +244,10 @@ impl Func {
|
|||||||
// number of arguments and the right types of arguments. As a result
|
// number of arguments and the right types of arguments. As a result
|
||||||
// we should be able to safely run through them all and read them.
|
// we should be able to safely run through them all and read them.
|
||||||
let mut args = Vec::with_capacity(ty_clone.params().len());
|
let mut args = Vec::with_capacity(ty_clone.params().len());
|
||||||
|
let store = Store::upgrade(&store_weak).unwrap();
|
||||||
for (i, ty) in ty_clone.params().iter().enumerate() {
|
for (i, ty) in ty_clone.params().iter().enumerate() {
|
||||||
unsafe {
|
unsafe {
|
||||||
args.push(Val::read_value_from(values_vec.add(i), ty));
|
args.push(Val::read_value_from(&store, values_vec.add(i), ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut returns = vec![Val::null(); ty_clone.results().len()];
|
let mut returns = vec![Val::null(); ty_clone.results().len()];
|
||||||
@@ -483,25 +484,25 @@ impl Func {
|
|||||||
.store
|
.store
|
||||||
.compiler()
|
.compiler()
|
||||||
.signatures()
|
.signatures()
|
||||||
.lookup(self.export.signature)
|
.lookup_wasm(self.export.signature)
|
||||||
.expect("failed to lookup signature");
|
.expect("failed to lookup signature");
|
||||||
|
|
||||||
// This is only called with `Export::Function`, and since it's coming
|
// This is only called with `Export::Function`, and since it's coming
|
||||||
// from wasmtime_runtime itself we should support all the types coming
|
// from wasmtime_runtime itself we should support all the types coming
|
||||||
// out of it, so assert such here.
|
// out of it, so assert such here.
|
||||||
FuncType::from_wasmtime_signature(&sig).expect("core wasm signature should be supported")
|
FuncType::from_wasm_func_type(&sig).expect("core wasm signature should be supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of parameters that this function takes.
|
/// Returns the number of parameters that this function takes.
|
||||||
pub fn param_arity(&self) -> usize {
|
pub fn param_arity(&self) -> usize {
|
||||||
let sig = self
|
self.instance
|
||||||
.instance
|
|
||||||
.store
|
.store
|
||||||
.compiler()
|
.compiler()
|
||||||
.signatures()
|
.signatures()
|
||||||
.lookup(self.export.signature)
|
.lookup_wasm(self.export.signature)
|
||||||
.expect("failed to lookup signature");
|
.expect("failed to lookup signature")
|
||||||
sig.params.len() - 2 // skip the two vmctx leading parameters
|
.params
|
||||||
|
.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of results this function produces.
|
/// Returns the number of results this function produces.
|
||||||
@@ -511,7 +512,7 @@ impl Func {
|
|||||||
.store
|
.store
|
||||||
.compiler()
|
.compiler()
|
||||||
.signatures()
|
.signatures()
|
||||||
.lookup(self.export.signature)
|
.lookup_wasm(self.export.signature)
|
||||||
.expect("failed to lookup signature");
|
.expect("failed to lookup signature");
|
||||||
sig.returns.len()
|
sig.returns.len()
|
||||||
}
|
}
|
||||||
@@ -546,7 +547,11 @@ impl Func {
|
|||||||
let param_tys = my_ty.params().iter();
|
let param_tys = my_ty.params().iter();
|
||||||
for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) {
|
for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) {
|
||||||
if arg.ty() != *ty {
|
if arg.ty() != *ty {
|
||||||
bail!("argument type mismatch");
|
bail!(
|
||||||
|
"argument type mismatch: found {} but expected {}",
|
||||||
|
arg.ty(),
|
||||||
|
ty
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if !arg.comes_from_same_store(&self.instance.store) {
|
if !arg.comes_from_same_store(&self.instance.store) {
|
||||||
bail!("cross-`Store` values are not currently supported");
|
bail!("cross-`Store` values are not currently supported");
|
||||||
@@ -571,7 +576,7 @@ impl Func {
|
|||||||
for (index, ty) in my_ty.results().iter().enumerate() {
|
for (index, ty) in my_ty.results().iter().enumerate() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = values_vec.as_ptr().add(index);
|
let ptr = values_vec.as_ptr().add(index);
|
||||||
results.push(Val::read_value_from(ptr, ty));
|
results.push(Val::read_value_from(&self.instance.store, ptr, ty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,7 +727,8 @@ impl Func {
|
|||||||
(get15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)
|
(get15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn store(&self) -> &Store {
|
/// Get a reference to this function's store.
|
||||||
|
pub fn store(&self) -> &Store {
|
||||||
&self.instance.store
|
&self.instance.store
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1038,6 +1044,12 @@ impl Caller<'_> {
|
|||||||
Some(Extern::Memory(mem))
|
Some(Extern::Memory(mem))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a handle to this caller's store.
|
||||||
|
pub fn store(&self) -> Store {
|
||||||
|
// See comment above the `store` member for why this unwrap is OK.
|
||||||
|
Store::upgrade(&self.store).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_into_func {
|
macro_rules! impl_into_func {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub use crate::func::*;
|
|||||||
pub use crate::instance::Instance;
|
pub use crate::instance::Instance;
|
||||||
pub use crate::linker::*;
|
pub use crate::linker::*;
|
||||||
pub use crate::module::Module;
|
pub use crate::module::Module;
|
||||||
pub use crate::r#ref::{ExternRef, HostRef};
|
pub use crate::r#ref::ExternRef;
|
||||||
pub use crate::runtime::*;
|
pub use crate::runtime::*;
|
||||||
pub use crate::trap::Trap;
|
pub use crate::trap::Trap;
|
||||||
pub use crate::types::*;
|
pub use crate::types::*;
|
||||||
|
|||||||
@@ -1,225 +1,81 @@
|
|||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::{self, RefCell};
|
use std::cell::RefCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
use wasmtime_runtime::VMExternRef;
|
||||||
trait InternalRefBase: Any {
|
|
||||||
fn as_any(&self) -> &dyn Any;
|
|
||||||
fn host_info(&self) -> Option<cell::RefMut<Box<dyn Any>>>;
|
|
||||||
fn set_host_info(&self, info: Option<Box<dyn Any>>);
|
|
||||||
fn ptr_eq(&self, other: &dyn InternalRefBase) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct InternalRef(Rc<dyn InternalRefBase>);
|
|
||||||
|
|
||||||
impl InternalRef {
|
|
||||||
pub fn is_ref<T: 'static>(&self) -> bool {
|
|
||||||
let r = self.0.as_any();
|
|
||||||
Any::is::<HostRef<T>>(r)
|
|
||||||
}
|
|
||||||
pub fn get_ref<T: 'static>(&self) -> HostRef<T> {
|
|
||||||
let r = self.0.as_any();
|
|
||||||
r.downcast_ref::<HostRef<T>>()
|
|
||||||
.expect("reference is not T type")
|
|
||||||
.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AnyAndHostInfo {
|
|
||||||
any: Box<dyn Any>,
|
|
||||||
host_info: Option<Box<dyn Any>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct OtherRef(Rc<RefCell<AnyAndHostInfo>>);
|
|
||||||
|
|
||||||
/// Represents an opaque reference to any data within WebAssembly.
|
/// Represents an opaque reference to any data within WebAssembly.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ExternRef {
|
pub struct ExternRef {
|
||||||
/// A reference to no data.
|
pub(crate) inner: VMExternRef,
|
||||||
Null,
|
pub(crate) store: Weak<crate::runtime::StoreInner>,
|
||||||
/// A reference to data stored internally in `wasmtime`.
|
|
||||||
Ref(InternalRef),
|
|
||||||
/// A reference to data located outside of `wasmtime`.
|
|
||||||
Other(OtherRef),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternRef {
|
impl ExternRef {
|
||||||
/// Creates a new instance of `ExternRef` from `Box<dyn Any>`.
|
/// Creates a new instance of `ExternRef` wrapping the given value.
|
||||||
pub fn new(data: Box<dyn Any>) -> Self {
|
pub fn new<T>(store: &crate::Store, value: T) -> ExternRef
|
||||||
let info = AnyAndHostInfo {
|
where
|
||||||
any: data,
|
T: 'static + Any,
|
||||||
host_info: None,
|
{
|
||||||
};
|
let inner = VMExternRef::new(value);
|
||||||
ExternRef::Other(OtherRef(Rc::new(RefCell::new(info))))
|
let store = store.weak();
|
||||||
|
ExternRef { inner, store }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Null` reference.
|
/// Get this reference's store.
|
||||||
pub fn null() -> Self {
|
///
|
||||||
ExternRef::Null
|
/// Returns `None` if this reference outlived its store.
|
||||||
|
pub fn store(&self) -> Option<crate::runtime::Store> {
|
||||||
|
crate::runtime::Store::upgrade(&self.store)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the data stored in the reference if available.
|
/// Get the underlying data for this `ExternRef`.
|
||||||
/// # Panics
|
pub fn data(&self) -> &dyn Any {
|
||||||
/// Panics if the variant isn't `ExternRef::Other`.
|
&*self.inner
|
||||||
pub fn data(&self) -> cell::Ref<Box<dyn Any>> {
|
|
||||||
match self {
|
|
||||||
ExternRef::Other(OtherRef(r)) => cell::Ref::map(r.borrow(), |r| &r.any),
|
|
||||||
_ => panic!("expected ExternRef::Other"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the two `ExternRef<T>`'s point to the same value (not just
|
/// Does this `ExternRef` point to the same inner value as `other`?0
|
||||||
/// values that compare as equal).
|
///
|
||||||
|
/// This is *only* pointer equality, and does *not* run any inner value's
|
||||||
|
/// `Eq` implementation.
|
||||||
pub fn ptr_eq(&self, other: &ExternRef) -> bool {
|
pub fn ptr_eq(&self, other: &ExternRef) -> bool {
|
||||||
match (self, other) {
|
VMExternRef::eq(&self.inner, &other.inner)
|
||||||
(ExternRef::Null, ExternRef::Null) => true,
|
|
||||||
(ExternRef::Ref(InternalRef(ref a)), ExternRef::Ref(InternalRef(ref b))) => {
|
|
||||||
a.ptr_eq(b.as_ref())
|
|
||||||
}
|
|
||||||
(ExternRef::Other(OtherRef(ref a)), ExternRef::Other(OtherRef(ref b))) => {
|
|
||||||
Rc::ptr_eq(a, b)
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a mutable reference to the host information if available.
|
/// Returns the host information for this `externref`, if previously created
|
||||||
/// # Panics
|
/// with `set_host_info`.
|
||||||
/// Panics if `ExternRef` is already borrowed or `ExternRef` is `Null`.
|
pub fn host_info(&self) -> Option<Rc<RefCell<dyn Any>>> {
|
||||||
pub fn host_info(&self) -> Option<cell::RefMut<Box<dyn Any>>> {
|
let store = crate::Store::upgrade(&self.store)?;
|
||||||
match self {
|
store.host_info(self)
|
||||||
ExternRef::Null => panic!("null"),
|
|
||||||
ExternRef::Ref(r) => r.0.host_info(),
|
|
||||||
ExternRef::Other(r) => {
|
|
||||||
let info = cell::RefMut::map(r.0.borrow_mut(), |b| &mut b.host_info);
|
|
||||||
if info.is_none() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(cell::RefMut::map(info, |info| info.as_mut().unwrap()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the host information for an `ExternRef`.
|
/// Set the host information for this `externref`, returning the old host
|
||||||
/// # Panics
|
/// information if it was previously set.
|
||||||
/// Panics if `ExternRef` is already borrowed or `ExternRef` is `Null`.
|
pub fn set_host_info<T>(&self, info: T) -> Option<Rc<RefCell<dyn Any>>>
|
||||||
pub fn set_host_info(&self, info: Option<Box<dyn Any>>) {
|
where
|
||||||
match self {
|
T: 'static + Any,
|
||||||
ExternRef::Null => panic!("null"),
|
{
|
||||||
ExternRef::Ref(r) => r.0.set_host_info(info),
|
let store = crate::Store::upgrade(&self.store)?;
|
||||||
ExternRef::Other(r) => {
|
store.set_host_info(self, Some(Rc::new(RefCell::new(info))))
|
||||||
r.0.borrow_mut().host_info = info;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove the host information for this `externref`, returning the old host
|
||||||
|
/// information if it was previously set.
|
||||||
|
pub fn remove_host_info(&self) -> Option<Rc<RefCell<dyn Any>>> {
|
||||||
|
let store = crate::Store::upgrade(&self.store)?;
|
||||||
|
store.set_host_info(self, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ExternRef {
|
impl fmt::Debug for ExternRef {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
let ExternRef { inner, store: _ } = self;
|
||||||
ExternRef::Null => write!(f, "null"),
|
let store = self.store();
|
||||||
ExternRef::Ref(_) => write!(f, "externref"),
|
f.debug_struct("ExternRef")
|
||||||
ExternRef::Other(_) => write!(f, "other ref"),
|
.field("inner", &inner)
|
||||||
}
|
.field("store", &store)
|
||||||
}
|
.finish()
|
||||||
}
|
|
||||||
|
|
||||||
struct ContentBox<T> {
|
|
||||||
content: T,
|
|
||||||
host_info: Option<Box<dyn Any>>,
|
|
||||||
externref_data: Weak<dyn InternalRefBase>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a piece of data located in the host environment.
|
|
||||||
pub struct HostRef<T>(Rc<RefCell<ContentBox<T>>>);
|
|
||||||
|
|
||||||
impl<T: 'static> HostRef<T> {
|
|
||||||
/// Creates a new `HostRef<T>` from `T`.
|
|
||||||
pub fn new(item: T) -> HostRef<T> {
|
|
||||||
let externref_data: Weak<HostRef<T>> = Weak::new();
|
|
||||||
let content = ContentBox {
|
|
||||||
content: item,
|
|
||||||
host_info: None,
|
|
||||||
externref_data,
|
|
||||||
};
|
|
||||||
HostRef(Rc::new(RefCell::new(content)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Immutably borrows the wrapped data.
|
|
||||||
/// # Panics
|
|
||||||
/// Panics if the value is currently mutably borrowed.
|
|
||||||
pub fn borrow(&self) -> cell::Ref<T> {
|
|
||||||
cell::Ref::map(self.0.borrow(), |b| &b.content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mutably borrows the wrapped data.
|
|
||||||
/// # Panics
|
|
||||||
/// Panics if the `HostRef<T>` is already borrowed.
|
|
||||||
pub fn borrow_mut(&self) -> cell::RefMut<T> {
|
|
||||||
cell::RefMut::map(self.0.borrow_mut(), |b| &mut b.content)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the two `HostRef<T>`'s point to the same value (not just
|
|
||||||
/// values that compare as equal).
|
|
||||||
pub fn ptr_eq(&self, other: &HostRef<T>) -> bool {
|
|
||||||
Rc::ptr_eq(&self.0, &other.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an opaque reference to the wrapped data in the form of
|
|
||||||
/// an `ExternRef`.
|
|
||||||
/// # Panics
|
|
||||||
/// Panics if `HostRef<T>` is already mutably borrowed.
|
|
||||||
pub fn externref(&self) -> ExternRef {
|
|
||||||
let r = self.0.borrow_mut().externref_data.upgrade();
|
|
||||||
if let Some(r) = r {
|
|
||||||
return ExternRef::Ref(InternalRef(r));
|
|
||||||
}
|
|
||||||
let externref_data: Rc<dyn InternalRefBase> = Rc::new(self.clone());
|
|
||||||
self.0.borrow_mut().externref_data = Rc::downgrade(&externref_data);
|
|
||||||
ExternRef::Ref(InternalRef(externref_data))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: 'static> InternalRefBase for HostRef<T> {
|
|
||||||
fn ptr_eq(&self, other: &dyn InternalRefBase) -> bool {
|
|
||||||
if let Some(other) = other.as_any().downcast_ref() {
|
|
||||||
self.ptr_eq(other)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn host_info(&self) -> Option<cell::RefMut<Box<dyn Any>>> {
|
|
||||||
let info = cell::RefMut::map(self.0.borrow_mut(), |b| &mut b.host_info);
|
|
||||||
if info.is_none() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(cell::RefMut::map(info, |info| info.as_mut().unwrap()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_host_info(&self, info: Option<Box<dyn Any>>) {
|
|
||||||
self.0.borrow_mut().host_info = info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Clone for HostRef<T> {
|
|
||||||
fn clone(&self) -> HostRef<T> {
|
|
||||||
HostRef(self.0.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: fmt::Debug> fmt::Debug for HostRef<T> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "Ref(")?;
|
|
||||||
self.0.borrow().content.fmt(f)?;
|
|
||||||
write!(f, ")")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
use crate::externals::MemoryCreator;
|
use crate::externals::MemoryCreator;
|
||||||
|
use crate::r#ref::ExternRef;
|
||||||
use crate::trampoline::{MemoryCreatorProxy, StoreInstanceHandle};
|
use crate::trampoline::{MemoryCreatorProxy, StoreInstanceHandle};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
use std::any::Any;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -14,7 +18,7 @@ use wasmtime_environ::{CacheConfig, Tunables};
|
|||||||
use wasmtime_jit::{native, CompilationStrategy, Compiler};
|
use wasmtime_jit::{native, CompilationStrategy, Compiler};
|
||||||
use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent};
|
use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, VMInterrupts,
|
debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, VMExternRef, VMInterrupts,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Runtime Environment
|
// Runtime Environment
|
||||||
@@ -83,6 +87,7 @@ impl Config {
|
|||||||
enable_bulk_memory: false,
|
enable_bulk_memory: false,
|
||||||
enable_simd: false,
|
enable_simd: false,
|
||||||
enable_multi_value: true,
|
enable_multi_value: true,
|
||||||
|
enable_tail_call: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
flags,
|
flags,
|
||||||
@@ -732,6 +737,26 @@ pub(crate) struct StoreInner {
|
|||||||
compiler: RefCell<Compiler>,
|
compiler: RefCell<Compiler>,
|
||||||
instances: RefCell<Vec<InstanceHandle>>,
|
instances: RefCell<Vec<InstanceHandle>>,
|
||||||
signal_handler: RefCell<Option<Box<SignalHandler<'static>>>>,
|
signal_handler: RefCell<Option<Box<SignalHandler<'static>>>>,
|
||||||
|
host_info: RefCell<HashMap<HostInfoKey, Rc<RefCell<dyn Any>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HostInfoKey(VMExternRef);
|
||||||
|
|
||||||
|
impl PartialEq for HostInfoKey {
|
||||||
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
VMExternRef::eq(&self.0, &rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for HostInfoKey {}
|
||||||
|
|
||||||
|
impl Hash for HostInfoKey {
|
||||||
|
fn hash<H>(&self, hasher: &mut H)
|
||||||
|
where
|
||||||
|
H: Hasher,
|
||||||
|
{
|
||||||
|
VMExternRef::hash(&self.0, hasher);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store {
|
impl Store {
|
||||||
@@ -757,6 +782,7 @@ impl Store {
|
|||||||
compiler: RefCell::new(compiler),
|
compiler: RefCell::new(compiler),
|
||||||
instances: RefCell::new(Vec::new()),
|
instances: RefCell::new(Vec::new()),
|
||||||
signal_handler: RefCell::new(None),
|
signal_handler: RefCell::new(None),
|
||||||
|
host_info: RefCell::new(HashMap::new()),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -808,6 +834,37 @@ impl Store {
|
|||||||
Rc::downgrade(&self.inner)
|
Rc::downgrade(&self.inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn upgrade(weak: &Weak<StoreInner>) -> Option<Self> {
|
||||||
|
let inner = weak.upgrade()?;
|
||||||
|
Some(Self { inner })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn host_info(&self, externref: &ExternRef) -> Option<Rc<RefCell<dyn Any>>> {
|
||||||
|
debug_assert!(
|
||||||
|
std::rc::Weak::ptr_eq(&self.weak(), &externref.store),
|
||||||
|
"externref must be from this store"
|
||||||
|
);
|
||||||
|
let infos = self.inner.host_info.borrow();
|
||||||
|
infos.get(&HostInfoKey(externref.inner.clone())).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_host_info(
|
||||||
|
&self,
|
||||||
|
externref: &ExternRef,
|
||||||
|
info: Option<Rc<RefCell<dyn Any>>>,
|
||||||
|
) -> Option<Rc<RefCell<dyn Any>>> {
|
||||||
|
debug_assert!(
|
||||||
|
std::rc::Weak::ptr_eq(&self.weak(), &externref.store),
|
||||||
|
"externref must be from this store"
|
||||||
|
);
|
||||||
|
let mut infos = self.inner.host_info.borrow_mut();
|
||||||
|
if let Some(info) = info {
|
||||||
|
infos.insert(HostInfoKey(externref.inner.clone()), info)
|
||||||
|
} else {
|
||||||
|
infos.remove(&HostInfoKey(externref.inner.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn signal_handler(&self) -> std::cell::Ref<'_, Option<Box<SignalHandler<'static>>>> {
|
pub(crate) fn signal_handler(&self) -> std::cell::Ref<'_, Option<Box<SignalHandler<'static>>>> {
|
||||||
self.inner.signal_handler.borrow()
|
self.inner.signal_handler.borrow()
|
||||||
}
|
}
|
||||||
@@ -926,6 +983,13 @@ impl Default for Store {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Store {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let inner = &*self.inner as *const StoreInner;
|
||||||
|
f.debug_struct("Store").field("inner", &inner).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for StoreInner {
|
impl Drop for StoreInner {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
for instance in self.instances.get_mut().iter() {
|
for instance in self.instances.get_mut().iter() {
|
||||||
|
|||||||
@@ -32,7 +32,12 @@ pub(crate) fn create_handle(
|
|||||||
.local
|
.local
|
||||||
.signatures
|
.signatures
|
||||||
.values()
|
.values()
|
||||||
.map(|sig| store.compiler().signatures().register(sig))
|
.map(|(wasm, native)| {
|
||||||
|
store
|
||||||
|
.compiler()
|
||||||
|
.signatures()
|
||||||
|
.register(wasm.clone(), native.clone())
|
||||||
|
})
|
||||||
.collect::<PrimaryMap<_, _>>();
|
.collect::<PrimaryMap<_, _>>();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
@@ -225,7 +225,10 @@ pub fn create_handle_with_function(
|
|||||||
|
|
||||||
// First up we manufacture a trampoline which has the ABI specified by `ft`
|
// First up we manufacture a trampoline which has the ABI specified by `ft`
|
||||||
// and calls into `stub_fn`...
|
// and calls into `stub_fn`...
|
||||||
let sig_id = module.local.signatures.push(sig.clone());
|
let sig_id = module
|
||||||
|
.local
|
||||||
|
.signatures
|
||||||
|
.push((ft.to_wasm_func_type(), sig.clone()));
|
||||||
let func_id = module.local.functions.push(sig_id);
|
let func_id = module.local.functions.push(sig_id);
|
||||||
module
|
module
|
||||||
.exports
|
.exports
|
||||||
@@ -244,7 +247,10 @@ pub fn create_handle_with_function(
|
|||||||
mem::size_of::<u128>(),
|
mem::size_of::<u128>(),
|
||||||
)?;
|
)?;
|
||||||
assert!(relocations.is_empty());
|
assert!(relocations.is_empty());
|
||||||
let sig_id = store.compiler().signatures().register(&sig);
|
let sig_id = store
|
||||||
|
.compiler()
|
||||||
|
.signatures()
|
||||||
|
.register(ft.to_wasm_func_type(), sig);
|
||||||
trampolines.insert(sig_id, trampoline);
|
trampolines.insert(sig_id, trampoline);
|
||||||
|
|
||||||
// Next up we wrap everything up into an `InstanceHandle` by publishing our
|
// Next up we wrap everything up into an `InstanceHandle` by publishing our
|
||||||
@@ -285,13 +291,19 @@ pub unsafe fn create_handle_with_raw_function(
|
|||||||
let mut finished_functions = PrimaryMap::new();
|
let mut finished_functions = PrimaryMap::new();
|
||||||
let mut trampolines = HashMap::new();
|
let mut trampolines = HashMap::new();
|
||||||
|
|
||||||
let sig_id = module.local.signatures.push(sig.clone());
|
let sig_id = module
|
||||||
|
.local
|
||||||
|
.signatures
|
||||||
|
.push((ft.to_wasm_func_type(), sig.clone()));
|
||||||
let func_id = module.local.functions.push(sig_id);
|
let func_id = module.local.functions.push(sig_id);
|
||||||
module
|
module
|
||||||
.exports
|
.exports
|
||||||
.insert("trampoline".to_string(), EntityIndex::Function(func_id));
|
.insert("trampoline".to_string(), EntityIndex::Function(func_id));
|
||||||
finished_functions.push(func);
|
finished_functions.push(func);
|
||||||
let sig_id = store.compiler().signatures().register(&sig);
|
let sig_id = store
|
||||||
|
.compiler()
|
||||||
|
.signatures()
|
||||||
|
.register(ft.to_wasm_func_type(), sig);
|
||||||
trampolines.insert(sig_id, trampoline);
|
trampolines.insert(sig_id, trampoline);
|
||||||
|
|
||||||
create_handle(module, store, finished_functions, trampolines, state)
|
create_handle(module, store, finished_functions, trampolines, state)
|
||||||
|
|||||||
@@ -67,6 +67,20 @@ pub enum ValType {
|
|||||||
FuncRef,
|
FuncRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ValType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ValType::I32 => write!(f, "i32"),
|
||||||
|
ValType::I64 => write!(f, "i64"),
|
||||||
|
ValType::F32 => write!(f, "f32"),
|
||||||
|
ValType::F64 => write!(f, "f64"),
|
||||||
|
ValType::V128 => write!(f, "v128"),
|
||||||
|
ValType::ExternRef => write!(f, "externref"),
|
||||||
|
ValType::FuncRef => write!(f, "funcref"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ValType {
|
impl ValType {
|
||||||
/// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`,
|
/// Returns true if `ValType` matches any of the numeric types. (e.g. `I32`,
|
||||||
/// `I64`, `F32`, `F64`).
|
/// `I64`, `F32`, `F64`).
|
||||||
@@ -106,6 +120,31 @@ impl ValType {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_wasm_type(&self) -> wasm::WasmType {
|
||||||
|
match self {
|
||||||
|
Self::I32 => wasm::WasmType::I32,
|
||||||
|
Self::I64 => wasm::WasmType::I64,
|
||||||
|
Self::F32 => wasm::WasmType::F32,
|
||||||
|
Self::F64 => wasm::WasmType::F64,
|
||||||
|
Self::V128 => wasm::WasmType::V128,
|
||||||
|
Self::FuncRef => wasm::WasmType::FuncRef,
|
||||||
|
Self::ExternRef => wasm::WasmType::ExternRef,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_wasm_type(ty: &wasm::WasmType) -> Option<Self> {
|
||||||
|
match ty {
|
||||||
|
wasm::WasmType::I32 => Some(Self::I32),
|
||||||
|
wasm::WasmType::I64 => Some(Self::I64),
|
||||||
|
wasm::WasmType::F32 => Some(Self::F32),
|
||||||
|
wasm::WasmType::F64 => Some(Self::F64),
|
||||||
|
wasm::WasmType::V128 => Some(Self::V128),
|
||||||
|
wasm::WasmType::FuncRef => Some(Self::FuncRef),
|
||||||
|
wasm::WasmType::ExternRef => Some(Self::ExternRef),
|
||||||
|
wasm::WasmType::Func | wasm::WasmType::EmptyBlockType => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// External Types
|
// External Types
|
||||||
@@ -184,12 +223,6 @@ impl From<TableType> for ExternType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function Types
|
|
||||||
fn from_wasmtime_abiparam(param: &ir::AbiParam) -> Option<ValType> {
|
|
||||||
assert_eq!(param.purpose, ir::ArgumentPurpose::Normal);
|
|
||||||
ValType::from_wasmtime_type(param.value_type)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A descriptor for a function in a WebAssembly module.
|
/// A descriptor for a function in a WebAssembly module.
|
||||||
///
|
///
|
||||||
/// WebAssembly functions can have 0 or more parameters and results.
|
/// WebAssembly functions can have 0 or more parameters and results.
|
||||||
@@ -218,6 +251,13 @@ impl FuncType {
|
|||||||
&self.results
|
&self.results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_wasm_func_type(&self) -> wasm::WasmFuncType {
|
||||||
|
wasm::WasmFuncType {
|
||||||
|
params: self.params.iter().map(|p| p.to_wasm_type()).collect(),
|
||||||
|
returns: self.results.iter().map(|r| r.to_wasm_type()).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `Some` if this function signature was compatible with cranelift,
|
/// Returns `Some` if this function signature was compatible with cranelift,
|
||||||
/// or `None` if one of the types/results wasn't supported or compatible
|
/// or `None` if one of the types/results wasn't supported or compatible
|
||||||
/// with cranelift.
|
/// with cranelift.
|
||||||
@@ -251,17 +291,16 @@ impl FuncType {
|
|||||||
/// Returns `None` if any types in the signature can't be converted to the
|
/// Returns `None` if any types in the signature can't be converted to the
|
||||||
/// types in this crate, but that should very rarely happen and largely only
|
/// types in this crate, but that should very rarely happen and largely only
|
||||||
/// indicate a bug in our cranelift integration.
|
/// indicate a bug in our cranelift integration.
|
||||||
pub(crate) fn from_wasmtime_signature(signature: &ir::Signature) -> Option<FuncType> {
|
pub(crate) fn from_wasm_func_type(signature: &wasm::WasmFuncType) -> Option<FuncType> {
|
||||||
let params = signature
|
let params = signature
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.skip(2) // skip the caller/callee vmctx
|
.map(|p| ValType::from_wasm_type(p))
|
||||||
.map(|p| from_wasmtime_abiparam(p))
|
|
||||||
.collect::<Option<Vec<_>>>()?;
|
.collect::<Option<Vec<_>>>()?;
|
||||||
let results = signature
|
let results = signature
|
||||||
.returns
|
.returns
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| from_wasmtime_abiparam(p))
|
.map(|r| ValType::from_wasm_type(r))
|
||||||
.collect::<Option<Vec<_>>>()?;
|
.collect::<Option<Vec<_>>>()?;
|
||||||
Some(FuncType {
|
Some(FuncType {
|
||||||
params: params.into_boxed_slice(),
|
params: params.into_boxed_slice(),
|
||||||
@@ -390,7 +429,7 @@ impl MemoryType {
|
|||||||
|
|
||||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||||
pub(crate) enum EntityType<'module> {
|
pub(crate) enum EntityType<'module> {
|
||||||
Function(&'module ir::Signature),
|
Function(&'module wasm::WasmFuncType),
|
||||||
Table(&'module wasm::Table),
|
Table(&'module wasm::Table),
|
||||||
Memory(&'module wasm::Memory),
|
Memory(&'module wasm::Memory),
|
||||||
Global(&'module wasm::Global),
|
Global(&'module wasm::Global),
|
||||||
@@ -404,7 +443,7 @@ impl<'module> EntityType<'module> {
|
|||||||
) -> EntityType<'module> {
|
) -> EntityType<'module> {
|
||||||
match entity_index {
|
match entity_index {
|
||||||
EntityIndex::Function(func_index) => {
|
EntityIndex::Function(func_index) => {
|
||||||
let sig = module.local.func_signature(*func_index);
|
let sig = module.local.wasm_func_type(*func_index);
|
||||||
EntityType::Function(&sig)
|
EntityType::Function(&sig)
|
||||||
}
|
}
|
||||||
EntityIndex::Table(table_index) => {
|
EntityIndex::Table(table_index) => {
|
||||||
@@ -422,7 +461,7 @@ impl<'module> EntityType<'module> {
|
|||||||
/// Convert this `EntityType` to an `ExternType`.
|
/// Convert this `EntityType` to an `ExternType`.
|
||||||
pub(crate) fn extern_type(&self) -> ExternType {
|
pub(crate) fn extern_type(&self) -> ExternType {
|
||||||
match self {
|
match self {
|
||||||
EntityType::Function(sig) => FuncType::from_wasmtime_signature(sig)
|
EntityType::Function(sig) => FuncType::from_wasm_func_type(sig)
|
||||||
.expect("core wasm function type should be supported")
|
.expect("core wasm function type should be supported")
|
||||||
.into(),
|
.into(),
|
||||||
EntityType::Table(table) => TableType::from_wasmtime_table(table).into(),
|
EntityType::Table(table) => TableType::from_wasmtime_table(table).into(),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::r#ref::ExternRef;
|
|||||||
use crate::{Func, Store, ValType};
|
use crate::{Func, Store, ValType};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use wasmtime_runtime::VMExternRef;
|
||||||
|
|
||||||
/// Possible runtime values that a WebAssembly module can either consume or
|
/// Possible runtime values that a WebAssembly module can either consume or
|
||||||
/// produce.
|
/// produce.
|
||||||
@@ -26,9 +27,7 @@ pub enum Val {
|
|||||||
F64(u64),
|
F64(u64),
|
||||||
|
|
||||||
/// An `externref` value which can hold opaque data to the wasm instance itself.
|
/// An `externref` value which can hold opaque data to the wasm instance itself.
|
||||||
///
|
ExternRef(Option<ExternRef>),
|
||||||
/// Note that this is a nullable value as well.
|
|
||||||
ExternRef(ExternRef),
|
|
||||||
|
|
||||||
/// A first-class reference to a WebAssembly function.
|
/// A first-class reference to a WebAssembly function.
|
||||||
FuncRef(Func),
|
FuncRef(Func),
|
||||||
@@ -64,7 +63,7 @@ macro_rules! accessors {
|
|||||||
impl Val {
|
impl Val {
|
||||||
/// Returns a null `externref` value.
|
/// Returns a null `externref` value.
|
||||||
pub fn null() -> Val {
|
pub fn null() -> Val {
|
||||||
Val::ExternRef(ExternRef::null())
|
Val::ExternRef(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the corresponding [`ValType`] for this `Val`.
|
/// Returns the corresponding [`ValType`] for this `Val`.
|
||||||
@@ -87,18 +86,31 @@ impl Val {
|
|||||||
Val::F32(u) => ptr::write(p as *mut u32, *u),
|
Val::F32(u) => ptr::write(p as *mut u32, *u),
|
||||||
Val::F64(u) => ptr::write(p as *mut u64, *u),
|
Val::F64(u) => ptr::write(p as *mut u64, *u),
|
||||||
Val::V128(b) => ptr::write(p as *mut u128, *b),
|
Val::V128(b) => ptr::write(p as *mut u128, *b),
|
||||||
|
Val::ExternRef(None) => ptr::write(p, 0),
|
||||||
|
Val::ExternRef(Some(x)) => ptr::write(p as *mut *mut u8, x.inner.clone().into_raw()),
|
||||||
_ => unimplemented!("Val::write_value_to"),
|
_ => unimplemented!("Val::write_value_to"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn read_value_from(p: *const u128, ty: &ValType) -> Val {
|
pub(crate) unsafe fn read_value_from(store: &Store, p: *const u128, ty: &ValType) -> Val {
|
||||||
match ty {
|
match ty {
|
||||||
ValType::I32 => Val::I32(ptr::read(p as *const i32)),
|
ValType::I32 => Val::I32(ptr::read(p as *const i32)),
|
||||||
ValType::I64 => Val::I64(ptr::read(p as *const i64)),
|
ValType::I64 => Val::I64(ptr::read(p as *const i64)),
|
||||||
ValType::F32 => Val::F32(ptr::read(p as *const u32)),
|
ValType::F32 => Val::F32(ptr::read(p as *const u32)),
|
||||||
ValType::F64 => Val::F64(ptr::read(p as *const u64)),
|
ValType::F64 => Val::F64(ptr::read(p as *const u64)),
|
||||||
ValType::V128 => Val::V128(ptr::read(p as *const u128)),
|
ValType::V128 => Val::V128(ptr::read(p as *const u128)),
|
||||||
_ => unimplemented!("Val::read_value_from"),
|
ValType::ExternRef => {
|
||||||
|
let raw = ptr::read(p as *const *mut u8);
|
||||||
|
if raw.is_null() {
|
||||||
|
Val::ExternRef(None)
|
||||||
|
} else {
|
||||||
|
Val::ExternRef(Some(ExternRef {
|
||||||
|
inner: VMExternRef::from_raw(raw),
|
||||||
|
store: store.weak(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unimplemented!("Val::read_value_from: {:?}", ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,24 +124,31 @@ impl Val {
|
|||||||
(V128(u128) v128 unwrap_v128 *e)
|
(V128(u128) v128 unwrap_v128 *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to access the underlying value of this `Val`, returning
|
/// Attempt to access the underlying `externref` value of this `Val`.
|
||||||
/// `None` if it is not the correct type.
|
|
||||||
///
|
///
|
||||||
/// This will return `Some` for both the `ExternRef` and `FuncRef` types.
|
/// If this is not an `externref`, then `None` is returned.
|
||||||
pub fn externref(&self) -> Option<ExternRef> {
|
///
|
||||||
|
/// If this is a null `externref`, then `Some(None)` is returned.
|
||||||
|
///
|
||||||
|
/// If this is a non-null `externref`, then `Some(Some(..))` is returned.
|
||||||
|
pub fn externref(&self) -> Option<Option<ExternRef>> {
|
||||||
match self {
|
match self {
|
||||||
Val::ExternRef(e) => Some(e.clone()),
|
Val::ExternRef(e) => Some(e.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying value of this `Val`, panicking if it's the
|
/// Returns the underlying `externref` value of this `Val`, panicking if it's the
|
||||||
/// wrong type.
|
/// wrong type.
|
||||||
///
|
///
|
||||||
|
/// If this is a null `externref`, then `None` is returned.
|
||||||
|
///
|
||||||
|
/// If this is a non-null `externref`, then `Some(..)` is returned.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if `self` is not of the right type.
|
/// Panics if `self` is not a (nullable) `externref`.
|
||||||
pub fn unwrap_externref(&self) -> ExternRef {
|
pub fn unwrap_externref(&self) -> Option<ExternRef> {
|
||||||
self.externref().expect("expected externref")
|
self.externref().expect("expected externref")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,8 +159,8 @@ impl Val {
|
|||||||
// TODO: need to implement this once we actually finalize what
|
// TODO: need to implement this once we actually finalize what
|
||||||
// `externref` will look like and it's actually implemented to pass it
|
// `externref` will look like and it's actually implemented to pass it
|
||||||
// to compiled wasm as well.
|
// to compiled wasm as well.
|
||||||
Val::ExternRef(ExternRef::Ref(_)) | Val::ExternRef(ExternRef::Other(_)) => false,
|
Val::ExternRef(Some(e)) => e.store.ptr_eq(&store.weak()),
|
||||||
Val::ExternRef(ExternRef::Null) => true,
|
Val::ExternRef(None) => true,
|
||||||
|
|
||||||
// Integers have no association with any particular store, so
|
// Integers have no association with any particular store, so
|
||||||
// they're always considered as "yes I came from that store",
|
// they're always considered as "yes I came from that store",
|
||||||
@@ -176,6 +195,12 @@ impl From<f64> for Val {
|
|||||||
|
|
||||||
impl From<ExternRef> for Val {
|
impl From<ExternRef> for Val {
|
||||||
fn from(val: ExternRef) -> Val {
|
fn from(val: ExternRef) -> Val {
|
||||||
|
Val::ExternRef(Some(val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Option<ExternRef>> for Val {
|
||||||
|
fn from(val: Option<ExternRef>) -> Val {
|
||||||
Val::ExternRef(val)
|
Val::ExternRef(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,7 +219,7 @@ pub(crate) fn into_checked_anyfunc(
|
|||||||
bail!("cross-`Store` values are not supported");
|
bail!("cross-`Store` values are not supported");
|
||||||
}
|
}
|
||||||
Ok(match val {
|
Ok(match val {
|
||||||
Val::ExternRef(ExternRef::Null) => wasmtime_runtime::VMCallerCheckedAnyfunc {
|
Val::ExternRef(None) => wasmtime_runtime::VMCallerCheckedAnyfunc {
|
||||||
func_ptr: ptr::null(),
|
func_ptr: ptr::null(),
|
||||||
type_index: wasmtime_runtime::VMSharedSignatureIndex::default(),
|
type_index: wasmtime_runtime::VMSharedSignatureIndex::default(),
|
||||||
vmctx: ptr::null_mut(),
|
vmctx: ptr::null_mut(),
|
||||||
@@ -216,7 +241,7 @@ pub(crate) fn from_checked_anyfunc(
|
|||||||
store: &Store,
|
store: &Store,
|
||||||
) -> Val {
|
) -> Val {
|
||||||
if item.type_index == wasmtime_runtime::VMSharedSignatureIndex::default() {
|
if item.type_index == wasmtime_runtime::VMSharedSignatureIndex::default() {
|
||||||
return Val::ExternRef(ExternRef::Null);
|
return Val::ExternRef(None);
|
||||||
}
|
}
|
||||||
let instance_handle = unsafe { wasmtime_runtime::InstanceHandle::from_vmctx(item.vmctx) };
|
let instance_handle = unsafe { wasmtime_runtime::InstanceHandle::from_vmctx(item.vmctx) };
|
||||||
let export = wasmtime_runtime::ExportFunction {
|
let export = wasmtime_runtime::ExportFunction {
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ pub fn link_spectest(linker: &mut Linker) -> Result<()> {
|
|||||||
linker.define("spectest", "global_f64", g)?;
|
linker.define("spectest", "global_f64", g)?;
|
||||||
|
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(10, Some(20)));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(10, Some(20)));
|
||||||
let table = Table::new(linker.store(), ty, Val::ExternRef(ExternRef::Null))?;
|
let table = Table::new(linker.store(), ty, Val::ExternRef(None))?;
|
||||||
linker.define("spectest", "table", table)?;
|
linker.define("spectest", "table", table)?;
|
||||||
|
|
||||||
let ty = MemoryType::new(Limits::new(1, Some(2)));
|
let ty = MemoryType::new(Limits::new(1, Some(2)));
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ use anyhow::{anyhow, bail, Context as _, Result};
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str;
|
use std::str;
|
||||||
use wasmtime::*;
|
use wasmtime::*;
|
||||||
use wast::parser::{self, ParseBuffer};
|
|
||||||
use wast::Wat;
|
use wast::Wat;
|
||||||
|
use wast::{
|
||||||
|
parser::{self, ParseBuffer},
|
||||||
|
RefType,
|
||||||
|
};
|
||||||
|
|
||||||
/// Translate from a `script::Value` to a `RuntimeValue`.
|
/// Translate from a `script::Value` to a `RuntimeValue`.
|
||||||
fn runtime_value(v: &wast::Expression<'_>) -> Result<Val> {
|
fn runtime_value(store: &Store, v: &wast::Expression<'_>) -> Result<Val> {
|
||||||
use wast::Instruction::*;
|
use wast::Instruction::*;
|
||||||
|
|
||||||
if v.instrs.len() != 1 {
|
if v.instrs.len() != 1 {
|
||||||
@@ -19,6 +22,8 @@ fn runtime_value(v: &wast::Expression<'_>) -> Result<Val> {
|
|||||||
F32Const(x) => Val::F32(x.bits),
|
F32Const(x) => Val::F32(x.bits),
|
||||||
F64Const(x) => Val::F64(x.bits),
|
F64Const(x) => Val::F64(x.bits),
|
||||||
V128Const(x) => Val::V128(u128::from_le_bytes(x.to_le_bytes())),
|
V128Const(x) => Val::V128(u128::from_le_bytes(x.to_le_bytes())),
|
||||||
|
RefNull(RefType::Extern) => Val::ExternRef(None),
|
||||||
|
RefExtern(x) => Val::ExternRef(Some(ExternRef::new(store, *x))),
|
||||||
other => bail!("couldn't convert {:?} to a runtime value", other),
|
other => bail!("couldn't convert {:?} to a runtime value", other),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -114,7 +119,7 @@ impl WastContext {
|
|||||||
let values = exec
|
let values = exec
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(runtime_value)
|
.map(|v| runtime_value(&self.store, v))
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
self.invoke(exec.module.map(|i| i.name()), exec.name, &values)
|
self.invoke(exec.module.map(|i| i.name()), exec.name, &values)
|
||||||
}
|
}
|
||||||
@@ -403,6 +408,18 @@ fn val_matches(actual: &Val, expected: &wast::AssertExpression) -> Result<bool>
|
|||||||
(Val::F32(a), wast::AssertExpression::F32(b)) => f32_matches(*a, b),
|
(Val::F32(a), wast::AssertExpression::F32(b)) => f32_matches(*a, b),
|
||||||
(Val::F64(a), wast::AssertExpression::F64(b)) => f64_matches(*a, b),
|
(Val::F64(a), wast::AssertExpression::F64(b)) => f64_matches(*a, b),
|
||||||
(Val::V128(a), wast::AssertExpression::V128(b)) => v128_matches(*a, b),
|
(Val::V128(a), wast::AssertExpression::V128(b)) => v128_matches(*a, b),
|
||||||
|
(Val::ExternRef(x), wast::AssertExpression::RefNull(wast::RefType::Extern)) => x.is_none(),
|
||||||
|
(Val::ExternRef(x), wast::AssertExpression::RefExtern(y)) => {
|
||||||
|
if let Some(x) = x {
|
||||||
|
let x = x
|
||||||
|
.data()
|
||||||
|
.downcast_ref::<u32>()
|
||||||
|
.expect("only u32 externrefs created in wast test suites");
|
||||||
|
x == y
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => bail!(
|
_ => bail!(
|
||||||
"don't know how to compare {:?} and {:?} yet",
|
"don't know how to compare {:?} and {:?} yet",
|
||||||
actual,
|
actual,
|
||||||
|
|||||||
0
fuzz/fuzz_targets/api_calls.rs
Executable file → Normal file
0
fuzz/fuzz_targets/api_calls.rs
Executable file → Normal file
0
fuzz/fuzz_targets/compile.rs
Executable file → Normal file
0
fuzz/fuzz_targets/compile.rs
Executable file → Normal file
0
fuzz/fuzz_targets/differential.rs
Executable file → Normal file
0
fuzz/fuzz_targets/differential.rs
Executable file → Normal file
0
fuzz/fuzz_targets/instantiate.rs
Executable file → Normal file
0
fuzz/fuzz_targets/instantiate.rs
Executable file → Normal file
0
fuzz/fuzz_targets/instantiate_translated.rs
Executable file → Normal file
0
fuzz/fuzz_targets/instantiate_translated.rs
Executable file → Normal file
@@ -28,47 +28,27 @@ fn bad_tables() {
|
|||||||
|
|
||||||
// get out of bounds
|
// get out of bounds
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(0, Some(1)));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(0, Some(1)));
|
||||||
let t = Table::new(
|
let t = Table::new(&Store::default(), ty.clone(), Val::ExternRef(None)).unwrap();
|
||||||
&Store::default(),
|
|
||||||
ty.clone(),
|
|
||||||
Val::ExternRef(ExternRef::Null),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert!(t.get(0).is_none());
|
assert!(t.get(0).is_none());
|
||||||
assert!(t.get(u32::max_value()).is_none());
|
assert!(t.get(u32::max_value()).is_none());
|
||||||
|
|
||||||
// set out of bounds or wrong type
|
// set out of bounds or wrong type
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(1, Some(1)));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(1, Some(1)));
|
||||||
let t = Table::new(
|
let t = Table::new(&Store::default(), ty.clone(), Val::ExternRef(None)).unwrap();
|
||||||
&Store::default(),
|
|
||||||
ty.clone(),
|
|
||||||
Val::ExternRef(ExternRef::Null),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert!(t.set(0, Val::I32(0)).is_err());
|
assert!(t.set(0, Val::I32(0)).is_err());
|
||||||
assert!(t.set(0, Val::ExternRef(ExternRef::Null)).is_ok());
|
assert!(t.set(0, Val::ExternRef(None)).is_ok());
|
||||||
assert!(t.set(1, Val::ExternRef(ExternRef::Null)).is_err());
|
assert!(t.set(1, Val::ExternRef(None)).is_err());
|
||||||
|
|
||||||
// grow beyond max
|
// grow beyond max
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(1, Some(1)));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(1, Some(1)));
|
||||||
let t = Table::new(
|
let t = Table::new(&Store::default(), ty.clone(), Val::ExternRef(None)).unwrap();
|
||||||
&Store::default(),
|
assert!(t.grow(0, Val::ExternRef(None)).is_ok());
|
||||||
ty.clone(),
|
assert!(t.grow(1, Val::ExternRef(None)).is_err());
|
||||||
Val::ExternRef(ExternRef::Null),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert!(t.grow(0, Val::ExternRef(ExternRef::Null)).is_ok());
|
|
||||||
assert!(t.grow(1, Val::ExternRef(ExternRef::Null)).is_err());
|
|
||||||
assert_eq!(t.size(), 1);
|
assert_eq!(t.size(), 1);
|
||||||
|
|
||||||
// grow wrong type
|
// grow wrong type
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(1, Some(2)));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(1, Some(2)));
|
||||||
let t = Table::new(
|
let t = Table::new(&Store::default(), ty.clone(), Val::ExternRef(None)).unwrap();
|
||||||
&Store::default(),
|
|
||||||
ty.clone(),
|
|
||||||
Val::ExternRef(ExternRef::Null),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert!(t.grow(1, Val::I32(0)).is_err());
|
assert!(t.grow(1, Val::I32(0)).is_err());
|
||||||
assert_eq!(t.size(), 1);
|
assert_eq!(t.size(), 1);
|
||||||
}
|
}
|
||||||
@@ -88,7 +68,7 @@ fn cross_store() -> anyhow::Result<()> {
|
|||||||
let ty = MemoryType::new(Limits::new(1, None));
|
let ty = MemoryType::new(Limits::new(1, None));
|
||||||
let memory = Memory::new(&store2, ty);
|
let memory = Memory::new(&store2, ty);
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
||||||
let table = Table::new(&store2, ty, Val::ExternRef(ExternRef::Null))?;
|
let table = Table::new(&store2, ty, Val::ExternRef(None))?;
|
||||||
|
|
||||||
let need_func = Module::new(&store1, r#"(module (import "" "" (func)))"#)?;
|
let need_func = Module::new(&store1, r#"(module (import "" "" (func)))"#)?;
|
||||||
assert!(Instance::new(&need_func, &[func.into()]).is_err());
|
assert!(Instance::new(&need_func, &[func.into()]).is_err());
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ fn link_twice_bad() -> Result<()> {
|
|||||||
|
|
||||||
// tables
|
// tables
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
||||||
let table = Table::new(&store, ty, Val::ExternRef(ExternRef::Null))?;
|
let table = Table::new(&store, ty, Val::ExternRef(None))?;
|
||||||
linker.define("", "", table.clone())?;
|
linker.define("", "", table.clone())?;
|
||||||
assert!(linker.define("", "", table.clone()).is_err());
|
assert!(linker.define("", "", table.clone()).is_err());
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(2, None));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(2, None));
|
||||||
let table = Table::new(&store, ty, Val::ExternRef(ExternRef::Null))?;
|
let table = Table::new(&store, ty, Val::ExternRef(None))?;
|
||||||
assert!(linker.define("", "", table.clone()).is_err());
|
assert!(linker.define("", "", table.clone()).is_err());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use wasmtime::*;
|
|||||||
fn get_none() {
|
fn get_none() {
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
||||||
let table = Table::new(&store, ty, Val::ExternRef(ExternRef::Null)).unwrap();
|
let table = Table::new(&store, ty, Val::ExternRef(None)).unwrap();
|
||||||
match table.get(0) {
|
match table.get(0) {
|
||||||
Some(Val::ExternRef(ExternRef::Null)) => {}
|
Some(Val::ExternRef(None)) => {}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
assert!(table.get(1).is_none());
|
assert!(table.get(1).is_none());
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ fn mismatched_arguments() -> Result<()> {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
func.call(&[Val::F32(0)]).unwrap_err().to_string(),
|
func.call(&[Val::F32(0)]).unwrap_err().to_string(),
|
||||||
"argument type mismatch",
|
"argument type mismatch: found f32 but expected i32",
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
func.call(&[Val::I32(0), Val::I32(1)])
|
func.call(&[Val::I32(0), Val::I32(1)])
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ fn use_func_after_drop() -> Result<()> {
|
|||||||
assert_eq!(closed_over_data, "abcd");
|
assert_eq!(closed_over_data, "abcd");
|
||||||
});
|
});
|
||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
||||||
table = Table::new(&store, ty, Val::ExternRef(ExternRef::Null))?;
|
table = Table::new(&store, ty, Val::ExternRef(None))?;
|
||||||
table.set(0, func.into())?;
|
table.set(0, func.into())?;
|
||||||
}
|
}
|
||||||
let func = table.get(0).unwrap().funcref().unwrap().clone();
|
let func = table.get(0).unwrap().funcref().unwrap().clone();
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
(module
|
||||||
|
(func (export "identity") (param externref) (result externref)
|
||||||
|
local.get 0))
|
||||||
|
|
||||||
|
(assert_return (invoke "identity" (ref.null extern))
|
||||||
|
(ref.null extern))
|
||||||
|
(assert_return (invoke "identity" (ref.extern 1))
|
||||||
|
(ref.extern 1))
|
||||||
Reference in New Issue
Block a user