mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-08 21:58:20 +00:00
Add an extra layer of indirection for shared globals
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user