1use crate::vmcontext::VMGlobalDefinition;
2use near_vm_types::{GlobalType, Mutability, Type, Value, WasmValueType};
3use parking_lot::Mutex;
4use std::cell::UnsafeCell;
5use std::ptr::NonNull;
6use thiserror::Error;
7
8#[derive(Debug)]
9pub struct Global {
11 ty: GlobalType,
12 vm_global_definition: Box<UnsafeCell<VMGlobalDefinition>>,
14 lock: Mutex<()>,
16}
17
18unsafe impl Send for Global {}
22unsafe impl Sync for Global {}
25
26#[derive(Error, Debug, Clone, PartialEq, Hash)]
28pub enum GlobalError {
29 #[error("Attempted to set an immutable global")]
31 ImmutableGlobalCannotBeSet,
32
33 #[error("Attempted to operate on a global of type {expected} as a global of type {found}")]
36 IncorrectType {
37 expected: Type,
39 found: Type,
41 },
42}
43
44impl Global {
45 pub fn new(global_type: GlobalType) -> Self {
47 Self {
48 ty: global_type,
49 vm_global_definition: Box::new(UnsafeCell::new(VMGlobalDefinition::new())),
50 lock: Mutex::new(()),
51 }
52 }
53
54 pub fn ty(&self) -> &GlobalType {
56 &self.ty
57 }
58
59 pub fn vmglobal(&self) -> NonNull<VMGlobalDefinition> {
61 let ptr = self.vm_global_definition.as_ref() as *const UnsafeCell<VMGlobalDefinition>
62 as *const VMGlobalDefinition as *mut VMGlobalDefinition;
63 unsafe { NonNull::new_unchecked(ptr) }
64 }
65
66 pub fn get<T: WasmValueType>(&self, store: &dyn std::any::Any) -> Value<T> {
71 let _global_guard = self.lock.lock();
72 unsafe {
73 let definition = &*self.vm_global_definition.get();
74 match self.ty().ty {
75 Type::I32 => Value::I32(definition.to_i32()),
76 Type::I64 => Value::I64(definition.to_i64()),
77 Type::F32 => Value::F32(definition.to_f32()),
78 Type::F64 => Value::F64(definition.to_f64()),
79 Type::V128 => Value::V128(definition.to_u128()),
80 Type::ExternRef => Value::ExternRef(definition.to_externref().into()),
81 Type::FuncRef => {
82 let p = definition.to_u128() as i128;
83 if p as usize == 0 {
84 Value::FuncRef(None)
85 } else {
86 let v = T::read_value_from(store, &p);
87 Value::FuncRef(Some(v))
88 }
89 }
90 }
91 }
92 }
93
94 pub unsafe fn set<T: WasmValueType>(&self, val: Value<T>) -> Result<(), GlobalError> {
99 let _global_guard = self.lock.lock();
100 if self.ty().mutability != Mutability::Var {
101 return Err(GlobalError::ImmutableGlobalCannotBeSet);
102 }
103 if val.ty() != self.ty().ty {
104 return Err(GlobalError::IncorrectType { expected: self.ty.ty, found: val.ty() });
105 }
106 unsafe { self.set_unchecked(val) }
107 }
108
109 pub unsafe fn set_unchecked<T: WasmValueType>(&self, val: Value<T>) -> Result<(), GlobalError> {
116 unsafe {
118 let definition = &mut *self.vm_global_definition.get();
119 match val {
120 Value::I32(i) => *definition.as_i32_mut() = i,
121 Value::I64(i) => *definition.as_i64_mut() = i,
122 Value::F32(f) => *definition.as_f32_mut() = f,
123 Value::F64(f) => *definition.as_f64_mut() = f,
124 Value::V128(x) => *definition.as_bytes_mut() = x.to_ne_bytes(),
125 Value::ExternRef(r) => {
126 let extern_ref = definition.as_externref_mut();
127 extern_ref.ref_drop();
128 *extern_ref = r.into()
129 }
130 Value::FuncRef(None) => *definition.as_u128_mut() = 0,
131 Value::FuncRef(Some(r)) => {
132 r.write_value_to(definition.as_u128_mut() as *mut u128 as *mut i128)
133 }
134 }
135 }
136 Ok(())
137 }
138}