Skip to content

Commit c3e513c

Browse files
authored
Fix checker when empty blocks result in unchanged-from-Top entry state. (#113)
The checker works by keeping a worklist of blocks to process, and adds a block to the worklist when its entry state changes. Every entry state is initially `Top` (in a lattice). The entry block is explicitly added to the worklist to kick off the processing. In ordinary cases, the entry block has some instructions that change state from `Top` to something else (lower in the lattice), and this is propagated to its successors; its successors are added to the worklist; and so on. No other state is `Top` from then on (because of monotonicity) so every reachable block is processed. However, if the entry block is completely empty except for the terminating branch, the state remains `Top`; then the entry state of its successors, even when updated, is still `Top`; and the state didn't change so the blocks are not added to the worklist. (Nevermind that they were not processed in the first place!) The bug is that the invariant "has been processed already with current state" is not true initially, when the current state is set to `Top` but nothing has been processed. This PR makes a simple fix: it adds every block to the worklist initially to be processed, in input order (which is usually RPO order in practice) as a good first heuristic; then if after processing the input state changes again, it can be reprocessed until fixpoint as always. Fixes bytecodealliance/wasmtime#5791.
1 parent 50b9cf8 commit c3e513c

File tree

1 file changed

+13
-2
lines changed

1 file changed

+13
-2
lines changed

src/checker.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -987,8 +987,19 @@ impl<'a, F: Function> Checker<'a, F> {
987987
let mut queue = Vec::new();
988988
let mut queue_set = FxHashSet::default();
989989

990-
queue.push(self.f.entry_block());
991-
queue_set.insert(self.f.entry_block());
990+
// Put every block in the queue to start with, to ensure
991+
// everything is visited even if the initial state remains
992+
// `Top` after preds update it.
993+
//
994+
// We add blocks in reverse order so that when we process
995+
// back-to-front below, we do our initial pass in input block
996+
// order, which is (usually) RPO order or at least a
997+
// reasonable visit order.
998+
for block in (0..self.f.num_blocks()).rev() {
999+
let block = Block::new(block);
1000+
queue.push(block);
1001+
queue_set.insert(block);
1002+
}
9921003

9931004
while !queue.is_empty() {
9941005
let block = queue.pop().unwrap();

0 commit comments

Comments
 (0)