3939#include "iseq.h"
4040#include "ruby/util.h"
4141#include "vm_core.h"
42+ #include "ractor_core.h"
4243#include "vm_callinfo.h"
4344#include "yjit.h"
4445#include "ruby/ractor.h"
@@ -161,6 +162,24 @@ iseq_clear_ic_references(const rb_iseq_t *iseq)
161162 }
162163}
163164
165+
166+ rb_hook_list_t *
167+ rb_iseq_local_hooks (const rb_iseq_t * iseq , rb_ractor_t * r , bool create )
168+ {
169+ rb_hook_list_t * hook_list = NULL ;
170+ st_data_t val ;
171+ if (st_lookup (rb_ractor_targeted_hooks (r ), (st_data_t )iseq , & val )) {
172+ hook_list = (rb_hook_list_t * )val ;
173+ RUBY_ASSERT (hook_list -> type == hook_list_type_targeted_iseq );
174+ }
175+ else if (create ) {
176+ hook_list = RB_ZALLOC (rb_hook_list_t );
177+ hook_list -> type = hook_list_type_targeted_iseq ;
178+ st_insert (rb_ractor_targeted_hooks (r ), (st_data_t )iseq , (st_data_t )hook_list );
179+ }
180+ return hook_list ;
181+ }
182+
164183void
165184rb_iseq_free (const rb_iseq_t * iseq )
166185{
@@ -213,10 +232,6 @@ rb_iseq_free(const rb_iseq_t *iseq)
213232 ruby_xfree (body );
214233 }
215234
216- if (iseq && ISEQ_EXECUTABLE_P (iseq ) && iseq -> aux .exec .local_hooks ) {
217- rb_hook_list_free (iseq -> aux .exec .local_hooks );
218- }
219-
220235 RUBY_FREE_LEAVE ("iseq" );
221236}
222237
@@ -448,10 +463,6 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
448463 else {
449464 /* executable */
450465 VM_ASSERT (ISEQ_EXECUTABLE_P (iseq ));
451-
452- if (iseq -> aux .exec .local_hooks ) {
453- rb_hook_list_mark_and_move (iseq -> aux .exec .local_hooks );
454- }
455466 }
456467
457468 RUBY_MARK_LEAVE ("iseq" );
@@ -2438,17 +2449,22 @@ rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
24382449 }
24392450}
24402451
2452+ static void rb_iseq_trace_flag_cleared (const rb_iseq_t * iseq , size_t pos );
2453+
24412454// Clear tracing event flags and turn off tracing for a given instruction as needed.
24422455// This is currently used after updating a one-shot line coverage for the current instruction.
24432456void
24442457rb_iseq_clear_event_flags (const rb_iseq_t * iseq , size_t pos , rb_event_flag_t reset )
24452458{
2446- struct iseq_insn_info_entry * entry = (struct iseq_insn_info_entry * )get_insn_info (iseq , pos );
2447- if (entry ) {
2448- entry -> events &= ~reset ;
2449- if (!(entry -> events & iseq -> aux .exec .global_trace_events )) {
2450- void rb_iseq_trace_flag_cleared (const rb_iseq_t * iseq , size_t pos );
2451- rb_iseq_trace_flag_cleared (iseq , pos );
2459+ RB_VM_LOCKING () {
2460+ rb_vm_barrier ();
2461+
2462+ struct iseq_insn_info_entry * entry = (struct iseq_insn_info_entry * )get_insn_info (iseq , pos );
2463+ if (entry ) {
2464+ entry -> events &= ~reset ;
2465+ if (!(entry -> events & iseq -> aux .exec .global_trace_events )) {
2466+ rb_iseq_trace_flag_cleared (iseq , pos );
2467+ }
24522468 }
24532469 }
24542470}
@@ -3930,14 +3946,15 @@ rb_vm_insn_decode(const VALUE encoded)
39303946
39313947// Turn on or off tracing for a given instruction address
39323948static inline int
3933- encoded_iseq_trace_instrument (VALUE * iseq_encoded_insn , rb_event_flag_t turnon , bool remain_current_trace )
3949+ encoded_iseq_trace_instrument (VALUE * iseq_encoded_insn , rb_event_flag_t turnon , bool remain_traced )
39343950{
3951+ ASSERT_vm_locking ();
39353952 st_data_t key = (st_data_t )* iseq_encoded_insn ;
39363953 st_data_t val ;
39373954
39383955 if (st_lookup (encoded_insn_data , key , & val )) {
39393956 insn_data_t * e = (insn_data_t * )val ;
3940- if (remain_current_trace && key == (st_data_t )e -> trace_encoded_insn ) {
3957+ if (remain_traced && key == (st_data_t )e -> trace_encoded_insn ) {
39413958 turnon = 1 ;
39423959 }
39433960 * iseq_encoded_insn = (VALUE ) (turnon ? e -> trace_encoded_insn : e -> notrace_encoded_insn );
@@ -3948,7 +3965,7 @@ encoded_iseq_trace_instrument(VALUE *iseq_encoded_insn, rb_event_flag_t turnon,
39483965}
39493966
39503967// Turn off tracing for an instruction at pos after tracing event flags are cleared
3951- void
3968+ static void
39523969rb_iseq_trace_flag_cleared (const rb_iseq_t * iseq , size_t pos )
39533970{
39543971 const struct rb_iseq_constant_body * const body = ISEQ_BODY (iseq );
@@ -3974,14 +3991,16 @@ add_bmethod_events(rb_event_flag_t events)
39743991
39753992// Note, to support call/return events for bmethods, turnon_event can have more events than tpval.
39763993static int
3977- iseq_add_local_tracepoint (const rb_iseq_t * iseq , rb_event_flag_t turnon_events , VALUE tpval , unsigned int target_line )
3994+ iseq_add_local_tracepoint (const rb_iseq_t * iseq , rb_event_flag_t turnon_events , VALUE tpval , unsigned int target_line , rb_ractor_t * r )
39783995{
39793996 unsigned int pc ;
39803997 int n = 0 ;
39813998 const struct rb_iseq_constant_body * const body = ISEQ_BODY (iseq );
39823999 VALUE * iseq_encoded = (VALUE * )body -> iseq_encoded ;
4000+ rb_iseq_t * iseq_mut = (rb_iseq_t * )iseq ;
39834001
39844002 VM_ASSERT (ISEQ_EXECUTABLE_P (iseq ));
4003+ ASSERT_vm_locking_with_barrier ();
39854004
39864005 for (pc = 0 ; pc < body -> iseq_size ;) {
39874006 const struct iseq_insn_info_entry * entry = get_insn_info (iseq , pc );
@@ -4003,11 +4022,9 @@ iseq_add_local_tracepoint(const rb_iseq_t *iseq, rb_event_flag_t turnon_events,
40034022 }
40044023
40054024 if (n > 0 ) {
4006- if (iseq -> aux .exec .local_hooks == NULL ) {
4007- ((rb_iseq_t * )iseq )-> aux .exec .local_hooks = RB_ZALLOC (rb_hook_list_t );
4008- iseq -> aux .exec .local_hooks -> is_local = true;
4009- }
4010- rb_hook_list_connect_tracepoint ((VALUE )iseq , iseq -> aux .exec .local_hooks , tpval , target_line );
4025+ rb_hook_list_t * hook_list = rb_iseq_local_hooks (iseq , r , true);
4026+ rb_hook_list_connect_local_tracepoint (hook_list , tpval , target_line );
4027+ iseq_mut -> aux .exec .local_hooks_cnt ++ ;
40114028 }
40124029
40134030 return n ;
@@ -4018,19 +4035,21 @@ struct trace_set_local_events_struct {
40184035 VALUE tpval ;
40194036 unsigned int target_line ;
40204037 int n ;
4038+ rb_ractor_t * r ;
40214039};
40224040
40234041static void
40244042iseq_add_local_tracepoint_i (const rb_iseq_t * iseq , void * p )
40254043{
40264044 struct trace_set_local_events_struct * data = (struct trace_set_local_events_struct * )p ;
4027- data -> n += iseq_add_local_tracepoint (iseq , data -> turnon_events , data -> tpval , data -> target_line );
4045+ data -> n += iseq_add_local_tracepoint (iseq , data -> turnon_events , data -> tpval , data -> target_line , data -> r );
40284046 iseq_iterate_children (iseq , iseq_add_local_tracepoint_i , p );
40294047}
40304048
40314049int
40324050rb_iseq_add_local_tracepoint_recursively (const rb_iseq_t * iseq , rb_event_flag_t turnon_events , VALUE tpval , unsigned int target_line , bool target_bmethod )
40334051{
4052+ ASSERT_vm_locking_with_barrier ();
40344053 struct trace_set_local_events_struct data ;
40354054 if (target_bmethod ) {
40364055 turnon_events = add_bmethod_events (turnon_events );
@@ -4039,35 +4058,52 @@ rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t
40394058 data .tpval = tpval ;
40404059 data .target_line = target_line ;
40414060 data .n = 0 ;
4061+ data .r = GET_RACTOR ();
40424062
40434063 iseq_add_local_tracepoint_i (iseq , (void * )& data );
4044- if (0 ) rb_funcall ( Qnil , rb_intern ( "puts" ), 1 , rb_iseq_disasm (iseq )); /* for debug */
4064+ if (0 ) fprintf ( stderr , "Iseq disasm:\n:%s" , RSTRING_PTR ( rb_iseq_disasm (iseq ) )); /* for debug */
40454065 return data .n ;
40464066}
40474067
40484068static int
4049- iseq_remove_local_tracepoint (const rb_iseq_t * iseq , VALUE tpval )
4069+ iseq_remove_local_tracepoint (const rb_iseq_t * iseq , VALUE tpval , rb_ractor_t * r )
40504070{
40514071 int n = 0 ;
4072+ unsigned int num_hooks_left ;
4073+ unsigned int pc ;
4074+ const struct rb_iseq_constant_body * body ;
4075+ rb_iseq_t * iseq_mut = (rb_iseq_t * )iseq ;
4076+ rb_hook_list_t * hook_list ;
4077+ VALUE * iseq_encoded ;
4078+ ASSERT_vm_locking_with_barrier ();
40524079
4053- if (iseq -> aux .exec .local_hooks ) {
4054- unsigned int pc ;
4055- const struct rb_iseq_constant_body * const body = ISEQ_BODY (iseq );
4056- VALUE * iseq_encoded = (VALUE * )body -> iseq_encoded ;
4080+ hook_list = rb_iseq_local_hooks (iseq , r , false);
4081+
4082+ if (hook_list ) {
40574083 rb_event_flag_t local_events = 0 ;
40584084
4059- rb_hook_list_remove_tracepoint (iseq -> aux .exec .local_hooks , tpval );
4060- local_events = iseq -> aux .exec .local_hooks -> events ;
4085+ rb_event_flag_t prev_events = hook_list -> events ;
4086+ if (rb_hook_list_remove_local_tracepoint (hook_list , tpval )) {
4087+ RUBY_ASSERT (iseq -> aux .exec .local_hooks_cnt > 0 );
4088+ iseq_mut -> aux .exec .local_hooks_cnt -- ;
4089+ local_events = hook_list -> events ; // remaining events for this ractor
4090+ num_hooks_left = rb_hook_list_count (hook_list );
4091+ if (local_events == 0 && prev_events != 0 ) {
4092+ st_delete (rb_ractor_targeted_hooks (r ), (st_data_t * )& iseq , NULL );
4093+ rb_hook_list_free (hook_list );
4094+ }
40614095
4062- if (local_events == 0 ) {
4063- rb_hook_list_free (iseq -> aux .exec .local_hooks );
4064- ((rb_iseq_t * )iseq )-> aux .exec .local_hooks = NULL ;
4065- }
4096+ if (iseq -> aux .exec .local_hooks_cnt == num_hooks_left ) {
4097+ body = ISEQ_BODY (iseq );
4098+ iseq_encoded = (VALUE * )body -> iseq_encoded ;
4099+ local_events = add_bmethod_events (local_events );
4100+ for (pc = 0 ; pc < body -> iseq_size ;) {
4101+ rb_event_flag_t pc_events = rb_iseq_event_flags (iseq , pc );
4102+ pc += encoded_iseq_trace_instrument (& iseq_encoded [pc ], pc_events & (local_events | iseq -> aux .exec .global_trace_events ), false);
4103+ }
4104+ }
40664105
4067- local_events = add_bmethod_events (local_events );
4068- for (pc = 0 ; pc < body -> iseq_size ;) {
4069- rb_event_flag_t pc_events = rb_iseq_event_flags (iseq , pc );
4070- pc += encoded_iseq_trace_instrument (& iseq_encoded [pc ], pc_events & (local_events | iseq -> aux .exec .global_trace_events ), false);
4106+ n ++ ;
40714107 }
40724108 }
40734109 return n ;
@@ -4076,22 +4112,25 @@ iseq_remove_local_tracepoint(const rb_iseq_t *iseq, VALUE tpval)
40764112struct trace_clear_local_events_struct {
40774113 VALUE tpval ;
40784114 int n ;
4115+ rb_ractor_t * r ;
40794116};
40804117
40814118static void
40824119iseq_remove_local_tracepoint_i (const rb_iseq_t * iseq , void * p )
40834120{
40844121 struct trace_clear_local_events_struct * data = (struct trace_clear_local_events_struct * )p ;
4085- data -> n += iseq_remove_local_tracepoint (iseq , data -> tpval );
4122+ data -> n += iseq_remove_local_tracepoint (iseq , data -> tpval , data -> r );
40864123 iseq_iterate_children (iseq , iseq_remove_local_tracepoint_i , p );
40874124}
40884125
40894126int
4090- rb_iseq_remove_local_tracepoint_recursively (const rb_iseq_t * iseq , VALUE tpval )
4127+ rb_iseq_remove_local_tracepoint_recursively (const rb_iseq_t * iseq , VALUE tpval , rb_ractor_t * r )
40914128{
40924129 struct trace_clear_local_events_struct data ;
4130+ ASSERT_vm_locking_with_barrier ();
40934131 data .tpval = tpval ;
40944132 data .n = 0 ;
4133+ data .r = r ;
40954134
40964135 iseq_remove_local_tracepoint_i (iseq , (void * )& data );
40974136 return data .n ;
@@ -4109,11 +4148,14 @@ rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events)
41094148 return ;
41104149 }
41114150 else {
4151+ // NOTE: this does not need VM barrier if it's a new ISEQ
41124152 unsigned int pc ;
41134153 const struct rb_iseq_constant_body * const body = ISEQ_BODY (iseq );
4154+
41144155 VALUE * iseq_encoded = (VALUE * )body -> iseq_encoded ;
41154156 rb_event_flag_t enabled_events ;
4116- rb_event_flag_t local_events = iseq -> aux .exec .local_hooks ? iseq -> aux .exec .local_hooks -> events : 0 ;
4157+ rb_hook_list_t * local_hooks = rb_iseq_local_hooks (iseq , GET_RACTOR (), false);
4158+ rb_event_flag_t local_events = local_hooks ? local_hooks -> events : 0 ;
41174159 ((rb_iseq_t * )iseq )-> aux .exec .global_trace_events = turnon_events ;
41184160 enabled_events = add_bmethod_events (turnon_events | local_events );
41194161
@@ -4129,6 +4171,7 @@ void rb_vm_cc_general(const struct rb_callcache *cc);
41294171static bool
41304172clear_attr_cc (VALUE v )
41314173{
4174+ ASSERT_vm_locking_with_barrier ();
41324175 if (imemo_type_p (v , imemo_callcache ) && vm_cc_ivar_p ((const struct rb_callcache * )v )) {
41334176 rb_vm_cc_general ((struct rb_callcache * )v );
41344177 return true;
@@ -4141,6 +4184,7 @@ clear_attr_cc(VALUE v)
41414184static bool
41424185clear_bf_cc (VALUE v )
41434186{
4187+ ASSERT_vm_locking_with_barrier ();
41444188 if (imemo_type_p (v , imemo_callcache ) && vm_cc_bf_p ((const struct rb_callcache * )v )) {
41454189 rb_vm_cc_general ((struct rb_callcache * )v );
41464190 return true;
@@ -4166,7 +4210,10 @@ clear_attr_ccs_i(void *vstart, void *vend, size_t stride, void *data)
41664210void
41674211rb_clear_attr_ccs (void )
41684212{
4169- rb_objspace_each_objects (clear_attr_ccs_i , NULL );
4213+ RB_VM_LOCKING () {
4214+ rb_vm_barrier ();
4215+ rb_objspace_each_objects (clear_attr_ccs_i , NULL );
4216+ }
41704217}
41714218
41724219static int
@@ -4185,6 +4232,7 @@ clear_bf_ccs_i(void *vstart, void *vend, size_t stride, void *data)
41854232void
41864233rb_clear_bf_ccs (void )
41874234{
4235+ ASSERT_vm_locking_with_barrier ();
41884236 rb_objspace_each_objects (clear_bf_ccs_i , NULL );
41894237}
41904238
@@ -4214,7 +4262,10 @@ trace_set_i(void *vstart, void *vend, size_t stride, void *data)
42144262void
42154263rb_iseq_trace_set_all (rb_event_flag_t turnon_events )
42164264{
4217- rb_objspace_each_objects (trace_set_i , & turnon_events );
4265+ RB_VM_LOCKING () {
4266+ rb_vm_barrier ();
4267+ rb_objspace_each_objects (trace_set_i , & turnon_events );
4268+ }
42184269}
42194270
42204271VALUE
0 commit comments