Use the GlobalAlloc trait for #[global_allocator]

This commit is contained in:
Simon Sapin 2018-04-03 17:12:57 +02:00
parent eb69593f73
commit 86753ce1cc
17 changed files with 171 additions and 710 deletions

1
src/Cargo.lock generated
View File

@ -19,7 +19,6 @@ dependencies = [
name = "alloc_jemalloc"
version = "0.0.0"
dependencies = [
"alloc_system 0.0.0",
"build_helper 0.1.0",
"cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",

View File

@ -29,16 +29,16 @@ looks like:
```rust
#![feature(global_allocator, allocator_api, heap_api)]
use std::heap::{Alloc, System, Layout, AllocErr};
use std::alloc::{GlobalAlloc, System, Layout, Void};
struct MyAllocator;
unsafe impl<'a> Alloc for &'a MyAllocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
unsafe impl GlobalAlloc for MyAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut Void {
System.alloc(layout)
}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) {
System.dealloc(ptr, layout)
}
}

View File

@ -16,26 +16,19 @@
issue = "32838")]
use core::intrinsics::{min_align_of_val, size_of_val};
use core::mem;
use core::usize;
#[doc(inline)]
pub use core::alloc::*;
#[cfg(stage0)]
extern "Rust" {
#[allocator]
#[rustc_allocator_nounwind]
fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
#[cold]
#[rustc_allocator_nounwind]
fn __rust_oom(err: *const u8) -> !;
#[rustc_allocator_nounwind]
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
#[rustc_allocator_nounwind]
fn __rust_usable_size(layout: *const u8,
min: *mut usize,
max: *mut usize);
#[rustc_allocator_nounwind]
fn __rust_realloc(ptr: *mut u8,
old_size: usize,
old_align: usize,
@ -44,31 +37,22 @@ extern "Rust" {
err: *mut u8) -> *mut u8;
#[rustc_allocator_nounwind]
fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
}
#[cfg(not(stage0))]
extern "Rust" {
#[allocator]
#[rustc_allocator_nounwind]
fn __rust_alloc_excess(size: usize,
align: usize,
excess: *mut usize,
err: *mut u8) -> *mut u8;
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
#[rustc_allocator_nounwind]
fn __rust_realloc_excess(ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize,
excess: *mut usize,
err: *mut u8) -> *mut u8;
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
#[rustc_allocator_nounwind]
fn __rust_grow_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize) -> u8;
fn __rust_realloc(ptr: *mut u8,
old_size: usize,
align: usize,
new_size: usize) -> *mut u8;
#[rustc_allocator_nounwind]
fn __rust_shrink_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize) -> u8;
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
}
#[derive(Copy, Clone, Default, Debug)]
@ -86,22 +70,15 @@ pub const Heap: Global = Global;
unsafe impl Alloc for Global {
#[inline]
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
let mut err = AllocErr;
let ptr = __rust_alloc(layout.size(),
layout.align(),
&mut err as *mut AllocErr as *mut u8);
if ptr.is_null() {
Err(AllocErr)
} else {
Ok(ptr)
}
}
#[cfg(not(stage0))]
let ptr = __rust_alloc(layout.size(), layout.align());
#[cfg(stage0)]
let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0);
#[inline]
#[cold]
fn oom(&mut self, err: AllocErr) -> ! {
unsafe {
__rust_oom(&err as *const AllocErr as *const u8)
if !ptr.is_null() {
Ok(ptr)
} else {
Err(AllocErr)
}
}
@ -110,18 +87,6 @@ unsafe impl Alloc for Global {
__rust_dealloc(ptr, layout.size(), layout.align())
}
#[inline]
fn usable_size(&self, layout: &Layout) -> (usize, usize) {
let mut min = 0;
let mut max = 0;
unsafe {
__rust_usable_size(layout as *const Layout as *const u8,
&mut min,
&mut max);
}
(min, max)
}
#[inline]
unsafe fn realloc(&mut self,
ptr: *mut u8,
@ -129,107 +94,34 @@ unsafe impl Alloc for Global {
new_layout: Layout)
-> Result<*mut u8, AllocErr>
{
let mut err = AllocErr;
let ptr = __rust_realloc(ptr,
layout.size(),
layout.align(),
new_layout.size(),
new_layout.align(),
&mut err as *mut AllocErr as *mut u8);
if ptr.is_null() {
Err(AllocErr)
if layout.align() == new_layout.align() {
#[cfg(not(stage0))]
let ptr = __rust_realloc(ptr, layout.size(), layout.align(), new_layout.size());
#[cfg(stage0)]
let ptr = __rust_realloc(ptr, layout.size(), layout.align(),
new_layout.size(), new_layout.align(), &mut 0);
if !ptr.is_null() {
Ok(ptr)
} else {
Err(AllocErr)
}
} else {
mem::forget(err);
Ok(ptr)
Err(AllocErr)
}
}
#[inline]
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
let mut err = AllocErr;
let ptr = __rust_alloc_zeroed(layout.size(),
layout.align(),
&mut err as *mut AllocErr as *mut u8);
if ptr.is_null() {
Err(AllocErr)
} else {
#[cfg(not(stage0))]
let ptr = __rust_alloc_zeroed(layout.size(), layout.align());
#[cfg(stage0)]
let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0);
if !ptr.is_null() {
Ok(ptr)
}
}
#[inline]
unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
let mut err = AllocErr;
let mut size = 0;
let ptr = __rust_alloc_excess(layout.size(),
layout.align(),
&mut size,
&mut err as *mut AllocErr as *mut u8);
if ptr.is_null() {
} else {
Err(AllocErr)
} else {
Ok(Excess(ptr, size))
}
}
#[inline]
unsafe fn realloc_excess(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<Excess, AllocErr> {
let mut err = AllocErr;
let mut size = 0;
let ptr = __rust_realloc_excess(ptr,
layout.size(),
layout.align(),
new_layout.size(),
new_layout.align(),
&mut size,
&mut err as *mut AllocErr as *mut u8);
if ptr.is_null() {
Err(AllocErr)
} else {
Ok(Excess(ptr, size))
}
}
#[inline]
unsafe fn grow_in_place(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout)
-> Result<(), CannotReallocInPlace>
{
debug_assert!(new_layout.size() >= layout.size());
debug_assert!(new_layout.align() == layout.align());
let ret = __rust_grow_in_place(ptr,
layout.size(),
layout.align(),
new_layout.size(),
new_layout.align());
if ret != 0 {
Ok(())
} else {
Err(CannotReallocInPlace)
}
}
#[inline]
unsafe fn shrink_in_place(&mut self,
ptr: *mut u8,
layout: Layout,
new_layout: Layout) -> Result<(), CannotReallocInPlace> {
debug_assert!(new_layout.size() <= layout.size());
debug_assert!(new_layout.align() == layout.align());
let ret = __rust_shrink_in_place(ptr,
layout.size(),
layout.align(),
new_layout.size(),
new_layout.align());
if ret != 0 {
Ok(())
} else {
Err(CannotReallocInPlace)
}
}
}

View File

@ -12,7 +12,6 @@ test = false
doc = false
[dependencies]
alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
libc = { path = "../rustc/libc_shim" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }

View File

@ -14,7 +14,6 @@
reason = "this library is unlikely to be stabilized in its current \
form or name",
issue = "27783")]
#![feature(alloc_system)]
#![feature(libc)]
#![feature(linkage)]
#![feature(staged_api)]
@ -23,15 +22,12 @@
#![cfg_attr(not(dummy_jemalloc), feature(allocator_api))]
#![rustc_alloc_kind = "exe"]
extern crate alloc_system;
extern crate libc;
#[cfg(not(dummy_jemalloc))]
pub use contents::*;
#[cfg(not(dummy_jemalloc))]
mod contents {
use core::alloc::{Alloc, AllocErr, Layout};
use alloc_system::System;
use libc::{c_int, c_void, size_t};
// Note that the symbols here are prefixed by default on macOS and Windows (we
@ -50,18 +46,10 @@ mod contents {
target_os = "dragonfly", target_os = "windows", target_env = "musl"),
link_name = "je_rallocx")]
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows", target_env = "musl"),
link_name = "je_xallocx")]
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows", target_env = "musl"),
link_name = "je_sdallocx")]
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows", target_env = "musl"),
link_name = "je_nallocx")]
fn nallocx(size: size_t, flags: c_int) -> size_t;
}
const MALLOCX_ZERO: c_int = 0x40;
@ -102,20 +90,12 @@ mod contents {
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_alloc(size: usize,
align: usize,
_err: *mut u8) -> *mut u8 {
pub unsafe extern fn __rde_alloc(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align, size);
let ptr = mallocx(size as size_t, flags) as *mut u8;
ptr
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_oom(err: *const u8) -> ! {
System.oom((*(err as *const AllocErr)).clone())
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
@ -125,44 +105,20 @@ mod contents {
sdallocx(ptr as *mut c_void, size, flags);
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_usable_size(layout: *const u8,
min: *mut usize,
max: *mut usize) {
let layout = &*(layout as *const Layout);
let flags = align_to_flags(layout.align(), layout.size());
let size = nallocx(layout.size(), flags) as usize;
*min = layout.size();
if size > 0 {
*max = size;
} else {
*max = layout.size();
}
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_realloc(ptr: *mut u8,
_old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize,
_err: *mut u8) -> *mut u8 {
if new_align != old_align {
return 0 as *mut u8
}
let flags = align_to_flags(new_align, new_size);
align: usize,
new_size: usize) -> *mut u8 {
let flags = align_to_flags(align, new_size);
let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8;
ptr
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_alloc_zeroed(size: usize,
align: usize,
_err: *mut u8) -> *mut u8 {
pub unsafe extern fn __rde_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
let ptr = if align <= MIN_ALIGN && align <= size {
calloc(size as size_t, 1) as *mut u8
} else {
@ -171,60 +127,4 @@ mod contents {
};
ptr
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_alloc_excess(size: usize,
align: usize,
excess: *mut usize,
err: *mut u8) -> *mut u8 {
let p = __rde_alloc(size, align, err);
if !p.is_null() {
let flags = align_to_flags(align, size);
*excess = nallocx(size, flags) as usize;
}
return p
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize,
excess: *mut usize,
err: *mut u8) -> *mut u8 {
let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err);
if !p.is_null() {
let flags = align_to_flags(new_align, new_size);
*excess = nallocx(new_size, flags) as usize;
}
p
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize) -> u8 {
__rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align)
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8,
_old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize) -> u8 {
if old_align == new_align {
let flags = align_to_flags(new_align, new_size);
(xallocx(ptr as *mut c_void, new_size, 0, flags) == new_size) as u8
} else {
0
}
}
}

View File

@ -11,7 +11,7 @@
use rustc::middle::allocator::AllocatorKind;
use rustc_errors;
use syntax::abi::Abi;
use syntax::ast::{Crate, Attribute, LitKind, StrStyle, ExprKind};
use syntax::ast::{Crate, Attribute, LitKind, StrStyle};
use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg};
use syntax::ast::{self, Ident, Item, ItemKind, TyKind, VisibilityKind, Expr};
use syntax::attr;
@ -88,7 +88,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
span,
kind: AllocatorKind::Global,
global: item.ident,
alloc: Ident::from_str("alloc"),
core: Ident::from_str("core"),
cx: ExtCtxt::new(self.sess, ecfg, self.resolver),
};
let super_path = f.cx.path(f.span, vec![
@ -96,7 +96,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
f.global,
]);
let mut items = vec![
f.cx.item_extern_crate(f.span, f.alloc),
f.cx.item_extern_crate(f.span, f.core),
f.cx.item_use_simple(
f.span,
respan(f.span.shrink_to_lo(), VisibilityKind::Inherited),
@ -126,7 +126,7 @@ struct AllocFnFactory<'a> {
span: Span,
kind: AllocatorKind,
global: Ident,
alloc: Ident,
core: Ident,
cx: ExtCtxt<'a>,
}
@ -143,8 +143,7 @@ impl<'a> AllocFnFactory<'a> {
self.arg_ty(ty, &mut abi_args, mk)
}).collect();
let result = self.call_allocator(method.name, args);
let (output_ty, output_expr) =
self.ret_ty(&method.output, &mut abi_args, mk, result);
let (output_ty, output_expr) = self.ret_ty(&method.output, result);
let kind = ItemKind::Fn(self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)),
Unsafety::Unsafe,
dummy_spanned(Constness::NotConst),
@ -159,16 +158,15 @@ impl<'a> AllocFnFactory<'a> {
fn call_allocator(&self, method: &str, mut args: Vec<P<Expr>>) -> P<Expr> {
let method = self.cx.path(self.span, vec![
self.alloc,
Ident::from_str("heap"),
Ident::from_str("Alloc"),
self.core,
Ident::from_str("alloc"),
Ident::from_str("GlobalAlloc"),
Ident::from_str(method),
]);
let method = self.cx.expr_path(method);
let allocator = self.cx.path_ident(self.span, self.global);
let allocator = self.cx.expr_path(allocator);
let allocator = self.cx.expr_addr_of(self.span, allocator);
let allocator = self.cx.expr_mut_addr_of(self.span, allocator);
args.insert(0, allocator);
self.cx.expr_call(self.span, method, args)
@ -205,8 +203,8 @@ impl<'a> AllocFnFactory<'a> {
args.push(self.cx.arg(self.span, align, ty_usize));
let layout_new = self.cx.path(self.span, vec![
self.alloc,
Ident::from_str("heap"),
self.core,
Ident::from_str("alloc"),
Ident::from_str("Layout"),
Ident::from_str("from_size_align_unchecked"),
]);
@ -219,286 +217,67 @@ impl<'a> AllocFnFactory<'a> {
layout
}
AllocatorTy::LayoutRef => {
let ident = ident();
args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
// Convert our `arg: *const u8` via:
//
// &*(arg as *const Layout)
let expr = self.cx.expr_ident(self.span, ident);
let expr = self.cx.expr_cast(self.span, expr, self.layout_ptr());
let expr = self.cx.expr_deref(self.span, expr);
self.cx.expr_addr_of(self.span, expr)
}
AllocatorTy::AllocErr => {
// We're creating:
//
// (*(arg as *const AllocErr)).clone()
let ident = ident();
args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
let expr = self.cx.expr_ident(self.span, ident);
let expr = self.cx.expr_cast(self.span, expr, self.alloc_err_ptr());
let expr = self.cx.expr_deref(self.span, expr);
self.cx.expr_method_call(
self.span,
expr,
Ident::from_str("clone"),
Vec::new()
)
}
AllocatorTy::Ptr => {
let ident = ident();
args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
let arg = self.cx.expr_ident(self.span, ident);
self.cx.expr_cast(self.span, arg, self.ptr_void())
}
AllocatorTy::Usize => {
let ident = ident();
args.push(self.cx.arg(self.span, ident, self.usize()));
self.cx.expr_ident(self.span, ident)
}
AllocatorTy::ResultPtr |
AllocatorTy::ResultExcess |
AllocatorTy::ResultUnit |
AllocatorTy::Bang |
AllocatorTy::UsizePair |
AllocatorTy::Unit => {
panic!("can't convert AllocatorTy to an argument")
}
}
}
fn ret_ty(&self,
ty: &AllocatorTy,
args: &mut Vec<Arg>,
ident: &mut FnMut() -> Ident,
expr: P<Expr>) -> (P<Ty>, P<Expr>)
{
fn ret_ty(&self, ty: &AllocatorTy, expr: P<Expr>) -> (P<Ty>, P<Expr>) {
match *ty {
AllocatorTy::UsizePair => {
// We're creating:
//
// let arg = #expr;
// *min = arg.0;
// *max = arg.1;
let min = ident();
let max = ident();
args.push(self.cx.arg(self.span, min, self.ptr_usize()));
args.push(self.cx.arg(self.span, max, self.ptr_usize()));
let ident = ident();
let stmt = self.cx.stmt_let(self.span, false, ident, expr);
let min = self.cx.expr_ident(self.span, min);
let max = self.cx.expr_ident(self.span, max);
let layout = self.cx.expr_ident(self.span, ident);
let assign_min = self.cx.expr(self.span, ExprKind::Assign(
self.cx.expr_deref(self.span, min),
self.cx.expr_tup_field_access(self.span, layout.clone(), 0),
));
let assign_min = self.cx.stmt_semi(assign_min);
let assign_max = self.cx.expr(self.span, ExprKind::Assign(
self.cx.expr_deref(self.span, max),
self.cx.expr_tup_field_access(self.span, layout.clone(), 1),
));
let assign_max = self.cx.stmt_semi(assign_max);
let stmts = vec![stmt, assign_min, assign_max];
let block = self.cx.block(self.span, stmts);
let ty_unit = self.cx.ty(self.span, TyKind::Tup(Vec::new()));
(ty_unit, self.cx.expr_block(block))
}
AllocatorTy::ResultExcess => {
// We're creating:
//
// match #expr {
// Ok(ptr) => {
// *excess = ptr.1;
// ptr.0
// }
// Err(e) => {
// ptr::write(err_ptr, e);
// 0 as *mut u8
// }
// }
let excess_ptr = ident();
args.push(self.cx.arg(self.span, excess_ptr, self.ptr_usize()));
let excess_ptr = self.cx.expr_ident(self.span, excess_ptr);
let err_ptr = ident();
args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8()));
let err_ptr = self.cx.expr_ident(self.span, err_ptr);
let err_ptr = self.cx.expr_cast(self.span,
err_ptr,
self.alloc_err_ptr());
let name = ident();
let ok_expr = {
let ptr = self.cx.expr_ident(self.span, name);
let write = self.cx.expr(self.span, ExprKind::Assign(
self.cx.expr_deref(self.span, excess_ptr),
self.cx.expr_tup_field_access(self.span, ptr.clone(), 1),
));
let write = self.cx.stmt_semi(write);
let ret = self.cx.expr_tup_field_access(self.span,
ptr.clone(),
0);
let ret = self.cx.stmt_expr(ret);
let block = self.cx.block(self.span, vec![write, ret]);
self.cx.expr_block(block)
};
let pat = self.cx.pat_ident(self.span, name);
let ok = self.cx.path_ident(self.span, Ident::from_str("Ok"));
let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]);
let ok = self.cx.arm(self.span, vec![ok], ok_expr);
let name = ident();
let err_expr = {
let err = self.cx.expr_ident(self.span, name);
let write = self.cx.path(self.span, vec![
self.alloc,
Ident::from_str("heap"),
Ident::from_str("__core"),
Ident::from_str("ptr"),
Ident::from_str("write"),
]);
let write = self.cx.expr_path(write);
let write = self.cx.expr_call(self.span, write,
vec![err_ptr, err]);
let write = self.cx.stmt_semi(write);
let null = self.cx.expr_usize(self.span, 0);
let null = self.cx.expr_cast(self.span, null, self.ptr_u8());
let null = self.cx.stmt_expr(null);
let block = self.cx.block(self.span, vec![write, null]);
self.cx.expr_block(block)
};
let pat = self.cx.pat_ident(self.span, name);
let err = self.cx.path_ident(self.span, Ident::from_str("Err"));
let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]);
let err = self.cx.arm(self.span, vec![err], err_expr);
let expr = self.cx.expr_match(self.span, expr, vec![ok, err]);
(self.ptr_u8(), expr)
}
AllocatorTy::ResultPtr => {
// We're creating:
//
// match #expr {
// Ok(ptr) => ptr,
// Err(e) => {
// ptr::write(err_ptr, e);
// 0 as *mut u8
// }
// }
// #expr as *mut u8
let err_ptr = ident();
args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8()));
let err_ptr = self.cx.expr_ident(self.span, err_ptr);
let err_ptr = self.cx.expr_cast(self.span,
err_ptr,
self.alloc_err_ptr());
let name = ident();
let ok_expr = self.cx.expr_ident(self.span, name);
let pat = self.cx.pat_ident(self.span, name);
let ok = self.cx.path_ident(self.span, Ident::from_str("Ok"));
let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]);
let ok = self.cx.arm(self.span, vec![ok], ok_expr);
let name = ident();
let err_expr = {
let err = self.cx.expr_ident(self.span, name);
let write = self.cx.path(self.span, vec![
self.alloc,
Ident::from_str("heap"),
Ident::from_str("__core"),
Ident::from_str("ptr"),
Ident::from_str("write"),
]);
let write = self.cx.expr_path(write);
let write = self.cx.expr_call(self.span, write,
vec![err_ptr, err]);
let write = self.cx.stmt_semi(write);
let null = self.cx.expr_usize(self.span, 0);
let null = self.cx.expr_cast(self.span, null, self.ptr_u8());
let null = self.cx.stmt_expr(null);
let block = self.cx.block(self.span, vec![write, null]);
self.cx.expr_block(block)
};
let pat = self.cx.pat_ident(self.span, name);
let err = self.cx.path_ident(self.span, Ident::from_str("Err"));
let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]);
let err = self.cx.arm(self.span, vec![err], err_expr);
let expr = self.cx.expr_match(self.span, expr, vec![ok, err]);
let expr = self.cx.expr_cast(self.span, expr, self.ptr_u8());
(self.ptr_u8(), expr)
}
AllocatorTy::ResultUnit => {
// We're creating:
//
// #expr.is_ok() as u8
let cast = self.cx.expr_method_call(
self.span,
expr,
Ident::from_str("is_ok"),
Vec::new()
);
let u8 = self.cx.path_ident(self.span, Ident::from_str("u8"));
let u8 = self.cx.ty_path(u8);
let cast = self.cx.expr_cast(self.span, cast, u8.clone());
(u8, cast)
}
AllocatorTy::Bang => {
(self.cx.ty(self.span, TyKind::Never), expr)
}
AllocatorTy::Unit => {
(self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr)
}
AllocatorTy::AllocErr |
AllocatorTy::Layout |
AllocatorTy::LayoutRef |
AllocatorTy::Usize |
AllocatorTy::Ptr => {
panic!("can't convert AllocatorTy to an output")
}
}
}
fn usize(&self) -> P<Ty> {
let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
self.cx.ty_path(usize)
}
fn ptr_u8(&self) -> P<Ty> {
let u8 = self.cx.path_ident(self.span, Ident::from_str("u8"));
let ty_u8 = self.cx.ty_path(u8);
self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
}
fn ptr_usize(&self) -> P<Ty> {
let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
let ty_usize = self.cx.ty_path(usize);
self.cx.ty_ptr(self.span, ty_usize, Mutability::Mutable)
}
fn layout_ptr(&self) -> P<Ty> {
let layout = self.cx.path(self.span, vec![
self.alloc,
Ident::from_str("heap"),
Ident::from_str("Layout"),
fn ptr_void(&self) -> P<Ty> {
let void = self.cx.path(self.span, vec![
self.core,
Ident::from_str("alloc"),
Ident::from_str("Void"),
]);
let layout = self.cx.ty_path(layout);
self.cx.ty_ptr(self.span, layout, Mutability::Mutable)
}
fn alloc_err_ptr(&self) -> P<Ty> {
let err = self.cx.path(self.span, vec![
self.alloc,
Ident::from_str("heap"),
Ident::from_str("AllocErr"),
]);
let err = self.cx.ty_path(err);
self.cx.ty_ptr(self.span, err, Mutability::Mutable)
let ty_void = self.cx.ty_path(void);
self.cx.ty_ptr(self.span, ty_void, Mutability::Mutable)
}
}

View File

@ -23,24 +23,14 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[
inputs: &[AllocatorTy::Layout],
output: AllocatorTy::ResultPtr,
},
AllocatorMethod {
name: "oom",
inputs: &[AllocatorTy::AllocErr],
output: AllocatorTy::Bang,
},
AllocatorMethod {
name: "dealloc",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
output: AllocatorTy::Unit,
},
AllocatorMethod {
name: "usable_size",
inputs: &[AllocatorTy::LayoutRef],
output: AllocatorTy::UsizePair,
},
AllocatorMethod {
name: "realloc",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Usize],
output: AllocatorTy::ResultPtr,
},
AllocatorMethod {
@ -48,26 +38,6 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[
inputs: &[AllocatorTy::Layout],
output: AllocatorTy::ResultPtr,
},
AllocatorMethod {
name: "alloc_excess",
inputs: &[AllocatorTy::Layout],
output: AllocatorTy::ResultExcess,
},
AllocatorMethod {
name: "realloc_excess",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
output: AllocatorTy::ResultExcess,
},
AllocatorMethod {
name: "grow_in_place",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
output: AllocatorTy::ResultUnit,
},
AllocatorMethod {
name: "shrink_in_place",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
output: AllocatorTy::ResultUnit,
},
];
pub struct AllocatorMethod {
@ -77,14 +47,9 @@ pub struct AllocatorMethod {
}
pub enum AllocatorTy {
AllocErr,
Bang,
Layout,
LayoutRef,
Ptr,
ResultExcess,
ResultPtr,
ResultUnit,
Unit,
UsizePair,
Usize,
}

View File

@ -30,7 +30,6 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind)
};
let i8 = llvm::LLVMInt8TypeInContext(llcx);
let i8p = llvm::LLVMPointerType(i8, 0);
let usizep = llvm::LLVMPointerType(usize, 0);
let void = llvm::LLVMVoidTypeInContext(llcx);
for method in ALLOCATOR_METHODS {
@ -41,40 +40,19 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind)
args.push(usize); // size
args.push(usize); // align
}
AllocatorTy::LayoutRef => args.push(i8p),
AllocatorTy::Ptr => args.push(i8p),
AllocatorTy::AllocErr => args.push(i8p),
AllocatorTy::Usize => args.push(usize),
AllocatorTy::Bang |
AllocatorTy::ResultExcess |
AllocatorTy::ResultPtr |
AllocatorTy::ResultUnit |
AllocatorTy::UsizePair |
AllocatorTy::Unit => panic!("invalid allocator arg"),
}
}
let output = match method.output {
AllocatorTy::UsizePair => {
args.push(usizep); // min
args.push(usizep); // max
None
}
AllocatorTy::Bang => None,
AllocatorTy::ResultExcess => {
args.push(i8p); // excess_ptr
args.push(i8p); // err_ptr
Some(i8p)
}
AllocatorTy::ResultPtr => {
args.push(i8p); // err_ptr
Some(i8p)
}
AllocatorTy::ResultUnit => Some(i8),
AllocatorTy::ResultPtr => Some(i8p),
AllocatorTy::Unit => None,
AllocatorTy::AllocErr |
AllocatorTy::Layout |
AllocatorTy::LayoutRef |
AllocatorTy::Usize |
AllocatorTy::Ptr => panic!("invalid allocator output"),
};
let ty = llvm::LLVMFunctionType(output.unwrap_or(void),

View File

@ -21,7 +21,7 @@
#[doc(hidden)]
#[allow(unused_attributes)]
pub mod __default_lib_allocator {
use super::{System, Layout, Alloc, AllocErr, CannotReallocInPlace};
use super::{System, Layout, GlobalAlloc, Void};
// for symbol names src/librustc/middle/allocator.rs
// for signatures src/librustc_allocator/lib.rs
@ -30,20 +30,9 @@ pub mod __default_lib_allocator {
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc(size: usize,
align: usize,
_err: *mut u8) -> *mut u8 {
pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
let layout = Layout::from_size_align_unchecked(size, align);
match System.alloc(layout) {
Ok(p) => p,
Err(AllocErr) => 0 as *mut u8,
}
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_oom(err: *const u8) -> ! {
System.oom((*(err as *const AllocErr)).clone())
System.alloc(layout) as *mut u8
}
#[no_mangle]
@ -51,110 +40,76 @@ pub mod __default_lib_allocator {
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
size: usize,
align: usize) {
System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_usable_size(layout: *const u8,
min: *mut usize,
max: *mut usize) {
let pair = System.usable_size(&*(layout as *const Layout));
*min = pair.0;
*max = pair.1;
System.dealloc(ptr as *mut Void, Layout::from_size_align_unchecked(size, align))
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize,
_err: *mut u8) -> *mut u8 {
let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
match System.realloc(ptr, old_layout, new_layout) {
Ok(p) => p,
Err(AllocErr) => 0 as *mut u8,
}
align: usize,
new_size: usize) -> *mut u8 {
let old_layout = Layout::from_size_align_unchecked(old_size, align);
System.realloc(ptr as *mut Void, old_layout, new_size) as *mut u8
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_zeroed(size: usize,
align: usize,
_err: *mut u8) -> *mut u8 {
pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
let layout = Layout::from_size_align_unchecked(size, align);
match System.alloc_zeroed(layout) {
Ok(p) => p,
Err(AllocErr) => 0 as *mut u8,
}
System.alloc_zeroed(layout) as *mut u8
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_excess(size: usize,
align: usize,
excess: *mut usize,
_err: *mut u8) -> *mut u8 {
let layout = Layout::from_size_align_unchecked(size, align);
match System.alloc_excess(layout) {
Ok(p) => {
*excess = p.1;
p.0
}
Err(AllocErr) => 0 as *mut u8,
#[cfg(stage0)]
pub mod stage0 {
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_usable_size(_layout: *const u8,
_min: *mut usize,
_max: *mut usize) {
unimplemented!()
}
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize,
excess: *mut usize,
_err: *mut u8) -> *mut u8 {
let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
match System.realloc_excess(ptr, old_layout, new_layout) {
Ok(p) => {
*excess = p.1;
p.0
}
Err(AllocErr) => 0 as *mut u8,
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_excess(_size: usize,
_align: usize,
_excess: *mut usize,
_err: *mut u8) -> *mut u8 {
unimplemented!()
}
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize) -> u8 {
let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
match System.grow_in_place(ptr, old_layout, new_layout) {
Ok(()) => 1,
Err(CannotReallocInPlace) => 0,
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_realloc_excess(_ptr: *mut u8,
_old_size: usize,
_old_align: usize,
_new_size: usize,
_new_align: usize,
_excess: *mut usize,
_err: *mut u8) -> *mut u8 {
unimplemented!()
}
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8,
old_size: usize,
old_align: usize,
new_size: usize,
new_align: usize) -> u8 {
let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
match System.shrink_in_place(ptr, old_layout, new_layout) {
Ok(()) => 1,
Err(CannotReallocInPlace) => 0,
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_grow_in_place(_ptr: *mut u8,
_old_size: usize,
_old_align: usize,
_new_size: usize,
_new_align: usize) -> u8 {
unimplemented!()
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_shrink_in_place(_ptr: *mut u8,
_old_size: usize,
_old_align: usize,
_new_size: usize,
_new_align: usize) -> u8 {
unimplemented!()
}
}
}

@ -1 +1 @@
Subproject commit 6ceaaa4b0176a200e4bbd347d6a991ab6c776ede
Subproject commit 7243155b1c3da0a980c868a87adebf00e0b33989

View File

@ -1,4 +1,4 @@
# If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
2018-03-10
2018-04-05

View File

@ -12,15 +12,9 @@
#[global_allocator]
static A: usize = 0;
//~^ the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~^ the trait bound `usize:
//~| the trait bound `usize:
//~| the trait bound `usize:
//~| the trait bound `usize:
fn main() {}

View File

@ -11,16 +11,16 @@
#![feature(allocator_api)]
#![crate_type = "rlib"]
use std::heap::*;
use std::alloc::*;
pub struct A;
unsafe impl<'a> Alloc for &'a A {
unsafe fn alloc(&mut self, _: Layout) -> Result<*mut u8, AllocErr> {
unsafe impl GlobalAlloc for A {
unsafe fn alloc(&self, _: Layout) -> *mut Void {
loop {}
}
unsafe fn dealloc(&mut self, _ptr: *mut u8, _: Layout) {
unsafe fn dealloc(&self, _ptr: *mut Void, _: Layout) {
loop {}
}
}

View File

@ -13,18 +13,18 @@
#![feature(heap_api, allocator_api)]
#![crate_type = "rlib"]
use std::heap::{Alloc, System, AllocErr, Layout};
use std::heap::{GlobalAlloc, System, Layout, Void};
use std::sync::atomic::{AtomicUsize, Ordering};
pub struct A(pub AtomicUsize);
unsafe impl<'a> Alloc for &'a A {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
unsafe impl GlobalAlloc for A {
unsafe fn alloc(&self, layout: Layout) -> *mut Void {
self.0.fetch_add(1, Ordering::SeqCst);
System.alloc(layout)
}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) {
self.0.fetch_add(1, Ordering::SeqCst);
System.dealloc(ptr, layout)
}

View File

@ -15,20 +15,20 @@
extern crate helper;
use std::heap::{Heap, Alloc, System, Layout, AllocErr};
use std::alloc::{self, Global, Alloc, System, Layout, Void};
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
struct A;
unsafe impl<'a> Alloc for &'a A {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
unsafe impl alloc::GlobalAlloc for A {
unsafe fn alloc(&self, layout: Layout) -> *mut Void {
HITS.fetch_add(1, Ordering::SeqCst);
System.alloc(layout)
}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
unsafe fn dealloc(&self, ptr: *mut Void, layout: Layout) {
HITS.fetch_add(1, Ordering::SeqCst);
System.dealloc(ptr, layout)
}
@ -45,10 +45,10 @@ fn main() {
unsafe {
let layout = Layout::from_size_align(4, 2).unwrap();
let ptr = Heap.alloc(layout.clone()).unwrap();
let ptr = Global.alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
assert_eq!(HITS.load(Ordering::SeqCst), n + 1);
Heap.dealloc(ptr, layout.clone());
Global.dealloc(ptr, layout.clone());
assert_eq!(HITS.load(Ordering::SeqCst), n + 2);
let s = String::with_capacity(10);

View File

@ -17,7 +17,7 @@
extern crate custom;
extern crate helper;
use std::heap::{Heap, Alloc, System, Layout};
use std::alloc::{Global, Alloc, System, Layout};
use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
#[global_allocator]
@ -28,10 +28,10 @@ fn main() {
let n = GLOBAL.0.load(Ordering::SeqCst);
let layout = Layout::from_size_align(4, 2).unwrap();
let ptr = Heap.alloc(layout.clone()).unwrap();
let ptr = Global.alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
Heap.dealloc(ptr, layout.clone());
Global.dealloc(ptr, layout.clone());
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
let ptr = System.alloc(layout.clone()).unwrap();

View File

@ -19,7 +19,7 @@ extern crate custom;
extern crate custom_as_global;
extern crate helper;
use std::heap::{Heap, Alloc, System, Layout};
use std::alloc::{Global, Alloc, GlobalAlloc, System, Layout};
use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
@ -30,25 +30,25 @@ fn main() {
let layout = Layout::from_size_align(4, 2).unwrap();
// Global allocator routes to the `custom_as_global` global
let ptr = Heap.alloc(layout.clone()).unwrap();
let ptr = Global.alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
assert_eq!(custom_as_global::get(), n + 1);
Heap.dealloc(ptr, layout.clone());
Global.dealloc(ptr, layout.clone());
assert_eq!(custom_as_global::get(), n + 2);
// Usage of the system allocator avoids all globals
let ptr = System.alloc(layout.clone()).unwrap();
let ptr = System.alloc(layout.clone());
helper::work_with(&ptr);
assert_eq!(custom_as_global::get(), n + 2);
System.dealloc(ptr, layout.clone());
assert_eq!(custom_as_global::get(), n + 2);
// Usage of our personal allocator doesn't affect other instances
let ptr = (&GLOBAL).alloc(layout.clone()).unwrap();
let ptr = GLOBAL.alloc(layout.clone());
helper::work_with(&ptr);
assert_eq!(custom_as_global::get(), n + 2);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 1);
(&GLOBAL).dealloc(ptr, layout);
GLOBAL.dealloc(ptr, layout);
assert_eq!(custom_as_global::get(), n + 2);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 2);
}