Skip to content

Commit c405fd9

Browse files
authored
Merge pull request #2 from alexcrichton/more-allocators
Updates and refinements to various apis and guarantees
2 parents 770abea + d80313c commit c405fd9

File tree

1 file changed

+93
-20
lines changed

1 file changed

+93
-20
lines changed

text/0000-global-allocators.md

+93-20
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,39 @@ trait described in [RFC 1398][], but is stripped down and the methods take
7373
[RFC 1398]: https://github.com/rust-lang/rfcs/blob/master/text/1398-kinds-of-allocators.md
7474

7575
```rust
76-
76+
/// A trait implemented by objects that can be global allocators.
77+
///
78+
/// Instances of this trait can be used to back allocations done through the
79+
/// `std::heap` API. This trait represents the fundamental ability to allocate
80+
/// memory in Rust.
81+
///
82+
/// To use a global allocator you'll need to use the `#[global_allocator]`
83+
/// attribute like so:
84+
///
85+
/// ```
86+
/// extern crate my_allocator;
87+
///
88+
/// #[global_allocator]
89+
/// static ALLOCATOR: MyAllocator = my_allocator::INIT;
90+
///
91+
/// fn main() {
92+
/// let _b = Box::new(2); // uses `MyAllocator` above
93+
/// }
94+
/// ```
95+
///
96+
/// # Unsafety
97+
///
98+
/// This trait is an `unsafe` trait as there are a number of guarantees a global
99+
/// allocator must adhere to which aren't expressible through the type system.
100+
/// First and foremost types that implement this trait must behave like, well,
101+
/// allocators! All pointers returned from `allocate` that are active in a
102+
/// program (disregarding those `deallocate`d) must point to disjoint chunks of
103+
/// memory. In other words, allocations need to be distinct and can't overlap.
104+
///
105+
/// Additionally it must be safe to allocate a chunk of memory on any thread of
106+
/// a program and then deallocate it on any other thread of the program.
77107
#[lang = "global_allocator"]
78-
pub unsafe trait GlobalAllocator: Send + Sync {
108+
pub unsafe trait GlobalAllocator: Send + Sync + 'static {
79109
/// Returns a pointer to a newly allocated region of memory suitable for the
80110
/// provided `Layout`. The contents of the memory are undefined.
81111
///
@@ -110,7 +140,7 @@ pub unsafe trait GlobalAllocator: Send + Sync {
110140
///
111141
/// The pointer must correspond to a region of memory previously allocated
112142
/// by this allocator with the provided layout.
113-
pub fn reallocate(&self, ptr: *mut u8, old_layout: Layout, layout: Layout) -> *mut u8 {
143+
pub unsafe fn reallocate(&self, ptr: *mut u8, old_layout: Layout, layout: Layout) -> *mut u8 {
114144
let new_ptr = self.alloc(layout);
115145
if !new_ptr.is_null() {
116146
ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(old_layout.size(), layout.size()));
@@ -128,6 +158,12 @@ trait: `usable_size` which is used nowhere in the standard library, and
128158
A global allocator is a type implementing `GlobalAllocator` which can be
129159
constructed in a constant expression.
130160

161+
Note that the precise type signatures used here are a little up for debate. It's
162+
expected that they will be settled (along with accompanying documentation as to
163+
guarantees) as part of stabilization in [rust-lang/rust#27700][stab-issue].
164+
165+
[stab-issue]: https://github.com/rust-lang/rust/issues/27700
166+
131167
## Using an allocator
132168

133169
While the `GlobalAllocator` trait can be used like any other, the most common
@@ -148,21 +184,21 @@ pub unsafe fn deallocate(&self, ptr: *mut u8, layout: Layout) {
148184
...
149185
}
150186

151-
pub fn reallocate(ptr: *mut u8, old_layout: Layout, layout: Layout) -> *mut u8 {
187+
pub unsafe fn reallocate(ptr: *mut u8, old_layout: Layout, layout: Layout) -> *mut u8 {
152188
...
153189
}
154190
```
155191

156192
Each of these functions simply delegates to the selected global allocator. The
157193
allocator is selected by tagging a static value of a type implementing
158-
`GlobalAllocator` with the `#[allocator]` annotation:
194+
`GlobalAllocator` with the `#[global_allocator]` annotation:
159195

160196
```rust
161197
extern crate my_allocator;
162198

163199
use my_allocator::{MyAllocator, MY_ALLOCATOR_INIT};
164200

165-
#[allocator]
201+
#[global_allocator]
166202
static ALLOCATOR: MyAllocator = MY_ALLOCATOR_INIT;
167203

168204
fn main() {
@@ -175,23 +211,60 @@ other static would bed.
175211

176212
## Standard library
177213

178-
A small `alloc_api` crate will be created which will contain the `Layout` type.
179-
The initial API will be more conservative than that described in [RFC 1398][],
180-
possibly nothing more than a `from_size_align` constructor and accessors for
181-
`size` and `align`.
214+
A `core::heap` module will be added with the `Layout` type and the
215+
`GlobalAllocator` trait. The initial API of `Layout` will be more conservative
216+
than that described in [RFC 1398][], possibly nothing more than a
217+
`from_size_align` constructor and accessors for `size` and `align`. It is
218+
intended that the API will grow over time with conveniences such as
219+
`Layout::new::<T>()`.
220+
221+
The `alloc::heap` module will reexport these types from `core::heap`. It will
222+
also provide top-level functions (like `allocate` above) which do not take an
223+
allocator but instead are routed through the global allocator. The `alloc`
224+
crate, however, will not provide a global allocator. Instead the compiler will
225+
understand that crates which transitively depend on `alloc` will require an
226+
allocator, with a per-target fallback default allocator used by the compiler.
182227

183-
The standard library will gain a new stable crate - `alloc_system`. This is the
184-
default allocator crate and corresponds to the "system" allocator (i.e. `malloc`
185-
etc on Unix and `HeapAlloc` etc on Windows).
228+
The standard library will grow a `std::heap` module that reexports the contents
229+
of `alloc::heap`. Additionally it will contain a system allocator definition:
186230

187-
The `alloc::heap` module will be reexported in `std` and stabilized. It will
188-
simply contain functions matching directly to those defined by the allocator
189-
API. The `alloc` crate itself may also be stabilized at a later date, but this
190-
RFC does not propose that. `Layout` will be reexported in the `heap` module.
231+
```rust
232+
pub struct SystemAllocator;
233+
234+
impl GlobalAllocator for SystemAllocator {
235+
// ...
236+
}
237+
```
238+
239+
The `SystemAllocator` is defined as having zero size, no fields, and always
240+
referring to the OS allocator (i.e. `malloc` etc on Unix and `HeapAlloc` etc on
241+
Windows).
242+
243+
The existing `alloc_system` and `alloc_jemalloc` crates will likely be
244+
deprecated and eventually removed. The `alloc_system` crate is replaced with the
245+
`SystemAllocator` structure in the standard library and the `alloc_jemalloc`
246+
crate will become available on crates.io. The `alloc_jemalloc` crate will likely
247+
look like:
248+
249+
```rust
250+
pub struct Jemalloc;
251+
252+
impl GlobalAllocator for Jemalloc {
253+
// ...
254+
}
255+
```
191256

192-
The existing `alloc_jemalloc` may continue to exist as an implementation detail
193-
of the Rust compiler, but it will never be stabilized. Applications wishing to
194-
use jemalloc can use a third-party crate from crates.io.
257+
It is not proposed in this RFC to switch the per-platform default allocator just
258+
yet. Assuming everything goes smoothly, however, it will likely be defined as
259+
`SystemAllocator` as platforms transition away from jemalloc-by-default once the
260+
jemalloc-from-crates.io is stable and usable.
261+
262+
The compiler will also no longer forbid cyclic the cyclic dependency between a
263+
crate defining an implementation of an allocator and the `alloc` crate itself.
264+
As a vestige of the current implementation this is only to get around linkage
265+
errors where the liballoc rlib references symbols defined in the "allocator
266+
crate". With this RFC the compiler has far more control over the ABI and linkage
267+
here, so this restriction is no longer necessary.
195268

196269
# How We Teach This
197270
[how-we-teach-this]: #how-we-teach-this

0 commit comments

Comments
 (0)