Skip to content

Commit 034f276

Browse files
committed
Use rb_gc_mark_weak for cc->klass.
This gets rid of the ordering constraints. Prior to this, the class CC table couldn't be made a managed object because if the table was freed before the class, it would then be impossible to invalidate all the associated CCs.
1 parent 4446e82 commit 034f276

8 files changed

Lines changed: 44 additions & 55 deletions

File tree

debug_counter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ RB_DEBUG_COUNTER(cc_temp) // dummy CC (stack-allocated)
4949
RB_DEBUG_COUNTER(cc_found_in_ccs) // count for CC lookup success in CCS
5050
RB_DEBUG_COUNTER(cc_not_found_in_ccs) // count for CC lookup success in CCS
5151

52-
RB_DEBUG_COUNTER(cc_ent_invalidate) // count for invalidating cc (cc->klass = 0)
52+
RB_DEBUG_COUNTER(cc_ent_invalidate) // count for invalidating cc (cc->klass = Qundef)
5353
RB_DEBUG_COUNTER(cc_cme_invalidate) // count for invalidating CME
5454

5555
RB_DEBUG_COUNTER(cc_invalidate_leaf) // count for invalidating klass if klass has no-subclasses

gc.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,7 +1213,7 @@ classext_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
12131213
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
12141214

12151215
rb_id_table_free(RCLASSEXT_M_TBL(ext));
1216-
rb_vm_cc_table_invalidate_ccs(RCLASSEXT_CC_TBL(ext), args->klass);
1216+
12171217
if (!RCLASSEXT_SHARED_CONST_TBL(ext) && (tbl = RCLASSEXT_CONST_TBL(ext)) != NULL) {
12181218
rb_free_const_table(tbl);
12191219
}
@@ -1243,7 +1243,6 @@ classext_iclass_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *a
12431243
if (RCLASSEXT_CALLABLE_M_TBL(ext) != NULL) {
12441244
rb_id_table_free(RCLASSEXT_CALLABLE_M_TBL(ext));
12451245
}
1246-
rb_vm_cc_table_invalidate_ccs(RCLASSEXT_CC_TBL(ext), args->klass);
12471246

12481247
rb_class_classext_free_subclasses(ext, args->klass);
12491248

@@ -4835,11 +4834,11 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
48354834
case imemo_callcache:
48364835
{
48374836
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
4838-
VALUE class_path = cc->klass ? rb_class_path_cached(cc->klass) : Qnil;
4837+
VALUE class_path = vm_cc_valid(cc) ? rb_class_path_cached(cc->klass) : Qnil;
48394838
const rb_callable_method_entry_t *cme = vm_cc_cme(cc);
48404839

48414840
APPEND_F("(klass:%s cme:%s%s (%p) call:%p",
4842-
NIL_P(class_path) ? (cc->klass ? "??" : "<NULL>") : RSTRING_PTR(class_path),
4841+
NIL_P(class_path) ? (vm_cc_valid(cc) ? "??" : "<NULL>") : RSTRING_PTR(class_path),
48434842
cme ? rb_id2name(cme->called_id) : "<NULL>",
48444843
cme ? (METHOD_ENTRY_INVALIDATED(cme) ? " [inv]" : "") : "",
48454844
(void *)cme,

imemo.c

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,8 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
352352
* reachable only through cc in these cases.
353353
*/
354354
struct rb_callcache *cc = (struct rb_callcache *)obj;
355-
if (reference_updating) {
356-
if (!cc->klass) {
357-
// already invalidated
358-
}
359-
else {
355+
if (vm_cc_valid(cc)) {
356+
if (reference_updating) {
360357
if (moved_or_living_object_strictly_p(cc->klass) &&
361358
moved_or_living_object_strictly_p((VALUE)cc->cme_)) {
362359
*((VALUE *)&cc->klass) = rb_gc_location(cc->klass);
@@ -367,11 +364,11 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
367364
vm_cc_invalidate(cc);
368365
}
369366
}
370-
}
371-
else {
372-
if (cc->klass && (vm_cc_super_p(cc) || vm_cc_refinement_p(cc))) {
373-
rb_gc_mark_movable((VALUE)cc->cme_);
374-
rb_gc_mark_movable((VALUE)cc->klass);
367+
else {
368+
rb_gc_mark_weak((VALUE *)&cc->klass);
369+
if ((vm_cc_super_p(cc) || vm_cc_refinement_p(cc))) {
370+
rb_gc_mark_movable((VALUE)cc->cme_);
371+
}
375372
}
376373
}
377374

@@ -521,18 +518,6 @@ rb_free_const_table(struct rb_id_table *tbl)
521518
rb_id_table_free(tbl);
522519
}
523520

524-
static void
525-
vm_ccs_invalidate(struct rb_class_cc_entries *ccs)
526-
{
527-
if (ccs->entries) {
528-
for (int i=0; i<ccs->len; i++) {
529-
const struct rb_callcache *cc = ccs->entries[i].cc;
530-
VM_ASSERT(!vm_cc_super_p(cc) && !vm_cc_refinement_p(cc));
531-
vm_cc_invalidate(cc);
532-
}
533-
}
534-
}
535-
536521
static void
537522
vm_ccs_free(struct rb_class_cc_entries *ccs)
538523
{
@@ -542,14 +527,6 @@ vm_ccs_free(struct rb_class_cc_entries *ccs)
542527
ruby_xfree(ccs);
543528
}
544529

545-
void
546-
rb_vm_ccs_invalidate_and_free(struct rb_class_cc_entries *ccs)
547-
{
548-
RB_DEBUG_COUNTER_INC(ccs_free);
549-
vm_ccs_invalidate(ccs);
550-
vm_ccs_free(ccs);
551-
}
552-
553530
static enum rb_id_table_iterator_result
554531
cc_tbl_free_i(VALUE ccs_ptr, void *data)
555532
{

iseq.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -325,15 +325,13 @@ cc_is_active(const struct rb_callcache *cc, bool reference_updating)
325325
cc = (const struct rb_callcache *)rb_gc_location((VALUE)cc);
326326
}
327327

328-
if (vm_cc_markable(cc)) {
329-
if (cc->klass) { // cc is not invalidated
330-
const struct rb_callable_method_entry_struct *cme = vm_cc_cme(cc);
331-
if (reference_updating) {
332-
cme = (const struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cme);
333-
}
334-
if (!METHOD_ENTRY_INVALIDATED(cme)) {
335-
return true;
336-
}
328+
if (vm_cc_markable(cc) && vm_cc_valid(cc)) {
329+
const struct rb_callable_method_entry_struct *cme = vm_cc_cme(cc);
330+
if (reference_updating) {
331+
cme = (const struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cme);
332+
}
333+
if (!METHOD_ENTRY_INVALIDATED(cme)) {
334+
return true;
337335
}
338336
}
339337
}

vm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ rb_serial_t ruby_vm_global_cvar_state = 1;
609609

610610
static const struct rb_callcache vm_empty_cc = {
611611
.flags = T_IMEMO | (imemo_callcache << FL_USHIFT) | VM_CALLCACHE_UNMARKABLE,
612-
.klass = Qfalse,
612+
.klass = Qundef,
613613
.cme_ = NULL,
614614
.call_ = vm_call_general,
615615
.aux_ = {
@@ -619,7 +619,7 @@ static const struct rb_callcache vm_empty_cc = {
619619

620620
static const struct rb_callcache vm_empty_cc_for_super = {
621621
.flags = T_IMEMO | (imemo_callcache << FL_USHIFT) | VM_CALLCACHE_UNMARKABLE,
622-
.klass = Qfalse,
622+
.klass = Qundef,
623623
.cme_ = NULL,
624624
.call_ = vm_call_super_method,
625625
.aux_ = {

vm_callinfo.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ struct rb_callcache {
281281
/* inline cache: key */
282282
const VALUE klass; // should not mark it because klass can not be free'd
283283
// because of this marking. When klass is collected,
284-
// cc will be cleared (cc->klass = 0) at rb_vm_cc_table_invalidate_ccs().
284+
// cc will be cleared (cc->klass = Qundef) at rb_vm_cc_table_invalidate_ccs().
285285

286286
/* inline cache: values */
287287
const struct rb_callable_method_entry_struct * const cme_;
@@ -324,12 +324,20 @@ vm_cc_attr_index_initialize(const struct rb_callcache *cc, shape_id_t shape_id)
324324
vm_cc_attr_index_set(cc, (attr_index_t)-1, shape_id);
325325
}
326326

327+
static inline VALUE
328+
cc_check_class(VALUE klass)
329+
{
330+
VM_ASSERT(klass == Qundef || RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS));
331+
return klass;
332+
}
333+
327334
static inline const struct rb_callcache *
328335
vm_cc_new(VALUE klass,
329336
const struct rb_callable_method_entry_struct *cme,
330337
vm_call_handler call,
331338
enum vm_cc_type type)
332339
{
340+
cc_check_class(klass);
333341
struct rb_callcache *cc = IMEMO_NEW(struct rb_callcache, imemo_callcache, klass);
334342
*((struct rb_callable_method_entry_struct **)&cc->cme_) = (struct rb_callable_method_entry_struct *)cme;
335343
*((vm_call_handler *)&cc->call_) = call;
@@ -374,7 +382,7 @@ vm_cc_refinement_p(const struct rb_callcache *cc)
374382
(imemo_callcache << FL_USHIFT) | \
375383
VM_CALLCACHE_UNMARKABLE | \
376384
VM_CALLCACHE_ON_STACK, \
377-
.klass = clazz, \
385+
.klass = cc_check_class(clazz), \
378386
.cme_ = cme, \
379387
.call_ = call, \
380388
.aux_ = aux, \
@@ -384,7 +392,7 @@ static inline bool
384392
vm_cc_class_check(const struct rb_callcache *cc, VALUE klass)
385393
{
386394
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
387-
VM_ASSERT(cc->klass == 0 ||
395+
VM_ASSERT(cc->klass == Qundef ||
388396
RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
389397
return cc->klass == klass;
390398
}
@@ -396,6 +404,13 @@ vm_cc_markable(const struct rb_callcache *cc)
396404
return FL_TEST_RAW((VALUE)cc, VM_CALLCACHE_UNMARKABLE) == 0;
397405
}
398406

407+
static inline bool
408+
vm_cc_valid(const struct rb_callcache *cc)
409+
{
410+
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
411+
return cc->klass && !UNDEF_P(cc->klass);
412+
}
413+
399414
static inline const struct rb_callable_method_entry_struct *
400415
vm_cc_cme(const struct rb_callcache *cc)
401416
{
@@ -447,7 +462,7 @@ vm_cc_cmethod_missing_reason(const struct rb_callcache *cc)
447462
static inline bool
448463
vm_cc_invalidated_p(const struct rb_callcache *cc)
449464
{
450-
if (cc->klass && !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc))) {
465+
if (vm_cc_valid(cc) && !METHOD_ENTRY_INVALIDATED(vm_cc_cme(cc))) {
451466
return false;
452467
}
453468
else {
@@ -543,9 +558,9 @@ vm_cc_invalidate(const struct rb_callcache *cc)
543558
{
544559
VM_ASSERT(IMEMO_TYPE_P(cc, imemo_callcache));
545560
VM_ASSERT(cc != vm_cc_empty());
546-
VM_ASSERT(cc->klass != 0); // should be enable
561+
VM_ASSERT(cc->klass != Qundef); // should be enable
547562

548-
*(VALUE *)&cc->klass = 0;
563+
*(VALUE *)&cc->klass = Qundef;
549564
RB_DEBUG_COUNTER_INC(cc_ent_invalidate);
550565
}
551566

vm_eval.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static inline VALUE vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, i
5757
VALUE
5858
rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *cme, int kw_splat)
5959
{
60-
const struct rb_callcache cc = VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme);
60+
const struct rb_callcache cc = VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, cme);
6161
return vm_call0_cc(ec, recv, id, argc, argv, &cc, kw_splat);
6262
}
6363

@@ -104,7 +104,7 @@ vm_call0_cc(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE
104104
static VALUE
105105
vm_call0_cme(rb_execution_context_t *ec, struct rb_calling_info *calling, const VALUE *argv, const rb_callable_method_entry_t *cme)
106106
{
107-
calling->cc = &VM_CC_ON_STACK(Qfalse, vm_call_general, {{ 0 }}, cme);
107+
calling->cc = &VM_CC_ON_STACK(Qundef, vm_call_general, {{ 0 }}, cme);
108108
return vm_call0_body(ec, calling, argv);
109109
}
110110

vm_method.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ invalidate_cc_refinement(st_data_t key, st_data_t data)
568568

569569
VM_ASSERT(vm_cc_refinement_p(cc));
570570

571-
if (cc->klass) {
571+
if (vm_cc_valid(cc)) {
572572
vm_cc_invalidate(cc);
573573
}
574574
}

0 commit comments

Comments
 (0)