Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support TLS access into dylibs on Windows #108089

Merged
merged 4 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions compiler/rustc_codegen_cranelift/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,22 @@ pub(crate) fn codegen_tls_ref<'tcx>(
def_id: DefId,
layout: TyAndLayout<'tcx>,
) -> CValue<'tcx> {
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("tls {:?}", def_id));
}
let tls_ptr = fx.bcx.ins().tls_value(fx.pointer_type, local_data_id);
let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) {
let instance = ty::Instance {
def: ty::InstanceDef::ThreadLocalShim(def_id),
substs: ty::InternalSubsts::empty(),
};
let func_ref = fx.get_function_ref(instance);
let call = fx.bcx.ins().call(func_ref, &[]);
fx.bcx.func.dfg.first_result(call)
} else {
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
if fx.clif_comments.enabled() {
fx.add_comment(local_data_id, format!("tls {:?}", def_id));
}
fx.bcx.ins().tls_value(fx.pointer_type, local_data_id)
};
CValue::by_val(tls_ptr, layout)
}

Expand Down
43 changes: 36 additions & 7 deletions compiler/rustc_codegen_ssa/src/back/symbol_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,29 @@ fn exported_symbols_provider_local(

// FIXME: Sorting this is unnecessary since we are sorting later anyway.
// Can we skip the later sorting?
let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| {
tcx.reachable_non_generics(LOCAL_CRATE)
.to_sorted(&hcx, true)
.into_iter()
.map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
.collect()
let sorted = tcx.with_stable_hashing_context(|hcx| {
tcx.reachable_non_generics(LOCAL_CRATE).to_sorted(&hcx, true)
});

let mut symbols: Vec<_> =
sorted.iter().map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect();

// Export TLS shims
if !tcx.sess.target.dll_tls_export {
symbols.extend(sorted.iter().filter_map(|(&def_id, &info)| {
tcx.needs_thread_local_shim(def_id).then(|| {
(
ExportedSymbol::ThreadLocalShim(def_id),
SymbolExportInfo {
level: info.level,
kind: SymbolExportKind::Text,
used: info.used,
},
)
})
}))
}

if tcx.entry_fn(()).is_some() {
let exported_symbol =
ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref()));
Expand Down Expand Up @@ -380,7 +395,9 @@ fn upstream_monomorphizations_provider(
continue;
}
}
ExportedSymbol::NonGeneric(..) | ExportedSymbol::NoDefId(..) => {
ExportedSymbol::NonGeneric(..)
| ExportedSymbol::ThreadLocalShim(..)
| ExportedSymbol::NoDefId(..) => {
// These are no monomorphizations
continue;
}
Expand Down Expand Up @@ -500,6 +517,16 @@ pub fn symbol_name_for_instance_in_crate<'tcx>(
instantiating_crate,
)
}
ExportedSymbol::ThreadLocalShim(def_id) => {
rustc_symbol_mangling::symbol_name_for_instance_in_crate(
tcx,
ty::Instance {
def: ty::InstanceDef::ThreadLocalShim(def_id),
substs: ty::InternalSubsts::empty(),
},
instantiating_crate,
)
}
ExportedSymbol::DropGlue(ty) => rustc_symbol_mangling::symbol_name_for_instance_in_crate(
tcx,
Instance::resolve_drop_in_place(tcx, ty),
Expand Down Expand Up @@ -548,6 +575,8 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
ExportedSymbol::DropGlue(..) => None,
// NoDefId always follow the target's default symbol decoration scheme.
ExportedSymbol::NoDefId(..) => None,
// ThreadLocalShim always follow the target's default symbol decoration scheme.
ExportedSymbol::ThreadLocalShim(..) => None,
};

let (conv, args) = instance
Expand Down
14 changes: 13 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,8 +516,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

mir::Rvalue::ThreadLocalRef(def_id) => {
assert!(bx.cx().tcx().is_static(def_id));
let static_ = bx.get_static(def_id);
let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id));
let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id)
{
let instance = ty::Instance {
def: ty::InstanceDef::ThreadLocalShim(def_id),
substs: ty::InternalSubsts::empty(),
};
let fn_ptr = bx.get_fn_addr(instance);
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
bx.call(fn_ty, Some(fn_abi), fn_ptr, &[], None)
} else {
bx.get_static(def_id)
};
OperandRef { val: OperandValue::Immediate(static_), layout }
}
mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
| ty::InstanceDef::DropGlue(..)
| ty::InstanceDef::CloneShim(..)
| ty::InstanceDef::FnPtrAddrShim(..)
| ty::InstanceDef::ThreadLocalShim(..)
| ty::InstanceDef::Item(_) => {
// We need MIR for this fn
let Some((body, instance)) =
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/middle/exported_symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub enum ExportedSymbol<'tcx> {
NonGeneric(DefId),
Generic(DefId, SubstsRef<'tcx>),
DropGlue(Ty<'tcx>),
ThreadLocalShim(DefId),
NoDefId(ty::SymbolName<'tcx>),
}

Expand All @@ -58,6 +59,10 @@ impl<'tcx> ExportedSymbol<'tcx> {
ExportedSymbol::DropGlue(ty) => {
tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty))
}
ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance {
def: ty::InstanceDef::ThreadLocalShim(def_id),
substs: ty::InternalSubsts::empty(),
}),
ExportedSymbol::NoDefId(symbol_name) => symbol_name,
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/mir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ impl<'tcx> CodegenUnit<'tcx> {
| InstanceDef::ClosureOnceShim { .. }
| InstanceDef::DropGlue(..)
| InstanceDef::CloneShim(..)
| InstanceDef::ThreadLocalShim(..)
| InstanceDef::FnPtrAddrShim(..) => None,
}
}
Expand Down
12 changes: 1 addition & 11 deletions compiler/rustc_middle/src/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,17 +164,7 @@ impl<'tcx> Rvalue<'tcx> {
Rvalue::Repeat(ref operand, count) => {
tcx.mk_array_with_const_len(operand.ty(local_decls, tcx), count)
}
Rvalue::ThreadLocalRef(did) => {
let static_ty = tcx.type_of(did).subst_identity();
if tcx.is_mutable_static(did) {
tcx.mk_mut_ptr(static_ty)
} else if tcx.is_foreign_item(did) {
tcx.mk_imm_ptr(static_ty)
} else {
// FIXME: These things don't *really* have 'static lifetime.
tcx.mk_imm_ref(tcx.lifetimes.re_static, static_ty)
}
}
Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did),
Rvalue::Ref(reg, bk, ref place) => {
let place_ty = place.ty(local_decls, tcx).ty;
tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() })
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ macro_rules! make_mir_visitor {
ty::InstanceDef::VTableShim(_def_id) |
ty::InstanceDef::ReifyShim(_def_id) |
ty::InstanceDef::Virtual(_def_id, _) |
ty::InstanceDef::ThreadLocalShim(_def_id) |
ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
ty::InstanceDef::DropGlue(_def_id, None) => {}

Expand Down
17 changes: 16 additions & 1 deletion compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ pub enum InstanceDef<'tcx> {
/// The `DefId` is the ID of the `call_once` method in `FnOnce`.
ClosureOnceShim { call_once: DefId, track_caller: bool },

/// Compiler-generated accessor for thread locals which returns a reference to the thread local
/// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking
/// native support.
ThreadLocalShim(DefId),

/// `core::ptr::drop_in_place::<T>`.
///
/// The `DefId` is for `core::ptr::drop_in_place`.
Expand Down Expand Up @@ -156,6 +161,7 @@ impl<'tcx> InstanceDef<'tcx> {
| InstanceDef::FnPtrShim(def_id, _)
| InstanceDef::Virtual(def_id, _)
| InstanceDef::Intrinsic(def_id)
| InstanceDef::ThreadLocalShim(def_id)
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
| InstanceDef::DropGlue(def_id, _)
| InstanceDef::CloneShim(def_id, _)
Expand All @@ -167,7 +173,9 @@ impl<'tcx> InstanceDef<'tcx> {
pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
match self {
ty::InstanceDef::Item(def) => Some(def.did),
ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id),
ty::InstanceDef::DropGlue(def_id, Some(_)) | InstanceDef::ThreadLocalShim(def_id) => {
Some(def_id)
}
InstanceDef::VTableShim(..)
| InstanceDef::ReifyShim(..)
| InstanceDef::FnPtrShim(..)
Expand All @@ -192,6 +200,7 @@ impl<'tcx> InstanceDef<'tcx> {
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
| InstanceDef::DropGlue(def_id, _)
| InstanceDef::CloneShim(def_id, _)
| InstanceDef::ThreadLocalShim(def_id)
| InstanceDef::FnPtrAddrShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
}
}
Expand All @@ -215,6 +224,7 @@ impl<'tcx> InstanceDef<'tcx> {
let def_id = match *self {
ty::InstanceDef::Item(def) => def.did,
ty::InstanceDef::DropGlue(_, Some(_)) => return false,
ty::InstanceDef::ThreadLocalShim(_) => return false,
_ => return true,
};
matches!(
Expand Down Expand Up @@ -255,6 +265,9 @@ impl<'tcx> InstanceDef<'tcx> {
)
});
}
if let ty::InstanceDef::ThreadLocalShim(..) = *self {
return false;
}
tcx.codegen_fn_attrs(self.def_id()).requests_inline()
}

Expand All @@ -278,6 +291,7 @@ impl<'tcx> InstanceDef<'tcx> {
pub fn has_polymorphic_mir_body(&self) -> bool {
match *self {
InstanceDef::CloneShim(..)
| InstanceDef::ThreadLocalShim(..)
| InstanceDef::FnPtrAddrShim(..)
| InstanceDef::FnPtrShim(..)
| InstanceDef::DropGlue(_, Some(_)) => false,
Expand Down Expand Up @@ -310,6 +324,7 @@ fn fmt_instance(
InstanceDef::Item(_) => Ok(()),
InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"),
InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"),
InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num),
InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2386,6 +2386,7 @@ impl<'tcx> TyCtxt<'tcx> {
| ty::InstanceDef::ClosureOnceShim { .. }
| ty::InstanceDef::DropGlue(..)
| ty::InstanceDef::CloneShim(..)
| ty::InstanceDef::ThreadLocalShim(..)
| ty::InstanceDef::FnPtrAddrShim(..) => self.mir_shims(instance),
}
}
Expand Down
22 changes: 22 additions & 0 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,28 @@ impl<'tcx> TyCtxt<'tcx> {
self.static_mutability(def_id) == Some(hir::Mutability::Mut)
}

/// Returns `true` if the item pointed to by `def_id` is a thread local which needs a
/// thread local shim generated.
#[inline]
pub fn needs_thread_local_shim(self, def_id: DefId) -> bool {
!self.sess.target.dll_tls_export
&& self.is_thread_local_static(def_id)
&& !self.is_foreign_item(def_id)
}

/// Returns the type a reference to the thread local takes in MIR.
pub fn thread_local_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
let static_ty = self.type_of(def_id).subst_identity();
if self.is_mutable_static(def_id) {
self.mk_mut_ptr(static_ty)
} else if self.is_foreign_item(def_id) {
self.mk_imm_ptr(static_ty)
} else {
// FIXME: These things don't *really* have 'static lifetime.
self.mk_imm_ref(self.lifetimes.re_static, static_ty)
}
}

/// Get the type of the pointer to the static that we use in MIR.
pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
// Make sure that any constants in the static's type are evaluated.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_transform/src/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ impl<'tcx> Inliner<'tcx> {
| InstanceDef::ClosureOnceShim { .. }
| InstanceDef::DropGlue(..)
| InstanceDef::CloneShim(..)
| InstanceDef::ThreadLocalShim(..)
| InstanceDef::FnPtrAddrShim(..) => return Ok(()),
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_transform/src/inline/cycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
| InstanceDef::ReifyShim(_)
| InstanceDef::FnPtrShim(..)
| InstanceDef::ClosureOnceShim { .. }
| InstanceDef::ThreadLocalShim { .. }
| InstanceDef::CloneShim(..) => {}

// This shim does not call any other functions, thus there can be no recursion.
Expand Down
29 changes: 29 additions & 0 deletions compiler/rustc_mir_transform/src/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'

build_drop_shim(tcx, def_id, ty)
}
ty::InstanceDef::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance),
ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
ty::InstanceDef::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty),
ty::InstanceDef::Virtual(..) => {
Expand Down Expand Up @@ -322,6 +323,34 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
}
}

fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> {
let def_id = instance.def_id();

let span = tcx.def_span(def_id);
let source_info = SourceInfo::outermost(span);

let mut blocks = IndexVec::with_capacity(1);
blocks.push(BasicBlockData {
statements: vec![Statement {
source_info,
kind: StatementKind::Assign(Box::new((
Place::return_place(),
Rvalue::ThreadLocalRef(def_id),
))),
}],
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
is_cleanup: false,
});

new_body(
MirSource::from_instance(instance),
blocks,
IndexVec::from_raw(vec![LocalDecl::new(tcx.thread_local_ptr_ty(def_id), span)]),
0,
span,
)
}

/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
debug!("build_clone_shim(def_id={:?})", def_id);
Expand Down
Loading