Skip to content

Commit 1384379

Browse files
committed
initial port of the exchange allocator to jemalloc
In stage0, all allocations are 8-byte aligned. Passing a size and alignment to free is not yet implemented everywhere (0 size and 8 align are used as placeholders). Fixing this is part of #13994. Closes #13616
1 parent aaf6e06 commit 1384379

File tree

11 files changed

+219
-151
lines changed

11 files changed

+219
-151
lines changed

src/libarena/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use std::mem::min_align_of;
3737
use std::num;
3838
use std::ptr::read;
3939
use std::rc::Rc;
40-
use std::rt::global_heap;
40+
use std::rt::heap::exchange_malloc;
4141

4242
// The way arena uses arrays is really deeply awful. The arrays are
4343
// allocated, and have capacities reserved, but the fill for the array
@@ -365,7 +365,7 @@ impl<T> TypedArenaChunk<T> {
365365
size = size.checked_add(&elems_size).unwrap();
366366

367367
let mut chunk = unsafe {
368-
let chunk = global_heap::exchange_malloc(size);
368+
let chunk = exchange_malloc(size);
369369
let mut chunk: Box<TypedArenaChunk<T>> = cast::transmute(chunk);
370370
mem::move_val_init(&mut chunk.next, next);
371371
chunk
@@ -386,7 +386,7 @@ impl<T> TypedArenaChunk<T> {
386386
size = size.checked_add(&elems_size).unwrap();
387387

388388
let mut chunk = unsafe {
389-
let chunk = global_heap::exchange_malloc(size, min_align_of::<TypedArenaChunk<T>>());
389+
let chunk = exchange_malloc(size, min_align_of::<TypedArenaChunk<T>>());
390390
let mut chunk: Box<TypedArenaChunk<T>> = cast::transmute(chunk);
391391
mem::move_val_init(&mut chunk.next, next);
392392
chunk

src/libcore/should_not_exist.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ extern {
3333
fn rust_malloc(size: uint) -> *u8;
3434
#[cfg(not(stage0))]
3535
fn rust_malloc(size: uint, align: uint) -> *u8;
36-
fn rust_free(ptr: *u8);
36+
fn rust_free(ptr: *u8, size: uint, align: uint);
3737
}
3838

3939
#[cfg(stage0)]
@@ -51,6 +51,7 @@ unsafe fn alloc(cap: uint) -> *mut Vec<()> {
5151
#[cfg(not(stage0))]
5252
unsafe fn alloc(cap: uint) -> *mut Vec<()> {
5353
let cap = cap.checked_add(&mem::size_of::<Vec<()>>()).unwrap();
54+
// this should use the real alignment, but the new representation will take care of that
5455
let ret = rust_malloc(cap, 8) as *mut Vec<()>;
5556
if ret.is_null() {
5657
intrinsics::abort();
@@ -118,7 +119,8 @@ impl FromIterator<char> for ~str {
118119
ptr::copy_nonoverlapping_memory(&mut (*ptr2).data,
119120
&(*ptr).data,
120121
len);
121-
rust_free(ptr as *u8);
122+
// FIXME: #13994: port to the sized deallocation API when available
123+
rust_free(ptr as *u8, 0, 8);
122124
cast::forget(ret);
123125
ret = cast::transmute(ptr2);
124126
ptr = ptr2;
@@ -188,7 +190,7 @@ impl<A: Clone> Clone for ~[A] {
188190
for j in range(0, *i as int) {
189191
ptr::read(&*p.offset(j));
190192
}
191-
rust_free(ret as *u8);
193+
rust_free(ret as *u8, 0, 8);
192194
});
193195
cast::transmute(ret)
194196
}

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
// Don't link to std. We are std.
111111
#![no_std]
112112

113+
#![allow(deprecated)]
113114
#![deny(missing_doc)]
114115

115116
// When testing libstd, bring in libuv as the I/O backend so tests can print

src/libstd/rc.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ use ops::{Deref, Drop};
3232
use option::{Option, Some, None};
3333
use ptr;
3434
use ptr::RawPtr;
35-
use rt::global_heap::exchange_free;
35+
use mem::{min_align_of, size_of};
36+
use rt::heap::exchange_free;
3637

3738
struct RcBox<T> {
3839
value: T,
@@ -104,7 +105,8 @@ impl<T> Drop for Rc<T> {
104105
self.dec_weak();
105106

106107
if self.weak() == 0 {
107-
exchange_free(self.ptr as *u8)
108+
exchange_free(self.ptr as *mut u8, size_of::<RcBox<T>>(),
109+
min_align_of::<RcBox<T>>())
108110
}
109111
}
110112
}
@@ -177,7 +179,8 @@ impl<T> Drop for Weak<T> {
177179
// the weak count starts at 1, and will only go to
178180
// zero if all the strong pointers have disappeared.
179181
if self.weak() == 0 {
180-
exchange_free(self.ptr as *u8)
182+
exchange_free(self.ptr as *mut u8, size_of::<RcBox<T>>(),
183+
min_align_of::<RcBox<T>>())
181184
}
182185
}
183186
}

src/libstd/rt/global_heap.rs

-131
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,6 @@
1414
use libc::{c_void, size_t, free, malloc, realloc};
1515
use ptr::{RawPtr, mut_null};
1616
use intrinsics::abort;
17-
use raw;
18-
use mem::size_of;
19-
20-
#[inline]
21-
pub fn get_box_size(body_size: uint, body_align: uint) -> uint {
22-
let header_size = size_of::<raw::Box<()>>();
23-
let total_size = align_to(header_size, body_align) + body_size;
24-
total_size
25-
}
26-
27-
// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power
28-
// of two.
29-
#[inline]
30-
fn align_to(size: uint, align: uint) -> uint {
31-
assert!(align != 0);
32-
(size + align - 1) & !(align - 1)
33-
}
3417

3518
/// A wrapper around libc::malloc, aborting on out-of-memory
3619
#[inline]
@@ -66,117 +49,3 @@ pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 {
6649
p as *mut u8
6750
}
6851
}
69-
70-
/// The allocator for unique pointers without contained managed pointers.
71-
#[cfg(not(test), stage0)]
72-
#[lang="exchange_malloc"]
73-
#[inline]
74-
pub unsafe fn exchange_malloc(size: uint) -> *mut u8 {
75-
// The compiler never calls `exchange_free` on Box<ZeroSizeType>, so
76-
// zero-size allocations can point to this `static`. It would be incorrect
77-
// to use a null pointer, due to enums assuming types like unique pointers
78-
// are never null.
79-
static EMPTY: () = ();
80-
81-
if size == 0 {
82-
&EMPTY as *() as *mut u8
83-
} else {
84-
malloc_raw(size)
85-
}
86-
}
87-
88-
/// The allocator for unique pointers without contained managed pointers.
89-
#[cfg(not(test), not(stage0))]
90-
#[lang="exchange_malloc"]
91-
#[inline]
92-
pub unsafe fn exchange_malloc(size: uint, _align: uint) -> *mut u8 {
93-
// The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size
94-
// allocations can point to this `static`. It would be incorrect to use a null
95-
// pointer, due to enums assuming types like unique pointers are never null.
96-
static EMPTY: () = ();
97-
98-
if size == 0 {
99-
&EMPTY as *() as *mut u8
100-
} else {
101-
malloc_raw(size)
102-
}
103-
}
104-
105-
// FIXME: #7496
106-
#[cfg(not(test))]
107-
#[lang="closure_exchange_malloc"]
108-
#[inline]
109-
pub unsafe fn closure_exchange_malloc_(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
110-
closure_exchange_malloc(drop_glue, size, align)
111-
}
112-
113-
#[inline]
114-
pub unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
115-
let total_size = get_box_size(size, align);
116-
let p = malloc_raw(total_size);
117-
118-
let alloc = p as *mut raw::Box<()>;
119-
(*alloc).drop_glue = drop_glue;
120-
121-
alloc as *u8
122-
}
123-
124-
// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
125-
// inside a landing pad may corrupt the state of the exception handler.
126-
#[cfg(not(test))]
127-
#[lang="exchange_free"]
128-
#[inline]
129-
pub unsafe fn exchange_free_(ptr: *u8) {
130-
exchange_free(ptr)
131-
}
132-
133-
#[inline]
134-
pub unsafe fn exchange_free(ptr: *u8) {
135-
free(ptr as *mut c_void);
136-
}
137-
138-
// hack for libcore
139-
#[no_mangle]
140-
#[doc(hidden)]
141-
#[deprecated]
142-
#[cfg(stage0)]
143-
pub extern "C" fn rust_malloc(size: uint) -> *mut u8 {
144-
unsafe { exchange_malloc(size) }
145-
}
146-
147-
// hack for libcore
148-
#[no_mangle]
149-
#[doc(hidden)]
150-
#[deprecated]
151-
#[cfg(not(stage0))]
152-
pub extern "C" fn rust_malloc(size: uint, align: uint) -> *mut u8 {
153-
unsafe { exchange_malloc(size, align) }
154-
}
155-
156-
// hack for libcore
157-
#[no_mangle]
158-
#[doc(hidden)]
159-
#[deprecated]
160-
pub extern "C" fn rust_free(ptr: *u8) {
161-
unsafe { exchange_free(ptr) }
162-
}
163-
164-
#[cfg(test)]
165-
mod bench {
166-
extern crate test;
167-
use self::test::Bencher;
168-
169-
#[bench]
170-
fn alloc_owned_small(b: &mut Bencher) {
171-
b.iter(|| {
172-
box 10
173-
})
174-
}
175-
176-
#[bench]
177-
fn alloc_owned_big(b: &mut Bencher) {
178-
b.iter(|| {
179-
box [10, ..1000]
180-
})
181-
}
182-
}

src/libstd/rt/heap.rs

+122
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,125 @@ pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
9898
pub fn usable_size(size: uint, align: uint) -> uint {
9999
unsafe { je_nallocx(size as size_t, mallocx_align(align)) as uint }
100100
}
101+
102+
/// The allocator for unique pointers.
103+
#[cfg(stage0)]
104+
#[lang="exchange_malloc"]
105+
#[inline(always)]
106+
pub unsafe fn exchange_malloc_(size: uint) -> *mut u8 {
107+
exchange_malloc(size)
108+
}
109+
110+
/// The allocator for unique pointers.
111+
#[cfg(not(test), not(stage0))]
112+
#[lang="exchange_malloc"]
113+
#[inline(always)]
114+
pub unsafe fn exchange_malloc_(size: uint, align: uint) -> *mut u8 {
115+
exchange_malloc(size, align)
116+
}
117+
118+
/// The allocator for unique pointers.
119+
#[cfg(stage0)]
120+
#[inline]
121+
pub unsafe fn exchange_malloc(size: uint) -> *mut u8 {
122+
// The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size
123+
// allocations can point to this `static`. It would be incorrect to use a null
124+
// pointer, due to enums assuming types like unique pointers are never null.
125+
static EMPTY: () = ();
126+
127+
if size == 0 {
128+
&EMPTY as *() as *mut u8
129+
} else {
130+
allocate(size, 8)
131+
}
132+
}
133+
134+
/// The allocator for unique pointers.
135+
#[cfg(not(stage0))]
136+
#[inline]
137+
pub unsafe fn exchange_malloc(size: uint, align: uint) -> *mut u8 {
138+
// The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size
139+
// allocations can point to this `static`. It would be incorrect to use a null
140+
// pointer, due to enums assuming types like unique pointers are never null.
141+
static EMPTY: () = ();
142+
143+
if size == 0 {
144+
&EMPTY as *() as *mut u8
145+
} else {
146+
allocate(size, align)
147+
}
148+
}
149+
150+
#[cfg(not(test))]
151+
#[lang="exchange_free"]
152+
#[inline]
153+
// FIXME: #13994 (rustc should pass align and size here)
154+
pub unsafe fn exchange_free_(ptr: *mut u8) {
155+
exchange_free(ptr, 0, 8)
156+
}
157+
158+
#[inline]
159+
pub unsafe fn exchange_free(ptr: *mut u8, size: uint, align: uint) {
160+
deallocate(ptr, size, align);
161+
}
162+
163+
// FIXME: #7496
164+
#[cfg(not(test))]
165+
#[lang="closure_exchange_malloc"]
166+
#[inline]
167+
unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *mut u8 {
168+
let total_size = ::rt::util::get_box_size(size, align);
169+
let p = allocate(total_size, 8);
170+
171+
let alloc = p as *mut ::raw::Box<()>;
172+
(*alloc).drop_glue = drop_glue;
173+
174+
alloc as *mut u8
175+
}
176+
177+
// hack for libcore
178+
#[no_mangle]
179+
#[doc(hidden)]
180+
#[deprecated]
181+
#[cfg(stage0, not(test))]
182+
pub extern "C" fn rust_malloc(size: uint) -> *mut u8 {
183+
unsafe { exchange_malloc(size) }
184+
}
185+
186+
// hack for libcore
187+
#[no_mangle]
188+
#[doc(hidden)]
189+
#[deprecated]
190+
#[cfg(not(stage0), not(test))]
191+
pub extern "C" fn rust_malloc(size: uint, align: uint) -> *mut u8 {
192+
unsafe { exchange_malloc(size, align) }
193+
}
194+
195+
// hack for libcore
196+
#[no_mangle]
197+
#[doc(hidden)]
198+
#[deprecated]
199+
#[cfg(not(test))]
200+
pub extern "C" fn rust_free(ptr: *mut u8, size: uint, align: uint) {
201+
unsafe { exchange_free(ptr, size, align) }
202+
}
203+
204+
#[cfg(test)]
205+
mod bench {
206+
extern crate test;
207+
use self::test::Bencher;
208+
209+
#[bench]
210+
fn alloc_owned_small(b: &mut Bencher) {
211+
b.iter(|| {
212+
box 10
213+
})
214+
}
215+
216+
#[bench]
217+
fn alloc_owned_big(b: &mut Bencher) {
218+
b.iter(|| {
219+
box [10, ..1000]
220+
})
221+
}
222+
}

src/libstd/rt/local_heap.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
1313
use cast;
1414
use iter::Iterator;
15+
use libc::{c_void, free};
1516
use mem;
1617
use ops::Drop;
1718
use option::{Option, None, Some};
@@ -58,7 +59,7 @@ impl LocalHeap {
5859

5960
#[inline]
6061
pub fn alloc(&mut self, drop_glue: fn(*mut u8), size: uint, align: uint) -> *mut Box {
61-
let total_size = global_heap::get_box_size(size, align);
62+
let total_size = ::rt::util::get_box_size(size, align);
6263
let alloc = self.memory_region.malloc(total_size);
6364
{
6465
// Make sure that we can't use `mybox` outside of this scope
@@ -226,7 +227,7 @@ impl MemoryRegion {
226227
self.release(cast::transmute(alloc));
227228
rtassert!(self.live_allocations > 0);
228229
self.live_allocations -= 1;
229-
global_heap::exchange_free(alloc as *u8)
230+
free(alloc as *mut c_void)
230231
}
231232
}
232233

0 commit comments

Comments
 (0)