From 7c121692309d0a4d1183ace406b0c4a2848e6da6 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Thu, 30 May 2024 18:12:29 +0200 Subject: [PATCH] Eliminate internal uses of `Data_Wrap_Struct` Ref: https://github.com/ruby/ruby/pull/10872 These should be the last internal uses of the old `Data` API inside Ruby itself. Some use remain in a couple default gems. --- array.c | 16 +++++++---- common.mk | 3 ++ compile.c | 18 ++++++++---- dir.c | 11 +++----- marshal.c | 82 +++++++++++++++++++++++++++++++++++++------------------ util.c | 48 ++++++++++++++++++++++++-------- 6 files changed, 122 insertions(+), 56 deletions(-) diff --git a/array.c b/array.c index 8355a45da5..dab933776f 100644 --- a/array.c +++ b/array.c @@ -6549,6 +6549,14 @@ rb_ary_shuffle(rb_execution_context_t *ec, VALUE ary, VALUE randgen) return ary; } +static const rb_data_type_t ary_sample_memo_type = { + .wrap_struct_name = "ary_sample_memo", + .function = { + .dfree = (RUBY_DATA_FUNC)st_free_table, + }, + .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY +}; + static VALUE ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE to_array) { @@ -6630,11 +6638,9 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE } else if (n <= memo_threshold / 2) { long max_idx = 0; -#undef RUBY_UNTYPED_DATA_WARNING -#define RUBY_UNTYPED_DATA_WARNING 0 - VALUE vmemo = Data_Wrap_Struct(0, 0, st_free_table, 0); + VALUE vmemo = TypedData_Wrap_Struct(0, &ary_sample_memo_type, 0); st_table *memo = st_init_numtable_with_size(n); - DATA_PTR(vmemo) = memo; + RTYPEDDATA_DATA(vmemo) = memo; result = rb_ary_new_capa(n); RARRAY_PTR_USE(result, ptr_result, { for (i=0; inewclass); - rb_gc_mark(p->oldclass); - return ST_CONTINUE; -} - -static void -mark_marshal_compat_t(void *tbl) -{ - if (!tbl) return; - st_foreach(tbl, mark_marshal_compat_i, 0); -} - static st_table *compat_allocator_table(void); void @@ -156,11 +140,10 @@ rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE (*dumper)(VALUE), rb_raise(rb_eTypeError, "no allocator"); } + compat_allocator_table(); compat = ALLOC(marshal_compat_t); - compat->newclass = Qnil; - compat->oldclass = Qnil; - compat->newclass = newclass; - compat->oldclass = oldclass; + RB_OBJ_WRITE(compat_allocator_tbl_wrapper, &compat->newclass, newclass); + RB_OBJ_WRITE(compat_allocator_tbl_wrapper, &compat->oldclass, oldclass); compat->dumper = dumper; compat->loader = loader; @@ -2525,28 +2508,75 @@ Init_marshal(void) } static int -free_compat_i(st_data_t key, st_data_t value, st_data_t _) +marshal_compat_table_mark_i(st_data_t key, st_data_t value, st_data_t _) +{ + marshal_compat_t *p = (marshal_compat_t *)value; + rb_gc_mark_movable(p->newclass); + rb_gc_mark_movable(p->oldclass); + return ST_CONTINUE; +} + +static void +marshal_compat_table_mark(void *tbl) +{ + if (!tbl) return; + st_foreach(tbl, marshal_compat_table_mark_i, 0); +} + +static int +marshal_compat_table_free_i(st_data_t key, st_data_t value, st_data_t _) { xfree((marshal_compat_t *)value); return ST_CONTINUE; } static void -free_compat_allocator_table(void *data) +marshal_compat_table_free(void *data) { - st_foreach(data, free_compat_i, 0); + st_foreach(data, marshal_compat_table_free_i, 0); st_free_table(data); } +static size_t +marshal_compat_table_memsize(const void *data) +{ + return st_memsize(data) + sizeof(marshal_compat_t) * st_table_size(data); +} + +static int +marshal_compat_table_compact_i(st_data_t key, st_data_t value, st_data_t _) +{ + marshal_compat_t *p = (marshal_compat_t *)value; + p->newclass = rb_gc_location(p->newclass); + p->oldclass = rb_gc_location(p->oldclass); + return ST_CONTINUE; +} + +static void +marshal_compat_table_compact(void *tbl) +{ + if (!tbl) return; + st_foreach(tbl, marshal_compat_table_compact_i, 0); +} + +static const rb_data_type_t marshal_compat_type = { + .wrap_struct_name = "marshal_compat_table", + .function = { + .dmark = marshal_compat_table_mark, + .dfree = marshal_compat_table_free, + .dsize = marshal_compat_table_memsize, + .dcompact = marshal_compat_table_compact, + }, + .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY, +}; + static st_table * compat_allocator_table(void) { if (compat_allocator_tbl) return compat_allocator_tbl; compat_allocator_tbl = st_init_numtable(); -#undef RUBY_UNTYPED_DATA_WARNING -#define RUBY_UNTYPED_DATA_WARNING 0 compat_allocator_tbl_wrapper = - Data_Wrap_Struct(0, mark_marshal_compat_t, free_compat_allocator_table, compat_allocator_tbl); + TypedData_Wrap_Struct(0, &marshal_compat_type, compat_allocator_tbl); rb_vm_register_global_object(compat_allocator_tbl_wrapper); return compat_allocator_tbl; } diff --git a/util.c b/util.c index 3c08879ce5..8a18814937 100644 --- a/util.c +++ b/util.c @@ -31,6 +31,7 @@ #include "internal.h" #include "internal/sanitizers.h" +#include "internal/imemo.h" #include "internal/util.h" #include "ruby/util.h" #include "ruby_atomic.h" @@ -543,41 +544,63 @@ ruby_strdup(const char *str) return tmp; } +#if defined HAVE_GETCWD +# if defined NO_GETCWD_MALLOC + char * ruby_getcwd(void) { -#if defined HAVE_GETCWD -# undef RUBY_UNTYPED_DATA_WARNING -# define RUBY_UNTYPED_DATA_WARNING 0 -# if defined NO_GETCWD_MALLOC - VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, RUBY_DEFAULT_FREE, NULL); + VALUE guard = rb_imemo_tmpbuf_auto_free_pointer(); int size = 200; char *buf = xmalloc(size); while (!getcwd(buf, size)) { int e = errno; if (e != ERANGE) { - xfree(buf); - DATA_PTR(guard) = NULL; + rb_free_tmp_buffer(&guard); rb_syserr_fail(e, "getcwd"); } size *= 2; - DATA_PTR(guard) = buf; + rb_imemo_tmpbuf_set_ptr(guard, buf); buf = xrealloc(buf, size); } + rb_free_tmp_buffer(&guard); + return buf; +} + # else - VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, free, NULL); + +static const rb_data_type_t getcwd_buffer_guard_type = { + .wrap_struct_name = "ruby_getcwd_guard", + .function = { + .dfree = free // not xfree. + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED +}; + +char * +ruby_getcwd(void) +{ + VALUE guard = TypedData_Wrap_Struct((VALUE)0, &getcwd_buffer_guard_type, NULL); char *buf, *cwd = getcwd(NULL, 0); - DATA_PTR(guard) = cwd; + RTYPEDDATA_DATA(guard) = cwd; if (!cwd) rb_sys_fail("getcwd"); buf = ruby_strdup(cwd); /* allocate by xmalloc */ free(cwd); + RTYPEDDATA_DATA(RB_GC_GUARD(guard)) = NULL; + return buf; +} + # endif - DATA_PTR(RB_GC_GUARD(guard)) = NULL; #else + # ifndef PATH_MAX # define PATH_MAX 8192 # endif + +char * +ruby_getcwd(void) +{ char *buf = xmalloc(PATH_MAX+1); if (!getwd(buf)) { @@ -585,10 +608,11 @@ ruby_getcwd(void) xfree(buf); rb_syserr_fail(e, "getwd"); } -#endif return buf; } +#endif + void ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *arg) {