diff --git a/library/alloc/src/bdwgc.rs b/library/alloc/src/bdwgc.rs index c0253731f4bff..24584a8e86c0d 100644 --- a/library/alloc/src/bdwgc.rs +++ b/library/alloc/src/bdwgc.rs @@ -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. @@ -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 { @@ -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 { @@ -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); } @@ -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, @@ -161,8 +164,9 @@ 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); } } @@ -170,8 +174,8 @@ pub mod metrics { 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)); } } @@ -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), diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index c4f8e1f8a2a41..c42f033d0d757 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -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 = [ diff --git a/library/std/src/gc.rs b/library/std/src/gc.rs index f8b6c7b29fabf..a61997051e777 100644 --- a/library/std/src/gc.rs +++ b/library/std/src/gc.rs @@ -427,6 +427,10 @@ impl Gc { #[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")] diff --git a/library/std/src/sys/alloc/unix.rs b/library/std/src/sys/alloc/unix.rs index 1af9d76629014..156b6895c61c1 100644 --- a/library/std/src/sys/alloc/unix.rs +++ b/library/std/src/sys/alloc/unix.rs @@ -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 and - // . - 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). - // - // - #[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 and + // . + 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). + // + // + #[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. diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index eede7e1bbd4a2..8be6dcb42c7a9 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -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"] diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index e0ad6856dc72c..08d55684002ad 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -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()); @@ -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); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 26ace66239fe0..f18e49f897c88 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -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, @@ -1240,6 +1241,7 @@ define_config! { gc_assertions: Option = "gc-assertions", gc_debug: Option = "gc-debug", gc_disable: Option = "gc-disable", + gc_default_allocator: Option = "gc-default-allocator", } } @@ -1331,6 +1333,7 @@ impl Config { gc_assertions: false, gc_debug: false, gc_disable: false, + gc_default_allocator: true, ..Default::default() } @@ -2067,6 +2070,7 @@ impl Config { gc_assertions, gc_debug, gc_disable, + gc_default_allocator, } = alloy; set(&mut config.gc_metrics, gc_metrics); @@ -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 { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index d33999ec0aec3..f3cbf6a295f82 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -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::>().join(" ") } diff --git a/tests/ui/runtime/gc/disable.rs b/tests/ui/runtime/gc/disable.rs index 5bd33e6b56afd..dccb69411ba0d 100644 --- a/tests/ui/runtime/gc/disable.rs +++ b/tests/ui/runtime/gc/disable.rs @@ -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();