3434extern st_table * rb_class_tbl ;
3535static ID id_attached ;
3636
37+ void
38+ rb_class_subclass_add (VALUE super , VALUE klass )
39+ {
40+ rb_subclass_entry_t * entry , * head ;
41+
42+ if (super && super != Qundef ) {
43+ entry = malloc (sizeof (* entry ));
44+ entry -> klass = klass ;
45+ entry -> next = NULL ;
46+
47+ head = RCLASS_EXT (super )-> subclasses ;
48+ if (head ) {
49+ entry -> next = head ;
50+ RCLASS_EXT (head -> klass )-> parent_subclasses = & entry -> next ;
51+ }
52+
53+ RCLASS_EXT (super )-> subclasses = entry ;
54+ RCLASS_EXT (klass )-> parent_subclasses = & RCLASS_EXT (super )-> subclasses ;
55+ }
56+ }
57+
58+ static void
59+ rb_module_add_to_subclasses_list (VALUE module , VALUE iclass )
60+ {
61+ rb_subclass_entry_t * entry , * head ;
62+
63+ entry = malloc (sizeof (* entry ));
64+ entry -> klass = iclass ;
65+ entry -> next = NULL ;
66+
67+ head = RCLASS_EXT (module )-> subclasses ;
68+ if (head ) {
69+ entry -> next = head ;
70+ RCLASS_EXT (head -> klass )-> module_subclasses = & entry -> next ;
71+ }
72+
73+ RCLASS_EXT (module )-> subclasses = entry ;
74+ RCLASS_EXT (iclass )-> module_subclasses = & RCLASS_EXT (module )-> subclasses ;
75+ }
76+
77+ void
78+ rb_class_remove_from_super_subclasses (VALUE klass )
79+ {
80+ rb_subclass_entry_t * entry ;
81+
82+ if (RCLASS_EXT (klass )-> parent_subclasses ) {
83+ entry = * RCLASS_EXT (klass )-> parent_subclasses ;
84+
85+ * RCLASS_EXT (klass )-> parent_subclasses = entry -> next ;
86+ if (entry -> next ) {
87+ RCLASS_EXT (entry -> next -> klass )-> parent_subclasses = RCLASS_EXT (klass )-> parent_subclasses ;
88+ }
89+ free (entry );
90+ }
91+
92+ RCLASS_EXT (klass )-> parent_subclasses = NULL ;
93+ }
94+
95+ void
96+ rb_class_remove_from_module_subclasses (VALUE klass )
97+ {
98+ rb_subclass_entry_t * entry ;
99+
100+ if (RCLASS_EXT (klass )-> module_subclasses ) {
101+ entry = * RCLASS_EXT (klass )-> module_subclasses ;
102+ * RCLASS_EXT (klass )-> module_subclasses = entry -> next ;
103+
104+ if (entry -> next ) {
105+ RCLASS_EXT (entry -> next -> klass )-> module_subclasses = RCLASS_EXT (klass )-> module_subclasses ;
106+ }
107+
108+ free (entry );
109+ }
110+
111+ RCLASS_EXT (klass )-> module_subclasses = NULL ;
112+ }
113+
114+ void
115+ rb_class_foreach_subclass (VALUE klass , void (* f )(VALUE ))
116+ {
117+ rb_subclass_entry_t * cur = RCLASS_EXT (klass )-> subclasses ;
118+
119+ /* do not be tempted to simplify this loop into a for loop, the order of
120+ operations is important here if `f` modifies the linked list */
121+ while (cur ) {
122+ VALUE curklass = cur -> klass ;
123+ cur = cur -> next ;
124+ f (curklass );
125+ }
126+ }
127+
128+ void
129+ rb_class_detach_subclasses (VALUE klass )
130+ {
131+ rb_class_foreach_subclass (klass , rb_class_remove_from_super_subclasses );
132+ }
133+
134+ void
135+ rb_class_detach_module_subclasses (VALUE klass )
136+ {
137+ rb_class_foreach_subclass (klass , rb_class_remove_from_module_subclasses );
138+ }
139+
37140/**
38141 * Allocates a struct RClass for a new class.
39142 *
@@ -54,9 +157,15 @@ class_alloc(VALUE flags, VALUE klass)
54157 RCLASS_IV_TBL (obj ) = 0 ;
55158 RCLASS_CONST_TBL (obj ) = 0 ;
56159 RCLASS_M_TBL (obj ) = 0 ;
57- RCLASS_SUPER ( obj ) = 0 ;
160+ RCLASS_SET_SUPER (( VALUE ) obj , 0 ) ;
58161 RCLASS_ORIGIN (obj ) = (VALUE )obj ;
59162 RCLASS_IV_INDEX_TBL (obj ) = 0 ;
163+
164+ RCLASS_EXT (obj )-> subclasses = NULL ;
165+ RCLASS_EXT (obj )-> parent_subclasses = NULL ;
166+ RCLASS_EXT (obj )-> module_subclasses = NULL ;
167+ RCLASS_EXT (obj )-> seq = rb_next_class_sequence ();
168+
60169 RCLASS_REFINED_CLASS (obj ) = Qnil ;
61170 RCLASS_EXT (obj )-> allocator = 0 ;
62171 return (VALUE )obj ;
@@ -77,7 +186,7 @@ rb_class_boot(VALUE super)
77186{
78187 VALUE klass = class_alloc (T_CLASS , rb_cClass );
79188
80- RCLASS_SUPER (klass ) = super ;
189+ RCLASS_SET_SUPER (klass , super ) ;
81190 RCLASS_M_TBL (klass ) = st_init_numtable ();
82191
83192 OBJ_INFECT (klass , super );
@@ -203,7 +312,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
203312 RBASIC (clone )-> klass = rb_singleton_class_clone (orig );
204313 rb_singleton_class_attached (RBASIC (clone )-> klass , (VALUE )clone );
205314 }
206- RCLASS_SUPER (clone ) = RCLASS_SUPER (orig );
315+ RCLASS_SET_SUPER (clone , RCLASS_SUPER (orig ) );
207316 RCLASS_EXT (clone )-> allocator = RCLASS_EXT (orig )-> allocator ;
208317 if (RCLASS_IV_TBL (orig )) {
209318 st_data_t id ;
@@ -261,7 +370,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
261370 RBASIC (clone )-> klass = rb_singleton_class_clone (klass );
262371 }
263372
264- RCLASS_SUPER (clone ) = RCLASS_SUPER (klass );
373+ RCLASS_SET_SUPER (clone , RCLASS_SUPER (klass ) );
265374 RCLASS_EXT (clone )-> allocator = RCLASS_EXT (klass )-> allocator ;
266375 if (RCLASS_IV_TBL (klass )) {
267376 RCLASS_IV_TBL (clone ) = st_copy (RCLASS_IV_TBL (klass ));
@@ -356,7 +465,7 @@ make_metaclass(VALUE klass)
356465
357466 super = RCLASS_SUPER (klass );
358467 while (RB_TYPE_P (super , T_ICLASS )) super = RCLASS_SUPER (super );
359- RCLASS_SUPER (metaclass ) = super ? ENSURE_EIGENCLASS (super ) : rb_cClass ;
468+ RCLASS_SET_SUPER (metaclass , super ? ENSURE_EIGENCLASS (super ) : rb_cClass ) ;
360469
361470 OBJ_INFECT (metaclass , RCLASS_SUPER (metaclass ));
362471
@@ -676,7 +785,7 @@ rb_include_class_new(VALUE module, VALUE super)
676785 RCLASS_IV_TBL (klass ) = RCLASS_IV_TBL (module );
677786 RCLASS_CONST_TBL (klass ) = RCLASS_CONST_TBL (module );
678787 RCLASS_M_TBL (klass ) = RCLASS_M_TBL (RCLASS_ORIGIN (module ));
679- RCLASS_SUPER (klass ) = super ;
788+ RCLASS_SET_SUPER (klass , super ) ;
680789 if (RB_TYPE_P (module , T_ICLASS )) {
681790 RBASIC (klass )-> klass = RBASIC (module )-> klass ;
682791 }
@@ -710,7 +819,6 @@ rb_include_module(VALUE klass, VALUE module)
710819 changed = include_modules_at (klass , RCLASS_ORIGIN (klass ), module );
711820 if (changed < 0 )
712821 rb_raise (rb_eArgError , "cyclic include detected" );
713- if (changed ) rb_clear_cache ();
714822}
715823
716824static int
@@ -723,8 +831,8 @@ add_refined_method_entry_i(st_data_t key, st_data_t value, st_data_t data)
723831static int
724832include_modules_at (const VALUE klass , VALUE c , VALUE module )
725833{
726- VALUE p ;
727- int changed = 0 ;
834+ VALUE p , iclass ;
835+ int method_changed = 0 , constant_changed = 0 ;
728836 const st_table * const klass_m_tbl = RCLASS_M_TBL (RCLASS_ORIGIN (klass ));
729837
730838 while (module ) {
@@ -750,7 +858,15 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
750858 break ;
751859 }
752860 }
753- c = RCLASS_SUPER (c ) = rb_include_class_new (module , RCLASS_SUPER (c ));
861+ iclass = rb_include_class_new (module , RCLASS_SUPER (c ));
862+ c = RCLASS_SET_SUPER (c , iclass );
863+
864+ if (BUILTIN_TYPE (module ) == T_ICLASS ) {
865+ rb_module_add_to_subclasses_list (RBASIC (module )-> klass , iclass );
866+ } else {
867+ rb_module_add_to_subclasses_list (module , iclass );
868+ }
869+
754870 if (FL_TEST (klass , RMODULE_IS_REFINEMENT )) {
755871 VALUE refined_class =
756872 rb_refinement_module_get_refined_class (klass );
@@ -760,14 +876,17 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
760876 FL_SET (c , RMODULE_INCLUDED_INTO_REFINEMENT );
761877 }
762878 if (RMODULE_M_TBL (module ) && RMODULE_M_TBL (module )-> num_entries )
763- changed = 1 ;
879+ method_changed = 1 ;
764880 if (RMODULE_CONST_TBL (module ) && RMODULE_CONST_TBL (module )-> num_entries )
765- changed = 1 ;
881+ constant_changed = 1 ;
766882 skip :
767883 module = RCLASS_SUPER (module );
768884 }
769885
770- return changed ;
886+ if (method_changed ) rb_clear_cache_by_class (klass );
887+ if (constant_changed ) rb_clear_cache ();
888+
889+ return method_changed ;
771890}
772891
773892static int
@@ -816,8 +935,8 @@ rb_prepend_module(VALUE klass, VALUE module)
816935 origin = RCLASS_ORIGIN (klass );
817936 if (origin == klass ) {
818937 origin = class_alloc (T_ICLASS , klass );
819- RCLASS_SUPER (origin ) = RCLASS_SUPER (klass );
820- RCLASS_SUPER (klass ) = origin ;
938+ RCLASS_SET_SUPER (origin , RCLASS_SUPER (klass ) );
939+ RCLASS_SET_SUPER (klass , origin ) ;
821940 RCLASS_ORIGIN (klass ) = origin ;
822941 RCLASS_M_TBL (origin ) = RCLASS_M_TBL (klass );
823942 RCLASS_M_TBL (klass ) = st_init_numtable ();
@@ -828,7 +947,6 @@ rb_prepend_module(VALUE klass, VALUE module)
828947 if (changed < 0 )
829948 rb_raise (rb_eArgError , "cyclic prepend detected" );
830949 if (changed ) {
831- rb_clear_cache ();
832950 rb_vm_check_redefinition_by_prepend (klass );
833951 }
834952}
0 commit comments