From 0ada02abe2c66f49159243b78994645a2936b706 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Thu, 25 Jul 2024 17:35:24 -0400 Subject: [PATCH] Put the default GC implementation back into gc.o We discovered that having gc.o and gc_impl.o in separate translation units diminishes codegen quality with GCC 11 on x86-64. This commit solves that problem by including default/gc.c into gc.c, letting the optimizer have visibility into the body of functions again in builds not using link-time optimization, which are common. This effectively restores things to the way they were before [Feature #20470] from the optimizer's perspective while maintaining the ability to build gc/default.c as a DSO. There were a few functions duplicated across gc.c and gc/default.c. Extract them and put them into gc/gc.h. --- common.mk | 194 +-------------------------------------------------- gc.c | 138 ++---------------------------------- gc/default.c | 141 +++---------------------------------- gc/gc.h | 146 +++++++++++++++++++++++++++++++++++++- gc/gc_impl.h | 174 +++++++++++++++++++++++++-------------------- 5 files changed, 257 insertions(+), 536 deletions(-) diff --git a/common.mk b/common.mk index b387c47a4a..a0c41e04e0 100644 --- a/common.mk +++ b/common.mk @@ -130,7 +130,6 @@ COMMONOBJS = array.$(OBJEXT) \ eval.$(OBJEXT) \ file.$(OBJEXT) \ gc.$(OBJEXT) \ - gc_impl.$(OBJEXT) \ hash.$(OBJEXT) \ inits.$(OBJEXT) \ imemo.$(OBJEXT) \ @@ -7238,6 +7237,7 @@ gc.$(OBJEXT): $(CCAN_DIR)/str/str.h gc.$(OBJEXT): $(hdrdir)/ruby.h gc.$(OBJEXT): $(hdrdir)/ruby/ruby.h gc.$(OBJEXT): $(hdrdir)/ruby/version.h +gc.$(OBJEXT): $(top_srcdir)/gc/default.c gc.$(OBJEXT): $(top_srcdir)/gc/gc.h gc.$(OBJEXT): $(top_srcdir)/gc/gc_impl.h gc.$(OBJEXT): $(top_srcdir)/internal/array.h @@ -7503,198 +7503,6 @@ gc.$(OBJEXT): {$(VPATH)}vm_core.h gc.$(OBJEXT): {$(VPATH)}vm_debug.h gc.$(OBJEXT): {$(VPATH)}vm_opts.h gc.$(OBJEXT): {$(VPATH)}vm_sync.h -gc_impl.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h -gc_impl.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h -gc_impl.$(OBJEXT): $(CCAN_DIR)/list/list.h -gc_impl.$(OBJEXT): $(CCAN_DIR)/str/str.h -gc_impl.$(OBJEXT): $(hdrdir)/ruby/ruby.h -gc_impl.$(OBJEXT): $(top_srcdir)/gc/default.c -gc_impl.$(OBJEXT): $(top_srcdir)/gc/gc.h -gc_impl.$(OBJEXT): $(top_srcdir)/gc/gc_impl.h -gc_impl.$(OBJEXT): $(top_srcdir)/internal/bits.h -gc_impl.$(OBJEXT): $(top_srcdir)/internal/compilers.h -gc_impl.$(OBJEXT): $(top_srcdir)/internal/hash.h -gc_impl.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h -gc_impl.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -gc_impl.$(OBJEXT): $(top_srcdir)/internal/string.h -gc_impl.$(OBJEXT): $(top_srcdir)/internal/warnings.h -gc_impl.$(OBJEXT): {$(VPATH)}assert.h -gc_impl.$(OBJEXT): {$(VPATH)}atomic.h -gc_impl.$(OBJEXT): {$(VPATH)}backward/2/assume.h -gc_impl.$(OBJEXT): {$(VPATH)}backward/2/attributes.h -gc_impl.$(OBJEXT): {$(VPATH)}backward/2/bool.h -gc_impl.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h -gc_impl.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h -gc_impl.$(OBJEXT): {$(VPATH)}backward/2/limits.h -gc_impl.$(OBJEXT): {$(VPATH)}backward/2/long_long.h -gc_impl.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h -gc_impl.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h -gc_impl.$(OBJEXT): {$(VPATH)}config.h -gc_impl.$(OBJEXT): {$(VPATH)}darray.h -gc_impl.$(OBJEXT): {$(VPATH)}debug.h -gc_impl.$(OBJEXT): {$(VPATH)}debug_counter.h -gc_impl.$(OBJEXT): {$(VPATH)}defines.h -gc_impl.$(OBJEXT): {$(VPATH)}encoding.h -gc_impl.$(OBJEXT): {$(VPATH)}intern.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/abi.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/anyargs.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/assume.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/cold.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/const.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/error.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/format.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/pure.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/warning.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/cast.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/config.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/constant_p.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rarray.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rclass.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rdata.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rfile.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rhash.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/robject.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rstring.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/ctype.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/dllexport.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/dosish.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/encoding/re.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/encoding/string.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/error.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/eval.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/event.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/fl_type.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/gc.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/glob.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/globals.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/has/builtin.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/has/extension.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/has/feature.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/has/warning.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/array.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/class.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/compar.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/complex.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/cont.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/dir.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/enum.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/error.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/eval.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/file.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/hash.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/io.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/load.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/object.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/parse.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/proc.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/process.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/random.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/range.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/rational.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/re.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/select.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/signal.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/string.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/struct.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/thread.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/time.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/variable.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/intern/vm.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/interpreter.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/iterator.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/memory.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/method.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/module.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/newobj.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/scan_args.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/special_consts.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/static_assert.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/stdalign.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/stdbool.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/stdckdint.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/symbol.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/value.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/value_type.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/variable.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/warning_push.h -gc_impl.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -gc_impl.$(OBJEXT): {$(VPATH)}missing.h -gc_impl.$(OBJEXT): {$(VPATH)}onigmo.h -gc_impl.$(OBJEXT): {$(VPATH)}oniguruma.h -gc_impl.$(OBJEXT): {$(VPATH)}probes.dmyh -gc_impl.$(OBJEXT): {$(VPATH)}probes.h -gc_impl.$(OBJEXT): {$(VPATH)}st.h -gc_impl.$(OBJEXT): {$(VPATH)}subst.h -gc_impl.$(OBJEXT): {$(VPATH)}thread.h -gc_impl.$(OBJEXT): {$(VPATH)}util.h -gc_impl.$(OBJEXT): {$(VPATH)}vm.h goruby.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h goruby.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h goruby.$(OBJEXT): $(CCAN_DIR)/list/list.h diff --git a/gc.c b/gc.c index c67567f7e8..84c3d6dd3b 100644 --- a/gc.c +++ b/gc.c @@ -83,7 +83,6 @@ #include "debug_counter.h" #include "eval_intern.h" #include "gc/gc.h" -#include "gc/gc_impl.h" #include "id_table.h" #include "internal.h" #include "internal/class.h" @@ -565,6 +564,10 @@ rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val) } #endif +static const char *obj_type_name(VALUE obj); +#define RB_AMALGAMATED_DEFAULT_GC +#include "gc/default.c" + #if USE_SHARED_GC && !defined(HAVE_DLOPEN) # error "Shared GC requires dlopen" #elif USE_SHARED_GC @@ -1899,43 +1902,6 @@ set_zero(st_data_t key, st_data_t val, st_data_t arg) return ST_CONTINUE; } -static VALUE -type_sym(size_t type) -{ - switch (type) { -#define COUNT_TYPE(t) case (t): return ID2SYM(rb_intern(#t)); break; - COUNT_TYPE(T_NONE); - COUNT_TYPE(T_OBJECT); - COUNT_TYPE(T_CLASS); - COUNT_TYPE(T_MODULE); - COUNT_TYPE(T_FLOAT); - COUNT_TYPE(T_STRING); - COUNT_TYPE(T_REGEXP); - COUNT_TYPE(T_ARRAY); - COUNT_TYPE(T_HASH); - COUNT_TYPE(T_STRUCT); - COUNT_TYPE(T_BIGNUM); - COUNT_TYPE(T_FILE); - COUNT_TYPE(T_DATA); - COUNT_TYPE(T_MATCH); - COUNT_TYPE(T_COMPLEX); - COUNT_TYPE(T_RATIONAL); - COUNT_TYPE(T_NIL); - COUNT_TYPE(T_TRUE); - COUNT_TYPE(T_FALSE); - COUNT_TYPE(T_SYMBOL); - COUNT_TYPE(T_FIXNUM); - COUNT_TYPE(T_IMEMO); - COUNT_TYPE(T_UNDEF); - COUNT_TYPE(T_NODE); - COUNT_TYPE(T_ICLASS); - COUNT_TYPE(T_ZOMBIE); - COUNT_TYPE(T_MOVED); -#undef COUNT_TYPE - default: return SIZET2NUM(type); break; - } -} - struct count_objects_data { size_t counts[T_MASK+1]; size_t freed; @@ -2392,16 +2358,6 @@ rb_mark_tbl(st_table *tbl) st_foreach(tbl, rb_mark_tbl_i, (st_data_t)rb_gc_get_objspace()); } -static int -gc_mark_tbl_no_pin_i(st_data_t key, st_data_t value, st_data_t data) -{ - void *objspace = (void *)data; - - rb_gc_impl_mark(objspace, (VALUE)value); - - return ST_CONTINUE; -} - static void gc_mark_tbl_no_pin(void *objspace, st_table *tbl) { @@ -2963,8 +2919,6 @@ gc_ref_update_array(void *objspace, VALUE v) } } -static void gc_ref_update_table_values_only(void *objspace, st_table *tbl); - static void gc_ref_update_object(void *objspace, VALUE v) { @@ -2990,90 +2944,12 @@ gc_ref_update_object(void *objspace, VALUE v) } } -static int -hash_replace_ref(st_data_t *key, st_data_t *value, st_data_t argp, int existing) -{ - void *objspace = (void *)argp; - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)*key)) { - *key = rb_gc_impl_location(objspace, (VALUE)*key); - } - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)*value)) { - *value = rb_gc_impl_location(objspace, (VALUE)*value); - } - - return ST_CONTINUE; -} - -static int -hash_foreach_replace(st_data_t key, st_data_t value, st_data_t argp, int error) -{ - void *objspace; - - objspace = (void *)argp; - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)key)) { - return ST_REPLACE; - } - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)value)) { - return ST_REPLACE; - } - return ST_CONTINUE; -} - -static int -hash_replace_ref_value(st_data_t *key, st_data_t *value, st_data_t argp, int existing) -{ - void *objspace = (void *)argp; - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)*value)) { - *value = rb_gc_impl_location(objspace, (VALUE)*value); - } - - return ST_CONTINUE; -} - -static int -hash_foreach_replace_value(st_data_t key, st_data_t value, st_data_t argp, int error) -{ - void *objspace; - - objspace = (void *)argp; - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)value)) { - return ST_REPLACE; - } - return ST_CONTINUE; -} - -static void -gc_ref_update_table_values_only(void *objspace, st_table *tbl) -{ - if (!tbl || tbl->num_entries == 0) return; - - if (st_foreach_with_replace(tbl, hash_foreach_replace_value, hash_replace_ref_value, (st_data_t)objspace)) { - rb_raise(rb_eRuntimeError, "hash modified during iteration"); - } -} - void rb_gc_ref_update_table_values_only(st_table *tbl) { gc_ref_update_table_values_only(rb_gc_get_objspace(), tbl); } -static void -gc_update_table_refs(void *objspace, st_table *tbl) -{ - if (!tbl || tbl->num_entries == 0) return; - - if (st_foreach_with_replace(tbl, hash_foreach_replace, hash_replace_ref, (st_data_t)objspace)) { - rb_raise(rb_eRuntimeError, "hash modified during iteration"); - } -} - /* Update MOVED references in a VALUE=>VALUE st_table */ void rb_gc_update_tbl_refs(st_table *ptr) @@ -4257,12 +4133,6 @@ ruby_malloc_size_overflow(size_t count, size_t elsize) count, elsize); } -static inline size_t -xmalloc2_size(const size_t count, const size_t elsize) -{ - return size_mul_or_raise(count, elsize, rb_eArgError); -} - void * ruby_xmalloc2(size_t n, size_t size) { diff --git a/gc/default.c b/gc/default.c index 362e5d4938..5dd7cc1df7 100644 --- a/gc/default.c +++ b/gc/default.c @@ -248,8 +248,10 @@ int ruby_rgengc_debug; # define RGENGC_CHECK_MODE 0 #endif +#ifndef GC_ASSERT // Note: using RUBY_ASSERT_WHEN() extend a macro in expr (info by nobu). -#define GC_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(RGENGC_CHECK_MODE > 0, expr, #expr) +# define GC_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(RGENGC_CHECK_MODE > 0, expr, #expr) +#endif /* RGENGC_PROFILE * 0: disable RGenGC profiling @@ -875,13 +877,17 @@ RVALUE_AGE_SET(VALUE obj, int age) #define gc_config_full_mark_set(b) (((int)b), objspace->gc_config.full_mark = (b)) #define gc_config_full_mark_val (objspace->gc_config.full_mark) -#define DURING_GC_COULD_MALLOC_REGION_START() \ +#ifndef DURING_GC_COULD_MALLOC_REGION_START +# define DURING_GC_COULD_MALLOC_REGION_START() \ assert(rb_during_gc()); \ bool _prev_enabled = rb_gc_impl_gc_enabled_p(objspace); \ rb_gc_impl_gc_disable(objspace, false) +#endif -#define DURING_GC_COULD_MALLOC_REGION_END() \ +#ifndef DURING_GC_COULD_MALLOC_REGION_END +# define DURING_GC_COULD_MALLOC_REGION_END() \ if (_prev_enabled) rb_gc_impl_gc_enable(objspace) +#endif static inline enum gc_mode gc_mode_verify(enum gc_mode mode) @@ -7340,84 +7346,6 @@ gc_ref_update(void *vstart, void *vend, size_t stride, rb_objspace_t *objspace, return 0; } -static int -hash_replace_ref_value(st_data_t *key, st_data_t *value, st_data_t argp, int existing) -{ - void *objspace = (void *)argp; - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)*value)) { - *value = rb_gc_impl_location(objspace, (VALUE)*value); - } - - return ST_CONTINUE; -} - -static int -hash_foreach_replace_value(st_data_t key, st_data_t value, st_data_t argp, int error) -{ - void *objspace; - - objspace = (void *)argp; - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)value)) { - return ST_REPLACE; - } - return ST_CONTINUE; -} - -static void -gc_ref_update_table_values_only(void *objspace, st_table *tbl) -{ - if (!tbl || tbl->num_entries == 0) return; - - if (st_foreach_with_replace(tbl, hash_foreach_replace_value, hash_replace_ref_value, (st_data_t)objspace)) { - rb_raise(rb_eRuntimeError, "hash modified during iteration"); - } -} - -static int -hash_foreach_replace(st_data_t key, st_data_t value, st_data_t argp, int error) -{ - void *objspace; - - objspace = (void *)argp; - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)key)) { - return ST_REPLACE; - } - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)value)) { - return ST_REPLACE; - } - return ST_CONTINUE; -} - -static int -hash_replace_ref(st_data_t *key, st_data_t *value, st_data_t argp, int existing) -{ - void *objspace = (void *)argp; - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)*key)) { - *key = rb_gc_impl_location(objspace, (VALUE)*key); - } - - if (rb_gc_impl_object_moved_p(objspace, (VALUE)*value)) { - *value = rb_gc_impl_location(objspace, (VALUE)*value); - } - - return ST_CONTINUE; -} - -static void -gc_update_table_refs(void *objspace, st_table *tbl) -{ - if (!tbl || tbl->num_entries == 0) return; - - if (st_foreach_with_replace(tbl, hash_foreach_replace, hash_replace_ref, (st_data_t)objspace)) { - rb_raise(rb_eRuntimeError, "hash modified during iteration"); - } -} - static void gc_update_references(rb_objspace_t *objspace) { @@ -8581,12 +8509,6 @@ rb_gc_impl_calloc(void *objspace_ptr, size_t size) return objspace_malloc_fixup(objspace, mem, size); } -static inline size_t -xmalloc2_size(const size_t count, const size_t elsize) -{ - return rb_size_mul_or_raise(count, elsize, rb_eArgError); -} - void * rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size) { @@ -9363,43 +9285,6 @@ gc_get_auto_compact(VALUE _) #endif #if GC_CAN_COMPILE_COMPACTION -static VALUE -type_sym(size_t type) -{ - switch (type) { -#define COUNT_TYPE(t) case (t): return ID2SYM(rb_intern(#t)); break; - COUNT_TYPE(T_NONE); - COUNT_TYPE(T_OBJECT); - COUNT_TYPE(T_CLASS); - COUNT_TYPE(T_MODULE); - COUNT_TYPE(T_FLOAT); - COUNT_TYPE(T_STRING); - COUNT_TYPE(T_REGEXP); - COUNT_TYPE(T_ARRAY); - COUNT_TYPE(T_HASH); - COUNT_TYPE(T_STRUCT); - COUNT_TYPE(T_BIGNUM); - COUNT_TYPE(T_FILE); - COUNT_TYPE(T_DATA); - COUNT_TYPE(T_MATCH); - COUNT_TYPE(T_COMPLEX); - COUNT_TYPE(T_RATIONAL); - COUNT_TYPE(T_NIL); - COUNT_TYPE(T_TRUE); - COUNT_TYPE(T_FALSE); - COUNT_TYPE(T_SYMBOL); - COUNT_TYPE(T_FIXNUM); - COUNT_TYPE(T_IMEMO); - COUNT_TYPE(T_UNDEF); - COUNT_TYPE(T_NODE); - COUNT_TYPE(T_ICLASS); - COUNT_TYPE(T_ZOMBIE); - COUNT_TYPE(T_MOVED); -#undef COUNT_TYPE - default: return SIZET2NUM(type); break; - } -} - /* * call-seq: * GC.latest_compact_info -> hash @@ -9654,14 +9539,6 @@ pin_value(st_data_t key, st_data_t value, st_data_t data) void rb_gc_impl_mark(void *objspace_ptr, VALUE obj); -static int -gc_mark_tbl_no_pin_i(st_data_t key, st_data_t value, st_data_t data) -{ - rb_gc_impl_mark((void *)data, (VALUE)value); - - return ST_CONTINUE; -} - #if MALLOC_ALLOCATED_SIZE /* * call-seq: diff --git a/gc/gc.h b/gc/gc.h index 5f9a7b218b..e8f3e2f6d6 100644 --- a/gc/gc.h +++ b/gc/gc.h @@ -1,7 +1,16 @@ #ifndef GC_GC_H #define GC_GC_H - +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Private header for the default GC and other GC implementations + * first introduced for [Feature #20470]. + */ #include "ruby/ruby.h" +#include "gc/gc_impl.h" RUBY_SYMBOL_EXPORT_BEGIN unsigned int rb_gc_vm_lock(void); @@ -39,4 +48,139 @@ RUBY_SYMBOL_EXPORT_END void rb_ractor_finish_marking(void); +// -------------------Private section begin------------------------ +// Functions in this section are private to the default GC and gc.c + +static int +hash_foreach_replace_value(st_data_t key, st_data_t value, st_data_t argp, int error) +{ + void *objspace; + + objspace = (void *)argp; + + if (rb_gc_impl_object_moved_p(objspace, (VALUE)value)) { + return ST_REPLACE; + } + return ST_CONTINUE; +} + +static int +hash_replace_ref_value(st_data_t *key, st_data_t *value, st_data_t argp, int existing) +{ + void *objspace = (void *)argp; + + if (rb_gc_impl_object_moved_p(objspace, (VALUE)*value)) { + *value = rb_gc_impl_location(objspace, (VALUE)*value); + } + + return ST_CONTINUE; +} + +static void +gc_ref_update_table_values_only(void *objspace, st_table *tbl) +{ + if (!tbl || tbl->num_entries == 0) return; + + if (st_foreach_with_replace(tbl, hash_foreach_replace_value, hash_replace_ref_value, (st_data_t)objspace)) { + rb_raise(rb_eRuntimeError, "hash modified during iteration"); + } +} + +static int +gc_mark_tbl_no_pin_i(st_data_t key, st_data_t value, st_data_t data) +{ + void *objspace = (void *)data; + + rb_gc_impl_mark(objspace, (VALUE)value); + + return ST_CONTINUE; +} + +static int +hash_foreach_replace(st_data_t key, st_data_t value, st_data_t argp, int error) +{ + void *objspace; + + objspace = (void *)argp; + + if (rb_gc_impl_object_moved_p(objspace, (VALUE)key)) { + return ST_REPLACE; + } + + if (rb_gc_impl_object_moved_p(objspace, (VALUE)value)) { + return ST_REPLACE; + } + return ST_CONTINUE; +} + +static int +hash_replace_ref(st_data_t *key, st_data_t *value, st_data_t argp, int existing) +{ + void *objspace = (void *)argp; + + if (rb_gc_impl_object_moved_p(objspace, (VALUE)*key)) { + *key = rb_gc_impl_location(objspace, (VALUE)*key); + } + + if (rb_gc_impl_object_moved_p(objspace, (VALUE)*value)) { + *value = rb_gc_impl_location(objspace, (VALUE)*value); + } + + return ST_CONTINUE; +} + +static void +gc_update_table_refs(void *objspace, st_table *tbl) +{ + if (!tbl || tbl->num_entries == 0) return; + + if (st_foreach_with_replace(tbl, hash_foreach_replace, hash_replace_ref, (st_data_t)objspace)) { + rb_raise(rb_eRuntimeError, "hash modified during iteration"); + } +} + +static inline size_t +xmalloc2_size(const size_t count, const size_t elsize) +{ + return rb_size_mul_or_raise(count, elsize, rb_eArgError); +} + +static VALUE +type_sym(size_t type) +{ + switch (type) { +#define COUNT_TYPE(t) case (t): return ID2SYM(rb_intern(#t)); break; + COUNT_TYPE(T_NONE); + COUNT_TYPE(T_OBJECT); + COUNT_TYPE(T_CLASS); + COUNT_TYPE(T_MODULE); + COUNT_TYPE(T_FLOAT); + COUNT_TYPE(T_STRING); + COUNT_TYPE(T_REGEXP); + COUNT_TYPE(T_ARRAY); + COUNT_TYPE(T_HASH); + COUNT_TYPE(T_STRUCT); + COUNT_TYPE(T_BIGNUM); + COUNT_TYPE(T_FILE); + COUNT_TYPE(T_DATA); + COUNT_TYPE(T_MATCH); + COUNT_TYPE(T_COMPLEX); + COUNT_TYPE(T_RATIONAL); + COUNT_TYPE(T_NIL); + COUNT_TYPE(T_TRUE); + COUNT_TYPE(T_FALSE); + COUNT_TYPE(T_SYMBOL); + COUNT_TYPE(T_FIXNUM); + COUNT_TYPE(T_IMEMO); + COUNT_TYPE(T_UNDEF); + COUNT_TYPE(T_NODE); + COUNT_TYPE(T_ICLASS); + COUNT_TYPE(T_ZOMBIE); + COUNT_TYPE(T_MOVED); +#undef COUNT_TYPE + default: return SIZET2NUM(type); break; + } +} +// -------------------Private section end------------------------ + #endif diff --git a/gc/gc_impl.h b/gc/gc_impl.h index 18249dc58b..befeddccb6 100644 --- a/gc/gc_impl.h +++ b/gc/gc_impl.h @@ -1,83 +1,105 @@ #ifndef GC_GC_IMPL_H #define GC_GC_IMPL_H - +/** + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @brief Header for GC implementations introduced in [Feature #20470]. + */ #include "ruby/ruby.h" -// Bootup -void *rb_gc_impl_objspace_alloc(void); -void rb_gc_impl_objspace_init(void *objspace_ptr); -void rb_gc_impl_objspace_free(void *objspace_ptr); -void *rb_gc_impl_ractor_cache_alloc(void *objspace_ptr); -void rb_gc_impl_ractor_cache_free(void *objspace_ptr, void *cache); -void rb_gc_impl_set_params(void *objspace_ptr); -void rb_gc_impl_init(void); -void rb_gc_impl_initial_stress_set(VALUE flag); -size_t *rb_gc_impl_size_pool_sizes(void *objspace_ptr); -// Shutdown -void rb_gc_impl_shutdown_free_objects(void *objspace_ptr); -// GC -void rb_gc_impl_start(void *objspace_ptr, bool full_mark, bool immediate_mark, bool immediate_sweep, bool compact); -bool rb_gc_impl_during_gc_p(void *objspace_ptr); -void rb_gc_impl_prepare_heap(void *objspace_ptr); -void rb_gc_impl_gc_enable(void *objspace_ptr); -void rb_gc_impl_gc_disable(void *objspace_ptr, bool finish_current_gc); -bool rb_gc_impl_gc_enabled_p(void *objspace_ptr); -void rb_gc_impl_stress_set(void *objspace_ptr, VALUE flag); -VALUE rb_gc_impl_stress_get(void *objspace_ptr); -VALUE rb_gc_impl_config_get(void *objspace_ptr); -VALUE rb_gc_impl_config_set(void *objspace_ptr, VALUE hash); -// Object allocation -VALUE rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t alloc_size); -size_t rb_gc_impl_obj_slot_size(VALUE obj); -size_t rb_gc_impl_size_pool_id_for_size(void *objspace_ptr, size_t size); -bool rb_gc_impl_size_allocatable_p(size_t size); -// Malloc -void *rb_gc_impl_malloc(void *objspace_ptr, size_t size); -void *rb_gc_impl_calloc(void *objspace_ptr, size_t size); -void *rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size); -void rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size); -void rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff); -// Marking -void rb_gc_impl_mark(void *objspace_ptr, VALUE obj); -void rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr); -void rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj); -void rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj); -void rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr); -void rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr); -void rb_gc_impl_objspace_mark(void *objspace_ptr); -// Compaction -bool rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj); -VALUE rb_gc_impl_location(void *objspace_ptr, VALUE value); -// Write barriers -void rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b); -void rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj); -void rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj); -// Heap walking -void rb_gc_impl_each_objects(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data); -void rb_gc_impl_each_object(void *objspace_ptr, void (*func)(VALUE obj, void *data), void *data); -// Finalizers -void rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), void *data); -VALUE rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block); -void rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj); -void rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj); -void rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr); -// Object ID -VALUE rb_gc_impl_object_id(void *objspace_ptr, VALUE obj); -VALUE rb_gc_impl_object_id_to_ref(void *objspace_ptr, VALUE object_id); -// Statistics -VALUE rb_gc_impl_set_measure_total_time(void *objspace_ptr, VALUE flag); -VALUE rb_gc_impl_get_measure_total_time(void *objspace_ptr); -VALUE rb_gc_impl_get_profile_total_time(void *objspace_ptr); -size_t rb_gc_impl_gc_count(void *objspace_ptr); -VALUE rb_gc_impl_latest_gc_info(void *objspace_ptr, VALUE key); -size_t rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym); -size_t rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym); -// Miscellaneous -size_t rb_gc_impl_obj_flags(void *objspace_ptr, VALUE obj, ID* flags, size_t max); -bool rb_gc_impl_pointer_to_heap_p(void *objspace_ptr, const void *ptr); -bool rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE obj); -void rb_gc_impl_set_event_hook(void *objspace_ptr, const rb_event_flag_t event); -void rb_gc_impl_copy_attributes(void *objspace_ptr, VALUE dest, VALUE obj); +// `GC_IMPL_FN` is an implementation detail of `!USE_SHARED_GC` builds +// to have the default GC in the same translation unit as gc.c for +// the sake of optimizer visibility. It expands to nothing unless +// you're the default GC. +// +// For the default GC, do not copy-paste this when implementing +// these functions. This takes advantage of internal linkage winning +// when appearing first. See C99 6.2.2p4. +#ifdef RB_AMALGAMATED_DEFAULT_GC +# define GC_IMPL_FN static +#else +# define GC_IMPL_FN +#endif +// Bootup +GC_IMPL_FN void *rb_gc_impl_objspace_alloc(void); +GC_IMPL_FN void rb_gc_impl_objspace_init(void *objspace_ptr); +GC_IMPL_FN void rb_gc_impl_objspace_free(void *objspace_ptr); +GC_IMPL_FN void *rb_gc_impl_ractor_cache_alloc(void *objspace_ptr); +GC_IMPL_FN void rb_gc_impl_ractor_cache_free(void *objspace_ptr, void *cache); +GC_IMPL_FN void rb_gc_impl_set_params(void *objspace_ptr); +GC_IMPL_FN void rb_gc_impl_init(void); +GC_IMPL_FN void rb_gc_impl_initial_stress_set(VALUE flag); +GC_IMPL_FN size_t *rb_gc_impl_size_pool_sizes(void *objspace_ptr); +// Shutdown +GC_IMPL_FN void rb_gc_impl_shutdown_free_objects(void *objspace_ptr); +// GC +GC_IMPL_FN void rb_gc_impl_start(void *objspace_ptr, bool full_mark, bool immediate_mark, bool immediate_sweep, bool compact); +GC_IMPL_FN bool rb_gc_impl_during_gc_p(void *objspace_ptr); +GC_IMPL_FN void rb_gc_impl_prepare_heap(void *objspace_ptr); +GC_IMPL_FN void rb_gc_impl_gc_enable(void *objspace_ptr); +GC_IMPL_FN void rb_gc_impl_gc_disable(void *objspace_ptr, bool finish_current_gc); +GC_IMPL_FN bool rb_gc_impl_gc_enabled_p(void *objspace_ptr); +GC_IMPL_FN void rb_gc_impl_stress_set(void *objspace_ptr, VALUE flag); +GC_IMPL_FN VALUE rb_gc_impl_stress_get(void *objspace_ptr); +GC_IMPL_FN VALUE rb_gc_impl_config_get(void *objspace_ptr); +GC_IMPL_FN VALUE rb_gc_impl_config_set(void *objspace_ptr, VALUE hash); +// Object allocation +GC_IMPL_FN VALUE rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t alloc_size); +GC_IMPL_FN size_t rb_gc_impl_obj_slot_size(VALUE obj); +GC_IMPL_FN size_t rb_gc_impl_size_pool_id_for_size(void *objspace_ptr, size_t size); +GC_IMPL_FN bool rb_gc_impl_size_allocatable_p(size_t size); +// Malloc +GC_IMPL_FN void *rb_gc_impl_malloc(void *objspace_ptr, size_t size); +GC_IMPL_FN void *rb_gc_impl_calloc(void *objspace_ptr, size_t size); +GC_IMPL_FN void *rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size); +GC_IMPL_FN void rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size); +GC_IMPL_FN void rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff); +// Marking +GC_IMPL_FN void rb_gc_impl_mark(void *objspace_ptr, VALUE obj); +GC_IMPL_FN void rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr); +GC_IMPL_FN void rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj); +GC_IMPL_FN void rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj); +GC_IMPL_FN void rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr); +GC_IMPL_FN void rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr); +GC_IMPL_FN void rb_gc_impl_objspace_mark(void *objspace_ptr); +// Compaction +GC_IMPL_FN bool rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj); +GC_IMPL_FN VALUE rb_gc_impl_location(void *objspace_ptr, VALUE value); +// Write barriers +GC_IMPL_FN void rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b); +GC_IMPL_FN void rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj); +GC_IMPL_FN void rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj); +// Heap walking +GC_IMPL_FN void rb_gc_impl_each_objects(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data); +GC_IMPL_FN void rb_gc_impl_each_object(void *objspace_ptr, void (*func)(VALUE obj, void *data), void *data); +// Finalizers +GC_IMPL_FN void rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), void *data); +GC_IMPL_FN VALUE rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block); +GC_IMPL_FN void rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj); +GC_IMPL_FN void rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj); +GC_IMPL_FN void rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr); +// Object ID +GC_IMPL_FN VALUE rb_gc_impl_object_id(void *objspace_ptr, VALUE obj); +GC_IMPL_FN VALUE rb_gc_impl_object_id_to_ref(void *objspace_ptr, VALUE object_id); +// Statistics +GC_IMPL_FN VALUE rb_gc_impl_set_measure_total_time(void *objspace_ptr, VALUE flag); +GC_IMPL_FN VALUE rb_gc_impl_get_measure_total_time(void *objspace_ptr); +GC_IMPL_FN VALUE rb_gc_impl_get_profile_total_time(void *objspace_ptr); +GC_IMPL_FN size_t rb_gc_impl_gc_count(void *objspace_ptr); +GC_IMPL_FN VALUE rb_gc_impl_latest_gc_info(void *objspace_ptr, VALUE key); +GC_IMPL_FN size_t rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym); +GC_IMPL_FN size_t rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym); +// Miscellaneous +GC_IMPL_FN size_t rb_gc_impl_obj_flags(void *objspace_ptr, VALUE obj, ID* flags, size_t max); +GC_IMPL_FN bool rb_gc_impl_pointer_to_heap_p(void *objspace_ptr, const void *ptr); +GC_IMPL_FN bool rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE obj); +GC_IMPL_FN void rb_gc_impl_set_event_hook(void *objspace_ptr, const rb_event_flag_t event); +GC_IMPL_FN void rb_gc_impl_copy_attributes(void *objspace_ptr, VALUE dest, VALUE obj); + +#undef GC_IMPL_FN #endif