From e2243ed232d6a67e4a3e84e30e82b792a39b21e0 Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Sun, 21 Dec 2025 00:32:30 +0000 Subject: [PATCH 1/3] [DOC] Correct typo --- string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/string.c b/string.c index 8c7c82c10f4fa8..b70cee020de6bd 100644 --- a/string.c +++ b/string.c @@ -12383,7 +12383,7 @@ sym_succ(VALUE sym) * * Returns: * - * - symbol.to_s <=> other.to_s, if +other+ is a symbol. + * - self.to_s <=> other.to_s, if +other+ is a symbol. * - +nil+, otherwise. * * Examples: From 1bc2a9158966a4a1556529d8bb50fae66fa11bb0 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sun, 21 Dec 2025 11:31:36 +0900 Subject: [PATCH 2/3] [DOC] Align tables in globals.md * Align "Contains" column in "Streams" table * Align some columns vertically * Remove a duplicate `$-a` description --- doc/language/globals.md | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/doc/language/globals.md b/doc/language/globals.md index 4d42798b8ca154..a4199e488ab585 100644 --- a/doc/language/globals.md +++ b/doc/language/globals.md @@ -14,16 +14,16 @@ require 'English' ### Exceptions -| Variable | \English | Contains | Initially | Read-Only | Reset By | -|:--------:|:-----------------:|-----------------------------------------|:---------:|:---------:|---------------| -| `$!` | `$ERROR_INFO` | \Exception object or `nil` | `nil` | Yes | Kernel#raise | -| `$@` | `$ERROR_POSITION` | \Array of backtrace positions or `nil` | `nil` | Yes | Kernel#raise | +| Variable | \English | Contains | Initially | Read-Only | Reset By | +|:--------:|:-----------------:|----------------------------------------|:---------:|:---------:|--------------| +| `$!` | `$ERROR_INFO` | \Exception object or `nil` | `nil` | Yes | Kernel#raise | +| `$@` | `$ERROR_POSITION` | \Array of backtrace positions or `nil` | `nil` | Yes | Kernel#raise | ### Pattern Matching | Variable | \English | Contains | Initially | Read-Only | Reset By | |:-------------:|:-------------------:|-----------------------------------|:---------:|:---------:|-----------------| -| `$~` | `$LAST_MATCH_INFO` | \MatchData object or `nil` | `nil` | No | Matcher methods | +| `$~` | `$LAST_MATCH_INFO` | \MatchData object or `nil` | `nil` | No | Matcher methods | | `$&` | `$MATCH` | Matched substring or `nil` | `nil` | No | Matcher methods | | `` $` `` | `$PRE_MATCH` | Substring left of match or `nil` | `nil` | No | Matcher methods | | `$'` | `$POST_MATCH` | Substring right of match or `nil` | `nil` | No | Matcher methods | @@ -41,15 +41,15 @@ require 'English' ### Streams -| Variable | \English | Contains | Initially | Read-Only | Reset By | -|:---------:|:----------------------------:|:-------------------------------------------:|:---------:|:---------:|----------------------| -| `$stdin` | | Standard input stream | `STDIN` | No | | +| Variable | \English | Contains | Initially | Read-Only | Reset By | +|:---------:|:----------------------------:|---------------------------------------------|:---------:|:---------:|----------------------| +| `$stdin` | | Standard input stream | `STDIN` | No | | | `$stdout` | | Standard output stream | `STDOUT` | No | | | `$stderr` | | Standard error stream | `STDERR` | No | | -| `$<` | `$DEFAULT_INPUT` | Default standard input | `ARGF` | Yes | | -| `$>` | `$DEFAULT_OUTPUT` | Default standard output | `STDOUT` | No | | -| `$.` | `$INPUT_LINE_NUMBER`, `$NR` | Input position of most recently read stream | 0 | No | Certain read methods | -| `$_` | `$LAST_READ_LINE` | String from most recently read stream | `nil` | No | Certain read methods | +| `$<` | `$DEFAULT_INPUT` | Default standard input | `ARGF` | Yes | | +| `$>` | `$DEFAULT_OUTPUT` | Default standard output | `STDOUT` | No | | +| `$.` | `$INPUT_LINE_NUMBER`, `$NR` | Input position of most recently read stream | 0 | No | Certain read methods | +| `$_` | `$LAST_READ_LINE` | String from most recently read stream | `nil` | No | Certain read methods | ### Processes @@ -64,11 +64,11 @@ require 'English' ### Debugging -| Variable | \English | Contains | Initially | Read-Only | Reset By | +| Variable | \English | Contains | Initially | Read-Only | Reset By | |:-----------:|:--------:|--------------------------------------------|:----------------------------:|:---------:|----------| -| `$FILENAME` | | Value returned by method `ARGF.filename` | Command-line argument or '-' | Yes | | -| `$DEBUG` | | Whether option `-d` or `--debug` was given | Command-line option | No | | -| `$VERBOSE` | | Whether option `-V` or `-W` was given | Command-line option | No | | +| `$FILENAME` | | Value returned by method `ARGF.filename` | Command-line argument or '-' | Yes | | +| `$DEBUG` | | Whether option `-d` or `--debug` was given | Command-line option | No | | +| `$VERBOSE` | | Whether option `-V` or `-W` was given | Command-line option | No | | ### Other Variables @@ -352,10 +352,6 @@ Aliased as `$-v` and `$-w`. ## Other Variables -### `$-a` - -Whether command-line option `-a` was given; read-only. - ### `$-F` The default field separator in String#split; must be a String or a From 038b158fa30d1b1cda153aeb10dac5f59f966036 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Sat, 20 Dec 2025 16:08:01 -0500 Subject: [PATCH 3/3] [ruby/mmtk] Implement fast path for bump pointer allocator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding a fast path for bump pointer allocator can improve allocation performance. For the following microbenchmark with MMTK_HEAP_MIN=100MiB: 10_000_000.times { String.new } Before: 810.7 ms ± 8.3 ms [User: 790.9 ms, System: 40.3 ms] After: 777.9 ms ± 10.4 ms [User: 759.0 ms, System: 37.9 ms] https://github.com/ruby/mmtk/commit/0ff5c9f579 --- gc/mmtk/cbindgen.toml | 5 +++++ gc/mmtk/mmtk.c | 34 +++++++++++++++++++++++++++++++--- gc/mmtk/mmtk.h | 7 +++++++ gc/mmtk/src/api.rs | 20 ++++++++++++++++++++ 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/gc/mmtk/cbindgen.toml b/gc/mmtk/cbindgen.toml index c66f829b3dd1d0..b99c30efc8c868 100644 --- a/gc/mmtk/cbindgen.toml +++ b/gc/mmtk/cbindgen.toml @@ -20,6 +20,11 @@ typedef void *MMTk_Address; typedef void *MMTk_ObjectReference; typedef void *MMTk_NullableObjectReference; typedef uint32_t MMTk_AllocationSemantics; + +typedef struct MMTk_BumpPointer { + uintptr_t cursor; + uintptr_t limit; +} MMTk_BumpPointer; """ [export] diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c index c0c1bf30ea34c9..fe1a17b2451715 100644 --- a/gc/mmtk/mmtk.c +++ b/gc/mmtk/mmtk.c @@ -48,6 +48,8 @@ struct MMTk_ractor_cache { MMTk_Mutator *mutator; bool gc_mutator_p; + + MMTk_BumpPointer *bump_pointer; }; struct MMTk_final_job { @@ -447,6 +449,7 @@ rb_gc_impl_ractor_cache_alloc(void *objspace_ptr, void *ractor) ccan_list_add(&objspace->ractor_caches, &cache->list_node); cache->mutator = mmtk_bind_mutator(cache); + cache->bump_pointer = mmtk_get_bump_pointer_allocator(cache->mutator); return cache; } @@ -612,6 +615,24 @@ rb_gc_impl_config_set(void *objspace_ptr, VALUE hash) // Object allocation +static VALUE +rb_mmtk_alloc_fast_path(struct objspace *objspace, struct MMTk_ractor_cache *ractor_cache, size_t size) +{ + MMTk_BumpPointer *bump_pointer = ractor_cache->bump_pointer; + if (bump_pointer == NULL) return 0; + + uintptr_t new_cursor = bump_pointer->cursor + size; + + if (new_cursor > bump_pointer->limit) { + return 0; + } + else { + VALUE obj = (VALUE)bump_pointer->cursor; + bump_pointer->cursor = new_cursor; + return obj; + } +} + VALUE rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, bool wb_protected, size_t alloc_size) { @@ -632,13 +653,20 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags mmtk_handle_user_collection_request(ractor_cache, false, false); } - VALUE *alloc_obj = mmtk_alloc(ractor_cache->mutator, alloc_size + 8, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT); + alloc_size += sizeof(VALUE); + + VALUE *alloc_obj = (VALUE *)rb_mmtk_alloc_fast_path(objspace, ractor_cache, alloc_size); + if (!alloc_obj) { + alloc_obj = mmtk_alloc(ractor_cache->mutator, alloc_size, MMTk_MIN_OBJ_ALIGN, 0, MMTK_ALLOCATION_SEMANTICS_DEFAULT); + } + alloc_obj++; - alloc_obj[-1] = alloc_size; + alloc_obj[-1] = alloc_size - sizeof(VALUE); alloc_obj[0] = flags; alloc_obj[1] = klass; - mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, alloc_size + 8, MMTK_ALLOCATION_SEMANTICS_DEFAULT); + // TODO: implement fast path for mmtk_post_alloc + mmtk_post_alloc(ractor_cache->mutator, (void*)alloc_obj, alloc_size, MMTK_ALLOCATION_SEMANTICS_DEFAULT); // TODO: only add when object needs obj_free to be called mmtk_add_obj_free_candidate(alloc_obj); diff --git a/gc/mmtk/mmtk.h b/gc/mmtk/mmtk.h index 18466c61108b40..45521e2671b5cb 100644 --- a/gc/mmtk/mmtk.h +++ b/gc/mmtk/mmtk.h @@ -20,6 +20,11 @@ typedef void *MMTk_ObjectReference; typedef void *MMTk_NullableObjectReference; typedef uint32_t MMTk_AllocationSemantics; +typedef struct MMTk_BumpPointer { + uintptr_t cursor; + uintptr_t limit; +} MMTk_BumpPointer; + #define MMTk_OBJREF_OFFSET 8 @@ -93,6 +98,8 @@ void mmtk_initialize_collection(MMTk_VMThread tls); MMTk_Mutator *mmtk_bind_mutator(MMTk_VMMutatorThread tls); +MMTk_BumpPointer *mmtk_get_bump_pointer_allocator(MMTk_Mutator *m); + void mmtk_destroy_mutator(MMTk_Mutator *mutator); void mmtk_handle_user_collection_request(MMTk_VMMutatorThread tls, bool force, bool exhaustive); diff --git a/gc/mmtk/src/api.rs b/gc/mmtk/src/api.rs index 006e987ea9d060..b99cbdc939f151 100644 --- a/gc/mmtk/src/api.rs +++ b/gc/mmtk/src/api.rs @@ -2,6 +2,8 @@ // They are called by C functions and they need to pass raw pointers to Rust. #![allow(clippy::missing_safety_doc)] +use mmtk::util::alloc::BumpPointer; +use mmtk::util::alloc::ImmixAllocator; use mmtk::util::options::PlanSelector; use std::str::FromStr; use std::sync::atomic::Ordering; @@ -174,6 +176,24 @@ pub extern "C" fn mmtk_bind_mutator(tls: VMMutatorThread) -> *mut RubyMutator { Box::into_raw(memory_manager::bind_mutator(mmtk(), tls)) } +#[no_mangle] +pub unsafe extern "C" fn mmtk_get_bump_pointer_allocator(m: *mut RubyMutator) -> *mut BumpPointer { + match *crate::BINDING.get().unwrap().mmtk.get_options().plan { + PlanSelector::Immix => { + let mutator: &mut Mutator = unsafe { &mut *m }; + let allocator = + unsafe { mutator.allocator_mut(mmtk::util::alloc::AllocatorSelector::Immix(0)) }; + + if let Some(immix_allocator) = allocator.downcast_mut::>() { + &mut immix_allocator.bump_pointer as *mut BumpPointer + } else { + panic!("Failed to get bump pointer allocator"); + } + } + _ => std::ptr::null_mut(), + } +} + #[no_mangle] pub unsafe extern "C" fn mmtk_destroy_mutator(mutator: *mut RubyMutator) { // notify mmtk-core about destroyed mutator