fn calltarget_request_rejit_for_module()

in src/profiler/elastic_apm_profiler/src/profiler/mod.rs [1513:1681]


    fn calltarget_request_rejit_for_module(
        &self,
        module_id: ModuleID,
        module_metadata: &ModuleMetadata,
    ) -> Result<usize, HRESULT> {
        let metadata_import = &module_metadata.import;
        let assembly_metadata: AssemblyMetaData =
            module_metadata.assembly_import.get_assembly_metadata()?;

        let mut method_ids = vec![];

        for integration in &module_metadata.integrations {
            let target = match integration.method_replacement.target() {
                Some(t)
                    if t.is_valid_for_assembly(
                        &module_metadata.assembly_name,
                        &assembly_metadata.version,
                    ) =>
                {
                    t
                }
                _ => continue,
            };

            let wrapper = match integration.method_replacement.wrapper() {
                Some(w) if w.action == WrapperMethodAction::CallTargetModification => w,
                _ => continue,
            };

            let type_def = match helpers::find_type_def_by_name(
                target.type_name(),
                &module_metadata.assembly_name,
                &metadata_import,
            ) {
                Some(t) => t,
                None => continue,
            };

            let method_defs =
                metadata_import.enum_methods_with_name(type_def, target.method_name())?;
            let mut rejit_target_found = false;
            for method_def in method_defs {
                let caller: FunctionInfo = match metadata_import.get_function_info(method_def) {
                    Ok(c) => c,
                    Err(e) => {
                        log::warn!(
                            "Could not get function_info for method_def={}, {}",
                            method_def,
                            e
                        );
                        continue;
                    }
                };

                let parsed_signature = match caller.method_signature.try_parse() {
                    Some(p) => p,
                    None => {
                        log::warn!(
                            "The method {} with signature={:?} cannot be parsed",
                            &caller.full_name(),
                            &caller.method_signature.data
                        );
                        continue;
                    }
                };

                let signature_types = match target.signature_types() {
                    Some(s) => s,
                    None => {
                        log::debug!("target does not have arguments defined");
                        continue;
                    }
                };

                if parsed_signature.arg_len as usize != signature_types.len() - 1 {
                    log::debug!(
                        "The caller for method_def {} expected {} arguments while integration has {}",
                        target.method_name(),
                        parsed_signature.arg_len as usize,
                        signature_types.len() - 1
                    );
                    continue;
                }

                log::trace!(
                    "comparing signature for method {}.{}",
                    target.type_name(),
                    target.method_name()
                );
                let mut mismatch = false;
                for arg_idx in 0..parsed_signature.arg_len {
                    let (start_idx, _) = parsed_signature.args[arg_idx as usize];
                    let (argument_type_name, _) = get_sig_type_token_name(
                        &parsed_signature.data[start_idx..],
                        &metadata_import,
                    );

                    let integration_argument_type_name = &signature_types[arg_idx as usize + 1];
                    log::trace!(
                        "-> {} = {}",
                        &argument_type_name,
                        integration_argument_type_name
                    );
                    if &argument_type_name != integration_argument_type_name
                        && integration_argument_type_name != IGNORE
                    {
                        mismatch = true;
                        break;
                    }
                }

                if mismatch {
                    log::debug!(
                        "The caller for method_def {} does not have the right type of arguments",
                        target.method_name()
                    );
                    continue;
                }

                rejit_target_found = true;

                let mut borrow = self.rejit_handler.borrow_mut();
                let rejit_handler: &mut RejitHandler = borrow.as_mut().unwrap();
                let rejit_module = rejit_handler.get_or_add_module(module_id);
                let rejit_method = rejit_module.get_or_add_method(method_def);
                rejit_method.set_function_info(caller);
                rejit_method.set_method_replacement(integration.method_replacement.clone());

                method_ids.push(method_def);

                if log::log_enabled!(Level::Info) {
                    let caller_assembly_is_domain_neutral = IS_DESKTOP_CLR.load(Ordering::SeqCst)
                        && self.cor_lib_module_loaded.load(Ordering::SeqCst)
                        && module_metadata.app_domain_id
                            == self.cor_app_domain_id.load(Ordering::SeqCst);
                    let caller = rejit_method.function_info().unwrap();

                    log::info!(
                        "enqueue for ReJIT module_id={}, method_def={}, app_domain_id={}, \
                        domain_neutral={}, assembly={}, type={}, method={}, signature={:?}",
                        module_id,
                        method_def,
                        module_metadata.app_domain_id,
                        caller_assembly_is_domain_neutral,
                        &module_metadata.assembly_name,
                        caller.type_info.as_ref().map_or("", |t| t.name.as_str()),
                        &caller.name,
                        &caller.signature.bytes()
                    );
                }
            }
            if !rejit_target_found {
                log::error!(
                    "No rejit method found for target: {}.{}",
                    target.type_name(),
                    target.method_name()
                )
            }
        }

        let len = method_ids.len();
        if !method_ids.is_empty() {
            let borrow = self.rejit_handler.borrow();
            let rejit_handler = borrow.as_ref().unwrap();
            rejit_handler.enqueue_for_rejit(vec![module_id; method_ids.len()], method_ids);
        }

        Ok(len)
    }