mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
8f55c15bfe
There are major questions remaining about the reentrancy that this allows. It doesn't have any users on github outside of a single project that uses it in a panic=abort project to show backtraces. It can still be emulated through #[alloc_error_handler] or set_alloc_error_hook depending on if you use the standard library or not. And finally it makes it harder to do various improvements to the allocator shim.
144 lines
4.3 KiB
Rust
144 lines
4.3 KiB
Rust
#[cfg(feature = "master")]
|
|
use gccjit::FnAttribute;
|
|
use gccjit::{Context, FunctionType, ToRValue, Type};
|
|
use rustc_ast::expand::allocator::{
|
|
AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name,
|
|
};
|
|
use rustc_middle::bug;
|
|
use rustc_middle::ty::TyCtxt;
|
|
use rustc_symbol_mangling::mangle_internal_symbol;
|
|
|
|
use crate::GccContext;
|
|
#[cfg(feature = "master")]
|
|
use crate::base::symbol_visibility_to_gcc;
|
|
|
|
pub(crate) unsafe fn codegen(
|
|
tcx: TyCtxt<'_>,
|
|
mods: &mut GccContext,
|
|
_module_name: &str,
|
|
methods: &[AllocatorMethod],
|
|
) {
|
|
let context = &mods.context;
|
|
let usize = match tcx.sess.target.pointer_width {
|
|
16 => context.new_type::<u16>(),
|
|
32 => context.new_type::<u32>(),
|
|
64 => context.new_type::<u64>(),
|
|
tws => bug!("Unsupported target word size for int: {}", tws),
|
|
};
|
|
let i8 = context.new_type::<i8>();
|
|
let i8p = i8.make_pointer();
|
|
|
|
for method in methods {
|
|
let mut types = Vec::with_capacity(method.inputs.len());
|
|
for input in method.inputs.iter() {
|
|
match input.ty {
|
|
AllocatorTy::Layout => {
|
|
types.push(usize);
|
|
types.push(usize);
|
|
}
|
|
AllocatorTy::Ptr => types.push(i8p),
|
|
AllocatorTy::Usize => types.push(usize),
|
|
|
|
AllocatorTy::Never | AllocatorTy::ResultPtr | AllocatorTy::Unit => {
|
|
panic!("invalid allocator arg")
|
|
}
|
|
}
|
|
}
|
|
let output = match method.output {
|
|
AllocatorTy::ResultPtr => Some(i8p),
|
|
AllocatorTy::Never | AllocatorTy::Unit => None,
|
|
|
|
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
|
|
panic!("invalid allocator output")
|
|
}
|
|
};
|
|
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
|
|
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
|
|
|
|
create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output);
|
|
}
|
|
|
|
create_wrapper_function(
|
|
tcx,
|
|
context,
|
|
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
|
|
None,
|
|
&[],
|
|
None,
|
|
);
|
|
}
|
|
|
|
fn create_wrapper_function(
|
|
tcx: TyCtxt<'_>,
|
|
context: &Context<'_>,
|
|
from_name: &str,
|
|
to_name: Option<&str>,
|
|
types: &[Type<'_>],
|
|
output: Option<Type<'_>>,
|
|
) {
|
|
let void = context.new_type::<()>();
|
|
|
|
let args: Vec<_> = types
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index)))
|
|
.collect();
|
|
let func = context.new_function(
|
|
None,
|
|
FunctionType::Exported,
|
|
output.unwrap_or(void),
|
|
&args,
|
|
from_name,
|
|
false,
|
|
);
|
|
|
|
#[cfg(feature = "master")]
|
|
func.add_attribute(FnAttribute::Visibility(symbol_visibility_to_gcc(
|
|
tcx.sess.default_visibility(),
|
|
)));
|
|
|
|
if tcx.sess.must_emit_unwind_tables() {
|
|
// TODO(antoyo): emit unwind tables.
|
|
}
|
|
|
|
let block = func.new_block("entry");
|
|
|
|
if let Some(to_name) = to_name {
|
|
let args: Vec<_> = types
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index)))
|
|
.collect();
|
|
let callee = context.new_function(
|
|
None,
|
|
FunctionType::Extern,
|
|
output.unwrap_or(void),
|
|
&args,
|
|
to_name,
|
|
false,
|
|
);
|
|
#[cfg(feature = "master")]
|
|
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
|
|
|
let args = args
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(i, _)| func.get_param(i as i32).to_rvalue())
|
|
.collect::<Vec<_>>();
|
|
let ret = context.new_call(None, callee, &args);
|
|
//llvm::LLVMSetTailCall(ret, True);
|
|
if output.is_some() {
|
|
block.end_with_return(None, ret);
|
|
} else {
|
|
block.add_eval(None, ret);
|
|
block.end_with_void_return(None);
|
|
}
|
|
} else {
|
|
assert!(output.is_none());
|
|
block.end_with_void_return(None);
|
|
}
|
|
|
|
// TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
|
|
// as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
|
|
}
|