1 // Copyright 2015 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.
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.
13 #![unstable(feature = "alloc_system",
14 reason
= "this library is unlikely to be stabilized in its current \
17 #![feature(global_allocator)]
18 #![feature(allocator_api)]
20 #![feature(core_intrinsics)]
21 #![feature(staged_api)]
22 #![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
24 // The minimum alignment guaranteed by the architecture. This value is used to
25 // add fast paths for low alignment values. In practice, the alignment is a
26 // constant at the call site and the branch will be optimized out.
27 #[cfg(all(any(target_arch = "x86",
30 target_arch
= "powerpc",
31 target_arch
= "powerpc64",
32 target_arch
= "asmjs",
33 target_arch
= "wasm32")))]
34 const MIN_ALIGN
: usize = 8;
35 #[cfg(all(any(target_arch = "x86_64",
36 target_arch
= "aarch64",
37 target_arch
= "mips64",
38 target_arch
= "s390x",
39 target_arch
= "sparc64")))]
40 const MIN_ALIGN
: usize = 16;
44 use self::alloc
::heap
::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}
;
46 #[unstable(feature = "allocator_api", issue = "32838")]
49 #[unstable(feature = "allocator_api", issue = "32838")]
50 unsafe impl Alloc
for System
{
52 unsafe fn alloc(&mut self, layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
53 (&*self).alloc(layout
)
57 unsafe fn alloc_zeroed(&mut self, layout
: Layout
)
58 -> Result
<*mut u8, AllocErr
>
60 (&*self).alloc_zeroed(layout
)
64 unsafe fn dealloc(&mut self, ptr
: *mut u8, layout
: Layout
) {
65 (&*self).dealloc(ptr
, layout
)
69 unsafe fn realloc(&mut self,
72 new_layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
73 (&*self).realloc(ptr
, old_layout
, new_layout
)
76 fn oom(&mut self, err
: AllocErr
) -> ! {
81 fn usable_size(&self, layout
: &Layout
) -> (usize, usize) {
82 (&self).usable_size(layout
)
86 unsafe fn alloc_excess(&mut self, layout
: Layout
) -> Result
<Excess
, AllocErr
> {
87 (&*self).alloc_excess(layout
)
91 unsafe fn realloc_excess(&mut self,
94 new_layout
: Layout
) -> Result
<Excess
, AllocErr
> {
95 (&*self).realloc_excess(ptr
, layout
, new_layout
)
99 unsafe fn grow_in_place(&mut self,
102 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
103 (&*self).grow_in_place(ptr
, layout
, new_layout
)
107 unsafe fn shrink_in_place(&mut self,
110 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
111 (&*self).shrink_in_place(ptr
, layout
, new_layout
)
115 #[cfg(any(unix, target_os = "redox"))]
124 use alloc
::heap
::{Alloc, AllocErr, Layout}
;
126 #[unstable(feature = "allocator_api", issue = "32838")]
127 unsafe impl<'a
> Alloc
for &'a System
{
129 unsafe fn alloc(&mut self, layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
130 let ptr
= if layout
.align() <= MIN_ALIGN
{
131 libc
::malloc(layout
.size()) as *mut u8
133 aligned_malloc(&layout
)
138 Err(AllocErr
::Exhausted { request: layout }
)
143 unsafe fn alloc_zeroed(&mut self, layout
: Layout
)
144 -> Result
<*mut u8, AllocErr
>
146 if layout
.align() <= MIN_ALIGN
{
147 let ptr
= libc
::calloc(layout
.size(), 1) as *mut u8;
151 Err(AllocErr
::Exhausted { request: layout }
)
154 let ret
= self.alloc(layout
.clone());
155 if let Ok(ptr
) = ret
{
156 ptr
::write_bytes(ptr
, 0, layout
.size());
163 unsafe fn dealloc(&mut self, ptr
: *mut u8, _layout
: Layout
) {
164 libc
::free(ptr
as *mut libc
::c_void
)
168 unsafe fn realloc(&mut self,
171 new_layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
172 if old_layout
.align() != new_layout
.align() {
173 return Err(AllocErr
::Unsupported
{
174 details
: "cannot change alignment on `realloc`",
178 if new_layout
.align() <= MIN_ALIGN
{
179 let ptr
= libc
::realloc(ptr
as *mut libc
::c_void
, new_layout
.size());
183 Err(AllocErr
::Exhausted { request: new_layout }
)
186 let res
= self.alloc(new_layout
.clone());
187 if let Ok(new_ptr
) = res
{
188 let size
= cmp
::min(old_layout
.size(), new_layout
.size());
189 ptr
::copy_nonoverlapping(ptr
, new_ptr
, size
);
190 self.dealloc(ptr
, old_layout
);
196 fn oom(&mut self, err
: AllocErr
) -> ! {
197 use core
::fmt
::{self, Write}
;
199 // Print a message to stderr before aborting to assist with
200 // debugging. It is critical that this code does not allocate any
201 // memory since we are in an OOM situation. Any errors are ignored
202 // while printing since there's nothing we can do about them and we
203 // are about to exit anyways.
204 drop(writeln
!(Stderr
, "fatal runtime error: {}", err
));
206 ::core
::intrinsics
::abort();
211 impl Write
for Stderr
{
212 fn write_str(&mut self, s
: &str) -> fmt
::Result
{
214 libc
::write(libc
::STDERR_FILENO
,
215 s
.as_ptr() as *const libc
::c_void
,
224 #[cfg(any(target_os = "android", target_os = "redox"))]
226 unsafe fn aligned_malloc(layout
: &Layout
) -> *mut u8 {
227 // On android we currently target API level 9 which unfortunately
228 // doesn't have the `posix_memalign` API used below. Instead we use
229 // `memalign`, but this unfortunately has the property on some systems
230 // where the memory returned cannot be deallocated by `free`!
232 // Upon closer inspection, however, this appears to work just fine with
233 // Android, so for this platform we should be fine to call `memalign`
234 // (which is present in API level 9). Some helpful references could
235 // possibly be chromium using memalign [1], attempts at documenting that
236 // memalign + free is ok [2] [3], or the current source of chromium
237 // which still uses memalign on android [4].
239 // [1]: https://codereview.chromium.org/10796020/
240 // [2]: https://code.google.com/p/android/issues/detail?id=35391
241 // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
242 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
243 // /memory/aligned_memory.cc
244 libc
::memalign(layout
.align(), layout
.size()) as *mut u8
247 #[cfg(not(any(target_os = "android", target_os = "redox")))]
249 unsafe fn aligned_malloc(layout
: &Layout
) -> *mut u8 {
250 let mut out
= ptr
::null_mut();
251 let ret
= libc
::posix_memalign(&mut out
, layout
.align(), layout
.size());
268 use alloc
::heap
::{Alloc, AllocErr, Layout, CannotReallocInPlace}
;
270 type LPVOID
= *mut u8;
271 type HANDLE
= LPVOID
;
275 type LPDWORD
= *mut DWORD
;
276 type LPOVERLAPPED
= *mut u8;
278 const STD_ERROR_HANDLE
: DWORD
= -12i32 as DWORD
;
281 fn GetProcessHeap() -> HANDLE
;
282 fn HeapAlloc(hHeap
: HANDLE
, dwFlags
: DWORD
, dwBytes
: SIZE_T
) -> LPVOID
;
283 fn HeapReAlloc(hHeap
: HANDLE
, dwFlags
: DWORD
, lpMem
: LPVOID
, dwBytes
: SIZE_T
) -> LPVOID
;
284 fn HeapFree(hHeap
: HANDLE
, dwFlags
: DWORD
, lpMem
: LPVOID
) -> BOOL
;
285 fn GetLastError() -> DWORD
;
286 fn WriteFile(hFile
: HANDLE
,
288 nNumberOfBytesToWrite
: DWORD
,
289 lpNumberOfBytesWritten
: LPDWORD
,
290 lpOverlapped
: LPOVERLAPPED
)
292 fn GetStdHandle(which
: DWORD
) -> HANDLE
;
296 struct Header(*mut u8);
298 const HEAP_ZERO_MEMORY
: DWORD
= 0x00000008;
299 const HEAP_REALLOC_IN_PLACE_ONLY
: DWORD
= 0x00000010;
301 unsafe fn get_header
<'a
>(ptr
: *mut u8) -> &'a
mut Header
{
302 &mut *(ptr
as *mut Header
).offset(-1)
305 unsafe fn align_ptr(ptr
: *mut u8, align
: usize) -> *mut u8 {
306 let aligned
= ptr
.offset((align
- (ptr
as usize & (align
- 1))) as isize);
307 *get_header(aligned
) = Header(ptr
);
312 unsafe fn allocate_with_flags(layout
: Layout
, flags
: DWORD
)
313 -> Result
<*mut u8, AllocErr
>
315 let ptr
= if layout
.align() <= MIN_ALIGN
{
316 HeapAlloc(GetProcessHeap(), flags
, layout
.size())
318 let size
= layout
.size() + layout
.align();
319 let ptr
= HeapAlloc(GetProcessHeap(), flags
, size
);
323 align_ptr(ptr
, layout
.align())
327 Err(AllocErr
::Exhausted { request: layout }
)
333 #[unstable(feature = "allocator_api", issue = "32838")]
334 unsafe impl<'a
> Alloc
for &'a System
{
336 unsafe fn alloc(&mut self, layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
337 allocate_with_flags(layout
, 0)
341 unsafe fn alloc_zeroed(&mut self, layout
: Layout
)
342 -> Result
<*mut u8, AllocErr
>
344 allocate_with_flags(layout
, HEAP_ZERO_MEMORY
)
348 unsafe fn dealloc(&mut self, ptr
: *mut u8, layout
: Layout
) {
349 if layout
.align() <= MIN_ALIGN
{
350 let err
= HeapFree(GetProcessHeap(), 0, ptr
as LPVOID
);
351 debug_assert
!(err
!= 0, "Failed to free heap memory: {}",
354 let header
= get_header(ptr
);
355 let err
= HeapFree(GetProcessHeap(), 0, header
.0 as LPVOID
);
356 debug_assert
!(err
!= 0, "Failed to free heap memory: {}",
362 unsafe fn realloc(&mut self,
365 new_layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
366 if old_layout
.align() != new_layout
.align() {
367 return Err(AllocErr
::Unsupported
{
368 details
: "cannot change alignment on `realloc`",
372 if new_layout
.align() <= MIN_ALIGN
{
373 let ptr
= HeapReAlloc(GetProcessHeap(),
380 Err(AllocErr
::Exhausted { request: new_layout }
)
383 let res
= self.alloc(new_layout
.clone());
384 if let Ok(new_ptr
) = res
{
385 let size
= cmp
::min(old_layout
.size(), new_layout
.size());
386 ptr
::copy_nonoverlapping(ptr
, new_ptr
, size
);
387 self.dealloc(ptr
, old_layout
);
394 unsafe fn grow_in_place(&mut self,
397 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
398 self.shrink_in_place(ptr
, layout
, new_layout
)
402 unsafe fn shrink_in_place(&mut self,
405 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
406 if old_layout
.align() != new_layout
.align() {
407 return Err(CannotReallocInPlace
)
410 let new
= if new_layout
.align() <= MIN_ALIGN
{
411 HeapReAlloc(GetProcessHeap(),
412 HEAP_REALLOC_IN_PLACE_ONLY
,
416 let header
= get_header(ptr
);
417 HeapReAlloc(GetProcessHeap(),
418 HEAP_REALLOC_IN_PLACE_ONLY
,
420 new_layout
.size() + new_layout
.align())
423 Err(CannotReallocInPlace
)
429 fn oom(&mut self, err
: AllocErr
) -> ! {
430 use core
::fmt
::{self, Write}
;
432 // Same as with unix we ignore all errors here
433 drop(writeln
!(Stderr
, "fatal runtime error: {}", err
));
435 ::core
::intrinsics
::abort();
440 impl Write
for Stderr
{
441 fn write_str(&mut self, s
: &str) -> fmt
::Result
{
443 // WriteFile silently fails if it is passed an invalid
444 // handle, so there is no need to check the result of
446 WriteFile(GetStdHandle(STD_ERROR_HANDLE
),
447 s
.as_ptr() as LPVOID
,