* Enable jitdump profiling support by default This the result of some of the investigation I was doing for #1017. I've done a number of refactorings here which culminated in a number of changes that all amount to what I think should result in jitdump support being enabled by default: * Pass in a list of finished functions instead of just a range to ensure that we're emitting jit dump data for a specific module rather than a whole `CodeMemory` which may have other modules. * Define `ProfilingStrategy` in the `wasmtime` crate to have everything locally-defined * Add support to the C API to enable profiling * Documentation added for profiling with jitdump to the book * Split out supported/unsupported files in `jitdump.rs` to avoid having lots of `#[cfg]`. * Make dependencies optional that are only used for `jitdump`. * Move initialization up-front to `JitDumpAgent::new()` instead of deferring it to the first module. * Pass around `Arc<dyn ProfilingAgent>` instead of `Option<Arc<Mutex<Box<dyn ProfilingAgent>>>>` The `jitdump` Cargo feature is now enabled by default which means that our published binaries, C API artifacts, and crates will support profiling at runtime by default. The support I don't think is fully fleshed out and working but I think it's probably in a good enough spot we can get users playing around with it!
677 lines
25 KiB
Rust
677 lines
25 KiB
Rust
use crate::frame_info::{GlobalFrameInfoRegistration, FRAME_INFO};
|
|
use crate::runtime::Store;
|
|
use crate::types::{
|
|
ExportType, ExternType, FuncType, GlobalType, ImportType, Limits, MemoryType, Mutability,
|
|
TableType, ValType,
|
|
};
|
|
use anyhow::{bail, Error, Result};
|
|
use std::path::Path;
|
|
use std::sync::{Arc, Mutex};
|
|
use wasmparser::{validate, ExternalKind, ImportSectionEntryType, ModuleReader, SectionCode};
|
|
use wasmtime_jit::CompiledModule;
|
|
|
|
fn into_memory_type(mt: wasmparser::MemoryType) -> Result<MemoryType> {
|
|
if mt.shared {
|
|
bail!("shared memories are not supported yet");
|
|
}
|
|
Ok(MemoryType::new(Limits::new(
|
|
mt.limits.initial,
|
|
mt.limits.maximum,
|
|
)))
|
|
}
|
|
|
|
fn into_global_type(gt: wasmparser::GlobalType) -> GlobalType {
|
|
let mutability = if gt.mutable {
|
|
Mutability::Var
|
|
} else {
|
|
Mutability::Const
|
|
};
|
|
GlobalType::new(into_valtype(>.content_type), mutability)
|
|
}
|
|
|
|
// `into_valtype` is used for `map` which requires `&T`.
|
|
#[allow(clippy::trivially_copy_pass_by_ref)]
|
|
fn into_valtype(ty: &wasmparser::Type) -> ValType {
|
|
use wasmparser::Type::*;
|
|
match ty {
|
|
I32 => ValType::I32,
|
|
I64 => ValType::I64,
|
|
F32 => ValType::F32,
|
|
F64 => ValType::F64,
|
|
V128 => ValType::V128,
|
|
AnyFunc => ValType::FuncRef,
|
|
AnyRef => ValType::AnyRef,
|
|
_ => unimplemented!("types in into_valtype"),
|
|
}
|
|
}
|
|
|
|
fn into_func_type(mt: wasmparser::FuncType) -> FuncType {
|
|
assert_eq!(mt.form, wasmparser::Type::Func);
|
|
let params = mt.params.iter().map(into_valtype).collect::<Vec<_>>();
|
|
let returns = mt.returns.iter().map(into_valtype).collect::<Vec<_>>();
|
|
FuncType::new(params.into_boxed_slice(), returns.into_boxed_slice())
|
|
}
|
|
|
|
fn into_table_type(tt: wasmparser::TableType) -> TableType {
|
|
assert!(
|
|
tt.element_type == wasmparser::Type::AnyFunc || tt.element_type == wasmparser::Type::AnyRef
|
|
);
|
|
let ty = into_valtype(&tt.element_type);
|
|
let limits = Limits::new(tt.limits.initial, tt.limits.maximum);
|
|
TableType::new(ty, limits)
|
|
}
|
|
|
|
/// A compiled WebAssembly module, ready to be instantiated.
|
|
///
|
|
/// A `Module` is a compiled in-memory representation of an input WebAssembly
|
|
/// binary. A `Module` is then used to create an [`Instance`](crate::Instance)
|
|
/// through an instantiation process. You cannot call functions or fetch
|
|
/// globals, for example, on a `Module` because it's purely a code
|
|
/// representation. Instead you'll need to create an
|
|
/// [`Instance`](crate::Instance) to interact with the wasm module.
|
|
///
|
|
/// Creating a `Module` currently involves compiling code, meaning that it can
|
|
/// be an expensive operation. All `Module` instances are compiled according to
|
|
/// the configuration in [`Config`], but typically they're JIT-compiled. If
|
|
/// you'd like to instantiate a module multiple times you can do so with
|
|
/// compiling the original wasm module only once with a single [`Module`]
|
|
/// instance.
|
|
///
|
|
/// ## Modules and `Clone`
|
|
///
|
|
/// Using `clone` on a `Module` is a cheap operation. It will not create an
|
|
/// entirely new module, but rather just a new reference to the existing module.
|
|
/// In other words it's a shallow copy, not a deep copy.
|
|
///
|
|
/// ## Examples
|
|
///
|
|
/// There are a number of ways you can create a `Module`, for example pulling
|
|
/// the bytes from a number of locations. One example is loading a module from
|
|
/// the filesystem:
|
|
///
|
|
/// ```no_run
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// let store = Store::default();
|
|
/// let module = Module::from_file(&store, "path/to/foo.wasm")?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// You can also load the wasm text format if more convenient too:
|
|
///
|
|
/// ```no_run
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// let store = Store::default();
|
|
/// // Now we're using the WebAssembly text extension: `.wat`!
|
|
/// let module = Module::from_file(&store, "path/to/foo.wat")?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// And if you've already got the bytes in-memory you can use the
|
|
/// [`Module::new`] constructor:
|
|
///
|
|
/// ```no_run
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// let store = Store::default();
|
|
/// # let wasm_bytes: Vec<u8> = Vec::new();
|
|
/// let module = Module::new(&store, &wasm_bytes)?;
|
|
///
|
|
/// // It also works with the text format!
|
|
/// let module = Module::new(&store, "(module (func))")?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// [`Config`]: crate::Config
|
|
#[derive(Clone)]
|
|
pub struct Module {
|
|
inner: Arc<ModuleInner>,
|
|
}
|
|
|
|
struct ModuleInner {
|
|
store: Store,
|
|
imports: Box<[ImportType]>,
|
|
exports: Box<[ExportType]>,
|
|
compiled: CompiledModule,
|
|
frame_info_registration: Mutex<Option<Option<GlobalFrameInfoRegistration>>>,
|
|
}
|
|
|
|
impl Module {
|
|
/// Creates a new WebAssembly `Module` from the given in-memory `bytes`.
|
|
///
|
|
/// The `bytes` provided must be in one of two formats:
|
|
///
|
|
/// * It can be a [binary-encoded][binary] WebAssembly module. This
|
|
/// is always supported.
|
|
/// * It may also be a [text-encoded][text] instance of the WebAssembly
|
|
/// text format. This is only supported when the `wat` feature of this
|
|
/// crate is enabled. If this is supplied then the text format will be
|
|
/// parsed before validation. Note that the `wat` feature is enabled by
|
|
/// default.
|
|
///
|
|
/// The data for the wasm module must be loaded in-memory if it's present
|
|
/// elsewhere, for example on disk. This requires that the entire binary is
|
|
/// loaded into memory all at once, this API does not support streaming
|
|
/// compilation of a module.
|
|
///
|
|
/// The WebAssembly binary will be decoded and validated. It will also be
|
|
/// compiled according to the configuration of the provided `store` and
|
|
/// cached in this type.
|
|
///
|
|
/// The provided `store` is a global cache for compiled resources as well as
|
|
/// configuration for what wasm features are enabled. It's recommended to
|
|
/// share a `store` among modules if possible.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// This function may fail and return an error. Errors may include
|
|
/// situations such as:
|
|
///
|
|
/// * The binary provided could not be decoded because it's not a valid
|
|
/// WebAssembly binary
|
|
/// * The WebAssembly binary may not validate (e.g. contains type errors)
|
|
/// * Implementation-specific limits were exceeded with a valid binary (for
|
|
/// example too many locals)
|
|
/// * The wasm binary may use features that are not enabled in the
|
|
/// configuration of `store`
|
|
/// * If the `wat` feature is enabled and the input is text, then it may be
|
|
/// rejected if it fails to parse.
|
|
///
|
|
/// The error returned should contain full information about why module
|
|
/// creation failed if one is returned.
|
|
///
|
|
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
|
/// [text]: https://webassembly.github.io/spec/core/text/index.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// The `new` function can be invoked with a in-memory array of bytes:
|
|
///
|
|
/// ```no_run
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// # let wasm_bytes: Vec<u8> = Vec::new();
|
|
/// let module = Module::new(&store, &wasm_bytes)?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// Or you can also pass in a string to be parsed as the wasm text
|
|
/// format:
|
|
///
|
|
/// ```
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// let module = Module::new(&store, "(module (func))")?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
pub fn new(store: &Store, bytes: impl AsRef<[u8]>) -> Result<Module> {
|
|
#[cfg(feature = "wat")]
|
|
let bytes = wat::parse_bytes(bytes.as_ref())?;
|
|
Module::from_binary(store, bytes.as_ref())
|
|
}
|
|
|
|
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
|
/// data. The provided `name` will be used in traps/backtrace details.
|
|
///
|
|
/// See [`Module::new`] for other details.
|
|
pub fn new_with_name(store: &Store, bytes: impl AsRef<[u8]>, name: &str) -> Result<Module> {
|
|
let mut module = Module::new(store, bytes.as_ref())?;
|
|
let inner = Arc::get_mut(&mut module.inner).unwrap();
|
|
Arc::get_mut(inner.compiled.module_mut()).unwrap().name = Some(name.to_string());
|
|
Ok(module)
|
|
}
|
|
|
|
/// Creates a new WebAssembly `Module` from the contents of the given
|
|
/// `file` on disk.
|
|
///
|
|
/// This is a convenience function that will read the `file` provided and
|
|
/// pass the bytes to the [`Module::new`] function. For more information
|
|
/// see [`Module::new`]
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```no_run
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// let store = Store::default();
|
|
/// let module = Module::from_file(&store, "./path/to/foo.wasm")?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// The `.wat` text format is also supported:
|
|
///
|
|
/// ```no_run
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// let module = Module::from_file(&store, "./path/to/foo.wat")?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
pub fn from_file(store: &Store, file: impl AsRef<Path>) -> Result<Module> {
|
|
#[cfg(feature = "wat")]
|
|
let wasm = wat::parse_file(file)?;
|
|
#[cfg(not(feature = "wat"))]
|
|
let wasm = std::fs::read(file)?;
|
|
Module::new(store, &wasm)
|
|
}
|
|
|
|
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
|
/// data.
|
|
///
|
|
/// This is similar to [`Module::new`] except that it requires that the
|
|
/// `binary` input is a WebAssembly binary, the text format is not supported
|
|
/// by this function. It's generally recommended to use [`Module::new`],
|
|
/// but if it's required to not support the text format this function can be
|
|
/// used instead.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// let wasm = b"\0asm\x01\0\0\0";
|
|
/// let module = Module::from_binary(&store, wasm)?;
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// Note that the text format is **not** accepted by this function:
|
|
///
|
|
/// ```
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// assert!(Module::from_binary(&store, b"(module)").is_err());
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
pub fn from_binary(store: &Store, binary: &[u8]) -> Result<Module> {
|
|
Module::validate(store, binary)?;
|
|
// Note that the call to `from_binary_unchecked` here should be ok
|
|
// because we previously validated the binary, meaning we're guaranteed
|
|
// to pass a valid binary for `store`.
|
|
unsafe { Module::from_binary_unchecked(store, binary) }
|
|
}
|
|
|
|
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
|
/// data, skipping validation and asserting that `binary` is a valid
|
|
/// WebAssembly module.
|
|
///
|
|
/// This function is the same as [`Module::new`] except that it skips the
|
|
/// call to [`Module::validate`] and it does not support the text format of
|
|
/// WebAssembly. The WebAssembly binary is not validated for
|
|
/// correctness and it is simply assumed as valid.
|
|
///
|
|
/// For more information about creation of a module and the `store` argument
|
|
/// see the documentation of [`Module::new`].
|
|
///
|
|
/// # Unsafety
|
|
///
|
|
/// This function is `unsafe` due to the unchecked assumption that the input
|
|
/// `binary` is valid. If the `binary` is not actually a valid wasm binary it
|
|
/// may cause invalid machine code to get generated, cause panics, etc.
|
|
///
|
|
/// It is only safe to call this method if [`Module::validate`] succeeds on
|
|
/// the same arguments passed to this function.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// This function may fail for many of the same reasons as [`Module::new`].
|
|
/// While this assumes that the binary is valid it still needs to actually
|
|
/// be somewhat valid for decoding purposes, and the basics of decoding can
|
|
/// still fail.
|
|
pub unsafe fn from_binary_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
|
let mut ret = Module::compile(store, binary)?;
|
|
ret.read_imports_and_exports(binary)?;
|
|
Ok(ret)
|
|
}
|
|
|
|
/// Validates `binary` input data as a WebAssembly binary given the
|
|
/// configuration in `store`.
|
|
///
|
|
/// This function will perform a speedy validation of the `binary` input
|
|
/// WebAssembly module (which is in [binary form][binary], the text format
|
|
/// is not accepted by this function) and return either `Ok` or `Err`
|
|
/// depending on the results of validation. The `store` argument indicates
|
|
/// configuration for WebAssembly features, for example, which are used to
|
|
/// indicate what should be valid and what shouldn't be.
|
|
///
|
|
/// Validation automatically happens as part of [`Module::new`], but is a
|
|
/// requirement for [`Module::from_binary_unchecked`] to be safe.
|
|
///
|
|
/// # Errors
|
|
///
|
|
/// If validation fails for any reason (type check error, usage of a feature
|
|
/// that wasn't enabled, etc) then an error with a description of the
|
|
/// validation issue will be returned.
|
|
///
|
|
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
|
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
|
|
let config = store.engine().config().validating_config.clone();
|
|
validate(binary, Some(config)).map_err(Error::new)
|
|
}
|
|
|
|
unsafe fn compile(store: &Store, binary: &[u8]) -> Result<Self> {
|
|
let compiled = CompiledModule::new(
|
|
&mut store.compiler_mut(),
|
|
binary,
|
|
store.engine().config().debug_info,
|
|
&*store.engine().config().profiler,
|
|
)?;
|
|
|
|
Ok(Module {
|
|
inner: Arc::new(ModuleInner {
|
|
store: store.clone(),
|
|
imports: Box::new([]),
|
|
exports: Box::new([]),
|
|
compiled,
|
|
frame_info_registration: Mutex::new(None),
|
|
}),
|
|
})
|
|
}
|
|
|
|
pub(crate) fn compiled_module(&self) -> &CompiledModule {
|
|
&self.inner.compiled
|
|
}
|
|
|
|
/// Returns identifier/name that this [`Module`] has. This name
|
|
/// is used in traps/backtrace details.
|
|
///
|
|
/// Note that most LLVM/clang/Rust-produced modules do not have a name
|
|
/// associated with them, but other wasm tooling can be used to inject or
|
|
/// add a name.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// let module = Module::new(&store, "(module $foo)")?;
|
|
/// assert_eq!(module.name(), Some("foo"));
|
|
///
|
|
/// let module = Module::new(&store, "(module)")?;
|
|
/// assert_eq!(module.name(), None);
|
|
///
|
|
/// let module = Module::new_with_name(&store, "(module)", "bar")?;
|
|
/// assert_eq!(module.name(), Some("bar"));
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
pub fn name(&self) -> Option<&str> {
|
|
self.inner.compiled.module().name.as_deref()
|
|
}
|
|
|
|
/// Returns the list of imports that this [`Module`] has and must be
|
|
/// satisfied.
|
|
///
|
|
/// This function returns the list of imports that the wasm module has, but
|
|
/// only the types of each import. The type of each import is used to
|
|
/// typecheck the [`Instance::new`](crate::Instance::new) method's `imports`
|
|
/// argument. The arguments to that function must match up 1-to-1 with the
|
|
/// entries in the array returned here.
|
|
///
|
|
/// The imports returned reflect the order of the imports in the wasm module
|
|
/// itself, and note that no form of deduplication happens.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// Modules with no imports return an empty list here:
|
|
///
|
|
/// ```
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// let module = Module::new(&store, "(module)")?;
|
|
/// assert_eq!(module.imports().len(), 0);
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// and modules with imports will have a non-empty list:
|
|
///
|
|
/// ```
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// let wat = r#"
|
|
/// (module
|
|
/// (import "host" "foo" (func))
|
|
/// )
|
|
/// "#;
|
|
/// let module = Module::new(&store, wat)?;
|
|
/// assert_eq!(module.imports().len(), 1);
|
|
/// let import = &module.imports()[0];
|
|
/// assert_eq!(import.module(), "host");
|
|
/// assert_eq!(import.name(), "foo");
|
|
/// match import.ty() {
|
|
/// ExternType::Func(_) => { /* ... */ }
|
|
/// _ => panic!("unexpected import type!"),
|
|
/// }
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
pub fn imports(&self) -> &[ImportType] {
|
|
&self.inner.imports
|
|
}
|
|
|
|
/// Returns the list of exports that this [`Module`] has and will be
|
|
/// available after instantiation.
|
|
///
|
|
/// This function will return the type of each item that will be returned
|
|
/// from [`Instance::exports`](crate::Instance::exports). Each entry in this
|
|
/// list corresponds 1-to-1 with that list, and the entries here will
|
|
/// indicate the name of the export along with the type of the export.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// Modules might not have any exports:
|
|
///
|
|
/// ```
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// let module = Module::new(&store, "(module)")?;
|
|
/// assert!(module.exports().is_empty());
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// When the exports are not empty, you can inspect each export:
|
|
///
|
|
/// ```
|
|
/// # use wasmtime::*;
|
|
/// # fn main() -> anyhow::Result<()> {
|
|
/// # let store = Store::default();
|
|
/// let wat = r#"
|
|
/// (module
|
|
/// (func (export "foo"))
|
|
/// (memory (export "memory") 1)
|
|
/// )
|
|
/// "#;
|
|
/// let module = Module::new(&store, wat)?;
|
|
/// assert_eq!(module.exports().len(), 2);
|
|
///
|
|
/// let foo = &module.exports()[0];
|
|
/// assert_eq!(foo.name(), "foo");
|
|
/// match foo.ty() {
|
|
/// ExternType::Func(_) => { /* ... */ }
|
|
/// _ => panic!("unexpected export type!"),
|
|
/// }
|
|
///
|
|
/// let memory = &module.exports()[1];
|
|
/// assert_eq!(memory.name(), "memory");
|
|
/// match memory.ty() {
|
|
/// ExternType::Memory(_) => { /* ... */ }
|
|
/// _ => panic!("unexpected export type!"),
|
|
/// }
|
|
/// # Ok(())
|
|
/// # }
|
|
/// ```
|
|
pub fn exports(&self) -> &[ExportType] {
|
|
&self.inner.exports
|
|
}
|
|
|
|
/// Returns the [`Store`] that this [`Module`] was compiled into.
|
|
pub fn store(&self) -> &Store {
|
|
&self.inner.store
|
|
}
|
|
|
|
fn read_imports_and_exports(&mut self, binary: &[u8]) -> Result<()> {
|
|
let inner = Arc::get_mut(&mut self.inner).unwrap();
|
|
let mut reader = ModuleReader::new(binary)?;
|
|
let mut imports = Vec::new();
|
|
let mut exports = Vec::new();
|
|
let mut memories = Vec::new();
|
|
let mut tables = Vec::new();
|
|
let mut func_sig = Vec::new();
|
|
let mut sigs = Vec::new();
|
|
let mut globals = Vec::new();
|
|
while !reader.eof() {
|
|
let section = reader.read()?;
|
|
match section.code {
|
|
SectionCode::Memory => {
|
|
let section = section.get_memory_section_reader()?;
|
|
memories.reserve_exact(section.get_count() as usize);
|
|
for entry in section {
|
|
memories.push(into_memory_type(entry?)?);
|
|
}
|
|
}
|
|
SectionCode::Type => {
|
|
let section = section.get_type_section_reader()?;
|
|
sigs.reserve_exact(section.get_count() as usize);
|
|
for entry in section {
|
|
sigs.push(into_func_type(entry?));
|
|
}
|
|
}
|
|
SectionCode::Function => {
|
|
let section = section.get_function_section_reader()?;
|
|
func_sig.reserve_exact(section.get_count() as usize);
|
|
for entry in section {
|
|
func_sig.push(entry?);
|
|
}
|
|
}
|
|
SectionCode::Global => {
|
|
let section = section.get_global_section_reader()?;
|
|
globals.reserve_exact(section.get_count() as usize);
|
|
for entry in section {
|
|
globals.push(into_global_type(entry?.ty));
|
|
}
|
|
}
|
|
SectionCode::Table => {
|
|
let section = section.get_table_section_reader()?;
|
|
tables.reserve_exact(section.get_count() as usize);
|
|
for entry in section {
|
|
tables.push(into_table_type(entry?))
|
|
}
|
|
}
|
|
SectionCode::Import => {
|
|
let section = section.get_import_section_reader()?;
|
|
imports.reserve_exact(section.get_count() as usize);
|
|
for entry in section {
|
|
let entry = entry?;
|
|
let r#type = match entry.ty {
|
|
ImportSectionEntryType::Function(index) => {
|
|
func_sig.push(index);
|
|
let sig = &sigs[index as usize];
|
|
ExternType::Func(sig.clone())
|
|
}
|
|
ImportSectionEntryType::Table(tt) => {
|
|
let table = into_table_type(tt);
|
|
tables.push(table.clone());
|
|
ExternType::Table(table)
|
|
}
|
|
ImportSectionEntryType::Memory(mt) => {
|
|
let memory = into_memory_type(mt)?;
|
|
memories.push(memory.clone());
|
|
ExternType::Memory(memory)
|
|
}
|
|
ImportSectionEntryType::Global(gt) => {
|
|
let global = into_global_type(gt);
|
|
globals.push(global.clone());
|
|
ExternType::Global(global)
|
|
}
|
|
};
|
|
imports.push(ImportType::new(entry.module, entry.field, r#type));
|
|
}
|
|
}
|
|
SectionCode::Export => {
|
|
let section = section.get_export_section_reader()?;
|
|
exports.reserve_exact(section.get_count() as usize);
|
|
for entry in section {
|
|
let entry = entry?;
|
|
let r#type = match entry.kind {
|
|
ExternalKind::Function => {
|
|
let sig_index = func_sig[entry.index as usize] as usize;
|
|
let sig = &sigs[sig_index];
|
|
ExternType::Func(sig.clone())
|
|
}
|
|
ExternalKind::Table => {
|
|
ExternType::Table(tables[entry.index as usize].clone())
|
|
}
|
|
ExternalKind::Memory => {
|
|
ExternType::Memory(memories[entry.index as usize].clone())
|
|
}
|
|
ExternalKind::Global => {
|
|
ExternType::Global(globals[entry.index as usize].clone())
|
|
}
|
|
};
|
|
exports.push(ExportType::new(entry.field, r#type));
|
|
}
|
|
}
|
|
SectionCode::Custom {
|
|
name: "webidl-bindings",
|
|
..
|
|
}
|
|
| SectionCode::Custom {
|
|
name: "wasm-interface-types",
|
|
..
|
|
} => {
|
|
bail!(
|
|
"\
|
|
support for interface types has temporarily been removed from `wasmtime`
|
|
|
|
for more information about this temoprary you can read on the issue online:
|
|
|
|
https://github.com/bytecodealliance/wasmtime/issues/1271
|
|
|
|
and for re-adding support for interface types you can see this issue:
|
|
|
|
https://github.com/bytecodealliance/wasmtime/issues/677
|
|
"
|
|
);
|
|
}
|
|
_ => {
|
|
// skip other sections
|
|
}
|
|
}
|
|
}
|
|
|
|
inner.imports = imports.into();
|
|
inner.exports = exports.into();
|
|
Ok(())
|
|
}
|
|
|
|
/// Register this module's stack frame information into the global scope.
|
|
///
|
|
/// This is required to ensure that any traps can be properly symbolicated.
|
|
pub(crate) fn register_frame_info(&self) {
|
|
let mut info = self.inner.frame_info_registration.lock().unwrap();
|
|
if info.is_some() {
|
|
return;
|
|
}
|
|
*info = Some(FRAME_INFO.register(&self.inner.compiled));
|
|
}
|
|
}
|