Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/ir/jumptable.rs
1693 views
1
//! Jump table representation.
2
//!
3
//! Jump tables are declared in the preamble and assigned an `ir::entities::JumpTable` reference.
4
//! The actual table of destinations is stored in a `JumpTableData` struct defined in this module.
5
6
use crate::ir::BlockCall;
7
use crate::ir::instructions::ValueListPool;
8
use alloc::vec::Vec;
9
use core::fmt::{self, Display, Formatter};
10
use core::slice::{Iter, IterMut};
11
12
#[cfg(feature = "enable-serde")]
13
use serde_derive::{Deserialize, Serialize};
14
15
/// Contents of a jump table.
16
///
17
/// All jump tables use 0-based indexing and are densely populated.
18
///
19
/// The default block for the jump table is stored as the first element of the underlying vector.
20
/// It can be accessed through the `default_block` and `default_block_mut` functions. All blocks
21
/// may be iterated using the `all_branches` and `all_branches_mut` functions, which will both
22
/// iterate over the default block first.
23
#[derive(Debug, Clone, PartialEq, Hash)]
24
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
25
pub struct JumpTableData {
26
// Table entries.
27
table: Vec<BlockCall>,
28
}
29
30
impl JumpTableData {
31
/// Create a new jump table with the provided blocks.
32
pub fn new(def: BlockCall, table: &[BlockCall]) -> Self {
33
Self {
34
table: std::iter::once(def).chain(table.iter().copied()).collect(),
35
}
36
}
37
38
/// Fetch the default block for this jump table.
39
pub fn default_block(&self) -> BlockCall {
40
*self.table.first().unwrap()
41
}
42
43
/// Mutable access to the default block of this jump table.
44
pub fn default_block_mut(&mut self) -> &mut BlockCall {
45
self.table.first_mut().unwrap()
46
}
47
48
/// The jump table and default block as a single slice. The default block will always be first.
49
pub fn all_branches(&self) -> &[BlockCall] {
50
self.table.as_slice()
51
}
52
53
/// The jump table and default block as a single mutable slice. The default block will always
54
/// be first.
55
pub fn all_branches_mut(&mut self) -> &mut [BlockCall] {
56
self.table.as_mut_slice()
57
}
58
59
/// Access the jump table as a slice. This excludes the default block.
60
pub fn as_slice(&self) -> &[BlockCall] {
61
&self.table.as_slice()[1..]
62
}
63
64
/// Access the jump table as a mutable slice. This excludes the default block.
65
pub fn as_mut_slice(&mut self) -> &mut [BlockCall] {
66
&mut self.table.as_mut_slice()[1..]
67
}
68
69
/// Returns an iterator to the jump table, excluding the default block.
70
#[deprecated(since = "7.0.0", note = "please use `.as_slice()` instead")]
71
pub fn iter(&self) -> Iter<'_, BlockCall> {
72
self.as_slice().iter()
73
}
74
75
/// Returns an iterator that allows modifying each value, excluding the default block.
76
#[deprecated(since = "7.0.0", note = "please use `.as_mut_slice()` instead")]
77
pub fn iter_mut(&mut self) -> IterMut<'_, BlockCall> {
78
self.as_mut_slice().iter_mut()
79
}
80
81
/// Clears all entries in this jump table, except for the default block.
82
pub fn clear(&mut self) {
83
self.table.drain(1..);
84
}
85
86
/// Return a value that can display the contents of this jump table.
87
pub fn display<'a>(&'a self, pool: &'a ValueListPool) -> DisplayJumpTable<'a> {
88
DisplayJumpTable { jt: self, pool }
89
}
90
}
91
92
/// A wrapper for the context required to display a [JumpTableData].
93
pub struct DisplayJumpTable<'a> {
94
jt: &'a JumpTableData,
95
pool: &'a ValueListPool,
96
}
97
98
impl<'a> Display for DisplayJumpTable<'a> {
99
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
100
write!(fmt, "{}, [", self.jt.default_block().display(self.pool))?;
101
if let Some((first, rest)) = self.jt.as_slice().split_first() {
102
write!(fmt, "{}", first.display(self.pool))?;
103
for block in rest {
104
write!(fmt, ", {}", block.display(self.pool))?;
105
}
106
}
107
write!(fmt, "]")
108
}
109
}
110
111
#[cfg(test)]
112
mod tests {
113
use super::JumpTableData;
114
use crate::entity::EntityRef;
115
use crate::ir::instructions::ValueListPool;
116
use crate::ir::{Block, BlockArg, BlockCall, Value};
117
use alloc::vec::Vec;
118
use std::string::ToString;
119
120
#[test]
121
fn empty() {
122
let mut pool = ValueListPool::default();
123
let def = BlockCall::new(Block::new(0), core::iter::empty(), &mut pool);
124
125
let jt = JumpTableData::new(def, &[]);
126
127
assert_eq!(jt.all_branches().get(0), Some(&def));
128
129
assert_eq!(jt.as_slice().get(0), None);
130
assert_eq!(jt.as_slice().get(10), None);
131
132
assert_eq!(jt.display(&pool).to_string(), "block0, []");
133
134
assert_eq!(jt.all_branches(), [def]);
135
assert_eq!(jt.as_slice(), []);
136
}
137
138
#[test]
139
fn insert() {
140
let mut pool = ValueListPool::default();
141
142
let v0 = Value::new(0);
143
let v1 = Value::new(1);
144
145
let e0 = Block::new(0);
146
let e1 = Block::new(1);
147
let e2 = Block::new(2);
148
149
let def = BlockCall::new(e0, core::iter::empty(), &mut pool);
150
let b1 = BlockCall::new(e1, core::iter::once(v0.into()), &mut pool);
151
let b2 = BlockCall::new(e2, core::iter::empty(), &mut pool);
152
let b3 = BlockCall::new(e1, core::iter::once(v1.into()), &mut pool);
153
154
let jt = JumpTableData::new(def, &[b1, b2, b3]);
155
156
assert_eq!(jt.default_block(), def);
157
assert_eq!(
158
jt.display(&pool).to_string(),
159
"block0, [block1(v0), block2, block1(v1)]"
160
);
161
162
assert_eq!(jt.all_branches(), [def, b1, b2, b3]);
163
assert_eq!(jt.as_slice(), [b1, b2, b3]);
164
165
assert_eq!(
166
jt.as_slice()[0].args(&pool).collect::<Vec<_>>(),
167
[BlockArg::Value(v0)]
168
);
169
assert_eq!(jt.as_slice()[1].args(&pool).collect::<Vec<_>>(), []);
170
assert_eq!(
171
jt.as_slice()[2].args(&pool).collect::<Vec<_>>(),
172
[BlockArg::Value(v1)]
173
);
174
}
175
}
176
177