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.
12 #![allow(unused_attributes)]
14 #![unstable(feature = "alloc_system",
15 reason
= "this library is unlikely to be stabilized in its current \
18 #![feature(global_allocator)]
19 #![feature(allocator_api)]
21 #![feature(core_intrinsics)]
22 #![feature(staged_api)]
23 #![feature(rustc_attrs)]
24 #![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
25 #![rustc_alloc_kind = "lib"]
27 // The minimum alignment guaranteed by the architecture. This value is used to
28 // add fast paths for low alignment values. In practice, the alignment is a
29 // constant at the call site and the branch will be optimized out.
30 #[cfg(all(any(target_arch = "x86",
33 target_arch
= "powerpc",
34 target_arch
= "powerpc64",
35 target_arch
= "asmjs",
36 target_arch
= "wasm32")))]
38 const MIN_ALIGN
: usize = 8;
39 #[cfg(all(any(target_arch = "x86_64",
40 target_arch
= "aarch64",
41 target_arch
= "mips64",
42 target_arch
= "s390x",
43 target_arch
= "sparc64")))]
45 const MIN_ALIGN
: usize = 16;
49 use self::alloc
::heap
::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}
;
51 #[unstable(feature = "allocator_api", issue = "32838")]
54 #[unstable(feature = "allocator_api", issue = "32838")]
55 unsafe impl Alloc
for System
{
57 unsafe fn alloc(&mut self, layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
58 (&*self).alloc(layout
)
62 unsafe fn alloc_zeroed(&mut self, layout
: Layout
)
63 -> Result
<*mut u8, AllocErr
>
65 (&*self).alloc_zeroed(layout
)
69 unsafe fn dealloc(&mut self, ptr
: *mut u8, layout
: Layout
) {
70 (&*self).dealloc(ptr
, layout
)
74 unsafe fn realloc(&mut self,
77 new_layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
78 (&*self).realloc(ptr
, old_layout
, new_layout
)
81 fn oom(&mut self, err
: AllocErr
) -> ! {
86 fn usable_size(&self, layout
: &Layout
) -> (usize, usize) {
87 (&self).usable_size(layout
)
91 unsafe fn alloc_excess(&mut self, layout
: Layout
) -> Result
<Excess
, AllocErr
> {
92 (&*self).alloc_excess(layout
)
96 unsafe fn realloc_excess(&mut self,
99 new_layout
: Layout
) -> Result
<Excess
, AllocErr
> {
100 (&*self).realloc_excess(ptr
, layout
, new_layout
)
104 unsafe fn grow_in_place(&mut self,
107 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
108 (&*self).grow_in_place(ptr
, layout
, new_layout
)
112 unsafe fn shrink_in_place(&mut self,
115 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
116 (&*self).shrink_in_place(ptr
, layout
, new_layout
)
120 #[cfg(any(unix, target_os = "redox"))]
129 use alloc
::heap
::{Alloc, AllocErr, Layout}
;
131 #[unstable(feature = "allocator_api", issue = "32838")]
132 unsafe impl<'a
> Alloc
for &'a System
{
134 unsafe fn alloc(&mut self, layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
135 let ptr
= if layout
.align() <= MIN_ALIGN
{
136 libc
::malloc(layout
.size()) as *mut u8
138 aligned_malloc(&layout
)
143 Err(AllocErr
::Exhausted { request: layout }
)
148 unsafe fn alloc_zeroed(&mut self, layout
: Layout
)
149 -> Result
<*mut u8, AllocErr
>
151 if layout
.align() <= MIN_ALIGN
{
152 let ptr
= libc
::calloc(layout
.size(), 1) as *mut u8;
156 Err(AllocErr
::Exhausted { request: layout }
)
159 let ret
= self.alloc(layout
.clone());
160 if let Ok(ptr
) = ret
{
161 ptr
::write_bytes(ptr
, 0, layout
.size());
168 unsafe fn dealloc(&mut self, ptr
: *mut u8, _layout
: Layout
) {
169 libc
::free(ptr
as *mut libc
::c_void
)
173 unsafe fn realloc(&mut self,
176 new_layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
177 if old_layout
.align() != new_layout
.align() {
178 return Err(AllocErr
::Unsupported
{
179 details
: "cannot change alignment on `realloc`",
183 if new_layout
.align() <= MIN_ALIGN
{
184 let ptr
= libc
::realloc(ptr
as *mut libc
::c_void
, new_layout
.size());
188 Err(AllocErr
::Exhausted { request: new_layout }
)
191 let res
= self.alloc(new_layout
.clone());
192 if let Ok(new_ptr
) = res
{
193 let size
= cmp
::min(old_layout
.size(), new_layout
.size());
194 ptr
::copy_nonoverlapping(ptr
, new_ptr
, size
);
195 self.dealloc(ptr
, old_layout
);
201 fn oom(&mut self, err
: AllocErr
) -> ! {
202 use core
::fmt
::{self, Write}
;
204 // Print a message to stderr before aborting to assist with
205 // debugging. It is critical that this code does not allocate any
206 // memory since we are in an OOM situation. Any errors are ignored
207 // while printing since there's nothing we can do about them and we
208 // are about to exit anyways.
209 drop(writeln
!(Stderr
, "fatal runtime error: {}", err
));
211 ::core
::intrinsics
::abort();
216 impl Write
for Stderr
{
217 fn write_str(&mut self, s
: &str) -> fmt
::Result
{
219 libc
::write(libc
::STDERR_FILENO
,
220 s
.as_ptr() as *const libc
::c_void
,
229 #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))]
231 unsafe fn aligned_malloc(layout
: &Layout
) -> *mut u8 {
232 // On android we currently target API level 9 which unfortunately
233 // doesn't have the `posix_memalign` API used below. Instead we use
234 // `memalign`, but this unfortunately has the property on some systems
235 // where the memory returned cannot be deallocated by `free`!
237 // Upon closer inspection, however, this appears to work just fine with
238 // Android, so for this platform we should be fine to call `memalign`
239 // (which is present in API level 9). Some helpful references could
240 // possibly be chromium using memalign [1], attempts at documenting that
241 // memalign + free is ok [2] [3], or the current source of chromium
242 // which still uses memalign on android [4].
244 // [1]: https://codereview.chromium.org/10796020/
245 // [2]: https://code.google.com/p/android/issues/detail?id=35391
246 // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
247 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
248 // /memory/aligned_memory.cc
249 libc
::memalign(layout
.align(), layout
.size()) as *mut u8
252 #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))]
254 unsafe fn aligned_malloc(layout
: &Layout
) -> *mut u8 {
255 let mut out
= ptr
::null_mut();
256 let ret
= libc
::posix_memalign(&mut out
, layout
.align(), layout
.size());
273 use alloc
::heap
::{Alloc, AllocErr, Layout, CannotReallocInPlace}
;
275 type LPVOID
= *mut u8;
276 type HANDLE
= LPVOID
;
280 type LPDWORD
= *mut DWORD
;
281 type LPOVERLAPPED
= *mut u8;
283 const STD_ERROR_HANDLE
: DWORD
= -12i32 as DWORD
;
286 fn GetProcessHeap() -> HANDLE
;
287 fn HeapAlloc(hHeap
: HANDLE
, dwFlags
: DWORD
, dwBytes
: SIZE_T
) -> LPVOID
;
288 fn HeapReAlloc(hHeap
: HANDLE
, dwFlags
: DWORD
, lpMem
: LPVOID
, dwBytes
: SIZE_T
) -> LPVOID
;
289 fn HeapFree(hHeap
: HANDLE
, dwFlags
: DWORD
, lpMem
: LPVOID
) -> BOOL
;
290 fn GetLastError() -> DWORD
;
291 fn WriteFile(hFile
: HANDLE
,
293 nNumberOfBytesToWrite
: DWORD
,
294 lpNumberOfBytesWritten
: LPDWORD
,
295 lpOverlapped
: LPOVERLAPPED
)
297 fn GetStdHandle(which
: DWORD
) -> HANDLE
;
301 struct Header(*mut u8);
303 const HEAP_ZERO_MEMORY
: DWORD
= 0x00000008;
304 const HEAP_REALLOC_IN_PLACE_ONLY
: DWORD
= 0x00000010;
306 unsafe fn get_header
<'a
>(ptr
: *mut u8) -> &'a
mut Header
{
307 &mut *(ptr
as *mut Header
).offset(-1)
310 unsafe fn align_ptr(ptr
: *mut u8, align
: usize) -> *mut u8 {
311 let aligned
= ptr
.offset((align
- (ptr
as usize & (align
- 1))) as isize);
312 *get_header(aligned
) = Header(ptr
);
317 unsafe fn allocate_with_flags(layout
: Layout
, flags
: DWORD
)
318 -> Result
<*mut u8, AllocErr
>
320 let ptr
= if layout
.align() <= MIN_ALIGN
{
321 HeapAlloc(GetProcessHeap(), flags
, layout
.size())
323 let size
= layout
.size() + layout
.align();
324 let ptr
= HeapAlloc(GetProcessHeap(), flags
, size
);
328 align_ptr(ptr
, layout
.align())
332 Err(AllocErr
::Exhausted { request: layout }
)
338 #[unstable(feature = "allocator_api", issue = "32838")]
339 unsafe impl<'a
> Alloc
for &'a System
{
341 unsafe fn alloc(&mut self, layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
342 allocate_with_flags(layout
, 0)
346 unsafe fn alloc_zeroed(&mut self, layout
: Layout
)
347 -> Result
<*mut u8, AllocErr
>
349 allocate_with_flags(layout
, HEAP_ZERO_MEMORY
)
353 unsafe fn dealloc(&mut self, ptr
: *mut u8, layout
: Layout
) {
354 if layout
.align() <= MIN_ALIGN
{
355 let err
= HeapFree(GetProcessHeap(), 0, ptr
as LPVOID
);
356 debug_assert
!(err
!= 0, "Failed to free heap memory: {}",
359 let header
= get_header(ptr
);
360 let err
= HeapFree(GetProcessHeap(), 0, header
.0 as LPVOID
);
361 debug_assert
!(err
!= 0, "Failed to free heap memory: {}",
367 unsafe fn realloc(&mut self,
370 new_layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
371 if old_layout
.align() != new_layout
.align() {
372 return Err(AllocErr
::Unsupported
{
373 details
: "cannot change alignment on `realloc`",
377 if new_layout
.align() <= MIN_ALIGN
{
378 let ptr
= HeapReAlloc(GetProcessHeap(),
385 Err(AllocErr
::Exhausted { request: new_layout }
)
388 let res
= self.alloc(new_layout
.clone());
389 if let Ok(new_ptr
) = res
{
390 let size
= cmp
::min(old_layout
.size(), new_layout
.size());
391 ptr
::copy_nonoverlapping(ptr
, new_ptr
, size
);
392 self.dealloc(ptr
, old_layout
);
399 unsafe fn grow_in_place(&mut self,
402 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
403 self.shrink_in_place(ptr
, layout
, new_layout
)
407 unsafe fn shrink_in_place(&mut self,
410 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
411 if old_layout
.align() != new_layout
.align() {
412 return Err(CannotReallocInPlace
)
415 let new
= if new_layout
.align() <= MIN_ALIGN
{
416 HeapReAlloc(GetProcessHeap(),
417 HEAP_REALLOC_IN_PLACE_ONLY
,
421 let header
= get_header(ptr
);
422 HeapReAlloc(GetProcessHeap(),
423 HEAP_REALLOC_IN_PLACE_ONLY
,
425 new_layout
.size() + new_layout
.align())
428 Err(CannotReallocInPlace
)
434 fn oom(&mut self, err
: AllocErr
) -> ! {
435 use core
::fmt
::{self, Write}
;
437 // Same as with unix we ignore all errors here
438 drop(writeln
!(Stderr
, "fatal runtime error: {}", err
));
440 ::core
::intrinsics
::abort();
445 impl Write
for Stderr
{
446 fn write_str(&mut self, s
: &str) -> fmt
::Result
{
448 // WriteFile silently fails if it is passed an invalid
449 // handle, so there is no need to check the result of
451 WriteFile(GetStdHandle(STD_ERROR_HANDLE
),
452 s
.as_ptr() as LPVOID
,
464 // This is an implementation of a global allocator on the wasm32 platform when
465 // emscripten is not in use. In that situation there's no actual runtime for us
466 // to lean on for allocation, so instead we provide our own!
468 // The wasm32 instruction set has two instructions for getting the current
469 // amount of memory and growing the amount of memory. These instructions are the
470 // foundation on which we're able to build an allocator, so we do so! Note that
471 // the instructions are also pretty "global" and this is the "global" allocator
474 // The current allocator here is the `dlmalloc` crate which we've got included
475 // in the rust-lang/rust repository as a submodule. The crate is a port of
476 // dlmalloc.c from C to Rust and is basically just so we can have "pure Rust"
477 // for now which is currently technically required (can't link with C yet).
479 // The crate itself provides a global allocator which on wasm has no
480 // synchronization as there are no threads!
481 #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
483 extern crate dlmalloc
;
485 use alloc
::heap
::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace}
;
487 use self::dlmalloc
::GlobalDlmalloc
;
489 #[unstable(feature = "allocator_api", issue = "32838")]
490 unsafe impl<'a
> Alloc
for &'a System
{
492 unsafe fn alloc(&mut self, layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
493 GlobalDlmalloc
.alloc(layout
)
497 unsafe fn alloc_zeroed(&mut self, layout
: Layout
)
498 -> Result
<*mut u8, AllocErr
>
500 GlobalDlmalloc
.alloc_zeroed(layout
)
504 unsafe fn dealloc(&mut self, ptr
: *mut u8, layout
: Layout
) {
505 GlobalDlmalloc
.dealloc(ptr
, layout
)
509 unsafe fn realloc(&mut self,
512 new_layout
: Layout
) -> Result
<*mut u8, AllocErr
> {
513 GlobalDlmalloc
.realloc(ptr
, old_layout
, new_layout
)
517 fn usable_size(&self, layout
: &Layout
) -> (usize, usize) {
518 GlobalDlmalloc
.usable_size(layout
)
522 unsafe fn alloc_excess(&mut self, layout
: Layout
) -> Result
<Excess
, AllocErr
> {
523 GlobalDlmalloc
.alloc_excess(layout
)
527 unsafe fn realloc_excess(&mut self,
530 new_layout
: Layout
) -> Result
<Excess
, AllocErr
> {
531 GlobalDlmalloc
.realloc_excess(ptr
, layout
, new_layout
)
535 unsafe fn grow_in_place(&mut self,
538 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
539 GlobalDlmalloc
.grow_in_place(ptr
, layout
, new_layout
)
543 unsafe fn shrink_in_place(&mut self,
546 new_layout
: Layout
) -> Result
<(), CannotReallocInPlace
> {
547 GlobalDlmalloc
.shrink_in_place(ptr
, layout
, new_layout
)