diff --git a/variable.c b/variable.c index 0c596d5c9e..4f0f83d203 100644 --- a/variable.c +++ b/variable.c @@ -1245,9 +1245,19 @@ rb_obj_fields(VALUE obj, ID field_name) goto generic_fields; default: generic_fields: - RB_VM_LOCKING() { - if (!st_lookup(generic_fields_tbl_, (st_data_t)obj, (st_data_t *)&fields_obj)) { - rb_bug("Object is missing entry in generic_fields_tbl"); + { + rb_execution_context_t *ec = GET_EC(); + if (ec->gen_fields_cache.obj == obj) { + fields_obj = ec->gen_fields_cache.fields_obj; + } + else { + RB_VM_LOCKING() { + if (!st_lookup(generic_fields_tbl_, (st_data_t)obj, (st_data_t *)&fields_obj)) { + rb_bug("Object is missing entry in generic_fields_tbl"); + } + } + ec->gen_fields_cache.fields_obj = fields_obj; + ec->gen_fields_cache.obj = obj; } } } @@ -1275,8 +1285,15 @@ rb_free_generic_ivar(VALUE obj) goto generic_fields; default: generic_fields: - RB_VM_LOCKING() { - st_delete(generic_fields_tbl_no_ractor_check(), &key, &value); + { + rb_execution_context_t *ec = GET_EC(); + if (ec->gen_fields_cache.obj == obj) { + ec->gen_fields_cache.obj = Qundef; + ec->gen_fields_cache.fields_obj = Qundef; + } + RB_VM_LOCKING() { + st_delete(generic_fields_tbl_no_ractor_check(), &key, &value); + } } } RBASIC_SET_SHAPE_ID(obj, ROOT_SHAPE_ID); @@ -1307,10 +1324,18 @@ rb_obj_set_fields(VALUE obj, VALUE fields_obj, ID field_name, VALUE original_fie goto generic_fields; default: generic_fields: - RB_VM_LOCKING() { - st_insert(generic_fields_tbl_, (st_data_t)obj, (st_data_t)fields_obj); + { + RB_VM_LOCKING() { + st_insert(generic_fields_tbl_, (st_data_t)obj, (st_data_t)fields_obj); + } + RB_OBJ_WRITTEN(obj, original_fields_obj, fields_obj); + + rb_execution_context_t *ec = GET_EC(); + if (ec->gen_fields_cache.fields_obj != fields_obj) { + ec->gen_fields_cache.obj = obj; + ec->gen_fields_cache.fields_obj = fields_obj; + } } - RB_OBJ_WRITTEN(obj, original_fields_obj, fields_obj); } if (original_fields_obj) { diff --git a/vm.c b/vm.c index 4223c2d2ac..479b3be94f 100644 --- a/vm.c +++ b/vm.c @@ -3441,6 +3441,9 @@ rb_execution_context_update(rb_execution_context_t *ec) } ec->storage = rb_gc_location(ec->storage); + + ec->gen_fields_cache.obj = rb_gc_location(ec->gen_fields_cache.obj); + ec->gen_fields_cache.fields_obj = rb_gc_location(ec->gen_fields_cache.fields_obj); } static enum rb_id_table_iterator_result @@ -3505,6 +3508,9 @@ rb_execution_context_mark(const rb_execution_context_t *ec) rb_gc_mark(ec->private_const_reference); rb_gc_mark_movable(ec->storage); + + rb_gc_mark_weak((VALUE *)&ec->gen_fields_cache.obj); + rb_gc_mark_weak((VALUE *)&ec->gen_fields_cache.fields_obj); } void rb_fiber_mark_self(rb_fiber_t *fib); diff --git a/vm_core.h b/vm_core.h index 569aebaba4..b5a04101ab 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1070,6 +1070,11 @@ struct rb_execution_context_struct { VALUE private_const_reference; + struct { + VALUE obj; + VALUE fields_obj; + } gen_fields_cache; + /* for GC */ struct { VALUE *stack_start;