Add field handle_weak_references to TypedData

This commit adds a field handle_weak_references to rb_data_type_struct for
the callback when handling weak references. This avoids TypedData objects
from needing to expose their rb_data_type_struct and weak references function.
This commit is contained in:
Peter Zhu 2025-12-30 16:03:35 -05:00
parent 1b3382cbab
commit 6939f03f4c
Notes: git 2026-01-04 14:03:07 +00:00
4 changed files with 70 additions and 90 deletions

41
cont.c
View File

@ -48,8 +48,8 @@ static const int DEBUG = 0;
#define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1))
static long pagesize;
const rb_data_type_t rb_cont_data_type;
const rb_data_type_t rb_fiber_data_type;
static const rb_data_type_t rb_cont_data_type;
static const rb_data_type_t rb_fiber_data_type;
static VALUE rb_cContinuation;
static VALUE rb_cFiber;
static VALUE rb_eFiberError;
@ -1239,17 +1239,11 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
asan_unpoison_memory_region(cont->machine.stack_src, size, false);
MEMCPY(cont->machine.stack, cont->machine.stack_src, VALUE, size);
}
const rb_data_type_t rb_cont_data_type = {
"continuation",
{cont_mark, cont_free, cont_memsize, cont_compact},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
void
rb_cont_handle_weak_references(VALUE obj)
static void
cont_handle_weak_references(void *ptr)
{
rb_context_t *cont;
TypedData_Get_Struct(obj, rb_context_t, &rb_cont_data_type, cont);
rb_context_t *cont = ptr;
if (!cont) return;
@ -1260,6 +1254,12 @@ rb_cont_handle_weak_references(VALUE obj)
}
}
static const rb_data_type_t rb_cont_data_type = {
"continuation",
{cont_mark, cont_free, cont_memsize, cont_compact, cont_handle_weak_references},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static inline void
cont_save_thread(rb_context_t *cont, rb_thread_t *th)
{
@ -1996,17 +1996,10 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
*
*/
const rb_data_type_t rb_fiber_data_type = {
"fiber",
{fiber_mark, fiber_free, fiber_memsize, fiber_compact,},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
void
rb_fiber_handle_weak_references(VALUE obj)
static void
fiber_handle_weak_references(void *ptr)
{
rb_fiber_t *fiber;
TypedData_Get_Struct(obj, rb_fiber_t, &rb_fiber_data_type, fiber);
rb_fiber_t *fiber = ptr;
if (!fiber) return;
@ -2017,6 +2010,12 @@ rb_fiber_handle_weak_references(VALUE obj)
}
}
static const rb_data_type_t rb_fiber_data_type = {
"fiber",
{fiber_mark, fiber_free, fiber_memsize, fiber_compact, fiber_handle_weak_references},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
fiber_alloc(VALUE klass)
{

29
gc.c
View File

@ -1204,17 +1204,6 @@ rb_gc_handle_weak_references_alive_p(VALUE obj)
return rb_gc_impl_handle_weak_references_alive_p(rb_gc_get_objspace(), obj);
}
extern const rb_data_type_t rb_weakmap_type;
void rb_wmap_handle_weak_references(VALUE obj);
extern const rb_data_type_t rb_weakkeymap_type;
void rb_wkmap_handle_weak_references(VALUE obj);
extern const rb_data_type_t rb_fiber_data_type;
void rb_fiber_handle_weak_references(VALUE obj);
extern const rb_data_type_t rb_cont_data_type;
void rb_cont_handle_weak_references(VALUE obj);
void
rb_gc_handle_weak_references(VALUE obj)
{
@ -1223,20 +1212,14 @@ rb_gc_handle_weak_references(VALUE obj)
if (RTYPEDDATA_P(obj)) {
const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
if (type == &rb_fiber_data_type) {
rb_fiber_handle_weak_references(obj);
}
else if (type == &rb_cont_data_type) {
rb_cont_handle_weak_references(obj);
}
else if (type == &rb_weakmap_type) {
rb_wmap_handle_weak_references(obj);
}
else if (type == &rb_weakkeymap_type) {
rb_wkmap_handle_weak_references(obj);
if (type->function.handle_weak_references) {
(type->function.handle_weak_references)(RTYPEDDATA_GET_DATA(obj));
}
else {
rb_bug("rb_gc_handle_weak_references: unknown TypedData %s", RTYPEDDATA_TYPE(obj)->wrap_struct_name);
rb_bug(
"rb_gc_handle_weak_references: TypedData %s does not implement handle_weak_references",
RTYPEDDATA_TYPE(obj)->wrap_struct_name
);
}
}
else {

View File

@ -262,11 +262,9 @@ struct rb_data_type_struct {
RUBY_DATA_FUNC dcompact;
/**
* This field is reserved for future extension. For now, it must be
* filled with zeros.
* @internal
*/
void *reserved[1]; /* For future extension.
This array *must* be filled with ZERO. */
void (*handle_weak_references)(void *);
} function;
/**

View File

@ -112,6 +112,26 @@ wmap_compact(void *ptr)
}
}
static int
rb_wmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
{
if (rb_gc_handle_weak_references_alive_p(key) &&
rb_gc_handle_weak_references_alive_p(val)) {
return ST_CONTINUE;
}
else {
return ST_DELETE;
}
}
static void
wmap_handle_weak_references(void *ptr)
{
struct weakmap *w = ptr;
st_foreach(w->table, rb_wmap_handle_weak_references_i, (st_data_t)0);
}
const rb_data_type_t rb_weakmap_type = {
"weakmap",
{
@ -119,6 +139,7 @@ const rb_data_type_t rb_weakmap_type = {
wmap_free,
wmap_memsize,
wmap_compact,
wmap_handle_weak_references,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@ -140,27 +161,6 @@ static const struct st_hash_type wmap_hash_type = {
wmap_hash,
};
static int
rb_wmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
{
if (rb_gc_handle_weak_references_alive_p(key) &&
rb_gc_handle_weak_references_alive_p(val)) {
return ST_CONTINUE;
}
else {
return ST_DELETE;
}
}
void
rb_wmap_handle_weak_references(VALUE self)
{
struct weakmap *w;
TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w);
st_foreach(w->table, rb_wmap_handle_weak_references_i, (st_data_t)0);
}
static VALUE
wmap_allocate(VALUE klass)
{
@ -588,13 +588,33 @@ wkmap_compact(void *ptr)
}
}
const rb_data_type_t rb_weakkeymap_type = {
static int
rb_wkmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
{
if (rb_gc_handle_weak_references_alive_p(key)) {
return ST_CONTINUE;
}
else {
return ST_DELETE;
}
}
static void
wkmap_handle_weak_references(void *ptr)
{
struct weakkeymap *w = ptr;
st_foreach(w->table, rb_wkmap_handle_weak_references_i, (st_data_t)0);
}
static const rb_data_type_t rb_weakkeymap_type = {
"weakkeymap",
{
wkmap_mark,
wkmap_free,
wkmap_memsize,
wkmap_compact,
wkmap_handle_weak_references,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
@ -621,26 +641,6 @@ static const struct st_hash_type wkmap_hash_type = {
wkmap_hash,
};
static int
rb_wkmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg)
{
if (rb_gc_handle_weak_references_alive_p(key)) {
return ST_CONTINUE;
}
else {
return ST_DELETE;
}
}
void
rb_wkmap_handle_weak_references(VALUE self)
{
struct weakkeymap *w;
TypedData_Get_Struct(self, struct weakkeymap, &rb_weakkeymap_type, w);
st_foreach(w->table, rb_wkmap_handle_weak_references_i, (st_data_t)0);
}
static VALUE
wkmap_allocate(VALUE klass)
{