1use crate::environ::{FuncEnvironment, GlobalVariable, WasmResult};
10use crate::translation_utils::{FuncIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex};
11use crate::{HashMap, Occupied, Vacant};
12use cranelift_codegen::ir::{self, Ebb, Inst, Value};
13use std::vec::Vec;
14
15#[derive(Debug)]
18pub enum ElseData {
19 NoElse {
24 branch_inst: Inst,
28 },
29
30 WithElse {
37 else_block: Ebb,
39 },
40}
41
42#[derive(Debug)]
53pub enum ControlStackFrame {
54 If {
55 destination: Ebb,
56 else_data: ElseData,
57 num_param_values: usize,
58 num_return_values: usize,
59 original_stack_size: usize,
60 exit_is_branched_to: bool,
61 blocktype: wasmparser::TypeOrFuncType,
62 head_is_reachable: bool,
64 consequent_ends_reachable: Option<bool>,
71 },
74 Block {
75 destination: Ebb,
76 num_param_values: usize,
77 num_return_values: usize,
78 original_stack_size: usize,
79 exit_is_branched_to: bool,
80 },
81 Loop {
82 destination: Ebb,
83 header: Ebb,
84 num_param_values: usize,
85 num_return_values: usize,
86 original_stack_size: usize,
87 },
88}
89
90impl ControlStackFrame {
92 pub fn num_return_values(&self) -> usize {
93 match *self {
94 Self::If {
95 num_return_values, ..
96 }
97 | Self::Block {
98 num_return_values, ..
99 }
100 | Self::Loop {
101 num_return_values, ..
102 } => num_return_values,
103 }
104 }
105 pub fn num_param_values(&self) -> usize {
106 match *self {
107 Self::If {
108 num_param_values, ..
109 }
110 | Self::Block {
111 num_param_values, ..
112 }
113 | Self::Loop {
114 num_param_values, ..
115 } => num_param_values,
116 }
117 }
118 pub fn following_code(&self) -> Ebb {
119 match *self {
120 Self::If { destination, .. }
121 | Self::Block { destination, .. }
122 | Self::Loop { destination, .. } => destination,
123 }
124 }
125 pub fn br_destination(&self) -> Ebb {
126 match *self {
127 Self::If { destination, .. } | Self::Block { destination, .. } => destination,
128 Self::Loop { header, .. } => header,
129 }
130 }
131 pub fn original_stack_size(&self) -> usize {
132 match *self {
133 Self::If {
134 original_stack_size,
135 ..
136 }
137 | Self::Block {
138 original_stack_size,
139 ..
140 }
141 | Self::Loop {
142 original_stack_size,
143 ..
144 } => original_stack_size,
145 }
146 }
147 pub fn is_loop(&self) -> bool {
148 match *self {
149 Self::If { .. } | Self::Block { .. } => false,
150 Self::Loop { .. } => true,
151 }
152 }
153
154 pub fn exit_is_branched_to(&self) -> bool {
155 match *self {
156 Self::If {
157 exit_is_branched_to,
158 ..
159 }
160 | Self::Block {
161 exit_is_branched_to,
162 ..
163 } => exit_is_branched_to,
164 Self::Loop { .. } => false,
165 }
166 }
167
168 pub fn set_branched_to_exit(&mut self) {
169 match *self {
170 Self::If {
171 ref mut exit_is_branched_to,
172 ..
173 }
174 | Self::Block {
175 ref mut exit_is_branched_to,
176 ..
177 } => *exit_is_branched_to = true,
178 Self::Loop { .. } => {}
179 }
180 }
181}
182
183pub struct FuncTranslationState {
189 pub(crate) stack: Vec<Value>,
192 pub(crate) control_stack: Vec<ControlStackFrame>,
194 pub(crate) reachable: bool,
197
198 globals: HashMap<GlobalIndex, GlobalVariable>,
200
201 heaps: HashMap<MemoryIndex, ir::Heap>,
203
204 tables: HashMap<TableIndex, ir::Table>,
206
207 signatures: HashMap<SignatureIndex, (ir::SigRef, usize)>,
211
212 functions: HashMap<FuncIndex, (ir::FuncRef, usize)>,
216}
217
218impl FuncTranslationState {
220 #[inline]
222 pub fn reachable(&self) -> bool {
223 self.reachable
224 }
225}
226
227impl FuncTranslationState {
228 pub(crate) fn new() -> Self {
230 Self {
231 stack: Vec::new(),
232 control_stack: Vec::new(),
233 reachable: true,
234 globals: HashMap::new(),
235 heaps: HashMap::new(),
236 tables: HashMap::new(),
237 signatures: HashMap::new(),
238 functions: HashMap::new(),
239 }
240 }
241
242 fn clear(&mut self) {
243 debug_assert!(self.stack.is_empty());
244 debug_assert!(self.control_stack.is_empty());
245 self.reachable = true;
246 self.globals.clear();
247 self.heaps.clear();
248 self.tables.clear();
249 self.signatures.clear();
250 self.functions.clear();
251 }
252
253 pub(crate) fn initialize(&mut self, sig: &ir::Signature, exit_block: Ebb) {
258 self.clear();
259 self.push_block(
260 exit_block,
261 0,
262 sig.returns
263 .iter()
264 .filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
265 .count(),
266 );
267 }
268
269 pub(crate) fn push1(&mut self, val: Value) {
271 self.stack.push(val);
272 }
273
274 pub(crate) fn pushn(&mut self, vals: &[Value]) {
276 self.stack.extend_from_slice(vals);
277 }
278
279 pub(crate) fn pop1(&mut self) -> Value {
281 self.stack
282 .pop()
283 .expect("attempted to pop a value from an empty stack")
284 }
285
286 pub(crate) fn peek1(&self) -> Value {
288 *self
289 .stack
290 .last()
291 .expect("attempted to peek at a value on an empty stack")
292 }
293
294 pub(crate) fn pop2(&mut self) -> (Value, Value) {
296 let v2 = self.stack.pop().unwrap();
297 let v1 = self.stack.pop().unwrap();
298 (v1, v2)
299 }
300
301 pub(crate) fn pop3(&mut self) -> (Value, Value, Value) {
303 let v3 = self.stack.pop().unwrap();
304 let v2 = self.stack.pop().unwrap();
305 let v1 = self.stack.pop().unwrap();
306 (v1, v2, v3)
307 }
308
309 #[inline]
312 fn ensure_length_is_at_least(&self, n: usize) {
313 debug_assert!(
314 n <= self.stack.len(),
315 "attempted to access {} values but stack only has {} values",
316 n,
317 self.stack.len()
318 )
319 }
320
321 pub(crate) fn popn(&mut self, n: usize) {
325 self.ensure_length_is_at_least(n);
326 let new_len = self.stack.len() - n;
327 self.stack.truncate(new_len);
328 }
329
330 pub(crate) fn peekn(&self, n: usize) -> &[Value] {
332 self.ensure_length_is_at_least(n);
333 &self.stack[self.stack.len() - n..]
334 }
335
336 pub(crate) fn peekn_mut(&mut self, n: usize) -> &mut [Value] {
338 self.ensure_length_is_at_least(n);
339 let len = self.stack.len();
340 &mut self.stack[len - n..]
341 }
342
343 pub(crate) fn push_block(
345 &mut self,
346 following_code: Ebb,
347 num_param_types: usize,
348 num_result_types: usize,
349 ) {
350 debug_assert!(num_param_types <= self.stack.len());
351 self.control_stack.push(ControlStackFrame::Block {
352 destination: following_code,
353 original_stack_size: self.stack.len() - num_param_types,
354 num_param_values: num_param_types,
355 num_return_values: num_result_types,
356 exit_is_branched_to: false,
357 });
358 }
359
360 pub(crate) fn push_loop(
362 &mut self,
363 header: Ebb,
364 following_code: Ebb,
365 num_param_types: usize,
366 num_result_types: usize,
367 ) {
368 debug_assert!(num_param_types <= self.stack.len());
369 self.control_stack.push(ControlStackFrame::Loop {
370 header,
371 destination: following_code,
372 original_stack_size: self.stack.len() - num_param_types,
373 num_param_values: num_param_types,
374 num_return_values: num_result_types,
375 });
376 }
377
378 pub(crate) fn push_if(
380 &mut self,
381 destination: Ebb,
382 else_data: ElseData,
383 num_param_types: usize,
384 num_result_types: usize,
385 blocktype: wasmparser::TypeOrFuncType,
386 ) {
387 debug_assert!(num_param_types <= self.stack.len());
388
389 self.stack.reserve(num_param_types);
395 for i in (self.stack.len() - num_param_types)..self.stack.len() {
396 let val = self.stack[i];
397 self.stack.push(val);
398 }
399
400 self.control_stack.push(ControlStackFrame::If {
401 destination,
402 else_data,
403 original_stack_size: self.stack.len() - num_param_types,
404 num_param_values: num_param_types,
405 num_return_values: num_result_types,
406 exit_is_branched_to: false,
407 head_is_reachable: self.reachable,
408 consequent_ends_reachable: None,
409 blocktype,
410 });
411 }
412}
413
414impl FuncTranslationState {
416 pub(crate) fn get_global<FE: FuncEnvironment + ?Sized>(
420 &mut self,
421 func: &mut ir::Function,
422 index: u32,
423 environ: &mut FE,
424 ) -> WasmResult<GlobalVariable> {
425 let index = GlobalIndex::from_u32(index);
426 match self.globals.entry(index) {
427 Occupied(entry) => Ok(*entry.get()),
428 Vacant(entry) => Ok(*entry.insert(environ.make_global(func, index)?)),
429 }
430 }
431
432 pub(crate) fn get_heap<FE: FuncEnvironment + ?Sized>(
435 &mut self,
436 func: &mut ir::Function,
437 index: u32,
438 environ: &mut FE,
439 ) -> WasmResult<ir::Heap> {
440 let index = MemoryIndex::from_u32(index);
441 match self.heaps.entry(index) {
442 Occupied(entry) => Ok(*entry.get()),
443 Vacant(entry) => Ok(*entry.insert(environ.make_heap(func, index)?)),
444 }
445 }
446
447 pub(crate) fn get_table<FE: FuncEnvironment + ?Sized>(
450 &mut self,
451 func: &mut ir::Function,
452 index: u32,
453 environ: &mut FE,
454 ) -> WasmResult<ir::Table> {
455 let index = TableIndex::from_u32(index);
456 match self.tables.entry(index) {
457 Occupied(entry) => Ok(*entry.get()),
458 Vacant(entry) => Ok(*entry.insert(environ.make_table(func, index)?)),
459 }
460 }
461
462 pub(crate) fn get_indirect_sig<FE: FuncEnvironment + ?Sized>(
467 &mut self,
468 func: &mut ir::Function,
469 index: u32,
470 environ: &mut FE,
471 ) -> WasmResult<(ir::SigRef, usize)> {
472 let index = SignatureIndex::from_u32(index);
473 match self.signatures.entry(index) {
474 Occupied(entry) => Ok(*entry.get()),
475 Vacant(entry) => {
476 let sig = environ.make_indirect_sig(func, index)?;
477 Ok(*entry.insert((sig, func.dfg.signatures[sig].num_normal_params())))
478 }
479 }
480 }
481
482 pub(crate) fn get_direct_func<FE: FuncEnvironment + ?Sized>(
487 &mut self,
488 func: &mut ir::Function,
489 index: u32,
490 environ: &mut FE,
491 ) -> WasmResult<(ir::FuncRef, usize)> {
492 let index = FuncIndex::from_u32(index);
493 match self.functions.entry(index) {
494 Occupied(entry) => Ok(*entry.get()),
495 Vacant(entry) => {
496 let fref = environ.make_direct_func(func, index)?;
497 let sig = func.dfg.ext_funcs[fref].signature;
498 Ok(*entry.insert((fref, func.dfg.signatures[sig].num_normal_params())))
499 }
500 }
501 }
502}