Skip to content

Commit

Permalink
refactor away from TableAndOwningInstance; Instance now manages lazy …
Browse files Browse the repository at this point in the history
…table init
  • Loading branch information
cfallin committed Feb 8, 2022
1 parent 8a7b606 commit f3aa888
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 172 deletions.
64 changes: 46 additions & 18 deletions crates/runtime/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use crate::export::Export;
use crate::externref::VMExternRefActivationsTable;
use crate::memory::{Memory, RuntimeMemoryCreator};
use crate::table::{Table, TableAndOwningInstance, TableElement, TableElementType};
use crate::table::{Table, TableElement, TableElementType};
use crate::traphandlers::Trap;
use crate::vmcontext::{
VMCallerCheckedAnyfunc, VMContext, VMFunctionImport, VMGlobalDefinition, VMGlobalImport,
Expand Down Expand Up @@ -700,10 +700,6 @@ impl Instance {
self.memory_init_segment(memory_index, range, dst, src, len)
}

pub(crate) fn runtime_info(&self) -> &dyn ModuleRuntimeInfo {
&*self.runtime_info
}

pub(crate) fn wasm_data(&self, range: Range<u32>) -> &[u8] {
&self.runtime_info.wasm_data()[range.start as usize..range.end as usize]
}
Expand Down Expand Up @@ -743,28 +739,49 @@ impl Instance {
// dropping a non-passive segment is a no-op (not a trap).
}

/// Get a table, its owning instance, and its defined index in
/// that instance regardless of whether it is locally-defined or
/// an imported, foreign table.
pub(crate) fn get_table_and_owning_instance(
/// Get a table by index regardless of whether it is
/// locally-defined or an imported, foreign table. Ensure that the
/// given range of elements in the table is lazily initialized.
/// We define this operation all-in-one for safety, and to avoid
/// passing around unbundled table, owning-instance,
/// index-in-owning-instance tuples.
pub(crate) fn get_table_with_lazy_init(
&mut self,
table_index: TableIndex,
) -> TableAndOwningInstance {
range: impl Iterator<Item = u32>,
) -> *mut Table {
let (idx, instance) = self.get_defined_table_index_and_instance(table_index);
let table = ptr::addr_of_mut!(instance.tables[idx]);
TableAndOwningInstance {
table,
instance: InstanceHandle {
instance: instance as *mut _,
},
defined_table_index: idx,
let elt_ty = instance.tables[idx].element_type();

if elt_ty == TableElementType::Func {
let len = instance.tables[idx].size();
for i in range.take_while(|i| *i < len) {
let value = instance.tables[idx].get(i);
if value.map(|v| v.is_uninit()).unwrap_or(false) {
let anyfunc = instance
.runtime_info
.lazy_table_data(idx)
.and_then(|lazy_data| lazy_data.elements.get(i as usize).cloned())
.flatten()
.and_then(|func_index| instance.get_caller_checked_anyfunc(func_index))
.unwrap_or(std::ptr::null_mut());
let value = TableElement::FuncRef(anyfunc);

instance.tables[idx]
.set(i, value)
.expect("Table type should match and index should be in-bounds");
}
}
}

ptr::addr_of_mut!(instance.tables[idx])
}

/// Get a table by index regardless of whether it is locally-defined or an
/// imported, foreign table.
pub(crate) fn get_table(&mut self, table_index: TableIndex) -> *mut Table {
self.get_table_and_owning_instance(table_index).table
let (idx, instance) = self.get_defined_table_index_and_instance(table_index);
ptr::addr_of_mut!(instance.tables[idx])
}

/// Get a locally-defined table.
Expand Down Expand Up @@ -899,6 +916,17 @@ impl InstanceHandle {
self.instance_mut().get_defined_table(index)
}

/// Get a table defined locally within this module, lazily
/// initializing the given range first.
pub fn get_defined_table_with_lazy_init(
&mut self,
index: DefinedTableIndex,
range: impl Iterator<Item = u32>,
) -> *mut Table {
let index = self.instance().module().table_index(index);
self.instance_mut().get_table_with_lazy_init(index, range)
}

/// Return a reference to the contained `Instance`.
#[inline]
pub(crate) fn instance(&self) -> &Instance {
Expand Down
4 changes: 1 addition & 3 deletions crates/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ pub use crate::instance::{
pub use crate::jit_int::GdbJitImageRegistration;
pub use crate::memory::{DefaultMemoryCreator, Memory, RuntimeLinearMemory, RuntimeMemoryCreator};
pub use crate::mmap::Mmap;
pub use crate::table::{
Table, TableAndOwningInstance, TableElement, TableLazyData, TablesLazyData,
};
pub use crate::table::{Table, TableElement, TableLazyData, TablesLazyData};
pub use crate::traphandlers::{
catch_traps, init_traps, raise_lib_trap, raise_user_trap, resume_panic, tls_eager_initialize,
SignalHandler, TlsRestore, Trap,
Expand Down
12 changes: 5 additions & 7 deletions crates/runtime/src/libcalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,9 @@ pub unsafe extern "C" fn table_copy(
let instance = (*vmctx).instance_mut();
let dst_table = instance.get_table(dst_table_index);
// Lazy-initialize the whole range in the source table first.
let mut src_info = instance.get_table_and_owning_instance(src_table_index);
src_info.lazy_init_range(src, len);
Table::copy(dst_table, src_info.table, dst, src, len)
let src_range = src..(src.checked_add(len).unwrap_or(u32::MAX));
let src_table = instance.get_table_with_lazy_init(src_table_index, src_range);
Table::copy(dst_table, src_table, dst, src, len)
};
if let Err(trap) = result {
raise_lib_trap(trap);
Expand Down Expand Up @@ -414,10 +414,8 @@ pub unsafe extern "C" fn table_get_lazy_init_funcref(
) -> *mut u8 {
let instance = (*vmctx).instance_mut();
let table_index = TableIndex::from_u32(table_index);
let mut table_info = instance.get_table_and_owning_instance(table_index);
table_info.lazy_init(index);
let elem = table_info
.table()
let table = instance.get_table_with_lazy_init(table_index, std::iter::once(index));
let elem = (*table)
.get(index)
.expect("table access already bounds-checked");

Expand Down
121 changes: 11 additions & 110 deletions crates/runtime/src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! `Table` is to WebAssembly tables what `LinearMemory` is to WebAssembly linear memories.

use crate::vmcontext::{VMCallerCheckedAnyfunc, VMTableDefinition};
use crate::{InstanceHandle, Store, Trap, VMExternRef};
use crate::{Store, Trap, VMExternRef};
use anyhow::{bail, format_err, Error, Result};
use std::convert::{TryFrom, TryInto};
use std::ops::Range;
Expand Down Expand Up @@ -145,6 +145,15 @@ impl TableElement {
Self::UninitFunc => panic!("Uninitialized table element value outside of table slot"),
}
}

/// Indicates whether this value is the "uninitialized element"
/// value.
pub(crate) fn is_uninit(&self) -> bool {
match self {
Self::UninitFunc => true,
_ => false,
}
}
}

impl From<*mut VMCallerCheckedAnyfunc> for TableElement {
Expand Down Expand Up @@ -196,7 +205,7 @@ pub enum Table {
/// FuncIndex (or None) for each element, and can be computed once for
/// the module.
pub struct TableLazyData {
elements: Vec<Option<FuncIndex>>,
pub(crate) elements: Vec<Option<FuncIndex>>,
}

/// Lazy initialization data for all tables in a module.
Expand Down Expand Up @@ -661,111 +670,3 @@ impl Default for Table {
}
}
}

/// A packaged-up reference to a table with its owning instance and
/// its defined-table index in that instance. Provides all information
/// needed to e.g. lazily initialize a table backed by data in the
/// defining module.
pub struct TableAndOwningInstance {
pub(crate) table: *mut Table,
pub(crate) instance: InstanceHandle,
pub(crate) defined_table_index: DefinedTableIndex,
}

impl TableAndOwningInstance {
/// Construct for a table known to be defined in a given InstanceHandle.
pub fn new(mut instance: InstanceHandle, index: DefinedTableIndex) -> Self {
let table = instance.get_defined_table(index);
Self {
table,
instance,
defined_table_index: index,
}
}

/// Get the contained table.
pub fn table(&self) -> &Table {
unsafe { self.table.as_ref().unwrap() }
}

/// Get the contained table.
pub fn table_mut(&mut self) -> &mut Table {
unsafe { self.table.as_mut().unwrap() }
}

/// Get the contained table as a raw pointer.
pub fn table_mut_ptr(&mut self) -> *mut Table {
self.table
}

/// Get the owning instance.
pub fn instance_mut(&mut self) -> &mut InstanceHandle {
&mut self.instance
}

/// Perform a lazy initialization on the given element, ensuring
/// it is not `TableElement::UninitFunc`. Has no effect on
/// non-funcref tables. Silently returns if `index` is
/// out-of-bounds (bounds checking happens at a higher level).
///
/// Requires access to the owning Instance, and the index that we
/// occupy in that instance, so that we can fetch the relevant
/// info for lazy-init and possibly cause the underlying anyfunc
/// to be lazily created.
pub fn lazy_init(&mut self, index: u32) {
let table = unsafe { self.table.as_mut().unwrap() };
let instance = self.instance.instance_mut();

if table.element_type() != TableElementType::Func {
return;
}
let elt_ptr = match table.elements_mut().get_mut(index as usize) {
Some(e) => e,
None => return,
};

if *elt_ptr == 0 {
// Initialize with an "initialized null"; this will be
// overwritten if we have a non-null func to fill in.
*elt_ptr = REF_INIT_BIT;

if let Some(data) = instance
.runtime_info()
.lazy_table_data(self.defined_table_index)
{
if let Some(&Some(func)) = data.elements.get(index as usize) {
if let Some(anyfunc) = instance.get_caller_checked_anyfunc(func) {
// Reborrow ptr.
let elt_ptr = table.elements_mut().get_mut(index as usize).unwrap();
*elt_ptr = unsafe { TableElement::FuncRef(anyfunc).into_table_value() };
}
}
}
}
}

/// Like `lazy_init`, but for a whole range of elements.
pub fn lazy_init_range(&mut self, start: u32, len: u32) {
let table = unsafe { self.table.as_mut().unwrap() };
// Check for out-of-bounds: this function must silently return
// (we'll raise the actual Trap during the operation that
// required the lazy init).
match start.checked_add(len) {
None => {
return;
}
Some(end) => {
if end
>= u32::try_from(table.elements().len())
.expect("Table size larger than u32::MAX")
{
return;
}
}
}

for i in start..(start + len) {
self.lazy_init(i);
}
}
}
Loading

0 comments on commit f3aa888

Please sign in to comment.