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