diff --git a/gc.c b/gc.c index 4105a0032e1411..d27919242728ab 100644 --- a/gc.c +++ b/gc.c @@ -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: diff --git a/node.c b/node.c index 2114fbaee5e73b..8c579cc2720179 100644 --- a/node.c +++ b/node.c @@ -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) -{ - if (ast->node_buffer) { - ast->node_buffer->tokens = rb_gc_location(ast->node_buffer->tokens); - - node_buffer_t *nb = ast->node_buffer; - iterate_node_values(ast, &nb->markable, update_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) +rb_ast_mark_and_move(rb_ast_t *ast, bool reference_updating) { if (ast->node_buffer) { - rb_gc_mark_movable(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, mark_ast_value, NULL); + iterate_node_values(ast, &nb->markable, mark_and_move_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); } } diff --git a/node.h b/node.h index 15233c9bc09b97..2e8868428aece1 100644 --- a/node.h +++ b/node.h @@ -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); diff --git a/ruby_parser.c b/ruby_parser.c index 74e02996b8d550..c4e37e3353dedb 100644 --- a/ruby_parser.c +++ b/ruby_parser.c @@ -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, diff --git a/rubyparser.h b/rubyparser.h index b07ccc06e15f1a..f3bd76d2ebc123 100644 --- a/rubyparser.h +++ b/rubyparser.h @@ -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 */