about summary refs log tree commit diff
path: root/compiler/rustc_symbol_mangling/src
diff options
context:
space:
mode:
authorBryanskiy <ivakin.kir@gmail.com>2024-09-30 21:07:36 +0300
committerBryanskiy <ivakin.kir@gmail.com>2025-05-04 22:03:15 +0300
commit14535312b522c0524dd94633cc6a49992b12cecd (patch)
treef397262aa2e597623ac7dc9a721da0360398808d /compiler/rustc_symbol_mangling/src
parent62c5f58f57670ce65e7fec34f8c4ba00c27da2d9 (diff)
downloadrust-14535312b522c0524dd94633cc6a49992b12cecd.tar.gz
rust-14535312b522c0524dd94633cc6a49992b12cecd.zip
Initial support for dynamically linked crates
Diffstat (limited to 'compiler/rustc_symbol_mangling/src')
-rw-r--r--compiler/rustc_symbol_mangling/src/export.rs181
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs23
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs20
3 files changed, 215 insertions, 9 deletions
diff --git a/compiler/rustc_symbol_mangling/src/export.rs b/compiler/rustc_symbol_mangling/src/export.rs
new file mode 100644
index 00000000000..770401fc8cf
--- /dev/null
+++ b/compiler/rustc_symbol_mangling/src/export.rs
@@ -0,0 +1,181 @@
+use std::assert_matches::debug_assert_matches;
+
+use rustc_abi::IntegerType;
+use rustc_data_structures::stable_hasher::StableHasher;
+use rustc_hashes::Hash128;
+use rustc_hir::def::DefKind;
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_span::symbol::{Symbol, sym};
+
+trait AbiHashStable<'tcx> {
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher);
+}
+macro_rules! default_hash_impl {
+    ($($t:ty,)+) => {
+        $(impl<'tcx> AbiHashStable<'tcx> for $t {
+            #[inline]
+            fn abi_hash(&self, _tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+                ::std::hash::Hash::hash(self, hasher);
+            }
+        })*
+    };
+}
+
+default_hash_impl! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, }
+
+impl<'tcx> AbiHashStable<'tcx> for bool {
+    #[inline]
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+        (if *self { 1u8 } else { 0u8 }).abi_hash(tcx, hasher);
+    }
+}
+
+impl<'tcx> AbiHashStable<'tcx> for str {
+    #[inline]
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+        self.as_bytes().abi_hash(tcx, hasher);
+    }
+}
+
+impl<'tcx> AbiHashStable<'tcx> for String {
+    #[inline]
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+        self[..].abi_hash(tcx, hasher);
+    }
+}
+
+impl<'tcx> AbiHashStable<'tcx> for Symbol {
+    #[inline]
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+        self.as_str().abi_hash(tcx, hasher);
+    }
+}
+
+impl<'tcx, T: AbiHashStable<'tcx>> AbiHashStable<'tcx> for [T] {
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+        self.len().abi_hash(tcx, hasher);
+        for item in self {
+            item.abi_hash(tcx, hasher);
+        }
+    }
+}
+
+impl<'tcx> AbiHashStable<'tcx> for Ty<'tcx> {
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+        match self.kind() {
+            ty::Bool => sym::bool.abi_hash(tcx, hasher),
+            ty::Char => sym::char.abi_hash(tcx, hasher),
+            ty::Int(int_ty) => int_ty.name_str().abi_hash(tcx, hasher),
+            ty::Uint(uint_ty) => uint_ty.name_str().abi_hash(tcx, hasher),
+            ty::Float(float_ty) => float_ty.name_str().abi_hash(tcx, hasher),
+
+            ty::Adt(adt_def, args) => {
+                adt_def.is_struct().abi_hash(tcx, hasher);
+                adt_def.is_enum().abi_hash(tcx, hasher);
+                adt_def.is_union().abi_hash(tcx, hasher);
+
+                if let Some(align) = adt_def.repr().align {
+                    align.bits().abi_hash(tcx, hasher);
+                }
+
+                if let Some(integer) = adt_def.repr().int {
+                    match integer {
+                        IntegerType::Pointer(sign) => sign.abi_hash(tcx, hasher),
+                        IntegerType::Fixed(integer, sign) => {
+                            integer.int_ty_str().abi_hash(tcx, hasher);
+                            sign.abi_hash(tcx, hasher);
+                        }
+                    }
+                }
+
+                if let Some(pack) = adt_def.repr().pack {
+                    pack.bits().abi_hash(tcx, hasher);
+                }
+
+                adt_def.repr().c().abi_hash(tcx, hasher);
+
+                for variant in adt_def.variants() {
+                    variant.name.abi_hash(tcx, hasher);
+                    for field in &variant.fields {
+                        field.name.abi_hash(tcx, hasher);
+                        let field_ty = tcx.type_of(field.did).instantiate_identity();
+                        field_ty.abi_hash(tcx, hasher);
+                    }
+                }
+                args.abi_hash(tcx, hasher);
+            }
+
+            ty::Tuple(args) if args.len() == 0 => {}
+
+            // FIXME: Not yet supported.
+            ty::Foreign(_)
+            | ty::Ref(_, _, _)
+            | ty::Str
+            | ty::Array(_, _)
+            | ty::Pat(_, _)
+            | ty::Slice(_)
+            | ty::RawPtr(_, _)
+            | ty::FnDef(_, _)
+            | ty::FnPtr(_, _)
+            | ty::Dynamic(_, _, _)
+            | ty::Closure(_, _)
+            | ty::CoroutineClosure(_, _)
+            | ty::Coroutine(_, _)
+            | ty::CoroutineWitness(_, _)
+            | ty::Never
+            | ty::Tuple(_)
+            | ty::Alias(_, _)
+            | ty::Param(_)
+            | ty::Bound(_, _)
+            | ty::Placeholder(_)
+            | ty::Infer(_)
+            | ty::UnsafeBinder(_) => unreachable!(),
+
+            ty::Error(_) => {}
+        }
+    }
+}
+
+impl<'tcx> AbiHashStable<'tcx> for ty::FnSig<'tcx> {
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+        for ty in self.inputs_and_output {
+            ty.abi_hash(tcx, hasher);
+        }
+        self.safety.is_safe().abi_hash(tcx, hasher);
+    }
+}
+
+impl<'tcx> AbiHashStable<'tcx> for ty::GenericArg<'tcx> {
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+        self.unpack().abi_hash(tcx, hasher);
+    }
+}
+
+impl<'tcx> AbiHashStable<'tcx> for ty::GenericArgKind<'tcx> {
+    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
+        match self {
+            ty::GenericArgKind::Type(t) => t.abi_hash(tcx, hasher),
+            ty::GenericArgKind::Lifetime(_) | ty::GenericArgKind::Const(_) => unimplemented!(),
+        }
+    }
+}
+
+pub(crate) fn compute_hash_of_export_fn<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+) -> String {
+    let def_id = instance.def_id();
+    debug_assert_matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn);
+
+    let args = instance.args;
+    let sig_ty = tcx.fn_sig(def_id).instantiate(tcx, args);
+    let sig_ty = tcx.instantiate_bound_regions_with_erased(sig_ty);
+
+    let hash = {
+        let mut hasher = StableHasher::new();
+        sig_ty.abi_hash(tcx, &mut hasher);
+        hasher.finish::<Hash128>()
+    };
+
+    hash.as_u128().to_string()
+}
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index ca8918e06aa..a51d7da878a 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -92,6 +92,7 @@
 #![cfg_attr(bootstrap, feature(let_chains))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
+#![feature(assert_matches)]
 #![feature(rustdoc_internals)]
 // tidy-alphabetical-end
 
@@ -104,6 +105,7 @@ use rustc_middle::ty::{self, Instance, TyCtxt};
 use rustc_session::config::SymbolManglingVersion;
 use tracing::debug;
 
+mod export;
 mod hashed;
 mod legacy;
 mod v0;
@@ -296,12 +298,21 @@ fn compute_symbol_name<'tcx>(
         tcx.symbol_mangling_version(mangling_version_crate)
     };
 
-    let symbol = match mangling_version {
-        SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
-        SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate),
-        SymbolManglingVersion::Hashed => hashed::mangle(tcx, instance, instantiating_crate, || {
-            v0::mangle(tcx, instance, instantiating_crate)
-        }),
+    let symbol = match tcx.is_exportable(def_id) {
+        true => format!(
+            "{}.{}",
+            v0::mangle(tcx, instance, instantiating_crate, true),
+            export::compute_hash_of_export_fn(tcx, instance)
+        ),
+        false => match mangling_version {
+            SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
+            SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate, false),
+            SymbolManglingVersion::Hashed => {
+                hashed::mangle(tcx, instance, instantiating_crate, || {
+                    v0::mangle(tcx, instance, instantiating_crate, false)
+                })
+            }
+        },
     };
 
     debug_assert!(
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index f8f2714ee42..ad391d56992 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -26,6 +26,7 @@ pub(super) fn mangle<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance: Instance<'tcx>,
     instantiating_crate: Option<CrateNum>,
+    is_exportable: bool,
 ) -> String {
     let def_id = instance.def_id();
     // FIXME(eddyb) this should ideally not be needed.
@@ -35,6 +36,7 @@ pub(super) fn mangle<'tcx>(
     let mut cx: SymbolMangler<'_> = SymbolMangler {
         tcx,
         start_offset: prefix.len(),
+        is_exportable,
         paths: FxHashMap::default(),
         types: FxHashMap::default(),
         consts: FxHashMap::default(),
@@ -93,6 +95,7 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin
     let mut cx: SymbolMangler<'_> = SymbolMangler {
         tcx,
         start_offset: prefix.len(),
+        is_exportable: false,
         paths: FxHashMap::default(),
         types: FxHashMap::default(),
         consts: FxHashMap::default(),
@@ -135,6 +138,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
     let mut cx = SymbolMangler {
         tcx,
         start_offset: 0,
+        is_exportable: false,
         paths: FxHashMap::default(),
         types: FxHashMap::default(),
         consts: FxHashMap::default(),
@@ -163,6 +167,7 @@ struct SymbolMangler<'tcx> {
     tcx: TyCtxt<'tcx>,
     binders: Vec<BinderLevel>,
     out: String,
+    is_exportable: bool,
 
     /// The length of the prefix in `out` (e.g. 2 for `_R`).
     start_offset: usize,
@@ -376,7 +381,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
                 args,
             )?;
         } else {
-            self.push_disambiguator(key.disambiguated_data.disambiguator as u64);
+            let exported_impl_order = self.tcx.stable_order_of_exportable_impls(impl_def_id.krate);
+            let disambiguator = match self.is_exportable {
+                true => exported_impl_order[&impl_def_id] as u64,
+                false => {
+                    exported_impl_order.len() as u64 + key.disambiguated_data.disambiguator as u64
+                }
+            };
+            self.push_disambiguator(disambiguator);
             self.print_def_path(parent_def_id, &[])?;
         }
 
@@ -818,8 +830,10 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
 
     fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
         self.push("C");
-        let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
-        self.push_disambiguator(stable_crate_id.as_u64());
+        if !self.is_exportable {
+            let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
+            self.push_disambiguator(stable_crate_id.as_u64());
+        }
         let name = self.tcx.crate_name(cnum);
         self.push_ident(name.as_str());
         Ok(())