Add an extra layer of indirection for shared globals

This commit is contained in:
Mark McCaskey
2020-07-02 18:23:19 -07:00
parent c717a25770
commit d4d738d97e
8 changed files with 153 additions and 92 deletions

View File

@@ -699,20 +699,19 @@ impl<'module_environment> BaseFuncEnvironment for FuncEnvironment<'module_enviro
let (ptr, offset) = {
let vmctx = self.vmctx(func);
if let Some(def_index) = self.module.local_global_index(index) {
let offset =
i32::try_from(self.offsets.vmctx_vmglobal_definition(def_index)).unwrap();
(vmctx, offset)
let from_offset = if let Some(def_index) = self.module.local_global_index(index) {
self.offsets.vmctx_vmglobal_definition(def_index)
} else {
let from_offset = self.offsets.vmctx_vmglobal_import_definition(index);
self.offsets.vmctx_vmglobal_import_definition(index)
};
let global = func.create_global_value(ir::GlobalValueData::Load {
base: vmctx,
offset: Offset32::new(i32::try_from(from_offset).unwrap()),
global_type: pointer_type,
readonly: true,
});
(global, 0)
}
};
Ok(GlobalVariable::Memory {

View File

@@ -834,14 +834,14 @@ impl<'ctx, 'a> CtxType<'ctx, 'a> {
let global_value_type = global_type.ty;
let global_mutability = global_type.mutability;
let global_ptr =
if let Some(local_global_index) = wasm_module.local_global_index(index) {
let offset = offsets.vmctx_vmglobal_definition(local_global_index);
let offset = intrinsics.i32_ty.const_int(offset.into(), false);
unsafe { cache_builder.build_gep(ctx_ptr_value, &[offset], "") }
let offset = if let Some(local_global_index) = wasm_module.local_global_index(index)
{
offsets.vmctx_vmglobal_definition(local_global_index)
} else {
let offset = offsets.vmctx_vmglobal_import(index);
offsets.vmctx_vmglobal_import(index)
};
let offset = intrinsics.i32_ty.const_int(offset.into(), false);
let global_ptr = {
let global_ptr_ptr =
unsafe { cache_builder.build_gep(ctx_ptr_value, &[offset], "") };
let global_ptr_ptr = cache_builder

View File

@@ -1898,7 +1898,13 @@ impl<'a> FuncGen<'a> {
self.module.local_global_index(global_index)
{
let offset = self.vmoffsets.vmctx_vmglobal_definition(local_global_index);
Location::Memory(Machine::get_vmctx_reg(), offset as i32)
self.emit_relaxed_binop(
Assembler::emit_mov,
Size::S64,
Location::Memory(Machine::get_vmctx_reg(), offset as i32),
Location::GPR(tmp),
);
Location::Memory(tmp, 0)
} else {
// Imported globals require one level of indirection.
let offset = self
@@ -1924,7 +1930,13 @@ impl<'a> FuncGen<'a> {
self.module.local_global_index(global_index)
{
let offset = self.vmoffsets.vmctx_vmglobal_definition(local_global_index);
Location::Memory(Machine::get_vmctx_reg(), offset as i32)
self.emit_relaxed_binop(
Assembler::emit_mov,
Size::S64,
Location::Memory(Machine::get_vmctx_reg(), offset as i32),
Location::GPR(tmp),
);
Location::Memory(tmp, 0)
} else {
// Imported globals require one level of indirection.
let offset = self

View File

@@ -109,7 +109,7 @@ pub trait Artifact {
.map_err(InstantiationError::Link)?
.into_boxed_slice();
let finished_globals = tunables
.create_globals(&module)
.create_globals(&module, &imports)
.map_err(InstantiationError::Link)?
.into_boxed_slice();

View File

@@ -6,7 +6,7 @@ use wasm_common::{
MemoryType, Mutability, TableIndex, TableType,
};
use wasmer_runtime::MemoryError;
use wasmer_runtime::{Global, Memory, ModuleInfo, Table};
use wasmer_runtime::{Global, Imports, Memory, ModuleInfo, Table};
use wasmer_runtime::{MemoryPlan, TablePlan};
/// Tunables for an engine
@@ -26,10 +26,12 @@ pub trait Tunables {
/// Create a global with the given value.
fn create_initialized_global(
&self,
module: &ModuleInfo,
imports: &Imports,
mutability: Mutability,
init: GlobalInit,
) -> Result<Arc<Global>, String> {
Ok(Arc::new(Global::new_with_init(mutability, init)))
Ok(Global::new_with_init(module, imports, mutability, init).map_err(|e| e.to_string())?)
}
/// Create a global with a default value.
@@ -77,16 +79,22 @@ pub trait Tunables {
fn create_globals(
&self,
module: &ModuleInfo,
imports: &Imports,
) -> Result<PrimaryMap<LocalGlobalIndex, Arc<Global>>, LinkError> {
let num_imports = module.num_imported_globals;
let mut vmctx_globals = PrimaryMap::with_capacity(module.globals.len() - num_imports);
for (idx, &global_type) in module.globals.iter().skip(num_imports) {
let idx = LocalGlobalIndex::new(idx.index());
let idx = module.local_global_index(idx).unwrap();
vmctx_globals.push(
if let Some(&initializer) = module.global_initializers.get(idx) {
self.create_initialized_global(global_type.mutability, initializer)
self.create_initialized_global(
module,
imports,
global_type.mutability,
initializer,
)
.map_err(LinkError::Resource)?
} else {
self.create_global(global_type)

View File

@@ -1,6 +1,9 @@
use crate::imports::Imports;
use crate::module::ModuleInfo;
use crate::vmcontext::VMGlobalDefinition;
use std::cell::UnsafeCell;
use std::ptr::NonNull;
use std::sync::Arc;
use std::sync::Mutex;
use thiserror::Error;
use wasm_common::{GlobalInit, GlobalType, Mutability, Type, Value};
@@ -52,53 +55,92 @@ impl Global {
}
/// Create a new, zero bit-pattern initialized global from a [`GlobalType`].
pub fn new_with_init(mutability: Mutability, value: GlobalInit) -> Self {
pub fn new_with_init(
module: &ModuleInfo,
imports: &Imports,
mutability: Mutability,
value: GlobalInit,
) -> Result<Arc<Self>, GlobalError> {
let mut vm_global_definition = VMGlobalDefinition::new();
let global_type = unsafe {
let ty = unsafe {
match value {
GlobalInit::I32Const(v) => {
*vm_global_definition.as_i32_mut() = v;
GlobalType {
ty: Type::I32,
mutability,
}
Type::I32
}
GlobalInit::I64Const(v) => {
*vm_global_definition.as_i64_mut() = v;
GlobalType {
ty: Type::I64,
mutability,
}
Type::I64
}
GlobalInit::F32Const(v) => {
*vm_global_definition.as_f32_mut() = v;
GlobalType {
ty: Type::F32,
mutability,
}
Type::F32
}
GlobalInit::F64Const(v) => {
*vm_global_definition.as_f64_mut() = v;
GlobalType {
ty: Type::F64,
mutability,
Type::F64
}
GlobalInit::GetGlobal(global_index) => {
/*let other_type = module.globals.get(global_index).map_err(|e| "global does not exist")?;
*/
if let Some(global_value) = imports.globals.get(global_index) {
return Ok(global_value.from.clone());
} else {
let idx = module.local_global_index(global_index).unwrap();
if let Some(&init) = module.global_initializers.get(idx) {
// TODO: test for cycles/infinite loops here
return Self::new_with_init(module, imports, mutability, init);
}
// global may not exist here.
// TODO: tests should test if initializing with local global with no initializer and
// initializing with an invalid global index
todo!("check for initializer?, otherwise 0")
}
}
_ => unimplemented!("Global is not implemented for initializer {:?}", value),
_ => unimplemented!(
"Global `new_with_init` is not implemented for initializer {:?}",
value
),
}
};
Ok(Arc::new(Self {
ty: GlobalType { ty, mutability },
vm_global_definition: Box::new(UnsafeCell::new(vm_global_definition)),
lock: Mutex::new(()),
}))
}
/// Create a new global initialized with the given value.
pub fn new_with_value<T>(mutability: Mutability, value: Value<T>) -> Self {
let mut vm_global_definition = VMGlobalDefinition::new();
let ty = unsafe {
match value {
Value::I32(v) => {
*vm_global_definition.as_i32_mut() = v;
Type::I32
}
Value::I64(v) => {
*vm_global_definition.as_i64_mut() = v;
Type::I64
}
Value::F32(v) => {
*vm_global_definition.as_f32_mut() = v;
Type::F32
}
Value::F64(v) => {
*vm_global_definition.as_f64_mut() = v;
Type::F64
}
_ => unimplemented!("Global `new_with_value` is not implemented for {:?}", value),
}
};
Self {
ty: global_type,
ty: GlobalType { ty, mutability },
vm_global_definition: Box::new(UnsafeCell::new(vm_global_definition)),
lock: Mutex::new(()),
}
}
/// Create a new, zero bit-pattern initialized global from a [`GlobalType`].
pub fn new_with_value<T>(mutability: Mutability, value: Value<T>) -> Self {
Self::new_with_init(mutability, GlobalInit::from_value(value))
}
/// Get the type of the global.
pub fn ty(&self) -> &GlobalType {
&self.ty

View File

@@ -252,11 +252,12 @@ impl Instance {
/// Return the indexed `VMGlobalDefinition`.
fn global_ptr(&self, index: LocalGlobalIndex) -> NonNull<VMGlobalDefinition> {
let index = usize::try_from(index.as_u32()).unwrap();
NonNull::new(unsafe { self.globals_ptr().add(index) }).unwrap()
// TODO:
NonNull::new(unsafe { *self.globals_ptr().add(index) }).unwrap()
}
/// Return a pointer to the `VMGlobalDefinition`s.
fn globals_ptr(&self) -> *mut VMGlobalDefinition {
fn globals_ptr(&self) -> *mut *mut VMGlobalDefinition {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_globals_begin()) }
}
@@ -822,10 +823,7 @@ impl InstanceHandle {
let vmctx_globals = finished_globals
.values()
.map(|m| {
let vmglobal_ptr = m.as_ref().vmglobal();
vmglobal_ptr.as_ref().clone()
})
.map(|m| m.vmglobal())
.collect::<PrimaryMap<LocalGlobalIndex, _>>()
.into_boxed_slice();
@@ -897,7 +895,7 @@ impl InstanceHandle {
);
ptr::copy(
vmctx_globals.values().as_slice().as_ptr(),
instance.globals_ptr() as *mut VMGlobalDefinition,
instance.globals_ptr() as *mut NonNull<VMGlobalDefinition>,
vmctx_globals.len(),
);
ptr::write(
@@ -1279,7 +1277,8 @@ fn initialize_globals(instance: &Instance) {
GlobalInit::F64Const(x) => *(*to).as_f64_mut() = *x,
GlobalInit::V128Const(x) => *(*to).as_u128_bits_mut() = *x.bytes(),
GlobalInit::GetGlobal(x) => {
let from = if let Some(def_x) = module.local_global_index(*x) {
let from: VMGlobalDefinition =
if let Some(def_x) = module.local_global_index(*x) {
instance.global(def_x)
} else {
instance.imported_global(*x).definition.as_ref().clone()

View File

@@ -277,16 +277,17 @@ impl VMOffsets {
}
}
/// Offsets for [`VMGlobalDefinition`].
/// Offsets for a non-null pointer to a [`VMGlobalDefinition`] used as a local global.
///
/// [`VMGlobalDefinition`]: crate::vmcontext::VMGlobalDefinition
impl VMOffsets {
/// Return the size of [`VMGlobalDefinition`]; this is the size of the largest value type (i.e. a
/// V128).
/// Return the size of a pointer to a [`VMGlobalDefinition`];
///
/// The underlying global itself is the size of the largest value type (i.e. a V128),
/// however the size of this type is just the size of a pointer.
/// [`VMGlobalDefinition`]: crate::vmcontext::VMGlobalDefinition
pub const fn size_of_vmglobal_definition(&self) -> u8 {
16
pub const fn size_of_vmglobal_local(&self) -> u8 {
self.pointer_size
}
}
@@ -426,7 +427,7 @@ impl VMOffsets {
self.vmctx_globals_begin()
.checked_add(
self.num_local_globals
.checked_mul(u32::from(self.size_of_vmglobal_definition()))
.checked_mul(u32::from(self.size_of_vmglobal_local()))
.unwrap(),
)
.unwrap()
@@ -559,7 +560,7 @@ impl VMOffsets {
.checked_add(
index
.as_u32()
.checked_mul(u32::from(self.size_of_vmglobal_definition()))
.checked_mul(u32::from(self.size_of_vmglobal_local()))
.unwrap(),
)
.unwrap()