use crate::exports::{ExportError, Exportable}; use crate::externals::Extern; use crate::store::{Store, StoreObject}; use crate::types::Val; use crate::GlobalType; use crate::Mutability; use crate::RuntimeError; use std::fmt; use std::sync::Arc; use wasmer_engine::{Export, ExportGlobal}; use wasmer_vm::{Global as RuntimeGlobal, VMExportGlobal}; /// A WebAssembly `global` instance. /// /// A global instance is the runtime representation of a global variable. /// It consists of an individual value and a flag indicating whether it is mutable. /// /// Spec: #[derive(Clone)] pub struct Global { store: Store, global: Arc, } impl Global { /// Create a new `Global` with the initial value [`Val`]. /// /// # Example /// /// ``` /// # use wasmer::{Global, Mutability, Store, Value}; /// # let store = Store::default(); /// # /// let g = Global::new(&store, Value::I32(1)); /// /// assert_eq!(g.get(), Value::I32(1)); /// assert_eq!(g.ty().mutability, Mutability::Const); /// ``` pub fn new(store: &Store, val: Val) -> Self { Self::from_value(store, val, Mutability::Const).unwrap() } /// Create a mutable `Global` with the initial value [`Val`]. /// /// # Example /// /// ``` /// # use wasmer::{Global, Mutability, Store, Value}; /// # let store = Store::default(); /// # /// let g = Global::new_mut(&store, Value::I32(1)); /// /// assert_eq!(g.get(), Value::I32(1)); /// assert_eq!(g.ty().mutability, Mutability::Var); /// ``` pub fn new_mut(store: &Store, val: Val) -> Self { Self::from_value(store, val, Mutability::Var).unwrap() } /// Create a `Global` with the initial value [`Val`] and the provided [`Mutability`]. fn from_value(store: &Store, val: Val, mutability: Mutability) -> Result { if !val.comes_from_same_store(store) { return Err(RuntimeError::new("cross-`Store` globals are not supported")); } let global = RuntimeGlobal::new(GlobalType { mutability, ty: val.ty(), }); unsafe { global .set_unchecked(val.clone()) .map_err(|e| RuntimeError::new(format!("create global for {:?}: {}", val, e)))?; }; Ok(Self { store: store.clone(), global: Arc::new(global), }) } /// Returns the [`GlobalType`] of the `Global`. /// /// # Example /// /// ``` /// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType}; /// # let store = Store::default(); /// # /// let c = Global::new(&store, Value::I32(1)); /// let v = Global::new_mut(&store, Value::I64(1)); /// /// assert_eq!(c.ty(), &GlobalType::new(Type::I32, Mutability::Const)); /// assert_eq!(v.ty(), &GlobalType::new(Type::I64, Mutability::Var)); /// ``` pub fn ty(&self) -> &GlobalType { self.global.ty() } /// Returns the [`Store`] where the `Global` belongs. /// /// # Example /// /// ``` /// # use wasmer::{Global, Store, Value}; /// # let store = Store::default(); /// # /// let g = Global::new(&store, Value::I32(1)); /// /// assert_eq!(g.store(), &store); /// ``` pub fn store(&self) -> &Store { &self.store } /// Retrieves the current value [`Val`] that the Global has. /// /// # Example /// /// ``` /// # use wasmer::{Global, Store, Value}; /// # let store = Store::default(); /// # /// let g = Global::new(&store, Value::I32(1)); /// /// assert_eq!(g.get(), Value::I32(1)); /// ``` pub fn get(&self) -> Val { self.global.get(&self.store) } /// Sets a custom value [`Val`] to the runtime Global. /// /// # Example /// /// ``` /// # use wasmer::{Global, Store, Value}; /// # let store = Store::default(); /// # /// let g = Global::new_mut(&store, Value::I32(1)); /// /// assert_eq!(g.get(), Value::I32(1)); /// /// g.set(Value::I32(2)); /// /// assert_eq!(g.get(), Value::I32(2)); /// ``` /// /// # Errors /// /// Trying to mutate a immutable global will raise an error: /// /// ```should_panic /// # use wasmer::{Global, Store, Value}; /// # let store = Store::default(); /// # /// let g = Global::new(&store, Value::I32(1)); /// /// g.set(Value::I32(2)).unwrap(); /// ``` /// /// Trying to set a value of a incompatible type will raise an error: /// /// ```should_panic /// # use wasmer::{Global, Store, Value}; /// # let store = Store::default(); /// # /// let g = Global::new(&store, Value::I32(1)); /// /// // This results in an error: `RuntimeError`. /// g.set(Value::I64(2)).unwrap(); /// ``` pub fn set(&self, val: Val) -> Result<(), RuntimeError> { if !val.comes_from_same_store(&self.store) { return Err(RuntimeError::new("cross-`Store` values are not supported")); } unsafe { self.global .set(val) .map_err(|e| RuntimeError::new(format!("{}", e)))?; } Ok(()) } pub(crate) fn from_vm_export(store: &Store, wasmer_export: ExportGlobal) -> Self { Self { store: store.clone(), global: wasmer_export.vm_global.from, } } /// Returns whether or not these two globals refer to the same data. /// /// # Example /// /// ``` /// # use wasmer::{Global, Store, Value}; /// # let store = Store::default(); /// # /// let g = Global::new(&store, Value::I32(1)); /// /// assert!(g.same(&g)); /// ``` pub fn same(&self, other: &Self) -> bool { Arc::ptr_eq(&self.global, &other.global) } } impl fmt::Debug for Global { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter .debug_struct("Global") .field("ty", &self.ty()) .field("value", &self.get()) .finish() } } impl<'a> Exportable<'a> for Global { fn to_export(&self) -> Export { ExportGlobal { vm_global: VMExportGlobal { from: self.global.clone(), instance_ref: None, }, } .into() } fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> { match _extern { Extern::Global(global) => Ok(global), _ => Err(ExportError::IncompatibleType), } } }