1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11
12 //! The global (exchange) heap.
13
14 use libc::{c_void, size_t, free, malloc, realloc};
15 use ptr::{RawPtr, mut_null};
16 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 }
34
35 /// A wrapper around libc::malloc, aborting on out-of-memory
36 #[inline]
37 pub unsafe fn malloc_raw(size: uint) -> *mut u8 {
38 // `malloc(0)` may allocate, but it may also return a null pointer
39 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html
40 if size == 0 {
41 mut_null()
42 } else {
43 let p = malloc(size as size_t);
44 if p.is_null() {
45 // we need a non-allocating way to print an error here
46 abort();
47 }
48 p as *mut u8
49 }
50 }
51
52 /// A wrapper around libc::realloc, aborting on out-of-memory
53 #[inline]
54 pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 {
55 // `realloc(ptr, 0)` may allocate, but it may also return a null pointer
56 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html
57 if size == 0 {
58 free(ptr as *mut c_void);
59 mut_null()
60 } else {
61 let p = realloc(ptr as *mut c_void, size as size_t);
62 if p.is_null() {
63 // we need a non-allocating way to print an error here
64 abort();
65 }
66 p as *mut u8
67 }
68 }
69
70 /// The allocator for unique pointers without contained managed pointers.
71 #[cfg(not(test))]
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 // FIXME: #7496
89 #[cfg(not(test))]
90 #[lang="closure_exchange_malloc"]
91 #[inline]
92 pub unsafe fn closure_exchange_malloc_(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
93 closure_exchange_malloc(drop_glue, size, align)
94 }
95
96 #[inline]
97 pub unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
98 let total_size = get_box_size(size, align);
99 let p = malloc_raw(total_size);
100
101 let alloc = p as *mut raw::Box<()>;
102 (*alloc).drop_glue = drop_glue;
103
104 alloc as *u8
105 }
106
107 // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
108 // inside a landing pad may corrupt the state of the exception handler.
109 #[cfg(not(test))]
110 #[lang="exchange_free"]
111 #[inline]
112 pub unsafe fn exchange_free_(ptr: *u8) {
113 exchange_free(ptr)
114 }
115
116 #[inline]
117 pub unsafe fn exchange_free(ptr: *u8) {
118 free(ptr as *mut c_void);
119 }
120
121 #[cfg(test)]
122 mod bench {
123 extern crate test;
124 use self::test::Bencher;
125
126 #[bench]
127 fn alloc_owned_small(b: &mut Bencher) {
128 b.iter(|| {
129 box 10
130 })
131 }
132
133 #[bench]
134 fn alloc_owned_big(b: &mut Bencher) {
135 b.iter(|| {
136 box [10, ..1000]
137 })
138 }
139 }
libstd/rt/global_heap.rs:20:10-20:10 -fn- definition:
pub fn get_box_size(body_size: uint, body_align: uint) -> uint {
let header_size = size_of::<raw::Box<()>>();
let total_size = align_to(header_size, body_align) + body_size;
references:- 297: pub unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint, align: uint) -> *u8 {
98: let total_size = get_box_size(size, align);
99: let p = malloc_raw(total_size);
libstd/rt/local_heap.rs:
60: 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 alloc = self.memory_region.malloc(total_size);
libstd/rt/global_heap.rs:116:10-116:10 -fn- definition:
pub unsafe fn exchange_free(ptr: *u8) {
free(ptr as *mut c_void);
}
references:- 6112: pub unsafe fn exchange_free_(ptr: *u8) {
113: exchange_free(ptr)
114: }
libstd/rt/local_heap.rs:
228: self.live_allocations -= 1;
229: global_heap::exchange_free(alloc as *u8)
230: }
libstd/slice.rs:
331: }
332: exchange_free(ret as *u8);
333: });
--
770: unsafe {
771: exchange_free(self.allocation as *u8)
772: }
libstd/rc.rs:
179: if self.weak() == 0 {
180: exchange_free(self.ptr as *u8)
181: }
libstd/rt/global_heap.rs:36:10-36:10 -fn- definition:
pub unsafe fn malloc_raw(size: uint) -> *mut u8 {
// `malloc(0)` may allocate, but it may also return a null pointer
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html
references:- 898: let total_size = get_box_size(size, align);
99: let p = malloc_raw(total_size);
libstd/rt/local_heap.rs:
189: let alloc: *AllocHeader = unsafe {
190: global_heap::malloc_raw(total_size) as *AllocHeader
191: };
libstd/slice.rs:
307: unsafe {
308: let ret = malloc_raw(size) as *mut RawVec<()>;
libstd/vec.rs:
1495: unsafe {
1496: let ret = malloc_raw(size) as *mut RawVec<()>;
libstd/c_str.rs:
104: let len = self.len() + 1;
105: let buf = unsafe { malloc_raw(len) } as *mut libc::c_char;
106: unsafe { ptr::copy_nonoverlapping_memory(buf, self.buf, len); }
--
329: let self_len = self.len();
330: let buf = malloc_raw(self_len + 1);
libstd/vec.rs:
98: let size = capacity.checked_mul(&size_of::<T>()).expect("capacity overflow");
99: let ptr = unsafe { malloc_raw(size) };
100: Vec { len: 0, cap: capacity, ptr: ptr as *mut T }
libstd/rt/global_heap.rs:53:10-53:10 -fn- definition:
pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 {
// `realloc(ptr, 0)` may allocate, but it may also return a null pointer
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html
references:- 4libstd/rt/local_heap.rs:
208: let alloc: *AllocHeader = unsafe {
209: global_heap::realloc_raw(orig_alloc as *mut u8,
210: total_size) as *AllocHeader
libstd/vec.rs:
505: // Overflow check is unnecessary as the vector is already at least this large.
506: self.ptr = realloc_raw(self.ptr as *mut u8, self.len * size_of::<T>()) as *mut T;
507: }
--
555: unsafe {
556: self.ptr = realloc_raw(self.ptr as *mut u8, size) as *mut T;
557: }