Auto merge of #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.)
This commit is contained in:
commit
a2b1646c59
@ -1,20 +1,28 @@
|
|||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Copy, HashStable_Generic)]
|
#[derive(Clone, Debug, Copy, Eq, PartialEq, HashStable_Generic)]
|
||||||
pub enum AllocatorKind {
|
pub enum AllocatorKind {
|
||||||
Global,
|
Global,
|
||||||
Default,
|
Default,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AllocatorKind {
|
pub fn global_fn_name(base: Symbol) -> String {
|
||||||
pub fn fn_name(&self, base: Symbol) -> String {
|
format!("__rust_{base}")
|
||||||
match *self {
|
}
|
||||||
AllocatorKind::Global => format!("__rg_{base}"),
|
|
||||||
AllocatorKind::Default => format!("__rdl_{base}"),
|
pub fn default_fn_name(base: Symbol) -> String {
|
||||||
}
|
format!("__rdl_{base}")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'static str {
|
||||||
|
match alloc_error_handler_kind {
|
||||||
|
AllocatorKind::Global => "__rg_oom",
|
||||||
|
AllocatorKind::Default => "__rdl_oom",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable";
|
||||||
|
|
||||||
pub enum AllocatorTy {
|
pub enum AllocatorTy {
|
||||||
Layout,
|
Layout,
|
||||||
Ptr,
|
Ptr,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::util::check_builtin_macro_attribute;
|
use crate::util::check_builtin_macro_attribute;
|
||||||
|
|
||||||
use rustc_ast::expand::allocator::{
|
use rustc_ast::expand::allocator::{
|
||||||
AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
|
global_fn_name, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
|
||||||
};
|
};
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
|
use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
|
||||||
@ -40,8 +40,7 @@ pub fn expand(
|
|||||||
|
|
||||||
// Generate a bunch of new items using the AllocFnFactory
|
// Generate a bunch of new items using the AllocFnFactory
|
||||||
let span = ecx.with_def_site_ctxt(item.span);
|
let span = ecx.with_def_site_ctxt(item.span);
|
||||||
let f =
|
let f = AllocFnFactory { span, ty_span, global: item.ident, cx: ecx };
|
||||||
AllocFnFactory { span, ty_span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
|
|
||||||
|
|
||||||
// Generate item statements for the allocator methods.
|
// Generate item statements for the allocator methods.
|
||||||
let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect();
|
let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect();
|
||||||
@ -63,7 +62,6 @@ pub fn expand(
|
|||||||
struct AllocFnFactory<'a, 'b> {
|
struct AllocFnFactory<'a, 'b> {
|
||||||
span: Span,
|
span: Span,
|
||||||
ty_span: Span,
|
ty_span: Span,
|
||||||
kind: AllocatorKind,
|
|
||||||
global: Ident,
|
global: Ident,
|
||||||
cx: &'b ExtCtxt<'a>,
|
cx: &'b ExtCtxt<'a>,
|
||||||
}
|
}
|
||||||
@ -92,7 +90,7 @@ fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt {
|
|||||||
}));
|
}));
|
||||||
let item = self.cx.item(
|
let item = self.cx.item(
|
||||||
self.span,
|
self.span,
|
||||||
Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
|
Ident::from_str_and_span(&global_fn_name(method.name), self.span),
|
||||||
self.attrs(),
|
self.attrs(),
|
||||||
kind,
|
kind,
|
||||||
);
|
);
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
|
use rustc_ast::expand::allocator::{
|
||||||
|
alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
|
||||||
|
ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||||
|
};
|
||||||
use rustc_codegen_ssa::base::allocator_kind_for_codegen;
|
use rustc_codegen_ssa::base::allocator_kind_for_codegen;
|
||||||
use rustc_session::config::OomStrategy;
|
use rustc_session::config::OomStrategy;
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
|
|
||||||
/// Returns whether an allocator shim was created
|
/// Returns whether an allocator shim was created
|
||||||
pub(crate) fn codegen(
|
pub(crate) fn codegen(
|
||||||
@ -34,41 +36,43 @@ fn codegen_inner(
|
|||||||
) {
|
) {
|
||||||
let usize_ty = module.target_config().pointer_type();
|
let usize_ty = module.target_config().pointer_type();
|
||||||
|
|
||||||
for method in ALLOCATOR_METHODS {
|
if kind == AllocatorKind::Default {
|
||||||
let mut arg_tys = Vec::with_capacity(method.inputs.len());
|
for method in ALLOCATOR_METHODS {
|
||||||
for ty in method.inputs.iter() {
|
let mut arg_tys = Vec::with_capacity(method.inputs.len());
|
||||||
match *ty {
|
for ty in method.inputs.iter() {
|
||||||
AllocatorTy::Layout => {
|
match *ty {
|
||||||
arg_tys.push(usize_ty); // size
|
AllocatorTy::Layout => {
|
||||||
arg_tys.push(usize_ty); // align
|
arg_tys.push(usize_ty); // size
|
||||||
|
arg_tys.push(usize_ty); // align
|
||||||
|
}
|
||||||
|
AllocatorTy::Ptr => arg_tys.push(usize_ty),
|
||||||
|
AllocatorTy::Usize => arg_tys.push(usize_ty),
|
||||||
|
|
||||||
|
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
|
||||||
}
|
}
|
||||||
AllocatorTy::Ptr => arg_tys.push(usize_ty),
|
|
||||||
AllocatorTy::Usize => arg_tys.push(usize_ty),
|
|
||||||
|
|
||||||
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
|
|
||||||
}
|
}
|
||||||
|
let output = match method.output {
|
||||||
|
AllocatorTy::ResultPtr => Some(usize_ty),
|
||||||
|
AllocatorTy::Unit => None,
|
||||||
|
|
||||||
|
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
|
||||||
|
panic!("invalid allocator output")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let sig = Signature {
|
||||||
|
call_conv: module.target_config().default_call_conv,
|
||||||
|
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
|
||||||
|
returns: output.into_iter().map(AbiParam::new).collect(),
|
||||||
|
};
|
||||||
|
crate::common::create_wrapper_function(
|
||||||
|
module,
|
||||||
|
unwind_context,
|
||||||
|
sig,
|
||||||
|
&global_fn_name(method.name),
|
||||||
|
&default_fn_name(method.name),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let output = match method.output {
|
|
||||||
AllocatorTy::ResultPtr => Some(usize_ty),
|
|
||||||
AllocatorTy::Unit => None,
|
|
||||||
|
|
||||||
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
|
|
||||||
panic!("invalid allocator output")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let sig = Signature {
|
|
||||||
call_conv: module.target_config().default_call_conv,
|
|
||||||
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
|
|
||||||
returns: output.into_iter().map(AbiParam::new).collect(),
|
|
||||||
};
|
|
||||||
crate::common::create_wrapper_function(
|
|
||||||
module,
|
|
||||||
unwind_context,
|
|
||||||
sig,
|
|
||||||
&format!("__rust_{}", method.name),
|
|
||||||
&kind.fn_name(method.name),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sig = Signature {
|
let sig = Signature {
|
||||||
@ -81,7 +85,7 @@ fn codegen_inner(
|
|||||||
unwind_context,
|
unwind_context,
|
||||||
sig,
|
sig,
|
||||||
"__rust_alloc_error_handler",
|
"__rust_alloc_error_handler",
|
||||||
&alloc_error_handler_kind.fn_name(sym::oom),
|
&alloc_error_handler_name(alloc_error_handler_kind),
|
||||||
);
|
);
|
||||||
|
|
||||||
let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap();
|
let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap();
|
||||||
@ -90,4 +94,11 @@ fn codegen_inner(
|
|||||||
let val = oom_strategy.should_panic();
|
let val = oom_strategy.should_panic();
|
||||||
data_ctx.define(Box::new([val]));
|
data_ctx.define(Box::new([val]));
|
||||||
module.define_data(data_id, &data_ctx).unwrap();
|
module.define_data(data_id, &data_ctx).unwrap();
|
||||||
|
|
||||||
|
let data_id =
|
||||||
|
module.declare_data(NO_ALLOC_SHIM_IS_UNSTABLE, Linkage::Export, false, false).unwrap();
|
||||||
|
let mut data_ctx = DataContext::new();
|
||||||
|
data_ctx.set_align(1);
|
||||||
|
data_ctx.define(Box::new([0]));
|
||||||
|
module.define_data(data_id, &data_ctx).unwrap();
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
#[cfg(feature="master")]
|
#[cfg(feature="master")]
|
||||||
use gccjit::FnAttribute;
|
use gccjit::FnAttribute;
|
||||||
use gccjit::{FunctionType, GlobalKind, ToRValue};
|
use gccjit::{FunctionType, GlobalKind, ToRValue};
|
||||||
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
|
use rustc_ast::expand::allocator::{
|
||||||
|
alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
|
||||||
|
ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||||
|
};
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::config::OomStrategy;
|
use rustc_session::config::OomStrategy;
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
|
|
||||||
use crate::GccContext;
|
use crate::GccContext;
|
||||||
|
|
||||||
@ -22,69 +24,71 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
|
|||||||
let i8p = i8.make_pointer();
|
let i8p = i8.make_pointer();
|
||||||
let void = context.new_type::<()>();
|
let void = context.new_type::<()>();
|
||||||
|
|
||||||
for method in ALLOCATOR_METHODS {
|
if kind == AllocatorKind::Default {
|
||||||
let mut types = Vec::with_capacity(method.inputs.len());
|
for method in ALLOCATOR_METHODS {
|
||||||
for ty in method.inputs.iter() {
|
let mut types = Vec::with_capacity(method.inputs.len());
|
||||||
match *ty {
|
for ty in method.inputs.iter() {
|
||||||
AllocatorTy::Layout => {
|
match *ty {
|
||||||
types.push(usize);
|
AllocatorTy::Layout => {
|
||||||
types.push(usize);
|
types.push(usize);
|
||||||
|
types.push(usize);
|
||||||
|
}
|
||||||
|
AllocatorTy::Ptr => types.push(i8p),
|
||||||
|
AllocatorTy::Usize => types.push(usize),
|
||||||
|
|
||||||
|
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
|
||||||
}
|
}
|
||||||
AllocatorTy::Ptr => types.push(i8p),
|
|
||||||
AllocatorTy::Usize => types.push(usize),
|
|
||||||
|
|
||||||
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
|
|
||||||
}
|
}
|
||||||
}
|
let output = match method.output {
|
||||||
let output = match method.output {
|
AllocatorTy::ResultPtr => Some(i8p),
|
||||||
AllocatorTy::ResultPtr => Some(i8p),
|
AllocatorTy::Unit => None,
|
||||||
AllocatorTy::Unit => None,
|
|
||||||
|
|
||||||
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
|
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
|
||||||
panic!("invalid allocator output")
|
panic!("invalid allocator output")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let name = global_fn_name(method.name);
|
||||||
|
|
||||||
|
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, name, false);
|
||||||
|
|
||||||
|
if tcx.sess.target.options.default_hidden_visibility {
|
||||||
|
#[cfg(feature="master")]
|
||||||
|
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||||
|
}
|
||||||
|
if tcx.sess.must_emit_unwind_tables() {
|
||||||
|
// TODO(antoyo): emit unwind tables.
|
||||||
}
|
}
|
||||||
};
|
|
||||||
let name = format!("__rust_{}", method.name);
|
|
||||||
|
|
||||||
let args: Vec<_> = types.iter().enumerate()
|
let callee = default_fn_name(method.name);
|
||||||
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
|
let args: Vec<_> = types.iter().enumerate()
|
||||||
.collect();
|
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
|
||||||
let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false);
|
.collect();
|
||||||
|
let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false);
|
||||||
if tcx.sess.target.options.default_hidden_visibility {
|
|
||||||
#[cfg(feature="master")]
|
#[cfg(feature="master")]
|
||||||
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||||
}
|
|
||||||
if tcx.sess.must_emit_unwind_tables() {
|
|
||||||
// TODO(antoyo): emit unwind tables.
|
|
||||||
}
|
|
||||||
|
|
||||||
let callee = kind.fn_name(method.name);
|
let block = func.new_block("entry");
|
||||||
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, callee, false);
|
|
||||||
#[cfg(feature="master")]
|
|
||||||
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
|
||||||
|
|
||||||
let block = func.new_block("entry");
|
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.end_with_void_return(None);
|
||||||
|
}
|
||||||
|
|
||||||
let args = args
|
// TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
|
||||||
.iter()
|
// as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
|
||||||
.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.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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let types = [usize, usize];
|
let types = [usize, usize];
|
||||||
@ -99,7 +103,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
|
|||||||
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||||
}
|
}
|
||||||
|
|
||||||
let callee = alloc_error_handler_kind.fn_name(sym::oom);
|
let callee = alloc_error_handler_name(alloc_error_handler_kind);
|
||||||
let args: Vec<_> = types.iter().enumerate()
|
let args: Vec<_> = types.iter().enumerate()
|
||||||
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
|
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
|
||||||
.collect();
|
.collect();
|
||||||
@ -123,4 +127,9 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
|
|||||||
let value = tcx.sess.opts.unstable_opts.oom.should_panic();
|
let value = tcx.sess.opts.unstable_opts.oom.should_panic();
|
||||||
let value = context.new_rvalue_from_int(i8, value as i32);
|
let value = context.new_rvalue_from_int(i8, value as i32);
|
||||||
global.global_set_initializer_rvalue(value);
|
global.global_set_initializer_rvalue(value);
|
||||||
|
|
||||||
|
let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string();
|
||||||
|
let global = context.new_global(None, GlobalKind::Exported, i8, name);
|
||||||
|
let value = context.new_rvalue_from_int(i8, 0);
|
||||||
|
global.global_set_initializer_rvalue(value);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use crate::attributes;
|
use crate::attributes;
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
|
use rustc_ast::expand::allocator::{
|
||||||
|
alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
|
||||||
|
ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||||
|
};
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::config::{DebugInfo, OomStrategy};
|
use rustc_session::config::{DebugInfo, OomStrategy};
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
|
|
||||||
use crate::debuginfo;
|
use crate::debuginfo;
|
||||||
use crate::llvm::{self, False, True};
|
use crate::llvm::{self, False, True};
|
||||||
@ -29,75 +31,78 @@ pub(crate) unsafe fn codegen(
|
|||||||
let i8p = llvm::LLVMPointerType(i8, 0);
|
let i8p = llvm::LLVMPointerType(i8, 0);
|
||||||
let void = llvm::LLVMVoidTypeInContext(llcx);
|
let void = llvm::LLVMVoidTypeInContext(llcx);
|
||||||
|
|
||||||
for method in ALLOCATOR_METHODS {
|
if kind == AllocatorKind::Default {
|
||||||
let mut args = Vec::with_capacity(method.inputs.len());
|
for method in ALLOCATOR_METHODS {
|
||||||
for ty in method.inputs.iter() {
|
let mut args = Vec::with_capacity(method.inputs.len());
|
||||||
match *ty {
|
for ty in method.inputs.iter() {
|
||||||
AllocatorTy::Layout => {
|
match *ty {
|
||||||
args.push(usize); // size
|
AllocatorTy::Layout => {
|
||||||
args.push(usize); // align
|
args.push(usize); // size
|
||||||
|
args.push(usize); // align
|
||||||
|
}
|
||||||
|
AllocatorTy::Ptr => args.push(i8p),
|
||||||
|
AllocatorTy::Usize => args.push(usize),
|
||||||
|
|
||||||
|
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
|
||||||
}
|
}
|
||||||
AllocatorTy::Ptr => args.push(i8p),
|
|
||||||
AllocatorTy::Usize => args.push(usize),
|
|
||||||
|
|
||||||
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
|
|
||||||
}
|
}
|
||||||
}
|
let output = match method.output {
|
||||||
let output = match method.output {
|
AllocatorTy::ResultPtr => Some(i8p),
|
||||||
AllocatorTy::ResultPtr => Some(i8p),
|
AllocatorTy::Unit => None,
|
||||||
AllocatorTy::Unit => None,
|
|
||||||
|
|
||||||
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
|
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
|
||||||
panic!("invalid allocator output")
|
panic!("invalid allocator output")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let ty = llvm::LLVMFunctionType(
|
||||||
|
output.unwrap_or(void),
|
||||||
|
args.as_ptr(),
|
||||||
|
args.len() as c_uint,
|
||||||
|
False,
|
||||||
|
);
|
||||||
|
let name = global_fn_name(method.name);
|
||||||
|
let llfn =
|
||||||
|
llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
|
||||||
|
|
||||||
|
if tcx.sess.target.default_hidden_visibility {
|
||||||
|
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
|
||||||
|
}
|
||||||
|
if tcx.sess.must_emit_unwind_tables() {
|
||||||
|
let uwtable = attributes::uwtable_attr(llcx);
|
||||||
|
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
let ty = llvm::LLVMFunctionType(
|
|
||||||
output.unwrap_or(void),
|
|
||||||
args.as_ptr(),
|
|
||||||
args.len() as c_uint,
|
|
||||||
False,
|
|
||||||
);
|
|
||||||
let name = format!("__rust_{}", method.name);
|
|
||||||
let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
|
|
||||||
|
|
||||||
if tcx.sess.target.default_hidden_visibility {
|
let callee = default_fn_name(method.name);
|
||||||
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
|
let callee =
|
||||||
|
llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
|
||||||
|
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
||||||
|
|
||||||
|
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
|
||||||
|
|
||||||
|
let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
|
||||||
|
llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
|
||||||
|
let args = args
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let ret = llvm::LLVMRustBuildCall(
|
||||||
|
llbuilder,
|
||||||
|
ty,
|
||||||
|
callee,
|
||||||
|
args.as_ptr(),
|
||||||
|
args.len() as c_uint,
|
||||||
|
[].as_ptr(),
|
||||||
|
0 as c_uint,
|
||||||
|
);
|
||||||
|
llvm::LLVMSetTailCall(ret, True);
|
||||||
|
if output.is_some() {
|
||||||
|
llvm::LLVMBuildRet(llbuilder, ret);
|
||||||
|
} else {
|
||||||
|
llvm::LLVMBuildRetVoid(llbuilder);
|
||||||
|
}
|
||||||
|
llvm::LLVMDisposeBuilder(llbuilder);
|
||||||
}
|
}
|
||||||
if tcx.sess.must_emit_unwind_tables() {
|
|
||||||
let uwtable = attributes::uwtable_attr(llcx);
|
|
||||||
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let callee = kind.fn_name(method.name);
|
|
||||||
let callee =
|
|
||||||
llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
|
|
||||||
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
|
||||||
|
|
||||||
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
|
|
||||||
|
|
||||||
let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
|
|
||||||
llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
|
|
||||||
let args = args
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let ret = llvm::LLVMRustBuildCall(
|
|
||||||
llbuilder,
|
|
||||||
ty,
|
|
||||||
callee,
|
|
||||||
args.as_ptr(),
|
|
||||||
args.len() as c_uint,
|
|
||||||
[].as_ptr(),
|
|
||||||
0 as c_uint,
|
|
||||||
);
|
|
||||||
llvm::LLVMSetTailCall(ret, True);
|
|
||||||
if output.is_some() {
|
|
||||||
llvm::LLVMBuildRet(llbuilder, ret);
|
|
||||||
} else {
|
|
||||||
llvm::LLVMBuildRetVoid(llbuilder);
|
|
||||||
}
|
|
||||||
llvm::LLVMDisposeBuilder(llbuilder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// rust alloc error handler
|
// rust alloc error handler
|
||||||
@ -118,7 +123,7 @@ pub(crate) unsafe fn codegen(
|
|||||||
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
|
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let callee = alloc_error_handler_kind.fn_name(sym::oom);
|
let callee = alloc_error_handler_name(alloc_error_handler_kind);
|
||||||
let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
|
let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
|
||||||
// -> ! DIFlagNoReturn
|
// -> ! DIFlagNoReturn
|
||||||
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
|
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
|
||||||
@ -156,6 +161,14 @@ pub(crate) unsafe fn codegen(
|
|||||||
let llval = llvm::LLVMConstInt(i8, val as u64, False);
|
let llval = llvm::LLVMConstInt(i8, val as u64, False);
|
||||||
llvm::LLVMSetInitializer(ll_g, llval);
|
llvm::LLVMSetInitializer(ll_g, llval);
|
||||||
|
|
||||||
|
let name = NO_ALLOC_SHIM_IS_UNSTABLE;
|
||||||
|
let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
|
||||||
|
if tcx.sess.target.default_hidden_visibility {
|
||||||
|
llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
|
||||||
|
}
|
||||||
|
let llval = llvm::LLVMConstInt(i8, 0, False);
|
||||||
|
llvm::LLVMSetInitializer(ll_g, llval);
|
||||||
|
|
||||||
if tcx.sess.opts.debuginfo != DebugInfo::None {
|
if tcx.sess.opts.debuginfo != DebugInfo::None {
|
||||||
let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
|
let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
|
||||||
debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
|
debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use std::collections::hash_map::Entry::*;
|
use std::collections::hash_map::Entry::*;
|
||||||
|
|
||||||
use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
|
use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE};
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
|
||||||
@ -241,6 +241,17 @@ fn exported_symbols_provider_local(
|
|||||||
used: false,
|
used: false,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let exported_symbol =
|
||||||
|
ExportedSymbol::NoDefId(SymbolName::new(tcx, NO_ALLOC_SHIM_IS_UNSTABLE));
|
||||||
|
symbols.push((
|
||||||
|
exported_symbol,
|
||||||
|
SymbolExportInfo {
|
||||||
|
level: SymbolExportLevel::Rust,
|
||||||
|
kind: SymbolExportKind::Data,
|
||||||
|
used: false,
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {
|
if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
use crate::locator::{CrateError, CrateLocator, CratePaths};
|
use crate::locator::{CrateError, CrateLocator, CratePaths};
|
||||||
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
|
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
|
||||||
|
|
||||||
use rustc_ast::expand::allocator::AllocatorKind;
|
use rustc_ast::expand::allocator::{alloc_error_handler_name, global_fn_name, AllocatorKind};
|
||||||
use rustc_ast::{self as ast, *};
|
use rustc_ast::{self as ast, *};
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::svh::Svh;
|
use rustc_data_structures::svh::Svh;
|
||||||
@ -1048,7 +1048,7 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc));
|
let name = Symbol::intern(&global_fn_name(sym::alloc));
|
||||||
let mut f = Finder { name, spans: Vec::new() };
|
let mut f = Finder { name, spans: Vec::new() };
|
||||||
visit::walk_crate(&mut f, krate);
|
visit::walk_crate(&mut f, krate);
|
||||||
f.spans
|
f.spans
|
||||||
@ -1070,7 +1070,7 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom));
|
let name = Symbol::intern(alloc_error_handler_name(AllocatorKind::Global));
|
||||||
let mut f = Finder { name, spans: Vec::new() };
|
let mut f = Finder { name, spans: Vec::new() };
|
||||||
visit::walk_crate(&mut f, krate);
|
visit::walk_crate(&mut f, krate);
|
||||||
f.spans
|
f.spans
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
#[rustc_allocator_zeroed]
|
#[rustc_allocator_zeroed]
|
||||||
#[rustc_nounwind]
|
#[rustc_nounwind]
|
||||||
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
|
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
|
||||||
|
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
static __rust_no_alloc_shim_is_unstable: u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The global memory allocator.
|
/// The global memory allocator.
|
||||||
@ -90,7 +93,14 @@
|
|||||||
#[must_use = "losing the pointer will leak memory"]
|
#[must_use = "losing the pointer will leak memory"]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
|
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
|
||||||
unsafe { __rust_alloc(layout.size(), layout.align()) }
|
unsafe {
|
||||||
|
// Make sure we don't accidentally allow omitting the allocator shim in
|
||||||
|
// stable code until it is actually stabilized.
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable);
|
||||||
|
|
||||||
|
__rust_alloc(layout.size(), layout.align())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deallocate memory with the global allocator.
|
/// Deallocate memory with the global allocator.
|
||||||
|
@ -651,6 +651,10 @@ fn alloc_extern_static(
|
|||||||
|
|
||||||
/// Sets up the "extern statics" for this machine.
|
/// Sets up the "extern statics" for this machine.
|
||||||
fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||||
|
// "__rust_no_alloc_shim_is_unstable"
|
||||||
|
let val = ImmTy::from_int(0, this.machine.layouts.u8);
|
||||||
|
Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?;
|
||||||
|
|
||||||
match this.tcx.sess.target.os.as_ref() {
|
match this.tcx.sess.target.os.as_ref() {
|
||||||
"linux" => {
|
"linux" => {
|
||||||
// "environ"
|
// "environ"
|
||||||
|
@ -347,7 +347,6 @@ fn emulate_foreign_item(
|
|||||||
/// Emulates calling the internal __rust_* allocator functions
|
/// Emulates calling the internal __rust_* allocator functions
|
||||||
fn emulate_allocator(
|
fn emulate_allocator(
|
||||||
&mut self,
|
&mut self,
|
||||||
symbol: Symbol,
|
|
||||||
default: impl FnOnce(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx>,
|
default: impl FnOnce(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx>,
|
||||||
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
|
) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
@ -359,11 +358,12 @@ fn emulate_allocator(
|
|||||||
|
|
||||||
match allocator_kind {
|
match allocator_kind {
|
||||||
AllocatorKind::Global => {
|
AllocatorKind::Global => {
|
||||||
let (body, instance) = this
|
// When `#[global_allocator]` is used, `__rust_*` is defined by the macro expansion
|
||||||
.lookup_exported_symbol(symbol)?
|
// of this attribute. As such we have to call an exported Rust function,
|
||||||
.expect("symbol should be present if there is a global allocator");
|
// and not execute any Miri shim. Somewhat unintuitively doing so is done
|
||||||
|
// by returning `NotSupported`, which triggers the `lookup_exported_symbol`
|
||||||
Ok(EmulateByNameResult::MirBody(body, instance))
|
// fallback case in `emulate_foreign_item`.
|
||||||
|
return Ok(EmulateByNameResult::NotSupported);
|
||||||
}
|
}
|
||||||
AllocatorKind::Default => {
|
AllocatorKind::Default => {
|
||||||
default(this)?;
|
default(this)?;
|
||||||
@ -558,11 +558,13 @@ fn emulate_foreign_item_by_name(
|
|||||||
|
|
||||||
// Rust allocation
|
// Rust allocation
|
||||||
"__rust_alloc" | "miri_alloc" => {
|
"__rust_alloc" | "miri_alloc" => {
|
||||||
let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
|
|
||||||
let size = this.read_target_usize(size)?;
|
|
||||||
let align = this.read_target_usize(align)?;
|
|
||||||
|
|
||||||
let default = |this: &mut MiriInterpCx<'mir, 'tcx>| {
|
let default = |this: &mut MiriInterpCx<'mir, 'tcx>| {
|
||||||
|
// Only call `check_shim` when `#[global_allocator]` isn't used. When that
|
||||||
|
// macro is used, we act like no shim exists, so that the exported function can run.
|
||||||
|
let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
|
||||||
|
let size = this.read_target_usize(size)?;
|
||||||
|
let align = this.read_target_usize(align)?;
|
||||||
|
|
||||||
Self::check_alloc_request(size, align)?;
|
Self::check_alloc_request(size, align)?;
|
||||||
|
|
||||||
let memory_kind = match link_name.as_str() {
|
let memory_kind = match link_name.as_str() {
|
||||||
@ -581,8 +583,7 @@ fn emulate_foreign_item_by_name(
|
|||||||
};
|
};
|
||||||
|
|
||||||
match link_name.as_str() {
|
match link_name.as_str() {
|
||||||
"__rust_alloc" =>
|
"__rust_alloc" => return this.emulate_allocator(default),
|
||||||
return this.emulate_allocator(Symbol::intern("__rg_alloc"), default),
|
|
||||||
"miri_alloc" => {
|
"miri_alloc" => {
|
||||||
default(this)?;
|
default(this)?;
|
||||||
return Ok(EmulateByNameResult::NeedsJumping);
|
return Ok(EmulateByNameResult::NeedsJumping);
|
||||||
@ -591,11 +592,13 @@ fn emulate_foreign_item_by_name(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"__rust_alloc_zeroed" => {
|
"__rust_alloc_zeroed" => {
|
||||||
let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
|
return this.emulate_allocator(|this| {
|
||||||
let size = this.read_target_usize(size)?;
|
// See the comment for `__rust_alloc` why `check_shim` is only called in the
|
||||||
let align = this.read_target_usize(align)?;
|
// default case.
|
||||||
|
let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
|
||||||
|
let size = this.read_target_usize(size)?;
|
||||||
|
let align = this.read_target_usize(align)?;
|
||||||
|
|
||||||
return this.emulate_allocator(Symbol::intern("__rg_alloc_zeroed"), |this| {
|
|
||||||
Self::check_alloc_request(size, align)?;
|
Self::check_alloc_request(size, align)?;
|
||||||
|
|
||||||
let ptr = this.allocate_ptr(
|
let ptr = this.allocate_ptr(
|
||||||
@ -614,12 +617,15 @@ fn emulate_foreign_item_by_name(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
"__rust_dealloc" | "miri_dealloc" => {
|
"__rust_dealloc" | "miri_dealloc" => {
|
||||||
let [ptr, old_size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
|
|
||||||
let ptr = this.read_pointer(ptr)?;
|
|
||||||
let old_size = this.read_target_usize(old_size)?;
|
|
||||||
let align = this.read_target_usize(align)?;
|
|
||||||
|
|
||||||
let default = |this: &mut MiriInterpCx<'mir, 'tcx>| {
|
let default = |this: &mut MiriInterpCx<'mir, 'tcx>| {
|
||||||
|
// See the comment for `__rust_alloc` why `check_shim` is only called in the
|
||||||
|
// default case.
|
||||||
|
let [ptr, old_size, align] =
|
||||||
|
this.check_shim(abi, Abi::Rust, link_name, args)?;
|
||||||
|
let ptr = this.read_pointer(ptr)?;
|
||||||
|
let old_size = this.read_target_usize(old_size)?;
|
||||||
|
let align = this.read_target_usize(align)?;
|
||||||
|
|
||||||
let memory_kind = match link_name.as_str() {
|
let memory_kind = match link_name.as_str() {
|
||||||
"__rust_dealloc" => MiriMemoryKind::Rust,
|
"__rust_dealloc" => MiriMemoryKind::Rust,
|
||||||
"miri_dealloc" => MiriMemoryKind::Miri,
|
"miri_dealloc" => MiriMemoryKind::Miri,
|
||||||
@ -635,8 +641,9 @@ fn emulate_foreign_item_by_name(
|
|||||||
};
|
};
|
||||||
|
|
||||||
match link_name.as_str() {
|
match link_name.as_str() {
|
||||||
"__rust_dealloc" =>
|
"__rust_dealloc" => {
|
||||||
return this.emulate_allocator(Symbol::intern("__rg_dealloc"), default),
|
return this.emulate_allocator(default);
|
||||||
|
}
|
||||||
"miri_dealloc" => {
|
"miri_dealloc" => {
|
||||||
default(this)?;
|
default(this)?;
|
||||||
return Ok(EmulateByNameResult::NeedsJumping);
|
return Ok(EmulateByNameResult::NeedsJumping);
|
||||||
@ -645,15 +652,17 @@ fn emulate_foreign_item_by_name(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"__rust_realloc" => {
|
"__rust_realloc" => {
|
||||||
let [ptr, old_size, align, new_size] =
|
return this.emulate_allocator(|this| {
|
||||||
this.check_shim(abi, Abi::Rust, link_name, args)?;
|
// See the comment for `__rust_alloc` why `check_shim` is only called in the
|
||||||
let ptr = this.read_pointer(ptr)?;
|
// default case.
|
||||||
let old_size = this.read_target_usize(old_size)?;
|
let [ptr, old_size, align, new_size] =
|
||||||
let align = this.read_target_usize(align)?;
|
this.check_shim(abi, Abi::Rust, link_name, args)?;
|
||||||
let new_size = this.read_target_usize(new_size)?;
|
let ptr = this.read_pointer(ptr)?;
|
||||||
// No need to check old_size; we anyway check that they match the allocation.
|
let old_size = this.read_target_usize(old_size)?;
|
||||||
|
let align = this.read_target_usize(align)?;
|
||||||
|
let new_size = this.read_target_usize(new_size)?;
|
||||||
|
// No need to check old_size; we anyway check that they match the allocation.
|
||||||
|
|
||||||
return this.emulate_allocator(Symbol::intern("__rg_realloc"), |this| {
|
|
||||||
Self::check_alloc_request(new_size, align)?;
|
Self::check_alloc_request(new_size, align)?;
|
||||||
|
|
||||||
let align = Align::from_bytes(align).unwrap();
|
let align = Align::from_bytes(align).unwrap();
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: memory leaked: ALLOC (Rust heap, size: 4, align: 4), allocated here:
|
error: memory leaked: ALLOC (Rust heap, size: 4, align: 4), allocated here:
|
||||||
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | unsafe { __rust_alloc(layout.size(), layout.align()) }
|
LL | __rust_alloc(layout.size(), layout.align())
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
= note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
= note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
= note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: memory leaked: ALLOC (Rust heap, size: 16, align: 4), allocated here:
|
error: memory leaked: ALLOC (Rust heap, size: 16, align: 4), allocated here:
|
||||||
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | unsafe { __rust_alloc(layout.size(), layout.align()) }
|
LL | __rust_alloc(layout.size(), layout.align())
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
= note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
= note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
= note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
error: memory leaked: ALLOC (Rust heap, size: 32, align: 8), allocated here:
|
error: memory leaked: ALLOC (Rust heap, size: 32, align: 8), allocated here:
|
||||||
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
|
|
|
|
||||||
LL | unsafe { __rust_alloc(layout.size(), layout.align()) }
|
LL | __rust_alloc(layout.size(), layout.align())
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
= note: inside `std::alloc::alloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
= note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
= note: inside `std::alloc::Global::alloc_impl` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||||
|
@ -31,7 +31,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn host_to_target_path(path: String) -> PathBuf {
|
fn host_to_target_path(path: String) -> PathBuf {
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{c_char, CStr, CString};
|
||||||
|
|
||||||
let path = CString::new(path).unwrap();
|
let path = CString::new(path).unwrap();
|
||||||
let mut out = Vec::with_capacity(1024);
|
let mut out = Vec::with_capacity(1024);
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
//
|
//
|
||||||
// no-system-llvm
|
// no-system-llvm
|
||||||
// compile-flags: -O
|
// compile-flags: -O
|
||||||
#![crate_type="lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn alloc_test(data: u32) {
|
pub fn alloc_test(data: u32) {
|
||||||
// CHECK-LABEL: @alloc_test
|
// CHECK-LABEL: @alloc_test
|
||||||
// CHECK-NEXT: start:
|
// CHECK-NEXT: start:
|
||||||
|
// CHECK-NEXT: {{.*}} load volatile i8, ptr @__rust_no_alloc_shim_is_unstable, align 1
|
||||||
// CHECK-NEXT: ret void
|
// CHECK-NEXT: ret void
|
||||||
let x = Box::new(data);
|
let x = Box::new(data);
|
||||||
drop(x);
|
drop(x);
|
||||||
|
@ -11,8 +11,6 @@
|
|||||||
|
|
||||||
// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
|
// Make sure that vtables don't have the unnamed_addr attribute when debuginfo is enabled.
|
||||||
// This helps debuggers more reliably map from dyn pointer to concrete type.
|
// This helps debuggers more reliably map from dyn pointer to concrete type.
|
||||||
// CHECK: @vtable.0 = private constant <{
|
|
||||||
// CHECK: @vtable.1 = private constant <{
|
|
||||||
// CHECK: @vtable.2 = private constant <{
|
// CHECK: @vtable.2 = private constant <{
|
||||||
// CHECK: @vtable.3 = private constant <{
|
// CHECK: @vtable.3 = private constant <{
|
||||||
// CHECK: @vtable.4 = private constant <{
|
// CHECK: @vtable.4 = private constant <{
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
// ignore-debug: the debug assertions get in the way
|
// ignore-debug: the debug assertions get in the way
|
||||||
// no-system-llvm
|
// no-system-llvm
|
||||||
// compile-flags: -O
|
// compile-flags: -O
|
||||||
#![crate_type="lib"]
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn sum_me() -> i32 {
|
pub fn sum_me() -> i32 {
|
||||||
// CHECK-LABEL: @sum_me
|
// CHECK-LABEL: @sum_me
|
||||||
// CHECK-NEXT: {{^.*:$}}
|
// CHECK-NEXT: {{^.*:$}}
|
||||||
|
// CHECK-NEXT: {{.*}} load volatile i8, ptr @__rust_no_alloc_shim_is_unstable, align 1
|
||||||
// CHECK-NEXT: ret i32 6
|
// CHECK-NEXT: ret i32 6
|
||||||
vec![1, 2, 3].iter().sum::<i32>()
|
vec![1, 2, 3].iter().sum::<i32>()
|
||||||
}
|
}
|
||||||
|
24
tests/run-make/no-alloc-shim/Makefile
Normal file
24
tests/run-make/no-alloc-shim/Makefile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
include ../tools.mk
|
||||||
|
|
||||||
|
# ignore-cross-compile
|
||||||
|
# ignore-msvc FIXME(bjorn3) can't figure out how to link with the MSVC toolchain
|
||||||
|
|
||||||
|
TARGET_LIBDIR = $$($(RUSTC) --print target-libdir)
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) foo.rs --crate-type bin --emit obj -Cpanic=abort
|
||||||
|
ifdef IS_MSVC
|
||||||
|
$(CC) $(CFLAGS) $(TMPDIR)/foo.o $(call OUT_EXE,foo) /link $(TARGET_LIBDIR)/liballoc-*.rlib $(TARGET_LIBDIR)/libcore-*.rlib $(TARGET_LIBDIR)/libcompiler_builtins-*.rlib
|
||||||
|
$(call OUT_EXE,foo)
|
||||||
|
else
|
||||||
|
$(CC) $(CFLAGS) $(TMPDIR)/foo.o $(TARGET_LIBDIR)/liballoc-*.rlib $(TARGET_LIBDIR)/libcore-*.rlib $(TARGET_LIBDIR)/libcompiler_builtins-*.rlib -o $(call RUN_BINFILE,foo)
|
||||||
|
$(call RUN_BINFILE,foo)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Check that linking without __rust_no_alloc_shim_is_unstable defined fails
|
||||||
|
$(RUSTC) foo.rs --crate-type bin --emit obj -Cpanic=abort --cfg check_feature_gate
|
||||||
|
ifdef IS_MSVC
|
||||||
|
$(CC) $(CFLAGS) $(TMPDIR)/foo.o $(call OUT_EXE,foo) /link $(TARGET_LIBDIR)/liballoc-*.rlib $(TARGET_LIBDIR)/libcore-*.rlib $(TARGET_LIBDIR)/libcompiler_builtins-*.rlib || exit 0 && exit 1
|
||||||
|
else
|
||||||
|
$(CC) $(CFLAGS) $(TMPDIR)/foo.o $(TARGET_LIBDIR)/liballoc-*.rlib $(TARGET_LIBDIR)/libcore-*.rlib $(TARGET_LIBDIR)/libcompiler_builtins-*.rlib -o $(call RUN_BINFILE,foo) || exit 0 && exit 1
|
||||||
|
endif
|
44
tests/run-make/no-alloc-shim/foo.rs
Normal file
44
tests/run-make/no-alloc-shim/foo.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#![feature(default_alloc_error_handler)]
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use alloc::alloc::{GlobalAlloc, Layout};
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn rust_eh_personality() {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOC: Alloc = Alloc;
|
||||||
|
|
||||||
|
struct Alloc;
|
||||||
|
|
||||||
|
unsafe impl GlobalAlloc for Alloc {
|
||||||
|
unsafe fn alloc(&self, _: Layout) -> *mut u8 {
|
||||||
|
core::ptr::null_mut()
|
||||||
|
}
|
||||||
|
unsafe fn dealloc(&self, _: *mut u8, _: Layout) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(check_feature_gate))]
|
||||||
|
#[no_mangle]
|
||||||
|
static __rust_no_alloc_shim_is_unstable: u8 = 0;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn main(_argc: usize, _argv: *const *const i8) -> i32 {
|
||||||
|
unsafe {
|
||||||
|
assert_eq!(alloc::alloc::alloc(Layout::new::<()>()), core::ptr::null_mut());
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user