Use rb_gc_mark_and_move for imemo

This commit is contained in:
Peter Zhu 2024-02-16 13:35:33 -05:00
parent 20f03100d5
commit c184aa8740
5 changed files with 105 additions and 216 deletions

271
gc.c
View File

@ -4710,6 +4710,14 @@ is_live_object(rb_objspace_t *objspace, VALUE ptr)
}
}
static bool
moved_or_living_object_strictly_p(rb_objspace_t *objspace, VALUE obj)
{
return obj &&
is_pointer_to_heap(objspace, (void *)obj) &&
(is_live_object(objspace, obj) || BUILTIN_TYPE(obj) == T_MOVED);
}
static inline int
is_markable_object(VALUE obj)
{
@ -6675,38 +6683,44 @@ rb_mark_hash(st_table *tbl)
}
static void
mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
mark_and_move_method_entry(rb_objspace_t *objspace, rb_method_entry_t *me, bool reference_updating)
{
const rb_method_definition_t *def = me->def;
rb_method_definition_t *def = me->def;
gc_mark(objspace, me->owner);
gc_mark(objspace, me->defined_class);
rb_gc_mark_and_move(&me->owner);
rb_gc_mark_and_move(&me->defined_class);
if (def) {
switch (def->type) {
case VM_METHOD_TYPE_ISEQ:
if (def->body.iseq.iseqptr) gc_mark(objspace, (VALUE)def->body.iseq.iseqptr);
gc_mark(objspace, (VALUE)def->body.iseq.cref);
if (def->body.iseq.iseqptr) {
rb_gc_mark_and_move_ptr(&def->body.iseq.iseqptr);
}
rb_gc_mark_and_move_ptr(&def->body.iseq.cref);
if (def->iseq_overload && me->defined_class) {
// it can be a key of "overloaded_cme" table
// so it should be pinned.
gc_mark_and_pin(objspace, (VALUE)me);
if (!reference_updating) {
if (def->iseq_overload && me->defined_class) {
// it can be a key of "overloaded_cme" table
// so it should be pinned.
gc_mark_and_pin(objspace, (VALUE)me);
}
}
break;
case VM_METHOD_TYPE_ATTRSET:
case VM_METHOD_TYPE_IVAR:
gc_mark(objspace, def->body.attr.location);
rb_gc_mark_and_move(&def->body.attr.location);
break;
case VM_METHOD_TYPE_BMETHOD:
gc_mark(objspace, def->body.bmethod.proc);
if (def->body.bmethod.hooks) rb_hook_list_mark(def->body.bmethod.hooks);
rb_gc_mark_and_move(&def->body.bmethod.proc);
if (!reference_updating) {
if (def->body.bmethod.hooks) rb_hook_list_mark(def->body.bmethod.hooks);
}
break;
case VM_METHOD_TYPE_ALIAS:
gc_mark(objspace, (VALUE)def->body.alias.original_me);
rb_gc_mark_and_move_ptr(&def->body.alias.original_me);
return;
case VM_METHOD_TYPE_REFINED:
gc_mark(objspace, (VALUE)def->body.refined.orig_me);
rb_gc_mark_and_move_ptr(&def->body.refined.orig_me);
break;
case VM_METHOD_TYPE_CFUNC:
case VM_METHOD_TYPE_ZSUPER:
@ -7189,65 +7203,80 @@ gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj)
}
static void
gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
gc_mark_and_move_imemo(rb_objspace_t *objspace, VALUE obj, bool reference_updating)
{
switch (imemo_type(obj)) {
case imemo_env:
{
const rb_env_t *env = (const rb_env_t *)obj;
rb_env_t *env = (rb_env_t *)obj;
if (LIKELY(env->ep)) {
// just after newobj() can be NULL here.
GC_ASSERT(env->ep[VM_ENV_DATA_INDEX_ENV] == obj);
GC_ASSERT(VM_ENV_ESCAPED_P(env->ep));
rb_gc_mark_values((long)env->env_size, env->env);
VM_ENV_FLAGS_SET(env->ep, VM_ENV_FLAG_WB_REQUIRED);
gc_mark(objspace, (VALUE)rb_vm_env_prev_env(env));
gc_mark(objspace, (VALUE)env->iseq);
GC_ASSERT(rb_gc_location(env->ep[VM_ENV_DATA_INDEX_ENV]) == rb_gc_location(obj));
GC_ASSERT(reference_updating || VM_ENV_ESCAPED_P(env->ep));
for (unsigned int i = 0; i < env->env_size; i++) {
rb_gc_mark_and_move((VALUE *)&env->env[i]);
}
rb_gc_mark_and_move_ptr(&env->iseq);
if (reference_updating) {
UPDATE_IF_MOVED(objspace, env->ep[VM_ENV_DATA_INDEX_ENV]);
}
else {
VM_ENV_FLAGS_SET(env->ep, VM_ENV_FLAG_WB_REQUIRED);
gc_mark(objspace, (VALUE)rb_vm_env_prev_env(env));
}
}
}
return;
case imemo_cref:
gc_mark(objspace, RANY(obj)->as.imemo.cref.klass_or_self);
gc_mark(objspace, (VALUE)RANY(obj)->as.imemo.cref.next);
gc_mark(objspace, RANY(obj)->as.imemo.cref.refinements);
rb_gc_mark_and_move(&RANY(obj)->as.imemo.cref.klass_or_self);
rb_gc_mark_and_move_ptr(&RANY(obj)->as.imemo.cref.next);
rb_gc_mark_and_move(&RANY(obj)->as.imemo.cref.refinements);
return;
case imemo_svar:
gc_mark(objspace, RANY(obj)->as.imemo.svar.cref_or_me);
gc_mark(objspace, RANY(obj)->as.imemo.svar.lastline);
gc_mark(objspace, RANY(obj)->as.imemo.svar.backref);
gc_mark(objspace, RANY(obj)->as.imemo.svar.others);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.svar.cref_or_me);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.svar.lastline);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.svar.backref);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.svar.others);
return;
case imemo_throw_data:
gc_mark(objspace, RANY(obj)->as.imemo.throw_data.throw_obj);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.throw_data.throw_obj);
return;
case imemo_ifunc:
gc_mark_maybe(objspace, (VALUE)RANY(obj)->as.imemo.ifunc.data);
if (!reference_updating) {
gc_mark_maybe(objspace, (VALUE)RANY(obj)->as.imemo.ifunc.data);
}
return;
case imemo_memo:
gc_mark(objspace, RANY(obj)->as.imemo.memo.v1);
gc_mark(objspace, RANY(obj)->as.imemo.memo.v2);
gc_mark_maybe(objspace, RANY(obj)->as.imemo.memo.u3.value);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.memo.v1);
rb_gc_mark_and_move((VALUE *)&RANY(obj)->as.imemo.memo.v2);
if (!reference_updating) {
gc_mark_maybe(objspace, RANY(obj)->as.imemo.memo.u3.value);
}
return;
case imemo_ment:
mark_method_entry(objspace, &RANY(obj)->as.imemo.ment);
mark_and_move_method_entry(objspace, &RANY(obj)->as.imemo.ment, reference_updating);
return;
case imemo_iseq:
rb_iseq_mark_and_move((rb_iseq_t *)obj, false);
rb_iseq_mark_and_move((rb_iseq_t *)obj, reference_updating);
return;
case imemo_tmpbuf:
{
const rb_imemo_tmpbuf_t *m = &RANY(obj)->as.imemo.alloc;
do {
rb_gc_mark_locations(m->ptr, m->ptr + m->cnt);
} while ((m = m->next) != NULL);
if (!reference_updating) {
const rb_imemo_tmpbuf_t *m = &RANY(obj)->as.imemo.alloc;
do {
rb_gc_mark_locations(m->ptr, m->ptr + m->cnt);
} while ((m = m->next) != NULL);
}
}
return;
case imemo_ast:
rb_ast_mark(&RANY(obj)->as.imemo.ast);
rb_ast_mark_and_move(&RANY(obj)->as.imemo.ast, reference_updating);
return;
case imemo_parser_strterm:
return;
case imemo_callinfo:
return;
case imemo_callcache:
@ -7272,15 +7301,32 @@ gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
*/
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
if (vm_cc_super_p(cc) || vm_cc_refinement_p(cc)) {
gc_mark(objspace, (VALUE)cc->cme_);
if (reference_updating) {
if (!cc->klass) {
// already invalidated
}
else {
if (moved_or_living_object_strictly_p(objspace, cc->klass) &&
moved_or_living_object_strictly_p(objspace, (VALUE)cc->cme_)) {
UPDATE_IF_MOVED(objspace, cc->klass);
TYPED_UPDATE_IF_MOVED(objspace, struct rb_callable_method_entry_struct *, cc->cme_);
}
else {
vm_cc_invalidate(cc);
}
}
}
else {
if (vm_cc_super_p(cc) || vm_cc_refinement_p(cc)) {
gc_mark(objspace, (VALUE)cc->cme_);
}
}
}
return;
case imemo_constcache:
{
const struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
gc_mark(objspace, ice->value);
struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
rb_gc_mark_and_move(&ice->value);
}
return;
#if VM_CHECK_MODE > 0
@ -7328,7 +7374,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
break;
case T_IMEMO:
gc_mark_imemo(objspace, obj);
gc_mark_and_move_imemo(objspace, obj, false);
return;
default:
@ -10359,46 +10405,6 @@ gc_ref_update_hash(rb_objspace_t * objspace, VALUE v)
rb_hash_stlike_foreach_with_replace(v, hash_foreach_replace, hash_replace_ref, (st_data_t)objspace);
}
static void
gc_ref_update_method_entry(rb_objspace_t *objspace, rb_method_entry_t *me)
{
rb_method_definition_t *def = me->def;
UPDATE_IF_MOVED(objspace, me->owner);
UPDATE_IF_MOVED(objspace, me->defined_class);
if (def) {
switch (def->type) {
case VM_METHOD_TYPE_ISEQ:
if (def->body.iseq.iseqptr) {
TYPED_UPDATE_IF_MOVED(objspace, rb_iseq_t *, def->body.iseq.iseqptr);
}
TYPED_UPDATE_IF_MOVED(objspace, rb_cref_t *, def->body.iseq.cref);
break;
case VM_METHOD_TYPE_ATTRSET:
case VM_METHOD_TYPE_IVAR:
UPDATE_IF_MOVED(objspace, def->body.attr.location);
break;
case VM_METHOD_TYPE_BMETHOD:
UPDATE_IF_MOVED(objspace, def->body.bmethod.proc);
break;
case VM_METHOD_TYPE_ALIAS:
TYPED_UPDATE_IF_MOVED(objspace, struct rb_method_entry_struct *, def->body.alias.original_me);
return;
case VM_METHOD_TYPE_REFINED:
TYPED_UPDATE_IF_MOVED(objspace, struct rb_method_entry_struct *, def->body.refined.orig_me);
break;
case VM_METHOD_TYPE_CFUNC:
case VM_METHOD_TYPE_ZSUPER:
case VM_METHOD_TYPE_MISSING:
case VM_METHOD_TYPE_OPTIMIZED:
case VM_METHOD_TYPE_UNDEF:
case VM_METHOD_TYPE_NOTIMPLEMENTED:
break;
}
}
}
static void
gc_update_values(rb_objspace_t *objspace, long n, VALUE *values)
{
@ -10415,93 +10421,6 @@ rb_gc_update_values(long n, VALUE *values)
gc_update_values(&rb_objspace, n, values);
}
static bool
moved_or_living_object_strictly_p(rb_objspace_t *objspace, VALUE obj)
{
return obj &&
is_pointer_to_heap(objspace, (void *)obj) &&
(is_live_object(objspace, obj) || BUILTIN_TYPE(obj) == T_MOVED);
}
static void
gc_ref_update_imemo(rb_objspace_t *objspace, VALUE obj)
{
switch (imemo_type(obj)) {
case imemo_env:
{
rb_env_t *env = (rb_env_t *)obj;
if (LIKELY(env->ep)) {
// just after newobj() can be NULL here.
TYPED_UPDATE_IF_MOVED(objspace, rb_iseq_t *, env->iseq);
UPDATE_IF_MOVED(objspace, env->ep[VM_ENV_DATA_INDEX_ENV]);
gc_update_values(objspace, (long)env->env_size, (VALUE *)env->env);
}
}
break;
case imemo_cref:
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.cref.klass_or_self);
TYPED_UPDATE_IF_MOVED(objspace, struct rb_cref_struct *, RANY(obj)->as.imemo.cref.next);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.cref.refinements);
break;
case imemo_svar:
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.cref_or_me);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.lastline);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.backref);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.others);
break;
case imemo_throw_data:
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.throw_data.throw_obj);
break;
case imemo_ifunc:
break;
case imemo_memo:
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.memo.v1);
UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.memo.v2);
break;
case imemo_ment:
gc_ref_update_method_entry(objspace, &RANY(obj)->as.imemo.ment);
break;
case imemo_iseq:
rb_iseq_mark_and_move((rb_iseq_t *)obj, true);
break;
case imemo_ast:
rb_ast_update_references((rb_ast_t *)obj);
break;
case imemo_callcache:
{
const struct rb_callcache *cc = (const struct rb_callcache *)obj;
if (!cc->klass) {
// already invalidated
}
else {
if (moved_or_living_object_strictly_p(objspace, cc->klass) &&
moved_or_living_object_strictly_p(objspace, (VALUE)cc->cme_)) {
UPDATE_IF_MOVED(objspace, cc->klass);
TYPED_UPDATE_IF_MOVED(objspace, struct rb_callable_method_entry_struct *, cc->cme_);
}
else {
vm_cc_invalidate(cc);
}
}
}
break;
case imemo_constcache:
{
const struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
UPDATE_IF_MOVED(objspace, ice->value);
}
break;
case imemo_parser_strterm:
case imemo_tmpbuf:
case imemo_callinfo:
break;
default:
rb_bug("not reachable %d", imemo_type(obj));
break;
}
}
static enum rb_id_table_iterator_result
check_id_table_move(VALUE value, void *data)
{
@ -10754,7 +10673,7 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
break;
case T_IMEMO:
gc_ref_update_imemo(objspace, obj);
gc_mark_and_move_imemo(objspace, obj, true);
return;
case T_NIL:

44
node.c
View File

@ -86,7 +86,7 @@ rb_node_buffer_new(void)
#define ruby_xrealloc(var,size) (ast->node_buffer->config->realloc_n((void *)var, 1, size))
#define rb_gc_mark ast->node_buffer->config->gc_mark
#define rb_gc_location ast->node_buffer->config->gc_location
#define rb_gc_mark_movable ast->node_buffer->config->gc_mark_movable
#define rb_gc_mark_and_move ast->node_buffer->config->gc_mark_and_move
#undef Qnil
#define Qnil ast->node_buffer->config->qnil
#define Qtrue ast->node_buffer->config->qtrue
@ -367,7 +367,7 @@ iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, vo
}
static void
mark_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
mark_and_move_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
{
#ifdef UNIVERSAL_PARSER
bug_report_func rb_bug = ast->node_buffer->config->bug;
@ -376,53 +376,23 @@ mark_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
switch (nd_type(node)) {
case NODE_MATCH:
case NODE_LIT:
rb_gc_mark_movable(RNODE_LIT(node)->nd_lit);
rb_gc_mark_and_move(&RNODE_LIT(node)->nd_lit);
break;
default:
rb_bug("unreachable node %s", ruby_node_name(nd_type(node)));
}
}
static void
update_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
{
#ifdef UNIVERSAL_PARSER
bug_report_func rb_bug = ast->node_buffer->config->bug;
#endif
switch (nd_type(node)) {
case NODE_MATCH:
case NODE_LIT:
RNODE_LIT(node)->nd_lit = rb_gc_location(RNODE_LIT(node)->nd_lit);
break;
default:
rb_bug("unreachable");
}
}
void
rb_ast_update_references(rb_ast_t *ast)
rb_ast_mark_and_move(rb_ast_t *ast, bool reference_updating)
{
if (ast->node_buffer) {
ast->node_buffer->tokens = rb_gc_location(ast->node_buffer->tokens);
rb_gc_mark_and_move(&ast->node_buffer->tokens);
node_buffer_t *nb = ast->node_buffer;
iterate_node_values(ast, &nb->markable, update_ast_value, NULL);
iterate_node_values(ast, &nb->markable, mark_and_move_ast_value, NULL);
if (ast->body.script_lines) ast->body.script_lines = rb_gc_location(ast->body.script_lines);
}
}
void
rb_ast_mark(rb_ast_t *ast)
{
if (ast->node_buffer) {
rb_gc_mark_movable(ast->node_buffer->tokens);
node_buffer_t *nb = ast->node_buffer;
iterate_node_values(ast, &nb->markable, mark_ast_value, NULL);
if (ast->body.script_lines) rb_gc_mark_movable(ast->body.script_lines);
if (ast->body.script_lines) rb_gc_mark_and_move(&ast->body.script_lines);
}
}

2
node.h
View File

@ -62,7 +62,7 @@ void rb_ast_node_type_change(NODE *n, enum node_type type);
const char *ruby_node_name(int node);
void rb_node_init(NODE *n, enum node_type type);
void rb_ast_mark(rb_ast_t*);
void rb_ast_mark_and_move(rb_ast_t *ast, bool reference_updating);
void rb_ast_update_references(rb_ast_t*);
void rb_ast_free(rb_ast_t*);
void rb_ast_set_tokens(rb_ast_t*, VALUE);

View File

@ -640,7 +640,7 @@ static const rb_parser_config_t rb_global_parser_config = {
.gc_register_mark_object = rb_gc_register_mark_object,
.gc_guard = gc_guard,
.gc_mark = rb_gc_mark,
.gc_mark_movable = rb_gc_mark_movable,
.gc_mark_and_move = rb_gc_mark_and_move,
.gc_location = rb_gc_location,
.reg_compile = rb_reg_compile,

View File

@ -1366,7 +1366,7 @@ typedef struct rb_parser_config_struct {
void (*gc_register_mark_object)(VALUE object);
void (*gc_guard)(VALUE);
void (*gc_mark)(VALUE);
void (*gc_mark_movable)(VALUE ptr);
void (*gc_mark_and_move)(VALUE *ptr);
VALUE (*gc_location)(VALUE value);
/* Re */