You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: global_invariant_instrumentation_v2.rs
    path of file: ./repos/diem/language/move-prover/bytecode/src
    
    the code of the file until where you have to start completion: // Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

// Transformation which injects global invariants into the bytecode.

#[allow(unused_imports)]
use log::{debug, info, log, warn};

use crate::{
    function_data_builder::FunctionDataBuilder,
    function_target::{FunctionData, FunctionTarget},
    function_target_pipeline::{
        FunctionTargetProcessor, FunctionTargetsHolder, FunctionVariant, VerificationFlavor,
    },
    options::ProverOptions,
    stackless_bytecode::{BorrowNode, Bytecode, Operation, PropKind},
    usage_analysis,
    verification_analysis_v2::InvariantAnalysisData,
};

use itertools::Itertools;
#[cfg(invariant_trace)]
use move_model::ty::TypeDisplayContext;
use move_model::{
    ast::{ConditionKind, Exp, GlobalInvariant},
    exp_generator::ExpGenerator,
    model::{FunId, FunctionEnv, GlobalEnv, GlobalId, Loc, QualifiedId, QualifiedInstId, StructId},
    pragmas::CONDITION_ISOLATED_PROP,
    spec_translator::{SpecTranslator, TranslatedSpec},
    ty::{Type, TypeUnificationAdapter, Variance},
};
use std::collections::{BTreeMap, BTreeSet};

const GLOBAL_INVARIANT_FAILS_MESSAGE: &str = "global memory invariant does
    
    fn instrument(&mut self, global_env: &GlobalEnv) {
        // Collect information
        let fun_env = self.builder.fun_env;
        let fun_id = fun_env.get_qualified_id();

        let inv_ana_data = global_env.get_extension::<InvariantAnalysisData>().unwrap();
        let disabled_inv_fun_set = &inv_ana_data.disabled_inv_fun_set;
        let non_inv_fun_set = &inv_ana_data.non_inv_fun_set;
        let target_invariants = &inv_ana_data.target_invariants;
        let disabled_invs_for_fun = &inv_ana_data.disabled_invs_for_fun;

        // Extract and clear current code
        let old_code = std::mem::take(&mut self.builder.data.code);

        // Emit entrypoint assumptions
        let mut entrypoint_invariants = self.filter_entrypoint_invariants(&self.related_invariants);
        if non_inv_fun_set.contains(&fun_id) {
            if let Some(invs_disabled) = disabled_invs_for_fun.get(&fun_id) {
                entrypoint_invariants = entrypoint_invariants
                    .difference(invs_disabled)
                    .cloned()
                    .collect();
            }
        }
        let xlated_spec = self.translate_invariants(&entrypoint_invariants);
        self.assert_or_assume_translated_invariants(
            &xlated_spec.invariants,
            &entrypoint_invariants,
            PropKind::Assume,
        );

        // In addition to the entrypoint invariants assumed just above, it is necessary
        // to assume more invariants in a special case.  When invariants are disabled in
        // this function but not in callers, we will later assert those invariants just
        // before return instructions.
        // We need to assume those invariants at the beginning of the function in order
        // to prove them later. They aren't necessarily entrypoint invariants if we are
        // verifying a function in a strict dependency, or in a friend module that does not
        // have the target module in its dependencies.
        // So, the next code finds the set of target invariants (which will be assumed on return)
        // and assumes those that are not entrypoint invariants.
        if disabled_inv_fun_set.contains(&fun_id) {
            // Separate the update invariants, because we never want to assume them.
            let (global_target_invs, _update_target_invs) =
                self.separate_update_invariants(target_invariants);
            let return_invariants: BTreeSet<_> = global_target_invs
                .difference(&entrypoint_invariants)
                .cloned()
                .collect();
            let xlated_spec = self.translate_invariants(&return_invariants);
            self.assert_or_assume_translated_invariants(
                &xlated_spec.invariants,
                &return_invariants,
                PropKind::Assume,
            );
        }

        // Generate new instrumented code.
        for bc in old_code {
            self.instrument_bytecode(bc, fun_id, &inv_ana_data, &entrypoint_invariants);
        }
    }