Skip to content

Commit f62d899

Browse files
committed
Default to using libgc alloc instead of system alloc
Previously users had to ensure they set the #[global_allocator] in order to use Alloy. This was never ideal, but it was necessary because it was too difficult to implement when we statically linked libgc. We've changed this to use dynamic linkage now, and I also know my way around the bootstrap process, so I've fixed this long standing annoyance. In addition, this is also needed for more precise metric tracking in our benchmarks, where we use different allocators depending whether we're constructing an `Rc` / `Arc` etc. Now, these will always correctly resolve to the libgc allocator.
1 parent fd8b135 commit f62d899

File tree

5 files changed

+24
-74
lines changed

5 files changed

+24
-74
lines changed

library/alloc/src/bdwgc.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::alloc::{AllocError, Allocator, GlobalAlloc, Layout};
1919
pub fn init(finalizer_thread: extern "C" fn()) {
2020
unsafe {
2121
api::GC_set_finalize_on_demand(1);
22+
api::GC_set_warn_proc(Some(api::GC_ignore_warn_proc));
2223
api::GC_set_finalizer_notifier(Some(finalizer_thread));
2324
#[cfg(feature = "gc-disable")]
2425
api::GC_disable();
@@ -53,7 +54,7 @@ unsafe impl GlobalAlloc for GcAllocator {
5354
}
5455

5556
#[inline]
56-
unsafe fn gc_malloc(layout: Layout) -> *mut u8 {
57+
pub unsafe fn gc_malloc(layout: Layout) -> *mut u8 {
5758
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
5859
unsafe { api::GC_malloc(layout.size()) as *mut u8 }
5960
} else {
@@ -69,7 +70,7 @@ unsafe fn gc_malloc(layout: Layout) -> *mut u8 {
6970
}
7071

7172
#[inline]
72-
unsafe fn gc_realloc(ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
73+
pub unsafe fn gc_realloc(ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
7374
if old_layout.align() <= MIN_ALIGN && old_layout.align() <= new_size {
7475
unsafe { api::GC_realloc(ptr as *mut c_void, new_size) as *mut u8 }
7576
} else {
@@ -88,7 +89,7 @@ unsafe fn gc_realloc(ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut
8889
}
8990

9091
#[inline]
91-
unsafe fn gc_free(ptr: *mut u8, _: Layout) {
92+
pub unsafe fn gc_free(ptr: *mut u8, _: Layout) {
9293
unsafe {
9394
api::GC_free(ptr as *mut c_void);
9495
}

library/std/src/sys/alloc/unix.rs

Lines changed: 5 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,24 @@
1-
use super::{MIN_ALIGN, realloc_fallback};
21
use crate::alloc::{GlobalAlloc, Layout, System};
3-
use crate::ptr;
42

53
#[stable(feature = "alloc_system_type", since = "1.28.0")]
64
unsafe impl GlobalAlloc for System {
75
#[inline]
86
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
9-
// jemalloc provides alignment less than MIN_ALIGN for small allocations.
10-
// So only rely on MIN_ALIGN if size >= align.
11-
// Also see <https://github.com/rust-lang/rust/issues/45955> and
12-
// <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
13-
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
14-
unsafe { libc::malloc(layout.size()) as *mut u8 }
15-
} else {
16-
// `posix_memalign` returns a non-aligned value if supplied a very
17-
// large alignment on older versions of Apple's platforms (unknown
18-
// exactly which version range, but the issue is definitely
19-
// present in macOS 10.14 and iOS 13.3).
20-
//
21-
// <https://github.com/rust-lang/rust/issues/30170>
22-
#[cfg(target_vendor = "apple")]
23-
{
24-
if layout.align() > (1 << 31) {
25-
return ptr::null_mut();
26-
}
27-
}
28-
unsafe { aligned_malloc(&layout) }
29-
}
7+
unsafe { crate::bdwgc::gc_malloc(layout) }
308
}
319

3210
#[inline]
3311
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
34-
// See the comment above in `alloc` for why this check looks the way it does.
35-
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
36-
unsafe { libc::calloc(layout.size(), 1) as *mut u8 }
37-
} else {
38-
let ptr = unsafe { self.alloc(layout) };
39-
if !ptr.is_null() {
40-
unsafe { ptr::write_bytes(ptr, 0, layout.size()) };
41-
}
42-
ptr
43-
}
12+
unsafe { crate::bdwgc::gc_malloc(layout) }
4413
}
4514

4615
#[inline]
47-
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
48-
unsafe { libc::free(ptr as *mut libc::c_void) }
16+
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
17+
unsafe { crate::bdwgc::gc_free(ptr, layout) }
4918
}
5019

5120
#[inline]
5221
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
53-
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
54-
unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 }
55-
} else {
56-
unsafe { realloc_fallback(self, ptr, layout, new_size) }
57-
}
58-
}
59-
}
60-
61-
cfg_if::cfg_if! {
62-
// We use posix_memalign wherever possible, but some targets have very incomplete POSIX coverage
63-
// so we need a fallback for those.
64-
if #[cfg(any(
65-
target_os = "horizon",
66-
target_os = "vita",
67-
))] {
68-
#[inline]
69-
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
70-
unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 }
71-
}
72-
} else {
73-
#[inline]
74-
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
75-
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
76-
let mut out = ptr::null_mut();
77-
// We prefer posix_memalign over aligned_alloc since it is more widely available, and
78-
// since with aligned_alloc, implementations are making almost arbitrary choices for
79-
// which alignments are "supported", making it hard to use. For instance, some
80-
// implementations require the size to be a multiple of the alignment (wasi emmalloc),
81-
// while others require the alignment to be at least the pointer size (Illumos, macOS).
82-
// posix_memalign only has one, clear requirement: that the alignment be a multiple of
83-
// `sizeof(void*)`. Since these are all powers of 2, we can just use max.
84-
let align = layout.align().max(crate::mem::size_of::<usize>());
85-
let ret = unsafe { libc::posix_memalign(&mut out, align, layout.size()) };
86-
if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
87-
}
22+
unsafe { crate::bdwgc::gc_realloc(ptr, layout, new_size) }
8823
}
8924
}

src/bootstrap/src/core/build_steps/compile.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,9 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
589589
// about libgc.
590590
cargo.rustflag("-L").rustflag(builder.bdwgc_out(target).join("lib").to_str().unwrap());
591591

592+
// Don't run the GC when we're building rustc.
593+
cargo.env("GC_DONT_GC", "true");
594+
592595
// Determine if we're going to compile in optimized C intrinsics to
593596
// the `compiler-builtins` crate. These intrinsics live in LLVM's
594597
// `compiler-rt` repository.
@@ -1234,6 +1237,9 @@ pub fn rustc_cargo(
12341237
let bindgen = builder.ensure(Bindgen { target });
12351238
cargo.env("RUSTC_BINDGEN", &bindgen.tool_path);
12361239

1240+
// Don't run the GC when we're building rustc.
1241+
cargo.env("GC_DONT_GC", "true");
1242+
12371243
// Building with protected visibility reduces the number of dynamic relocations needed, giving
12381244
// us a faster startup time. However GNU ld < 2.40 will error if we try to link a shared object
12391245
// with direct references to protected symbols, so for now we only use protected symbols if

src/bootstrap/src/core/build_steps/test.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ impl Step for Cargotest {
262262
.args(builder.config.test_args())
263263
.env("RUSTC", builder.rustc(compiler))
264264
.env("RUSTDOC", builder.rustdoc(compiler))
265+
.env("GC_DONT_GC", "true")
265266
.env("RUSTC_BINDGEN", &bindgen.tool_path);
266267
add_rustdoc_cargo_linker_args(
267268
&mut cmd,
@@ -849,7 +850,8 @@ impl Step for RustdocTheme {
849850
.env("RUSTDOC_LIBDIR", builder.sysroot_target_libdir(self.compiler, self.compiler.host))
850851
.env("CFG_RELEASE_CHANNEL", &builder.config.channel)
851852
.env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
852-
.env("RUSTC_BOOTSTRAP", "1");
853+
.env("RUSTC_BOOTSTRAP", "1")
854+
.env("GC_DONT_GC", "true");
853855
cmd.args(linker_args(builder, self.compiler.host, LldThreads::No, self.compiler.stage));
854856

855857
cmd.delay_failure().run(builder);
@@ -880,6 +882,7 @@ impl Step for RustdocJSStd {
880882
builder.config.nodejs.as_ref().expect("need nodejs to run rustdoc-js-std tests");
881883
let mut command = command(nodejs);
882884
command
885+
.env("GC_DONT_GC", "true")
883886
.arg(builder.src.join("src/tools/rustdoc-js/tester.js"))
884887
.arg("--crate-name")
885888
.arg("std")
@@ -1058,6 +1061,8 @@ impl Step for RustdocGUI {
10581061
cmd.arg("--npm").arg(npm);
10591062
}
10601063

1064+
cmd.env("GC_DONT_GC", "true");
1065+
10611066
let _time = helpers::timeit(builder);
10621067
let _guard = builder.msg_sysroot_tool(
10631068
Kind::Test,
@@ -1646,6 +1651,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
16461651
}
16471652

16481653
let mut cmd = builder.tool_cmd(Tool::Compiletest);
1654+
cmd.env("GC_DONT_GC", "true");
16491655

16501656
if suite == "mir-opt" {
16511657
builder.ensure(compile::Std::new(compiler, target).is_for_mir_opt_tests(true));
@@ -2517,6 +2523,7 @@ fn run_cargo_test<'a>(
25172523

25182524
let bindgen = builder.ensure(Bindgen { target: compiler.host });
25192525
cargo.env("RUSTC_BINDGEN", &bindgen.tool_path);
2526+
cargo.env("GC_DONT_GC", "true");
25202527

25212528
#[cfg(feature = "build-metrics")]
25222529
builder.metrics.begin_test_suite(

tests/ui/runtime/gc/disable.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use std::gc::{disable, enable, is_enabled, try_enable};
88

99
fn main() {
10+
enable();
1011
assert!(is_enabled());
1112
disable();
1213
disable();

0 commit comments

Comments
 (0)