@@ -587,32 +587,6 @@ rb_invalidate_method_caches(struct rb_id_table *cm_tbl, VALUE cc_tbl)
587587 }
588588}
589589
590- static int
591- invalidate_cc_refinement (st_data_t key , st_data_t data )
592- {
593- VALUE v = (VALUE )key ;
594- void * ptr = rb_asan_poisoned_object_p (v );
595- rb_asan_unpoison_object (v , false);
596-
597- if (rb_gc_pointer_to_heap_p (v ) &&
598- !rb_objspace_garbage_object_p (v ) &&
599- RBASIC (v )-> flags ) { // liveness check
600- const struct rb_callcache * cc = (const struct rb_callcache * )v ;
601-
602- VM_ASSERT (vm_cc_refinement_p (cc ));
603-
604- if (vm_cc_valid (cc )) {
605- vm_cc_invalidate (cc );
606- }
607- }
608-
609- if (ptr ) {
610- rb_asan_poison_object (v );
611- }
612-
613- return ST_CONTINUE ;
614- }
615-
616590static st_index_t
617591vm_ci_hash (VALUE v )
618592{
@@ -722,28 +696,94 @@ rb_vm_ci_free(const struct rb_callinfo *ci)
722696 st_delete (vm -> ci_table , & key , NULL );
723697}
724698
725- void
726- rb_vm_insert_cc_refinement (const struct rb_callcache * cc )
699+ struct cc_refinement_entries {
700+ VALUE * entries ;
701+ size_t len ;
702+ size_t capa ;
703+ };
704+
705+ static void
706+ cc_refinement_set_free (void * ptr )
727707{
728- st_data_t key = (st_data_t )cc ;
708+ struct cc_refinement_entries * e = ptr ;
709+ xfree (e -> entries );
710+ }
729711
730- rb_vm_t * vm = GET_VM ();
731- RB_VM_LOCK_ENTER ();
732- {
733- rb_set_insert (vm -> cc_refinement_table , key );
712+ static size_t
713+ cc_refinement_set_memsize (const void * ptr )
714+ {
715+ const struct cc_refinement_entries * e = ptr ;
716+ return e -> capa * sizeof (VALUE );
717+ }
718+
719+ static void
720+ cc_refinement_set_compact (void * ptr )
721+ {
722+ struct cc_refinement_entries * e = ptr ;
723+ for (size_t i = 0 ; i < e -> len ; i ++ ) {
724+ e -> entries [i ] = rb_gc_location (e -> entries [i ]);
734725 }
735- RB_VM_LOCK_LEAVE ();
736726}
737727
738- void
739- rb_vm_delete_cc_refinement ( const struct rb_callcache * cc )
728+ static void
729+ cc_refinement_set_handle_weak_references ( void * ptr )
740730{
741- ASSERT_vm_locking ();
731+ struct cc_refinement_entries * e = ptr ;
732+ size_t write = 0 ;
733+ for (size_t read = 0 ; read < e -> len ; read ++ ) {
734+ if (rb_gc_handle_weak_references_alive_p (e -> entries [read ])) {
735+ e -> entries [write ++ ] = e -> entries [read ];
736+ }
737+ }
738+ e -> len = write ;
739+ }
740+
741+ static const rb_data_type_t cc_refinement_set_type = {
742+ "VM/cc_refinement_set" ,
743+ {
744+ NULL ,
745+ cc_refinement_set_free ,
746+ cc_refinement_set_memsize ,
747+ cc_refinement_set_compact ,
748+ cc_refinement_set_handle_weak_references ,
749+ },
750+ 0 , 0 , RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
751+ };
752+
753+ VALUE
754+ rb_cc_refinement_set_create (void )
755+ {
756+ struct cc_refinement_entries * e ;
757+ VALUE obj = TypedData_Make_Struct (0 , struct cc_refinement_entries , & cc_refinement_set_type , e );
758+
759+ e -> entries = NULL ;
760+ e -> len = 0 ;
761+ e -> capa = 0 ;
762+
763+ rb_gc_declare_weak_references (obj );
764+
765+ return obj ;
766+ }
742767
768+ void
769+ rb_vm_insert_cc_refinement (const struct rb_callcache * cc )
770+ {
743771 rb_vm_t * vm = GET_VM ();
744- st_data_t key = (st_data_t )cc ;
772+ RB_VM_LOCK_ENTER ();
773+ {
774+ struct cc_refinement_entries * e = RTYPEDDATA_GET_DATA (vm -> cc_refinement_set );
775+ if (e -> len == e -> capa ) {
776+ size_t new_capa = e -> capa == 0 ? 16 : e -> capa * 2 ;
777+ SIZED_REALLOC_N (e -> entries , VALUE , new_capa , e -> capa );
778+ e -> capa = new_capa ;
779+ }
780+ e -> entries [e -> len ++ ] = (VALUE )cc ;
745781
746- rb_set_table_delete (vm -> cc_refinement_table , & key );
782+ // We never mark the cc, but we need to issue a writebarrier so that
783+ // the refinement set can be added to the remembered set
784+ RB_OBJ_WRITTEN (vm -> cc_refinement_set , Qundef , (VALUE )cc );
785+ }
786+ RB_VM_LOCK_LEAVE ();
747787}
748788
749789void
@@ -753,9 +793,23 @@ rb_clear_all_refinement_method_cache(void)
753793
754794 RB_VM_LOCK_ENTER ();
755795 {
756- rb_set_table_foreach (vm -> cc_refinement_table , invalidate_cc_refinement , (st_data_t )NULL );
757- rb_set_table_clear (vm -> cc_refinement_table );
758- rb_set_compact_table (vm -> cc_refinement_table );
796+ struct cc_refinement_entries * e = RTYPEDDATA_GET_DATA (vm -> cc_refinement_set );
797+ for (size_t i = 0 ; i < e -> len ; i ++ ) {
798+ VALUE v = e -> entries [i ];
799+
800+ // All objects should be live as weak references are pruned in
801+ // cc_refinement_set_handle_weak_references
802+ VM_ASSERT (rb_gc_pointer_to_heap_p (v ));
803+ VM_ASSERT (!rb_objspace_garbage_object_p (v ));
804+
805+ const struct rb_callcache * cc = (const struct rb_callcache * )v ;
806+ VM_ASSERT (vm_cc_refinement_p (cc ));
807+
808+ if (vm_cc_valid (cc )) {
809+ vm_cc_invalidate (cc );
810+ }
811+ }
812+ e -> len = 0 ;
759813 }
760814 RB_VM_LOCK_LEAVE ();
761815
0 commit comments