1use crate::func_environ::{FuncEnvironment, GlobalVariable};
13use crate::heap::Heap;
14use crate::translator::code_translator::CatchClause;
15use crate::{HashMap, Occupied, Vacant};
16use cranelift_codegen::ir::{self, Block, Inst, Value};
17use cranelift_frontend::FunctionBuilder;
18use itertools::Itertools;
19use std::vec::Vec;
20use wasmer_types::{
21 CATCH_ALL_TAG_VALUE, FunctionIndex, GlobalIndex, MemoryIndex, SignatureIndex, WasmResult,
22};
23
24#[derive(Debug)]
27pub enum ElseData {
28 NoElse {
33 branch_inst: Inst,
37
38 placeholder: Block,
40 },
41
42 WithElse {
49 else_block: Block,
51 },
52}
53
54#[derive(Debug)]
65pub enum ControlStackFrame {
66 If {
67 destination: Block,
68 else_data: ElseData,
69 num_param_values: usize,
70 num_return_values: usize,
71 original_stack_size: usize,
72 exit_is_branched_to: bool,
73 blocktype: wasmer_compiler::wasmparser::BlockType,
74 head_is_reachable: bool,
76 consequent_ends_reachable: Option<bool>,
83 },
86 Block {
87 destination: Block,
88 num_param_values: usize,
89 num_return_values: usize,
90 original_stack_size: usize,
91 exit_is_branched_to: bool,
92 try_table_info: Option<(HandlerStateCheckpoint, Vec<Block>)>,
95 },
96 Loop {
97 destination: Block,
98 header: Block,
99 num_param_values: usize,
100 num_return_values: usize,
101 original_stack_size: usize,
102 },
103}
104
105impl ControlStackFrame {
107 pub fn num_return_values(&self) -> usize {
108 match *self {
109 Self::If {
110 num_return_values, ..
111 }
112 | Self::Block {
113 num_return_values, ..
114 }
115 | Self::Loop {
116 num_return_values, ..
117 } => num_return_values,
118 }
119 }
120 pub fn num_param_values(&self) -> usize {
121 match *self {
122 Self::If {
123 num_param_values, ..
124 }
125 | Self::Block {
126 num_param_values, ..
127 }
128 | Self::Loop {
129 num_param_values, ..
130 } => num_param_values,
131 }
132 }
133 pub fn following_code(&self) -> Block {
134 match *self {
135 Self::If { destination, .. }
136 | Self::Block { destination, .. }
137 | Self::Loop { destination, .. } => destination,
138 }
139 }
140 pub fn br_destination(&self) -> Block {
141 match *self {
142 Self::If { destination, .. } | Self::Block { destination, .. } => destination,
143 Self::Loop { header, .. } => header,
144 }
145 }
146 fn original_stack_size(&self) -> usize {
149 match *self {
150 Self::If {
151 original_stack_size,
152 ..
153 }
154 | Self::Block {
155 original_stack_size,
156 ..
157 }
158 | Self::Loop {
159 original_stack_size,
160 ..
161 } => original_stack_size,
162 }
163 }
164 pub fn is_loop(&self) -> bool {
165 match *self {
166 Self::If { .. } | Self::Block { .. } => false,
167 Self::Loop { .. } => true,
168 }
169 }
170
171 pub fn exit_is_branched_to(&self) -> bool {
172 match *self {
173 Self::If {
174 exit_is_branched_to,
175 ..
176 }
177 | Self::Block {
178 exit_is_branched_to,
179 ..
180 } => exit_is_branched_to,
181 Self::Loop { .. } => false,
182 }
183 }
184
185 pub fn set_branched_to_exit(&mut self) {
186 match *self {
187 Self::If {
188 ref mut exit_is_branched_to,
189 ..
190 }
191 | Self::Block {
192 ref mut exit_is_branched_to,
193 ..
194 } => *exit_is_branched_to = true,
195 Self::Loop { .. } => {}
196 }
197 }
198
199 pub fn truncate_value_stack_to_else_params(&self, stack: &mut Vec<Value>) {
202 debug_assert!(matches!(self, &Self::If { .. }));
203 stack.truncate(self.original_stack_size());
204 }
205
206 pub fn truncate_value_stack_to_original_size(&self, stack: &mut Vec<Value>) {
209 let num_duplicated_params = match self {
215 &Self::If {
216 num_param_values, ..
217 } => {
218 debug_assert!(num_param_values <= self.original_stack_size());
219 num_param_values
220 }
221 _ => 0,
222 };
223 stack.truncate(self.original_stack_size() - num_duplicated_params);
224 }
225
226 pub fn restore_catch_handlers(
229 &self,
230 handlers: &mut HandlerState,
231 builder: &mut FunctionBuilder,
232 ) {
233 if let Self::Block {
234 try_table_info: Some((checkpoint, catch_blocks)),
235 ..
236 } = self
237 {
238 handlers.restore_checkpoint(*checkpoint);
239 for block in catch_blocks {
240 builder.seal_block(*block);
241 }
242 }
243 }
244}
245
246pub struct FuncTranslationState {
252 pub(crate) stack: Vec<Value>,
255 pub(crate) control_stack: Vec<ControlStackFrame>,
257 pub(crate) handlers: HandlerState,
259 pub(crate) reachable: bool,
262
263 globals: HashMap<GlobalIndex, GlobalVariable>,
265
266 heaps: HashMap<MemoryIndex, Heap>,
268
269 signatures: HashMap<SignatureIndex, (ir::SigRef, usize)>,
273
274 functions: HashMap<FunctionIndex, (ir::FuncRef, usize)>,
278}
279
280impl FuncTranslationState {
282 #[inline]
284 #[allow(dead_code)]
285 pub fn reachable(&self) -> bool {
286 self.reachable
287 }
288}
289
290#[derive(Clone, Copy, Debug)]
291pub(crate) struct HandlerStateCheckpoint(usize, usize);
292
293#[derive(Default)]
294pub(crate) struct HandlerState {
295 handlers: Vec<Block>,
296 clauses: Vec<CatchClause>,
297}
298
299#[derive(Debug)]
300pub(crate) struct LandingPad {
301 pub(crate) block: Block,
302 pub(crate) clauses: Vec<CatchClause>,
303}
304
305impl HandlerState {
306 pub fn add_handler(&mut self, block: Block) {
307 self.handlers.push(block);
308 }
309
310 pub fn add_clause(&mut self, clause: CatchClause) {
311 self.clauses.push(clause);
312 }
313
314 pub fn take_checkpoint(&self) -> HandlerStateCheckpoint {
315 HandlerStateCheckpoint(self.handlers.len(), self.clauses.len())
316 }
317
318 pub fn restore_checkpoint(&mut self, checkpoint: HandlerStateCheckpoint) {
319 debug_assert!(checkpoint.0 <= self.handlers.len());
320 debug_assert!(checkpoint.1 <= self.clauses.len());
321 self.handlers.truncate(checkpoint.0);
322 self.clauses.truncate(checkpoint.1);
323 }
324
325 pub fn landing_pad(&self) -> Option<LandingPad> {
327 self.handlers.last().copied().map(|block| LandingPad {
328 block,
329 clauses: self.unique_clauses(),
330 })
331 }
332
333 pub fn unique_clauses(&self) -> Vec<CatchClause> {
335 self.clauses
336 .iter()
337 .rev()
339 .unique_by(|c| c.tag_value)
340 .take_while_inclusive(|c| c.tag_value != CATCH_ALL_TAG_VALUE)
342 .cloned()
343 .collect()
344 }
345
346 pub fn is_empty(&self) -> bool {
347 self.handlers.is_empty()
348 }
349
350 pub fn clear(&mut self) {
351 self.handlers.clear();
352 self.clauses.clear();
353 }
354}
355
356impl FuncTranslationState {
357 pub(crate) fn new() -> Self {
359 Self {
360 stack: Vec::new(),
361 control_stack: Vec::new(),
364 handlers: HandlerState::default(),
365 reachable: true,
366 globals: HashMap::new(),
367 heaps: HashMap::new(),
368 signatures: HashMap::new(),
369 functions: HashMap::new(),
370 }
371 }
372
373 fn clear(&mut self) {
374 debug_assert!(self.stack.is_empty());
375 debug_assert!(self.control_stack.is_empty());
376 debug_assert!(self.handlers.is_empty());
377 self.reachable = true;
378 self.handlers.clear();
379 self.globals.clear();
380 self.heaps.clear();
381 self.signatures.clear();
382 self.functions.clear();
383 }
384
385 pub(crate) fn initialize(
390 &mut self,
391 _sig: &ir::Signature,
392 exit_block: Block,
393 result_count: usize,
394 ) {
395 self.clear();
396 self.push_block(exit_block, 0, result_count);
397 }
398
399 pub(crate) fn push1(&mut self, val: Value) {
401 self.stack.push(val);
402 }
403
404 pub(crate) fn pushn(&mut self, vals: &[Value]) {
406 self.stack.extend_from_slice(vals);
407 }
408
409 pub(crate) fn pop1(&mut self) -> Value {
411 self.stack
412 .pop()
413 .expect("attempted to pop a value from an empty stack")
414 }
415
416 pub(crate) fn peek1(&self) -> Value {
418 *self
419 .stack
420 .last()
421 .expect("attempted to peek at a value on an empty stack")
422 }
423
424 pub(crate) fn pop2(&mut self) -> (Value, Value) {
426 let v2 = self.pop1();
427 let v1 = self.pop1();
428 (v1, v2)
429 }
430
431 pub(crate) fn pop3(&mut self) -> (Value, Value, Value) {
433 let v3 = self.pop1();
434 let v2 = self.pop1();
435 let v1 = self.pop1();
436 (v1, v2, v3)
437 }
438
439 #[inline]
442 fn ensure_length_is_at_least(&self, n: usize) {
443 debug_assert!(
444 n <= self.stack.len(),
445 "attempted to access {} values but stack only has {} values",
446 n,
447 self.stack.len()
448 );
449 }
450
451 pub(crate) fn popn(&mut self, n: usize) {
455 self.ensure_length_is_at_least(n);
456 let new_len = self.stack.len() - n;
457 self.stack.truncate(new_len);
458 }
459
460 pub(crate) fn peekn(&self, n: usize) -> &[Value] {
462 self.ensure_length_is_at_least(n);
463 &self.stack[self.stack.len() - n..]
464 }
465
466 pub(crate) fn peekn_mut(&mut self, n: usize) -> &mut [Value] {
468 self.ensure_length_is_at_least(n);
469 let len = self.stack.len();
470 &mut self.stack[len - n..]
471 }
472
473 fn push_block_impl(
474 &mut self,
475 following_code: Block,
476 num_param_types: usize,
477 num_result_types: usize,
478 try_table_info: Option<(HandlerStateCheckpoint, Vec<Block>)>,
479 ) {
480 debug_assert!(num_param_types <= self.stack.len());
481 self.control_stack.push(ControlStackFrame::Block {
482 destination: following_code,
483 original_stack_size: self.stack.len() - num_param_types,
484 num_param_values: num_param_types,
485 num_return_values: num_result_types,
486 exit_is_branched_to: false,
487 try_table_info,
488 });
489 }
490
491 pub(crate) fn push_block(
493 &mut self,
494 following_code: Block,
495 num_param_types: usize,
496 num_result_types: usize,
497 ) {
498 self.push_block_impl(following_code, num_param_types, num_result_types, None);
499 }
500
501 pub(crate) fn push_try_table_block(
503 &mut self,
504 following_code: Block,
505 catch_blocks: Vec<Block>,
506 num_param_types: usize,
507 num_result_types: usize,
508 checkpoint: HandlerStateCheckpoint,
509 ) {
510 self.push_block_impl(
511 following_code,
512 num_param_types,
513 num_result_types,
514 Some((checkpoint, catch_blocks)),
515 );
516 }
517
518 pub(crate) fn push_loop(
520 &mut self,
521 header: Block,
522 following_code: Block,
523 num_param_types: usize,
524 num_result_types: usize,
525 ) {
526 debug_assert!(num_param_types <= self.stack.len());
527 self.control_stack.push(ControlStackFrame::Loop {
528 header,
529 destination: following_code,
530 original_stack_size: self.stack.len() - num_param_types,
531 num_param_values: num_param_types,
532 num_return_values: num_result_types,
533 });
534 }
535
536 pub(crate) fn push_if(
538 &mut self,
539 destination: Block,
540 else_data: ElseData,
541 num_param_types: usize,
542 num_result_types: usize,
543 blocktype: wasmer_compiler::wasmparser::BlockType,
544 ) {
545 debug_assert!(num_param_types <= self.stack.len());
546
547 self.stack.reserve(num_param_types);
553 for i in (self.stack.len() - num_param_types)..self.stack.len() {
554 let val = self.stack[i];
555 self.stack.push(val);
556 }
557
558 self.control_stack.push(ControlStackFrame::If {
559 destination,
560 else_data,
561 original_stack_size: self.stack.len() - num_param_types,
562 num_param_values: num_param_types,
563 num_return_values: num_result_types,
564 exit_is_branched_to: false,
565 head_is_reachable: self.reachable,
566 consequent_ends_reachable: None,
567 blocktype,
568 });
569 }
570}
571
572impl FuncTranslationState {
574 pub(crate) fn get_global(
578 &mut self,
579 func: &mut ir::Function,
580 index: u32,
581 environ: &mut FuncEnvironment<'_>,
582 ) -> WasmResult<GlobalVariable> {
583 let index = GlobalIndex::from_u32(index);
584 match self.globals.entry(index) {
585 Occupied(entry) => Ok(*entry.get()),
586 Vacant(entry) => Ok(*entry.insert(environ.make_global(func, index)?)),
587 }
588 }
589
590 pub(crate) fn get_heap(
593 &mut self,
594 func: &mut ir::Function,
595 index: u32,
596 environ: &mut FuncEnvironment<'_>,
597 ) -> WasmResult<Heap> {
598 let index = MemoryIndex::from_u32(index);
599 match self.heaps.entry(index) {
600 Occupied(entry) => Ok(*entry.get()),
601 Vacant(entry) => Ok(*entry.insert(environ.make_heap(func, index)?)),
602 }
603 }
604
605 pub(crate) fn get_indirect_sig(
610 &mut self,
611 func: &mut ir::Function,
612 index: u32,
613 environ: &mut FuncEnvironment<'_>,
614 ) -> WasmResult<(ir::SigRef, usize)> {
615 let index = SignatureIndex::from_u32(index);
616 match self.signatures.entry(index) {
617 Occupied(entry) => Ok(*entry.get()),
618 Vacant(entry) => {
619 let sig = environ.make_indirect_sig(func, index)?;
620 Ok(*entry.insert((sig, num_wasm_parameters(environ, &func.dfg.signatures[sig]))))
621 }
622 }
623 }
624
625 pub(crate) fn get_direct_func(
630 &mut self,
631 func: &mut ir::Function,
632 index: u32,
633 environ: &mut FuncEnvironment<'_>,
634 ) -> WasmResult<(ir::FuncRef, usize)> {
635 let index = FunctionIndex::from_u32(index);
636 match self.functions.entry(index) {
637 Occupied(entry) => Ok(*entry.get()),
638 Vacant(entry) => {
639 let fref = environ.make_direct_func(func, index)?;
640 let sig = func.dfg.ext_funcs[fref].signature;
641 Ok(*entry.insert((
642 fref,
643 num_wasm_parameters(environ, &func.dfg.signatures[sig]),
644 )))
645 }
646 }
647 }
648}
649
650fn num_wasm_parameters(environ: &FuncEnvironment<'_>, signature: &ir::Signature) -> usize {
651 (0..signature.params.len())
652 .filter(|index| environ.is_wasm_parameter(signature, *index))
653 .count()
654}