tinywasm/interpreter/stack/
call_stack.rs1use core::ops::ControlFlow;
2
3use super::BlockType;
4use crate::interpreter::values::*;
5use crate::Trap;
6use crate::{unlikely, Error};
7
8use alloc::boxed::Box;
9use alloc::{rc::Rc, vec, vec::Vec};
10use tinywasm_types::{Instruction, LocalAddr, ModuleInstanceAddr, WasmFunction, WasmValue};
11
12pub(crate) const MAX_CALL_STACK_SIZE: usize = 1024;
13
14#[derive(Debug)]
15pub(crate) struct CallStack {
16 stack: Vec<CallFrame>,
17}
18
19impl CallStack {
20 #[inline]
21 pub(crate) fn new(initial_frame: CallFrame) -> Self {
22 Self { stack: vec![initial_frame] }
23 }
24
25 #[inline(always)]
26 pub(crate) fn pop(&mut self) -> Option<CallFrame> {
27 self.stack.pop()
28 }
29
30 #[inline(always)]
31 pub(crate) fn push(&mut self, call_frame: CallFrame) -> ControlFlow<Option<Error>> {
32 if unlikely((self.stack.len() + 1) >= MAX_CALL_STACK_SIZE) {
33 return ControlFlow::Break(Some(Trap::CallStackOverflow.into()));
34 }
35 self.stack.push(call_frame);
36 ControlFlow::Continue(())
37 }
38}
39
40#[derive(Debug)]
41pub(crate) struct CallFrame {
42 instr_ptr: usize,
43 func_instance: Rc<WasmFunction>,
44 block_ptr: u32,
45 module_addr: ModuleInstanceAddr,
46 pub(crate) locals: Locals,
47}
48
49#[derive(Debug)]
50pub(crate) struct Locals {
51 pub(crate) locals_32: Box<[Value32]>,
52 pub(crate) locals_64: Box<[Value64]>,
53 pub(crate) locals_128: Box<[Value128]>,
54 pub(crate) locals_ref: Box<[ValueRef]>,
55}
56
57impl Locals {
58 pub(crate) fn get<T: InternalValue>(&self, local_index: LocalAddr) -> T {
59 T::local_get(self, local_index)
60 }
61
62 pub(crate) fn set<T: InternalValue>(&mut self, local_index: LocalAddr, value: T) {
63 T::local_set(self, local_index, value)
64 }
65}
66
67impl CallFrame {
68 #[inline(always)]
69 pub(crate) fn instr_ptr(&self) -> usize {
70 self.instr_ptr
71 }
72
73 #[inline(always)]
74 pub(crate) fn incr_instr_ptr(&mut self) {
75 self.instr_ptr += 1;
76 }
77
78 #[inline(always)]
79 pub(crate) fn jump(&mut self, offset: usize) {
80 self.instr_ptr += offset;
81 }
82
83 #[inline(always)]
84 pub(crate) fn module_addr(&self) -> ModuleInstanceAddr {
85 self.module_addr
86 }
87
88 #[inline(always)]
89 pub(crate) fn block_ptr(&self) -> u32 {
90 self.block_ptr
91 }
92
93 #[inline(always)]
94 pub(crate) fn fetch_instr(&self) -> &Instruction {
95 &self.func_instance.instructions[self.instr_ptr]
96 }
97
98 #[inline(always)]
101 pub(crate) fn break_to(
102 &mut self,
103 break_to_relative: u32,
104 values: &mut super::ValueStack,
105 blocks: &mut super::BlockStack,
106 ) -> Option<()> {
107 let break_to = blocks.get_relative_to(break_to_relative, self.block_ptr)?;
108
109 match break_to.ty {
112 BlockType::Loop => {
113 self.instr_ptr = break_to.instr_ptr;
115
116 values.truncate_keep(break_to.stack_ptr, break_to.params);
118
119 if break_to_relative != 0 {
121 blocks.truncate(blocks.len() as u32 - break_to_relative);
123 return Some(());
124 }
125 }
126
127 BlockType::Block | BlockType::If | BlockType::Else => {
128 values.truncate_keep(break_to.stack_ptr, break_to.results);
131
132 self.instr_ptr = break_to.instr_ptr + break_to.end_instr_offset as usize;
134
135 blocks.truncate(blocks.len() as u32 - (break_to_relative + 1));
137 }
138 }
139
140 Some(())
141 }
142
143 #[inline(always)]
144 pub(crate) fn new(
145 wasm_func_inst: Rc<WasmFunction>,
146 owner: ModuleInstanceAddr,
147 params: &[WasmValue],
148 block_ptr: u32,
149 ) -> Self {
150 let locals = {
151 let mut locals_32 = Vec::new();
152 locals_32.reserve_exact(wasm_func_inst.locals.c32 as usize);
153 let mut locals_64 = Vec::new();
154 locals_64.reserve_exact(wasm_func_inst.locals.c64 as usize);
155 let mut locals_128 = Vec::new();
156 locals_128.reserve_exact(wasm_func_inst.locals.c128 as usize);
157 let mut locals_ref = Vec::new();
158 locals_ref.reserve_exact(wasm_func_inst.locals.cref as usize);
159
160 for p in params {
161 match p.into() {
162 TinyWasmValue::Value32(v) => locals_32.push(v),
163 TinyWasmValue::Value64(v) => locals_64.push(v),
164 TinyWasmValue::Value128(v) => locals_128.push(v),
165 TinyWasmValue::ValueRef(v) => locals_ref.push(v),
166 }
167 }
168
169 locals_32.resize_with(wasm_func_inst.locals.c32 as usize, Default::default);
170 locals_64.resize_with(wasm_func_inst.locals.c64 as usize, Default::default);
171 locals_128.resize_with(wasm_func_inst.locals.c128 as usize, Default::default);
172 locals_ref.resize_with(wasm_func_inst.locals.cref as usize, Default::default);
173
174 Locals {
175 locals_32: locals_32.into_boxed_slice(),
176 locals_64: locals_64.into_boxed_slice(),
177 locals_128: locals_128.into_boxed_slice(),
178 locals_ref: locals_ref.into_boxed_slice(),
179 }
180 };
181
182 Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals }
183 }
184
185 #[inline]
186 pub(crate) fn new_raw(
187 wasm_func_inst: Rc<WasmFunction>,
188 owner: ModuleInstanceAddr,
189 locals: Locals,
190 block_ptr: u32,
191 ) -> Self {
192 Self { instr_ptr: 0, func_instance: wasm_func_inst, module_addr: owner, block_ptr, locals }
193 }
194
195 #[inline(always)]
196 pub(crate) fn instructions(&self) -> &[Instruction] {
197 &self.func_instance.instructions
198 }
199}