rustc_symbol_mangling/
hashed.rs

1use std::fmt::Write;
2
3use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
4use rustc_hir::def_id::CrateNum;
5use rustc_middle::ty::{Instance, TyCtxt};
6
7use crate::v0;
8
9pub(super) fn mangle<'tcx>(
10    tcx: TyCtxt<'tcx>,
11    instance: Instance<'tcx>,
12    instantiating_crate: Option<CrateNum>,
13    full_mangling_name: impl FnOnce() -> String,
14) -> String {
15    // The symbol of a generic function may be scattered in multiple downstream dylibs.
16    // If the symbol of a generic function still contains `crate name`, hash conflicts between the
17    // generic function and other symbols of the same `crate` cannot be detected in time during
18    // construction. This symbol conflict is left over until it occurs during run time.
19    // In this case, `instantiating-crate name` is used to replace `crate name` can completely
20    // eliminate the risk of the preceding potential hash conflict.
21    let crate_num =
22        if let Some(krate) = instantiating_crate { krate } else { instance.def_id().krate };
23
24    let mut symbol = "_RNxC".to_string();
25    v0::push_ident(tcx.crate_name(crate_num).as_str(), &mut symbol);
26
27    let hash = tcx.with_stable_hashing_context(|mut hcx| {
28        let mut hasher = StableHasher::new();
29        full_mangling_name().hash_stable(&mut hcx, &mut hasher);
30        hasher.finish::<Hash64>().as_u64()
31    });
32
33    push_hash64(hash, &mut symbol);
34
35    symbol
36}
37
38// The hash is encoded based on `base-62` and the final terminator `_` is removed because it does
39// not help prevent hash collisions
40fn push_hash64(hash: u64, output: &mut String) {
41    let hash = v0::encode_integer_62(hash);
42    let hash_len = hash.len();
43    let _ = write!(output, "{hash_len}H{}", &hash[..hash_len - 1]);
44}