Skip to content

Commit a2b1646

Browse files
committed
Auto merge of rust-lang#86844 - bjorn3:global_alloc_improvements, r=pnkfelix
Support #[global_allocator] without the allocator shim This makes it possible to use liballoc/libstd in combination with `--emit obj` if you use `#[global_allocator]`. This is what rust-for-linux uses right now and systemd may use in the future. Currently they have to depend on the exact implementation of the allocator shim to create one themself as `--emit obj` doesn't create an allocator shim. Note that currently the allocator shim also defines the oom error handler, which is normally required too. Once `#![feature(default_alloc_error_handler)]` becomes the only option, this can be avoided. In addition when using only fallible allocator methods and either `--cfg no_global_oom_handling` for liballoc (like rust-for-linux) or `--gc-sections` no references to the oom error handler will exist. To avoid this feature being insta-stable, you will have to define `__rust_no_alloc_shim_is_unstable` to avoid linker errors. (Labeling this with both T-compiler and T-lang as it originally involved both an implementation detail and had an insta-stable user facing change. As noted above, the `__rust_no_alloc_shim_is_unstable` symbol requirement should prevent unintended dependence on this unstable feature.)
2 parents cade266 + 33d9b58 commit a2b1646

File tree

19 files changed

+358
-217
lines changed

19 files changed

+358
-217
lines changed

compiler/rustc_ast/src/expand/allocator.rs

+15-7
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
use rustc_span::symbol::{sym, Symbol};
22

3-
#[derive(Clone, Debug, Copy, HashStable_Generic)]
3+
#[derive(Clone, Debug, Copy, Eq, PartialEq, HashStable_Generic)]
44
pub enum AllocatorKind {
55
Global,
66
Default,
77
}
88

9-
impl AllocatorKind {
10-
pub fn fn_name(&self, base: Symbol) -> String {
11-
match *self {
12-
AllocatorKind::Global => format!("__rg_{base}"),
13-
AllocatorKind::Default => format!("__rdl_{base}"),
14-
}
9+
pub fn global_fn_name(base: Symbol) -> String {
10+
format!("__rust_{base}")
11+
}
12+
13+
pub fn default_fn_name(base: Symbol) -> String {
14+
format!("__rdl_{base}")
15+
}
16+
17+
pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'static str {
18+
match alloc_error_handler_kind {
19+
AllocatorKind::Global => "__rg_oom",
20+
AllocatorKind::Default => "__rdl_oom",
1521
}
1622
}
1723

24+
pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable";
25+
1826
pub enum AllocatorTy {
1927
Layout,
2028
Ptr,

compiler/rustc_builtin_macros/src/global_allocator.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::util::check_builtin_macro_attribute;
22

33
use rustc_ast::expand::allocator::{
4-
AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
4+
global_fn_name, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
55
};
66
use rustc_ast::ptr::P;
77
use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
@@ -40,8 +40,7 @@ pub fn expand(
4040

4141
// Generate a bunch of new items using the AllocFnFactory
4242
let span = ecx.with_def_site_ctxt(item.span);
43-
let f =
44-
AllocFnFactory { span, ty_span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
43+
let f = AllocFnFactory { span, ty_span, global: item.ident, cx: ecx };
4544

4645
// Generate item statements for the allocator methods.
4746
let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect();
@@ -63,7 +62,6 @@ pub fn expand(
6362
struct AllocFnFactory<'a, 'b> {
6463
span: Span,
6564
ty_span: Span,
66-
kind: AllocatorKind,
6765
global: Ident,
6866
cx: &'b ExtCtxt<'a>,
6967
}
@@ -92,7 +90,7 @@ impl AllocFnFactory<'_, '_> {
9290
}));
9391
let item = self.cx.item(
9492
self.span,
95-
Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
93+
Ident::from_str_and_span(&global_fn_name(method.name), self.span),
9694
self.attrs(),
9795
kind,
9896
);

compiler/rustc_codegen_cranelift/src/allocator.rs

+45-34
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

44
use crate::prelude::*;
55

6-
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
6+
use rustc_ast::expand::allocator::{
7+
alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
8+
ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
9+
};
710
use rustc_codegen_ssa::base::allocator_kind_for_codegen;
811
use rustc_session::config::OomStrategy;
9-
use rustc_span::symbol::sym;
1012

1113
/// Returns whether an allocator shim was created
1214
pub(crate) fn codegen(
@@ -34,41 +36,43 @@ fn codegen_inner(
3436
) {
3537
let usize_ty = module.target_config().pointer_type();
3638

37-
for method in ALLOCATOR_METHODS {
38-
let mut arg_tys = Vec::with_capacity(method.inputs.len());
39-
for ty in method.inputs.iter() {
40-
match *ty {
41-
AllocatorTy::Layout => {
42-
arg_tys.push(usize_ty); // size
43-
arg_tys.push(usize_ty); // align
44-
}
45-
AllocatorTy::Ptr => arg_tys.push(usize_ty),
46-
AllocatorTy::Usize => arg_tys.push(usize_ty),
39+
if kind == AllocatorKind::Default {
40+
for method in ALLOCATOR_METHODS {
41+
let mut arg_tys = Vec::with_capacity(method.inputs.len());
42+
for ty in method.inputs.iter() {
43+
match *ty {
44+
AllocatorTy::Layout => {
45+
arg_tys.push(usize_ty); // size
46+
arg_tys.push(usize_ty); // align
47+
}
48+
AllocatorTy::Ptr => arg_tys.push(usize_ty),
49+
AllocatorTy::Usize => arg_tys.push(usize_ty),
4750

48-
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
51+
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
52+
}
4953
}
50-
}
51-
let output = match method.output {
52-
AllocatorTy::ResultPtr => Some(usize_ty),
53-
AllocatorTy::Unit => None,
54+
let output = match method.output {
55+
AllocatorTy::ResultPtr => Some(usize_ty),
56+
AllocatorTy::Unit => None,
5457

55-
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
56-
panic!("invalid allocator output")
57-
}
58-
};
58+
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
59+
panic!("invalid allocator output")
60+
}
61+
};
5962

60-
let sig = Signature {
61-
call_conv: module.target_config().default_call_conv,
62-
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
63-
returns: output.into_iter().map(AbiParam::new).collect(),
64-
};
65-
crate::common::create_wrapper_function(
66-
module,
67-
unwind_context,
68-
sig,
69-
&format!("__rust_{}", method.name),
70-
&kind.fn_name(method.name),
71-
);
63+
let sig = Signature {
64+
call_conv: module.target_config().default_call_conv,
65+
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
66+
returns: output.into_iter().map(AbiParam::new).collect(),
67+
};
68+
crate::common::create_wrapper_function(
69+
module,
70+
unwind_context,
71+
sig,
72+
&global_fn_name(method.name),
73+
&default_fn_name(method.name),
74+
);
75+
}
7276
}
7377

7478
let sig = Signature {
@@ -81,7 +85,7 @@ fn codegen_inner(
8185
unwind_context,
8286
sig,
8387
"__rust_alloc_error_handler",
84-
&alloc_error_handler_kind.fn_name(sym::oom),
88+
&alloc_error_handler_name(alloc_error_handler_kind),
8589
);
8690

8791
let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap();
@@ -90,4 +94,11 @@ fn codegen_inner(
9094
let val = oom_strategy.should_panic();
9195
data_ctx.define(Box::new([val]));
9296
module.define_data(data_id, &data_ctx).unwrap();
97+
98+
let data_id =
99+
module.declare_data(NO_ALLOC_SHIM_IS_UNSTABLE, Linkage::Export, false, false).unwrap();
100+
let mut data_ctx = DataContext::new();
101+
data_ctx.set_align(1);
102+
data_ctx.define(Box::new([0]));
103+
module.define_data(data_id, &data_ctx).unwrap();
93104
}
+67-58
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
#[cfg(feature="master")]
22
use gccjit::FnAttribute;
33
use gccjit::{FunctionType, GlobalKind, ToRValue};
4-
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
4+
use rustc_ast::expand::allocator::{
5+
alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
6+
ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
7+
};
58
use rustc_middle::bug;
69
use rustc_middle::ty::TyCtxt;
710
use rustc_session::config::OomStrategy;
8-
use rustc_span::symbol::sym;
911

1012
use crate::GccContext;
1113

@@ -22,69 +24,71 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
2224
let i8p = i8.make_pointer();
2325
let void = context.new_type::<()>();
2426

25-
for method in ALLOCATOR_METHODS {
26-
let mut types = Vec::with_capacity(method.inputs.len());
27-
for ty in method.inputs.iter() {
28-
match *ty {
29-
AllocatorTy::Layout => {
30-
types.push(usize);
31-
types.push(usize);
27+
if kind == AllocatorKind::Default {
28+
for method in ALLOCATOR_METHODS {
29+
let mut types = Vec::with_capacity(method.inputs.len());
30+
for ty in method.inputs.iter() {
31+
match *ty {
32+
AllocatorTy::Layout => {
33+
types.push(usize);
34+
types.push(usize);
35+
}
36+
AllocatorTy::Ptr => types.push(i8p),
37+
AllocatorTy::Usize => types.push(usize),
38+
39+
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
3240
}
33-
AllocatorTy::Ptr => types.push(i8p),
34-
AllocatorTy::Usize => types.push(usize),
35-
36-
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
3741
}
38-
}
39-
let output = match method.output {
40-
AllocatorTy::ResultPtr => Some(i8p),
41-
AllocatorTy::Unit => None,
42+
let output = match method.output {
43+
AllocatorTy::ResultPtr => Some(i8p),
44+
AllocatorTy::Unit => None,
4245

43-
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
44-
panic!("invalid allocator output")
45-
}
46-
};
47-
let name = format!("__rust_{}", method.name);
46+
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
47+
panic!("invalid allocator output")
48+
}
49+
};
50+
let name = global_fn_name(method.name);
4851

49-
let args: Vec<_> = types.iter().enumerate()
50-
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
51-
.collect();
52-
let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false);
52+
let args: Vec<_> = types.iter().enumerate()
53+
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
54+
.collect();
55+
let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false);
5356

54-
if tcx.sess.target.options.default_hidden_visibility {
57+
if tcx.sess.target.options.default_hidden_visibility {
58+
#[cfg(feature="master")]
59+
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
60+
}
61+
if tcx.sess.must_emit_unwind_tables() {
62+
// TODO(antoyo): emit unwind tables.
63+
}
64+
65+
let callee = default_fn_name(method.name);
66+
let args: Vec<_> = types.iter().enumerate()
67+
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
68+
.collect();
69+
let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false);
5570
#[cfg(feature="master")]
56-
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
57-
}
58-
if tcx.sess.must_emit_unwind_tables() {
59-
// TODO(antoyo): emit unwind tables.
60-
}
71+
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
72+
73+
let block = func.new_block("entry");
74+
75+
let args = args
76+
.iter()
77+
.enumerate()
78+
.map(|(i, _)| func.get_param(i as i32).to_rvalue())
79+
.collect::<Vec<_>>();
80+
let ret = context.new_call(None, callee, &args);
81+
//llvm::LLVMSetTailCall(ret, True);
82+
if output.is_some() {
83+
block.end_with_return(None, ret);
84+
}
85+
else {
86+
block.end_with_void_return(None);
87+
}
6188

62-
let callee = kind.fn_name(method.name);
63-
let args: Vec<_> = types.iter().enumerate()
64-
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
65-
.collect();
66-
let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false);
67-
#[cfg(feature="master")]
68-
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
69-
70-
let block = func.new_block("entry");
71-
72-
let args = args
73-
.iter()
74-
.enumerate()
75-
.map(|(i, _)| func.get_param(i as i32).to_rvalue())
76-
.collect::<Vec<_>>();
77-
let ret = context.new_call(None, callee, &args);
78-
//llvm::LLVMSetTailCall(ret, True);
79-
if output.is_some() {
80-
block.end_with_return(None, ret);
81-
}
82-
else {
83-
block.end_with_void_return(None);
89+
// TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
90+
// as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
8491
}
85-
86-
// TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
87-
// as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
8892
}
8993

9094
let types = [usize, usize];
@@ -99,7 +103,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
99103
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
100104
}
101105

102-
let callee = alloc_error_handler_kind.fn_name(sym::oom);
106+
let callee = alloc_error_handler_name(alloc_error_handler_kind);
103107
let args: Vec<_> = types.iter().enumerate()
104108
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
105109
.collect();
@@ -123,4 +127,9 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
123127
let value = tcx.sess.opts.unstable_opts.oom.should_panic();
124128
let value = context.new_rvalue_from_int(i8, value as i32);
125129
global.global_set_initializer_rvalue(value);
130+
131+
let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string();
132+
let global = context.new_global(None, GlobalKind::Exported, i8, name);
133+
let value = context.new_rvalue_from_int(i8, 0);
134+
global.global_set_initializer_rvalue(value);
126135
}

0 commit comments

Comments
 (0)