If an object calls rb_gc_mark on a field, it pins the child. Such objects are potential pinning parents that must be handled specially. Reducing such objects can reduce the overhead it imposes on copying GC.
This issue keeps a list of built-in types that are PPPs, and why they pin their children.
Some object can pin its children
T_DATA: Some third-party libraries were written before Ruby introduced moving GC.
T_IMEMO
[ ] imemo_ifunc:
gc_mark_maybe(RANY(obj)->as.imemo.ifunc.data) type: VALUE
ifunc represents a "block written in C",
and data is the "extra argument" passed to the block in addition to the yielded data.
I guess because the ifunc is written in C,
the data can be anything (as long as the C func recognizes),
even though it is supposed to be a VALUE which holds a Ruby value.
It could be a compromise due to frequent misuse.
[ ] imemo_memo:
gc_mark_maybe(RANY(obj)->as.imemo.memo.u3.value)
It looks like a generic "memo" type. The u3 field is an untagged union that can be anything.
It is part of a union, but rb_strterm_mark already tested the tag.
[ ] T_HASH: If Hash#compare_by_identity is called, it will pin_key_mark_value.
compare_by_identity: Sets self to consider only identity in comparing keys;
two keys are considered the same only if they are the same object; returns self.
Cannot be undone. Good candidate for using remembered set.
Can be made non-PPP by introducing address-based hashing.
If an object calls
rb_gc_mark
on a field, it pins the child. Such objects are potential pinning parents that must be handled specially. Reducing such objects can reduce the overhead it imposes on copying GC.Related higher-level issues are:
This issue keeps a list of built-in types that are PPPs, and why they pin their children.
Some object can pin its children
T_DATA
: Some third-party libraries were written before Ruby introduced moving GC.T_IMEMO
imemo_ifunc
:gc_mark_maybe(RANY(obj)->as.imemo.ifunc.data)
type:VALUE
ifunc
represents a "block written in C", anddata
is the "extra argument" passed to the block in addition to the yielded data.data
can be anything (as long as the C func recognizes), even though it is supposed to be aVALUE
which holds a Ruby value. It could be a compromise due to frequent misuse.imemo_memo
:gc_mark_maybe(RANY(obj)->as.imemo.memo.u3.value)
u3
field is an untagged union that can be anything.imemo_iseq
(No longer PPP since https://github.com/ruby/ruby/pull/7156):aux
membersrb_gc_mark(iseq->aux.loader.obj)
rb_gc_mark(compile_data->catch_table_ary)
rb_hook_list_mark(iseq->aux.exec.local_hooks)
which callsrb_gc_mark(hook->data)
for each hook.rb_iseq_mark_insn_storage(compile_data->insn.storage_head)
which callsrb_gc_mark(op)
iseq->aux
) Other union variants do not hold reference at the same offset, so it has to be conservative.rb_iseq_mark
is testing the union tags!mjit_mark_cc_entries(body)
imemo_tmpbuf
:rb_gc_mark_locations
on all offsets.ALLOCV
. I think it has to be PPP because of it conservative nature.imemo_ast
:rb_gc_mark(ast->node_buffer->mark_hash)
rb_gc_mark(ast->body.compile_option)
rb_gc_mark(ast->body.script_lines)
rb_ast_update_references
only callsupdate_ast_value
on eachNODE
, but not the three fields above.imemo_parser_strterm
:rb_gc_mark(heredoc->lastline)
rb_strterm_mark
already tested the tag.T_HASH
: IfHash#compare_by_identity
is called, it willpin_key_mark_value
.compare_by_identity
: Sets self to consider only identity in comparing keys; two keys are considered the same only if they are the same object; returns self.T_OBJECT
gc_mark_children
-> (if EXIVAR)rb_mark_generic_ivar
->gen_ivtbl_mark
->rb_gc_mark
generic_iv_tbl_
: (in variable.c) a globalst_table
mapping obj togen_ivtable
.