1use super::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(&mut self, sig: &ir::Signature, exit_block: Block) {
390 self.clear();
391 self.push_block(
392 exit_block,
393 0,
394 sig.returns
395 .iter()
396 .filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
397 .count(),
398 );
399 }
400
401 pub(crate) fn push1(&mut self, val: Value) {
403 self.stack.push(val);
404 }
405
406 pub(crate) fn pushn(&mut self, vals: &[Value]) {
408 self.stack.extend_from_slice(vals);
409 }
410
411 pub(crate) fn pop1(&mut self) -> Value {
413 self.stack
414 .pop()
415 .expect("attempted to pop a value from an empty stack")
416 }
417
418 pub(crate) fn peek1(&self) -> Value {
420 *self
421 .stack
422 .last()
423 .expect("attempted to peek at a value on an empty stack")
424 }
425
426 pub(crate) fn pop2(&mut self) -> (Value, Value) {
428 let v2 = self.pop1();
429 let v1 = self.pop1();
430 (v1, v2)
431 }
432
433 pub(crate) fn pop3(&mut self) -> (Value, Value, Value) {
435 let v3 = self.pop1();
436 let v2 = self.pop1();
437 let v1 = self.pop1();
438 (v1, v2, v3)
439 }
440
441 #[inline]
444 fn ensure_length_is_at_least(&self, n: usize) {
445 debug_assert!(
446 n <= self.stack.len(),
447 "attempted to access {} values but stack only has {} values",
448 n,
449 self.stack.len()
450 );
451 }
452
453 pub(crate) fn popn(&mut self, n: usize) {
457 self.ensure_length_is_at_least(n);
458 let new_len = self.stack.len() - n;
459 self.stack.truncate(new_len);
460 }
461
462 pub(crate) fn peekn(&self, n: usize) -> &[Value] {
464 self.ensure_length_is_at_least(n);
465 &self.stack[self.stack.len() - n..]
466 }
467
468 pub(crate) fn peekn_mut(&mut self, n: usize) -> &mut [Value] {
470 self.ensure_length_is_at_least(n);
471 let len = self.stack.len();
472 &mut self.stack[len - n..]
473 }
474
475 fn push_block_impl(
476 &mut self,
477 following_code: Block,
478 num_param_types: usize,
479 num_result_types: usize,
480 try_table_info: Option<(HandlerStateCheckpoint, Vec<Block>)>,
481 ) {
482 debug_assert!(num_param_types <= self.stack.len());
483 self.control_stack.push(ControlStackFrame::Block {
484 destination: following_code,
485 original_stack_size: self.stack.len() - num_param_types,
486 num_param_values: num_param_types,
487 num_return_values: num_result_types,
488 exit_is_branched_to: false,
489 try_table_info,
490 });
491 }
492
493 pub(crate) fn push_block(
495 &mut self,
496 following_code: Block,
497 num_param_types: usize,
498 num_result_types: usize,
499 ) {
500 self.push_block_impl(following_code, num_param_types, num_result_types, None);
501 }
502
503 pub(crate) fn push_try_table_block(
505 &mut self,
506 following_code: Block,
507 catch_blocks: Vec<Block>,
508 num_param_types: usize,
509 num_result_types: usize,
510 checkpoint: HandlerStateCheckpoint,
511 ) {
512 self.push_block_impl(
513 following_code,
514 num_param_types,
515 num_result_types,
516 Some((checkpoint, catch_blocks)),
517 );
518 }
519
520 pub(crate) fn push_loop(
522 &mut self,
523 header: Block,
524 following_code: Block,
525 num_param_types: usize,
526 num_result_types: usize,
527 ) {
528 debug_assert!(num_param_types <= self.stack.len());
529 self.control_stack.push(ControlStackFrame::Loop {
530 header,
531 destination: following_code,
532 original_stack_size: self.stack.len() - num_param_types,
533 num_param_values: num_param_types,
534 num_return_values: num_result_types,
535 });
536 }
537
538 pub(crate) fn push_if(
540 &mut self,
541 destination: Block,
542 else_data: ElseData,
543 num_param_types: usize,
544 num_result_types: usize,
545 blocktype: wasmer_compiler::wasmparser::BlockType,
546 ) {
547 debug_assert!(num_param_types <= self.stack.len());
548
549 self.stack.reserve(num_param_types);
555 for i in (self.stack.len() - num_param_types)..self.stack.len() {
556 let val = self.stack[i];
557 self.stack.push(val);
558 }
559
560 self.control_stack.push(ControlStackFrame::If {
561 destination,
562 else_data,
563 original_stack_size: self.stack.len() - num_param_types,
564 num_param_values: num_param_types,
565 num_return_values: num_result_types,
566 exit_is_branched_to: false,
567 head_is_reachable: self.reachable,
568 consequent_ends_reachable: None,
569 blocktype,
570 });
571 }
572}
573
574impl FuncTranslationState {
576 pub(crate) fn get_global<FE: FuncEnvironment + ?Sized>(
580 &mut self,
581 func: &mut ir::Function,
582 index: u32,
583 environ: &mut FE,
584 ) -> WasmResult<GlobalVariable> {
585 let index = GlobalIndex::from_u32(index);
586 match self.globals.entry(index) {
587 Occupied(entry) => Ok(*entry.get()),
588 Vacant(entry) => Ok(*entry.insert(environ.make_global(func, index)?)),
589 }
590 }
591
592 pub(crate) fn get_heap<FE: FuncEnvironment + ?Sized>(
595 &mut self,
596 func: &mut ir::Function,
597 index: u32,
598 environ: &mut FE,
599 ) -> WasmResult<Heap> {
600 let index = MemoryIndex::from_u32(index);
601 match self.heaps.entry(index) {
602 Occupied(entry) => Ok(*entry.get()),
603 Vacant(entry) => Ok(*entry.insert(environ.make_heap(func, index)?)),
604 }
605 }
606
607 pub(crate) fn get_indirect_sig<FE: FuncEnvironment + ?Sized>(
612 &mut self,
613 func: &mut ir::Function,
614 index: u32,
615 environ: &mut FE,
616 ) -> WasmResult<(ir::SigRef, usize)> {
617 let index = SignatureIndex::from_u32(index);
618 match self.signatures.entry(index) {
619 Occupied(entry) => Ok(*entry.get()),
620 Vacant(entry) => {
621 let sig = environ.make_indirect_sig(func, index)?;
622 Ok(*entry.insert((sig, num_wasm_parameters(environ, &func.dfg.signatures[sig]))))
623 }
624 }
625 }
626
627 pub(crate) fn get_direct_func<FE: FuncEnvironment + ?Sized>(
632 &mut self,
633 func: &mut ir::Function,
634 index: u32,
635 environ: &mut FE,
636 ) -> WasmResult<(ir::FuncRef, usize)> {
637 let index = FunctionIndex::from_u32(index);
638 match self.functions.entry(index) {
639 Occupied(entry) => Ok(*entry.get()),
640 Vacant(entry) => {
641 let fref = environ.make_direct_func(func, index)?;
642 let sig = func.dfg.ext_funcs[fref].signature;
643 Ok(*entry.insert((
644 fref,
645 num_wasm_parameters(environ, &func.dfg.signatures[sig]),
646 )))
647 }
648 }
649 }
650}
651
652fn num_wasm_parameters<FE: FuncEnvironment + ?Sized>(
653 environ: &FE,
654 signature: &ir::Signature,
655) -> usize {
656 (0..signature.params.len())
657 .filter(|index| environ.is_wasm_parameter(signature, *index))
658 .count()
659}