Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 756d555

Browse files
author
Charlie Somerville
committed
* class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h, vm_method.c: Implement class hierarchy method cache invalidation. [ruby-core:55053] [Feature ruby#8426] [rubyGH-387] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42822 b2dd03c8-39d4-4d8f-98ff-823fe69b080e Conflicts: ChangeLog class.c eval.c internal.h variable.c vm_insnhelper.c
1 parent de6ba0f commit 756d555

14 files changed

+346
-111
lines changed

class.c

+135-16
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,109 @@
3434
extern st_table *rb_class_tbl;
3535
static 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,16 @@ 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+
RCLASS_EXT(obj)->mc_tbl = NULL;
169+
60170
RCLASS_REFINED_CLASS(obj) = Qnil;
61171
RCLASS_EXT(obj)->allocator = 0;
62172
return (VALUE)obj;
@@ -77,7 +187,7 @@ rb_class_boot(VALUE super)
77187
{
78188
VALUE klass = class_alloc(T_CLASS, rb_cClass);
79189

80-
RCLASS_SUPER(klass) = super;
190+
RCLASS_SET_SUPER(klass, super);
81191
RCLASS_M_TBL(klass) = st_init_numtable();
82192

83193
OBJ_INFECT(klass, super);
@@ -203,7 +313,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
203313
RBASIC(clone)->klass = rb_singleton_class_clone(orig);
204314
rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
205315
}
206-
RCLASS_SUPER(clone) = RCLASS_SUPER(orig);
316+
RCLASS_SET_SUPER(clone, RCLASS_SUPER(orig));
207317
RCLASS_EXT(clone)->allocator = RCLASS_EXT(orig)->allocator;
208318
if (RCLASS_IV_TBL(orig)) {
209319
st_data_t id;
@@ -261,7 +371,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
261371
RBASIC(clone)->klass = rb_singleton_class_clone(klass);
262372
}
263373

264-
RCLASS_SUPER(clone) = RCLASS_SUPER(klass);
374+
RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
265375
RCLASS_EXT(clone)->allocator = RCLASS_EXT(klass)->allocator;
266376
if (RCLASS_IV_TBL(klass)) {
267377
RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(klass));
@@ -356,7 +466,7 @@ make_metaclass(VALUE klass)
356466

357467
super = RCLASS_SUPER(klass);
358468
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);
360470

361471
OBJ_INFECT(metaclass, RCLASS_SUPER(metaclass));
362472

@@ -676,7 +786,7 @@ rb_include_class_new(VALUE module, VALUE super)
676786
RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
677787
RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);
678788
RCLASS_M_TBL(klass) = RCLASS_M_TBL(RCLASS_ORIGIN(module));
679-
RCLASS_SUPER(klass) = super;
789+
RCLASS_SET_SUPER(klass, super);
680790
if (RB_TYPE_P(module, T_ICLASS)) {
681791
RBASIC(klass)->klass = RBASIC(module)->klass;
682792
}
@@ -710,7 +820,6 @@ rb_include_module(VALUE klass, VALUE module)
710820
changed = include_modules_at(klass, RCLASS_ORIGIN(klass), module);
711821
if (changed < 0)
712822
rb_raise(rb_eArgError, "cyclic include detected");
713-
if (changed) rb_clear_cache();
714823
}
715824

716825
static int
@@ -723,8 +832,8 @@ add_refined_method_entry_i(st_data_t key, st_data_t value, st_data_t data)
723832
static int
724833
include_modules_at(const VALUE klass, VALUE c, VALUE module)
725834
{
726-
VALUE p;
727-
int changed = 0;
835+
VALUE p, iclass;
836+
int method_changed = 0, constant_changed = 0;
728837
const st_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass));
729838

730839
while (module) {
@@ -750,7 +859,15 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
750859
break;
751860
}
752861
}
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+
754871
if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
755872
VALUE refined_class =
756873
rb_refinement_module_get_refined_class(klass);
@@ -760,14 +877,17 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module)
760877
FL_SET(c, RMODULE_INCLUDED_INTO_REFINEMENT);
761878
}
762879
if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
763-
changed = 1;
880+
method_changed = 1;
764881
if (RMODULE_CONST_TBL(module) && RMODULE_CONST_TBL(module)->num_entries)
765-
changed = 1;
882+
constant_changed = 1;
766883
skip:
767884
module = RCLASS_SUPER(module);
768885
}
769886

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;
771891
}
772892

773893
static int
@@ -816,8 +936,8 @@ rb_prepend_module(VALUE klass, VALUE module)
816936
origin = RCLASS_ORIGIN(klass);
817937
if (origin == klass) {
818938
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);
821941
RCLASS_ORIGIN(klass) = origin;
822942
RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
823943
RCLASS_M_TBL(klass) = st_init_numtable();
@@ -828,7 +948,6 @@ rb_prepend_module(VALUE klass, VALUE module)
828948
if (changed < 0)
829949
rb_raise(rb_eArgError, "cyclic prepend detected");
830950
if (changed) {
831-
rb_clear_cache();
832951
rb_vm_check_redefinition_by_prepend(klass);
833952
}
834953
}

compile.c

+1
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,7 @@ new_callinfo(rb_iseq_t *iseq, ID mid, int argc, VALUE block, unsigned long flag)
959959
}
960960
}
961961
ci->vmstat = 0;
962+
ci->seq = 0;
962963
ci->blockptr = 0;
963964
ci->recv = Qundef;
964965
ci->call = 0; /* TODO: should set default function? */

eval.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@ rb_using_refinement(NODE *cref, VALUE klass, VALUE module)
10971097
module = RCLASS_SUPER(module);
10981098
while (module && module != klass) {
10991099
FL_SET(module, RMODULE_IS_OVERLAID);
1100-
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
1100+
c = RCLASS_SET_SUPER(c, rb_include_class_new(module, RCLASS_SUPER(c)));
11011101
RCLASS_REFINED_CLASS(c) = klass;
11021102
module = RCLASS_SUPER(module);
11031103
}
@@ -1156,8 +1156,8 @@ add_activated_refinement(VALUE activated_refinements,
11561156
refinement = RCLASS_SUPER(refinement);
11571157
while (refinement) {
11581158
FL_SET(refinement, RMODULE_IS_OVERLAID);
1159-
c = RCLASS_SUPER(c) =
1160-
rb_include_class_new(refinement, RCLASS_SUPER(c));
1159+
c = RCLASS_SET_SUPER(c,
1160+
rb_include_class_new(refinement, RCLASS_SUPER(c)));
11611161
RCLASS_REFINED_CLASS(c) = klass;
11621162
refinement = RCLASS_SUPER(refinement);
11631163
}
@@ -1210,7 +1210,7 @@ rb_mod_refine(VALUE module, VALUE klass)
12101210
refinement = rb_hash_lookup(refinements, klass);
12111211
if (NIL_P(refinement)) {
12121212
refinement = rb_module_new();
1213-
RCLASS_SUPER(refinement) = klass;
1213+
RCLASS_SET_SUPER(refinement, klass);
12141214
FL_SET(refinement, RMODULE_IS_REFINEMENT);
12151215
CONST_ID(id_refined_class, "__refined_class__");
12161216
rb_ivar_set(refinement, id_refined_class, klass);
@@ -1356,7 +1356,7 @@ top_using(VALUE self, VALUE module)
13561356
}
13571357
Check_Type(module, T_MODULE);
13581358
rb_using_module(cref, module);
1359-
rb_clear_cache();
1359+
rb_clear_cache_by_class(rb_cObject);
13601360
return self;
13611361
}
13621362

gc.c

+39-3
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,20 @@ rb_free_m_table(st_table *tbl)
807807
st_free_table(tbl);
808808
}
809809

810+
static int
811+
free_method_cache_entry_i(ID key, method_cache_entry_t *entry, st_data_t data)
812+
{
813+
free(entry);
814+
return ST_CONTINUE;
815+
}
816+
817+
void
818+
rb_free_mc_table(st_table *tbl)
819+
{
820+
st_foreach(tbl, free_method_cache_entry_i, 0);
821+
st_free_table(tbl);
822+
}
823+
810824
static int
811825
free_const_entry_i(ID key, rb_const_entry_t *ce, st_data_t data)
812826
{
@@ -930,7 +944,6 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
930944
break;
931945
case T_MODULE:
932946
case T_CLASS:
933-
rb_clear_cache_by_class((VALUE)obj);
934947
if (RCLASS_M_TBL(obj)) {
935948
rb_free_m_table(RCLASS_M_TBL(obj));
936949
}
@@ -943,7 +956,23 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
943956
if (RCLASS_IV_INDEX_TBL(obj)) {
944957
st_free_table(RCLASS_IV_INDEX_TBL(obj));
945958
}
946-
xfree(RANY(obj)->as.klass.ptr);
959+
if (RCLASS_EXT(obj)->subclasses) {
960+
if (BUILTIN_TYPE(obj) == T_MODULE) {
961+
rb_class_detach_module_subclasses(obj);
962+
} else {
963+
rb_class_detach_subclasses(obj);
964+
}
965+
RCLASS_EXT(obj)->subclasses = NULL;
966+
}
967+
if (RCLASS_EXT(obj)->mc_tbl) {
968+
rb_free_mc_table(RCLASS_EXT(obj)->mc_tbl);
969+
RCLASS_EXT(obj)->mc_tbl = NULL;
970+
}
971+
rb_class_remove_from_module_subclasses(obj);
972+
rb_class_remove_from_super_subclasses(obj);
973+
if (RANY(obj)->as.klass.ptr)
974+
xfree(RANY(obj)->as.klass.ptr);
975+
RANY(obj)->as.klass.ptr = NULL;
947976
break;
948977
case T_STRING:
949978
rb_str_free(obj);
@@ -995,7 +1024,14 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
9951024
break;
9961025
case T_ICLASS:
9971026
/* iClass shares table with the module */
1027+
if (RCLASS_EXT(obj)->subclasses) {
1028+
rb_class_detach_subclasses(obj);
1029+
RCLASS_EXT(obj)->subclasses = NULL;
1030+
}
1031+
rb_class_remove_from_module_subclasses(obj);
1032+
rb_class_remove_from_super_subclasses(obj);
9981033
xfree(RANY(obj)->as.klass.ptr);
1034+
RANY(obj)->as.klass.ptr = NULL;
9991035
break;
10001036

10011037
case T_FLOAT:
@@ -2792,7 +2828,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
27922828
if (!RCLASS_EXT(obj)) break;
27932829
mark_tbl(objspace, RCLASS_IV_TBL(obj));
27942830
mark_const_tbl(objspace, RCLASS_CONST_TBL(obj));
2795-
ptr = RCLASS_SUPER(obj);
2831+
ptr = RCLASS_SUPER((VALUE)obj);
27962832
goto again;
27972833

27982834
case T_ARRAY:

insns.def

+2-2
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ setconstant
218218
{
219219
vm_check_if_namespace(cbase);
220220
rb_const_set(cbase, id, val);
221-
INC_VM_STATE_VERSION();
221+
rb_clear_cache_by_class(cbase);
222222
}
223223

224224
/**
@@ -975,7 +975,7 @@ defineclass
975975
class_iseq->local_size, 0);
976976
RESTORE_REGS();
977977

978-
INC_VM_STATE_VERSION();
978+
rb_clear_cache_by_class(klass);
979979
NEXT_INSN();
980980
}
981981

0 commit comments

Comments
 (0)