pub fn new(code: &[Bytecode]) -> Self {
        fn is_back_edge(cur_block: BlockId, target_block: BlockId) -> bool {
            target_block <= cur_block
        }

        let code_len = code.len() as CodeOffset;
        // First go through and collect block ids, i.e., offsets that begin basic blocks.
        // Need to do this first in order to handle backwards edges.
        let mut block_ids = Set::new();
        block_ids.insert(ENTRY_BLOCK_ID);
        for pc in 0..code.len() {
            VMControlFlowGraph::record_block_ids(pc as CodeOffset, code, &mut block_ids);
        }

        // Create basic blocks
        let mut blocks = Map::new();
        let mut entry = 0;
        let mut exit_to_entry = Map::new();
        for pc in 0..code.len() {
            let co_pc = pc as CodeOffset;

            // Create a basic block
            if Self::is_end_of_block(co_pc, code, &block_ids) {
                let exit = co_pc;
                exit_to_entry.insert(exit, entry);
                let successors = Bytecode::get_successors(co_pc, code);
                let bb = BasicBlock { exit, successors };
                blocks.insert(entry, bb);
                entry = co_pc + 1;
            }
        }
        let blocks = blocks;
        assert_eq!(entry, code_len);

        // Determine traversal order
        // build a DAG subgraph (remove the loop back edges)
        let dag: Map<BlockId, Set<BlockId>> = blocks
            .iter()
            .map(|(id, block)| {
                let id = *id;
                let non_loop_continue_successors = block
                    .successors
                    .iter()
                    // remove the loop back edges
                    // this simple check for back edges relies on guarantees from the control flow
                    // verifier (control_flow.rs)
                    .filter(|successor| !is_back_edge(id, **successor))
                    .copied()
                    .collect();
                (id, non_loop_continue_successors)
            })
            .collect();
        // assert it is a dag
        debug_assert!(dag.iter().all(|(id, successors)| successors
            .iter()
            .all(|successor| !is_back_edge(*id, *successor))));

        // build the post-order traversal
        let mut post_order = Vec::with_capacity(blocks.len());
        let mut finished = Set::new();
        let mut stack = vec![(ENTRY_BLOCK_ID, /* is_first_visit */ true)];
        while let Some((cur, is_first_visit)) = stack.pop() {
            if is_first_visit {
                stack.push((cur, false));
                stack.extend(
                    dag[&cur]
                        .iter()
                        .filter(|successor| !finished.contains(*successor))
                        .map(|successor| (*successor, /* is_first_visit */ true)),
                );
            } else {
                debug_assert!(dag[&cur]
                    .iter()
                    .all(|successor| finished.contains(successor)));
                if finished.insert(cur) {
                    post_order.push(cur)
                }
            }
        }
        // traversal order is the reverse post-order
        let traversal_order = {
            post_order.reverse();
            post_order
        };
        // build a mapping from a block id to the next block id in the traversal order
        let traversal_successors = traversal_order
            .windows(2)
            .map(|window| {
                debug_assert!(window.len() == 2);
                (window[0], window[1])
            })
            .collect();

        // Gather loop head information
        let mut loop_heads: Map<BlockId, Set<BlockId>> = Map::new();
        for (id, block) in &blocks {
            for successor in &block.successors {
                // this simple check for back edges relies on guarantees from the control flow
                // verifier (control_flow.rs)
                if is_back_edge(*id, *successor) {
                    loop_heads.entry(*successor).or_default().insert(*id);
                }
            }
        }

        VMControlFlowGraph {
            blocks,
            traversal_successors,
            loop_heads,
        }
    }
// Requires checks from the control flow verifier (control_flow.rs)
Requires checks from the control flow verifier (control_flow.rs)
Requires checks from the control flow verifier ( control_flow . rs )
pub fn new(code: &[Bytecode]) -> Self {
        fn is_back_edge(cur_block: BlockId, target_block: BlockId) -> bool {
            target_block <= cur_block
        }
        let code_len = code.len() as CodeOffset;
        // First go through and collect block ids, i.e., offsets that begin basic blocks.
        // Need to do this first in order to handle backwards edges.
        let mut block_ids = Set::new();
        block_ids.insert(ENTRY_BLOCK_ID);
        for pc in 0..code.len() {
            VMControlFlowGraph::record_block_ids(pc as CodeOffset, code, &mut block_ids);
        }
        // Create basic blocks
        let mut blocks = Map::new();
        let mut entry = 0;
        let mut exit_to_entry = Map::new();
        for pc in 0..code.len() {
            let co_pc = pc as CodeOffset;
            // Create a basic block
            if Self::is_end_of_block(co_pc, code, &block_ids) {
                let exit = co_pc;
                exit_to_entry.insert(exit, entry);
                let successors = Bytecode::get_successors(co_pc, code);
                let bb = BasicBlock { exit, successors };
                blocks.insert(entry, bb);
                entry = co_pc + 1;
            }
        }
        let blocks = blocks;
        assert_eq!(entry, code_len);
        // Determine traversal order
        // build a DAG subgraph (remove the loop back edges)
        let dag: Map<BlockId, Set<BlockId>> = blocks
            .iter()
            .map(|(id, block)| {
                let id = *id;
                let non_loop_continue_successors = block
                    .successors
                    .iter()
                    // remove the loop back edges
                    // this simple check for back edges relies on guarantees from the control flow
                    // verifier (control_flow.rs)
                    .filter(|successor| !is_back_edge(id, **successor))
                    .copied()
                    .collect();
                (id, non_loop_continue_successors)
            })
            .collect();
        // assert it is a dag
        debug_assert!(dag.iter().all(|(id, successors)| successors
            .iter()
            .all(|successor| !is_back_edge(*id, *successor))));
        // build the post-order traversal
        let mut post_order = Vec::with_capacity(blocks.len());
        let mut finished = Set::new();
        let mut stack = vec![(ENTRY_BLOCK_ID, /* is_first_visit */ true)];
        while let Some((cur, is_first_visit)) = stack.pop() {
            if is_first_visit {
                stack.push((cur, false));
                stack.extend(
                    dag[&cur]
                        .iter()
                        .filter(|successor| !finished.contains(*successor))
                        .map(|successor| (*successor, /* is_first_visit */ true)),
                );
            } else {
                debug_assert!(dag[&cur]
                    .iter()
                    .all(|successor| finished.contains(successor)));
                if finished.insert(cur) {
                    post_order.push(cur)
                }
            }
        }
        // traversal order is the reverse post-order
        let traversal_order = {
            post_order.reverse();
            post_order
        };
        // build a mapping from a block id to the next block id in the traversal order
        let traversal_successors = traversal_order
            .windows(2)
            .map(|window| {
                debug_assert!(window.len() == 2);
                (window[0], window[1])
            })
            .collect();
        // Gather loop head information
        let mut loop_heads: Map<BlockId, Set<BlockId>> = Map::new();
        for (id, block) in &blocks {
            for successor in &block.successors {
                // this simple check for back edges relies on guarantees from the control flow
                // verifier (control_flow.rs)
                if is_back_edge(*id, *successor) {
                    loop_heads.entry(*successor).or_default().insert(*id);
                }
            }
        }
        VMControlFlowGraph {
            blocks,
            traversal_successors,
            loop_heads,
        }
    }
pub fn new ( code : & [ Bytecode ] ) -> Self { fn is_back_edge ( cur_block : BlockId , target_block : BlockId ) -> bool { target_block <= cur_block } let code_len = code . len ( ) as CodeOffset ; // First go through and collect block ids, i.e., offsets that begin basic blocks. // Need to do this first in order to handle backwards edges. let mut block_ids = Set :: new ( ) ; block_ids . insert ( ENTRY_BLOCK_ID ) ; for pc in 0 .. code . len ( ) { VMControlFlowGraph :: record_block_ids ( pc as CodeOffset , code , & mut block_ids ) ; } // Create basic blocks let mut blocks = Map :: new ( ) ; let mut entry = 0 ; let mut exit_to_entry = Map :: new ( ) ; for pc in 0 .. code . len ( ) { let co_pc = pc as CodeOffset ; // Create a basic block if Self :: is_end_of_block ( co_pc , code , & block_ids ) { let exit = co_pc ; exit_to_entry . insert ( exit , entry ) ; let successors = Bytecode :: get_successors ( co_pc , code ) ; let bb = BasicBlock { exit , successors } ; blocks . insert ( entry , bb ) ; entry = co_pc + 1 ; } } let blocks = blocks ; assert_eq ! ( entry code_len ) ; // Determine traversal order // build a DAG subgraph (remove the loop back edges) let dag : Map < BlockId , Set < BlockId > > = blocks . iter ( ) . map ( | ( id , block ) | { let id = * id ; let non_loop_continue_successors = block . successors . iter ( ) // remove the loop back edges // this simple check for back edges relies on guarantees from the control flow // verifier (control_flow.rs) . filter ( | successor | ! is_back_edge ( id , * * successor ) ) . copied ( ) . collect ( ) ; ( id , non_loop_continue_successors ) } ) . collect ( ) ; // assert it is a dag debug_assert ! ( dag iter ( ) all ( ( id successors ) successors iter ( ) all ( successor is_back_edge ( id successor ) ) ) ) ; // build the post-order traversal let mut post_order = Vec :: with_capacity ( blocks . len ( ) ) ; let mut finished = Set :: new ( ) ; let mut stack = vec ! [ ( ENTRY_BLOCK_ID /* is_first_visit */ true ) ] ; while let Some ( ( cur , is_first_visit ) ) = stack . pop ( ) { if is_first_visit { stack . push ( ( cur , false ) ) ; stack . extend ( dag [ & cur ] . iter ( ) . filter ( | successor | ! finished . contains ( * successor ) ) . map ( | successor | ( * successor , /* is_first_visit */ true ) ) , ) ; } else { debug_assert ! ( dag [ cur ] iter ( ) all ( successor finished contains ( successor ) ) ) ; if finished . insert ( cur ) { post_order . push ( cur ) } } } // traversal order is the reverse post-order let traversal_order = { post_order . reverse ( ) ; post_order } ; // build a mapping from a block id to the next block id in the traversal order let traversal_successors = traversal_order . windows ( 2 ) . map ( | window | { debug_assert ! ( window len ( ) 2 ) ; ( window [ 0 ] , window [ 1 ] ) } ) . collect ( ) ; // Gather loop head information let mut loop_heads : Map < BlockId , Set < BlockId > > = Map :: new ( ) ; for ( id , block ) in & blocks { for successor in & block . successors { // this simple check for back edges relies on guarantees from the control flow // verifier (control_flow.rs) if is_back_edge ( * id , * successor ) { loop_heads . entry ( * successor ) . or_default ( ) . insert ( * id ) ; } } } VMControlFlowGraph { blocks , traversal_successors , loop_heads , } }
Requires checks from the control flow verifier (control_flow.rs)
Requires checks from the control flow verifier ( control_flow . rs )
code
&[Bytecode]