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,16 @@ 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
+ RCLASS_EXT (obj )-> mc_tbl = NULL ;
169
+
60
170
RCLASS_REFINED_CLASS (obj ) = Qnil ;
61
171
RCLASS_EXT (obj )-> allocator = 0 ;
62
172
return (VALUE )obj ;
@@ -77,7 +187,7 @@ rb_class_boot(VALUE super)
77
187
{
78
188
VALUE klass = class_alloc (T_CLASS , rb_cClass );
79
189
80
- RCLASS_SUPER (klass ) = super ;
190
+ RCLASS_SET_SUPER (klass , super ) ;
81
191
RCLASS_M_TBL (klass ) = st_init_numtable ();
82
192
83
193
OBJ_INFECT (klass , super );
@@ -203,7 +313,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
203
313
RBASIC (clone )-> klass = rb_singleton_class_clone (orig );
204
314
rb_singleton_class_attached (RBASIC (clone )-> klass , (VALUE )clone );
205
315
}
206
- RCLASS_SUPER (clone ) = RCLASS_SUPER (orig );
316
+ RCLASS_SET_SUPER (clone , RCLASS_SUPER (orig ) );
207
317
RCLASS_EXT (clone )-> allocator = RCLASS_EXT (orig )-> allocator ;
208
318
if (RCLASS_IV_TBL (orig )) {
209
319
st_data_t id ;
@@ -261,7 +371,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
261
371
RBASIC (clone )-> klass = rb_singleton_class_clone (klass );
262
372
}
263
373
264
- RCLASS_SUPER (clone ) = RCLASS_SUPER (klass );
374
+ RCLASS_SET_SUPER (clone , RCLASS_SUPER (klass ) );
265
375
RCLASS_EXT (clone )-> allocator = RCLASS_EXT (klass )-> allocator ;
266
376
if (RCLASS_IV_TBL (klass )) {
267
377
RCLASS_IV_TBL (clone ) = st_copy (RCLASS_IV_TBL (klass ));
@@ -356,7 +466,7 @@ make_metaclass(VALUE klass)
356
466
357
467
super = RCLASS_SUPER (klass );
358
468
while (RB_TYPE_P (super , T_ICLASS )) super = RCLASS_SUPER (super );
359
- RCLASS_SUPER (metaclass ) = super ? ENSURE_EIGENCLASS (super ) : rb_cClass ;
469
+ RCLASS_SET_SUPER (metaclass , super ? ENSURE_EIGENCLASS (super ) : rb_cClass ) ;
360
470
361
471
OBJ_INFECT (metaclass , RCLASS_SUPER (metaclass ));
362
472
@@ -676,7 +786,7 @@ rb_include_class_new(VALUE module, VALUE super)
676
786
RCLASS_IV_TBL (klass ) = RCLASS_IV_TBL (module );
677
787
RCLASS_CONST_TBL (klass ) = RCLASS_CONST_TBL (module );
678
788
RCLASS_M_TBL (klass ) = RCLASS_M_TBL (RCLASS_ORIGIN (module ));
679
- RCLASS_SUPER (klass ) = super ;
789
+ RCLASS_SET_SUPER (klass , super ) ;
680
790
if (RB_TYPE_P (module , T_ICLASS )) {
681
791
RBASIC (klass )-> klass = RBASIC (module )-> klass ;
682
792
}
@@ -710,7 +820,6 @@ rb_include_module(VALUE klass, VALUE module)
710
820
changed = include_modules_at (klass , RCLASS_ORIGIN (klass ), module );
711
821
if (changed < 0 )
712
822
rb_raise (rb_eArgError , "cyclic include detected" );
713
- if (changed ) rb_clear_cache ();
714
823
}
715
824
716
825
static int
@@ -723,8 +832,8 @@ add_refined_method_entry_i(st_data_t key, st_data_t value, st_data_t data)
723
832
static int
724
833
include_modules_at (const VALUE klass , VALUE c , VALUE module )
725
834
{
726
- VALUE p ;
727
- int changed = 0 ;
835
+ VALUE p , iclass ;
836
+ int method_changed = 0 , constant_changed = 0 ;
728
837
const st_table * const klass_m_tbl = RCLASS_M_TBL (RCLASS_ORIGIN (klass ));
729
838
730
839
while (module ) {
@@ -750,7 +859,15 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
750
859
break ;
751
860
}
752
861
}
753
- c = RCLASS_SUPER (c ) = rb_include_class_new (module , RCLASS_SUPER (c ));
862
+ iclass = rb_include_class_new (module , RCLASS_SUPER (c ));
863
+ c = RCLASS_SET_SUPER (c , iclass );
864
+
865
+ if (BUILTIN_TYPE (module ) == T_ICLASS ) {
866
+ rb_module_add_to_subclasses_list (RBASIC (module )-> klass , iclass );
867
+ } else {
868
+ rb_module_add_to_subclasses_list (module , iclass );
869
+ }
870
+
754
871
if (FL_TEST (klass , RMODULE_IS_REFINEMENT )) {
755
872
VALUE refined_class =
756
873
rb_refinement_module_get_refined_class (klass );
@@ -760,14 +877,17 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
760
877
FL_SET (c , RMODULE_INCLUDED_INTO_REFINEMENT );
761
878
}
762
879
if (RMODULE_M_TBL (module ) && RMODULE_M_TBL (module )-> num_entries )
763
- changed = 1 ;
880
+ method_changed = 1 ;
764
881
if (RMODULE_CONST_TBL (module ) && RMODULE_CONST_TBL (module )-> num_entries )
765
- changed = 1 ;
882
+ constant_changed = 1 ;
766
883
skip :
767
884
module = RCLASS_SUPER (module );
768
885
}
769
886
770
- return changed ;
887
+ if (method_changed ) rb_clear_cache_by_class (klass );
888
+ if (constant_changed ) rb_clear_cache ();
889
+
890
+ return method_changed ;
771
891
}
772
892
773
893
static int
@@ -816,8 +936,8 @@ rb_prepend_module(VALUE klass, VALUE module)
816
936
origin = RCLASS_ORIGIN (klass );
817
937
if (origin == klass ) {
818
938
origin = class_alloc (T_ICLASS , klass );
819
- RCLASS_SUPER (origin ) = RCLASS_SUPER (klass );
820
- RCLASS_SUPER (klass ) = origin ;
939
+ RCLASS_SET_SUPER (origin , RCLASS_SUPER (klass ) );
940
+ RCLASS_SET_SUPER (klass , origin ) ;
821
941
RCLASS_ORIGIN (klass ) = origin ;
822
942
RCLASS_M_TBL (origin ) = RCLASS_M_TBL (klass );
823
943
RCLASS_M_TBL (klass ) = st_init_numtable ();
@@ -828,7 +948,6 @@ rb_prepend_module(VALUE klass, VALUE module)
828
948
if (changed < 0 )
829
949
rb_raise (rb_eArgError , "cyclic prepend detected" );
830
950
if (changed ) {
831
- rb_clear_cache ();
832
951
rb_vm_check_redefinition_by_prepend (klass );
833
952
}
834
953
}
0 commit comments