Move Instance's module field into InstanceContents.

This commit is contained in:
Dan Gohman
2019-02-22 10:43:38 -08:00
parent c91ca1b10c
commit 1ab9e17517

View File

@@ -184,6 +184,9 @@ fn global_mut<'vmctx>(
/// FIXME: Should this be pub(crate)? /// FIXME: Should this be pub(crate)?
#[repr(C)] #[repr(C)]
pub struct InstanceContents { pub struct InstanceContents {
/// The `Module` this `Instance` was instantiated from.
module: Rc<Module>,
/// Offsets in the `vmctx` region. /// Offsets in the `vmctx` region.
offsets: VMOffsets, offsets: VMOffsets,
@@ -204,7 +207,7 @@ pub struct InstanceContents {
/// Hosts can store arbitrary per-instance information here. /// Hosts can store arbitrary per-instance information here.
host_state: Box<dyn Any>, host_state: Box<dyn Any>,
/// Context pointer used by compiled wasm code. This field is last, and /// Additional context used by compiled wasm code. This field is last, and
/// represents a dynamically-sized array that extends beyond the nominal /// represents a dynamically-sized array that extends beyond the nominal
/// end of the struct (similar to a flexible array member). /// end of the struct (similar to a flexible array member).
vmctx: VMContext, vmctx: VMContext,
@@ -364,14 +367,10 @@ impl InstanceContents {
self.vmctx_mut() self.vmctx_mut()
} }
fn invoke_function( fn invoke_function(&mut self, index: FuncIndex) -> Result<(), InstantiationError> {
&mut self,
module: &Module,
index: FuncIndex,
) -> Result<(), InstantiationError> {
// TODO: Check that the callee's calling convention matches what we expect. // TODO: Check that the callee's calling convention matches what we expect.
let (callee_address, callee_vmctx) = match module.defined_func_index(index) { let (callee_address, callee_vmctx) = match self.module.defined_func_index(index) {
Some(defined_index) => { Some(defined_index) => {
let body = *self let body = *self
.finished_functions .finished_functions
@@ -380,7 +379,7 @@ impl InstanceContents {
(body, self.vmctx_mut() as *mut VMContext) (body, self.vmctx_mut() as *mut VMContext)
} }
None => { None => {
assert!(index.index() < module.imported_funcs.len()); assert!(index.index() < self.module.imported_funcs.len());
let import = self.imported_function(index); let import = self.imported_function(index);
(import.body, import.vmctx) (import.body, import.vmctx)
} }
@@ -392,34 +391,34 @@ impl InstanceContents {
} }
/// Invoke the WebAssembly start function of the instance, if one is present. /// Invoke the WebAssembly start function of the instance, if one is present.
fn invoke_start_function(&mut self, module: &Module) -> Result<(), InstantiationError> { fn invoke_start_function(&mut self) -> Result<(), InstantiationError> {
if let Some(start_index) = module.start_func { if let Some(start_index) = self.module.start_func {
self.invoke_function(module, start_index) self.invoke_function(start_index)
} else if let Some(start_export) = module.exports.get("_start") { } else if let Some(start_export) = self.module.exports.get("_start") {
// As a compatibility measure, if the module doesn't have a start // As a compatibility measure, if the module doesn't have a start
// function but does have a _start function exported, call that. // function but does have a _start function exported, call that.
match start_export { match start_export {
wasmtime_environ::Export::Function(func_index) => { wasmtime_environ::Export::Function(func_index) => {
let sig = &module.signatures[module.functions[*func_index]]; let sig = &self.module.signatures[self.module.functions[*func_index]];
// No wasm params or returns; just the vmctx param. // No wasm params or returns; just the vmctx param.
if sig.params.len() == 1 && sig.returns.is_empty() { if sig.params.len() == 1 && sig.returns.is_empty() {
self.invoke_function(module, *func_index) self.invoke_function(*func_index)
} else { } else {
Ok(()) Ok(())
} }
} }
_ => Ok(()), _ => Ok(()),
} }
} else if let Some(main_export) = module.exports.get("main") { } else if let Some(main_export) = self.module.exports.get("main") {
// As a further compatibility measure, if the module doesn't have a // As a further compatibility measure, if the module doesn't have a
// start function or a _start function exported, but does have a main // start function or a _start function exported, but does have a main
// function exported, call that. // function exported, call that.
match main_export { match main_export {
wasmtime_environ::Export::Function(func_index) => { wasmtime_environ::Export::Function(func_index) => {
let sig = &module.signatures[module.functions[*func_index]]; let sig = &self.module.signatures[self.module.functions[*func_index]];
// No wasm params or returns; just the vmctx param. // No wasm params or returns; just the vmctx param.
if sig.params.len() == 1 && sig.returns.is_empty() { if sig.params.len() == 1 && sig.returns.is_empty() {
self.invoke_function(module, *func_index) self.invoke_function(*func_index)
} else { } else {
Ok(()) Ok(())
} }
@@ -584,9 +583,6 @@ impl Drop for MmapField {
/// Note that compiled wasm code passes around raw pointers to `Instance`, so /// Note that compiled wasm code passes around raw pointers to `Instance`, so
/// this shouldn't be moved. /// this shouldn't be moved.
pub struct Instance { pub struct Instance {
/// The `Module` this `Instance` was instantiated from.
module: Rc<Module>,
/// The `Mmap` containing the contents of the instance. /// The `Mmap` containing the contents of the instance.
mmap_field: MmapField, mmap_field: MmapField,
} }
@@ -632,6 +628,7 @@ impl Instance {
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
let contents_ptr = contents_mmap.as_mut_ptr() as *mut InstanceContents; let contents_ptr = contents_mmap.as_mut_ptr() as *mut InstanceContents;
let contents = InstanceContents { let contents = InstanceContents {
module,
global_exports, global_exports,
offsets, offsets,
memories, memories,
@@ -690,16 +687,16 @@ impl Instance {
} }
// Check initializer bounds before initializing anything. // Check initializer bounds before initializing anything.
check_table_init_bounds(&*module, contents)?; check_table_init_bounds(contents)?;
check_memory_init_bounds(&*module, contents, data_initializers)?; check_memory_init_bounds(contents, data_initializers)?;
// Apply the initializers. // Apply the initializers.
initialize_tables(&*module, contents)?; initialize_tables(contents)?;
initialize_memories(&*module, contents, data_initializers)?; initialize_memories(contents, data_initializers)?;
initialize_globals(&*module, contents); initialize_globals(contents);
// Collect the exports for the global export map. // Collect the exports for the global export map.
for (field, decl) in &module.exports { for (field, decl) in &contents.module.exports {
use std::collections::hash_map::Entry::*; use std::collections::hash_map::Entry::*;
let cell: &RefCell<HashMap<std::string::String, core::option::Option<Export>>> = let cell: &RefCell<HashMap<std::string::String, core::option::Option<Export>>> =
contents.global_exports.borrow(); contents.global_exports.borrow();
@@ -708,7 +705,7 @@ impl Instance {
match map.entry(field.to_string()) { match map.entry(field.to_string()) {
Vacant(entry) => { Vacant(entry) => {
entry.insert(Some(lookup_by_declaration( entry.insert(Some(lookup_by_declaration(
&module, &contents.module,
&mut contents.vmctx, &mut contents.vmctx,
&contents.offsets, &contents.offsets,
&contents.finished_functions, &contents.finished_functions,
@@ -726,10 +723,9 @@ impl Instance {
// The WebAssembly spec specifies that the start function is // The WebAssembly spec specifies that the start function is
// invoked automatically at instantiation time. // invoked automatically at instantiation time.
contents.invoke_start_function(&*module)?; contents.invoke_start_function()?;
Ok(Self { Ok(Self {
module,
mmap_field: MmapField { mmap_field: MmapField {
mmap: contents_mmap, mmap: contents_mmap,
}, },
@@ -758,7 +754,7 @@ impl Instance {
/// Lookup an export with the given name. /// Lookup an export with the given name.
pub fn lookup(&mut self, field: &str) -> Option<Export> { pub fn lookup(&mut self, field: &str) -> Option<Export> {
let export = if let Some(export) = self.module.exports.get(field) { let export = if let Some(export) = self.mmap_field.contents().module.exports.get(field) {
export.clone() export.clone()
} else { } else {
return None; return None;
@@ -784,7 +780,7 @@ impl Instance {
pub fn lookup_by_declaration(&mut self, export: &wasmtime_environ::Export) -> Export { pub fn lookup_by_declaration(&mut self, export: &wasmtime_environ::Export) -> Export {
let contents = self.mmap_field.contents_mut(); let contents = self.mmap_field.contents_mut();
lookup_by_declaration( lookup_by_declaration(
&self.module, &contents.module,
&mut contents.vmctx, &mut contents.vmctx,
&contents.offsets, &contents.offsets,
&contents.finished_functions, &contents.finished_functions,
@@ -810,7 +806,7 @@ impl Instance {
/// are export names, and the values are export declarations which can be /// are export names, and the values are export declarations which can be
/// resolved `lookup_by_declaration`. /// resolved `lookup_by_declaration`.
pub fn exports(&self) -> indexmap::map::Iter<String, wasmtime_environ::Export> { pub fn exports(&self) -> indexmap::map::Iter<String, wasmtime_environ::Export> {
self.module.exports.iter() self.mmap_field.contents().module.exports.iter()
} }
} }
@@ -879,15 +875,13 @@ fn lookup_by_declaration(
} }
} }
fn check_table_init_bounds( fn check_table_init_bounds(contents: &mut InstanceContents) -> Result<(), InstantiationError> {
module: &Module, let module = Rc::clone(&contents.module);
contents: &mut InstanceContents,
) -> Result<(), InstantiationError> {
for init in &module.table_elements { for init in &module.table_elements {
let start = get_table_init_start(init, module, contents); let start = get_table_init_start(init, contents);
let slice = get_table_slice( let slice = get_table_slice(
init, init,
module, &contents.module,
&mut contents.tables, &mut contents.tables,
&contents.vmctx, &contents.vmctx,
&contents.offsets, &contents.offsets,
@@ -904,15 +898,11 @@ fn check_table_init_bounds(
} }
/// Compute the offset for a memory data initializer. /// Compute the offset for a memory data initializer.
fn get_memory_init_start( fn get_memory_init_start(init: &DataInitializer<'_>, contents: &mut InstanceContents) -> usize {
init: &DataInitializer<'_>,
module: &Module,
contents: &mut InstanceContents,
) -> usize {
let mut start = init.location.offset; let mut start = init.location.offset;
if let Some(base) = init.location.base { if let Some(base) = init.location.base {
let global = if let Some(def_index) = module.defined_global_index(base) { let global = if let Some(def_index) = contents.module.defined_global_index(base) {
contents.global_mut(def_index) contents.global_mut(def_index)
} else { } else {
contents.imported_global(base).from contents.imported_global(base).from
@@ -926,11 +916,11 @@ fn get_memory_init_start(
/// Return a byte-slice view of a memory's data. /// Return a byte-slice view of a memory's data.
fn get_memory_slice<'contents>( fn get_memory_slice<'contents>(
init: &DataInitializer<'_>, init: &DataInitializer<'_>,
module: &Module,
contents: &'contents mut InstanceContents, contents: &'contents mut InstanceContents,
) -> &'contents mut [u8] { ) -> &'contents mut [u8] {
let memory = if let Some(defined_memory_index) = let memory = if let Some(defined_memory_index) = contents
module.defined_memory_index(init.location.memory_index) .module
.defined_memory_index(init.location.memory_index)
{ {
contents.memory(defined_memory_index) contents.memory(defined_memory_index)
} else { } else {
@@ -944,13 +934,12 @@ fn get_memory_slice<'contents>(
} }
fn check_memory_init_bounds( fn check_memory_init_bounds(
module: &Module,
contents: &mut InstanceContents, contents: &mut InstanceContents,
data_initializers: &[DataInitializer<'_>], data_initializers: &[DataInitializer<'_>],
) -> Result<(), InstantiationError> { ) -> Result<(), InstantiationError> {
for init in data_initializers { for init in data_initializers {
let start = get_memory_init_start(init, module, contents); let start = get_memory_init_start(init, contents);
let mem_slice = get_memory_slice(init, module, contents); let mem_slice = get_memory_slice(init, contents);
if mem_slice.get_mut(start..start + init.data.len()).is_none() { if mem_slice.get_mut(start..start + init.data.len()).is_none() {
return Err(InstantiationError::Link(LinkError( return Err(InstantiationError::Link(LinkError(
@@ -974,15 +963,11 @@ fn create_tables(module: &Module) -> BoxedSlice<DefinedTableIndex, Table> {
} }
/// Compute the offset for a table element initializer. /// Compute the offset for a table element initializer.
fn get_table_init_start( fn get_table_init_start(init: &TableElements, contents: &mut InstanceContents) -> usize {
init: &TableElements,
module: &Module,
contents: &mut InstanceContents,
) -> usize {
let mut start = init.offset; let mut start = init.offset;
if let Some(base) = init.base { if let Some(base) = init.base {
let global = if let Some(def_index) = module.defined_global_index(base) { let global = if let Some(def_index) = contents.module.defined_global_index(base) {
contents.global_mut(def_index) contents.global_mut(def_index)
} else { } else {
contents.imported_global(base).from contents.imported_global(base).from
@@ -1013,16 +998,14 @@ fn get_table_slice<'contents>(
} }
/// Initialize the table memory from the provided initializers. /// Initialize the table memory from the provided initializers.
fn initialize_tables( fn initialize_tables(contents: &mut InstanceContents) -> Result<(), InstantiationError> {
module: &Module,
contents: &mut InstanceContents,
) -> Result<(), InstantiationError> {
let vmctx: *mut VMContext = contents.vmctx_mut(); let vmctx: *mut VMContext = contents.vmctx_mut();
let module = Rc::clone(&contents.module);
for init in &module.table_elements { for init in &module.table_elements {
let start = get_table_init_start(init, module, contents); let start = get_table_init_start(init, contents);
let slice = get_table_slice( let slice = get_table_slice(
init, init,
module, &contents.module,
&mut contents.tables, &mut contents.tables,
&contents.vmctx, &contents.vmctx,
&contents.offsets, &contents.offsets,
@@ -1030,9 +1013,9 @@ fn initialize_tables(
let subslice = &mut slice[start..start + init.elements.len()]; let subslice = &mut slice[start..start + init.elements.len()];
for (i, func_idx) in init.elements.iter().enumerate() { for (i, func_idx) in init.elements.iter().enumerate() {
let callee_sig = module.functions[*func_idx]; let callee_sig = contents.module.functions[*func_idx];
let (callee_ptr, callee_vmctx) = let (callee_ptr, callee_vmctx) =
if let Some(index) = module.defined_func_index(*func_idx) { if let Some(index) = contents.module.defined_func_index(*func_idx) {
(contents.finished_functions[index], vmctx) (contents.finished_functions[index], vmctx)
} else { } else {
let imported_func = let imported_func =
@@ -1066,13 +1049,12 @@ fn create_memories(
/// Initialize the table memory from the provided initializers. /// Initialize the table memory from the provided initializers.
fn initialize_memories( fn initialize_memories(
module: &Module,
contents: &mut InstanceContents, contents: &mut InstanceContents,
data_initializers: &[DataInitializer<'_>], data_initializers: &[DataInitializer<'_>],
) -> Result<(), InstantiationError> { ) -> Result<(), InstantiationError> {
for init in data_initializers { for init in data_initializers {
let start = get_memory_init_start(init, module, contents); let start = get_memory_init_start(init, contents);
let mem_slice = get_memory_slice(init, module, contents); let mem_slice = get_memory_slice(init, contents);
let to_init = &mut mem_slice[start..start + init.data.len()]; let to_init = &mut mem_slice[start..start + init.data.len()];
to_init.copy_from_slice(init.data); to_init.copy_from_slice(init.data);
@@ -1094,7 +1076,8 @@ fn create_globals(module: &Module) -> BoxedSlice<DefinedGlobalIndex, VMGlobalDef
vmctx_globals.into_boxed_slice() vmctx_globals.into_boxed_slice()
} }
fn initialize_globals(module: &Module, contents: &mut InstanceContents) { fn initialize_globals(contents: &mut InstanceContents) {
let module = Rc::clone(&contents.module);
let num_imports = module.imported_globals.len(); let num_imports = module.imported_globals.len();
for (index, global) in module.globals.iter().skip(num_imports) { for (index, global) in module.globals.iter().skip(num_imports) {
let def_index = module.defined_global_index(index).unwrap(); let def_index = module.defined_global_index(index).unwrap();