diff options
41 files changed, 880 insertions, 2298 deletions
diff --git a/bootstraptest/test_attr.rb b/bootstraptest/test_attr.rb index 3cb9d3eb39..721a847145 100644 --- a/bootstraptest/test_attr.rb +++ b/bootstraptest/test_attr.rb @@ -34,19 +34,3 @@ assert_equal %{ok}, %{ print "ok" end }, '[ruby-core:15120]' - -assert_equal %{ok}, %{ - class Big - attr_reader :foo - def initialize - @foo = "ok" - end - end - - obj = Big.new - 100.times do |i| - obj.instance_variable_set(:"@ivar_\#{i}", i) - end - - Big.new.foo -} @@ -136,7 +136,6 @@ COMMONOBJS = array.$(OBJEXT) \ regsyntax.$(OBJEXT) \ ruby.$(OBJEXT) \ scheduler.$(OBJEXT) \ - shape.$(OBJEXT) \ signal.$(OBJEXT) \ sprintf.$(OBJEXT) \ st.$(OBJEXT) \ @@ -1833,7 +1832,6 @@ array.$(OBJEXT): $(top_srcdir)/internal/proc.h array.$(OBJEXT): $(top_srcdir)/internal/rational.h array.$(OBJEXT): $(top_srcdir)/internal/serial.h array.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -array.$(OBJEXT): $(top_srcdir)/internal/variable.h array.$(OBJEXT): $(top_srcdir)/internal/vm.h array.$(OBJEXT): $(top_srcdir)/internal/warnings.h array.$(OBJEXT): {$(VPATH)}array.c @@ -1850,7 +1848,6 @@ array.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h array.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h array.$(OBJEXT): {$(VPATH)}builtin.h array.$(OBJEXT): {$(VPATH)}config.h -array.$(OBJEXT): {$(VPATH)}constant.h array.$(OBJEXT): {$(VPATH)}debug_counter.h array.$(OBJEXT): {$(VPATH)}defines.h array.$(OBJEXT): {$(VPATH)}encoding.h @@ -2013,7 +2010,6 @@ array.$(OBJEXT): {$(VPATH)}oniguruma.h array.$(OBJEXT): {$(VPATH)}probes.dmyh array.$(OBJEXT): {$(VPATH)}probes.h array.$(OBJEXT): {$(VPATH)}ruby_assert.h -array.$(OBJEXT): {$(VPATH)}shape.h array.$(OBJEXT): {$(VPATH)}st.h array.$(OBJEXT): {$(VPATH)}subst.h array.$(OBJEXT): {$(VPATH)}transient_heap.h @@ -2032,7 +2028,6 @@ ast.$(OBJEXT): $(top_srcdir)/internal/parse.h ast.$(OBJEXT): $(top_srcdir)/internal/serial.h ast.$(OBJEXT): $(top_srcdir)/internal/static_assert.h ast.$(OBJEXT): $(top_srcdir)/internal/symbol.h -ast.$(OBJEXT): $(top_srcdir)/internal/variable.h ast.$(OBJEXT): $(top_srcdir)/internal/vm.h ast.$(OBJEXT): $(top_srcdir)/internal/warnings.h ast.$(OBJEXT): {$(VPATH)}assert.h @@ -2050,11 +2045,9 @@ ast.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h ast.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h ast.$(OBJEXT): {$(VPATH)}builtin.h ast.$(OBJEXT): {$(VPATH)}config.h -ast.$(OBJEXT): {$(VPATH)}constant.h ast.$(OBJEXT): {$(VPATH)}defines.h ast.$(OBJEXT): {$(VPATH)}encoding.h ast.$(OBJEXT): {$(VPATH)}id.h -ast.$(OBJEXT): {$(VPATH)}id_table.h ast.$(OBJEXT): {$(VPATH)}intern.h ast.$(OBJEXT): {$(VPATH)}internal.h ast.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -2214,7 +2207,6 @@ ast.$(OBJEXT): {$(VPATH)}onigmo.h ast.$(OBJEXT): {$(VPATH)}oniguruma.h ast.$(OBJEXT): {$(VPATH)}ruby_assert.h ast.$(OBJEXT): {$(VPATH)}ruby_atomic.h -ast.$(OBJEXT): {$(VPATH)}shape.h ast.$(OBJEXT): {$(VPATH)}st.h ast.$(OBJEXT): {$(VPATH)}subst.h ast.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -2398,7 +2390,6 @@ bignum.$(OBJEXT): {$(VPATH)}internal/warning_push.h bignum.$(OBJEXT): {$(VPATH)}internal/xmalloc.h bignum.$(OBJEXT): {$(VPATH)}missing.h bignum.$(OBJEXT): {$(VPATH)}ruby_assert.h -bignum.$(OBJEXT): {$(VPATH)}shape.h bignum.$(OBJEXT): {$(VPATH)}st.h bignum.$(OBJEXT): {$(VPATH)}subst.h bignum.$(OBJEXT): {$(VPATH)}thread.h @@ -2414,7 +2405,6 @@ builtin.$(OBJEXT): $(top_srcdir)/internal/gc.h builtin.$(OBJEXT): $(top_srcdir)/internal/imemo.h builtin.$(OBJEXT): $(top_srcdir)/internal/serial.h builtin.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -builtin.$(OBJEXT): $(top_srcdir)/internal/variable.h builtin.$(OBJEXT): $(top_srcdir)/internal/vm.h builtin.$(OBJEXT): $(top_srcdir)/internal/warnings.h builtin.$(OBJEXT): {$(VPATH)}assert.h @@ -2432,10 +2422,8 @@ builtin.$(OBJEXT): {$(VPATH)}builtin.c builtin.$(OBJEXT): {$(VPATH)}builtin.h builtin.$(OBJEXT): {$(VPATH)}builtin_binary.inc builtin.$(OBJEXT): {$(VPATH)}config.h -builtin.$(OBJEXT): {$(VPATH)}constant.h builtin.$(OBJEXT): {$(VPATH)}defines.h builtin.$(OBJEXT): {$(VPATH)}id.h -builtin.$(OBJEXT): {$(VPATH)}id_table.h builtin.$(OBJEXT): {$(VPATH)}intern.h builtin.$(OBJEXT): {$(VPATH)}internal.h builtin.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -2584,7 +2572,6 @@ builtin.$(OBJEXT): {$(VPATH)}missing.h builtin.$(OBJEXT): {$(VPATH)}node.h builtin.$(OBJEXT): {$(VPATH)}ruby_assert.h builtin.$(OBJEXT): {$(VPATH)}ruby_atomic.h -builtin.$(OBJEXT): {$(VPATH)}shape.h builtin.$(OBJEXT): {$(VPATH)}st.h builtin.$(OBJEXT): {$(VPATH)}subst.h builtin.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -2787,7 +2774,6 @@ class.$(OBJEXT): {$(VPATH)}onigmo.h class.$(OBJEXT): {$(VPATH)}oniguruma.h class.$(OBJEXT): {$(VPATH)}ruby_assert.h class.$(OBJEXT): {$(VPATH)}ruby_atomic.h -class.$(OBJEXT): {$(VPATH)}shape.h class.$(OBJEXT): {$(VPATH)}st.h class.$(OBJEXT): {$(VPATH)}subst.h class.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -3191,7 +3177,6 @@ compile.$(OBJEXT): {$(VPATH)}re.h compile.$(OBJEXT): {$(VPATH)}regex.h compile.$(OBJEXT): {$(VPATH)}ruby_assert.h compile.$(OBJEXT): {$(VPATH)}ruby_atomic.h -compile.$(OBJEXT): {$(VPATH)}shape.h compile.$(OBJEXT): {$(VPATH)}st.h compile.$(OBJEXT): {$(VPATH)}subst.h compile.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -3216,7 +3201,6 @@ complex.$(OBJEXT): $(top_srcdir)/internal/object.h complex.$(OBJEXT): $(top_srcdir)/internal/rational.h complex.$(OBJEXT): $(top_srcdir)/internal/serial.h complex.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -complex.$(OBJEXT): $(top_srcdir)/internal/variable.h complex.$(OBJEXT): $(top_srcdir)/internal/vm.h complex.$(OBJEXT): $(top_srcdir)/internal/warnings.h complex.$(OBJEXT): {$(VPATH)}assert.h @@ -3231,7 +3215,6 @@ complex.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h complex.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h complex.$(OBJEXT): {$(VPATH)}complex.c complex.$(OBJEXT): {$(VPATH)}config.h -complex.$(OBJEXT): {$(VPATH)}constant.h complex.$(OBJEXT): {$(VPATH)}defines.h complex.$(OBJEXT): {$(VPATH)}id.h complex.$(OBJEXT): {$(VPATH)}id_table.h @@ -3379,7 +3362,6 @@ complex.$(OBJEXT): {$(VPATH)}internal/warning_push.h complex.$(OBJEXT): {$(VPATH)}internal/xmalloc.h complex.$(OBJEXT): {$(VPATH)}missing.h complex.$(OBJEXT): {$(VPATH)}ruby_assert.h -complex.$(OBJEXT): {$(VPATH)}shape.h complex.$(OBJEXT): {$(VPATH)}st.h complex.$(OBJEXT): {$(VPATH)}subst.h cont.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h @@ -3397,7 +3379,6 @@ cont.$(OBJEXT): $(top_srcdir)/internal/proc.h cont.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h cont.$(OBJEXT): $(top_srcdir)/internal/serial.h cont.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -cont.$(OBJEXT): $(top_srcdir)/internal/variable.h cont.$(OBJEXT): $(top_srcdir)/internal/vm.h cont.$(OBJEXT): $(top_srcdir)/internal/warnings.h cont.$(OBJEXT): {$(VPATH)}$(COROUTINE_H) @@ -3413,7 +3394,6 @@ cont.$(OBJEXT): {$(VPATH)}backward/2/long_long.h cont.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h cont.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h cont.$(OBJEXT): {$(VPATH)}config.h -cont.$(OBJEXT): {$(VPATH)}constant.h cont.$(OBJEXT): {$(VPATH)}cont.c cont.$(OBJEXT): {$(VPATH)}debug_counter.h cont.$(OBJEXT): {$(VPATH)}defines.h @@ -3572,7 +3552,6 @@ cont.$(OBJEXT): {$(VPATH)}ractor.h cont.$(OBJEXT): {$(VPATH)}ractor_core.h cont.$(OBJEXT): {$(VPATH)}ruby_assert.h cont.$(OBJEXT): {$(VPATH)}ruby_atomic.h -cont.$(OBJEXT): {$(VPATH)}shape.h cont.$(OBJEXT): {$(VPATH)}st.h cont.$(OBJEXT): {$(VPATH)}subst.h cont.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -3593,7 +3572,6 @@ debug.$(OBJEXT): $(top_srcdir)/internal/imemo.h debug.$(OBJEXT): $(top_srcdir)/internal/serial.h debug.$(OBJEXT): $(top_srcdir)/internal/signal.h debug.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -debug.$(OBJEXT): $(top_srcdir)/internal/variable.h debug.$(OBJEXT): $(top_srcdir)/internal/vm.h debug.$(OBJEXT): $(top_srcdir)/internal/warnings.h debug.$(OBJEXT): {$(VPATH)}assert.h @@ -3608,7 +3586,6 @@ debug.$(OBJEXT): {$(VPATH)}backward/2/long_long.h debug.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h debug.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h debug.$(OBJEXT): {$(VPATH)}config.h -debug.$(OBJEXT): {$(VPATH)}constant.h debug.$(OBJEXT): {$(VPATH)}debug.c debug.$(OBJEXT): {$(VPATH)}debug_counter.h debug.$(OBJEXT): {$(VPATH)}defines.h @@ -3779,7 +3756,6 @@ debug.$(OBJEXT): {$(VPATH)}ractor.h debug.$(OBJEXT): {$(VPATH)}ractor_core.h debug.$(OBJEXT): {$(VPATH)}ruby_assert.h debug.$(OBJEXT): {$(VPATH)}ruby_atomic.h -debug.$(OBJEXT): {$(VPATH)}shape.h debug.$(OBJEXT): {$(VPATH)}st.h debug.$(OBJEXT): {$(VPATH)}subst.h debug.$(OBJEXT): {$(VPATH)}symbol.h @@ -3964,7 +3940,6 @@ dir.$(OBJEXT): $(top_srcdir)/internal/object.h dir.$(OBJEXT): $(top_srcdir)/internal/serial.h dir.$(OBJEXT): $(top_srcdir)/internal/static_assert.h dir.$(OBJEXT): $(top_srcdir)/internal/string.h -dir.$(OBJEXT): $(top_srcdir)/internal/variable.h dir.$(OBJEXT): $(top_srcdir)/internal/vm.h dir.$(OBJEXT): $(top_srcdir)/internal/warnings.h dir.$(OBJEXT): {$(VPATH)}assert.h @@ -3979,7 +3954,6 @@ dir.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h dir.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h dir.$(OBJEXT): {$(VPATH)}builtin.h dir.$(OBJEXT): {$(VPATH)}config.h -dir.$(OBJEXT): {$(VPATH)}constant.h dir.$(OBJEXT): {$(VPATH)}defines.h dir.$(OBJEXT): {$(VPATH)}dir.c dir.$(OBJEXT): {$(VPATH)}dir.rbinc @@ -4142,7 +4116,6 @@ dir.$(OBJEXT): {$(VPATH)}io.h dir.$(OBJEXT): {$(VPATH)}missing.h dir.$(OBJEXT): {$(VPATH)}onigmo.h dir.$(OBJEXT): {$(VPATH)}oniguruma.h -dir.$(OBJEXT): {$(VPATH)}shape.h dir.$(OBJEXT): {$(VPATH)}st.h dir.$(OBJEXT): {$(VPATH)}subst.h dir.$(OBJEXT): {$(VPATH)}thread.h @@ -5468,7 +5441,6 @@ encoding.$(OBJEXT): $(top_srcdir)/internal/object.h encoding.$(OBJEXT): $(top_srcdir)/internal/serial.h encoding.$(OBJEXT): $(top_srcdir)/internal/static_assert.h encoding.$(OBJEXT): $(top_srcdir)/internal/string.h -encoding.$(OBJEXT): $(top_srcdir)/internal/variable.h encoding.$(OBJEXT): $(top_srcdir)/internal/vm.h encoding.$(OBJEXT): $(top_srcdir)/internal/warnings.h encoding.$(OBJEXT): {$(VPATH)}assert.h @@ -5482,7 +5454,6 @@ encoding.$(OBJEXT): {$(VPATH)}backward/2/long_long.h encoding.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h encoding.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h encoding.$(OBJEXT): {$(VPATH)}config.h -encoding.$(OBJEXT): {$(VPATH)}constant.h encoding.$(OBJEXT): {$(VPATH)}debug_counter.h encoding.$(OBJEXT): {$(VPATH)}defines.h encoding.$(OBJEXT): {$(VPATH)}encindex.h @@ -5645,7 +5616,6 @@ encoding.$(OBJEXT): {$(VPATH)}onigmo.h encoding.$(OBJEXT): {$(VPATH)}oniguruma.h encoding.$(OBJEXT): {$(VPATH)}regenc.h encoding.$(OBJEXT): {$(VPATH)}ruby_assert.h -encoding.$(OBJEXT): {$(VPATH)}shape.h encoding.$(OBJEXT): {$(VPATH)}st.h encoding.$(OBJEXT): {$(VPATH)}subst.h encoding.$(OBJEXT): {$(VPATH)}util.h @@ -5670,7 +5640,6 @@ enum.$(OBJEXT): $(top_srcdir)/internal/rational.h enum.$(OBJEXT): $(top_srcdir)/internal/re.h enum.$(OBJEXT): $(top_srcdir)/internal/serial.h enum.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -enum.$(OBJEXT): $(top_srcdir)/internal/variable.h enum.$(OBJEXT): $(top_srcdir)/internal/vm.h enum.$(OBJEXT): $(top_srcdir)/internal/warnings.h enum.$(OBJEXT): {$(VPATH)}assert.h @@ -5684,7 +5653,6 @@ enum.$(OBJEXT): {$(VPATH)}backward/2/long_long.h enum.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h enum.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h enum.$(OBJEXT): {$(VPATH)}config.h -enum.$(OBJEXT): {$(VPATH)}constant.h enum.$(OBJEXT): {$(VPATH)}defines.h enum.$(OBJEXT): {$(VPATH)}encoding.h enum.$(OBJEXT): {$(VPATH)}enum.c @@ -5845,7 +5813,6 @@ enum.$(OBJEXT): {$(VPATH)}missing.h enum.$(OBJEXT): {$(VPATH)}onigmo.h enum.$(OBJEXT): {$(VPATH)}oniguruma.h enum.$(OBJEXT): {$(VPATH)}ruby_assert.h -enum.$(OBJEXT): {$(VPATH)}shape.h enum.$(OBJEXT): {$(VPATH)}st.h enum.$(OBJEXT): {$(VPATH)}subst.h enum.$(OBJEXT): {$(VPATH)}symbol.h @@ -6245,7 +6212,6 @@ error.$(OBJEXT): {$(VPATH)}onigmo.h error.$(OBJEXT): {$(VPATH)}oniguruma.h error.$(OBJEXT): {$(VPATH)}ruby_assert.h error.$(OBJEXT): {$(VPATH)}ruby_atomic.h -error.$(OBJEXT): {$(VPATH)}shape.h error.$(OBJEXT): {$(VPATH)}st.h error.$(OBJEXT): {$(VPATH)}subst.h error.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -6467,7 +6433,6 @@ eval.$(OBJEXT): {$(VPATH)}ractor.h eval.$(OBJEXT): {$(VPATH)}ractor_core.h eval.$(OBJEXT): {$(VPATH)}ruby_assert.h eval.$(OBJEXT): {$(VPATH)}ruby_atomic.h -eval.$(OBJEXT): {$(VPATH)}shape.h eval.$(OBJEXT): {$(VPATH)}st.h eval.$(OBJEXT): {$(VPATH)}subst.h eval.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -6508,7 +6473,6 @@ file.$(OBJEXT): $(top_srcdir)/internal/serial.h file.$(OBJEXT): $(top_srcdir)/internal/static_assert.h file.$(OBJEXT): $(top_srcdir)/internal/string.h file.$(OBJEXT): $(top_srcdir)/internal/thread.h -file.$(OBJEXT): $(top_srcdir)/internal/variable.h file.$(OBJEXT): $(top_srcdir)/internal/vm.h file.$(OBJEXT): $(top_srcdir)/internal/warnings.h file.$(OBJEXT): {$(VPATH)}assert.h @@ -6522,7 +6486,6 @@ file.$(OBJEXT): {$(VPATH)}backward/2/long_long.h file.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h file.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h file.$(OBJEXT): {$(VPATH)}config.h -file.$(OBJEXT): {$(VPATH)}constant.h file.$(OBJEXT): {$(VPATH)}defines.h file.$(OBJEXT): {$(VPATH)}dln.h file.$(OBJEXT): {$(VPATH)}encindex.h @@ -6685,7 +6648,6 @@ file.$(OBJEXT): {$(VPATH)}io.h file.$(OBJEXT): {$(VPATH)}missing.h file.$(OBJEXT): {$(VPATH)}onigmo.h file.$(OBJEXT): {$(VPATH)}oniguruma.h -file.$(OBJEXT): {$(VPATH)}shape.h file.$(OBJEXT): {$(VPATH)}st.h file.$(OBJEXT): {$(VPATH)}subst.h file.$(OBJEXT): {$(VPATH)}thread.h @@ -6918,7 +6880,6 @@ gc.$(OBJEXT): {$(VPATH)}regex.h gc.$(OBJEXT): {$(VPATH)}regint.h gc.$(OBJEXT): {$(VPATH)}ruby_assert.h gc.$(OBJEXT): {$(VPATH)}ruby_atomic.h -gc.$(OBJEXT): {$(VPATH)}shape.h gc.$(OBJEXT): {$(VPATH)}st.h gc.$(OBJEXT): {$(VPATH)}subst.h gc.$(OBJEXT): {$(VPATH)}symbol.h @@ -6944,7 +6905,6 @@ goruby.$(OBJEXT): $(top_srcdir)/internal/gc.h goruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h goruby.$(OBJEXT): $(top_srcdir)/internal/serial.h goruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -goruby.$(OBJEXT): $(top_srcdir)/internal/variable.h goruby.$(OBJEXT): $(top_srcdir)/internal/vm.h goruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h goruby.$(OBJEXT): {$(VPATH)}assert.h @@ -6960,13 +6920,11 @@ goruby.$(OBJEXT): {$(VPATH)}backward/2/long_long.h goruby.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h goruby.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h goruby.$(OBJEXT): {$(VPATH)}config.h -goruby.$(OBJEXT): {$(VPATH)}constant.h goruby.$(OBJEXT): {$(VPATH)}defines.h goruby.$(OBJEXT): {$(VPATH)}golf_prelude.c goruby.$(OBJEXT): {$(VPATH)}golf_prelude.rb goruby.$(OBJEXT): {$(VPATH)}goruby.c goruby.$(OBJEXT): {$(VPATH)}id.h -goruby.$(OBJEXT): {$(VPATH)}id_table.h goruby.$(OBJEXT): {$(VPATH)}intern.h goruby.$(OBJEXT): {$(VPATH)}internal.h goruby.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -7116,7 +7074,6 @@ goruby.$(OBJEXT): {$(VPATH)}missing.h goruby.$(OBJEXT): {$(VPATH)}node.h goruby.$(OBJEXT): {$(VPATH)}ruby_assert.h goruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h -goruby.$(OBJEXT): {$(VPATH)}shape.h goruby.$(OBJEXT): {$(VPATH)}st.h goruby.$(OBJEXT): {$(VPATH)}subst.h goruby.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -7142,7 +7099,6 @@ hash.$(OBJEXT): $(top_srcdir)/internal/string.h hash.$(OBJEXT): $(top_srcdir)/internal/symbol.h hash.$(OBJEXT): $(top_srcdir)/internal/thread.h hash.$(OBJEXT): $(top_srcdir)/internal/time.h -hash.$(OBJEXT): $(top_srcdir)/internal/variable.h hash.$(OBJEXT): $(top_srcdir)/internal/vm.h hash.$(OBJEXT): $(top_srcdir)/internal/warnings.h hash.$(OBJEXT): {$(VPATH)}assert.h @@ -7156,7 +7112,6 @@ hash.$(OBJEXT): {$(VPATH)}backward/2/long_long.h hash.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h hash.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h hash.$(OBJEXT): {$(VPATH)}config.h -hash.$(OBJEXT): {$(VPATH)}constant.h hash.$(OBJEXT): {$(VPATH)}debug_counter.h hash.$(OBJEXT): {$(VPATH)}defines.h hash.$(OBJEXT): {$(VPATH)}encoding.h @@ -7321,7 +7276,6 @@ hash.$(OBJEXT): {$(VPATH)}probes.dmyh hash.$(OBJEXT): {$(VPATH)}probes.h hash.$(OBJEXT): {$(VPATH)}ractor.h hash.$(OBJEXT): {$(VPATH)}ruby_assert.h -hash.$(OBJEXT): {$(VPATH)}shape.h hash.$(OBJEXT): {$(VPATH)}st.h hash.$(OBJEXT): {$(VPATH)}subst.h hash.$(OBJEXT): {$(VPATH)}symbol.h @@ -7706,7 +7660,6 @@ io.$(OBJEXT): {$(VPATH)}oniguruma.h io.$(OBJEXT): {$(VPATH)}ractor.h io.$(OBJEXT): {$(VPATH)}ruby_assert.h io.$(OBJEXT): {$(VPATH)}ruby_atomic.h -io.$(OBJEXT): {$(VPATH)}shape.h io.$(OBJEXT): {$(VPATH)}st.h io.$(OBJEXT): {$(VPATH)}subst.h io.$(OBJEXT): {$(VPATH)}thread.h @@ -8109,7 +8062,6 @@ iseq.$(OBJEXT): {$(VPATH)}oniguruma.h iseq.$(OBJEXT): {$(VPATH)}ractor.h iseq.$(OBJEXT): {$(VPATH)}ruby_assert.h iseq.$(OBJEXT): {$(VPATH)}ruby_atomic.h -iseq.$(OBJEXT): {$(VPATH)}shape.h iseq.$(OBJEXT): {$(VPATH)}st.h iseq.$(OBJEXT): {$(VPATH)}subst.h iseq.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -8322,7 +8274,6 @@ load.$(OBJEXT): {$(VPATH)}probes.dmyh load.$(OBJEXT): {$(VPATH)}probes.h load.$(OBJEXT): {$(VPATH)}ruby_assert.h load.$(OBJEXT): {$(VPATH)}ruby_atomic.h -load.$(OBJEXT): {$(VPATH)}shape.h load.$(OBJEXT): {$(VPATH)}st.h load.$(OBJEXT): {$(VPATH)}subst.h load.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -8841,7 +8792,6 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/string.h marshal.$(OBJEXT): $(top_srcdir)/internal/struct.h marshal.$(OBJEXT): $(top_srcdir)/internal/symbol.h marshal.$(OBJEXT): $(top_srcdir)/internal/util.h -marshal.$(OBJEXT): $(top_srcdir)/internal/variable.h marshal.$(OBJEXT): $(top_srcdir)/internal/vm.h marshal.$(OBJEXT): $(top_srcdir)/internal/warnings.h marshal.$(OBJEXT): {$(VPATH)}assert.h @@ -8856,7 +8806,6 @@ marshal.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h marshal.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h marshal.$(OBJEXT): {$(VPATH)}builtin.h marshal.$(OBJEXT): {$(VPATH)}config.h -marshal.$(OBJEXT): {$(VPATH)}constant.h marshal.$(OBJEXT): {$(VPATH)}defines.h marshal.$(OBJEXT): {$(VPATH)}encindex.h marshal.$(OBJEXT): {$(VPATH)}encoding.h @@ -9018,7 +8967,6 @@ marshal.$(OBJEXT): {$(VPATH)}marshal.rbinc marshal.$(OBJEXT): {$(VPATH)}missing.h marshal.$(OBJEXT): {$(VPATH)}onigmo.h marshal.$(OBJEXT): {$(VPATH)}oniguruma.h -marshal.$(OBJEXT): {$(VPATH)}shape.h marshal.$(OBJEXT): {$(VPATH)}st.h marshal.$(OBJEXT): {$(VPATH)}subst.h marshal.$(OBJEXT): {$(VPATH)}util.h @@ -9032,7 +8980,6 @@ math.$(OBJEXT): $(top_srcdir)/internal/math.h math.$(OBJEXT): $(top_srcdir)/internal/object.h math.$(OBJEXT): $(top_srcdir)/internal/serial.h math.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -math.$(OBJEXT): $(top_srcdir)/internal/variable.h math.$(OBJEXT): $(top_srcdir)/internal/vm.h math.$(OBJEXT): $(top_srcdir)/internal/warnings.h math.$(OBJEXT): {$(VPATH)}assert.h @@ -9046,7 +8993,6 @@ math.$(OBJEXT): {$(VPATH)}backward/2/long_long.h math.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h math.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h math.$(OBJEXT): {$(VPATH)}config.h -math.$(OBJEXT): {$(VPATH)}constant.h math.$(OBJEXT): {$(VPATH)}defines.h math.$(OBJEXT): {$(VPATH)}id_table.h math.$(OBJEXT): {$(VPATH)}intern.h @@ -9193,7 +9139,6 @@ math.$(OBJEXT): {$(VPATH)}internal/warning_push.h math.$(OBJEXT): {$(VPATH)}internal/xmalloc.h math.$(OBJEXT): {$(VPATH)}math.c math.$(OBJEXT): {$(VPATH)}missing.h -math.$(OBJEXT): {$(VPATH)}shape.h math.$(OBJEXT): {$(VPATH)}st.h math.$(OBJEXT): {$(VPATH)}subst.h memory_view.$(OBJEXT): $(hdrdir)/ruby/ruby.h @@ -9375,7 +9320,6 @@ miniinit.$(OBJEXT): $(top_srcdir)/internal/gc.h miniinit.$(OBJEXT): $(top_srcdir)/internal/imemo.h miniinit.$(OBJEXT): $(top_srcdir)/internal/serial.h miniinit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -miniinit.$(OBJEXT): $(top_srcdir)/internal/variable.h miniinit.$(OBJEXT): $(top_srcdir)/internal/vm.h miniinit.$(OBJEXT): $(top_srcdir)/internal/warnings.h miniinit.$(OBJEXT): {$(VPATH)}array.rb @@ -9393,14 +9337,12 @@ miniinit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h miniinit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h miniinit.$(OBJEXT): {$(VPATH)}builtin.h miniinit.$(OBJEXT): {$(VPATH)}config.h -miniinit.$(OBJEXT): {$(VPATH)}constant.h miniinit.$(OBJEXT): {$(VPATH)}defines.h miniinit.$(OBJEXT): {$(VPATH)}dir.rb miniinit.$(OBJEXT): {$(VPATH)}encoding.h miniinit.$(OBJEXT): {$(VPATH)}gc.rb miniinit.$(OBJEXT): {$(VPATH)}gem_prelude.rb miniinit.$(OBJEXT): {$(VPATH)}id.h -miniinit.$(OBJEXT): {$(VPATH)}id_table.h miniinit.$(OBJEXT): {$(VPATH)}intern.h miniinit.$(OBJEXT): {$(VPATH)}internal.h miniinit.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -9574,7 +9516,6 @@ miniinit.$(OBJEXT): {$(VPATH)}prelude.rb miniinit.$(OBJEXT): {$(VPATH)}ractor.rb miniinit.$(OBJEXT): {$(VPATH)}ruby_assert.h miniinit.$(OBJEXT): {$(VPATH)}ruby_atomic.h -miniinit.$(OBJEXT): {$(VPATH)}shape.h miniinit.$(OBJEXT): {$(VPATH)}st.h miniinit.$(OBJEXT): {$(VPATH)}subst.h miniinit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -9606,7 +9547,6 @@ mjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h mjit.$(OBJEXT): $(top_srcdir)/internal/process.h mjit.$(OBJEXT): $(top_srcdir)/internal/serial.h mjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -mjit.$(OBJEXT): $(top_srcdir)/internal/variable.h mjit.$(OBJEXT): $(top_srcdir)/internal/vm.h mjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h mjit.$(OBJEXT): {$(VPATH)}assert.h @@ -9801,7 +9741,6 @@ mjit.$(OBJEXT): {$(VPATH)}ractor.h mjit.$(OBJEXT): {$(VPATH)}ractor_core.h mjit.$(OBJEXT): {$(VPATH)}ruby_assert.h mjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h -mjit.$(OBJEXT): {$(VPATH)}shape.h mjit.$(OBJEXT): {$(VPATH)}st.h mjit.$(OBJEXT): {$(VPATH)}subst.h mjit.$(OBJEXT): {$(VPATH)}thread.h @@ -10012,7 +9951,6 @@ mjit_compiler.$(OBJEXT): {$(VPATH)}mjit_unit.h mjit_compiler.$(OBJEXT): {$(VPATH)}node.h mjit_compiler.$(OBJEXT): {$(VPATH)}ruby_assert.h mjit_compiler.$(OBJEXT): {$(VPATH)}ruby_atomic.h -mjit_compiler.$(OBJEXT): {$(VPATH)}shape.h mjit_compiler.$(OBJEXT): {$(VPATH)}st.h mjit_compiler.$(OBJEXT): {$(VPATH)}subst.h mjit_compiler.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -10202,7 +10140,6 @@ node.$(OBJEXT): {$(VPATH)}node.c node.$(OBJEXT): {$(VPATH)}node.h node.$(OBJEXT): {$(VPATH)}ruby_assert.h node.$(OBJEXT): {$(VPATH)}ruby_atomic.h -node.$(OBJEXT): {$(VPATH)}shape.h node.$(OBJEXT): {$(VPATH)}st.h node.$(OBJEXT): {$(VPATH)}subst.h node.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -10405,7 +10342,6 @@ numeric.$(OBJEXT): {$(VPATH)}numeric.rbinc numeric.$(OBJEXT): {$(VPATH)}onigmo.h numeric.$(OBJEXT): {$(VPATH)}oniguruma.h numeric.$(OBJEXT): {$(VPATH)}ruby_assert.h -numeric.$(OBJEXT): {$(VPATH)}shape.h numeric.$(OBJEXT): {$(VPATH)}st.h numeric.$(OBJEXT): {$(VPATH)}subst.h numeric.$(OBJEXT): {$(VPATH)}util.h @@ -10607,7 +10543,6 @@ object.$(OBJEXT): {$(VPATH)}onigmo.h object.$(OBJEXT): {$(VPATH)}oniguruma.h object.$(OBJEXT): {$(VPATH)}probes.dmyh object.$(OBJEXT): {$(VPATH)}probes.h -object.$(OBJEXT): {$(VPATH)}shape.h object.$(OBJEXT): {$(VPATH)}st.h object.$(OBJEXT): {$(VPATH)}subst.h object.$(OBJEXT): {$(VPATH)}util.h @@ -11026,7 +10961,6 @@ proc.$(OBJEXT): $(top_srcdir)/internal/serial.h proc.$(OBJEXT): $(top_srcdir)/internal/static_assert.h proc.$(OBJEXT): $(top_srcdir)/internal/string.h proc.$(OBJEXT): $(top_srcdir)/internal/symbol.h -proc.$(OBJEXT): $(top_srcdir)/internal/variable.h proc.$(OBJEXT): $(top_srcdir)/internal/vm.h proc.$(OBJEXT): $(top_srcdir)/internal/warnings.h proc.$(OBJEXT): {$(VPATH)}assert.h @@ -11041,7 +10975,6 @@ proc.$(OBJEXT): {$(VPATH)}backward/2/long_long.h proc.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h proc.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h proc.$(OBJEXT): {$(VPATH)}config.h -proc.$(OBJEXT): {$(VPATH)}constant.h proc.$(OBJEXT): {$(VPATH)}defines.h proc.$(OBJEXT): {$(VPATH)}encoding.h proc.$(OBJEXT): {$(VPATH)}eval_intern.h @@ -11208,7 +11141,6 @@ proc.$(OBJEXT): {$(VPATH)}oniguruma.h proc.$(OBJEXT): {$(VPATH)}proc.c proc.$(OBJEXT): {$(VPATH)}ruby_assert.h proc.$(OBJEXT): {$(VPATH)}ruby_atomic.h -proc.$(OBJEXT): {$(VPATH)}shape.h proc.$(OBJEXT): {$(VPATH)}st.h proc.$(OBJEXT): {$(VPATH)}subst.h proc.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -11428,7 +11360,6 @@ process.$(OBJEXT): {$(VPATH)}process.c process.$(OBJEXT): {$(VPATH)}ractor.h process.$(OBJEXT): {$(VPATH)}ruby_assert.h process.$(OBJEXT): {$(VPATH)}ruby_atomic.h -process.$(OBJEXT): {$(VPATH)}shape.h process.$(OBJEXT): {$(VPATH)}st.h process.$(OBJEXT): {$(VPATH)}subst.h process.$(OBJEXT): {$(VPATH)}thread.h @@ -11459,7 +11390,6 @@ ractor.$(OBJEXT): $(top_srcdir)/internal/static_assert.h ractor.$(OBJEXT): $(top_srcdir)/internal/string.h ractor.$(OBJEXT): $(top_srcdir)/internal/struct.h ractor.$(OBJEXT): $(top_srcdir)/internal/thread.h -ractor.$(OBJEXT): $(top_srcdir)/internal/variable.h ractor.$(OBJEXT): $(top_srcdir)/internal/vm.h ractor.$(OBJEXT): $(top_srcdir)/internal/warnings.h ractor.$(OBJEXT): {$(VPATH)}assert.h @@ -11475,7 +11405,6 @@ ractor.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h ractor.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h ractor.$(OBJEXT): {$(VPATH)}builtin.h ractor.$(OBJEXT): {$(VPATH)}config.h -ractor.$(OBJEXT): {$(VPATH)}constant.h ractor.$(OBJEXT): {$(VPATH)}debug_counter.h ractor.$(OBJEXT): {$(VPATH)}defines.h ractor.$(OBJEXT): {$(VPATH)}encoding.h @@ -11645,7 +11574,6 @@ ractor.$(OBJEXT): {$(VPATH)}ractor.rbinc ractor.$(OBJEXT): {$(VPATH)}ractor_core.h ractor.$(OBJEXT): {$(VPATH)}ruby_assert.h ractor.$(OBJEXT): {$(VPATH)}ruby_atomic.h -ractor.$(OBJEXT): {$(VPATH)}shape.h ractor.$(OBJEXT): {$(VPATH)}st.h ractor.$(OBJEXT): {$(VPATH)}subst.h ractor.$(OBJEXT): {$(VPATH)}thread.h @@ -12043,7 +11971,6 @@ rational.$(OBJEXT): $(top_srcdir)/internal/object.h rational.$(OBJEXT): $(top_srcdir)/internal/rational.h rational.$(OBJEXT): $(top_srcdir)/internal/serial.h rational.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -rational.$(OBJEXT): $(top_srcdir)/internal/variable.h rational.$(OBJEXT): $(top_srcdir)/internal/vm.h rational.$(OBJEXT): $(top_srcdir)/internal/warnings.h rational.$(OBJEXT): {$(VPATH)}assert.h @@ -12057,7 +11984,6 @@ rational.$(OBJEXT): {$(VPATH)}backward/2/long_long.h rational.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h rational.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h rational.$(OBJEXT): {$(VPATH)}config.h -rational.$(OBJEXT): {$(VPATH)}constant.h rational.$(OBJEXT): {$(VPATH)}defines.h rational.$(OBJEXT): {$(VPATH)}id.h rational.$(OBJEXT): {$(VPATH)}id_table.h @@ -12206,7 +12132,6 @@ rational.$(OBJEXT): {$(VPATH)}internal/xmalloc.h rational.$(OBJEXT): {$(VPATH)}missing.h rational.$(OBJEXT): {$(VPATH)}rational.c rational.$(OBJEXT): {$(VPATH)}ruby_assert.h -rational.$(OBJEXT): {$(VPATH)}shape.h rational.$(OBJEXT): {$(VPATH)}st.h rational.$(OBJEXT): {$(VPATH)}subst.h re.$(OBJEXT): $(hdrdir)/ruby.h @@ -12404,7 +12329,6 @@ re.$(OBJEXT): {$(VPATH)}re.h re.$(OBJEXT): {$(VPATH)}regenc.h re.$(OBJEXT): {$(VPATH)}regex.h re.$(OBJEXT): {$(VPATH)}regint.h -re.$(OBJEXT): {$(VPATH)}shape.h re.$(OBJEXT): {$(VPATH)}st.h re.$(OBJEXT): {$(VPATH)}subst.h re.$(OBJEXT): {$(VPATH)}util.h @@ -13602,7 +13526,6 @@ ruby.$(OBJEXT): {$(VPATH)}oniguruma.h ruby.$(OBJEXT): {$(VPATH)}ruby.c ruby.$(OBJEXT): {$(VPATH)}ruby_assert.h ruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h -ruby.$(OBJEXT): {$(VPATH)}shape.h ruby.$(OBJEXT): {$(VPATH)}st.h ruby.$(OBJEXT): {$(VPATH)}subst.h ruby.$(OBJEXT): {$(VPATH)}thread.h @@ -13624,7 +13547,6 @@ scheduler.$(OBJEXT): $(top_srcdir)/internal/imemo.h scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h scheduler.$(OBJEXT): $(top_srcdir)/internal/static_assert.h scheduler.$(OBJEXT): $(top_srcdir)/internal/thread.h -scheduler.$(OBJEXT): $(top_srcdir)/internal/variable.h scheduler.$(OBJEXT): $(top_srcdir)/internal/vm.h scheduler.$(OBJEXT): $(top_srcdir)/internal/warnings.h scheduler.$(OBJEXT): {$(VPATH)}assert.h @@ -13639,12 +13561,10 @@ scheduler.$(OBJEXT): {$(VPATH)}backward/2/long_long.h scheduler.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h scheduler.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h scheduler.$(OBJEXT): {$(VPATH)}config.h -scheduler.$(OBJEXT): {$(VPATH)}constant.h scheduler.$(OBJEXT): {$(VPATH)}defines.h scheduler.$(OBJEXT): {$(VPATH)}encoding.h scheduler.$(OBJEXT): {$(VPATH)}fiber/scheduler.h scheduler.$(OBJEXT): {$(VPATH)}id.h -scheduler.$(OBJEXT): {$(VPATH)}id_table.h scheduler.$(OBJEXT): {$(VPATH)}intern.h scheduler.$(OBJEXT): {$(VPATH)}internal.h scheduler.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -13806,7 +13726,6 @@ scheduler.$(OBJEXT): {$(VPATH)}oniguruma.h scheduler.$(OBJEXT): {$(VPATH)}ruby_assert.h scheduler.$(OBJEXT): {$(VPATH)}ruby_atomic.h scheduler.$(OBJEXT): {$(VPATH)}scheduler.c -scheduler.$(OBJEXT): {$(VPATH)}shape.h scheduler.$(OBJEXT): {$(VPATH)}st.h scheduler.$(OBJEXT): {$(VPATH)}subst.h scheduler.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -13972,208 +13891,6 @@ setproctitle.$(OBJEXT): {$(VPATH)}setproctitle.c setproctitle.$(OBJEXT): {$(VPATH)}st.h setproctitle.$(OBJEXT): {$(VPATH)}subst.h setproctitle.$(OBJEXT): {$(VPATH)}util.h -shape.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h -shape.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h -shape.$(OBJEXT): $(CCAN_DIR)/list/list.h -shape.$(OBJEXT): $(CCAN_DIR)/str/str.h -shape.$(OBJEXT): $(hdrdir)/ruby/ruby.h -shape.$(OBJEXT): $(top_srcdir)/internal/array.h -shape.$(OBJEXT): $(top_srcdir)/internal/class.h -shape.$(OBJEXT): $(top_srcdir)/internal/compilers.h -shape.$(OBJEXT): $(top_srcdir)/internal/gc.h -shape.$(OBJEXT): $(top_srcdir)/internal/imemo.h -shape.$(OBJEXT): $(top_srcdir)/internal/serial.h -shape.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -shape.$(OBJEXT): $(top_srcdir)/internal/symbol.h -shape.$(OBJEXT): $(top_srcdir)/internal/variable.h -shape.$(OBJEXT): $(top_srcdir)/internal/vm.h -shape.$(OBJEXT): $(top_srcdir)/internal/warnings.h -shape.$(OBJEXT): {$(VPATH)}assert.h -shape.$(OBJEXT): {$(VPATH)}atomic.h -shape.$(OBJEXT): {$(VPATH)}backward/2/assume.h -shape.$(OBJEXT): {$(VPATH)}backward/2/attributes.h -shape.$(OBJEXT): {$(VPATH)}backward/2/bool.h -shape.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h -shape.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h -shape.$(OBJEXT): {$(VPATH)}backward/2/limits.h -shape.$(OBJEXT): {$(VPATH)}backward/2/long_long.h -shape.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h -shape.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h -shape.$(OBJEXT): {$(VPATH)}config.h -shape.$(OBJEXT): {$(VPATH)}constant.h -shape.$(OBJEXT): {$(VPATH)}debug_counter.h -shape.$(OBJEXT): {$(VPATH)}defines.h -shape.$(OBJEXT): {$(VPATH)}encoding.h -shape.$(OBJEXT): {$(VPATH)}id.h -shape.$(OBJEXT): {$(VPATH)}id_table.h -shape.$(OBJEXT): {$(VPATH)}intern.h -shape.$(OBJEXT): {$(VPATH)}internal.h -shape.$(OBJEXT): {$(VPATH)}internal/abi.h -shape.$(OBJEXT): {$(VPATH)}internal/anyargs.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h -shape.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h -shape.$(OBJEXT): {$(VPATH)}internal/assume.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/cold.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/const.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/error.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/format.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/pure.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/warning.h -shape.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h -shape.$(OBJEXT): {$(VPATH)}internal/cast.h -shape.$(OBJEXT): {$(VPATH)}internal/compiler_is.h -shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h -shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h -shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h -shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h -shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h -shape.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h -shape.$(OBJEXT): {$(VPATH)}internal/compiler_since.h -shape.$(OBJEXT): {$(VPATH)}internal/config.h -shape.$(OBJEXT): {$(VPATH)}internal/constant_p.h -shape.$(OBJEXT): {$(VPATH)}internal/core.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rarray.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rclass.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rdata.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rfile.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rhash.h -shape.$(OBJEXT): {$(VPATH)}internal/core/robject.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rstring.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h -shape.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h -shape.$(OBJEXT): {$(VPATH)}internal/ctype.h -shape.$(OBJEXT): {$(VPATH)}internal/dllexport.h -shape.$(OBJEXT): {$(VPATH)}internal/dosish.h -shape.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h -shape.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h -shape.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h -shape.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h -shape.$(OBJEXT): {$(VPATH)}internal/encoding/re.h -shape.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h -shape.$(OBJEXT): {$(VPATH)}internal/encoding/string.h -shape.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h -shape.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h -shape.$(OBJEXT): {$(VPATH)}internal/error.h -shape.$(OBJEXT): {$(VPATH)}internal/eval.h -shape.$(OBJEXT): {$(VPATH)}internal/event.h -shape.$(OBJEXT): {$(VPATH)}internal/fl_type.h -shape.$(OBJEXT): {$(VPATH)}internal/gc.h -shape.$(OBJEXT): {$(VPATH)}internal/glob.h -shape.$(OBJEXT): {$(VPATH)}internal/globals.h -shape.$(OBJEXT): {$(VPATH)}internal/has/attribute.h -shape.$(OBJEXT): {$(VPATH)}internal/has/builtin.h -shape.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h -shape.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h -shape.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h -shape.$(OBJEXT): {$(VPATH)}internal/has/extension.h -shape.$(OBJEXT): {$(VPATH)}internal/has/feature.h -shape.$(OBJEXT): {$(VPATH)}internal/has/warning.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/array.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/class.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/compar.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/complex.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/cont.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/dir.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/enum.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/error.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/eval.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/file.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/gc.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/hash.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/io.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/load.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/object.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/parse.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/proc.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/process.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/random.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/range.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/rational.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/re.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/select.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/signal.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/string.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/struct.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/thread.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/time.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/variable.h -shape.$(OBJEXT): {$(VPATH)}internal/intern/vm.h -shape.$(OBJEXT): {$(VPATH)}internal/interpreter.h -shape.$(OBJEXT): {$(VPATH)}internal/iterator.h -shape.$(OBJEXT): {$(VPATH)}internal/memory.h -shape.$(OBJEXT): {$(VPATH)}internal/method.h -shape.$(OBJEXT): {$(VPATH)}internal/module.h -shape.$(OBJEXT): {$(VPATH)}internal/newobj.h -shape.$(OBJEXT): {$(VPATH)}internal/rgengc.h -shape.$(OBJEXT): {$(VPATH)}internal/scan_args.h -shape.$(OBJEXT): {$(VPATH)}internal/special_consts.h -shape.$(OBJEXT): {$(VPATH)}internal/static_assert.h -shape.$(OBJEXT): {$(VPATH)}internal/stdalign.h -shape.$(OBJEXT): {$(VPATH)}internal/stdbool.h -shape.$(OBJEXT): {$(VPATH)}internal/symbol.h -shape.$(OBJEXT): {$(VPATH)}internal/value.h -shape.$(OBJEXT): {$(VPATH)}internal/value_type.h -shape.$(OBJEXT): {$(VPATH)}internal/variable.h -shape.$(OBJEXT): {$(VPATH)}internal/warning_push.h -shape.$(OBJEXT): {$(VPATH)}internal/xmalloc.h -shape.$(OBJEXT): {$(VPATH)}method.h -shape.$(OBJEXT): {$(VPATH)}missing.h -shape.$(OBJEXT): {$(VPATH)}node.h -shape.$(OBJEXT): {$(VPATH)}onigmo.h -shape.$(OBJEXT): {$(VPATH)}oniguruma.h -shape.$(OBJEXT): {$(VPATH)}ruby_assert.h -shape.$(OBJEXT): {$(VPATH)}ruby_atomic.h -shape.$(OBJEXT): {$(VPATH)}shape.c -shape.$(OBJEXT): {$(VPATH)}shape.h -shape.$(OBJEXT): {$(VPATH)}st.h -shape.$(OBJEXT): {$(VPATH)}subst.h -shape.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h -shape.$(OBJEXT): {$(VPATH)}thread_native.h -shape.$(OBJEXT): {$(VPATH)}vm_core.h -shape.$(OBJEXT): {$(VPATH)}vm_debug.h -shape.$(OBJEXT): {$(VPATH)}vm_opts.h -shape.$(OBJEXT): {$(VPATH)}vm_sync.h signal.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h signal.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h signal.$(OBJEXT): $(CCAN_DIR)/list/list.h @@ -14190,7 +13907,6 @@ signal.$(OBJEXT): $(top_srcdir)/internal/signal.h signal.$(OBJEXT): $(top_srcdir)/internal/static_assert.h signal.$(OBJEXT): $(top_srcdir)/internal/string.h signal.$(OBJEXT): $(top_srcdir)/internal/thread.h -signal.$(OBJEXT): $(top_srcdir)/internal/variable.h signal.$(OBJEXT): $(top_srcdir)/internal/vm.h signal.$(OBJEXT): $(top_srcdir)/internal/warnings.h signal.$(OBJEXT): {$(VPATH)}assert.h @@ -14205,7 +13921,6 @@ signal.$(OBJEXT): {$(VPATH)}backward/2/long_long.h signal.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h signal.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h signal.$(OBJEXT): {$(VPATH)}config.h -signal.$(OBJEXT): {$(VPATH)}constant.h signal.$(OBJEXT): {$(VPATH)}debug_counter.h signal.$(OBJEXT): {$(VPATH)}defines.h signal.$(OBJEXT): {$(VPATH)}encoding.h @@ -14372,7 +14087,6 @@ signal.$(OBJEXT): {$(VPATH)}ractor.h signal.$(OBJEXT): {$(VPATH)}ractor_core.h signal.$(OBJEXT): {$(VPATH)}ruby_assert.h signal.$(OBJEXT): {$(VPATH)}ruby_atomic.h -signal.$(OBJEXT): {$(VPATH)}shape.h signal.$(OBJEXT): {$(VPATH)}signal.c signal.$(OBJEXT): {$(VPATH)}st.h signal.$(OBJEXT): {$(VPATH)}subst.h @@ -14397,7 +14111,6 @@ sprintf.$(OBJEXT): $(top_srcdir)/internal/serial.h sprintf.$(OBJEXT): $(top_srcdir)/internal/static_assert.h sprintf.$(OBJEXT): $(top_srcdir)/internal/string.h sprintf.$(OBJEXT): $(top_srcdir)/internal/symbol.h -sprintf.$(OBJEXT): $(top_srcdir)/internal/variable.h sprintf.$(OBJEXT): $(top_srcdir)/internal/vm.h sprintf.$(OBJEXT): $(top_srcdir)/internal/warnings.h sprintf.$(OBJEXT): {$(VPATH)}assert.h @@ -14411,7 +14124,6 @@ sprintf.$(OBJEXT): {$(VPATH)}backward/2/long_long.h sprintf.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h sprintf.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h sprintf.$(OBJEXT): {$(VPATH)}config.h -sprintf.$(OBJEXT): {$(VPATH)}constant.h sprintf.$(OBJEXT): {$(VPATH)}defines.h sprintf.$(OBJEXT): {$(VPATH)}encoding.h sprintf.$(OBJEXT): {$(VPATH)}id.h @@ -14573,7 +14285,6 @@ sprintf.$(OBJEXT): {$(VPATH)}onigmo.h sprintf.$(OBJEXT): {$(VPATH)}oniguruma.h sprintf.$(OBJEXT): {$(VPATH)}re.h sprintf.$(OBJEXT): {$(VPATH)}regex.h -sprintf.$(OBJEXT): {$(VPATH)}shape.h sprintf.$(OBJEXT): {$(VPATH)}sprintf.c sprintf.$(OBJEXT): {$(VPATH)}st.h sprintf.$(OBJEXT): {$(VPATH)}subst.h @@ -14942,7 +14653,6 @@ string.$(OBJEXT): $(top_srcdir)/internal/serial.h string.$(OBJEXT): $(top_srcdir)/internal/static_assert.h string.$(OBJEXT): $(top_srcdir)/internal/string.h string.$(OBJEXT): $(top_srcdir)/internal/transcode.h -string.$(OBJEXT): $(top_srcdir)/internal/variable.h string.$(OBJEXT): $(top_srcdir)/internal/vm.h string.$(OBJEXT): $(top_srcdir)/internal/warnings.h string.$(OBJEXT): {$(VPATH)}assert.h @@ -14957,7 +14667,6 @@ string.$(OBJEXT): {$(VPATH)}backward/2/long_long.h string.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h string.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h string.$(OBJEXT): {$(VPATH)}config.h -string.$(OBJEXT): {$(VPATH)}constant.h string.$(OBJEXT): {$(VPATH)}debug_counter.h string.$(OBJEXT): {$(VPATH)}defines.h string.$(OBJEXT): {$(VPATH)}encindex.h @@ -15125,7 +14834,6 @@ string.$(OBJEXT): {$(VPATH)}probes.h string.$(OBJEXT): {$(VPATH)}re.h string.$(OBJEXT): {$(VPATH)}regex.h string.$(OBJEXT): {$(VPATH)}ruby_assert.h -string.$(OBJEXT): {$(VPATH)}shape.h string.$(OBJEXT): {$(VPATH)}st.h string.$(OBJEXT): {$(VPATH)}string.c string.$(OBJEXT): {$(VPATH)}subst.h @@ -15182,7 +14890,6 @@ struct.$(OBJEXT): $(top_srcdir)/internal/static_assert.h struct.$(OBJEXT): $(top_srcdir)/internal/string.h struct.$(OBJEXT): $(top_srcdir)/internal/struct.h struct.$(OBJEXT): $(top_srcdir)/internal/symbol.h -struct.$(OBJEXT): $(top_srcdir)/internal/variable.h struct.$(OBJEXT): $(top_srcdir)/internal/vm.h struct.$(OBJEXT): $(top_srcdir)/internal/warnings.h struct.$(OBJEXT): {$(VPATH)}assert.h @@ -15198,7 +14905,6 @@ struct.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h struct.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h struct.$(OBJEXT): {$(VPATH)}builtin.h struct.$(OBJEXT): {$(VPATH)}config.h -struct.$(OBJEXT): {$(VPATH)}constant.h struct.$(OBJEXT): {$(VPATH)}defines.h struct.$(OBJEXT): {$(VPATH)}encoding.h struct.$(OBJEXT): {$(VPATH)}id.h @@ -15361,7 +15067,6 @@ struct.$(OBJEXT): {$(VPATH)}onigmo.h struct.$(OBJEXT): {$(VPATH)}oniguruma.h struct.$(OBJEXT): {$(VPATH)}ruby_assert.h struct.$(OBJEXT): {$(VPATH)}ruby_atomic.h -struct.$(OBJEXT): {$(VPATH)}shape.h struct.$(OBJEXT): {$(VPATH)}st.h struct.$(OBJEXT): {$(VPATH)}struct.c struct.$(OBJEXT): {$(VPATH)}subst.h @@ -15381,7 +15086,6 @@ symbol.$(OBJEXT): $(top_srcdir)/internal/serial.h symbol.$(OBJEXT): $(top_srcdir)/internal/static_assert.h symbol.$(OBJEXT): $(top_srcdir)/internal/string.h symbol.$(OBJEXT): $(top_srcdir)/internal/symbol.h -symbol.$(OBJEXT): $(top_srcdir)/internal/variable.h symbol.$(OBJEXT): $(top_srcdir)/internal/vm.h symbol.$(OBJEXT): $(top_srcdir)/internal/warnings.h symbol.$(OBJEXT): {$(VPATH)}assert.h @@ -15395,7 +15099,6 @@ symbol.$(OBJEXT): {$(VPATH)}backward/2/long_long.h symbol.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h symbol.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h symbol.$(OBJEXT): {$(VPATH)}config.h -symbol.$(OBJEXT): {$(VPATH)}constant.h symbol.$(OBJEXT): {$(VPATH)}debug_counter.h symbol.$(OBJEXT): {$(VPATH)}defines.h symbol.$(OBJEXT): {$(VPATH)}encoding.h @@ -15561,7 +15264,6 @@ symbol.$(OBJEXT): {$(VPATH)}oniguruma.h symbol.$(OBJEXT): {$(VPATH)}probes.dmyh symbol.$(OBJEXT): {$(VPATH)}probes.h symbol.$(OBJEXT): {$(VPATH)}ruby_assert.h -symbol.$(OBJEXT): {$(VPATH)}shape.h symbol.$(OBJEXT): {$(VPATH)}st.h symbol.$(OBJEXT): {$(VPATH)}subst.h symbol.$(OBJEXT): {$(VPATH)}symbol.c @@ -15592,7 +15294,6 @@ thread.$(OBJEXT): $(top_srcdir)/internal/static_assert.h thread.$(OBJEXT): $(top_srcdir)/internal/string.h thread.$(OBJEXT): $(top_srcdir)/internal/thread.h thread.$(OBJEXT): $(top_srcdir)/internal/time.h -thread.$(OBJEXT): $(top_srcdir)/internal/variable.h thread.$(OBJEXT): $(top_srcdir)/internal/vm.h thread.$(OBJEXT): $(top_srcdir)/internal/warnings.h thread.$(OBJEXT): {$(VPATH)}assert.h @@ -15608,7 +15309,6 @@ thread.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h thread.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h thread.$(OBJEXT): {$(VPATH)}builtin.h thread.$(OBJEXT): {$(VPATH)}config.h -thread.$(OBJEXT): {$(VPATH)}constant.h thread.$(OBJEXT): {$(VPATH)}debug.h thread.$(OBJEXT): {$(VPATH)}debug_counter.h thread.$(OBJEXT): {$(VPATH)}defines.h @@ -15782,7 +15482,6 @@ thread.$(OBJEXT): {$(VPATH)}ractor.h thread.$(OBJEXT): {$(VPATH)}ractor_core.h thread.$(OBJEXT): {$(VPATH)}ruby_assert.h thread.$(OBJEXT): {$(VPATH)}ruby_atomic.h -thread.$(OBJEXT): {$(VPATH)}shape.h thread.$(OBJEXT): {$(VPATH)}st.h thread.$(OBJEXT): {$(VPATH)}subst.h thread.$(OBJEXT): {$(VPATH)}thread.c @@ -16003,7 +15702,6 @@ transcode.$(OBJEXT): $(top_srcdir)/internal/serial.h transcode.$(OBJEXT): $(top_srcdir)/internal/static_assert.h transcode.$(OBJEXT): $(top_srcdir)/internal/string.h transcode.$(OBJEXT): $(top_srcdir)/internal/transcode.h -transcode.$(OBJEXT): $(top_srcdir)/internal/variable.h transcode.$(OBJEXT): $(top_srcdir)/internal/warnings.h transcode.$(OBJEXT): {$(VPATH)}assert.h transcode.$(OBJEXT): {$(VPATH)}backward/2/assume.h @@ -16016,7 +15714,6 @@ transcode.$(OBJEXT): {$(VPATH)}backward/2/long_long.h transcode.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h transcode.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h transcode.$(OBJEXT): {$(VPATH)}config.h -transcode.$(OBJEXT): {$(VPATH)}constant.h transcode.$(OBJEXT): {$(VPATH)}defines.h transcode.$(OBJEXT): {$(VPATH)}encoding.h transcode.$(OBJEXT): {$(VPATH)}id.h @@ -16175,7 +15872,6 @@ transcode.$(OBJEXT): {$(VPATH)}internal/xmalloc.h transcode.$(OBJEXT): {$(VPATH)}missing.h transcode.$(OBJEXT): {$(VPATH)}onigmo.h transcode.$(OBJEXT): {$(VPATH)}oniguruma.h -transcode.$(OBJEXT): {$(VPATH)}shape.h transcode.$(OBJEXT): {$(VPATH)}st.h transcode.$(OBJEXT): {$(VPATH)}subst.h transcode.$(OBJEXT): {$(VPATH)}transcode.c @@ -16725,7 +16421,6 @@ variable.$(OBJEXT): {$(VPATH)}ractor.h variable.$(OBJEXT): {$(VPATH)}ractor_core.h variable.$(OBJEXT): {$(VPATH)}ruby_assert.h variable.$(OBJEXT): {$(VPATH)}ruby_atomic.h -variable.$(OBJEXT): {$(VPATH)}shape.h variable.$(OBJEXT): {$(VPATH)}st.h variable.$(OBJEXT): {$(VPATH)}subst.h variable.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -16751,7 +16446,6 @@ version.$(OBJEXT): $(top_srcdir)/internal/gc.h version.$(OBJEXT): $(top_srcdir)/internal/imemo.h version.$(OBJEXT): $(top_srcdir)/internal/serial.h version.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -version.$(OBJEXT): $(top_srcdir)/internal/variable.h version.$(OBJEXT): $(top_srcdir)/internal/vm.h version.$(OBJEXT): $(top_srcdir)/internal/warnings.h version.$(OBJEXT): $(top_srcdir)/revision.h @@ -16768,11 +16462,9 @@ version.$(OBJEXT): {$(VPATH)}backward/2/long_long.h version.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h version.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h version.$(OBJEXT): {$(VPATH)}config.h -version.$(OBJEXT): {$(VPATH)}constant.h version.$(OBJEXT): {$(VPATH)}debug_counter.h version.$(OBJEXT): {$(VPATH)}defines.h version.$(OBJEXT): {$(VPATH)}id.h -version.$(OBJEXT): {$(VPATH)}id_table.h version.$(OBJEXT): {$(VPATH)}intern.h version.$(OBJEXT): {$(VPATH)}internal.h version.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -16921,7 +16613,6 @@ version.$(OBJEXT): {$(VPATH)}mjit.h version.$(OBJEXT): {$(VPATH)}node.h version.$(OBJEXT): {$(VPATH)}ruby_assert.h version.$(OBJEXT): {$(VPATH)}ruby_atomic.h -version.$(OBJEXT): {$(VPATH)}shape.h version.$(OBJEXT): {$(VPATH)}st.h version.$(OBJEXT): {$(VPATH)}subst.h version.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -17157,7 +16848,6 @@ vm.$(OBJEXT): {$(VPATH)}ractor.h vm.$(OBJEXT): {$(VPATH)}ractor_core.h vm.$(OBJEXT): {$(VPATH)}ruby_assert.h vm.$(OBJEXT): {$(VPATH)}ruby_atomic.h -vm.$(OBJEXT): {$(VPATH)}shape.h vm.$(OBJEXT): {$(VPATH)}st.h vm.$(OBJEXT): {$(VPATH)}subst.h vm.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -17194,7 +16884,6 @@ vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/string.h -vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/warnings.h vm_backtrace.$(OBJEXT): {$(VPATH)}assert.h @@ -17209,13 +16898,11 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/long_long.h vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h vm_backtrace.$(OBJEXT): {$(VPATH)}config.h -vm_backtrace.$(OBJEXT): {$(VPATH)}constant.h vm_backtrace.$(OBJEXT): {$(VPATH)}debug.h vm_backtrace.$(OBJEXT): {$(VPATH)}defines.h vm_backtrace.$(OBJEXT): {$(VPATH)}encoding.h vm_backtrace.$(OBJEXT): {$(VPATH)}eval_intern.h vm_backtrace.$(OBJEXT): {$(VPATH)}id.h -vm_backtrace.$(OBJEXT): {$(VPATH)}id_table.h vm_backtrace.$(OBJEXT): {$(VPATH)}intern.h vm_backtrace.$(OBJEXT): {$(VPATH)}internal.h vm_backtrace.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -17375,7 +17062,6 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}onigmo.h vm_backtrace.$(OBJEXT): {$(VPATH)}oniguruma.h vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_assert.h vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_atomic.h -vm_backtrace.$(OBJEXT): {$(VPATH)}shape.h vm_backtrace.$(OBJEXT): {$(VPATH)}st.h vm_backtrace.$(OBJEXT): {$(VPATH)}subst.h vm_backtrace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -17566,7 +17252,6 @@ vm_dump.$(OBJEXT): {$(VPATH)}ractor.h vm_dump.$(OBJEXT): {$(VPATH)}ractor_core.h vm_dump.$(OBJEXT): {$(VPATH)}ruby_assert.h vm_dump.$(OBJEXT): {$(VPATH)}ruby_atomic.h -vm_dump.$(OBJEXT): {$(VPATH)}shape.h vm_dump.$(OBJEXT): {$(VPATH)}st.h vm_dump.$(OBJEXT): {$(VPATH)}subst.h vm_dump.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -17586,7 +17271,6 @@ vm_sync.$(OBJEXT): $(top_srcdir)/internal/gc.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/static_assert.h -vm_sync.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/warnings.h vm_sync.$(OBJEXT): {$(VPATH)}assert.h @@ -17601,7 +17285,6 @@ vm_sync.$(OBJEXT): {$(VPATH)}backward/2/long_long.h vm_sync.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h vm_sync.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h vm_sync.$(OBJEXT): {$(VPATH)}config.h -vm_sync.$(OBJEXT): {$(VPATH)}constant.h vm_sync.$(OBJEXT): {$(VPATH)}debug_counter.h vm_sync.$(OBJEXT): {$(VPATH)}defines.h vm_sync.$(OBJEXT): {$(VPATH)}gc.h @@ -17756,7 +17439,6 @@ vm_sync.$(OBJEXT): {$(VPATH)}ractor.h vm_sync.$(OBJEXT): {$(VPATH)}ractor_core.h vm_sync.$(OBJEXT): {$(VPATH)}ruby_assert.h vm_sync.$(OBJEXT): {$(VPATH)}ruby_atomic.h -vm_sync.$(OBJEXT): {$(VPATH)}shape.h vm_sync.$(OBJEXT): {$(VPATH)}st.h vm_sync.$(OBJEXT): {$(VPATH)}subst.h vm_sync.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -17780,7 +17462,6 @@ vm_trace.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/symbol.h -vm_trace.$(OBJEXT): $(top_srcdir)/internal/variable.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/vm.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/warnings.h vm_trace.$(OBJEXT): {$(VPATH)}assert.h @@ -17796,14 +17477,12 @@ vm_trace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h vm_trace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h vm_trace.$(OBJEXT): {$(VPATH)}builtin.h vm_trace.$(OBJEXT): {$(VPATH)}config.h -vm_trace.$(OBJEXT): {$(VPATH)}constant.h vm_trace.$(OBJEXT): {$(VPATH)}debug.h vm_trace.$(OBJEXT): {$(VPATH)}debug_counter.h vm_trace.$(OBJEXT): {$(VPATH)}defines.h vm_trace.$(OBJEXT): {$(VPATH)}encoding.h vm_trace.$(OBJEXT): {$(VPATH)}eval_intern.h vm_trace.$(OBJEXT): {$(VPATH)}id.h -vm_trace.$(OBJEXT): {$(VPATH)}id_table.h vm_trace.$(OBJEXT): {$(VPATH)}intern.h vm_trace.$(OBJEXT): {$(VPATH)}internal.h vm_trace.$(OBJEXT): {$(VPATH)}internal/abi.h @@ -17965,7 +17644,6 @@ vm_trace.$(OBJEXT): {$(VPATH)}oniguruma.h vm_trace.$(OBJEXT): {$(VPATH)}ractor.h vm_trace.$(OBJEXT): {$(VPATH)}ruby_assert.h vm_trace.$(OBJEXT): {$(VPATH)}ruby_atomic.h -vm_trace.$(OBJEXT): {$(VPATH)}shape.h vm_trace.$(OBJEXT): {$(VPATH)}st.h vm_trace.$(OBJEXT): {$(VPATH)}subst.h vm_trace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h @@ -2058,7 +2058,20 @@ cdhash_set_label_i(VALUE key, VALUE val, VALUE ptr) static inline VALUE get_ivar_ic_value(rb_iseq_t *iseq,ID id) { - return INT2FIX(ISEQ_BODY(iseq)->ivc_size++); + VALUE val; + struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table; + if (tbl) { + if (rb_id_table_lookup(tbl,id,&val)) { + return val; + } + } + else { + tbl = rb_id_table_create(1); + ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl; + } + val = INT2FIX(ISEQ_BODY(iseq)->ivc_size++); + rb_id_table_insert(tbl,id,val); + return val; } static inline VALUE @@ -2459,13 +2472,9 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) generated_iseq[code_index + 1 + j] = (VALUE)ic; } break; - case TS_IVC: /* inline ivar cache */ - { - unsigned int ic_index = FIX2UINT(operands[j]); - vm_ic_attr_index_initialize(((IVC)&body->is_entries[ic_index]), INVALID_SHAPE_ID); - } case TS_ISE: /* inline storage entry: `once` insn */ case TS_ICVARC: /* inline cvar cache */ + case TS_IVC: /* inline ivar cache */ { unsigned int ic_index = FIX2UINT(operands[j]); IC ic = &ISEQ_IS_ENTRY_START(body, type)[ic_index].ic_cache; @@ -11505,11 +11514,6 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod ISE ic = ISEQ_IS_ENTRY_START(load_body, operand_type) + op; code[code_index] = (VALUE)ic; - - if (operand_type == TS_IVC) { - vm_ic_attr_index_initialize(((IVC)code[code_index]), INVALID_SHAPE_ID); - } - } break; case TS_CALLDATA: diff --git a/debug_counter.h b/debug_counter.h index f3a799913b..c6f4176e97 100644 --- a/debug_counter.h +++ b/debug_counter.h @@ -130,6 +130,7 @@ RB_DEBUG_COUNTER(frame_C2R) /* instance variable counts * * * ivar_get_ic_hit/miss: ivar_get inline cache (ic) hit/miss counts (VM insn) + * * ivar_get_ic_miss_serial: ivar_get ic miss reason by serial (VM insn) * * ivar_get_ic_miss_unset: ... by unset (VM insn) * * ivar_get_ic_miss_noobject: ... by "not T_OBJECT" (VM insn) * * ivar_set_...: same counts with ivar_set (VM insn) @@ -139,17 +140,17 @@ RB_DEBUG_COUNTER(frame_C2R) */ RB_DEBUG_COUNTER(ivar_get_ic_hit) RB_DEBUG_COUNTER(ivar_get_ic_miss) +RB_DEBUG_COUNTER(ivar_get_ic_miss_serial) +RB_DEBUG_COUNTER(ivar_get_ic_miss_unset) RB_DEBUG_COUNTER(ivar_get_ic_miss_noobject) RB_DEBUG_COUNTER(ivar_set_ic_hit) RB_DEBUG_COUNTER(ivar_set_ic_miss) +RB_DEBUG_COUNTER(ivar_set_ic_miss_serial) +RB_DEBUG_COUNTER(ivar_set_ic_miss_unset) RB_DEBUG_COUNTER(ivar_set_ic_miss_iv_hit) RB_DEBUG_COUNTER(ivar_set_ic_miss_noobject) RB_DEBUG_COUNTER(ivar_get_base) RB_DEBUG_COUNTER(ivar_set_base) -RB_DEBUG_COUNTER(ivar_get_ic_miss_set) -RB_DEBUG_COUNTER(ivar_get_cc_miss_set) -RB_DEBUG_COUNTER(ivar_get_ic_miss_unset) -RB_DEBUG_COUNTER(ivar_get_cc_miss_unset) /* local variable counts * diff --git a/ext/coverage/depend b/ext/coverage/depend index 719c6c6e79..57d368d3f5 100644 --- a/ext/coverage/depend +++ b/ext/coverage/depend @@ -165,9 +165,7 @@ coverage.o: $(top_srcdir)/ccan/check_type/check_type.h coverage.o: $(top_srcdir)/ccan/container_of/container_of.h coverage.o: $(top_srcdir)/ccan/list/list.h coverage.o: $(top_srcdir)/ccan/str/str.h -coverage.o: $(top_srcdir)/constant.h coverage.o: $(top_srcdir)/gc.h -coverage.o: $(top_srcdir)/id_table.h coverage.o: $(top_srcdir)/internal.h coverage.o: $(top_srcdir)/internal/array.h coverage.o: $(top_srcdir)/internal/compilers.h @@ -178,14 +176,12 @@ coverage.o: $(top_srcdir)/internal/sanitizers.h coverage.o: $(top_srcdir)/internal/serial.h coverage.o: $(top_srcdir)/internal/static_assert.h coverage.o: $(top_srcdir)/internal/thread.h -coverage.o: $(top_srcdir)/internal/variable.h coverage.o: $(top_srcdir)/internal/vm.h coverage.o: $(top_srcdir)/internal/warnings.h coverage.o: $(top_srcdir)/method.h coverage.o: $(top_srcdir)/node.h coverage.o: $(top_srcdir)/ruby_assert.h coverage.o: $(top_srcdir)/ruby_atomic.h -coverage.o: $(top_srcdir)/shape.h coverage.o: $(top_srcdir)/thread_pthread.h coverage.o: $(top_srcdir)/vm_core.h coverage.o: $(top_srcdir)/vm_opts.h diff --git a/ext/objspace/depend b/ext/objspace/depend index 88c66a232b..c4da8031cc 100644 --- a/ext/objspace/depend +++ b/ext/objspace/depend @@ -350,7 +350,6 @@ objspace.o: $(top_srcdir)/internal/serial.h objspace.o: $(top_srcdir)/internal/static_assert.h objspace.o: $(top_srcdir)/internal/warnings.h objspace.o: $(top_srcdir)/node.h -objspace.o: $(top_srcdir)/shape.h objspace.o: $(top_srcdir)/symbol.h objspace.o: objspace.c objspace.o: {$(VPATH)}id.h @@ -534,9 +533,7 @@ 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)/constant.h objspace_dump.o: $(top_srcdir)/gc.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/compilers.h @@ -547,14 +544,12 @@ objspace_dump.o: $(top_srcdir)/internal/sanitizers.h objspace_dump.o: $(top_srcdir)/internal/serial.h objspace_dump.o: $(top_srcdir)/internal/static_assert.h objspace_dump.o: $(top_srcdir)/internal/string.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)/shape.h objspace_dump.o: $(top_srcdir)/thread_pthread.h objspace_dump.o: $(top_srcdir)/vm_core.h objspace_dump.o: $(top_srcdir)/vm_opts.h @@ -2895,7 +2895,8 @@ rb_class_instance_allocate_internal(VALUE klass, VALUE flags, bool wb_protected) GC_ASSERT((flags & RUBY_T_MASK) == T_OBJECT); GC_ASSERT(flags & ROBJECT_EMBED); - uint32_t index_tbl_num_entries = RCLASS_EXT(klass)->max_iv_count; + st_table *index_tbl = RCLASS_IV_INDEX_TBL(klass); + uint32_t index_tbl_num_entries = index_tbl == NULL ? 0 : (uint32_t)index_tbl->num_entries; size_t size; bool embed = true; @@ -2930,7 +2931,7 @@ rb_class_instance_allocate_internal(VALUE klass, VALUE flags, bool wb_protected) #endif } else { - rb_ensure_iv_list_size(obj, 0, index_tbl_num_entries); + rb_init_iv_list(obj); } return obj; @@ -3205,6 +3206,20 @@ rb_free_const_table(struct rb_id_table *tbl) rb_id_table_free(tbl); } +static int +free_iv_index_tbl_free_i(st_data_t key, st_data_t value, st_data_t data) +{ + xfree((void *)value); + return ST_CONTINUE; +} + +static void +iv_index_tbl_free(struct st_table *tbl) +{ + st_foreach(tbl, free_iv_index_tbl_free_i, 0); + st_free_table(tbl); +} + // alive: if false, target pointers can be freed already. // To check it, we need objspace parameter. static void @@ -3420,16 +3435,6 @@ obj_free(rb_objspace_t *objspace, VALUE obj) RB_DEBUG_COUNTER_INC(obj_obj_transient); } else { - rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj)); - if (shape) { - VALUE klass = RBASIC_CLASS(obj); - - // Increment max_iv_count if applicable, used to determine size pool allocation - uint32_t num_of_ivs = shape->iv_count; - if (RCLASS_EXT(klass)->max_iv_count < num_of_ivs) { - RCLASS_EXT(klass)->max_iv_count = num_of_ivs; - } - } xfree(RANY(obj)->as.object.as.heap.ivptr); RB_DEBUG_COUNTER_INC(obj_obj_ptr); } @@ -3444,6 +3449,9 @@ obj_free(rb_objspace_t *objspace, VALUE obj) if (RCLASS_CONST_TBL(obj)) { rb_free_const_table(RCLASS_CONST_TBL(obj)); } + if (RCLASS_IV_INDEX_TBL(obj)) { + iv_index_tbl_free(RCLASS_IV_INDEX_TBL(obj)); + } if (RCLASS_CVC_TBL(obj)) { rb_id_table_foreach_values(RCLASS_CVC_TBL(obj), cvar_table_free_i, NULL); rb_id_table_free(RCLASS_CVC_TBL(obj)); @@ -4865,6 +4873,10 @@ obj_memsize_of(VALUE obj, int use_all_types) if (RCLASS_CVC_TBL(obj)) { size += rb_id_table_memsize(RCLASS_CVC_TBL(obj)); } + if (RCLASS_IV_INDEX_TBL(obj)) { + // TODO: more correct value + size += st_memsize(RCLASS_IV_INDEX_TBL(obj)); + } if (RCLASS_EXT(obj)->iv_tbl) { size += st_memsize(RCLASS_EXT(obj)->iv_tbl); } @@ -10395,6 +10407,15 @@ update_subclass_entries(rb_objspace_t *objspace, rb_subclass_entry_t *entry) } } +static int +update_iv_index_tbl_i(st_data_t key, st_data_t value, st_data_t arg) +{ + rb_objspace_t *objspace = (rb_objspace_t *)arg; + struct rb_iv_index_tbl_entry *ent = (struct rb_iv_index_tbl_entry *)value; + UPDATE_IF_MOVED(objspace, ent->class_value); + return ST_CONTINUE; +} + static void update_class_ext(rb_objspace_t *objspace, rb_classext_t *ext) { @@ -10402,6 +10423,11 @@ update_class_ext(rb_objspace_t *objspace, rb_classext_t *ext) UPDATE_IF_MOVED(objspace, ext->includer); UPDATE_IF_MOVED(objspace, ext->refined_class); update_subclass_entries(objspace, ext->subclasses); + + // ext->iv_index_tbl + if (ext->iv_index_tbl) { + st_foreach(ext->iv_index_tbl, update_iv_index_tbl_i, (st_data_t)objspace); + } } static void diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h index bec0b45fd4..7823061d8f 100644 --- a/include/ruby/internal/core/robject.h +++ b/include/ruby/internal/core/robject.h @@ -46,6 +46,7 @@ #define ROBJECT_EMBED ROBJECT_EMBED #define ROBJECT_NUMIV ROBJECT_NUMIV #define ROBJECT_IVPTR ROBJECT_IVPTR +#define ROBJECT_IV_INDEX_TBL ROBJECT_IV_INDEX_TBL /** @endcond */ /** @@ -131,7 +132,7 @@ struct RObject { * * This is a shortcut for `RCLASS_IV_INDEX_TBL(rb_obj_class(obj))`. */ - struct rb_id_table *iv_index_tbl; + struct st_table *iv_index_tbl; } heap; #if USE_RVARGC diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h index 7383426b23..c51bd2e9d9 100644 --- a/include/ruby/internal/fl_type.h +++ b/include/ruby/internal/fl_type.h @@ -941,8 +941,21 @@ RB_OBJ_FREEZE_RAW(VALUE obj) RB_FL_SET_RAW(obj, RUBY_FL_FREEZE); } -RUBY_SYMBOL_EXPORT_BEGIN -void rb_obj_freeze_inline(VALUE obj); -RUBY_SYMBOL_EXPORT_END +/** + * Prevents further modifications to the given object. ::rb_eFrozenError shall + * be raised if modification is attempted. + * + * @param[out] x Object in question. + */ +static inline void +rb_obj_freeze_inline(VALUE x) +{ + if (RB_FL_ABLE(x)) { + RB_OBJ_FREEZE_RAW(x); + if (RBASIC_CLASS(x) && !(RBASIC(x)->flags & RUBY_FL_SINGLETON)) { + rb_freeze_singleton_class(x); + } + } +} #endif /* RBIMPL_FL_TYPE_H */ @@ -77,7 +77,6 @@ rb_call_inits(void) CALL(vm_stack_canary); CALL(ast); CALL(gc_stress); - CALL(shape); // enable builtin loading CALL(builtin); diff --git a/internal.h b/internal.h index 695c9cfb7e..0740ae99e5 100644 --- a/internal.h +++ b/internal.h @@ -48,6 +48,9 @@ #undef RHASH_TBL #undef RHASH_EMPTY_P +/* internal/object.h */ +#undef ROBJECT_IV_INDEX_TBL + /* internal/struct.h */ #undef RSTRUCT_LEN #undef RSTRUCT_PTR diff --git a/internal/class.h b/internal/class.h index 4a3e09ddc7..ae680564a6 100644 --- a/internal/class.h +++ b/internal/class.h @@ -14,7 +14,6 @@ #include "ruby/internal/stdbool.h" /* for bool */ #include "ruby/intern.h" /* for rb_alloc_func_t */ #include "ruby/ruby.h" /* for struct RBasic */ -#include "shape.h" #ifdef RCLASS_SUPER # undef RCLASS_SUPER @@ -28,8 +27,8 @@ struct rb_subclass_entry { struct rb_iv_index_tbl_entry { uint32_t index; - shape_id_t source_shape_id; - shape_id_t dest_shape_id; + rb_serial_t class_serial; + VALUE class_value; }; struct rb_cvar_class_tbl_entry { @@ -39,6 +38,7 @@ struct rb_cvar_class_tbl_entry { }; struct rb_classext_struct { + struct st_table *iv_index_tbl; // ID -> struct rb_iv_index_tbl_entry struct st_table *iv_tbl; #if SIZEOF_SERIAL_T == SIZEOF_VALUE /* otherwise m_tbl is in struct RClass */ struct rb_id_table *m_tbl; @@ -64,10 +64,6 @@ struct rb_classext_struct { const VALUE refined_class; rb_alloc_func_t allocator; const VALUE includer; - uint32_t max_iv_count; -#if !SHAPE_IN_BASIC_FLAGS - shape_id_t shape_id; -#endif }; struct RClass { @@ -106,6 +102,7 @@ typedef struct rb_classext_struct rb_classext_t; #define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl) #define RCLASS_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl) #define RCLASS_CVC_TBL(c) (RCLASS_EXT(c)->cvc_tbl) +#define RCLASS_IV_INDEX_TBL(c) (RCLASS_EXT(c)->iv_index_tbl) #define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin_) #define RCLASS_REFINED_CLASS(c) (RCLASS_EXT(c)->refined_class) #if SIZEOF_SERIAL_T == SIZEOF_VALUE diff --git a/internal/object.h b/internal/object.h index 7b54e13dd2..88f3a44bc6 100644 --- a/internal/object.h +++ b/internal/object.h @@ -9,6 +9,11 @@ * @brief Internal header for Object. */ #include "ruby/ruby.h" /* for VALUE */ +#include "internal/class.h" /* for RCLASS_IV_INDEX_TBL */ + +#ifdef ROBJECT_IV_INDEX_TBL +# undef ROBJECT_IV_INDEX_TBL +#endif /* object.c */ VALUE rb_class_search_ancestor(VALUE klass, VALUE super); @@ -21,6 +26,7 @@ int rb_bool_expected(VALUE, const char *, int raise); static inline void RBASIC_CLEAR_CLASS(VALUE obj); static inline void RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass); static inline void RBASIC_SET_CLASS(VALUE obj, VALUE klass); +static inline struct st_table *ROBJECT_IV_INDEX_TBL_inline(VALUE obj); RUBY_SYMBOL_EXPORT_BEGIN /* object.c (export) */ @@ -58,4 +64,20 @@ RBASIC_SET_CLASS(VALUE obj, VALUE klass) RBASIC_SET_CLASS_RAW(obj, klass); RB_OBJ_WRITTEN(obj, oldv, klass); } + +RBIMPL_ATTR_PURE() +static inline struct st_table * +ROBJECT_IV_INDEX_TBL_inline(VALUE obj) +{ + if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) { + VALUE klass = rb_obj_class(obj); + return RCLASS_IV_INDEX_TBL(klass); + } + else { + const struct RObject *const ptr = ROBJECT(obj); + return ptr->as.heap.iv_index_tbl; + } +} +#define ROBJECT_IV_INDEX_TBL ROBJECT_IV_INDEX_TBL_inline + #endif /* INTERNAL_OBJECT_H */ diff --git a/internal/variable.h b/internal/variable.h index 47037a3392..1a19e8964b 100644 --- a/internal/variable.h +++ b/internal/variable.h @@ -37,9 +37,6 @@ static inline void ROBJ_TRANSIENT_SET(VALUE obj); static inline void ROBJ_TRANSIENT_UNSET(VALUE obj); uint32_t rb_obj_ensure_iv_index_mapping(VALUE obj, ID id); -struct gen_ivtbl; -int rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl); - RUBY_SYMBOL_EXPORT_BEGIN /* variable.c (export) */ void rb_mark_generic_ivar(VALUE); @@ -55,8 +52,6 @@ VALUE rb_gvar_set(ID, VALUE); VALUE rb_gvar_defined(ID); void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID); void rb_init_iv_list(VALUE obj); -void rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize); -struct gen_ivtbl * rb_ensure_generic_iv_list_size(VALUE obj, uint32_t newsize); MJIT_SYMBOL_EXPORT_END static inline bool @@ -230,8 +230,18 @@ rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data) union iseq_inline_storage_entry *is_entries = body->is_entries; if (body->is_entries) { - // Skip iterating over ivc caches - is_entries += body->ivc_size; + // IVC entries + for (unsigned int i = 0; i < body->ivc_size; i++, is_entries++) { + IVC ivc = (IVC)is_entries; + if (ivc->entry) { + RUBY_ASSERT(!RB_TYPE_P(ivc->entry->class_value, T_NONE)); + + VALUE nv = func(data, ivc->entry->class_value); + if (ivc->entry->class_value != nv) { + ivc->entry->class_value = nv; + } + } + } // ICVARC entries for (unsigned int i = 0; i < body->icvarc_size; i++, is_entries++) { diff --git a/lib/mjit/compiler.rb b/lib/mjit/compiler.rb index 06f018c934..49f28ab690 100644 --- a/lib/mjit/compiler.rb +++ b/lib/mjit/compiler.rb @@ -73,6 +73,23 @@ module RubyVM::MJIT src << "#undef GET_SELF\n" src << "#define GET_SELF() cfp_self\n" + # Generate merged ivar guards first if needed + if !status.compile_info.disable_ivar_cache && status.merge_ivar_guards_p + src << " if (UNLIKELY(!(RB_TYPE_P(GET_SELF(), T_OBJECT) && (rb_serial_t)#{status.ivar_serial} == RCLASS_SERIAL(RBASIC(GET_SELF())->klass) &&" + if USE_RVARGC + src << "#{status.max_ivar_index} < ROBJECT_NUMIV(GET_SELF())" # index < ROBJECT_NUMIV(obj) + else + if status.max_ivar_index >= ROBJECT_EMBED_LEN_MAX + src << "#{status.max_ivar_index} < ROBJECT_NUMIV(GET_SELF())" # index < ROBJECT_NUMIV(obj) && !RB_FL_ANY_RAW(obj, ROBJECT_EMBED) + else + src << "ROBJECT_EMBED_LEN_MAX == ROBJECT_NUMIV(GET_SELF())" # index < ROBJECT_NUMIV(obj) && RB_FL_ANY_RAW(obj, ROBJECT_EMBED) + end + end + src << "))) {\n" + src << " goto ivar_cancel;\n" + src << " }\n" + end + # Simulate `opt_pc` in setup_parameters_complex. Other PCs which may be passed by catch tables # are not considered since vm_exec doesn't call jit_exec for catch tables. if iseq.body.param.flags.has_opt @@ -86,13 +103,6 @@ module RubyVM::MJIT src << " }\n" end - # Generate merged ivar guards first if needed - if !status.compile_info.disable_ivar_cache && status.merge_ivar_guards_p - src << " if (UNLIKELY(!(RB_TYPE_P(GET_SELF(), T_OBJECT)))) {" - src << " goto ivar_cancel;\n" - src << " }\n" - end - C.fprintf(f, src) compile_insns(0, 0, status, iseq.body, f) compile_cancel_handler(f, iseq.body, status) @@ -353,37 +363,52 @@ module RubyVM::MJIT ic_copy = (status.is_entries + (C.iseq_inline_storage_entry.new(operands[1]) - body.is_entries)).iv_cache src = +'' - if !status.compile_info.disable_ivar_cache && ic_copy.source_shape_id != C.INVALID_SHAPE_ID + if !status.compile_info.disable_ivar_cache && ic_copy.entry # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`. # compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos) # JIT: prepare vm_getivar/vm_setivar arguments and variables src << "{\n" src << " VALUE obj = GET_SELF();\n" - src << " const shape_id_t source_shape_id = (rb_serial_t)#{ic_copy.source_shape_id};\n" - # JIT: cache hit path of vm_getivar/vm_setivar, or cancel JIT (recompile it with exivar) - if insn_name == :setinstancevariable - src << " const uint32_t index = #{ic_copy.attr_index - 1};\n" - src << " const shape_id_t dest_shape_id = (rb_serial_t)#{ic_copy.dest_shape_id};\n" - src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj) && \n" - src << " dest_shape_id != ROBJECT_SHAPE_ID(obj)) {\n" - src << " if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) {\n" - src << " rb_init_iv_list(obj);\n" - src << " }\n" - src << " ROBJECT_SET_SHAPE_ID(obj, dest_shape_id);\n" - src << " VALUE *ptr = ROBJECT_IVPTR(obj);\n" - src << " RB_OBJ_WRITE(obj, &ptr[index], stack[#{stack_size - 1}]);\n" - src << " }\n" + src << " const uint32_t index = #{ic_copy.entry.index};\n" + if status.merge_ivar_guards_p + # JIT: Access ivar without checking these VM_ASSERTed prerequisites as we checked them in the beginning of `mjit_compile_body` + src << " VM_ASSERT(RB_TYPE_P(obj, T_OBJECT));\n" + src << " VM_ASSERT((rb_serial_t)#{ic_copy.entry.class_serial} == RCLASS_SERIAL(RBASIC(obj)->klass));\n" + src << " VM_ASSERT(index < ROBJECT_NUMIV(obj));\n" + if insn_name == :setinstancevariable + if USE_RVARGC + src << " if (LIKELY(!RB_OBJ_FROZEN_RAW(obj) && index < ROBJECT_NUMIV(obj))) {\n" + src << " RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[index], stack[#{stack_size - 1}]);\n" + else + heap_ivar_p = status.max_ivar_index >= ROBJECT_EMBED_LEN_MAX + src << " if (LIKELY(!RB_OBJ_FROZEN_RAW(obj) && #{heap_ivar_p ? 'true' : 'RB_FL_ANY_RAW(obj, ROBJECT_EMBED)'})) {\n" + src << " RB_OBJ_WRITE(obj, &ROBJECT(obj)->as.#{heap_ivar_p ? 'heap.ivptr[index]' : 'ary[index]'}, stack[#{stack_size - 1}]);\n" + end + src << " }\n" + else + src << " VALUE val;\n" + if USE_RVARGC + src << " if (LIKELY(index < ROBJECT_NUMIV(obj) && (val = ROBJECT_IVPTR(obj)[index]) != Qundef)) {\n" + else + heap_ivar_p = status.max_ivar_index >= ROBJECT_EMBED_LEN_MAX + src << " if (LIKELY(#{heap_ivar_p ? 'true' : 'RB_FL_ANY_RAW(obj, ROBJECT_EMBED)'} && (val = ROBJECT(obj)->as.#{heap_ivar_p ? 'heap.ivptr[index]' : 'ary[index]'}) != Qundef)) {\n" + end + src << " stack[#{stack_size}] = val;\n" + src << " }\n" + end else - if ic_copy.attr_index == 0 # cache hit, but uninitialized iv - src << " /* Uninitialized instance variable */\n" - src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj)) {\n" - src << " stack[#{stack_size}] = Qnil;\n" + src << " const rb_serial_t ic_serial = (rb_serial_t)#{ic_copy.entry.class_serial};\n" + # JIT: cache hit path of vm_getivar/vm_setivar, or cancel JIT (recompile it with exivar) + if insn_name == :setinstancevariable + src << " if (LIKELY(RB_TYPE_P(obj, T_OBJECT) && ic_serial == RCLASS_SERIAL(RBASIC(obj)->klass) && index < ROBJECT_NUMIV(obj) && !RB_OBJ_FROZEN_RAW(obj))) {\n" + src << " VALUE *ptr = ROBJECT_IVPTR(obj);\n" + src << " RB_OBJ_WRITE(obj, &ptr[index], stack[#{stack_size - 1}]);\n" src << " }\n" else - src << " const uint32_t index = #{ic_copy.attr_index - 1};\n" - src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj)) {\n" - src << " stack[#{stack_size}] = ROBJECT_IVPTR(obj)[index];\n" + src << " VALUE val;\n" + src << " if (LIKELY(RB_TYPE_P(obj, T_OBJECT) && ic_serial == RCLASS_SERIAL(RBASIC(obj)->klass) && index < ROBJECT_NUMIV(obj) && (val = ROBJECT_IVPTR(obj)[index]) != Qundef)) {\n" + src << " stack[#{stack_size}] = val;\n" src << " }\n" end end @@ -394,19 +419,20 @@ module RubyVM::MJIT src << " }\n" src << "}\n" return src - elsif insn_name == :getinstancevariable && !status.compile_info.disable_exivar_cache && ic_copy.source_shape_id != C.INVALID_SHAPE_ID + elsif insn_name == :getinstancevariable && !status.compile_info.disable_exivar_cache && ic_copy.entry # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`. # compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos) # JIT: prepare vm_getivar's arguments and variables src << "{\n" src << " VALUE obj = GET_SELF();\n" - src << " const shape_id_t source_shape_id = (rb_serial_t)#{ic_copy.source_shape_id};\n" - src << " const uint32_t index = #{ic_copy.attr_index - 1};\n" + src << " const rb_serial_t ic_serial = (rb_serial_t)#{ic_copy.entry.class_serial};\n" + src << " const uint32_t index = #{ic_copy.entry.index};\n" # JIT: cache hit path of vm_getivar, or cancel JIT (recompile it without any ivar optimization) src << " struct gen_ivtbl *ivtbl;\n" - src << " if (LIKELY(FL_TEST_RAW(obj, FL_EXIVAR) && source_shape_id == rb_shape_get_shape_id(obj) && rb_ivar_generic_ivtbl_lookup(obj, &ivtbl))) {\n" - src << " stack[#{stack_size}] = ivtbl->ivptr[index];\n" + src << " VALUE val;\n" + src << " if (LIKELY(FL_TEST_RAW(obj, FL_EXIVAR) && ic_serial == RCLASS_SERIAL(RBASIC(obj)->klass) && rb_ivar_generic_ivtbl_lookup(obj, &ivtbl) && index < ivtbl->numiv && (val = ivtbl->ivptr[index]) != Qundef)) {\n" + src << " stack[#{stack_size}] = val;\n" src << " }\n" src << " else {\n" src << " reg_cfp->pc = original_body_iseq + #{pos};\n" @@ -806,16 +832,35 @@ module RubyVM::MJIT def init_ivar_compile_status(body, status) C.mjit_capture_is_entries(body, status.is_entries) + num_ivars = 0 pos = 0 + status.max_ivar_index = 0 + status.ivar_serial = 0 while pos < body.iseq_size insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos])) if insn.name == :getinstancevariable || insn.name == :setinstancevariable - status.merge_ivar_guards_p = true - return + ic = body.iseq_encoded[pos+2] + ic_copy = (status.is_entries + (C.iseq_inline_storage_entry.new(ic) - body.is_entries)).iv_cache + if ic_copy.entry # Only initialized (ic_serial > 0) IVCs are optimized + num_ivars += 1 + + if status.max_ivar_index < ic_copy.entry.index + status.max_ivar_index = ic_copy.entry.index + end + + if status.ivar_serial == 0 + status.ivar_serial = ic_copy.entry.class_serial + elsif status.ivar_serial != ic_copy.entry.class_serial + # Multiple classes have used this ISeq. Give up assuming one serial. + status.merge_ivar_guards_p = false + return + end + end end pos += insn.len end + status.merge_ivar_guards_p = status.ivar_serial > 0 && num_ivars >= 2 end # Expand simple macro that doesn't require dynamic C code. @@ -39,7 +39,6 @@ #include "ruby/st.h" #include "ruby/util.h" #include "builtin.h" -#include "shape.h" #define BITSPERSHORT (2*CHAR_BIT) #define SHORTMASK ((1<<BITSPERSHORT)-1) @@ -623,6 +622,10 @@ w_obj_each(st_data_t key, st_data_t val, st_data_t a) } return ST_CONTINUE; } + if (!ivarg->num_ivar) { + rb_raise(rb_eRuntimeError, "instance variable added to %"PRIsVALUE" instance", + CLASS_OF(arg->obj)); + } --ivarg->num_ivar; w_symbol(ID2SYM(id), arg->arg); w_object(value, arg->arg, arg->limit); @@ -717,7 +720,6 @@ has_ivars(VALUE obj, VALUE encname, VALUE *ivobj) static void w_ivar_each(VALUE obj, st_index_t num, struct dump_call_arg *arg) { - shape_id_t shape_id = rb_shape_get_shape_id(arg->obj); struct w_ivar_arg ivarg = {arg, num}; if (!num) return; rb_ivar_foreach(obj, w_obj_each, (st_data_t)&ivarg); @@ -725,10 +727,6 @@ w_ivar_each(VALUE obj, st_index_t num, struct dump_call_arg *arg) rb_raise(rb_eRuntimeError, "instance variable removed from %"PRIsVALUE" instance", CLASS_OF(arg->obj)); } - if (shape_id != rb_shape_get_shape_id(arg->obj)) { - rb_raise(rb_eRuntimeError, "instance variable added to %"PRIsVALUE" instance", - CLASS_OF(arg->obj)); - } } static void diff --git a/misc/lldb_cruby.py b/misc/lldb_cruby.py index 9ef9d3967b..595d54dfab 100755 --- a/misc/lldb_cruby.py +++ b/misc/lldb_cruby.py @@ -418,7 +418,6 @@ def lldb_inspect(debugger, target, result, val): elif flType == RUBY_T_IMEMO: # I'm not sure how to get IMEMO_MASK out of lldb. It's not in globals() imemo_type = (flags >> RUBY_FL_USHIFT) & 0x0F # IMEMO_MASK - print("T_IMEMO: ", file=result) append_command_output(debugger, "p (enum imemo_type) %d" % imemo_type, result) append_command_output(debugger, "p *(struct MEMO *) %0#x" % val.GetValueAsUnsigned(), result) @@ -5,10 +5,6 @@ module RubyVM::MJIT C = Object.new class << C - def SHAPE_BITS - RubyVM::Shape::SHAPE_BITS - end - def ROBJECT_EMBED_LEN_MAX Primitive.cexpr! 'INT2NUM(RBIMPL_EMBED_LEN_MAX_OF(VALUE))' end @@ -169,14 +165,6 @@ module RubyVM::MJIT Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_ISEQ) } end - def C.INVALID_SHAPE_ID - Primitive.cexpr! %q{ ULONG2NUM(INVALID_SHAPE_ID) } - end - - def C.SHAPE_MASK - Primitive.cexpr! %q{ ULONG2NUM(SHAPE_MASK) } - end - def C.CALL_DATA @CALL_DATA ||= self.rb_call_data end @@ -193,10 +181,6 @@ module RubyVM::MJIT @RB_BUILTIN ||= self.rb_builtin_function end - def C.attr_index_t - @attr_index_t ||= CType::Immediate.parse("uint32_t") - end - def C.compile_branch @compile_branch ||= CType::Struct.new( "compile_branch", Primitive.cexpr!("SIZEOF(struct compile_branch)"), @@ -217,6 +201,7 @@ module RubyVM::MJIT compiled_id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compiled_id)")], compile_info: [CType::Pointer.new { self.rb_mjit_compile_info }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compile_info)")], merge_ivar_guards_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), merge_ivar_guards_p)")], + ivar_serial: [self.rb_serial_t, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), ivar_serial)")], max_ivar_index: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), max_ivar_index)")], inlined_iseqs: [CType::Pointer.new { CType::Pointer.new { self.rb_iseq_constant_body } }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), inlined_iseqs)")], inline_context: [self.inlined_call_context, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), inline_context)")], @@ -255,9 +240,7 @@ module RubyVM::MJIT def C.iseq_inline_iv_cache_entry @iseq_inline_iv_cache_entry ||= CType::Struct.new( "iseq_inline_iv_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_iv_cache_entry)"), - source_shape_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), source_shape_id)")], - dest_shape_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), dest_shape_id)")], - attr_index: [self.attr_index_t, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), attr_index)")], + entry: [CType::Pointer.new { self.rb_iv_index_tbl_entry }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), entry)")], ) end @@ -330,11 +313,7 @@ module RubyVM::MJIT call_: [self.vm_call_handler, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), call_)")], aux_: [CType::Union.new( "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_)"), - attr: CType::Struct.new( - "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_.attr)"), - index: [self.attr_index_t, Primitive.cexpr!("OFFSETOF(((struct rb_callcache *)NULL)->aux_.attr, index)")], - dest_shape_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF(((struct rb_callcache *)NULL)->aux_.attr, dest_shape_id)")], - ), + attr_index: CType::Immediate.parse("unsigned int"), method_missing_reason: self.method_missing_reason, v: self.VALUE, ), Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), aux_)")], @@ -524,8 +503,8 @@ module RubyVM::MJIT @rb_iv_index_tbl_entry ||= CType::Struct.new( "rb_iv_index_tbl_entry", Primitive.cexpr!("SIZEOF(struct rb_iv_index_tbl_entry)"), index: [CType::Immediate.parse("uint32_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), index)")], - source_shape_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), source_shape_id)")], - dest_shape_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), dest_shape_id)")], + class_serial: [self.rb_serial_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), class_serial)")], + class_value: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iv_index_tbl_entry *)NULL)), class_value)")], ) end @@ -598,10 +577,6 @@ module RubyVM::MJIT @VALUE ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(VALUE)"), Primitive.cexpr!("SIGNED_TYPE_P(VALUE)")) end - def C.shape_id_t - @shape_id_t ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(shape_id_t)"), Primitive.cexpr!("SIGNED_TYPE_P(shape_id_t)")) - end - def C._Bool CType::Bool.new end diff --git a/mjit_compiler.h b/mjit_compiler.h index b465be00fd..da79054420 100644 --- a/mjit_compiler.h +++ b/mjit_compiler.h @@ -8,7 +8,6 @@ #include "builtin.h" #include "mjit.h" #include "mjit_unit.h" -#include "shape.h" // Macros to check if a position is already compiled using compile_status.stack_size_for_pos #define NOT_COMPILED_STACK_SIZE -1 @@ -49,6 +48,7 @@ struct compile_status { // Mutated optimization levels struct rb_mjit_compile_info *compile_info; bool merge_ivar_guards_p; // If true, merge guards of ivar accesses + rb_serial_t ivar_serial; // ic_serial of IVC in is_entries (used only when merge_ivar_guards_p) size_t max_ivar_index; // Max IVC index in is_entries (used only when merge_ivar_guards_p) // If `inlined_iseqs[pos]` is not NULL, `mjit_compile_body` tries to inline ISeq there. const struct rb_iseq_constant_body **inlined_iseqs; @@ -39,7 +39,6 @@ #include "ruby/util.h" #include "ruby/assert.h" #include "builtin.h" -#include "shape.h" /*! * \addtogroup object @@ -272,33 +271,9 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj) VALUE *src_buf = ROBJECT_IVPTR(obj); uint32_t dest_len = ROBJECT_NUMIV(dest); uint32_t src_len = ROBJECT_NUMIV(obj); - uint32_t max_len = dest_len < src_len ? src_len : dest_len; + uint32_t len = dest_len < src_len ? dest_len : src_len; - rb_ensure_iv_list_size(dest, dest_len, max_len); - - dest_len = ROBJECT_NUMIV(dest); - uint32_t min_len = dest_len > src_len ? src_len : dest_len; - - if (RBASIC(obj)->flags & ROBJECT_EMBED) { - src_buf = ROBJECT(obj)->as.ary; - - // embedded -> embedded - if (RBASIC(dest)->flags & ROBJECT_EMBED) { - dest_buf = ROBJECT(dest)->as.ary; - } - // embedded -> extended - else { - dest_buf = ROBJECT(dest)->as.heap.ivptr; - } - } - // extended -> extended - else { - RUBY_ASSERT(!(RBASIC(dest)->flags & ROBJECT_EMBED)); - dest_buf = ROBJECT(dest)->as.heap.ivptr; - src_buf = ROBJECT(obj)->as.heap.ivptr; - } - - MEMCPY(dest_buf, src_buf, VALUE, min_len); + MEMCPY(dest_buf, src_buf, VALUE, len); } static void @@ -308,23 +283,10 @@ init_copy(VALUE dest, VALUE obj) rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest)); } RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR); - // Copies the shape id from obj to dest RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR); rb_copy_wb_protected_attribute(dest, obj); rb_copy_generic_ivar(dest, obj); rb_gc_copy_finalizer(dest, obj); - - rb_shape_t *shape_to_set = rb_shape_get_shape(obj); - - // If the object is frozen, the "dup"'d object will *not* be frozen, - // so we need to copy the frozen shape's parent to the new object. - if (rb_shape_frozen_shape_p(shape_to_set)) { - shape_to_set = shape_to_set->parent; - } - - // shape ids are different - rb_shape_set_shape(dest, shape_to_set); - if (RB_TYPE_P(obj, T_OBJECT)) { rb_obj_copy_ivar(dest, obj); } @@ -430,9 +392,6 @@ mutable_obj_clone(VALUE obj, VALUE kwfreeze) case Qnil: rb_funcall(clone, id_init_clone, 1, obj); RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE; - if (RB_OBJ_FROZEN(obj)) { - rb_shape_transition_shape_frozen(clone); - } break; case Qtrue: { @@ -448,7 +407,6 @@ mutable_obj_clone(VALUE obj, VALUE kwfreeze) argv[1] = freeze_true_hash; rb_funcallv_kw(clone, id_init_clone, 2, argv, RB_PASS_KEYWORDS); RBASIC(clone)->flags |= FL_FREEZE; - rb_shape_transition_shape_frozen(clone); break; } case Qfalse: diff --git a/ractor_core.h b/ractor_core.h index 9d4b8387c7..a065f5f809 100644 --- a/ractor_core.h +++ b/ractor_core.h @@ -289,13 +289,11 @@ rb_ractor_id(const rb_ractor_t *r) #if RACTOR_CHECK_MODE > 0 uint32_t rb_ractor_current_id(void); -// If ractor check mode is enabled, shape bits needs to be smaller -STATIC_ASSERT(shape_bits, SHAPE_BITS == 16); static inline void rb_ractor_setup_belonging_to(VALUE obj, uint32_t rid) { - VALUE flags = RBASIC(obj)->flags & 0xffff0000ffffffff; // 4B + VALUE flags = RBASIC(obj)->flags & 0xffffffff; // 4B RBASIC(obj)->flags = flags | ((VALUE)rid << 32); } @@ -312,7 +310,7 @@ rb_ractor_belonging(VALUE obj) return 0; } else { - return RBASIC(obj)->flags >> 32 & 0xFFFF; + return RBASIC(obj)->flags >> 32; } } diff --git a/shape.c b/shape.c deleted file mode 100644 index a6a5adf854..0000000000 --- a/shape.c +++ /dev/null @@ -1,523 +0,0 @@ -#include "vm_core.h" -#include "vm_sync.h" -#include "shape.h" -#include "internal/class.h" -#include "internal/symbol.h" -#include "internal/variable.h" -#include <stdbool.h> - -/* - * Shape getters - */ -static rb_shape_t* -rb_shape_get_root_shape(void) { - return GET_VM()->root_shape; -} - -shape_id_t -rb_shape_id(rb_shape_t * shape) -{ - return (shape_id_t)(shape - GET_VM()->shape_list); -} - -static rb_shape_t* -rb_shape_get_frozen_root_shape(void) { - return GET_VM()->frozen_root_shape; -} - -bool -rb_shape_root_shape_p(rb_shape_t* shape) { - return shape == rb_shape_get_root_shape(); -} - -rb_shape_t* -rb_shape_get_shape_by_id(shape_id_t shape_id) -{ - RUBY_ASSERT(shape_id != INVALID_SHAPE_ID); - - rb_vm_t *vm = GET_VM(); - rb_shape_t *shape = &vm->shape_list[shape_id]; - return shape; -} - -rb_shape_t* -rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id) -{ - RUBY_ASSERT(shape_id != INVALID_SHAPE_ID); - - rb_vm_t *vm = GET_VM(); - rb_shape_t *shape = &vm->shape_list[shape_id]; - return shape; -} - -#if !SHAPE_IN_BASIC_FLAGS -static inline shape_id_t -RCLASS_SHAPE_ID(VALUE obj) -{ - return RCLASS_EXT(obj)->shape_id; -} - -shape_id_t rb_generic_shape_id(VALUE obj); -#endif - -shape_id_t -rb_shape_get_shape_id(VALUE obj) -{ - if (RB_SPECIAL_CONST_P(obj)) { - return FROZEN_ROOT_SHAPE_ID; - } - -#if SHAPE_IN_BASIC_FLAGS - return RBASIC_SHAPE_ID(obj); -#else - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - return ROBJECT_SHAPE_ID(obj); - break; - case T_CLASS: - case T_MODULE: - return RCLASS_SHAPE_ID(obj); - default: - return rb_generic_shape_id(obj); - } -#endif -} - -rb_shape_t* -rb_shape_get_shape(VALUE obj) -{ - return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj)); -} - -static rb_shape_t * -rb_shape_lookup_id(rb_shape_t* shape, ID id, enum shape_type shape_type) { - while (shape->parent) { - if (shape->edge_name == id) { - // If the shape type is different, we don't - // want this to count as a "found" ID - if (shape_type == (enum shape_type)shape->type) { - return shape; - } - else { - return NULL; - } - } - shape = shape->parent; - } - return NULL; -} - -static rb_shape_t* -get_next_shape_internal(rb_shape_t* shape, ID id, VALUE obj, enum shape_type shape_type) -{ - rb_shape_t *res = NULL; - RUBY_ASSERT(SHAPE_FROZEN != (enum shape_type)shape->type); - RB_VM_LOCK_ENTER(); - { - if (rb_shape_lookup_id(shape, id, shape_type)) { - // If shape already contains the ivar that is being set, we'll return shape - res = shape; - } - else { - if (!shape->edges) { - shape->edges = rb_id_table_create(0); - } - - // Lookup the shape in edges - if there's already an edge and a corresponding shape for it, - // we can return that. Otherwise, we'll need to get a new shape - if (!rb_id_table_lookup(shape->edges, id, (VALUE *)&res)) { - // In this case, the shape exists, but the shape is garbage, so we need to recreate it - if (res) { - rb_id_table_delete(shape->edges, id); - res->parent = NULL; - } - - rb_shape_t * new_shape = rb_shape_alloc(id, shape); - - new_shape->type = (uint8_t)shape_type; - - switch(shape_type) { - case SHAPE_IVAR: - new_shape->iv_count = new_shape->parent->iv_count + 1; - - // Check if we should update max_iv_count on the object's class - if (BUILTIN_TYPE(obj) == T_OBJECT) { - VALUE klass = rb_obj_class(obj); - if (new_shape->iv_count > RCLASS_EXT(klass)->max_iv_count) { - RCLASS_EXT(klass)->max_iv_count = new_shape->iv_count; - } - } - break; - case SHAPE_IVAR_UNDEF: - case SHAPE_FROZEN: - new_shape->iv_count = new_shape->parent->iv_count; - break; - case SHAPE_ROOT: - rb_bug("Unreachable"); - break; - } - - rb_id_table_insert(shape->edges, id, (VALUE)new_shape); - - res = new_shape; - } - } - } - RB_VM_LOCK_LEAVE(); - return res; -} - -MJIT_FUNC_EXPORTED int -rb_shape_frozen_shape_p(rb_shape_t* shape) -{ - return SHAPE_FROZEN == (enum shape_type)shape->type; -} - -void -rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape) -{ - rb_shape_t* next_shape = get_next_shape_internal(shape, id, obj, SHAPE_IVAR_UNDEF); - - if (shape == next_shape) { - return; - } - - rb_shape_set_shape(obj, next_shape); -} - -void -rb_shape_transition_shape_frozen(VALUE obj) -{ - rb_shape_t* shape = rb_shape_get_shape(obj); - RUBY_ASSERT(shape); - RUBY_ASSERT(RB_OBJ_FROZEN(obj)); - - if (rb_shape_frozen_shape_p(shape)) { - return; - } - - rb_shape_t* next_shape; - - if (shape == rb_shape_get_root_shape()) { - switch(BUILTIN_TYPE(obj)) { - case T_OBJECT: - case T_CLASS: - case T_MODULE: - break; - default: - return; - } - next_shape = rb_shape_get_frozen_root_shape(); - } - else { - static ID id_frozen; - if (!id_frozen) { - id_frozen = rb_make_internal_id(); - } - - next_shape = get_next_shape_internal(shape, (ID)id_frozen, obj, SHAPE_FROZEN); - } - - RUBY_ASSERT(next_shape); - rb_shape_set_shape(obj, next_shape); -} - -void -rb_shape_transition_shape(VALUE obj, ID id, rb_shape_t *shape) -{ - rb_shape_t* next_shape = rb_shape_get_next(shape, obj, id); - if (shape == next_shape) { - return; - } - rb_shape_set_shape(obj, next_shape); -} - -rb_shape_t* -rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id) -{ - return get_next_shape_internal(shape, id, obj, SHAPE_IVAR); -} - -bool -rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t *value) { - while (shape->parent) { - if (shape->edge_name == id) { - enum shape_type shape_type; - shape_type = (enum shape_type)shape->type; - - switch(shape_type) { - case SHAPE_IVAR: - RUBY_ASSERT(shape->iv_count > 0); - *value = shape->iv_count - 1; - return true; - case SHAPE_IVAR_UNDEF: - case SHAPE_ROOT: - return false; - case SHAPE_FROZEN: - rb_bug("Ivar should not exist on frozen transition\n"); - } - } - shape = shape->parent; - } - return false; -} - -static rb_shape_t * -shape_alloc(void) -{ - rb_vm_t *vm = GET_VM(); - shape_id_t shape_id = vm->next_shape_id; - vm->next_shape_id++; - - if (shape_id == MAX_SHAPE_ID) { - // TODO: Make an OutOfShapesError ?? - rb_bug("Out of shapes\n"); - } - - return &GET_VM()->shape_list[shape_id]; -} - -rb_shape_t * -rb_shape_alloc(ID edge_name, rb_shape_t * parent) -{ - rb_shape_t * shape = shape_alloc(); - - shape->edge_name = edge_name; - shape->iv_count = 0; - shape->parent = parent; - - return shape; -} - -MJIT_FUNC_EXPORTED void -rb_shape_set_shape(VALUE obj, rb_shape_t* shape) -{ - rb_shape_set_shape_id(obj, rb_shape_id(shape)); -} - -VALUE rb_cShape; - -/* - * Exposing Shape to Ruby via RubyVM.debug_shape - */ -static const rb_data_type_t shape_data_type = { - "Shape", - {NULL, NULL, NULL,}, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED -}; - -static VALUE -rb_wrapped_shape_id(VALUE self) { - rb_shape_t * shape; - TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); - return INT2NUM(rb_shape_id(shape)); -} - -static VALUE -rb_shape_type(VALUE self) { - rb_shape_t * shape; - TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); - return INT2NUM(shape->type); -} - -static VALUE -rb_shape_parent_id(VALUE self) -{ - rb_shape_t * shape; - TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); - if (shape->parent) { - return INT2NUM(rb_shape_id(shape->parent)); - } - else { - return Qnil; - } -} - -static VALUE parse_key(ID key) { - if ((key & RUBY_ID_INTERNAL) == RUBY_ID_INTERNAL) { - return LONG2NUM(key); - } else { - return ID2SYM(key); - } -} - -static VALUE -rb_shape_t_to_rb_cShape(rb_shape_t *shape) { - union { const rb_shape_t *in; void *out; } deconst; - VALUE res; - deconst.in = shape; - res = TypedData_Wrap_Struct(rb_cShape, &shape_data_type, deconst.out); - - return res; -} - -static enum rb_id_table_iterator_result rb_edges_to_hash(ID key, VALUE value, void *ref) -{ - rb_hash_aset(*(VALUE *)ref, parse_key(key), rb_shape_t_to_rb_cShape((rb_shape_t*)value)); - return ID_TABLE_CONTINUE; -} - -static VALUE -rb_shape_edges(VALUE self) -{ - rb_shape_t* shape; - TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); - - VALUE hash = rb_hash_new(); - - if (shape->edges) { - rb_id_table_foreach(shape->edges, rb_edges_to_hash, &hash); - } - - return hash; -} - -static VALUE -rb_shape_edge_name(VALUE self) -{ - rb_shape_t* shape; - TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); - - if (shape->edge_name) { - return ID2SYM(shape->edge_name); - } - else { - return Qnil; - } -} - -static VALUE -rb_shape_iv_count(VALUE self) -{ - rb_shape_t* shape; - TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); - - return INT2NUM(shape->iv_count); -} - -static VALUE -rb_shape_export_depth(VALUE self) -{ - rb_shape_t* shape; - TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); - - unsigned int depth = 0; - while (shape->parent) { - depth++; - shape = shape->parent; - } - return INT2NUM(depth); -} - -static VALUE -rb_shape_parent(VALUE self) -{ - rb_shape_t * shape; - TypedData_Get_Struct(self, rb_shape_t, &shape_data_type, shape); - if (shape->parent) { - return rb_shape_t_to_rb_cShape(shape->parent); - } - else { - return Qnil; - } -} - -VALUE rb_shape_debug_shape(VALUE self, VALUE obj) { - return rb_shape_t_to_rb_cShape(rb_shape_get_shape(obj)); -} - -VALUE rb_shape_debug_root_shape(VALUE self) { - return rb_shape_t_to_rb_cShape(rb_shape_get_root_shape()); -} - -VALUE rb_shape_debug_frozen_root_shape(VALUE self) { - return rb_shape_t_to_rb_cShape(rb_shape_get_frozen_root_shape()); -} - -VALUE rb_obj_shape(rb_shape_t* shape); - -static enum rb_id_table_iterator_result collect_keys_and_values(ID key, VALUE value, void *ref) -{ - rb_hash_aset(*(VALUE *)ref, parse_key(key), rb_obj_shape((rb_shape_t*)value)); - return ID_TABLE_CONTINUE; -} - -static VALUE edges(struct rb_id_table* edges) -{ - VALUE hash = rb_hash_new(); - if (edges) - rb_id_table_foreach(edges, collect_keys_and_values, &hash); - return hash; -} - -VALUE rb_obj_shape(rb_shape_t* shape) { - VALUE rb_shape = rb_hash_new(); - - rb_hash_aset(rb_shape, ID2SYM(rb_intern("id")), INT2NUM(rb_shape_id(shape))); - rb_hash_aset(rb_shape, ID2SYM(rb_intern("edges")), edges(shape->edges)); - - if (shape == rb_shape_get_root_shape()) { - rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_id")), INT2NUM(ROOT_SHAPE_ID)); - } - else { - rb_hash_aset(rb_shape, ID2SYM(rb_intern("parent_id")), INT2NUM(rb_shape_id(shape->parent))); - } - - rb_hash_aset(rb_shape, ID2SYM(rb_intern("edge_name")), rb_id2str(shape->edge_name)); - return rb_shape; -} - -static VALUE shape_transition_tree(VALUE self) { - return rb_obj_shape(rb_shape_get_root_shape()); -} - -static VALUE shape_count(VALUE self) { - int shape_count = 0; - rb_vm_t *vm = GET_VM(); - for(shape_id_t i = 0; i < vm->next_shape_id; i++) { - if(rb_shape_get_shape_by_id_without_assertion(i)) { - shape_count++; - } - } - return INT2NUM(shape_count); -} - -static VALUE -shape_max_shape_count(VALUE self) -{ - return INT2NUM(GET_VM()->next_shape_id); -} - -VALUE -rb_shape_flags_mask(void) -{ - return SHAPE_FLAG_MASK; -} - -void -Init_shape(void) -{ - rb_cShape = rb_define_class_under(rb_cRubyVM, "Shape", rb_cObject); - rb_undef_alloc_func(rb_cShape); - - rb_define_method(rb_cShape, "parent_id", rb_shape_parent_id, 0); - rb_define_method(rb_cShape, "parent", rb_shape_parent, 0); - rb_define_method(rb_cShape, "edges", rb_shape_edges, 0); - rb_define_method(rb_cShape, "edge_name", rb_shape_edge_name, 0); - rb_define_method(rb_cShape, "iv_count", rb_shape_iv_count, 0); - rb_define_method(rb_cShape, "depth", rb_shape_export_depth, 0); - rb_define_method(rb_cShape, "id", rb_wrapped_shape_id, 0); - rb_define_method(rb_cShape, "type", rb_shape_type, 0); - rb_define_const(rb_cShape, "SHAPE_ROOT", INT2NUM(SHAPE_ROOT)); - rb_define_const(rb_cShape, "SHAPE_IVAR", INT2NUM(SHAPE_IVAR)); - rb_define_const(rb_cShape, "SHAPE_IVAR_UNDEF", INT2NUM(SHAPE_IVAR_UNDEF)); - rb_define_const(rb_cShape, "SHAPE_FROZEN", INT2NUM(SHAPE_FROZEN)); - rb_define_const(rb_cShape, "SHAPE_BITS", INT2NUM(SHAPE_BITS)); - - rb_define_module_function(rb_cRubyVM, "debug_shape_transition_tree", shape_transition_tree, 0); - rb_define_module_function(rb_cRubyVM, "debug_shape_count", shape_count, 0); - rb_define_singleton_method(rb_cRubyVM, "debug_shape", rb_shape_debug_shape, 1); - rb_define_singleton_method(rb_cRubyVM, "debug_max_shape_count", shape_max_shape_count, 0); - rb_define_singleton_method(rb_cRubyVM, "debug_root_shape", rb_shape_debug_root_shape, 0); - rb_define_singleton_method(rb_cRubyVM, "debug_frozen_root_shape", rb_shape_debug_frozen_root_shape, 0); -} diff --git a/shape.h b/shape.h deleted file mode 100644 index 66b8e580c9..0000000000 --- a/shape.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef RUBY_SHAPE_H -#define RUBY_SHAPE_H -#if (SIZEOF_UINT64_T == SIZEOF_VALUE) -#define SIZEOF_SHAPE_T 4 -#define SHAPE_IN_BASIC_FLAGS 1 -typedef uint32_t attr_index_t; -#else -#define SIZEOF_SHAPE_T 2 -#define SHAPE_IN_BASIC_FLAGS 0 -typedef uint16_t attr_index_t; -#endif - -#define MAX_IVARS (attr_index_t)(-1) - -#if RUBY_DEBUG || (defined(VM_CHECK_MODE) && VM_CHECK_MODE > 0) -# if SIZEOF_SHAPE_T == 4 -typedef uint32_t shape_id_t; -# define SHAPE_BITS 16 -# else -typedef uint16_t shape_id_t; -# define SHAPE_BITS 16 -# endif -#else -# if SIZEOF_SHAPE_T == 4 -typedef uint32_t shape_id_t; -# define SHAPE_BITS 32 -# else -typedef uint16_t shape_id_t; -# define SHAPE_BITS 16 -# endif -#endif - -# define SHAPE_MASK (((uintptr_t)1 << SHAPE_BITS) - 1) -# define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_BITS) - -# define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_BITS) - -# define SHAPE_BITMAP_SIZE 16384 - -# define MAX_SHAPE_ID (SHAPE_MASK - 1) -# define INVALID_SHAPE_ID SHAPE_MASK -# define ROOT_SHAPE_ID 0x0 -# define FROZEN_ROOT_SHAPE_ID 0x1 - -struct rb_shape { - struct rb_shape * parent; // Pointer to the parent - struct rb_id_table * edges; // id_table from ID (ivar) to next shape - ID edge_name; // ID (ivar) for transition from parent to rb_shape - attr_index_t iv_count; - uint8_t type; -}; - -typedef struct rb_shape rb_shape_t; - -enum shape_type { - SHAPE_ROOT, - SHAPE_IVAR, - SHAPE_FROZEN, - SHAPE_IVAR_UNDEF, -}; - -static inline shape_id_t -IMEMO_CACHED_SHAPE_ID(VALUE cc) -{ - RBIMPL_ASSERT_TYPE((VALUE)cc, RUBY_T_IMEMO); - return (shape_id_t)(SHAPE_MASK & (RBASIC(cc)->flags >> SHAPE_FLAG_SHIFT)); -} - -static inline void -IMEMO_SET_CACHED_SHAPE_ID(VALUE cc, shape_id_t shape_id) -{ - RBIMPL_ASSERT_TYPE((VALUE)cc, RUBY_T_IMEMO); - RBASIC(cc)->flags &= SHAPE_FLAG_MASK; - RBASIC(cc)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT); -} - -#if SHAPE_IN_BASIC_FLAGS -static inline shape_id_t -RBASIC_SHAPE_ID(VALUE obj) -{ - RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj)); - return (shape_id_t)(SHAPE_MASK & ((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT)); -} - -static inline void -RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id) -{ - // Ractors are occupying the upper 32 bits of flags, but only in debug mode - // Object shapes are occupying top bits - RBASIC(obj)->flags &= SHAPE_FLAG_MASK; - RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT); -} - -static inline shape_id_t -ROBJECT_SHAPE_ID(VALUE obj) -{ - RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); - return RBASIC_SHAPE_ID(obj); -} - -static inline void -ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id) -{ - RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); - RBASIC_SET_SHAPE_ID(obj, shape_id); -} - -#else - -static inline shape_id_t -ROBJECT_SHAPE_ID(VALUE obj) -{ - RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); - return (shape_id_t)(SHAPE_MASK & (RBASIC(obj)->flags >> SHAPE_FLAG_SHIFT)); -} - -static inline void -ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id) -{ - RBASIC(obj)->flags &= SHAPE_FLAG_MASK; - RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT); -} -#endif - -bool rb_shape_root_shape_p(rb_shape_t* shape); - -rb_shape_t* rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id); - -MJIT_SYMBOL_EXPORT_BEGIN -rb_shape_t* rb_shape_get_shape_by_id(shape_id_t shape_id); -void rb_shape_set_shape(VALUE obj, rb_shape_t* shape); -shape_id_t rb_shape_get_shape_id(VALUE obj); -rb_shape_t* rb_shape_get_shape(VALUE obj); -int rb_shape_frozen_shape_p(rb_shape_t* shape); -void rb_shape_transition_shape_frozen(VALUE obj); -void rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape); -void rb_shape_transition_shape(VALUE obj, ID id, rb_shape_t *shape); -rb_shape_t* rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id); -bool rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t * value); -shape_id_t rb_shape_id(rb_shape_t * shape); -MJIT_SYMBOL_EXPORT_END - -rb_shape_t * rb_shape_alloc(ID edge_name, rb_shape_t * parent); - -bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id); - -VALUE rb_obj_debug_shape(VALUE self, VALUE obj); -VALUE rb_shape_flags_mask(void); - -#endif diff --git a/test/-ext-/marshal/test_internal_ivar.rb b/test/-ext-/marshal/test_internal_ivar.rb index 9359c7f113..a32138f6e8 100644 --- a/test/-ext-/marshal/test_internal_ivar.rb +++ b/test/-ext-/marshal/test_internal_ivar.rb @@ -7,7 +7,6 @@ module Bug end module Bug::Marshal class TestInternalIVar < Test::Unit::TestCase def test_marshal - pend "We don't support IVs with ID of 0" v = InternalIVar.new("hello", "world", "bye") assert_equal("hello", v.normal) assert_equal("world", v.internal) diff --git a/test/ruby/test_mjit.rb b/test/ruby/test_mjit.rb index 4c6cc6f39f..e49195f763 100644 --- a/test/ruby/test_mjit.rb +++ b/test/ruby/test_mjit.rb @@ -831,7 +831,7 @@ class TestMJIT < Test::Unit::TestCase end def test_inlined_exivar - assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "aaa", success_count: 4, recompile_count: 2, min_calls: 2) + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "aaa", success_count: 3, recompile_count: 1, min_calls: 2) begin; class Foo < Hash def initialize @@ -850,7 +850,7 @@ class TestMJIT < Test::Unit::TestCase end def test_inlined_undefined_ivar - assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "bbb", success_count: 2, min_calls: 2) + assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: "bbb", success_count: 3, min_calls: 3) begin; class Foo def initialize diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb index a9d5d4b13e..83208bbcdb 100644 --- a/test/ruby/test_object.rb +++ b/test/ruby/test_object.rb @@ -993,13 +993,4 @@ class TestObject < Test::Unit::TestCase end EOS end - - def test_frozen_inspect - obj = Object.new - obj.instance_variable_set(:@a, "a") - ins = obj.inspect - obj.freeze - - assert_equal(ins, obj.inspect) - end end diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb deleted file mode 100644 index 807d485354..0000000000 --- a/test/ruby/test_shapes.rb +++ /dev/null @@ -1,173 +0,0 @@ -# frozen_string_literal: false -require 'test/unit' - -# These test the functionality of object shapes -class TestShapes < Test::Unit::TestCase - class Example - def initialize - @a = 1 - end - end - - class RemoveAndAdd - def add_foo - @foo = 1 - end - - def remove - remove_instance_variable(:@foo) - end - - def add_bar - @bar = 1 - end - end - - # RubyVM.debug_shape returns new instances of shape objects for - # each call. This helper method allows us to define equality for - # shapes - def assert_shape_equal(shape1, shape2) - assert_equal(shape1.id, shape2.id) - assert_equal(shape1.parent_id, shape2.parent_id) - assert_equal(shape1.depth, shape2.depth) - assert_equal(shape1.type, shape2.type) - end - - def refute_shape_equal(shape1, shape2) - refute_equal(shape1.id, shape2.id) - end - - def test_iv_index - example = RemoveAndAdd.new - shape = RubyVM.debug_shape(example) - assert_equal 0, shape.iv_count - - example.add_foo # makes a transition - new_shape = RubyVM.debug_shape(example) - assert_equal([:@foo], example.instance_variables) - assert_equal(shape.id, new_shape.parent.id) - assert_equal(1, new_shape.iv_count) - - example.remove # makes a transition - remove_shape = RubyVM.debug_shape(example) - assert_equal([], example.instance_variables) - assert_equal(new_shape.id, remove_shape.parent.id) - assert_equal(1, remove_shape.iv_count) - - example.add_bar # makes a transition - bar_shape = RubyVM.debug_shape(example) - assert_equal([:@bar], example.instance_variables) - assert_equal(remove_shape.id, bar_shape.parent.id) - assert_equal(2, bar_shape.iv_count) - end - - def test_new_obj_has_root_shape - assert_shape_equal(RubyVM.debug_root_shape, RubyVM.debug_shape(Object.new)) - end - - def test_frozen_new_obj_has_frozen_root_shape - assert_shape_equal( - RubyVM.debug_frozen_root_shape, - RubyVM.debug_shape(Object.new.freeze) - ) - end - - def test_str_has_root_shape - assert_shape_equal(RubyVM.debug_root_shape, RubyVM.debug_shape("")) - end - - def test_array_has_root_shape - assert_shape_equal(RubyVM.debug_root_shape, RubyVM.debug_shape([])) - end - - def test_hash_has_root_shape - assert_shape_equal(RubyVM.debug_root_shape, RubyVM.debug_shape({})) - end - - def test_true_has_frozen_root_shape - assert_shape_equal(RubyVM.debug_frozen_root_shape, RubyVM.debug_shape(true)) - end - - def test_nil_has_frozen_root_shape - assert_shape_equal(RubyVM.debug_frozen_root_shape, RubyVM.debug_shape(nil)) - end - - def test_basic_shape_transition - obj = Example.new - refute_equal(RubyVM.debug_root_shape, RubyVM.debug_shape(obj)) - assert_shape_equal(RubyVM.debug_root_shape.edges[:@a], RubyVM.debug_shape(obj)) - assert_equal(obj.instance_variable_get(:@a), 1) - end - - def test_different_objects_make_same_transition - obj = Example.new - obj2 = "" - obj2.instance_variable_set(:@a, 1) - assert_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2)) - end - - def test_duplicating_objects - obj = Example.new - obj2 = obj.dup - assert_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2)) - end - - def test_freezing_and_duplicating_object - obj = Object.new.freeze - obj2 = obj.dup - refute_predicate(obj2, :frozen?) - # dup'd objects shouldn't be frozen, and the shape should be the - # parent shape of the copied object - assert_equal(RubyVM.debug_shape(obj).parent.id, RubyVM.debug_shape(obj2).id) - end - - def test_freezing_and_duplicating_object_with_ivars - obj = Example.new.freeze - obj2 = obj.dup - refute_predicate(obj2, :frozen?) - refute_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2)) - assert_equal(obj2.instance_variable_get(:@a), 1) - end - - def test_freezing_and_duplicating_string_with_ivars - str = "str" - str.instance_variable_set(:@a, 1) - str.freeze - str2 = str.dup - refute_predicate(str2, :frozen?) - refute_equal(RubyVM.debug_shape(str).id, RubyVM.debug_shape(str2).id) - assert_equal(str2.instance_variable_get(:@a), 1) - end - - def test_freezing_and_cloning_objects - obj = Object.new.freeze - obj2 = obj.clone(freeze: true) - assert_predicate(obj2, :frozen?) - assert_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2)) - end - - def test_freezing_and_cloning_object_with_ivars - obj = Example.new.freeze - obj2 = obj.clone(freeze: true) - assert_predicate(obj2, :frozen?) - assert_shape_equal(RubyVM.debug_shape(obj), RubyVM.debug_shape(obj2)) - assert_equal(obj2.instance_variable_get(:@a), 1) - end - - def test_freezing_and_cloning_string - str = "str".freeze - str2 = str.clone(freeze: true) - assert_predicate(str2, :frozen?) - assert_shape_equal(RubyVM.debug_shape(str), RubyVM.debug_shape(str2)) - end - - def test_freezing_and_cloning_string_with_ivars - str = "str" - str.instance_variable_set(:@a, 1) - str.freeze - str2 = str.clone(freeze: true) - assert_predicate(str2, :frozen?) - assert_shape_equal(RubyVM.debug_shape(str), RubyVM.debug_shape(str2)) - assert_equal(str2.instance_variable_get(:@a), 1) - end -end diff --git a/tool/mjit/bindgen.rb b/tool/mjit/bindgen.rb index 8c21d42449..d0f9bf527b 100755 --- a/tool/mjit/bindgen.rb +++ b/tool/mjit/bindgen.rb @@ -341,17 +341,12 @@ generator = BindingGenerator.new( VM_METHOD_TYPE_CFUNC VM_METHOD_TYPE_ISEQ ], - ULONG: %w[ - INVALID_SHAPE_ID - SHAPE_MASK - ], }, types: %w[ CALL_DATA IC IVC RB_BUILTIN - attr_index_t compile_branch compile_status inlined_call_context @@ -365,10 +360,10 @@ generator = BindingGenerator.new( rb_callable_method_entry_struct rb_callcache rb_callinfo - rb_control_frame_t rb_cref_t - rb_execution_context_struct + rb_control_frame_t rb_execution_context_t + rb_execution_context_struct rb_iseq_constant_body rb_iseq_location_t rb_iseq_struct @@ -383,7 +378,6 @@ generator = BindingGenerator.new( ], dynamic_types: %w[ VALUE - shape_id_t ], skip_fields: { 'rb_execution_context_struct.machine': %w[regs], # differs between macOS and Linux diff --git a/variable.c b/variable.c index b5e95b7f1c..056a1000b8 100644 --- a/variable.c +++ b/variable.c @@ -34,7 +34,6 @@ #include "ruby/st.h" #include "ruby/util.h" #include "transient_heap.h" -#include "shape.h" #include "variable.h" #include "vm_core.h" #include "ractor_core.h" @@ -64,9 +63,12 @@ static VALUE rb_const_search(VALUE klass, ID id, int exclude, int recurse, int v static st_table *generic_iv_tbl_; struct ivar_update { - struct gen_ivtbl *ivtbl; - uint32_t iv_index; - rb_shape_t* shape; + union { + st_table *iv_index_tbl; + struct gen_ivtbl *ivtbl; + } u; + st_data_t index; + int iv_extended; }; void @@ -894,6 +896,30 @@ rb_alias_variable(ID name1, ID name2) entry1->var = entry2->var; } +static bool +iv_index_tbl_lookup(struct st_table *tbl, ID id, uint32_t *indexp) +{ + st_data_t ent_data; + int r; + + if (tbl == NULL) return false; + + RB_VM_LOCK_ENTER(); + { + r = st_lookup(tbl, (st_data_t)id, &ent_data); + } + RB_VM_LOCK_LEAVE(); + + if (r) { + struct rb_iv_index_tbl_entry *ent = (void *)ent_data; + *indexp = ent->index; + return true; + } + else { + return false; + } +} + static void IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(ID id) { @@ -931,20 +957,7 @@ generic_ivtbl_no_ractor_check(VALUE obj) } static int -gen_ivtbl_get_unlocked(VALUE obj, ID id, struct gen_ivtbl **ivtbl) -{ - st_data_t data; - - if (st_lookup(generic_ivtbl(obj, id, false), (st_data_t)obj, &data)) { - *ivtbl = (struct gen_ivtbl *)data; - return 1; - } - - return 0; -} - -MJIT_FUNC_EXPORTED int -rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl) +gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl) { st_data_t data; int r = 0; @@ -964,7 +977,63 @@ rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl) MJIT_FUNC_EXPORTED int rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **ivtbl) { - return rb_gen_ivtbl_get(obj, 0, ivtbl); + return gen_ivtbl_get(obj, 0, ivtbl); +} + +MJIT_FUNC_EXPORTED VALUE +rb_ivar_generic_lookup_with_index(VALUE obj, ID id, uint32_t index) +{ + struct gen_ivtbl *ivtbl; + + if (gen_ivtbl_get(obj, id, &ivtbl)) { + if (LIKELY(index < ivtbl->numiv)) { + VALUE val = ivtbl->ivptr[index]; + return val; + } + } + + return Qundef; +} + +static VALUE +generic_ivar_delete(VALUE obj, ID id, VALUE undef) +{ + struct gen_ivtbl *ivtbl; + + if (gen_ivtbl_get(obj, id, &ivtbl)) { + st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); + uint32_t index; + + if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &index)) { + if (index < ivtbl->numiv) { + VALUE ret = ivtbl->ivptr[index]; + + ivtbl->ivptr[index] = Qundef; + return ret == Qundef ? undef : ret; + } + } + } + return undef; +} + +static VALUE +generic_ivar_get(VALUE obj, ID id, VALUE undef) +{ + struct gen_ivtbl *ivtbl; + + if (gen_ivtbl_get(obj, id, &ivtbl)) { + st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); + uint32_t index; + + if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &index)) { + if (index < ivtbl->numiv) { + VALUE ret = ivtbl->ivptr[index]; + + return ret == Qundef ? undef : ret; + } + } + } + return undef; } static size_t @@ -976,8 +1045,6 @@ gen_ivtbl_bytes(size_t n) static struct gen_ivtbl * gen_ivtbl_resize(struct gen_ivtbl *old, uint32_t n) { - RUBY_ASSERT(n > 0); - uint32_t len = old ? old->numiv : 0; struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n)); @@ -1002,6 +1069,18 @@ gen_ivtbl_dup(const struct gen_ivtbl *orig) } #endif +static uint32_t +iv_index_tbl_newsize(struct ivar_update *ivup) +{ + if (!ivup->iv_extended) { + return (uint32_t)ivup->u.iv_index_tbl->num_entries; + } + else { + uint32_t index = (uint32_t)ivup->index; /* should not overflow */ + return (index+1) + (index+1)/4; /* (index+1)*1.25 */ + } +} + static int generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing) { @@ -1012,22 +1091,53 @@ generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing) if (existing) { ivtbl = (struct gen_ivtbl *)*v; - if (ivup->iv_index < ivtbl->numiv) { - ivup->ivtbl = ivtbl; + if (ivup->index < ivtbl->numiv) { + ivup->u.ivtbl = ivtbl; return ST_STOP; } } FL_SET((VALUE)*k, FL_EXIVAR); - ivtbl = gen_ivtbl_resize(ivtbl, ivup->shape->iv_count); - // Reinsert in to the hash table because ivtbl might be a newly resized chunk of memory + uint32_t newsize = iv_index_tbl_newsize(ivup); + ivtbl = gen_ivtbl_resize(ivtbl, newsize); *v = (st_data_t)ivtbl; - ivup->ivtbl = ivtbl; -#if !SHAPE_IN_BASIC_FLAGS - ivtbl->shape_id = rb_shape_id(ivup->shape); -#endif + ivup->u.ivtbl = ivtbl; return ST_CONTINUE; } +static VALUE +generic_ivar_defined(VALUE obj, ID id) +{ + struct gen_ivtbl *ivtbl; + st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); + uint32_t index; + + if (!iv_index_tbl_lookup(iv_index_tbl, id, &index)) return Qfalse; + if (!gen_ivtbl_get(obj, id, &ivtbl)) return Qfalse; + + return RBOOL((index < ivtbl->numiv) && (ivtbl->ivptr[index] != Qundef)); +} + +static int +generic_ivar_remove(VALUE obj, ID id, VALUE *valp) +{ + struct gen_ivtbl *ivtbl; + uint32_t index; + st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); + + if (!iv_index_tbl) return 0; + if (!iv_index_tbl_lookup(iv_index_tbl, id, &index)) return 0; + if (!gen_ivtbl_get(obj, id, &ivtbl)) return 0; + + if (index < ivtbl->numiv) { + if (ivtbl->ivptr[index] != Qundef) { + *valp = ivtbl->ivptr[index]; + ivtbl->ivptr[index] = Qundef; + return 1; + } + } + return 0; +} + static void gen_ivtbl_mark(const struct gen_ivtbl *ivtbl) { @@ -1043,7 +1153,7 @@ rb_mark_generic_ivar(VALUE obj) { struct gen_ivtbl *ivtbl; - if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) { + if (gen_ivtbl_get(obj, 0, &ivtbl)) { gen_ivtbl_mark(ivtbl); } } @@ -1072,35 +1182,11 @@ rb_generic_ivar_memsize(VALUE obj) { struct gen_ivtbl *ivtbl; - if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) + if (gen_ivtbl_get(obj, 0, &ivtbl)) return gen_ivtbl_bytes(ivtbl->numiv); return 0; } -#if !SHAPE_IN_BASIC_FLAGS -MJIT_FUNC_EXPORTED shape_id_t -rb_generic_shape_id(VALUE obj) -{ - struct gen_ivtbl *ivtbl = 0; - shape_id_t shape_id = 0; - - RB_VM_LOCK_ENTER(); - { - st_table* global_iv_table = generic_ivtbl(obj, 0, false); - - if (global_iv_table && st_lookup(global_iv_table, obj, (st_data_t *)&ivtbl)) { - shape_id = ivtbl->shape_id; - } - else if (OBJ_FROZEN(obj)) { - shape_id = FROZEN_ROOT_SHAPE_ID; - } - } - RB_VM_LOCK_LEAVE(); - - return shape_id; -} -#endif - static size_t gen_ivtbl_count(const struct gen_ivtbl *ivtbl) { @@ -1168,16 +1254,23 @@ VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef) { if (SPECIAL_CONST_P(obj)) return undef; - - shape_id_t shape_id; - VALUE * ivar_list; - rb_shape_t * shape; - -#if SHAPE_IN_BASIC_FLAGS - shape_id = RBASIC_SHAPE_ID(obj); -#endif - switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + { + uint32_t index; + uint32_t len = ROBJECT_NUMIV(obj); + VALUE *ptr = ROBJECT_IVPTR(obj); + VALUE val; + + if (iv_index_tbl_lookup(ROBJECT_IV_INDEX_TBL(obj), id, &index) && + index < len && + (val = ptr[index]) != Qundef) { + return val; + } + else { + break; + } + } case T_CLASS: case T_MODULE: { @@ -1194,37 +1287,14 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef) return val; } else { - return undef; + break; } } - case T_OBJECT: - { -#if !SHAPE_IN_BASIC_FLAGS - shape_id = ROBJECT_SHAPE_ID(obj); -#endif - ivar_list = ROBJECT_IVPTR(obj); - break; - } default: - if (FL_TEST_RAW(obj, FL_EXIVAR)) { - struct gen_ivtbl *ivtbl; - rb_gen_ivtbl_get(obj, id, &ivtbl); -#if !SHAPE_IN_BASIC_FLAGS - shape_id = ivtbl->shape_id; -#endif - ivar_list = ivtbl->ivptr; - } else { - return undef; - } + if (FL_TEST(obj, FL_EXIVAR)) + return generic_ivar_get(obj, id, undef); break; } - - attr_index_t index = 0; - shape = rb_shape_get_shape_by_id(shape_id); - if (rb_shape_get_iv_index(shape, id, &index)) { - return ivar_list[index]; - } - return undef; } @@ -1245,12 +1315,26 @@ rb_attr_get(VALUE obj, ID id) static VALUE rb_ivar_delete(VALUE obj, ID id, VALUE undef) { - rb_check_frozen(obj); - - VALUE val = Qnil; - attr_index_t index; + VALUE *ptr; + struct st_table *iv_index_tbl; + uint32_t len, index; + rb_check_frozen(obj); switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + len = ROBJECT_NUMIV(obj); + ptr = ROBJECT_IVPTR(obj); + iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); + if (iv_index_tbl_lookup(iv_index_tbl, id, &index) && + index < len) { + VALUE val = ptr[index]; + ptr[index] = Qundef; + + if (val != Qundef) { + return val; + } + } + break; case T_CLASS: case T_MODULE: IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id); @@ -1261,33 +1345,11 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef) } } break; - case T_OBJECT: { - rb_shape_t * shape = rb_shape_get_shape(obj); - if (rb_shape_get_iv_index(shape, id, &index)) { - rb_shape_transition_shape_remove_ivar(obj, id, shape); - val = ROBJECT_IVPTR(obj)[index]; - ROBJECT_IVPTR(obj)[index] = Qundef; - return val; - } - - break; - } - default: { - rb_shape_t * shape = rb_shape_get_shape(obj); - - if (rb_shape_get_iv_index(shape, id, &index)) { - rb_shape_transition_shape_remove_ivar(obj, id, shape); - struct gen_ivtbl *ivtbl; - rb_gen_ivtbl_get(obj, id, &ivtbl); - val = ivtbl->ivptr[index]; - ivtbl->ivptr[index] = Qundef; - return val; - } - + default: + if (FL_TEST(obj, FL_EXIVAR)) + return generic_ivar_delete(obj, id, undef); break; - } } - return undef; } @@ -1297,31 +1359,67 @@ rb_attr_delete(VALUE obj, ID id) return rb_ivar_delete(obj, id, Qnil); } +static st_table * +iv_index_tbl_make(VALUE obj, VALUE klass) +{ + st_table *iv_index_tbl; + + if (UNLIKELY(!klass)) { + rb_raise(rb_eTypeError, "hidden object cannot have instance variables"); + } + + if ((iv_index_tbl = RCLASS_IV_INDEX_TBL(klass)) == NULL) { + RB_VM_LOCK_ENTER(); + if ((iv_index_tbl = RCLASS_IV_INDEX_TBL(klass)) == NULL) { + iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable(); + } + RB_VM_LOCK_LEAVE(); + } + + return iv_index_tbl; +} + +static void +iv_index_tbl_extend(struct ivar_update *ivup, ID id, VALUE klass) +{ + ASSERT_vm_locking(); + st_data_t ent_data; + struct rb_iv_index_tbl_entry *ent; + + if (st_lookup(ivup->u.iv_index_tbl, (st_data_t)id, &ent_data)) { + ent = (void *)ent_data; + ivup->index = ent->index; + return; + } + if (ivup->u.iv_index_tbl->num_entries >= INT_MAX) { + rb_raise(rb_eArgError, "too many instance variables"); + } + ent = ALLOC(struct rb_iv_index_tbl_entry); + ent->index = ivup->index = (uint32_t)ivup->u.iv_index_tbl->num_entries; + ent->class_value = klass; + ent->class_serial = RCLASS_SERIAL(klass); + st_add_direct(ivup->u.iv_index_tbl, (st_data_t)id, (st_data_t)ent); + ivup->iv_extended = 1; +} + static void generic_ivar_set(VALUE obj, ID id, VALUE val) { + VALUE klass = rb_obj_class(obj); struct ivar_update ivup; - // The returned shape will have `id` in its iv_table - rb_shape_t * shape = rb_shape_get_next(rb_shape_get_shape(obj), obj, id); - ivup.shape = shape; + ivup.iv_extended = 0; + ivup.u.iv_index_tbl = iv_index_tbl_make(obj, klass); RB_VM_LOCK_ENTER(); { - attr_index_t ent_data; - if (rb_shape_get_iv_index(shape, id, &ent_data)) { - ivup.iv_index = (uint32_t) ent_data; - } - else { - rb_bug("unreachable. Shape was not found for id: %s", rb_id2name(id)); - } - - st_update(generic_ivtbl(obj, id, false), (st_data_t)obj, generic_ivar_update, (st_data_t)&ivup); + iv_index_tbl_extend(&ivup, id, klass); + st_update(generic_ivtbl(obj, id, false), (st_data_t)obj, generic_ivar_update, + (st_data_t)&ivup); } RB_VM_LOCK_LEAVE(); - ivup.ivtbl->ivptr[ivup.iv_index] = val; + ivup.u.ivtbl->ivptr[ivup.index] = val; - rb_shape_set_shape(obj, shape); RB_OBJ_WRITTEN(obj, Qundef, val); } @@ -1388,8 +1486,8 @@ rb_obj_transient_heap_evacuate(VALUE obj, int promote) } #endif -void -rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize) +static void +init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table *index_tbl) { VALUE *ptr = ROBJECT_IVPTR(obj); VALUE *newptr; @@ -1412,34 +1510,35 @@ rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize) #else ROBJECT(obj)->as.heap.numiv = newsize; #endif + ROBJECT(obj)->as.heap.iv_index_tbl = index_tbl; +} + +void +rb_init_iv_list(VALUE obj) +{ + st_table *index_tbl = ROBJECT_IV_INDEX_TBL(obj); + uint32_t newsize = (uint32_t)index_tbl->num_entries; + uint32_t len = ROBJECT_NUMIV(obj); + init_iv_list(obj, len, newsize, index_tbl); } -struct gen_ivtbl * -rb_ensure_generic_iv_list_size(VALUE obj, uint32_t newsize) +// Retrieve or create the id-to-index mapping for a given object and an +// instance variable name. +static struct ivar_update +obj_ensure_iv_index_mapping(VALUE obj, ID id) { - struct gen_ivtbl * ivtbl = 0; + VALUE klass = rb_obj_class(obj); + struct ivar_update ivup; + ivup.iv_extended = 0; + ivup.u.iv_index_tbl = iv_index_tbl_make(obj, klass); RB_VM_LOCK_ENTER(); { - if (UNLIKELY(!gen_ivtbl_get_unlocked(obj, 0, &ivtbl) || newsize > ivtbl->numiv)) { - ivtbl = gen_ivtbl_resize(ivtbl, newsize); - st_insert(generic_ivtbl_no_ractor_check(obj), (st_data_t)obj, (st_data_t)ivtbl); - FL_SET_RAW(obj, FL_EXIVAR); - } + iv_index_tbl_extend(&ivup, id, klass); } RB_VM_LOCK_LEAVE(); - RUBY_ASSERT(ivtbl); - - return ivtbl; -} - -void -rb_init_iv_list(VALUE obj) -{ - uint32_t newsize = rb_shape_get_shape(obj)->iv_count * 2.0; - uint32_t len = ROBJECT_NUMIV(obj); - rb_ensure_iv_list_size(obj, len, newsize < len ? len : newsize); + return ivup; } // Return the instance variable index for a given name and T_OBJECT object. The @@ -1453,108 +1552,26 @@ uint32_t rb_obj_ensure_iv_index_mapping(VALUE obj, ID id) { RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT)); - attr_index_t index; - - // Ensure there is a transition for IVAR +id+ - rb_shape_transition_shape(obj, id, rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))); - - // Get the current shape - rb_shape_t * shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj)); - - if (!rb_shape_get_iv_index(shape, id, &index)) { - rb_bug("unreachable. Shape was not found for id: %s", rb_id2name(id)); - } - - uint32_t len = ROBJECT_NUMIV(obj); - if (len <= index) { - uint32_t newsize = (shape->iv_count + 1) * 1.25; - rb_ensure_iv_list_size(obj, len, newsize); - } - RUBY_ASSERT(index <= ROBJECT_NUMIV(obj)); - return index; + // This uint32_t cast shouldn't lose information as it's checked in + // iv_index_tbl_extend(). The index is stored as an uint32_t in + // struct rb_iv_index_tbl_entry. + return (uint32_t)obj_ensure_iv_index_mapping(obj, id).index; } static VALUE obj_ivar_set(VALUE obj, ID id, VALUE val) { - attr_index_t index = rb_obj_ensure_iv_index_mapping(obj, id); - RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[index], val); - return val; -} - -/* Set the instance variable +val+ on object +obj+ at ivar name +id+. - * This function only works with T_OBJECT objects, so make sure - * +obj+ is of type T_OBJECT before using this function. - */ -VALUE -rb_vm_set_ivar_id(VALUE obj, ID id, VALUE val) -{ - rb_check_frozen_internal(obj); - obj_ivar_set(obj, id, val); - return val; -} - -bool -rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id) -{ - if (rb_shape_get_shape_id(obj) == shape_id) { - return false; - } + uint32_t len; + struct ivar_update ivup = obj_ensure_iv_index_mapping(obj, id); -#if SHAPE_IN_BASIC_FLAGS - RBASIC_SET_SHAPE_ID(obj, shape_id); -#else - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - ROBJECT_SET_SHAPE_ID(obj, shape_id); - break; - case T_CLASS: - case T_MODULE: - { - RCLASS_EXT(obj)->shape_id = shape_id; - break; - } - default: - { - if (shape_id != FROZEN_ROOT_SHAPE_ID) { - struct gen_ivtbl *ivtbl = 0; - RB_VM_LOCK_ENTER(); - { - st_table* global_iv_table = generic_ivtbl(obj, 0, false); - - if (st_lookup(global_iv_table, obj, (st_data_t *)&ivtbl)) { - ivtbl->shape_id = shape_id; - } - else { - rb_bug("Expected shape_id entry in global iv table"); - } - } - RB_VM_LOCK_LEAVE(); - } - } + len = ROBJECT_NUMIV(obj); + if (len <= ivup.index) { + uint32_t newsize = iv_index_tbl_newsize(&ivup); + init_iv_list(obj, len, newsize, ivup.u.iv_index_tbl); } -#endif - - return true; -} - -/** - * Prevents further modifications to the given object. ::rb_eFrozenError shall - * be raised if modification is attempted. - * - * @param[out] x Object in question. - */ -void rb_obj_freeze_inline(VALUE x) -{ - if (RB_FL_ABLE(x)) { - RB_OBJ_FREEZE_RAW(x); + RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val); - rb_shape_transition_shape_frozen(x); - - if (RBASIC_CLASS(x) && !(RBASIC(x)->flags & RUBY_FL_SINGLETON)) { - rb_freeze_singleton_class(x); - } - } + return val; } static void @@ -1564,14 +1581,10 @@ ivar_set(VALUE obj, ID id, VALUE val) switch (BUILTIN_TYPE(obj)) { case T_OBJECT: - { - obj_ivar_set(obj, id, val); - break; - } + obj_ivar_set(obj, id, val); + break; case T_CLASS: case T_MODULE: - // TODO: Transition shapes on classes - //rb_shape_transition_shape(obj, id, rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))); IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id); rb_class_ivar_set(obj, id, val); break; @@ -1601,86 +1614,161 @@ rb_ivar_set_internal(VALUE obj, ID id, VALUE val) VALUE rb_ivar_defined(VALUE obj, ID id) { - attr_index_t index; + VALUE val; + struct st_table *iv_index_tbl; + uint32_t index; if (SPECIAL_CONST_P(obj)) return Qfalse; switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); + if (iv_index_tbl_lookup(iv_index_tbl, id, &index) && + index < ROBJECT_NUMIV(obj) && + (val = ROBJECT_IVPTR(obj)[index]) != Qundef) { + return Qtrue; + } + break; case T_CLASS: case T_MODULE: - if (RCLASS_IV_TBL(obj) && lock_st_is_member(RCLASS_IV_TBL(obj), (st_data_t)id)) { + if (RCLASS_IV_TBL(obj) && lock_st_is_member(RCLASS_IV_TBL(obj), (st_data_t)id)) return Qtrue; - } - else { - return Qfalse; - } + break; default: - return RBOOL(rb_shape_get_iv_index(rb_shape_get_shape(obj), id, &index)); + if (FL_TEST(obj, FL_EXIVAR)) + return generic_ivar_defined(obj, id); + break; } + return Qfalse; } typedef int rb_ivar_foreach_callback_func(ID key, VALUE val, st_data_t arg); st_data_t rb_st_nth_key(st_table *tab, st_index_t index); -static void -iterate_over_shapes_with_callback(rb_shape_t *shape, VALUE* iv_list, rb_ivar_foreach_callback_func *callback, st_data_t arg) { - switch ((enum shape_type)shape->type) { - case SHAPE_ROOT: - return; - case SHAPE_IVAR: - iterate_over_shapes_with_callback(shape->parent, iv_list, callback, arg); - VALUE val = iv_list[shape->iv_count - 1]; - if (val != Qundef) { - callback(shape->edge_name, val, arg); - } - return; - case SHAPE_IVAR_UNDEF: - case SHAPE_FROZEN: - iterate_over_shapes_with_callback(shape->parent, iv_list, callback, arg); - return; +static ID +iv_index_tbl_nth_id(st_table *iv_index_tbl, uint32_t index) +{ + st_data_t key; + RB_VM_LOCK_ENTER(); + { + key = rb_st_nth_key(iv_index_tbl, index); + } + RB_VM_LOCK_LEAVE(); + return (ID)key; +} + +static inline bool +ivar_each_i(st_table *iv_index_tbl, VALUE val, uint32_t i, rb_ivar_foreach_callback_func *func, st_data_t arg) +{ + if (val != Qundef) { + ID id = iv_index_tbl_nth_id(iv_index_tbl, i); + switch (func(id, val, arg)) { + case ST_CHECK: + case ST_CONTINUE: + break; + case ST_STOP: + return true; + default: + rb_bug("unreachable"); + } } + return false; } static void obj_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg) { - rb_shape_t* shape = rb_shape_get_shape(obj); - iterate_over_shapes_with_callback(shape, ROBJECT_IVPTR(obj), func, arg); + st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); + if (!iv_index_tbl) return; + uint32_t i=0; + + for (i=0; i < ROBJECT_NUMIV(obj); i++) { + VALUE val = ROBJECT_IVPTR(obj)[i]; + if (ivar_each_i(iv_index_tbl, val, i, func, arg)) { + return; + } + } } static void gen_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg) { - rb_shape_t *shape = rb_shape_get_shape(obj); struct gen_ivtbl *ivtbl; - if (!rb_gen_ivtbl_get(obj, 0, &ivtbl)) return; + st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); + if (!iv_index_tbl) return; + if (!gen_ivtbl_get(obj, 0, &ivtbl)) return; - iterate_over_shapes_with_callback(shape, ivtbl->ivptr, func, arg); + for (uint32_t i=0; i<ivtbl->numiv; i++) { + VALUE val = ivtbl->ivptr[i]; + if (ivar_each_i(iv_index_tbl, val, i, func, arg)) { + return; + } + } +} + +struct givar_copy { + VALUE obj; + VALUE klass; + st_table *iv_index_tbl; + struct gen_ivtbl *ivtbl; +}; + +static int +gen_ivar_copy(ID id, VALUE val, st_data_t arg) +{ + struct givar_copy *c = (struct givar_copy *)arg; + struct ivar_update ivup; + + ivup.iv_extended = 0; + ivup.u.iv_index_tbl = c->iv_index_tbl; + + RB_VM_LOCK_ENTER(); + { + iv_index_tbl_extend(&ivup, id, c->klass); + } + RB_VM_LOCK_LEAVE(); + + if (ivup.index >= c->ivtbl->numiv) { + uint32_t newsize = iv_index_tbl_newsize(&ivup); + c->ivtbl = gen_ivtbl_resize(c->ivtbl, newsize); + } + c->ivtbl->ivptr[ivup.index] = val; + + RB_OBJ_WRITTEN(c->obj, Qundef, val); + + return ST_CONTINUE; } void rb_copy_generic_ivar(VALUE clone, VALUE obj) { - struct gen_ivtbl *obj_ivtbl; - struct gen_ivtbl *new_ivtbl; + struct gen_ivtbl *ivtbl; rb_check_frozen(clone); if (!FL_TEST(obj, FL_EXIVAR)) { goto clear; } + if (gen_ivtbl_get(obj, 0, &ivtbl)) { + struct givar_copy c; + uint32_t i; - if (rb_gen_ivtbl_get(obj, 0, &obj_ivtbl)) { - if (gen_ivtbl_count(obj_ivtbl) == 0) + if (gen_ivtbl_count(ivtbl) == 0) goto clear; - new_ivtbl = gen_ivtbl_resize(0, obj_ivtbl->numiv); - FL_SET(clone, FL_EXIVAR); - - for (uint32_t i=0; i<obj_ivtbl->numiv; i++) { - new_ivtbl->ivptr[i] = obj_ivtbl->ivptr[i]; - RB_OBJ_WRITTEN(clone, Qundef, &new_ivtbl[i]); + if (gen_ivtbl_get(clone, 0, &c.ivtbl)) { + for (i = 0; i < c.ivtbl->numiv; i++) + c.ivtbl->ivptr[i] = Qundef; + } + else { + c.ivtbl = gen_ivtbl_resize(0, ivtbl->numiv); + FL_SET(clone, FL_EXIVAR); } + VALUE klass = rb_obj_class(clone); + c.iv_index_tbl = iv_index_tbl_make(clone, klass); + c.obj = clone; + c.klass = klass; + gen_ivar_each(obj, gen_ivar_copy, (st_data_t)&c); /* * c.ivtbl may change in gen_ivar_copy due to realloc, * no need to free @@ -1688,17 +1776,9 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj) RB_VM_LOCK_ENTER(); { generic_ivtbl_no_ractor_check(clone); - st_insert(generic_ivtbl_no_ractor_check(obj), (st_data_t)clone, (st_data_t)new_ivtbl); + st_insert(generic_ivtbl_no_ractor_check(obj), (st_data_t)clone, (st_data_t)c.ivtbl); } RB_VM_LOCK_LEAVE(); - - rb_shape_t * obj_shape = rb_shape_get_shape(obj); - if (rb_shape_frozen_shape_p(obj_shape)) { - rb_shape_set_shape(clone, obj_shape->parent); - } - else { - rb_shape_set_shape(clone, obj_shape); - } } return; @@ -1766,7 +1846,7 @@ rb_ivar_count(VALUE obj) switch (BUILTIN_TYPE(obj)) { case T_OBJECT: - if (rb_shape_get_shape(obj)->iv_count > 0) { + if (ROBJECT_IV_INDEX_TBL(obj) != 0) { st_index_t i, count, num = ROBJECT_NUMIV(obj); const VALUE *const ivptr = ROBJECT_IVPTR(obj); for (i = count = 0; i < num; ++i) { @@ -1787,7 +1867,7 @@ rb_ivar_count(VALUE obj) if (FL_TEST(obj, FL_EXIVAR)) { struct gen_ivtbl *ivtbl; - if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) { + if (gen_ivtbl_get(obj, 0, &ivtbl)) { return gen_ivtbl_count(ivtbl); } } @@ -1885,53 +1965,40 @@ rb_obj_remove_instance_variable(VALUE obj, VALUE name) { VALUE val = Qnil; const ID id = id_for_var(obj, name, an, instance); + st_data_t n, v; + struct st_table *iv_index_tbl; + uint32_t index; - // Frozen check comes here because it's expected that we raise a - // NameError (from the id_for_var check) before we raise a FrozenError rb_check_frozen(obj); - - attr_index_t index; - if (!id) { goto not_defined; } switch (BUILTIN_TYPE(obj)) { + case T_OBJECT: + iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); + if (iv_index_tbl_lookup(iv_index_tbl, id, &index) && + index < ROBJECT_NUMIV(obj) && + (val = ROBJECT_IVPTR(obj)[index]) != Qundef) { + ROBJECT_IVPTR(obj)[index] = Qundef; + return val; + } + break; case T_CLASS: case T_MODULE: IVAR_ACCESSOR_SHOULD_BE_MAIN_RACTOR(id); - if (RCLASS_IV_TBL(obj)) { - st_data_t id_data = (st_data_t)id, val; - if (lock_st_delete(RCLASS_IV_TBL(obj), &id_data, &val)) { - return (VALUE)val; - } + n = id; + if (RCLASS_IV_TBL(obj) && lock_st_delete(RCLASS_IV_TBL(obj), &n, &v)) { + return (VALUE)v; } break; - case T_OBJECT: { - rb_shape_t * shape = rb_shape_get_shape(obj); - if (rb_shape_get_iv_index(shape, id, &index)) { - rb_shape_transition_shape_remove_ivar(obj, id, shape); - val = ROBJECT_IVPTR(obj)[index]; - ROBJECT_IVPTR(obj)[index] = Qundef; - return val; - } - - break; - } - default: { - rb_shape_t * shape = rb_shape_get_shape(obj); - - if (rb_shape_get_iv_index(shape, id, &index)) { - rb_shape_transition_shape_remove_ivar(obj, id, shape); - struct gen_ivtbl *ivtbl; - rb_gen_ivtbl_get(obj, id, &ivtbl); - val = ivtbl->ivptr[index]; - ivtbl->ivptr[index] = Qundef; - return val; + default: + if (FL_TEST(obj, FL_EXIVAR)) { + if (generic_ivar_remove(obj, id, &val)) { + return val; + } } - break; - } } not_defined: diff --git a/variable.h b/variable.h index 314ac82df0..55596b00de 100644 --- a/variable.h +++ b/variable.h @@ -11,19 +11,11 @@ /* per-object */ struct gen_ivtbl { -#if !SHAPE_IN_BASIC_FLAGS - uint16_t shape_id; -#endif uint32_t numiv; VALUE ivptr[FLEX_ARY_LEN]; }; int rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **); - -#include "shape.h" -#if !SHAPE_IN_BASIC_FLAGS -shape_id_t rb_generic_shape_id(VALUE obj); -#endif - +VALUE rb_ivar_generic_lookup_with_index(VALUE obj, ID id, uint32_t index); #endif /* RUBY_TOPLEVEL_VARIABLE_H */ @@ -26,7 +26,6 @@ #include "internal/thread.h" #include "internal/vm.h" #include "internal/sanitizers.h" -#include "internal/variable.h" #include "iseq.h" #include "mjit.h" #include "yjit.h" @@ -4022,11 +4021,6 @@ Init_BareVM(void) rb_native_cond_initialize(&vm->ractor.sync.terminate_cond); } -#ifndef _WIN32 -#include <unistd.h> -#include <sys/mman.h> -#endif - void Init_vm_objects(void) { @@ -4038,31 +4032,6 @@ Init_vm_objects(void) vm->mark_object_ary = rb_ary_hidden_new(128); vm->loading_table = st_init_strtable(); vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 10000); - -#if HAVE_MMAP - vm->shape_list = (rb_shape_t *)mmap(NULL, rb_size_mul_or_raise(SHAPE_BITMAP_SIZE * 32, sizeof(rb_shape_t), rb_eRuntimeError), - PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (vm->shape_list == MAP_FAILED) { - vm->shape_list = 0; - } -#else - vm->shape_list = xcalloc(SHAPE_BITMAP_SIZE * 32, sizeof(rb_shape_t)); -#endif - - if (!vm->shape_list) { - rb_memerror(); - } - - // Root shape - vm->root_shape = rb_shape_alloc(0, 0); - RUBY_ASSERT(rb_shape_id(vm->root_shape) == ROOT_SHAPE_ID); - - // Frozen root shape - vm->frozen_root_shape = rb_shape_alloc(rb_make_internal_id(), vm->root_shape); - vm->frozen_root_shape->type = (uint8_t)SHAPE_FROZEN; - RUBY_ASSERT(rb_shape_id(vm->frozen_root_shape) == FROZEN_ROOT_SHAPE_ID); - - vm->next_shape_id = 2; } /* Stub for builtin function when not building YJIT units*/ diff --git a/vm_callinfo.h b/vm_callinfo.h index e5b04c0709..fd2215be7d 100644 --- a/vm_callinfo.h +++ b/vm_callinfo.h @@ -10,7 +10,6 @@ #include "debug_counter.h" #include "internal/class.h" -#include "shape.h" enum vm_call_flag_bits { VM_CALL_ARGS_SPLAT_bit, /* m(*args) */ @@ -285,32 +284,14 @@ struct rb_callcache { const vm_call_handler call_; union { - struct { - const attr_index_t index; - shape_id_t dest_shape_id; - } attr; + const unsigned int attr_index; const enum method_missing_reason method_missing_reason; /* used by method_missing */ VALUE v; } aux_; }; -#define VM_CALLCACHE_UNMARKABLE FL_FREEZE -#define VM_CALLCACHE_ON_STACK FL_EXIVAR - -extern const struct rb_callcache *rb_vm_empty_cc(void); -extern const struct rb_callcache *rb_vm_empty_cc_for_super(void); - -#define vm_cc_empty() rb_vm_empty_cc() - -static inline void -vm_cc_attr_index_initialize(const struct rb_callcache *cc, shape_id_t shape_id) -{ - VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); - VM_ASSERT(cc != vm_cc_empty()); - IMEMO_SET_CACHED_SHAPE_ID((VALUE)cc, shape_id); - *(attr_index_t *)&cc->aux_.attr.index = 0; - *(shape_id_t *)&cc->aux_.attr.dest_shape_id = shape_id; -} +#define VM_CALLCACHE_UNMARKABLE IMEMO_FL_USER0 +#define VM_CALLCACHE_ON_STACK IMEMO_FL_USER1 static inline const struct rb_callcache * vm_cc_new(VALUE klass, @@ -318,7 +299,6 @@ vm_cc_new(VALUE klass, vm_call_handler call) { const struct rb_callcache *cc = (const struct rb_callcache *)rb_imemo_new(imemo_callcache, (VALUE)cme, (VALUE)call, 0, klass); - vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID); RB_DEBUG_COUNTER_INC(cc_new); return cc; } @@ -370,71 +350,30 @@ vm_cc_call(const struct rb_callcache *cc) return cc->call_; } -static inline attr_index_t +static inline unsigned int vm_cc_attr_index(const struct rb_callcache *cc) { VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); - return cc->aux_.attr.index - 1; + return cc->aux_.attr_index - 1; } static inline bool vm_cc_attr_index_p(const struct rb_callcache *cc) { VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); - return cc->aux_.attr.index != 0; -} - -static inline shape_id_t -vm_cc_attr_index_source_shape_id(const struct rb_callcache *cc) -{ - VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); - - return IMEMO_CACHED_SHAPE_ID((VALUE)cc); + return cc->aux_.attr_index > 0; } -static inline shape_id_t -vm_cc_attr_shape_id(const struct rb_callcache *cc) +static inline uint32_t +vm_ic_entry_index(const struct iseq_inline_iv_cache_entry *ic) { - VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); - return vm_cc_attr_index_source_shape_id(cc); -} - -static inline shape_id_t -vm_cc_attr_index_dest_shape_id(const struct rb_callcache *cc) -{ - VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); - - return cc->aux_.attr.dest_shape_id; -} - -static inline attr_index_t -vm_ic_attr_index(const struct iseq_inline_iv_cache_entry *ic) -{ - return ic->attr_index - 1; + return ic->entry->index; } static inline bool -vm_ic_attr_index_p(const struct iseq_inline_iv_cache_entry *ic) -{ - return ic->attr_index > 0; -} - -static inline shape_id_t -vm_ic_attr_shape_id(const struct iseq_inline_iv_cache_entry *ic) -{ - return ic->source_shape_id; -} - -static inline shape_id_t -vm_ic_attr_index_source_shape_id(const struct iseq_inline_iv_cache_entry *ic) +vm_ic_entry_p(const struct iseq_inline_iv_cache_entry *ic) { - return ic->source_shape_id; -} - -static inline shape_id_t -vm_ic_attr_index_dest_shape_id(const struct iseq_inline_iv_cache_entry *ic) -{ - return ic->dest_shape_id; + return ic->entry; } static inline unsigned int @@ -468,6 +407,10 @@ vm_cc_valid_p(const struct rb_callcache *cc, const rb_callable_method_entry_t *c } } +extern const struct rb_callcache *rb_vm_empty_cc(void); +extern const struct rb_callcache *rb_vm_empty_cc_for_super(void); +#define vm_cc_empty() rb_vm_empty_cc() + /* callcache: mutate */ static inline void @@ -479,29 +422,26 @@ vm_cc_call_set(const struct rb_callcache *cc, vm_call_handler call) } static inline void -vm_cc_attr_index_set(const struct rb_callcache *cc, attr_index_t index, shape_id_t source_shape_id, shape_id_t dest_shape_id) +vm_cc_attr_index_set(const struct rb_callcache *cc, int index) { VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); VM_ASSERT(cc != vm_cc_empty()); - IMEMO_SET_CACHED_SHAPE_ID((VALUE)cc, source_shape_id); - *(attr_index_t *)&cc->aux_.attr.index = (index + 1); - *(shape_id_t *)&cc->aux_.attr.dest_shape_id = dest_shape_id; + *(int *)&cc->aux_.attr_index = index + 1; } static inline void -vm_ic_attr_index_set(const rb_iseq_t *iseq, const struct iseq_inline_iv_cache_entry *ic, attr_index_t index, shape_id_t source_shape_id, shape_id_t dest_shape_id) +vm_ic_entry_set(struct iseq_inline_iv_cache_entry *ic, struct rb_iv_index_tbl_entry *entry, const rb_iseq_t *iseq) { - *(shape_id_t *)&ic->source_shape_id = source_shape_id; - *(shape_id_t *)&ic->dest_shape_id = dest_shape_id; - *(attr_index_t *)&ic->attr_index = index + 1; + ic->entry = entry; + RB_OBJ_WRITTEN(iseq, Qundef, entry->class_value); } static inline void -vm_ic_attr_index_initialize(const struct iseq_inline_iv_cache_entry *ic, shape_id_t shape_id) +vm_cc_attr_index_initialize(const struct rb_callcache *cc) { - *(shape_id_t *)&ic->source_shape_id = shape_id; - *(shape_id_t *)&ic->dest_shape_id = shape_id; - *(attr_index_t *)&ic->attr_index = 0; + VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache)); + VM_ASSERT(cc != vm_cc_empty()); + *(int *)&cc->aux_.attr_index = 0; } static inline void @@ -99,7 +99,6 @@ extern int ruby_assert_critical_section_entered; #include "ruby/st.h" #include "ruby_atomic.h" #include "vm_opts.h" -#include "shape.h" #include "ruby/thread_native.h" @@ -273,9 +272,7 @@ struct iseq_inline_constant_cache { }; struct iseq_inline_iv_cache_entry { - shape_id_t source_shape_id; - shape_id_t dest_shape_id; - attr_index_t attr_index; + struct rb_iv_index_tbl_entry *entry; }; struct iseq_inline_cvar_cache_entry { @@ -690,12 +687,6 @@ typedef struct rb_vm_struct { VALUE mark_object_ary; const VALUE special_exceptions[ruby_special_error_count]; - /* object shapes */ - rb_shape_t *shape_list; - rb_shape_t *root_shape; - rb_shape_t *frozen_root_shape; - shape_id_t next_shape_id; - /* load */ VALUE top_self; VALUE load_path; @@ -47,7 +47,7 @@ rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE { struct rb_calling_info calling = { .ci = &VM_CI_ON_STACK(id, kw_splat ? VM_CALL_KW_SPLAT : 0, argc, NULL), - .cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme), + .cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, { 0 }, cme), .block_handler = vm_passed_block_handler(ec), .recv = recv, .argc = argc, @@ -89,7 +89,7 @@ vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE static VALUE vm_call0_cme(rb_execution_context_t *ec, struct rb_calling_info *calling, const VALUE *argv, const rb_callable_method_entry_t *cme) { - calling->cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme); + calling->cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, { 0 }, cme); return vm_call0_body(ec, calling, argv); } diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 8d1369c604..a662de468d 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -50,11 +50,6 @@ MJIT_STATIC VALUE ruby_vm_special_exception_copy(VALUE exc) { VALUE e = rb_obj_alloc(rb_class_real(RBASIC_CLASS(exc))); - rb_shape_t * shape = rb_shape_get_shape(exc); - if (rb_shape_frozen_shape_p(shape)) { - shape = shape->parent; - } - rb_shape_set_shape(e, shape); rb_obj_copy_ivar(e, exc); return e; } @@ -1090,17 +1085,35 @@ vm_get_cvar_base(const rb_cref_t *cref, const rb_control_frame_t *cfp, int top_l return klass; } -ALWAYS_INLINE(static void fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, attr_index_t index, shape_id_t shape_id)); +static bool +iv_index_tbl_lookup(struct st_table *iv_index_tbl, ID id, struct rb_iv_index_tbl_entry **ent) +{ + int found; + st_data_t ent_data; + + if (iv_index_tbl == NULL) return false; + + RB_VM_LOCK_ENTER(); + { + found = st_lookup(iv_index_tbl, (st_data_t)id, &ent_data); + } + RB_VM_LOCK_LEAVE(); + if (found) *ent = (struct rb_iv_index_tbl_entry *)ent_data; + + return found ? true : false; +} + +ALWAYS_INLINE(static void fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, struct rb_iv_index_tbl_entry *ent)); + static inline void -fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, attr_index_t index, shape_id_t shape_id) +fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, struct rb_iv_index_tbl_entry *ent) { - if (is_attr) { - if (vm_cc_markable(cc)) { - vm_cc_attr_index_set(cc, index, shape_id, shape_id); - } + // fill cache + if (!is_attr) { + vm_ic_entry_set(ic, ent, iseq); } else { - vm_ic_attr_index_set(iseq, ic, index, shape_id, shape_id); + vm_cc_attr_index_set(cc, ent->index); } } @@ -1110,120 +1123,68 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call { #if OPT_IC_FOR_IVAR VALUE val = Qundef; - shape_id_t shape_id; - VALUE * ivar_list; if (SPECIAL_CONST_P(obj)) { - return Qnil; + // frozen? } + else if (LIKELY(is_attr ? + RB_DEBUG_COUNTER_INC_UNLESS(ivar_get_ic_miss_unset, vm_cc_attr_index_p(cc)) : + RB_DEBUG_COUNTER_INC_UNLESS(ivar_get_ic_miss_serial, vm_ic_entry_p(ic) && ic->entry->class_serial == RCLASS_SERIAL(RBASIC(obj)->klass)))) { + uint32_t index = !is_attr ? vm_ic_entry_index(ic): (vm_cc_attr_index(cc)); -#if SHAPE_IN_BASIC_FLAGS - shape_id = RBASIC_SHAPE_ID(obj); -#endif + RB_DEBUG_COUNTER_INC(ivar_get_ic_hit); - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - ivar_list = ROBJECT_IVPTR(obj); - VM_ASSERT(rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true); + if (LIKELY(BUILTIN_TYPE(obj) == T_OBJECT) && + LIKELY(index < ROBJECT_NUMIV(obj))) { + val = ROBJECT_IVPTR(obj)[index]; -#if !SHAPE_IN_BASIC_FLAGS - shape_id = ROBJECT_SHAPE_ID(obj); -#endif - break; - case T_CLASS: - case T_MODULE: - { - goto general_path; - } - default: - if (FL_TEST_RAW(obj, FL_EXIVAR)) { - struct gen_ivtbl *ivtbl; - rb_gen_ivtbl_get(obj, id, &ivtbl); -#if !SHAPE_IN_BASIC_FLAGS - shape_id = ivtbl->shape_id; -#endif - ivar_list = ivtbl->ivptr; - } else { - return Qnil; - } - } - - shape_id_t cached_id; + VM_ASSERT(rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true); + } + else if (FL_TEST_RAW(obj, FL_EXIVAR)) { + val = rb_ivar_generic_lookup_with_index(obj, id, index); + } - if (is_attr) { - cached_id = vm_cc_attr_shape_id(cc); + goto ret; } else { - cached_id = vm_ic_attr_shape_id(ic); - } + struct rb_iv_index_tbl_entry *ent; - attr_index_t index; + if (BUILTIN_TYPE(obj) == T_OBJECT) { + struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); - if (LIKELY(cached_id == shape_id)) { - RB_DEBUG_COUNTER_INC(ivar_get_ic_hit); + if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &ent)) { + fill_ivar_cache(iseq, ic, cc, is_attr, ent); - if (is_attr && vm_cc_attr_index_p(cc)) { - index = vm_cc_attr_index(cc); - } - else if (!is_attr && vm_ic_attr_index_p(ic)) { - index = vm_ic_attr_index(ic); - } - else { - return Qnil; + // get value + if (ent->index < ROBJECT_NUMIV(obj)) { + val = ROBJECT_IVPTR(obj)[ent->index]; + + VM_ASSERT(rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true); + } + } } + else if (FL_TEST_RAW(obj, FL_EXIVAR)) { + struct st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj)); - val = ivar_list[index]; - VM_ASSERT(BUILTIN_TYPE(obj) == T_OBJECT && rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true); - } - else { // cache miss case -#if RUBY_DEBUG - if (is_attr) { - if (cached_id != INVALID_SHAPE_ID) { - RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_set); - } else { - RB_DEBUG_COUNTER_INC(ivar_get_cc_miss_unset); + if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &ent)) { + fill_ivar_cache(iseq, ic, cc, is_attr, ent); + val = rb_ivar_generic_lookup_with_index(obj, id, ent->index); } } else { - if (cached_id != INVALID_SHAPE_ID) { - RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_set); - } else { - RB_DEBUG_COUNTER_INC(ivar_get_ic_miss_unset); - } + // T_CLASS / T_MODULE + goto general_path; } -#endif - - attr_index_t index; - rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id); - if (rb_shape_get_iv_index(shape, id, &index)) { - // This fills in the cache with the shared cache object. - // "ent" is the shared cache object - fill_ivar_cache(iseq, ic, cc, is_attr, index, shape_id); - - // We fetched the ivar list above - val = ivar_list[index]; + ret: + if (LIKELY(val != Qundef)) { + return val; } else { - if (is_attr) { - if (vm_cc_markable(cc)) { - vm_cc_attr_index_initialize(cc, shape_id); - } - } - else { - vm_ic_attr_index_initialize(ic, shape_id); - } - - val = Qnil; + return Qnil; } - } - - RUBY_ASSERT(val != Qundef); - - return val; - -general_path: + general_path: #endif /* OPT_IC_FOR_IVAR */ RB_DEBUG_COUNTER_INC(ivar_get_ic_miss); @@ -1235,20 +1196,6 @@ general_path: } } -static void -populate_cache(attr_index_t index, shape_id_t shape_id, shape_id_t next_shape_id, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, bool is_attr) -{ - // Cache population code - if (is_attr) { - if (vm_cc_markable(cc)) { - vm_cc_attr_index_set(cc, index, shape_id, next_shape_id); - } - } - else { - vm_ic_attr_index_set(iseq, ic, index, shape_id, next_shape_id); - } -} - ALWAYS_INLINE(static VALUE vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr)); NOINLINE(static VALUE vm_setivar_slowpath_ivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic)); NOINLINE(static VALUE vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, const struct rb_callcache *cc)); @@ -1256,72 +1203,35 @@ NOINLINE(static VALUE vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, cons static VALUE vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr) { -#if OPT_IC_FOR_IVAR - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - { - rb_check_frozen_internal(obj); - - attr_index_t index; - - uint32_t num_iv = ROBJECT_NUMIV(obj); - rb_shape_t* shape = rb_shape_get_shape(obj); - shape_id_t current_shape_id = ROBJECT_SHAPE_ID(obj); - shape_id_t next_shape_id = current_shape_id; - - rb_shape_t* next_shape = rb_shape_get_next(shape, obj, id); - - if (shape != next_shape) { - rb_shape_set_shape(obj, next_shape); - next_shape_id = ROBJECT_SHAPE_ID(obj); - } - - if (rb_shape_get_iv_index(next_shape, id, &index)) { // based off the hash stored in the transition tree - if (index >= MAX_IVARS) { - rb_raise(rb_eArgError, "too many instance variables"); - } - - populate_cache(index, current_shape_id, next_shape_id, id, iseq, ic, cc, is_attr); - } - else { - rb_bug("Didn't find instance variable %s\n", rb_id2name(id)); - } - - // Ensure the IV buffer is wide enough to store the IV - if (UNLIKELY(index >= num_iv)) { - rb_init_iv_list(obj); - } + rb_check_frozen_internal(obj); - VALUE *ptr = ROBJECT_IVPTR(obj); - RB_OBJ_WRITE(obj, &ptr[index], val); - RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_iv_hit); +#if OPT_IC_FOR_IVAR + if (RB_TYPE_P(obj, T_OBJECT)) { + struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); + struct rb_iv_index_tbl_entry *ent; - return val; + if (iv_index_tbl_lookup(iv_index_tbl, id, &ent)) { + if (!is_attr) { + vm_ic_entry_set(ic, ent, iseq); + } + else if (ent->index >= INT_MAX) { + rb_raise(rb_eArgError, "too many instance variables"); + } + else { + vm_cc_attr_index_set(cc, (int)(ent->index)); } - case T_CLASS: - case T_MODULE: - break; - default: - { - shape_id_t shape_id = rb_shape_get_shape_id(obj); - rb_ivar_set(obj, id, val); - shape_id_t next_shape_id = rb_shape_get_shape_id(obj); - rb_shape_t *next_shape = rb_shape_get_shape_by_id(next_shape_id); - attr_index_t index; - - if (rb_shape_get_iv_index(next_shape, id, &index)) { // based off the hash stored in the transition tree - if (index >= MAX_IVARS) { - rb_raise(rb_eArgError, "too many instance variables"); - } - populate_cache(index, shape_id, next_shape_id, id, iseq, ic, cc, is_attr); - } - else { - rb_bug("didn't find the id\n"); - } + uint32_t index = ent->index; - return val; + if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { + rb_init_iv_list(obj); } + VALUE *ptr = ROBJECT_IVPTR(obj); + RB_OBJ_WRITE(obj, &ptr[index], val); + RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_iv_hit); + + return val; + } } #endif RB_DEBUG_COUNTER_INC(ivar_set_ic_miss); @@ -1340,94 +1250,39 @@ vm_setivar_slowpath_attr(VALUE obj, ID id, VALUE val, const struct rb_callcache return vm_setivar_slowpath(obj, id, val, NULL, NULL, cc, true); } -NOINLINE(static VALUE vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t source_shape_id, shape_id_t dest_shape_id, attr_index_t index)); -static VALUE -vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t source_shape_id, shape_id_t dest_shape_id, attr_index_t index) -{ -#if SHAPE_IN_BASIC_FLAGS - shape_id_t shape_id = RBASIC_SHAPE_ID(obj); -#else - shape_id_t shape_id = rb_generic_shape_id(obj); -#endif - - // Cache hit case - if (shape_id == source_shape_id) { - RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); - - struct gen_ivtbl *ivtbl = 0; - if (dest_shape_id != shape_id) { - ivtbl = rb_ensure_generic_iv_list_size(obj, index + 1); -#if SHAPE_IN_BASIC_FLAGS - RBASIC_SET_SHAPE_ID(obj, dest_shape_id); -#else - ivtbl->shape_id = dest_shape_id; -#endif - } - else { - // Just get the IV table - rb_gen_ivtbl_get(obj, 0, &ivtbl); - } - - VALUE *ptr = ivtbl->ivptr; - - RB_OBJ_WRITE(obj, &ptr[index], val); - - RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); - - return val; - } - - return Qundef; -} - static inline VALUE -vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t source_shape_id, shape_id_t dest_shape_id, attr_index_t index) +vm_setivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr) { #if OPT_IC_FOR_IVAR - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - { - VM_ASSERT(!rb_ractor_shareable_p(obj) || rb_obj_frozen_p(obj)); - // If object's shape id is the same as the source - // then do the shape transition and write the ivar - // If object's shape id is the same as the dest - // then write the ivar - shape_id_t shape_id = ROBJECT_SHAPE_ID(obj); - - // Do we have a cache hit *and* is the CC intitialized - if (shape_id == source_shape_id) { - RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); - - VM_ASSERT(!rb_ractor_shareable_p(obj)); - - if (dest_shape_id != shape_id) { - if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { - rb_init_iv_list(obj); - } - ROBJECT_SET_SHAPE_ID(obj, dest_shape_id); - } - - RUBY_ASSERT(index < ROBJECT_NUMIV(obj)); + if (LIKELY(RB_TYPE_P(obj, T_OBJECT)) && + LIKELY(!RB_OBJ_FROZEN_RAW(obj))) { - VALUE *ptr = ROBJECT_IVPTR(obj); + VM_ASSERT(!rb_ractor_shareable_p(obj)); - RB_OBJ_WRITE(obj, &ptr[index], val); + if (LIKELY( + (!is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_serial, vm_ic_entry_p(ic) && ic->entry->class_serial == RCLASS_SERIAL(RBASIC(obj)->klass))) || + ( is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_unset, vm_cc_attr_index_p(cc))))) { + uint32_t index = !is_attr ? vm_ic_entry_index(ic) : vm_cc_attr_index(cc); - RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); - - return val; - } + if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { + rb_init_iv_list(obj); } - break; - case T_CLASS: - case T_MODULE: + VALUE *ptr = ROBJECT_IVPTR(obj); + RB_OBJ_WRITE(obj, &ptr[index], val); + RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); + return val; /* inline cache hit */ + } + } + else { RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_noobject); - default: - break; } - - return Qundef; #endif /* OPT_IC_FOR_IVAR */ + if (is_attr) { + return vm_setivar_slowpath_attr(obj, id, val, cc); + } + else { + return vm_setivar_slowpath_ivar(obj, id, val, iseq, ic); + } } static VALUE @@ -1522,22 +1377,7 @@ vm_getinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, IVC ic) static inline void vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IVC ic) { - shape_id_t source_shape_id = vm_ic_attr_index_source_shape_id(ic); - attr_index_t index = vm_ic_attr_index(ic); - shape_id_t dest_shape_id = vm_ic_attr_index_dest_shape_id(ic); - if (UNLIKELY(vm_setivar(obj, id, val, source_shape_id, dest_shape_id, index) == Qundef)) { - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - case T_CLASS: - case T_MODULE: - break; - default: - if (vm_setivar_default(obj, id, val, source_shape_id, dest_shape_id, index) != Qundef) { - return; - } - } - vm_setivar_slowpath_ivar(obj, id, val, iseq, ic); - } + vm_setivar(obj, id, val, iseq, ic, 0, 0); } void @@ -1546,6 +1386,28 @@ rb_vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IV vm_setinstancevariable(iseq, obj, id, val, ic); } +/* Set the instance variable +val+ on object +obj+ at the +index+. + * This function only works with T_OBJECT objects, so make sure + * +obj+ is of type T_OBJECT before using this function. + */ +VALUE +rb_vm_set_ivar_idx(VALUE obj, uint32_t index, VALUE val) +{ + RUBY_ASSERT(RB_TYPE_P(obj, T_OBJECT)); + + rb_check_frozen_internal(obj); + + VM_ASSERT(!rb_ractor_shareable_p(obj)); + + if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { + rb_init_iv_list(obj); + } + VALUE *ptr = ROBJECT_IVPTR(obj); + RB_OBJ_WRITE(obj, &ptr[index], val); + + return val; +} + static VALUE vm_throw_continue(const rb_execution_context_t *ec, VALUE err) { @@ -3238,45 +3100,17 @@ vm_call_ivar(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_call const struct rb_callcache *cc = calling->cc; RB_DEBUG_COUNTER_INC(ccf_ivar); cfp->sp -= 1; - VALUE ivar = vm_getivar(calling->recv, vm_cc_cme(cc)->def->body.attr.id, NULL, NULL, cc, TRUE); - return ivar; + return vm_getivar(calling->recv, vm_cc_cme(cc)->def->body.attr.id, NULL, NULL, cc, TRUE); } static VALUE -vm_call_attrset_direct(rb_execution_context_t *ec, rb_control_frame_t *cfp, const struct rb_callcache *cc, VALUE obj) +vm_call_attrset(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling) { + const struct rb_callcache *cc = calling->cc; RB_DEBUG_COUNTER_INC(ccf_attrset); VALUE val = *(cfp->sp - 1); cfp->sp -= 2; - shape_id_t source_shape_id = vm_cc_attr_index_source_shape_id(cc); - attr_index_t index = vm_cc_attr_index(cc); - shape_id_t dest_shape_id = vm_cc_attr_index_dest_shape_id(cc); - ID id = vm_cc_cme(cc)->def->body.attr.id; - rb_check_frozen_internal(obj); - VALUE res = vm_setivar(obj, id, val, source_shape_id, dest_shape_id, index); - if (res == Qundef) { - switch (BUILTIN_TYPE(obj)) { - case T_OBJECT: - case T_CLASS: - case T_MODULE: - break; - default: - { - res = vm_setivar_default(obj, id, val, source_shape_id, dest_shape_id, index); - if (res != Qundef) { - return res; - } - } - } - res = vm_setivar_slowpath_attr(obj, id, val, cc); - } - return res; -} - -static VALUE -vm_call_attrset(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling) -{ - return vm_call_attrset_direct(ec, cfp, calling->cc, calling->recv); + return vm_setivar(calling->recv, vm_cc_cme(cc)->def->body.attr.id, val, NULL, NULL, cc, 1); } bool @@ -3385,7 +3219,7 @@ vm_call_alias(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_cal { calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, - {{0}}, + { 0 }, aliased_callable_method_entry(vm_cc_cme(calling->cc))); return vm_call_method_each_type(ec, cfp, calling); @@ -3555,7 +3389,7 @@ vm_call_method_missing_body(rb_execution_context_t *ec, rb_control_frame_t *reg_ ec->method_missing_reason = reason; calling->ci = &VM_CI_ON_STACK(idMethodMissing, flag, argc, vm_ci_kwarg(orig_ci)); - calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, + calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, { 0 }, rb_callable_method_entry_without_refinements(CLASS_OF(calling->recv), idMethodMissing, NULL)); return vm_call_method(ec, reg_cfp, calling); } @@ -3581,7 +3415,7 @@ vm_call_zsuper(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_ca cme = refined_method_callable_without_refinement(cme); } - calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, cme); + calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, { 0 }, cme); return vm_call_method_each_type(ec, cfp, calling); } @@ -3688,7 +3522,7 @@ search_refined_method(rb_execution_context_t *ec, rb_control_frame_t *cfp, struc static VALUE vm_call_refined(rb_execution_context_t *ec, rb_control_frame_t *cfp, struct rb_calling_info *calling) { - struct rb_callcache *ref_cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, + struct rb_callcache *ref_cc = &VM_CC_ON_STACK(Qundef, vm_call_general, { 0 }, search_refined_method(ec, cfp, calling)); if (vm_cc_cme(ref_cc)) { @@ -3868,45 +3702,18 @@ vm_call_method_each_type(rb_execution_context_t *ec, rb_control_frame_t *cfp, st CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); rb_check_arity(calling->argc, 1, 1); - + vm_cc_attr_index_initialize(cc); const unsigned int aset_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT | VM_CALL_KWARG); - - if (vm_cc_markable(cc)) { - vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID); - VM_CALL_METHOD_ATTR(v, - vm_call_attrset_direct(ec, cfp, cc, calling->recv), - CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask))); - } else { - cc = &((struct rb_callcache) { - .flags = T_IMEMO | - (imemo_callcache << FL_USHIFT) | - VM_CALLCACHE_UNMARKABLE | - ((VALUE)INVALID_SHAPE_ID << SHAPE_FLAG_SHIFT) | - VM_CALLCACHE_ON_STACK, - .klass = cc->klass, - .cme_ = cc->cme_, - .call_ = cc->call_, - .aux_ = { - .attr = { - .index = 0, - .dest_shape_id = INVALID_SHAPE_ID, - } - }, - }); - - VM_CALL_METHOD_ATTR(v, - vm_call_attrset_direct(ec, cfp, cc, calling->recv), - CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask))); - } + VM_CALL_METHOD_ATTR(v, + vm_call_attrset(ec, cfp, calling), + CC_SET_FASTPATH(cc, vm_call_attrset, !(vm_ci_flag(ci) & aset_mask))); return v; case VM_METHOD_TYPE_IVAR: CALLER_SETUP_ARG(cfp, calling, ci); CALLER_REMOVE_EMPTY_KW_SPLAT(cfp, calling, ci); rb_check_arity(calling->argc, 0, 0); - if (vm_cc_markable(cc)) { - vm_cc_attr_index_initialize(cc, INVALID_SHAPE_ID); - } + vm_cc_attr_index_initialize(cc); const unsigned int ivar_mask = (VM_CALL_ARGS_SPLAT | VM_CALL_KW_SPLAT); VM_CALL_METHOD_ATTR(v, vm_call_ivar(ec, cfp, calling), diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index 4b50d888de..c3d4a39a2b 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -40,7 +40,6 @@ fn main() { .header("internal.h") .header("internal/re.h") .header("include/ruby/ruby.h") - .header("shape.h") .header("vm_core.h") .header("vm_callinfo.h") @@ -82,12 +81,6 @@ fn main() { // This function prints info about a value and is useful for debugging .allowlist_function("rb_obj_info_dump") - // From shape.h - .allowlist_function("rb_shape_get_shape_id") - .allowlist_function("rb_shape_get_shape_by_id") - .allowlist_function("rb_shape_flags_mask") - .allowlist_function("rb_shape_get_iv_index") - // From ruby/internal/intern/object.h .allowlist_function("rb_obj_is_kind_of") diff --git a/yjit/src/asm/x86_64/mod.rs b/yjit/src/asm/x86_64/mod.rs index 42d97b7e80..d310e3bf12 100644 --- a/yjit/src/asm/x86_64/mod.rs +++ b/yjit/src/asm/x86_64/mod.rs @@ -617,7 +617,7 @@ fn write_rm_multi(cb: &mut CodeBlock, op_mem_reg8: u8, op_mem_reg_pref: u8, op_r write_rm(cb, sz_pref, rex_w, X86Opnd::None, opnd0, op_ext_imm, &[op_mem_imm_lrg]); cb.write_int(uimm.value, if opnd_size > 32 { 32 } else { opnd_size.into() }); } else { - panic!("immediate value too large (num_bits={})", num_bits); + panic!("immediate value too large"); } }, _ => unreachable!() diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index ceb834d4c7..d0de7011c7 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -1938,9 +1938,11 @@ fn gen_set_ivar( let val_opnd = ctx.stack_pop(1); let recv_opnd = ctx.stack_pop(1); - // Call rb_vm_set_ivar_id with the receiver, the ivar name, and the value + let ivar_index: u32 = unsafe { rb_obj_ensure_iv_index_mapping(recv, ivar_name) }; + + // Call rb_vm_set_ivar_idx with the receiver, the index of the ivar, and the value let val = asm.ccall( - rb_vm_set_ivar_id as *const u8, + rb_vm_set_ivar_idx as *const u8, vec![ recv_opnd, Opnd::UImm(ivar_name), @@ -2021,82 +2023,81 @@ fn gen_get_ivar( return EndBlock; } - let ivar_index = unsafe { - let shape_id = comptime_receiver.shape_of(); - let shape = rb_shape_get_shape_by_id(shape_id); - let mut ivar_index: u32 = 0; - if rb_shape_get_iv_index(shape, ivar_name, &mut ivar_index) { - Some(ivar_index as usize) - } else { - None - } - }; - - // must be before stack_pop - let recv_type = ctx.get_opnd_type(recv_opnd); - - // Upgrade type - if !recv_type.is_heap() { - ctx.upgrade_opnd_type(recv_opnd, Type::UnknownHeap); - } + // FIXME: Mapping the index could fail when there is too many ivar names. If we're + // compiling for a branch stub that can cause the exception to be thrown from the + // wrong PC. + let ivar_index = + unsafe { rb_obj_ensure_iv_index_mapping(comptime_receiver, ivar_name) }.as_usize(); // Pop receiver if it's on the temp stack if recv_opnd != SelfOpnd { ctx.stack_pop(1); } - // Guard heap object - if !recv_type.is_heap() { - guard_object_is_heap(asm, recv, side_exit); + if USE_RVARGC != 0 { + // Check that the ivar table is big enough + // Check that the slot is inside the ivar table (num_slots > index) + let num_slots = Opnd::mem(32, recv, ROBJECT_OFFSET_NUMIV); + asm.cmp(num_slots, Opnd::UImm(ivar_index as u64)); + asm.jbe(counted_exit!(ocb, side_exit, getivar_idx_out_of_range).into()); } // Compile time self is embedded and the ivar index lands within the object - let embed_test_result = unsafe { FL_TEST_RAW(comptime_receiver, VALUE(ROBJECT_EMBED.as_usize())) != VALUE(0) }; - - let flags_mask: usize = unsafe { rb_shape_flags_mask() }.as_usize(); - let expected_flags_mask: usize = (RUBY_T_MASK as usize) | !flags_mask | (ROBJECT_EMBED as usize); - let expected_flags = comptime_receiver.builtin_flags() & expected_flags_mask; - - // Combined guard for all flags: shape, embeddedness, and T_OBJECT - let flags_opnd = Opnd::mem(64, recv, RUBY_OFFSET_RBASIC_FLAGS); - - asm.comment("guard shape, embedded, and T_OBJECT"); - let flags_opnd = asm.and(flags_opnd, Opnd::UImm(expected_flags_mask as u64)); - asm.cmp(flags_opnd, Opnd::UImm(expected_flags as u64)); - jit_chain_guard( - JCC_JNE, - jit, - &starting_context, - asm, - ocb, - max_chain_depth, - side_exit, - ); - - // If there is no IVAR index, then the ivar was undefined - // when we entered the compiler. That means we can just return - // nil for this shape + iv name - if ivar_index.is_none() { - let out_opnd = ctx.stack_push(Type::Nil); - asm.mov(out_opnd, Qnil.into()); - } else if embed_test_result { + let test_result = unsafe { FL_TEST_RAW(comptime_receiver, VALUE(ROBJECT_EMBED.as_usize())) != VALUE(0) }; + if test_result { // See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h + // Guard that self is embedded + // TODO: BT and JC is shorter + asm.comment("guard embedded getivar"); + let flags_opnd = Opnd::mem(64, recv, RUBY_OFFSET_RBASIC_FLAGS); + asm.test(flags_opnd, Opnd::UImm(ROBJECT_EMBED as u64)); + let side_exit = counted_exit!(ocb, side_exit, getivar_megamorphic); + jit_chain_guard( + JCC_JZ, + jit, + &starting_context, + asm, + ocb, + max_chain_depth, + side_exit, + ); + // Load the variable - let offs = ROBJECT_OFFSET_AS_ARY + (ivar_index.unwrap() * SIZEOF_VALUE) as i32; + let offs = ROBJECT_OFFSET_AS_ARY + (ivar_index * SIZEOF_VALUE) as i32; let ivar_opnd = Opnd::mem(64, recv, offs); + // Guard that the variable is not Qundef + asm.cmp(ivar_opnd, Qundef.into()); + let out_val = asm.csel_e(Qnil.into(), ivar_opnd); + // Push the ivar on the stack let out_opnd = ctx.stack_push(Type::Unknown); - asm.mov(out_opnd, ivar_opnd); + asm.mov(out_opnd, out_val); } else { // Compile time value is *not* embedded. + // Guard that value is *not* embedded + // See ROBJECT_IVPTR() from include/ruby/internal/core/robject.h + asm.comment("guard extended getivar"); + let flags_opnd = Opnd::mem(64, recv, RUBY_OFFSET_RBASIC_FLAGS); + asm.test(flags_opnd, Opnd::UImm(ROBJECT_EMBED as u64)); + let megamorphic_side_exit = counted_exit!(ocb, side_exit, getivar_megamorphic); + jit_chain_guard( + JCC_JNZ, + jit, + &starting_context, + asm, + ocb, + max_chain_depth, + megamorphic_side_exit, + ); + if USE_RVARGC == 0 { // Check that the extended table is big enough // Check that the slot is inside the extended table (num_slots > index) let num_slots = Opnd::mem(32, recv, ROBJECT_OFFSET_NUMIV); - asm.cmp(num_slots, Opnd::UImm(ivar_index.unwrap() as u64)); + asm.cmp(num_slots, Opnd::UImm(ivar_index as u64)); asm.jbe(counted_exit!(ocb, side_exit, getivar_idx_out_of_range).into()); } @@ -2104,10 +2105,15 @@ fn gen_get_ivar( let tbl_opnd = asm.load(Opnd::mem(64, recv, ROBJECT_OFFSET_AS_HEAP_IVPTR)); // Read the ivar from the extended table - let ivar_opnd = Opnd::mem(64, tbl_opnd, (SIZEOF_VALUE * ivar_index.unwrap()) as i32); + let ivar_opnd = Opnd::mem(64, tbl_opnd, (SIZEOF_VALUE * ivar_index) as i32); + + // Check that the ivar is not Qundef + asm.cmp(ivar_opnd, Qundef.into()); + let out_val = asm.csel_ne(ivar_opnd, Qnil.into()); + // Push the ivar on the stack let out_opnd = ctx.stack_push(Type::Unknown); - asm.mov(out_opnd, ivar_opnd); + asm.mov(out_opnd, out_val); } // Jump to next instruction. This allows guard chains to share the same successor. @@ -2130,12 +2136,25 @@ fn gen_getinstancevariable( let ivar_name = jit_get_arg(jit, 0).as_u64(); let comptime_val = jit_peek_at_self(jit); + let comptime_val_klass = comptime_val.class_of(); // Generate a side exit let side_exit = get_side_exit(jit, ocb, ctx); // Guard that the receiver has the same class as the one from compile time. let self_asm_opnd = Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SELF); + jit_guard_known_klass( + jit, + ctx, + asm, + ocb, + comptime_val_klass, + self_asm_opnd, + SelfOpnd, + comptime_val, + GET_IVAR_MAX_DEPTH, + side_exit, + ); gen_get_ivar( jit, diff --git a/yjit/src/cruby.rs b/yjit/src/cruby.rs index 4307937707..c379034a4c 100644 --- a/yjit/src/cruby.rs +++ b/yjit/src/cruby.rs @@ -120,7 +120,7 @@ extern "C" { obj: VALUE, v: VALUE, ) -> bool; - pub fn rb_vm_set_ivar_id(obj: VALUE, idx: u32, val: VALUE) -> VALUE; + pub fn rb_vm_set_ivar_idx(obj: VALUE, idx: u32, val: VALUE) -> VALUE; pub fn rb_vm_setinstancevariable(iseq: IseqPtr, obj: VALUE, id: ID, val: VALUE, ic: IVC); pub fn rb_aliased_callable_method_entry( me: *const rb_callable_method_entry_t, @@ -354,26 +354,18 @@ impl VALUE { /// Read the flags bits from the RBasic object, then return a Ruby type enum (e.g. RUBY_T_ARRAY) pub fn builtin_type(self) -> ruby_value_type { - (self.builtin_flags() & (RUBY_T_MASK as usize)) as ruby_value_type - } - - pub fn builtin_flags(self) -> usize { assert!(!self.special_const_p()); let VALUE(cval) = self; let rbasic_ptr = cval as *const RBasic; let flags_bits: usize = unsafe { (*rbasic_ptr).flags }.as_usize(); - return flags_bits; + (flags_bits & (RUBY_T_MASK as usize)) as ruby_value_type } pub fn class_of(self) -> VALUE { unsafe { CLASS_OF(self) } } - pub fn shape_of(self) -> u32 { - unsafe { rb_shape_get_shape_id(self) } - } - pub fn as_isize(self) -> isize { let VALUE(is) = self; is as isize diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index 04380f5bd5..f58bf1ca05 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -269,29 +269,6 @@ extern "C" { extern "C" { pub fn rb_reg_new_ary(ary: VALUE, options: ::std::os::raw::c_int) -> VALUE; } -pub type attr_index_t = u32; -pub type shape_id_t = u32; -#[repr(C)] -pub struct rb_shape { - pub parent: *mut rb_shape, - pub edges: *mut rb_id_table, - pub edge_name: ID, - pub iv_count: attr_index_t, - pub type_: u8, -} -pub type rb_shape_t = rb_shape; -extern "C" { - pub fn rb_shape_get_shape_by_id(shape_id: shape_id_t) -> *mut rb_shape_t; -} -extern "C" { - pub fn rb_shape_get_shape_id(obj: VALUE) -> shape_id_t; -} -extern "C" { - pub fn rb_shape_get_iv_index(shape: *mut rb_shape_t, id: ID, value: *mut attr_index_t) -> bool; -} -extern "C" { - pub fn rb_shape_flags_mask() -> VALUE; -} pub const idDot2: ruby_method_ids = 128; pub const idDot3: ruby_method_ids = 129; pub const idUPlus: ruby_method_ids = 132; @@ -595,11 +572,6 @@ pub const OPTIMIZED_METHOD_TYPE_STRUCT_AREF: method_optimized_type = 3; pub const OPTIMIZED_METHOD_TYPE_STRUCT_ASET: method_optimized_type = 4; pub const OPTIMIZED_METHOD_TYPE__MAX: method_optimized_type = 5; pub type method_optimized_type = u32; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct rb_id_table { - _unused: [u8; 0], -} extern "C" { pub fn rb_method_entry_at(obj: VALUE, id: ID) -> *const rb_method_entry_t; } @@ -628,10 +600,9 @@ pub struct iseq_inline_constant_cache { pub segments: *const ID, } #[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct iseq_inline_iv_cache_entry { - pub source_shape_id: shape_id_t, - pub dest_shape_id: shape_id_t, - pub attr_index: attr_index_t, + pub entry: *mut rb_iv_index_tbl_entry, } #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -727,6 +698,12 @@ extern "C" { ) -> *const rb_callable_method_entry_t; } #[repr(C)] +pub struct rb_iv_index_tbl_entry { + pub index: u32, + pub class_serial: rb_serial_t, + pub class_value: VALUE, +} +#[repr(C)] pub struct rb_cvar_class_tbl_entry { pub index: u32, pub global_cvar_state: rb_serial_t, |