@aptre/v86 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/LICENSE.MIT +22 -0
- package/Readme.md +237 -0
- package/dist/v86.browser.js +26666 -0
- package/dist/v86.browser.js.map +7 -0
- package/dist/v86.js +26632 -0
- package/dist/v86.js.map +7 -0
- package/gen/generate_analyzer.ts +512 -0
- package/gen/generate_interpreter.ts +522 -0
- package/gen/generate_jit.ts +624 -0
- package/gen/rust_ast.ts +107 -0
- package/gen/util.ts +35 -0
- package/gen/x86_table.ts +1836 -0
- package/lib/9p.ts +1547 -0
- package/lib/filesystem.ts +1879 -0
- package/lib/marshall.ts +168 -0
- package/lib/softfloat/softfloat.c +32501 -0
- package/lib/zstd/zstddeclib.c +13520 -0
- package/package.json +75 -0
- package/src/acpi.ts +267 -0
- package/src/browser/dummy_screen.ts +106 -0
- package/src/browser/fake_network.ts +1771 -0
- package/src/browser/fetch_network.ts +361 -0
- package/src/browser/filestorage.ts +124 -0
- package/src/browser/inbrowser_network.ts +57 -0
- package/src/browser/keyboard.ts +564 -0
- package/src/browser/main.ts +3415 -0
- package/src/browser/mouse.ts +255 -0
- package/src/browser/network.ts +142 -0
- package/src/browser/print_stats.ts +336 -0
- package/src/browser/screen.ts +978 -0
- package/src/browser/serial.ts +316 -0
- package/src/browser/speaker.ts +1223 -0
- package/src/browser/starter.ts +1688 -0
- package/src/browser/wisp_network.ts +332 -0
- package/src/browser/worker_bus.ts +64 -0
- package/src/buffer.ts +652 -0
- package/src/bus.ts +78 -0
- package/src/const.ts +128 -0
- package/src/cpu.ts +2891 -0
- package/src/dma.ts +474 -0
- package/src/elf.ts +251 -0
- package/src/floppy.ts +1778 -0
- package/src/ide.ts +3455 -0
- package/src/io.ts +504 -0
- package/src/iso9660.ts +317 -0
- package/src/kernel.ts +250 -0
- package/src/lib.ts +645 -0
- package/src/log.ts +149 -0
- package/src/main.ts +199 -0
- package/src/ne2k.ts +1589 -0
- package/src/pci.ts +815 -0
- package/src/pit.ts +406 -0
- package/src/ps2.ts +820 -0
- package/src/rtc.ts +537 -0
- package/src/rust/analysis.rs +101 -0
- package/src/rust/codegen.rs +2660 -0
- package/src/rust/config.rs +3 -0
- package/src/rust/control_flow.rs +425 -0
- package/src/rust/cpu/apic.rs +658 -0
- package/src/rust/cpu/arith.rs +1207 -0
- package/src/rust/cpu/call_indirect.rs +2 -0
- package/src/rust/cpu/cpu.rs +4501 -0
- package/src/rust/cpu/fpu.rs +923 -0
- package/src/rust/cpu/global_pointers.rs +112 -0
- package/src/rust/cpu/instructions.rs +2486 -0
- package/src/rust/cpu/instructions_0f.rs +5261 -0
- package/src/rust/cpu/ioapic.rs +316 -0
- package/src/rust/cpu/memory.rs +351 -0
- package/src/rust/cpu/misc_instr.rs +613 -0
- package/src/rust/cpu/mod.rs +16 -0
- package/src/rust/cpu/modrm.rs +133 -0
- package/src/rust/cpu/pic.rs +402 -0
- package/src/rust/cpu/sse_instr.rs +361 -0
- package/src/rust/cpu/string.rs +701 -0
- package/src/rust/cpu/vga.rs +175 -0
- package/src/rust/cpu_context.rs +69 -0
- package/src/rust/dbg.rs +98 -0
- package/src/rust/gen/analyzer.rs +3807 -0
- package/src/rust/gen/analyzer0f.rs +3992 -0
- package/src/rust/gen/interpreter.rs +4447 -0
- package/src/rust/gen/interpreter0f.rs +5404 -0
- package/src/rust/gen/jit.rs +5080 -0
- package/src/rust/gen/jit0f.rs +5547 -0
- package/src/rust/gen/mod.rs +14 -0
- package/src/rust/jit.rs +2443 -0
- package/src/rust/jit_instructions.rs +7881 -0
- package/src/rust/js_api.rs +6 -0
- package/src/rust/leb.rs +46 -0
- package/src/rust/lib.rs +29 -0
- package/src/rust/modrm.rs +330 -0
- package/src/rust/opstats.rs +249 -0
- package/src/rust/page.rs +15 -0
- package/src/rust/paging.rs +25 -0
- package/src/rust/prefix.rs +15 -0
- package/src/rust/profiler.rs +155 -0
- package/src/rust/regs.rs +38 -0
- package/src/rust/softfloat.rs +286 -0
- package/src/rust/state_flags.rs +27 -0
- package/src/rust/wasmgen/mod.rs +2 -0
- package/src/rust/wasmgen/wasm_builder.rs +1047 -0
- package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
- package/src/rust/zstd.rs +105 -0
- package/src/sb16.ts +1928 -0
- package/src/state.ts +359 -0
- package/src/uart.ts +472 -0
- package/src/vga.ts +2791 -0
- package/src/virtio.ts +1756 -0
- package/src/virtio_balloon.ts +273 -0
- package/src/virtio_console.ts +372 -0
- package/src/virtio_net.ts +326 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
use std::collections::HashSet;
|
|
2
|
+
use std::collections::{BTreeMap, BTreeSet};
|
|
3
|
+
use std::iter;
|
|
4
|
+
|
|
5
|
+
use crate::jit::{BasicBlock, BasicBlockType, MAX_EXTRA_BASIC_BLOCKS};
|
|
6
|
+
use crate::profiler;
|
|
7
|
+
|
|
8
|
+
const ENTRY_NODE_ID: u32 = 0xffff_ffff;
|
|
9
|
+
|
|
10
|
+
// this code works fine with either BTree or Hash Maps/Sets
|
|
11
|
+
// - HashMap / HashSet: slightly faster
|
|
12
|
+
// - BTreeMap / BTreeSet: stable iteration order (graphs don't change between rust versions, required for expect tests)
|
|
13
|
+
type Set = BTreeSet<u32>;
|
|
14
|
+
type Graph = BTreeMap<u32, Set>;
|
|
15
|
+
|
|
16
|
+
/// Reverse the direction of all edges in the graph
|
|
17
|
+
fn rev_graph_edges(nodes: &Graph) -> Graph {
|
|
18
|
+
let mut rev_nodes = Graph::new();
|
|
19
|
+
for (from, tos) in nodes {
|
|
20
|
+
for to in tos {
|
|
21
|
+
rev_nodes
|
|
22
|
+
.entry(*to)
|
|
23
|
+
.or_insert_with(|| Set::new())
|
|
24
|
+
.insert(*from);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
rev_nodes
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
pub fn make_graph(basic_blocks: &Vec<BasicBlock>) -> Graph {
|
|
31
|
+
let mut nodes = Graph::new();
|
|
32
|
+
let mut entry_edges = Set::new();
|
|
33
|
+
|
|
34
|
+
for b in basic_blocks.iter() {
|
|
35
|
+
let mut edges = Set::new();
|
|
36
|
+
|
|
37
|
+
match &b.ty {
|
|
38
|
+
&BasicBlockType::ConditionalJump {
|
|
39
|
+
next_block_addr,
|
|
40
|
+
next_block_branch_taken_addr,
|
|
41
|
+
..
|
|
42
|
+
} => {
|
|
43
|
+
if let Some(next_block_addr) = next_block_addr {
|
|
44
|
+
edges.insert(next_block_addr);
|
|
45
|
+
}
|
|
46
|
+
if let Some(next_block_branch_taken_addr) = next_block_branch_taken_addr {
|
|
47
|
+
edges.insert(next_block_branch_taken_addr);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
&BasicBlockType::Normal {
|
|
51
|
+
next_block_addr: Some(next_block_addr),
|
|
52
|
+
..
|
|
53
|
+
} => {
|
|
54
|
+
edges.insert(next_block_addr);
|
|
55
|
+
},
|
|
56
|
+
&BasicBlockType::Normal {
|
|
57
|
+
next_block_addr: None,
|
|
58
|
+
..
|
|
59
|
+
} => {},
|
|
60
|
+
BasicBlockType::Exit => {},
|
|
61
|
+
BasicBlockType::AbsoluteEip => {
|
|
62
|
+
// Not necessary: We generate a loop around the outer brtable unconditionally
|
|
63
|
+
//edges.insert(ENTRY_NODE_ID);
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
nodes.insert(b.addr, edges);
|
|
68
|
+
|
|
69
|
+
if b.is_entry_block {
|
|
70
|
+
entry_edges.insert(b.addr);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Entry node that represents the initial basic block of the generated function (must be
|
|
75
|
+
// able to reach all entry nodes)
|
|
76
|
+
nodes.insert(ENTRY_NODE_ID, entry_edges);
|
|
77
|
+
return nodes;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pub enum WasmStructure {
|
|
81
|
+
BasicBlock(u32),
|
|
82
|
+
Dispatcher(Vec<u32>),
|
|
83
|
+
Loop(Vec<WasmStructure>),
|
|
84
|
+
Block(Vec<WasmStructure>),
|
|
85
|
+
}
|
|
86
|
+
impl WasmStructure {
|
|
87
|
+
pub fn print(&self, depth: usize) {
|
|
88
|
+
match self {
|
|
89
|
+
Self::BasicBlock(addr) => {
|
|
90
|
+
dbg_log!("{} 0x{:x}", " ".repeat(depth), addr);
|
|
91
|
+
},
|
|
92
|
+
Self::Dispatcher(entries) => {
|
|
93
|
+
dbg_log!("{} Dispatcher entries:", " ".repeat(depth));
|
|
94
|
+
for e in entries {
|
|
95
|
+
dbg_log!("{} {:x}", " ".repeat(depth), e);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
Self::Loop(elements) => {
|
|
99
|
+
dbg_log!("{} loop_void({})", " ".repeat(depth), elements.len());
|
|
100
|
+
for e in elements {
|
|
101
|
+
e.print(depth + 1)
|
|
102
|
+
}
|
|
103
|
+
dbg_log!("{} loop_end({})", " ".repeat(depth), elements.len());
|
|
104
|
+
},
|
|
105
|
+
Self::Block(elements) => {
|
|
106
|
+
dbg_log!("{} block_void({})", " ".repeat(depth), elements.len());
|
|
107
|
+
for e in elements {
|
|
108
|
+
e.print(depth + 1)
|
|
109
|
+
}
|
|
110
|
+
dbg_log!("{} block_end({})", " ".repeat(depth), elements.len());
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
fn branches(&self, edges: &Graph) -> HashSet<u32> {
|
|
116
|
+
fn handle(block: &WasmStructure, edges: &Graph, result: &mut HashSet<u32>) {
|
|
117
|
+
match block {
|
|
118
|
+
WasmStructure::BasicBlock(addr) => result.extend(edges.get(&addr).unwrap()),
|
|
119
|
+
WasmStructure::Dispatcher(entries) => result.extend(entries),
|
|
120
|
+
WasmStructure::Loop(children) | WasmStructure::Block(children) => {
|
|
121
|
+
for c in children.iter() {
|
|
122
|
+
handle(c, edges, result);
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let mut result = HashSet::new();
|
|
129
|
+
handle(self, edges, &mut result);
|
|
130
|
+
result
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
pub fn head(&self) -> Box<dyn iter::Iterator<Item = u32> + '_> {
|
|
134
|
+
match self {
|
|
135
|
+
Self::BasicBlock(addr) => Box::new(iter::once(*addr)),
|
|
136
|
+
Self::Dispatcher(entries) => Box::new(entries.iter().copied()),
|
|
137
|
+
Self::Loop(children) => children.first().unwrap().head(),
|
|
138
|
+
Self::Block(elements) => elements.first().unwrap().head(),
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// Check:
|
|
144
|
+
/// - Dispatcher appears at the beginning of a loop
|
|
145
|
+
/// - No two nested blocks at the end
|
|
146
|
+
/// - No two nested loops at the beginning
|
|
147
|
+
/// - No empty blocks or loops
|
|
148
|
+
/// - The entry node block is not present
|
|
149
|
+
pub fn assert_invariants(blocks: &Vec<WasmStructure>) {
|
|
150
|
+
fn check(node: &WasmStructure, in_tail_block: bool, in_head_loop: bool, is_first: bool) {
|
|
151
|
+
match node {
|
|
152
|
+
WasmStructure::Block(children) => {
|
|
153
|
+
dbg_assert!(!in_tail_block);
|
|
154
|
+
dbg_assert!(!children.is_empty());
|
|
155
|
+
for (i, c) in children.iter().enumerate() {
|
|
156
|
+
let is_first = i == 0;
|
|
157
|
+
let is_last = i == children.len() - 1;
|
|
158
|
+
check(c, is_last, in_head_loop && is_first, is_first);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
WasmStructure::Loop(children) => {
|
|
162
|
+
dbg_assert!(!in_head_loop);
|
|
163
|
+
dbg_assert!(!children.is_empty());
|
|
164
|
+
for (i, c) in children.iter().enumerate() {
|
|
165
|
+
let is_first = i == 0;
|
|
166
|
+
let is_last = i == children.len() - 1;
|
|
167
|
+
check(c, in_tail_block && is_last, is_first, is_first);
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
&WasmStructure::BasicBlock(addr) => {
|
|
171
|
+
dbg_assert!(addr != ENTRY_NODE_ID);
|
|
172
|
+
},
|
|
173
|
+
WasmStructure::Dispatcher(_) => {
|
|
174
|
+
dbg_assert!(is_first);
|
|
175
|
+
//dbg_assert!(in_head_loop); // fails for module dispatcher
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
for (i, b) in blocks.iter().enumerate() {
|
|
181
|
+
check(b, false, false, i == 0);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/// Strongly connected components via Kosaraju's algorithm
|
|
186
|
+
fn scc(edges: &Graph, rev_edges: &Graph) -> Vec<Vec<u32>> {
|
|
187
|
+
fn visit(
|
|
188
|
+
node: u32,
|
|
189
|
+
edges: &Graph,
|
|
190
|
+
rev_edges: &Graph,
|
|
191
|
+
visited: &mut HashSet<u32>,
|
|
192
|
+
l: &mut Vec<u32>,
|
|
193
|
+
) {
|
|
194
|
+
if visited.contains(&node) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
visited.insert(node);
|
|
198
|
+
for &next in edges.get(&node).unwrap() {
|
|
199
|
+
visit(next, edges, rev_edges, visited, l);
|
|
200
|
+
}
|
|
201
|
+
l.push(node);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
let mut l = Vec::new();
|
|
205
|
+
let mut visited = HashSet::new();
|
|
206
|
+
for &node in edges.keys() {
|
|
207
|
+
visit(node, edges, rev_edges, &mut visited, &mut l);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
fn assign(
|
|
211
|
+
node: u32,
|
|
212
|
+
edges: &Graph,
|
|
213
|
+
rev_edges: &Graph,
|
|
214
|
+
assigned: &mut HashSet<u32>,
|
|
215
|
+
group: &mut Vec<u32>,
|
|
216
|
+
) {
|
|
217
|
+
if assigned.contains(&node) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
assigned.insert(node);
|
|
221
|
+
group.push(node);
|
|
222
|
+
if let Some(nexts) = rev_edges.get(&node) {
|
|
223
|
+
for &next in nexts {
|
|
224
|
+
assign(next, edges, rev_edges, assigned, group);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
let mut assigned = HashSet::new();
|
|
229
|
+
let mut assignment = Vec::new();
|
|
230
|
+
for &node in l.iter().rev() {
|
|
231
|
+
let mut group = Vec::new();
|
|
232
|
+
assign(node, edges, rev_edges, &mut assigned, &mut group);
|
|
233
|
+
if !group.is_empty() {
|
|
234
|
+
assignment.push(group);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
assignment
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
pub fn loopify(nodes: &Graph) -> Vec<WasmStructure> {
|
|
242
|
+
let rev_nodes = rev_graph_edges(nodes);
|
|
243
|
+
let groups = scc(nodes, &rev_nodes);
|
|
244
|
+
|
|
245
|
+
return groups
|
|
246
|
+
.iter()
|
|
247
|
+
.flat_map(|group| {
|
|
248
|
+
dbg_assert!(!group.is_empty());
|
|
249
|
+
if group.len() == 1 {
|
|
250
|
+
let addr = group[0];
|
|
251
|
+
if addr == ENTRY_NODE_ID {
|
|
252
|
+
let entries = nodes.get(&ENTRY_NODE_ID).unwrap().iter().copied().collect();
|
|
253
|
+
return vec![WasmStructure::Dispatcher(entries)].into_iter();
|
|
254
|
+
}
|
|
255
|
+
let block = WasmStructure::BasicBlock(addr);
|
|
256
|
+
// self-loops
|
|
257
|
+
if nodes.get(&group[0]).unwrap().contains(&group[0]) {
|
|
258
|
+
return vec![WasmStructure::Loop(vec![block])].into_iter();
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
return vec![block].into_iter();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let entries_to_group: Vec<u32> = group
|
|
266
|
+
.iter()
|
|
267
|
+
.filter(|addr| {
|
|
268
|
+
// reachable from outside of the group
|
|
269
|
+
rev_nodes.get(addr).map_or(false, |x| {
|
|
270
|
+
x.iter().any(|incoming| !group.contains(incoming))
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
.copied()
|
|
274
|
+
.collect();
|
|
275
|
+
|
|
276
|
+
if entries_to_group.len() != 1 {
|
|
277
|
+
//dbg_log!(
|
|
278
|
+
// "Compiling multi-entry loop with {} entries and {} basic blocks",
|
|
279
|
+
// entries_to_group.len(),
|
|
280
|
+
// group.len()
|
|
281
|
+
//);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let max_extra_basic_blocks = unsafe { MAX_EXTRA_BASIC_BLOCKS } as usize;
|
|
285
|
+
|
|
286
|
+
if entries_to_group.len() * group.len() > max_extra_basic_blocks {
|
|
287
|
+
let mut subgroup_edges: Graph = Graph::new();
|
|
288
|
+
for elem in group {
|
|
289
|
+
subgroup_edges.insert(
|
|
290
|
+
*elem,
|
|
291
|
+
nodes
|
|
292
|
+
.get(&elem)
|
|
293
|
+
.unwrap()
|
|
294
|
+
.iter()
|
|
295
|
+
.filter(|dest| {
|
|
296
|
+
// XXX: This might remove forward edges to other loop entries
|
|
297
|
+
// Probably not an issue since it can go through the
|
|
298
|
+
// dispatcher
|
|
299
|
+
group.contains(dest) && !entries_to_group.contains(dest)
|
|
300
|
+
})
|
|
301
|
+
.copied()
|
|
302
|
+
.collect(),
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
let mut loop_nodes = loopify(&subgroup_edges);
|
|
307
|
+
|
|
308
|
+
if entries_to_group.len() > 1 {
|
|
309
|
+
loop_nodes.insert(0, WasmStructure::Dispatcher(entries_to_group));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return vec![WasmStructure::Loop(loop_nodes)].into_iter();
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
profiler::stat_increment_by(
|
|
316
|
+
profiler::stat::COMPILE_DUPLICATED_BASIC_BLOCK,
|
|
317
|
+
((entries_to_group.len() - 1) * group.len()) as u64,
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
let nodes: Vec<WasmStructure> = entries_to_group
|
|
321
|
+
.iter()
|
|
322
|
+
.map(|&entry| {
|
|
323
|
+
let mut subgroup_edges: Graph = Graph::new();
|
|
324
|
+
for &elem in group {
|
|
325
|
+
subgroup_edges.insert(
|
|
326
|
+
elem,
|
|
327
|
+
nodes
|
|
328
|
+
.get(&elem)
|
|
329
|
+
.unwrap()
|
|
330
|
+
.iter()
|
|
331
|
+
.copied()
|
|
332
|
+
.filter(|dest| group.contains(dest) && *dest != entry)
|
|
333
|
+
.collect(),
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
let loop_nodes = loopify(&subgroup_edges);
|
|
337
|
+
WasmStructure::Loop(loop_nodes)
|
|
338
|
+
})
|
|
339
|
+
.collect();
|
|
340
|
+
|
|
341
|
+
nodes.into_iter()
|
|
342
|
+
}
|
|
343
|
+
})
|
|
344
|
+
.collect();
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
pub fn blockify(blocks: &mut Vec<WasmStructure>, edges: &Graph) {
|
|
348
|
+
let mut cached_branches: Vec<HashSet<u32>> = Vec::new();
|
|
349
|
+
for i in 0..blocks.len() {
|
|
350
|
+
cached_branches.push(blocks[i].branches(edges));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
let mut i = 0;
|
|
354
|
+
while i < blocks.len() {
|
|
355
|
+
match &mut blocks[i] {
|
|
356
|
+
WasmStructure::BasicBlock(_) | WasmStructure::Dispatcher(_) => {},
|
|
357
|
+
WasmStructure::Loop (
|
|
358
|
+
blocks
|
|
359
|
+
)
|
|
360
|
+
// TODO: Might be faster to do this *after* inserting blocks in this block
|
|
361
|
+
| WasmStructure::Block(blocks) => blockify(blocks, edges),
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
let source = {
|
|
365
|
+
let mut source = None;
|
|
366
|
+
for j in 0..i {
|
|
367
|
+
if blocks[i].head().any(|bb| cached_branches[j].contains(&bb)) {
|
|
368
|
+
source = Some(j);
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
match source {
|
|
373
|
+
Some(s) => s,
|
|
374
|
+
None => {
|
|
375
|
+
i += 1;
|
|
376
|
+
continue;
|
|
377
|
+
},
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// This is optional: Avoid putting a single basic block into a block
|
|
382
|
+
if source == i - 1 {
|
|
383
|
+
match &blocks[source] {
|
|
384
|
+
&WasmStructure::BasicBlock(_) => {
|
|
385
|
+
i += 1;
|
|
386
|
+
continue;
|
|
387
|
+
},
|
|
388
|
+
_ => {},
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
let replacement = WasmStructure::Block(Vec::new());
|
|
393
|
+
let children: Vec<WasmStructure> =
|
|
394
|
+
blocks.splice(source..i, iter::once(replacement)).collect();
|
|
395
|
+
match &mut blocks[source] {
|
|
396
|
+
WasmStructure::Block(c) => c.extend(children),
|
|
397
|
+
_ => {
|
|
398
|
+
dbg_assert!(false);
|
|
399
|
+
},
|
|
400
|
+
}
|
|
401
|
+
match &blocks[source + 1] {
|
|
402
|
+
WasmStructure::BasicBlock(_) =>
|
|
403
|
+
//dbg_assert!(*b == bbs.next().unwrap())
|
|
404
|
+
{},
|
|
405
|
+
WasmStructure::Dispatcher(_) => {},
|
|
406
|
+
WasmStructure::Loop(_blocks) | WasmStructure::Block(_blocks) => {}, //dbg_assert!(blocks[0].head() == bb),
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
{
|
|
410
|
+
let replacement = HashSet::new();
|
|
411
|
+
let children: Vec<HashSet<u32>> = cached_branches
|
|
412
|
+
.splice(source..i, iter::once(replacement))
|
|
413
|
+
.collect();
|
|
414
|
+
dbg_assert!(cached_branches[source].len() == 0);
|
|
415
|
+
let mut iter = children.into_iter();
|
|
416
|
+
cached_branches[source] = iter.next().unwrap();
|
|
417
|
+
for c in iter {
|
|
418
|
+
cached_branches[source].extend(c);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// skip the inserted block and this block
|
|
423
|
+
i = source + 2;
|
|
424
|
+
}
|
|
425
|
+
}
|