Skip to content

Commit 5fad627

Browse files
committed
Starting to implement a frame allocator for Rustc
1 parent d86cf13 commit 5fad627

File tree

14 files changed

+244
-1
lines changed

14 files changed

+244
-1
lines changed

configure

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ opt codegen-tests 1 "run the src/test/codegen tests"
637637
opt option-checking 1 "complain about unrecognized options in this configure script"
638638
opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)"
639639
opt vendor 0 "enable usage of vendored Rust crates"
640+
opt frame-alloc 0 "enable the frame allocator"
640641

641642
# Optimization and debugging options. These may be overridden by the release channel, etc.
642643
opt_nosave optimize 1 "build optimized rust code"

src/Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/bootstrap/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub struct Config {
7777
// libstd features
7878
pub debug_jemalloc: bool,
7979
pub use_jemalloc: bool,
80+
pub use_alloc_frame: bool,
8081
pub backtrace: bool, // support for RUST_BACKTRACE
8182

8283
// misc
@@ -176,6 +177,7 @@ struct Rust {
176177
debuginfo_lines: Option<bool>,
177178
debug_jemalloc: Option<bool>,
178179
use_jemalloc: Option<bool>,
180+
use_alloc_frame: Option<bool>,
179181
backtrace: Option<bool>,
180182
default_linker: Option<String>,
181183
default_ar: Option<String>,
@@ -203,6 +205,7 @@ impl Config {
203205
let mut config = Config::default();
204206
config.llvm_optimize = true;
205207
config.use_jemalloc = true;
208+
config.use_alloc_frame = false;
206209
config.backtrace = true;
207210
config.rust_optimize = true;
208211
config.rust_optimize_tests = true;
@@ -298,6 +301,7 @@ impl Config {
298301
set(&mut config.rust_rpath, rust.rpath);
299302
set(&mut config.debug_jemalloc, rust.debug_jemalloc);
300303
set(&mut config.use_jemalloc, rust.use_jemalloc);
304+
set(&mut config.use_alloc_frame, rust.use_alloc_frame);
301305
set(&mut config.backtrace, rust.backtrace);
302306
set(&mut config.channel, rust.channel.clone());
303307
config.rustc_default_linker = rust.default_linker.clone();
@@ -385,6 +389,7 @@ impl Config {
385389
("DEBUGINFO_LINES", self.rust_debuginfo_lines),
386390
("JEMALLOC", self.use_jemalloc),
387391
("DEBUG_JEMALLOC", self.debug_jemalloc),
392+
("FRAME_ALLOC", self.use_alloc_frame),
388393
("RPATH", self.rust_rpath),
389394
("OPTIMIZE_TESTS", self.rust_optimize_tests),
390395
("DEBUGINFO_TESTS", self.rust_debuginfo_tests),

src/bootstrap/config.toml.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@
137137
# Whether or not jemalloc is built with its debug option set
138138
#debug-jemalloc = false
139139

140+
# Whether or not the frame allocator is built and enabled
141+
#use-alloc-frame = false
142+
140143
# Whether or not `panic!`s generate backtraces (RUST_BACKTRACE)
141144
#backtrace = true
142145

src/bootstrap/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,9 @@ impl Build {
609609
if self.config.use_jemalloc {
610610
features.push_str(" jemalloc");
611611
}
612+
if self.config.use_alloc_frame {
613+
features.push_str(" alloc_frame");
614+
}
612615
if self.config.backtrace {
613616
features.push_str(" backtrace");
614617
}
@@ -621,6 +624,9 @@ impl Build {
621624
if self.config.use_jemalloc {
622625
features.push_str(" jemalloc");
623626
}
627+
if self.config.use_alloc_frame {
628+
features.push_str(" alloc_frame");
629+
}
624630
return features
625631
}
626632

src/liballoc_frame/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
authors = ["The Rust Project Developers"]
3+
name = "alloc_frame"
4+
version = "0.0.0"
5+
6+
[lib]
7+
name = "alloc_frame"
8+
path = "lib.rs"
9+
test = false
10+
11+
[dependencies]
12+
core = { path = "../libcore" }
13+
libc = { path = "../rustc/libc_shim" }

src/liballoc_frame/lib.rs

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
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.
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+
#![crate_name = "alloc_frame"]
12+
#![crate_type = "rlib"]
13+
#![no_std]
14+
#![allocator]
15+
#![cfg_attr(not(stage0), deny(warnings))]
16+
#![unstable(feature = "alloc_frame",
17+
reason = "this library is unlikely to be stabilized in its current \
18+
form or name",
19+
issue = "0")]
20+
#![feature(allocator)]
21+
#![feature(const_fn)]
22+
#![feature(staged_api)]
23+
#![feature(libc)]
24+
#![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
25+
26+
extern crate libc;
27+
28+
use core::ptr;
29+
30+
// The minimum alignment guaranteed by the architecture. This value is used to
31+
// add fast paths for low alignment values. In practice, the alignment is a
32+
// constant at the call site and the branch will be optimized out.
33+
#[cfg(all(any(target_arch = "x86",
34+
target_arch = "arm",
35+
target_arch = "mips",
36+
target_arch = "powerpc",
37+
target_arch = "powerpc64",
38+
target_arch = "asmjs",
39+
target_arch = "wasm32")))]
40+
const MIN_ALIGN: usize = 8;
41+
#[cfg(all(any(target_arch = "x86_64",
42+
target_arch = "aarch64",
43+
target_arch = "mips64",
44+
target_arch = "s390x")))]
45+
const MIN_ALIGN: usize = 16;
46+
47+
// The size of the chunk which is actually allocated
48+
const CHUNK_SIZE: usize = 4096 * 16;
49+
const CHUNK_ALIGN: usize = 4096;
50+
51+
static mut HEAP: *mut u8 = ptr::null_mut();
52+
static mut HEAP_LEFT: usize = 0;
53+
54+
#[no_mangle]
55+
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
56+
let new_align = if align < MIN_ALIGN { MIN_ALIGN } else { align };
57+
let new_size = (size + new_align - 1) & !(new_align - 1);
58+
59+
unsafe {
60+
if new_size < HEAP_LEFT {
61+
HEAP_LEFT -= new_size;
62+
let p = HEAP;
63+
HEAP = HEAP.offset(new_size as isize);
64+
return p;
65+
} else if new_size > CHUNK_SIZE {
66+
return imp::allocate(size, align);
67+
} else {
68+
HEAP_LEFT = CHUNK_SIZE - new_size;
69+
let p = imp::allocate(CHUNK_SIZE, CHUNK_ALIGN);
70+
HEAP = p.offset(new_size as isize);
71+
return p;
72+
}
73+
}
74+
}
75+
76+
#[no_mangle]
77+
pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
78+
}
79+
80+
#[no_mangle]
81+
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
82+
old_size: usize,
83+
size: usize,
84+
align: usize)
85+
-> *mut u8 {
86+
let new_ptr = __rust_allocate(size, align);
87+
unsafe { libc::memcpy(new_ptr as *mut _, ptr as *mut _, old_size); }
88+
new_ptr
89+
}
90+
91+
#[no_mangle]
92+
pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
93+
old_size: usize,
94+
_size: usize,
95+
_align: usize)
96+
-> usize {
97+
old_size
98+
}
99+
100+
#[no_mangle]
101+
pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize {
102+
size
103+
}
104+
105+
#[cfg(any(unix, target_os = "redox"))]
106+
mod imp {
107+
use core::cmp;
108+
use MIN_ALIGN;
109+
110+
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
111+
if align <= MIN_ALIGN {
112+
libc::malloc(size as libc::size_t) as *mut u8
113+
} else {
114+
aligned_malloc(size, align)
115+
}
116+
}
117+
118+
#[cfg(any(target_os = "android", target_os = "redox"))]
119+
unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
120+
// On android we currently target API level 9 which unfortunately
121+
// doesn't have the `posix_memalign` API used below. Instead we use
122+
// `memalign`, but this unfortunately has the property on some systems
123+
// where the memory returned cannot be deallocated by `free`!
124+
//
125+
// Upon closer inspection, however, this appears to work just fine with
126+
// Android, so for this platform we should be fine to call `memalign`
127+
// (which is present in API level 9). Some helpful references could
128+
// possibly be chromium using memalign [1], attempts at documenting that
129+
// memalign + free is ok [2] [3], or the current source of chromium
130+
// which still uses memalign on android [4].
131+
//
132+
// [1]: https://codereview.chromium.org/10796020/
133+
// [2]: https://code.google.com/p/android/issues/detail?id=35391
134+
// [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
135+
// [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
136+
// /memory/aligned_memory.cc
137+
libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
138+
}
139+
140+
#[cfg(not(any(target_os = "android", target_os = "redox")))]
141+
unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
142+
let mut out = ptr::null_mut();
143+
let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
144+
if ret != 0 {
145+
ptr::null_mut()
146+
} else {
147+
out as *mut u8
148+
}
149+
}
150+
}
151+
152+
#[cfg(windows)]
153+
#[allow(bad_style)]
154+
mod imp {
155+
use MIN_ALIGN;
156+
157+
type LPVOID = *mut u8;
158+
type HANDLE = LPVOID;
159+
type SIZE_T = usize;
160+
type DWORD = u32;
161+
162+
extern "system" {
163+
fn GetProcessHeap() -> HANDLE;
164+
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
165+
}
166+
167+
#[repr(C)]
168+
struct Header(*mut u8);
169+
170+
unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
171+
&mut *(ptr as *mut Header).offset(-1)
172+
}
173+
174+
unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
175+
let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
176+
*get_header(aligned) = Header(ptr);
177+
aligned
178+
}
179+
180+
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
181+
if align <= MIN_ALIGN {
182+
HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
183+
} else {
184+
let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
185+
if ptr.is_null() {
186+
return ptr;
187+
}
188+
align_ptr(ptr, align)
189+
}
190+
}
191+
}

src/libstd/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ crate-type = ["dylib", "rlib"]
1313
alloc = { path = "../liballoc" }
1414
alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true }
1515
alloc_system = { path = "../liballoc_system" }
16+
alloc_frame = { path = "../liballoc_frame", optional = true }
1617
panic_unwind = { path = "../libpanic_unwind", optional = true }
1718
panic_abort = { path = "../libpanic_abort" }
1819
collections = { path = "../libcollections" }

src/libstd/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ extern crate libc;
331331
// We always need an unwinder currently for backtraces
332332
extern crate unwind;
333333

334-
#[cfg(stage0)]
334+
#[cfg(all(stage0, not(alloc_frame)))]
335335
extern crate alloc_system;
336336

337337
// compiler-rt intrinsics

src/rustc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ path = "rustdoc.rs"
1717
rustc_back = { path = "../librustc_back" }
1818
rustc_driver = { path = "../librustc_driver" }
1919
rustdoc = { path = "../librustdoc" }
20+
alloc_frame = { path = "../liballoc_frame", optional = true }
2021

2122
[features]
2223
jemalloc = ["rustc_back/jemalloc"]

src/rustc/rustc.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@
99
// except according to those terms.
1010

1111
#![feature(rustc_private)]
12+
#![cfg_attr(feature = "alloc_frame", feature(alloc_frame))]
1213

1314
extern crate rustc_driver;
1415

16+
// Use the frame allocator to speed up runtime
17+
#[cfg(feature = "alloc_frame")]
18+
extern crate alloc_frame;
19+
1520
fn main() { rustc_driver::main() }

src/rustc/rustdoc.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@
99
// except according to those terms.
1010

1111
#![feature(rustdoc)]
12+
#![cfg_attr(feature = "alloc_frame", feature(alloc_frame))]
1213

1314
extern crate rustdoc;
1415

16+
// Use the frame allocator to speed up runtime
17+
#[cfg(feature = "alloc_frame")]
18+
extern crate alloc_frame;
19+
1520
fn main() { rustdoc::main() }

src/rustc/std_shim/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ core = { path = "../../libcore" }
3737
backtrace = ["std/backtrace"]
3838
debug-jemalloc = ["std/debug-jemalloc"]
3939
jemalloc = ["std/jemalloc"]
40+
alloc_frame = ["std/alloc_frame"]
4041
panic-unwind = ["std/panic-unwind"]

src/tools/tidy/src/pal.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const EXCEPTION_PATHS: &'static [&'static str] = &[
5353
// std crates
5454
"src/liballoc_jemalloc",
5555
"src/liballoc_system",
56+
"src/liballoc_frame",
5657
"src/liblibc",
5758
"src/libpanic_abort",
5859
"src/libpanic_unwind",

0 commit comments

Comments
 (0)