Make Instance a refcounting handle around InstanceContents.
This commit is contained in:
@@ -254,7 +254,11 @@ pub fn inspect_memory<'instance>(
|
||||
/// Read a global in this `Instance` identified by an export name.
|
||||
pub fn get(instance: &Instance, global_name: &str) -> Result<RuntimeValue, ActionError> {
|
||||
let (definition, global) = match unsafe { instance.lookup_immutable(global_name) } {
|
||||
Some(Export::Global { definition, global }) => (definition, global),
|
||||
Some(Export::Global {
|
||||
definition,
|
||||
vmctx: _,
|
||||
global,
|
||||
}) => (definition, global),
|
||||
Some(_) => {
|
||||
return Err(ActionError::Kind(format!(
|
||||
"exported item \"{}\" is not a global variable",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::action::{get, inspect_memory, invoke};
|
||||
use crate::{
|
||||
instantiate, ActionError, ActionOutcome, Compiler, Instance, InstanceIndex, Namespace,
|
||||
RuntimeValue, SetupError,
|
||||
instantiate, ActionError, ActionOutcome, Compiler, Instance, Namespace, RuntimeValue,
|
||||
SetupError,
|
||||
};
|
||||
use cranelift_codegen::isa::TargetIsa;
|
||||
use std::borrow::ToOwned;
|
||||
@@ -96,13 +97,10 @@ impl Context {
|
||||
)
|
||||
}
|
||||
|
||||
/// Return the instance index for the instance with the given name.
|
||||
pub fn get_instance_index(
|
||||
&mut self,
|
||||
instance_name: &str,
|
||||
) -> Result<InstanceIndex, UnknownInstance> {
|
||||
/// Return the instance associated with the given name.
|
||||
pub fn get_instance(&mut self, instance_name: &str) -> Result<&mut Instance, UnknownInstance> {
|
||||
self.namespace
|
||||
.get_instance_index(instance_name)
|
||||
.get_instance(instance_name)
|
||||
.ok_or_else(|| UnknownInstance {
|
||||
instance_name: instance_name.to_string(),
|
||||
})
|
||||
@@ -113,72 +111,84 @@ impl Context {
|
||||
&mut self,
|
||||
instance_name: Option<String>,
|
||||
data: &[u8],
|
||||
) -> Result<InstanceIndex, ActionError> {
|
||||
) -> Result<Instance, ActionError> {
|
||||
let instance = self.instantiate(data).map_err(ActionError::Setup)?;
|
||||
Ok(self.instance(instance_name, instance))
|
||||
self.optionally_name_instance(instance_name, instance.clone());
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
/// Install a new `Instance` in this `Namespace`, optionally with the
|
||||
/// given name, and return its index.
|
||||
pub fn instance(&mut self, instance_name: Option<String>, instance: Instance) -> InstanceIndex {
|
||||
self.namespace.instance(instance_name, instance)
|
||||
/// If `name` isn't None, register it for the given instance.
|
||||
pub fn optionally_name_instance(&mut self, name: Option<String>, instance: Instance) {
|
||||
if let Some(name) = name {
|
||||
self.namespace.name_instance(name, instance);
|
||||
}
|
||||
}
|
||||
|
||||
/// Register a name for the given instance.
|
||||
pub fn name_instance(&mut self, name: String, instance: Instance) {
|
||||
self.namespace.name_instance(name, instance);
|
||||
}
|
||||
|
||||
/// Register an additional name for an existing registered instance.
|
||||
pub fn alias(&mut self, name: &str, as_name: String) -> Result<(), UnknownInstance> {
|
||||
let index = self.get_instance_index(&name)?;
|
||||
self.alias_for_indexed(index, as_name);
|
||||
let instance = self.get_instance(&name)?.clone();
|
||||
self.name_instance(as_name, instance);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Register an additional name for an existing registered instance.
|
||||
pub fn alias_for_indexed(&mut self, index: InstanceIndex, as_name: String) {
|
||||
self.namespace.alias_for_indexed(index, as_name)
|
||||
}
|
||||
|
||||
/// Invoke an exported function from an instance.
|
||||
pub fn invoke(
|
||||
/// Invoke an exported function from a named instance.
|
||||
pub fn invoke_named(
|
||||
&mut self,
|
||||
instance_name: &str,
|
||||
field: &str,
|
||||
args: &[RuntimeValue],
|
||||
) -> Result<ActionOutcome, ContextError> {
|
||||
let index = self
|
||||
.get_instance_index(&instance_name)
|
||||
.map_err(ContextError::Instance)?;
|
||||
self.invoke_indexed(index, field, args)
|
||||
let mut instance = self
|
||||
.get_instance(&instance_name)
|
||||
.map_err(ContextError::Instance)?
|
||||
.clone();
|
||||
self.invoke(&mut instance, field, args)
|
||||
.map_err(ContextError::Action)
|
||||
}
|
||||
|
||||
/// Invoke an exported function from an instance.
|
||||
pub fn invoke_indexed(
|
||||
pub fn invoke(
|
||||
&mut self,
|
||||
index: InstanceIndex,
|
||||
instance: &mut Instance,
|
||||
field: &str,
|
||||
args: &[RuntimeValue],
|
||||
) -> Result<ActionOutcome, ActionError> {
|
||||
self.namespace
|
||||
.invoke(&mut *self.compiler, index, field, &args)
|
||||
invoke(&mut *self.compiler, instance, field, &args)
|
||||
}
|
||||
|
||||
/// Get the value of an exported global variable from an instance.
|
||||
pub fn get(&mut self, instance_name: &str, field: &str) -> Result<ActionOutcome, ContextError> {
|
||||
let index = self
|
||||
.get_instance_index(&instance_name)
|
||||
.map_err(ContextError::Instance)?;
|
||||
self.get_indexed(index, field).map_err(ContextError::Action)
|
||||
}
|
||||
|
||||
/// Get the value of an exported global variable from an instance.
|
||||
pub fn get_indexed(
|
||||
pub fn get_named(
|
||||
&mut self,
|
||||
index: InstanceIndex,
|
||||
instance_name: &str,
|
||||
field: &str,
|
||||
) -> Result<ActionOutcome, ActionError> {
|
||||
self.namespace
|
||||
.get(index, field)
|
||||
.map(|value| ActionOutcome::Returned {
|
||||
values: vec![value],
|
||||
})
|
||||
) -> Result<ActionOutcome, ContextError> {
|
||||
let mut instance = self
|
||||
.get_instance(&instance_name)
|
||||
.map_err(ContextError::Instance)?
|
||||
.clone();
|
||||
self.get(&mut instance, field).map_err(ContextError::Action)
|
||||
}
|
||||
|
||||
/// Get the value of an exported global variable from an instance.
|
||||
pub fn get(&mut self, instance: &Instance, field: &str) -> Result<ActionOutcome, ActionError> {
|
||||
get(instance, field).map(|value| ActionOutcome::Returned {
|
||||
values: vec![value],
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a slice of memory from an instance.
|
||||
pub fn inspect_memory<'instance>(
|
||||
&self,
|
||||
instance: &'instance Instance,
|
||||
field_name: &str,
|
||||
start: usize,
|
||||
len: usize,
|
||||
) -> Result<&'instance [u8], ActionError> {
|
||||
inspect_memory(instance, field_name, start, len)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ pub use crate::compiler::Compiler;
|
||||
pub use crate::context::{Context, ContextError, UnknownInstance};
|
||||
pub use crate::instantiate::{instantiate, CompiledModule, SetupError};
|
||||
pub use crate::link::link_module;
|
||||
pub use crate::namespace::{InstanceIndex, Namespace};
|
||||
pub use crate::namespace::Namespace;
|
||||
pub use crate::resolver::{NullResolver, Resolver};
|
||||
pub use crate::target_tunables::target_tunables;
|
||||
|
||||
|
||||
@@ -5,14 +5,15 @@ use core::ptr::write_unaligned;
|
||||
use cranelift_codegen::binemit::Reloc;
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use cranelift_wasm::{DefinedFuncIndex, Global, GlobalInit, Memory, Table, TableElementType};
|
||||
use std::collections::HashSet;
|
||||
use std::vec::Vec;
|
||||
use wasmtime_environ::{
|
||||
MemoryPlan, MemoryStyle, Module, Relocation, RelocationTarget, Relocations, TablePlan,
|
||||
};
|
||||
use wasmtime_runtime::libcalls;
|
||||
use wasmtime_runtime::{
|
||||
Export, Imports, LinkError, VMFunctionBody, VMFunctionImport, VMGlobalImport, VMMemoryImport,
|
||||
VMTableImport,
|
||||
Export, Imports, Instance, LinkError, VMFunctionBody, VMFunctionImport, VMGlobalImport,
|
||||
VMMemoryImport, VMTableImport,
|
||||
};
|
||||
|
||||
/// Links a module that has been compiled with `compiled_module` in `wasmtime-environ`.
|
||||
@@ -22,6 +23,8 @@ pub fn link_module(
|
||||
relocations: Relocations,
|
||||
resolver: &mut dyn Resolver,
|
||||
) -> Result<Imports, LinkError> {
|
||||
let mut dependencies = HashSet::new();
|
||||
|
||||
let mut function_imports = PrimaryMap::with_capacity(module.imported_funcs.len());
|
||||
for (index, (ref module_name, ref field)) in module.imported_funcs.iter() {
|
||||
match resolver.resolve(module_name, field) {
|
||||
@@ -41,6 +44,7 @@ pub fn link_module(
|
||||
signature, import_signature)
|
||||
));
|
||||
}
|
||||
dependencies.insert(Instance::from_vmctx(vmctx));
|
||||
function_imports.push(VMFunctionImport {
|
||||
body: address,
|
||||
vmctx,
|
||||
@@ -78,6 +82,7 @@ pub fn link_module(
|
||||
module_name, field,
|
||||
)));
|
||||
}
|
||||
dependencies.insert(Instance::from_vmctx(vmctx));
|
||||
table_imports.push(VMTableImport {
|
||||
from: definition,
|
||||
vmctx,
|
||||
@@ -131,6 +136,7 @@ pub fn link_module(
|
||||
}
|
||||
assert!(memory.offset_guard_size >= import_memory.offset_guard_size);
|
||||
|
||||
dependencies.insert(Instance::from_vmctx(vmctx));
|
||||
memory_imports.push(VMMemoryImport {
|
||||
from: definition,
|
||||
vmctx,
|
||||
@@ -156,7 +162,17 @@ pub fn link_module(
|
||||
for (index, (ref module_name, ref field)) in module.imported_globals.iter() {
|
||||
match resolver.resolve(module_name, field) {
|
||||
Some(export_value) => match export_value {
|
||||
Export::Global { definition, global } => {
|
||||
Export::Table { .. } | Export::Memory { .. } | Export::Function { .. } => {
|
||||
return Err(LinkError(format!(
|
||||
"{}/{}: exported global incompatible with global import",
|
||||
module_name, field
|
||||
)));
|
||||
}
|
||||
Export::Global {
|
||||
definition,
|
||||
vmctx,
|
||||
global,
|
||||
} => {
|
||||
let imported_global = module.globals[index];
|
||||
if !is_global_compatible(&global, &imported_global) {
|
||||
return Err(LinkError(format!(
|
||||
@@ -164,14 +180,9 @@ pub fn link_module(
|
||||
module_name, field
|
||||
)));
|
||||
}
|
||||
dependencies.insert(Instance::from_vmctx(vmctx));
|
||||
global_imports.push(VMGlobalImport { from: definition });
|
||||
}
|
||||
Export::Table { .. } | Export::Memory { .. } | Export::Function { .. } => {
|
||||
return Err(LinkError(format!(
|
||||
"{}/{}: exported global incompatible with global import",
|
||||
module_name, field
|
||||
)));
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(LinkError(format!(
|
||||
@@ -186,6 +197,7 @@ pub fn link_module(
|
||||
relocate(allocated_functions, relocations, module);
|
||||
|
||||
Ok(Imports::new(
|
||||
dependencies,
|
||||
function_imports,
|
||||
table_imports,
|
||||
memory_imports,
|
||||
|
||||
@@ -3,29 +3,17 @@
|
||||
//! and resolve imports to exports among them.
|
||||
|
||||
use super::HashMap;
|
||||
use crate::action::{get, inspect_memory, invoke};
|
||||
use crate::action::{ActionError, ActionOutcome, RuntimeValue};
|
||||
use crate::compiler::Compiler;
|
||||
use crate::resolver::Resolver;
|
||||
use cranelift_entity::PrimaryMap;
|
||||
use std::string::String;
|
||||
use wasmtime_runtime::{Export, Instance};
|
||||
|
||||
/// An opaque reference to an `Instance` within a `Namespace`.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct InstanceIndex(u32);
|
||||
entity_impl!(InstanceIndex, "instance");
|
||||
|
||||
/// A namespace containing instances keyed by name.
|
||||
///
|
||||
/// Note that `Namespace` implements the `Resolver` trait, so it can resolve
|
||||
/// imports using defined exports.
|
||||
pub struct Namespace {
|
||||
/// Mapping from identifiers to indices in `self.instances`.
|
||||
names: HashMap<String, InstanceIndex>,
|
||||
|
||||
/// The instances, available by index.
|
||||
instances: PrimaryMap<InstanceIndex, Instance>,
|
||||
names: HashMap<String, Instance>,
|
||||
}
|
||||
|
||||
impl Namespace {
|
||||
@@ -33,62 +21,25 @@ impl Namespace {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
names: HashMap::new(),
|
||||
instances: PrimaryMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Install a new `Instance` in this `Namespace`, optionally with the
|
||||
/// given name, and return its index.
|
||||
pub fn instance(&mut self, instance_name: Option<String>, instance: Instance) -> InstanceIndex {
|
||||
let index = self.instances.push(instance);
|
||||
if let Some(instance_name) = instance_name {
|
||||
self.names.insert(instance_name, index);
|
||||
}
|
||||
index
|
||||
pub fn name_instance(&mut self, name: String, instance: Instance) {
|
||||
self.names.insert(name, instance);
|
||||
}
|
||||
|
||||
/// Get the instance index registered with the given `instance_name`.
|
||||
pub fn get_instance_index(&mut self, instance_name: &str) -> Option<InstanceIndex> {
|
||||
self.names.get_mut(instance_name).cloned()
|
||||
}
|
||||
|
||||
/// Register an additional name for an existing registered instance.
|
||||
pub fn alias_for_indexed(&mut self, existing_index: InstanceIndex, new_name: String) {
|
||||
self.names.insert(new_name, existing_index);
|
||||
}
|
||||
|
||||
/// Invoke an exported function from an instance.
|
||||
pub fn invoke(
|
||||
&mut self,
|
||||
compiler: &mut Compiler,
|
||||
index: InstanceIndex,
|
||||
field_name: &str,
|
||||
args: &[RuntimeValue],
|
||||
) -> Result<ActionOutcome, ActionError> {
|
||||
invoke(compiler, &mut self.instances[index], field_name, args)
|
||||
}
|
||||
|
||||
/// Get a slice of memory from an instance.
|
||||
pub fn inspect_memory(
|
||||
&self,
|
||||
index: InstanceIndex,
|
||||
field_name: &str,
|
||||
start: usize,
|
||||
len: usize,
|
||||
) -> Result<&[u8], ActionError> {
|
||||
inspect_memory(&self.instances[index], field_name, start, len)
|
||||
}
|
||||
|
||||
/// Get the value of an exported global from an instance.
|
||||
pub fn get(&self, index: InstanceIndex, field_name: &str) -> Result<RuntimeValue, ActionError> {
|
||||
get(&self.instances[index], field_name)
|
||||
pub fn get_instance(&mut self, name: &str) -> Option<&mut Instance> {
|
||||
self.names.get_mut(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolver for Namespace {
|
||||
fn resolve(&mut self, instance: &str, field: &str) -> Option<Export> {
|
||||
if let Some(index) = self.names.get(instance) {
|
||||
self.instances[*index].lookup(field)
|
||||
fn resolve(&mut self, name: &str, field: &str) -> Option<Export> {
|
||||
if let Some(instance) = self.names.get_mut(name) {
|
||||
instance.lookup(field)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user