about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorTim Diekmann <tim.diekmann@3dvision.de>2020-03-24 11:45:38 +0100
committerTim Diekmann <tim.diekmann@3dvision.de>2020-03-26 17:10:54 +0100
commit56cbf2f22aeb6448acd7eb49e9b2554c80bdbf79 (patch)
treeaf24a0972cda1bd07560e36c5edd5aa14b53fc7d /src/libstd
parent2fbb07525e2f07a815e780a4268b11916248b5a9 (diff)
downloadrust-56cbf2f22aeb6448acd7eb49e9b2554c80bdbf79.tar.gz
rust-56cbf2f22aeb6448acd7eb49e9b2554c80bdbf79.zip
Overhaul of the `AllocRef` trait to match allocator-wg's latest consens
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/alloc.rs109
-rw-r--r--src/libstd/error.rs9
2 files changed, 78 insertions, 40 deletions
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
index 25f3ddcbeba..9ad0eae705f 100644
--- a/src/libstd/alloc.rs
+++ b/src/libstd/alloc.rs
@@ -61,6 +61,7 @@
 
 #![stable(feature = "alloc_module", since = "1.28.0")]
 
+use core::intrinsics;
 use core::ptr::NonNull;
 use core::sync::atomic::{AtomicPtr, Ordering};
 use core::{mem, ptr};
@@ -133,60 +134,106 @@ pub use alloc_crate::alloc::*;
 #[derive(Debug, Default, Copy, Clone)]
 pub struct System;
 
-// The AllocRef impl checks the layout size to be non-zero and forwards to the GlobalAlloc impl,
-// which is in `std::sys::*::alloc`.
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl AllocRef for System {
     #[inline]
-    fn alloc(&mut self, layout: Layout) -> Result<(NonNull<u8>, usize), AllocErr> {
-        if layout.size() == 0 {
+    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<(NonNull<u8>, usize), AllocErr> {
+        let new_size = layout.size();
+        if new_size == 0 {
             Ok((layout.dangling(), 0))
         } else {
             unsafe {
-                NonNull::new(GlobalAlloc::alloc(self, layout))
-                    .ok_or(AllocErr)
-                    .map(|p| (p, layout.size()))
+                let raw_ptr = match init {
+                    AllocInit::Uninitialized => GlobalAlloc::alloc(self, layout),
+                    AllocInit::Zeroed => GlobalAlloc::alloc_zeroed(self, layout),
+                };
+                let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
+                Ok((ptr, new_size))
             }
         }
     }
 
     #[inline]
-    fn alloc_zeroed(&mut self, layout: Layout) -> Result<(NonNull<u8>, usize), AllocErr> {
-        if layout.size() == 0 {
-            Ok((layout.dangling(), 0))
-        } else {
-            unsafe {
-                NonNull::new(GlobalAlloc::alloc_zeroed(self, layout))
-                    .ok_or(AllocErr)
-                    .map(|p| (p, layout.size()))
-            }
+    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
+        if layout.size() != 0 {
+            GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
         }
     }
 
     #[inline]
-    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
-        if layout.size() != 0 {
-            GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
+    unsafe fn grow(
+        &mut self,
+        ptr: NonNull<u8>,
+        layout: Layout,
+        new_size: usize,
+        placement: ReallocPlacement,
+        init: AllocInit,
+    ) -> Result<(NonNull<u8>, usize), AllocErr> {
+        let old_size = layout.size();
+        debug_assert!(
+            new_size >= old_size,
+            "`new_size` must be greater than or equal to `layout.size()`"
+        );
+
+        if old_size == new_size {
+            return Ok((ptr, new_size));
+        }
+
+        match placement {
+            ReallocPlacement::MayMove => {
+                if old_size == 0 {
+                    self.alloc(Layout::from_size_align_unchecked(new_size, layout.align()), init)
+                } else {
+                    // `realloc` probably checks for `new_size > old_size` or something similar.
+                    // `new_size` must be greater than or equal to `old_size` due to the safety constraint,
+                    // and `new_size` == `old_size` was caught before
+                    intrinsics::assume(new_size > old_size);
+                    let ptr =
+                        NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size))
+                            .ok_or(AllocErr)?;
+                    let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
+                    init.initialize_offset(ptr, new_layout, old_size);
+                    Ok((ptr, new_size))
+                }
+            }
+            ReallocPlacement::InPlace => Err(AllocErr),
         }
     }
 
     #[inline]
-    unsafe fn realloc(
+    unsafe fn shrink(
         &mut self,
         ptr: NonNull<u8>,
         layout: Layout,
         new_size: usize,
+        placement: ReallocPlacement,
     ) -> Result<(NonNull<u8>, usize), AllocErr> {
-        match (layout.size(), new_size) {
-            (0, 0) => Ok((layout.dangling(), 0)),
-            (0, _) => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())),
-            (_, 0) => {
-                self.dealloc(ptr, layout);
-                Ok((layout.dangling(), 0))
+        let old_size = layout.size();
+        debug_assert!(
+            new_size <= old_size,
+            "`new_size` must be smaller than or equal to `layout.size()`"
+        );
+
+        if old_size == new_size {
+            return Ok((ptr, new_size));
+        }
+
+        match placement {
+            ReallocPlacement::MayMove => {
+                let ptr = if new_size == 0 {
+                    self.dealloc(ptr, layout);
+                    layout.dangling()
+                } else {
+                    // `realloc` probably checks for `new_size > old_size` or something similar.
+                    // `new_size` must be smaller than or equal to `old_size` due to the safety constraint,
+                    // and `new_size` == `old_size` was caught before
+                    intrinsics::assume(new_size < old_size);
+                    NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size))
+                        .ok_or(AllocErr)?
+                };
+                Ok((ptr, new_size))
             }
-            (_, _) => NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size))
-                .ok_or(AllocErr)
-                .map(|p| (p, new_size)),
+            ReallocPlacement::InPlace => Err(AllocErr),
         }
     }
 }
@@ -238,9 +285,7 @@ pub fn rust_oom(layout: Layout) -> ! {
     let hook: fn(Layout) =
         if hook.is_null() { default_alloc_error_hook } else { unsafe { mem::transmute(hook) } };
     hook(layout);
-    unsafe {
-        crate::sys::abort_internal();
-    }
+    unsafe { crate::sys::abort_internal() }
 }
 
 #[cfg(not(test))]
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index b394f2efc2e..24b57f12e8d 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -15,7 +15,7 @@
 
 use core::array;
 
-use crate::alloc::{AllocErr, CannotReallocInPlace, LayoutErr};
+use crate::alloc::{AllocErr, LayoutErr};
 use crate::any::TypeId;
 use crate::backtrace::Backtrace;
 use crate::borrow::Cow;
@@ -409,13 +409,6 @@ impl Error for AllocErr {}
 )]
 impl Error for LayoutErr {}
 
-#[unstable(
-    feature = "allocator_api",
-    reason = "the precise API and guarantees it provides may be tweaked.",
-    issue = "32838"
-)]
-impl Error for CannotReallocInPlace {}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Error for str::ParseBoolError {
     #[allow(deprecated)]