]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/global_heap.rs
add an align parameter to exchange_malloc
[rust.git] / src / libstd / rt / global_heap.rs
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), 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 }