diff --git a/lib/compiler-cranelift/src/func_environ.rs b/lib/compiler-cranelift/src/func_environ.rs index 682e82143..3f04d1397 100644 --- a/lib/compiler-cranelift/src/func_environ.rs +++ b/lib/compiler-cranelift/src/func_environ.rs @@ -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); - 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) - } + 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 { diff --git a/lib/compiler-llvm/src/translator/intrinsics.rs b/lib/compiler-llvm/src/translator/intrinsics.rs index 7ee62984a..97b6e4e05 100644 --- a/lib/compiler-llvm/src/translator/intrinsics.rs +++ b/lib/compiler-llvm/src/translator/intrinsics.rs @@ -834,34 +834,34 @@ 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], "") } - } else { - let offset = offsets.vmctx_vmglobal_import(index); - let offset = intrinsics.i32_ty.const_int(offset.into(), false); - let global_ptr_ptr = - unsafe { cache_builder.build_gep(ctx_ptr_value, &[offset], "") }; - let global_ptr_ptr = cache_builder - .build_bitcast( - global_ptr_ptr, - intrinsics.i32_ptr_ty.ptr_type(AddressSpace::Generic), - "", - ) - .into_pointer_value(); - let global_ptr = cache_builder - .build_load(global_ptr_ptr, "") - .into_pointer_value(); - tbaa_label( - module, - intrinsics, - format!("global_ptr {}", index.as_u32()), - global_ptr.as_instruction_value().unwrap(), - ); - global_ptr - }; + let offset = if let Some(local_global_index) = wasm_module.local_global_index(index) + { + offsets.vmctx_vmglobal_definition(local_global_index) + } else { + 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 + .build_bitcast( + global_ptr_ptr, + intrinsics.i32_ptr_ty.ptr_type(AddressSpace::Generic), + "", + ) + .into_pointer_value(); + let global_ptr = cache_builder + .build_load(global_ptr_ptr, "") + .into_pointer_value(); + tbaa_label( + module, + intrinsics, + format!("global_ptr {}", index.as_u32()), + global_ptr.as_instruction_value().unwrap(), + ); + global_ptr + }; let global_ptr = cache_builder .build_bitcast( global_ptr, diff --git a/lib/compiler-singlepass/src/codegen_x64.rs b/lib/compiler-singlepass/src/codegen_x64.rs index 2d1c0bbfc..0db07864f 100644 --- a/lib/compiler-singlepass/src/codegen_x64.rs +++ b/lib/compiler-singlepass/src/codegen_x64.rs @@ -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 diff --git a/lib/engine/src/artifact.rs b/lib/engine/src/artifact.rs index 3fa1711d0..72a70c9e9 100644 --- a/lib/engine/src/artifact.rs +++ b/lib/engine/src/artifact.rs @@ -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(); diff --git a/lib/engine/src/tunables.rs b/lib/engine/src/tunables.rs index ad10e8e8a..936d2d921 100644 --- a/lib/engine/src/tunables.rs +++ b/lib/engine/src/tunables.rs @@ -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, 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,17 +79,23 @@ pub trait Tunables { fn create_globals( &self, module: &ModuleInfo, + imports: &Imports, ) -> Result>, 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) - .map_err(LinkError::Resource)? + self.create_initialized_global( + module, + imports, + global_type.mutability, + initializer, + ) + .map_err(LinkError::Resource)? } else { self.create_global(global_type) .map_err(LinkError::Resource)? diff --git a/lib/runtime/src/global.rs b/lib/runtime/src/global.rs index 159abe0dc..aac01a512 100644 --- a/lib/runtime/src/global.rs +++ b/lib/runtime/src/global.rs @@ -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, 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(mutability: Mutability, value: Value) -> 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(mutability: Mutability, value: Value) -> Self { - Self::new_with_init(mutability, GlobalInit::from_value(value)) - } - /// Get the type of the global. pub fn ty(&self) -> &GlobalType { &self.ty diff --git a/lib/runtime/src/instance.rs b/lib/runtime/src/instance.rs index c0500b265..478d5aa88 100644 --- a/lib/runtime/src/instance.rs +++ b/lib/runtime/src/instance.rs @@ -252,11 +252,12 @@ impl Instance { /// Return the indexed `VMGlobalDefinition`. fn global_ptr(&self, index: LocalGlobalIndex) -> NonNull { 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::>() .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, vmctx_globals.len(), ); ptr::write( @@ -1279,11 +1277,12 @@ 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) { - instance.global(def_x) - } else { - instance.imported_global(*x).definition.as_ref().clone() - }; + 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() + }; *to = from; } GlobalInit::RefNullConst | GlobalInit::RefFunc(_) => unimplemented!(), diff --git a/lib/runtime/src/vmoffsets.rs b/lib/runtime/src/vmoffsets.rs index d6046a69d..4e6ba103a 100644 --- a/lib/runtime/src/vmoffsets.rs +++ b/lib/runtime/src/vmoffsets.rs @@ -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()