34
34
extern st_table * rb_class_tbl ;
35
35
static ID id_attached ;
36
36
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
+
37
140
/**
38
141
* Allocates a struct RClass for a new class.
39
142
*
@@ -54,9 +157,15 @@ class_alloc(VALUE flags, VALUE klass)
54
157
RCLASS_IV_TBL (obj ) = 0 ;
55
158
RCLASS_CONST_TBL (obj ) = 0 ;
56
159
RCLASS_M_TBL (obj ) = 0 ;
57
- RCLASS_SUPER ( obj ) = 0 ;
160
+ RCLASS_SET_SUPER (( VALUE ) obj , 0 ) ;
58
161
RCLASS_ORIGIN (obj ) = (VALUE )obj ;
59
162
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
+
60
169
RCLASS_REFINED_CLASS (obj ) = Qnil ;
61
170
RCLASS_EXT (obj )-> allocator = 0 ;
62
171
return (VALUE )obj ;
@@ -77,7 +186,7 @@ rb_class_boot(VALUE super)
77
186
{
78
187
VALUE klass = class_alloc (T_CLASS , rb_cClass );
79
188
80
- RCLASS_SUPER (klass ) = super ;
189
+ RCLASS_SET_SUPER (klass , super ) ;
81
190
RCLASS_M_TBL (klass ) = st_init_numtable ();
82
191
83
192
OBJ_INFECT (klass , super );
@@ -203,7 +312,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
203
312
RBASIC (clone )-> klass = rb_singleton_class_clone (orig );
204
313
rb_singleton_class_attached (RBASIC (clone )-> klass , (VALUE )clone );
205
314
}
206
- RCLASS_SUPER (clone ) = RCLASS_SUPER (orig );
315
+ RCLASS_SET_SUPER (clone , RCLASS_SUPER (orig ) );
207
316
RCLASS_EXT (clone )-> allocator = RCLASS_EXT (orig )-> allocator ;
208
317
if (RCLASS_IV_TBL (orig )) {
209
318
st_data_t id ;
@@ -261,7 +370,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
261
370
RBASIC (clone )-> klass = rb_singleton_class_clone (klass );
262
371
}
263
372
264
- RCLASS_SUPER (clone ) = RCLASS_SUPER (klass );
373
+ RCLASS_SET_SUPER (clone , RCLASS_SUPER (klass ) );
265
374
RCLASS_EXT (clone )-> allocator = RCLASS_EXT (klass )-> allocator ;
266
375
if (RCLASS_IV_TBL (klass )) {
267
376
RCLASS_IV_TBL (clone ) = st_copy (RCLASS_IV_TBL (klass ));
@@ -356,7 +465,7 @@ make_metaclass(VALUE klass)
356
465
357
466
super = RCLASS_SUPER (klass );
358
467
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 ) ;
360
469
361
470
OBJ_INFECT (metaclass , RCLASS_SUPER (metaclass ));
362
471
@@ -676,7 +785,7 @@ rb_include_class_new(VALUE module, VALUE super)
676
785
RCLASS_IV_TBL (klass ) = RCLASS_IV_TBL (module );
677
786
RCLASS_CONST_TBL (klass ) = RCLASS_CONST_TBL (module );
678
787
RCLASS_M_TBL (klass ) = RCLASS_M_TBL (RCLASS_ORIGIN (module ));
679
- RCLASS_SUPER (klass ) = super ;
788
+ RCLASS_SET_SUPER (klass , super ) ;
680
789
if (RB_TYPE_P (module , T_ICLASS )) {
681
790
RBASIC (klass )-> klass = RBASIC (module )-> klass ;
682
791
}
@@ -710,7 +819,6 @@ rb_include_module(VALUE klass, VALUE module)
710
819
changed = include_modules_at (klass , RCLASS_ORIGIN (klass ), module );
711
820
if (changed < 0 )
712
821
rb_raise (rb_eArgError , "cyclic include detected" );
713
- if (changed ) rb_clear_cache ();
714
822
}
715
823
716
824
static int
@@ -723,8 +831,8 @@ add_refined_method_entry_i(st_data_t key, st_data_t value, st_data_t data)
723
831
static int
724
832
include_modules_at (const VALUE klass , VALUE c , VALUE module )
725
833
{
726
- VALUE p ;
727
- int changed = 0 ;
834
+ VALUE p , iclass ;
835
+ int method_changed = 0 , constant_changed = 0 ;
728
836
const st_table * const klass_m_tbl = RCLASS_M_TBL (RCLASS_ORIGIN (klass ));
729
837
730
838
while (module ) {
@@ -750,7 +858,15 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
750
858
break ;
751
859
}
752
860
}
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
+
754
870
if (FL_TEST (klass , RMODULE_IS_REFINEMENT )) {
755
871
VALUE refined_class =
756
872
rb_refinement_module_get_refined_class (klass );
@@ -760,14 +876,17 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
760
876
FL_SET (c , RMODULE_INCLUDED_INTO_REFINEMENT );
761
877
}
762
878
if (RMODULE_M_TBL (module ) && RMODULE_M_TBL (module )-> num_entries )
763
- changed = 1 ;
879
+ method_changed = 1 ;
764
880
if (RMODULE_CONST_TBL (module ) && RMODULE_CONST_TBL (module )-> num_entries )
765
- changed = 1 ;
881
+ constant_changed = 1 ;
766
882
skip :
767
883
module = RCLASS_SUPER (module );
768
884
}
769
885
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 ;
771
890
}
772
891
773
892
static int
@@ -816,8 +935,8 @@ rb_prepend_module(VALUE klass, VALUE module)
816
935
origin = RCLASS_ORIGIN (klass );
817
936
if (origin == klass ) {
818
937
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 ) ;
821
940
RCLASS_ORIGIN (klass ) = origin ;
822
941
RCLASS_M_TBL (origin ) = RCLASS_M_TBL (klass );
823
942
RCLASS_M_TBL (klass ) = st_init_numtable ();
@@ -828,7 +947,6 @@ rb_prepend_module(VALUE klass, VALUE module)
828
947
if (changed < 0 )
829
948
rb_raise (rb_eArgError , "cyclic prepend detected" );
830
949
if (changed ) {
831
- rb_clear_cache ();
832
950
rb_vm_check_redefinition_by_prepend (klass );
833
951
}
834
952
}
0 commit comments