fn instrument(mut self, pack: &InstrumentationPack) -> FunctionData {
        // extract and clear current code
        let old_code = std::mem::take(&mut self.builder.data.code);

        // pre-translate invariants
        //
        // NOTE: here, we need to save a reference to the `TranslatedSpec` for two special types
        // of instructions, OpaqueCallEnd and Return, in order to handle update invariants.
        //
        // - For an OpaqueCallEnd, we need to find the matching OpaqueCallBegin and emit the state
        //   snapshotting instructions there.
        //
        // - For a Return, we need to emit the state snapshotting instructions at the entry point,
        //   after the entry point assumptions.
        let xlated_entrypoint = self.translate_invariants(&pack.entrypoint_assumptions);
        let xlated_exitpoint = self.translate_invariants(&pack.exitpoint_assertions);

        let mut xlated_inlined = BTreeMap::new();
        let mut xlated_for_opaque_begin = BTreeMap::new();
        let mut xlated_for_opaque_end = BTreeMap::new();
        for (&code_offset, related_invs) in &pack.per_bytecode_assertions {
            let xlated = self.translate_invariants(related_invs);
            xlated_inlined.insert(code_offset, xlated);

            // for OpaqueCallEnd, we need to place assumptions about update invariants at the
            // matching OpaqueCallBegin
            if let Bytecode::Call(_, _, Operation::OpaqueCallEnd(..), ..) =
                old_code.get(code_offset as usize).unwrap()
            {
                for needle in (0..(code_offset.wrapping_sub(1) as usize)).rev() {
                    if matches!(
                        old_code.get(needle).unwrap(),
                        Bytecode::Call(_, _, Operation::OpaqueCallBegin(..), ..)
                    ) {
                        let needle = needle as CodeOffset;
                        xlated_for_opaque_begin.insert(needle, code_offset);
                        xlated_for_opaque_end.insert(code_offset, needle);
                        break;
                    }
                }
            }
        }

        // Step 1: emit entrypoint assumptions
        self.assert_or_assume_translated_invariants(&xlated_entrypoint, PropKind::Assume);

        // Step 2: emit entrypoint snapshots. This can happen if this function defers invariant
        // checking to the return point and one of the suspended invariant is an update invariant.
        self.emit_state_saves_for_update_invs(&xlated_exitpoint);

        // Step 3: go over the bytecode and instrument assertions.
        //         For update invariants, instrument state snapshots before the bytecode.
        for (code_offset, bc) in old_code.into_iter().enumerate() {
            let code_offset = code_offset as CodeOffset;

            // pre-instrumentation for state snapshots
            if let Some(xlated) = xlated_for_opaque_begin
                .get(&code_offset)
                .map(|offset| xlated_inlined.get(offset).unwrap())
            {
                self.emit_state_saves_for_update_invs(xlated);
            }

            if let Some(xlated) = xlated_inlined.get(&code_offset) {
                // skip pre-instrumentation for OpaqueCallEnd, already got them on OpaqueCallBegin
                if !xlated_for_opaque_end.contains_key(&code_offset) {
                    self.emit_state_saves_for_update_invs(xlated);
                }
            }

            // for the return bytecode, the assertion comes before the bytecode
            if matches!(bc, Bytecode::Ret(..)) {
                self.assert_or_assume_translated_invariants(&xlated_exitpoint, PropKind::Assert);
            }

            // the bytecode itself
            self.builder.emit(bc);

            // post-instrumentation for assertions
            if let Some(xlated) = xlated_inlined.get(&code_offset) {
                self.assert_or_assume_translated_invariants(xlated, PropKind::Assert);
            }
        }

        // override the number of ghost type parameters
        self.builder.data.ghost_type_param_count = pack.ghost_type_param_count;

        // Finally, return with the new data accumulated
        self.builder.data
    }
/// The driver function for the overall instrumentation process
The driver function for the overall instrumentation process
The driver function for the overall instrumentation process
fn instrument(mut self, pack: &InstrumentationPack) -> FunctionData {
        // extract and clear current code
        let old_code = std::mem::take(&mut self.builder.data.code);
        // pre-translate invariants
        //
        // NOTE: here, we need to save a reference to the `TranslatedSpec` for two special types
        // of instructions, OpaqueCallEnd and Return, in order to handle update invariants.
        //
        // - For an OpaqueCallEnd, we need to find the matching OpaqueCallBegin and emit the state
        //   snapshotting instructions there.
        //
        // - For a Return, we need to emit the state snapshotting instructions at the entry point,
        //   after the entry point assumptions.
        let xlated_entrypoint = self.translate_invariants(&pack.entrypoint_assumptions);
        let xlated_exitpoint = self.translate_invariants(&pack.exitpoint_assertions);
        let mut xlated_inlined = BTreeMap::new();
        let mut xlated_for_opaque_begin = BTreeMap::new();
        let mut xlated_for_opaque_end = BTreeMap::new();
        for (&code_offset, related_invs) in &pack.per_bytecode_assertions {
            let xlated = self.translate_invariants(related_invs);
            xlated_inlined.insert(code_offset, xlated);
            // for OpaqueCallEnd, we need to place assumptions about update invariants at the
            // matching OpaqueCallBegin
            if let Bytecode::Call(_, _, Operation::OpaqueCallEnd(..), ..) =
                old_code.get(code_offset as usize).unwrap()
            {
                for needle in (0..(code_offset.wrapping_sub(1) as usize)).rev() {
                    if matches!(
                        old_code.get(needle).unwrap(),
                        Bytecode::Call(_, _, Operation::OpaqueCallBegin(..), ..)
                    ) {
                        let needle = needle as CodeOffset;
                        xlated_for_opaque_begin.insert(needle, code_offset);
                        xlated_for_opaque_end.insert(code_offset, needle);
                        break;
                    }
                }
            }
        }
        // Step 1: emit entrypoint assumptions
        self.assert_or_assume_translated_invariants(&xlated_entrypoint, PropKind::Assume);
        // Step 2: emit entrypoint snapshots. This can happen if this function defers invariant
        // checking to the return point and one of the suspended invariant is an update invariant.
        self.emit_state_saves_for_update_invs(&xlated_exitpoint);
        // Step 3: go over the bytecode and instrument assertions.
        //         For update invariants, instrument state snapshots before the bytecode.
        for (code_offset, bc) in old_code.into_iter().enumerate() {
            let code_offset = code_offset as CodeOffset;
            // pre-instrumentation for state snapshots
            if let Some(xlated) = xlated_for_opaque_begin
                .get(&code_offset)
                .map(|offset| xlated_inlined.get(offset).unwrap())
            {
                self.emit_state_saves_for_update_invs(xlated);
            }
            if let Some(xlated) = xlated_inlined.get(&code_offset) {
                // skip pre-instrumentation for OpaqueCallEnd, already got them on OpaqueCallBegin
                if !xlated_for_opaque_end.contains_key(&code_offset) {
                    self.emit_state_saves_for_update_invs(xlated);
                }
            }
            // for the return bytecode, the assertion comes before the bytecode
            if matches!(bc, Bytecode::Ret(..)) {
                self.assert_or_assume_translated_invariants(&xlated_exitpoint, PropKind::Assert);
            }
            // the bytecode itself
            self.builder.emit(bc);
            // post-instrumentation for assertions
            if let Some(xlated) = xlated_inlined.get(&code_offset) {
                self.assert_or_assume_translated_invariants(xlated, PropKind::Assert);
            }
        }
        // override the number of ghost type parameters
        self.builder.data.ghost_type_param_count = pack.ghost_type_param_count;
        // Finally, return with the new data accumulated
        self.builder.data
    }
fn instrument ( mut self , pack : & InstrumentationPack ) -> FunctionData { // extract and clear current code let old_code = std :: mem :: take ( & mut self . builder . data . code ) ; // pre-translate invariants // // NOTE: here, we need to save a reference to the `TranslatedSpec` for two special types // of instructions, OpaqueCallEnd and Return, in order to handle update invariants. // // - For an OpaqueCallEnd, we need to find the matching OpaqueCallBegin and emit the state //   snapshotting instructions there. // // - For a Return, we need to emit the state snapshotting instructions at the entry point, //   after the entry point assumptions. let xlated_entrypoint = self . translate_invariants ( & pack . entrypoint_assumptions ) ; let xlated_exitpoint = self . translate_invariants ( & pack . exitpoint_assertions ) ; let mut xlated_inlined = BTreeMap :: new ( ) ; let mut xlated_for_opaque_begin = BTreeMap :: new ( ) ; let mut xlated_for_opaque_end = BTreeMap :: new ( ) ; for ( & code_offset , related_invs ) in & pack . per_bytecode_assertions { let xlated = self . translate_invariants ( related_invs ) ; xlated_inlined . insert ( code_offset , xlated ) ; // for OpaqueCallEnd, we need to place assumptions about update invariants at the // matching OpaqueCallBegin if let Bytecode :: Call ( _ , _ , Operation :: OpaqueCallEnd ( .. ) , .. ) = old_code . get ( code_offset as usize ) . unwrap ( ) { for needle in ( 0 .. ( code_offset . wrapping_sub ( 1 ) as usize ) ) . rev ( ) { if matches ! ( old_code get ( needle ) unwrap ( ) Bytecode Call ( Operation OpaqueCallBegin ( ) ) ) { let needle = needle as CodeOffset ; xlated_for_opaque_begin . insert ( needle , code_offset ) ; xlated_for_opaque_end . insert ( code_offset , needle ) ; break ; } } } } // Step 1: emit entrypoint assumptions self . assert_or_assume_translated_invariants ( & xlated_entrypoint , PropKind :: Assume ) ; // Step 2: emit entrypoint snapshots. This can happen if this function defers invariant // checking to the return point and one of the suspended invariant is an update invariant. self . emit_state_saves_for_update_invs ( & xlated_exitpoint ) ; // Step 3: go over the bytecode and instrument assertions. //         For update invariants, instrument state snapshots before the bytecode. for ( code_offset , bc ) in old_code . into_iter ( ) . enumerate ( ) { let code_offset = code_offset as CodeOffset ; // pre-instrumentation for state snapshots if let Some ( xlated ) = xlated_for_opaque_begin . get ( & code_offset ) . map ( | offset | xlated_inlined . get ( offset ) . unwrap ( ) ) { self . emit_state_saves_for_update_invs ( xlated ) ; } if let Some ( xlated ) = xlated_inlined . get ( & code_offset ) { // skip pre-instrumentation for OpaqueCallEnd, already got them on OpaqueCallBegin if ! xlated_for_opaque_end . contains_key ( & code_offset ) { self . emit_state_saves_for_update_invs ( xlated ) ; } } // for the return bytecode, the assertion comes before the bytecode if matches ! ( bc Bytecode Ret ( ) ) { self . assert_or_assume_translated_invariants ( & xlated_exitpoint , PropKind :: Assert ) ; } // the bytecode itself self . builder . emit ( bc ) ; // post-instrumentation for assertions if let Some ( xlated ) = xlated_inlined . get ( & code_offset ) { self . assert_or_assume_translated_invariants ( xlated , PropKind :: Assert ) ; } } // override the number of ghost type parameters self . builder . data . ghost_type_param_count = pack . ghost_type_param_count ; // Finally, return with the new data accumulated self . builder . data }
The driver function for the overall instrumentation process
The driver function for the overall instrumentation process
mut self
pack
&InstrumentationPack