summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Valentine-House <matt@eightbitraptor.com>2026-05-07 14:24:58 +0100
committergit <svn-admin@ruby-lang.org>2026-05-08 15:13:14 +0000
commit06caa59cc3b2787ade201a5ecbe3339930e85105 (patch)
treec2fc3bdad37323fea0867cad3faaaf6b9f2aede6
parent9fefb48643648234a71726e62ea7da2749cb85f4 (diff)
[ruby/mmtk] Introduce support for ractor_belonging.
This is a debug mode in Ruby where an extra word is used after each object to store the address of the Ractor that owns the object, used for debug purposes only. While we're working on Ractors, we also need to be able to test with MMTk enabled, so we should introduce support for this to the MMTk binding as well. As implemented we'll default the binding options to have everything disabled and hardcoded to 0, as was always the case, but if RACTOR_CHECK_MODE is enabled, we'll build and pass a valid RubyBinding object to MMTk. https://github.com/ruby/mmtk/commit/83cb291313
-rw-r--r--gc/mmtk/mmtk.c31
-rw-r--r--gc/mmtk/mmtk.h2
-rw-r--r--gc/mmtk/src/api.rs12
3 files changed, 37 insertions, 8 deletions
diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c
index e4cd71925c..9b1aed4e5b 100644
--- a/gc/mmtk/mmtk.c
+++ b/gc/mmtk/mmtk.c
@@ -16,6 +16,22 @@
#include <sys/sysctl.h>
#endif
+#ifndef VM_CHECK_MODE
+# define VM_CHECK_MODE RUBY_DEBUG
+#endif
+
+// From ractor_core.h
+#ifndef RACTOR_CHECK_MODE
+# define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
+#endif
+
+#if RACTOR_CHECK_MODE
+# define RVALUE_SUFFIX_SIZE sizeof(VALUE)
+void rb_ractor_setup_belonging(VALUE obj);
+#else
+# define RVALUE_SUFFIX_SIZE 0
+#endif
+
struct objspace {
bool measure_gc_time;
bool gc_stress;
@@ -557,7 +573,11 @@ void *
rb_gc_impl_objspace_alloc(void)
{
MMTk_Builder *builder = rb_mmtk_builder_init();
- mmtk_init_binding(builder, NULL, &ruby_upcalls);
+ MMTk_RubyBindingOptions binding_options = {
+ .ractor_check_mode = RACTOR_CHECK_MODE != 0,
+ .suffix_size = RVALUE_SUFFIX_SIZE,
+ };
+ mmtk_init_binding(builder, &binding_options, &ruby_upcalls);
return calloc(1, sizeof(struct objspace));
}
@@ -885,7 +905,8 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
mmtk_handle_user_collection_request(ractor_cache, false, false);
}
- alloc_size += sizeof(VALUE);
+ // Layout: [hidden size header (sizeof(VALUE))][payload (alloc_size)][suffix (RVALUE_SUFFIX_SIZE)]
+ alloc_size += sizeof(VALUE) + RVALUE_SUFFIX_SIZE;
VALUE *alloc_obj = (VALUE *)rb_mmtk_alloc_fast_path(objspace, ractor_cache, alloc_size);
if (!alloc_obj) {
@@ -893,7 +914,7 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
}
alloc_obj++;
- alloc_obj[-1] = alloc_size - sizeof(VALUE);
+ alloc_obj[-1] = alloc_size - sizeof(VALUE) - RVALUE_SUFFIX_SIZE;
alloc_obj[0] = flags;
alloc_obj[1] = klass;
@@ -905,6 +926,10 @@ rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags
objspace->total_allocated_objects++;
+#if RACTOR_CHECK_MODE
+ rb_ractor_setup_belonging((VALUE)alloc_obj);
+#endif
+
return (VALUE)alloc_obj;
}
diff --git a/gc/mmtk/mmtk.h b/gc/mmtk/mmtk.h
index ee338c87ef..e8f95920dd 100644
--- a/gc/mmtk/mmtk.h
+++ b/gc/mmtk/mmtk.h
@@ -95,7 +95,7 @@ bool mmtk_is_reachable(MMTk_ObjectReference object);
MMTk_Builder *mmtk_builder_default(void);
void mmtk_init_binding(MMTk_Builder *builder,
- const struct MMTk_RubyBindingOptions *_binding_options,
+ const struct MMTk_RubyBindingOptions *binding_options,
const struct MMTk_RubyUpcalls *upcalls);
void mmtk_initialize_collection(MMTk_VMThread tls);
diff --git a/gc/mmtk/src/api.rs b/gc/mmtk/src/api.rs
index b9797f6fe2..0c73cd74eb 100644
--- a/gc/mmtk/src/api.rs
+++ b/gc/mmtk/src/api.rs
@@ -181,7 +181,7 @@ pub extern "C" fn mmtk_builder_default() -> *mut MMTKBuilder {
#[no_mangle]
pub unsafe extern "C" fn mmtk_init_binding(
builder: *mut MMTKBuilder,
- _binding_options: *const RubyBindingOptions,
+ binding_options: *const RubyBindingOptions,
upcalls: *const RubyUpcalls,
) {
crate::MUTATOR_THREAD_PANIC_HANDLER
@@ -191,9 +191,13 @@ pub unsafe extern "C" fn mmtk_init_binding(
crate::set_panic_hook();
let builder: Box<MMTKBuilder> = unsafe { Box::from_raw(builder) };
- let binding_options = RubyBindingOptions {
- ractor_check_mode: false,
- suffix_size: 0,
+ let binding_options = if binding_options.is_null() {
+ RubyBindingOptions {
+ ractor_check_mode: false,
+ suffix_size: 0,
+ }
+ } else {
+ unsafe { (*binding_options).clone() }
};
let mmtk_boxed = mmtk_init(&builder);
let mmtk_static = Box::leak(Box::new(mmtk_boxed));