namespace on read

This commit is contained in:
Satoshi Tagomori 2025-04-30 13:48:02 +09:00
parent 49742414f6
commit 382645d440
86 changed files with 5850 additions and 702 deletions

View File

@ -32,8 +32,8 @@ builtin_lookup(const char *feature, size_t *psize)
return bin; return bin;
} }
void static void
rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table) load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
{ {
// search binary // search binary
size_t size; size_t size;
@ -50,8 +50,22 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
ASSUME(iseq); // otherwise an exception should have raised ASSUME(iseq); // otherwise an exception should have raised
vm->builtin_function_table = NULL; vm->builtin_function_table = NULL;
rb_namespace_enable_builtin();
// exec // exec
rb_iseq_eval(rb_iseq_check(iseq)); if (rb_namespace_available() && rb_mNamespaceRefiner) {
rb_iseq_eval_with_refinement(rb_iseq_check(iseq), rb_mNamespaceRefiner);
} else {
rb_iseq_eval(rb_iseq_check(iseq));
}
rb_namespace_disable_builtin();
}
void
rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
{
load_with_builtin_functions(feature_name, table);
} }
#endif #endif
@ -71,5 +85,5 @@ Init_builtin(void)
void void
Init_builtin_features(void) Init_builtin_features(void)
{ {
rb_load_with_builtin_functions("gem_prelude", NULL); load_with_builtin_functions("gem_prelude", NULL);
} }

1193
class.c

File diff suppressed because it is too large Load Diff

255
common.mk
View File

@ -140,6 +140,7 @@ COMMONOBJS = array.$(OBJEXT) \
marshal.$(OBJEXT) \ marshal.$(OBJEXT) \
math.$(OBJEXT) \ math.$(OBJEXT) \
memory_view.$(OBJEXT) \ memory_view.$(OBJEXT) \
namespace.$(OBJEXT) \
node.$(OBJEXT) \ node.$(OBJEXT) \
node_dump.$(OBJEXT) \ node_dump.$(OBJEXT) \
numeric.$(OBJEXT) \ numeric.$(OBJEXT) \
@ -2116,6 +2117,7 @@ array.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
array.$(OBJEXT): $(top_srcdir)/internal/gc.h array.$(OBJEXT): $(top_srcdir)/internal/gc.h
array.$(OBJEXT): $(top_srcdir)/internal/hash.h array.$(OBJEXT): $(top_srcdir)/internal/hash.h
array.$(OBJEXT): $(top_srcdir)/internal/imemo.h array.$(OBJEXT): $(top_srcdir)/internal/imemo.h
array.$(OBJEXT): $(top_srcdir)/internal/namespace.h
array.$(OBJEXT): $(top_srcdir)/internal/numeric.h array.$(OBJEXT): $(top_srcdir)/internal/numeric.h
array.$(OBJEXT): $(top_srcdir)/internal/object.h array.$(OBJEXT): $(top_srcdir)/internal/object.h
array.$(OBJEXT): $(top_srcdir)/internal/proc.h array.$(OBJEXT): $(top_srcdir)/internal/proc.h
@ -2333,6 +2335,7 @@ ast.$(OBJEXT): $(top_srcdir)/internal/complex.h
ast.$(OBJEXT): $(top_srcdir)/internal/fixnum.h ast.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
ast.$(OBJEXT): $(top_srcdir)/internal/gc.h ast.$(OBJEXT): $(top_srcdir)/internal/gc.h
ast.$(OBJEXT): $(top_srcdir)/internal/imemo.h ast.$(OBJEXT): $(top_srcdir)/internal/imemo.h
ast.$(OBJEXT): $(top_srcdir)/internal/namespace.h
ast.$(OBJEXT): $(top_srcdir)/internal/numeric.h ast.$(OBJEXT): $(top_srcdir)/internal/numeric.h
ast.$(OBJEXT): $(top_srcdir)/internal/parse.h ast.$(OBJEXT): $(top_srcdir)/internal/parse.h
ast.$(OBJEXT): $(top_srcdir)/internal/rational.h ast.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -2572,6 +2575,7 @@ bignum.$(OBJEXT): $(top_srcdir)/internal/complex.h
bignum.$(OBJEXT): $(top_srcdir)/internal/fixnum.h bignum.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
bignum.$(OBJEXT): $(top_srcdir)/internal/gc.h bignum.$(OBJEXT): $(top_srcdir)/internal/gc.h
bignum.$(OBJEXT): $(top_srcdir)/internal/imemo.h bignum.$(OBJEXT): $(top_srcdir)/internal/imemo.h
bignum.$(OBJEXT): $(top_srcdir)/internal/namespace.h
bignum.$(OBJEXT): $(top_srcdir)/internal/numeric.h bignum.$(OBJEXT): $(top_srcdir)/internal/numeric.h
bignum.$(OBJEXT): $(top_srcdir)/internal/object.h bignum.$(OBJEXT): $(top_srcdir)/internal/object.h
bignum.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h bignum.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -2777,6 +2781,7 @@ builtin.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
builtin.$(OBJEXT): $(top_srcdir)/internal/compilers.h builtin.$(OBJEXT): $(top_srcdir)/internal/compilers.h
builtin.$(OBJEXT): $(top_srcdir)/internal/gc.h builtin.$(OBJEXT): $(top_srcdir)/internal/gc.h
builtin.$(OBJEXT): $(top_srcdir)/internal/imemo.h builtin.$(OBJEXT): $(top_srcdir)/internal/imemo.h
builtin.$(OBJEXT): $(top_srcdir)/internal/namespace.h
builtin.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h builtin.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
builtin.$(OBJEXT): $(top_srcdir)/internal/serial.h builtin.$(OBJEXT): $(top_srcdir)/internal/serial.h
builtin.$(OBJEXT): $(top_srcdir)/internal/set_table.h builtin.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -3008,6 +3013,7 @@ class.$(OBJEXT): $(top_srcdir)/internal/eval.h
class.$(OBJEXT): $(top_srcdir)/internal/gc.h class.$(OBJEXT): $(top_srcdir)/internal/gc.h
class.$(OBJEXT): $(top_srcdir)/internal/hash.h class.$(OBJEXT): $(top_srcdir)/internal/hash.h
class.$(OBJEXT): $(top_srcdir)/internal/imemo.h class.$(OBJEXT): $(top_srcdir)/internal/imemo.h
class.$(OBJEXT): $(top_srcdir)/internal/namespace.h
class.$(OBJEXT): $(top_srcdir)/internal/object.h class.$(OBJEXT): $(top_srcdir)/internal/object.h
class.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h class.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
class.$(OBJEXT): $(top_srcdir)/internal/serial.h class.$(OBJEXT): $(top_srcdir)/internal/serial.h
@ -3408,6 +3414,7 @@ compile.$(OBJEXT): $(top_srcdir)/internal/gc.h
compile.$(OBJEXT): $(top_srcdir)/internal/hash.h compile.$(OBJEXT): $(top_srcdir)/internal/hash.h
compile.$(OBJEXT): $(top_srcdir)/internal/imemo.h compile.$(OBJEXT): $(top_srcdir)/internal/imemo.h
compile.$(OBJEXT): $(top_srcdir)/internal/io.h compile.$(OBJEXT): $(top_srcdir)/internal/io.h
compile.$(OBJEXT): $(top_srcdir)/internal/namespace.h
compile.$(OBJEXT): $(top_srcdir)/internal/numeric.h compile.$(OBJEXT): $(top_srcdir)/internal/numeric.h
compile.$(OBJEXT): $(top_srcdir)/internal/object.h compile.$(OBJEXT): $(top_srcdir)/internal/object.h
compile.$(OBJEXT): $(top_srcdir)/internal/parse.h compile.$(OBJEXT): $(top_srcdir)/internal/parse.h
@ -3669,6 +3676,7 @@ complex.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
complex.$(OBJEXT): $(top_srcdir)/internal/gc.h complex.$(OBJEXT): $(top_srcdir)/internal/gc.h
complex.$(OBJEXT): $(top_srcdir)/internal/imemo.h complex.$(OBJEXT): $(top_srcdir)/internal/imemo.h
complex.$(OBJEXT): $(top_srcdir)/internal/math.h complex.$(OBJEXT): $(top_srcdir)/internal/math.h
complex.$(OBJEXT): $(top_srcdir)/internal/namespace.h
complex.$(OBJEXT): $(top_srcdir)/internal/numeric.h complex.$(OBJEXT): $(top_srcdir)/internal/numeric.h
complex.$(OBJEXT): $(top_srcdir)/internal/object.h complex.$(OBJEXT): $(top_srcdir)/internal/object.h
complex.$(OBJEXT): $(top_srcdir)/internal/rational.h complex.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -3881,6 +3889,7 @@ cont.$(OBJEXT): $(top_srcdir)/internal/cont.h
cont.$(OBJEXT): $(top_srcdir)/internal/error.h cont.$(OBJEXT): $(top_srcdir)/internal/error.h
cont.$(OBJEXT): $(top_srcdir)/internal/gc.h cont.$(OBJEXT): $(top_srcdir)/internal/gc.h
cont.$(OBJEXT): $(top_srcdir)/internal/imemo.h cont.$(OBJEXT): $(top_srcdir)/internal/imemo.h
cont.$(OBJEXT): $(top_srcdir)/internal/namespace.h
cont.$(OBJEXT): $(top_srcdir)/internal/proc.h cont.$(OBJEXT): $(top_srcdir)/internal/proc.h
cont.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h cont.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
cont.$(OBJEXT): $(top_srcdir)/internal/serial.h cont.$(OBJEXT): $(top_srcdir)/internal/serial.h
@ -4120,6 +4129,7 @@ debug.$(OBJEXT): $(top_srcdir)/internal/class.h
debug.$(OBJEXT): $(top_srcdir)/internal/compilers.h debug.$(OBJEXT): $(top_srcdir)/internal/compilers.h
debug.$(OBJEXT): $(top_srcdir)/internal/gc.h debug.$(OBJEXT): $(top_srcdir)/internal/gc.h
debug.$(OBJEXT): $(top_srcdir)/internal/imemo.h debug.$(OBJEXT): $(top_srcdir)/internal/imemo.h
debug.$(OBJEXT): $(top_srcdir)/internal/namespace.h
debug.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h debug.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
debug.$(OBJEXT): $(top_srcdir)/internal/serial.h debug.$(OBJEXT): $(top_srcdir)/internal/serial.h
debug.$(OBJEXT): $(top_srcdir)/internal/set_table.h debug.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -4500,6 +4510,7 @@ dir.$(OBJEXT): $(top_srcdir)/internal/file.h
dir.$(OBJEXT): $(top_srcdir)/internal/gc.h dir.$(OBJEXT): $(top_srcdir)/internal/gc.h
dir.$(OBJEXT): $(top_srcdir)/internal/imemo.h dir.$(OBJEXT): $(top_srcdir)/internal/imemo.h
dir.$(OBJEXT): $(top_srcdir)/internal/io.h dir.$(OBJEXT): $(top_srcdir)/internal/io.h
dir.$(OBJEXT): $(top_srcdir)/internal/namespace.h
dir.$(OBJEXT): $(top_srcdir)/internal/object.h dir.$(OBJEXT): $(top_srcdir)/internal/object.h
dir.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h dir.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
dir.$(OBJEXT): $(top_srcdir)/internal/serial.h dir.$(OBJEXT): $(top_srcdir)/internal/serial.h
@ -4701,6 +4712,7 @@ dir.$(OBJEXT): {$(VPATH)}vm_core.h
dir.$(OBJEXT): {$(VPATH)}vm_opts.h dir.$(OBJEXT): {$(VPATH)}vm_opts.h
dln.$(OBJEXT): $(hdrdir)/ruby/ruby.h dln.$(OBJEXT): $(hdrdir)/ruby/ruby.h
dln.$(OBJEXT): $(top_srcdir)/internal/compilers.h dln.$(OBJEXT): $(top_srcdir)/internal/compilers.h
dln.$(OBJEXT): $(top_srcdir)/internal/namespace.h
dln.$(OBJEXT): $(top_srcdir)/internal/warnings.h dln.$(OBJEXT): $(top_srcdir)/internal/warnings.h
dln.$(OBJEXT): {$(VPATH)}assert.h dln.$(OBJEXT): {$(VPATH)}assert.h
dln.$(OBJEXT): {$(VPATH)}backward/2/assume.h dln.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@ -6431,6 +6443,7 @@ enumerator.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/gc.h enumerator.$(OBJEXT): $(top_srcdir)/internal/gc.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/hash.h enumerator.$(OBJEXT): $(top_srcdir)/internal/hash.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/imemo.h enumerator.$(OBJEXT): $(top_srcdir)/internal/imemo.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/namespace.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/numeric.h enumerator.$(OBJEXT): $(top_srcdir)/internal/numeric.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/range.h enumerator.$(OBJEXT): $(top_srcdir)/internal/range.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/rational.h enumerator.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -6647,6 +6660,7 @@ error.$(OBJEXT): $(top_srcdir)/internal/hash.h
error.$(OBJEXT): $(top_srcdir)/internal/imemo.h error.$(OBJEXT): $(top_srcdir)/internal/imemo.h
error.$(OBJEXT): $(top_srcdir)/internal/io.h error.$(OBJEXT): $(top_srcdir)/internal/io.h
error.$(OBJEXT): $(top_srcdir)/internal/load.h error.$(OBJEXT): $(top_srcdir)/internal/load.h
error.$(OBJEXT): $(top_srcdir)/internal/namespace.h
error.$(OBJEXT): $(top_srcdir)/internal/object.h error.$(OBJEXT): $(top_srcdir)/internal/object.h
error.$(OBJEXT): $(top_srcdir)/internal/process.h error.$(OBJEXT): $(top_srcdir)/internal/process.h
error.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h error.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -6871,6 +6885,7 @@ eval.$(OBJEXT): $(top_srcdir)/internal/hash.h
eval.$(OBJEXT): $(top_srcdir)/internal/imemo.h eval.$(OBJEXT): $(top_srcdir)/internal/imemo.h
eval.$(OBJEXT): $(top_srcdir)/internal/inits.h eval.$(OBJEXT): $(top_srcdir)/internal/inits.h
eval.$(OBJEXT): $(top_srcdir)/internal/io.h eval.$(OBJEXT): $(top_srcdir)/internal/io.h
eval.$(OBJEXT): $(top_srcdir)/internal/namespace.h
eval.$(OBJEXT): $(top_srcdir)/internal/object.h eval.$(OBJEXT): $(top_srcdir)/internal/object.h
eval.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h eval.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
eval.$(OBJEXT): $(top_srcdir)/internal/serial.h eval.$(OBJEXT): $(top_srcdir)/internal/serial.h
@ -7350,6 +7365,7 @@ gc.$(OBJEXT): $(top_srcdir)/internal/gc.h
gc.$(OBJEXT): $(top_srcdir)/internal/hash.h gc.$(OBJEXT): $(top_srcdir)/internal/hash.h
gc.$(OBJEXT): $(top_srcdir)/internal/imemo.h gc.$(OBJEXT): $(top_srcdir)/internal/imemo.h
gc.$(OBJEXT): $(top_srcdir)/internal/io.h gc.$(OBJEXT): $(top_srcdir)/internal/io.h
gc.$(OBJEXT): $(top_srcdir)/internal/namespace.h
gc.$(OBJEXT): $(top_srcdir)/internal/numeric.h gc.$(OBJEXT): $(top_srcdir)/internal/numeric.h
gc.$(OBJEXT): $(top_srcdir)/internal/object.h gc.$(OBJEXT): $(top_srcdir)/internal/object.h
gc.$(OBJEXT): $(top_srcdir)/internal/proc.h gc.$(OBJEXT): $(top_srcdir)/internal/proc.h
@ -7614,6 +7630,7 @@ goruby.$(OBJEXT): $(top_srcdir)/internal/complex.h
goruby.$(OBJEXT): $(top_srcdir)/internal/fixnum.h goruby.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
goruby.$(OBJEXT): $(top_srcdir)/internal/gc.h goruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
goruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h goruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h
goruby.$(OBJEXT): $(top_srcdir)/internal/namespace.h
goruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h goruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
goruby.$(OBJEXT): $(top_srcdir)/internal/parse.h goruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
goruby.$(OBJEXT): $(top_srcdir)/internal/rational.h goruby.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -7855,6 +7872,7 @@ hash.$(OBJEXT): $(top_srcdir)/internal/error.h
hash.$(OBJEXT): $(top_srcdir)/internal/gc.h hash.$(OBJEXT): $(top_srcdir)/internal/gc.h
hash.$(OBJEXT): $(top_srcdir)/internal/hash.h hash.$(OBJEXT): $(top_srcdir)/internal/hash.h
hash.$(OBJEXT): $(top_srcdir)/internal/imemo.h hash.$(OBJEXT): $(top_srcdir)/internal/imemo.h
hash.$(OBJEXT): $(top_srcdir)/internal/namespace.h
hash.$(OBJEXT): $(top_srcdir)/internal/object.h hash.$(OBJEXT): $(top_srcdir)/internal/object.h
hash.$(OBJEXT): $(top_srcdir)/internal/proc.h hash.$(OBJEXT): $(top_srcdir)/internal/proc.h
hash.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h hash.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -8478,6 +8496,7 @@ io.$(OBJEXT): $(top_srcdir)/internal/gc.h
io.$(OBJEXT): $(top_srcdir)/internal/imemo.h io.$(OBJEXT): $(top_srcdir)/internal/imemo.h
io.$(OBJEXT): $(top_srcdir)/internal/inits.h io.$(OBJEXT): $(top_srcdir)/internal/inits.h
io.$(OBJEXT): $(top_srcdir)/internal/io.h io.$(OBJEXT): $(top_srcdir)/internal/io.h
io.$(OBJEXT): $(top_srcdir)/internal/namespace.h
io.$(OBJEXT): $(top_srcdir)/internal/numeric.h io.$(OBJEXT): $(top_srcdir)/internal/numeric.h
io.$(OBJEXT): $(top_srcdir)/internal/object.h io.$(OBJEXT): $(top_srcdir)/internal/object.h
io.$(OBJEXT): $(top_srcdir)/internal/process.h io.$(OBJEXT): $(top_srcdir)/internal/process.h
@ -8920,6 +8939,7 @@ iseq.$(OBJEXT): $(top_srcdir)/internal/gc.h
iseq.$(OBJEXT): $(top_srcdir)/internal/hash.h iseq.$(OBJEXT): $(top_srcdir)/internal/hash.h
iseq.$(OBJEXT): $(top_srcdir)/internal/imemo.h iseq.$(OBJEXT): $(top_srcdir)/internal/imemo.h
iseq.$(OBJEXT): $(top_srcdir)/internal/io.h iseq.$(OBJEXT): $(top_srcdir)/internal/io.h
iseq.$(OBJEXT): $(top_srcdir)/internal/namespace.h
iseq.$(OBJEXT): $(top_srcdir)/internal/numeric.h iseq.$(OBJEXT): $(top_srcdir)/internal/numeric.h
iseq.$(OBJEXT): $(top_srcdir)/internal/parse.h iseq.$(OBJEXT): $(top_srcdir)/internal/parse.h
iseq.$(OBJEXT): $(top_srcdir)/internal/rational.h iseq.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -9406,12 +9426,14 @@ load.$(OBJEXT): $(top_srcdir)/internal/compilers.h
load.$(OBJEXT): $(top_srcdir)/internal/complex.h load.$(OBJEXT): $(top_srcdir)/internal/complex.h
load.$(OBJEXT): $(top_srcdir)/internal/dir.h load.$(OBJEXT): $(top_srcdir)/internal/dir.h
load.$(OBJEXT): $(top_srcdir)/internal/error.h load.$(OBJEXT): $(top_srcdir)/internal/error.h
load.$(OBJEXT): $(top_srcdir)/internal/eval.h
load.$(OBJEXT): $(top_srcdir)/internal/file.h load.$(OBJEXT): $(top_srcdir)/internal/file.h
load.$(OBJEXT): $(top_srcdir)/internal/fixnum.h load.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
load.$(OBJEXT): $(top_srcdir)/internal/gc.h load.$(OBJEXT): $(top_srcdir)/internal/gc.h
load.$(OBJEXT): $(top_srcdir)/internal/hash.h load.$(OBJEXT): $(top_srcdir)/internal/hash.h
load.$(OBJEXT): $(top_srcdir)/internal/imemo.h load.$(OBJEXT): $(top_srcdir)/internal/imemo.h
load.$(OBJEXT): $(top_srcdir)/internal/load.h load.$(OBJEXT): $(top_srcdir)/internal/load.h
load.$(OBJEXT): $(top_srcdir)/internal/namespace.h
load.$(OBJEXT): $(top_srcdir)/internal/numeric.h load.$(OBJEXT): $(top_srcdir)/internal/numeric.h
load.$(OBJEXT): $(top_srcdir)/internal/parse.h load.$(OBJEXT): $(top_srcdir)/internal/parse.h
load.$(OBJEXT): $(top_srcdir)/internal/rational.h load.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -10156,6 +10178,7 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
marshal.$(OBJEXT): $(top_srcdir)/internal/gc.h marshal.$(OBJEXT): $(top_srcdir)/internal/gc.h
marshal.$(OBJEXT): $(top_srcdir)/internal/hash.h marshal.$(OBJEXT): $(top_srcdir)/internal/hash.h
marshal.$(OBJEXT): $(top_srcdir)/internal/imemo.h marshal.$(OBJEXT): $(top_srcdir)/internal/imemo.h
marshal.$(OBJEXT): $(top_srcdir)/internal/namespace.h
marshal.$(OBJEXT): $(top_srcdir)/internal/numeric.h marshal.$(OBJEXT): $(top_srcdir)/internal/numeric.h
marshal.$(OBJEXT): $(top_srcdir)/internal/object.h marshal.$(OBJEXT): $(top_srcdir)/internal/object.h
marshal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h marshal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -10547,6 +10570,7 @@ memory_view.$(OBJEXT): $(top_srcdir)/internal/compilers.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/gc.h memory_view.$(OBJEXT): $(top_srcdir)/internal/gc.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/hash.h memory_view.$(OBJEXT): $(top_srcdir)/internal/hash.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/imemo.h memory_view.$(OBJEXT): $(top_srcdir)/internal/imemo.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/namespace.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h memory_view.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/serial.h memory_view.$(OBJEXT): $(top_srcdir)/internal/serial.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/set_table.h memory_view.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -10757,6 +10781,7 @@ miniinit.$(OBJEXT): $(top_srcdir)/internal/complex.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h miniinit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/gc.h miniinit.$(OBJEXT): $(top_srcdir)/internal/gc.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/imemo.h miniinit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/namespace.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/numeric.h miniinit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/parse.h miniinit.$(OBJEXT): $(top_srcdir)/internal/parse.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/rational.h miniinit.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -11002,6 +11027,206 @@ miniinit.$(OBJEXT): {$(VPATH)}warning.rb
miniinit.$(OBJEXT): {$(VPATH)}yjit.rb miniinit.$(OBJEXT): {$(VPATH)}yjit.rb
miniinit.$(OBJEXT): {$(VPATH)}yjit_hook.rb miniinit.$(OBJEXT): {$(VPATH)}yjit_hook.rb
miniinit.$(OBJEXT): {$(VPATH)}zjit.rb miniinit.$(OBJEXT): {$(VPATH)}zjit.rb
namespace.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
namespace.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
namespace.$(OBJEXT): $(CCAN_DIR)/list/list.h
namespace.$(OBJEXT): $(CCAN_DIR)/str/str.h
namespace.$(OBJEXT): $(hdrdir)/ruby/ruby.h
namespace.$(OBJEXT): $(top_srcdir)/internal/array.h
namespace.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
namespace.$(OBJEXT): $(top_srcdir)/internal/compilers.h
namespace.$(OBJEXT): $(top_srcdir)/internal/file.h
namespace.$(OBJEXT): $(top_srcdir)/internal/gc.h
namespace.$(OBJEXT): $(top_srcdir)/internal/hash.h
namespace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
namespace.$(OBJEXT): $(top_srcdir)/internal/load.h
namespace.$(OBJEXT): $(top_srcdir)/internal/namespace.h
namespace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
namespace.$(OBJEXT): $(top_srcdir)/internal/serial.h
namespace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
namespace.$(OBJEXT): $(top_srcdir)/internal/vm.h
namespace.$(OBJEXT): $(top_srcdir)/internal/warnings.h
namespace.$(OBJEXT): {$(VPATH)}assert.h
namespace.$(OBJEXT): {$(VPATH)}atomic.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/assume.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/bool.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/limits.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
namespace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
namespace.$(OBJEXT): {$(VPATH)}config.h
namespace.$(OBJEXT): {$(VPATH)}defines.h
namespace.$(OBJEXT): {$(VPATH)}encoding.h
namespace.$(OBJEXT): {$(VPATH)}id.h
namespace.$(OBJEXT): {$(VPATH)}intern.h
namespace.$(OBJEXT): {$(VPATH)}internal.h
namespace.$(OBJEXT): {$(VPATH)}internal/abi.h
namespace.$(OBJEXT): {$(VPATH)}internal/anyargs.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
namespace.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
namespace.$(OBJEXT): {$(VPATH)}internal/assume.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/const.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/error.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/format.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
namespace.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
namespace.$(OBJEXT): {$(VPATH)}internal/cast.h
namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
namespace.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
namespace.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
namespace.$(OBJEXT): {$(VPATH)}internal/config.h
namespace.$(OBJEXT): {$(VPATH)}internal/constant_p.h
namespace.$(OBJEXT): {$(VPATH)}internal/core.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/robject.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
namespace.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
namespace.$(OBJEXT): {$(VPATH)}internal/ctype.h
namespace.$(OBJEXT): {$(VPATH)}internal/dllexport.h
namespace.$(OBJEXT): {$(VPATH)}internal/dosish.h
namespace.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
namespace.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
namespace.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
namespace.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
namespace.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
namespace.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
namespace.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
namespace.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
namespace.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
namespace.$(OBJEXT): {$(VPATH)}internal/error.h
namespace.$(OBJEXT): {$(VPATH)}internal/eval.h
namespace.$(OBJEXT): {$(VPATH)}internal/event.h
namespace.$(OBJEXT): {$(VPATH)}internal/fl_type.h
namespace.$(OBJEXT): {$(VPATH)}internal/gc.h
namespace.$(OBJEXT): {$(VPATH)}internal/glob.h
namespace.$(OBJEXT): {$(VPATH)}internal/globals.h
namespace.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
namespace.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
namespace.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
namespace.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
namespace.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
namespace.$(OBJEXT): {$(VPATH)}internal/has/extension.h
namespace.$(OBJEXT): {$(VPATH)}internal/has/feature.h
namespace.$(OBJEXT): {$(VPATH)}internal/has/warning.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/array.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/class.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/error.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/file.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/object.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/process.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/random.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/range.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/re.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/select.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/string.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/time.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
namespace.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
namespace.$(OBJEXT): {$(VPATH)}internal/interpreter.h
namespace.$(OBJEXT): {$(VPATH)}internal/iterator.h
namespace.$(OBJEXT): {$(VPATH)}internal/memory.h
namespace.$(OBJEXT): {$(VPATH)}internal/method.h
namespace.$(OBJEXT): {$(VPATH)}internal/module.h
namespace.$(OBJEXT): {$(VPATH)}internal/newobj.h
namespace.$(OBJEXT): {$(VPATH)}internal/scan_args.h
namespace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
namespace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
namespace.$(OBJEXT): {$(VPATH)}internal/stdalign.h
namespace.$(OBJEXT): {$(VPATH)}internal/stdbool.h
namespace.$(OBJEXT): {$(VPATH)}internal/symbol.h
namespace.$(OBJEXT): {$(VPATH)}internal/value.h
namespace.$(OBJEXT): {$(VPATH)}internal/value_type.h
namespace.$(OBJEXT): {$(VPATH)}internal/variable.h
namespace.$(OBJEXT): {$(VPATH)}internal/warning_push.h
namespace.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
namespace.$(OBJEXT): {$(VPATH)}method.h
namespace.$(OBJEXT): {$(VPATH)}missing.h
namespace.$(OBJEXT): {$(VPATH)}namespace.c
namespace.$(OBJEXT): {$(VPATH)}node.h
namespace.$(OBJEXT): {$(VPATH)}onigmo.h
namespace.$(OBJEXT): {$(VPATH)}oniguruma.h
namespace.$(OBJEXT): {$(VPATH)}ruby_assert.h
namespace.$(OBJEXT): {$(VPATH)}ruby_atomic.h
namespace.$(OBJEXT): {$(VPATH)}rubyparser.h
namespace.$(OBJEXT): {$(VPATH)}st.h
namespace.$(OBJEXT): {$(VPATH)}subst.h
namespace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
namespace.$(OBJEXT): {$(VPATH)}thread_native.h
namespace.$(OBJEXT): {$(VPATH)}util.h
namespace.$(OBJEXT): {$(VPATH)}vm_core.h
namespace.$(OBJEXT): {$(VPATH)}vm_opts.h
node.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h node.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
node.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h node.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
node.$(OBJEXT): $(CCAN_DIR)/list/list.h node.$(OBJEXT): $(CCAN_DIR)/list/list.h
@ -11013,6 +11238,7 @@ node.$(OBJEXT): $(top_srcdir)/internal/compilers.h
node.$(OBJEXT): $(top_srcdir)/internal/gc.h node.$(OBJEXT): $(top_srcdir)/internal/gc.h
node.$(OBJEXT): $(top_srcdir)/internal/hash.h node.$(OBJEXT): $(top_srcdir)/internal/hash.h
node.$(OBJEXT): $(top_srcdir)/internal/imemo.h node.$(OBJEXT): $(top_srcdir)/internal/imemo.h
node.$(OBJEXT): $(top_srcdir)/internal/namespace.h
node.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h node.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
node.$(OBJEXT): $(top_srcdir)/internal/serial.h node.$(OBJEXT): $(top_srcdir)/internal/serial.h
node.$(OBJEXT): $(top_srcdir)/internal/set_table.h node.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -11221,6 +11447,7 @@ node_dump.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h node_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/hash.h node_dump.$(OBJEXT): $(top_srcdir)/internal/hash.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h node_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/namespace.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/numeric.h node_dump.$(OBJEXT): $(top_srcdir)/internal/numeric.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/parse.h node_dump.$(OBJEXT): $(top_srcdir)/internal/parse.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/rational.h node_dump.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -11436,6 +11663,7 @@ numeric.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
numeric.$(OBJEXT): $(top_srcdir)/internal/gc.h numeric.$(OBJEXT): $(top_srcdir)/internal/gc.h
numeric.$(OBJEXT): $(top_srcdir)/internal/hash.h numeric.$(OBJEXT): $(top_srcdir)/internal/hash.h
numeric.$(OBJEXT): $(top_srcdir)/internal/imemo.h numeric.$(OBJEXT): $(top_srcdir)/internal/imemo.h
numeric.$(OBJEXT): $(top_srcdir)/internal/namespace.h
numeric.$(OBJEXT): $(top_srcdir)/internal/numeric.h numeric.$(OBJEXT): $(top_srcdir)/internal/numeric.h
numeric.$(OBJEXT): $(top_srcdir)/internal/object.h numeric.$(OBJEXT): $(top_srcdir)/internal/object.h
numeric.$(OBJEXT): $(top_srcdir)/internal/rational.h numeric.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -11653,6 +11881,7 @@ object.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
object.$(OBJEXT): $(top_srcdir)/internal/gc.h object.$(OBJEXT): $(top_srcdir)/internal/gc.h
object.$(OBJEXT): $(top_srcdir)/internal/imemo.h object.$(OBJEXT): $(top_srcdir)/internal/imemo.h
object.$(OBJEXT): $(top_srcdir)/internal/inits.h object.$(OBJEXT): $(top_srcdir)/internal/inits.h
object.$(OBJEXT): $(top_srcdir)/internal/namespace.h
object.$(OBJEXT): $(top_srcdir)/internal/numeric.h object.$(OBJEXT): $(top_srcdir)/internal/numeric.h
object.$(OBJEXT): $(top_srcdir)/internal/object.h object.$(OBJEXT): $(top_srcdir)/internal/object.h
object.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h object.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -11873,6 +12102,7 @@ pack.$(OBJEXT): $(top_srcdir)/internal/bits.h
pack.$(OBJEXT): $(top_srcdir)/internal/compilers.h pack.$(OBJEXT): $(top_srcdir)/internal/compilers.h
pack.$(OBJEXT): $(top_srcdir)/internal/gc.h pack.$(OBJEXT): $(top_srcdir)/internal/gc.h
pack.$(OBJEXT): $(top_srcdir)/internal/imemo.h pack.$(OBJEXT): $(top_srcdir)/internal/imemo.h
pack.$(OBJEXT): $(top_srcdir)/internal/namespace.h
pack.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h pack.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
pack.$(OBJEXT): $(top_srcdir)/internal/serial.h pack.$(OBJEXT): $(top_srcdir)/internal/serial.h
pack.$(OBJEXT): $(top_srcdir)/internal/set_table.h pack.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -12090,6 +12320,7 @@ parse.$(OBJEXT): $(top_srcdir)/internal/gc.h
parse.$(OBJEXT): $(top_srcdir)/internal/hash.h parse.$(OBJEXT): $(top_srcdir)/internal/hash.h
parse.$(OBJEXT): $(top_srcdir)/internal/imemo.h parse.$(OBJEXT): $(top_srcdir)/internal/imemo.h
parse.$(OBJEXT): $(top_srcdir)/internal/io.h parse.$(OBJEXT): $(top_srcdir)/internal/io.h
parse.$(OBJEXT): $(top_srcdir)/internal/namespace.h
parse.$(OBJEXT): $(top_srcdir)/internal/numeric.h parse.$(OBJEXT): $(top_srcdir)/internal/numeric.h
parse.$(OBJEXT): $(top_srcdir)/internal/parse.h parse.$(OBJEXT): $(top_srcdir)/internal/parse.h
parse.$(OBJEXT): $(top_srcdir)/internal/rational.h parse.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -13368,6 +13599,7 @@ proc.$(OBJEXT): $(top_srcdir)/internal/eval.h
proc.$(OBJEXT): $(top_srcdir)/internal/gc.h proc.$(OBJEXT): $(top_srcdir)/internal/gc.h
proc.$(OBJEXT): $(top_srcdir)/internal/hash.h proc.$(OBJEXT): $(top_srcdir)/internal/hash.h
proc.$(OBJEXT): $(top_srcdir)/internal/imemo.h proc.$(OBJEXT): $(top_srcdir)/internal/imemo.h
proc.$(OBJEXT): $(top_srcdir)/internal/namespace.h
proc.$(OBJEXT): $(top_srcdir)/internal/object.h proc.$(OBJEXT): $(top_srcdir)/internal/object.h
proc.$(OBJEXT): $(top_srcdir)/internal/proc.h proc.$(OBJEXT): $(top_srcdir)/internal/proc.h
proc.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h proc.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -13614,6 +13846,7 @@ process.$(OBJEXT): $(top_srcdir)/internal/gc.h
process.$(OBJEXT): $(top_srcdir)/internal/hash.h process.$(OBJEXT): $(top_srcdir)/internal/hash.h
process.$(OBJEXT): $(top_srcdir)/internal/imemo.h process.$(OBJEXT): $(top_srcdir)/internal/imemo.h
process.$(OBJEXT): $(top_srcdir)/internal/io.h process.$(OBJEXT): $(top_srcdir)/internal/io.h
process.$(OBJEXT): $(top_srcdir)/internal/namespace.h
process.$(OBJEXT): $(top_srcdir)/internal/numeric.h process.$(OBJEXT): $(top_srcdir)/internal/numeric.h
process.$(OBJEXT): $(top_srcdir)/internal/object.h process.$(OBJEXT): $(top_srcdir)/internal/object.h
process.$(OBJEXT): $(top_srcdir)/internal/process.h process.$(OBJEXT): $(top_srcdir)/internal/process.h
@ -13839,6 +14072,7 @@ ractor.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
ractor.$(OBJEXT): $(top_srcdir)/internal/gc.h ractor.$(OBJEXT): $(top_srcdir)/internal/gc.h
ractor.$(OBJEXT): $(top_srcdir)/internal/hash.h ractor.$(OBJEXT): $(top_srcdir)/internal/hash.h
ractor.$(OBJEXT): $(top_srcdir)/internal/imemo.h ractor.$(OBJEXT): $(top_srcdir)/internal/imemo.h
ractor.$(OBJEXT): $(top_srcdir)/internal/namespace.h
ractor.$(OBJEXT): $(top_srcdir)/internal/numeric.h ractor.$(OBJEXT): $(top_srcdir)/internal/numeric.h
ractor.$(OBJEXT): $(top_srcdir)/internal/object.h ractor.$(OBJEXT): $(top_srcdir)/internal/object.h
ractor.$(OBJEXT): $(top_srcdir)/internal/ractor.h ractor.$(OBJEXT): $(top_srcdir)/internal/ractor.h
@ -14061,6 +14295,7 @@ random.$(OBJEXT): $(top_srcdir)/internal/compilers.h
random.$(OBJEXT): $(top_srcdir)/internal/fixnum.h random.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
random.$(OBJEXT): $(top_srcdir)/internal/gc.h random.$(OBJEXT): $(top_srcdir)/internal/gc.h
random.$(OBJEXT): $(top_srcdir)/internal/imemo.h random.$(OBJEXT): $(top_srcdir)/internal/imemo.h
random.$(OBJEXT): $(top_srcdir)/internal/namespace.h
random.$(OBJEXT): $(top_srcdir)/internal/numeric.h random.$(OBJEXT): $(top_srcdir)/internal/numeric.h
random.$(OBJEXT): $(top_srcdir)/internal/random.h random.$(OBJEXT): $(top_srcdir)/internal/random.h
random.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h random.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -14467,6 +14702,7 @@ rational.$(OBJEXT): $(top_srcdir)/internal/complex.h
rational.$(OBJEXT): $(top_srcdir)/internal/fixnum.h rational.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
rational.$(OBJEXT): $(top_srcdir)/internal/gc.h rational.$(OBJEXT): $(top_srcdir)/internal/gc.h
rational.$(OBJEXT): $(top_srcdir)/internal/imemo.h rational.$(OBJEXT): $(top_srcdir)/internal/imemo.h
rational.$(OBJEXT): $(top_srcdir)/internal/namespace.h
rational.$(OBJEXT): $(top_srcdir)/internal/numeric.h rational.$(OBJEXT): $(top_srcdir)/internal/numeric.h
rational.$(OBJEXT): $(top_srcdir)/internal/object.h rational.$(OBJEXT): $(top_srcdir)/internal/object.h
rational.$(OBJEXT): $(top_srcdir)/internal/rational.h rational.$(OBJEXT): $(top_srcdir)/internal/rational.h
@ -14676,6 +14912,7 @@ re.$(OBJEXT): $(top_srcdir)/internal/encoding.h
re.$(OBJEXT): $(top_srcdir)/internal/gc.h re.$(OBJEXT): $(top_srcdir)/internal/gc.h
re.$(OBJEXT): $(top_srcdir)/internal/hash.h re.$(OBJEXT): $(top_srcdir)/internal/hash.h
re.$(OBJEXT): $(top_srcdir)/internal/imemo.h re.$(OBJEXT): $(top_srcdir)/internal/imemo.h
re.$(OBJEXT): $(top_srcdir)/internal/namespace.h
re.$(OBJEXT): $(top_srcdir)/internal/object.h re.$(OBJEXT): $(top_srcdir)/internal/object.h
re.$(OBJEXT): $(top_srcdir)/internal/ractor.h re.$(OBJEXT): $(top_srcdir)/internal/ractor.h
re.$(OBJEXT): $(top_srcdir)/internal/re.h re.$(OBJEXT): $(top_srcdir)/internal/re.h
@ -15890,6 +16127,7 @@ ruby.$(OBJEXT): $(top_srcdir)/internal/io.h
ruby.$(OBJEXT): $(top_srcdir)/internal/load.h ruby.$(OBJEXT): $(top_srcdir)/internal/load.h
ruby.$(OBJEXT): $(top_srcdir)/internal/loadpath.h ruby.$(OBJEXT): $(top_srcdir)/internal/loadpath.h
ruby.$(OBJEXT): $(top_srcdir)/internal/missing.h ruby.$(OBJEXT): $(top_srcdir)/internal/missing.h
ruby.$(OBJEXT): $(top_srcdir)/internal/namespace.h
ruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h ruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
ruby.$(OBJEXT): $(top_srcdir)/internal/object.h ruby.$(OBJEXT): $(top_srcdir)/internal/object.h
ruby.$(OBJEXT): $(top_srcdir)/internal/parse.h ruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
@ -16321,6 +16559,7 @@ scheduler.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/compilers.h scheduler.$(OBJEXT): $(top_srcdir)/internal/compilers.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/gc.h scheduler.$(OBJEXT): $(top_srcdir)/internal/gc.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/imemo.h scheduler.$(OBJEXT): $(top_srcdir)/internal/imemo.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/namespace.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h scheduler.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/set_table.h scheduler.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -16895,6 +17134,7 @@ shape.$(OBJEXT): $(top_srcdir)/internal/compilers.h
shape.$(OBJEXT): $(top_srcdir)/internal/error.h shape.$(OBJEXT): $(top_srcdir)/internal/error.h
shape.$(OBJEXT): $(top_srcdir)/internal/gc.h shape.$(OBJEXT): $(top_srcdir)/internal/gc.h
shape.$(OBJEXT): $(top_srcdir)/internal/imemo.h shape.$(OBJEXT): $(top_srcdir)/internal/imemo.h
shape.$(OBJEXT): $(top_srcdir)/internal/namespace.h
shape.$(OBJEXT): $(top_srcdir)/internal/object.h shape.$(OBJEXT): $(top_srcdir)/internal/object.h
shape.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h shape.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
shape.$(OBJEXT): $(top_srcdir)/internal/serial.h shape.$(OBJEXT): $(top_srcdir)/internal/serial.h
@ -17107,6 +17347,7 @@ signal.$(OBJEXT): $(top_srcdir)/internal/error.h
signal.$(OBJEXT): $(top_srcdir)/internal/eval.h signal.$(OBJEXT): $(top_srcdir)/internal/eval.h
signal.$(OBJEXT): $(top_srcdir)/internal/gc.h signal.$(OBJEXT): $(top_srcdir)/internal/gc.h
signal.$(OBJEXT): $(top_srcdir)/internal/imemo.h signal.$(OBJEXT): $(top_srcdir)/internal/imemo.h
signal.$(OBJEXT): $(top_srcdir)/internal/namespace.h
signal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h signal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
signal.$(OBJEXT): $(top_srcdir)/internal/serial.h signal.$(OBJEXT): $(top_srcdir)/internal/serial.h
signal.$(OBJEXT): $(top_srcdir)/internal/set_table.h signal.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -17873,6 +18114,7 @@ string.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
string.$(OBJEXT): $(top_srcdir)/internal/gc.h string.$(OBJEXT): $(top_srcdir)/internal/gc.h
string.$(OBJEXT): $(top_srcdir)/internal/hash.h string.$(OBJEXT): $(top_srcdir)/internal/hash.h
string.$(OBJEXT): $(top_srcdir)/internal/imemo.h string.$(OBJEXT): $(top_srcdir)/internal/imemo.h
string.$(OBJEXT): $(top_srcdir)/internal/namespace.h
string.$(OBJEXT): $(top_srcdir)/internal/numeric.h string.$(OBJEXT): $(top_srcdir)/internal/numeric.h
string.$(OBJEXT): $(top_srcdir)/internal/object.h string.$(OBJEXT): $(top_srcdir)/internal/object.h
string.$(OBJEXT): $(top_srcdir)/internal/proc.h string.$(OBJEXT): $(top_srcdir)/internal/proc.h
@ -18126,6 +18368,7 @@ struct.$(OBJEXT): $(top_srcdir)/internal/error.h
struct.$(OBJEXT): $(top_srcdir)/internal/gc.h struct.$(OBJEXT): $(top_srcdir)/internal/gc.h
struct.$(OBJEXT): $(top_srcdir)/internal/hash.h struct.$(OBJEXT): $(top_srcdir)/internal/hash.h
struct.$(OBJEXT): $(top_srcdir)/internal/imemo.h struct.$(OBJEXT): $(top_srcdir)/internal/imemo.h
struct.$(OBJEXT): $(top_srcdir)/internal/namespace.h
struct.$(OBJEXT): $(top_srcdir)/internal/object.h struct.$(OBJEXT): $(top_srcdir)/internal/object.h
struct.$(OBJEXT): $(top_srcdir)/internal/proc.h struct.$(OBJEXT): $(top_srcdir)/internal/proc.h
struct.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h struct.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -18340,6 +18583,7 @@ symbol.$(OBJEXT): $(top_srcdir)/internal/error.h
symbol.$(OBJEXT): $(top_srcdir)/internal/gc.h symbol.$(OBJEXT): $(top_srcdir)/internal/gc.h
symbol.$(OBJEXT): $(top_srcdir)/internal/hash.h symbol.$(OBJEXT): $(top_srcdir)/internal/hash.h
symbol.$(OBJEXT): $(top_srcdir)/internal/imemo.h symbol.$(OBJEXT): $(top_srcdir)/internal/imemo.h
symbol.$(OBJEXT): $(top_srcdir)/internal/namespace.h
symbol.$(OBJEXT): $(top_srcdir)/internal/object.h symbol.$(OBJEXT): $(top_srcdir)/internal/object.h
symbol.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h symbol.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
symbol.$(OBJEXT): $(top_srcdir)/internal/serial.h symbol.$(OBJEXT): $(top_srcdir)/internal/serial.h
@ -18564,6 +18808,7 @@ thread.$(OBJEXT): $(top_srcdir)/internal/gc.h
thread.$(OBJEXT): $(top_srcdir)/internal/hash.h thread.$(OBJEXT): $(top_srcdir)/internal/hash.h
thread.$(OBJEXT): $(top_srcdir)/internal/imemo.h thread.$(OBJEXT): $(top_srcdir)/internal/imemo.h
thread.$(OBJEXT): $(top_srcdir)/internal/io.h thread.$(OBJEXT): $(top_srcdir)/internal/io.h
thread.$(OBJEXT): $(top_srcdir)/internal/namespace.h
thread.$(OBJEXT): $(top_srcdir)/internal/object.h thread.$(OBJEXT): $(top_srcdir)/internal/object.h
thread.$(OBJEXT): $(top_srcdir)/internal/proc.h thread.$(OBJEXT): $(top_srcdir)/internal/proc.h
thread.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h thread.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -18819,6 +19064,7 @@ time.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
time.$(OBJEXT): $(top_srcdir)/internal/gc.h time.$(OBJEXT): $(top_srcdir)/internal/gc.h
time.$(OBJEXT): $(top_srcdir)/internal/hash.h time.$(OBJEXT): $(top_srcdir)/internal/hash.h
time.$(OBJEXT): $(top_srcdir)/internal/imemo.h time.$(OBJEXT): $(top_srcdir)/internal/imemo.h
time.$(OBJEXT): $(top_srcdir)/internal/namespace.h
time.$(OBJEXT): $(top_srcdir)/internal/numeric.h time.$(OBJEXT): $(top_srcdir)/internal/numeric.h
time.$(OBJEXT): $(top_srcdir)/internal/rational.h time.$(OBJEXT): $(top_srcdir)/internal/rational.h
time.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h time.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -19391,6 +19637,7 @@ variable.$(OBJEXT): $(top_srcdir)/internal/eval.h
variable.$(OBJEXT): $(top_srcdir)/internal/gc.h variable.$(OBJEXT): $(top_srcdir)/internal/gc.h
variable.$(OBJEXT): $(top_srcdir)/internal/hash.h variable.$(OBJEXT): $(top_srcdir)/internal/hash.h
variable.$(OBJEXT): $(top_srcdir)/internal/imemo.h variable.$(OBJEXT): $(top_srcdir)/internal/imemo.h
variable.$(OBJEXT): $(top_srcdir)/internal/namespace.h
variable.$(OBJEXT): $(top_srcdir)/internal/object.h variable.$(OBJEXT): $(top_srcdir)/internal/object.h
variable.$(OBJEXT): $(top_srcdir)/internal/re.h variable.$(OBJEXT): $(top_srcdir)/internal/re.h
variable.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h variable.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@ -19608,6 +19855,7 @@ version.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
version.$(OBJEXT): $(top_srcdir)/internal/compilers.h version.$(OBJEXT): $(top_srcdir)/internal/compilers.h
version.$(OBJEXT): $(top_srcdir)/internal/gc.h version.$(OBJEXT): $(top_srcdir)/internal/gc.h
version.$(OBJEXT): $(top_srcdir)/internal/imemo.h version.$(OBJEXT): $(top_srcdir)/internal/imemo.h
version.$(OBJEXT): $(top_srcdir)/internal/namespace.h
version.$(OBJEXT): $(top_srcdir)/internal/parse.h version.$(OBJEXT): $(top_srcdir)/internal/parse.h
version.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h version.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
version.$(OBJEXT): $(top_srcdir)/internal/serial.h version.$(OBJEXT): $(top_srcdir)/internal/serial.h
@ -19830,6 +20078,7 @@ vm.$(OBJEXT): $(top_srcdir)/internal/hash.h
vm.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm.$(OBJEXT): $(top_srcdir)/internal/imemo.h
vm.$(OBJEXT): $(top_srcdir)/internal/inits.h vm.$(OBJEXT): $(top_srcdir)/internal/inits.h
vm.$(OBJEXT): $(top_srcdir)/internal/missing.h vm.$(OBJEXT): $(top_srcdir)/internal/missing.h
vm.$(OBJEXT): $(top_srcdir)/internal/namespace.h
vm.$(OBJEXT): $(top_srcdir)/internal/numeric.h vm.$(OBJEXT): $(top_srcdir)/internal/numeric.h
vm.$(OBJEXT): $(top_srcdir)/internal/object.h vm.$(OBJEXT): $(top_srcdir)/internal/object.h
vm.$(OBJEXT): $(top_srcdir)/internal/parse.h vm.$(OBJEXT): $(top_srcdir)/internal/parse.h
@ -20103,6 +20352,7 @@ vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/error.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/error.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/gc.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/namespace.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/set_table.h vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -20335,6 +20585,7 @@ vm_dump.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/namespace.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/set_table.h vm_dump.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -20567,6 +20818,7 @@ vm_sync.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/compilers.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/gc.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/imemo.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/namespace.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/set_table.h vm_sync.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -20778,6 +21030,7 @@ vm_trace.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/gc.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/hash.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/hash.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/imemo.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/namespace.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/serial.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/set_table.h vm_trace.$(OBJEXT): $(top_srcdir)/internal/set_table.h
@ -21016,6 +21269,7 @@ weakmap.$(OBJEXT): $(top_srcdir)/internal/compilers.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/gc.h weakmap.$(OBJEXT): $(top_srcdir)/internal/gc.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/hash.h weakmap.$(OBJEXT): $(top_srcdir)/internal/hash.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/imemo.h weakmap.$(OBJEXT): $(top_srcdir)/internal/imemo.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/namespace.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/proc.h weakmap.$(OBJEXT): $(top_srcdir)/internal/proc.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h weakmap.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
weakmap.$(OBJEXT): $(top_srcdir)/internal/serial.h weakmap.$(OBJEXT): $(top_srcdir)/internal/serial.h
@ -21221,6 +21475,7 @@ yjit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
yjit.$(OBJEXT): $(top_srcdir)/internal/gc.h yjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
yjit.$(OBJEXT): $(top_srcdir)/internal/hash.h yjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
yjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h yjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
yjit.$(OBJEXT): $(top_srcdir)/internal/namespace.h
yjit.$(OBJEXT): $(top_srcdir)/internal/numeric.h yjit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
yjit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h yjit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
yjit.$(OBJEXT): $(top_srcdir)/internal/serial.h yjit.$(OBJEXT): $(top_srcdir)/internal/serial.h

41
dln.c
View File

@ -26,6 +26,7 @@ static void dln_loaderror(const char *format, ...);
#include "dln.h" #include "dln.h"
#include "internal.h" #include "internal.h"
#include "internal/compilers.h" #include "internal/compilers.h"
#include "internal/namespace.h"
#ifdef HAVE_STDLIB_H #ifdef HAVE_STDLIB_H
# include <stdlib.h> # include <stdlib.h>
@ -382,10 +383,14 @@ dln_open(const char *file)
# endif # endif
# ifndef RTLD_GLOBAL # ifndef RTLD_GLOBAL
# define RTLD_GLOBAL 0 # define RTLD_GLOBAL 0
# endif
# ifndef RTLD_LOCAL
# define RTLD_LOCAL 0 /* TODO: 0??? some systems (including libc) use 0x00100 for RTLD_GLOBAL, 0x00000 for RTLD_LOCAL */
# endif # endif
/* Load file */ /* Load file */
handle = dlopen(file, RTLD_LAZY|RTLD_GLOBAL); int mode = rb_namespace_available() ? RTLD_LAZY|RTLD_LOCAL : RTLD_LAZY|RTLD_GLOBAL;
handle = dlopen(file, mode);
if (handle == NULL) { if (handle == NULL) {
error = dln_strerror(); error = dln_strerror();
goto failed; goto failed;
@ -497,8 +502,8 @@ abi_check_enabled_p(void)
} }
#endif #endif
void * static void *
dln_load(const char *file) dln_load_and_init(const char *file, const char *init_fct_name)
{ {
#if defined(_WIN32) || defined(USE_DLN_DLOPEN) #if defined(_WIN32) || defined(USE_DLN_DLOPEN)
void *handle = dln_open(file); void *handle = dln_open(file);
@ -512,9 +517,6 @@ dln_load(const char *file)
} }
#endif #endif
char *init_fct_name;
init_funcname(&init_fct_name, file);
/* Call the init code */ /* Call the init code */
dln_sym_callable(void, (void), handle, init_fct_name)(); dln_sym_callable(void, (void), handle, init_fct_name)();
@ -524,6 +526,7 @@ dln_load(const char *file)
{ {
void (*init_fct)(void); void (*init_fct)(void);
/* TODO: check - AIX's load system call will return the first/last symbol/function? */
init_fct = (void(*)(void))load((char*)file, 1, 0); init_fct = (void(*)(void))load((char*)file, 1, 0);
if (init_fct == NULL) { if (init_fct == NULL) {
aix_loaderror(file); aix_loaderror(file);
@ -540,3 +543,29 @@ dln_load(const char *file)
return 0; /* dummy return */ return 0; /* dummy return */
} }
void *
dln_load(const char *file)
{
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
char *init_fct_name;
init_funcname(&init_fct_name, file);
return dln_load_and_init(file, init_fct_name);
#else
dln_notimplement();
return 0;
#endif
}
void *
dln_load_feature(const char *file, const char *fname)
{
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
char *init_fct_name;
init_funcname(&init_fct_name, fname);
return dln_load_and_init(file, init_fct_name);
#else
dln_notimplement();
return 0;
#endif
}

1
dln.h
View File

@ -25,6 +25,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
char *dln_find_exe_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL); char *dln_find_exe_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
char *dln_find_file_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL); char *dln_find_file_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
void *dln_load(const char*); void *dln_load(const char*);
void *dln_load_feature(const char*, const char*);
void *dln_symbol(void*,const char*); void *dln_symbol(void*,const char*);
RUBY_SYMBOL_EXPORT_END RUBY_SYMBOL_EXPORT_END

View File

@ -12,6 +12,15 @@ dln_load(const char *file)
UNREACHABLE_RETURN(NULL); UNREACHABLE_RETURN(NULL);
} }
NORETURN(void *dln_load_feature(const char*,const char*));
void*
dln_load_feature(const char *file, const char *fname)
{
rb_loaderror("this executable file can't load extension libraries");
UNREACHABLE_RETURN(NULL);
}
NORETURN(void *dln_symbol(void*,const char*)); NORETURN(void *dln_symbol(void*,const char*));
void* void*
dln_symbol(void *handle, const char *symbol) dln_symbol(void *handle, const char *symbol)

80
eval.c
View File

@ -1192,6 +1192,8 @@ rb_mod_append_features(VALUE module, VALUE include)
return module; return module;
} }
static VALUE refinement_import_methods(int argc, VALUE *argv, VALUE refinement);
/* /*
* call-seq: * call-seq:
* include(module, ...) -> self * include(module, ...) -> self
@ -1345,9 +1347,9 @@ rb_using_refinement(rb_cref_t *cref, VALUE klass, VALUE module)
} }
superclass = refinement_superclass(superclass); superclass = refinement_superclass(superclass);
c = iclass = rb_include_class_new(module, superclass); c = iclass = rb_include_class_new(module, superclass);
RB_OBJ_WRITE(c, &RCLASS_REFINED_CLASS(c), klass); RCLASS_SET_REFINED_CLASS(c, klass);
RCLASS_M_TBL(c) = RCLASS_M_TBL(module); RCLASS_WRITE_M_TBL(c, RCLASS_M_TBL(module));
rb_hash_aset(CREF_REFINEMENTS(cref), klass, iclass); rb_hash_aset(CREF_REFINEMENTS(cref), klass, iclass);
} }
@ -1402,6 +1404,12 @@ rb_using_module(const rb_cref_t *cref, VALUE module)
rb_clear_all_refinement_method_cache(); rb_clear_all_refinement_method_cache();
} }
void
rb_vm_using_module(VALUE module)
{
rb_using_module(rb_vm_cref_replace_with_duplicated_cref(), module);
}
/* /*
* call-seq: * call-seq:
* target -> class_or_module * target -> class_or_module
@ -1442,43 +1450,24 @@ add_activated_refinement(VALUE activated_refinements,
} }
superclass = refinement_superclass(superclass); superclass = refinement_superclass(superclass);
c = iclass = rb_include_class_new(refinement, superclass); c = iclass = rb_include_class_new(refinement, superclass);
RB_OBJ_WRITE(c, &RCLASS_REFINED_CLASS(c), klass); RCLASS_SET_REFINED_CLASS(c, klass);
refinement = RCLASS_SUPER(refinement); refinement = RCLASS_SUPER(refinement);
while (refinement && refinement != klass) { while (refinement && refinement != klass) {
c = RCLASS_SET_SUPER(c, rb_include_class_new(refinement, RCLASS_SUPER(c))); c = rb_class_set_super(c, rb_include_class_new(refinement, RCLASS_SUPER(c)));
RB_OBJ_WRITE(c, &RCLASS_REFINED_CLASS(c), klass); RCLASS_SET_REFINED_CLASS(c, klass);
refinement = RCLASS_SUPER(refinement); refinement = RCLASS_SUPER(refinement);
} }
rb_hash_aset(activated_refinements, klass, iclass); rb_hash_aset(activated_refinements, klass, iclass);
} }
/* void
* call-seq: rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass)
* refine(mod) { block } -> module
*
* Refine <i>mod</i> in the receiver.
*
* Returns a module, where refined methods are defined.
*/
static VALUE
rb_mod_refine(VALUE module, VALUE klass)
{ {
VALUE refinement; VALUE refinement;
ID id_refinements, id_activated_refinements, ID id_refinements, id_activated_refinements,
id_refined_class, id_defined_at; id_refined_class, id_defined_at;
VALUE refinements, activated_refinements; VALUE refinements, activated_refinements;
rb_thread_t *th = GET_THREAD();
VALUE block_handler = rb_vm_frame_block_handler(th->ec->cfp);
if (block_handler == VM_BLOCK_HANDLER_NONE) {
rb_raise(rb_eArgError, "no block given");
}
if (vm_block_handler_type(block_handler) != block_handler_type_iseq) {
rb_raise(rb_eArgError, "can't pass a Proc as a block to Module#refine");
}
ensure_class_or_module(klass);
CONST_ID(id_refinements, "__refinements__"); CONST_ID(id_refinements, "__refinements__");
refinements = rb_attr_get(module, id_refinements); refinements = rb_attr_get(module, id_refinements);
if (NIL_P(refinements)) { if (NIL_P(refinements)) {
@ -1496,7 +1485,7 @@ rb_mod_refine(VALUE module, VALUE klass)
if (NIL_P(refinement)) { if (NIL_P(refinement)) {
VALUE superclass = refinement_superclass(klass); VALUE superclass = refinement_superclass(klass);
refinement = rb_refinement_new(); refinement = rb_refinement_new();
RCLASS_SET_SUPER(refinement, superclass); rb_class_set_super(refinement, superclass);
RUBY_ASSERT(BUILTIN_TYPE(refinement) == T_MODULE); RUBY_ASSERT(BUILTIN_TYPE(refinement) == T_MODULE);
FL_SET(refinement, RMODULE_IS_REFINEMENT); FL_SET(refinement, RMODULE_IS_REFINEMENT);
CONST_ID(id_refined_class, "__refined_class__"); CONST_ID(id_refined_class, "__refined_class__");
@ -1506,8 +1495,41 @@ rb_mod_refine(VALUE module, VALUE klass)
rb_hash_aset(refinements, klass, refinement); rb_hash_aset(refinements, klass, refinement);
add_activated_refinement(activated_refinements, klass, refinement); add_activated_refinement(activated_refinements, klass, refinement);
} }
rb_yield_refine_block(refinement, activated_refinements);
return refinement; data->refinement = refinement;
data->refinements = activated_refinements;
}
/*
* call-seq:
* refine(mod) { block } -> module
*
* Refine <i>mod</i> in the receiver.
*
* Returns a module, where refined methods are defined.
*/
static VALUE
rb_mod_refine(VALUE module, VALUE klass)
{
/* module is the receiver of #refine, klass is a module to be refined (`mod` in the doc) */
rb_thread_t *th = GET_THREAD();
VALUE block_handler = rb_vm_frame_block_handler(th->ec->cfp);
struct rb_refinements_data data;
if (block_handler == VM_BLOCK_HANDLER_NONE) {
rb_raise(rb_eArgError, "no block given");
}
if (vm_block_handler_type(block_handler) != block_handler_type_iseq) {
rb_raise(rb_eArgError, "can't pass a Proc as a block to Module#refine");
}
ensure_class_or_module(klass);
rb_refinement_setup(&data, module, klass);
rb_yield_refine_block(data.refinement, data.refinements);
return data.refinement;
} }
static void static void

View File

@ -296,6 +296,7 @@ VALUE rb_vm_make_jump_tag_but_local_jump(enum ruby_tag_type state, VALUE val);
rb_cref_t *rb_vm_cref(void); rb_cref_t *rb_vm_cref(void);
rb_cref_t *rb_vm_cref_replace_with_duplicated_cref(void); rb_cref_t *rb_vm_cref_replace_with_duplicated_cref(void);
VALUE rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, VALUE block_handler, VALUE filename); VALUE rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, VALUE block_handler, VALUE filename);
VALUE rb_vm_call_cfunc2(VALUE recv, VALUE (*func)(VALUE, VALUE), VALUE arg1, VALUE arg2, VALUE block_handler, VALUE filename);
void rb_vm_set_progname(VALUE filename); void rb_vm_set_progname(VALUE filename);
VALUE rb_vm_cbase(void); VALUE rb_vm_cbase(void);

View File

@ -0,0 +1 @@
create_makefile('-test-/namespace/yay1')

View File

@ -0,0 +1,28 @@
#include "yay1.h"
VALUE
yay_value(void)
{
return rb_str_new_cstr("yay");
}
static VALUE
yay1_f_version(VALUE klass)
{
return rb_str_new_cstr("1.0.0");
}
static VALUE
yay1_yay(VALUE klass)
{
return yay_value();
}
void
Init_yay1(void)
{
VALUE mod = rb_define_module("Yay");
rb_define_const(mod, "VERSION", rb_str_new_cstr("1.0.0"));
rb_define_singleton_method(mod, "version", yay1_f_version, 0);
rb_define_singleton_method(mod, "yay", yay1_yay, 0);
}

View File

@ -0,0 +1,4 @@
LIBRARY yay1
EXPORTS
Init_yay1
yay_value

View File

@ -0,0 +1,4 @@
#include <ruby.h>
#include "ruby/internal/dllexport.h"
RUBY_EXTERN VALUE yay_value(void);

View File

@ -0,0 +1 @@
create_makefile('-test-/namespace/yay2')

View File

@ -0,0 +1,28 @@
#include "yay2.h"
VALUE
yay_value(void)
{
return rb_str_new_cstr("yaaay");
}
static VALUE
yay2_f_version(VALUE klass)
{
return rb_str_new_cstr("2.0.0");
}
static VALUE
yay2_yay(VALUE klass)
{
return yay_value();
}
void
Init_yay2(void)
{
VALUE mod = rb_define_module("Yay");
rb_define_const(mod, "VERSION", rb_str_new_cstr("2.0.0"));
rb_define_singleton_method(mod, "version", yay2_f_version, 0);
rb_define_singleton_method(mod, "yay", yay2_yay, 0);
}

View File

@ -0,0 +1,4 @@
LIBRARY yay2
EXPORTS
Init_yay2
yay_value

View File

@ -0,0 +1,4 @@
#include <ruby.h>
#include "ruby/internal/dllexport.h"
RUBY_EXTERN VALUE yay_value(void);

View File

@ -186,6 +186,7 @@ coverage.o: $(top_srcdir)/internal/compilers.h
coverage.o: $(top_srcdir)/internal/gc.h coverage.o: $(top_srcdir)/internal/gc.h
coverage.o: $(top_srcdir)/internal/hash.h coverage.o: $(top_srcdir)/internal/hash.h
coverage.o: $(top_srcdir)/internal/imemo.h coverage.o: $(top_srcdir)/internal/imemo.h
coverage.o: $(top_srcdir)/internal/namespace.h
coverage.o: $(top_srcdir)/internal/sanitizers.h coverage.o: $(top_srcdir)/internal/sanitizers.h
coverage.o: $(top_srcdir)/internal/serial.h coverage.o: $(top_srcdir)/internal/serial.h
coverage.o: $(top_srcdir)/internal/set_table.h coverage.o: $(top_srcdir)/internal/set_table.h

View File

@ -183,6 +183,7 @@ object_tracing.o: $(top_srcdir)/internal/basic_operators.h
object_tracing.o: $(top_srcdir)/internal/compilers.h object_tracing.o: $(top_srcdir)/internal/compilers.h
object_tracing.o: $(top_srcdir)/internal/gc.h object_tracing.o: $(top_srcdir)/internal/gc.h
object_tracing.o: $(top_srcdir)/internal/imemo.h object_tracing.o: $(top_srcdir)/internal/imemo.h
object_tracing.o: $(top_srcdir)/internal/namespace.h
object_tracing.o: $(top_srcdir)/internal/sanitizers.h object_tracing.o: $(top_srcdir)/internal/sanitizers.h
object_tracing.o: $(top_srcdir)/internal/serial.h object_tracing.o: $(top_srcdir)/internal/serial.h
object_tracing.o: $(top_srcdir)/internal/set_table.h object_tracing.o: $(top_srcdir)/internal/set_table.h
@ -392,6 +393,7 @@ objspace.o: $(top_srcdir)/internal/compilers.h
objspace.o: $(top_srcdir)/internal/gc.h objspace.o: $(top_srcdir)/internal/gc.h
objspace.o: $(top_srcdir)/internal/hash.h objspace.o: $(top_srcdir)/internal/hash.h
objspace.o: $(top_srcdir)/internal/imemo.h objspace.o: $(top_srcdir)/internal/imemo.h
objspace.o: $(top_srcdir)/internal/namespace.h
objspace.o: $(top_srcdir)/internal/sanitizers.h objspace.o: $(top_srcdir)/internal/sanitizers.h
objspace.o: $(top_srcdir)/internal/serial.h objspace.o: $(top_srcdir)/internal/serial.h
objspace.o: $(top_srcdir)/internal/set_table.h objspace.o: $(top_srcdir)/internal/set_table.h
@ -605,6 +607,7 @@ objspace_dump.o: $(top_srcdir)/internal/gc.h
objspace_dump.o: $(top_srcdir)/internal/hash.h objspace_dump.o: $(top_srcdir)/internal/hash.h
objspace_dump.o: $(top_srcdir)/internal/imemo.h objspace_dump.o: $(top_srcdir)/internal/imemo.h
objspace_dump.o: $(top_srcdir)/internal/io.h objspace_dump.o: $(top_srcdir)/internal/io.h
objspace_dump.o: $(top_srcdir)/internal/namespace.h
objspace_dump.o: $(top_srcdir)/internal/sanitizers.h objspace_dump.o: $(top_srcdir)/internal/sanitizers.h
objspace_dump.o: $(top_srcdir)/internal/serial.h objspace_dump.o: $(top_srcdir)/internal/serial.h
objspace_dump.o: $(top_srcdir)/internal/set_table.h objspace_dump.o: $(top_srcdir)/internal/set_table.h

View File

@ -792,7 +792,7 @@ objspace_internal_super_of(VALUE self, VALUE obj)
case T_MODULE: case T_MODULE:
case T_CLASS: case T_CLASS:
case T_ICLASS: case T_ICLASS:
super = RCLASS_SUPER(obj); super = rb_class_super_of(obj);
break; break;
default: default:
rb_raise(rb_eArgError, "class or module is expected"); rb_raise(rb_eArgError, "class or module is expected");

View File

@ -537,7 +537,7 @@ dump_object(VALUE obj, struct dump_config *dc)
case T_CLASS: case T_CLASS:
dump_append(dc, ", \"variation_count\":"); dump_append(dc, ", \"variation_count\":");
dump_append_d(dc, RCLASS_EXT(obj)->variation_count); dump_append_d(dc, rb_class_variation_count(obj));
case T_MODULE: case T_MODULE:
if (rb_class_get_superclass(obj)) { if (rb_class_get_superclass(obj)) {
@ -560,7 +560,7 @@ dump_object(VALUE obj, struct dump_config *dc)
} }
} }
if (RCLASS_SINGLETON_P(obj)) { if (rb_class_singleton_p(obj)) {
dump_append(dc, ", \"singleton\":true"); dump_append(dc, ", \"singleton\":true");
} }
} }

View File

@ -591,6 +591,7 @@ ripper.o: $(top_srcdir)/internal/gc.h
ripper.o: $(top_srcdir)/internal/hash.h ripper.o: $(top_srcdir)/internal/hash.h
ripper.o: $(top_srcdir)/internal/imemo.h ripper.o: $(top_srcdir)/internal/imemo.h
ripper.o: $(top_srcdir)/internal/io.h ripper.o: $(top_srcdir)/internal/io.h
ripper.o: $(top_srcdir)/internal/namespace.h
ripper.o: $(top_srcdir)/internal/numeric.h ripper.o: $(top_srcdir)/internal/numeric.h
ripper.o: $(top_srcdir)/internal/parse.h ripper.o: $(top_srcdir)/internal/parse.h
ripper.o: $(top_srcdir)/internal/rational.h ripper.o: $(top_srcdir)/internal/rational.h

View File

@ -200,6 +200,7 @@ ancdata.o: $(top_srcdir)/internal/error.h
ancdata.o: $(top_srcdir)/internal/gc.h ancdata.o: $(top_srcdir)/internal/gc.h
ancdata.o: $(top_srcdir)/internal/imemo.h ancdata.o: $(top_srcdir)/internal/imemo.h
ancdata.o: $(top_srcdir)/internal/io.h ancdata.o: $(top_srcdir)/internal/io.h
ancdata.o: $(top_srcdir)/internal/namespace.h
ancdata.o: $(top_srcdir)/internal/sanitizers.h ancdata.o: $(top_srcdir)/internal/sanitizers.h
ancdata.o: $(top_srcdir)/internal/serial.h ancdata.o: $(top_srcdir)/internal/serial.h
ancdata.o: $(top_srcdir)/internal/set_table.h ancdata.o: $(top_srcdir)/internal/set_table.h
@ -412,6 +413,7 @@ basicsocket.o: $(top_srcdir)/internal/error.h
basicsocket.o: $(top_srcdir)/internal/gc.h basicsocket.o: $(top_srcdir)/internal/gc.h
basicsocket.o: $(top_srcdir)/internal/imemo.h basicsocket.o: $(top_srcdir)/internal/imemo.h
basicsocket.o: $(top_srcdir)/internal/io.h basicsocket.o: $(top_srcdir)/internal/io.h
basicsocket.o: $(top_srcdir)/internal/namespace.h
basicsocket.o: $(top_srcdir)/internal/sanitizers.h basicsocket.o: $(top_srcdir)/internal/sanitizers.h
basicsocket.o: $(top_srcdir)/internal/serial.h basicsocket.o: $(top_srcdir)/internal/serial.h
basicsocket.o: $(top_srcdir)/internal/set_table.h basicsocket.o: $(top_srcdir)/internal/set_table.h
@ -624,6 +626,7 @@ constants.o: $(top_srcdir)/internal/error.h
constants.o: $(top_srcdir)/internal/gc.h constants.o: $(top_srcdir)/internal/gc.h
constants.o: $(top_srcdir)/internal/imemo.h constants.o: $(top_srcdir)/internal/imemo.h
constants.o: $(top_srcdir)/internal/io.h constants.o: $(top_srcdir)/internal/io.h
constants.o: $(top_srcdir)/internal/namespace.h
constants.o: $(top_srcdir)/internal/sanitizers.h constants.o: $(top_srcdir)/internal/sanitizers.h
constants.o: $(top_srcdir)/internal/serial.h constants.o: $(top_srcdir)/internal/serial.h
constants.o: $(top_srcdir)/internal/set_table.h constants.o: $(top_srcdir)/internal/set_table.h
@ -837,6 +840,7 @@ ifaddr.o: $(top_srcdir)/internal/error.h
ifaddr.o: $(top_srcdir)/internal/gc.h ifaddr.o: $(top_srcdir)/internal/gc.h
ifaddr.o: $(top_srcdir)/internal/imemo.h ifaddr.o: $(top_srcdir)/internal/imemo.h
ifaddr.o: $(top_srcdir)/internal/io.h ifaddr.o: $(top_srcdir)/internal/io.h
ifaddr.o: $(top_srcdir)/internal/namespace.h
ifaddr.o: $(top_srcdir)/internal/sanitizers.h ifaddr.o: $(top_srcdir)/internal/sanitizers.h
ifaddr.o: $(top_srcdir)/internal/serial.h ifaddr.o: $(top_srcdir)/internal/serial.h
ifaddr.o: $(top_srcdir)/internal/set_table.h ifaddr.o: $(top_srcdir)/internal/set_table.h
@ -1049,6 +1053,7 @@ init.o: $(top_srcdir)/internal/error.h
init.o: $(top_srcdir)/internal/gc.h init.o: $(top_srcdir)/internal/gc.h
init.o: $(top_srcdir)/internal/imemo.h init.o: $(top_srcdir)/internal/imemo.h
init.o: $(top_srcdir)/internal/io.h init.o: $(top_srcdir)/internal/io.h
init.o: $(top_srcdir)/internal/namespace.h
init.o: $(top_srcdir)/internal/sanitizers.h init.o: $(top_srcdir)/internal/sanitizers.h
init.o: $(top_srcdir)/internal/serial.h init.o: $(top_srcdir)/internal/serial.h
init.o: $(top_srcdir)/internal/set_table.h init.o: $(top_srcdir)/internal/set_table.h
@ -1261,6 +1266,7 @@ ipsocket.o: $(top_srcdir)/internal/error.h
ipsocket.o: $(top_srcdir)/internal/gc.h ipsocket.o: $(top_srcdir)/internal/gc.h
ipsocket.o: $(top_srcdir)/internal/imemo.h ipsocket.o: $(top_srcdir)/internal/imemo.h
ipsocket.o: $(top_srcdir)/internal/io.h ipsocket.o: $(top_srcdir)/internal/io.h
ipsocket.o: $(top_srcdir)/internal/namespace.h
ipsocket.o: $(top_srcdir)/internal/sanitizers.h ipsocket.o: $(top_srcdir)/internal/sanitizers.h
ipsocket.o: $(top_srcdir)/internal/serial.h ipsocket.o: $(top_srcdir)/internal/serial.h
ipsocket.o: $(top_srcdir)/internal/set_table.h ipsocket.o: $(top_srcdir)/internal/set_table.h
@ -1473,6 +1479,7 @@ option.o: $(top_srcdir)/internal/error.h
option.o: $(top_srcdir)/internal/gc.h option.o: $(top_srcdir)/internal/gc.h
option.o: $(top_srcdir)/internal/imemo.h option.o: $(top_srcdir)/internal/imemo.h
option.o: $(top_srcdir)/internal/io.h option.o: $(top_srcdir)/internal/io.h
option.o: $(top_srcdir)/internal/namespace.h
option.o: $(top_srcdir)/internal/sanitizers.h option.o: $(top_srcdir)/internal/sanitizers.h
option.o: $(top_srcdir)/internal/serial.h option.o: $(top_srcdir)/internal/serial.h
option.o: $(top_srcdir)/internal/set_table.h option.o: $(top_srcdir)/internal/set_table.h
@ -1685,6 +1692,7 @@ raddrinfo.o: $(top_srcdir)/internal/error.h
raddrinfo.o: $(top_srcdir)/internal/gc.h raddrinfo.o: $(top_srcdir)/internal/gc.h
raddrinfo.o: $(top_srcdir)/internal/imemo.h raddrinfo.o: $(top_srcdir)/internal/imemo.h
raddrinfo.o: $(top_srcdir)/internal/io.h raddrinfo.o: $(top_srcdir)/internal/io.h
raddrinfo.o: $(top_srcdir)/internal/namespace.h
raddrinfo.o: $(top_srcdir)/internal/sanitizers.h raddrinfo.o: $(top_srcdir)/internal/sanitizers.h
raddrinfo.o: $(top_srcdir)/internal/serial.h raddrinfo.o: $(top_srcdir)/internal/serial.h
raddrinfo.o: $(top_srcdir)/internal/set_table.h raddrinfo.o: $(top_srcdir)/internal/set_table.h
@ -1897,6 +1905,7 @@ socket.o: $(top_srcdir)/internal/error.h
socket.o: $(top_srcdir)/internal/gc.h socket.o: $(top_srcdir)/internal/gc.h
socket.o: $(top_srcdir)/internal/imemo.h socket.o: $(top_srcdir)/internal/imemo.h
socket.o: $(top_srcdir)/internal/io.h socket.o: $(top_srcdir)/internal/io.h
socket.o: $(top_srcdir)/internal/namespace.h
socket.o: $(top_srcdir)/internal/sanitizers.h socket.o: $(top_srcdir)/internal/sanitizers.h
socket.o: $(top_srcdir)/internal/serial.h socket.o: $(top_srcdir)/internal/serial.h
socket.o: $(top_srcdir)/internal/set_table.h socket.o: $(top_srcdir)/internal/set_table.h
@ -2109,6 +2118,7 @@ sockssocket.o: $(top_srcdir)/internal/error.h
sockssocket.o: $(top_srcdir)/internal/gc.h sockssocket.o: $(top_srcdir)/internal/gc.h
sockssocket.o: $(top_srcdir)/internal/imemo.h sockssocket.o: $(top_srcdir)/internal/imemo.h
sockssocket.o: $(top_srcdir)/internal/io.h sockssocket.o: $(top_srcdir)/internal/io.h
sockssocket.o: $(top_srcdir)/internal/namespace.h
sockssocket.o: $(top_srcdir)/internal/sanitizers.h sockssocket.o: $(top_srcdir)/internal/sanitizers.h
sockssocket.o: $(top_srcdir)/internal/serial.h sockssocket.o: $(top_srcdir)/internal/serial.h
sockssocket.o: $(top_srcdir)/internal/set_table.h sockssocket.o: $(top_srcdir)/internal/set_table.h
@ -2321,6 +2331,7 @@ tcpserver.o: $(top_srcdir)/internal/error.h
tcpserver.o: $(top_srcdir)/internal/gc.h tcpserver.o: $(top_srcdir)/internal/gc.h
tcpserver.o: $(top_srcdir)/internal/imemo.h tcpserver.o: $(top_srcdir)/internal/imemo.h
tcpserver.o: $(top_srcdir)/internal/io.h tcpserver.o: $(top_srcdir)/internal/io.h
tcpserver.o: $(top_srcdir)/internal/namespace.h
tcpserver.o: $(top_srcdir)/internal/sanitizers.h tcpserver.o: $(top_srcdir)/internal/sanitizers.h
tcpserver.o: $(top_srcdir)/internal/serial.h tcpserver.o: $(top_srcdir)/internal/serial.h
tcpserver.o: $(top_srcdir)/internal/set_table.h tcpserver.o: $(top_srcdir)/internal/set_table.h
@ -2533,6 +2544,7 @@ tcpsocket.o: $(top_srcdir)/internal/error.h
tcpsocket.o: $(top_srcdir)/internal/gc.h tcpsocket.o: $(top_srcdir)/internal/gc.h
tcpsocket.o: $(top_srcdir)/internal/imemo.h tcpsocket.o: $(top_srcdir)/internal/imemo.h
tcpsocket.o: $(top_srcdir)/internal/io.h tcpsocket.o: $(top_srcdir)/internal/io.h
tcpsocket.o: $(top_srcdir)/internal/namespace.h
tcpsocket.o: $(top_srcdir)/internal/sanitizers.h tcpsocket.o: $(top_srcdir)/internal/sanitizers.h
tcpsocket.o: $(top_srcdir)/internal/serial.h tcpsocket.o: $(top_srcdir)/internal/serial.h
tcpsocket.o: $(top_srcdir)/internal/set_table.h tcpsocket.o: $(top_srcdir)/internal/set_table.h
@ -2745,6 +2757,7 @@ udpsocket.o: $(top_srcdir)/internal/error.h
udpsocket.o: $(top_srcdir)/internal/gc.h udpsocket.o: $(top_srcdir)/internal/gc.h
udpsocket.o: $(top_srcdir)/internal/imemo.h udpsocket.o: $(top_srcdir)/internal/imemo.h
udpsocket.o: $(top_srcdir)/internal/io.h udpsocket.o: $(top_srcdir)/internal/io.h
udpsocket.o: $(top_srcdir)/internal/namespace.h
udpsocket.o: $(top_srcdir)/internal/sanitizers.h udpsocket.o: $(top_srcdir)/internal/sanitizers.h
udpsocket.o: $(top_srcdir)/internal/serial.h udpsocket.o: $(top_srcdir)/internal/serial.h
udpsocket.o: $(top_srcdir)/internal/set_table.h udpsocket.o: $(top_srcdir)/internal/set_table.h
@ -2957,6 +2970,7 @@ unixserver.o: $(top_srcdir)/internal/error.h
unixserver.o: $(top_srcdir)/internal/gc.h unixserver.o: $(top_srcdir)/internal/gc.h
unixserver.o: $(top_srcdir)/internal/imemo.h unixserver.o: $(top_srcdir)/internal/imemo.h
unixserver.o: $(top_srcdir)/internal/io.h unixserver.o: $(top_srcdir)/internal/io.h
unixserver.o: $(top_srcdir)/internal/namespace.h
unixserver.o: $(top_srcdir)/internal/sanitizers.h unixserver.o: $(top_srcdir)/internal/sanitizers.h
unixserver.o: $(top_srcdir)/internal/serial.h unixserver.o: $(top_srcdir)/internal/serial.h
unixserver.o: $(top_srcdir)/internal/set_table.h unixserver.o: $(top_srcdir)/internal/set_table.h
@ -3169,6 +3183,7 @@ unixsocket.o: $(top_srcdir)/internal/error.h
unixsocket.o: $(top_srcdir)/internal/gc.h unixsocket.o: $(top_srcdir)/internal/gc.h
unixsocket.o: $(top_srcdir)/internal/imemo.h unixsocket.o: $(top_srcdir)/internal/imemo.h
unixsocket.o: $(top_srcdir)/internal/io.h unixsocket.o: $(top_srcdir)/internal/io.h
unixsocket.o: $(top_srcdir)/internal/namespace.h
unixsocket.o: $(top_srcdir)/internal/sanitizers.h unixsocket.o: $(top_srcdir)/internal/sanitizers.h
unixsocket.o: $(top_srcdir)/internal/serial.h unixsocket.o: $(top_srcdir)/internal/serial.h
unixsocket.o: $(top_srcdir)/internal/set_table.h unixsocket.o: $(top_srcdir)/internal/set_table.h

527
gc.c
View File

@ -1210,9 +1210,68 @@ rb_data_free(void *objspace, VALUE obj)
return true; return true;
} }
struct classext_foreach_args {
VALUE klass;
bool obj_too_complex;
rb_objspace_t *objspace; // used for update_*
};
static void
classext_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
{
struct rb_id_table *tbl;
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
rb_id_table_free(RCLASSEXT_M_TBL(ext));
rb_cc_tbl_free(RCLASSEXT_CC_TBL(ext), args->klass);
if (args->obj_too_complex) {
st_free_table((st_table *)RCLASSEXT_FIELDS(ext));
}
else {
xfree(RCLASSEXT_FIELDS(ext));
}
if (!RCLASSEXT_SHARED_CONST_TBL(ext) && (tbl = RCLASSEXT_CONST_TBL(ext)) != NULL) {
rb_free_const_table(tbl);
}
if ((tbl = RCLASSEXT_CVC_TBL(ext)) != NULL) {
rb_id_table_foreach_values(tbl, cvar_table_free_i, NULL);
rb_id_table_free(tbl);
}
rb_class_classext_free_subclasses(ext, args->klass);
if (RCLASSEXT_SUPERCLASSES_OWNER(ext)) {
xfree(RCLASSEXT_SUPERCLASSES(ext));
}
if (!is_prime) { // the prime classext will be freed with RClass
xfree(ext);
}
}
static void
classext_iclass_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
{
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
/* Method table is not shared for origin iclasses of classes */
rb_id_table_free(RCLASSEXT_M_TBL(ext));
}
if (RCLASSEXT_CALLABLE_M_TBL(ext) != NULL) {
rb_id_table_free(RCLASSEXT_CALLABLE_M_TBL(ext));
}
rb_cc_tbl_free(RCLASSEXT_CC_TBL(ext), args->klass);
rb_class_classext_free_subclasses(ext, args->klass);
if (!is_prime) { // the prime classext will be freed with RClass
xfree(ext);
}
}
bool bool
rb_gc_obj_free(void *objspace, VALUE obj) rb_gc_obj_free(void *objspace, VALUE obj)
{ {
struct classext_foreach_args args;
RB_DEBUG_COUNTER_INC(obj_free); RB_DEBUG_COUNTER_INC(obj_free);
switch (BUILTIN_TYPE(obj)) { switch (BUILTIN_TYPE(obj)) {
@ -1242,29 +1301,13 @@ rb_gc_obj_free(void *objspace, VALUE obj)
break; break;
case T_MODULE: case T_MODULE:
case T_CLASS: case T_CLASS:
rb_id_table_free(RCLASS_M_TBL(obj)); args.klass = obj;
rb_cc_table_free(obj); args.obj_too_complex = rb_shape_obj_too_complex_p(obj) ? true : false;
if (rb_shape_obj_too_complex_p(obj)) {
st_free_table((st_table *)RCLASS_FIELDS(obj));
}
else {
xfree(RCLASS_FIELDS(obj));
}
if (RCLASS_CONST_TBL(obj)) { rb_class_classext_foreach(obj, classext_free, (void *)&args);
rb_free_const_table(RCLASS_CONST_TBL(obj)); if (RCLASS(obj)->ns_classext_tbl) {
st_free_table(RCLASS(obj)->ns_classext_tbl);
} }
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));
}
rb_class_remove_subclass_head(obj);
rb_class_remove_from_module_subclasses(obj);
rb_class_remove_from_super_subclasses(obj);
if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) {
xfree(RCLASS_SUPERCLASSES(obj));
}
(void)RB_DEBUG_COUNTER_INC_IF(obj_module_ptr, BUILTIN_TYPE(obj) == T_MODULE); (void)RB_DEBUG_COUNTER_INC_IF(obj_module_ptr, BUILTIN_TYPE(obj) == T_MODULE);
(void)RB_DEBUG_COUNTER_INC_IF(obj_class_ptr, BUILTIN_TYPE(obj) == T_CLASS); (void)RB_DEBUG_COUNTER_INC_IF(obj_class_ptr, BUILTIN_TYPE(obj) == T_CLASS);
break; break;
@ -1363,18 +1406,12 @@ rb_gc_obj_free(void *objspace, VALUE obj)
case T_MOVED: case T_MOVED:
break; break;
case T_ICLASS: case T_ICLASS:
/* Basically , T_ICLASS shares table with the module */ args.klass = obj;
if (RICLASS_OWNS_M_TBL_P(obj)) {
/* Method table is not shared for origin iclasses of classes */ rb_class_classext_foreach(obj, classext_iclass_free, (void *)&args);
rb_id_table_free(RCLASS_M_TBL(obj)); if (RCLASS(obj)->ns_classext_tbl) {
st_free_table(RCLASS(obj)->ns_classext_tbl);
} }
if (RCLASS_CALLABLE_M_TBL(obj) != NULL) {
rb_id_table_free(RCLASS_CALLABLE_M_TBL(obj));
}
rb_class_remove_subclass_head(obj);
rb_cc_table_free(obj);
rb_class_remove_from_module_subclasses(obj);
rb_class_remove_from_super_subclasses(obj);
RB_DEBUG_COUNTER_INC(obj_iclass_ptr); RB_DEBUG_COUNTER_INC(obj_iclass_ptr);
break; break;
@ -2124,6 +2161,60 @@ cc_table_memsize(struct rb_id_table *cc_table)
return total; return total;
} }
static void
classext_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
{
size_t *size = (size_t *)arg;
size_t s = 0;
if (RCLASSEXT_M_TBL(ext)) {
s += rb_id_table_memsize(RCLASSEXT_M_TBL(ext));
}
if (RCLASSEXT_CVC_TBL(ext)) {
s += rb_id_table_memsize(RCLASSEXT_CVC_TBL(ext));
}
if (RCLASSEXT_CONST_TBL(ext)) {
s += rb_id_table_memsize(RCLASSEXT_CONST_TBL(ext));
}
if (RCLASSEXT_CC_TBL(ext)) {
s += cc_table_memsize(RCLASSEXT_CC_TBL(ext));
}
if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
s += (RCLASSEXT_SUPERCLASS_DEPTH(ext) + 1) * sizeof(VALUE);
}
if (!prime) {
s += sizeof(rb_classext_t);
}
*size += s;
}
static void
classext_fields_hash_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
{
size_t *size = (size_t *)arg;
size_t count;
RB_VM_LOCK_ENTER();
{
count = rb_st_table_size((st_table *)RCLASSEXT_FIELDS(ext));
}
RB_VM_LOCK_LEAVE();
// class IV sizes are allocated as powers of two
*size += SIZEOF_VALUE << bit_length(count);
}
static void
classext_superclasses_memsize(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
{
size_t *size = (size_t *)arg;
size_t array_size;
if (RCLASSEXT_SUPERCLASSES_OWNER(ext)) {
array_size = RCLASSEXT_SUPERCLASS_DEPTH(ext);
if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext))
array_size += 1;
*size += array_size * sizeof(VALUE);
}
}
size_t size_t
rb_obj_memsize_of(VALUE obj) rb_obj_memsize_of(VALUE obj)
{ {
@ -2148,23 +2239,16 @@ rb_obj_memsize_of(VALUE obj)
break; break;
case T_MODULE: case T_MODULE:
case T_CLASS: case T_CLASS:
if (RCLASS_M_TBL(obj)) { rb_class_classext_foreach(obj, classext_memsize, (void *)&size);
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
} if (rb_shape_obj_too_complex_p(obj)) {
// class IV sizes are allocated as powers of two rb_class_classext_foreach(obj, classext_fields_hash_memsize, (void *)&size);
size += SIZEOF_VALUE << bit_length(RCLASS_FIELDS_COUNT(obj)); } else {
if (RCLASS_CVC_TBL(obj)) { // class IV sizes are allocated as powers of two
size += rb_id_table_memsize(RCLASS_CVC_TBL(obj)); size += SIZEOF_VALUE << bit_length(RCLASS_FIELDS_COUNT(obj));
}
if (RCLASS_EXT(obj)->const_tbl) {
size += rb_id_table_memsize(RCLASS_EXT(obj)->const_tbl);
}
if (RCLASS_CC_TBL(obj)) {
size += cc_table_memsize(RCLASS_CC_TBL(obj));
}
if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) {
size += (RCLASS_SUPERCLASS_DEPTH(obj) + 1) * sizeof(VALUE);
} }
rb_class_classext_foreach(obj, classext_superclasses_memsize, (void *)&size);
break; break;
case T_ICLASS: case T_ICLASS:
if (RICLASS_OWNS_M_TBL_P(obj)) { if (RICLASS_OWNS_M_TBL_P(obj)) {
@ -2172,8 +2256,8 @@ rb_obj_memsize_of(VALUE obj)
size += rb_id_table_memsize(RCLASS_M_TBL(obj)); size += rb_id_table_memsize(RCLASS_M_TBL(obj));
} }
} }
if (RCLASS_CC_TBL(obj)) { if (RCLASS_WRITABLE_CC_TBL(obj)) {
size += cc_table_memsize(RCLASS_CC_TBL(obj)); size += cc_table_memsize(RCLASS_WRITABLE_CC_TBL(obj));
} }
break; break;
case T_STRING: case T_STRING:
@ -2634,6 +2718,86 @@ mark_m_tbl(void *objspace, struct rb_id_table *tbl)
} }
} }
static enum rb_id_table_iterator_result
mark_const_entry_i(VALUE value, void *objspace)
{
const rb_const_entry_t *ce = (const rb_const_entry_t *)value;
gc_mark_internal(ce->value);
gc_mark_internal(ce->file);
return ID_TABLE_CONTINUE;
}
static void
mark_const_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
{
if (!tbl) return;
rb_id_table_foreach_values(tbl, mark_const_entry_i, objspace);
}
struct mark_cc_entry_args {
rb_objspace_t *objspace;
VALUE klass;
};
static enum rb_id_table_iterator_result
mark_cc_entry_i(ID id, VALUE ccs_ptr, void *data)
{
struct mark_cc_entry_args *args = (struct mark_cc_entry_args *)data;
struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
VM_ASSERT(vm_ccs_p(ccs));
VM_ASSERT(id == ccs->cme->called_id);
if (METHOD_ENTRY_INVALIDATED(ccs->cme)) {
rb_vm_ccs_free(ccs);
return ID_TABLE_DELETE;
}
else {
gc_mark_internal((VALUE)ccs->cme);
for (int i=0; i<ccs->len; i++) {
VM_ASSERT(args->klass == ccs->entries[i].cc->klass);
VM_ASSERT(vm_cc_check_cme(ccs->entries[i].cc, ccs->cme));
gc_mark_internal((VALUE)ccs->entries[i].cc);
}
return ID_TABLE_CONTINUE;
}
}
static void
mark_cc_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl, VALUE klass)
{
struct mark_cc_entry_args args;
if (!tbl) return;
args.objspace = objspace;
args.klass = klass;
rb_id_table_foreach(tbl, mark_cc_entry_i, (void *)&args);
}
static enum rb_id_table_iterator_result
mark_cvc_tbl_i(VALUE cvc_entry, void *objspace)
{
struct rb_cvar_class_tbl_entry *entry;
entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
RUBY_ASSERT(entry->cref == 0 || (BUILTIN_TYPE((VALUE)entry->cref) == T_IMEMO && IMEMO_TYPE_P(entry->cref, imemo_cref)));
gc_mark_internal((VALUE)entry->cref);
return ID_TABLE_CONTINUE;
}
static void
mark_cvc_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
{
if (!tbl) return;
rb_id_table_foreach_values(tbl, mark_cvc_tbl_i, objspace);
}
#if STACK_GROW_DIRECTION < 0 #if STACK_GROW_DIRECTION < 0
#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START) #define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START)
#elif STACK_GROW_DIRECTION > 0 #elif STACK_GROW_DIRECTION > 0
@ -2796,45 +2960,12 @@ rb_mark_tbl_no_pin(st_table *tbl)
gc_mark_tbl_no_pin(tbl); gc_mark_tbl_no_pin(tbl);
} }
static enum rb_id_table_iterator_result
mark_cvc_tbl_i(VALUE cvc_entry, void *objspace)
{
struct rb_cvar_class_tbl_entry *entry;
entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
RUBY_ASSERT(entry->cref == 0 || (BUILTIN_TYPE((VALUE)entry->cref) == T_IMEMO && IMEMO_TYPE_P(entry->cref, imemo_cref)));
gc_mark_internal((VALUE)entry->cref);
return ID_TABLE_CONTINUE;
}
static void
mark_cvc_tbl(void *objspace, VALUE klass)
{
struct rb_id_table *tbl = RCLASS_CVC_TBL(klass);
if (tbl) {
rb_id_table_foreach_values(tbl, mark_cvc_tbl_i, objspace);
}
}
static bool static bool
gc_declarative_marking_p(const rb_data_type_t *type) gc_declarative_marking_p(const rb_data_type_t *type)
{ {
return (type->flags & RUBY_TYPED_DECL_MARKING) != 0; return (type->flags & RUBY_TYPED_DECL_MARKING) != 0;
} }
static enum rb_id_table_iterator_result
mark_const_table_i(VALUE value, void *objspace)
{
const rb_const_entry_t *ce = (const rb_const_entry_t *)value;
gc_mark_internal(ce->value);
gc_mark_internal(ce->file);
return ID_TABLE_CONTINUE;
}
void void
rb_gc_mark_roots(void *objspace, const char **categoryp) rb_gc_mark_roots(void *objspace, const char **categoryp)
{ {
@ -2875,11 +3006,62 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
#undef MARK_CHECKPOINT #undef MARK_CHECKPOINT
} }
struct gc_mark_classext_foreach_arg {
rb_objspace_t *objspace;
VALUE obj;
};
static void
gc_mark_classext_module(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
{
struct gc_mark_classext_foreach_arg *foreach_arg = (struct gc_mark_classext_foreach_arg *)arg;
rb_objspace_t *objspace = foreach_arg->objspace;
VALUE obj = foreach_arg->obj;
if (RCLASSEXT_SUPER(ext)) {
gc_mark_internal(RCLASSEXT_SUPER(ext));
}
mark_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
if (rb_shape_obj_too_complex_p(obj)) {
gc_mark_tbl_no_pin((st_table *)RCLASSEXT_FIELDS(ext));
// for the case ELSE is written in rb_gc_mark_children() because it's per RClass, not classext
}
if (!RCLASSEXT_SHARED_CONST_TBL(ext) && RCLASSEXT_CONST_TBL(ext)) {
mark_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
}
mark_m_tbl(objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
mark_cc_tbl(objspace, RCLASSEXT_CC_TBL(ext), obj);
mark_cvc_tbl(objspace, RCLASSEXT_CVC_TBL(ext));
gc_mark_internal(RCLASSEXT_CLASSPATH(ext));
}
static void
gc_mark_classext_iclass(rb_classext_t *ext, bool prime, VALUE namespace, void *arg)
{
struct gc_mark_classext_foreach_arg *foreach_arg = (struct gc_mark_classext_foreach_arg *)arg;
rb_objspace_t *objspace = foreach_arg->objspace;
VALUE iclass = foreach_arg->obj;
if (RCLASSEXT_SUPER(ext)) {
gc_mark_internal(RCLASSEXT_SUPER(ext));
}
if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
mark_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
}
if (RCLASSEXT_INCLUDER(ext)) {
gc_mark_internal(RCLASSEXT_INCLUDER(ext));
}
mark_m_tbl(objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
mark_cc_tbl(objspace, RCLASSEXT_CC_TBL(ext), iclass);
}
#define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA_TYPE(d)->function.dmark #define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA_TYPE(d)->function.dmark
void void
rb_gc_mark_children(void *objspace, VALUE obj) rb_gc_mark_children(void *objspace, VALUE obj)
{ {
struct gc_mark_classext_foreach_arg foreach_args;
if (FL_TEST_RAW(obj, FL_EXIVAR)) { if (FL_TEST_RAW(obj, FL_EXIVAR)) {
rb_mark_generic_ivar(obj); rb_mark_generic_ivar(obj);
} }
@ -2920,42 +3102,21 @@ rb_gc_mark_children(void *objspace, VALUE obj)
} }
// Continue to the shared T_CLASS/T_MODULE // Continue to the shared T_CLASS/T_MODULE
case T_MODULE: case T_MODULE:
if (RCLASS_SUPER(obj)) { foreach_args.objspace = objspace;
gc_mark_internal(RCLASS_SUPER(obj)); foreach_args.obj = obj;
} rb_class_classext_foreach(obj, gc_mark_classext_module, (void *)&foreach_args);
mark_m_tbl(objspace, RCLASS_M_TBL(obj)); if (!rb_shape_obj_too_complex_p(obj)) {
mark_cvc_tbl(objspace, obj);
rb_cc_table_mark(obj);
if (rb_shape_obj_too_complex_p(obj)) {
gc_mark_tbl_no_pin((st_table *)RCLASS_FIELDS(obj));
}
else {
for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(obj); i++) { for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(obj); i++) {
gc_mark_internal(RCLASS_FIELDS(obj)[i]); gc_mark_internal(RCLASS_PRIME_FIELDS(obj)[i]);
} }
} }
if (RCLASS_CONST_TBL(obj)) {
rb_id_table_foreach_values(RCLASS_CONST_TBL(obj), mark_const_table_i, objspace);
}
gc_mark_internal(RCLASS_EXT(obj)->classpath);
break; break;
case T_ICLASS: case T_ICLASS:
if (RICLASS_OWNS_M_TBL_P(obj)) { foreach_args.objspace = objspace;
mark_m_tbl(objspace, RCLASS_M_TBL(obj)); foreach_args.obj = obj;
} rb_class_classext_foreach(obj, gc_mark_classext_iclass, (void *)&foreach_args);
if (RCLASS_SUPER(obj)) {
gc_mark_internal(RCLASS_SUPER(obj));
}
if (RCLASS_INCLUDER(obj)) {
gc_mark_internal(RCLASS_INCLUDER(obj));
}
mark_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
rb_cc_table_mark(obj);
break; break;
case T_ARRAY: case T_ARRAY:
@ -3031,8 +3192,8 @@ rb_gc_mark_children(void *objspace, VALUE obj)
VALUE klass = RBASIC_CLASS(obj); VALUE klass = RBASIC_CLASS(obj);
// Increment max_iv_count if applicable, used to determine size pool allocation // Increment max_iv_count if applicable, used to determine size pool allocation
if (RCLASS_EXT(klass)->max_iv_count < fields_count) { if (RCLASS_MAX_IV_COUNT(klass) < fields_count) {
RCLASS_EXT(klass)->max_iv_count = fields_count; RCLASS_WRITE_MAX_IV_COUNT(klass, fields_count);
} }
} }
@ -3482,12 +3643,10 @@ update_cc_tbl_i(VALUE ccs_ptr, void *objspace)
} }
static void static void
update_cc_tbl(void *objspace, VALUE klass) update_cc_tbl(void *objspace, struct rb_id_table *tbl)
{ {
struct rb_id_table *tbl = RCLASS_CC_TBL(klass); if (!tbl) return;
if (tbl) { rb_id_table_foreach_values(tbl, update_cc_tbl_i, objspace);
rb_id_table_foreach_values(tbl, update_cc_tbl_i, objspace);
}
} }
static enum rb_id_table_iterator_result static enum rb_id_table_iterator_result
@ -3507,16 +3666,14 @@ update_cvc_tbl_i(VALUE cvc_entry, void *objspace)
} }
static void static void
update_cvc_tbl(void *objspace, VALUE klass) update_cvc_tbl(void *objspace, struct rb_id_table *tbl)
{ {
struct rb_id_table *tbl = RCLASS_CVC_TBL(klass); if (!tbl) return;
if (tbl) { rb_id_table_foreach_values(tbl, update_cvc_tbl_i, objspace);
rb_id_table_foreach_values(tbl, update_cvc_tbl_i, objspace);
}
} }
static enum rb_id_table_iterator_result static enum rb_id_table_iterator_result
update_const_table(VALUE value, void *objspace) update_const_tbl_i(VALUE value, void *objspace)
{ {
rb_const_entry_t *ce = (rb_const_entry_t *)value; rb_const_entry_t *ce = (rb_const_entry_t *)value;
@ -3535,35 +3692,93 @@ static void
update_const_tbl(void *objspace, struct rb_id_table *tbl) update_const_tbl(void *objspace, struct rb_id_table *tbl)
{ {
if (!tbl) return; if (!tbl) return;
rb_id_table_foreach_values(tbl, update_const_table, objspace); rb_id_table_foreach_values(tbl, update_const_tbl_i, objspace);
} }
static void static void
update_subclass_entries(void *objspace, rb_subclass_entry_t *entry) update_subclasses(void *objspace, rb_classext_t *ext)
{ {
rb_subclass_entry_t *entry;
rb_subclass_anchor_t *anchor = RCLASSEXT_SUBCLASSES(ext);
if (!anchor) return;
entry = anchor->head;
while (entry) { while (entry) {
UPDATE_IF_MOVED(objspace, entry->klass); if (entry->klass)
UPDATE_IF_MOVED(objspace, entry->klass);
entry = entry->next; entry = entry->next;
} }
} }
static void static void
update_class_ext(void *objspace, rb_classext_t *ext) update_superclasses(rb_objspace_t *objspace, rb_classext_t *ext)
{ {
UPDATE_IF_MOVED(objspace, ext->origin_); size_t array_size = RCLASSEXT_SUPERCLASS_DEPTH(ext);
UPDATE_IF_MOVED(objspace, ext->includer); if (RCLASSEXT_SUPERCLASSES_OWNER(ext)) {
UPDATE_IF_MOVED(objspace, ext->refined_class); if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext))
update_subclass_entries(objspace, ext->subclasses); array_size += 1;
for (size_t i = 0; i < array_size; i++) {
UPDATE_IF_MOVED(objspace, RCLASSEXT_SUPERCLASSES(ext)[i]);
}
}
} }
static void static void
update_superclasses(void *objspace, VALUE obj) update_classext_values(rb_objspace_t *objspace, rb_classext_t *ext)
{ {
if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) { UPDATE_IF_MOVED(objspace, RCLASSEXT_ORIGIN(ext));
for (size_t i = 0; i < RCLASS_SUPERCLASS_DEPTH(obj) + 1; i++) { UPDATE_IF_MOVED(objspace, RCLASSEXT_REFINED_CLASS(ext));
UPDATE_IF_MOVED(objspace, RCLASS_SUPERCLASSES(obj)[i]); UPDATE_IF_MOVED(objspace, RCLASSEXT_INCLUDER(ext));
UPDATE_IF_MOVED(objspace, RCLASSEXT_CLASSPATH(ext));
}
static void
update_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
{
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
VALUE klass = args->klass;
rb_objspace_t *objspace = args->objspace;
if (RCLASSEXT_SUPER(ext)) {
UPDATE_IF_MOVED(objspace, RCLASSEXT_SUPER(ext));
}
update_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
if (args->obj_too_complex) {
gc_ref_update_table_values_only((st_table *)RCLASSEXT_FIELDS(ext));
} else {
// Classext is not copied in this case
for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(klass); i++) {
UPDATE_IF_MOVED(objspace, RCLASSEXT_FIELDS(RCLASS_EXT(klass))[i]);
} }
} }
if (!RCLASSEXT_SHARED_CONST_TBL(ext)) {
update_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
}
update_cc_tbl(objspace, RCLASSEXT_CC_TBL(ext));
update_cvc_tbl(objspace, RCLASSEXT_CVC_TBL(ext));
update_superclasses(objspace, ext);
update_subclasses(objspace, ext);
update_classext_values(objspace, ext);
}
static void
update_iclass_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
{
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
rb_objspace_t *objspace = args->objspace;
if (RCLASSEXT_SUPER(ext)) {
UPDATE_IF_MOVED(objspace, RCLASSEXT_SUPER(ext));
}
update_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
update_m_tbl(objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
update_cc_tbl(objspace, RCLASSEXT_CC_TBL(ext));
update_subclasses(objspace, ext);
update_classext_values(objspace, ext);
} }
extern rb_symbols_t ruby_global_symbols; extern rb_symbols_t ruby_global_symbols;
@ -3884,6 +4099,8 @@ rb_gc_update_vm_references(void *objspace)
void void
rb_gc_update_object_references(void *objspace, VALUE obj) rb_gc_update_object_references(void *objspace, VALUE obj)
{ {
struct classext_foreach_args args;
switch (BUILTIN_TYPE(obj)) { switch (BUILTIN_TYPE(obj)) {
case T_CLASS: case T_CLASS:
if (FL_TEST_RAW(obj, FL_SINGLETON)) { if (FL_TEST_RAW(obj, FL_SINGLETON)) {
@ -3891,39 +4108,15 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
} }
// Continue to the shared T_CLASS/T_MODULE // Continue to the shared T_CLASS/T_MODULE
case T_MODULE: case T_MODULE:
if (RCLASS_SUPER((VALUE)obj)) { args.klass = obj;
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super); args.obj_too_complex = rb_shape_obj_too_complex_p(obj);
} args.objspace = objspace;
update_m_tbl(objspace, RCLASS_M_TBL(obj)); rb_class_classext_foreach(obj, update_classext, (void *)&args);
update_cc_tbl(objspace, obj);
update_cvc_tbl(objspace, obj);
update_superclasses(objspace, obj);
if (rb_shape_obj_too_complex_p(obj)) {
gc_ref_update_table_values_only(RCLASS_FIELDS_HASH(obj));
}
else {
for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(obj); i++) {
UPDATE_IF_MOVED(objspace, RCLASS_FIELDS(obj)[i]);
}
}
update_class_ext(objspace, RCLASS_EXT(obj));
update_const_tbl(objspace, RCLASS_CONST_TBL(obj));
UPDATE_IF_MOVED(objspace, RCLASS_EXT(obj)->classpath);
break; break;
case T_ICLASS: case T_ICLASS:
if (RICLASS_OWNS_M_TBL_P(obj)) { args.objspace = objspace;
update_m_tbl(objspace, RCLASS_M_TBL(obj)); rb_class_classext_foreach(obj, update_iclass_classext, (void *)&args);
}
if (RCLASS_SUPER((VALUE)obj)) {
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
}
update_class_ext(objspace, RCLASS_EXT(obj));
update_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
update_cc_tbl(objspace, obj);
break; break;
case T_IMEMO: case T_IMEMO:

19
imemo.c
View File

@ -170,13 +170,14 @@ rb_imemo_memsize(VALUE obj)
static enum rb_id_table_iterator_result static enum rb_id_table_iterator_result
cc_table_mark_i(VALUE ccs_ptr, void *data) cc_table_mark_i(VALUE ccs_ptr, void *data)
{ {
// looks duplicate to mark_cc_entry_i (gc.c)
struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr; struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
VM_ASSERT(vm_ccs_p(ccs)); VM_ASSERT(vm_ccs_p(ccs));
#if VM_CHECK_MODE > 0 #if VM_CHECK_MODE > 0
VALUE klass = (VALUE)data; VALUE klass = (VALUE)data;
VALUE lookup_val; VALUE lookup_val;
VM_ASSERT(rb_id_table_lookup(RCLASS_CC_TBL(klass), ccs->cme->called_id, &lookup_val)); VM_ASSERT(rb_id_table_lookup(RCLASS_WRITABLE_CC_TBL(klass), ccs->cme->called_id, &lookup_val));
VM_ASSERT(lookup_val == ccs_ptr); VM_ASSERT(lookup_val == ccs_ptr);
#endif #endif
@ -200,7 +201,8 @@ cc_table_mark_i(VALUE ccs_ptr, void *data)
void void
rb_cc_table_mark(VALUE klass) rb_cc_table_mark(VALUE klass)
{ {
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); // TODO: delete this (and cc_table_mark_i) if it's ok
struct rb_id_table *cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
if (cc_tbl) { if (cc_tbl) {
rb_id_table_foreach_values(cc_tbl, cc_table_mark_i, (void *)klass); rb_id_table_foreach_values(cc_tbl, cc_table_mark_i, (void *)klass);
} }
@ -492,7 +494,10 @@ cc_table_free_i(VALUE ccs_ptr, void *data)
void void
rb_cc_table_free(VALUE klass) rb_cc_table_free(VALUE klass)
{ {
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); // This can be called and work well only for IClass
// And classext_iclass_free uses rb_cc_tbl_free now.
// TODO: remove this if it's ok
struct rb_id_table *cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
if (cc_tbl) { if (cc_tbl) {
rb_id_table_foreach_values(cc_tbl, cc_table_free_i, (void *)klass); rb_id_table_foreach_values(cc_tbl, cc_table_free_i, (void *)klass);
@ -500,6 +505,14 @@ rb_cc_table_free(VALUE klass)
} }
} }
void
rb_cc_tbl_free(struct rb_id_table *cc_tbl, VALUE klass)
{
if (!cc_tbl) return;
rb_id_table_foreach_values(cc_tbl, cc_table_free_i, (void *)klass);
rb_id_table_free(cc_tbl);
}
void void
rb_imemo_free(VALUE obj) rb_imemo_free(VALUE obj)
{ {

View File

@ -84,6 +84,8 @@ RUBY_EXTERN VALUE rb_cMethod; /**< `Method` class. */
RUBY_EXTERN VALUE rb_cModule; /**< `Module` class. */ RUBY_EXTERN VALUE rb_cModule; /**< `Module` class. */
RUBY_EXTERN VALUE rb_cRefinement; /**< `Refinement` class. */ RUBY_EXTERN VALUE rb_cRefinement; /**< `Refinement` class. */
RUBY_EXTERN VALUE rb_cNameErrorMesg; /**< `NameError::Message` class. */ RUBY_EXTERN VALUE rb_cNameErrorMesg; /**< `NameError::Message` class. */
RUBY_EXTERN VALUE rb_cNamespace; /**< `Namespace` class. */
RUBY_EXTERN VALUE rb_mNamespaceRefiner; /**< `Namespace::Refiner` module. */
RUBY_EXTERN VALUE rb_cNilClass; /**< `NilClass` class. */ RUBY_EXTERN VALUE rb_cNilClass; /**< `NilClass` class. */
RUBY_EXTERN VALUE rb_cNumeric; /**< `Numeric` class. */ RUBY_EXTERN VALUE rb_cNumeric; /**< `Numeric` class. */
RUBY_EXTERN VALUE rb_cProc; /**< `Proc` class. */ RUBY_EXTERN VALUE rb_cProc; /**< `Proc` class. */

View File

@ -77,6 +77,7 @@ rb_call_inits(void)
CALL(Prism); CALL(Prism);
CALL(unicode_version); CALL(unicode_version);
CALL(Set); CALL(Set);
CALL(Namespace);
// enable builtin loading // enable builtin loading
CALL(builtin); CALL(builtin);

View File

@ -10,6 +10,7 @@
*/ */
#include "id.h" #include "id.h"
#include "id_table.h" /* for struct rb_id_table */ #include "id_table.h" /* for struct rb_id_table */
#include "internal/namespace.h" /* for rb_current_namespace */
#include "internal/serial.h" /* for rb_serial_t */ #include "internal/serial.h" /* for rb_serial_t */
#include "internal/static_assert.h" #include "internal/static_assert.h"
#include "internal/variable.h" /* for rb_class_ivar_set */ #include "internal/variable.h" /* for rb_class_ivar_set */
@ -26,6 +27,41 @@
# undef RCLASS_SUPER # undef RCLASS_SUPER
#endif #endif
struct rb_ns_subclasses {
long refcount;
struct st_table *tbl;
};
typedef struct rb_ns_subclasses rb_ns_subclasses_t;
static inline long
rb_ns_subclasses_ref_count(rb_ns_subclasses_t *ns_sub)
{
return ns_sub->refcount;
}
static inline rb_ns_subclasses_t *
rb_ns_subclasses_ref_inc(rb_ns_subclasses_t *ns_sub)
{
ns_sub->refcount++;
return ns_sub;
}
static inline void
rb_ns_subclasses_ref_dec(rb_ns_subclasses_t *ns_sub)
{
ns_sub->refcount--;
if (ns_sub->refcount == 0) {
st_free_table(ns_sub->tbl);
xfree(ns_sub);
}
}
struct rb_subclass_anchor {
rb_ns_subclasses_t *ns_subclasses;
struct rb_subclass_entry *head;
};
typedef struct rb_subclass_anchor rb_subclass_anchor_t;
struct rb_subclass_entry { struct rb_subclass_entry {
VALUE klass; VALUE klass;
struct rb_subclass_entry *next; struct rb_subclass_entry *next;
@ -41,21 +77,36 @@ struct rb_cvar_class_tbl_entry {
}; };
struct rb_classext_struct { struct rb_classext_struct {
const rb_namespace_t *ns;
VALUE super;
VALUE *fields; // Fields are either ivar or other internal properties stored inline VALUE *fields; // Fields are either ivar or other internal properties stored inline
struct rb_id_table *m_tbl;
struct rb_id_table *const_tbl; struct rb_id_table *const_tbl;
struct rb_id_table *callable_m_tbl; struct rb_id_table *callable_m_tbl;
struct rb_id_table *cc_tbl; /* ID -> [[ci1, cc1], [ci2, cc2] ...] */ struct rb_id_table *cc_tbl; /* ID -> [[ci1, cc1], [ci2, cc2] ...] */
struct rb_id_table *cvc_tbl; struct rb_id_table *cvc_tbl;
size_t superclass_depth; size_t superclass_depth;
VALUE *superclasses; VALUE *superclasses;
struct rb_subclass_entry *subclasses;
struct rb_subclass_entry *subclass_entry;
/** /**
* In the case that this is an `ICLASS`, `module_subclasses` points to the link * The head of subclasses is a blank (w/o klass) entry to be referred from anchor (and be never deleted).
* (anchor -> head -> 1st-entry)
*/
struct rb_subclass_anchor *subclasses;
/**
* The `ns_super_subclasses` points the `ns_subclasses` struct to retreive the subclasses
* of the super class in a specific namespace.
* In compaction GCs, collecting a classext should trigger the deletion of a rb_subclass_entry
* from the super's subclasses. But it may be prevented by the read barrier.
* Fetching the super's subclasses for a ns is to avoid the read barrier in that process.
*/
rb_ns_subclasses_t *ns_super_subclasses;
/**
* In the case that this is an `ICLASS`, `ns_module_subclasses` points to the link
* in the module's `subclasses` list that indicates that the klass has been * in the module's `subclasses` list that indicates that the klass has been
* included. Hopefully that makes sense. * included. Hopefully that makes sense.
*/ */
struct rb_subclass_entry *module_subclass_entry; rb_ns_subclasses_t *ns_module_subclasses;
const VALUE origin_; const VALUE origin_;
const VALUE refined_class; const VALUE refined_class;
union { union {
@ -71,6 +122,11 @@ struct rb_classext_struct {
unsigned char variation_count; unsigned char variation_count;
bool permanent_classpath : 1; bool permanent_classpath : 1;
bool cloned : 1; bool cloned : 1;
bool shared_const_tbl : 1;
bool iclass_is_origin : 1;
bool iclass_origin_shared_mtbl : 1;
bool superclasses_owner : 1;
bool superclasses_with_self : 1;
VALUE classpath; VALUE classpath;
}; };
typedef struct rb_classext_struct rb_classext_t; typedef struct rb_classext_struct rb_classext_t;
@ -79,46 +135,394 @@ STATIC_ASSERT(shape_max_variations, SHAPE_MAX_VARIATIONS < (1 << (sizeof(((rb_cl
struct RClass { struct RClass {
struct RBasic basic; struct RBasic basic;
VALUE super; st_table *ns_classext_tbl; // ns_object -> (rb_classext_t *)
struct rb_id_table *m_tbl; bool prime_classext_readable : 1;
bool prime_classext_writable : 1;
}; };
// Assert that classes can be embedded in heaps[2] (which has 160B slot size) /** TODO: Update or remove this assertion
STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass) + sizeof(rb_classext_t) <= 4 * RVALUE_SIZE); * // Assert that classes can be embedded in heaps[2] (which has 160B slot size)
* STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass) + sizeof(rb_classext_t) <= 4 * RVALUE_SIZE);
*/
struct RClass_and_rb_classext_t { struct RClass_and_rb_classext_t {
struct RClass rclass; struct RClass rclass;
rb_classext_t classext; rb_classext_t classext;
}; };
#define RCLASS_PRIME_READABLE_P(obj) (RCLASS(obj)->prime_classext_readable)
#define RCLASS_PRIME_WRITABLE_P(obj) (RCLASS(obj)->prime_classext_writable)
static inline bool RCLASS_SINGLETON_P(VALUE klass);
static inline void RCLASS_SET_CLASSEXT_TABLE(VALUE obj, st_table *tbl);
static inline void RCLASS_SET_PRIME_CLASSEXT_READWRITE(VALUE obj, bool readable, bool writable);
#define RCLASS_EXT(c) (&((struct RClass_and_rb_classext_t*)(c))->classext) #define RCLASS_EXT(c) (&((struct RClass_and_rb_classext_t*)(c))->classext)
#define RCLASS_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl) #define RCLASS_EXT_PRIME_P(ext, c) (&((struct RClass_and_rb_classext_t*)(c))->classext == ext)
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
#define RCLASS_FIELDS(c) (RCLASS_EXT(c)->fields) static inline rb_classext_t * RCLASS_EXT_READABLE_IN_NS(VALUE obj, const rb_namespace_t *ns);
#define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl) static inline rb_classext_t * RCLASS_EXT_READABLE(VALUE obj);
#define RCLASS_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl) static inline rb_classext_t * RCLASS_EXT_WRITABLE_IN_NS(VALUE obj, const rb_namespace_t *ns);
#define RCLASS_CVC_TBL(c) (RCLASS_EXT(c)->cvc_tbl) static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj);
#define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin_)
// Raw accessor
#define RCLASS_CLASSEXT_TBL(klass) (RCLASS(klass)->ns_classext_tbl)
#define RCLASSEXT_NS(ext) (ext->ns)
#define RCLASSEXT_SUPER(ext) (ext->super)
#define RCLASSEXT_FIELDS(ext) (ext->fields)
#define RCLASSEXT_M_TBL(ext) (ext->m_tbl)
#define RCLASSEXT_CONST_TBL(ext) (ext->const_tbl)
#define RCLASSEXT_CALLABLE_M_TBL(ext) (ext->callable_m_tbl)
#define RCLASSEXT_CC_TBL(ext) (ext->cc_tbl)
#define RCLASSEXT_CVC_TBL(ext) (ext->cvc_tbl)
#define RCLASSEXT_SUPERCLASS_DEPTH(ext) (ext->superclass_depth)
#define RCLASSEXT_SUPERCLASSES(ext) (ext->superclasses)
#define RCLASSEXT_SUBCLASSES(ext) (ext->subclasses)
#define RCLASSEXT_NS_SUPER_SUBCLASSES(ext) (ext->ns_super_subclasses)
#define RCLASSEXT_NS_MODULE_SUBCLASSES(ext) (ext->ns_module_subclasses)
#define RCLASSEXT_ORIGIN(ext) (ext->origin_)
#define RCLASSEXT_REFINED_CLASS(ext) (ext->refined_class)
// class.allocator/singleton_class.attached_object are not accessed directly via RCLASSEXT_*
#define RCLASSEXT_INCLUDER(ext) (ext->includer)
#define RCLASSEXT_MAX_IV_COUNT(ext) (ext->max_iv_count)
#define RCLASSEXT_VARIATION_COUNT(ext) (ext->variation_count)
#define RCLASSEXT_PERMANENT_CLASSPATH(ext) (ext->permanent_classpath)
#define RCLASSEXT_CLONED(ext) (ext->cloned)
#define RCLASSEXT_SHARED_CONST_TBL(ext) (ext->shared_const_tbl)
#define RCLASSEXT_ICLASS_IS_ORIGIN(ext) (ext->iclass_is_origin)
#define RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext) (ext->iclass_origin_shared_mtbl)
#define RCLASSEXT_SUPERCLASSES_OWNER(ext) (ext->superclasses_owner)
#define RCLASSEXT_SUPERCLASSES_WITH_SELF(ext) (ext->superclasses_with_self)
#define RCLASSEXT_CLASSPATH(ext) (ext->classpath)
static inline void RCLASSEXT_SET_ORIGIN(rb_classext_t *ext, VALUE klass, VALUE origin);
static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer);
/* Prime classext entry accessor for very specific reason */
#define RCLASS_PRIME_NS(c) (RCLASS_EXT(c)->ns)
// To invalidate CC by inserting&invalidating method entry into tables containing the target cme
// See clear_method_cache_by_id_in_class()
#define RCLASS_PRIME_FIELDS(c) (RCLASS_EXT(c)->fields)
#define RCLASS_PRIME_M_TBL(c) (RCLASS_EXT(c)->m_tbl)
#define RCLASS_PRIME_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl)
#define RCLASS_PRIME_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl)
#define RCLASS_PRIME_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl)
#define RCLASS_M_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT(c)->m_tbl != tbl)
#define RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT(c)->callable_m_tbl != tbl)
#define RCLASS_CC_TBL_NOT_PRIME_P(c, tbl) (RCLASS_EXT(c)->cc_tbl != tbl)
// Read accessor, regarding namespaces
#define RCLASS_SUPER(c) (RCLASS_EXT_READABLE(c)->super)
#define RCLASS_M_TBL(c) (RCLASS_EXT_READABLE(c)->m_tbl)
#define RCLASS_CONST_TBL(c) (RCLASS_EXT_READABLE(c)->const_tbl)
/*
* Both cc_tbl/callable_m_tbl are cache and always be changed when referreed,
* so always should be writable.
*/
// #define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT_READABLE(c)->callable_m_tbl)
// #define RCLASS_CC_TBL(c) (RCLASS_EXT_READABLE(c)->cc_tbl)
#define RCLASS_CVC_TBL(c) (RCLASS_EXT_READABLE(c)->cvc_tbl)
#define RCLASS_SUPERCLASS_DEPTH(c) (RCLASS_EXT_READABLE(c)->superclass_depth)
#define RCLASS_SUPERCLASSES(c) (RCLASS_EXT_READABLE(c)->superclasses)
#define RCLASS_SUPERCLASSES_WITH_SELF_P(c) (RCLASS_EXT_READABLE(c)->superclasses_with_self)
#define RCLASS_SUBCLASSES_X(c) (RCLASS_EXT_READABLE(c)->subclasses)
#define RCLASS_SUBCLASSES_FIRST(c) (RCLASS_EXT_READABLE(c)->subclasses->head->next)
#define RCLASS_ORIGIN(c) (RCLASS_EXT_READABLE(c)->origin_)
#define RICLASS_IS_ORIGIN_P(c) (RCLASS_EXT_READABLE(c)->iclass_is_origin)
#define RCLASS_MAX_IV_COUNT(c) (RCLASS_EXT_READABLE(c)->max_iv_count)
#define RCLASS_VARIATION_COUNT(c) (RCLASS_EXT_READABLE(c)->variation_count)
#define RCLASS_PERMANENT_CLASSPATH_P(c) (RCLASS_EXT_READABLE(c)->permanent_classpath)
#define RCLASS_CLONED_P(c) (RCLASS_EXT_READABLE(c)->cloned)
#define RCLASS_CLASSPATH(c) (RCLASS_EXT_READABLE(c)->classpath)
// namespaces don't make changes on these refined_class/attached_object/includer
#define RCLASS_REFINED_CLASS(c) (RCLASS_EXT(c)->refined_class) #define RCLASS_REFINED_CLASS(c) (RCLASS_EXT(c)->refined_class)
#define RCLASS_INCLUDER(c) (RCLASS_EXT(c)->includer)
#define RCLASS_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->subclass_entry)
#define RCLASS_MODULE_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->module_subclass_entry)
#define RCLASS_SUBCLASSES(c) (RCLASS_EXT(c)->subclasses)
#define RCLASS_SUPERCLASS_DEPTH(c) (RCLASS_EXT(c)->superclass_depth)
#define RCLASS_SUPERCLASSES(c) (RCLASS_EXT(c)->superclasses)
#define RCLASS_ATTACHED_OBJECT(c) (RCLASS_EXT(c)->as.singleton_class.attached_object) #define RCLASS_ATTACHED_OBJECT(c) (RCLASS_EXT(c)->as.singleton_class.attached_object)
#define RCLASS_INCLUDER(c) (RCLASS_EXT(c)->includer)
// Writable classext entries (instead of RCLASS_SET_*) because member data will be operated directly
#define RCLASS_WRITABLE_M_TBL(c) (RCLASS_EXT_WRITABLE(c)->m_tbl)
#define RCLASS_WRITABLE_CONST_TBL(c) (RCLASS_EXT_WRITABLE(c)->const_tbl)
#define RCLASS_WRITABLE_CALLABLE_M_TBL(c) (RCLASS_EXT_WRITABLE(c)->callable_m_tbl)
#define RCLASS_WRITABLE_CC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cc_tbl)
#define RCLASS_WRITABLE_CVC_TBL(c) (RCLASS_EXT_WRITABLE(c)->cvc_tbl)
#define RCLASS_WRITABLE_SUBCLASSES(c) (RCLASS_EXT_WRITABLE(c)->subclasses)
static inline void RCLASS_SET_SUPER(VALUE klass, VALUE super);
static inline void RCLASS_WRITE_SUPER(VALUE klass, VALUE super);
static inline st_table * RCLASS_FIELDS_HASH(VALUE obj);
static inline st_table * RCLASS_WRITABLE_FIELDS_HASH(VALUE obj);
static inline void RCLASS_SET_FIELDS_HASH(VALUE obj, const st_table *table);
static inline void RCLASS_WRITE_FIELDS_HASH(VALUE obj, const st_table *table);
static inline uint32_t RCLASS_FIELDS_COUNT(VALUE obj);
static inline void RCLASS_SET_M_TBL(VALUE klass, struct rb_id_table *table);
static inline void RCLASS_WRITE_M_TBL(VALUE klass, struct rb_id_table *table);
static inline void RCLASS_SET_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared);
static inline void RCLASS_WRITE_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared);
static inline void RCLASS_WRITE_CALLABLE_M_TBL(VALUE klass, struct rb_id_table *table);
static inline void RCLASS_WRITE_CC_TBL(VALUE klass, struct rb_id_table *table);
static inline void RCLASS_SET_CVC_TBL(VALUE klass, struct rb_id_table *table);
static inline void RCLASS_WRITE_CVC_TBL(VALUE klass, struct rb_id_table *table);
static inline void RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool owns_it, bool with_self);
static inline void RCLASS_SET_SUBCLASSES(VALUE klass, rb_subclass_anchor_t *anchor);
static inline void RCLASS_WRITE_SUBCLASSES(VALUE klass, rb_subclass_anchor_t *anchor);
static inline void RCLASS_WRITE_NS_SUPER_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses);
static inline void RCLASS_WRITE_NS_MODULE_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses);
static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin);
static inline void RCLASS_WRITE_ORIGIN(VALUE klass, VALUE origin);
static inline void RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass);
static inline void RICLASS_WRITE_ORIGIN_SHARED_MTBL(VALUE iclass);
static inline bool RICLASS_OWNS_M_TBL_P(VALUE iclass);
static inline void RCLASS_SET_REFINED_CLASS(VALUE klass, VALUE refined);
static inline rb_alloc_func_t RCLASS_ALLOCATOR(VALUE klass);
static inline void RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator);
static inline VALUE RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object);
static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass);
static inline void RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count);
static inline void RCLASS_WRITE_MAX_IV_COUNT(VALUE klass, attr_index_t count);
static inline void RCLASS_SET_CLONED(VALUE klass, bool cloned);
static inline void RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent);
static inline void RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent);
#define RCLASS_IS_ROOT FL_USER0 #define RCLASS_IS_ROOT FL_USER0
#define RICLASS_IS_ORIGIN FL_USER0 // #define RICLASS_IS_ORIGIN FL_USER0 // TODO: Delete this
#define RCLASS_SUPERCLASSES_INCLUDE_SELF FL_USER2 // #define RCLASS_SUPERCLASSES_INCLUD_SELF FL_USER2 // TODO: Delete this
#define RICLASS_ORIGIN_SHARED_MTBL FL_USER3 // #define RICLASS_ORIGIN_SHARED_MTBL FL_USER3 // TODO: Delete this
VALUE rb_class_debug_duplicate_classext(VALUE klass, VALUE namespace); // TODO: only for development
VALUE rb_class_debug_dump_all_classext(VALUE klass); // TODO: only for development
VALUE rb_class_debug_dump_all_classext_super(VALUE klass, VALUE upto); // TODO: only for development
void rb_class_debug_print_classext(const char *label, const char *opt, VALUE klass);
VALUE rb_class_debug_print_module(VALUE);
/* class.c */
rb_classext_t * rb_class_duplicate_classext(rb_classext_t *orig, VALUE obj, const rb_namespace_t *ns);
void rb_class_ensure_writable(VALUE obj);
static inline int
RCLASS_SET_NAMESPACE_CLASSEXT(VALUE obj, const rb_namespace_t *ns, rb_classext_t *ext)
{
int tbl_created = 0;
st_table *tbl = RCLASS_CLASSEXT_TBL(obj);
VM_ASSERT(NAMESPACE_USER_P(ns)); // non-prime classext is only for user namespace, with ns_object
VM_ASSERT(RCLASSEXT_NS(ext) == ns);
if (!tbl) {
RCLASS_CLASSEXT_TBL(obj) = tbl = st_init_numtable_with_size(1);
tbl_created = 1;
}
rb_st_insert(tbl, (st_data_t)ns->ns_object, (st_data_t)ext);
return tbl_created;
}
static inline void
RCLASS_SET_PRIME_CLASSEXT_READWRITE(VALUE obj, bool readable, bool writable)
{
RCLASS(obj)->prime_classext_readable = readable;
RCLASS(obj)->prime_classext_writable = writable;
}
static inline rb_classext_t *
RCLASS_EXT_TABLE_LOOKUP_INTERNAL(VALUE obj, const rb_namespace_t *ns)
{
st_data_t classext_ptr;
st_table *classext_tbl = RCLASS_CLASSEXT_TBL(obj);
if (classext_tbl) {
if (rb_st_lookup(classext_tbl, (st_data_t)ns->ns_object, &classext_ptr)) {
return (rb_classext_t *)classext_ptr;
}
}
return NULL;
}
static inline rb_classext_t *
RCLASS_EXT_READABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
{
rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns);
if (ext)
return ext;
// Classext for the ns not found. Refer the prime one instead.
return RCLASS_EXT(obj);
}
static inline rb_classext_t *
RCLASS_EXT_READABLE_IN_NS(VALUE obj, const rb_namespace_t *ns)
{
if (!ns
|| NAMESPACE_BUILTIN_P(ns)
|| RCLASS(obj)->prime_classext_readable) {
return RCLASS_EXT(obj);
}
return RCLASS_EXT_READABLE_LOOKUP(obj, ns);
}
static inline rb_classext_t *
RCLASS_EXT_READABLE(VALUE obj)
{
const rb_namespace_t *ns;
if (RCLASS(obj)->prime_classext_readable) {
return RCLASS_EXT(obj);
}
// delay namespace loading to optimize for unmodified classes
ns = rb_current_namespace();
if (!ns || NAMESPACE_BUILTIN_P(ns)) {
return RCLASS_EXT(obj);
}
return RCLASS_EXT_READABLE_LOOKUP(obj, ns);
}
static inline rb_classext_t *
RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
{
rb_classext_t *ext;
int table_created = 0;
ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns);
if (ext)
return ext;
if (!rb_shape_obj_too_complex_p(obj)) {
// TODO: Handle object shapes properly
rb_evict_ivars_to_hash(obj); // fallback to ivptr for ivars from shapes
}
RB_VM_LOCK_ENTER();
{
// re-check the classext is not created to avoid the multi-thread race
ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns);
if (!ext) {
ext = rb_class_duplicate_classext(RCLASS_EXT(obj), obj, ns);
table_created = RCLASS_SET_NAMESPACE_CLASSEXT(obj, ns, ext);
if (table_created) {
RCLASS_SET_PRIME_CLASSEXT_READWRITE(obj, false, false);
}
}
}
RB_VM_LOCK_LEAVE();
return ext;
}
static inline rb_classext_t *
RCLASS_EXT_WRITABLE_IN_NS(VALUE obj, const rb_namespace_t *ns)
{
if (!ns
|| NAMESPACE_BUILTIN_P(ns)
|| RCLASS(obj)->prime_classext_writable) {
return RCLASS_EXT(obj);
}
return RCLASS_EXT_WRITABLE_LOOKUP(obj, ns);
}
static inline rb_classext_t *
RCLASS_EXT_WRITABLE(VALUE obj)
{
const rb_namespace_t *ns;
if (RCLASS(obj)->prime_classext_writable) {
return RCLASS_EXT(obj);
}
// delay namespace loading to optimize for unmodified classes
ns = rb_current_namespace();
if (!ns || NAMESPACE_BUILTIN_P(ns)) {
// If no namespace is specified, Ruby VM is in bootstrap
// and the clean class definition is under construction.
return RCLASS_EXT(obj);
}
return RCLASS_EXT_WRITABLE_LOOKUP(obj, ns);
}
static inline void
RCLASSEXT_SET_ORIGIN(rb_classext_t *ext, VALUE klass, VALUE origin)
{
RB_OBJ_WRITE(klass, &(RCLASSEXT_ORIGIN(ext)), origin);
}
static inline void
RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE includer)
{
RB_OBJ_WRITE(klass, &(RCLASSEXT_INCLUDER(ext)), includer);
}
/* class.c */
typedef void rb_class_classext_foreach_callback_func(rb_classext_t *classext, bool is_prime, VALUE namespace, void *arg);
void rb_class_classext_foreach(VALUE klass, rb_class_classext_foreach_callback_func *func, void *arg);
void rb_class_subclass_add(VALUE super, VALUE klass);
void rb_class_remove_from_super_subclasses(VALUE);
void rb_class_remove_from_module_subclasses(VALUE);
void rb_class_classext_free_subclasses(rb_classext_t *, VALUE);
void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE);
void rb_class_detach_subclasses(VALUE);
void rb_class_detach_module_subclasses(VALUE);
void rb_class_update_superclasses(VALUE);
size_t rb_class_superclasses_memsize(VALUE);
void rb_class_remove_subclass_head(VALUE);
int rb_singleton_class_internal_p(VALUE sklass);
VALUE rb_class_set_super(VALUE klass, VALUE super);
VALUE rb_class_boot(VALUE);
VALUE rb_class_s_alloc(VALUE klass);
VALUE rb_module_s_alloc(VALUE klass);
void rb_module_set_initialized(VALUE module);
void rb_module_check_initializable(VALUE module);
VALUE rb_make_metaclass(VALUE, VALUE);
VALUE rb_include_class_new(VALUE, VALUE);
VALUE rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super);
VALUE rb_obj_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_private_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_public_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_class_undefined_instance_methods(VALUE mod);
VALUE rb_special_singleton_class(VALUE);
VALUE rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach);
VALUE rb_singleton_class_get(VALUE obj);
void rb_undef_methods_from(VALUE klass, VALUE super);
VALUE rb_class_inherited(VALUE, VALUE);
VALUE rb_keyword_error_new(const char *, VALUE);
RUBY_SYMBOL_EXPORT_BEGIN
/* for objspace */
VALUE rb_class_super_of(VALUE klass);
VALUE rb_class_singleton_p(VALUE klass);
unsigned char rb_class_variation_count(VALUE klass);
RUBY_SYMBOL_EXPORT_END
static inline bool
RCLASS_SINGLETON_P(VALUE klass)
{
return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON);
}
static inline void
RCLASS_SET_SUPER(VALUE klass, VALUE super)
{
RB_OBJ_WRITE(klass, &RCLASSEXT_SUPER(RCLASS_EXT(klass)), super);
}
static inline void
RCLASS_WRITE_SUPER(VALUE klass, VALUE super)
{
RB_OBJ_WRITE(klass, &RCLASSEXT_SUPER(RCLASS_EXT_WRITABLE(klass)), super);
}
static inline st_table * static inline st_table *
RCLASS_FIELDS_HASH(VALUE obj) RCLASS_FIELDS_HASH(VALUE obj)
{ {
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
return (st_table *)RCLASS_FIELDS(obj); return (st_table *)RCLASSEXT_FIELDS(RCLASS_EXT_READABLE(obj));
}
static inline st_table *
RCLASS_WRITABLE_FIELDS_HASH(VALUE obj)
{
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
return (st_table *)RCLASSEXT_FIELDS(RCLASS_EXT_WRITABLE(obj));
} }
static inline void static inline void
@ -126,7 +530,15 @@ RCLASS_SET_FIELDS_HASH(VALUE obj, const st_table *tbl)
{ {
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
RCLASS_FIELDS(obj) = (VALUE *)tbl; RCLASSEXT_FIELDS(RCLASS_EXT(obj)) = (VALUE *)tbl;
}
static inline void
RCLASS_WRITE_FIELDS_HASH(VALUE obj, const st_table *tbl)
{
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
RCLASSEXT_FIELDS(RCLASS_EXT_WRITABLE(obj)) = (VALUE *)tbl;
} }
static inline uint32_t static inline uint32_t
@ -155,51 +567,62 @@ static inline void
RCLASS_SET_M_TBL(VALUE klass, struct rb_id_table *table) RCLASS_SET_M_TBL(VALUE klass, struct rb_id_table *table)
{ {
RUBY_ASSERT(!RB_OBJ_PROMOTED(klass)); RUBY_ASSERT(!RB_OBJ_PROMOTED(klass));
RCLASS_M_TBL(klass) = table; RCLASSEXT_M_TBL(RCLASS_EXT(klass)) = table;
} }
/* class.c */ static inline void
void rb_class_subclass_add(VALUE super, VALUE klass); RCLASS_WRITE_M_TBL(VALUE klass, struct rb_id_table *table)
void rb_class_remove_from_super_subclasses(VALUE);
void rb_class_update_superclasses(VALUE);
size_t rb_class_superclasses_memsize(VALUE);
void rb_class_remove_subclass_head(VALUE);
int rb_singleton_class_internal_p(VALUE sklass);
VALUE rb_class_boot(VALUE);
VALUE rb_class_s_alloc(VALUE klass);
VALUE rb_module_s_alloc(VALUE klass);
void rb_module_set_initialized(VALUE module);
void rb_module_check_initializable(VALUE module);
VALUE rb_make_metaclass(VALUE, VALUE);
VALUE rb_include_class_new(VALUE, VALUE);
void rb_class_foreach_subclass(VALUE klass, void (*f)(VALUE, VALUE), VALUE);
void rb_class_detach_subclasses(VALUE);
void rb_class_detach_module_subclasses(VALUE);
void rb_class_remove_from_module_subclasses(VALUE);
VALUE rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super);
VALUE rb_obj_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_protected_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_private_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_obj_public_methods(int argc, const VALUE *argv, VALUE obj);
VALUE rb_class_undefined_instance_methods(VALUE mod);
VALUE rb_special_singleton_class(VALUE);
VALUE rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach);
VALUE rb_singleton_class_get(VALUE obj);
void rb_undef_methods_from(VALUE klass, VALUE super);
static inline void RCLASS_SET_ORIGIN(VALUE klass, VALUE origin);
static inline void RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass);
static inline VALUE RCLASS_SUPER(VALUE klass);
static inline VALUE RCLASS_SET_SUPER(VALUE klass, VALUE super);
static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass);
VALUE rb_class_inherited(VALUE, VALUE);
VALUE rb_keyword_error_new(const char *, VALUE);
static inline bool
RCLASS_SINGLETON_P(VALUE klass)
{ {
return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON); RUBY_ASSERT(!RB_OBJ_PROMOTED(klass));
RCLASSEXT_M_TBL(RCLASS_EXT_WRITABLE(klass)) = table;
}
static inline void
RCLASS_SET_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared)
{
rb_classext_t *ext = RCLASS_EXT(klass);
RCLASSEXT_CONST_TBL(ext) = table;
if (shared)
RCLASSEXT_SHARED_CONST_TBL(ext) = true;
}
static inline void
RCLASS_WRITE_CONST_TBL(VALUE klass, struct rb_id_table *table, bool shared)
{
rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
RCLASSEXT_CONST_TBL(ext) = table;
if (shared)
RCLASSEXT_SHARED_CONST_TBL(ext) = true;
}
static inline void
RCLASS_WRITE_CALLABLE_M_TBL(VALUE klass, struct rb_id_table *table)
{
RCLASSEXT_CALLABLE_M_TBL(RCLASS_EXT_WRITABLE(klass)) = table;
}
static inline void
RCLASS_WRITE_CC_TBL(VALUE klass, struct rb_id_table *table)
{
RCLASSEXT_CC_TBL(RCLASS_EXT_WRITABLE(klass)) = table;
}
static inline void
RCLASS_SET_CVC_TBL(VALUE klass, struct rb_id_table *table)
{
RCLASSEXT_CVC_TBL(RCLASS_EXT(klass)) = table;
}
static inline void
RCLASS_WRITE_CVC_TBL(VALUE klass, struct rb_id_table *table)
{
RCLASSEXT_CVC_TBL(RCLASS_EXT_WRITABLE(klass)) = table;
}
static inline void
RCLASS_SET_REFINED_CLASS(VALUE klass, VALUE refined)
{
RB_OBJ_WRITE(klass, &RCLASSEXT_REFINED_CLASS(RCLASS_EXT(klass)), refined);
} }
static inline rb_alloc_func_t static inline rb_alloc_func_t
@ -215,26 +638,42 @@ static inline void
RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator) RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator)
{ {
assert(!RCLASS_SINGLETON_P(klass)); assert(!RCLASS_SINGLETON_P(klass));
RCLASS_EXT(klass)->as.class.allocator = allocator; RCLASS_EXT(klass)->as.class.allocator = allocator; // Allocator is set only on the initial definition
} }
static inline void static inline void
RCLASS_SET_ORIGIN(VALUE klass, VALUE origin) RCLASS_SET_ORIGIN(VALUE klass, VALUE origin)
{ {
RB_OBJ_WRITE(klass, &RCLASS_ORIGIN(klass), origin); rb_classext_t *ext = RCLASS_EXT(klass);
if (klass != origin) FL_SET(origin, RICLASS_IS_ORIGIN); RB_OBJ_WRITE(klass, &RCLASSEXT_ORIGIN(ext), origin);
if (klass != origin) RCLASSEXT_ICLASS_IS_ORIGIN(RCLASS_EXT_WRITABLE(origin)) = true;
}
static inline void
RCLASS_WRITE_ORIGIN(VALUE klass, VALUE origin)
{
rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
RB_OBJ_WRITE(klass, &RCLASSEXT_ORIGIN(ext), origin);
if (klass != origin) RCLASSEXT_ICLASS_IS_ORIGIN(RCLASS_EXT_WRITABLE(origin)) = true;
} }
static inline void static inline void
RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass) RICLASS_SET_ORIGIN_SHARED_MTBL(VALUE iclass)
{ {
FL_SET(iclass, RICLASS_ORIGIN_SHARED_MTBL); RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(RCLASS_EXT(iclass)) = true;
}
static inline void
RICLASS_WRITE_ORIGIN_SHARED_MTBL(VALUE iclass)
{
RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(RCLASS_EXT_WRITABLE(iclass)) = true;
} }
static inline bool static inline bool
RICLASS_OWNS_M_TBL_P(VALUE iclass) RICLASS_OWNS_M_TBL_P(VALUE iclass)
{ {
return FL_TEST_RAW(iclass, RICLASS_IS_ORIGIN | RICLASS_ORIGIN_SHARED_MTBL) == RICLASS_IS_ORIGIN; rb_classext_t *ext = RCLASS_EXT_READABLE(iclass);
return RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext);
} }
static inline void static inline void
@ -243,32 +682,61 @@ RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass)
RB_OBJ_WRITE(iclass, &RCLASS_INCLUDER(iclass), klass); RB_OBJ_WRITE(iclass, &RCLASS_INCLUDER(iclass), klass);
} }
static inline VALUE static inline void
RCLASS_SUPER(VALUE klass) RCLASS_WRITE_SUPERCLASSES(VALUE klass, size_t depth, VALUE *superclasses, bool owns_it, bool with_self)
{ {
return RCLASS(klass)->super; rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
RCLASSEXT_SUPERCLASS_DEPTH(ext) = depth;
RCLASSEXT_SUPERCLASSES(ext) = superclasses;
RCLASSEXT_SUPERCLASSES_OWNER(ext) = owns_it;
RCLASSEXT_SUPERCLASSES_WITH_SELF(ext) = with_self;
} }
static inline VALUE static inline void
RCLASS_SET_SUPER(VALUE klass, VALUE super) RCLASS_SET_SUBCLASSES(VALUE klass, struct rb_subclass_anchor *anchor)
{ {
if (super) { rb_classext_t *ext = RCLASS_EXT(klass);
rb_class_remove_from_super_subclasses(klass); RCLASSEXT_SUBCLASSES(ext) = anchor;
rb_class_subclass_add(super, klass); }
}
RB_OBJ_WRITE(klass, &RCLASS(klass)->super, super); static inline void
rb_class_update_superclasses(klass); RCLASS_WRITE_NS_SUPER_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses)
return super; {
rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
if (RCLASSEXT_NS_SUPER_SUBCLASSES(ext))
rb_ns_subclasses_ref_dec(RCLASSEXT_NS_SUPER_SUBCLASSES(ext));
RCLASSEXT_NS_SUPER_SUBCLASSES(ext) = rb_ns_subclasses_ref_inc(ns_subclasses);
}
static inline void
RCLASS_WRITE_NS_MODULE_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses)
{
rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
if (RCLASSEXT_NS_MODULE_SUBCLASSES(ext))
rb_ns_subclasses_ref_dec(RCLASSEXT_NS_MODULE_SUBCLASSES(ext));
RCLASSEXT_NS_MODULE_SUBCLASSES(ext) = rb_ns_subclasses_ref_inc(ns_subclasses);
} }
static inline void static inline void
RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent) RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent)
{ {
rb_classext_t *ext = RCLASS_EXT_READABLE(klass);
assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE); assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE);
assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING); assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING);
RB_OBJ_WRITE(klass, &(RCLASS_EXT(klass)->classpath), classpath); RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath);
RCLASS_EXT(klass)->permanent_classpath = permanent; RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent;
}
static inline void
RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool permanent)
{
rb_classext_t *ext = RCLASS_EXT_WRITABLE(klass);
assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE);
assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING);
RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath);
RCLASSEXT_PERMANENT_CLASSPATH(ext) = permanent;
} }
static inline VALUE static inline VALUE
@ -280,4 +748,22 @@ RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object)
return attached_object; return attached_object;
} }
static inline void
RCLASS_SET_MAX_IV_COUNT(VALUE klass, attr_index_t count)
{
RCLASSEXT_MAX_IV_COUNT(RCLASS_EXT(klass)) = count;
}
static inline void
RCLASS_WRITE_MAX_IV_COUNT(VALUE klass, attr_index_t count)
{
RCLASSEXT_MAX_IV_COUNT(RCLASS_EXT_WRITABLE(klass)) = count;
}
static inline void
RCLASS_SET_CLONED(VALUE klass, bool cloned)
{
RCLASSEXT_CLONED(RCLASS_EXT(klass)) = cloned;
}
#endif /* INTERNAL_CLASS_H */ #endif /* INTERNAL_CLASS_H */

View File

@ -16,11 +16,18 @@
#define id_status ruby_static_id_status #define id_status ruby_static_id_status
/* eval.c */ /* eval.c */
struct rb_refinements_data {
VALUE refinement;
VALUE refinements;
};
extern ID ruby_static_id_signo; extern ID ruby_static_id_signo;
extern ID ruby_static_id_status; extern ID ruby_static_id_status;
VALUE rb_refinement_module_get_refined_class(VALUE module); VALUE rb_refinement_module_get_refined_class(VALUE module);
void rb_class_modify_check(VALUE); void rb_class_modify_check(VALUE);
NORETURN(VALUE rb_f_raise(int argc, VALUE *argv)); NORETURN(VALUE rb_f_raise(int argc, VALUE *argv));
void rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass);
void rb_vm_using_module(VALUE module);
VALUE rb_top_main_class(const char *method); VALUE rb_top_main_class(const char *method);
/* eval_error.c */ /* eval_error.c */

View File

@ -10,6 +10,7 @@
*/ */
#include "ruby/internal/config.h" #include "ruby/internal/config.h"
#include <stddef.h> /* for size_t */ #include <stddef.h> /* for size_t */
#include "id_table.h"
#include "internal/array.h" /* for rb_ary_hidden_new_fill */ #include "internal/array.h" /* for rb_ary_hidden_new_fill */
#include "ruby/internal/stdbool.h" /* for bool */ #include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/ruby.h" /* for rb_block_call_func_t */ #include "ruby/ruby.h" /* for rb_block_call_func_t */
@ -24,6 +25,7 @@
#define IMEMO_FL_USER3 FL_USER7 #define IMEMO_FL_USER3 FL_USER7
#define IMEMO_FL_USER4 FL_USER8 #define IMEMO_FL_USER4 FL_USER8
#define IMEMO_FL_USER5 FL_USER9 #define IMEMO_FL_USER5 FL_USER9
#define IMEMO_FL_USER6 FL_USER10
enum imemo_type { enum imemo_type {
imemo_env = 0, imemo_env = 0,
@ -149,6 +151,7 @@ size_t rb_imemo_memsize(VALUE obj);
void rb_cc_table_mark(VALUE klass); void rb_cc_table_mark(VALUE klass);
void rb_imemo_mark_and_move(VALUE obj, bool reference_updating); void rb_imemo_mark_and_move(VALUE obj, bool reference_updating);
void rb_cc_table_free(VALUE klass); void rb_cc_table_free(VALUE klass);
void rb_cc_tbl_free(struct rb_id_table *cc_tbl, VALUE klass);
void rb_imemo_free(VALUE obj); void rb_imemo_free(VALUE obj);
RUBY_SYMBOL_EXPORT_BEGIN RUBY_SYMBOL_EXPORT_BEGIN

View File

@ -12,6 +12,8 @@
/* load.c */ /* load.c */
VALUE rb_get_expanded_load_path(void); VALUE rb_get_expanded_load_path(void);
VALUE rb_load_entrypoint(VALUE args);
VALUE rb_require_relative_entrypoint(VALUE fname);
int rb_require_internal(VALUE fname); int rb_require_internal(VALUE fname);
NORETURN(void rb_load_fail(VALUE, const char*)); NORETURN(void rb_load_fail(VALUE, const char*));

80
internal/namespace.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef INTERNAL_NAMESPACE_H /*-*-C-*-vi:se ft=c:*/
#define INTERNAL_NAMESPACE_H
#include "ruby/ruby.h" /* for VALUE */
/**
* @author Satoshi Tagomori <tagomoris@gmail.com>
* @copyright This file is a part of the programming language Ruby.
* Permission is hereby granted, to either redistribute and/or
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
* @brief Internal header for Fiber.
*/
struct rb_namespace_struct {
/*
* To retrieve Namespace object that provides #require and so on.
* That is used from load.c, etc., that uses rb_namespace_t internally.
*/
VALUE ns_object;
long ns_id; // namespace id to generate ext filenames
VALUE top_self;
VALUE load_path;
VALUE load_path_snapshot;
VALUE load_path_check_cache;
VALUE expanded_load_path;
VALUE loaded_features;
VALUE loaded_features_snapshot;
VALUE loaded_features_realpaths;
VALUE loaded_features_realpath_map;
struct st_table *loaded_features_index;
struct st_table *loading_table;
VALUE ruby_dln_libmap;
VALUE gvar_tbl;
bool is_builtin;
bool is_user;
bool is_optional;
};
typedef struct rb_namespace_struct rb_namespace_t;
#define NAMESPACE_BUILTIN_P(ns) (ns && ns->is_builtin)
#define NAMESPACE_USER_P(ns) (ns && ns->is_user)
#define NAMESPACE_OPTIONAL_P(ns) (ns && ns->is_optional)
#define NAMESPACE_MAIN_P(ns) (ns && ns->is_user && !ns->is_optional)
#define NAMESPACE_METHOD_DEFINITION(mdef) (mdef ? mdef->ns : NULL)
#define NAMESPACE_METHOD_ENTRY(me) (me ? NAMESPACE_METHOD_DEFINITION(me->def) : NULL)
#define NAMESPACE_CC(cc) (cc ? NAMESPACE_METHOD_ENTRY(cc->cme_) : NULL)
#define NAMESPACE_CC_ENTRIES(ccs) (ccs ? NAMESPACE_METHOD_ENTRY(ccs->cme) : NULL)
int rb_namespace_available(void);
void rb_namespace_enable_builtin(void);
void rb_namespace_disable_builtin(void);
void rb_namespace_push_loading_namespace(const rb_namespace_t *);
void rb_namespace_pop_loading_namespace(const rb_namespace_t *);
rb_namespace_t * rb_root_namespace(void);
const rb_namespace_t *rb_builtin_namespace(void);
rb_namespace_t * rb_main_namespace(void);
const rb_namespace_t * rb_definition_namespace(void);
const rb_namespace_t * rb_loading_namespace(void);
const rb_namespace_t * rb_current_namespace(void);
VALUE rb_current_namespace_details(VALUE);
void rb_namespace_entry_mark(void *);
rb_namespace_t * rb_get_namespace_t(VALUE ns);
VALUE rb_get_namespace_object(rb_namespace_t *ns);
typedef VALUE namespace_exec_func(VALUE arg);
VALUE rb_namespace_exec(const rb_namespace_t *ns, namespace_exec_func *func, VALUE arg);
VALUE rb_namespace_local_extension(VALUE namespace, VALUE fname, VALUE path);
void rb_initialize_main_namespace(void);
bool rb_namespace_debug_mode_p(void);
#endif /* INTERNAL_NAMESPACE_H */

View File

@ -23,11 +23,13 @@ VALUE rb_search_class_path(VALUE);
VALUE rb_attr_delete(VALUE, ID); VALUE rb_attr_delete(VALUE, ID);
void rb_autoload_str(VALUE mod, ID id, VALUE file); void rb_autoload_str(VALUE mod, ID id, VALUE file);
VALUE rb_autoload_at_p(VALUE, ID, int); VALUE rb_autoload_at_p(VALUE, ID, int);
void rb_autoload_copy_table_for_namespace(st_table *, const rb_namespace_t *);
NORETURN(VALUE rb_mod_const_missing(VALUE,VALUE)); NORETURN(VALUE rb_mod_const_missing(VALUE,VALUE));
rb_gvar_getter_t *rb_gvar_getter_function_of(ID); rb_gvar_getter_t *rb_gvar_getter_function_of(ID);
rb_gvar_setter_t *rb_gvar_setter_function_of(ID); rb_gvar_setter_t *rb_gvar_setter_function_of(ID);
void rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_); void rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_);
void rb_gvar_ractor_local(const char *name); void rb_gvar_ractor_local(const char *name);
void rb_gvar_namespace_ready(const char *name);
/** /**
* Sets the name of a module. * Sets the name of a module.

View File

@ -77,6 +77,7 @@ void rb_check_stack_overflow(void);
#define RB_BLOCK_NO_USE_PACKED_ARGS 2 #define RB_BLOCK_NO_USE_PACKED_ARGS 2
VALUE rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t bl_proc, VALUE data2, long flags); VALUE rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t bl_proc, VALUE data2, long flags);
struct vm_ifunc *rb_current_ifunc(void); struct vm_ifunc *rb_current_ifunc(void);
VALUE rb_gccct_clear_table(VALUE);
#if USE_YJIT #if USE_YJIT
/* vm_exec.c */ /* vm_exec.c */

2
iseq.c
View File

@ -2919,7 +2919,7 @@ rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq)
attr_index_t count = (attr_index_t)rb_id_table_size(iv_names); attr_index_t count = (attr_index_t)rb_id_table_size(iv_names);
VALUE superclass = rb_class_superclass(klass); VALUE superclass = rb_class_superclass(klass);
count += RCLASS_EXT(superclass)->max_iv_count; count += RCLASSEXT_MAX_IV_COUNT(RCLASS_EXT_READABLE(superclass));
rb_id_table_free(iv_names); rb_id_table_free(iv_names);

View File

@ -219,6 +219,7 @@ class Gem::Package
# Adds a checksum for each entry in the gem to checksums.yaml.gz. # Adds a checksum for each entry in the gem to checksums.yaml.gz.
def add_checksums(tar) def add_checksums(tar)
require 'psych'
Gem.load_yaml Gem.load_yaml
checksums_by_algorithm = Hash.new {|h, algorithm| h[algorithm] = {} } checksums_by_algorithm = Hash.new {|h, algorithm| h[algorithm] = {} }
@ -552,6 +553,7 @@ EOM
# Reads and loads checksums.yaml.gz from the tar file +gem+ # Reads and loads checksums.yaml.gz from the tar file +gem+
def read_checksums(gem) def read_checksums(gem)
require_relative 'safe_yaml'
Gem.load_yaml Gem.load_yaml
@checksums = gem.seek "checksums.yaml.gz" do |entry| @checksums = gem.seek "checksums.yaml.gz" do |entry|

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'psych'
module Gem module Gem
### ###
# This module is used for safely loading YAML specs from a gem. The # This module is used for safely loading YAML specs from a gem. The

452
load.c
View File

@ -7,9 +7,11 @@
#include "internal.h" #include "internal.h"
#include "internal/dir.h" #include "internal/dir.h"
#include "internal/error.h" #include "internal/error.h"
#include "internal/eval.h"
#include "internal/file.h" #include "internal/file.h"
#include "internal/hash.h" #include "internal/hash.h"
#include "internal/load.h" #include "internal/load.h"
#include "internal/namespace.h"
#include "internal/ruby_parser.h" #include "internal/ruby_parser.h"
#include "internal/thread.h" #include "internal/thread.h"
#include "internal/variable.h" #include "internal/variable.h"
@ -19,6 +21,7 @@
#include "ruby/encoding.h" #include "ruby/encoding.h"
#include "ruby/util.h" #include "ruby/util.h"
#include "ractor_core.h" #include "ractor_core.h"
#include "vm_core.h"
static VALUE ruby_dln_libmap; static VALUE ruby_dln_libmap;
@ -36,6 +39,38 @@ static VALUE ruby_dln_libmap;
# error Need integer for VALUE # error Need integer for VALUE
#endif #endif
#define IS_NAMESPACE(obj) (CLASS_OF(obj) == rb_cNamespace)
struct vm_and_namespace_struct {
rb_vm_t *vm;
rb_namespace_t *ns;
};
typedef struct vm_and_namespace_struct vm_ns_t;
#define GET_vm_ns() vm_ns_t vm_ns_v = { .vm = GET_VM(), .ns = (rb_namespace_t *)rb_current_namespace(), }; vm_ns_t *vm_ns = &vm_ns_v;
#define GET_loading_vm_ns() vm_ns_t vm_ns_v = { .vm = GET_VM(), .ns = (rb_namespace_t *)rb_loading_namespace(), }; vm_ns_t *vm_ns = &vm_ns_v;
#define CURRENT_NS_attr(vm_ns, attr) (NAMESPACE_USER_P(vm_ns->ns) ? vm_ns->ns->attr : vm_ns->vm->attr)
#define SET_NS_attr(vm_ns, attr, value) do { \
if (NAMESPACE_USER_P(vm_ns->ns)) { vm_ns->ns->attr = value; } \
else { vm_ns->vm->attr = value; } \
} while (0)
#define SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, value) SET_NS_attr(vm_ns, load_path_check_cache, value)
#define SET_NS_EXPANDED_LOAD_PATH(vm_ns, value) SET_NS_attr(vm_ns, expanded_load_path, value)
#define CURRENT_NS_LOAD_PATH(vm_ns) CURRENT_NS_attr(vm_ns, load_path)
#define CURRENT_NS_LOAD_PATH_SNAPSHOT(vm_ns) CURRENT_NS_attr(vm_ns, load_path_snapshot)
#define CURRENT_NS_LOAD_PATH_CHECK_CACHE(vm_ns) CURRENT_NS_attr(vm_ns, load_path_check_cache)
#define CURRENT_NS_EXPANDED_LOAD_PATH(vm_ns) CURRENT_NS_attr(vm_ns, expanded_load_path)
#define CURRENT_NS_LOADING_TABLE(vm_ns) CURRENT_NS_attr(vm_ns, loading_table)
#define CURRENT_NS_LOADED_FEATURES(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features)
#define CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features_snapshot)
#define CURRENT_NS_LOADED_FEATURES_REALPATHS(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features_realpaths)
#define CURRENT_NS_LOADED_FEATURES_REALPATH_MAP(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features_realpath_map)
#define CURRENT_NS_LOADED_FEATURES_INDEX(vm_ns) CURRENT_NS_attr(vm_ns, loaded_features_index)
#define CURRENT_NS_RUBY_DLN_LIBMAP(vm_ns, map) (NAMESPACE_USER_P(vm_ns->ns) ? vm_ns->ns->ruby_dln_libmap : map)
enum { enum {
loadable_ext_rb = (0+ /* .rb extension is the first in both tables */ loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
1) /* offset by rb_find_file_ext() */ 1) /* offset by rb_find_file_ext() */
@ -64,10 +99,11 @@ enum expand_type {
string objects in $LOAD_PATH are frozen. string objects in $LOAD_PATH are frozen.
*/ */
static void static void
rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_relative, int *has_non_cache) rb_construct_expanded_load_path(vm_ns_t *vm_ns, enum expand_type type, int *has_relative, int *has_non_cache)
{ {
VALUE load_path = vm->load_path; VALUE load_path = CURRENT_NS_LOAD_PATH(vm_ns);
VALUE expanded_load_path = vm->expanded_load_path; VALUE expanded_load_path = CURRENT_NS_EXPANDED_LOAD_PATH(vm_ns);
VALUE snapshot;
VALUE ary; VALUE ary;
long i; long i;
@ -106,108 +142,117 @@ rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_rel
rb_ary_push(ary, rb_fstring(expanded_path)); rb_ary_push(ary, rb_fstring(expanded_path));
} }
rb_ary_freeze(ary); rb_ary_freeze(ary);
vm->expanded_load_path = ary; SET_NS_EXPANDED_LOAD_PATH(vm_ns, ary);
rb_ary_replace(vm->load_path_snapshot, vm->load_path); snapshot = CURRENT_NS_LOAD_PATH_SNAPSHOT(vm_ns);
load_path = CURRENT_NS_LOAD_PATH(vm_ns);
rb_ary_replace(snapshot, load_path);
} }
static VALUE static VALUE
get_expanded_load_path(rb_vm_t *vm) get_expanded_load_path(vm_ns_t *vm_ns)
{ {
VALUE check_cache;
const VALUE non_cache = Qtrue; const VALUE non_cache = Qtrue;
const VALUE load_path_snapshot = CURRENT_NS_LOAD_PATH_SNAPSHOT(vm_ns);
const VALUE load_path = CURRENT_NS_LOAD_PATH(vm_ns);
if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) { if (!rb_ary_shared_with_p(load_path_snapshot, load_path)) {
/* The load path was modified. Rebuild the expanded load path. */ /* The load path was modified. Rebuild the expanded load path. */
int has_relative = 0, has_non_cache = 0; int has_relative = 0, has_non_cache = 0;
rb_construct_expanded_load_path(vm, EXPAND_ALL, &has_relative, &has_non_cache); rb_construct_expanded_load_path(vm_ns, EXPAND_ALL, &has_relative, &has_non_cache);
if (has_relative) { if (has_relative) {
vm->load_path_check_cache = rb_dir_getwd_ospath(); SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, rb_dir_getwd_ospath());
} }
else if (has_non_cache) { else if (has_non_cache) {
/* Non string object. */ /* Non string object. */
vm->load_path_check_cache = non_cache; SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, non_cache);
} }
else { else {
vm->load_path_check_cache = 0; SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, 0);
} }
} }
else if (vm->load_path_check_cache == non_cache) { else if ((check_cache = CURRENT_NS_LOAD_PATH_CHECK_CACHE(vm_ns)) == non_cache) {
int has_relative = 1, has_non_cache = 1; int has_relative = 1, has_non_cache = 1;
/* Expand only non-cacheable objects. */ /* Expand only non-cacheable objects. */
rb_construct_expanded_load_path(vm, EXPAND_NON_CACHE, rb_construct_expanded_load_path(vm_ns, EXPAND_NON_CACHE,
&has_relative, &has_non_cache); &has_relative, &has_non_cache);
} }
else if (vm->load_path_check_cache) { else if (check_cache) {
int has_relative = 1, has_non_cache = 1; int has_relative = 1, has_non_cache = 1;
VALUE cwd = rb_dir_getwd_ospath(); VALUE cwd = rb_dir_getwd_ospath();
if (!rb_str_equal(vm->load_path_check_cache, cwd)) { if (!rb_str_equal(check_cache, cwd)) {
/* Current working directory or filesystem encoding was changed. /* Current working directory or filesystem encoding was changed.
Expand relative load path and non-cacheable objects again. */ Expand relative load path and non-cacheable objects again. */
vm->load_path_check_cache = cwd; SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, cwd);
rb_construct_expanded_load_path(vm, EXPAND_RELATIVE, rb_construct_expanded_load_path(vm_ns, EXPAND_RELATIVE,
&has_relative, &has_non_cache); &has_relative, &has_non_cache);
} }
else { else {
/* Expand only tilde (User HOME) and non-cacheable objects. */ /* Expand only tilde (User HOME) and non-cacheable objects. */
rb_construct_expanded_load_path(vm, EXPAND_HOME, rb_construct_expanded_load_path(vm_ns, EXPAND_HOME,
&has_relative, &has_non_cache); &has_relative, &has_non_cache);
} }
} }
return vm->expanded_load_path; return CURRENT_NS_EXPANDED_LOAD_PATH(vm_ns);
} }
VALUE VALUE
rb_get_expanded_load_path(void) rb_get_expanded_load_path(void)
{ {
return get_expanded_load_path(GET_VM()); GET_loading_vm_ns();
return get_expanded_load_path(vm_ns);
} }
static VALUE static VALUE
load_path_getter(ID id, VALUE * p) load_path_getter(ID id, VALUE * p)
{ {
rb_vm_t *vm = (void *)p; GET_loading_vm_ns();
return vm->load_path; return CURRENT_NS_LOAD_PATH(vm_ns);
} }
static VALUE static VALUE
get_loaded_features(rb_vm_t *vm) get_loaded_features(vm_ns_t *vm_ns)
{ {
return vm->loaded_features; return CURRENT_NS_LOADED_FEATURES(vm_ns);
} }
static VALUE static VALUE
get_loaded_features_realpaths(rb_vm_t *vm) get_loaded_features_realpaths(vm_ns_t *vm_ns)
{ {
return vm->loaded_features_realpaths; return CURRENT_NS_LOADED_FEATURES_REALPATHS(vm_ns);
} }
static VALUE static VALUE
get_loaded_features_realpath_map(rb_vm_t *vm) get_loaded_features_realpath_map(vm_ns_t *vm_ns)
{ {
return vm->loaded_features_realpath_map; return CURRENT_NS_LOADED_FEATURES_REALPATH_MAP(vm_ns);
} }
static VALUE static VALUE
get_LOADED_FEATURES(ID _x, VALUE *_y) get_LOADED_FEATURES(ID _x, VALUE *_y)
{ {
return get_loaded_features(GET_VM()); GET_loading_vm_ns();
return get_loaded_features(vm_ns);
} }
static void static void
reset_loaded_features_snapshot(rb_vm_t *vm) reset_loaded_features_snapshot(vm_ns_t *vm_ns)
{ {
rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features); VALUE snapshot = CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns);
VALUE loaded_features = CURRENT_NS_LOADED_FEATURES(vm_ns);
rb_ary_replace(snapshot, loaded_features);
} }
static struct st_table * static struct st_table *
get_loaded_features_index_raw(rb_vm_t *vm) get_loaded_features_index_raw(vm_ns_t *vm_ns)
{ {
return vm->loaded_features_index; return CURRENT_NS_LOADED_FEATURES_INDEX(vm_ns);
} }
static st_table * static st_table *
get_loading_table(rb_vm_t *vm) get_loading_table(vm_ns_t *vm_ns)
{ {
return vm->loading_table; return CURRENT_NS_LOADING_TABLE(vm_ns);
} }
static st_data_t static st_data_t
@ -228,7 +273,7 @@ is_rbext_path(VALUE feature_path)
typedef rb_darray(long) feature_indexes_t; typedef rb_darray(long) feature_indexes_t;
struct features_index_add_single_args { struct features_index_add_single_args {
rb_vm_t *vm; vm_ns_t *vm_ns;
VALUE offset; VALUE offset;
bool rb; bool rb;
}; };
@ -237,7 +282,7 @@ static int
features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t raw_args, int existing) features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t raw_args, int existing)
{ {
struct features_index_add_single_args *args = (struct features_index_add_single_args *)raw_args; struct features_index_add_single_args *args = (struct features_index_add_single_args *)raw_args;
rb_vm_t *vm = args->vm; vm_ns_t *vm_ns = args->vm_ns;
VALUE offset = args->offset; VALUE offset = args->offset;
bool rb = args->rb; bool rb = args->rb;
@ -245,7 +290,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
VALUE this_feature_index = *value; VALUE this_feature_index = *value;
if (FIXNUM_P(this_feature_index)) { if (FIXNUM_P(this_feature_index)) {
VALUE loaded_features = get_loaded_features(vm); VALUE loaded_features = get_loaded_features(vm_ns);
VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index)); VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index));
feature_indexes_t feature_indexes; feature_indexes_t feature_indexes;
@ -265,7 +310,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
long pos = -1; long pos = -1;
if (rb) { if (rb) {
VALUE loaded_features = get_loaded_features(vm); VALUE loaded_features = get_loaded_features(vm_ns);
for (size_t i = 0; i < rb_darray_size(feature_indexes); ++i) { for (size_t i = 0; i < rb_darray_size(feature_indexes); ++i) {
long idx = rb_darray_get(feature_indexes, i); long idx = rb_darray_get(feature_indexes, i);
VALUE this_feature_path = RARRAY_AREF(loaded_features, idx); VALUE this_feature_path = RARRAY_AREF(loaded_features, idx);
@ -297,7 +342,7 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
} }
static void static void
features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset, bool rb) features_index_add_single(vm_ns_t *vm_ns, const char* str, size_t len, VALUE offset, bool rb)
{ {
struct st_table *features_index; struct st_table *features_index;
st_data_t short_feature_key; st_data_t short_feature_key;
@ -305,10 +350,10 @@ features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset
Check_Type(offset, T_FIXNUM); Check_Type(offset, T_FIXNUM);
short_feature_key = feature_key(str, len); short_feature_key = feature_key(str, len);
features_index = get_loaded_features_index_raw(vm); features_index = get_loaded_features_index_raw(vm_ns);
struct features_index_add_single_args args = { struct features_index_add_single_args args = {
.vm = vm, .vm_ns = vm_ns,
.offset = offset, .offset = offset,
.rb = rb, .rb = rb,
}; };
@ -325,7 +370,7 @@ features_index_add_single(rb_vm_t *vm, const char* str, size_t len, VALUE offset
relies on for its fast lookup. relies on for its fast lookup.
*/ */
static void static void
features_index_add(rb_vm_t *vm, VALUE feature, VALUE offset) features_index_add(vm_ns_t *vm_ns, VALUE feature, VALUE offset)
{ {
const char *feature_str, *feature_end, *ext, *p; const char *feature_str, *feature_end, *ext, *p;
bool rb = false; bool rb = false;
@ -351,14 +396,14 @@ features_index_add(rb_vm_t *vm, VALUE feature, VALUE offset)
if (p < feature_str) if (p < feature_str)
break; break;
/* Now *p == '/'. We reach this point for every '/' in `feature`. */ /* Now *p == '/'. We reach this point for every '/' in `feature`. */
features_index_add_single(vm, p + 1, feature_end - p - 1, offset, false); features_index_add_single(vm_ns, p + 1, feature_end - p - 1, offset, false);
if (ext) { if (ext) {
features_index_add_single(vm, p + 1, ext - p - 1, offset, rb); features_index_add_single(vm_ns, p + 1, ext - p - 1, offset, rb);
} }
} }
features_index_add_single(vm, feature_str, feature_end - feature_str, offset, false); features_index_add_single(vm_ns, feature_str, feature_end - feature_str, offset, false);
if (ext) { if (ext) {
features_index_add_single(vm, feature_str, ext - feature_str, offset, rb); features_index_add_single(vm_ns, feature_str, ext - feature_str, offset, rb);
} }
} }
@ -375,27 +420,31 @@ loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
void void
rb_free_loaded_features_index(rb_vm_t *vm) rb_free_loaded_features_index(rb_vm_t *vm)
{ {
/* Destructs vm->loaded_features_index directly because this is only for
the VM destruction */
st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0); st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
st_free_table(vm->loaded_features_index); st_free_table(vm->loaded_features_index);
} }
static st_table *
get_loaded_features_index(rb_vm_t *vm)
{
VALUE features;
int i;
if (!rb_ary_shared_with_p(vm->loaded_features_snapshot, vm->loaded_features)) {
static st_table *
get_loaded_features_index(vm_ns_t *vm_ns)
{
int i;
VALUE features = CURRENT_NS_LOADED_FEATURES(vm_ns);
const VALUE snapshot = CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns);
if (!rb_ary_shared_with_p(snapshot, features)) {
/* The sharing was broken; something (other than us in rb_provide_feature()) /* The sharing was broken; something (other than us in rb_provide_feature())
modified loaded_features. Rebuild the index. */ modified loaded_features. Rebuild the index. */
st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0); st_foreach(CURRENT_NS_LOADED_FEATURES_INDEX(vm_ns), loaded_features_index_clear_i, 0);
VALUE realpaths = vm->loaded_features_realpaths; VALUE realpaths = CURRENT_NS_LOADED_FEATURES_REALPATHS(vm_ns);
VALUE realpath_map = vm->loaded_features_realpath_map; VALUE realpath_map = CURRENT_NS_LOADED_FEATURES_REALPATH_MAP(vm_ns);
VALUE previous_realpath_map = rb_hash_dup(realpath_map); VALUE previous_realpath_map = rb_hash_dup(realpath_map);
rb_hash_clear(realpaths); rb_hash_clear(realpaths);
rb_hash_clear(realpath_map); rb_hash_clear(realpath_map);
features = vm->loaded_features;
for (i = 0; i < RARRAY_LEN(features); i++) { for (i = 0; i < RARRAY_LEN(features); i++) {
VALUE entry, as_str; VALUE entry, as_str;
as_str = entry = rb_ary_entry(features, i); as_str = entry = rb_ary_entry(features, i);
@ -403,11 +452,11 @@ get_loaded_features_index(rb_vm_t *vm)
as_str = rb_fstring(as_str); as_str = rb_fstring(as_str);
if (as_str != entry) if (as_str != entry)
rb_ary_store(features, i, as_str); rb_ary_store(features, i, as_str);
features_index_add(vm, as_str, INT2FIX(i)); features_index_add(vm_ns, as_str, INT2FIX(i));
} }
reset_loaded_features_snapshot(vm); reset_loaded_features_snapshot(vm_ns);
features = rb_ary_dup(vm->loaded_features_snapshot); features = CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns);
long j = RARRAY_LEN(features); long j = RARRAY_LEN(features);
for (i = 0; i < j; i++) { for (i = 0; i < j; i++) {
VALUE as_str = rb_ary_entry(features, i); VALUE as_str = rb_ary_entry(features, i);
@ -421,7 +470,7 @@ get_loaded_features_index(rb_vm_t *vm)
rb_hash_aset(realpath_map, as_str, realpath); rb_hash_aset(realpath_map, as_str, realpath);
} }
} }
return vm->loaded_features_index; return CURRENT_NS_LOADED_FEATURES_INDEX(vm_ns);
} }
/* This searches `load_path` for a value such that /* This searches `load_path` for a value such that
@ -506,7 +555,7 @@ loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
* 'u': unsuffixed * 'u': unsuffixed
*/ */
static int static int
rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn) rb_feature_p(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int expanded, const char **fn)
{ {
VALUE features, this_feature_index = Qnil, v, p, load_path = 0; VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
const char *f, *e; const char *f, *e;
@ -527,8 +576,8 @@ rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expa
elen = 0; elen = 0;
type = 0; type = 0;
} }
features = get_loaded_features(vm); features = get_loaded_features(vm_ns);
features_index = get_loaded_features_index(vm); features_index = get_loaded_features_index(vm_ns);
key = feature_key(feature, strlen(feature)); key = feature_key(feature, strlen(feature));
/* We search `features` for an entry such that either /* We search `features` for an entry such that either
@ -575,7 +624,7 @@ rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expa
if ((n = RSTRING_LEN(v)) < len) continue; if ((n = RSTRING_LEN(v)) < len) continue;
if (strncmp(f, feature, len) != 0) { if (strncmp(f, feature, len) != 0) {
if (expanded) continue; if (expanded) continue;
if (!load_path) load_path = get_expanded_load_path(vm); if (!load_path) load_path = get_expanded_load_path(vm_ns);
if (!(p = loaded_feature_path(f, n, feature, len, type, load_path))) if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
continue; continue;
expanded = 1; expanded = 1;
@ -595,14 +644,14 @@ rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expa
} }
} }
loading_tbl = get_loading_table(vm); loading_tbl = get_loading_table(vm_ns);
f = 0; f = 0;
if (!expanded && !rb_is_absolute_path(feature)) { if (!expanded && !rb_is_absolute_path(feature)) {
struct loaded_feature_searching fs; struct loaded_feature_searching fs;
fs.name = feature; fs.name = feature;
fs.len = len; fs.len = len;
fs.type = type; fs.type = type;
fs.load_path = load_path ? load_path : get_expanded_load_path(vm); fs.load_path = load_path ? load_path : get_expanded_load_path(vm_ns);
fs.result = 0; fs.result = 0;
st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs); st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
if ((f = fs.result) != 0) { if ((f = fs.result) != 0) {
@ -657,7 +706,7 @@ rb_provided(const char *feature)
} }
static int static int
feature_provided(rb_vm_t *vm, const char *feature, const char **loading) feature_provided(vm_ns_t *vm_ns, const char *feature, const char **loading)
{ {
const char *ext = strrchr(feature, '.'); const char *ext = strrchr(feature, '.');
VALUE fullpath = 0; VALUE fullpath = 0;
@ -669,15 +718,15 @@ feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
} }
if (ext && !strchr(ext, '/')) { if (ext && !strchr(ext, '/')) {
if (IS_RBEXT(ext)) { if (IS_RBEXT(ext)) {
if (rb_feature_p(vm, feature, ext, TRUE, FALSE, loading)) return TRUE; if (rb_feature_p(vm_ns, feature, ext, TRUE, FALSE, loading)) return TRUE;
return FALSE; return FALSE;
} }
else if (IS_SOEXT(ext) || IS_DLEXT(ext)) { else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
if (rb_feature_p(vm, feature, ext, FALSE, FALSE, loading)) return TRUE; if (rb_feature_p(vm_ns, feature, ext, FALSE, FALSE, loading)) return TRUE;
return FALSE; return FALSE;
} }
} }
if (rb_feature_p(vm, feature, 0, TRUE, FALSE, loading)) if (rb_feature_p(vm_ns, feature, 0, TRUE, FALSE, loading))
return TRUE; return TRUE;
RB_GC_GUARD(fullpath); RB_GC_GUARD(fullpath);
return FALSE; return FALSE;
@ -686,35 +735,41 @@ feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
int int
rb_feature_provided(const char *feature, const char **loading) rb_feature_provided(const char *feature, const char **loading)
{ {
return feature_provided(GET_VM(), feature, loading); GET_vm_ns();
return feature_provided(vm_ns, feature, loading);
} }
static void static void
rb_provide_feature(rb_vm_t *vm, VALUE feature) rb_provide_feature(vm_ns_t *vm_ns, VALUE feature)
{ {
VALUE features; VALUE features;
features = get_loaded_features(vm); features = get_loaded_features(vm_ns);
if (OBJ_FROZEN(features)) { if (OBJ_FROZEN(features)) {
rb_raise(rb_eRuntimeError, rb_raise(rb_eRuntimeError,
"$LOADED_FEATURES is frozen; cannot append feature"); "$LOADED_FEATURES is frozen; cannot append feature");
} }
feature = rb_fstring(feature); feature = rb_fstring(feature);
get_loaded_features_index(vm); get_loaded_features_index(vm_ns);
// If loaded_features and loaded_features_snapshot share the same backing // If loaded_features and loaded_features_snapshot share the same backing
// array, pushing into it would cause the whole array to be copied. // array, pushing into it would cause the whole array to be copied.
// To avoid this we first clear loaded_features_snapshot. // To avoid this we first clear loaded_features_snapshot.
rb_ary_clear(vm->loaded_features_snapshot); rb_ary_clear(CURRENT_NS_LOADED_FEATURES_SNAPSHOT(vm_ns));
rb_ary_push(features, feature); rb_ary_push(features, feature);
features_index_add(vm, feature, INT2FIX(RARRAY_LEN(features)-1)); features_index_add(vm_ns, feature, INT2FIX(RARRAY_LEN(features)-1));
reset_loaded_features_snapshot(vm); reset_loaded_features_snapshot(vm_ns);
} }
void void
rb_provide(const char *feature) rb_provide(const char *feature)
{ {
rb_provide_feature(GET_VM(), rb_fstring_cstr(feature)); /*
* rb_provide() must use rb_current_namespace to store provided features
* in the current namespace's loaded_features, etc.
*/
GET_vm_ns();
rb_provide_feature(vm_ns, rb_fstring_cstr(feature));
} }
NORETURN(static void load_failed(VALUE)); NORETURN(static void load_failed(VALUE));
@ -732,17 +787,34 @@ realpath_internal_cached(VALUE hash, VALUE path)
return realpath; return realpath;
} }
struct iseq_eval_in_namespace_data {
const rb_iseq_t *iseq;
bool in_builtin;
};
static VALUE
iseq_eval_in_namespace(VALUE arg)
{
struct iseq_eval_in_namespace_data *data = (struct iseq_eval_in_namespace_data *)arg;
if (rb_namespace_available() && data->in_builtin) {
return rb_iseq_eval_with_refinement(data->iseq, rb_mNamespaceRefiner);
} else {
return rb_iseq_eval(data->iseq);
}
}
static inline void static inline void
load_iseq_eval(rb_execution_context_t *ec, VALUE fname) load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
{ {
GET_loading_vm_ns();
const rb_namespace_t *loading_ns = rb_loading_namespace();
const rb_iseq_t *iseq = rb_iseq_load_iseq(fname); const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
if (!iseq) { if (!iseq) {
rb_execution_context_t *ec = GET_EC(); rb_execution_context_t *ec = GET_EC();
VALUE v = rb_vm_push_frame_fname(ec, fname); VALUE v = rb_vm_push_frame_fname(ec, fname);
rb_thread_t *th = rb_ec_thread_ptr(ec); VALUE realpath_map = get_loaded_features_realpath_map(vm_ns);
VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
if (rb_ruby_prism_p()) { if (rb_ruby_prism_p()) {
pm_parse_result_t result = { 0 }; pm_parse_result_t result = { 0 };
@ -786,13 +858,23 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
RB_GC_GUARD(v); RB_GC_GUARD(v);
} }
rb_exec_event_hook_script_compiled(ec, iseq, Qnil); rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
rb_iseq_eval(iseq);
if (loading_ns) {
struct iseq_eval_in_namespace_data arg = {
.iseq = iseq,
.in_builtin = NAMESPACE_BUILTIN_P(loading_ns),
};
rb_namespace_exec(loading_ns, iseq_eval_in_namespace, (VALUE)&arg);
} else {
rb_iseq_eval(iseq);
}
} }
static inline enum ruby_tag_type static inline enum ruby_tag_type
load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper) load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
{ {
enum ruby_tag_type state; enum ruby_tag_type state;
rb_namespace_t *ns;
rb_thread_t *th = rb_ec_thread_ptr(ec); rb_thread_t *th = rb_ec_thread_ptr(ec);
volatile VALUE wrapper = th->top_wrapper; volatile VALUE wrapper = th->top_wrapper;
volatile VALUE self = th->top_self; volatile VALUE self = th->top_self;
@ -803,7 +885,15 @@ load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
ec->errinfo = Qnil; /* ensure */ ec->errinfo = Qnil; /* ensure */
/* load in module as toplevel */ /* load in module as toplevel */
th->top_self = rb_obj_clone(rb_vm_top_self()); if (IS_NAMESPACE(load_wrapper)) {
ns = rb_get_namespace_t(load_wrapper);
if (!ns->top_self) {
ns->top_self = rb_obj_clone(rb_vm_top_self());
}
th->top_self = ns->top_self;
} else {
th->top_self = rb_obj_clone(rb_vm_top_self());
}
th->top_wrapper = load_wrapper; th->top_wrapper = load_wrapper;
rb_extend_object(th->top_self, th->top_wrapper); rb_extend_object(th->top_self, th->top_wrapper);
@ -838,7 +928,9 @@ raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
static void static void
rb_load_internal(VALUE fname, VALUE wrap) rb_load_internal(VALUE fname, VALUE wrap)
{ {
VALUE namespace;
rb_execution_context_t *ec = GET_EC(); rb_execution_context_t *ec = GET_EC();
const rb_namespace_t *ns = rb_loading_namespace();
enum ruby_tag_type state = TAG_NONE; enum ruby_tag_type state = TAG_NONE;
if (RTEST(wrap)) { if (RTEST(wrap)) {
if (!RB_TYPE_P(wrap, T_MODULE)) { if (!RB_TYPE_P(wrap, T_MODULE)) {
@ -846,6 +938,10 @@ rb_load_internal(VALUE fname, VALUE wrap)
} }
state = load_wrapping(ec, fname, wrap); state = load_wrapping(ec, fname, wrap);
} }
else if (NAMESPACE_OPTIONAL_P(ns)) {
namespace = ns->ns_object;
state = load_wrapping(ec, fname, namespace);
}
else { else {
load_iseq_eval(ec, fname); load_iseq_eval(ec, fname);
} }
@ -874,6 +970,40 @@ rb_load_protect(VALUE fname, int wrap, int *pstate)
if (state != TAG_NONE) *pstate = state; if (state != TAG_NONE) *pstate = state;
} }
static VALUE
load_entrypoint_internal(VALUE fname, VALUE wrap)
{
VALUE path, orig_fname;
orig_fname = rb_get_path_check_to_string(fname);
fname = rb_str_encode_ospath(orig_fname);
RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
path = rb_find_file(fname);
if (!path) {
if (!rb_file_load_ok(RSTRING_PTR(fname)))
load_failed(orig_fname);
path = fname;
}
rb_load_internal(path, wrap);
RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
return Qtrue;
}
VALUE
rb_load_entrypoint(VALUE args)
{
VALUE fname, wrap;
if (RARRAY_LEN(args) != 2) {
rb_bug("invalid arguments: %ld", RARRAY_LEN(args));
}
fname = rb_ary_entry(args, 0);
wrap = rb_ary_entry(args, 1);
return load_entrypoint_internal(fname, wrap);
}
/* /*
* call-seq: * call-seq:
* load(filename, wrap=false) -> true * load(filename, wrap=false) -> true
@ -907,32 +1037,16 @@ rb_load_protect(VALUE fname, int wrap, int *pstate)
static VALUE static VALUE
rb_f_load(int argc, VALUE *argv, VALUE _) rb_f_load(int argc, VALUE *argv, VALUE _)
{ {
VALUE fname, wrap, path, orig_fname; VALUE fname, wrap;
rb_scan_args(argc, argv, "11", &fname, &wrap); rb_scan_args(argc, argv, "11", &fname, &wrap);
return load_entrypoint_internal(fname, wrap);
orig_fname = rb_get_path_check_to_string(fname);
fname = rb_str_encode_ospath(orig_fname);
RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
path = rb_find_file(fname);
if (!path) {
if (!rb_file_load_ok(RSTRING_PTR(fname)))
load_failed(orig_fname);
path = fname;
}
rb_load_internal(path, wrap);
RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
return Qtrue;
} }
static char * static char *
load_lock(rb_vm_t *vm, const char *ftptr, bool warn) load_lock(vm_ns_t *vm_ns, const char *ftptr, bool warn)
{ {
st_data_t data; st_data_t data;
st_table *loading_tbl = get_loading_table(vm); st_table *loading_tbl = get_loading_table(vm_ns);
if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) { if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
/* partial state */ /* partial state */
@ -974,11 +1088,11 @@ release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int exis
} }
static void static void
load_unlock(rb_vm_t *vm, const char *ftptr, int done) load_unlock(vm_ns_t *vm_ns, const char *ftptr, int done)
{ {
if (ftptr) { if (ftptr) {
st_data_t key = (st_data_t)ftptr; st_data_t key = (st_data_t)ftptr;
st_table *loading_tbl = get_loading_table(vm); st_table *loading_tbl = get_loading_table(vm_ns);
st_update(loading_tbl, key, release_thread_shield, done); st_update(loading_tbl, key, release_thread_shield, done);
} }
@ -1026,9 +1140,22 @@ static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
VALUE VALUE
rb_f_require(VALUE obj, VALUE fname) rb_f_require(VALUE obj, VALUE fname)
{ {
// const rb_namespace_t *ns = rb_loading_namespace();
// printf("F:current loading ns: %ld\n", ns->ns_id);
return rb_require_string(fname); return rb_require_string(fname);
} }
VALUE
rb_require_relative_entrypoint(VALUE fname)
{
VALUE base = rb_current_realfilepath();
if (NIL_P(base)) {
rb_loaderror("cannot infer basepath");
}
base = rb_file_dirname(base);
return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
}
/* /*
* call-seq: * call-seq:
* require_relative(string) -> true or false * require_relative(string) -> true or false
@ -1041,18 +1168,13 @@ rb_f_require(VALUE obj, VALUE fname)
VALUE VALUE
rb_f_require_relative(VALUE obj, VALUE fname) rb_f_require_relative(VALUE obj, VALUE fname)
{ {
VALUE base = rb_current_realfilepath(); return rb_require_relative_entrypoint(fname);
if (NIL_P(base)) {
rb_loaderror("cannot infer basepath");
}
base = rb_file_dirname(base);
return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
} }
typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn); typedef int (*feature_func)(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int expanded, const char **fn);
static int static int
search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_feature_p) search_required(vm_ns_t *vm_ns, VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
{ {
VALUE tmp; VALUE tmp;
char *ext, *ftptr; char *ext, *ftptr;
@ -1063,20 +1185,20 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
ext = strrchr(ftptr = RSTRING_PTR(fname), '.'); ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
if (ext && !strchr(ext, '/')) { if (ext && !strchr(ext, '/')) {
if (IS_RBEXT(ext)) { if (IS_RBEXT(ext)) {
if (rb_feature_p(vm, ftptr, ext, TRUE, FALSE, &loading)) { if (rb_feature_p(vm_ns, ftptr, ext, TRUE, FALSE, &loading)) {
if (loading) *path = rb_filesystem_str_new_cstr(loading); if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 'r'; return 'r';
} }
if ((tmp = rb_find_file(fname)) != 0) { if ((tmp = rb_find_file(fname)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
if (!rb_feature_p(vm, ftptr, ext, TRUE, TRUE, &loading) || loading) if (!rb_feature_p(vm_ns, ftptr, ext, TRUE, TRUE, &loading) || loading)
*path = tmp; *path = tmp;
return 'r'; return 'r';
} }
return 0; return 0;
} }
else if (IS_SOEXT(ext)) { else if (IS_SOEXT(ext)) {
if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) { if (rb_feature_p(vm_ns, ftptr, ext, FALSE, FALSE, &loading)) {
if (loading) *path = rb_filesystem_str_new_cstr(loading); if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 's'; return 's';
} }
@ -1085,25 +1207,25 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
OBJ_FREEZE(tmp); OBJ_FREEZE(tmp);
if ((tmp = rb_find_file(tmp)) != 0) { if ((tmp = rb_find_file(tmp)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading) if (!rb_feature_p(vm_ns, ftptr, ext, FALSE, TRUE, &loading) || loading)
*path = tmp; *path = tmp;
return 's'; return 's';
} }
} }
else if (IS_DLEXT(ext)) { else if (IS_DLEXT(ext)) {
if (rb_feature_p(vm, ftptr, ext, FALSE, FALSE, &loading)) { if (rb_feature_p(vm_ns, ftptr, ext, FALSE, FALSE, &loading)) {
if (loading) *path = rb_filesystem_str_new_cstr(loading); if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 's'; return 's';
} }
if ((tmp = rb_find_file(fname)) != 0) { if ((tmp = rb_find_file(fname)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
if (!rb_feature_p(vm, ftptr, ext, FALSE, TRUE, &loading) || loading) if (!rb_feature_p(vm_ns, ftptr, ext, FALSE, TRUE, &loading) || loading)
*path = tmp; *path = tmp;
return 's'; return 's';
} }
} }
} }
else if ((ft = rb_feature_p(vm, ftptr, 0, FALSE, FALSE, &loading)) == 'r') { else if ((ft = rb_feature_p(vm_ns, ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
if (loading) *path = rb_filesystem_str_new_cstr(loading); if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 'r'; return 'r';
} }
@ -1112,7 +1234,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
// Check if it's a statically linked extension when // Check if it's a statically linked extension when
// not already a feature and not found as a dynamic library. // not already a feature and not found as a dynamic library.
if (!ft && type != loadable_ext_rb && vm->static_ext_inits) { if (!ft && type != loadable_ext_rb && vm_ns->vm->static_ext_inits) {
VALUE lookup_name = tmp; VALUE lookup_name = tmp;
// Append ".so" if not already present so for example "etc" can find "etc.so". // Append ".so" if not already present so for example "etc" can find "etc.so".
// We always register statically linked extensions with a ".so" extension. // We always register statically linked extensions with a ".so" extension.
@ -1122,7 +1244,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
rb_str_cat_cstr(lookup_name, ".so"); rb_str_cat_cstr(lookup_name, ".so");
} }
ftptr = RSTRING_PTR(lookup_name); ftptr = RSTRING_PTR(lookup_name);
if (st_lookup(vm->static_ext_inits, (st_data_t)ftptr, NULL)) { if (st_lookup(vm_ns->vm->static_ext_inits, (st_data_t)ftptr, NULL)) {
*path = rb_filesystem_str_new_cstr(ftptr); *path = rb_filesystem_str_new_cstr(ftptr);
RB_GC_GUARD(lookup_name); RB_GC_GUARD(lookup_name);
return 's'; return 's';
@ -1134,7 +1256,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
if (ft) if (ft)
goto feature_present; goto feature_present;
ftptr = RSTRING_PTR(tmp); ftptr = RSTRING_PTR(tmp);
return rb_feature_p(vm, ftptr, 0, FALSE, TRUE, 0); return rb_feature_p(vm_ns, ftptr, 0, FALSE, TRUE, 0);
default: default:
if (ft) { if (ft) {
@ -1143,7 +1265,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
/* fall through */ /* fall through */
case loadable_ext_rb: case loadable_ext_rb:
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
if (rb_feature_p(vm, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading) if (rb_feature_p(vm_ns, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
break; break;
*path = tmp; *path = tmp;
} }
@ -1161,10 +1283,15 @@ load_failed(VALUE fname)
} }
static VALUE static VALUE
load_ext(VALUE path) load_ext(VALUE path, VALUE fname)
{ {
VALUE loaded = path;
GET_loading_vm_ns();
if (NAMESPACE_USER_P(vm_ns->ns)) {
loaded = rb_namespace_local_extension(vm_ns->ns->ns_object, fname, path);
}
rb_scope_visibility_set(METHOD_VISI_PUBLIC); rb_scope_visibility_set(METHOD_VISI_PUBLIC);
return (VALUE)dln_load(RSTRING_PTR(path)); return (VALUE)dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname));
} }
static bool static bool
@ -1181,7 +1308,7 @@ run_static_ext_init(rb_vm_t *vm, const char *feature)
} }
static int static int
no_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn) no_feature_p(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int expanded, const char **fn)
{ {
return 0; return 0;
} }
@ -1193,10 +1320,11 @@ rb_resolve_feature_path(VALUE klass, VALUE fname)
VALUE path; VALUE path;
int found; int found;
VALUE sym; VALUE sym;
GET_loading_vm_ns();
fname = rb_get_path(fname); fname = rb_get_path(fname);
path = rb_str_encode_ospath(fname); path = rb_str_encode_ospath(fname);
found = search_required(GET_VM(), path, &path, no_feature_p); found = search_required(vm_ns, path, &path, no_feature_p);
switch (found) { switch (found) {
case 'r': case 'r':
@ -1231,6 +1359,20 @@ rb_ext_ractor_safe(bool flag)
GET_THREAD()->ext_config.ractor_safe = flag; GET_THREAD()->ext_config.ractor_safe = flag;
} }
struct rb_vm_call_cfunc2_data {
VALUE recv;
VALUE arg1;
VALUE arg2;
VALUE block_handler;
VALUE filename;
};
static VALUE
call_load_ext_in_ns(VALUE data){
struct rb_vm_call_cfunc2_data *arg = (struct rb_vm_call_cfunc2_data *)data;
return rb_vm_call_cfunc2(arg->recv, load_ext, arg->arg1, arg->arg2, arg->block_handler, arg->filename);
}
/* /*
* returns * returns
* 0: if already loaded (false) * 0: if already loaded (false)
@ -1250,13 +1392,14 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
th->top_wrapper, th->top_self, ec->errinfo, th->top_wrapper, th->top_self, ec->errinfo,
ec, ec,
}; };
GET_loading_vm_ns();
enum ruby_tag_type state; enum ruby_tag_type state;
char *volatile ftptr = 0; char *volatile ftptr = 0;
VALUE path; VALUE path;
volatile VALUE saved_path; volatile VALUE saved_path;
volatile VALUE realpath = 0; volatile VALUE realpath = 0;
VALUE realpaths = get_loaded_features_realpaths(th->vm); VALUE realpaths = get_loaded_features_realpaths(vm_ns);
VALUE realpath_map = get_loaded_features_realpath_map(th->vm); VALUE realpath_map = get_loaded_features_realpath_map(vm_ns);
volatile bool reset_ext_config = false; volatile bool reset_ext_config = false;
struct rb_ext_config prev_ext_config; struct rb_ext_config prev_ext_config;
@ -1272,12 +1415,12 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
int found; int found;
RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname)); RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
found = search_required(th->vm, path, &saved_path, rb_feature_p); found = search_required(vm_ns, path, &saved_path, rb_feature_p);
RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname)); RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
path = saved_path; path = saved_path;
if (found) { if (found) {
if (!path || !(ftptr = load_lock(th->vm, RSTRING_PTR(path), warn))) { if (!path || !(ftptr = load_lock(vm_ns, RSTRING_PTR(path), warn))) {
result = 0; result = 0;
} }
else if (!*ftptr) { else if (!*ftptr) {
@ -1293,15 +1436,30 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
else { else {
switch (found) { switch (found) {
case 'r': case 'r':
load_iseq_eval(saved.ec, path); // iseq_eval_in_namespace will be called with the loading namespace eventually
if (NAMESPACE_OPTIONAL_P(vm_ns->ns)) {
// check with NAMESPACE_OPTIONAL_P (not NAMESPACE_USER_P) for NS1::xxx naming
// it is not expected for the main namespace
load_wrapping(saved.ec, path, vm_ns->ns->ns_object);
} else {
load_iseq_eval(saved.ec, path);
}
break; break;
case 's': case 's':
// the loading namespace must be set to the current namespace before calling load_ext
reset_ext_config = true; reset_ext_config = true;
ext_config_push(th, &prev_ext_config); ext_config_push(th, &prev_ext_config);
handle = rb_vm_call_cfunc(rb_vm_top_self(), load_ext, struct rb_vm_call_cfunc2_data arg = {
path, VM_BLOCK_HANDLER_NONE, path); .recv = rb_vm_top_self(),
rb_hash_aset(ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle)); .arg1 = path,
.arg2 = fname,
.block_handler = VM_BLOCK_HANDLER_NONE,
.filename = path,
};
handle = rb_namespace_exec(vm_ns->ns, call_load_ext_in_ns, (VALUE)&arg);
rb_hash_aset(CURRENT_NS_RUBY_DLN_LIBMAP(vm_ns, ruby_dln_libmap), path,
SVALUE2NUM((SIGNED_VALUE)handle));
break; break;
} }
result = TAG_RETURN; result = TAG_RETURN;
@ -1317,7 +1475,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
if (reset_ext_config) ext_config_pop(th2, &prev_ext_config); if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
path = saved_path; path = saved_path;
if (ftptr) load_unlock(th2->vm, RSTRING_PTR(path), !state); if (ftptr) load_unlock(vm_ns, RSTRING_PTR(path), !state);
if (state) { if (state) {
if (state == TAG_FATAL || state == TAG_THROW) { if (state == TAG_FATAL || state == TAG_THROW) {
@ -1343,7 +1501,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
} }
if (result == TAG_RETURN) { if (result == TAG_RETURN) {
rb_provide_feature(th2->vm, path); rb_provide_feature(vm_ns, path);
VALUE real = realpath; VALUE real = realpath;
if (real) { if (real) {
real = rb_fstring(real); real = rb_fstring(real);
@ -1442,15 +1600,15 @@ void
ruby_init_ext(const char *name, void (*init)(void)) ruby_init_ext(const char *name, void (*init)(void))
{ {
st_table *inits_table; st_table *inits_table;
rb_vm_t *vm = GET_VM(); GET_loading_vm_ns();
if (feature_provided(vm, name, 0)) if (feature_provided(vm_ns, name, 0))
return; return;
inits_table = vm->static_ext_inits; inits_table = vm_ns->vm->static_ext_inits;
if (!inits_table) { if (!inits_table) {
inits_table = st_init_strtable(); inits_table = st_init_strtable();
vm->static_ext_inits = inits_table; vm_ns->vm->static_ext_inits = inits_table;
} }
st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init); st_update(inits_table, (st_data_t)name, register_init_ext, (st_data_t)init);
} }
@ -1595,6 +1753,7 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
VALUE path; VALUE path;
char *ext; char *ext;
VALUE fname_str = rb_str_new_cstr(fname); VALUE fname_str = rb_str_new_cstr(fname);
GET_loading_vm_ns();
resolved = rb_resolve_feature_path((VALUE)NULL, fname_str); resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
if (NIL_P(resolved)) { if (NIL_P(resolved)) {
@ -1602,7 +1761,7 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
if (!ext || !IS_SOEXT(ext)) { if (!ext || !IS_SOEXT(ext)) {
rb_str_cat_cstr(fname_str, ".so"); rb_str_cat_cstr(fname_str, ".so");
} }
if (rb_feature_p(GET_VM(), fname, 0, FALSE, FALSE, 0)) { if (rb_feature_p(vm_ns, fname, 0, FALSE, FALSE, 0)) {
return dln_symbol(NULL, symbol); return dln_symbol(NULL, symbol);
} }
return NULL; return NULL;
@ -1611,7 +1770,7 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
return NULL; return NULL;
} }
path = rb_ary_entry(resolved, 1); path = rb_ary_entry(resolved, 1);
handle = rb_hash_lookup(ruby_dln_libmap, path); handle = rb_hash_lookup(CURRENT_NS_RUBY_DLN_LIBMAP(vm_ns, ruby_dln_libmap), path);
if (NIL_P(handle)) { if (NIL_P(handle)) {
return NULL; return NULL;
} }
@ -1626,6 +1785,7 @@ Init_load(void)
ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1); ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter); rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
rb_gvar_namespace_ready(var_load_path);
rb_alias_variable(rb_intern_const("$-I"), id_load_path); rb_alias_variable(rb_intern_const("$-I"), id_load_path);
rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path); rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
vm->load_path = rb_ary_new(); vm->load_path = rb_ary_new();
@ -1635,7 +1795,9 @@ Init_load(void)
rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1); rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0); rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0); rb_gvar_namespace_ready("$\"");
rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0); // TODO: rb_alias_variable ?
rb_gvar_namespace_ready("$LOADED_FEATURES");
vm->loaded_features = rb_ary_new(); vm->loaded_features = rb_ary_new();
vm->loaded_features_snapshot = rb_ary_hidden_new(0); vm->loaded_features_snapshot = rb_ary_hidden_new(0);
vm->loaded_features_index = st_init_numtable(); vm->loaded_features_index = st_init_numtable();

View File

@ -531,7 +531,7 @@ w_extended(VALUE klass, struct dump_arg *arg, int check)
klass = RCLASS_SUPER(klass); klass = RCLASS_SUPER(klass);
} }
while (BUILTIN_TYPE(klass) == T_ICLASS) { while (BUILTIN_TYPE(klass) == T_ICLASS) {
if (!FL_TEST(klass, RICLASS_IS_ORIGIN) || if (!RICLASS_IS_ORIGIN_P(klass) ||
BUILTIN_TYPE(RBASIC(klass)->klass) != T_MODULE) { BUILTIN_TYPE(RBASIC(klass)->klass) != T_MODULE) {
VALUE path = rb_class_name(RBASIC(klass)->klass); VALUE path = rb_class_name(RBASIC(klass)->klass);
w_byte(TYPE_EXTENDED, arg); w_byte(TYPE_EXTENDED, arg);

View File

@ -197,6 +197,7 @@ struct rb_method_definition_struct {
ID original_id; ID original_id;
uintptr_t method_serial; uintptr_t method_serial;
const rb_namespace_t *ns;
}; };
struct rb_id_table; struct rb_id_table;
@ -247,6 +248,7 @@ const rb_callable_method_entry_t *rb_method_entry_complement_defined_class(const
void rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src); void rb_method_entry_copy(rb_method_entry_t *dst, const rb_method_entry_t *src);
void rb_method_table_insert(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me); void rb_method_table_insert(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me);
void rb_method_table_insert0(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me, bool iclass_shared_mtbl);
void rb_scope_visibility_set(rb_method_visibility_t); void rb_scope_visibility_set(rb_method_visibility_t);
@ -254,5 +256,6 @@ VALUE rb_unnamed_parameters(int arity);
void rb_clear_method_cache(VALUE klass_or_module, ID mid); void rb_clear_method_cache(VALUE klass_or_module, ID mid);
void rb_clear_all_refinement_method_cache(void); void rb_clear_all_refinement_method_cache(void);
void rb_invalidate_method_caches(struct rb_id_table *cm_tbl, struct rb_id_table *cc_tbl);
#endif /* RUBY_METHOD_H */ #endif /* RUBY_METHOD_H */

View File

@ -1,5 +1,6 @@
#include "internal.h" #include "internal.h"
#include "internal/array.h" #include "internal/array.h"
#include "internal/eval.h"
#include "iseq.h" #include "iseq.h"
#include "vm_core.h" #include "vm_core.h"
#include "builtin.h" #include "builtin.h"
@ -95,9 +96,23 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta
return iseq; return iseq;
} }
static void
load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
{
const rb_iseq_t *iseq = builtin_iseq_load(feature_name, table);
rb_namespace_enable_builtin();
rb_iseq_eval_with_refinement(iseq, rb_mNamespaceRefiner);
rb_namespace_disable_builtin();
}
void void
rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table) rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
{ {
const rb_iseq_t *iseq = builtin_iseq_load(feature_name, table); const rb_iseq_t *iseq;
rb_iseq_eval(iseq); if (rb_namespace_available() && rb_mNamespaceRefiner) {
load_with_builtin_functions(feature_name, table);
} else {
iseq = builtin_iseq_load(feature_name, table);
rb_iseq_eval(iseq);
}
} }

1139
namespace.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -121,7 +121,7 @@ rb_obj_reveal(VALUE obj, VALUE klass)
VALUE VALUE
rb_class_allocate_instance(VALUE klass) rb_class_allocate_instance(VALUE klass)
{ {
uint32_t index_tbl_num_entries = RCLASS_EXT(klass)->max_iv_count; uint32_t index_tbl_num_entries = RCLASS_MAX_IV_COUNT(klass);
size_t size = rb_obj_embedded_size(index_tbl_num_entries); size_t size = rb_obj_embedded_size(index_tbl_num_entries);
if (!rb_gc_size_allocatable_p(size)) { if (!rb_gc_size_allocatable_p(size)) {
@ -2097,7 +2097,7 @@ rb_class_initialize(int argc, VALUE *argv, VALUE klass)
rb_raise(rb_eTypeError, "can't inherit uninitialized class"); rb_raise(rb_eTypeError, "can't inherit uninitialized class");
} }
} }
RCLASS_SET_SUPER(klass, super); rb_class_set_super(klass, super);
rb_make_metaclass(klass, RBASIC(super)->klass); rb_make_metaclass(klass, RBASIC(super)->klass);
rb_class_inherited(super, klass); rb_class_inherited(super, klass);
rb_mod_initialize_exec(klass); rb_mod_initialize_exec(klass);
@ -2269,17 +2269,21 @@ rb_class_superclass(VALUE klass)
RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS)); RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS));
VALUE super = RCLASS_SUPER(klass); VALUE super = RCLASS_SUPER(klass);
VALUE *superclasses;
size_t superclasses_depth;
if (!super) { if (!super) {
if (klass == rb_cBasicObject) return Qnil; if (klass == rb_cBasicObject) return Qnil;
rb_raise(rb_eTypeError, "uninitialized class"); rb_raise(rb_eTypeError, "uninitialized class");
} }
if (!RCLASS_SUPERCLASS_DEPTH(klass)) { superclasses_depth = RCLASS_SUPERCLASS_DEPTH(klass);
if (!superclasses_depth) {
return Qnil; return Qnil;
} }
else { else {
super = RCLASS_SUPERCLASSES(klass)[RCLASS_SUPERCLASS_DEPTH(klass) - 1]; superclasses = RCLASS_SUPERCLASSES(klass);
super = superclasses[superclasses_depth - 1];
RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS)); RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS));
return super; return super;
} }
@ -2288,7 +2292,7 @@ rb_class_superclass(VALUE klass)
VALUE VALUE
rb_class_get_superclass(VALUE klass) rb_class_get_superclass(VALUE klass)
{ {
return RCLASS(klass)->super; return RCLASS_SUPER(klass);
} }
static const char bad_instance_name[] = "'%1$s' is not allowed as an instance variable name"; static const char bad_instance_name[] = "'%1$s' is not allowed as an instance variable name";
@ -4599,6 +4603,13 @@ InitVM_Object(void)
rb_define_method(rb_cModule, "deprecate_constant", rb_mod_deprecate_constant, -1); /* in variable.c */ rb_define_method(rb_cModule, "deprecate_constant", rb_mod_deprecate_constant, -1); /* in variable.c */
rb_define_method(rb_cModule, "singleton_class?", rb_mod_singleton_p, 0); rb_define_method(rb_cModule, "singleton_class?", rb_mod_singleton_p, 0);
// TODO: only for development
rb_define_method(rb_cModule, "debug_duplicate_classext", rb_class_debug_duplicate_classext, 1);
rb_define_method(rb_cModule, "debug_dump_all_classext", rb_class_debug_dump_all_classext, 0);
rb_define_method(rb_cModule, "debug_dump_all_classext_super", rb_class_debug_dump_all_classext_super, 1);
rb_define_method(rb_cBasicObject, "debug_print_module", rb_class_debug_print_module, 0);
rb_define_method(rb_singleton_class(rb_cClass), "allocate", rb_class_alloc_m, 0); rb_define_method(rb_singleton_class(rb_cClass), "allocate", rb_class_alloc_m, 0);
rb_define_method(rb_cClass, "allocate", rb_class_alloc_m, 0); rb_define_method(rb_cClass, "allocate", rb_class_alloc_m, 0);
rb_define_method(rb_cClass, "new", rb_class_new_instance_pass_kw, -1); rb_define_method(rb_cClass, "new", rb_class_new_instance_pass_kw, -1);

20
proc.c
View File

@ -678,6 +678,7 @@ cfunc_proc_new(VALUE klass, VALUE ifunc)
{ {
rb_proc_t *proc; rb_proc_t *proc;
cfunc_proc_t *sproc; cfunc_proc_t *sproc;
const rb_namespace_t *ns = rb_current_namespace();
VALUE procval = TypedData_Make_Struct(klass, cfunc_proc_t, &proc_data_type, sproc); VALUE procval = TypedData_Make_Struct(klass, cfunc_proc_t, &proc_data_type, sproc);
VALUE *ep; VALUE *ep;
@ -692,6 +693,7 @@ cfunc_proc_new(VALUE klass, VALUE ifunc)
/* self? */ /* self? */
RB_OBJ_WRITE(procval, &proc->block.as.captured.code.ifunc, ifunc); RB_OBJ_WRITE(procval, &proc->block.as.captured.code.ifunc, ifunc);
proc->ns = ns;
proc->is_lambda = TRUE; proc->is_lambda = TRUE;
return procval; return procval;
} }
@ -727,6 +729,7 @@ sym_proc_new(VALUE klass, VALUE sym)
GetProcPtr(procval, proc); GetProcPtr(procval, proc);
vm_block_type_set(&proc->block, block_type_symbol); vm_block_type_set(&proc->block, block_type_symbol);
// No namespace specified: similar to built-in methods
proc->is_lambda = TRUE; proc->is_lambda = TRUE;
RB_OBJ_WRITE(procval, &proc->block.as.symbol, sym); RB_OBJ_WRITE(procval, &proc->block.as.symbol, sym);
return procval; return procval;
@ -2006,6 +2009,21 @@ method_owner(VALUE obj)
return data->owner; return data->owner;
} }
static VALUE
method_namespace(VALUE obj)
{
struct METHOD *data;
const rb_namespace_t *ns;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
ns = data->me->def->ns;
if (!ns) return Qfalse;
if (ns->ns_object) return ns->ns_object;
// This should not happen
rb_bug("Unexpected namespace on the method definition: %p", ns);
return Qtrue;
}
void void
rb_method_name_error(VALUE klass, VALUE str) rb_method_name_error(VALUE klass, VALUE str)
{ {
@ -4466,6 +4484,8 @@ Init_Proc(void)
rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1); rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1);
rb_define_method(rb_mKernel, "singleton_method", rb_obj_singleton_method, 1); rb_define_method(rb_mKernel, "singleton_method", rb_obj_singleton_method, 1);
rb_define_method(rb_cMethod, "namespace", method_namespace, 0);
/* UnboundMethod */ /* UnboundMethod */
rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject); rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject);
rb_undef_alloc_func(rb_cUnboundMethod); rb_undef_alloc_func(rb_cUnboundMethod);

3
ruby.c
View File

@ -1824,6 +1824,9 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
ruby_init_prelude(); ruby_init_prelude();
if (rb_namespace_available())
rb_initialize_main_namespace();
// Initialize JITs after prelude because JITing prelude is typically not optimal. // Initialize JITs after prelude because JITing prelude is typically not optimal.
#if USE_YJIT #if USE_YJIT
rb_yjit_init(opt->yjit); rb_yjit_init(opt->yjit);

12
shape.c
View File

@ -656,7 +656,7 @@ rb_shape_transition_remove_ivar(VALUE obj, ID id, VALUE *removed)
switch(BUILTIN_TYPE(obj)) { switch(BUILTIN_TYPE(obj)) {
case T_CLASS: case T_CLASS:
case T_MODULE: case T_MODULE:
fields = RCLASS_FIELDS(obj); fields = RCLASS_PRIME_FIELDS(obj);
break; break;
case T_OBJECT: case T_OBJECT:
fields = ROBJECT_FIELDS(obj); fields = ROBJECT_FIELDS(obj);
@ -803,7 +803,7 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
if (BUILTIN_TYPE(obj) == T_OBJECT) { if (BUILTIN_TYPE(obj) == T_OBJECT) {
VALUE klass = rb_obj_class(obj); VALUE klass = rb_obj_class(obj);
allow_new_shape = RCLASS_EXT(klass)->variation_count < SHAPE_MAX_VARIATIONS; allow_new_shape = RCLASS_VARIATION_COUNT(klass) < SHAPE_MAX_VARIATIONS;
} }
bool variation_created = false; bool variation_created = false;
@ -812,14 +812,14 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
// Check if we should update max_iv_count on the object's class // Check if we should update max_iv_count on the object's class
if (BUILTIN_TYPE(obj) == T_OBJECT) { if (BUILTIN_TYPE(obj) == T_OBJECT) {
VALUE klass = rb_obj_class(obj); VALUE klass = rb_obj_class(obj);
if (new_shape->next_field_index > RCLASS_EXT(klass)->max_iv_count) { if (new_shape->next_field_index > RCLASS_MAX_IV_COUNT(klass)) {
RCLASS_EXT(klass)->max_iv_count = new_shape->next_field_index; RCLASS_SET_MAX_IV_COUNT(klass, new_shape->next_field_index);
} }
if (variation_created) { if (variation_created) {
RCLASS_EXT(klass)->variation_count++; RCLASS_VARIATION_COUNT(klass)++;
if (emit_warnings && rb_warning_category_enabled_p(RB_WARN_CATEGORY_PERFORMANCE)) { if (emit_warnings && rb_warning_category_enabled_p(RB_WARN_CATEGORY_PERFORMANCE)) {
if (RCLASS_EXT(klass)->variation_count >= SHAPE_MAX_VARIATIONS) { if (RCLASS_VARIATION_COUNT(klass) >= SHAPE_MAX_VARIATIONS) {
rb_category_warn( rb_category_warn(
RB_WARN_CATEGORY_PERFORMANCE, RB_WARN_CATEGORY_PERFORMANCE,
"The class %"PRIsVALUE" reached %d shape variations, instance variables accesses will be slower and memory usage increased.\n" "The class %"PRIsVALUE" reached %d shape variations, instance variables accesses will be slower and memory usage increased.\n"

View File

@ -7,10 +7,17 @@ describe "Module#ancestors" do
ModuleSpecs.ancestors.should == [ModuleSpecs] ModuleSpecs.ancestors.should == [ModuleSpecs]
ModuleSpecs::Basic.ancestors.should == [ModuleSpecs::Basic] ModuleSpecs::Basic.ancestors.should == [ModuleSpecs::Basic]
ModuleSpecs::Super.ancestors.should == [ModuleSpecs::Super, ModuleSpecs::Basic] ModuleSpecs::Super.ancestors.should == [ModuleSpecs::Super, ModuleSpecs::Basic]
ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should == if Namespace.enabled?
[ModuleSpecs::Parent, Object, Kernel, BasicObject] ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should == [ModuleSpecs::Parent, Object, Namespace::Loader, Kernel, BasicObject]
[ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Kernel, BasicObject] ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
[ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Namespace::Loader, Kernel, BasicObject]
else
ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
[ModuleSpecs::Parent, Object, Kernel, BasicObject]
ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
[ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Kernel, BasicObject]
end
end end
it "returns only modules and classes" do it "returns only modules and classes" do

View File

@ -0,0 +1,97 @@
# frozen_string_literal: true
require 'test/unit'
class Test_Load_Extensions < Test::Unit::TestCase
ENV_ENABLE_NAMESPACE = {'RUBY_NAMESPACE' => '1'}
def test_load_extension
pend
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
require '-test-/namespace/yay1'
assert_equal "1.0.0", Yay.version
assert_equal "yay", Yay.yay
end;
end
def test_extension_contamination_in_global
pend
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
begin;
require '-test-/namespace/yay1'
yay1 = Yay
assert_equal "1.0.0", Yay.version
assert_equal "yay", Yay.yay
require '-test-/namespace/yay2'
assert_equal "2.0.0", Yay.version
v = Yay.yay
assert(v == "yay" || v == "yaaay") # "yay" on Linux, "yaaay" on macOS, Win32
end;
end
def test_load_extension_in_namespace
pend
assert_separately([ENV_ENABLE_NAMESPACE], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
ns = Namespace.new
ns.require '-test-/namespace/yay1'
assert_equal "1.0.0", ns::Yay.version
assert_raise(NameError) { Yay }
end;
end
def test_different_version_extensions
pend
assert_separately([ENV_ENABLE_NAMESPACE], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
ns1 = Namespace.new
ns2 = Namespace.new
ns1.require('-test-/namespace/yay1')
ns2.require('-test-/namespace/yay2')
assert_raise(NameError) { Yay }
assert_not_nil ns1::Yay
assert_not_nil ns2::Yay
assert_equal "1.0.0", ns1::Yay::VERSION
assert_equal "2.0.0", ns2::Yay::VERSION
assert_equal "1.0.0", ns1::Yay.version
assert_equal "2.0.0", ns2::Yay.version
end;
end
def test_loading_extensions_from_global_to_local
pend
assert_separately([ENV_ENABLE_NAMESPACE], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
require '-test-/namespace/yay1'
assert_equal "1.0.0", Yay.version
assert_equal "yay", Yay.yay
ns = Namespace.new
ns.require '-test-/namespace/yay2'
assert_equal "2.0.0", ns::Yay.version
assert_equal "yaaay", ns::Yay.yay
assert_equal "yay", Yay.yay
end;
end
def test_loading_extensions_from_local_to_global
pend
assert_separately([ENV_ENABLE_NAMESPACE], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
ns = Namespace.new
ns.require '-test-/namespace/yay1'
assert_equal "1.0.0", ns::Yay.version
assert_equal "yay", ns::Yay.yay
require '-test-/namespace/yay2'
assert_equal "2.0.0", Yay.version
assert_equal "yaaay", Yay.yay
assert_equal "yay", ns::Yay.yay
end;
end
end

View File

@ -9,7 +9,11 @@ class TestABI < Test::Unit::TestCase
assert_separately [], <<~RUBY assert_separately [], <<~RUBY
err = assert_raise(LoadError) { require "-test-/abi" } err = assert_raise(LoadError) { require "-test-/abi" }
assert_match(/incompatible ABI version/, err.message) assert_match(/incompatible ABI version/, err.message)
assert_include err.message, "/-test-/abi." if Namespace.enabled?
assert_include err.message, "_-test-+abi."
else
assert_include err.message, "/-test-/abi."
end
RUBY RUBY
end end
@ -27,7 +31,11 @@ class TestABI < Test::Unit::TestCase
assert_separately [{ "RUBY_ABI_CHECK" => "1" }], <<~RUBY assert_separately [{ "RUBY_ABI_CHECK" => "1" }], <<~RUBY
err = assert_raise(LoadError) { require "-test-/abi" } err = assert_raise(LoadError) { require "-test-/abi" }
assert_match(/incompatible ABI version/, err.message) assert_match(/incompatible ABI version/, err.message)
assert_include err.message, "/-test-/abi." if Namespace.enabled?
assert_include err.message, "_-test-+abi."
else
assert_include err.message, "/-test-/abi."
end
RUBY RUBY
end end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class NS_A
VERSION = "1.1.0"
def yay
"yay #{VERSION}"
end
end
module NS_B
VERSION = "1.1.0"
def self.yay
"yay_b1"
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class NS_A
VERSION = "1.2.0"
def yay
"yay #{VERSION}"
end
end
module NS_B
VERSION = "1.2.0"
def self.yay
"yay_b1"
end
end

15
test/ruby/namespace/a.rb Normal file
View File

@ -0,0 +1,15 @@
class NS_A
FOO = "foo_a1"
def yay
"yay_a1"
end
end
module NS_B
BAR = "bar_b1"
def self.yay
"yay_b1"
end
end

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
autoload :NS_A, File.join(__dir__, 'a.1_1_0')
NS_A.new.yay
module NS_B
autoload :BAR, File.join(__dir__, 'a')
end

View File

@ -0,0 +1,2 @@
module Blank1
end

View File

@ -0,0 +1,2 @@
module Blank1
end

View File

@ -0,0 +1,2 @@
module Blank2
end

View File

@ -0,0 +1,5 @@
module Bar
def self.caller(proc_value)
proc_value.call
end
end

View File

@ -0,0 +1,8 @@
foo
#### TODO: this code should be valid, but can't be for now
# module Foo
# def self.wow
# foo
# end
# end

View File

@ -0,0 +1,147 @@
class String
STR_CONST1 = 111
STR_CONST2 = 222
STR_CONST3 = 333
end
class String
STR_CONST1 = 112
def self.set0(val)
const_set(:STR_CONST0, val)
end
def self.remove0
remove_const(:STR_CONST0)
end
def refer0
STR_CONST0
end
def refer1
STR_CONST1
end
def refer2
STR_CONST2
end
def refer3
STR_CONST3
end
end
module ForConsts
CONST1 = 111
end
TOP_CONST = 10
module ForConsts
CONST1 = 112
CONST2 = 222
CONST3 = 333
def self.refer_all
ForConsts::CONST1
ForConsts::CONST2
ForConsts::CONST3
String::STR_CONST1
String::STR_CONST2
String::STR_CONST3
end
def self.refer1
CONST1
end
def self.get1
const_get(:CONST1)
end
def self.refer2
CONST2
end
def self.get2
const_get(:CONST2)
end
def self.refer3
CONST3
end
def self.get3
const_get(:CONST3)
end
def self.refer_top_const
TOP_CONST
end
# for String
class Proxy
def call_str_refer0
String.new.refer0
end
def call_str_get0
String.const_get(:STR_CONST0)
end
def call_str_set0(val)
String.set0(val)
end
def call_str_remove0
String.remove0
end
def call_str_refer1
String.new.refer1
end
def call_str_get1
String.const_get(:STR_CONST1)
end
String::STR_CONST2 = 223
def call_str_refer2
String.new.refer2
end
def call_str_get2
String.const_get(:STR_CONST2)
end
def call_str_set3
String.const_set(:STR_CONST3, 334)
end
def call_str_refer3
String.new.refer3
end
def call_str_get3
String.const_get(:STR_CONST3)
end
# for Integer
Integer::INT_CONST1 = 1
def refer_int_const1
Integer::INT_CONST1
end
end
end
# should not raise errors
ForConsts.refer_all
String::STR_CONST1
Integer::INT_CONST1
# If we execute this sentence once, the constant value will be cached on ISeq inline constant cache.
# And it changes the behavior of ForConsts.refer_consts_directly called from global.
# ForConsts.refer_consts_directly # should not raise errors too

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
$ns_in_ns = ::Namespace.current
module CurrentNamespace
def self.in_require
$ns_in_ns
end
def self.in_method_call
::Namespace.current
end
end

View File

@ -0,0 +1,5 @@
def foo
"foooooooooo"
end
foo # should not raise errors

View File

@ -0,0 +1,37 @@
module LineSplitter
def self.read
$-0
end
def self.write(char)
$-0 = char
end
end
module FieldSplitter
def self.read
$,
end
def self.write(char)
$, = char
end
end
module UniqueGvar
def self.read
$used_only_in_ns
end
def self.write(val)
$used_only_in_ns = val
end
def self.write_only(val)
$write_only_var_in_ns = val
end
def self.gvars_in_ns
global_variables
end
end

View File

@ -0,0 +1,9 @@
module LineSplitter
def self.read
$-0
end
def self.write(char)
$-0 = char
end
end

View File

@ -0,0 +1,26 @@
module LoadPathCheck
FIRST_LOAD_PATH = $LOAD_PATH.dup
FIRST_LOAD_PATH_RESPOND_TO_RESOLVE = $LOAD_PATH.respond_to?(:resolve_feature_path)
FIRST_LOADED_FEATURES = $LOADED_FEATURES.dup
HERE = File.dirname(__FILE__)
def self.current_load_path
$LOAD_PATH
end
def self.current_loaded_features
$LOADED_FEATURES
end
def self.require_blank1
$LOAD_PATH << HERE
require 'blank1'
end
def self.require_blank2
require 'blank2'
end
end
LoadPathCheck.require_blank1

10
test/ruby/namespace/ns.rb Normal file
View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
NS1 = Namespace.new
NS1.require_relative('a.1_1_0')
def yay
NS1::NS_B::yay
end
yay

View File

@ -0,0 +1,31 @@
module StringExt
FOO = "foo 1"
def say_foo
"I'm saying " + FOO
end
end
class String
include StringExt
def say
say_foo
end
end
module OpenClassWithInclude
def self.say
String.new.say
end
def self.say_foo
String.new.say_foo
end
def self.say_with_obj(str)
str.say
end
def self.refer_foo
String::FOO
end
end

View File

@ -0,0 +1,14 @@
module Target
def self.foo
"fooooo"
end
end
module Foo
def self.callee
lambda do
Target.foo
end
end
end

View File

@ -0,0 +1,5 @@
module Bar
def self.caller(proc_value)
proc_value.call
end
end

View File

@ -0,0 +1,64 @@
class String
FOO = "foo"
def yay
"yay"
end
end
module ProcLookupTestA
module B
VALUE = 222
end
end
module ProcInNS
def self.make_proc_from_block(&b)
b
end
def self.call_proc(proc_arg)
proc_arg.call
end
def self.make_str_proc(type)
case type
when :proc_new then Proc.new { String.new.yay }
when :proc_f then proc { String.new.yay }
when :lambda_f then lambda { String.new.yay }
when :lambda_l then ->(){ String.new.yay }
when :block then make_proc_from_block { String.new.yay }
else
raise "invalid type :#{type}"
end
end
def self.make_const_proc(type)
case type
when :proc_new then Proc.new { ProcLookupTestA::B::VALUE }
when :proc_f then proc { ProcLookupTestA::B::VALUE }
when :lambda_f then lambda { ProcLookupTestA::B::VALUE }
when :lambda_l then ->(){ ProcLookupTestA::B::VALUE }
when :block then make_proc_from_block { ProcLookupTestA::B::VALUE }
else
raise "invalid type :#{type}"
end
end
def self.make_str_const_proc(type)
case type
when :proc_new then Proc.new { String::FOO }
when :proc_f then proc { String::FOO }
when :lambda_f then lambda { String::FOO }
when :lambda_l then ->(){ String::FOO }
when :block then make_proc_from_block { String::FOO }
else
raise "invalid type :#{type}"
end
end
CONST_PROC_NEW = Proc.new { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
CONST_PROC_F = proc { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
CONST_LAMBDA_F = lambda { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
CONST_LAMBDA_L = ->() { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
CONST_BLOCK = make_proc_from_block { [String.new.yay, String::FOO, ProcLookupTestA::B::VALUE.to_s].join(',') }
end

View File

@ -0,0 +1,3 @@
# frozen_string_literal: true
raise "Yay!"

View File

@ -0,0 +1,12 @@
module Foo
def self.foo
"fooooo"
end
def self.callee
lambda do
Foo.foo
end
end
end

View File

@ -0,0 +1,65 @@
class String
def self.greeting
"Good evening!"
end
end
class Integer
class << self
def answer
42
end
end
end
class Array
def a
size
end
def self.blank
[]
end
def b
size
end
end
class Hash
def a
size
end
class << self
def http_200
{status: 200, body: 'OK'}
end
end
def b
size
end
end
module SingletonMethods
def self.string_greeing
String.greeting
end
def self.integer_answer
Integer.answer
end
def self.array_blank
Array.blank
end
def self.hash_http_200
Hash.http_200
end
def self.array_instance_methods_return_size(ary)
[ary.a, ary.b]
end
def self.hash_instance_methods_return_size(hash)
[hash.a, hash.b]
end
end

View File

@ -0,0 +1,13 @@
class String
def yay
"yay"
end
end
String.new.yay # check this doesn't raise NoMethodError
module Bar
def self.yay
String.new.yay
end
end

View File

@ -0,0 +1,5 @@
module Foo
def self.yay
String.new.yay
end
end

View File

@ -0,0 +1 @@
Foo.yay

View File

@ -0,0 +1,12 @@
module Baz
def self.yay
eval 'String.new.yay'
end
def self.yay_with_binding
suffix = ", yay!"
eval 'String.new.yay + suffix', binding
end
end
Baz.yay # should not raise NeMethodError

View File

@ -0,0 +1,33 @@
def yaaay
"yay!"
end
module Foo
def self.foo
yaaay
end
end
eval 'def foo; "foo"; end'
Foo.foo # Should not raise NameError
foo
module Bar
def self.bar
foo
end
end
Bar.bar
$def_retval_in_namespace = def boooo
"boo"
end
module Baz
def self.baz
raise "#{$def_retval_in_namespace}"
end
end

View File

@ -224,11 +224,18 @@ p Foo::Bar
Kernel.module_eval do Kernel.module_eval do
alias old_require require alias old_require require
end end
Namespace.module_eval do
alias old_require require
end
called_with = [] called_with = []
Kernel.send :define_method, :require do |path| Kernel.send :define_method, :require do |path|
called_with << path called_with << path
old_require path old_require path
end end
Namespace.send :define_method, :require do |path|
called_with << path
old_require path
end
yield called_with yield called_with
ensure ensure
Kernel.module_eval do Kernel.module_eval do
@ -236,6 +243,11 @@ p Foo::Bar
alias require old_require alias require old_require
undef old_require undef old_require
end end
Namespace.module_eval do
undef require
alias require old_require
undef old_require
end
end end
def test_require_implemented_in_ruby_is_called def test_require_implemented_in_ruby_is_called
@ -249,7 +261,8 @@ p Foo::Bar
ensure ensure
remove_autoload_constant remove_autoload_constant
end end
assert_equal [file.path], called_with # .dup to prevent breaking called_with by autoloading pp, etc
assert_equal [file.path], called_with.dup
} }
end end
end end
@ -267,7 +280,8 @@ p Foo::Bar
ensure ensure
remove_autoload_constant remove_autoload_constant
end end
assert_equal [a.path, b.path], called_with # .dup to prevent breaking called_with by autoloading pp, etc
assert_equal [a.path, b.path], called_with.dup
end end
end end
end end

516
test/ruby/test_namespace.rb Normal file
View File

@ -0,0 +1,516 @@
# frozen_string_literal: true
require 'test/unit'
class TestNamespace < Test::Unit::TestCase
ENV_ENABLE_NAMESPACE = {'RUBY_NAMESPACE' => '1'}
def setup
@n = Namespace.new if Namespace.enabled?
end
def teardown
@n = nil
end
def test_namespace_availability
env_has_RUBY_NAMESPACE = (ENV['RUBY_NAMESPACE'].to_i == 1)
assert_equal env_has_RUBY_NAMESPACE, Namespace.enabled?
end
def test_current_namespace
pend unless Namespace.enabled?
main = Namespace.current
assert main.inspect.include?("main")
@n.require_relative('namespace/current')
assert_equal @n, @n::CurrentNamespace.in_require
assert_equal @n, @n::CurrentNamespace.in_method_call
assert_equal main, Namespace.current
end
def test_require_rb_separately
pend unless Namespace.enabled?
assert_raise(NameError) { NS_A }
assert_raise(NameError) { NS_B }
@n.require(File.join(__dir__, 'namespace', 'a.1_1_0'))
assert_not_nil @n::NS_A
assert_not_nil @n::NS_B
assert_equal "1.1.0", @n::NS_A::VERSION
assert_equal "yay 1.1.0", @n::NS_A.new.yay
assert_equal "1.1.0", @n::NS_B::VERSION
assert_equal "yay_b1", @n::NS_B.yay
assert_raise(NameError) { NS_A }
assert_raise(NameError) { NS_B }
end
def test_require_relative_rb_separately
pend unless Namespace.enabled?
assert_raise(NameError) { NS_A }
assert_raise(NameError) { NS_B }
@n.require_relative('namespace/a.1_1_0')
assert_not_nil @n::NS_A
assert_not_nil @n::NS_B
assert_equal "1.1.0", @n::NS_A::VERSION
assert_equal "yay 1.1.0", @n::NS_A.new.yay
assert_equal "1.1.0", @n::NS_B::VERSION
assert_equal "yay_b1", @n::NS_B.yay
assert_raise(NameError) { NS_A }
assert_raise(NameError) { NS_B }
end
def test_load_separately
pend unless Namespace.enabled?
assert_raise(NameError) { NS_A }
assert_raise(NameError) { NS_B }
@n.load(File.join(__dir__, 'namespace', 'a.1_1_0.rb'))
assert_not_nil @n::NS_A
assert_not_nil @n::NS_B
assert_equal "1.1.0", @n::NS_A::VERSION
assert_equal "yay 1.1.0", @n::NS_A.new.yay
assert_equal "1.1.0", @n::NS_B::VERSION
assert_equal "yay_b1", @n::NS_B.yay
assert_raise(NameError) { NS_A }
assert_raise(NameError) { NS_B }
end
def test_namespace_in_namespace
pend unless Namespace.enabled?
assert_raise(NameError) { NS1 }
assert_raise(NameError) { NS_A }
assert_raise(NameError) { NS_B }
@n.require_relative('namespace/ns')
assert_not_nil @n::NS1
assert_not_nil @n::NS1::NS_A
assert_not_nil @n::NS1::NS_B
assert_equal "1.1.0", @n::NS1::NS_A::VERSION
assert_equal "yay 1.1.0", @n::NS1::NS_A.new.yay
assert_equal "1.1.0", @n::NS1::NS_B::VERSION
assert_equal "yay_b1", @n::NS1::NS_B.yay
assert_raise(NameError) { NS1 }
assert_raise(NameError) { NS_A }
assert_raise(NameError) { NS_B }
end
def test_require_rb_2versions
pend unless Namespace.enabled?
assert_raise(NameError) { NS_A }
@n.require(File.join(__dir__, 'namespace', 'a.1_2_0'))
assert_equal "1.2.0", @n::NS_A::VERSION
assert_equal "yay 1.2.0", @n::NS_A.new.yay
n2 = Namespace.new
n2.require(File.join(__dir__, 'namespace', 'a.1_1_0'))
assert_equal "1.1.0", n2::NS_A::VERSION
assert_equal "yay 1.1.0", n2::NS_A.new.yay
# recheck @n is not affected by the following require
assert_equal "1.2.0", @n::NS_A::VERSION
assert_equal "yay 1.2.0", @n::NS_A.new.yay
assert_raise(NameError) { NS_A }
end
def test_raising_errors_in_require
pend unless Namespace.enabled?
assert_raise(RuntimeError, "Yay!") { @n.require(File.join(__dir__, 'namespace', 'raise')) }
assert Namespace.current.inspect.include?("main")
end
def test_autoload_in_namespace
pend unless Namespace.enabled?
assert_raise(NameError) { NS_A }
@n.require_relative('namespace/autoloading')
# autoloaded A is visible from global
assert_equal '1.1.0', @n::NS_A::VERSION
assert_raise(NameError) { NS_A }
# autoload trigger NS_B::BAR is valid even from global
assert_equal 'bar_b1', @n::NS_B::BAR
assert_raise(NameError) { NS_A }
assert_raise(NameError) { NS_B }
end
def test_continuous_top_level_method_in_a_namespace
pend unless Namespace.enabled?
@n.require_relative('namespace/define_toplevel')
@n.require_relative('namespace/call_toplevel')
assert_raise(NameError) { foo }
end
def test_top_level_methods_in_namespace
pend # TODO: fix loading/current namespace detection
pend unless Namespace.enabled?
@n.require_relative('namespace/top_level')
assert_equal "yay!", @n::Foo.foo
assert_raise(NameError) { yaaay }
assert_equal "foo", @n::Bar.bar
assert_raise_with_message(RuntimeError, "boooo") { @n::Baz.baz }
end
def test_proc_defined_in_namespace_refers_module_in_namespace
pend unless Namespace.enabled?
# require_relative dosn't work well in assert_separately even with __FILE__ and __LINE__
assert_separately([ENV_ENABLE_NAMESPACE], __FILE__, __LINE__, "here = '#{__dir__}'; #{<<~"begin;"}\n#{<<~'end;'}")
begin;
ns1 = Namespace.new
ns1.require(File.join("#{here}", 'namespace/proc_callee'))
proc_v = ns1::Foo.callee
assert_raise(NameError) { Target }
assert ns1::Target
assert_equal "fooooo", proc_v.call # refers Target in the namespace ns1
ns1.require(File.join("#{here}", 'namespace/proc_caller'))
assert_equal "fooooo", ns1::Bar.caller(proc_v)
ns2 = Namespace.new
ns2.require(File.join("#{here}", 'namespace/proc_caller'))
assert_raise(NameError) { ns2::Target }
assert_equal "fooooo", ns2::Bar.caller(proc_v) # refers Target in the namespace ns1
end;
end
def test_proc_defined_globally_refers_global_module
pend unless Namespace.enabled?
# require_relative dosn't work well in assert_separately even with __FILE__ and __LINE__
assert_separately([ENV_ENABLE_NAMESPACE], __FILE__, __LINE__, "here = '#{__dir__}'; #{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
begin;
require(File.join("#{here}", 'namespace/proc_callee'))
def Target.foo
"yay"
end
proc_v = Foo.callee
assert Target
assert_equal "yay", proc_v.call # refers global Foo
ns1 = Namespace.new
ns1.require(File.join("#{here}", 'namespace/proc_caller'))
assert_equal "yay", ns1::Bar.caller(proc_v)
ns2 = Namespace.new
ns2.require(File.join("#{here}", 'namespace/proc_callee'))
ns2.require(File.join("#{here}", 'namespace/proc_caller'))
assert_equal "fooooo", ns2::Foo.callee.call
assert_equal "yay", ns2::Bar.caller(proc_v) # should refer the global Target, not Foo in ns2
end;
end
def test_methods_added_in_namespace_are_invisible_globally
pend unless Namespace.enabled?
@n.require_relative('namespace/string_ext')
assert_equal "yay", @n::Bar.yay
assert_raise(NoMethodError){ String.new.yay }
end
def test_continuous_method_definitions_in_a_namespace
pend unless Namespace.enabled?
@n.require_relative('namespace/string_ext')
assert_equal "yay", @n::Bar.yay
@n.require_relative('namespace/string_ext_caller')
assert_equal "yay", @n::Foo.yay
@n.require_relative('namespace/string_ext_calling')
end
def test_methods_added_in_namespace_later_than_caller_code
pend unless Namespace.enabled?
@n.require_relative('namespace/string_ext_caller')
@n.require_relative('namespace/string_ext')
assert_equal "yay", @n::Bar.yay
assert_equal "yay", @n::Foo.yay
end
def test_method_added_in_namespace_are_available_on_eval
pend unless Namespace.enabled?
@n.require_relative('namespace/string_ext')
@n.require_relative('namespace/string_ext_eval_caller')
assert_equal "yay", @n::Baz.yay
end
def test_method_added_in_namespace_are_available_on_eval_with_binding
pend unless Namespace.enabled?
@n.require_relative('namespace/string_ext')
@n.require_relative('namespace/string_ext_eval_caller')
assert_equal "yay, yay!", @n::Baz.yay_with_binding
end
def test_methods_and_constants_added_by_include
pend unless Namespace.enabled?
@n.require_relative('namespace/open_class_with_include')
assert_equal "I'm saying foo 1", @n::OpenClassWithInclude.say
assert_equal "I'm saying foo 1", @n::OpenClassWithInclude.say_foo
assert_equal "I'm saying foo 1", @n::OpenClassWithInclude.say_with_obj("wow")
assert_raise(NameError) { String::FOO }
assert_equal "foo 1", @n::OpenClassWithInclude.refer_foo
end
end
module ProcLookupTestA
module B
VALUE = 111
end
end
class TestNamespace < Test::Unit::TestCase
def make_proc_from_block(&b)
b
end
def test_proc_from_main_works_with_global_definitions
pend unless Namespace.enabled?
@n.require_relative('namespace/procs')
proc_and_labels = [
[Proc.new { String.new.yay }, "Proc.new"],
[proc { String.new.yay }, "proc{}"],
[lambda { String.new.yay }, "lambda{}"],
[->(){ String.new.yay }, "->(){}"],
[make_proc_from_block { String.new.yay }, "make_proc_from_block"],
[@n::ProcInNS.make_proc_from_block { String.new.yay }, "make_proc_from_block in @n"],
]
proc_and_labels.each do |str_pr|
pr, pr_label = str_pr
assert_raise(NoMethodError, "NoMethodError expected: #{pr_label}, called in main") { pr.call }
assert_raise(NoMethodError, "NoMethodError expected: #{pr_label}, called in @n") { @n::ProcInNS.call_proc(pr) }
end
const_and_labels = [
[Proc.new { ProcLookupTestA::B::VALUE }, "Proc.new"],
[proc { ProcLookupTestA::B::VALUE }, "proc{}"],
[lambda { ProcLookupTestA::B::VALUE }, "lambda{}"],
[->(){ ProcLookupTestA::B::VALUE }, "->(){}"],
[make_proc_from_block { ProcLookupTestA::B::VALUE }, "make_proc_from_block"],
[@n::ProcInNS.make_proc_from_block { ProcLookupTestA::B::VALUE }, "make_proc_from_block in @n"],
]
const_and_labels.each do |const_pr|
pr, pr_label = const_pr
assert_equal 111, pr.call, "111 expected, #{pr_label} called in main"
assert_equal 111, @n::ProcInNS.call_proc(pr), "111 expected, #{pr_label} called in @n"
end
end
def test_proc_from_namespace_works_with_definitions_in_namespace
pend unless Namespace.enabled?
@n.require_relative('namespace/procs')
proc_types = [:proc_new, :proc_f, :lambda_f, :lambda_l, :block]
proc_types.each do |proc_type|
assert_equal 222, @n::ProcInNS.make_const_proc(proc_type).call, "ProcLookupTestA::B::VALUE should be 222 in @n"
assert_equal "foo", @n::ProcInNS.make_str_const_proc(proc_type).call, "String::FOO should be \"foo\" in @n"
assert_equal "yay", @n::ProcInNS.make_str_proc(proc_type).call, "String#yay should be callable in @n"
#
# TODO: method calls not-in-methods nor procs can't handle the current namespace correctly.
#
# assert_equal "yay,foo,222",
# @n::ProcInNS.const_get(('CONST_' + proc_type.to_s.upcase).to_sym).call,
# "Proc assigned to constants should refer constants correctly in @n"
end
end
def test_class_module_singleton_methods
pend unless Namespace.enabled?
@n.require_relative('namespace/singleton_methods')
assert_equal "Good evening!", @n::SingletonMethods.string_greeing # def self.greeting
assert_equal 42, @n::SingletonMethods.integer_answer # class << self; def answer
assert_equal([], @n::SingletonMethods.array_blank) # def self.blank w/ instance methods
assert_equal({status: 200, body: 'OK'}, @n::SingletonMethods.hash_http_200) # class << self; def ... w/ instance methods
assert_equal([4, 4], @n::SingletonMethods.array_instance_methods_return_size([1, 2, 3, 4]))
assert_equal([3, 3], @n::SingletonMethods.hash_instance_methods_return_size({a: 2, b: 4, c: 8}))
assert_raise(NoMethodError) { String.greeting }
assert_raise(NoMethodError) { Integer.answer }
assert_raise(NoMethodError) { Array.blank }
assert_raise(NoMethodError) { Hash.http_200 }
end
def test_add_constants_in_namespace
pend unless Namespace.enabled?
String.const_set(:STR_CONST0, 999)
assert_equal 999, String::STR_CONST0
assert_equal 999, String.const_get(:STR_CONST0)
assert_raise(NameError) { String.const_get(:STR_CONST1) }
assert_raise(NameError) { String::STR_CONST2 }
assert_raise(NameError) { String::STR_CONST3 }
assert_raise(NameError) { Integer.const_get(:INT_CONST1) }
EnvUtil.suppress_warning do
@n.require_relative('namespace/consts')
end
assert_equal 999, String::STR_CONST0
assert_raise(NameError) { String::STR_CONST1 }
assert_raise(NameError) { String::STR_CONST2 }
assert_raise(NameError) { Integer::INT_CONST1 }
assert_not_nil @n::ForConsts.refer_all
assert_equal 112, @n::ForConsts.refer1
assert_equal 112, @n::ForConsts.get1
assert_equal 112, @n::ForConsts::CONST1
assert_equal 222, @n::ForConsts.refer2
assert_equal 222, @n::ForConsts.get2
assert_equal 222, @n::ForConsts::CONST2
assert_equal 333, @n::ForConsts.refer3
assert_equal 333, @n::ForConsts.get3
assert_equal 333, @n::ForConsts::CONST3
EnvUtil.suppress_warning do
@n::ForConsts.const_set(:CONST3, 334)
end
assert_equal 334, @n::ForConsts::CONST3
assert_equal 334, @n::ForConsts.refer3
assert_equal 334, @n::ForConsts.get3
assert_equal 10, @n::ForConsts.refer_top_const
# use Proxy object to use usual methods instead of singleton methods
proxy = @n::ForConsts::Proxy.new
assert_raise(NameError){ proxy.call_str_refer0 }
assert_raise(NameError){ proxy.call_str_get0 }
proxy.call_str_set0(30)
assert_equal 30, proxy.call_str_refer0
assert_equal 30, proxy.call_str_get0
assert_equal 999, String::STR_CONST0
proxy.call_str_remove0
assert_raise(NameError){ proxy.call_str_refer0 }
assert_raise(NameError){ proxy.call_str_get0 }
assert_equal 112, proxy.call_str_refer1
assert_equal 112, proxy.call_str_get1
assert_equal 223, proxy.call_str_refer2
assert_equal 223, proxy.call_str_get2
assert_equal 333, proxy.call_str_refer3
assert_equal 333, proxy.call_str_get3
EnvUtil.suppress_warning do
proxy.call_str_set3
end
assert_equal 334, proxy.call_str_refer3
assert_equal 334, proxy.call_str_get3
assert_equal 1, proxy.refer_int_const1
assert_equal 999, String::STR_CONST0
assert_raise(NameError) { String::STR_CONST1 }
assert_raise(NameError) { String::STR_CONST2 }
assert_raise(NameError) { String::STR_CONST3 }
assert_raise(NameError) { Integer::INT_CONST1 }
end
def test_global_variables
default_l = $-0
default_f = $,
pend unless Namespace.enabled?
assert_equal "\n", $-0 # equal to $/, line splitter
assert_equal nil, $, # field splitter
@n.require_relative('namespace/global_vars')
# read first
assert_equal "\n", @n::LineSplitter.read
@n::LineSplitter.write("\r\n")
assert_equal "\r\n", @n::LineSplitter.read
assert_equal "\n", $-0
# write first
@n::FieldSplitter.write(",")
assert_equal ",", @n::FieldSplitter.read
assert_equal nil, $,
# used only in ns
assert !global_variables.include?(:$used_only_in_ns)
@n::UniqueGvar.write(123)
assert_equal 123, @n::UniqueGvar.read
assert_nil $used_only_in_ns
# Kernel#global_variables returns the sum of all gvars.
global_gvars = global_variables.sort
assert_equal global_gvars, @n::UniqueGvar.gvars_in_ns.sort
@n::UniqueGvar.write_only(456)
assert_equal (global_gvars + [:$write_only_var_in_ns]).sort, @n::UniqueGvar.gvars_in_ns.sort
assert_equal (global_gvars + [:$write_only_var_in_ns]).sort, global_variables.sort
ensure
EnvUtil.suppress_warning do
$-0 = default_l
$, = default_f
end
end
def test_load_path_and_loaded_features
pend unless Namespace.enabled?
assert $LOAD_PATH.respond_to?(:resolve_feature_path)
@n.require_relative('namespace/load_path')
assert_not_equal $LOAD_PATH, @n::LoadPathCheck::FIRST_LOAD_PATH
assert @n::LoadPathCheck::FIRST_LOAD_PATH_RESPOND_TO_RESOLVE
namespace_dir = File.join(__dir__, 'namespace')
# TODO: $LOADED_FEATURES in method calls should refer the current namespace in addition to the loading namespace.
# assert @n::LoadPathCheck.current_loaded_features.include?(File.join(namespace_dir, 'blank1.rb'))
# assert !@n::LoadPathCheck.current_loaded_features.include?(File.join(namespace_dir, 'blank2.rb'))
# assert @n::LoadPathCheck.require_blank2
# assert @n::LoadPathCheck.current_loaded_features.include?(File.join(namespace_dir, 'blank2.rb'))
assert !$LOADED_FEATURES.include?(File.join(namespace_dir, 'blank1.rb'))
assert !$LOADED_FEATURES.include?(File.join(namespace_dir, 'blank2.rb'))
end
end

View File

@ -260,6 +260,8 @@ class TestRubyOptions < Test::Unit::TestCase
end end
def test_parser_flag def test_parser_flag
omit if ENV["RUBYOPT"]&.include?("--parser=")
assert_in_out_err(%w(--parser=prism -e) + ["puts :hi"], "", %w(hi), []) assert_in_out_err(%w(--parser=prism -e) + ["puts :hi"], "", %w(hi), [])
assert_in_out_err(%w(--parser=prism --dump=parsetree -e _=:hi), "", /"hi"/, []) assert_in_out_err(%w(--parser=prism --dump=parsetree -e _=:hi), "", /"hi"/, [])

View File

@ -25,6 +25,7 @@
#include "internal/error.h" #include "internal/error.h"
#include "internal/eval.h" #include "internal/eval.h"
#include "internal/hash.h" #include "internal/hash.h"
#include "internal/namespace.h"
#include "internal/object.h" #include "internal/object.h"
#include "internal/gc.h" #include "internal/gc.h"
#include "internal/re.h" #include "internal/re.h"
@ -109,10 +110,10 @@ classname(VALUE klass, bool *permanent)
{ {
*permanent = false; *permanent = false;
VALUE classpath = RCLASS_EXT(klass)->classpath; VALUE classpath = RCLASS_CLASSPATH(klass);
if (classpath == 0) return Qnil; if (classpath == 0) return Qnil;
*permanent = RCLASS_EXT(klass)->permanent_classpath; *permanent = RCLASS_PERMANENT_CLASSPATH_P(klass);
return classpath; return classpath;
} }
@ -210,7 +211,7 @@ static enum rb_id_table_iterator_result
set_sub_temporary_name_i(ID id, VALUE val, void *data) set_sub_temporary_name_i(ID id, VALUE val, void *data)
{ {
val = ((rb_const_entry_t *)val)->value; val = ((rb_const_entry_t *)val)->value;
if (rb_namespace_p(val) && !RCLASS_EXT(val)->permanent_classpath) { if (rb_namespace_p(val) && !RCLASS_PERMANENT_CLASSPATH_P(val)) {
VALUE arg = (VALUE)data; VALUE arg = (VALUE)data;
struct sub_temporary_name_args *args = data; struct sub_temporary_name_args *args = data;
args->last = id; args->last = id;
@ -222,7 +223,7 @@ set_sub_temporary_name_i(ID id, VALUE val, void *data)
static void static void
set_sub_temporary_name_foreach(VALUE mod, struct sub_temporary_name_args *args, VALUE name) set_sub_temporary_name_foreach(VALUE mod, struct sub_temporary_name_args *args, VALUE name)
{ {
RCLASS_SET_CLASSPATH(mod, name, FALSE); RCLASS_WRITE_CLASSPATH(mod, name, FALSE);
struct rb_id_table *tbl = RCLASS_CONST_TBL(mod); struct rb_id_table *tbl = RCLASS_CONST_TBL(mod);
if (!tbl) return; if (!tbl) return;
if (!name) { if (!name) {
@ -296,7 +297,7 @@ VALUE
rb_mod_set_temporary_name(VALUE mod, VALUE name) rb_mod_set_temporary_name(VALUE mod, VALUE name)
{ {
// We don't allow setting the name if the classpath is already permanent: // We don't allow setting the name if the classpath is already permanent:
if (RCLASS_EXT(mod)->permanent_classpath) { if (RCLASS_PERMANENT_CLASSPATH_P(mod)) {
rb_raise(rb_eRuntimeError, "can't change permanent name"); rb_raise(rb_eRuntimeError, "can't change permanent name");
} }
@ -529,6 +530,7 @@ struct rb_global_variable {
rb_gvar_marker_t *marker; rb_gvar_marker_t *marker;
rb_gvar_compact_t *compactor; rb_gvar_compact_t *compactor;
struct trace_var *trace; struct trace_var *trace;
bool namespace_ready;
}; };
struct rb_global_entry { struct rb_global_entry {
@ -604,6 +606,13 @@ rb_gvar_ractor_local(const char *name)
entry->ractor_local = true; entry->ractor_local = true;
} }
void
rb_gvar_namespace_ready(const char *name)
{
struct rb_global_entry *entry = rb_find_global_entry(rb_intern(name));
entry->var->namespace_ready = true;
}
static void static void
rb_gvar_undef_compactor(void *var) rb_gvar_undef_compactor(void *var)
{ {
@ -629,6 +638,7 @@ rb_global_entry(ID id)
var->block_trace = 0; var->block_trace = 0;
var->trace = 0; var->trace = 0;
var->namespace_ready = false;
rb_id_table_insert(rb_global_tbl, id, (VALUE)entry); rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
} }
return entry; return entry;
@ -982,13 +992,27 @@ rb_gvar_set_entry(struct rb_global_entry *entry, VALUE val)
return val; return val;
} }
#define USE_NAMESPACE_GVAR_TBL(ns,entry) \
(NAMESPACE_OPTIONAL_P(ns) && \
(!entry || !entry->var->namespace_ready || entry->var->setter != rb_gvar_readonly_setter))
VALUE VALUE
rb_gvar_set(ID id, VALUE val) rb_gvar_set(ID id, VALUE val)
{ {
VALUE retval;
struct rb_global_entry *entry; struct rb_global_entry *entry;
const rb_namespace_t *ns = rb_current_namespace();
entry = rb_global_entry(id); entry = rb_global_entry(id);
return rb_gvar_set_entry(entry, val); if (USE_NAMESPACE_GVAR_TBL(ns, entry)) {
rb_hash_aset(ns->gvar_tbl, rb_id2sym(entry->id), val);
retval = val;
// TODO: think about trace
} else {
retval = rb_gvar_set_entry(entry, val);
}
return retval;
} }
VALUE VALUE
@ -1000,9 +1024,27 @@ rb_gv_set(const char *name, VALUE val)
VALUE VALUE
rb_gvar_get(ID id) rb_gvar_get(ID id)
{ {
VALUE retval, gvars, key;
struct rb_global_entry *entry = rb_global_entry(id); struct rb_global_entry *entry = rb_global_entry(id);
struct rb_global_variable *var = entry->var; struct rb_global_variable *var = entry->var;
return (*var->getter)(entry->id, var->data); const rb_namespace_t *ns = rb_current_namespace();
if (USE_NAMESPACE_GVAR_TBL(ns, entry)) {
gvars = ns->gvar_tbl;
key = rb_id2sym(entry->id);
if (RTEST(rb_hash_has_key(gvars, key))) { // this gvar is already cached
retval = rb_hash_aref(gvars, key);
} else {
retval = (*var->getter)(entry->id, var->data);
if (rb_obj_respond_to(retval, rb_intern("clone"), 1)) {
retval = rb_funcall(retval, rb_intern("clone"), 0);
}
rb_hash_aset(gvars, key, retval);
}
} else {
retval = (*var->getter)(entry->id, var->data);
}
return retval;
} }
VALUE VALUE
@ -1056,6 +1098,7 @@ rb_f_global_variables(void)
if (!rb_ractor_main_p()) { if (!rb_ractor_main_p()) {
rb_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors"); rb_raise(rb_eRactorIsolationError, "can not access global variables from non-main Ractors");
} }
/* gvar access (get/set) in namespaces creates gvar entries globally */
rb_id_table_foreach(rb_global_tbl, gvar_i, (void *)ary); rb_id_table_foreach(rb_global_tbl, gvar_i, (void *)ary);
if (!NIL_P(backref)) { if (!NIL_P(backref)) {
@ -1335,7 +1378,7 @@ rb_obj_field_get(VALUE obj, rb_shape_t *target_shape)
case T_CLASS: case T_CLASS:
case T_MODULE: case T_MODULE:
ASSERT_vm_locking(); ASSERT_vm_locking();
fields = RCLASS_FIELDS(obj); fields = RCLASS_PRIME_FIELDS(obj);
break; break;
case T_OBJECT: case T_OBJECT:
fields = ROBJECT_FIELDS(obj); fields = ROBJECT_FIELDS(obj);
@ -1392,7 +1435,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
found = rb_shape_get_iv_index(shape, id, &index); found = rb_shape_get_iv_index(shape, id, &index);
if (found) { if (found) {
ivar_list = RCLASS_FIELDS(obj); ivar_list = RCLASS_PRIME_FIELDS(obj);
RUBY_ASSERT(ivar_list); RUBY_ASSERT(ivar_list);
val = ivar_list[index]; val = ivar_list[index];
@ -1501,7 +1544,7 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
switch (BUILTIN_TYPE(obj)) { switch (BUILTIN_TYPE(obj)) {
case T_CLASS: case T_CLASS:
case T_MODULE: case T_MODULE:
table = RCLASS_FIELDS_HASH(obj); table = RCLASS_WRITABLE_FIELDS_HASH(obj);
break; break;
case T_OBJECT: case T_OBJECT:
@ -1551,7 +1594,7 @@ obj_transition_too_complex(VALUE obj, st_table *table)
break; break;
case T_CLASS: case T_CLASS:
case T_MODULE: case T_MODULE:
old_fields = RCLASS_FIELDS(obj); old_fields = RCLASS_PRIME_FIELDS(obj);
rb_shape_set_shape_id(obj, shape_id); rb_shape_set_shape_id(obj, shape_id);
RCLASS_SET_FIELDS_HASH(obj, table); RCLASS_SET_FIELDS_HASH(obj, table);
break; break;
@ -2124,7 +2167,7 @@ rb_ivar_defined(VALUE obj, ID id)
switch (BUILTIN_TYPE(obj)) { switch (BUILTIN_TYPE(obj)) {
case T_CLASS: case T_CLASS:
case T_MODULE: case T_MODULE:
table = (st_table *)RCLASS_FIELDS(obj); table = (st_table *)RCLASS_FIELDS_HASH(obj);
break; break;
case T_OBJECT: case T_OBJECT:
@ -2188,7 +2231,8 @@ iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_fu
break; break;
case T_CLASS: case T_CLASS:
case T_MODULE: case T_MODULE:
iv_list = RCLASS_FIELDS(itr_data->obj); RUBY_ASSERT(!rb_shape_obj_too_complex_p(itr_data->obj));
iv_list = RCLASS_PRIME_FIELDS(itr_data->obj);
break; break;
default: default:
iv_list = itr_data->fields_tbl->as.shape.fields; iv_list = itr_data->fields_tbl->as.shape.fields;
@ -2280,7 +2324,7 @@ class_fields_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg,
}; };
if (rb_shape_obj_too_complex_p(obj)) { if (rb_shape_obj_too_complex_p(obj)) {
rb_st_foreach(RCLASS_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data); rb_st_foreach(RCLASS_WRITABLE_FIELDS_HASH(obj), each_hash_iv, (st_data_t)&itr_data);
} }
else { else {
iterate_over_shapes_with_callback(shape, func, &itr_data); iterate_over_shapes_with_callback(shape, func, &itr_data);
@ -2701,7 +2745,7 @@ autoload_data(VALUE mod, ID id)
// If we are called with a non-origin ICLASS, fetch the autoload data from // If we are called with a non-origin ICLASS, fetch the autoload data from
// the original module. // the original module.
if (RB_TYPE_P(mod, T_ICLASS)) { if (RB_TYPE_P(mod, T_ICLASS)) {
if (FL_TEST_RAW(mod, RICLASS_IS_ORIGIN)) { if (RICLASS_IS_ORIGIN_P(mod)) {
return 0; return 0;
} }
else { else {
@ -2729,6 +2773,10 @@ struct autoload_const {
// The shared "autoload_data" if multiple constants are defined from the same feature. // The shared "autoload_data" if multiple constants are defined from the same feature.
VALUE autoload_data_value; VALUE autoload_data_value;
// The namespace object when the autoload is called in a user namespace
// Otherwise, Qnil means the builtin namespace, Qfalse means unspecified.
VALUE namespace;
// The module we are loading a constant into. // The module we are loading a constant into.
VALUE module; VALUE module;
@ -2866,6 +2914,70 @@ get_autoload_data(VALUE autoload_const_value, struct autoload_const **autoload_c
return autoload_data; return autoload_data;
} }
struct autoload_copy_table_data {
VALUE dst_tbl_value;
struct st_table *dst_tbl;
const rb_namespace_t *ns;
};
static int
autoload_copy_table_for_namespace_i(st_data_t key, st_data_t value, st_data_t arg)
{
struct autoload_const *autoload_const;
struct autoload_copy_table_data *data = (struct autoload_copy_table_data *)arg;
struct st_table *tbl = data->dst_tbl;
VALUE tbl_value = data->dst_tbl_value;
const rb_namespace_t *ns = data->ns;
VALUE src_value = (VALUE)value;
struct autoload_const *src_const = rb_check_typeddata(src_value, &autoload_const_type);
// autoload_data can be shared between copies because the feature is equal between copies.
VALUE autoload_data_value = src_const->autoload_data_value;
struct autoload_data *autoload_data = rb_check_typeddata(autoload_data_value, &autoload_data_type);
VALUE new_value = TypedData_Make_Struct(0, struct autoload_const, &autoload_const_type, autoload_const);
autoload_const->namespace = rb_get_namespace_object((rb_namespace_t *)ns);
autoload_const->module = src_const->module;
autoload_const->name = src_const->name;
autoload_const->value = src_const->value;
autoload_const->flag = src_const->flag;
autoload_const->autoload_data_value = autoload_data_value;
ccan_list_add_tail(&autoload_data->constants, &autoload_const->cnode);
st_insert(tbl, (st_data_t)autoload_const->name, (st_data_t)new_value);
RB_OBJ_WRITTEN(tbl_value, Qundef, new_value);
return ST_CONTINUE;
}
void
rb_autoload_copy_table_for_namespace(st_table *iv_ptr, const rb_namespace_t *ns)
{
struct st_table *src_tbl, *dst_tbl;
VALUE src_tbl_value, dst_tbl_value;
if (!rb_st_lookup(iv_ptr, (st_data_t)autoload, (st_data_t *)&src_tbl_value)) {
// the class has no autoload table yet.
return;
}
if (!RTEST(src_tbl_value) || !(src_tbl = check_autoload_table(src_tbl_value))) {
// the __autoload__ ivar value isn't autoload table value.
return;
}
src_tbl = check_autoload_table(src_tbl_value);
dst_tbl_value = TypedData_Wrap_Struct(0, &autoload_table_type, NULL);
RTYPEDDATA_DATA(dst_tbl_value) = dst_tbl = st_init_numtable();
struct autoload_copy_table_data data = {
.dst_tbl_value = dst_tbl_value,
.dst_tbl = dst_tbl,
.ns = ns,
};
st_foreach(src_tbl, autoload_copy_table_for_namespace_i, (st_data_t)&data);
st_insert(iv_ptr, (st_data_t)autoload, (st_data_t)dst_tbl_value);
}
void void
rb_autoload(VALUE module, ID name, const char *feature) rb_autoload(VALUE module, ID name, const char *feature)
{ {
@ -2883,6 +2995,7 @@ struct autoload_arguments {
VALUE module; VALUE module;
ID name; ID name;
VALUE feature; VALUE feature;
VALUE namespace;
}; };
static VALUE static VALUE
@ -2952,6 +3065,7 @@ autoload_synchronized(VALUE _arguments)
{ {
struct autoload_const *autoload_const; struct autoload_const *autoload_const;
VALUE autoload_const_value = TypedData_Make_Struct(0, struct autoload_const, &autoload_const_type, autoload_const); VALUE autoload_const_value = TypedData_Make_Struct(0, struct autoload_const, &autoload_const_type, autoload_const);
autoload_const->namespace = arguments->namespace;
autoload_const->module = arguments->module; autoload_const->module = arguments->module;
autoload_const->name = arguments->name; autoload_const->name = arguments->name;
autoload_const->value = Qundef; autoload_const->value = Qundef;
@ -2968,6 +3082,9 @@ autoload_synchronized(VALUE _arguments)
void void
rb_autoload_str(VALUE module, ID name, VALUE feature) rb_autoload_str(VALUE module, ID name, VALUE feature)
{ {
const rb_namespace_t *ns = rb_current_namespace();
VALUE current_namespace = rb_get_namespace_object((rb_namespace_t *)ns);
if (!rb_is_const_id(name)) { if (!rb_is_const_id(name)) {
rb_raise(rb_eNameError, "autoload must be constant name: %"PRIsVALUE"", QUOTE_ID(name)); rb_raise(rb_eNameError, "autoload must be constant name: %"PRIsVALUE"", QUOTE_ID(name));
} }
@ -2981,6 +3098,7 @@ rb_autoload_str(VALUE module, ID name, VALUE feature)
.module = module, .module = module,
.name = name, .name = name,
.feature = feature, .feature = feature,
.namespace = current_namespace,
}; };
VALUE result = rb_mutex_synchronize(autoload_mutex, autoload_synchronized, (VALUE)&arguments); VALUE result = rb_mutex_synchronize(autoload_mutex, autoload_synchronized, (VALUE)&arguments);
@ -3241,22 +3359,82 @@ autoload_apply_constants(VALUE _arguments)
return Qtrue; return Qtrue;
} }
struct autoload_feature_require_data {
struct autoload_load_arguments *arguments;
VALUE receiver;
VALUE feature;
};
static VALUE
autoload_feature_require_in_builtin(VALUE arg)
{
struct autoload_feature_require_data *data = (struct autoload_feature_require_data *)arg;
VALUE result = rb_funcall(data->receiver, rb_intern("require"), 1, data->feature);
if (RTEST(result)) {
return rb_mutex_synchronize(autoload_mutex, autoload_apply_constants, (VALUE)data->arguments);
}
return Qnil;
}
static VALUE
autoload_feature_require_ensure_in_builtin(VALUE _arg)
{
/*
* The gccct should be cleared again after the rb_funcall() to remove
* the inconsistent cache entry against the current namespace.
*/
rb_gccct_clear_table(Qnil);
rb_namespace_disable_builtin();
return Qnil;
}
static VALUE
autoload_feature_require_in_builtin_wrap(VALUE arg)
{
return rb_ensure(autoload_feature_require_in_builtin, arg,
autoload_feature_require_ensure_in_builtin, Qnil);
}
static VALUE static VALUE
autoload_feature_require(VALUE _arguments) autoload_feature_require(VALUE _arguments)
{ {
VALUE receiver = rb_vm_top_self();
struct autoload_load_arguments *arguments = (struct autoload_load_arguments*)_arguments; struct autoload_load_arguments *arguments = (struct autoload_load_arguments*)_arguments;
struct autoload_const *autoload_const = arguments->autoload_const; struct autoload_const *autoload_const = arguments->autoload_const;
VALUE autoload_namespace = autoload_const->namespace;
// We save this for later use in autoload_apply_constants: // We save this for later use in autoload_apply_constants:
arguments->autoload_data = rb_check_typeddata(autoload_const->autoload_data_value, &autoload_data_type); arguments->autoload_data = rb_check_typeddata(autoload_const->autoload_data_value, &autoload_data_type);
VALUE result = rb_funcall(rb_vm_top_self(), rb_intern("require"), 1, arguments->autoload_data->feature); if (NIL_P(autoload_namespace)) {
rb_namespace_enable_builtin();
/*
* Clear the global cc cache table because the require method can be different from the current
* namespace's one and it may cause inconsistent cc-cme states.
* For example, the assertion below may fail in gccct_method_search();
* VM_ASSERT(vm_cc_check_cme(cc, rb_callable_method_entry(klass, mid)))
*/
rb_gccct_clear_table(Qnil);
struct autoload_feature_require_data data = {
.arguments = arguments,
.receiver = receiver,
.feature = arguments->autoload_data->feature,
};
return rb_namespace_exec(rb_builtin_namespace(), autoload_feature_require_in_builtin_wrap, (VALUE)&data);
}
if (RTEST(autoload_namespace) && NAMESPACE_OPTIONAL_P(rb_get_namespace_t(autoload_namespace))) {
receiver = autoload_namespace;
}
VALUE result = rb_funcall(receiver, rb_intern("require"), 1, arguments->autoload_data->feature);
if (RTEST(result)) { if (RTEST(result)) {
return rb_mutex_synchronize(autoload_mutex, autoload_apply_constants, _arguments); return rb_mutex_synchronize(autoload_mutex, autoload_apply_constants, _arguments);
} }
return result; return result;
} }
@ -3580,6 +3758,8 @@ rb_mod_remove_const(VALUE mod, VALUE name)
return rb_const_remove(mod, id); return rb_const_remove(mod, id);
} }
static rb_const_entry_t * const_lookup(struct rb_id_table *tbl, ID id);
VALUE VALUE
rb_const_remove(VALUE mod, ID id) rb_const_remove(VALUE mod, ID id)
{ {
@ -3589,7 +3769,7 @@ rb_const_remove(VALUE mod, ID id)
rb_check_frozen(mod); rb_check_frozen(mod);
ce = rb_const_lookup(mod, id); ce = rb_const_lookup(mod, id);
if (!ce || !rb_id_table_delete(RCLASS_CONST_TBL(mod), id)) { if (!ce || !rb_id_table_delete(RCLASS_WRITABLE_CONST_TBL(mod), id)) {
if (rb_const_defined_at(mod, id)) { if (rb_const_defined_at(mod, id)) {
rb_name_err_raise("cannot remove %2$s::%1$s", mod, ID2SYM(id)); rb_name_err_raise("cannot remove %2$s::%1$s", mod, ID2SYM(id));
} }
@ -3607,7 +3787,11 @@ rb_const_remove(VALUE mod, ID id)
val = Qnil; val = Qnil;
} }
ruby_xfree(ce); if (ce == const_lookup(RCLASS_PRIME_CONST_TBL(mod), id)) {
// skip free'ing the ce because it still exists in the prime classext
} else {
ruby_xfree(ce);
}
return val; return val;
} }
@ -3829,8 +4013,8 @@ set_namespace_path_i(ID id, VALUE v, void *payload)
} }
set_namespace_path(value, build_const_path(parental_path, id)); set_namespace_path(value, build_const_path(parental_path, id));
if (!RCLASS_EXT(value)->permanent_classpath) { if (!RCLASS_PERMANENT_CLASSPATH_P(value)) {
RCLASS_SET_CLASSPATH(value, 0, false); RCLASS_WRITE_CLASSPATH(value, 0, false);
} }
return ID_TABLE_CONTINUE; return ID_TABLE_CONTINUE;
@ -3848,7 +4032,7 @@ set_namespace_path(VALUE named_namespace, VALUE namespace_path)
RB_VM_LOCK_ENTER(); RB_VM_LOCK_ENTER();
{ {
RCLASS_SET_CLASSPATH(named_namespace, namespace_path, true); RCLASS_WRITE_CLASSPATH(named_namespace, namespace_path, true);
if (const_table) { if (const_table) {
rb_id_table_foreach(const_table, set_namespace_path_i, &namespace_path); rb_id_table_foreach(const_table, set_namespace_path_i, &namespace_path);
@ -3884,9 +4068,10 @@ const_set(VALUE klass, ID id, VALUE val)
RB_VM_LOCK_ENTER(); RB_VM_LOCK_ENTER();
{ {
struct rb_id_table *tbl = RCLASS_CONST_TBL(klass); struct rb_id_table *tbl = RCLASS_WRITABLE_CONST_TBL(klass);
if (!tbl) { if (!tbl) {
RCLASS_CONST_TBL(klass) = tbl = rb_id_table_create(0); tbl = rb_id_table_create(0);
RCLASS_WRITE_CONST_TBL(klass, tbl, false);
rb_clear_constant_cache_for_id(id); rb_clear_constant_cache_for_id(id);
ce = ZALLOC(rb_const_entry_t); ce = ZALLOC(rb_const_entry_t);
rb_id_table_insert(tbl, id, (VALUE)ce); rb_id_table_insert(tbl, id, (VALUE)ce);
@ -4010,6 +4195,7 @@ const_tbl_update(struct autoload_const *ac, int autoload_force)
setup_const_entry(ce, klass, val, visibility); setup_const_entry(ce, klass, val, visibility);
} }
else { else {
tbl = RCLASS_WRITABLE_CONST_TBL(klass);
rb_clear_constant_cache_for_id(id); rb_clear_constant_cache_for_id(id);
ce = ZALLOC(rb_const_entry_t); ce = ZALLOC(rb_const_entry_t);
@ -4172,7 +4358,7 @@ static int
cvar_lookup_at(VALUE klass, ID id, st_data_t *v) cvar_lookup_at(VALUE klass, ID id, st_data_t *v)
{ {
if (RB_TYPE_P(klass, T_ICLASS)) { if (RB_TYPE_P(klass, T_ICLASS)) {
if (FL_TEST_RAW(klass, RICLASS_IS_ORIGIN)) { if (RICLASS_IS_ORIGIN_P(klass)) {
return 0; return 0;
} }
else { else {
@ -4277,10 +4463,11 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
int result = rb_class_ivar_set(target, id, val); int result = rb_class_ivar_set(target, id, val);
struct rb_id_table *rb_cvc_tbl = RCLASS_CVC_TBL(target); struct rb_id_table *rb_cvc_tbl = RCLASS_WRITABLE_CVC_TBL(target);
if (!rb_cvc_tbl) { if (!rb_cvc_tbl) {
rb_cvc_tbl = RCLASS_CVC_TBL(target) = rb_id_table_create(2); rb_cvc_tbl = rb_id_table_create(2);
RCLASS_WRITE_CVC_TBL(target, rb_cvc_tbl);
} }
struct rb_cvar_class_tbl_entry *ent; struct rb_cvar_class_tbl_entry *ent;
@ -4304,7 +4491,7 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
// cvar in this lookup. // cvar in this lookup.
if (result == 0) { if (result == 0) {
if (RB_TYPE_P(target, T_CLASS)) { if (RB_TYPE_P(target, T_CLASS)) {
if (RCLASS_SUBCLASSES(target)) { if (RCLASS_SUBCLASSES_FIRST(target)) {
rb_class_foreach_subclass(target, check_for_cvar_table, id); rb_class_foreach_subclass(target, check_for_cvar_table, id);
} }
} }
@ -4538,13 +4725,13 @@ class_ivar_set_shape_fields(VALUE obj, void *_data)
{ {
RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
return RCLASS_FIELDS(obj); return RCLASS_PRIME_FIELDS(obj);
} }
static void static void
class_ivar_set_shape_resize_fields(VALUE obj, attr_index_t _old_capa, attr_index_t new_capa, void *_data) class_ivar_set_shape_resize_fields(VALUE obj, attr_index_t _old_capa, attr_index_t new_capa, void *_data)
{ {
REALLOC_N(RCLASS_FIELDS(obj), VALUE, new_capa); REALLOC_N(RCLASS_PRIME_FIELDS(obj), VALUE, new_capa);
} }
static void static void
@ -4564,7 +4751,7 @@ class_ivar_set_too_complex_table(VALUE obj, void *_data)
{ {
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
return RCLASS_FIELDS_HASH(obj); return RCLASS_WRITABLE_FIELDS_HASH(obj);
} }
int int
@ -4574,6 +4761,8 @@ rb_class_ivar_set(VALUE obj, ID id, VALUE val)
bool existing = false; bool existing = false;
rb_check_frozen(obj); rb_check_frozen(obj);
rb_class_ensure_writable(obj);
RB_VM_LOCK_ENTER(); RB_VM_LOCK_ENTER();
{ {
existing = general_ivar_set(obj, id, val, NULL, existing = general_ivar_set(obj, id, val, NULL,
@ -4620,11 +4809,9 @@ rb_fields_tbl_copy(VALUE dst, VALUE src)
rb_ivar_foreach(src, tbl_copy_i, dst); rb_ivar_foreach(src, tbl_copy_i, dst);
} }
rb_const_entry_t * static rb_const_entry_t *
rb_const_lookup(VALUE klass, ID id) const_lookup(struct rb_id_table *tbl, ID id)
{ {
struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
if (tbl) { if (tbl) {
VALUE val; VALUE val;
bool r; bool r;
@ -4638,3 +4825,9 @@ rb_const_lookup(VALUE klass, ID id)
} }
return NULL; return NULL;
} }
rb_const_entry_t *
rb_const_lookup(VALUE klass, ID id)
{
return const_lookup(RCLASS_CONST_TBL(klass), id);
}

63
vm.c
View File

@ -21,6 +21,7 @@
#include "internal/gc.h" #include "internal/gc.h"
#include "internal/inits.h" #include "internal/inits.h"
#include "internal/missing.h" #include "internal/missing.h"
#include "internal/namespace.h"
#include "internal/object.h" #include "internal/object.h"
#include "internal/proc.h" #include "internal/proc.h"
#include "internal/re.h" #include "internal/re.h"
@ -1164,6 +1165,7 @@ vm_proc_create_from_captured(VALUE klass,
{ {
VALUE procval = rb_proc_alloc(klass); VALUE procval = rb_proc_alloc(klass);
rb_proc_t *proc = RTYPEDDATA_DATA(procval); rb_proc_t *proc = RTYPEDDATA_DATA(procval);
const rb_namespace_t *ns = rb_current_namespace();
VM_ASSERT(VM_EP_IN_HEAP_P(GET_EC(), captured->ep)); VM_ASSERT(VM_EP_IN_HEAP_P(GET_EC(), captured->ep));
@ -1173,6 +1175,7 @@ vm_proc_create_from_captured(VALUE klass,
rb_vm_block_ep_update(procval, &proc->block, captured->ep); rb_vm_block_ep_update(procval, &proc->block, captured->ep);
vm_block_type_set(&proc->block, block_type); vm_block_type_set(&proc->block, block_type);
proc->ns = ns;
proc->is_from_method = is_from_method; proc->is_from_method = is_from_method;
proc->is_lambda = is_lambda; proc->is_lambda = is_lambda;
@ -1204,10 +1207,12 @@ proc_create(VALUE klass, const struct rb_block *block, int8_t is_from_method, in
{ {
VALUE procval = rb_proc_alloc(klass); VALUE procval = rb_proc_alloc(klass);
rb_proc_t *proc = RTYPEDDATA_DATA(procval); rb_proc_t *proc = RTYPEDDATA_DATA(procval);
const rb_namespace_t *ns = rb_current_namespace();
VM_ASSERT(VM_EP_IN_HEAP_P(GET_EC(), vm_block_ep(block))); VM_ASSERT(VM_EP_IN_HEAP_P(GET_EC(), vm_block_ep(block)));
rb_vm_block_copy(procval, &proc->block, block); rb_vm_block_copy(procval, &proc->block, block);
vm_block_type_set(&proc->block, block->type); vm_block_type_set(&proc->block, block->type);
proc->ns = ns;
proc->is_from_method = is_from_method; proc->is_from_method = is_from_method;
proc->is_lambda = is_lambda; proc->is_lambda = is_lambda;
@ -2182,7 +2187,7 @@ static void
rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass) rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass)
{ {
st_data_t bop; st_data_t bop;
if (RB_TYPE_P(klass, T_ICLASS) && FL_TEST(klass, RICLASS_IS_ORIGIN) && if (RB_TYPE_P(klass, T_ICLASS) && RICLASS_IS_ORIGIN_P(klass) &&
RB_TYPE_P(RBASIC_CLASS(klass), T_CLASS)) { RB_TYPE_P(RBASIC_CLASS(klass), T_CLASS)) {
klass = RBASIC_CLASS(klass); klass = RBASIC_CLASS(klass);
} }
@ -2871,6 +2876,19 @@ rb_iseq_eval(const rb_iseq_t *iseq)
rb_execution_context_t *ec = GET_EC(); rb_execution_context_t *ec = GET_EC();
VALUE val; VALUE val;
vm_set_top_stack(ec, iseq); vm_set_top_stack(ec, iseq);
// TODO: set the namespace frame like require/load
val = vm_exec(ec);
return val;
}
VALUE
rb_iseq_eval_with_refinement(const rb_iseq_t *iseq, VALUE mod)
{
rb_execution_context_t *ec = GET_EC();
VALUE val;
vm_set_top_stack(ec, iseq);
rb_vm_using_module(mod);
// TODO: set the namespace frame like require/load
val = vm_exec(ec); val = vm_exec(ec);
return val; return val;
} }
@ -2880,8 +2898,8 @@ rb_iseq_eval_main(const rb_iseq_t *iseq)
{ {
rb_execution_context_t *ec = GET_EC(); rb_execution_context_t *ec = GET_EC();
VALUE val; VALUE val;
vm_set_main_stack(ec, iseq); vm_set_main_stack(ec, iseq);
// TODO: set the namespace frame like require/load
val = vm_exec(ec); val = vm_exec(ec);
return val; return val;
} }
@ -2934,6 +2952,26 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
return val; return val;
} }
VALUE
rb_vm_call_cfunc2(VALUE recv, VALUE (*func)(VALUE, VALUE), VALUE arg1, VALUE arg2,
VALUE block_handler, VALUE filename)
{
rb_execution_context_t *ec = GET_EC();
const rb_control_frame_t *reg_cfp = ec->cfp;
const rb_iseq_t *iseq = rb_iseq_new(Qnil, filename, filename, Qnil, 0, ISEQ_TYPE_TOP);
VALUE val;
vm_push_frame(ec, iseq, VM_FRAME_MAGIC_TOP | VM_ENV_FLAG_LOCAL | VM_FRAME_FLAG_FINISH,
recv, block_handler,
(VALUE)vm_cref_new_toplevel(ec), /* cref or me */
0, reg_cfp->sp, 0, 0);
val = (*func)(arg1, arg2);
rb_vm_pop_frame(ec);
return val;
}
/* vm */ /* vm */
void void
@ -2956,6 +2994,7 @@ rb_vm_update_references(void *ptr)
vm->loaded_features_realpaths = rb_gc_location(vm->loaded_features_realpaths); vm->loaded_features_realpaths = rb_gc_location(vm->loaded_features_realpaths);
vm->loaded_features_realpath_map = rb_gc_location(vm->loaded_features_realpath_map); vm->loaded_features_realpath_map = rb_gc_location(vm->loaded_features_realpath_map);
vm->top_self = rb_gc_location(vm->top_self); vm->top_self = rb_gc_location(vm->top_self);
vm->require_stack = rb_gc_location(vm->require_stack);
vm->orig_progname = rb_gc_location(vm->orig_progname); vm->orig_progname = rb_gc_location(vm->orig_progname);
rb_gc_update_values(RUBY_NSIG, vm->trap_list.cmd); rb_gc_update_values(RUBY_NSIG, vm->trap_list.cmd);
@ -3027,6 +3066,10 @@ rb_vm_mark(void *ptr)
rb_gc_mark_maybe(*list->varptr); rb_gc_mark_maybe(*list->varptr);
} }
if (vm->main_namespace) {
rb_namespace_entry_mark((void *)vm->main_namespace);
}
rb_gc_mark_movable(vm->mark_object_ary); rb_gc_mark_movable(vm->mark_object_ary);
rb_gc_mark_movable(vm->load_path); rb_gc_mark_movable(vm->load_path);
rb_gc_mark_movable(vm->load_path_snapshot); rb_gc_mark_movable(vm->load_path_snapshot);
@ -3036,6 +3079,7 @@ rb_vm_mark(void *ptr)
rb_gc_mark_movable(vm->loaded_features_snapshot); rb_gc_mark_movable(vm->loaded_features_snapshot);
rb_gc_mark_movable(vm->loaded_features_realpaths); rb_gc_mark_movable(vm->loaded_features_realpaths);
rb_gc_mark_movable(vm->loaded_features_realpath_map); rb_gc_mark_movable(vm->loaded_features_realpath_map);
rb_gc_mark_movable(vm->require_stack);
rb_gc_mark_movable(vm->top_self); rb_gc_mark_movable(vm->top_self);
rb_gc_mark_movable(vm->orig_progname); rb_gc_mark_movable(vm->orig_progname);
rb_gc_mark_movable(vm->coverages); rb_gc_mark_movable(vm->coverages);
@ -3113,7 +3157,8 @@ ruby_vm_destruct(rb_vm_t *vm)
rb_id_table_free(vm->negative_cme_table); rb_id_table_free(vm->negative_cme_table);
st_free_table(vm->overloaded_cme_table); st_free_table(vm->overloaded_cme_table);
rb_id_table_free(RCLASS(rb_mRubyVMFrozenCore)->m_tbl); // TODO: Is this ignorable for classext->m_tbl ?
// rb_id_table_free(RCLASS(rb_mRubyVMFrozenCore)->m_tbl);
rb_shape_free_all(); rb_shape_free_all();
@ -3505,6 +3550,8 @@ thread_mark(void *ptr)
rb_gc_mark(th->pending_interrupt_mask_stack); rb_gc_mark(th->pending_interrupt_mask_stack);
rb_gc_mark(th->top_self); rb_gc_mark(th->top_self);
rb_gc_mark(th->top_wrapper); rb_gc_mark(th->top_wrapper);
rb_gc_mark(th->namespaces);
if (NAMESPACE_USER_P(th->ns)) rb_namespace_entry_mark(th->ns);
if (th->root_fiber) rb_fiber_mark_self(th->root_fiber); if (th->root_fiber) rb_fiber_mark_self(th->root_fiber);
RUBY_ASSERT(th->ec == rb_fiberptr_get_ec(th->ec->fiber_ptr)); RUBY_ASSERT(th->ec == rb_fiberptr_get_ec(th->ec->fiber_ptr));
@ -3653,6 +3700,8 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
th->last_status = Qnil; th->last_status = Qnil;
th->top_wrapper = 0; th->top_wrapper = 0;
th->top_self = vm->top_self; // 0 while self == 0 th->top_self = vm->top_self; // 0 while self == 0
th->namespaces = 0;
th->ns = 0;
th->value = Qundef; th->value = Qundef;
th->ec->errinfo = Qnil; th->ec->errinfo = Qnil;
@ -3682,10 +3731,16 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
VALUE VALUE
rb_thread_alloc(VALUE klass) rb_thread_alloc(VALUE klass)
{ {
rb_namespace_t *ns;
rb_execution_context_t *ec = GET_EC();
VALUE self = thread_alloc(klass); VALUE self = thread_alloc(klass);
rb_thread_t *target_th = rb_thread_ptr(self); rb_thread_t *target_th = rb_thread_ptr(self);
target_th->ractor = GET_RACTOR(); target_th->ractor = GET_RACTOR();
th_init(target_th, self, target_th->vm = GET_VM()); th_init(target_th, self, target_th->vm = GET_VM());
if ((ns = rb_ec_thread_ptr(ec)->ns) == 0) {
ns = rb_main_namespace();
}
target_th->ns = ns;
return self; return self;
} }
@ -4234,6 +4289,8 @@ Init_VM(void)
th->vm = vm; th->vm = vm;
th->top_wrapper = 0; th->top_wrapper = 0;
th->top_self = rb_vm_top_self(); th->top_self = rb_vm_top_self();
th->namespaces = 0;
th->ns = 0;
rb_vm_register_global_object((VALUE)iseq); rb_vm_register_global_object((VALUE)iseq);
th->ec->cfp->iseq = iseq; th->ec->cfp->iseq = iseq;

View File

@ -597,10 +597,13 @@ vm_cc_check_cme(const struct rb_callcache *cc, const rb_callable_method_entry_t
#if 1 #if 1
// debug print // debug print
fprintf(stderr, "iseq_overload:%d\n", (int)cme->def->iseq_overload); fprintf(stderr, "iseq_overload:%d, cme:%p (def:%p), cm_cc_cme(cc):%p (def:%p)\n",
(int)cme->def->iseq_overload,
cme, cme->def,
vm_cc_cme(cc), vm_cc_cme(cc)->def);
rp(cme); rp(cme);
rp(vm_cc_cme(cc)); rp(vm_cc_cme(cc));
rb_vm_lookup_overloaded_cme(cme); rp(rb_vm_lookup_overloaded_cme(cme));
#endif #endif
return false; return false;
} }

View File

@ -118,6 +118,7 @@ extern int ruby_assert_critical_section_entered;
#include "internal.h" #include "internal.h"
#include "internal/array.h" #include "internal/array.h"
#include "internal/basic_operators.h" #include "internal/basic_operators.h"
#include "internal/namespace.h"
#include "internal/sanitizers.h" #include "internal/sanitizers.h"
#include "internal/serial.h" #include "internal/serial.h"
#include "internal/set_table.h" #include "internal/set_table.h"
@ -312,6 +313,7 @@ struct rb_calling_info {
int argc; int argc;
bool kw_splat; bool kw_splat;
VALUE heap_argv; VALUE heap_argv;
const rb_namespace_t *proc_ns;
}; };
#ifndef VM_ARGC_STACK_MAX #ifndef VM_ARGC_STACK_MAX
@ -743,6 +745,9 @@ typedef struct rb_vm_struct {
struct global_object_list *global_object_list; struct global_object_list *global_object_list;
const VALUE special_exceptions[ruby_special_error_count]; const VALUE special_exceptions[ruby_special_error_count];
/* namespace */
rb_namespace_t *main_namespace;
/* load */ /* load */
VALUE top_self; VALUE top_self;
VALUE load_path; VALUE load_path;
@ -818,6 +823,8 @@ typedef struct rb_vm_struct {
size_t fiber_machine_stack_size; size_t fiber_machine_stack_size;
} default_params; } default_params;
// TODO: a single require_stack can't support multi-threaded require trees
VALUE require_stack;
} rb_vm_t; } rb_vm_t;
/* default values */ /* default values */
@ -1119,6 +1126,9 @@ typedef struct rb_thread_struct {
/* for load(true) */ /* for load(true) */
VALUE top_self; VALUE top_self;
VALUE top_wrapper; VALUE top_wrapper;
/* for namespace */
VALUE namespaces; // Stack of namespaces
rb_namespace_t *ns; // The current one
/* thread control */ /* thread control */
@ -1258,6 +1268,7 @@ RUBY_SYMBOL_EXPORT_END
typedef struct { typedef struct {
const struct rb_block block; const struct rb_block block;
const rb_namespace_t *ns;
unsigned int is_from_method: 1; /* bool */ unsigned int is_from_method: 1; /* bool */
unsigned int is_lambda: 1; /* bool */ unsigned int is_lambda: 1; /* bool */
unsigned int is_isolated: 1; /* bool */ unsigned int is_isolated: 1; /* bool */
@ -1349,11 +1360,11 @@ typedef rb_control_frame_t *
enum vm_frame_env_flags { enum vm_frame_env_flags {
/* Frame/Environment flag bits: /* Frame/Environment flag bits:
* MMMM MMMM MMMM MMMM ____ FFFF FFFE EEEX (LSB) * MMMM MMMM MMMM MMMM __FF FFFF FFFE EEEX (LSB)
* *
* X : tag for GC marking (It seems as Fixnum) * X : tag for GC marking (It seems as Fixnum)
* EEE : 4 bits Env flags * EEE : 4 bits Env flags
* FF..: 7 bits Frame flags * FF..: 9 bits Frame flags
* MM..: 15 bits frame magic (to check frame corruption) * MM..: 15 bits frame magic (to check frame corruption)
*/ */
@ -1378,6 +1389,8 @@ enum vm_frame_env_flags {
VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = 0x0200, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = 0x0200,
VM_FRAME_FLAG_CFRAME_KW = 0x0400, VM_FRAME_FLAG_CFRAME_KW = 0x0400,
VM_FRAME_FLAG_PASSED = 0x0800, VM_FRAME_FLAG_PASSED = 0x0800,
VM_FRAME_FLAG_NS_SWITCH = 0x1000,
VM_FRAME_FLAG_LOAD_ISEQ = 0x2000,
/* env flag */ /* env flag */
VM_ENV_FLAG_LOCAL = 0x0002, VM_ENV_FLAG_LOCAL = 0x0002,
@ -1476,6 +1489,12 @@ VM_FRAME_RUBYFRAME_P(const rb_control_frame_t *cfp)
return !VM_FRAME_CFRAME_P(cfp); return !VM_FRAME_CFRAME_P(cfp);
} }
static inline int
VM_FRAME_NS_SWITCH_P(const rb_control_frame_t *cfp)
{
return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_NS_SWITCH) != 0;
}
#define RUBYVM_CFUNC_FRAME_P(cfp) \ #define RUBYVM_CFUNC_FRAME_P(cfp) \
(VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC) (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC)
@ -1823,6 +1842,7 @@ NORETURN(void rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int
/* functions about thread/vm execution */ /* functions about thread/vm execution */
RUBY_SYMBOL_EXPORT_BEGIN RUBY_SYMBOL_EXPORT_BEGIN
VALUE rb_iseq_eval(const rb_iseq_t *iseq); VALUE rb_iseq_eval(const rb_iseq_t *iseq);
VALUE rb_iseq_eval_with_refinement(const rb_iseq_t *iseq, VALUE mod);
VALUE rb_iseq_eval_main(const rb_iseq_t *iseq); VALUE rb_iseq_eval_main(const rb_iseq_t *iseq);
VALUE rb_iseq_path(const rb_iseq_t *iseq); VALUE rb_iseq_path(const rb_iseq_t *iseq);
VALUE rb_iseq_realpath(const rb_iseq_t *iseq); VALUE rb_iseq_realpath(const rb_iseq_t *iseq);

View File

@ -400,9 +400,9 @@ static inline const rb_callable_method_entry_t *rb_search_method_entry(VALUE rec
static inline enum method_missing_reason rb_method_call_status(rb_execution_context_t *ec, const rb_callable_method_entry_t *me, call_type scope, VALUE self); static inline enum method_missing_reason rb_method_call_status(rb_execution_context_t *ec, const rb_callable_method_entry_t *me, call_type scope, VALUE self);
static VALUE static VALUE
gccct_hash(VALUE klass, ID mid) gccct_hash(VALUE klass, VALUE namespace, ID mid)
{ {
return (klass >> 3) ^ (VALUE)mid; return ((klass ^ namespace) >> 3) ^ (VALUE)mid;
} }
NOINLINE(static const struct rb_callcache *gccct_method_search_slowpath(rb_vm_t *vm, VALUE klass, unsigned int index, const struct rb_callinfo * ci)); NOINLINE(static const struct rb_callcache *gccct_method_search_slowpath(rb_vm_t *vm, VALUE klass, unsigned int index, const struct rb_callinfo * ci));
@ -447,7 +447,8 @@ scope_to_ci(call_type scope, ID mid, int argc, struct rb_callinfo *ci)
static inline const struct rb_callcache * static inline const struct rb_callcache *
gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct rb_callinfo *ci) gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct rb_callinfo *ci)
{ {
VALUE klass; VALUE klass, ns_value;
const rb_namespace_t *ns = rb_current_namespace();
if (!SPECIAL_CONST_P(recv)) { if (!SPECIAL_CONST_P(recv)) {
klass = RBASIC_CLASS(recv); klass = RBASIC_CLASS(recv);
@ -457,8 +458,13 @@ gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct
klass = CLASS_OF(recv); klass = CLASS_OF(recv);
} }
if (NAMESPACE_USER_P(ns)) {
ns_value = ns->ns_object;
} else {
ns_value = 0;
}
// search global method cache // search global method cache
unsigned int index = (unsigned int)(gccct_hash(klass, mid) % VM_GLOBAL_CC_CACHE_TABLE_SIZE); unsigned int index = (unsigned int)(gccct_hash(klass, ns_value, mid) % VM_GLOBAL_CC_CACHE_TABLE_SIZE);
rb_vm_t *vm = rb_ec_vm_ptr(ec); rb_vm_t *vm = rb_ec_vm_ptr(ec);
const struct rb_callcache *cc = vm->global_cc_cache_table[index]; const struct rb_callcache *cc = vm->global_cc_cache_table[index];
@ -483,6 +489,17 @@ gccct_method_search(rb_execution_context_t *ec, VALUE recv, ID mid, const struct
return gccct_method_search_slowpath(vm, klass, index, ci); return gccct_method_search_slowpath(vm, klass, index, ci);
} }
VALUE
rb_gccct_clear_table(VALUE _self)
{
int i;
rb_vm_t *vm = GET_VM();
for (i=0; i<VM_GLOBAL_CC_CACHE_TABLE_SIZE; i++) {
vm->global_cc_cache_table[i] = NULL;
}
return Qnil;
}
/** /**
* @internal * @internal
* calls the specified method. * calls the specified method.
@ -1978,6 +1995,7 @@ eval_string_with_cref(VALUE self, VALUE src, rb_cref_t *cref, VALUE file, int li
cref = vm_cref_dup(orig_cref); cref = vm_cref_dup(orig_cref);
} }
vm_set_eval_stack(ec, iseq, cref, &block); vm_set_eval_stack(ec, iseq, cref, &block);
// TODO: set the namespace frame
/* kick */ /* kick */
return vm_exec(ec); return vm_exec(ec);
@ -2000,6 +2018,8 @@ eval_string_with_scope(VALUE scope, VALUE src, VALUE file, int line)
vm_bind_update_env(scope, bind, vm_make_env_object(ec, ec->cfp)); vm_bind_update_env(scope, bind, vm_make_env_object(ec, ec->cfp));
} }
// TODO: set the namespace frame
/* kick */ /* kick */
return vm_exec(ec); return vm_exec(ec);
} }
@ -2865,6 +2885,7 @@ Init_vm_eval(void)
rb_define_method(rb_eUncaughtThrow, "value", uncaught_throw_value, 0); rb_define_method(rb_eUncaughtThrow, "value", uncaught_throw_value, 0);
rb_define_method(rb_eUncaughtThrow, "to_s", uncaught_throw_to_s, 0); rb_define_method(rb_eUncaughtThrow, "to_s", uncaught_throw_to_s, 0);
rb_define_singleton_method(rb_cModule, "gccct_clear_table", rb_gccct_clear_table, 0);
id_result = rb_intern_const("result"); id_result = rb_intern_const("result");
id_tag = rb_intern_const("tag"); id_tag = rb_intern_const("tag");
id_value = rb_intern_const("value"); id_value = rb_intern_const("value");

View File

@ -134,7 +134,7 @@ callable_method_entry_p(const rb_callable_method_entry_t *cme)
return TRUE; return TRUE;
} }
else { else {
VM_ASSERT(IMEMO_TYPE_P((VALUE)cme, imemo_ment)); VM_ASSERT(IMEMO_TYPE_P((VALUE)cme, imemo_ment), "imemo_type:%s", rb_imemo_name(imemo_type((VALUE)cme)));
if (callable_class_p(cme->defined_class)) { if (callable_class_p(cme->defined_class)) {
return TRUE; return TRUE;
@ -418,7 +418,7 @@ vm_push_frame(rb_execution_context_t *ec,
#if VM_DEBUG_BP_CHECK #if VM_DEBUG_BP_CHECK
.bp_check = sp, .bp_check = sp,
#endif #endif
.jit_return = NULL .jit_return = NULL,
}; };
/* Ensure the initialization of `*cfp` above never gets reordered with the update of `ec->cfp` below. /* Ensure the initialization of `*cfp` above never gets reordered with the update of `ec->cfp` below.
@ -963,7 +963,7 @@ vm_get_const_key_cref(const VALUE *ep)
while (cref) { while (cref) {
if (RCLASS_SINGLETON_P(CREF_CLASS(cref)) || if (RCLASS_SINGLETON_P(CREF_CLASS(cref)) ||
RCLASS_EXT(CREF_CLASS(cref))->cloned) { RCLASS_CLONED_P(CREF_CLASS(cref)) ) {
return key_cref; return key_cref;
} }
cref = CREF_NEXT(cref); cref = CREF_NEXT(cref);
@ -1256,7 +1256,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
} }
} }
ivar_list = RCLASS_FIELDS(obj); ivar_list = RCLASS_PRIME_FIELDS(obj);
#if !SHAPE_IN_BASIC_FLAGS #if !SHAPE_IN_BASIC_FLAGS
shape_id = RCLASS_SHAPE_ID(obj); shape_id = RCLASS_SHAPE_ID(obj);
@ -1335,7 +1335,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
switch (BUILTIN_TYPE(obj)) { switch (BUILTIN_TYPE(obj)) {
case T_CLASS: case T_CLASS:
case T_MODULE: case T_MODULE:
table = (st_table *)RCLASS_FIELDS(obj); table = (st_table *)RCLASS_FIELDS_HASH(obj);
break; break;
case T_OBJECT: case T_OBJECT:
@ -2079,7 +2079,7 @@ static const struct rb_callcache *
vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci) vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
{ {
const ID mid = vm_ci_mid(ci); const ID mid = vm_ci_mid(ci);
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); struct rb_id_table *cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
struct rb_class_cc_entries *ccs = NULL; struct rb_class_cc_entries *ccs = NULL;
VALUE ccs_data; VALUE ccs_data;
@ -2125,7 +2125,8 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
} }
} }
else { else {
cc_tbl = RCLASS_CC_TBL(klass) = rb_id_table_create(2); cc_tbl = rb_id_table_create(2);
RCLASS_WRITE_CC_TBL(klass, cc_tbl);
} }
RB_DEBUG_COUNTER_INC(cc_not_found_in_ccs); RB_DEBUG_COUNTER_INC(cc_not_found_in_ccs);
@ -4123,7 +4124,7 @@ rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner)
VALUE klass = current_class; VALUE klass = current_class;
/* for prepended Module, then start from cover class */ /* for prepended Module, then start from cover class */
if (RB_TYPE_P(klass, T_ICLASS) && FL_TEST(klass, RICLASS_IS_ORIGIN) && if (RB_TYPE_P(klass, T_ICLASS) && RICLASS_IS_ORIGIN_P(klass) &&
RB_TYPE_P(RBASIC_CLASS(klass), T_CLASS)) { RB_TYPE_P(RBASIC_CLASS(klass), T_CLASS)) {
klass = RBASIC_CLASS(klass); klass = RBASIC_CLASS(klass);
} }
@ -5109,6 +5110,20 @@ block_proc_is_lambda(const VALUE procval)
} }
} }
static inline const rb_namespace_t *
block_proc_namespace(const VALUE procval)
{
rb_proc_t *proc;
if (procval) {
GetProcPtr(procval, proc);
return proc->ns;
}
else {
return NULL;
}
}
static VALUE static VALUE
vm_yield_with_cfunc(rb_execution_context_t *ec, vm_yield_with_cfunc(rb_execution_context_t *ec,
const struct rb_captured_block *captured, const struct rb_captured_block *captured,
@ -5259,11 +5274,16 @@ vm_invoke_iseq_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
VALUE * const rsp = GET_SP() - calling->argc; VALUE * const rsp = GET_SP() - calling->argc;
VALUE * const argv = rsp; VALUE * const argv = rsp;
int opt_pc = vm_callee_setup_block_arg(ec, calling, ci, iseq, argv, is_lambda ? arg_setup_method : arg_setup_block); int opt_pc = vm_callee_setup_block_arg(ec, calling, ci, iseq, argv, is_lambda ? arg_setup_method : arg_setup_block);
int frame_flag = VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0);
SET_SP(rsp); SET_SP(rsp);
if (calling->proc_ns) {
frame_flag |= VM_FRAME_FLAG_NS_SWITCH;
}
vm_push_frame(ec, iseq, vm_push_frame(ec, iseq,
VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0), frame_flag,
captured->self, captured->self,
VM_GUARDED_PREV_EP(captured->ep), 0, VM_GUARDED_PREV_EP(captured->ep), 0,
ISEQ_BODY(iseq)->iseq_encoded + opt_pc, ISEQ_BODY(iseq)->iseq_encoded + opt_pc,
@ -5362,6 +5382,9 @@ vm_invoke_proc_block(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp,
{ {
while (vm_block_handler_type(block_handler) == block_handler_type_proc) { while (vm_block_handler_type(block_handler) == block_handler_type_proc) {
VALUE proc = VM_BH_TO_PROC(block_handler); VALUE proc = VM_BH_TO_PROC(block_handler);
if (!calling->proc_ns) {
calling->proc_ns = block_proc_namespace(proc);
}
is_lambda = block_proc_is_lambda(proc); is_lambda = block_proc_is_lambda(proc);
block_handler = vm_proc_to_block_handler(proc); block_handler = vm_proc_to_block_handler(proc);
} }
@ -5812,6 +5835,7 @@ vm_define_class(ID id, rb_num_t flags, VALUE cbase, VALUE super)
/* find klass */ /* find klass */
rb_autoload_load(cbase, id); rb_autoload_load(cbase, id);
if ((klass = vm_const_get_under(id, flags, cbase)) != 0) { if ((klass = vm_const_get_under(id, flags, cbase)) != 0) {
if (!vm_check_if_class(id, flags, super, klass)) if (!vm_check_if_class(id, flags, super, klass))
unmatched_redefinition("class", cbase, id, klass); unmatched_redefinition("class", cbase, id, klass);
@ -5913,8 +5937,7 @@ vm_define_method(const rb_execution_context_t *ec, VALUE obj, ID id, VALUE iseqv
rb_add_method_iseq(klass, id, (const rb_iseq_t *)iseqval, cref, visi); rb_add_method_iseq(klass, id, (const rb_iseq_t *)iseqval, cref, visi);
// Set max_iv_count on klasses based on number of ivar sets that are in the initialize method // Set max_iv_count on klasses based on number of ivar sets that are in the initialize method
if (id == idInitialize && klass != rb_cObject && RB_TYPE_P(klass, T_CLASS) && (rb_get_alloc_func(klass) == rb_class_allocate_instance)) { if (id == idInitialize && klass != rb_cObject && RB_TYPE_P(klass, T_CLASS) && (rb_get_alloc_func(klass) == rb_class_allocate_instance)) {
RCLASS_WRITE_MAX_IV_COUNT(klass, rb_estimate_iv_count(klass, (const rb_iseq_t *)iseqval));
RCLASS_EXT(klass)->max_iv_count = rb_estimate_iv_count(klass, (const rb_iseq_t *)iseqval);
} }
if (!is_singleton && vm_scope_module_func_check(ec)) { if (!is_singleton && vm_scope_module_func_check(ec)) {

View File

@ -39,7 +39,7 @@ vm_ccs_dump_i(ID mid, VALUE val, void *data)
static void static void
vm_ccs_dump(VALUE klass, ID target_mid) vm_ccs_dump(VALUE klass, ID target_mid)
{ {
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); struct rb_id_table *cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
if (cc_tbl) { if (cc_tbl) {
VALUE ccs; VALUE ccs;
if (target_mid) { if (target_mid) {
@ -87,18 +87,18 @@ vm_mtbl_dump(VALUE klass, ID target_mid)
else { else {
fprintf(stderr, " MTBL: NULL\n"); fprintf(stderr, " MTBL: NULL\n");
} }
if (RCLASS_CALLABLE_M_TBL(klass)) { if (RCLASS_WRITABLE_CALLABLE_M_TBL(klass)) {
if (target_mid != 0) { if (target_mid != 0) {
if (rb_id_table_lookup(RCLASS_CALLABLE_M_TBL(klass), target_mid, &me)) { if (rb_id_table_lookup(RCLASS_WRITABLE_CALLABLE_M_TBL(klass), target_mid, &me)) {
rp_m(" [CM**] ", me); rp_m(" [CM**] ", me);
} }
} }
else { else {
fprintf(stderr, " ## RCLASS_CALLABLE_M_TBL\n"); fprintf(stderr, " ## RCLASS_CALLABLE_M_TBL\n");
rb_id_table_foreach(RCLASS_CALLABLE_M_TBL(klass), vm_cme_dump_i, NULL); rb_id_table_foreach(RCLASS_WRITABLE_CALLABLE_M_TBL(klass), vm_cme_dump_i, NULL);
} }
} }
if (RCLASS_CC_TBL(klass)) { if (RCLASS_WRITABLE_CC_TBL(klass)) {
vm_ccs_dump(klass, target_mid); vm_ccs_dump(klass, target_mid);
} }
klass = RCLASS_SUPER(klass); klass = RCLASS_SUPER(klass);
@ -166,6 +166,78 @@ const rb_method_entry_t * rb_method_entry_clone(const rb_method_entry_t *src_me)
static const rb_callable_method_entry_t *complemented_callable_method_entry(VALUE klass, ID id); static const rb_callable_method_entry_t *complemented_callable_method_entry(VALUE klass, ID id);
static const rb_callable_method_entry_t *lookup_overloaded_cme(const rb_callable_method_entry_t *cme); static const rb_callable_method_entry_t *lookup_overloaded_cme(const rb_callable_method_entry_t *cme);
static void
invalidate_method_cache_in_cc_table(struct rb_id_table *tbl, ID mid)
{
VALUE ccs_data;
if (tbl && rb_id_table_lookup(tbl, mid, &ccs_data)) {
struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data;
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
if (NIL_P(ccs->cme->owner)) invalidate_negative_cache(mid);
rb_vm_ccs_free(ccs);
rb_id_table_delete(tbl, mid);
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_ccs);
}
}
static void
invalidate_callable_method_entry_in_callable_m_table(struct rb_id_table *tbl, ID mid)
{
VALUE cme;
if (tbl && rb_id_table_lookup(tbl, mid, &cme)) {
if (rb_yjit_enabled_p) {
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
}
rb_id_table_delete(tbl, mid);
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_callable);
}
}
struct invalidate_callable_method_entry_foreach_arg {
VALUE klass;
ID mid;
const rb_method_entry_t *cme;
const rb_method_entry_t *newer;
};
static void
invalidate_callable_method_entry_in_every_m_table_i(rb_classext_t *ext, bool is_prime, VALUE namespace, void *data)
{
st_data_t me;
struct invalidate_callable_method_entry_foreach_arg *arg = (struct invalidate_callable_method_entry_foreach_arg *)data;
struct rb_id_table *tbl = RCLASSEXT_M_TBL(ext);
if (rb_id_table_lookup(tbl, arg->mid, &me) && arg->cme == (const rb_method_entry_t *)me) {
rb_method_table_insert(arg->klass, tbl, arg->mid, arg->newer);
}
}
static void
invalidate_callable_method_entry_in_every_m_table(VALUE klass, ID mid, const rb_callable_method_entry_t *cme)
{
// The argument cme must be invalidated later in the caller side
const rb_method_entry_t *newer = rb_method_entry_clone((const rb_method_entry_t *)cme);
struct invalidate_callable_method_entry_foreach_arg arg = {
.klass = klass,
.mid = mid,
.cme = (const rb_method_entry_t *) cme,
.newer = newer,
};
rb_class_classext_foreach(klass, invalidate_callable_method_entry_in_every_m_table_i, (void *)&arg);
}
static void
invalidate_complemented_method_entry_in_callable_m_table(struct rb_id_table *tbl, ID mid)
{
VALUE cme;
if (tbl && rb_id_table_lookup(tbl, mid, &cme)) {
if (rb_yjit_enabled_p) {
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
}
rb_id_table_delete(tbl, mid);
RB_DEBUG_COUNTER_INC(cc_invalidate_tree_callable);
}
}
static void static void
clear_method_cache_by_id_in_class(VALUE klass, ID mid) clear_method_cache_by_id_in_class(VALUE klass, ID mid)
@ -174,33 +246,24 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
if (rb_objspace_garbage_object_p(klass)) return; if (rb_objspace_garbage_object_p(klass)) return;
RB_VM_LOCK_ENTER(); RB_VM_LOCK_ENTER();
if (LIKELY(RCLASS_SUBCLASSES(klass) == NULL)) { if (LIKELY(RCLASS_SUBCLASSES_FIRST(klass) == NULL)) {
// no subclasses // no subclasses
// check only current class // check only current class
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
VALUE ccs_data;
// invalidate CCs // invalidate CCs
if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, &ccs_data)) { struct rb_id_table *cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data; invalidate_method_cache_in_cc_table(cc_tbl, mid);
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)ccs->cme); if (RCLASS_CC_TBL_NOT_PRIME_P(klass, cc_tbl)) {
if (NIL_P(ccs->cme->owner)) invalidate_negative_cache(mid); invalidate_method_cache_in_cc_table(RCLASS_PRIME_CC_TBL(klass), mid);
rb_vm_ccs_free(ccs);
rb_id_table_delete(cc_tbl, mid);
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_ccs);
} }
// remove from callable_m_tbl, if exists // remove from callable_m_tbl, if exists
struct rb_id_table *cm_tbl; struct rb_id_table *cm_tbl = RCLASS_WRITABLE_CALLABLE_M_TBL(klass);
if ((cm_tbl = RCLASS_CALLABLE_M_TBL(klass)) != NULL) { invalidate_callable_method_entry_in_callable_m_table(cm_tbl, mid);
VALUE cme; if (RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(klass, cm_tbl)) {
if (rb_yjit_enabled_p && rb_id_table_lookup(cm_tbl, mid, &cme)) { invalidate_callable_method_entry_in_callable_m_table(RCLASS_PRIME_CALLABLE_M_TBL(klass), mid);
rb_yjit_cme_invalidate((rb_callable_method_entry_t *)cme);
}
rb_id_table_delete(cm_tbl, mid);
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_callable);
} }
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf); RB_DEBUG_COUNTER_INC(cc_invalidate_leaf);
} }
else { else {
@ -223,10 +286,9 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
else { else {
klass_housing_cme = RCLASS_ORIGIN(owner); klass_housing_cme = RCLASS_ORIGIN(owner);
} }
// replace the cme that will be invalid
VM_ASSERT(lookup_method_table(klass_housing_cme, mid) == (const rb_method_entry_t *)cme); // replace the cme that will be invalid in the all classexts
const rb_method_entry_t *new_cme = rb_method_entry_clone((const rb_method_entry_t *)cme); invalidate_callable_method_entry_in_every_m_table(klass_housing_cme, mid, cme);
rb_method_table_insert(klass_housing_cme, RCLASS_M_TBL(klass_housing_cme), mid, new_cme);
} }
vm_cme_invalidate((rb_callable_method_entry_t *)cme); vm_cme_invalidate((rb_callable_method_entry_t *)cme);
@ -234,7 +296,7 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
// In case of refinement ME, also invalidate the wrapped ME that // In case of refinement ME, also invalidate the wrapped ME that
// could be cached at some callsite and is unreachable from any // could be cached at some callsite and is unreachable from any
// RCLASS_CC_TBL. // RCLASS_WRITABLE_CC_TBL.
if (cme->def->type == VM_METHOD_TYPE_REFINED && cme->def->body.refined.orig_me) { if (cme->def->type == VM_METHOD_TYPE_REFINED && cme->def->body.refined.orig_me) {
vm_cme_invalidate((rb_callable_method_entry_t *)cme->def->body.refined.orig_me); vm_cme_invalidate((rb_callable_method_entry_t *)cme->def->body.refined.orig_me);
} }
@ -250,11 +312,12 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
// invalidate complement tbl // invalidate complement tbl
if (METHOD_ENTRY_COMPLEMENTED(cme)) { if (METHOD_ENTRY_COMPLEMENTED(cme)) {
VALUE defined_class = cme->defined_class; VALUE defined_class = cme->defined_class;
struct rb_id_table *cm_tbl = RCLASS_CALLABLE_M_TBL(defined_class); struct rb_id_table *cm_tbl = RCLASS_WRITABLE_CALLABLE_M_TBL(defined_class);
VM_ASSERT(cm_tbl != NULL); invalidate_complemented_method_entry_in_callable_m_table(cm_tbl, mid);
int r = rb_id_table_delete(cm_tbl, mid); if (RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(defined_class, cm_tbl)) {
VM_ASSERT(r == TRUE); (void)r; struct rb_id_table *prime_cm_table = RCLASS_PRIME_CALLABLE_M_TBL(defined_class);
RB_DEBUG_COUNTER_INC(cc_invalidate_tree_callable); invalidate_complemented_method_entry_in_callable_m_table(prime_cm_table, mid);
}
} }
RB_DEBUG_COUNTER_INC(cc_invalidate_tree); RB_DEBUG_COUNTER_INC(cc_invalidate_tree);
@ -263,6 +326,9 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
invalidate_negative_cache(mid); invalidate_negative_cache(mid);
} }
} }
rb_gccct_clear_table(Qnil);
RB_VM_LOCK_LEAVE(); RB_VM_LOCK_LEAVE();
} }
@ -302,6 +368,32 @@ rb_clear_method_cache(VALUE klass_or_module, ID mid)
} }
} }
static enum rb_id_table_iterator_result
invalidate_method_entry_in_iclass_callable_m_tbl(VALUE cme, void *data)
{
vm_cme_invalidate((rb_callable_method_entry_t *)cme);
return ID_TABLE_DELETE;
}
static enum rb_id_table_iterator_result
invalidate_ccs_in_iclass_cc_tbl(VALUE value, void *data)
{
struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)value;
vm_cme_invalidate((rb_callable_method_entry_t *)ccs->cme);
return ID_TABLE_DELETE;
}
void
rb_invalidate_method_caches(struct rb_id_table *cm_tbl, struct rb_id_table *cc_tbl)
{
if (cm_tbl) {
rb_id_table_foreach_values(cm_tbl, invalidate_method_entry_in_iclass_callable_m_tbl, NULL);
}
if (cc_tbl) {
rb_id_table_foreach_values(cc_tbl, invalidate_ccs_in_iclass_cc_tbl, NULL);
}
}
static int static int
invalidate_all_refinement_cc(void *vstart, void *vend, size_t stride, void *data) invalidate_all_refinement_cc(void *vstart, void *vend, size_t stride, void *data)
{ {
@ -446,13 +538,18 @@ rb_clear_all_refinement_method_cache(void)
void void
rb_method_table_insert(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me) rb_method_table_insert(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me)
{
rb_method_table_insert0(klass, table, method_id, me, RB_TYPE_P(klass, T_ICLASS) && !RICLASS_OWNS_M_TBL_P(klass));
}
void
rb_method_table_insert0(VALUE klass, struct rb_id_table *table, ID method_id, const rb_method_entry_t *me, bool iclass_shared_mtbl)
{ {
VALUE table_owner = klass; VALUE table_owner = klass;
if (RB_TYPE_P(klass, T_ICLASS) && !RICLASS_OWNS_M_TBL_P(klass)) { if (iclass_shared_mtbl) {
table_owner = RBASIC(table_owner)->klass; table_owner = RBASIC(table_owner)->klass;
} }
VM_ASSERT_TYPE3(table_owner, T_CLASS, T_ICLASS, T_MODULE); VM_ASSERT_TYPE3(table_owner, T_CLASS, T_ICLASS, T_MODULE);
VM_ASSERT(table == RCLASS_M_TBL(table_owner));
rb_id_table_insert(table, method_id, (VALUE)me); rb_id_table_insert(table, method_id, (VALUE)me);
RB_OBJ_WRITTEN(table_owner, Qundef, (VALUE)me); RB_OBJ_WRITTEN(table_owner, Qundef, (VALUE)me);
} }
@ -760,6 +857,7 @@ rb_method_definition_create(rb_method_type_t type, ID mid)
def->original_id = mid; def->original_id = mid;
static uintptr_t method_serial = 1; static uintptr_t method_serial = 1;
def->method_serial = method_serial++; def->method_serial = method_serial++;
def->ns = rb_current_namespace();
return def; return def;
} }
@ -1003,7 +1101,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
rb_clear_method_cache(orig_klass, mid); rb_clear_method_cache(orig_klass, mid);
} }
} }
mtbl = RCLASS_M_TBL(klass); mtbl = RCLASS_WRITABLE_M_TBL(klass);
/* check re-definition */ /* check re-definition */
if (rb_id_table_lookup(mtbl, mid, &data)) { if (rb_id_table_lookup(mtbl, mid, &data)) {
@ -1331,7 +1429,11 @@ search_method0(VALUE klass, ID id, VALUE *defined_class_ptr, bool skip_refined)
if (me == NULL) RB_DEBUG_COUNTER_INC(mc_search_notfound); if (me == NULL) RB_DEBUG_COUNTER_INC(mc_search_notfound);
VM_ASSERT(me == NULL || !METHOD_ENTRY_INVALIDATED(me)); VM_ASSERT(me == NULL || !METHOD_ENTRY_INVALIDATED(me),
"invalid me, mid:%s, klass:%s(%s)",
rb_id2name(id),
RTEST(rb_mod_name(klass)) ? RSTRING_PTR(rb_mod_name(klass)) : "anonymous",
rb_obj_info(klass));
return me; return me;
} }
@ -1366,23 +1468,27 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_
struct rb_id_table *mtbl; struct rb_id_table *mtbl;
const rb_callable_method_entry_t *cme; const rb_callable_method_entry_t *cme;
VALUE cme_data; VALUE cme_data;
int cme_found = 0;
if (me) { if (me) {
if (me->defined_class == 0) { if (me->defined_class == 0) {
RB_DEBUG_COUNTER_INC(mc_cme_complement); RB_DEBUG_COUNTER_INC(mc_cme_complement);
VM_ASSERT_TYPE2(defined_class, T_ICLASS, T_MODULE); VM_ASSERT_TYPE2(defined_class, T_ICLASS, T_MODULE);
mtbl = RCLASS_CALLABLE_M_TBL(defined_class); mtbl = RCLASS_WRITABLE_CALLABLE_M_TBL(defined_class);
if (mtbl && rb_id_table_lookup(mtbl, id, &cme_data)) { if (mtbl && rb_id_table_lookup(mtbl, id, &cme_data)) {
cme = (rb_callable_method_entry_t *)cme_data; cme = (rb_callable_method_entry_t *)cme_data;
cme_found = 1;
}
if (cme_found) {
RB_DEBUG_COUNTER_INC(mc_cme_complement_hit); RB_DEBUG_COUNTER_INC(mc_cme_complement_hit);
VM_ASSERT(callable_method_entry_p(cme)); VM_ASSERT(callable_method_entry_p(cme));
VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme)); VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme));
} }
else if (create) { else if (create) {
if (!mtbl) { if (!mtbl) {
mtbl = RCLASS_EXT(defined_class)->callable_m_tbl = rb_id_table_create(0); mtbl = rb_id_table_create(0);
RCLASS_WRITE_CALLABLE_M_TBL(defined_class, mtbl);
} }
cme = rb_method_entry_complement_defined_class(me, me->called_id, defined_class); cme = rb_method_entry_complement_defined_class(me, me->called_id, defined_class);
rb_id_table_insert(mtbl, id, (VALUE)cme); rb_id_table_insert(mtbl, id, (VALUE)cme);
@ -1418,7 +1524,7 @@ cached_callable_method_entry(VALUE klass, ID mid)
{ {
ASSERT_vm_locking(); ASSERT_vm_locking();
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); struct rb_id_table *cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
VALUE ccs_data; VALUE ccs_data;
if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, &ccs_data)) { if (cc_tbl && rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
@ -1446,11 +1552,12 @@ cache_callable_method_entry(VALUE klass, ID mid, const rb_callable_method_entry_
ASSERT_vm_locking(); ASSERT_vm_locking();
VM_ASSERT(cme != NULL); VM_ASSERT(cme != NULL);
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass); struct rb_id_table *cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
VALUE ccs_data; VALUE ccs_data;
if (!cc_tbl) { if (!cc_tbl) {
cc_tbl = RCLASS_CC_TBL(klass) = rb_id_table_create(2); cc_tbl = rb_id_table_create(2);
RCLASS_WRITE_CC_TBL(klass, cc_tbl);
} }
if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) { if (rb_id_table_lookup(cc_tbl, mid, &ccs_data)) {
@ -1694,7 +1801,7 @@ remove_method(VALUE klass, ID mid)
rb_clear_method_cache(self, mid); rb_clear_method_cache(self, mid);
} }
rb_clear_method_cache(klass, mid); rb_clear_method_cache(klass, mid);
rb_id_table_delete(RCLASS_M_TBL(klass), mid); rb_id_table_delete(RCLASS_WRITABLE_M_TBL(klass), mid);
rb_vm_check_redefinition_opt_method(me, klass); rb_vm_check_redefinition_opt_method(me, klass);