wasmer_c_api/wasm_c_api/externals/
global.rs

1use crate::error::update_last_error;
2
3use super::super::store::wasm_store_t;
4use super::super::types::wasm_globaltype_t;
5use super::super::value::wasm_val_t;
6use super::wasm_extern_t;
7use std::convert::TryInto;
8use wasmer_api::{Extern, Global, Value};
9
10#[allow(non_camel_case_types)]
11#[repr(C)]
12#[derive(Clone)]
13pub struct wasm_global_t {
14    pub(crate) extern_: wasm_extern_t,
15}
16
17impl wasm_global_t {
18    pub(crate) fn try_from(e: &wasm_extern_t) -> Option<&wasm_global_t> {
19        match &e.inner {
20            Extern::Global(_) => Some(unsafe { &*(e as *const _ as *const _) }),
21            _ => None,
22        }
23    }
24}
25
26#[unsafe(no_mangle)]
27pub unsafe extern "C" fn wasm_global_new(
28    store: Option<&mut wasm_store_t>,
29    global_type: Option<&wasm_globaltype_t>,
30    val: Option<&wasm_val_t>,
31) -> Option<Box<wasm_global_t>> {
32    let global_type = global_type?;
33    let store = store?;
34    let mut store_mut = unsafe { store.inner.store_mut() };
35    let val = val?;
36
37    let global_type = &global_type.inner().global_type;
38    let wasm_val = val.try_into().ok()?;
39    let global = if global_type.mutability.is_mutable() {
40        Global::new_mut(&mut store_mut, wasm_val)
41    } else {
42        Global::new(&mut store_mut, wasm_val)
43    };
44    Some(Box::new(wasm_global_t {
45        extern_: wasm_extern_t::new(store.inner.clone(), global.into()),
46    }))
47}
48
49#[unsafe(no_mangle)]
50pub unsafe extern "C" fn wasm_global_delete(_global: Option<Box<wasm_global_t>>) {}
51
52#[unsafe(no_mangle)]
53pub unsafe extern "C" fn wasm_global_copy(global: &wasm_global_t) -> Box<wasm_global_t> {
54    // do shallow copy
55    Box::new(global.clone())
56}
57
58#[unsafe(no_mangle)]
59pub unsafe extern "C" fn wasm_global_get(
60    global: Option<&mut wasm_global_t>,
61    // own
62    out: Option<&mut wasm_val_t>,
63) {
64    let Some(global) = global else {
65        update_last_error("global pointer is null");
66        return;
67    };
68    let Some(out) = out else {
69        update_last_error("out pointer is null");
70        return;
71    };
72    let wasm_global = global.extern_.global();
73    let value = {
74        let mut store_mut = unsafe { global.extern_.store.store_mut() };
75        wasm_global.get(&mut store_mut)
76    };
77    let store = global.extern_.store.clone();
78    let new_val = c_try!(wasm_val_t::from_value(&value, &store); otherwise ());
79    // `out` is an owned out-parameter; write without dropping stale contents.
80    unsafe { std::ptr::write(out, new_val) };
81}
82
83/// Note: This function returns nothing by design but it can raise an
84/// error if setting a new value fails.
85#[unsafe(no_mangle)]
86pub unsafe extern "C" fn wasm_global_set(
87    global: Option<&mut wasm_global_t>,
88    val: Option<&wasm_val_t>,
89) {
90    let Some(global) = global else {
91        update_last_error("global pointer is null");
92        return;
93    };
94    let Some(val) = val else {
95        update_last_error("val pointer is null");
96        return;
97    };
98    let value: Value = c_try!(val.try_into(); otherwise ());
99    let wasm_global = global.extern_.global();
100    let mut store_mut = unsafe { global.extern_.store.store_mut() };
101    c_try!(wasm_global.set(&mut store_mut, value); otherwise ());
102}
103
104#[unsafe(no_mangle)]
105pub unsafe extern "C" fn wasm_global_same(
106    wasm_global1: &wasm_global_t,
107    wasm_global2: &wasm_global_t,
108) -> bool {
109    wasm_global1.extern_.global() == wasm_global2.extern_.global()
110}
111
112#[unsafe(no_mangle)]
113pub unsafe extern "C" fn wasm_global_type(
114    global: Option<&wasm_global_t>,
115) -> Option<Box<wasm_globaltype_t>> {
116    let global = global?;
117    let store_ref = unsafe { global.extern_.store.store() };
118    Some(Box::new(wasm_globaltype_t::new(
119        global.extern_.global().ty(&store_ref),
120    )))
121}
122
123#[cfg(test)]
124mod tests {
125    use inline_c::assert_c;
126
127    #[allow(
128        unexpected_cfgs,
129        reason = "tools like cargo-llvm-coverage pass --cfg coverage"
130    )]
131    #[cfg_attr(coverage_nightly, coverage(off))]
132    #[test]
133    fn test_set_host_global_immutable() {
134        (assert_c! {
135            #include "tests/wasmer.h"
136
137            int main() {
138                wasm_engine_t* engine = wasm_engine_new();
139                wasm_store_t* store = wasm_store_new(engine);
140
141                wasm_val_t forty_two = WASM_F32_VAL(42);
142                wasm_val_t forty_three = WASM_F32_VAL(43);
143
144                wasm_valtype_t* valtype = wasm_valtype_new_i32();
145                wasm_globaltype_t* global_type = wasm_globaltype_new(valtype, WASM_CONST);
146                wasm_global_t* global = wasm_global_new(store, global_type, &forty_two);
147
148                wasm_globaltype_delete(global_type);
149
150                wasm_global_set(global, &forty_three);
151
152                assert(wasmer_last_error_length() > 0);
153
154                wasm_global_delete(global);
155                wasm_store_delete(store);
156                wasm_engine_delete(engine);
157
158                return 0;
159            }
160        })
161        .success();
162    }
163
164    #[allow(
165        unexpected_cfgs,
166        reason = "tools like cargo-llvm-coverage pass --cfg coverage"
167    )]
168    #[cfg_attr(coverage_nightly, coverage(off))]
169    #[test]
170    fn test_set_guest_global_immutable() {
171        (assert_c! {
172            #include "tests/wasmer.h"
173
174            int main() {
175                wasm_engine_t* engine = wasm_engine_new();
176                wasm_store_t* store = wasm_store_new(engine);
177
178                wasm_byte_vec_t wat;
179                wasmer_byte_vec_new_from_string(&wat, "(module (global $global (export \"global\") f32 (f32.const 1)))");
180                wasm_byte_vec_t wasm_bytes;
181                wat2wasm(&wat, &wasm_bytes);
182                wasm_module_t* module = wasm_module_new(store, &wasm_bytes);
183                wasm_extern_vec_t import_object = WASM_EMPTY_VEC;
184                wasm_instance_t* instance = wasm_instance_new(store, module, &import_object, NULL);
185
186                wasm_extern_vec_t exports;
187                wasm_instance_exports(instance, &exports);
188                wasm_global_t* global = wasm_extern_as_global(exports.data[0]);
189
190                wasm_val_t forty_two = WASM_F32_VAL(42);
191                wasm_global_set(global, &forty_two);
192
193                printf("%d", wasmer_last_error_length());
194                assert(wasmer_last_error_length() > 0);
195
196                wasm_instance_delete(instance);
197                wasm_byte_vec_delete(&wasm_bytes);
198                wasm_byte_vec_delete(&wat);
199                wasm_extern_vec_delete(&exports);
200                wasm_store_delete(store);
201                wasm_engine_delete(engine);
202
203                return 0;
204            }
205        })
206        .success();
207    }
208}