wasm/execution/interpreter_loop/
variable.rs

1use core::ops::ControlFlow;
2
3use crate::{
4    assert_validated::UnwrapValidatedExt,
5    core::{
6        indices::{GlobalIdx, LocalIdx},
7        reader::types::opcode,
8    },
9    execution::interpreter_loop::{define_instruction_fn, Args},
10};
11
12define_instruction_fn! {
13    local_get,
14    fuel_check = flat(opcode::LOCAL_GET),
15    |Args {
16         resumable, wasm, ..
17     }| {
18        // SAFETY: Validation guarantees there to be a valid local index
19        // next.
20        let local_idx = unsafe { LocalIdx::read_unchecked(wasm) };
21        let value = *resumable.stack.get_local(local_idx);
22        resumable.stack.push_value(value)?;
23        trace!("Instruction: local.get {} [] -> [t]", local_idx);
24        Ok(ControlFlow::Continue(()))
25    }
26}
27
28define_instruction_fn! {
29    local_set,
30    fuel_check = flat(opcode::LOCAL_SET),
31    |Args {
32         resumable, wasm, ..
33     }| {
34        // SAFETY: Validation guarantees there to be a valid local index
35        // next.
36        let local_idx = unsafe { LocalIdx::read_unchecked(wasm) };
37        let value = resumable.stack.pop_value();
38        *resumable.stack.get_local_mut(local_idx) = value;
39        trace!("Instruction: local.set {} [t] -> []", local_idx);
40        Ok(ControlFlow::Continue(()))
41    }
42}
43
44define_instruction_fn! {
45    local_tee,
46    fuel_check = flat(opcode::LOCAL_TEE),
47    |Args {
48         resumable, wasm, ..
49     }| {
50        // SAFETY: Validation guarantees there to be a valid local index
51        // next.
52        let local_idx = unsafe { LocalIdx::read_unchecked(wasm) };
53        let value = resumable.stack.peek_value().unwrap_validated();
54        *resumable.stack.get_local_mut(local_idx) = value;
55        trace!("Instruction: local.tee {} [t] -> [t]", local_idx);
56        Ok(ControlFlow::Continue(()))
57    }
58}
59
60define_instruction_fn! {
61    global_get,
62    fuel_check = flat(opcode::GLOBAL_GET),
63    |Args {
64         store_inner,
65         modules,
66         resumable,
67         wasm,
68         current_module,
69         ..
70     }| {
71        // SAFETY: Validation guarantees there to be a valid global
72        // index next.
73        let global_idx = unsafe { GlobalIdx::read_unchecked(wasm) };
74        // SAFETY: The current module address must come from the current
75        // store, because it is the only parameter to this function that
76        // can contain module addresses. All stores guarantee all
77        // addresses in them to be valid within themselves.
78        let module = unsafe { modules.get(*current_module) };
79
80        // SAFETY: Validation guarantees the global index to be valid in
81        // the current module.
82        let global_addr = *unsafe { module.global_addrs.get(global_idx) };
83        // SAFETY: This global address was just read from the current
84        // store. Therefore, it is valid in the current store.
85        let global = unsafe { store_inner.globals.get(global_addr) };
86
87        resumable.stack.push_value(global.value)?;
88
89        trace!(
90            "Instruction: global.get '{}' [<GLOBAL>] -> [{:?}]",
91            global_idx,
92            global.value
93        );
94        Ok(ControlFlow::Continue(()))
95    }
96}
97
98define_instruction_fn! {
99    global_set,
100    fuel_check = flat(opcode::GLOBAL_SET),
101    |Args {
102         store_inner,
103         modules,
104         resumable,
105         wasm,
106         current_module,
107         ..
108     }| {
109        // SAFETY: Validation guarantees there to be a valid global
110        // index next.
111        let global_idx = unsafe { GlobalIdx::read_unchecked(wasm) };
112        // SAFETY: The current module address must come from the current
113        // store, because it is the only parameter to this function that
114        // can contain module addresses. All stores guarantee all
115        // addresses in them to be valid within themselves.
116        let module = unsafe { modules.get(*current_module) };
117        // SAFETY: Validation guarantees the global index to be valid in
118        // the current module.
119        let global_addr = *unsafe { module.global_addrs.get(global_idx) };
120        // SAFETY: This global address was just read from the current
121        // store. Therefore, it is valid in the current store.
122        let global = unsafe { store_inner.globals.get_mut(global_addr) };
123
124        global.value = resumable.stack.pop_value();
125        trace!("Instruction: GLOBAL_SET");
126        Ok(ControlFlow::Continue(()))
127    }
128}