1use crate::func_environ::FuncEnvironment;
7use crate::translate::environ::GlobalVariable;
8use crate::translate::Heap;
9use cranelift_codegen::ir::{self, Block, Inst, Value};
10use std::collections::hash_map::{Entry::Occupied, Entry::Vacant, HashMap};
11use std::vec::Vec;
12use wasmtime_environ::{FuncIndex, GlobalIndex, MemoryIndex, TypeIndex, WasmResult};
13
14#[derive(Debug)]
17pub enum ElseData {
18 NoElse {
23 branch_inst: Inst,
27
28 placeholder: Block,
30 },
31
32 WithElse {
39 else_block: Block,
41 },
42}
43
44#[derive(Debug)]
54pub enum ControlStackFrame {
55 If {
56 destination: Block,
57 else_data: ElseData,
58 num_param_values: usize,
59 num_return_values: usize,
60 original_stack_size: usize,
61 exit_is_branched_to: bool,
62 blocktype: wasmparser::BlockType,
63 head_is_reachable: bool,
65 consequent_ends_reachable: Option<bool>,
72 },
75 Block {
76 destination: Block,
77 num_param_values: usize,
78 num_return_values: usize,
79 original_stack_size: usize,
80 exit_is_branched_to: bool,
81 },
82 Loop {
83 destination: Block,
84 header: Block,
85 num_param_values: usize,
86 num_return_values: usize,
87 original_stack_size: usize,
88 },
89}
90
91impl ControlStackFrame {
93 pub fn num_return_values(&self) -> usize {
94 match *self {
95 Self::If {
96 num_return_values, ..
97 }
98 | Self::Block {
99 num_return_values, ..
100 }
101 | Self::Loop {
102 num_return_values, ..
103 } => num_return_values,
104 }
105 }
106 pub fn num_param_values(&self) -> usize {
107 match *self {
108 Self::If {
109 num_param_values, ..
110 }
111 | Self::Block {
112 num_param_values, ..
113 }
114 | Self::Loop {
115 num_param_values, ..
116 } => num_param_values,
117 }
118 }
119 pub fn following_code(&self) -> Block {
120 match *self {
121 Self::If { destination, .. }
122 | Self::Block { destination, .. }
123 | Self::Loop { destination, .. } => destination,
124 }
125 }
126 pub fn br_destination(&self) -> Block {
127 match *self {
128 Self::If { destination, .. } | Self::Block { destination, .. } => destination,
129 Self::Loop { header, .. } => header,
130 }
131 }
132 fn original_stack_size(&self) -> usize {
135 match *self {
136 Self::If {
137 original_stack_size,
138 ..
139 }
140 | Self::Block {
141 original_stack_size,
142 ..
143 }
144 | Self::Loop {
145 original_stack_size,
146 ..
147 } => original_stack_size,
148 }
149 }
150 pub fn is_loop(&self) -> bool {
151 match *self {
152 Self::If { .. } | Self::Block { .. } => false,
153 Self::Loop { .. } => true,
154 }
155 }
156
157 pub fn exit_is_branched_to(&self) -> bool {
158 match *self {
159 Self::If {
160 exit_is_branched_to,
161 ..
162 }
163 | Self::Block {
164 exit_is_branched_to,
165 ..
166 } => exit_is_branched_to,
167 Self::Loop { .. } => false,
168 }
169 }
170
171 pub fn set_branched_to_exit(&mut self) {
172 match *self {
173 Self::If {
174 ref mut exit_is_branched_to,
175 ..
176 }
177 | Self::Block {
178 ref mut exit_is_branched_to,
179 ..
180 } => *exit_is_branched_to = true,
181 Self::Loop { .. } => {}
182 }
183 }
184
185 pub fn truncate_value_stack_to_else_params(&self, stack: &mut Vec<Value>) {
188 debug_assert!(matches!(self, &ControlStackFrame::If { .. }));
189 stack.truncate(self.original_stack_size());
190 }
191
192 pub fn truncate_value_stack_to_original_size(&self, stack: &mut Vec<Value>) {
195 let num_duplicated_params = match self {
201 &ControlStackFrame::If {
202 num_param_values, ..
203 } => {
204 debug_assert!(num_param_values <= self.original_stack_size());
205 num_param_values
206 }
207 _ => 0,
208 };
209 stack.truncate(self.original_stack_size() - num_duplicated_params);
210 }
211}
212
213pub struct FuncTranslationState {
219 pub(crate) stack: Vec<Value>,
222 pub(crate) control_stack: Vec<ControlStackFrame>,
224 pub(crate) reachable: bool,
227
228 globals: HashMap<GlobalIndex, GlobalVariable>,
230
231 memory_to_heap: HashMap<MemoryIndex, Heap>,
233
234 signatures: HashMap<TypeIndex, (ir::SigRef, usize)>,
238
239 functions: HashMap<FuncIndex, (ir::FuncRef, usize)>,
243}
244
245impl FuncTranslationState {
247 #[inline]
249 pub fn reachable(&self) -> bool {
250 self.reachable
251 }
252}
253
254impl FuncTranslationState {
255 pub(crate) fn new() -> Self {
257 Self {
258 stack: Vec::new(),
259 control_stack: Vec::new(),
260 reachable: true,
261 globals: HashMap::new(),
262 memory_to_heap: HashMap::new(),
263 signatures: HashMap::new(),
264 functions: HashMap::new(),
265 }
266 }
267
268 fn clear(&mut self) {
269 debug_assert!(self.stack.is_empty());
270 debug_assert!(self.control_stack.is_empty());
271 self.reachable = true;
272 self.globals.clear();
273 self.memory_to_heap.clear();
274 self.signatures.clear();
275 self.functions.clear();
276 }
277
278 pub(crate) fn initialize(&mut self, sig: &ir::Signature, exit_block: Block) {
283 self.clear();
284 self.push_block(
285 exit_block,
286 0,
287 sig.returns
288 .iter()
289 .filter(|arg| arg.purpose == ir::ArgumentPurpose::Normal)
290 .count(),
291 );
292 }
293
294 pub(crate) fn push1(&mut self, val: Value) {
296 self.stack.push(val);
297 }
298
299 pub(crate) fn push2(&mut self, val1: Value, val2: Value) {
301 self.stack.push(val1);
302 self.stack.push(val2);
303 }
304
305 pub(crate) fn pushn(&mut self, vals: &[Value]) {
307 self.stack.extend_from_slice(vals);
308 }
309
310 pub(crate) fn pop1(&mut self) -> Value {
312 self.stack
313 .pop()
314 .expect("attempted to pop a value from an empty stack")
315 }
316
317 pub(crate) fn peek1(&self) -> Value {
319 *self
320 .stack
321 .last()
322 .expect("attempted to peek at a value on an empty stack")
323 }
324
325 pub(crate) fn pop2(&mut self) -> (Value, Value) {
327 let v2 = self.stack.pop().unwrap();
328 let v1 = self.stack.pop().unwrap();
329 (v1, v2)
330 }
331
332 pub(crate) fn pop3(&mut self) -> (Value, Value, Value) {
334 let v3 = self.stack.pop().unwrap();
335 let v2 = self.stack.pop().unwrap();
336 let v1 = self.stack.pop().unwrap();
337 (v1, v2, v3)
338 }
339
340 pub(crate) fn pop4(&mut self) -> (Value, Value, Value, Value) {
342 let v4 = self.stack.pop().unwrap();
343 let v3 = self.stack.pop().unwrap();
344 let v2 = self.stack.pop().unwrap();
345 let v1 = self.stack.pop().unwrap();
346 (v1, v2, v3, v4)
347 }
348
349 pub(crate) fn pop5(&mut self) -> (Value, Value, Value, Value, Value) {
351 let v5 = self.stack.pop().unwrap();
352 let v4 = self.stack.pop().unwrap();
353 let v3 = self.stack.pop().unwrap();
354 let v2 = self.stack.pop().unwrap();
355 let v1 = self.stack.pop().unwrap();
356 (v1, v2, v3, v4, v5)
357 }
358
359 #[inline]
362 fn ensure_length_is_at_least(&self, n: usize) {
363 debug_assert!(
364 n <= self.stack.len(),
365 "attempted to access {} values but stack only has {} values",
366 n,
367 self.stack.len()
368 )
369 }
370
371 pub(crate) fn popn(&mut self, n: usize) {
375 self.ensure_length_is_at_least(n);
376 let new_len = self.stack.len() - n;
377 self.stack.truncate(new_len);
378 }
379
380 pub(crate) fn peekn(&self, n: usize) -> &[Value] {
382 self.ensure_length_is_at_least(n);
383 &self.stack[self.stack.len() - n..]
384 }
385
386 pub(crate) fn peekn_mut(&mut self, n: usize) -> &mut [Value] {
388 self.ensure_length_is_at_least(n);
389 let len = self.stack.len();
390 &mut self.stack[len - n..]
391 }
392
393 pub(crate) fn push_block(
395 &mut self,
396 following_code: Block,
397 num_param_types: usize,
398 num_result_types: usize,
399 ) {
400 debug_assert!(num_param_types <= self.stack.len());
401 self.control_stack.push(ControlStackFrame::Block {
402 destination: following_code,
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 });
408 }
409
410 pub(crate) fn push_loop(
412 &mut self,
413 header: Block,
414 following_code: Block,
415 num_param_types: usize,
416 num_result_types: usize,
417 ) {
418 debug_assert!(num_param_types <= self.stack.len());
419 self.control_stack.push(ControlStackFrame::Loop {
420 header,
421 destination: following_code,
422 original_stack_size: self.stack.len() - num_param_types,
423 num_param_values: num_param_types,
424 num_return_values: num_result_types,
425 });
426 }
427
428 pub(crate) fn push_if(
430 &mut self,
431 destination: Block,
432 else_data: ElseData,
433 num_param_types: usize,
434 num_result_types: usize,
435 blocktype: wasmparser::BlockType,
436 ) {
437 debug_assert!(num_param_types <= self.stack.len());
438
439 self.stack.reserve(num_param_types);
445 for i in (self.stack.len() - num_param_types)..self.stack.len() {
446 let val = self.stack[i];
447 self.stack.push(val);
448 }
449
450 self.control_stack.push(ControlStackFrame::If {
451 destination,
452 else_data,
453 original_stack_size: self.stack.len() - num_param_types,
454 num_param_values: num_param_types,
455 num_return_values: num_result_types,
456 exit_is_branched_to: false,
457 head_is_reachable: self.reachable,
458 consequent_ends_reachable: None,
459 blocktype,
460 });
461 }
462}
463
464impl FuncTranslationState {
466 pub(crate) fn get_global(
470 &mut self,
471 func: &mut ir::Function,
472 index: u32,
473 environ: &mut FuncEnvironment<'_>,
474 ) -> WasmResult<GlobalVariable> {
475 let index = GlobalIndex::from_u32(index);
476 match self.globals.entry(index) {
477 Occupied(entry) => Ok(*entry.get()),
478 Vacant(entry) => Ok(*entry.insert(environ.make_global(func, index)?)),
479 }
480 }
481
482 pub(crate) fn get_heap(
485 &mut self,
486 func: &mut ir::Function,
487 index: u32,
488 environ: &mut FuncEnvironment<'_>,
489 ) -> WasmResult<Heap> {
490 let index = MemoryIndex::from_u32(index);
491 match self.memory_to_heap.entry(index) {
492 Occupied(entry) => Ok(*entry.get()),
493 Vacant(entry) => Ok(*entry.insert(environ.make_heap(func, index)?)),
494 }
495 }
496
497 pub(crate) fn get_indirect_sig(
502 &mut self,
503 func: &mut ir::Function,
504 index: u32,
505 environ: &mut FuncEnvironment<'_>,
506 ) -> WasmResult<(ir::SigRef, usize)> {
507 let index = TypeIndex::from_u32(index);
508 match self.signatures.entry(index) {
509 Occupied(entry) => Ok(*entry.get()),
510 Vacant(entry) => {
511 let sig = environ.make_indirect_sig(func, index)?;
512 Ok(*entry.insert((sig, num_wasm_parameters(environ, &func.dfg.signatures[sig]))))
513 }
514 }
515 }
516
517 pub(crate) fn get_direct_func(
522 &mut self,
523 func: &mut ir::Function,
524 index: u32,
525 environ: &mut FuncEnvironment<'_>,
526 ) -> WasmResult<(ir::FuncRef, usize)> {
527 let index = FuncIndex::from_u32(index);
528 match self.functions.entry(index) {
529 Occupied(entry) => Ok(*entry.get()),
530 Vacant(entry) => {
531 let fref = environ.make_direct_func(func, index)?;
532 let sig = func.dfg.ext_funcs[fref].signature;
533 Ok(*entry.insert((
534 fref,
535 num_wasm_parameters(environ, &func.dfg.signatures[sig]),
536 )))
537 }
538 }
539 }
540}
541
542fn num_wasm_parameters(environ: &FuncEnvironment<'_>, signature: &ir::Signature) -> usize {
543 (0..signature.params.len())
544 .filter(|index| environ.is_wasm_parameter(signature, *index))
545 .count()
546}