summaryrefslogtreecommitdiff
path: root/ext/objspace
diff options
context:
space:
mode:
Diffstat (limited to 'ext/objspace')
-rw-r--r--ext/objspace/depend576
-rw-r--r--ext/objspace/lib/objspace.rb135
-rw-r--r--ext/objspace/lib/objspace/trace.rb45
-rw-r--r--ext/objspace/object_tracing.c281
-rw-r--r--ext/objspace/objspace.c725
-rw-r--r--ext/objspace/objspace_dump.c984
6 files changed, 1918 insertions, 828 deletions
diff --git a/ext/objspace/depend b/ext/objspace/depend
index 84e944f228..d9dfc0c42b 100644
--- a/ext/objspace/depend
+++ b/ext/objspace/depend
@@ -1,31 +1,376 @@
# AUTOGENERATED DEPENDENCIES START
object_tracing.o: $(RUBY_EXTCONF_H)
object_tracing.o: $(arch_hdrdir)/ruby/config.h
-object_tracing.o: $(hdrdir)/ruby.h
object_tracing.o: $(hdrdir)/ruby/assert.h
+object_tracing.o: $(hdrdir)/ruby/atomic.h
object_tracing.o: $(hdrdir)/ruby/backward.h
+object_tracing.o: $(hdrdir)/ruby/backward/2/assume.h
+object_tracing.o: $(hdrdir)/ruby/backward/2/attributes.h
+object_tracing.o: $(hdrdir)/ruby/backward/2/bool.h
+object_tracing.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+object_tracing.o: $(hdrdir)/ruby/backward/2/inttypes.h
+object_tracing.o: $(hdrdir)/ruby/backward/2/limits.h
+object_tracing.o: $(hdrdir)/ruby/backward/2/long_long.h
+object_tracing.o: $(hdrdir)/ruby/backward/2/stdalign.h
+object_tracing.o: $(hdrdir)/ruby/backward/2/stdarg.h
object_tracing.o: $(hdrdir)/ruby/debug.h
object_tracing.o: $(hdrdir)/ruby/defines.h
object_tracing.o: $(hdrdir)/ruby/encoding.h
object_tracing.o: $(hdrdir)/ruby/intern.h
-object_tracing.o: $(hdrdir)/ruby/io.h
+object_tracing.o: $(hdrdir)/ruby/internal/abi.h
+object_tracing.o: $(hdrdir)/ruby/internal/anyargs.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+object_tracing.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+object_tracing.o: $(hdrdir)/ruby/internal/assume.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/artificial.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/cold.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/const.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/error.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/format.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/noalias.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/noinline.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/pure.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/restrict.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/warning.h
+object_tracing.o: $(hdrdir)/ruby/internal/attr/weakref.h
+object_tracing.o: $(hdrdir)/ruby/internal/cast.h
+object_tracing.o: $(hdrdir)/ruby/internal/compiler_is.h
+object_tracing.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+object_tracing.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+object_tracing.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+object_tracing.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+object_tracing.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+object_tracing.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+object_tracing.o: $(hdrdir)/ruby/internal/compiler_since.h
+object_tracing.o: $(hdrdir)/ruby/internal/config.h
+object_tracing.o: $(hdrdir)/ruby/internal/constant_p.h
+object_tracing.o: $(hdrdir)/ruby/internal/core.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rarray.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rbasic.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rbignum.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rclass.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rdata.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rfile.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rhash.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/robject.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rregexp.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rstring.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rstruct.h
+object_tracing.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+object_tracing.o: $(hdrdir)/ruby/internal/ctype.h
+object_tracing.o: $(hdrdir)/ruby/internal/dllexport.h
+object_tracing.o: $(hdrdir)/ruby/internal/dosish.h
+object_tracing.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+object_tracing.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+object_tracing.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+object_tracing.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+object_tracing.o: $(hdrdir)/ruby/internal/encoding/re.h
+object_tracing.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+object_tracing.o: $(hdrdir)/ruby/internal/encoding/string.h
+object_tracing.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+object_tracing.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+object_tracing.o: $(hdrdir)/ruby/internal/error.h
+object_tracing.o: $(hdrdir)/ruby/internal/eval.h
+object_tracing.o: $(hdrdir)/ruby/internal/event.h
+object_tracing.o: $(hdrdir)/ruby/internal/fl_type.h
+object_tracing.o: $(hdrdir)/ruby/internal/gc.h
+object_tracing.o: $(hdrdir)/ruby/internal/glob.h
+object_tracing.o: $(hdrdir)/ruby/internal/globals.h
+object_tracing.o: $(hdrdir)/ruby/internal/has/attribute.h
+object_tracing.o: $(hdrdir)/ruby/internal/has/builtin.h
+object_tracing.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+object_tracing.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+object_tracing.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+object_tracing.o: $(hdrdir)/ruby/internal/has/extension.h
+object_tracing.o: $(hdrdir)/ruby/internal/has/feature.h
+object_tracing.o: $(hdrdir)/ruby/internal/has/warning.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/array.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/bignum.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/class.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/compar.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/complex.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/cont.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/dir.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/enum.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/error.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/eval.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/file.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/hash.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/io.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/load.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/marshal.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/numeric.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/object.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/parse.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/proc.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/process.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/random.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/range.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/rational.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/re.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/ruby.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/select.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/set.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/signal.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/string.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/struct.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/thread.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/time.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/variable.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/vm.h
+object_tracing.o: $(hdrdir)/ruby/internal/interpreter.h
+object_tracing.o: $(hdrdir)/ruby/internal/iterator.h
+object_tracing.o: $(hdrdir)/ruby/internal/memory.h
+object_tracing.o: $(hdrdir)/ruby/internal/method.h
+object_tracing.o: $(hdrdir)/ruby/internal/module.h
+object_tracing.o: $(hdrdir)/ruby/internal/newobj.h
+object_tracing.o: $(hdrdir)/ruby/internal/scan_args.h
+object_tracing.o: $(hdrdir)/ruby/internal/special_consts.h
+object_tracing.o: $(hdrdir)/ruby/internal/static_assert.h
+object_tracing.o: $(hdrdir)/ruby/internal/stdalign.h
+object_tracing.o: $(hdrdir)/ruby/internal/stdbool.h
+object_tracing.o: $(hdrdir)/ruby/internal/stdckdint.h
+object_tracing.o: $(hdrdir)/ruby/internal/symbol.h
+object_tracing.o: $(hdrdir)/ruby/internal/value.h
+object_tracing.o: $(hdrdir)/ruby/internal/value_type.h
+object_tracing.o: $(hdrdir)/ruby/internal/variable.h
+object_tracing.o: $(hdrdir)/ruby/internal/warning_push.h
+object_tracing.o: $(hdrdir)/ruby/internal/xmalloc.h
object_tracing.o: $(hdrdir)/ruby/missing.h
object_tracing.o: $(hdrdir)/ruby/onigmo.h
object_tracing.o: $(hdrdir)/ruby/oniguruma.h
object_tracing.o: $(hdrdir)/ruby/ruby.h
object_tracing.o: $(hdrdir)/ruby/st.h
object_tracing.o: $(hdrdir)/ruby/subst.h
+object_tracing.o: $(hdrdir)/ruby/thread_native.h
+object_tracing.o: $(top_srcdir)/ccan/check_type/check_type.h
+object_tracing.o: $(top_srcdir)/ccan/container_of/container_of.h
+object_tracing.o: $(top_srcdir)/ccan/list/list.h
+object_tracing.o: $(top_srcdir)/ccan/str/str.h
+object_tracing.o: $(top_srcdir)/id_table.h
object_tracing.o: $(top_srcdir)/internal.h
+object_tracing.o: $(top_srcdir)/internal/array.h
+object_tracing.o: $(top_srcdir)/internal/basic_operators.h
+object_tracing.o: $(top_srcdir)/internal/box.h
+object_tracing.o: $(top_srcdir)/internal/compilers.h
+object_tracing.o: $(top_srcdir)/internal/gc.h
+object_tracing.o: $(top_srcdir)/internal/imemo.h
+object_tracing.o: $(top_srcdir)/internal/sanitizers.h
+object_tracing.o: $(top_srcdir)/internal/serial.h
+object_tracing.o: $(top_srcdir)/internal/set_table.h
+object_tracing.o: $(top_srcdir)/internal/static_assert.h
+object_tracing.o: $(top_srcdir)/internal/vm.h
+object_tracing.o: $(top_srcdir)/internal/warnings.h
+object_tracing.o: $(top_srcdir)/method.h
+object_tracing.o: $(top_srcdir)/node.h
+object_tracing.o: $(top_srcdir)/ruby_assert.h
+object_tracing.o: $(top_srcdir)/ruby_atomic.h
+object_tracing.o: $(top_srcdir)/rubyparser.h
+object_tracing.o: $(top_srcdir)/thread_pthread.h
+object_tracing.o: $(top_srcdir)/vm_core.h
+object_tracing.o: $(top_srcdir)/vm_opts.h
object_tracing.o: object_tracing.c
object_tracing.o: objspace.h
+object_tracing.o: {$(VPATH)}id.h
objspace.o: $(RUBY_EXTCONF_H)
objspace.o: $(arch_hdrdir)/ruby/config.h
-objspace.o: $(hdrdir)/ruby.h
objspace.o: $(hdrdir)/ruby/assert.h
+objspace.o: $(hdrdir)/ruby/atomic.h
objspace.o: $(hdrdir)/ruby/backward.h
+objspace.o: $(hdrdir)/ruby/backward/2/assume.h
+objspace.o: $(hdrdir)/ruby/backward/2/attributes.h
+objspace.o: $(hdrdir)/ruby/backward/2/bool.h
+objspace.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+objspace.o: $(hdrdir)/ruby/backward/2/inttypes.h
+objspace.o: $(hdrdir)/ruby/backward/2/limits.h
+objspace.o: $(hdrdir)/ruby/backward/2/long_long.h
+objspace.o: $(hdrdir)/ruby/backward/2/stdalign.h
+objspace.o: $(hdrdir)/ruby/backward/2/stdarg.h
objspace.o: $(hdrdir)/ruby/defines.h
objspace.o: $(hdrdir)/ruby/encoding.h
objspace.o: $(hdrdir)/ruby/intern.h
+objspace.o: $(hdrdir)/ruby/internal/abi.h
+objspace.o: $(hdrdir)/ruby/internal/anyargs.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+objspace.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+objspace.o: $(hdrdir)/ruby/internal/assume.h
+objspace.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+objspace.o: $(hdrdir)/ruby/internal/attr/artificial.h
+objspace.o: $(hdrdir)/ruby/internal/attr/cold.h
+objspace.o: $(hdrdir)/ruby/internal/attr/const.h
+objspace.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+objspace.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+objspace.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+objspace.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+objspace.o: $(hdrdir)/ruby/internal/attr/error.h
+objspace.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+objspace.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+objspace.o: $(hdrdir)/ruby/internal/attr/format.h
+objspace.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+objspace.o: $(hdrdir)/ruby/internal/attr/noalias.h
+objspace.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+objspace.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+objspace.o: $(hdrdir)/ruby/internal/attr/noinline.h
+objspace.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+objspace.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+objspace.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+objspace.o: $(hdrdir)/ruby/internal/attr/pure.h
+objspace.o: $(hdrdir)/ruby/internal/attr/restrict.h
+objspace.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+objspace.o: $(hdrdir)/ruby/internal/attr/warning.h
+objspace.o: $(hdrdir)/ruby/internal/attr/weakref.h
+objspace.o: $(hdrdir)/ruby/internal/cast.h
+objspace.o: $(hdrdir)/ruby/internal/compiler_is.h
+objspace.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+objspace.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+objspace.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+objspace.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+objspace.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+objspace.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+objspace.o: $(hdrdir)/ruby/internal/compiler_since.h
+objspace.o: $(hdrdir)/ruby/internal/config.h
+objspace.o: $(hdrdir)/ruby/internal/constant_p.h
+objspace.o: $(hdrdir)/ruby/internal/core.h
+objspace.o: $(hdrdir)/ruby/internal/core/rarray.h
+objspace.o: $(hdrdir)/ruby/internal/core/rbasic.h
+objspace.o: $(hdrdir)/ruby/internal/core/rbignum.h
+objspace.o: $(hdrdir)/ruby/internal/core/rclass.h
+objspace.o: $(hdrdir)/ruby/internal/core/rdata.h
+objspace.o: $(hdrdir)/ruby/internal/core/rfile.h
+objspace.o: $(hdrdir)/ruby/internal/core/rhash.h
+objspace.o: $(hdrdir)/ruby/internal/core/rmatch.h
+objspace.o: $(hdrdir)/ruby/internal/core/robject.h
+objspace.o: $(hdrdir)/ruby/internal/core/rregexp.h
+objspace.o: $(hdrdir)/ruby/internal/core/rstring.h
+objspace.o: $(hdrdir)/ruby/internal/core/rstruct.h
+objspace.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+objspace.o: $(hdrdir)/ruby/internal/ctype.h
+objspace.o: $(hdrdir)/ruby/internal/dllexport.h
+objspace.o: $(hdrdir)/ruby/internal/dosish.h
+objspace.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+objspace.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+objspace.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+objspace.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+objspace.o: $(hdrdir)/ruby/internal/encoding/re.h
+objspace.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+objspace.o: $(hdrdir)/ruby/internal/encoding/string.h
+objspace.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+objspace.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+objspace.o: $(hdrdir)/ruby/internal/error.h
+objspace.o: $(hdrdir)/ruby/internal/eval.h
+objspace.o: $(hdrdir)/ruby/internal/event.h
+objspace.o: $(hdrdir)/ruby/internal/fl_type.h
+objspace.o: $(hdrdir)/ruby/internal/gc.h
+objspace.o: $(hdrdir)/ruby/internal/glob.h
+objspace.o: $(hdrdir)/ruby/internal/globals.h
+objspace.o: $(hdrdir)/ruby/internal/has/attribute.h
+objspace.o: $(hdrdir)/ruby/internal/has/builtin.h
+objspace.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+objspace.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+objspace.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+objspace.o: $(hdrdir)/ruby/internal/has/extension.h
+objspace.o: $(hdrdir)/ruby/internal/has/feature.h
+objspace.o: $(hdrdir)/ruby/internal/has/warning.h
+objspace.o: $(hdrdir)/ruby/internal/intern/array.h
+objspace.o: $(hdrdir)/ruby/internal/intern/bignum.h
+objspace.o: $(hdrdir)/ruby/internal/intern/class.h
+objspace.o: $(hdrdir)/ruby/internal/intern/compar.h
+objspace.o: $(hdrdir)/ruby/internal/intern/complex.h
+objspace.o: $(hdrdir)/ruby/internal/intern/cont.h
+objspace.o: $(hdrdir)/ruby/internal/intern/dir.h
+objspace.o: $(hdrdir)/ruby/internal/intern/enum.h
+objspace.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+objspace.o: $(hdrdir)/ruby/internal/intern/error.h
+objspace.o: $(hdrdir)/ruby/internal/intern/eval.h
+objspace.o: $(hdrdir)/ruby/internal/intern/file.h
+objspace.o: $(hdrdir)/ruby/internal/intern/hash.h
+objspace.o: $(hdrdir)/ruby/internal/intern/io.h
+objspace.o: $(hdrdir)/ruby/internal/intern/load.h
+objspace.o: $(hdrdir)/ruby/internal/intern/marshal.h
+objspace.o: $(hdrdir)/ruby/internal/intern/numeric.h
+objspace.o: $(hdrdir)/ruby/internal/intern/object.h
+objspace.o: $(hdrdir)/ruby/internal/intern/parse.h
+objspace.o: $(hdrdir)/ruby/internal/intern/proc.h
+objspace.o: $(hdrdir)/ruby/internal/intern/process.h
+objspace.o: $(hdrdir)/ruby/internal/intern/random.h
+objspace.o: $(hdrdir)/ruby/internal/intern/range.h
+objspace.o: $(hdrdir)/ruby/internal/intern/rational.h
+objspace.o: $(hdrdir)/ruby/internal/intern/re.h
+objspace.o: $(hdrdir)/ruby/internal/intern/ruby.h
+objspace.o: $(hdrdir)/ruby/internal/intern/select.h
+objspace.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+objspace.o: $(hdrdir)/ruby/internal/intern/set.h
+objspace.o: $(hdrdir)/ruby/internal/intern/signal.h
+objspace.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+objspace.o: $(hdrdir)/ruby/internal/intern/string.h
+objspace.o: $(hdrdir)/ruby/internal/intern/struct.h
+objspace.o: $(hdrdir)/ruby/internal/intern/thread.h
+objspace.o: $(hdrdir)/ruby/internal/intern/time.h
+objspace.o: $(hdrdir)/ruby/internal/intern/variable.h
+objspace.o: $(hdrdir)/ruby/internal/intern/vm.h
+objspace.o: $(hdrdir)/ruby/internal/interpreter.h
+objspace.o: $(hdrdir)/ruby/internal/iterator.h
+objspace.o: $(hdrdir)/ruby/internal/memory.h
+objspace.o: $(hdrdir)/ruby/internal/method.h
+objspace.o: $(hdrdir)/ruby/internal/module.h
+objspace.o: $(hdrdir)/ruby/internal/newobj.h
+objspace.o: $(hdrdir)/ruby/internal/scan_args.h
+objspace.o: $(hdrdir)/ruby/internal/special_consts.h
+objspace.o: $(hdrdir)/ruby/internal/static_assert.h
+objspace.o: $(hdrdir)/ruby/internal/stdalign.h
+objspace.o: $(hdrdir)/ruby/internal/stdbool.h
+objspace.o: $(hdrdir)/ruby/internal/stdckdint.h
+objspace.o: $(hdrdir)/ruby/internal/symbol.h
+objspace.o: $(hdrdir)/ruby/internal/value.h
+objspace.o: $(hdrdir)/ruby/internal/value_type.h
+objspace.o: $(hdrdir)/ruby/internal/variable.h
+objspace.o: $(hdrdir)/ruby/internal/warning_push.h
+objspace.o: $(hdrdir)/ruby/internal/xmalloc.h
objspace.o: $(hdrdir)/ruby/io.h
objspace.o: $(hdrdir)/ruby/missing.h
objspace.o: $(hdrdir)/ruby/onigmo.h
@@ -35,21 +380,213 @@ objspace.o: $(hdrdir)/ruby/regex.h
objspace.o: $(hdrdir)/ruby/ruby.h
objspace.o: $(hdrdir)/ruby/st.h
objspace.o: $(hdrdir)/ruby/subst.h
-objspace.o: $(top_srcdir)/gc.h
+objspace.o: $(hdrdir)/ruby/thread_native.h
+objspace.o: $(top_srcdir)/ccan/check_type/check_type.h
+objspace.o: $(top_srcdir)/ccan/container_of/container_of.h
+objspace.o: $(top_srcdir)/ccan/list/list.h
+objspace.o: $(top_srcdir)/ccan/str/str.h
+objspace.o: $(top_srcdir)/constant.h
+objspace.o: $(top_srcdir)/debug_counter.h
+objspace.o: $(top_srcdir)/id_table.h
objspace.o: $(top_srcdir)/internal.h
+objspace.o: $(top_srcdir)/internal/array.h
+objspace.o: $(top_srcdir)/internal/basic_operators.h
+objspace.o: $(top_srcdir)/internal/box.h
+objspace.o: $(top_srcdir)/internal/class.h
+objspace.o: $(top_srcdir)/internal/compilers.h
+objspace.o: $(top_srcdir)/internal/gc.h
+objspace.o: $(top_srcdir)/internal/hash.h
+objspace.o: $(top_srcdir)/internal/imemo.h
+objspace.o: $(top_srcdir)/internal/sanitizers.h
+objspace.o: $(top_srcdir)/internal/serial.h
+objspace.o: $(top_srcdir)/internal/set_table.h
+objspace.o: $(top_srcdir)/internal/static_assert.h
+objspace.o: $(top_srcdir)/internal/struct.h
+objspace.o: $(top_srcdir)/internal/variable.h
+objspace.o: $(top_srcdir)/internal/vm.h
+objspace.o: $(top_srcdir)/internal/warnings.h
+objspace.o: $(top_srcdir)/method.h
objspace.o: $(top_srcdir)/node.h
+objspace.o: $(top_srcdir)/ruby_assert.h
+objspace.o: $(top_srcdir)/ruby_atomic.h
+objspace.o: $(top_srcdir)/rubyparser.h
+objspace.o: $(top_srcdir)/shape.h
objspace.o: $(top_srcdir)/symbol.h
+objspace.o: $(top_srcdir)/thread_pthread.h
+objspace.o: $(top_srcdir)/vm_core.h
+objspace.o: $(top_srcdir)/vm_debug.h
+objspace.o: $(top_srcdir)/vm_opts.h
+objspace.o: $(top_srcdir)/vm_sync.h
objspace.o: objspace.c
objspace.o: {$(VPATH)}id.h
objspace_dump.o: $(RUBY_EXTCONF_H)
objspace_dump.o: $(arch_hdrdir)/ruby/config.h
-objspace_dump.o: $(hdrdir)/ruby.h
objspace_dump.o: $(hdrdir)/ruby/assert.h
+objspace_dump.o: $(hdrdir)/ruby/atomic.h
objspace_dump.o: $(hdrdir)/ruby/backward.h
+objspace_dump.o: $(hdrdir)/ruby/backward/2/assume.h
+objspace_dump.o: $(hdrdir)/ruby/backward/2/attributes.h
+objspace_dump.o: $(hdrdir)/ruby/backward/2/bool.h
+objspace_dump.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
+objspace_dump.o: $(hdrdir)/ruby/backward/2/inttypes.h
+objspace_dump.o: $(hdrdir)/ruby/backward/2/limits.h
+objspace_dump.o: $(hdrdir)/ruby/backward/2/long_long.h
+objspace_dump.o: $(hdrdir)/ruby/backward/2/stdalign.h
+objspace_dump.o: $(hdrdir)/ruby/backward/2/stdarg.h
objspace_dump.o: $(hdrdir)/ruby/debug.h
objspace_dump.o: $(hdrdir)/ruby/defines.h
objspace_dump.o: $(hdrdir)/ruby/encoding.h
objspace_dump.o: $(hdrdir)/ruby/intern.h
+objspace_dump.o: $(hdrdir)/ruby/internal/abi.h
+objspace_dump.o: $(hdrdir)/ruby/internal/anyargs.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+objspace_dump.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+objspace_dump.o: $(hdrdir)/ruby/internal/assume.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/artificial.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/cold.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/const.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/error.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/format.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/noalias.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/noinline.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/pure.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/restrict.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/warning.h
+objspace_dump.o: $(hdrdir)/ruby/internal/attr/weakref.h
+objspace_dump.o: $(hdrdir)/ruby/internal/cast.h
+objspace_dump.o: $(hdrdir)/ruby/internal/compiler_is.h
+objspace_dump.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+objspace_dump.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+objspace_dump.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+objspace_dump.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+objspace_dump.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+objspace_dump.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+objspace_dump.o: $(hdrdir)/ruby/internal/compiler_since.h
+objspace_dump.o: $(hdrdir)/ruby/internal/config.h
+objspace_dump.o: $(hdrdir)/ruby/internal/constant_p.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rarray.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rbasic.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rbignum.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rclass.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rdata.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rfile.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rhash.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/robject.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rregexp.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rstring.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rstruct.h
+objspace_dump.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+objspace_dump.o: $(hdrdir)/ruby/internal/ctype.h
+objspace_dump.o: $(hdrdir)/ruby/internal/dllexport.h
+objspace_dump.o: $(hdrdir)/ruby/internal/dosish.h
+objspace_dump.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+objspace_dump.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+objspace_dump.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+objspace_dump.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+objspace_dump.o: $(hdrdir)/ruby/internal/encoding/re.h
+objspace_dump.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+objspace_dump.o: $(hdrdir)/ruby/internal/encoding/string.h
+objspace_dump.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+objspace_dump.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+objspace_dump.o: $(hdrdir)/ruby/internal/error.h
+objspace_dump.o: $(hdrdir)/ruby/internal/eval.h
+objspace_dump.o: $(hdrdir)/ruby/internal/event.h
+objspace_dump.o: $(hdrdir)/ruby/internal/fl_type.h
+objspace_dump.o: $(hdrdir)/ruby/internal/gc.h
+objspace_dump.o: $(hdrdir)/ruby/internal/glob.h
+objspace_dump.o: $(hdrdir)/ruby/internal/globals.h
+objspace_dump.o: $(hdrdir)/ruby/internal/has/attribute.h
+objspace_dump.o: $(hdrdir)/ruby/internal/has/builtin.h
+objspace_dump.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+objspace_dump.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+objspace_dump.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+objspace_dump.o: $(hdrdir)/ruby/internal/has/extension.h
+objspace_dump.o: $(hdrdir)/ruby/internal/has/feature.h
+objspace_dump.o: $(hdrdir)/ruby/internal/has/warning.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/array.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/bignum.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/class.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/compar.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/complex.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/cont.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/dir.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/enum.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/error.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/eval.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/file.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/hash.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/io.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/load.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/marshal.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/numeric.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/object.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/parse.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/proc.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/process.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/random.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/range.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/rational.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/re.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/ruby.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/select.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/set.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/signal.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/string.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/struct.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/thread.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/time.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/variable.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/vm.h
+objspace_dump.o: $(hdrdir)/ruby/internal/interpreter.h
+objspace_dump.o: $(hdrdir)/ruby/internal/iterator.h
+objspace_dump.o: $(hdrdir)/ruby/internal/memory.h
+objspace_dump.o: $(hdrdir)/ruby/internal/method.h
+objspace_dump.o: $(hdrdir)/ruby/internal/module.h
+objspace_dump.o: $(hdrdir)/ruby/internal/newobj.h
+objspace_dump.o: $(hdrdir)/ruby/internal/scan_args.h
+objspace_dump.o: $(hdrdir)/ruby/internal/special_consts.h
+objspace_dump.o: $(hdrdir)/ruby/internal/static_assert.h
+objspace_dump.o: $(hdrdir)/ruby/internal/stdalign.h
+objspace_dump.o: $(hdrdir)/ruby/internal/stdbool.h
+objspace_dump.o: $(hdrdir)/ruby/internal/stdckdint.h
+objspace_dump.o: $(hdrdir)/ruby/internal/symbol.h
+objspace_dump.o: $(hdrdir)/ruby/internal/value.h
+objspace_dump.o: $(hdrdir)/ruby/internal/value_type.h
+objspace_dump.o: $(hdrdir)/ruby/internal/variable.h
+objspace_dump.o: $(hdrdir)/ruby/internal/warning_push.h
+objspace_dump.o: $(hdrdir)/ruby/internal/xmalloc.h
objspace_dump.o: $(hdrdir)/ruby/io.h
objspace_dump.o: $(hdrdir)/ruby/missing.h
objspace_dump.o: $(hdrdir)/ruby/onigmo.h
@@ -58,20 +595,47 @@ objspace_dump.o: $(hdrdir)/ruby/ruby.h
objspace_dump.o: $(hdrdir)/ruby/st.h
objspace_dump.o: $(hdrdir)/ruby/subst.h
objspace_dump.o: $(hdrdir)/ruby/thread_native.h
+objspace_dump.o: $(hdrdir)/ruby/util.h
objspace_dump.o: $(top_srcdir)/ccan/check_type/check_type.h
objspace_dump.o: $(top_srcdir)/ccan/container_of/container_of.h
objspace_dump.o: $(top_srcdir)/ccan/list/list.h
objspace_dump.o: $(top_srcdir)/ccan/str/str.h
-objspace_dump.o: $(top_srcdir)/gc.h
+objspace_dump.o: $(top_srcdir)/constant.h
+objspace_dump.o: $(top_srcdir)/debug_counter.h
+objspace_dump.o: $(top_srcdir)/encindex.h
+objspace_dump.o: $(top_srcdir)/id_table.h
objspace_dump.o: $(top_srcdir)/internal.h
+objspace_dump.o: $(top_srcdir)/internal/array.h
+objspace_dump.o: $(top_srcdir)/internal/basic_operators.h
+objspace_dump.o: $(top_srcdir)/internal/box.h
+objspace_dump.o: $(top_srcdir)/internal/class.h
+objspace_dump.o: $(top_srcdir)/internal/compilers.h
+objspace_dump.o: $(top_srcdir)/internal/gc.h
+objspace_dump.o: $(top_srcdir)/internal/hash.h
+objspace_dump.o: $(top_srcdir)/internal/imemo.h
+objspace_dump.o: $(top_srcdir)/internal/io.h
+objspace_dump.o: $(top_srcdir)/internal/sanitizers.h
+objspace_dump.o: $(top_srcdir)/internal/serial.h
+objspace_dump.o: $(top_srcdir)/internal/set_table.h
+objspace_dump.o: $(top_srcdir)/internal/static_assert.h
+objspace_dump.o: $(top_srcdir)/internal/string.h
+objspace_dump.o: $(top_srcdir)/internal/struct.h
+objspace_dump.o: $(top_srcdir)/internal/variable.h
+objspace_dump.o: $(top_srcdir)/internal/vm.h
+objspace_dump.o: $(top_srcdir)/internal/warnings.h
objspace_dump.o: $(top_srcdir)/method.h
objspace_dump.o: $(top_srcdir)/node.h
objspace_dump.o: $(top_srcdir)/ruby_assert.h
objspace_dump.o: $(top_srcdir)/ruby_atomic.h
+objspace_dump.o: $(top_srcdir)/rubyparser.h
+objspace_dump.o: $(top_srcdir)/shape.h
+objspace_dump.o: $(top_srcdir)/symbol.h
objspace_dump.o: $(top_srcdir)/thread_pthread.h
+objspace_dump.o: $(top_srcdir)/vm_callinfo.h
objspace_dump.o: $(top_srcdir)/vm_core.h
objspace_dump.o: $(top_srcdir)/vm_debug.h
objspace_dump.o: $(top_srcdir)/vm_opts.h
+objspace_dump.o: $(top_srcdir)/vm_sync.h
objspace_dump.o: objspace.h
objspace_dump.o: objspace_dump.c
objspace_dump.o: {$(VPATH)}id.h
diff --git a/ext/objspace/lib/objspace.rb b/ext/objspace/lib/objspace.rb
new file mode 100644
index 0000000000..47873f5112
--- /dev/null
+++ b/ext/objspace/lib/objspace.rb
@@ -0,0 +1,135 @@
+# frozen_string_literal: true
+
+require 'objspace.so'
+
+module ObjectSpace
+ class << self
+ private :_dump
+ private :_dump_all
+ private :_dump_shapes
+ end
+
+ module_function
+
+ # Dump the contents of a ruby object as JSON.
+ #
+ # _output_ can be one of: +:stdout+, +:file+, +:string+, or IO object.
+ #
+ # * +:file+ means dumping to a tempfile and returning corresponding File object;
+ # * +:stdout+ means printing the dump and returning +nil+;
+ # * +:string+ means returning a string with the dump;
+ # * if an instance of IO object is provided, the output goes there, and the object
+ # is returned.
+ #
+ # This method is only expected to work with C Ruby.
+ # This is an experimental method and is subject to change.
+ # In particular, the function signature and output format are
+ # not guaranteed to be compatible in future versions of ruby.
+ def dump(obj, output: :string)
+ out = case output
+ when :file, nil
+ require 'tempfile'
+ Tempfile.create(%w(rubyobj .json))
+ when :stdout
+ STDOUT
+ when :string
+ +''
+ when IO
+ output
+ else
+ raise ArgumentError, "wrong output option: #{output.inspect}"
+ end
+
+ ret = _dump(obj, out)
+ return nil if output == :stdout
+ ret
+ end
+
+
+ # Dump the contents of the ruby heap as JSON.
+ #
+ # _output_ argument is the same as for #dump.
+ #
+ # _full_ must be a boolean. If true, all heap slots are dumped including the empty ones (+T_NONE+).
+ #
+ # _since_ must be a non-negative integer or +nil+.
+ #
+ # If _since_ is a positive integer, only objects of that generation and
+ # newer generations are dumped. The current generation can be accessed using
+ # GC::count. Objects that were allocated without object allocation tracing enabled
+ # are ignored. See ::trace_object_allocations for more information and
+ # examples.
+ #
+ # If _since_ is omitted or is +nil+, all objects are dumped.
+ #
+ # _shapes_ must be a boolean or a non-negative integer.
+ #
+ # If _shapes_ is a positive integer, only shapes newer than the provided
+ # shape id are dumped. The current shape_id can be accessed using <tt>RubyVM.stat(:next_shape_id)</tt>.
+ #
+ # If _shapes_ is +false+, no shapes are dumped.
+ #
+ # To only dump objects allocated past a certain point you can combine _since_ and _shapes_:
+ # ObjectSpace.trace_object_allocations
+ # GC.start
+ # gc_generation = GC.count
+ # shape_generation = RubyVM.stat(:next_shape_id)
+ # call_method_to_instrument
+ # ObjectSpace.dump_all(since: gc_generation, shapes: shape_generation)
+ #
+ # This method is only expected to work with C Ruby.
+ # This is an experimental method and is subject to change.
+ # In particular, the function signature and output format are
+ # not guaranteed to be compatible in future versions of ruby.
+ def dump_all(output: :file, full: false, since: nil, shapes: true)
+ out = case output
+ when :file, nil
+ require 'tempfile'
+ Tempfile.create(%w(rubyheap .json))
+ when :stdout
+ STDOUT
+ when :string
+ +''
+ when IO
+ output
+ else
+ raise ArgumentError, "wrong output option: #{output.inspect}"
+ end
+
+ shapes = 0 if shapes == true
+ ret = _dump_all(out, full, since, shapes)
+ return nil if output == :stdout
+ ret
+ end
+
+ # Dump the contents of the ruby shape tree as JSON.
+ #
+ # _output_ argument is the same as for #dump.
+ #
+ # If _since_ is a positive integer, only shapes newer than the provided
+ # shape id are dumped. The current shape_id can be accessed using <tt>RubyVM.stat(:next_shape_id)</tt>.
+ #
+ # This method is only expected to work with C Ruby.
+ # This is an experimental method and is subject to change.
+ # In particular, the function signature and output format are
+ # not guaranteed to be compatible in future versions of ruby.
+ def dump_shapes(output: :file, since: 0)
+ out = case output
+ when :file, nil
+ require 'tempfile'
+ Tempfile.create(%w(rubyshapes .json))
+ when :stdout
+ STDOUT
+ when :string
+ +''
+ when IO
+ output
+ else
+ raise ArgumentError, "wrong output option: #{output.inspect}"
+ end
+
+ ret = _dump_shapes(out, since)
+ return nil if output == :stdout
+ ret
+ end
+end
diff --git a/ext/objspace/lib/objspace/trace.rb b/ext/objspace/lib/objspace/trace.rb
new file mode 100644
index 0000000000..c23f5a9d52
--- /dev/null
+++ b/ext/objspace/lib/objspace/trace.rb
@@ -0,0 +1,45 @@
+# This is a simple tool to enable the object allocation tracer.
+# When you have an object of unknown provenance, you can use this
+# to investigate where the object in question is created.
+#
+# = Important notice
+#
+# This is only for debugging purpose. Do not use this in production.
+# Require'ing this file immediately starts tracing the object allocation,
+# which brings a large performance overhead.
+#
+# = Usage
+#
+# 1. Add `require "objspace/trace"` into your code (or add `-robjspace/trace` into the command line)
+# 2. `p obj` will show the allocation site of `obj`
+#
+# Note: This redefines `Kernel#p` method, but not `Object#inspect`.
+#
+# = Examples
+#
+# 1: require "objspace/trace"
+# 2:
+# 3: obj = "str"
+# 4:
+# 5: p obj #=> "str" @ test.rb:3
+
+require 'objspace.so'
+
+module Kernel
+ remove_method :p
+ define_method(:p) do |*objs|
+ objs.each do |obj|
+ file = ObjectSpace.allocation_sourcefile(obj)
+ line = ObjectSpace.allocation_sourceline(obj)
+ if file
+ puts "#{ obj.inspect } @ #{ file }:#{ line }"
+ else
+ puts obj.inspect
+ end
+ end
+ end
+end
+
+ObjectSpace.trace_object_allocations_start
+
+warn "objspace/trace is enabled"
diff --git a/ext/objspace/object_tracing.c b/ext/objspace/object_tracing.c
index 7c354498ab..c06f1f68dd 100644
--- a/ext/objspace/object_tracing.c
+++ b/ext/objspace/object_tracing.c
@@ -14,6 +14,7 @@
**********************************************************************/
#include "internal.h"
+#include "internal/gc.h"
#include "ruby/debug.h"
#include "objspace.h"
@@ -31,42 +32,50 @@ static const char *
make_unique_str(st_table *tbl, const char *str, long len)
{
if (!str) {
- return NULL;
+ return NULL;
}
else {
- st_data_t n;
- char *result;
-
- if (st_lookup(tbl, (st_data_t)str, &n)) {
- st_insert(tbl, (st_data_t)str, n+1);
- st_get_key(tbl, (st_data_t)str, &n);
- result = (char *)n;
- }
- else {
- result = (char *)ruby_xmalloc(len+1);
- strncpy(result, str, len);
- result[len] = 0;
- st_add_direct(tbl, (st_data_t)result, 1);
- }
- return result;
+ st_data_t n;
+ char *result;
+
+ if (st_lookup(tbl, (st_data_t)str, &n)) {
+ st_insert(tbl, (st_data_t)str, n+1);
+ st_get_key(tbl, (st_data_t)str, &n);
+ result = (char *)n;
+ }
+ else {
+ result = (char *)ruby_xmalloc(len+1);
+ strncpy(result, str, len);
+ result[len] = 0;
+ st_add_direct(tbl, (st_data_t)result, 1);
+ }
+ return result;
}
}
+static int
+delete_unique_str_dec(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
+{
+ assert(existing);
+ *value = arg;
+ return ST_CONTINUE;
+}
+
static void
delete_unique_str(st_table *tbl, const char *str)
{
if (str) {
- st_data_t n;
-
- st_lookup(tbl, (st_data_t)str, &n);
- if (n == 1) {
- n = (st_data_t)str;
- st_delete(tbl, &n, 0);
- ruby_xfree((char *)n);
- }
- else {
- st_insert(tbl, (st_data_t)str, n-1);
- }
+ st_data_t n;
+
+ st_lookup(tbl, (st_data_t)str, &n);
+ if (n == 1) {
+ n = (st_data_t)str;
+ st_delete(tbl, &n, 0);
+ ruby_xfree((char *)n);
+ }
+ else {
+ st_update(tbl, (st_data_t)str, delete_unique_str_dec, (st_data_t)(n-1));
+ }
}
}
@@ -87,18 +96,18 @@ newobj_i(VALUE tpval, void *data)
st_data_t v;
if (st_lookup(arg->object_table, (st_data_t)obj, &v)) {
- info = (struct allocation_info *)v;
- if (arg->keep_remains) {
- if (info->living) {
- /* do nothing. there is possibility to keep living if FREEOBJ events while suppressing tracing */
- }
- }
- /* reuse info */
- delete_unique_str(arg->str_table, info->path);
- delete_unique_str(arg->str_table, info->class_path);
+ info = (struct allocation_info *)v;
+ if (arg->keep_remains) {
+ if (info->living) {
+ /* do nothing. there is possibility to keep living if FREEOBJ events while suppressing tracing */
+ }
+ }
+ /* reuse info */
+ delete_unique_str(arg->str_table, info->path);
+ delete_unique_str(arg->str_table, info->class_path);
}
else {
- info = (struct allocation_info *)ruby_xmalloc(sizeof(struct allocation_info));
+ info = (struct allocation_info *)ruby_xmalloc(sizeof(struct allocation_info));
}
info->living = 1;
info->flags = RBASIC(obj)->flags;
@@ -121,36 +130,123 @@ freeobj_i(VALUE tpval, void *data)
st_data_t v;
struct allocation_info *info;
+ /* Modifying the st table can cause allocations, which can trigger GC.
+ * Since freeobj_i is called during GC, it must not trigger another GC. */
+ VALUE gc_disabled = rb_gc_disable_no_rest();
+
if (arg->keep_remains) {
- if (st_lookup(arg->object_table, obj, &v)) {
- info = (struct allocation_info *)v;
- info->living = 0;
- }
+ if (st_lookup(arg->object_table, obj, &v)) {
+ info = (struct allocation_info *)v;
+ info->living = 0;
+ }
}
else {
- if (st_delete(arg->object_table, &obj, &v)) {
- info = (struct allocation_info *)v;
- delete_unique_str(arg->str_table, info->path);
- delete_unique_str(arg->str_table, info->class_path);
- ruby_xfree(info);
- }
+ if (st_delete(arg->object_table, &obj, &v)) {
+ info = (struct allocation_info *)v;
+ delete_unique_str(arg->str_table, info->path);
+ delete_unique_str(arg->str_table, info->class_path);
+ ruby_xfree(info);
+ }
}
+
+ if (gc_disabled == Qfalse) rb_gc_enable();
}
static int
-free_keys_i(st_data_t key, st_data_t value, void *data)
+free_keys_i(st_data_t key, st_data_t value, st_data_t data)
{
ruby_xfree((void *)key);
return ST_CONTINUE;
}
static int
-free_values_i(st_data_t key, st_data_t value, void *data)
+free_values_i(st_data_t key, st_data_t value, st_data_t data)
{
ruby_xfree((void *)value);
return ST_CONTINUE;
}
+static void
+allocation_info_tracer_mark(void *ptr)
+{
+ struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr;
+ rb_gc_mark(trace_arg->newobj_trace);
+ rb_gc_mark(trace_arg->freeobj_trace);
+}
+
+static void
+allocation_info_tracer_free(void *ptr)
+{
+ struct traceobj_arg *arg = (struct traceobj_arg *)ptr;
+ /* clear tables */
+ st_foreach(arg->object_table, free_values_i, 0);
+ st_free_table(arg->object_table);
+ st_foreach(arg->str_table, free_keys_i, 0);
+ st_free_table(arg->str_table);
+ xfree(arg);
+}
+
+static size_t
+allocation_info_tracer_memsize(const void *ptr)
+{
+ size_t size;
+ struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr;
+ size = sizeof(*trace_arg);
+ size += st_memsize(trace_arg->object_table);
+ size += st_memsize(trace_arg->str_table);
+ return size;
+}
+
+static int
+allocation_info_tracer_compact_update_object_table_i(st_data_t key, st_data_t value, st_data_t data)
+{
+ st_table *table = (st_table *)data;
+
+ if (!rb_gc_pointer_to_heap_p(key)) {
+ struct allocation_info *info = (struct allocation_info *)value;
+ xfree(info);
+ return ST_DELETE;
+ }
+
+ if (key != rb_gc_location(key)) {
+ DURING_GC_COULD_MALLOC_REGION_START();
+ {
+ st_insert(table, rb_gc_location(key), value);
+ }
+ DURING_GC_COULD_MALLOC_REGION_END();
+
+ return ST_DELETE;
+ }
+
+ return ST_CONTINUE;
+}
+
+static void
+allocation_info_tracer_compact(void *ptr)
+{
+ struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr;
+
+ if (trace_arg->object_table &&
+ st_foreach(
+ trace_arg->object_table,
+ allocation_info_tracer_compact_update_object_table_i,
+ (st_data_t)trace_arg->object_table)) {
+ rb_raise(rb_eRuntimeError, "hash modified during iteration");
+ }
+}
+
+static const rb_data_type_t allocation_info_tracer_type = {
+ "ObjectTracing/allocation_info_tracer",
+ {
+ allocation_info_tracer_mark,
+ allocation_info_tracer_free, /* Never called because global */
+ allocation_info_tracer_memsize,
+ allocation_info_tracer_compact,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+};
+
+static VALUE traceobj_arg;
static struct traceobj_arg *tmp_trace_arg; /* TODO: Do not use global variables */
static int tmp_keep_remains; /* TODO: Do not use global variables */
@@ -158,13 +254,15 @@ static struct traceobj_arg *
get_traceobj_arg(void)
{
if (tmp_trace_arg == 0) {
- tmp_trace_arg = ALLOC_N(struct traceobj_arg, 1);
- tmp_trace_arg->running = 0;
- tmp_trace_arg->keep_remains = tmp_keep_remains;
- tmp_trace_arg->newobj_trace = 0;
- tmp_trace_arg->freeobj_trace = 0;
- tmp_trace_arg->object_table = st_init_numtable();
- tmp_trace_arg->str_table = st_init_strtable();
+ VALUE obj = TypedData_Make_Struct(rb_cObject, struct traceobj_arg, &allocation_info_tracer_type, tmp_trace_arg);
+ traceobj_arg = obj;
+ rb_gc_register_mark_object(traceobj_arg);
+ tmp_trace_arg->running = 0;
+ tmp_trace_arg->keep_remains = tmp_keep_remains;
+ tmp_trace_arg->newobj_trace = 0;
+ tmp_trace_arg->freeobj_trace = 0;
+ tmp_trace_arg->object_table = st_init_numtable();
+ tmp_trace_arg->str_table = st_init_strtable();
}
return tmp_trace_arg;
}
@@ -181,17 +279,15 @@ trace_object_allocations_start(VALUE self)
struct traceobj_arg *arg = get_traceobj_arg();
if (arg->running++ > 0) {
- /* do nothing */
+ /* do nothing */
}
else {
- if (arg->newobj_trace == 0) {
- arg->newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, arg);
- rb_gc_register_mark_object(arg->newobj_trace);
- arg->freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, arg);
- rb_gc_register_mark_object(arg->freeobj_trace);
- }
- rb_tracepoint_enable(arg->newobj_trace);
- rb_tracepoint_enable(arg->freeobj_trace);
+ if (arg->newobj_trace == 0) {
+ arg->newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, arg);
+ arg->freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, arg);
+ }
+ rb_tracepoint_enable(arg->newobj_trace);
+ rb_tracepoint_enable(arg->freeobj_trace);
}
return Qnil;
@@ -212,12 +308,16 @@ trace_object_allocations_stop(VALUE self)
struct traceobj_arg *arg = get_traceobj_arg();
if (arg->running > 0) {
- arg->running--;
+ arg->running--;
}
if (arg->running == 0) {
- rb_tracepoint_disable(arg->newobj_trace);
- rb_tracepoint_disable(arg->freeobj_trace);
+ if (arg->newobj_trace != 0) {
+ rb_tracepoint_disable(arg->newobj_trace);
+ }
+ if (arg->freeobj_trace != 0) {
+ rb_tracepoint_disable(arg->freeobj_trace);
+ }
}
return Qnil;
@@ -295,8 +395,8 @@ object_allocations_reporter_i(st_data_t key, st_data_t val, st_data_t ptr)
else fprintf(out, "C: %p", (void *)info->klass);
fprintf(out, "@%s:%lu", info->path ? info->path : "", info->line);
if (!NIL_P(info->mid)) {
- VALUE m = rb_sym2str(info->mid);
- fprintf(out, " (%s)", RSTRING_PTR(m));
+ VALUE m = rb_sym2str(info->mid);
+ fprintf(out, " (%s)", RSTRING_PTR(m));
}
fprintf(out, ")\n");
@@ -308,18 +408,25 @@ object_allocations_reporter(FILE *out, void *ptr)
{
fprintf(out, "== object_allocations_reporter: START\n");
if (tmp_trace_arg) {
- st_foreach(tmp_trace_arg->object_table, object_allocations_reporter_i, (st_data_t)out);
+ st_foreach(tmp_trace_arg->object_table, object_allocations_reporter_i, (st_data_t)out);
}
fprintf(out, "== object_allocations_reporter: END\n");
}
+/*
+ * call-seq: trace_object_allocations_debug_start
+ *
+ * Starts tracing object allocations for GC debugging.
+ * If you encounter the BUG "... is T_NONE" (and so on) on your
+ * application, please try this method at the beginning of your app.
+ */
static VALUE
trace_object_allocations_debug_start(VALUE self)
{
tmp_keep_remains = 1;
if (object_allocations_reporter_registered == 0) {
- object_allocations_reporter_registered = 1;
- rb_bug_reporter_add(object_allocations_reporter, 0);
+ object_allocations_reporter_registered = 1;
+ rb_bug_reporter_add(object_allocations_reporter, 0);
}
return trace_object_allocations_start(self);
@@ -329,10 +436,10 @@ static struct allocation_info *
lookup_allocation_info(VALUE obj)
{
if (tmp_trace_arg) {
- st_data_t info;
- if (st_lookup(tmp_trace_arg->object_table, obj, &info)) {
- return (struct allocation_info *)info;
- }
+ st_data_t info;
+ if (st_lookup(tmp_trace_arg->object_table, obj, &info)) {
+ return (struct allocation_info *)info;
+ }
}
return NULL;
}
@@ -356,10 +463,10 @@ allocation_sourcefile(VALUE self, VALUE obj)
struct allocation_info *info = lookup_allocation_info(obj);
if (info && info->path) {
- return rb_str_new2(info->path);
+ return rb_str_new2(info->path);
}
else {
- return Qnil;
+ return Qnil;
}
}
@@ -376,10 +483,10 @@ allocation_sourceline(VALUE self, VALUE obj)
struct allocation_info *info = lookup_allocation_info(obj);
if (info) {
- return INT2FIX(info->line);
+ return INT2FIX(info->line);
}
else {
- return Qnil;
+ return Qnil;
}
}
@@ -407,10 +514,10 @@ allocation_class_path(VALUE self, VALUE obj)
struct allocation_info *info = lookup_allocation_info(obj);
if (info && info->class_path) {
- return rb_str_new2(info->class_path);
+ return rb_str_new2(info->class_path);
}
else {
- return Qnil;
+ return Qnil;
}
}
@@ -439,10 +546,10 @@ allocation_method_id(VALUE self, VALUE obj)
{
struct allocation_info *info = lookup_allocation_info(obj);
if (info) {
- return info->mid;
+ return info->mid;
}
else {
- return Qnil;
+ return Qnil;
}
}
@@ -471,10 +578,10 @@ allocation_generation(VALUE self, VALUE obj)
{
struct allocation_info *info = lookup_allocation_info(obj);
if (info) {
- return SIZET2NUM(info->generation);
+ return SIZET2NUM(info->generation);
}
else {
- return Qnil;
+ return Qnil;
}
}
diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c
index 427d2c4e98..457ffc2789 100644
--- a/ext/objspace/objspace.c
+++ b/ext/objspace/objspace.c
@@ -12,28 +12,37 @@
**********************************************************************/
-#include <ruby/io.h>
#include "internal.h"
-#include <ruby/st.h>
-#include <ruby/re.h>
-#include "node.h"
-#include "gc.h"
+#include "internal/class.h"
+#include "internal/compilers.h"
+#include "internal/gc.h"
+#include "internal/hash.h"
+#include "internal/imemo.h"
+#include "internal/sanitizers.h"
+#include "ruby/io.h"
+#include "ruby/re.h"
+#include "ruby/st.h"
#include "symbol.h"
+#undef rb_funcall
+
+#include "ruby/ruby.h"
+
/*
* call-seq:
* ObjectSpace.memsize_of(obj) -> Integer
*
- * Return consuming memory size of obj.
+ * Return consuming memory size of obj in bytes.
*
* Note that the return size is incomplete. You need to deal with this
* information as only a *HINT*. Especially, the size of +T_DATA+ may not be
* correct.
*
- * This method is only expected to work with C Ruby.
+ * This method is only expected to work with CRuby.
*
- * From Ruby 2.2, memsize_of(obj) returns a memory size includes
- * sizeof(RVALUE).
+ * From Ruby 3.2 with Variable Width Allocation, it returns the actual slot
+ * size used plus any additional memory allocated outside the slot (such
+ * as external strings, arrays, or hash tables).
*/
static VALUE
@@ -47,56 +56,76 @@ struct total_data {
VALUE klass;
};
+static void
+total_i(VALUE v, void *ptr)
+{
+ struct total_data *data = (struct total_data *)ptr;
+
+ if (!rb_objspace_internal_object_p(v)) {
+ if (data->klass == 0 || rb_obj_is_kind_of(v, data->klass)) {
+ data->total += rb_obj_memsize_of(v);
+ }
+ }
+}
+
+typedef void (*each_obj_with_flags)(VALUE, void*);
+
+struct obj_itr {
+ each_obj_with_flags cb;
+ void *data;
+};
+
static int
-total_i(void *vstart, void *vend, size_t stride, void *ptr)
+heap_iter(void *vstart, void *vend, size_t stride, void *ptr)
{
+ struct obj_itr * ctx = (struct obj_itr *)ptr;
VALUE v;
- struct total_data *data = (struct total_data *)ptr;
for (v = (VALUE)vstart; v != (VALUE)vend; v += stride) {
- if (RBASIC(v)->flags) {
- switch (BUILTIN_TYPE(v)) {
- case T_NONE:
- case T_IMEMO:
- case T_ICLASS:
- case T_NODE:
- case T_ZOMBIE:
- continue;
- default:
- if (data->klass == 0 || rb_obj_is_kind_of(v, data->klass)) {
- data->total += rb_obj_memsize_of(v);
- }
- }
- }
+ void *poisoned = rb_asan_poisoned_object_p(v);
+ rb_asan_unpoison_object(v, false);
+
+ if (RBASIC(v)->flags) {
+ (*ctx->cb)(v, ctx->data);
+ }
+
+ if (poisoned) {
+ rb_asan_poison_object(v);
+ }
}
return 0;
}
+static void
+each_object_with_flags(each_obj_with_flags cb, void *ctx)
+{
+ struct obj_itr data;
+ data.cb = cb;
+ data.data = ctx;
+ rb_objspace_each_objects(heap_iter, &data);
+}
+
/*
* call-seq:
- * ObjectSpace.memsize_of_all([klass]) -> Integer
- *
- * Return consuming memory size of all living objects.
+ * ObjectSpace.memsize_of_all(klass = nil) -> integer
*
- * If +klass+ (should be Class object) is given, return the total memory size
- * of instances of the given class.
+ * Returns the total memory size of all living objects in bytes.
*
- * Note that the returned size is incomplete. You need to deal with this
- * information as only a *HINT*. Especially, the size of +T_DATA+ may not be
- * correct.
+ * ObjectSpace.memsize_of_all # => 12502001
*
- * Note that this method does *NOT* return total malloc'ed memory size.
+ * If +klass+ is given (which must be a Class or Module), returns the total
+ * memory size of objects whose class is, or is a subclass, of +klass+.
*
- * This method can be defined by the following Ruby code:
+ * class MyClass; end
+ * ObjectSpace.memsize_of_all(MyClass) # => 0
+ * o = MyClass.new
+ * ObjectSpace.memsize_of_all(MyClass) # => 40
*
- * def memsize_of_all klass = false
- * total = 0
- * ObjectSpace.each_object{|e|
- * total += ObjectSpace.memsize_of(e) if klass == false || e.kind_of?(klass)
- * }
- * total
- * end
+ * Note that the value returned may be an underestimate of the actual amount
+ * of memory used. Therefore, the value returned should only be used as a hint,
+ * rather than a source of truth. In particular, the size of +T_DATA+ objects may
+ * not be correct.
*
* This method is only expected to work with C Ruby.
*/
@@ -107,10 +136,10 @@ memsize_of_all_m(int argc, VALUE *argv, VALUE self)
struct total_data data = {0, 0};
if (argc > 0) {
- rb_scan_args(argc, argv, "01", &data.klass);
+ rb_scan_args(argc, argv, "01", &data.klass);
}
- rb_objspace_each_objects(total_i, &data);
+ each_object_with_flags(total_i, &data);
return SIZET2NUM(data.total);
}
@@ -137,24 +166,17 @@ setup_hash(int argc, VALUE *argv)
hash = rb_hash_new();
}
else if (!RHASH_EMPTY_P(hash)) {
- st_foreach(RHASH_TBL(hash), set_zero_i, hash);
+ rb_hash_foreach(hash, set_zero_i, (st_data_t)hash);
}
return hash;
}
-static int
-cos_i(void *vstart, void *vend, size_t stride, void *data)
+static void
+cos_i(VALUE v, void *data)
{
size_t *counts = (size_t *)data;
- VALUE v = (VALUE)vstart;
-
- for (;v != (VALUE)vend; v += stride) {
- if (RBASIC(v)->flags) {
- counts[BUILTIN_TYPE(v)] += rb_obj_memsize_of(v);
- }
- }
- return 0;
+ counts[BUILTIN_TYPE(v)] += rb_obj_memsize_of(v);
}
static VALUE
@@ -163,33 +185,33 @@ type2sym(enum ruby_value_type i)
VALUE type;
switch (i) {
#define CASE_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break;
- CASE_TYPE(T_NONE);
- CASE_TYPE(T_OBJECT);
- CASE_TYPE(T_CLASS);
- CASE_TYPE(T_MODULE);
- CASE_TYPE(T_FLOAT);
- CASE_TYPE(T_STRING);
- CASE_TYPE(T_REGEXP);
- CASE_TYPE(T_ARRAY);
- CASE_TYPE(T_HASH);
- CASE_TYPE(T_STRUCT);
- CASE_TYPE(T_BIGNUM);
- CASE_TYPE(T_FILE);
- CASE_TYPE(T_DATA);
- CASE_TYPE(T_MATCH);
- CASE_TYPE(T_COMPLEX);
- CASE_TYPE(T_RATIONAL);
- CASE_TYPE(T_NIL);
- CASE_TYPE(T_TRUE);
- CASE_TYPE(T_FALSE);
- CASE_TYPE(T_SYMBOL);
- CASE_TYPE(T_FIXNUM);
- CASE_TYPE(T_UNDEF);
- CASE_TYPE(T_IMEMO);
- CASE_TYPE(T_NODE);
- CASE_TYPE(T_ICLASS);
+ CASE_TYPE(T_NONE);
+ CASE_TYPE(T_OBJECT);
+ CASE_TYPE(T_CLASS);
+ CASE_TYPE(T_MODULE);
+ CASE_TYPE(T_FLOAT);
+ CASE_TYPE(T_STRING);
+ CASE_TYPE(T_REGEXP);
+ CASE_TYPE(T_ARRAY);
+ CASE_TYPE(T_HASH);
+ CASE_TYPE(T_STRUCT);
+ CASE_TYPE(T_BIGNUM);
+ CASE_TYPE(T_FILE);
+ CASE_TYPE(T_DATA);
+ CASE_TYPE(T_MATCH);
+ CASE_TYPE(T_COMPLEX);
+ CASE_TYPE(T_RATIONAL);
+ CASE_TYPE(T_NIL);
+ CASE_TYPE(T_TRUE);
+ CASE_TYPE(T_FALSE);
+ CASE_TYPE(T_SYMBOL);
+ CASE_TYPE(T_FIXNUM);
+ CASE_TYPE(T_UNDEF);
+ CASE_TYPE(T_IMEMO);
+ CASE_TYPE(T_NODE);
+ CASE_TYPE(T_ICLASS);
CASE_TYPE(T_MOVED);
- CASE_TYPE(T_ZOMBIE);
+ CASE_TYPE(T_ZOMBIE);
#undef CASE_TYPE
default: rb_bug("type2sym: unknown type (%d)", i);
}
@@ -228,17 +250,17 @@ count_objects_size(int argc, VALUE *argv, VALUE os)
VALUE hash = setup_hash(argc, argv);
for (i = 0; i <= T_MASK; i++) {
- counts[i] = 0;
+ counts[i] = 0;
}
- rb_objspace_each_objects(cos_i, &counts[0]);
+ each_object_with_flags(cos_i, &counts[0]);
for (i = 0; i <= T_MASK; i++) {
- if (counts[i]) {
- VALUE type = type2sym(i);
- total += counts[i];
- rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
- }
+ if (counts[i]) {
+ VALUE type = type2sym(i);
+ total += counts[i];
+ rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
+ }
}
rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
return hash;
@@ -249,53 +271,47 @@ struct dynamic_symbol_counts {
size_t immortal;
};
-static int
-cs_i(void *vstart, void *vend, size_t stride, void *n)
+static void
+cs_i(VALUE v, void *n)
{
struct dynamic_symbol_counts *counts = (struct dynamic_symbol_counts *)n;
- VALUE v = (VALUE)vstart;
-
- for (; v != (VALUE)vend; v += stride) {
- if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_SYMBOL) {
- ID id = RSYMBOL(v)->id;
- if ((id & ~ID_SCOPE_MASK) == 0) {
- counts->mortal++;
- }
- else {
- counts->immortal++;
- }
- }
- }
- return 0;
+ if (BUILTIN_TYPE(v) == T_SYMBOL) {
+ ID id = RSYMBOL(v)->id;
+ if ((id & ~ID_SCOPE_MASK) == 0) {
+ counts->mortal++;
+ }
+ else {
+ counts->immortal++;
+ }
+ }
}
size_t rb_sym_immortal_count(void);
/*
* call-seq:
- * ObjectSpace.count_symbols([result_hash]) -> hash
+ * ObjectSpace.count_symbols(result_hash = nil) -> hash
*
- * Counts symbols for each Symbol type.
+ * Returns a hash containing the number of objects for each Symbol type.
*
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * The types of Symbols are the following:
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
- *
- * Note:
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
+ * - +mortal_dynamic_symbol+: Symbols that are garbage collectable.
+ * - +immortal_dynamic_symbol+: Symbols that are objects allocated from the
+ * garbage collector, but are not garbage collectable.
+ * - +immortal_static_symbol+: Symbols that are not allocated from the
+ * garbage collector, and are thus not garbage collectable.
+ * - +immortal_symbol+: the sum of +immortal_dynamic_symbol+ and +immortal_static_symbol+.
*
- * This method is only expected to work with C Ruby.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * On this version of MRI, they have 3 types of Symbols (and 1 total counts).
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
- * * mortal_dynamic_symbol: GC target symbols (collected by GC)
- * * immortal_dynamic_symbol: Immortal symbols promoted from dynamic symbols (do not collected by GC)
- * * immortal_static_symbol: Immortal symbols (do not collected by GC)
- * * immortal_symbol: total immortal symbols (immortal_dynamic_symbol+immortal_static_symbol)
+ * This method is only expected to work with C Ruby.
*/
static VALUE
@@ -305,7 +321,7 @@ count_symbols(int argc, VALUE *argv, VALUE os)
VALUE hash = setup_hash(argc, argv);
size_t immortal_symbols = rb_sym_immortal_count();
- rb_objspace_each_objects(cs_i, &dynamic_counts);
+ each_object_with_flags(cs_i, &dynamic_counts);
rb_hash_aset(hash, ID2SYM(rb_intern("mortal_dynamic_symbol")), SIZET2NUM(dynamic_counts.mortal));
rb_hash_aset(hash, ID2SYM(rb_intern("immortal_dynamic_symbol")), SIZET2NUM(dynamic_counts.immortal));
@@ -315,239 +331,51 @@ count_symbols(int argc, VALUE *argv, VALUE os)
return hash;
}
-static int
-cn_i(void *vstart, void *vend, size_t stride, void *n)
-{
- size_t *nodes = (size_t *)n;
- VALUE v = (VALUE)vstart;
-
- for (; v != (VALUE)vend; v += stride) {
- if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_NODE) {
- size_t s = nd_type((NODE *)v);
- nodes[s]++;
- }
- }
-
- return 0;
-}
-
-/*
- * call-seq:
- * ObjectSpace.count_nodes([result_hash]) -> hash
- *
- * Counts nodes for each node type.
- *
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
- *
- * It returns a hash as:
- *
- * {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...}
- *
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
- *
- * Note:
- * The contents of the returned hash is implementation defined.
- * It may be changed in future.
- *
- * This method is only expected to work with C Ruby.
- */
-
-static VALUE
-count_nodes(int argc, VALUE *argv, VALUE os)
-{
- size_t nodes[NODE_LAST+1];
- enum node_type i;
- VALUE hash = setup_hash(argc, argv);
-
- for (i = 0; i <= NODE_LAST; i++) {
- nodes[i] = 0;
- }
-
- rb_objspace_each_objects(cn_i, &nodes[0]);
-
- for (i=0; i<NODE_LAST; i++) {
- if (nodes[i] != 0) {
- VALUE node;
- switch (i) {
-#define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); goto set
- COUNT_NODE(NODE_SCOPE);
- COUNT_NODE(NODE_BLOCK);
- COUNT_NODE(NODE_IF);
- COUNT_NODE(NODE_UNLESS);
- COUNT_NODE(NODE_CASE);
- COUNT_NODE(NODE_CASE2);
- COUNT_NODE(NODE_CASE3);
- COUNT_NODE(NODE_WHEN);
- COUNT_NODE(NODE_IN);
- COUNT_NODE(NODE_WHILE);
- COUNT_NODE(NODE_UNTIL);
- COUNT_NODE(NODE_ITER);
- COUNT_NODE(NODE_FOR);
- COUNT_NODE(NODE_FOR_MASGN);
- COUNT_NODE(NODE_BREAK);
- COUNT_NODE(NODE_NEXT);
- COUNT_NODE(NODE_REDO);
- COUNT_NODE(NODE_RETRY);
- COUNT_NODE(NODE_BEGIN);
- COUNT_NODE(NODE_RESCUE);
- COUNT_NODE(NODE_RESBODY);
- COUNT_NODE(NODE_ENSURE);
- COUNT_NODE(NODE_AND);
- COUNT_NODE(NODE_OR);
- COUNT_NODE(NODE_MASGN);
- COUNT_NODE(NODE_LASGN);
- COUNT_NODE(NODE_DASGN);
- COUNT_NODE(NODE_DASGN_CURR);
- COUNT_NODE(NODE_GASGN);
- COUNT_NODE(NODE_IASGN);
- COUNT_NODE(NODE_CDECL);
- COUNT_NODE(NODE_CVASGN);
- COUNT_NODE(NODE_OP_ASGN1);
- COUNT_NODE(NODE_OP_ASGN2);
- COUNT_NODE(NODE_OP_ASGN_AND);
- COUNT_NODE(NODE_OP_ASGN_OR);
- COUNT_NODE(NODE_OP_CDECL);
- COUNT_NODE(NODE_CALL);
- COUNT_NODE(NODE_OPCALL);
- COUNT_NODE(NODE_FCALL);
- COUNT_NODE(NODE_VCALL);
- COUNT_NODE(NODE_QCALL);
- COUNT_NODE(NODE_SUPER);
- COUNT_NODE(NODE_ZSUPER);
- COUNT_NODE(NODE_ARRAY);
- COUNT_NODE(NODE_ZARRAY);
- COUNT_NODE(NODE_VALUES);
- COUNT_NODE(NODE_HASH);
- COUNT_NODE(NODE_RETURN);
- COUNT_NODE(NODE_YIELD);
- COUNT_NODE(NODE_LVAR);
- COUNT_NODE(NODE_DVAR);
- COUNT_NODE(NODE_GVAR);
- COUNT_NODE(NODE_IVAR);
- COUNT_NODE(NODE_CONST);
- COUNT_NODE(NODE_CVAR);
- COUNT_NODE(NODE_NTH_REF);
- COUNT_NODE(NODE_BACK_REF);
- COUNT_NODE(NODE_MATCH);
- COUNT_NODE(NODE_MATCH2);
- COUNT_NODE(NODE_MATCH3);
- COUNT_NODE(NODE_LIT);
- COUNT_NODE(NODE_STR);
- COUNT_NODE(NODE_DSTR);
- COUNT_NODE(NODE_XSTR);
- COUNT_NODE(NODE_DXSTR);
- COUNT_NODE(NODE_EVSTR);
- COUNT_NODE(NODE_DREGX);
- COUNT_NODE(NODE_ONCE);
- COUNT_NODE(NODE_ARGS);
- COUNT_NODE(NODE_ARGS_AUX);
- COUNT_NODE(NODE_OPT_ARG);
- COUNT_NODE(NODE_KW_ARG);
- COUNT_NODE(NODE_POSTARG);
- COUNT_NODE(NODE_ARGSCAT);
- COUNT_NODE(NODE_ARGSPUSH);
- COUNT_NODE(NODE_SPLAT);
- COUNT_NODE(NODE_BLOCK_PASS);
- COUNT_NODE(NODE_DEFN);
- COUNT_NODE(NODE_DEFS);
- COUNT_NODE(NODE_ALIAS);
- COUNT_NODE(NODE_VALIAS);
- COUNT_NODE(NODE_UNDEF);
- COUNT_NODE(NODE_CLASS);
- COUNT_NODE(NODE_MODULE);
- COUNT_NODE(NODE_SCLASS);
- COUNT_NODE(NODE_COLON2);
- COUNT_NODE(NODE_COLON3);
- COUNT_NODE(NODE_DOT2);
- COUNT_NODE(NODE_DOT3);
- COUNT_NODE(NODE_FLIP2);
- COUNT_NODE(NODE_FLIP3);
- COUNT_NODE(NODE_SELF);
- COUNT_NODE(NODE_NIL);
- COUNT_NODE(NODE_TRUE);
- COUNT_NODE(NODE_FALSE);
- COUNT_NODE(NODE_ERRINFO);
- COUNT_NODE(NODE_DEFINED);
- COUNT_NODE(NODE_POSTEXE);
- COUNT_NODE(NODE_DSYM);
- COUNT_NODE(NODE_ATTRASGN);
- COUNT_NODE(NODE_LAMBDA);
- COUNT_NODE(NODE_METHREF);
- COUNT_NODE(NODE_ARYPTN);
- COUNT_NODE(NODE_HSHPTN);
-#undef COUNT_NODE
- case NODE_LAST: break;
- }
- UNREACHABLE;
- set:
- rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
- }
- }
- return hash;
-}
-
-static int
-cto_i(void *vstart, void *vend, size_t stride, void *data)
+static void
+cto_i(VALUE v, void *data)
{
VALUE hash = (VALUE)data;
- VALUE v = (VALUE)vstart;
-
- for (; v != (VALUE)vend; v += stride) {
- if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_DATA) {
- VALUE counter;
- VALUE key = RBASIC(v)->klass;
-
- if (key == 0) {
- const char *name = rb_objspace_data_type_name(v);
- if (name == 0) name = "unknown";
- key = ID2SYM(rb_intern(name));
- }
-
- counter = rb_hash_aref(hash, key);
- if (NIL_P(counter)) {
- counter = INT2FIX(1);
- }
- else {
- counter = INT2FIX(FIX2INT(counter) + 1);
- }
-
- rb_hash_aset(hash, key, counter);
- }
- }
- return 0;
+ if (BUILTIN_TYPE(v) == T_DATA) {
+ VALUE counter;
+ VALUE key = RBASIC(v)->klass;
+
+ if (key == 0) {
+ const char *name = rb_objspace_data_type_name(v);
+ if (name == 0) name = "unknown";
+ key = ID2SYM(rb_intern(name));
+ }
+
+ counter = rb_hash_aref(hash, key);
+ if (NIL_P(counter)) {
+ counter = INT2FIX(1);
+ }
+ else {
+ counter = INT2FIX(FIX2INT(counter) + 1);
+ }
+
+ rb_hash_aset(hash, key, counter);
+ }
}
/*
* call-seq:
- * ObjectSpace.count_tdata_objects([result_hash]) -> hash
- *
- * Counts objects for each +T_DATA+ type.
- *
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * ObjectSpace.count_tdata_objects(result_hash = nil) -> hash
*
- * It returns a hash as:
- *
- * {RubyVM::InstructionSequence=>504, :parser=>5, :barrier=>6,
- * :mutex=>6, Proc=>60, RubyVM::Env=>57, Mutex=>1, Encoding=>99,
- * ThreadGroup=>1, Binding=>1, Thread=>1, RubyVM=>1, :iseq=>1,
- * Random=>1, ARGF.class=>1, Data=>1, :autoload=>3, Time=>2}
- * # T_DATA objects existing at startup on r32276.
- *
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
+ * Returns a hash containing the number of objects for each +T_DATA+ type.
+ * The keys are Class objects when the +T_DATA+ object has an associated class,
+ * or Symbol objects of the name defined in the +rb_data_type_struct+ for internal
+ * +T_DATA+ objects.
*
- * The contents of the returned hash is implementation specific and may change
- * in the future.
+ * ObjectSpace.count_tdata_objects
+ * # => {RBS::Location => 39255, marshal_compat_table: 1, Encoding => 103, mutex: 1, ... }
*
- * In this version, keys are Class object or Symbol object.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * If object is kind of normal (accessible) object, the key is Class object.
- * If object is not a kind of normal (internal) object, the key is symbol
- * name, registered by rb_data_type_struct.
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
* This method is only expected to work with C Ruby.
*/
@@ -556,63 +384,52 @@ static VALUE
count_tdata_objects(int argc, VALUE *argv, VALUE self)
{
VALUE hash = setup_hash(argc, argv);
- rb_objspace_each_objects(cto_i, (void *)hash);
+ each_object_with_flags(cto_i, (void *)hash);
return hash;
}
static ID imemo_type_ids[IMEMO_MASK+1];
-static int
-count_imemo_objects_i(void *vstart, void *vend, size_t stride, void *data)
+static void
+count_imemo_objects_i(VALUE v, void *data)
{
VALUE hash = (VALUE)data;
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_IMEMO) {
- VALUE counter;
- VALUE key = ID2SYM(imemo_type_ids[imemo_type(v)]);
+ if (BUILTIN_TYPE(v) == T_IMEMO) {
+ VALUE counter;
+ VALUE key = ID2SYM(imemo_type_ids[imemo_type(v)]);
- counter = rb_hash_aref(hash, key);
+ counter = rb_hash_aref(hash, key);
- if (NIL_P(counter)) {
- counter = INT2FIX(1);
- }
- else {
- counter = INT2FIX(FIX2INT(counter) + 1);
- }
+ if (NIL_P(counter)) {
+ counter = INT2FIX(1);
+ }
+ else {
+ counter = INT2FIX(FIX2INT(counter) + 1);
+ }
- rb_hash_aset(hash, key, counter);
- }
+ rb_hash_aset(hash, key, counter);
}
-
- return 0;
}
/*
* call-seq:
- * ObjectSpace.count_imemo_objects([result_hash]) -> hash
- *
- * Counts objects for each +T_IMEMO+ type.
- *
- * This method is only for MRI developers interested in performance and memory
- * usage of Ruby programs.
+ * ObjectSpace.count_imemo_objects(result_hash = nil) -> hash
*
- * It returns a hash as:
- *
- * {:imemo_ifunc=>8,
- * :imemo_svar=>7,
- * :imemo_cref=>509,
- * :imemo_memo=>1,
- * :imemo_throw_data=>1}
+ * Returns a hash containing the number of objects for each +T_IMEMO+ type.
+ * The keys are Symbol objects of the +T_IMEMO+ type name.
+ * +T_IMEMO+ objects are Ruby internal objects that are not visible to Ruby
+ * programs.
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
+ * ObjectSpace.count_imemo_objects
+ * # => {imemo_callcache: 5482, imemo_constcache: 1258, imemo_ment: 13906, ... }
*
- * The contents of the returned hash is implementation specific and may change
- * in the future.
+ * If the optional argument +result_hash+ is given, it is overwritten and
+ * returned. This is intended to avoid the probe effect.
*
- * In this version, keys are symbol objects.
+ * This method is intended for developers interested in performance and memory
+ * usage of Ruby programs. The contents of the returned hash is implementation
+ * specific and may change in the future.
*
* This method is only expected to work with C Ruby.
*/
@@ -623,20 +440,24 @@ count_imemo_objects(int argc, VALUE *argv, VALUE self)
VALUE hash = setup_hash(argc, argv);
if (imemo_type_ids[0] == 0) {
- imemo_type_ids[0] = rb_intern("imemo_env");
- imemo_type_ids[1] = rb_intern("imemo_cref");
- imemo_type_ids[2] = rb_intern("imemo_svar");
- imemo_type_ids[3] = rb_intern("imemo_throw_data");
- imemo_type_ids[4] = rb_intern("imemo_ifunc");
- imemo_type_ids[5] = rb_intern("imemo_memo");
- imemo_type_ids[6] = rb_intern("imemo_ment");
- imemo_type_ids[7] = rb_intern("imemo_iseq");
- imemo_type_ids[8] = rb_intern("imemo_tmpbuf");
- imemo_type_ids[9] = rb_intern("imemo_ast");
- imemo_type_ids[10] = rb_intern("imemo_parser_strterm");
+#define INIT_IMEMO_TYPE_ID(n) (imemo_type_ids[n] = rb_intern_const(#n))
+ INIT_IMEMO_TYPE_ID(imemo_env);
+ INIT_IMEMO_TYPE_ID(imemo_cref);
+ INIT_IMEMO_TYPE_ID(imemo_svar);
+ INIT_IMEMO_TYPE_ID(imemo_throw_data);
+ INIT_IMEMO_TYPE_ID(imemo_ifunc);
+ INIT_IMEMO_TYPE_ID(imemo_memo);
+ INIT_IMEMO_TYPE_ID(imemo_ment);
+ INIT_IMEMO_TYPE_ID(imemo_iseq);
+ INIT_IMEMO_TYPE_ID(imemo_tmpbuf);
+ INIT_IMEMO_TYPE_ID(imemo_callinfo);
+ INIT_IMEMO_TYPE_ID(imemo_callcache);
+ INIT_IMEMO_TYPE_ID(imemo_constcache);
+ INIT_IMEMO_TYPE_ID(imemo_fields);
+#undef INIT_IMEMO_TYPE_ID
}
- rb_objspace_each_objects(count_imemo_objects_i, (void *)hash);
+ each_object_with_flags(count_imemo_objects_i, (void *)hash);
return hash;
}
@@ -660,12 +481,12 @@ static const rb_data_type_t iow_data_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
-static VALUE rb_mInternalObjectWrapper;
+static VALUE rb_cInternalObjectWrapper;
static VALUE
iow_newobj(VALUE obj)
{
- return TypedData_Wrap_Struct(rb_mInternalObjectWrapper, &iow_data_type, (void *)obj);
+ return TypedData_Wrap_Struct(rb_cInternalObjectWrapper, &iow_data_type, (void *)obj);
}
/* Returns the type of the internal object. */
@@ -695,8 +516,8 @@ iow_internal_object_id(VALUE self)
}
struct rof_data {
- st_table *refs;
- VALUE internals;
+ VALUE refs;
+ VALUE values;
};
static void
@@ -706,12 +527,16 @@ reachable_object_from_i(VALUE obj, void *data_ptr)
VALUE key = obj;
VALUE val = obj;
- if (rb_objspace_markable_object_p(obj)) {
- if (rb_objspace_internal_object_p(obj)) {
- val = iow_newobj(obj);
- rb_ary_push(data->internals, val);
- }
- st_insert(data->refs, key, val);
+ if (!rb_objspace_garbage_object_p(obj)) {
+ if (NIL_P(rb_hash_lookup(data->refs, key))) {
+ rb_hash_aset(data->refs, key, Qtrue);
+
+ if (rb_objspace_internal_object_p(obj)) {
+ val = iow_newobj(obj);
+ }
+
+ rb_ary_push(data->values, val);
+ }
}
}
@@ -748,7 +573,7 @@ collect_values(st_data_t key, st_data_t value, st_data_t data)
*
* With this method, you can find memory leaks.
*
- * This method is only expected to work except with C Ruby.
+ * This method is only expected to work with C Ruby.
*
* Example:
* ObjectSpace.reachable_objects_from(['a', 'b', 'c'])
@@ -768,24 +593,22 @@ collect_values(st_data_t key, st_data_t value, st_data_t data)
static VALUE
reachable_objects_from(VALUE self, VALUE obj)
{
- if (rb_objspace_markable_object_p(obj)) {
- VALUE ret = rb_ary_new();
- struct rof_data data;
+ if (!RB_SPECIAL_CONST_P(obj)) {
+ struct rof_data data;
- if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
- obj = (VALUE)DATA_PTR(obj);
- }
+ if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
+ obj = (VALUE)DATA_PTR(obj);
+ }
- data.refs = st_init_numtable();
- data.internals = rb_ary_new();
+ data.refs = rb_obj_hide(rb_ident_hash_new());
+ data.values = rb_ary_new();
- rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data);
+ rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data);
- st_foreach(data.refs, collect_values, (st_data_t)ret);
- return ret;
+ return data.values;
}
else {
- return Qnil;
+ return Qnil;
}
}
@@ -804,26 +627,26 @@ reachable_object_from_root_i(const char *category, VALUE obj, void *ptr)
VALUE category_objects;
if (category == data->last_category) {
- category_str = data->last_category_str;
- category_objects = data->last_category_objects;
+ category_str = data->last_category_str;
+ category_objects = data->last_category_objects;
}
else {
- data->last_category = category;
- category_str = data->last_category_str = rb_str_new2(category);
- category_objects = data->last_category_objects = rb_ident_hash_new();
- if (!NIL_P(rb_hash_lookup(data->categories, category_str))) {
- rb_bug("reachable_object_from_root_i: category should insert at once");
- }
- rb_hash_aset(data->categories, category_str, category_objects);
+ data->last_category = category;
+ category_str = data->last_category_str = rb_str_new2(category);
+ category_objects = data->last_category_objects = rb_ident_hash_new();
+ if (!NIL_P(rb_hash_lookup(data->categories, category_str))) {
+ rb_bug("reachable_object_from_root_i: category should insert at once");
+ }
+ rb_hash_aset(data->categories, category_str, category_objects);
}
- if (rb_objspace_markable_object_p(obj) &&
- obj != data->categories &&
- obj != data->last_category_objects) {
- if (rb_objspace_internal_object_p(obj)) {
- obj = iow_newobj(obj);
- }
- rb_hash_aset(category_objects, obj, obj);
+ if (!rb_objspace_garbage_object_p(obj) &&
+ obj != data->categories &&
+ obj != data->last_category_objects) {
+ if (rb_objspace_internal_object_p(obj)) {
+ obj = iow_newobj(obj);
+ }
+ rb_hash_aset(category_objects, obj, obj);
}
}
@@ -859,13 +682,14 @@ static VALUE
wrap_klass_iow(VALUE klass)
{
if (!RTEST(klass)) {
- return Qnil;
+ return Qnil;
}
- else if (RB_TYPE_P(klass, T_ICLASS)) {
- return iow_newobj(klass);
+ else if (RB_TYPE_P(klass, T_ICLASS) ||
+ CLASS_OF(klass) == Qfalse /* hidden object */) {
+ return iow_newobj(klass);
}
else {
- return klass;
+ return klass;
}
}
@@ -884,11 +708,16 @@ objspace_internal_class_of(VALUE self, VALUE obj)
VALUE klass;
if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
- obj = (VALUE)DATA_PTR(obj);
+ obj = (VALUE)DATA_PTR(obj);
}
- klass = CLASS_OF(obj);
- return wrap_klass_iow(klass);
+ if (RB_TYPE_P(obj, T_IMEMO)) {
+ return Qnil;
+ }
+ else {
+ klass = CLASS_OF(obj);
+ return wrap_klass_iow(klass);
+ }
}
/*
@@ -906,17 +735,17 @@ objspace_internal_super_of(VALUE self, VALUE obj)
VALUE super;
if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
- obj = (VALUE)DATA_PTR(obj);
+ obj = (VALUE)DATA_PTR(obj);
}
switch (OBJ_BUILTIN_TYPE(obj)) {
case T_MODULE:
case T_CLASS:
case T_ICLASS:
- super = RCLASS_SUPER(obj);
- break;
+ super = rb_class_super_of(obj);
+ break;
default:
- rb_raise(rb_eArgError, "class or module is expected");
+ rb_raise(rb_eArgError, "class or module is expected");
}
return wrap_klass_iow(super);
@@ -934,7 +763,7 @@ void Init_objspace_dump(VALUE rb_mObjSpace);
*
* You need to <code>require 'objspace'</code> to use this extension module.
*
- * Generally, you *SHOULD NOT* use this library if you do not know
+ * Generally, you *SHOULD* *NOT* use this library if you do not know
* about the MRI implementation. Mainly, this library is for (memory)
* profiler developers and MRI developers who need to know about MRI
* memory usage.
@@ -955,7 +784,6 @@ Init_objspace(void)
rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1);
rb_define_module_function(rb_mObjSpace, "count_symbols", count_symbols, -1);
- rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1);
rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1);
rb_define_module_function(rb_mObjSpace, "count_imemo_objects", count_imemo_objects, -1);
@@ -974,10 +802,11 @@ Init_objspace(void)
*
* You can use the #type method to check the type of the internal object.
*/
- rb_mInternalObjectWrapper = rb_define_class_under(rb_mObjSpace, "InternalObjectWrapper", rb_cObject);
- rb_define_method(rb_mInternalObjectWrapper, "type", iow_type, 0);
- rb_define_method(rb_mInternalObjectWrapper, "inspect", iow_inspect, 0);
- rb_define_method(rb_mInternalObjectWrapper, "internal_object_id", iow_internal_object_id, 0);
+ rb_cInternalObjectWrapper = rb_define_class_under(rb_mObjSpace, "InternalObjectWrapper", rb_cObject);
+ rb_undef_alloc_func(rb_cInternalObjectWrapper);
+ rb_define_method(rb_cInternalObjectWrapper, "type", iow_type, 0);
+ rb_define_method(rb_cInternalObjectWrapper, "inspect", iow_inspect, 0);
+ rb_define_method(rb_cInternalObjectWrapper, "internal_object_id", iow_internal_object_id, 0);
Init_object_tracing(rb_mObjSpace);
Init_objspace_dump(rb_mObjSpace);
diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c
index 7dcee589bf..da64698346 100644
--- a/ext/objspace/objspace_dump.c
+++ b/ext/objspace/objspace_dump.c
@@ -12,46 +12,189 @@
**********************************************************************/
-#include "ruby/io.h"
+#include "id_table.h"
#include "internal.h"
-#include "ruby/debug.h"
-#include "gc.h"
+#include "internal/array.h"
+#include "internal/class.h"
+#include "internal/gc.h"
+#include "internal/hash.h"
+#include "internal/io.h"
+#include "internal/string.h"
+#include "internal/sanitizers.h"
+#include "symbol.h"
+#include "shape.h"
#include "node.h"
-#include "vm_core.h"
#include "objspace.h"
+#include "ruby/debug.h"
+#include "ruby/util.h"
+#include "ruby/io.h"
+#include "vm_callinfo.h"
+#include "vm_sync.h"
+
+RUBY_EXTERN const char ruby_hexdigits[];
-static VALUE sym_output, sym_stdout, sym_string, sym_file;
-static VALUE sym_full;
+#define BUFFER_CAPACITY 4096
struct dump_config {
- VALUE type;
- FILE *stream;
+ VALUE given_output;
+ VALUE output_io;
VALUE string;
+ FILE *stream;
const char *root_category;
VALUE cur_obj;
VALUE cur_obj_klass;
+ size_t cur_page_slot_size;
size_t cur_obj_references;
unsigned int roots: 1;
unsigned int full_heap: 1;
+ unsigned int partial_dump;
+ size_t since;
+ size_t shapes_since;
+ unsigned long buffer_len;
+ char buffer[BUFFER_CAPACITY];
};
-PRINTF_ARGS(static void dump_append(struct dump_config *, const char *, ...), 2, 3);
static void
-dump_append(struct dump_config *dc, const char *format, ...)
+dump_flush(struct dump_config *dc)
{
- va_list vl;
- va_start(vl, format);
+ if (dc->buffer_len) {
+ if (dc->stream) {
+ size_t written = fwrite(dc->buffer, sizeof(dc->buffer[0]), dc->buffer_len, dc->stream);
+ if (written < dc->buffer_len) {
+ MEMMOVE(dc->buffer, dc->buffer + written, char, dc->buffer_len - written);
+ dc->buffer_len -= written;
+ return;
+ }
+ }
+ else if (dc->string) {
+ rb_str_cat(dc->string, dc->buffer, dc->buffer_len);
+ }
+ dc->buffer_len = 0;
+ }
+}
- if (dc->stream) {
- vfprintf(dc->stream, format, vl);
+static inline void
+buffer_ensure_capa(struct dump_config *dc, unsigned long requested)
+{
+ RUBY_ASSERT(requested <= BUFFER_CAPACITY);
+ if (requested + dc->buffer_len >= BUFFER_CAPACITY) {
+ dump_flush(dc);
+ if (requested + dc->buffer_len >= BUFFER_CAPACITY) {
+ rb_raise(rb_eIOError, "full buffer");
+ }
+ }
+}
+
+static void
+buffer_append(struct dump_config *dc, const char *cstr, unsigned long len)
+{
+ if (LIKELY(len > 0)) {
+ buffer_ensure_capa(dc, len);
+ MEMCPY(dc->buffer + dc->buffer_len, cstr, char, len);
+ dc->buffer_len += len;
+ }
+}
+
+# define dump_append(dc, str) buffer_append(dc, (str), (long)strlen(str))
+
+static void
+dump_append_ld(struct dump_config *dc, const long number)
+{
+ const unsigned int width = DECIMAL_SIZE_OF_BITS(sizeof(number) * CHAR_BIT - 1) + 2;
+ buffer_ensure_capa(dc, width);
+ unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "%ld", number);
+ RUBY_ASSERT(required <= width);
+ dc->buffer_len += required;
+}
+
+static void
+dump_append_lu(struct dump_config *dc, const unsigned long number)
+{
+ const unsigned int width = DECIMAL_SIZE_OF_BITS(sizeof(number) * CHAR_BIT) + 1;
+ buffer_ensure_capa(dc, width);
+ unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "%lu", number);
+ RUBY_ASSERT(required <= width);
+ dc->buffer_len += required;
+}
+
+static void
+dump_append_g(struct dump_config *dc, const double number)
+{
+ unsigned long capa_left = BUFFER_CAPACITY - dc->buffer_len;
+ unsigned long required = snprintf(dc->buffer + dc->buffer_len, capa_left, "%#g", number);
+
+ if (required >= capa_left) {
+ buffer_ensure_capa(dc, required);
+ capa_left = BUFFER_CAPACITY - dc->buffer_len;
+ snprintf(dc->buffer + dc->buffer_len, capa_left, "%#g", number);
+ }
+ dc->buffer_len += required;
+}
+
+static void
+dump_append_d(struct dump_config *dc, const int number)
+{
+ const unsigned int width = DECIMAL_SIZE_OF_BITS(sizeof(number) * CHAR_BIT - 1) + 2;
+ buffer_ensure_capa(dc, width);
+ unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "%d", number);
+ RUBY_ASSERT(required <= width);
+ dc->buffer_len += required;
+}
+
+static void
+dump_append_sizet(struct dump_config *dc, const size_t number)
+{
+ const unsigned int width = DECIMAL_SIZE_OF_BITS(sizeof(number) * CHAR_BIT) + 1;
+ buffer_ensure_capa(dc, width);
+ unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "%"PRIuSIZE, number);
+ RUBY_ASSERT(required <= width);
+ dc->buffer_len += required;
+}
+
+static void
+dump_append_c(struct dump_config *dc, unsigned char c)
+{
+ if (c <= 0x1f) {
+ const unsigned int width = rb_strlen_lit("\\u0000") + 1;
+ buffer_ensure_capa(dc, width);
+ unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "\\u00%02x", c);
+ RUBY_ASSERT(required <= width);
+ dc->buffer_len += required;
+ }
+ else {
+ buffer_ensure_capa(dc, 1);
+ dc->buffer[dc->buffer_len] = c;
+ dc->buffer_len++;
}
- else if (dc->string)
- rb_str_vcatf(dc->string, format, vl);
+}
- va_end(vl);
+static void
+dump_append_ptr(struct dump_config *dc, VALUE ref)
+{
+ char buffer[roomof(sizeof(VALUE) * CHAR_BIT, 4) + rb_strlen_lit("\"0x\"")];
+ char *buffer_start, *buffer_end;
+
+ buffer_start = buffer_end = &buffer[sizeof(buffer)];
+ *--buffer_start = '"';
+ while (ref) {
+ *--buffer_start = ruby_hexdigits[ref & 0xF];
+ ref >>= 4;
+ }
+ *--buffer_start = 'x';
+ *--buffer_start = '0';
+ *--buffer_start = '"';
+ buffer_append(dc, buffer_start, buffer_end - buffer_start);
}
static void
+dump_append_ref(struct dump_config *dc, VALUE ref)
+{
+ RUBY_ASSERT(ref > 0);
+ dump_append_ptr(dc, ref);
+}
+
+
+static void
dump_append_string_value(struct dump_config *dc, VALUE obj)
{
long i;
@@ -60,35 +203,37 @@ dump_append_string_value(struct dump_config *dc, VALUE obj)
dump_append(dc, "\"");
for (i = 0, value = RSTRING_PTR(obj); i < RSTRING_LEN(obj); i++) {
- switch ((c = value[i])) {
- case '\\':
- case '"':
- dump_append(dc, "\\%c", c);
- break;
- case '\0':
- dump_append(dc, "\\u0000");
- break;
- case '\b':
- dump_append(dc, "\\b");
- break;
- case '\t':
- dump_append(dc, "\\t");
- break;
- case '\f':
- dump_append(dc, "\\f");
- break;
- case '\n':
- dump_append(dc, "\\n");
- break;
- case '\r':
- dump_append(dc, "\\r");
- break;
- default:
- if (c <= 0x1f)
- dump_append(dc, "\\u%04d", c);
- else
- dump_append(dc, "%c", c);
- }
+ switch ((c = value[i])) {
+ case '\\':
+ dump_append(dc, "\\\\");
+ break;
+ case '"':
+ dump_append(dc, "\\\"");
+ break;
+ case '\0':
+ dump_append(dc, "\\u0000");
+ break;
+ case '\b':
+ dump_append(dc, "\\b");
+ break;
+ case '\t':
+ dump_append(dc, "\\t");
+ break;
+ case '\f':
+ dump_append(dc, "\\f");
+ break;
+ case '\n':
+ dump_append(dc, "\\n");
+ break;
+ case '\r':
+ dump_append(dc, "\\r");
+ break;
+ case '\177':
+ dump_append(dc, "\\u007f");
+ break;
+ default:
+ dump_append_c(dc, c);
+ }
}
dump_append(dc, "\"");
}
@@ -106,33 +251,34 @@ obj_type(VALUE obj)
{
switch (BUILTIN_TYPE(obj)) {
#define CASE_TYPE(type) case T_##type: return #type
- CASE_TYPE(NONE);
- CASE_TYPE(NIL);
- CASE_TYPE(OBJECT);
- CASE_TYPE(CLASS);
- CASE_TYPE(ICLASS);
- CASE_TYPE(MODULE);
- CASE_TYPE(FLOAT);
- CASE_TYPE(STRING);
- CASE_TYPE(REGEXP);
- CASE_TYPE(ARRAY);
- CASE_TYPE(HASH);
- CASE_TYPE(STRUCT);
- CASE_TYPE(BIGNUM);
- CASE_TYPE(FILE);
- CASE_TYPE(FIXNUM);
- CASE_TYPE(TRUE);
- CASE_TYPE(FALSE);
- CASE_TYPE(DATA);
- CASE_TYPE(MATCH);
- CASE_TYPE(SYMBOL);
- CASE_TYPE(RATIONAL);
- CASE_TYPE(COMPLEX);
- CASE_TYPE(IMEMO);
- CASE_TYPE(UNDEF);
- CASE_TYPE(NODE);
- CASE_TYPE(ZOMBIE);
+ CASE_TYPE(NONE);
+ CASE_TYPE(NIL);
+ CASE_TYPE(OBJECT);
+ CASE_TYPE(CLASS);
+ CASE_TYPE(ICLASS);
+ CASE_TYPE(MODULE);
+ CASE_TYPE(FLOAT);
+ CASE_TYPE(STRING);
+ CASE_TYPE(REGEXP);
+ CASE_TYPE(ARRAY);
+ CASE_TYPE(HASH);
+ CASE_TYPE(STRUCT);
+ CASE_TYPE(BIGNUM);
+ CASE_TYPE(FILE);
+ CASE_TYPE(FIXNUM);
+ CASE_TYPE(TRUE);
+ CASE_TYPE(FALSE);
+ CASE_TYPE(DATA);
+ CASE_TYPE(MATCH);
+ CASE_TYPE(SYMBOL);
+ CASE_TYPE(RATIONAL);
+ CASE_TYPE(COMPLEX);
+ CASE_TYPE(IMEMO);
+ CASE_TYPE(UNDEF);
+ CASE_TYPE(NODE);
+ CASE_TYPE(ZOMBIE);
#undef CASE_TYPE
+ default: break;
}
return "UNKNOWN";
}
@@ -141,25 +287,25 @@ static void
dump_append_special_const(struct dump_config *dc, VALUE value)
{
if (value == Qtrue) {
- dump_append(dc, "true");
+ dump_append(dc, "true");
}
else if (value == Qfalse) {
- dump_append(dc, "false");
+ dump_append(dc, "false");
}
else if (value == Qnil) {
- dump_append(dc, "null");
+ dump_append(dc, "null");
}
else if (FIXNUM_P(value)) {
- dump_append(dc, "%ld", FIX2LONG(value));
+ dump_append_ld(dc, FIX2LONG(value));
}
else if (FLONUM_P(value)) {
- dump_append(dc, "%#g", RFLOAT_VALUE(value));
+ dump_append_g(dc, RFLOAT_VALUE(value));
}
else if (SYMBOL_P(value)) {
- dump_append_symbol_value(dc, value);
+ dump_append_symbol_value(dc, value);
}
else {
- dump_append(dc, "{}");
+ dump_append(dc, "{}");
}
}
@@ -169,175 +315,352 @@ reachable_object_i(VALUE ref, void *data)
struct dump_config *dc = (struct dump_config *)data;
if (dc->cur_obj_klass == ref)
- return;
+ return;
- if (dc->cur_obj_references == 0)
- dump_append(dc, ", \"references\":[\"%#"PRIxVALUE"\"", ref);
- else
- dump_append(dc, ", \"%#"PRIxVALUE"\"", ref);
+ if (dc->cur_obj_references == 0) {
+ dump_append(dc, ", \"references\":[");
+ dump_append_ref(dc, ref);
+ }
+ else {
+ dump_append(dc, ", ");
+ dump_append_ref(dc, ref);
+ }
dc->cur_obj_references++;
}
+static bool
+dump_string_ascii_only(const char *str, long size)
+{
+ for (long i = 0; i < size; i++) {
+ if (str[i] & 0x80) {
+ return false;
+ }
+ }
+ return true;
+}
+
static void
dump_append_string_content(struct dump_config *dc, VALUE obj)
{
- dump_append(dc, ", \"bytesize\":%ld", RSTRING_LEN(obj));
- if (!STR_EMBED_P(obj) && !STR_SHARED_P(obj) && (long)rb_str_capacity(obj) != RSTRING_LEN(obj))
- dump_append(dc, ", \"capacity\":%"PRIuSIZE, rb_str_capacity(obj));
+ dump_append(dc, ", \"bytesize\":");
+ dump_append_ld(dc, RSTRING_LEN(obj));
+ if (!STR_EMBED_P(obj) && !STR_SHARED_P(obj) && (long)rb_str_capacity(obj) != RSTRING_LEN(obj)) {
+ dump_append(dc, ", \"capacity\":");
+ dump_append_sizet(dc, rb_str_capacity(obj));
+ }
- if (is_ascii_string(obj)) {
- dump_append(dc, ", \"value\":");
- dump_append_string_value(dc, obj);
+ if (RSTRING_LEN(obj) && rb_enc_asciicompat(rb_enc_from_index(ENCODING_GET(obj)))) {
+ int cr = ENC_CODERANGE(obj);
+ if (cr == RUBY_ENC_CODERANGE_UNKNOWN) {
+ if (dump_string_ascii_only(RSTRING_PTR(obj), RSTRING_LEN(obj))) {
+ cr = RUBY_ENC_CODERANGE_7BIT;
+ }
+ }
+ if (cr == RUBY_ENC_CODERANGE_7BIT) {
+ dump_append(dc, ", \"value\":");
+ dump_append_string_value(dc, obj);
+ }
}
}
-static const char *
-imemo_name(int imemo)
+static inline void
+dump_append_id(struct dump_config *dc, ID id)
{
- switch(imemo) {
-#define TYPE_STR(t) case(imemo_##t): return #t
- TYPE_STR(env);
- TYPE_STR(cref);
- TYPE_STR(svar);
- TYPE_STR(throw_data);
- TYPE_STR(ifunc);
- TYPE_STR(memo);
- TYPE_STR(ment);
- TYPE_STR(iseq);
- TYPE_STR(tmpbuf);
- TYPE_STR(ast);
- TYPE_STR(parser_strterm);
- default:
- return "unknown";
-#undef TYPE_STR
+ VALUE str = rb_sym2str(ID2SYM(id));
+ if (RTEST(str)) {
+ dump_append_string_value(dc, str);
+ }
+ else {
+ dump_append(dc, "\"ID_INTERNAL(");
+ dump_append_sizet(dc, rb_id_to_serial(id));
+ dump_append(dc, ")\"");
}
}
+
static void
dump_object(VALUE obj, struct dump_config *dc)
{
size_t memsize;
- struct allocation_info *ainfo;
+ struct allocation_info *ainfo = objspace_lookup_allocation_info(obj);
rb_io_t *fptr;
- ID flags[RB_OBJ_GC_FLAGS_MAX];
- size_t n, i;
+ ID mid;
if (SPECIAL_CONST_P(obj)) {
- dump_append_special_const(dc, obj);
- return;
+ dump_append_special_const(dc, obj);
+ return;
}
dc->cur_obj = obj;
dc->cur_obj_references = 0;
- dc->cur_obj_klass = BUILTIN_TYPE(obj) == T_NODE ? 0 : RBASIC_CLASS(obj);
+ if (BUILTIN_TYPE(obj) == T_NODE || (BUILTIN_TYPE(obj) == T_IMEMO && !IMEMO_TYPE_P(obj, imemo_fields))) {
+ dc->cur_obj_klass = 0;
+ }
+ else {
+ dc->cur_obj_klass = RBASIC_CLASS(obj);
+ }
+
+ if (dc->partial_dump && (!ainfo || ainfo->generation < dc->since)) {
+ return;
+ }
if (dc->cur_obj == dc->string)
- return;
+ return;
+
+ dump_append(dc, "{\"address\":");
+ dump_append_ref(dc, obj);
+
+ dump_append(dc, ", \"type\":\"");
+ dump_append(dc, obj_type(obj));
+ dump_append(dc, "\"");
+
+ if (BUILTIN_TYPE(obj) != T_IMEMO || IMEMO_TYPE_P(obj, imemo_fields)) {
+ size_t shape_id = rb_obj_shape_id(obj) & SHAPE_ID_OFFSET_MASK;
+ dump_append(dc, ", \"shape_id\":");
+ dump_append_sizet(dc, shape_id);
+ }
- dump_append(dc, "{\"address\":\"%#"PRIxVALUE"\", \"type\":\"%s\"", obj, obj_type(obj));
+ dump_append(dc, ", \"slot_size\":");
+ dump_append_sizet(dc, dc->cur_page_slot_size);
- if (dc->cur_obj_klass)
- dump_append(dc, ", \"class\":\"%#"PRIxVALUE"\"", dc->cur_obj_klass);
+ if (dc->cur_obj_klass) {
+ dump_append(dc, ", \"class\":");
+ dump_append_ref(dc, dc->cur_obj_klass);
+ }
if (rb_obj_frozen_p(obj))
- dump_append(dc, ", \"frozen\":true");
+ dump_append(dc, ", \"frozen\":true");
switch (BUILTIN_TYPE(obj)) {
case T_NONE:
- dump_append(dc, "}\n");
- return;
+ dump_append(dc, "}\n");
+ return;
case T_IMEMO:
- dump_append(dc, ", \"imemo_type\":\"%s\"", imemo_name(imemo_type(obj)));
- break;
+ dump_append(dc, ", \"imemo_type\":\"");
+ dump_append(dc, rb_imemo_name(imemo_type(obj)));
+ dump_append(dc, "\"");
+
+ switch (imemo_type(obj)) {
+ case imemo_callinfo:
+ mid = vm_ci_mid((const struct rb_callinfo *)obj);
+ if (mid != 0) {
+ dump_append(dc, ", \"mid\":");
+ dump_append_id(dc, mid);
+ }
+ break;
+
+ case imemo_callcache:
+ {
+ VALUE klass = ((const struct rb_callcache *)obj)->klass;
+ if (klass != Qundef) {
+ mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id;
+ if (mid != 0) {
+ dump_append(dc, ", \"called_id\":");
+ dump_append_id(dc, mid);
+
+ }
+
+ dump_append(dc, ", \"receiver_class\":");
+ dump_append_ref(dc, klass);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
case T_SYMBOL:
- dump_append_string_content(dc, rb_sym2str(obj));
- break;
+ dump_append_string_content(dc, rb_sym2str(obj));
+ break;
case T_STRING:
- if (STR_EMBED_P(obj))
- dump_append(dc, ", \"embedded\":true");
- if (is_broken_string(obj))
- dump_append(dc, ", \"broken\":true");
- if (FL_TEST(obj, RSTRING_FSTR))
- dump_append(dc, ", \"fstring\":true");
- if (STR_SHARED_P(obj))
- dump_append(dc, ", \"shared\":true");
- else
- dump_append_string_content(dc, obj);
-
- if (!ENCODING_IS_ASCII8BIT(obj))
- dump_append(dc, ", \"encoding\":\"%s\"", rb_enc_name(rb_enc_from_index(ENCODING_GET(obj))));
- break;
+ if (STR_EMBED_P(obj))
+ dump_append(dc, ", \"embedded\":true");
+ if (FL_TEST(obj, RSTRING_FSTR))
+ dump_append(dc, ", \"fstring\":true");
+ if (CHILLED_STRING_P(obj))
+ dump_append(dc, ", \"chilled\":true");
+ if (STR_SHARED_P(obj))
+ dump_append(dc, ", \"shared\":true");
+ else
+ dump_append_string_content(dc, obj);
+
+ if (!ENCODING_IS_ASCII8BIT(obj)) {
+ dump_append(dc, ", \"encoding\":\"");
+ dump_append(dc, rb_enc_name(rb_enc_from_index(ENCODING_GET(obj))));
+ dump_append(dc, "\"");
+ }
+
+ dump_append(dc, ", \"coderange\":\"");
+ switch (RB_ENC_CODERANGE(obj)) {
+ case RUBY_ENC_CODERANGE_UNKNOWN:
+ dump_append(dc, "unknown");
+ break;
+ case RUBY_ENC_CODERANGE_7BIT:
+ dump_append(dc, "7bit");
+ break;
+ case RUBY_ENC_CODERANGE_VALID:
+ dump_append(dc, "valid");
+ break;
+ case RUBY_ENC_CODERANGE_BROKEN:
+ dump_append(dc, "broken");
+ break;
+ }
+ dump_append(dc, "\"");
+
+ if (RB_ENC_CODERANGE(obj) == RUBY_ENC_CODERANGE_BROKEN)
+ dump_append(dc, ", \"broken\":true");
+
+ break;
case T_HASH:
- dump_append(dc, ", \"size\":%"PRIuSIZE, (size_t)RHASH_SIZE(obj));
- if (FL_TEST(obj, HASH_PROC_DEFAULT))
- dump_append(dc, ", \"default\":\"%#"PRIxVALUE"\"", RHASH_IFNONE(obj));
- break;
+ dump_append(dc, ", \"size\":");
+ dump_append_sizet(dc, (size_t)RHASH_SIZE(obj));
+ if (FL_TEST(obj, RHASH_PROC_DEFAULT)) {
+ dump_append(dc, ", \"default\":");
+ dump_append_ref(dc, RHASH_IFNONE(obj));
+ }
+ break;
case T_ARRAY:
- dump_append(dc, ", \"length\":%ld", RARRAY_LEN(obj));
- if (RARRAY_LEN(obj) > 0 && FL_TEST(obj, ELTS_SHARED))
- dump_append(dc, ", \"shared\":true");
- if (RARRAY_LEN(obj) > 0 && FL_TEST(obj, RARRAY_EMBED_FLAG))
- dump_append(dc, ", \"embedded\":true");
- break;
+ dump_append(dc, ", \"length\":");
+ dump_append_ld(dc, RARRAY_LEN(obj));
+ if (RARRAY_LEN(obj) > 0 && FL_TEST(obj, RARRAY_SHARED_FLAG))
+ dump_append(dc, ", \"shared\":true");
+ if (FL_TEST(obj, RARRAY_EMBED_FLAG))
+ dump_append(dc, ", \"embedded\":true");
+ break;
+
+ case T_ICLASS:
+ if (rb_class_get_superclass(obj)) {
+ dump_append(dc, ", \"superclass\":");
+ dump_append_ref(dc, rb_class_get_superclass(obj));
+ }
+ break;
case T_CLASS:
+ dump_append(dc, ", \"variation_count\":");
+ dump_append_d(dc, rb_class_variation_count(obj));
+
case T_MODULE:
- if (dc->cur_obj_klass)
- dump_append(dc, ", \"name\":\"%s\"", rb_class2name(obj));
- break;
+ if (rb_class_get_superclass(obj)) {
+ dump_append(dc, ", \"superclass\":");
+ dump_append_ref(dc, rb_class_get_superclass(obj));
+ }
+
+ if (dc->cur_obj_klass) {
+ VALUE mod_name = rb_mod_name(obj);
+ if (!NIL_P(mod_name)) {
+ dump_append(dc, ", \"name\":");
+ dump_append_string_value(dc, mod_name);
+ }
+ else {
+ VALUE real_mod_name = rb_mod_name(rb_class_real(obj));
+ if (RTEST(real_mod_name)) {
+ dump_append(dc, ", \"real_class_name\":\"");
+ dump_append(dc, RSTRING_PTR(real_mod_name));
+ dump_append(dc, "\"");
+ }
+ }
+
+ if (rb_class_singleton_p(obj)) {
+ dump_append(dc, ", \"singleton\":true");
+ }
+ }
+ break;
case T_DATA:
- if (RTYPEDDATA_P(obj))
- dump_append(dc, ", \"struct\":\"%s\"", RTYPEDDATA_TYPE(obj)->wrap_struct_name);
- break;
+ if (RTYPEDDATA_P(obj)) {
+ dump_append(dc, ", \"struct\":\"");
+ dump_append(dc, RTYPEDDATA_TYPE(obj)->wrap_struct_name);
+ dump_append(dc, "\"");
+ }
+ break;
case T_FLOAT:
- dump_append(dc, ", \"value\":\"%g\"", RFLOAT_VALUE(obj));
- break;
+ dump_append(dc, ", \"value\":\"");
+ dump_append_g(dc, RFLOAT_VALUE(obj));
+ dump_append(dc, "\"");
+ break;
case T_OBJECT:
- dump_append(dc, ", \"ivars\":%u", ROBJECT_NUMIV(obj));
- break;
+ if (!FL_TEST_RAW(obj, ROBJECT_HEAP)) {
+ dump_append(dc, ", \"embedded\":true");
+ }
+
+ dump_append(dc, ", \"ivars\":");
+ dump_append_lu(dc, ROBJECT_FIELDS_COUNT(obj));
+ if (rb_shape_obj_too_complex_p(obj)) {
+ dump_append(dc, ", \"too_complex_shape\":true");
+ }
+ break;
case T_FILE:
- fptr = RFILE(obj)->fptr;
- if (fptr)
- dump_append(dc, ", \"fd\":%d", fptr->fd);
- break;
+ fptr = RFILE(obj)->fptr;
+ if (fptr) {
+ dump_append(dc, ", \"fd\":");
+ dump_append_d(dc, fptr->fd);
+ }
+ break;
case T_ZOMBIE:
- dump_append(dc, "}\n");
- return;
+ dump_append(dc, "}\n");
+ return;
+
+ default:
+ break;
}
rb_objspace_reachable_objects_from(obj, reachable_object_i, dc);
if (dc->cur_obj_references > 0)
- dump_append(dc, "]");
+ dump_append(dc, "]");
+
+ if (ainfo) {
+ if (ainfo->path) {
+ dump_append(dc, ", \"file\":\"");
+ dump_append(dc, ainfo->path);
+ dump_append(dc, "\"");
+ }
+ if (ainfo->line) {
+ dump_append(dc, ", \"line\":");
+ dump_append_lu(dc, ainfo->line);
+ }
+ if (RTEST(ainfo->mid)) {
+ VALUE m = rb_sym2str(ainfo->mid);
+ dump_append(dc, ", \"method\":");
+ dump_append_string_value(dc, m);
+ }
+ dump_append(dc, ", \"generation\":");
+ dump_append_sizet(dc, ainfo->generation);
+ }
- if ((ainfo = objspace_lookup_allocation_info(obj))) {
- dump_append(dc, ", \"file\":\"%s\", \"line\":%lu", ainfo->path, ainfo->line);
- if (RTEST(ainfo->mid)) {
- VALUE m = rb_sym2str(ainfo->mid);
- dump_append(dc, ", \"method\":\"%s\"", RSTRING_PTR(m));
- }
- dump_append(dc, ", \"generation\":%"PRIuSIZE, ainfo->generation);
+ if ((memsize = rb_obj_memsize_of(obj)) > 0) {
+ dump_append(dc, ", \"memsize\":");
+ dump_append_sizet(dc, memsize);
}
- if ((memsize = rb_obj_memsize_of(obj)) > 0)
- dump_append(dc, ", \"memsize\":%"PRIuSIZE, memsize);
+ struct rb_gc_object_metadata_entry *gc_metadata = rb_gc_object_metadata(obj);
+ for (int i = 0; gc_metadata[i].name != 0; i++) {
+ if (i == 0) {
+ dump_append(dc, ", \"flags\":{");
+ }
+ else {
+ dump_append(dc, ", ");
+ }
+
+ dump_append(dc, "\"");
+ dump_append(dc, rb_id2name(gc_metadata[i].name));
+ dump_append(dc, "\":");
+ dump_append_special_const(dc, gc_metadata[i].val);
+ }
- if ((n = rb_obj_gc_flags(obj, flags, sizeof(flags))) > 0) {
- dump_append(dc, ", \"flags\":{");
- for (i=0; i<n; i++) {
- dump_append(dc, "\"%s\":true", rb_id2name(flags[i]));
- if (i != n-1) dump_append(dc, ", ");
- }
- dump_append(dc, "}");
+ /* If rb_gc_object_metadata had any entries, we need to close the opening
+ * `"flags":{`. */
+ if (gc_metadata[0].name != 0) {
+ dump_append(dc, "}");
}
dump_append(dc, "}\n");
@@ -349,8 +672,16 @@ heap_i(void *vstart, void *vend, size_t stride, void *data)
struct dump_config *dc = (struct dump_config *)data;
VALUE v = (VALUE)vstart;
for (; v != (VALUE)vend; v += stride) {
- if (dc->full_heap || RBASIC(v)->flags)
- dump_object(v, dc);
+ void *ptr = rb_asan_poisoned_object_p(v);
+ rb_asan_unpoison_object(v, false);
+ dc->cur_page_slot_size = stride;
+
+ if (dc->full_heap || RBASIC(v)->flags)
+ dump_object(v, dc);
+
+ if (ptr) {
+ rb_asan_poison_object(v);
+ }
}
return 0;
}
@@ -361,138 +692,222 @@ root_obj_i(const char *category, VALUE obj, void *data)
struct dump_config *dc = (struct dump_config *)data;
if (dc->root_category != NULL && category != dc->root_category)
- dump_append(dc, "]}\n");
- if (dc->root_category == NULL || category != dc->root_category)
- dump_append(dc, "{\"type\":\"ROOT\", \"root\":\"%s\", \"references\":[\"%#"PRIxVALUE"\"", category, obj);
- else
- dump_append(dc, ", \"%#"PRIxVALUE"\"", obj);
+ dump_append(dc, "]}\n");
+ if (dc->root_category == NULL || category != dc->root_category) {
+ dump_append(dc, "{\"type\":\"ROOT\", \"root\":\"");
+ dump_append(dc, category);
+ dump_append(dc, "\", \"references\":[");
+ dump_append_ref(dc, obj);
+ }
+ else {
+ dump_append(dc, ", ");
+ dump_append_ref(dc, obj);
+ }
dc->root_category = category;
dc->roots = 1;
}
-static VALUE
-dump_output(struct dump_config *dc, VALUE opts, VALUE output, const char *filename)
+static void
+dump_output(struct dump_config *dc, VALUE output, VALUE full, VALUE since, VALUE shapes)
{
- VALUE tmp;
-
+ dc->given_output = output;
dc->full_heap = 0;
+ dc->buffer_len = 0;
- if (RTEST(opts)) {
- output = rb_hash_aref(opts, sym_output);
-
- if (Qtrue == rb_hash_lookup2(opts, sym_full, Qfalse))
- dc->full_heap = 1;
- }
-
- if (output == sym_stdout) {
- dc->stream = stdout;
- dc->string = Qnil;
+ if (TYPE(output) == T_STRING) {
+ dc->stream = NULL;
+ dc->string = output;
}
- else if (output == sym_file) {
- rb_io_t *fptr;
- rb_require("tempfile");
- tmp = rb_assoc_new(rb_str_new_cstr(filename), rb_str_new_cstr(".json"));
- tmp = rb_funcallv(rb_path2class("Tempfile"), rb_intern("create"), 1, &tmp);
- io:
- dc->string = rb_io_get_write_io(tmp);
- rb_io_flush(dc->string);
- GetOpenFile(dc->string, fptr);
- dc->stream = rb_io_stdio_file(fptr);
+ else {
+ rb_io_t *fptr;
+ // Output should be an IO, typecheck and get a FILE* for writing.
+ // We cannot write with the usual IO code here because writes
+ // interleave with calls to rb_gc_mark(). The usual IO code can
+ // cause a thread switch, raise exceptions, and even run arbitrary
+ // ruby code through the fiber scheduler.
+ //
+ // Mark functions generally can't handle these possibilities so
+ // the usual IO code is unsafe in this context. (For example,
+ // there are many ways to crash when ruby code runs and mutates
+ // the execution context while rb_execution_context_mark() is in
+ // progress.)
+ //
+ // Using FILE* isn't perfect, but it avoids the most acute problems.
+ output = rb_io_get_io(output);
+ dc->output_io = rb_io_get_write_io(output);
+ rb_io_flush(dc->output_io);
+ GetOpenFile(dc->output_io, fptr);
+ dc->stream = rb_io_stdio_file(fptr);
+ dc->string = Qfalse;
}
- else if (output == sym_string) {
- dc->string = rb_str_new_cstr("");
+
+ if (full == Qtrue) {
+ dc->full_heap = 1;
}
- else if (!NIL_P(tmp = rb_io_check_io(output))) {
- output = sym_file;
- goto io;
+
+ if (RTEST(since)) {
+ dc->partial_dump = 1;
+ dc->since = NUM2SIZET(since);
}
else {
- rb_raise(rb_eArgError, "wrong output option: %"PRIsVALUE, output);
+ dc->partial_dump = 0;
}
- return output;
+
+ dc->shapes_since = RTEST(shapes) ? NUM2SIZET(shapes) : 0;
}
static VALUE
-dump_result(struct dump_config *dc, VALUE output)
+dump_result(struct dump_config *dc)
{
- if (output == sym_string) {
- return rb_str_resurrect(dc->string);
- }
- else if (output == sym_file) {
- rb_io_flush(dc->string);
- return dc->string;
+ dump_flush(dc);
+
+ if (dc->stream) {
+ fflush(dc->stream);
}
- else {
- return Qnil;
+ if (dc->string) {
+ return dc->string;
}
+ return dc->given_output;
}
-/*
- * call-seq:
- * ObjectSpace.dump(obj[, output: :string]) # => "{ ... }"
- * ObjectSpace.dump(obj, output: :file) # => #<File:/tmp/rubyobj20131125-88733-1xkfmpv.json>
- * ObjectSpace.dump(obj, output: :stdout) # => nil
- *
- * Dump the contents of a ruby object as JSON.
- *
- * This method is only expected to work with C Ruby.
- * This is an experimental method and is subject to change.
- * In particular, the function signature and output format are
- * not guaranteed to be compatible in future versions of ruby.
- */
-
static VALUE
-objspace_dump(int argc, VALUE *argv, VALUE os)
+dump_locked(void *args_p)
{
- static const char filename[] = "rubyobj";
- VALUE obj = Qnil, opts = Qnil, output;
struct dump_config dc = {0,};
+ VALUE obj = ((VALUE*)args_p)[0];
+ VALUE output = ((VALUE*)args_p)[1];
- rb_scan_args(argc, argv, "1:", &obj, &opts);
-
- output = dump_output(&dc, opts, sym_string, filename);
+ if (!RB_SPECIAL_CONST_P(obj)) {
+ dc.cur_page_slot_size = rb_gc_obj_slot_size(obj);
+ }
+ dump_output(&dc, output, Qnil, Qnil, Qnil);
dump_object(obj, &dc);
- return dump_result(&dc, output);
-}
-
-/*
- * call-seq:
- * ObjectSpace.dump_all([output: :file]) # => #<File:/tmp/rubyheap20131125-88469-laoj3v.json>
- * ObjectSpace.dump_all(output: :stdout) # => nil
- * ObjectSpace.dump_all(output: :string) # => "{...}\n{...}\n..."
- * ObjectSpace.dump_all(output:
- * File.open('heap.json','w')) # => #<File:heap.json>
- *
- * Dump the contents of the ruby heap as JSON.
- *
- * This method is only expected to work with C Ruby.
- * This is an experimental method and is subject to change.
- * In particular, the function signature and output format are
- * not guaranteed to be compatible in future versions of ruby.
- */
+ return dump_result(&dc);
+}
+
+/* :nodoc: */
+static VALUE
+objspace_dump(VALUE os, VALUE obj, VALUE output)
+{
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = output;
+ return rb_vm_lock_with_barrier(dump_locked, (void*)args);
+}
+
+static void
+shape_id_i(shape_id_t shape_id, void *data)
+{
+ struct dump_config *dc = (struct dump_config *)data;
+
+ if (shape_id < dc->shapes_since) {
+ return;
+ }
+
+ dump_append(dc, "{\"address\":");
+ dump_append_ref(dc, (VALUE)RSHAPE(shape_id));
+
+ dump_append(dc, ", \"type\":\"SHAPE\", \"id\":");
+ dump_append_sizet(dc, shape_id);
+
+ if (RSHAPE_TYPE(shape_id) != SHAPE_ROOT) {
+ dump_append(dc, ", \"parent_id\":");
+ dump_append_lu(dc, RSHAPE_PARENT_RAW_ID(shape_id));
+ }
+
+ dump_append(dc, ", \"depth\":");
+ dump_append_sizet(dc, rb_shape_depth(shape_id));
+
+ switch (RSHAPE_TYPE(shape_id)) {
+ case SHAPE_ROOT:
+ dump_append(dc, ", \"shape_type\":\"ROOT\"");
+ break;
+ case SHAPE_IVAR:
+ dump_append(dc, ", \"shape_type\":\"IVAR\"");
+
+ dump_append(dc, ",\"edge_name\":");
+ dump_append_id(dc, RSHAPE_EDGE_NAME(shape_id));
+
+ break;
+ case SHAPE_OBJ_ID:
+ dump_append(dc, ", \"shape_type\":\"OBJ_ID\"");
+ break;
+ }
+
+ dump_append(dc, ", \"edges\":");
+ dump_append_sizet(dc, rb_shape_edges_count(shape_id));
+
+ dump_append(dc, ", \"memsize\":");
+ dump_append_sizet(dc, rb_shape_memsize(shape_id));
+
+ dump_append(dc, "}\n");
+}
static VALUE
-objspace_dump_all(int argc, VALUE *argv, VALUE os)
+dump_all_locked(void *args_p)
{
- static const char filename[] = "rubyheap";
- VALUE opts = Qnil, output;
struct dump_config dc = {0,};
+ VALUE output = ((VALUE*)args_p)[0];
+ VALUE full = ((VALUE*)args_p)[1];
+ VALUE since = ((VALUE*)args_p)[2];
+ VALUE shapes = ((VALUE*)args_p)[3];
- rb_scan_args(argc, argv, "0:", &opts);
+ dump_output(&dc, output, full, since, shapes);
- output = dump_output(&dc, opts, sym_file, filename);
+ if (!dc.partial_dump || dc.since == 0) {
+ /* dump roots */
+ rb_objspace_reachable_objects_from_root(root_obj_i, &dc);
+ if (dc.roots) dump_append(&dc, "]}\n");
+ }
- /* dump roots */
- rb_objspace_reachable_objects_from_root(root_obj_i, &dc);
- if (dc.roots) dump_append(&dc, "]}\n");
+ if (RTEST(shapes)) {
+ rb_shape_each_shape_id(shape_id_i, &dc);
+ }
/* dump all objects */
rb_objspace_each_objects(heap_i, &dc);
- return dump_result(&dc, output);
+ return dump_result(&dc);
+}
+
+/* :nodoc: */
+static VALUE
+objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes)
+{
+ VALUE args[4];
+ args[0] = output;
+ args[1] = full;
+ args[2] = since;
+ args[3] = shapes;
+ return rb_vm_lock_with_barrier(dump_all_locked, (void*)args);
+}
+
+static VALUE
+dump_shapes_locked(void *args_p)
+{
+ struct dump_config dc = {0,};
+ VALUE output = ((VALUE*)args_p)[0];
+ VALUE shapes = ((VALUE*)args_p)[1];
+
+ dump_output(&dc, output, Qfalse, Qnil, shapes);
+
+ if (RTEST(shapes)) {
+ rb_shape_each_shape_id(shape_id_i, &dc);
+ }
+ return dump_result(&dc);
+}
+
+/* :nodoc: */
+static VALUE
+objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes)
+{
+ VALUE args[2];
+ args[0] = output;
+ args[1] = shapes;
+ return rb_vm_lock_with_barrier(dump_shapes_locked, (void*)args);
}
void
@@ -502,16 +917,11 @@ Init_objspace_dump(VALUE rb_mObjSpace)
#if 0
rb_mObjSpace = rb_define_module("ObjectSpace"); /* let rdoc know */
#endif
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ RB_EXT_RACTOR_SAFE(true);
+#endif
- rb_define_module_function(rb_mObjSpace, "dump", objspace_dump, -1);
- rb_define_module_function(rb_mObjSpace, "dump_all", objspace_dump_all, -1);
-
- sym_output = ID2SYM(rb_intern("output"));
- sym_stdout = ID2SYM(rb_intern("stdout"));
- sym_string = ID2SYM(rb_intern("string"));
- sym_file = ID2SYM(rb_intern("file"));
- sym_full = ID2SYM(rb_intern("full"));
-
- /* force create static IDs */
- rb_obj_gc_flags(rb_mObjSpace, 0, 0);
+ rb_define_module_function(rb_mObjSpace, "_dump", objspace_dump, 2);
+ rb_define_module_function(rb_mObjSpace, "_dump_all", objspace_dump_all, 4);
+ rb_define_module_function(rb_mObjSpace, "_dump_shapes", objspace_dump_shapes, 2);
}