From 0511ec851cd290fac520dbe5a862b409488e159e Mon Sep 17 00:00:00 2001 From: Kunshan Wang Date: Wed, 16 Oct 2024 15:23:51 +0800 Subject: [PATCH] Unregister PPP when no longer a PPP (iseq) This commit allows the GC to detect if a registered PPP is no longer a PPP and remove it from the PPP list. Notably, iseq becomes a PPP since ISEQ_COMPILE_DATA_ALLOC, and stops being a PPP after ISEQ_COMPILE_DATA_CLEAR. --- gc/default.c | 2 +- hash.c | 8 +++--- internal/mmtk.h | 1 + internal/mmtk_support.h | 3 ++- iseq.c | 17 ++++++++++++ iseq.h | 9 +++++++ mmtk_support.c | 57 +++++++++++++++++++++++++++++++++++------ 7 files changed, 83 insertions(+), 14 deletions(-) diff --git a/gc/default.c b/gc/default.c index 8cbd057ab5190e..532fd170e9eb17 100644 --- a/gc/default.c +++ b/gc/default.c @@ -2269,7 +2269,7 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace, #if USE_MMTK if (rb_mmtk_enabled_p()) { rb_mmtk_maybe_register_obj_free_candidate(obj); - rb_mmtk_maybe_register_ppp(obj); + rb_mmtk_maybe_register_initial_ppp(obj); } #endif diff --git a/hash.c b/hash.c index daf7ea09653d91..51c92a3143179c 100644 --- a/hash.c +++ b/hash.c @@ -54,7 +54,7 @@ #include "internal/mmtk_macros.h" #if USE_MMTK -#include "internal/mmtk.h" // For mmtk_register_ppp +#include "internal/mmtk_support.h" // For rb_mmtk_register_ppp #endif /* Flags of RHash @@ -4458,7 +4458,7 @@ rb_hash_compare_by_id(VALUE hash) #if USE_MMTK if (rb_mmtk_enabled_p()) { - mmtk_register_ppp((MMTk_ObjectReference)hash); + rb_mmtk_register_ppp(hash); } #endif @@ -4486,7 +4486,7 @@ rb_ident_hash_new(void) #if USE_MMTK if (rb_mmtk_enabled_p()) { - mmtk_register_ppp((MMTk_ObjectReference)hash); + rb_mmtk_register_ppp(hash); } #endif @@ -4501,7 +4501,7 @@ rb_ident_hash_new_with_size(st_index_t size) #if USE_MMTK if (rb_mmtk_enabled_p()) { - mmtk_register_ppp((MMTk_ObjectReference)hash); + rb_mmtk_register_ppp(hash); } #endif diff --git a/internal/mmtk.h b/internal/mmtk.h index 1f58042365d5d1..8f1e02d5150123 100644 --- a/internal/mmtk.h +++ b/internal/mmtk.h @@ -78,6 +78,7 @@ typedef struct MMTk_RubyUpcalls { void (*scan_final_jobs_roots)(void); void (*scan_roots_in_mutator_thread)(MMTk_VMMutatorThread mutator_tls, MMTk_VMWorkerThread worker_tls); + bool (*is_no_longer_ppp)(MMTk_ObjectReference); void (*scan_object_ruby_style)(MMTk_ObjectReference object); void (*call_gc_mark_children)(MMTk_ObjectReference object); void (*call_obj_free)(MMTk_ObjectReference object); diff --git a/internal/mmtk_support.h b/internal/mmtk_support.h index b698b80fbcb108..2a5a6afb0147ae 100644 --- a/internal/mmtk_support.h +++ b/internal/mmtk_support.h @@ -68,7 +68,8 @@ bool rb_mmtk_object_moved_p(VALUE obj); VALUE rb_mmtk_maybe_forward(VALUE object); // PPP support -void rb_mmtk_maybe_register_ppp(VALUE obj); +void rb_mmtk_register_ppp(VALUE obj); +void rb_mmtk_maybe_register_initial_ppp(VALUE obj); // Finalization and exiting void rb_mmtk_maybe_register_obj_free_candidate(VALUE obj); diff --git a/iseq.c b/iseq.c index 282371f84a8e50..c81d9b467e4889 100644 --- a/iseq.c +++ b/iseq.c @@ -45,6 +45,9 @@ #include "insns.inc" #include "insns_info.inc" +// Conditional compilation macros for MMTk. +#include "internal/mmtk_macros.h" + VALUE rb_cISeq; static VALUE iseqw_new(const rb_iseq_t *iseq); static const rb_iseq_t *iseqw_check(VALUE iseqw); @@ -440,6 +443,20 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating) RUBY_MARK_LEAVE("iseq"); } +#if USE_MMTK +void rb_mmtk_iseq_register_ppp(rb_iseq_t *iseq) +{ + WHEN_USING_MMTK({ + rb_mmtk_register_ppp((VALUE)iseq); + }) +} + +bool rb_mmtk_iseq_is_no_longer_ppp(rb_iseq_t *iseq) +{ + return !FL_TEST_RAW((VALUE)iseq, ISEQ_USE_COMPILE_DATA); +} +#endif + static size_t param_keyword_size(const struct rb_iseq_param_keyword *pkw) { diff --git a/iseq.h b/iseq.h index a0b59c441f6a8c..c33b4c4c35446f 100644 --- a/iseq.h +++ b/iseq.h @@ -136,6 +136,11 @@ struct iseq_compile_data { #endif }; +#if USE_MMTK +void rb_mmtk_iseq_register_ppp(rb_iseq_t *iseq); +bool rb_mmtk_iseq_is_no_longer_ppp(rb_iseq_t *iseq); +#endif + static inline struct iseq_compile_data * ISEQ_COMPILE_DATA(const rb_iseq_t *iseq) { @@ -152,6 +157,10 @@ ISEQ_COMPILE_DATA_ALLOC(rb_iseq_t *iseq) { iseq->aux.compile_data = ZALLOC(struct iseq_compile_data); iseq->flags |= ISEQ_USE_COMPILE_DATA; + +#if USE_MMTK + rb_mmtk_iseq_register_ppp(iseq); +#endif } static inline void diff --git a/mmtk_support.c b/mmtk_support.c index e060f078909be1..1c4e9193f63327 100644 --- a/mmtk_support.c +++ b/mmtk_support.c @@ -6,6 +6,7 @@ #include "internal/imemo.h" #include "internal/thread.h" #include "internal/variable.h" +#include "iseq.h" #include "ruby/ruby.h" #include "ractor_core.h" #include "vm_core.h" @@ -633,8 +634,13 @@ rb_mmtk_maybe_forward(VALUE value) // PPP support //////////////////////////////////////////////////////////////////////////////// +// Return true if an object is a PPP when allocated. +// This does not include PPP types that may become PPPs during its lifetime, such as +// - Hash (when starting to compare keys by identity) +// - iseq (since ISEQ_COMPILE_DATA_ALLOC) static bool -rb_mmtk_is_ppp(VALUE obj) { +rb_mmtk_is_initially_ppp(VALUE obj) +{ RUBY_ASSERT(!rb_special_const_p(obj)); switch (RB_BUILTIN_TYPE(obj)) { @@ -642,7 +648,6 @@ rb_mmtk_is_ppp(VALUE obj) { return true; case T_IMEMO: switch (imemo_type(obj)) { - case imemo_iseq: case imemo_tmpbuf: case imemo_ast: case imemo_ifunc: @@ -657,6 +662,32 @@ rb_mmtk_is_ppp(VALUE obj) { } } +// Return true if a registered PPP is no longer a PPP. Return false otherwise. +// The return value doesn't matter for objects that are not registered as PPP. +static bool +rb_mmtk_is_no_longer_ppp(MMTk_ObjectReference objref) +{ + VALUE obj = (VALUE)objref; + RUBY_ASSERT(!rb_special_const_p(obj)); + + switch (RB_BUILTIN_TYPE(obj)) { + case T_IMEMO: + switch (imemo_type(obj)) { + case imemo_iseq: { + if (rb_mmtk_iseq_is_no_longer_ppp((rb_iseq_t*)obj)) { + return true; + } + } + default: + break; + } + default: + break; + } + + return false; +} + static void rb_mmtk_flush_ppp_buffer(struct rb_mmtk_values_buffer *buffer) { @@ -666,14 +697,23 @@ rb_mmtk_flush_ppp_buffer(struct rb_mmtk_values_buffer *buffer) } void -rb_mmtk_maybe_register_ppp(VALUE obj) { +rb_mmtk_register_ppp(VALUE obj) +{ RUBY_ASSERT(!rb_special_const_p(obj)); - if (rb_mmtk_is_ppp(obj)) { - struct rb_mmtk_values_buffer *buffer = &rb_mmtk_mutator_local.ppp_buffer; - if (rb_mmtk_values_buffer_append(buffer, obj)) { - rb_mmtk_flush_ppp_buffer(buffer); - } + struct rb_mmtk_values_buffer *buffer = &rb_mmtk_mutator_local.ppp_buffer; + if (rb_mmtk_values_buffer_append(buffer, obj)) { + rb_mmtk_flush_ppp_buffer(buffer); + } +} + +void +rb_mmtk_maybe_register_initial_ppp(VALUE obj) +{ + RUBY_ASSERT(!rb_special_const_p(obj)); + + if (rb_mmtk_is_initially_ppp(obj)) { + rb_mmtk_register_ppp(obj); } } @@ -1661,6 +1701,7 @@ MMTk_RubyUpcalls ruby_upcalls = { rb_mmtk_scan_misc_roots, rb_mmtk_scan_final_jobs_roots, rb_mmtk_scan_roots_in_mutator_thread, + rb_mmtk_is_no_longer_ppp, rb_mmtk_scan_object_ruby_style, rb_mmtk_call_gc_mark_children, rb_mmtk_call_obj_free,