Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions library/alloc/src/bdwgc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ use crate::alloc::{AllocError, Allocator, GlobalAlloc, Layout};
pub fn init(finalizer_thread: extern "C" fn()) {
unsafe {
api::GC_set_finalize_on_demand(1);
api::GC_set_warn_proc(Some(api::GC_ignore_warn_proc));
api::GC_set_finalizer_notifier(Some(finalizer_thread));
#[cfg(feature = "gc-disable")]
api::GC_disable();
metrics::init();
// The final initialization must come last.
Expand Down Expand Up @@ -53,7 +53,7 @@ unsafe impl GlobalAlloc for GcAllocator {
}

#[inline]
unsafe fn gc_malloc(layout: Layout) -> *mut u8 {
pub unsafe fn gc_malloc(layout: Layout) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
unsafe { api::GC_malloc(layout.size()) as *mut u8 }
} else {
Expand All @@ -69,7 +69,7 @@ unsafe fn gc_malloc(layout: Layout) -> *mut u8 {
}

#[inline]
unsafe fn gc_realloc(ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
pub unsafe fn gc_realloc(ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
if old_layout.align() <= MIN_ALIGN && old_layout.align() <= new_size {
unsafe { api::GC_realloc(ptr as *mut c_void, new_size) as *mut u8 }
} else {
Expand All @@ -88,7 +88,7 @@ unsafe fn gc_realloc(ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut
}

#[inline]
unsafe fn gc_free(ptr: *mut u8, _: Layout) {
pub unsafe fn gc_free(ptr: *mut u8, _: Layout) {
unsafe {
api::GC_free(ptr as *mut c_void);
}
Expand Down Expand Up @@ -130,12 +130,15 @@ pub mod metrics {
}

#[cfg(feature = "gc-metrics")]
mod active {
pub mod active {
#![allow(dead_code)]
use core::sync::atomic::{AtomicU64, Ordering};

use super::{Metric, MetricsImpl};
use crate::bdwgc::api;

pub(super) struct Metrics {
#[derive(Debug)]
pub struct Metrics {
finalizers_registered: AtomicU64,
finalizers_elidable: AtomicU64,
finalizers_completed: AtomicU64,
Expand All @@ -161,17 +164,18 @@ pub mod metrics {
}
}

pub extern "C" fn record_post_collection(event: crate::GC_EventType) {
if event == crate::GC_EventType_GC_EVENT_END {
#[no_mangle]
pub extern "C" fn record_post_collection(event: api::GC_EventType) {
if event == api::GC_EventType_GC_EVENT_END {
super::METRICS.capture(false);
}
}

impl MetricsImpl for Metrics {
fn init(&self) {
unsafe {
crate::GC_enable_benchmark_stats();
crate::GC_set_on_collection_event(Some(record_post_collection));
api::GC_enable_benchmark_stats();
api::GC_set_on_collection_event(Some(record_post_collection));
}
}

Expand Down Expand Up @@ -207,7 +211,7 @@ pub mod metrics {
// Must preserve this ordering as it's hardcoded inside BDWGC.
// See src/bdwgc/misc.c:2812
unsafe {
crate::GC_log_metrics(
api::GC_log_metrics(
self.finalizers_completed.load(Ordering::Relaxed),
self.finalizers_registered.load(Ordering::Relaxed),
self.allocated_gc.load(Ordering::Relaxed),
Expand Down
1 change: 1 addition & 0 deletions library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ premature-finalizer-prevention = []
premature-finalizer-prevention-optimize = []
finalizer-elision = []
gc-disable = ["alloc/gc-disable"]
gc-default-allocator = []

# Make panics and failed asserts immediately abort without formatting any message
panic_immediate_abort = [
Expand Down
4 changes: 4 additions & 0 deletions library/std/src/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,10 @@ impl<T> Gc<T> {
#[inline(always)]
#[cfg(not(no_global_oom_handling))]
unsafe fn new_internal(value: T) -> Self {
if !is_enabled() {
enable();
}

#[cfg(not(bootstrap))]
{
#[cfg(feature = "finalizer-elision")]
Expand Down
93 changes: 61 additions & 32 deletions library/std/src/sys/alloc/unix.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,92 @@
use super::{MIN_ALIGN, realloc_fallback};
use crate::alloc::{GlobalAlloc, Layout, System};
#[cfg(not(feature = "gc-default-allocator"))]
use crate::ptr;

#[stable(feature = "alloc_system_type", since = "1.28.0")]
unsafe impl GlobalAlloc for System {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
// jemalloc provides alignment less than MIN_ALIGN for small allocations.
// So only rely on MIN_ALIGN if size >= align.
// Also see <https://github.com/rust-lang/rust/issues/45955> and
// <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
unsafe { libc::malloc(layout.size()) as *mut u8 }
} else {
// `posix_memalign` returns a non-aligned value if supplied a very
// large alignment on older versions of Apple's platforms (unknown
// exactly which version range, but the issue is definitely
// present in macOS 10.14 and iOS 13.3).
//
// <https://github.com/rust-lang/rust/issues/30170>
#[cfg(target_vendor = "apple")]
{
if layout.align() > (1 << 31) {
return ptr::null_mut();
#[cfg(feature = "gc-default-allocator")]
unsafe {
alloc::bdwgc::gc_malloc(layout)
}
#[cfg(not(feature = "gc-default-allocator"))]
{
// jemalloc provides alignment less than MIN_ALIGN for small allocations.
// So only rely on MIN_ALIGN if size >= align.
// Also see <https://github.com/rust-lang/rust/issues/45955> and
// <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
if layout.align() <= super::MIN_ALIGN && layout.align() <= layout.size() {
unsafe { libc::malloc(layout.size()) as *mut u8 }
} else {
// `posix_memalign` returns a non-aligned value if supplied a very
// large alignment on older versions of Apple's platforms (unknown
// exactly which version range, but the issue is definitely
// present in macOS 10.14 and iOS 13.3).
//
// <https://github.com/rust-lang/rust/issues/30170>
#[cfg(target_vendor = "apple")]
{
if layout.align() > (1 << 31) {
return ptr::null_mut();
}
}
unsafe { aligned_malloc(&layout) }
}
unsafe { aligned_malloc(&layout) }
}
}

#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
// See the comment above in `alloc` for why this check looks the way it does.
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
unsafe { libc::calloc(layout.size(), 1) as *mut u8 }
} else {
let ptr = unsafe { self.alloc(layout) };
if !ptr.is_null() {
unsafe { ptr::write_bytes(ptr, 0, layout.size()) };
#[cfg(feature = "gc-default-allocator")]
unsafe {
alloc::bdwgc::gc_malloc(layout)
}
#[cfg(not(feature = "gc-default-allocator"))]
{
// See the comment above in `alloc` for why this check looks the way it does.
if layout.align() <= super::MIN_ALIGN && layout.align() <= layout.size() {
unsafe { libc::calloc(layout.size(), 1) as *mut u8 }
} else {
let ptr = unsafe { self.alloc(layout) };
if !ptr.is_null() {
unsafe { ptr::write_bytes(ptr, 0, layout.size()) };
}
ptr
}
ptr
}
}

#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
unsafe { libc::free(ptr as *mut libc::c_void) }
#[cfg(feature = "gc-default-allocator")]
unsafe {
alloc::bdwgc::gc_free(ptr, _layout)
}
#[cfg(not(feature = "gc-default-allocator"))]
unsafe {
libc::free(ptr as *mut libc::c_void)
}
}

#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 }
} else {
unsafe { realloc_fallback(self, ptr, layout, new_size) }
#[cfg(feature = "gc-default-allocator")]
unsafe {
alloc::bdwgc::gc_realloc(ptr, layout, new_size)
}
#[cfg(not(feature = "gc-default-allocator"))]
{
if layout.align() <= super::MIN_ALIGN && layout.align() <= new_size {
unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 }
} else {
unsafe { super::realloc_fallback(self, ptr, layout, new_size) }
}
}
}
}

#[cfg(not(feature = "gc-default-allocator"))]
cfg_if::cfg_if! {
// We use posix_memalign wherever possible, but some targets have very incomplete POSIX coverage
// so we need a fallback for those.
Expand Down
1 change: 1 addition & 0 deletions library/sysroot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ premature-finalizer-prevention = ["std/premature-finalizer-prevention"]
premature-finalizer-prevention-optimize = ["std/premature-finalizer-prevention-optimize"]
gc-disable = ["std/gc-disable"]
gc-metrics = ["std/gc-metrics"]
gc-default-allocator = ["std/gc-default-allocator"]
5 changes: 4 additions & 1 deletion src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,9 @@ impl Step for Rustc {
let compiler = self.compiler;
let host = self.compiler.host;

let tarball = Tarball::new(builder, "rustc", &host.triple);
let mut tarball = Tarball::new(builder, "rustc", &host.triple);

tarball.permit_symlinks(true);

// Prepare the rustc "image", what will actually end up getting installed
prepare_image(builder, compiler, tarball.image_dir());
Expand Down Expand Up @@ -678,6 +680,7 @@ impl Step for Std {

let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
tarball.include_target_in_component_name(true);
tarball.permit_symlinks(true);

let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
let stamp = build_stamp::libstd_stamp(builder, compiler_to_use, target);
Expand Down
5 changes: 5 additions & 0 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ pub struct Config {
pub gc_assertions: bool,
pub gc_debug: bool,
pub gc_disable: bool,
pub gc_default_allocator: bool,

// misc
pub low_priority: bool,
Expand Down Expand Up @@ -1240,6 +1241,7 @@ define_config! {
gc_assertions: Option<bool> = "gc-assertions",
gc_debug: Option<bool> = "gc-debug",
gc_disable: Option<bool> = "gc-disable",
gc_default_allocator: Option<bool> = "gc-default-allocator",
}
}

Expand Down Expand Up @@ -1331,6 +1333,7 @@ impl Config {
gc_assertions: false,
gc_debug: false,
gc_disable: false,
gc_default_allocator: true,

..Default::default()
}
Expand Down Expand Up @@ -2067,6 +2070,7 @@ impl Config {
gc_assertions,
gc_debug,
gc_disable,
gc_default_allocator,
} = alloy;

set(&mut config.gc_metrics, gc_metrics);
Expand All @@ -2080,6 +2084,7 @@ impl Config {
set(&mut config.gc_assertions, gc_assertions);
set(&mut config.gc_debug, gc_debug);
set(&mut config.gc_disable, gc_disable);
set(&mut config.gc_default_allocator, gc_default_allocator);
}

if let Some(llvm) = toml.llvm {
Expand Down
3 changes: 3 additions & 0 deletions src/bootstrap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,9 @@ impl Build {
if self.config.gc_disable {
features.insert("gc-disable");
}
if self.config.gc_default_allocator {
features.insert("gc-default-allocator");
}
features.into_iter().collect::<Vec<_>>().join(" ")
}

Expand Down
5 changes: 4 additions & 1 deletion tests/ui/runtime/gc/disable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
#![allow(unused_variables)]
#![allow(unused_imports)]

use std::gc::{disable, enable, is_enabled, try_enable};
use std::gc::{Gc, disable, enable, is_enabled, try_enable};

fn main() {
assert!(!is_enabled());
// First allocation needed to enable the GC
let gc = Gc::new(123);
assert!(is_enabled());
disable();
disable();
Expand Down