Move FL_SINGLETON to FL_USER1

This frees FL_USER0 on both T_MODULE and T_CLASS.

Note: prior to this, FL_SINGLETON was never set on T_MODULE,
so checking for `FL_SINGLETON` without first checking that
`FL_TYPE` was `T_CLASS` was valid. That's no longer the case.
This commit is contained in:
Jean Boussier 2024-03-06 11:04:22 -05:00 committed by Peter Zhu
parent b88973165a
commit b4a69351ec
23 changed files with 76 additions and 56 deletions

30
class.c
View File

@ -32,7 +32,7 @@
/* Flags of T_CLASS /* Flags of T_CLASS
* *
* 0: RUBY_FL_SINGLETON * 1: RUBY_FL_SINGLETON
* This class is a singleton class. * This class is a singleton class.
* 2: RCLASS_SUPERCLASSES_INCLUDE_SELF * 2: RCLASS_SUPERCLASSES_INCLUDE_SELF
* The RCLASS_SUPERCLASSES contains the class as the last element. * The RCLASS_SUPERCLASSES contains the class as the last element.
@ -340,7 +340,7 @@ rb_check_inheritable(VALUE super)
rb_raise(rb_eTypeError, "superclass must be an instance of Class (given an instance of %"PRIsVALUE")", rb_raise(rb_eTypeError, "superclass must be an instance of Class (given an instance of %"PRIsVALUE")",
rb_obj_class(super)); rb_obj_class(super));
} }
if (RBASIC(super)->flags & FL_SINGLETON) { if (RCLASS_SINGLETON_P(super)) {
rb_raise(rb_eTypeError, "can't make subclass of singleton class"); rb_raise(rb_eTypeError, "can't make subclass of singleton class");
} }
if (super == rb_cClass) { if (super == rb_cClass) {
@ -426,7 +426,7 @@ class_init_copy_check(VALUE clone, VALUE orig)
if (RCLASS_SUPER(clone) != 0 || clone == rb_cBasicObject) { if (RCLASS_SUPER(clone) != 0 || clone == rb_cBasicObject) {
rb_raise(rb_eTypeError, "already initialized class"); rb_raise(rb_eTypeError, "already initialized class");
} }
if (FL_TEST(orig, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(orig)) {
rb_raise(rb_eTypeError, "can't copy singleton class"); rb_raise(rb_eTypeError, "can't copy singleton class");
} }
} }
@ -544,7 +544,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
RCLASS_EXT(clone)->cloned = true; RCLASS_EXT(clone)->cloned = true;
RCLASS_EXT(orig)->cloned = true; RCLASS_EXT(orig)->cloned = true;
if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { if (!RCLASS_SINGLETON_P(CLASS_OF(clone))) {
RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig)); RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig));
rb_singleton_class_attached(METACLASS_OF(clone), (VALUE)clone); rb_singleton_class_attached(METACLASS_OF(clone), (VALUE)clone);
} }
@ -650,7 +650,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
// attached to an object other than `obj`. In which case `obj` does not have // attached to an object other than `obj`. In which case `obj` does not have
// a material singleton class attached yet and there is no singleton class // a material singleton class attached yet and there is no singleton class
// to clone. // to clone.
if (!(FL_TEST(klass, FL_SINGLETON) && RCLASS_ATTACHED_OBJECT(klass) == obj)) { if (!(RCLASS_SINGLETON_P(klass) && RCLASS_ATTACHED_OBJECT(klass) == obj)) {
// nothing to clone // nothing to clone
return klass; return klass;
} }
@ -701,7 +701,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
void void
rb_singleton_class_attached(VALUE klass, VALUE obj) rb_singleton_class_attached(VALUE klass, VALUE obj)
{ {
if (FL_TEST(klass, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(klass)) {
RCLASS_SET_ATTACHED_OBJECT(klass, obj); RCLASS_SET_ATTACHED_OBJECT(klass, obj);
} }
} }
@ -1607,7 +1607,7 @@ class_descendants_recursive(VALUE klass, VALUE v)
{ {
struct subclass_traverse_data *data = (struct subclass_traverse_data *) v; struct subclass_traverse_data *data = (struct subclass_traverse_data *) v;
if (BUILTIN_TYPE(klass) == T_CLASS && !FL_TEST(klass, FL_SINGLETON)) { if (BUILTIN_TYPE(klass) == T_CLASS && !RCLASS_SINGLETON_P(klass)) {
if (data->buffer && data->count < data->maxcount && !rb_objspace_garbage_object_p(klass)) { if (data->buffer && data->count < data->maxcount && !rb_objspace_garbage_object_p(klass)) {
// assumes that this does not cause GC as long as the length does not exceed the capacity // assumes that this does not cause GC as long as the length does not exceed the capacity
rb_ary_push(data->buffer, klass); rb_ary_push(data->buffer, klass);
@ -1712,7 +1712,7 @@ rb_class_subclasses(VALUE klass)
VALUE VALUE
rb_class_attached_object(VALUE klass) rb_class_attached_object(VALUE klass)
{ {
if (!FL_TEST(klass, FL_SINGLETON)) { if (!RCLASS_SINGLETON_P(klass)) {
rb_raise(rb_eTypeError, "'%"PRIsVALUE"' is not a singleton class", klass); rb_raise(rb_eTypeError, "'%"PRIsVALUE"' is not a singleton class", klass);
} }
@ -1815,7 +1815,7 @@ static bool
particular_class_p(VALUE mod) particular_class_p(VALUE mod)
{ {
if (!mod) return false; if (!mod) return false;
if (FL_TEST(mod, FL_SINGLETON)) return true; if (RCLASS_SINGLETON_P(mod)) return true;
if (BUILTIN_TYPE(mod) == T_ICLASS) return true; if (BUILTIN_TYPE(mod) == T_ICLASS) return true;
return false; return false;
} }
@ -2092,19 +2092,19 @@ rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj)
int recur = TRUE; int recur = TRUE;
if (rb_check_arity(argc, 0, 1)) recur = RTEST(argv[0]); if (rb_check_arity(argc, 0, 1)) recur = RTEST(argv[0]);
if (RB_TYPE_P(obj, T_CLASS) && FL_TEST(obj, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(obj)) {
rb_singleton_class(obj); rb_singleton_class(obj);
} }
klass = CLASS_OF(obj); klass = CLASS_OF(obj);
origin = RCLASS_ORIGIN(klass); origin = RCLASS_ORIGIN(klass);
me_arg.list = st_init_numtable(); me_arg.list = st_init_numtable();
me_arg.recur = recur; me_arg.recur = recur;
if (klass && FL_TEST(klass, FL_SINGLETON)) { if (klass && RCLASS_SINGLETON_P(klass)) {
if ((mtbl = RCLASS_M_TBL(origin)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg); if ((mtbl = RCLASS_M_TBL(origin)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
klass = RCLASS_SUPER(klass); klass = RCLASS_SUPER(klass);
} }
if (recur) { if (recur) {
while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) { while (klass && (RCLASS_SINGLETON_P(klass) || RB_TYPE_P(klass, T_ICLASS))) {
if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg); if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
klass = RCLASS_SUPER(klass); klass = RCLASS_SUPER(klass);
} }
@ -2244,7 +2244,7 @@ singleton_class_of(VALUE obj)
} }
klass = METACLASS_OF(obj); klass = METACLASS_OF(obj);
if (!(FL_TEST(klass, FL_SINGLETON) && if (!(RCLASS_SINGLETON_P(klass) &&
RCLASS_ATTACHED_OBJECT(klass) == obj)) { RCLASS_ATTACHED_OBJECT(klass) == obj)) {
klass = rb_make_metaclass(obj, klass); klass = rb_make_metaclass(obj, klass);
} }
@ -2258,7 +2258,7 @@ void
rb_freeze_singleton_class(VALUE x) rb_freeze_singleton_class(VALUE x)
{ {
/* should not propagate to meta-meta-class, and so on */ /* should not propagate to meta-meta-class, and so on */
if (!(RBASIC(x)->flags & FL_SINGLETON)) { if (!RCLASS_SINGLETON_P(x)) {
VALUE klass = RBASIC_CLASS(x); VALUE klass = RBASIC_CLASS(x);
if (klass && // no class when hidden from ObjectSpace if (klass && // no class when hidden from ObjectSpace
FL_TEST(klass, (FL_SINGLETON|FL_FREEZE)) == FL_SINGLETON) { FL_TEST(klass, (FL_SINGLETON|FL_FREEZE)) == FL_SINGLETON) {
@ -2283,7 +2283,7 @@ rb_singleton_class_get(VALUE obj)
return rb_special_singleton_class(obj); return rb_special_singleton_class(obj);
} }
klass = METACLASS_OF(obj); klass = METACLASS_OF(obj);
if (!FL_TEST(klass, FL_SINGLETON)) return Qnil; if (!RCLASS_SINGLETON_P(klass)) return Qnil;
if (RCLASS_ATTACHED_OBJECT(klass) != obj) return Qnil; if (RCLASS_ATTACHED_OBJECT(klass) != obj) return Qnil;
return klass; return klass;
} }

View File

@ -6537,6 +6537,7 @@ error.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
error.$(OBJEXT): {$(VPATH)}builtin.h error.$(OBJEXT): {$(VPATH)}builtin.h
error.$(OBJEXT): {$(VPATH)}config.h error.$(OBJEXT): {$(VPATH)}config.h
error.$(OBJEXT): {$(VPATH)}constant.h error.$(OBJEXT): {$(VPATH)}constant.h
error.$(OBJEXT): {$(VPATH)}debug_counter.h
error.$(OBJEXT): {$(VPATH)}defines.h error.$(OBJEXT): {$(VPATH)}defines.h
error.$(OBJEXT): {$(VPATH)}encoding.h error.$(OBJEXT): {$(VPATH)}encoding.h
error.$(OBJEXT): {$(VPATH)}error.c error.$(OBJEXT): {$(VPATH)}error.c
@ -6709,7 +6710,9 @@ error.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
error.$(OBJEXT): {$(VPATH)}thread_native.h error.$(OBJEXT): {$(VPATH)}thread_native.h
error.$(OBJEXT): {$(VPATH)}util.h error.$(OBJEXT): {$(VPATH)}util.h
error.$(OBJEXT): {$(VPATH)}vm_core.h error.$(OBJEXT): {$(VPATH)}vm_core.h
error.$(OBJEXT): {$(VPATH)}vm_debug.h
error.$(OBJEXT): {$(VPATH)}vm_opts.h error.$(OBJEXT): {$(VPATH)}vm_opts.h
error.$(OBJEXT): {$(VPATH)}vm_sync.h
error.$(OBJEXT): {$(VPATH)}warning.rbinc error.$(OBJEXT): {$(VPATH)}warning.rbinc
error.$(OBJEXT): {$(VPATH)}yjit.h error.$(OBJEXT): {$(VPATH)}yjit.h
eval.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h eval.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
@ -8353,6 +8356,7 @@ io.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
io.$(OBJEXT): {$(VPATH)}builtin.h io.$(OBJEXT): {$(VPATH)}builtin.h
io.$(OBJEXT): {$(VPATH)}config.h io.$(OBJEXT): {$(VPATH)}config.h
io.$(OBJEXT): {$(VPATH)}constant.h io.$(OBJEXT): {$(VPATH)}constant.h
io.$(OBJEXT): {$(VPATH)}debug_counter.h
io.$(OBJEXT): {$(VPATH)}defines.h io.$(OBJEXT): {$(VPATH)}defines.h
io.$(OBJEXT): {$(VPATH)}dln.h io.$(OBJEXT): {$(VPATH)}dln.h
io.$(OBJEXT): {$(VPATH)}encindex.h io.$(OBJEXT): {$(VPATH)}encindex.h
@ -8531,7 +8535,9 @@ io.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
io.$(OBJEXT): {$(VPATH)}thread_native.h io.$(OBJEXT): {$(VPATH)}thread_native.h
io.$(OBJEXT): {$(VPATH)}util.h io.$(OBJEXT): {$(VPATH)}util.h
io.$(OBJEXT): {$(VPATH)}vm_core.h io.$(OBJEXT): {$(VPATH)}vm_core.h
io.$(OBJEXT): {$(VPATH)}vm_debug.h
io.$(OBJEXT): {$(VPATH)}vm_opts.h io.$(OBJEXT): {$(VPATH)}vm_opts.h
io.$(OBJEXT): {$(VPATH)}vm_sync.h
io_buffer.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h io_buffer.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
io_buffer.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h io_buffer.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
io_buffer.$(OBJEXT): $(CCAN_DIR)/list/list.h io_buffer.$(OBJEXT): $(CCAN_DIR)/list/list.h
@ -10790,6 +10796,7 @@ node_dump.$(OBJEXT): $(top_srcdir)/internal/array.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h node_dump.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/bignum.h node_dump.$(OBJEXT): $(top_srcdir)/internal/bignum.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/bits.h node_dump.$(OBJEXT): $(top_srcdir)/internal/bits.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/class.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h node_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/complex.h node_dump.$(OBJEXT): $(top_srcdir)/internal/complex.h
node_dump.$(OBJEXT): $(top_srcdir)/internal/fixnum.h node_dump.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
@ -10818,6 +10825,7 @@ node_dump.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
node_dump.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h node_dump.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
node_dump.$(OBJEXT): {$(VPATH)}config.h node_dump.$(OBJEXT): {$(VPATH)}config.h
node_dump.$(OBJEXT): {$(VPATH)}constant.h node_dump.$(OBJEXT): {$(VPATH)}constant.h
node_dump.$(OBJEXT): {$(VPATH)}debug_counter.h
node_dump.$(OBJEXT): {$(VPATH)}defines.h node_dump.$(OBJEXT): {$(VPATH)}defines.h
node_dump.$(OBJEXT): {$(VPATH)}encoding.h node_dump.$(OBJEXT): {$(VPATH)}encoding.h
node_dump.$(OBJEXT): {$(VPATH)}id.h node_dump.$(OBJEXT): {$(VPATH)}id.h
@ -10987,7 +10995,9 @@ node_dump.$(OBJEXT): {$(VPATH)}subst.h
node_dump.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h node_dump.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
node_dump.$(OBJEXT): {$(VPATH)}thread_native.h node_dump.$(OBJEXT): {$(VPATH)}thread_native.h
node_dump.$(OBJEXT): {$(VPATH)}vm_core.h node_dump.$(OBJEXT): {$(VPATH)}vm_core.h
node_dump.$(OBJEXT): {$(VPATH)}vm_debug.h
node_dump.$(OBJEXT): {$(VPATH)}vm_opts.h node_dump.$(OBJEXT): {$(VPATH)}vm_opts.h
node_dump.$(OBJEXT): {$(VPATH)}vm_sync.h
numeric.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h numeric.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
numeric.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h numeric.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
numeric.$(OBJEXT): $(CCAN_DIR)/list/list.h numeric.$(OBJEXT): $(CCAN_DIR)/list/list.h

View File

@ -32,6 +32,7 @@
#endif #endif
#include "internal.h" #include "internal.h"
#include "internal/class.h"
#include "internal/error.h" #include "internal/error.h"
#include "internal/eval.h" #include "internal/eval.h"
#include "internal/hash.h" #include "internal/hash.h"
@ -2388,7 +2389,7 @@ name_err_mesg_to_str(VALUE obj)
VALUE klass; VALUE klass;
object: object:
klass = CLASS_OF(obj); klass = CLASS_OF(obj);
if (RB_TYPE_P(klass, T_CLASS) && FL_TEST(klass, FL_SINGLETON)) { if (RB_TYPE_P(klass, T_CLASS) && RCLASS_SINGLETON_P(klass)) {
s = FAKE_CSTR(&s_str, ""); s = FAKE_CSTR(&s_str, "");
if (obj == rb_vm_top_self()) { if (obj == rb_vm_top_self()) {
c = FAKE_CSTR(&c_str, "main"); c = FAKE_CSTR(&c_str, "main");

2
eval.c
View File

@ -428,7 +428,7 @@ rb_class_modify_check(VALUE klass)
if (OBJ_FROZEN(klass)) { if (OBJ_FROZEN(klass)) {
const char *desc; const char *desc;
if (FL_TEST(klass, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(klass)) {
desc = "object"; desc = "object";
klass = RCLASS_ATTACHED_OBJECT(klass); klass = RCLASS_ATTACHED_OBJECT(klass);
if (!SPECIAL_CONST_P(klass)) { if (!SPECIAL_CONST_P(klass)) {

View File

@ -560,7 +560,7 @@ dump_object(VALUE obj, struct dump_config *dc)
} }
} }
if (FL_TEST(obj, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(obj)) {
dump_append(dc, ", \"singleton\":true"); dump_append(dc, ", \"singleton\":true");
} }
} }

2
gc.c
View File

@ -3763,7 +3763,7 @@ internal_object_p(VALUE obj)
break; break;
case T_CLASS: case T_CLASS:
if (!p->as.basic.klass) break; if (!p->as.basic.klass) break;
if (FL_TEST(obj, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(obj)) {
return rb_singleton_class_internal_p(obj); return rb_singleton_class_internal_p(obj);
} }
return 0; return 0;

View File

@ -395,7 +395,7 @@ ruby_fl_type {
* 3rd parties. It must be an implementation detail that they should never * 3rd parties. It must be an implementation detail that they should never
* know. Might better be hidden. * know. Might better be hidden.
*/ */
RUBY_FL_SINGLETON = RUBY_FL_USER0, RUBY_FL_SINGLETON = RUBY_FL_USER1,
}; };
enum { enum {

View File

@ -195,10 +195,16 @@ static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass);
VALUE rb_class_inherited(VALUE, VALUE); VALUE rb_class_inherited(VALUE, VALUE);
VALUE rb_keyword_error_new(const char *, VALUE); VALUE rb_keyword_error_new(const char *, VALUE);
static inline bool
RCLASS_SINGLETON_P(VALUE klass)
{
return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON);
}
static inline rb_alloc_func_t static inline rb_alloc_func_t
RCLASS_ALLOCATOR(VALUE klass) RCLASS_ALLOCATOR(VALUE klass)
{ {
if (FL_TEST_RAW(klass, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(klass)) {
return 0; return 0;
} }
return RCLASS_EXT(klass)->as.class.allocator; return RCLASS_EXT(klass)->as.class.allocator;
@ -207,7 +213,7 @@ RCLASS_ALLOCATOR(VALUE klass)
static inline void static inline void
RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator) RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator)
{ {
assert(!FL_TEST(klass, FL_SINGLETON)); assert(!RCLASS_SINGLETON_P(klass));
RCLASS_EXT(klass)->as.class.allocator = allocator; RCLASS_EXT(klass)->as.class.allocator = allocator;
} }
@ -267,8 +273,7 @@ RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent)
static inline VALUE static inline VALUE
RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object) RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object)
{ {
assert(BUILTIN_TYPE(klass) == T_CLASS); assert(RCLASS_SINGLETON_P(klass));
assert(FL_TEST_RAW(klass, FL_SINGLETON));
RB_OBJ_WRITE(klass, &RCLASS_EXT(klass)->as.singleton_class.attached_object, attached_object); RB_OBJ_WRITE(klass, &RCLASS_EXT(klass)->as.singleton_class.attached_object, attached_object);
return attached_object; return attached_object;

3
io.c
View File

@ -112,6 +112,7 @@
#include "encindex.h" #include "encindex.h"
#include "id.h" #include "id.h"
#include "internal.h" #include "internal.h"
#include "internal/class.h"
#include "internal/encoding.h" #include "internal/encoding.h"
#include "internal/error.h" #include "internal/error.h"
#include "internal/inits.h" #include "internal/inits.h"
@ -2276,7 +2277,7 @@ rb_io_writev(VALUE io, int argc, const VALUE *argv)
if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) { if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) { if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
VALUE klass = CLASS_OF(io); VALUE klass = CLASS_OF(io);
char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#'; char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
rb_category_warning( rb_category_warning(
RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface" RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
" which accepts just one argument", " which accepts just one argument",

View File

@ -3736,7 +3736,7 @@ module RubyVM::RJIT
ctx.upgrade_opnd_type(insn_opnd, Type::Flonum) ctx.upgrade_opnd_type(insn_opnd, Type::Flonum)
end end
elsif C.FL_TEST(known_klass, C::RUBY_FL_SINGLETON) && comptime_obj == C.rb_class_attached_object(known_klass) elsif C.RCLASS_SINGLETON_P(known_klass) && comptime_obj == C.rb_class_attached_object(known_klass)
# Singleton classes are attached to one specific object, so we can # Singleton classes are attached to one specific object, so we can
# avoid one memory access (and potentially the is_heap check) by # avoid one memory access (and potentially the is_heap check) by
# looking for the expected object directly. # looking for the expected object directly.

View File

@ -533,7 +533,7 @@ hash_each(VALUE key, VALUE value, VALUE v)
static void static void
w_extended(VALUE klass, struct dump_arg *arg, int check) w_extended(VALUE klass, struct dump_arg *arg, int check)
{ {
if (check && FL_TEST(klass, FL_SINGLETON)) { if (check && RCLASS_SINGLETON_P(klass)) {
VALUE origin = RCLASS_ORIGIN(klass); VALUE origin = RCLASS_ORIGIN(klass);
if (SINGLETON_DUMP_UNABLE_P(klass) || if (SINGLETON_DUMP_UNABLE_P(klass) ||
(origin != klass && SINGLETON_DUMP_UNABLE_P(origin))) { (origin != klass && SINGLETON_DUMP_UNABLE_P(origin))) {

View File

@ -10,6 +10,7 @@
**********************************************************************/ **********************************************************************/
#include "internal.h" #include "internal.h"
#include "internal/class.h"
#include "internal/hash.h" #include "internal/hash.h"
#include "internal/ruby_parser.h" #include "internal/ruby_parser.h"
#include "internal/variable.h" #include "internal/variable.h"
@ -89,7 +90,7 @@ rb_dump_literal(VALUE lit)
switch (RB_BUILTIN_TYPE(lit)) { switch (RB_BUILTIN_TYPE(lit)) {
case T_CLASS: case T_MODULE: case T_ICLASS: case T_CLASS: case T_MODULE: case T_ICLASS:
str = rb_class_path(lit); str = rb_class_path(lit);
if (FL_TEST(lit, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(lit)) {
str = rb_sprintf("<%"PRIsVALUE">", str); str = rb_sprintf("<%"PRIsVALUE">", str);
} }
return str; return str;

View File

@ -288,7 +288,7 @@ VALUE
rb_class_real(VALUE cl) rb_class_real(VALUE cl)
{ {
while (cl && while (cl &&
((RBASIC(cl)->flags & FL_SINGLETON) || BUILTIN_TYPE(cl) == T_ICLASS)) { (RCLASS_SINGLETON_P(cl) || BUILTIN_TYPE(cl) == T_ICLASS)) {
cl = RCLASS_SUPER(cl); cl = RCLASS_SUPER(cl);
} }
return cl; return cl;
@ -493,7 +493,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
VALUE singleton = rb_singleton_class_clone_and_attach(obj, clone); VALUE singleton = rb_singleton_class_clone_and_attach(obj, clone);
RBASIC_SET_CLASS(clone, singleton); RBASIC_SET_CLASS(clone, singleton);
if (FL_TEST(singleton, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(singleton)) {
rb_singleton_class_attached(singleton, clone); rb_singleton_class_attached(singleton, clone);
} }
@ -1745,7 +1745,7 @@ rb_mod_to_s(VALUE klass)
ID id_defined_at; ID id_defined_at;
VALUE refined_class, defined_at; VALUE refined_class, defined_at;
if (FL_TEST(klass, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(klass)) {
VALUE s = rb_usascii_str_new2("#<Class:"); VALUE s = rb_usascii_str_new2("#<Class:");
VALUE v = RCLASS_ATTACHED_OBJECT(klass); VALUE v = RCLASS_ATTACHED_OBJECT(klass);
@ -2121,7 +2121,7 @@ class_get_alloc_func(VALUE klass)
if (RCLASS_SUPER(klass) == 0 && klass != rb_cBasicObject) { if (RCLASS_SUPER(klass) == 0 && klass != rb_cBasicObject) {
rb_raise(rb_eTypeError, "can't instantiate uninitialized class"); rb_raise(rb_eTypeError, "can't instantiate uninitialized class");
} }
if (FL_TEST(klass, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(klass)) {
rb_raise(rb_eTypeError, "can't create instance of singleton class"); rb_raise(rb_eTypeError, "can't create instance of singleton class");
} }
allocator = rb_get_alloc_func(klass); allocator = rb_get_alloc_func(klass);
@ -3082,7 +3082,7 @@ rb_mod_cvar_defined(VALUE obj, VALUE iv)
static VALUE static VALUE
rb_mod_singleton_p(VALUE klass) rb_mod_singleton_p(VALUE klass)
{ {
return RBOOL(RB_TYPE_P(klass, T_CLASS) && FL_TEST(klass, FL_SINGLETON)); return RBOOL(RCLASS_SINGLETON_P(klass));
} }
/*! \private */ /*! \private */

10
proc.c
View File

@ -1945,7 +1945,7 @@ rb_method_name_error(VALUE klass, VALUE str)
VALUE c = klass; VALUE c = klass;
VALUE s = Qundef; VALUE s = Qundef;
if (FL_TEST(c, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(c)) {
VALUE obj = RCLASS_ATTACHED_OBJECT(klass); VALUE obj = RCLASS_ATTACHED_OBJECT(klass);
switch (BUILTIN_TYPE(obj)) { switch (BUILTIN_TYPE(obj)) {
@ -2194,7 +2194,7 @@ rb_mod_define_method_with_visibility(int argc, VALUE *argv, VALUE mod, const str
struct METHOD *method = (struct METHOD *)RTYPEDDATA_GET_DATA(body); struct METHOD *method = (struct METHOD *)RTYPEDDATA_GET_DATA(body);
if (method->me->owner != mod && !RB_TYPE_P(method->me->owner, T_MODULE) && if (method->me->owner != mod && !RB_TYPE_P(method->me->owner, T_MODULE) &&
!RTEST(rb_class_inherited_p(mod, method->me->owner))) { !RTEST(rb_class_inherited_p(mod, method->me->owner))) {
if (FL_TEST(method->me->owner, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(method->me->owner)) {
rb_raise(rb_eTypeError, rb_raise(rb_eTypeError,
"can't bind singleton method to a different class"); "can't bind singleton method to a different class");
} }
@ -2561,7 +2561,7 @@ convert_umethod_to_method_components(const struct METHOD *data, VALUE recv, VALU
if (!NIL_P(refined_class)) methclass = refined_class; if (!NIL_P(refined_class)) methclass = refined_class;
} }
if (!RB_TYPE_P(methclass, T_MODULE) && !RTEST(rb_obj_is_kind_of(recv, methclass))) { if (!RB_TYPE_P(methclass, T_MODULE) && !RTEST(rb_obj_is_kind_of(recv, methclass))) {
if (FL_TEST(methclass, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(methclass)) {
rb_raise(rb_eTypeError, rb_raise(rb_eTypeError,
"singleton method called for a different object"); "singleton method called for a different object");
} }
@ -3132,7 +3132,7 @@ method_inspect(VALUE method)
// UnboundMethod // UnboundMethod
rb_str_buf_append(str, rb_inspect(defined_class)); rb_str_buf_append(str, rb_inspect(defined_class));
} }
else if (FL_TEST(mklass, FL_SINGLETON)) { else if (RCLASS_SINGLETON_P(mklass)) {
VALUE v = RCLASS_ATTACHED_OBJECT(mklass); VALUE v = RCLASS_ATTACHED_OBJECT(mklass);
if (UNDEF_P(data->recv)) { if (UNDEF_P(data->recv)) {
@ -3152,7 +3152,7 @@ method_inspect(VALUE method)
} }
else { else {
mklass = data->klass; mklass = data->klass;
if (FL_TEST(mklass, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(mklass)) {
VALUE v = RCLASS_ATTACHED_OBJECT(mklass); VALUE v = RCLASS_ATTACHED_OBJECT(mklass);
if (!(RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE))) { if (!(RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE))) {
do { do {

View File

@ -326,6 +326,10 @@ module RubyVM::RJIT # :nodoc: all
def RCLASS_ORIGIN(klass) def RCLASS_ORIGIN(klass)
Primitive.cexpr! 'RCLASS_ORIGIN(klass)' Primitive.cexpr! 'RCLASS_ORIGIN(klass)'
end end
def RCLASS_SINGLETON_P(klass)
Primitive.cexpr! 'RCLASS_SINGLETON_P(klass)'
end
end end
# #
@ -392,7 +396,6 @@ module RubyVM::RJIT # :nodoc: all
C::RUBY_FLONUM_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FLONUM_FLAG) } C::RUBY_FLONUM_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FLONUM_FLAG) }
C::RUBY_FLONUM_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FLONUM_MASK) } C::RUBY_FLONUM_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FLONUM_MASK) }
C::RUBY_FL_FREEZE = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FL_FREEZE) } C::RUBY_FL_FREEZE = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FL_FREEZE) }
C::RUBY_FL_SINGLETON = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FL_SINGLETON) }
C::RUBY_IMMEDIATE_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_IMMEDIATE_MASK) } C::RUBY_IMMEDIATE_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_IMMEDIATE_MASK) }
C::RUBY_SPECIAL_SHIFT = Primitive.cexpr! %q{ SIZET2NUM(RUBY_SPECIAL_SHIFT) } C::RUBY_SPECIAL_SHIFT = Primitive.cexpr! %q{ SIZET2NUM(RUBY_SPECIAL_SHIFT) }
C::RUBY_SYMBOL_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_SYMBOL_FLAG) } C::RUBY_SYMBOL_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_SYMBOL_FLAG) }

View File

@ -423,7 +423,6 @@ generator = BindingGenerator.new(
RUBY_FIXNUM_FLAG RUBY_FIXNUM_FLAG
RUBY_FLONUM_FLAG RUBY_FLONUM_FLAG
RUBY_FLONUM_MASK RUBY_FLONUM_MASK
RUBY_FL_SINGLETON
RUBY_IMMEDIATE_MASK RUBY_IMMEDIATE_MASK
RUBY_SPECIAL_SHIFT RUBY_SPECIAL_SHIFT
RUBY_SYMBOL_FLAG RUBY_SYMBOL_FLAG

View File

@ -1826,7 +1826,7 @@ void rb_obj_freeze_inline(VALUE x)
} }
rb_shape_set_shape(x, next_shape); rb_shape_set_shape(x, next_shape);
if (RBASIC_CLASS(x) && !(RBASIC(x)->flags & RUBY_FL_SINGLETON)) { if (RBASIC_CLASS(x)) {
rb_freeze_singleton_class(x); rb_freeze_singleton_class(x);
} }
} }
@ -3855,7 +3855,7 @@ cvar_lookup_at(VALUE klass, ID id, st_data_t *v)
static VALUE static VALUE
cvar_front_klass(VALUE klass) cvar_front_klass(VALUE klass)
{ {
if (FL_TEST(klass, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(klass)) {
VALUE obj = RCLASS_ATTACHED_OBJECT(klass); VALUE obj = RCLASS_ATTACHED_OBJECT(klass);
if (rb_namespace_p(obj)) { if (rb_namespace_p(obj)) {
return obj; return obj;
@ -4064,7 +4064,7 @@ static void*
mod_cvar_of(VALUE mod, void *data) mod_cvar_of(VALUE mod, void *data)
{ {
VALUE tmp = mod; VALUE tmp = mod;
if (FL_TEST(mod, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(mod)) {
if (rb_namespace_p(RCLASS_ATTACHED_OBJECT(mod))) { if (rb_namespace_p(RCLASS_ATTACHED_OBJECT(mod))) {
data = mod_cvar_at(tmp, data); data = mod_cvar_at(tmp, data);
tmp = cvar_front_klass(tmp); tmp = cvar_front_klass(tmp);

2
vm.c
View File

@ -619,7 +619,7 @@ rb_dtrace_setup(rb_execution_context_t *ec, VALUE klass, ID id,
if (RB_TYPE_P(klass, T_ICLASS)) { if (RB_TYPE_P(klass, T_ICLASS)) {
klass = RBASIC(klass)->klass; klass = RBASIC(klass)->klass;
} }
else if (FL_TEST(klass, FL_SINGLETON)) { else if (RCLASS_SINGLETON_P(klass)) {
klass = RCLASS_ATTACHED_OBJECT(klass); klass = RCLASS_ATTACHED_OBJECT(klass);
if (NIL_P(klass)) return FALSE; if (NIL_P(klass)) return FALSE;
} }

View File

@ -198,7 +198,7 @@ gen_method_name(VALUE owner, VALUE name)
{ {
bool permanent; bool permanent;
if (RB_TYPE_P(owner, T_CLASS) || RB_TYPE_P(owner, T_MODULE)) { if (RB_TYPE_P(owner, T_CLASS) || RB_TYPE_P(owner, T_MODULE)) {
if (RBASIC(owner)->flags & FL_SINGLETON) { if (RCLASS_SINGLETON_P(owner)) {
VALUE v = RCLASS_ATTACHED_OBJECT(owner); VALUE v = RCLASS_ATTACHED_OBJECT(owner);
if (RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE)) { if (RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE)) {
v = rb_mod_name0(v, &permanent); v = rb_mod_name0(v, &permanent);
@ -1784,7 +1784,7 @@ rb_profile_frame_classpath(VALUE frame)
if (RB_TYPE_P(klass, T_ICLASS)) { if (RB_TYPE_P(klass, T_ICLASS)) {
klass = RBASIC(klass)->klass; klass = RBASIC(klass)->klass;
} }
else if (FL_TEST(klass, FL_SINGLETON)) { else if (RCLASS_SINGLETON_P(klass)) {
klass = RCLASS_ATTACHED_OBJECT(klass); klass = RCLASS_ATTACHED_OBJECT(klass);
if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE)) if (!RB_TYPE_P(klass, T_CLASS) && !RB_TYPE_P(klass, T_MODULE))
return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass); return rb_sprintf("#<%s:%p>", rb_class2name(rb_obj_class(klass)), (void*)klass);
@ -1801,7 +1801,7 @@ rb_profile_frame_singleton_method_p(VALUE frame)
{ {
VALUE klass = frame2klass(frame); VALUE klass = frame2klass(frame);
return RBOOL(klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON)); return RBOOL(klass && !NIL_P(klass) && RCLASS_SINGLETON_P(klass));
} }
VALUE VALUE

View File

@ -957,7 +957,7 @@ vm_get_const_key_cref(const VALUE *ep)
const rb_cref_t *key_cref = cref; const rb_cref_t *key_cref = cref;
while (cref) { while (cref) {
if (FL_TEST(CREF_CLASS(cref), FL_SINGLETON) || if (RCLASS_SINGLETON_P(CREF_CLASS(cref)) ||
RCLASS_EXT(CREF_CLASS(cref))->cloned) { RCLASS_EXT(CREF_CLASS(cref))->cloned) {
return key_cref; return key_cref;
} }
@ -1171,7 +1171,7 @@ vm_get_cvar_base(const rb_cref_t *cref, const rb_control_frame_t *cfp, int top_l
} }
while (CREF_NEXT(cref) && while (CREF_NEXT(cref) &&
(NIL_P(CREF_CLASS(cref)) || FL_TEST(CREF_CLASS(cref), FL_SINGLETON) || (NIL_P(CREF_CLASS(cref)) || RCLASS_SINGLETON_P(CREF_CLASS(cref)) ||
CREF_PUSHED_BY_EVAL(cref) || CREF_SINGLETON(cref))) { CREF_PUSHED_BY_EVAL(cref) || CREF_SINGLETON(cref))) {
cref = CREF_NEXT(cref); cref = CREF_NEXT(cref);
} }

View File

@ -962,7 +962,7 @@ rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibil
} }
orig_klass = klass; orig_klass = klass;
if (!FL_TEST(klass, FL_SINGLETON) && if (!RCLASS_SINGLETON_P(klass) &&
type != VM_METHOD_TYPE_NOTIMPLEMENTED && type != VM_METHOD_TYPE_NOTIMPLEMENTED &&
type != VM_METHOD_TYPE_ZSUPER) { type != VM_METHOD_TYPE_ZSUPER) {
switch (mid) { switch (mid) {
@ -1199,7 +1199,7 @@ rb_check_overloaded_cme(const rb_callable_method_entry_t *cme, const struct rb_c
const VALUE arg = ID2SYM(mid); \ const VALUE arg = ID2SYM(mid); \
VALUE recv_class = (klass); \ VALUE recv_class = (klass); \
ID hook_id = (hook); \ ID hook_id = (hook); \
if (FL_TEST((klass), FL_SINGLETON)) { \ if (RCLASS_SINGLETON_P((klass))) { \
recv_class = RCLASS_ATTACHED_OBJECT((klass)); \ recv_class = RCLASS_ATTACHED_OBJECT((klass)); \
hook_id = singleton_##hook; \ hook_id = singleton_##hook; \
} \ } \
@ -1264,7 +1264,7 @@ void
rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE)) rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
{ {
Check_Type(klass, T_CLASS); Check_Type(klass, T_CLASS);
if (FL_TEST_RAW(klass, FL_SINGLETON)) { if (RCLASS_SINGLETON_P(klass)) {
rb_raise(rb_eTypeError, "can't define an allocator for a singleton class"); rb_raise(rb_eTypeError, "can't define an allocator for a singleton class");
} }
RCLASS_SET_ALLOCATOR(klass, func); RCLASS_SET_ALLOCATOR(klass, func);
@ -2898,8 +2898,8 @@ vm_respond_to(rb_execution_context_t *ec, VALUE klass, VALUE obj, ID id, int pri
rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
"%"PRIsVALUE"%c""respond_to?(:%"PRIsVALUE") uses" "%"PRIsVALUE"%c""respond_to?(:%"PRIsVALUE") uses"
" the deprecated method signature, which takes one parameter", " the deprecated method signature, which takes one parameter",
(FL_TEST(klass, FL_SINGLETON) ? obj : klass), (RCLASS_SINGLETON_P(klass) ? obj : klass),
(FL_TEST(klass, FL_SINGLETON) ? '.' : '#'), (RCLASS_SINGLETON_P(klass) ? '.' : '#'),
QUOTE_ID(id)); QUOTE_ID(id));
if (!NIL_P(location)) { if (!NIL_P(location)) {
VALUE path = RARRAY_AREF(location, 0); VALUE path = RARRAY_AREF(location, 0);

View File

@ -734,7 +734,7 @@ call_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klas
if (RB_TYPE_P(klass, T_ICLASS)) { if (RB_TYPE_P(klass, T_ICLASS)) {
klass = RBASIC(klass)->klass; klass = RBASIC(klass)->klass;
} }
else if (FL_TEST(klass, FL_SINGLETON)) { else if (RCLASS_SINGLETON_P(klass)) {
klass = RCLASS_ATTACHED_OBJECT(klass); klass = RCLASS_ATTACHED_OBJECT(klass);
} }
} }

View File

@ -252,7 +252,7 @@ pub const RUBY_FL_USER17: ruby_fl_type = 536870912;
pub const RUBY_FL_USER18: ruby_fl_type = 1073741824; pub const RUBY_FL_USER18: ruby_fl_type = 1073741824;
pub const RUBY_FL_USER19: ruby_fl_type = -2147483648; pub const RUBY_FL_USER19: ruby_fl_type = -2147483648;
pub const RUBY_ELTS_SHARED: ruby_fl_type = 16384; pub const RUBY_ELTS_SHARED: ruby_fl_type = 16384;
pub const RUBY_FL_SINGLETON: ruby_fl_type = 4096; pub const RUBY_FL_SINGLETON: ruby_fl_type = 8192;
pub type ruby_fl_type = i32; pub type ruby_fl_type = i32;
pub const RSTRING_NOEMBED: ruby_rstring_flags = 8192; pub const RSTRING_NOEMBED: ruby_rstring_flags = 8192;
pub const RSTRING_FSTR: ruby_rstring_flags = 536870912; pub const RSTRING_FSTR: ruby_rstring_flags = 536870912;