namespace on read
This commit is contained in:
parent
49742414f6
commit
382645d440
20
builtin.c
20
builtin.c
@ -32,8 +32,8 @@ builtin_lookup(const char *feature, size_t *psize)
|
||||
return bin;
|
||||
}
|
||||
|
||||
void
|
||||
rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
|
||||
static void
|
||||
load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table)
|
||||
{
|
||||
// search binary
|
||||
size_t size;
|
||||
@ -50,10 +50,24 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
|
||||
ASSUME(iseq); // otherwise an exception should have raised
|
||||
vm->builtin_function_table = NULL;
|
||||
|
||||
rb_namespace_enable_builtin();
|
||||
|
||||
// exec
|
||||
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
|
||||
|
||||
void
|
||||
@ -71,5 +85,5 @@ Init_builtin(void)
|
||||
void
|
||||
Init_builtin_features(void)
|
||||
{
|
||||
rb_load_with_builtin_functions("gem_prelude", NULL);
|
||||
load_with_builtin_functions("gem_prelude", NULL);
|
||||
}
|
||||
|
255
common.mk
255
common.mk
@ -140,6 +140,7 @@ COMMONOBJS = array.$(OBJEXT) \
|
||||
marshal.$(OBJEXT) \
|
||||
math.$(OBJEXT) \
|
||||
memory_view.$(OBJEXT) \
|
||||
namespace.$(OBJEXT) \
|
||||
node.$(OBJEXT) \
|
||||
node_dump.$(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/hash.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/object.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/gc.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/parse.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/gc.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/object.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/gc.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/serial.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/hash.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/sanitizers.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/imemo.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/object.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/imemo.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/object.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/gc.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/sanitizers.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/gc.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/serial.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/imemo.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/sanitizers.h
|
||||
dir.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
||||
@ -4701,6 +4712,7 @@ dir.$(OBJEXT): {$(VPATH)}vm_core.h
|
||||
dir.$(OBJEXT): {$(VPATH)}vm_opts.h
|
||||
dln.$(OBJEXT): $(hdrdir)/ruby/ruby.h
|
||||
dln.$(OBJEXT): $(top_srcdir)/internal/compilers.h
|
||||
dln.$(OBJEXT): $(top_srcdir)/internal/namespace.h
|
||||
dln.$(OBJEXT): $(top_srcdir)/internal/warnings.h
|
||||
dln.$(OBJEXT): {$(VPATH)}assert.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/hash.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/range.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/io.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/process.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/inits.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/sanitizers.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/imemo.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/object.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/gc.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/parse.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/hash.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/proc.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/inits.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/object.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/imemo.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/parse.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/dir.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/fixnum.h
|
||||
load.$(OBJEXT): $(top_srcdir)/internal/gc.h
|
||||
load.$(OBJEXT): $(top_srcdir)/internal/hash.h
|
||||
load.$(OBJEXT): $(top_srcdir)/internal/imemo.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/parse.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/hash.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/object.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/hash.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/serial.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/gc.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/parse.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_hook.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)/container_of/container_of.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/hash.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/serial.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/hash.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/parse.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/hash.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/object.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/imemo.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/object.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/gc.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/serial.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/imemo.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/parse.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/hash.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/proc.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/imemo.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/object.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/hash.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/object.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/gc.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/random.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/gc.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/object.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/hash.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/ractor.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/loadpath.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/object.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/gc.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/serial.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/gc.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/sanitizers.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/gc.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/serial.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/hash.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/object.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/hash.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/proc.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/hash.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/sanitizers.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/imemo.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/proc.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/hash.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/rational.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/hash.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/re.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/gc.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/sanitizers.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/inits.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/object.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/gc.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/serial.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/gc.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/serial.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/gc.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/serial.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/hash.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/serial.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/hash.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/sanitizers.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/hash.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/sanitizers.h
|
||||
yjit.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
||||
|
41
dln.c
41
dln.c
@ -26,6 +26,7 @@ static void dln_loaderror(const char *format, ...);
|
||||
#include "dln.h"
|
||||
#include "internal.h"
|
||||
#include "internal/compilers.h"
|
||||
#include "internal/namespace.h"
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
@ -382,10 +383,14 @@ dln_open(const char *file)
|
||||
# endif
|
||||
# ifndef RTLD_GLOBAL
|
||||
# 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
|
||||
|
||||
/* 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) {
|
||||
error = dln_strerror();
|
||||
goto failed;
|
||||
@ -497,8 +502,8 @@ abi_check_enabled_p(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
void *
|
||||
dln_load(const char *file)
|
||||
static void *
|
||||
dln_load_and_init(const char *file, const char *init_fct_name)
|
||||
{
|
||||
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
|
||||
void *handle = dln_open(file);
|
||||
@ -512,9 +517,6 @@ dln_load(const char *file)
|
||||
}
|
||||
#endif
|
||||
|
||||
char *init_fct_name;
|
||||
init_funcname(&init_fct_name, file);
|
||||
|
||||
/* Call the init code */
|
||||
dln_sym_callable(void, (void), handle, init_fct_name)();
|
||||
|
||||
@ -524,6 +526,7 @@ dln_load(const char *file)
|
||||
{
|
||||
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);
|
||||
if (init_fct == NULL) {
|
||||
aix_loaderror(file);
|
||||
@ -540,3 +543,29 @@ dln_load(const char *file)
|
||||
|
||||
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
1
dln.h
@ -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_file_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
|
||||
void *dln_load(const char*);
|
||||
void *dln_load_feature(const char*, const char*);
|
||||
void *dln_symbol(void*,const char*);
|
||||
|
||||
RUBY_SYMBOL_EXPORT_END
|
||||
|
9
dmydln.c
9
dmydln.c
@ -12,6 +12,15 @@ dln_load(const char *file)
|
||||
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*));
|
||||
void*
|
||||
dln_symbol(void *handle, const char *symbol)
|
||||
|
80
eval.c
80
eval.c
@ -1192,6 +1192,8 @@ rb_mod_append_features(VALUE module, VALUE include)
|
||||
return module;
|
||||
}
|
||||
|
||||
static VALUE refinement_import_methods(int argc, VALUE *argv, VALUE refinement);
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* include(module, ...) -> self
|
||||
@ -1345,9 +1347,9 @@ rb_using_refinement(rb_cref_t *cref, VALUE klass, VALUE module)
|
||||
}
|
||||
superclass = refinement_superclass(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);
|
||||
}
|
||||
@ -1402,6 +1404,12 @@ rb_using_module(const rb_cref_t *cref, VALUE module)
|
||||
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:
|
||||
* target -> class_or_module
|
||||
@ -1442,43 +1450,24 @@ add_activated_refinement(VALUE activated_refinements,
|
||||
}
|
||||
superclass = refinement_superclass(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);
|
||||
while (refinement && refinement != klass) {
|
||||
c = RCLASS_SET_SUPER(c, rb_include_class_new(refinement, RCLASS_SUPER(c)));
|
||||
RB_OBJ_WRITE(c, &RCLASS_REFINED_CLASS(c), klass);
|
||||
c = rb_class_set_super(c, rb_include_class_new(refinement, RCLASS_SUPER(c)));
|
||||
RCLASS_SET_REFINED_CLASS(c, klass);
|
||||
refinement = RCLASS_SUPER(refinement);
|
||||
}
|
||||
rb_hash_aset(activated_refinements, klass, iclass);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
void
|
||||
rb_refinement_setup(struct rb_refinements_data *data, VALUE module, VALUE klass)
|
||||
{
|
||||
VALUE refinement;
|
||||
ID id_refinements, id_activated_refinements,
|
||||
id_refined_class, id_defined_at;
|
||||
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__");
|
||||
refinements = rb_attr_get(module, id_refinements);
|
||||
if (NIL_P(refinements)) {
|
||||
@ -1496,7 +1485,7 @@ rb_mod_refine(VALUE module, VALUE klass)
|
||||
if (NIL_P(refinement)) {
|
||||
VALUE superclass = refinement_superclass(klass);
|
||||
refinement = rb_refinement_new();
|
||||
RCLASS_SET_SUPER(refinement, superclass);
|
||||
rb_class_set_super(refinement, superclass);
|
||||
RUBY_ASSERT(BUILTIN_TYPE(refinement) == T_MODULE);
|
||||
FL_SET(refinement, RMODULE_IS_REFINEMENT);
|
||||
CONST_ID(id_refined_class, "__refined_class__");
|
||||
@ -1506,8 +1495,41 @@ rb_mod_refine(VALUE module, VALUE klass)
|
||||
rb_hash_aset(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
|
||||
|
@ -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_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_cfunc2(VALUE recv, VALUE (*func)(VALUE, VALUE), VALUE arg1, VALUE arg2, VALUE block_handler, VALUE filename);
|
||||
void rb_vm_set_progname(VALUE filename);
|
||||
VALUE rb_vm_cbase(void);
|
||||
|
||||
|
1
ext/-test-/namespace/yay1/extconf.rb
Normal file
1
ext/-test-/namespace/yay1/extconf.rb
Normal file
@ -0,0 +1 @@
|
||||
create_makefile('-test-/namespace/yay1')
|
28
ext/-test-/namespace/yay1/yay1.c
Normal file
28
ext/-test-/namespace/yay1/yay1.c
Normal 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);
|
||||
}
|
4
ext/-test-/namespace/yay1/yay1.def
Normal file
4
ext/-test-/namespace/yay1/yay1.def
Normal file
@ -0,0 +1,4 @@
|
||||
LIBRARY yay1
|
||||
EXPORTS
|
||||
Init_yay1
|
||||
yay_value
|
4
ext/-test-/namespace/yay1/yay1.h
Normal file
4
ext/-test-/namespace/yay1/yay1.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include <ruby.h>
|
||||
#include "ruby/internal/dllexport.h"
|
||||
|
||||
RUBY_EXTERN VALUE yay_value(void);
|
1
ext/-test-/namespace/yay2/extconf.rb
Normal file
1
ext/-test-/namespace/yay2/extconf.rb
Normal file
@ -0,0 +1 @@
|
||||
create_makefile('-test-/namespace/yay2')
|
28
ext/-test-/namespace/yay2/yay2.c
Normal file
28
ext/-test-/namespace/yay2/yay2.c
Normal 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);
|
||||
}
|
4
ext/-test-/namespace/yay2/yay2.def
Normal file
4
ext/-test-/namespace/yay2/yay2.def
Normal file
@ -0,0 +1,4 @@
|
||||
LIBRARY yay2
|
||||
EXPORTS
|
||||
Init_yay2
|
||||
yay_value
|
4
ext/-test-/namespace/yay2/yay2.h
Normal file
4
ext/-test-/namespace/yay2/yay2.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include <ruby.h>
|
||||
#include "ruby/internal/dllexport.h"
|
||||
|
||||
RUBY_EXTERN VALUE yay_value(void);
|
@ -186,6 +186,7 @@ coverage.o: $(top_srcdir)/internal/compilers.h
|
||||
coverage.o: $(top_srcdir)/internal/gc.h
|
||||
coverage.o: $(top_srcdir)/internal/hash.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/serial.h
|
||||
coverage.o: $(top_srcdir)/internal/set_table.h
|
||||
|
@ -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/gc.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/serial.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/hash.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/serial.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/imemo.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/serial.h
|
||||
objspace_dump.o: $(top_srcdir)/internal/set_table.h
|
||||
|
@ -792,7 +792,7 @@ objspace_internal_super_of(VALUE self, VALUE obj)
|
||||
case T_MODULE:
|
||||
case T_CLASS:
|
||||
case T_ICLASS:
|
||||
super = RCLASS_SUPER(obj);
|
||||
super = rb_class_super_of(obj);
|
||||
break;
|
||||
default:
|
||||
rb_raise(rb_eArgError, "class or module is expected");
|
||||
|
@ -537,7 +537,7 @@ dump_object(VALUE obj, struct dump_config *dc)
|
||||
|
||||
case T_CLASS:
|
||||
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:
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
@ -591,6 +591,7 @@ ripper.o: $(top_srcdir)/internal/gc.h
|
||||
ripper.o: $(top_srcdir)/internal/hash.h
|
||||
ripper.o: $(top_srcdir)/internal/imemo.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/parse.h
|
||||
ripper.o: $(top_srcdir)/internal/rational.h
|
||||
|
@ -200,6 +200,7 @@ ancdata.o: $(top_srcdir)/internal/error.h
|
||||
ancdata.o: $(top_srcdir)/internal/gc.h
|
||||
ancdata.o: $(top_srcdir)/internal/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.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/imemo.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/serial.h
|
||||
unixsocket.o: $(top_srcdir)/internal/set_table.h
|
||||
|
517
gc.c
517
gc.c
@ -1210,9 +1210,68 @@ rb_data_free(void *objspace, VALUE obj)
|
||||
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
|
||||
rb_gc_obj_free(void *objspace, VALUE obj)
|
||||
{
|
||||
struct classext_foreach_args args;
|
||||
|
||||
RB_DEBUG_COUNTER_INC(obj_free);
|
||||
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
@ -1242,29 +1301,13 @@ rb_gc_obj_free(void *objspace, VALUE obj)
|
||||
break;
|
||||
case T_MODULE:
|
||||
case T_CLASS:
|
||||
rb_id_table_free(RCLASS_M_TBL(obj));
|
||||
rb_cc_table_free(obj);
|
||||
if (rb_shape_obj_too_complex_p(obj)) {
|
||||
st_free_table((st_table *)RCLASS_FIELDS(obj));
|
||||
}
|
||||
else {
|
||||
xfree(RCLASS_FIELDS(obj));
|
||||
}
|
||||
args.klass = obj;
|
||||
args.obj_too_complex = rb_shape_obj_too_complex_p(obj) ? true : false;
|
||||
|
||||
if (RCLASS_CONST_TBL(obj)) {
|
||||
rb_free_const_table(RCLASS_CONST_TBL(obj));
|
||||
rb_class_classext_foreach(obj, classext_free, (void *)&args);
|
||||
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_class_ptr, BUILTIN_TYPE(obj) == T_CLASS);
|
||||
break;
|
||||
@ -1363,18 +1406,12 @@ rb_gc_obj_free(void *objspace, VALUE obj)
|
||||
case T_MOVED:
|
||||
break;
|
||||
case T_ICLASS:
|
||||
/* Basically , T_ICLASS shares table with the module */
|
||||
if (RICLASS_OWNS_M_TBL_P(obj)) {
|
||||
/* Method table is not shared for origin iclasses of classes */
|
||||
rb_id_table_free(RCLASS_M_TBL(obj));
|
||||
args.klass = obj;
|
||||
|
||||
rb_class_classext_foreach(obj, classext_iclass_free, (void *)&args);
|
||||
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);
|
||||
break;
|
||||
@ -2124,6 +2161,60 @@ cc_table_memsize(struct rb_id_table *cc_table)
|
||||
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
|
||||
rb_obj_memsize_of(VALUE obj)
|
||||
{
|
||||
@ -2148,23 +2239,16 @@ rb_obj_memsize_of(VALUE obj)
|
||||
break;
|
||||
case T_MODULE:
|
||||
case T_CLASS:
|
||||
if (RCLASS_M_TBL(obj)) {
|
||||
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
|
||||
}
|
||||
rb_class_classext_foreach(obj, classext_memsize, (void *)&size);
|
||||
|
||||
if (rb_shape_obj_too_complex_p(obj)) {
|
||||
rb_class_classext_foreach(obj, classext_fields_hash_memsize, (void *)&size);
|
||||
} else {
|
||||
// class IV sizes are allocated as powers of two
|
||||
size += SIZEOF_VALUE << bit_length(RCLASS_FIELDS_COUNT(obj));
|
||||
if (RCLASS_CVC_TBL(obj)) {
|
||||
size += rb_id_table_memsize(RCLASS_CVC_TBL(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;
|
||||
case T_ICLASS:
|
||||
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));
|
||||
}
|
||||
}
|
||||
if (RCLASS_CC_TBL(obj)) {
|
||||
size += cc_table_memsize(RCLASS_CC_TBL(obj));
|
||||
if (RCLASS_WRITABLE_CC_TBL(obj)) {
|
||||
size += cc_table_memsize(RCLASS_WRITABLE_CC_TBL(obj));
|
||||
}
|
||||
break;
|
||||
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
|
||||
#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START)
|
||||
#elif STACK_GROW_DIRECTION > 0
|
||||
@ -2796,45 +2960,12 @@ rb_mark_tbl_no_pin(st_table *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
|
||||
gc_declarative_marking_p(const rb_data_type_t *type)
|
||||
{
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
void
|
||||
rb_gc_mark_children(void *objspace, VALUE obj)
|
||||
{
|
||||
struct gc_mark_classext_foreach_arg foreach_args;
|
||||
|
||||
if (FL_TEST_RAW(obj, FL_EXIVAR)) {
|
||||
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
|
||||
case T_MODULE:
|
||||
if (RCLASS_SUPER(obj)) {
|
||||
gc_mark_internal(RCLASS_SUPER(obj));
|
||||
}
|
||||
foreach_args.objspace = objspace;
|
||||
foreach_args.obj = obj;
|
||||
rb_class_classext_foreach(obj, gc_mark_classext_module, (void *)&foreach_args);
|
||||
|
||||
mark_m_tbl(objspace, RCLASS_M_TBL(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 {
|
||||
if (!rb_shape_obj_too_complex_p(obj)) {
|
||||
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;
|
||||
|
||||
case T_ICLASS:
|
||||
if (RICLASS_OWNS_M_TBL_P(obj)) {
|
||||
mark_m_tbl(objspace, RCLASS_M_TBL(obj));
|
||||
}
|
||||
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);
|
||||
foreach_args.objspace = objspace;
|
||||
foreach_args.obj = obj;
|
||||
rb_class_classext_foreach(obj, gc_mark_classext_iclass, (void *)&foreach_args);
|
||||
break;
|
||||
|
||||
case T_ARRAY:
|
||||
@ -3031,8 +3192,8 @@ rb_gc_mark_children(void *objspace, VALUE obj)
|
||||
VALUE klass = RBASIC_CLASS(obj);
|
||||
|
||||
// Increment max_iv_count if applicable, used to determine size pool allocation
|
||||
if (RCLASS_EXT(klass)->max_iv_count < fields_count) {
|
||||
RCLASS_EXT(klass)->max_iv_count = fields_count;
|
||||
if (RCLASS_MAX_IV_COUNT(klass) < fields_count) {
|
||||
RCLASS_WRITE_MAX_IV_COUNT(klass, fields_count);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3482,13 +3643,11 @@ update_cc_tbl_i(VALUE ccs_ptr, void *objspace)
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!tbl) return;
|
||||
rb_id_table_foreach_values(tbl, update_cc_tbl_i, objspace);
|
||||
}
|
||||
}
|
||||
|
||||
static enum rb_id_table_iterator_result
|
||||
update_cvc_tbl_i(VALUE cvc_entry, void *objspace)
|
||||
@ -3507,16 +3666,14 @@ update_cvc_tbl_i(VALUE cvc_entry, void *objspace)
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!tbl) return;
|
||||
rb_id_table_foreach_values(tbl, update_cvc_tbl_i, objspace);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -3535,35 +3692,93 @@ static void
|
||||
update_const_tbl(void *objspace, struct rb_id_table *tbl)
|
||||
{
|
||||
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
|
||||
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) {
|
||||
if (entry->klass)
|
||||
UPDATE_IF_MOVED(objspace, entry->klass);
|
||||
entry = entry->next;
|
||||
}
|
||||
}
|
||||
|
||||
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_);
|
||||
UPDATE_IF_MOVED(objspace, ext->includer);
|
||||
UPDATE_IF_MOVED(objspace, ext->refined_class);
|
||||
update_subclass_entries(objspace, ext->subclasses);
|
||||
size_t array_size = RCLASSEXT_SUPERCLASS_DEPTH(ext);
|
||||
if (RCLASSEXT_SUPERCLASSES_OWNER(ext)) {
|
||||
if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext))
|
||||
array_size += 1;
|
||||
for (size_t i = 0; i < array_size; i++) {
|
||||
UPDATE_IF_MOVED(objspace, RCLASSEXT_SUPERCLASSES(ext)[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
for (size_t i = 0; i < RCLASS_SUPERCLASS_DEPTH(obj) + 1; i++) {
|
||||
UPDATE_IF_MOVED(objspace, RCLASS_SUPERCLASSES(obj)[i]);
|
||||
UPDATE_IF_MOVED(objspace, RCLASSEXT_ORIGIN(ext));
|
||||
UPDATE_IF_MOVED(objspace, RCLASSEXT_REFINED_CLASS(ext));
|
||||
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;
|
||||
@ -3884,6 +4099,8 @@ rb_gc_update_vm_references(void *objspace)
|
||||
void
|
||||
rb_gc_update_object_references(void *objspace, VALUE obj)
|
||||
{
|
||||
struct classext_foreach_args args;
|
||||
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_CLASS:
|
||||
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
|
||||
case T_MODULE:
|
||||
if (RCLASS_SUPER((VALUE)obj)) {
|
||||
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
|
||||
}
|
||||
update_m_tbl(objspace, RCLASS_M_TBL(obj));
|
||||
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);
|
||||
args.klass = obj;
|
||||
args.obj_too_complex = rb_shape_obj_too_complex_p(obj);
|
||||
args.objspace = objspace;
|
||||
rb_class_classext_foreach(obj, update_classext, (void *)&args);
|
||||
break;
|
||||
|
||||
case T_ICLASS:
|
||||
if (RICLASS_OWNS_M_TBL_P(obj)) {
|
||||
update_m_tbl(objspace, RCLASS_M_TBL(obj));
|
||||
}
|
||||
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);
|
||||
args.objspace = objspace;
|
||||
rb_class_classext_foreach(obj, update_iclass_classext, (void *)&args);
|
||||
break;
|
||||
|
||||
case T_IMEMO:
|
||||
|
19
imemo.c
19
imemo.c
@ -170,13 +170,14 @@ rb_imemo_memsize(VALUE obj)
|
||||
static enum rb_id_table_iterator_result
|
||||
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;
|
||||
VM_ASSERT(vm_ccs_p(ccs));
|
||||
#if VM_CHECK_MODE > 0
|
||||
VALUE klass = (VALUE)data;
|
||||
|
||||
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);
|
||||
#endif
|
||||
|
||||
@ -200,7 +201,8 @@ cc_table_mark_i(VALUE ccs_ptr, void *data)
|
||||
void
|
||||
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) {
|
||||
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
|
||||
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) {
|
||||
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
|
||||
rb_imemo_free(VALUE obj)
|
||||
{
|
||||
|
@ -84,6 +84,8 @@ RUBY_EXTERN VALUE rb_cMethod; /**< `Method` class. */
|
||||
RUBY_EXTERN VALUE rb_cModule; /**< `Module` class. */
|
||||
RUBY_EXTERN VALUE rb_cRefinement; /**< `Refinement` 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_cNumeric; /**< `Numeric` class. */
|
||||
RUBY_EXTERN VALUE rb_cProc; /**< `Proc` class. */
|
||||
|
1
inits.c
1
inits.c
@ -77,6 +77,7 @@ rb_call_inits(void)
|
||||
CALL(Prism);
|
||||
CALL(unicode_version);
|
||||
CALL(Set);
|
||||
CALL(Namespace);
|
||||
|
||||
// enable builtin loading
|
||||
CALL(builtin);
|
||||
|
658
internal/class.h
658
internal/class.h
@ -10,6 +10,7 @@
|
||||
*/
|
||||
#include "id.h"
|
||||
#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/static_assert.h"
|
||||
#include "internal/variable.h" /* for rb_class_ivar_set */
|
||||
@ -26,6 +27,41 @@
|
||||
# undef RCLASS_SUPER
|
||||
#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 {
|
||||
VALUE klass;
|
||||
struct rb_subclass_entry *next;
|
||||
@ -41,21 +77,36 @@ struct rb_cvar_class_tbl_entry {
|
||||
};
|
||||
|
||||
struct rb_classext_struct {
|
||||
const rb_namespace_t *ns;
|
||||
VALUE super;
|
||||
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 *callable_m_tbl;
|
||||
struct rb_id_table *cc_tbl; /* ID -> [[ci1, cc1], [ci2, cc2] ...] */
|
||||
struct rb_id_table *cvc_tbl;
|
||||
size_t superclass_depth;
|
||||
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
|
||||
* included. Hopefully that makes sense.
|
||||
*/
|
||||
struct rb_subclass_entry *module_subclass_entry;
|
||||
rb_ns_subclasses_t *ns_module_subclasses;
|
||||
|
||||
const VALUE origin_;
|
||||
const VALUE refined_class;
|
||||
union {
|
||||
@ -71,6 +122,11 @@ struct rb_classext_struct {
|
||||
unsigned char variation_count;
|
||||
bool permanent_classpath : 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;
|
||||
};
|
||||
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 RBasic basic;
|
||||
VALUE super;
|
||||
struct rb_id_table *m_tbl;
|
||||
st_table *ns_classext_tbl; // ns_object -> (rb_classext_t *)
|
||||
bool prime_classext_readable : 1;
|
||||
bool prime_classext_writable : 1;
|
||||
};
|
||||
|
||||
// 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);
|
||||
/** TODO: Update or remove this assertion
|
||||
* // 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 rclass;
|
||||
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_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl)
|
||||
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
|
||||
#define RCLASS_FIELDS(c) (RCLASS_EXT(c)->fields)
|
||||
#define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl)
|
||||
#define RCLASS_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl)
|
||||
#define RCLASS_CVC_TBL(c) (RCLASS_EXT(c)->cvc_tbl)
|
||||
#define RCLASS_ORIGIN(c) (RCLASS_EXT(c)->origin_)
|
||||
#define RCLASS_EXT_PRIME_P(ext, c) (&((struct RClass_and_rb_classext_t*)(c))->classext == ext)
|
||||
|
||||
static inline rb_classext_t * RCLASS_EXT_READABLE_IN_NS(VALUE obj, const rb_namespace_t *ns);
|
||||
static inline rb_classext_t * RCLASS_EXT_READABLE(VALUE obj);
|
||||
static inline rb_classext_t * RCLASS_EXT_WRITABLE_IN_NS(VALUE obj, const rb_namespace_t *ns);
|
||||
static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj);
|
||||
|
||||
// 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_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_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 RICLASS_IS_ORIGIN FL_USER0
|
||||
#define RCLASS_SUPERCLASSES_INCLUDE_SELF FL_USER2
|
||||
#define RICLASS_ORIGIN_SHARED_MTBL FL_USER3
|
||||
// #define RICLASS_IS_ORIGIN FL_USER0 // TODO: Delete this
|
||||
// #define RCLASS_SUPERCLASSES_INCLUD_SELF FL_USER2 // TODO: Delete this
|
||||
// #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 *
|
||||
RCLASS_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 *)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
|
||||
@ -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_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
|
||||
@ -155,51 +567,62 @@ static inline void
|
||||
RCLASS_SET_M_TBL(VALUE klass, struct rb_id_table *table)
|
||||
{
|
||||
RUBY_ASSERT(!RB_OBJ_PROMOTED(klass));
|
||||
RCLASS_M_TBL(klass) = table;
|
||||
RCLASSEXT_M_TBL(RCLASS_EXT(klass)) = table;
|
||||
}
|
||||
|
||||
/* class.c */
|
||||
void rb_class_subclass_add(VALUE super, VALUE klass);
|
||||
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)
|
||||
static inline void
|
||||
RCLASS_WRITE_M_TBL(VALUE klass, struct rb_id_table *table)
|
||||
{
|
||||
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
|
||||
@ -215,26 +638,42 @@ static inline void
|
||||
RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator)
|
||||
{
|
||||
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
|
||||
RCLASS_SET_ORIGIN(VALUE klass, VALUE origin)
|
||||
{
|
||||
RB_OBJ_WRITE(klass, &RCLASS_ORIGIN(klass), origin);
|
||||
if (klass != origin) FL_SET(origin, RICLASS_IS_ORIGIN);
|
||||
rb_classext_t *ext = RCLASS_EXT(klass);
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -243,32 +682,61 @@ RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass)
|
||||
RB_OBJ_WRITE(iclass, &RCLASS_INCLUDER(iclass), klass);
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
RCLASS_SUPER(VALUE klass)
|
||||
static inline void
|
||||
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
|
||||
RCLASS_SET_SUPER(VALUE klass, VALUE super)
|
||||
static inline void
|
||||
RCLASS_SET_SUBCLASSES(VALUE klass, struct rb_subclass_anchor *anchor)
|
||||
{
|
||||
if (super) {
|
||||
rb_class_remove_from_super_subclasses(klass);
|
||||
rb_class_subclass_add(super, klass);
|
||||
rb_classext_t *ext = RCLASS_EXT(klass);
|
||||
RCLASSEXT_SUBCLASSES(ext) = anchor;
|
||||
}
|
||||
RB_OBJ_WRITE(klass, &RCLASS(klass)->super, super);
|
||||
rb_class_update_superclasses(klass);
|
||||
return super;
|
||||
|
||||
static inline void
|
||||
RCLASS_WRITE_NS_SUPER_SUBCLASSES(VALUE klass, rb_ns_subclasses_t *ns_subclasses)
|
||||
{
|
||||
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
|
||||
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(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING);
|
||||
|
||||
RB_OBJ_WRITE(klass, &(RCLASS_EXT(klass)->classpath), classpath);
|
||||
RCLASS_EXT(klass)->permanent_classpath = permanent;
|
||||
RB_OBJ_WRITE(klass, &(RCLASSEXT_CLASSPATH(ext)), classpath);
|
||||
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
|
||||
@ -280,4 +748,22 @@ RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE 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 */
|
||||
|
@ -16,11 +16,18 @@
|
||||
#define id_status ruby_static_id_status
|
||||
|
||||
/* eval.c */
|
||||
struct rb_refinements_data {
|
||||
VALUE refinement;
|
||||
VALUE refinements;
|
||||
};
|
||||
|
||||
extern ID ruby_static_id_signo;
|
||||
extern ID ruby_static_id_status;
|
||||
VALUE rb_refinement_module_get_refined_class(VALUE module);
|
||||
void rb_class_modify_check(VALUE);
|
||||
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);
|
||||
|
||||
/* eval_error.c */
|
||||
|
@ -10,6 +10,7 @@
|
||||
*/
|
||||
#include "ruby/internal/config.h"
|
||||
#include <stddef.h> /* for size_t */
|
||||
#include "id_table.h"
|
||||
#include "internal/array.h" /* for rb_ary_hidden_new_fill */
|
||||
#include "ruby/internal/stdbool.h" /* for bool */
|
||||
#include "ruby/ruby.h" /* for rb_block_call_func_t */
|
||||
@ -24,6 +25,7 @@
|
||||
#define IMEMO_FL_USER3 FL_USER7
|
||||
#define IMEMO_FL_USER4 FL_USER8
|
||||
#define IMEMO_FL_USER5 FL_USER9
|
||||
#define IMEMO_FL_USER6 FL_USER10
|
||||
|
||||
enum imemo_type {
|
||||
imemo_env = 0,
|
||||
@ -149,6 +151,7 @@ size_t rb_imemo_memsize(VALUE obj);
|
||||
void rb_cc_table_mark(VALUE klass);
|
||||
void rb_imemo_mark_and_move(VALUE obj, bool reference_updating);
|
||||
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);
|
||||
|
||||
RUBY_SYMBOL_EXPORT_BEGIN
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
/* load.c */
|
||||
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);
|
||||
NORETURN(void rb_load_fail(VALUE, const char*));
|
||||
|
||||
|
80
internal/namespace.h
Normal file
80
internal/namespace.h
Normal 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 */
|
@ -23,11 +23,13 @@ VALUE rb_search_class_path(VALUE);
|
||||
VALUE rb_attr_delete(VALUE, ID);
|
||||
void rb_autoload_str(VALUE mod, ID id, VALUE file);
|
||||
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));
|
||||
rb_gvar_getter_t *rb_gvar_getter_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_ractor_local(const char *name);
|
||||
void rb_gvar_namespace_ready(const char *name);
|
||||
|
||||
/**
|
||||
* Sets the name of a module.
|
||||
|
@ -77,6 +77,7 @@ void rb_check_stack_overflow(void);
|
||||
#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);
|
||||
struct vm_ifunc *rb_current_ifunc(void);
|
||||
VALUE rb_gccct_clear_table(VALUE);
|
||||
|
||||
#if USE_YJIT
|
||||
/* vm_exec.c */
|
||||
|
2
iseq.c
2
iseq.c
@ -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);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -219,6 +219,7 @@ class Gem::Package
|
||||
# Adds a checksum for each entry in the gem to checksums.yaml.gz.
|
||||
|
||||
def add_checksums(tar)
|
||||
require 'psych'
|
||||
Gem.load_yaml
|
||||
|
||||
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+
|
||||
|
||||
def read_checksums(gem)
|
||||
require_relative 'safe_yaml'
|
||||
Gem.load_yaml
|
||||
|
||||
@checksums = gem.seek "checksums.yaml.gz" do |entry|
|
||||
|
@ -1,5 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'psych'
|
||||
|
||||
module Gem
|
||||
###
|
||||
# This module is used for safely loading YAML specs from a gem. The
|
||||
|
446
load.c
446
load.c
@ -7,9 +7,11 @@
|
||||
#include "internal.h"
|
||||
#include "internal/dir.h"
|
||||
#include "internal/error.h"
|
||||
#include "internal/eval.h"
|
||||
#include "internal/file.h"
|
||||
#include "internal/hash.h"
|
||||
#include "internal/load.h"
|
||||
#include "internal/namespace.h"
|
||||
#include "internal/ruby_parser.h"
|
||||
#include "internal/thread.h"
|
||||
#include "internal/variable.h"
|
||||
@ -19,6 +21,7 @@
|
||||
#include "ruby/encoding.h"
|
||||
#include "ruby/util.h"
|
||||
#include "ractor_core.h"
|
||||
#include "vm_core.h"
|
||||
|
||||
static VALUE ruby_dln_libmap;
|
||||
|
||||
@ -36,6 +39,38 @@ static VALUE ruby_dln_libmap;
|
||||
# error Need integer for VALUE
|
||||
#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 {
|
||||
loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
|
||||
1) /* offset by rb_find_file_ext() */
|
||||
@ -64,10 +99,11 @@ enum expand_type {
|
||||
string objects in $LOAD_PATH are frozen.
|
||||
*/
|
||||
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 expanded_load_path = vm->expanded_load_path;
|
||||
VALUE load_path = CURRENT_NS_LOAD_PATH(vm_ns);
|
||||
VALUE expanded_load_path = CURRENT_NS_EXPANDED_LOAD_PATH(vm_ns);
|
||||
VALUE snapshot;
|
||||
VALUE ary;
|
||||
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_freeze(ary);
|
||||
vm->expanded_load_path = ary;
|
||||
rb_ary_replace(vm->load_path_snapshot, vm->load_path);
|
||||
SET_NS_EXPANDED_LOAD_PATH(vm_ns, ary);
|
||||
snapshot = CURRENT_NS_LOAD_PATH_SNAPSHOT(vm_ns);
|
||||
load_path = CURRENT_NS_LOAD_PATH(vm_ns);
|
||||
rb_ary_replace(snapshot, load_path);
|
||||
}
|
||||
|
||||
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 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. */
|
||||
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) {
|
||||
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) {
|
||||
/* Non string object. */
|
||||
vm->load_path_check_cache = non_cache;
|
||||
SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, non_cache);
|
||||
}
|
||||
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;
|
||||
/* 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);
|
||||
}
|
||||
else if (vm->load_path_check_cache) {
|
||||
else if (check_cache) {
|
||||
int has_relative = 1, has_non_cache = 1;
|
||||
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.
|
||||
Expand relative load path and non-cacheable objects again. */
|
||||
vm->load_path_check_cache = cwd;
|
||||
rb_construct_expanded_load_path(vm, EXPAND_RELATIVE,
|
||||
SET_NS_LOAD_PATH_CHECK_CACHE(vm_ns, cwd);
|
||||
rb_construct_expanded_load_path(vm_ns, EXPAND_RELATIVE,
|
||||
&has_relative, &has_non_cache);
|
||||
}
|
||||
else {
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
return vm->expanded_load_path;
|
||||
return CURRENT_NS_EXPANDED_LOAD_PATH(vm_ns);
|
||||
}
|
||||
|
||||
VALUE
|
||||
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
|
||||
load_path_getter(ID id, VALUE * p)
|
||||
{
|
||||
rb_vm_t *vm = (void *)p;
|
||||
return vm->load_path;
|
||||
GET_loading_vm_ns();
|
||||
return CURRENT_NS_LOAD_PATH(vm_ns);
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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 *
|
||||
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 *
|
||||
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
|
||||
@ -228,7 +273,7 @@ is_rbext_path(VALUE feature_path)
|
||||
typedef rb_darray(long) feature_indexes_t;
|
||||
|
||||
struct features_index_add_single_args {
|
||||
rb_vm_t *vm;
|
||||
vm_ns_t *vm_ns;
|
||||
VALUE offset;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
|
||||
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));
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
long idx = rb_darray_get(feature_indexes, i);
|
||||
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
|
||||
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;
|
||||
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);
|
||||
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 = {
|
||||
.vm = vm,
|
||||
.vm_ns = vm_ns,
|
||||
.offset = offset,
|
||||
.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.
|
||||
*/
|
||||
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;
|
||||
bool rb = false;
|
||||
@ -351,14 +396,14 @@ features_index_add(rb_vm_t *vm, VALUE feature, VALUE offset)
|
||||
if (p < feature_str)
|
||||
break;
|
||||
/* 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) {
|
||||
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) {
|
||||
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
|
||||
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_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())
|
||||
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 realpath_map = vm->loaded_features_realpath_map;
|
||||
VALUE realpaths = CURRENT_NS_LOADED_FEATURES_REALPATHS(vm_ns);
|
||||
VALUE realpath_map = CURRENT_NS_LOADED_FEATURES_REALPATH_MAP(vm_ns);
|
||||
VALUE previous_realpath_map = rb_hash_dup(realpath_map);
|
||||
rb_hash_clear(realpaths);
|
||||
rb_hash_clear(realpath_map);
|
||||
features = vm->loaded_features;
|
||||
for (i = 0; i < RARRAY_LEN(features); i++) {
|
||||
VALUE entry, as_str;
|
||||
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);
|
||||
if (as_str != entry)
|
||||
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);
|
||||
for (i = 0; i < j; 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);
|
||||
}
|
||||
}
|
||||
return vm->loaded_features_index;
|
||||
return CURRENT_NS_LOADED_FEATURES_INDEX(vm_ns);
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
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;
|
||||
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;
|
||||
type = 0;
|
||||
}
|
||||
features = get_loaded_features(vm);
|
||||
features_index = get_loaded_features_index(vm);
|
||||
features = get_loaded_features(vm_ns);
|
||||
features_index = get_loaded_features_index(vm_ns);
|
||||
|
||||
key = feature_key(feature, strlen(feature));
|
||||
/* 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 (strncmp(f, feature, len) != 0) {
|
||||
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)))
|
||||
continue;
|
||||
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;
|
||||
if (!expanded && !rb_is_absolute_path(feature)) {
|
||||
struct loaded_feature_searching fs;
|
||||
fs.name = feature;
|
||||
fs.len = len;
|
||||
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;
|
||||
st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
|
||||
if ((f = fs.result) != 0) {
|
||||
@ -657,7 +706,7 @@ rb_provided(const char *feature)
|
||||
}
|
||||
|
||||
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, '.');
|
||||
VALUE fullpath = 0;
|
||||
@ -669,15 +718,15 @@ feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
|
||||
}
|
||||
if (ext && !strchr(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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (rb_feature_p(vm, feature, 0, TRUE, FALSE, loading))
|
||||
if (rb_feature_p(vm_ns, feature, 0, TRUE, FALSE, loading))
|
||||
return TRUE;
|
||||
RB_GC_GUARD(fullpath);
|
||||
return FALSE;
|
||||
@ -686,35 +735,41 @@ feature_provided(rb_vm_t *vm, const char *feature, const char **loading)
|
||||
int
|
||||
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
|
||||
rb_provide_feature(rb_vm_t *vm, VALUE feature)
|
||||
rb_provide_feature(vm_ns_t *vm_ns, VALUE feature)
|
||||
{
|
||||
VALUE features;
|
||||
|
||||
features = get_loaded_features(vm);
|
||||
features = get_loaded_features(vm_ns);
|
||||
if (OBJ_FROZEN(features)) {
|
||||
rb_raise(rb_eRuntimeError,
|
||||
"$LOADED_FEATURES is frozen; cannot append 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
|
||||
// array, pushing into it would cause the whole array to be copied.
|
||||
// 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);
|
||||
features_index_add(vm, feature, INT2FIX(RARRAY_LEN(features)-1));
|
||||
reset_loaded_features_snapshot(vm);
|
||||
features_index_add(vm_ns, feature, INT2FIX(RARRAY_LEN(features)-1));
|
||||
reset_loaded_features_snapshot(vm_ns);
|
||||
}
|
||||
|
||||
void
|
||||
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));
|
||||
@ -732,17 +787,34 @@ realpath_internal_cached(VALUE hash, VALUE path)
|
||||
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
|
||||
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);
|
||||
|
||||
if (!iseq) {
|
||||
rb_execution_context_t *ec = GET_EC();
|
||||
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(th->vm);
|
||||
VALUE realpath_map = get_loaded_features_realpath_map(vm_ns);
|
||||
|
||||
if (rb_ruby_prism_p()) {
|
||||
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_exec_event_hook_script_compiled(ec, iseq, Qnil);
|
||||
|
||||
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
|
||||
load_wrapping(rb_execution_context_t *ec, VALUE fname, VALUE load_wrapper)
|
||||
{
|
||||
enum ruby_tag_type state;
|
||||
rb_namespace_t *ns;
|
||||
rb_thread_t *th = rb_ec_thread_ptr(ec);
|
||||
volatile VALUE wrapper = th->top_wrapper;
|
||||
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 */
|
||||
|
||||
/* load in module as toplevel */
|
||||
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;
|
||||
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
|
||||
rb_load_internal(VALUE fname, VALUE wrap)
|
||||
{
|
||||
VALUE namespace;
|
||||
rb_execution_context_t *ec = GET_EC();
|
||||
const rb_namespace_t *ns = rb_loading_namespace();
|
||||
enum ruby_tag_type state = TAG_NONE;
|
||||
if (RTEST(wrap)) {
|
||||
if (!RB_TYPE_P(wrap, T_MODULE)) {
|
||||
@ -846,6 +938,10 @@ rb_load_internal(VALUE fname, VALUE wrap)
|
||||
}
|
||||
state = load_wrapping(ec, fname, wrap);
|
||||
}
|
||||
else if (NAMESPACE_OPTIONAL_P(ns)) {
|
||||
namespace = ns->ns_object;
|
||||
state = load_wrapping(ec, fname, namespace);
|
||||
}
|
||||
else {
|
||||
load_iseq_eval(ec, fname);
|
||||
}
|
||||
@ -874,6 +970,40 @@ rb_load_protect(VALUE fname, int wrap, int *pstate)
|
||||
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:
|
||||
* load(filename, wrap=false) -> true
|
||||
@ -907,32 +1037,16 @@ rb_load_protect(VALUE fname, int wrap, int *pstate)
|
||||
static 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);
|
||||
|
||||
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;
|
||||
return load_entrypoint_internal(fname, wrap);
|
||||
}
|
||||
|
||||
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_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)) {
|
||||
/* 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
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
@ -1026,9 +1140,22 @@ static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
|
||||
VALUE
|
||||
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);
|
||||
}
|
||||
|
||||
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:
|
||||
* require_relative(string) -> true or false
|
||||
@ -1041,18 +1168,13 @@ rb_f_require(VALUE obj, VALUE fname)
|
||||
VALUE
|
||||
rb_f_require_relative(VALUE obj, 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);
|
||||
return rb_require_relative_entrypoint(fname);
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
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), '.');
|
||||
if (ext && !strchr(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);
|
||||
return 'r';
|
||||
}
|
||||
if ((tmp = rb_find_file(fname)) != 0) {
|
||||
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;
|
||||
return 'r';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
return 's';
|
||||
}
|
||||
@ -1085,25 +1207,25 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
|
||||
OBJ_FREEZE(tmp);
|
||||
if ((tmp = rb_find_file(tmp)) != 0) {
|
||||
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;
|
||||
return 's';
|
||||
}
|
||||
}
|
||||
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);
|
||||
return 's';
|
||||
}
|
||||
if ((tmp = rb_find_file(fname)) != 0) {
|
||||
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;
|
||||
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);
|
||||
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
|
||||
// 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;
|
||||
// Append ".so" if not already present so for example "etc" can find "etc.so".
|
||||
// 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");
|
||||
}
|
||||
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);
|
||||
RB_GC_GUARD(lookup_name);
|
||||
return 's';
|
||||
@ -1134,7 +1256,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
|
||||
if (ft)
|
||||
goto feature_present;
|
||||
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:
|
||||
if (ft) {
|
||||
@ -1143,7 +1265,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
|
||||
/* fall through */
|
||||
case loadable_ext_rb:
|
||||
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;
|
||||
*path = tmp;
|
||||
}
|
||||
@ -1161,10 +1283,15 @@ load_failed(VALUE fname)
|
||||
}
|
||||
|
||||
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);
|
||||
return (VALUE)dln_load(RSTRING_PTR(path));
|
||||
return (VALUE)dln_load_feature(RSTRING_PTR(loaded), RSTRING_PTR(fname));
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1181,7 +1308,7 @@ run_static_ext_init(rb_vm_t *vm, const char *feature)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -1193,10 +1320,11 @@ rb_resolve_feature_path(VALUE klass, VALUE fname)
|
||||
VALUE path;
|
||||
int found;
|
||||
VALUE sym;
|
||||
GET_loading_vm_ns();
|
||||
|
||||
fname = rb_get_path(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) {
|
||||
case 'r':
|
||||
@ -1231,6 +1359,20 @@ rb_ext_ractor_safe(bool 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
|
||||
* 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,
|
||||
ec,
|
||||
};
|
||||
GET_loading_vm_ns();
|
||||
enum ruby_tag_type state;
|
||||
char *volatile ftptr = 0;
|
||||
VALUE path;
|
||||
volatile VALUE saved_path;
|
||||
volatile VALUE realpath = 0;
|
||||
VALUE realpaths = get_loaded_features_realpaths(th->vm);
|
||||
VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
|
||||
VALUE realpaths = get_loaded_features_realpaths(vm_ns);
|
||||
VALUE realpath_map = get_loaded_features_realpath_map(vm_ns);
|
||||
volatile bool reset_ext_config = false;
|
||||
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;
|
||||
|
||||
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));
|
||||
path = saved_path;
|
||||
|
||||
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;
|
||||
}
|
||||
else if (!*ftptr) {
|
||||
@ -1293,15 +1436,30 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
|
||||
else {
|
||||
switch (found) {
|
||||
case 'r':
|
||||
// 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;
|
||||
|
||||
case 's':
|
||||
// the loading namespace must be set to the current namespace before calling load_ext
|
||||
reset_ext_config = true;
|
||||
ext_config_push(th, &prev_ext_config);
|
||||
handle = rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
|
||||
path, VM_BLOCK_HANDLER_NONE, path);
|
||||
rb_hash_aset(ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle));
|
||||
struct rb_vm_call_cfunc2_data arg = {
|
||||
.recv = rb_vm_top_self(),
|
||||
.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;
|
||||
}
|
||||
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);
|
||||
|
||||
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 == 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) {
|
||||
rb_provide_feature(th2->vm, path);
|
||||
rb_provide_feature(vm_ns, path);
|
||||
VALUE real = realpath;
|
||||
if (real) {
|
||||
real = rb_fstring(real);
|
||||
@ -1442,15 +1600,15 @@ void
|
||||
ruby_init_ext(const char *name, void (*init)(void))
|
||||
{
|
||||
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;
|
||||
|
||||
inits_table = vm->static_ext_inits;
|
||||
inits_table = vm_ns->vm->static_ext_inits;
|
||||
if (!inits_table) {
|
||||
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);
|
||||
}
|
||||
@ -1595,6 +1753,7 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
|
||||
VALUE path;
|
||||
char *ext;
|
||||
VALUE fname_str = rb_str_new_cstr(fname);
|
||||
GET_loading_vm_ns();
|
||||
|
||||
resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
|
||||
if (NIL_P(resolved)) {
|
||||
@ -1602,7 +1761,7 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
|
||||
if (!ext || !IS_SOEXT(ext)) {
|
||||
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 NULL;
|
||||
@ -1611,7 +1770,7 @@ rb_ext_resolve_symbol(const char* fname, const char* symbol)
|
||||
return NULL;
|
||||
}
|
||||
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)) {
|
||||
return NULL;
|
||||
}
|
||||
@ -1626,6 +1785,7 @@ Init_load(void)
|
||||
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_gvar_namespace_ready(var_load_path);
|
||||
rb_alias_variable(rb_intern_const("$-I"), id_load_path);
|
||||
rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
|
||||
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_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_snapshot = rb_ary_hidden_new(0);
|
||||
vm->loaded_features_index = st_init_numtable();
|
||||
|
@ -531,7 +531,7 @@ w_extended(VALUE klass, struct dump_arg *arg, int check)
|
||||
klass = RCLASS_SUPER(klass);
|
||||
}
|
||||
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) {
|
||||
VALUE path = rb_class_name(RBASIC(klass)->klass);
|
||||
w_byte(TYPE_EXTENDED, arg);
|
||||
|
3
method.h
3
method.h
@ -197,6 +197,7 @@ struct rb_method_definition_struct {
|
||||
|
||||
ID original_id;
|
||||
uintptr_t method_serial;
|
||||
const rb_namespace_t *ns;
|
||||
};
|
||||
|
||||
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_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);
|
||||
|
||||
@ -254,5 +256,6 @@ VALUE rb_unnamed_parameters(int arity);
|
||||
|
||||
void rb_clear_method_cache(VALUE klass_or_module, ID mid);
|
||||
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 */
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "internal.h"
|
||||
#include "internal/array.h"
|
||||
#include "internal/eval.h"
|
||||
#include "iseq.h"
|
||||
#include "vm_core.h"
|
||||
#include "builtin.h"
|
||||
@ -95,9 +96,23 @@ builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *ta
|
||||
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
|
||||
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;
|
||||
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
1139
namespace.c
Normal file
File diff suppressed because it is too large
Load Diff
21
object.c
21
object.c
@ -121,7 +121,7 @@ rb_obj_reveal(VALUE obj, VALUE klass)
|
||||
VALUE
|
||||
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);
|
||||
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");
|
||||
}
|
||||
}
|
||||
RCLASS_SET_SUPER(klass, super);
|
||||
rb_class_set_super(klass, super);
|
||||
rb_make_metaclass(klass, RBASIC(super)->klass);
|
||||
rb_class_inherited(super, klass);
|
||||
rb_mod_initialize_exec(klass);
|
||||
@ -2269,17 +2269,21 @@ rb_class_superclass(VALUE klass)
|
||||
RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS));
|
||||
|
||||
VALUE super = RCLASS_SUPER(klass);
|
||||
VALUE *superclasses;
|
||||
size_t superclasses_depth;
|
||||
|
||||
if (!super) {
|
||||
if (klass == rb_cBasicObject) return Qnil;
|
||||
rb_raise(rb_eTypeError, "uninitialized class");
|
||||
}
|
||||
|
||||
if (!RCLASS_SUPERCLASS_DEPTH(klass)) {
|
||||
superclasses_depth = RCLASS_SUPERCLASS_DEPTH(klass);
|
||||
if (!superclasses_depth) {
|
||||
return Qnil;
|
||||
}
|
||||
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));
|
||||
return super;
|
||||
}
|
||||
@ -2288,7 +2292,7 @@ rb_class_superclass(VALUE klass)
|
||||
VALUE
|
||||
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";
|
||||
@ -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, "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_cClass, "allocate", rb_class_alloc_m, 0);
|
||||
rb_define_method(rb_cClass, "new", rb_class_new_instance_pass_kw, -1);
|
||||
|
20
proc.c
20
proc.c
@ -678,6 +678,7 @@ cfunc_proc_new(VALUE klass, VALUE ifunc)
|
||||
{
|
||||
rb_proc_t *proc;
|
||||
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 *ep;
|
||||
|
||||
@ -692,6 +693,7 @@ cfunc_proc_new(VALUE klass, VALUE ifunc)
|
||||
|
||||
/* self? */
|
||||
RB_OBJ_WRITE(procval, &proc->block.as.captured.code.ifunc, ifunc);
|
||||
proc->ns = ns;
|
||||
proc->is_lambda = TRUE;
|
||||
return procval;
|
||||
}
|
||||
@ -727,6 +729,7 @@ sym_proc_new(VALUE klass, VALUE sym)
|
||||
GetProcPtr(procval, proc);
|
||||
|
||||
vm_block_type_set(&proc->block, block_type_symbol);
|
||||
// No namespace specified: similar to built-in methods
|
||||
proc->is_lambda = TRUE;
|
||||
RB_OBJ_WRITE(procval, &proc->block.as.symbol, sym);
|
||||
return procval;
|
||||
@ -2006,6 +2009,21 @@ method_owner(VALUE obj)
|
||||
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
|
||||
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, "singleton_method", rb_obj_singleton_method, 1);
|
||||
|
||||
rb_define_method(rb_cMethod, "namespace", method_namespace, 0);
|
||||
|
||||
/* UnboundMethod */
|
||||
rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject);
|
||||
rb_undef_alloc_func(rb_cUnboundMethod);
|
||||
|
3
ruby.c
3
ruby.c
@ -1824,6 +1824,9 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
|
||||
|
||||
ruby_init_prelude();
|
||||
|
||||
if (rb_namespace_available())
|
||||
rb_initialize_main_namespace();
|
||||
|
||||
// Initialize JITs after prelude because JITing prelude is typically not optimal.
|
||||
#if USE_YJIT
|
||||
rb_yjit_init(opt->yjit);
|
||||
|
12
shape.c
12
shape.c
@ -656,7 +656,7 @@ rb_shape_transition_remove_ivar(VALUE obj, ID id, VALUE *removed)
|
||||
switch(BUILTIN_TYPE(obj)) {
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
fields = RCLASS_FIELDS(obj);
|
||||
fields = RCLASS_PRIME_FIELDS(obj);
|
||||
break;
|
||||
case T_OBJECT:
|
||||
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) {
|
||||
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;
|
||||
@ -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
|
||||
if (BUILTIN_TYPE(obj) == T_OBJECT) {
|
||||
VALUE klass = rb_obj_class(obj);
|
||||
if (new_shape->next_field_index > RCLASS_EXT(klass)->max_iv_count) {
|
||||
RCLASS_EXT(klass)->max_iv_count = new_shape->next_field_index;
|
||||
if (new_shape->next_field_index > RCLASS_MAX_IV_COUNT(klass)) {
|
||||
RCLASS_SET_MAX_IV_COUNT(klass, new_shape->next_field_index);
|
||||
}
|
||||
|
||||
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 (RCLASS_EXT(klass)->variation_count >= SHAPE_MAX_VARIATIONS) {
|
||||
if (RCLASS_VARIATION_COUNT(klass) >= SHAPE_MAX_VARIATIONS) {
|
||||
rb_category_warn(
|
||||
RB_WARN_CATEGORY_PERFORMANCE,
|
||||
"The class %"PRIsVALUE" reached %d shape variations, instance variables accesses will be slower and memory usage increased.\n"
|
||||
|
@ -7,11 +7,18 @@ describe "Module#ancestors" do
|
||||
ModuleSpecs.ancestors.should == [ModuleSpecs]
|
||||
ModuleSpecs::Basic.ancestors.should == [ModuleSpecs::Basic]
|
||||
ModuleSpecs::Super.ancestors.should == [ModuleSpecs::Super, ModuleSpecs::Basic]
|
||||
if Namespace.enabled?
|
||||
ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
|
||||
[ModuleSpecs::Parent, Object, Namespace::Loader, 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
|
||||
|
||||
it "returns only modules and classes" do
|
||||
class << ModuleSpecs::Child; self; end.ancestors.should include(ModuleSpecs::Internal, Class, Module, Object, Kernel)
|
||||
|
97
test/-ext-/namespace/test_load_ext.rb
Normal file
97
test/-ext-/namespace/test_load_ext.rb
Normal 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
|
@ -9,7 +9,11 @@ class TestABI < Test::Unit::TestCase
|
||||
assert_separately [], <<~RUBY
|
||||
err = assert_raise(LoadError) { require "-test-/abi" }
|
||||
assert_match(/incompatible ABI version/, err.message)
|
||||
if Namespace.enabled?
|
||||
assert_include err.message, "_-test-+abi."
|
||||
else
|
||||
assert_include err.message, "/-test-/abi."
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
@ -27,7 +31,11 @@ class TestABI < Test::Unit::TestCase
|
||||
assert_separately [{ "RUBY_ABI_CHECK" => "1" }], <<~RUBY
|
||||
err = assert_raise(LoadError) { require "-test-/abi" }
|
||||
assert_match(/incompatible ABI version/, err.message)
|
||||
if Namespace.enabled?
|
||||
assert_include err.message, "_-test-+abi."
|
||||
else
|
||||
assert_include err.message, "/-test-/abi."
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
|
17
test/ruby/namespace/a.1_1_0.rb
Normal file
17
test/ruby/namespace/a.1_1_0.rb
Normal 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
|
17
test/ruby/namespace/a.1_2_0.rb
Normal file
17
test/ruby/namespace/a.1_2_0.rb
Normal 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
15
test/ruby/namespace/a.rb
Normal 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
|
8
test/ruby/namespace/autoloading.rb
Normal file
8
test/ruby/namespace/autoloading.rb
Normal 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
|
2
test/ruby/namespace/blank.rb
Normal file
2
test/ruby/namespace/blank.rb
Normal file
@ -0,0 +1,2 @@
|
||||
module Blank1
|
||||
end
|
2
test/ruby/namespace/blank1.rb
Normal file
2
test/ruby/namespace/blank1.rb
Normal file
@ -0,0 +1,2 @@
|
||||
module Blank1
|
||||
end
|
2
test/ruby/namespace/blank2.rb
Normal file
2
test/ruby/namespace/blank2.rb
Normal file
@ -0,0 +1,2 @@
|
||||
module Blank2
|
||||
end
|
5
test/ruby/namespace/call_proc.rb
Normal file
5
test/ruby/namespace/call_proc.rb
Normal file
@ -0,0 +1,5 @@
|
||||
module Bar
|
||||
def self.caller(proc_value)
|
||||
proc_value.call
|
||||
end
|
||||
end
|
8
test/ruby/namespace/call_toplevel.rb
Normal file
8
test/ruby/namespace/call_toplevel.rb
Normal 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
|
147
test/ruby/namespace/consts.rb
Normal file
147
test/ruby/namespace/consts.rb
Normal 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
|
13
test/ruby/namespace/current.rb
Normal file
13
test/ruby/namespace/current.rb
Normal 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
|
5
test/ruby/namespace/define_toplevel.rb
Normal file
5
test/ruby/namespace/define_toplevel.rb
Normal file
@ -0,0 +1,5 @@
|
||||
def foo
|
||||
"foooooooooo"
|
||||
end
|
||||
|
||||
foo # should not raise errors
|
37
test/ruby/namespace/global_vars.rb
Normal file
37
test/ruby/namespace/global_vars.rb
Normal 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
|
9
test/ruby/namespace/line_splitter.rb
Normal file
9
test/ruby/namespace/line_splitter.rb
Normal file
@ -0,0 +1,9 @@
|
||||
module LineSplitter
|
||||
def self.read
|
||||
$-0
|
||||
end
|
||||
|
||||
def self.write(char)
|
||||
$-0 = char
|
||||
end
|
||||
end
|
26
test/ruby/namespace/load_path.rb
Normal file
26
test/ruby/namespace/load_path.rb
Normal 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
10
test/ruby/namespace/ns.rb
Normal 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
|
31
test/ruby/namespace/open_class_with_include.rb
Normal file
31
test/ruby/namespace/open_class_with_include.rb
Normal 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
|
14
test/ruby/namespace/proc_callee.rb
Normal file
14
test/ruby/namespace/proc_callee.rb
Normal 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
|
||||
|
5
test/ruby/namespace/proc_caller.rb
Normal file
5
test/ruby/namespace/proc_caller.rb
Normal file
@ -0,0 +1,5 @@
|
||||
module Bar
|
||||
def self.caller(proc_value)
|
||||
proc_value.call
|
||||
end
|
||||
end
|
64
test/ruby/namespace/procs.rb
Normal file
64
test/ruby/namespace/procs.rb
Normal 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
|
3
test/ruby/namespace/raise.rb
Normal file
3
test/ruby/namespace/raise.rb
Normal file
@ -0,0 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
raise "Yay!"
|
12
test/ruby/namespace/returns_proc.rb
Normal file
12
test/ruby/namespace/returns_proc.rb
Normal file
@ -0,0 +1,12 @@
|
||||
module Foo
|
||||
def self.foo
|
||||
"fooooo"
|
||||
end
|
||||
|
||||
def self.callee
|
||||
lambda do
|
||||
Foo.foo
|
||||
end
|
||||
end
|
||||
end
|
||||
|
65
test/ruby/namespace/singleton_methods.rb
Normal file
65
test/ruby/namespace/singleton_methods.rb
Normal 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
|
13
test/ruby/namespace/string_ext.rb
Normal file
13
test/ruby/namespace/string_ext.rb
Normal 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
|
5
test/ruby/namespace/string_ext_caller.rb
Normal file
5
test/ruby/namespace/string_ext_caller.rb
Normal file
@ -0,0 +1,5 @@
|
||||
module Foo
|
||||
def self.yay
|
||||
String.new.yay
|
||||
end
|
||||
end
|
1
test/ruby/namespace/string_ext_calling.rb
Normal file
1
test/ruby/namespace/string_ext_calling.rb
Normal file
@ -0,0 +1 @@
|
||||
Foo.yay
|
12
test/ruby/namespace/string_ext_eval_caller.rb
Normal file
12
test/ruby/namespace/string_ext_eval_caller.rb
Normal 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
|
33
test/ruby/namespace/top_level.rb
Normal file
33
test/ruby/namespace/top_level.rb
Normal 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
|
@ -224,11 +224,18 @@ p Foo::Bar
|
||||
Kernel.module_eval do
|
||||
alias old_require require
|
||||
end
|
||||
Namespace.module_eval do
|
||||
alias old_require require
|
||||
end
|
||||
called_with = []
|
||||
Kernel.send :define_method, :require do |path|
|
||||
called_with << path
|
||||
old_require path
|
||||
end
|
||||
Namespace.send :define_method, :require do |path|
|
||||
called_with << path
|
||||
old_require path
|
||||
end
|
||||
yield called_with
|
||||
ensure
|
||||
Kernel.module_eval do
|
||||
@ -236,6 +243,11 @@ p Foo::Bar
|
||||
alias require old_require
|
||||
undef old_require
|
||||
end
|
||||
Namespace.module_eval do
|
||||
undef require
|
||||
alias require old_require
|
||||
undef old_require
|
||||
end
|
||||
end
|
||||
|
||||
def test_require_implemented_in_ruby_is_called
|
||||
@ -249,7 +261,8 @@ p Foo::Bar
|
||||
ensure
|
||||
remove_autoload_constant
|
||||
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
|
||||
@ -267,7 +280,8 @@ p Foo::Bar
|
||||
ensure
|
||||
remove_autoload_constant
|
||||
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
|
||||
|
516
test/ruby/test_namespace.rb
Normal file
516
test/ruby/test_namespace.rb
Normal 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
|
@ -260,6 +260,8 @@ class TestRubyOptions < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
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 --dump=parsetree -e _=:hi), "", /"hi"/, [])
|
||||
|
||||
|
261
variable.c
261
variable.c
@ -25,6 +25,7 @@
|
||||
#include "internal/error.h"
|
||||
#include "internal/eval.h"
|
||||
#include "internal/hash.h"
|
||||
#include "internal/namespace.h"
|
||||
#include "internal/object.h"
|
||||
#include "internal/gc.h"
|
||||
#include "internal/re.h"
|
||||
@ -109,10 +110,10 @@ classname(VALUE klass, bool *permanent)
|
||||
{
|
||||
*permanent = false;
|
||||
|
||||
VALUE classpath = RCLASS_EXT(klass)->classpath;
|
||||
VALUE classpath = RCLASS_CLASSPATH(klass);
|
||||
if (classpath == 0) return Qnil;
|
||||
|
||||
*permanent = RCLASS_EXT(klass)->permanent_classpath;
|
||||
*permanent = RCLASS_PERMANENT_CLASSPATH_P(klass);
|
||||
|
||||
return classpath;
|
||||
}
|
||||
@ -210,7 +211,7 @@ static enum rb_id_table_iterator_result
|
||||
set_sub_temporary_name_i(ID id, VALUE val, void *data)
|
||||
{
|
||||
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;
|
||||
struct sub_temporary_name_args *args = data;
|
||||
args->last = id;
|
||||
@ -222,7 +223,7 @@ set_sub_temporary_name_i(ID id, VALUE val, void *data)
|
||||
static void
|
||||
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);
|
||||
if (!tbl) return;
|
||||
if (!name) {
|
||||
@ -296,7 +297,7 @@ VALUE
|
||||
rb_mod_set_temporary_name(VALUE mod, VALUE name)
|
||||
{
|
||||
// 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");
|
||||
}
|
||||
|
||||
@ -529,6 +530,7 @@ struct rb_global_variable {
|
||||
rb_gvar_marker_t *marker;
|
||||
rb_gvar_compact_t *compactor;
|
||||
struct trace_var *trace;
|
||||
bool namespace_ready;
|
||||
};
|
||||
|
||||
struct rb_global_entry {
|
||||
@ -604,6 +606,13 @@ rb_gvar_ractor_local(const char *name)
|
||||
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
|
||||
rb_gvar_undef_compactor(void *var)
|
||||
{
|
||||
@ -629,6 +638,7 @@ rb_global_entry(ID id)
|
||||
|
||||
var->block_trace = 0;
|
||||
var->trace = 0;
|
||||
var->namespace_ready = false;
|
||||
rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
|
||||
}
|
||||
return entry;
|
||||
@ -982,13 +992,27 @@ rb_gvar_set_entry(struct rb_global_entry *entry, VALUE 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
|
||||
rb_gvar_set(ID id, VALUE val)
|
||||
{
|
||||
VALUE retval;
|
||||
struct rb_global_entry *entry;
|
||||
const rb_namespace_t *ns = rb_current_namespace();
|
||||
|
||||
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
|
||||
@ -1000,9 +1024,27 @@ rb_gv_set(const char *name, VALUE val)
|
||||
VALUE
|
||||
rb_gvar_get(ID id)
|
||||
{
|
||||
VALUE retval, gvars, key;
|
||||
struct rb_global_entry *entry = rb_global_entry(id);
|
||||
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
|
||||
@ -1056,6 +1098,7 @@ rb_f_global_variables(void)
|
||||
if (!rb_ractor_main_p()) {
|
||||
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);
|
||||
if (!NIL_P(backref)) {
|
||||
@ -1335,7 +1378,7 @@ rb_obj_field_get(VALUE obj, rb_shape_t *target_shape)
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
ASSERT_vm_locking();
|
||||
fields = RCLASS_FIELDS(obj);
|
||||
fields = RCLASS_PRIME_FIELDS(obj);
|
||||
break;
|
||||
case T_OBJECT:
|
||||
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);
|
||||
|
||||
if (found) {
|
||||
ivar_list = RCLASS_FIELDS(obj);
|
||||
ivar_list = RCLASS_PRIME_FIELDS(obj);
|
||||
RUBY_ASSERT(ivar_list);
|
||||
|
||||
val = ivar_list[index];
|
||||
@ -1501,7 +1544,7 @@ rb_ivar_delete(VALUE obj, ID id, VALUE undef)
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
table = RCLASS_FIELDS_HASH(obj);
|
||||
table = RCLASS_WRITABLE_FIELDS_HASH(obj);
|
||||
break;
|
||||
|
||||
case T_OBJECT:
|
||||
@ -1551,7 +1594,7 @@ obj_transition_too_complex(VALUE obj, st_table *table)
|
||||
break;
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
old_fields = RCLASS_FIELDS(obj);
|
||||
old_fields = RCLASS_PRIME_FIELDS(obj);
|
||||
rb_shape_set_shape_id(obj, shape_id);
|
||||
RCLASS_SET_FIELDS_HASH(obj, table);
|
||||
break;
|
||||
@ -2124,7 +2167,7 @@ rb_ivar_defined(VALUE obj, ID id)
|
||||
switch (BUILTIN_TYPE(obj)) {
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
table = (st_table *)RCLASS_FIELDS(obj);
|
||||
table = (st_table *)RCLASS_FIELDS_HASH(obj);
|
||||
break;
|
||||
|
||||
case T_OBJECT:
|
||||
@ -2188,7 +2231,8 @@ iterate_over_shapes_with_callback(rb_shape_t *shape, rb_ivar_foreach_callback_fu
|
||||
break;
|
||||
case T_CLASS:
|
||||
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;
|
||||
default:
|
||||
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)) {
|
||||
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 {
|
||||
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
|
||||
// the original module.
|
||||
if (RB_TYPE_P(mod, T_ICLASS)) {
|
||||
if (FL_TEST_RAW(mod, RICLASS_IS_ORIGIN)) {
|
||||
if (RICLASS_IS_ORIGIN_P(mod)) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
@ -2729,6 +2773,10 @@ struct autoload_const {
|
||||
// The shared "autoload_data" if multiple constants are defined from the same feature.
|
||||
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.
|
||||
VALUE module;
|
||||
|
||||
@ -2866,6 +2914,70 @@ get_autoload_data(VALUE autoload_const_value, struct autoload_const **autoload_c
|
||||
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
|
||||
rb_autoload(VALUE module, ID name, const char *feature)
|
||||
{
|
||||
@ -2883,6 +2995,7 @@ struct autoload_arguments {
|
||||
VALUE module;
|
||||
ID name;
|
||||
VALUE feature;
|
||||
VALUE namespace;
|
||||
};
|
||||
|
||||
static VALUE
|
||||
@ -2952,6 +3065,7 @@ autoload_synchronized(VALUE _arguments)
|
||||
{
|
||||
struct autoload_const *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->name = arguments->name;
|
||||
autoload_const->value = Qundef;
|
||||
@ -2968,6 +3082,9 @@ autoload_synchronized(VALUE _arguments)
|
||||
void
|
||||
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)) {
|
||||
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,
|
||||
.name = name,
|
||||
.feature = feature,
|
||||
.namespace = current_namespace,
|
||||
};
|
||||
|
||||
VALUE result = rb_mutex_synchronize(autoload_mutex, autoload_synchronized, (VALUE)&arguments);
|
||||
@ -3241,22 +3359,82 @@ autoload_apply_constants(VALUE _arguments)
|
||||
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
|
||||
autoload_feature_require(VALUE _arguments)
|
||||
{
|
||||
VALUE receiver = rb_vm_top_self();
|
||||
|
||||
struct autoload_load_arguments *arguments = (struct autoload_load_arguments*)_arguments;
|
||||
|
||||
struct autoload_const *autoload_const = arguments->autoload_const;
|
||||
VALUE autoload_namespace = autoload_const->namespace;
|
||||
|
||||
// We save this for later use in autoload_apply_constants:
|
||||
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)) {
|
||||
return rb_mutex_synchronize(autoload_mutex, autoload_apply_constants, _arguments);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3580,6 +3758,8 @@ rb_mod_remove_const(VALUE mod, VALUE name)
|
||||
return rb_const_remove(mod, id);
|
||||
}
|
||||
|
||||
static rb_const_entry_t * const_lookup(struct rb_id_table *tbl, ID id);
|
||||
|
||||
VALUE
|
||||
rb_const_remove(VALUE mod, ID id)
|
||||
{
|
||||
@ -3589,7 +3769,7 @@ rb_const_remove(VALUE mod, ID id)
|
||||
rb_check_frozen(mod);
|
||||
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -3829,8 +4013,8 @@ set_namespace_path_i(ID id, VALUE v, void *payload)
|
||||
}
|
||||
set_namespace_path(value, build_const_path(parental_path, id));
|
||||
|
||||
if (!RCLASS_EXT(value)->permanent_classpath) {
|
||||
RCLASS_SET_CLASSPATH(value, 0, false);
|
||||
if (!RCLASS_PERMANENT_CLASSPATH_P(value)) {
|
||||
RCLASS_WRITE_CLASSPATH(value, 0, false);
|
||||
}
|
||||
|
||||
return ID_TABLE_CONTINUE;
|
||||
@ -3848,7 +4032,7 @@ set_namespace_path(VALUE named_namespace, VALUE namespace_path)
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
RCLASS_SET_CLASSPATH(named_namespace, namespace_path, true);
|
||||
RCLASS_WRITE_CLASSPATH(named_namespace, namespace_path, true);
|
||||
|
||||
if (const_table) {
|
||||
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();
|
||||
{
|
||||
struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
|
||||
struct rb_id_table *tbl = RCLASS_WRITABLE_CONST_TBL(klass);
|
||||
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);
|
||||
ce = ZALLOC(rb_const_entry_t);
|
||||
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);
|
||||
}
|
||||
else {
|
||||
tbl = RCLASS_WRITABLE_CONST_TBL(klass);
|
||||
rb_clear_constant_cache_for_id(id);
|
||||
|
||||
ce = ZALLOC(rb_const_entry_t);
|
||||
@ -4172,7 +4358,7 @@ static int
|
||||
cvar_lookup_at(VALUE klass, ID id, st_data_t *v)
|
||||
{
|
||||
if (RB_TYPE_P(klass, T_ICLASS)) {
|
||||
if (FL_TEST_RAW(klass, RICLASS_IS_ORIGIN)) {
|
||||
if (RICLASS_IS_ORIGIN_P(klass)) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
@ -4277,10 +4463,11 @@ rb_cvar_set(VALUE klass, ID id, VALUE 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) {
|
||||
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;
|
||||
@ -4304,7 +4491,7 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
|
||||
// cvar in this lookup.
|
||||
if (result == 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -4538,13 +4725,13 @@ class_ivar_set_shape_fields(VALUE obj, void *_data)
|
||||
{
|
||||
RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj));
|
||||
|
||||
return RCLASS_FIELDS(obj);
|
||||
return RCLASS_PRIME_FIELDS(obj);
|
||||
}
|
||||
|
||||
static void
|
||||
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
|
||||
@ -4564,7 +4751,7 @@ class_ivar_set_too_complex_table(VALUE obj, void *_data)
|
||||
{
|
||||
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
|
||||
|
||||
return RCLASS_FIELDS_HASH(obj);
|
||||
return RCLASS_WRITABLE_FIELDS_HASH(obj);
|
||||
}
|
||||
|
||||
int
|
||||
@ -4574,6 +4761,8 @@ rb_class_ivar_set(VALUE obj, ID id, VALUE val)
|
||||
bool existing = false;
|
||||
rb_check_frozen(obj);
|
||||
|
||||
rb_class_ensure_writable(obj);
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
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_const_entry_t *
|
||||
rb_const_lookup(VALUE klass, ID id)
|
||||
static rb_const_entry_t *
|
||||
const_lookup(struct rb_id_table *tbl, ID id)
|
||||
{
|
||||
struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
|
||||
|
||||
if (tbl) {
|
||||
VALUE val;
|
||||
bool r;
|
||||
@ -4638,3 +4825,9 @@ rb_const_lookup(VALUE klass, ID id)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rb_const_entry_t *
|
||||
rb_const_lookup(VALUE klass, ID id)
|
||||
{
|
||||
return const_lookup(RCLASS_CONST_TBL(klass), id);
|
||||
}
|
||||
|
63
vm.c
63
vm.c
@ -21,6 +21,7 @@
|
||||
#include "internal/gc.h"
|
||||
#include "internal/inits.h"
|
||||
#include "internal/missing.h"
|
||||
#include "internal/namespace.h"
|
||||
#include "internal/object.h"
|
||||
#include "internal/proc.h"
|
||||
#include "internal/re.h"
|
||||
@ -1164,6 +1165,7 @@ vm_proc_create_from_captured(VALUE klass,
|
||||
{
|
||||
VALUE procval = rb_proc_alloc(klass);
|
||||
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));
|
||||
|
||||
@ -1173,6 +1175,7 @@ vm_proc_create_from_captured(VALUE klass,
|
||||
rb_vm_block_ep_update(procval, &proc->block, captured->ep);
|
||||
|
||||
vm_block_type_set(&proc->block, block_type);
|
||||
proc->ns = ns;
|
||||
proc->is_from_method = is_from_method;
|
||||
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);
|
||||
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)));
|
||||
rb_vm_block_copy(procval, &proc->block, block);
|
||||
vm_block_type_set(&proc->block, block->type);
|
||||
proc->ns = ns;
|
||||
proc->is_from_method = is_from_method;
|
||||
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)
|
||||
{
|
||||
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)) {
|
||||
klass = RBASIC_CLASS(klass);
|
||||
}
|
||||
@ -2871,6 +2876,19 @@ rb_iseq_eval(const rb_iseq_t *iseq)
|
||||
rb_execution_context_t *ec = GET_EC();
|
||||
VALUE val;
|
||||
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);
|
||||
return val;
|
||||
}
|
||||
@ -2880,8 +2898,8 @@ rb_iseq_eval_main(const rb_iseq_t *iseq)
|
||||
{
|
||||
rb_execution_context_t *ec = GET_EC();
|
||||
VALUE val;
|
||||
|
||||
vm_set_main_stack(ec, iseq);
|
||||
// TODO: set the namespace frame like require/load
|
||||
val = vm_exec(ec);
|
||||
return val;
|
||||
}
|
||||
@ -2934,6 +2952,26 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg,
|
||||
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 */
|
||||
|
||||
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_realpath_map = rb_gc_location(vm->loaded_features_realpath_map);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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->load_path);
|
||||
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_realpaths);
|
||||
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->orig_progname);
|
||||
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);
|
||||
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();
|
||||
|
||||
@ -3505,6 +3550,8 @@ thread_mark(void *ptr)
|
||||
rb_gc_mark(th->pending_interrupt_mask_stack);
|
||||
rb_gc_mark(th->top_self);
|
||||
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);
|
||||
|
||||
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->top_wrapper = 0;
|
||||
th->top_self = vm->top_self; // 0 while self == 0
|
||||
th->namespaces = 0;
|
||||
th->ns = 0;
|
||||
th->value = Qundef;
|
||||
|
||||
th->ec->errinfo = Qnil;
|
||||
@ -3682,10 +3731,16 @@ th_init(rb_thread_t *th, VALUE self, rb_vm_t *vm)
|
||||
VALUE
|
||||
rb_thread_alloc(VALUE klass)
|
||||
{
|
||||
rb_namespace_t *ns;
|
||||
rb_execution_context_t *ec = GET_EC();
|
||||
VALUE self = thread_alloc(klass);
|
||||
rb_thread_t *target_th = rb_thread_ptr(self);
|
||||
target_th->ractor = GET_RACTOR();
|
||||
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;
|
||||
}
|
||||
|
||||
@ -4234,6 +4289,8 @@ Init_VM(void)
|
||||
th->vm = vm;
|
||||
th->top_wrapper = 0;
|
||||
th->top_self = rb_vm_top_self();
|
||||
th->namespaces = 0;
|
||||
th->ns = 0;
|
||||
|
||||
rb_vm_register_global_object((VALUE)iseq);
|
||||
th->ec->cfp->iseq = iseq;
|
||||
|
@ -597,10 +597,13 @@ vm_cc_check_cme(const struct rb_callcache *cc, const rb_callable_method_entry_t
|
||||
#if 1
|
||||
// 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(vm_cc_cme(cc));
|
||||
rb_vm_lookup_overloaded_cme(cme);
|
||||
rp(rb_vm_lookup_overloaded_cme(cme));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
24
vm_core.h
24
vm_core.h
@ -118,6 +118,7 @@ extern int ruby_assert_critical_section_entered;
|
||||
#include "internal.h"
|
||||
#include "internal/array.h"
|
||||
#include "internal/basic_operators.h"
|
||||
#include "internal/namespace.h"
|
||||
#include "internal/sanitizers.h"
|
||||
#include "internal/serial.h"
|
||||
#include "internal/set_table.h"
|
||||
@ -312,6 +313,7 @@ struct rb_calling_info {
|
||||
int argc;
|
||||
bool kw_splat;
|
||||
VALUE heap_argv;
|
||||
const rb_namespace_t *proc_ns;
|
||||
};
|
||||
|
||||
#ifndef VM_ARGC_STACK_MAX
|
||||
@ -743,6 +745,9 @@ typedef struct rb_vm_struct {
|
||||
struct global_object_list *global_object_list;
|
||||
const VALUE special_exceptions[ruby_special_error_count];
|
||||
|
||||
/* namespace */
|
||||
rb_namespace_t *main_namespace;
|
||||
|
||||
/* load */
|
||||
VALUE top_self;
|
||||
VALUE load_path;
|
||||
@ -818,6 +823,8 @@ typedef struct rb_vm_struct {
|
||||
size_t fiber_machine_stack_size;
|
||||
} default_params;
|
||||
|
||||
// TODO: a single require_stack can't support multi-threaded require trees
|
||||
VALUE require_stack;
|
||||
} rb_vm_t;
|
||||
|
||||
/* default values */
|
||||
@ -1119,6 +1126,9 @@ typedef struct rb_thread_struct {
|
||||
/* for load(true) */
|
||||
VALUE top_self;
|
||||
VALUE top_wrapper;
|
||||
/* for namespace */
|
||||
VALUE namespaces; // Stack of namespaces
|
||||
rb_namespace_t *ns; // The current one
|
||||
|
||||
/* thread control */
|
||||
|
||||
@ -1258,6 +1268,7 @@ RUBY_SYMBOL_EXPORT_END
|
||||
|
||||
typedef struct {
|
||||
const struct rb_block block;
|
||||
const rb_namespace_t *ns;
|
||||
unsigned int is_from_method: 1; /* bool */
|
||||
unsigned int is_lambda: 1; /* bool */
|
||||
unsigned int is_isolated: 1; /* bool */
|
||||
@ -1349,11 +1360,11 @@ typedef rb_control_frame_t *
|
||||
|
||||
enum vm_frame_env_flags {
|
||||
/* 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)
|
||||
* EEE : 4 bits Env flags
|
||||
* FF..: 7 bits Frame flags
|
||||
* FF..: 9 bits Frame flags
|
||||
* 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_CFRAME_KW = 0x0400,
|
||||
VM_FRAME_FLAG_PASSED = 0x0800,
|
||||
VM_FRAME_FLAG_NS_SWITCH = 0x1000,
|
||||
VM_FRAME_FLAG_LOAD_ISEQ = 0x2000,
|
||||
|
||||
/* env flag */
|
||||
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);
|
||||
}
|
||||
|
||||
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) \
|
||||
(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 */
|
||||
RUBY_SYMBOL_EXPORT_BEGIN
|
||||
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_path(const rb_iseq_t *iseq);
|
||||
VALUE rb_iseq_realpath(const rb_iseq_t *iseq);
|
||||
|
29
vm_eval.c
29
vm_eval.c
@ -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 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));
|
||||
@ -447,7 +447,8 @@ scope_to_ci(call_type scope, ID mid, int argc, struct rb_callinfo *ci)
|
||||
static inline const struct rb_callcache *
|
||||
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)) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (NAMESPACE_USER_P(ns)) {
|
||||
ns_value = ns->ns_object;
|
||||
} else {
|
||||
ns_value = 0;
|
||||
}
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
vm_set_eval_stack(ec, iseq, cref, &block);
|
||||
// TODO: set the namespace frame
|
||||
|
||||
/* kick */
|
||||
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));
|
||||
}
|
||||
|
||||
// TODO: set the namespace frame
|
||||
|
||||
/* kick */
|
||||
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, "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_tag = rb_intern_const("tag");
|
||||
id_value = rb_intern_const("value");
|
||||
|
@ -134,7 +134,7 @@ callable_method_entry_p(const rb_callable_method_entry_t *cme)
|
||||
return TRUE;
|
||||
}
|
||||
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)) {
|
||||
return TRUE;
|
||||
@ -418,7 +418,7 @@ vm_push_frame(rb_execution_context_t *ec,
|
||||
#if VM_DEBUG_BP_CHECK
|
||||
.bp_check = sp,
|
||||
#endif
|
||||
.jit_return = NULL
|
||||
.jit_return = NULL,
|
||||
};
|
||||
|
||||
/* 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) {
|
||||
if (RCLASS_SINGLETON_P(CREF_CLASS(cref)) ||
|
||||
RCLASS_EXT(CREF_CLASS(cref))->cloned) {
|
||||
RCLASS_CLONED_P(CREF_CLASS(cref)) ) {
|
||||
return key_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
|
||||
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)) {
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
table = (st_table *)RCLASS_FIELDS(obj);
|
||||
table = (st_table *)RCLASS_FIELDS_HASH(obj);
|
||||
break;
|
||||
|
||||
case T_OBJECT:
|
||||
@ -2079,7 +2079,7 @@ static const struct rb_callcache *
|
||||
vm_search_cc(const VALUE klass, const struct rb_callinfo * const 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;
|
||||
VALUE ccs_data;
|
||||
|
||||
@ -2125,7 +2125,8 @@ vm_search_cc(const VALUE klass, const struct rb_callinfo * const ci)
|
||||
}
|
||||
}
|
||||
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);
|
||||
@ -4123,7 +4124,7 @@ rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner)
|
||||
VALUE klass = current_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)) {
|
||||
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
|
||||
vm_yield_with_cfunc(rb_execution_context_t *ec,
|
||||
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 argv = rsp;
|
||||
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);
|
||||
|
||||
if (calling->proc_ns) {
|
||||
frame_flag |= VM_FRAME_FLAG_NS_SWITCH;
|
||||
}
|
||||
|
||||
vm_push_frame(ec, iseq,
|
||||
VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0),
|
||||
frame_flag,
|
||||
captured->self,
|
||||
VM_GUARDED_PREV_EP(captured->ep), 0,
|
||||
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) {
|
||||
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);
|
||||
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 */
|
||||
rb_autoload_load(cbase, id);
|
||||
|
||||
if ((klass = vm_const_get_under(id, flags, cbase)) != 0) {
|
||||
if (!vm_check_if_class(id, flags, super, 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);
|
||||
// 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)) {
|
||||
|
||||
RCLASS_EXT(klass)->max_iv_count = rb_estimate_iv_count(klass, (const rb_iseq_t *)iseqval);
|
||||
RCLASS_WRITE_MAX_IV_COUNT(klass, rb_estimate_iv_count(klass, (const rb_iseq_t *)iseqval));
|
||||
}
|
||||
|
||||
if (!is_singleton && vm_scope_module_func_check(ec)) {
|
||||
|
197
vm_method.c
197
vm_method.c
@ -39,7 +39,7 @@ vm_ccs_dump_i(ID mid, VALUE val, void *data)
|
||||
static void
|
||||
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) {
|
||||
VALUE ccs;
|
||||
if (target_mid) {
|
||||
@ -87,18 +87,18 @@ vm_mtbl_dump(VALUE klass, ID target_mid)
|
||||
else {
|
||||
fprintf(stderr, " MTBL: NULL\n");
|
||||
}
|
||||
if (RCLASS_CALLABLE_M_TBL(klass)) {
|
||||
if (RCLASS_WRITABLE_CALLABLE_M_TBL(klass)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
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);
|
||||
}
|
||||
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 *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
|
||||
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;
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
if (LIKELY(RCLASS_SUBCLASSES(klass) == NULL)) {
|
||||
if (LIKELY(RCLASS_SUBCLASSES_FIRST(klass) == NULL)) {
|
||||
// no subclasses
|
||||
// check only current class
|
||||
|
||||
struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
|
||||
VALUE ccs_data;
|
||||
|
||||
// invalidate CCs
|
||||
if (cc_tbl && rb_id_table_lookup(cc_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(cc_tbl, mid);
|
||||
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf_ccs);
|
||||
struct rb_id_table *cc_tbl = RCLASS_WRITABLE_CC_TBL(klass);
|
||||
invalidate_method_cache_in_cc_table(cc_tbl, mid);
|
||||
if (RCLASS_CC_TBL_NOT_PRIME_P(klass, cc_tbl)) {
|
||||
invalidate_method_cache_in_cc_table(RCLASS_PRIME_CC_TBL(klass), mid);
|
||||
}
|
||||
|
||||
// remove from callable_m_tbl, if exists
|
||||
struct rb_id_table *cm_tbl;
|
||||
if ((cm_tbl = RCLASS_CALLABLE_M_TBL(klass)) != NULL) {
|
||||
VALUE cme;
|
||||
if (rb_yjit_enabled_p && rb_id_table_lookup(cm_tbl, mid, &cme)) {
|
||||
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);
|
||||
struct rb_id_table *cm_tbl = RCLASS_WRITABLE_CALLABLE_M_TBL(klass);
|
||||
invalidate_callable_method_entry_in_callable_m_table(cm_tbl, mid);
|
||||
if (RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(klass, cm_tbl)) {
|
||||
invalidate_callable_method_entry_in_callable_m_table(RCLASS_PRIME_CALLABLE_M_TBL(klass), mid);
|
||||
}
|
||||
|
||||
RB_DEBUG_COUNTER_INC(cc_invalidate_leaf);
|
||||
}
|
||||
else {
|
||||
@ -223,10 +286,9 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid)
|
||||
else {
|
||||
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);
|
||||
const rb_method_entry_t *new_cme = rb_method_entry_clone((const rb_method_entry_t *)cme);
|
||||
rb_method_table_insert(klass_housing_cme, RCLASS_M_TBL(klass_housing_cme), mid, new_cme);
|
||||
|
||||
// replace the cme that will be invalid in the all classexts
|
||||
invalidate_callable_method_entry_in_every_m_table(klass_housing_cme, mid, 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
|
||||
// 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) {
|
||||
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
|
||||
if (METHOD_ENTRY_COMPLEMENTED(cme)) {
|
||||
VALUE defined_class = cme->defined_class;
|
||||
struct rb_id_table *cm_tbl = RCLASS_CALLABLE_M_TBL(defined_class);
|
||||
VM_ASSERT(cm_tbl != NULL);
|
||||
int r = rb_id_table_delete(cm_tbl, mid);
|
||||
VM_ASSERT(r == TRUE); (void)r;
|
||||
RB_DEBUG_COUNTER_INC(cc_invalidate_tree_callable);
|
||||
struct rb_id_table *cm_tbl = RCLASS_WRITABLE_CALLABLE_M_TBL(defined_class);
|
||||
invalidate_complemented_method_entry_in_callable_m_table(cm_tbl, mid);
|
||||
if (RCLASS_CALLABLE_M_TBL_NOT_PRIME_P(defined_class, cm_tbl)) {
|
||||
struct rb_id_table *prime_cm_table = RCLASS_PRIME_CALLABLE_M_TBL(defined_class);
|
||||
invalidate_complemented_method_entry_in_callable_m_table(prime_cm_table, mid);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
rb_gccct_clear_table(Qnil);
|
||||
|
||||
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
|
||||
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
|
||||
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;
|
||||
if (RB_TYPE_P(klass, T_ICLASS) && !RICLASS_OWNS_M_TBL_P(klass)) {
|
||||
if (iclass_shared_mtbl) {
|
||||
table_owner = RBASIC(table_owner)->klass;
|
||||
}
|
||||
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_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;
|
||||
static uintptr_t method_serial = 1;
|
||||
def->method_serial = method_serial++;
|
||||
def->ns = rb_current_namespace();
|
||||
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);
|
||||
}
|
||||
}
|
||||
mtbl = RCLASS_M_TBL(klass);
|
||||
mtbl = RCLASS_WRITABLE_M_TBL(klass);
|
||||
|
||||
/* check re-definition */
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1366,23 +1468,27 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_
|
||||
struct rb_id_table *mtbl;
|
||||
const rb_callable_method_entry_t *cme;
|
||||
VALUE cme_data;
|
||||
int cme_found = 0;
|
||||
|
||||
if (me) {
|
||||
if (me->defined_class == 0) {
|
||||
RB_DEBUG_COUNTER_INC(mc_cme_complement);
|
||||
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)) {
|
||||
cme = (rb_callable_method_entry_t *)cme_data;
|
||||
cme_found = 1;
|
||||
}
|
||||
if (cme_found) {
|
||||
RB_DEBUG_COUNTER_INC(mc_cme_complement_hit);
|
||||
VM_ASSERT(callable_method_entry_p(cme));
|
||||
VM_ASSERT(!METHOD_ENTRY_INVALIDATED(cme));
|
||||
}
|
||||
else if (create) {
|
||||
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);
|
||||
rb_id_table_insert(mtbl, id, (VALUE)cme);
|
||||
@ -1418,7 +1524,7 @@ cached_callable_method_entry(VALUE klass, ID mid)
|
||||
{
|
||||
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;
|
||||
|
||||
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();
|
||||
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;
|
||||
|
||||
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)) {
|
||||
@ -1694,7 +1801,7 @@ remove_method(VALUE klass, ID mid)
|
||||
rb_clear_method_cache(self, 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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user