diff options
Diffstat (limited to 'vm_core.h')
| -rw-r--r-- | vm_core.h | 302 |
1 files changed, 219 insertions, 83 deletions
@@ -118,7 +118,7 @@ extern int ruby_assert_critical_section_entered; #include "internal.h" #include "internal/array.h" #include "internal/basic_operators.h" -#include "internal/namespace.h" +#include "internal/box.h" #include "internal/sanitizers.h" #include "internal/serial.h" #include "internal/set_table.h" @@ -261,10 +261,8 @@ union ic_serial_entry { struct iseq_inline_constant_cache_entry { VALUE flags; - VALUE value; // v0 - VALUE _unused1; // v1 - VALUE _unused2; // v2 - const rb_cref_t *ic_cref; // v3 + VALUE value; + const rb_cref_t *ic_cref; }; STATIC_ASSERT(sizeof_iseq_inline_constant_cache_entry, (offsetof(struct iseq_inline_constant_cache_entry, ic_cref) + @@ -288,7 +286,7 @@ struct iseq_inline_constant_cache { }; struct iseq_inline_iv_cache_entry { - uint64_t value; // dest_shape_id in former half, attr_index in latter half + uint64_t value; // Either rb_setivar_cache or rb_getivar_cache packed in a uint64_t. ID iv_set_name; }; @@ -313,23 +311,30 @@ struct rb_calling_info { int argc; bool kw_splat; VALUE heap_argv; - const rb_namespace_t *proc_ns; }; #ifndef VM_ARGC_STACK_MAX #define VM_ARGC_STACK_MAX 128 #endif +#define VM_KW_SPECIFIED_BITS_MAX (32-1) /* TODO: 32 -> Fixnum's max bits */ + # define CALLING_ARGC(calling) ((calling)->heap_argv ? RARRAY_LENINT((calling)->heap_argv) : (calling)->argc) struct rb_execution_context_struct; -#if 1 -#define CoreDataFromValue(obj, type) (type*)DATA_PTR(obj) +#ifndef RUBY_CORE_DATA_TYPE_CHECK +# if RUBY_DEBUG +# define RUBY_CORE_DATA_TYPE_CHECK 1 +# else +# define RUBY_CORE_DATA_TYPE_CHECK 0 +# endif +#endif +#if !RUBY_CORE_DATA_TYPE_CHECK +#define GetCoreDataFromValue(obj, type, data_type, ptr) ((ptr) = (type*)RTYPEDDATA_GET_DATA(obj)) #else -#define CoreDataFromValue(obj, type) (type*)rb_data_object_get(obj) +#define GetCoreDataFromValue(obj, type, data_type, ptr) TypedData_Get_Struct(obj, type, data_type, ptr) #endif -#define GetCoreDataFromValue(obj, type, ptr) ((ptr) = CoreDataFromValue((obj), type)) typedef struct rb_iseq_location_struct { VALUE pathobj; /* String (path) or Array [path, realpath]. Frozen. */ @@ -398,9 +403,12 @@ enum rb_builtin_attr { BUILTIN_ATTR_INLINE_BLOCK = 0x04, // The iseq acts like a C method in backtraces. BUILTIN_ATTR_C_TRACE = 0x08, + // The iseq uses noint branch/jump opcodes that skip interrupt checking. + BUILTIN_ATTR_WITHOUT_INTERRUPTS = 0x10, }; typedef VALUE (*rb_jit_func_t)(struct rb_execution_context_struct *, struct rb_control_frame_struct *); +typedef VALUE (*rb_zjit_func_t)(struct rb_execution_context_struct *, struct rb_control_frame_struct *, rb_jit_func_t); struct rb_iseq_constant_body { enum rb_iseq_type type; @@ -431,7 +439,7 @@ struct rb_iseq_constant_body { * size = M+N+O+(*1)+K+(&1)+(**1) // parameter size. */ - struct { + struct rb_iseq_parameters { struct { unsigned int has_lead : 1; unsigned int has_opt : 1; @@ -448,6 +456,7 @@ struct rb_iseq_constant_body { unsigned int anon_kwrest: 1; unsigned int use_block: 1; unsigned int forwardable: 1; + unsigned int accepts_no_block: 1; } flags; unsigned int size; @@ -498,6 +507,12 @@ struct rb_iseq_constant_body { const ID *local_table; /* must free */ + enum lvar_state { + lvar_uninitialized, + lvar_initialized, + lvar_reassigned, + } *lvar_states; + /* catch table */ struct iseq_catch_table *catch_table; @@ -578,7 +593,7 @@ struct rb_iseq_struct { } loader; struct { - struct rb_hook_list_struct *local_hooks; + unsigned int local_hooks_cnt; rb_event_flag_t global_trace_events; } exec; } aux; @@ -629,8 +644,10 @@ enum ruby_special_exceptions { ruby_special_error_count }; +extern const rb_data_type_t ruby_vm_data_type; + #define GetVMPtr(obj, ptr) \ - GetCoreDataFromValue((obj), rb_vm_t, (ptr)) + GetCoreDataFromValue((obj), rb_vm_t, &ruby_vm_data_type, (ptr)) struct rb_vm_struct; typedef void rb_vm_at_exit_func(struct rb_vm_struct*); @@ -644,23 +661,24 @@ void *rb_objspace_alloc(void); void rb_objspace_free(void *objspace); void rb_objspace_call_finalizer(void); +enum rb_hook_list_type { + hook_list_type_ractor_local, + hook_list_type_targeted_iseq, + hook_list_type_targeted_def, // C function + hook_list_type_global +}; + typedef struct rb_hook_list_struct { struct rb_event_hook_struct *hooks; rb_event_flag_t events; unsigned int running; + enum rb_hook_list_type type; bool need_clean; - bool is_local; } rb_hook_list_t; - // see builtin.h for definition typedef const struct rb_builtin_function *RB_BUILTIN; -struct global_object_list { - VALUE *varptr; - struct global_object_list *next; -}; - typedef struct rb_vm_struct { VALUE self; @@ -747,35 +765,28 @@ typedef struct rb_vm_struct { /* object management */ VALUE mark_object_ary; - struct global_object_list *global_object_list; + VALUE **global_object_list; + size_t global_object_list_size; + size_t global_object_list_capa; const VALUE special_exceptions[ruby_special_error_count]; - /* namespace */ - rb_namespace_t *main_namespace; + /* Ruby Box */ + rb_box_t *master_box; + rb_box_t *root_box; + rb_box_t *main_box; /* load */ - VALUE top_self; - VALUE load_path; - VALUE load_path_snapshot; - VALUE load_path_check_cache; - VALUE expanded_load_path; - VALUE loaded_features; - VALUE loaded_features_snapshot; - VALUE loaded_features_realpaths; - VALUE loaded_features_realpath_map; - struct st_table *loaded_features_index; - struct st_table *loading_table; // For running the init function of statically linked // extensions when they are loaded - struct st_table *static_ext_inits; + struct st_table static_ext_inits; /* signal */ struct { VALUE cmd[RUBY_NSIG]; } trap_list; - /* postponed_job (async-signal-safe, and thread-safe) */ - struct rb_postponed_job_queue *postponed_job_queue; + /* hook (for internal events: NEWOBJ, FREEOBJ, GC events, etc.) */ + rb_hook_list_t global_hooks; int src_encoding_index; @@ -799,23 +810,24 @@ typedef struct rb_vm_struct { const struct rb_builtin_function *builtin_function_table; - st_table *ci_table; - struct rb_id_table *negative_cme_table; - st_table *overloaded_cme_table; // cme -> overloaded_cme - set_table *unused_block_warning_table; - set_table *cc_refinement_table; + st_table ci_table; + struct rb_id_table negative_cme_table; + st_table overloaded_cme_table; // cme -> overloaded_cme + set_table unused_block_warning_table; + VALUE cc_refinement_set; // This id table contains a mapping from ID to ICs. It does this with ID // keys and nested st_tables as values. The nested tables have ICs as keys // and Qtrue as values. It is used when inline constant caches need to be // invalidated or ISEQs are being freed. - struct rb_id_table *constant_cache; + struct rb_id_table constant_cache; ID inserting_constant_cache_id; #ifndef VM_GLOBAL_CC_CACHE_TABLE_SIZE #define VM_GLOBAL_CC_CACHE_TABLE_SIZE 1023 #endif const struct rb_callcache *global_cc_cache_table[VM_GLOBAL_CC_CACHE_TABLE_SIZE]; // vm_eval.c + bool global_cc_cache_table_used; // vm_eval.c #if defined(USE_VM_CLOCK) && USE_VM_CLOCK uint32_t clock; @@ -828,11 +840,10 @@ typedef struct rb_vm_struct { size_t fiber_vm_stack_size; size_t fiber_machine_stack_size; } default_params; - - // TODO: a single require_stack can't support multi-threaded require trees - VALUE require_stack; } rb_vm_t; +extern bool ruby_vm_during_cleanup; + /* default values */ #define RUBY_VM_SIZE_ALIGN 4096 @@ -851,7 +862,7 @@ typedef struct rb_vm_struct { #define RUBY_VM_FIBER_MACHINE_STACK_SIZE_MIN ( 16 * 1024 * sizeof(VALUE)) /* 64 KB or 128 KB */ #endif -#if __has_feature(memory_sanitizer) || __has_feature(address_sanitizer) +#if __has_feature(memory_sanitizer) || __has_feature(address_sanitizer) || __has_feature(leak_sanitizer) /* It seems sanitizers consume A LOT of machine stacks */ #undef RUBY_VM_THREAD_MACHINE_STACK_SIZE #define RUBY_VM_THREAD_MACHINE_STACK_SIZE (1024 * 1024 * sizeof(VALUE)) @@ -907,7 +918,7 @@ struct rb_block { typedef struct rb_control_frame_struct { const VALUE *pc; // cfp[0] VALUE *sp; // cfp[1] - const rb_iseq_t *iseq; // cfp[2] + const rb_iseq_t *_iseq; // cfp[2] -- use CFP_ISEQ(cfp) to read VALUE self; // cfp[3] / block[0] const VALUE *ep; // cfp[4] / block[1] const void *block_code; // cfp[5] / block[2] -- iseq, ifunc, or forwarded block handler @@ -1004,6 +1015,10 @@ struct rb_vm_tag { struct rb_vm_tag *prev; enum ruby_tag_type state; unsigned int lock_rec; +#if USE_ZJIT + // ec->cfp as of EC_PUSH_TAG, which is saved for materializing JITFrame. + rb_control_frame_t *cfp; +#endif }; STATIC_ASSERT(rb_vm_tag_buf_offset, offsetof(struct rb_vm_tag, buf) > 0); @@ -1014,6 +1029,7 @@ STATIC_ASSERT(rb_vm_tag_buf_end, struct rb_unblock_callback { rb_unblock_function_t *func; void *arg; + rb_atomic_t event_serial; }; struct rb_mutex_struct; @@ -1043,6 +1059,8 @@ struct rb_execution_context_struct { rb_fiber_t *fiber_ptr; struct rb_thread_struct *thread_ptr; + rb_serial_t serial; + rb_serial_t ractor_id; /* storage (ec (fiber) local) */ struct rb_id_table *local_storage; @@ -1109,6 +1127,10 @@ void rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t // @param ec the execution context to update. void rb_ec_clear_vm_stack(rb_execution_context_t *ec); +// Close an execution context and free related resources that are no longer needed. +// @param ec the execution context to close. +void rb_ec_close(rb_execution_context_t *ec); + struct rb_ext_config { bool ractor_safe; }; @@ -1137,14 +1159,12 @@ typedef struct rb_thread_struct { /* for load(true) */ VALUE top_self; VALUE top_wrapper; - /* for namespace */ - VALUE namespaces; // Stack of namespaces - rb_namespace_t *ns; // The current one /* thread control */ BITFIELD(enum rb_thread_status, status, 2); /* bit flags */ + unsigned int main_thread : 1; unsigned int has_dedicated_nt : 1; unsigned int to_kill : 1; unsigned int abort_on_exception: 1; @@ -1225,9 +1245,12 @@ typedef enum { #define VM_DEFINECLASS_TYPE(x) ((rb_vm_defineclass_type_t)(x) & VM_DEFINECLASS_TYPE_MASK) #define VM_DEFINECLASS_FLAG_SCOPED 0x08 #define VM_DEFINECLASS_FLAG_HAS_SUPERCLASS 0x10 +#define VM_DEFINECLASS_FLAG_DYNAMIC_CREF 0x20 #define VM_DEFINECLASS_SCOPED_P(x) ((x) & VM_DEFINECLASS_FLAG_SCOPED) #define VM_DEFINECLASS_HAS_SUPERCLASS_P(x) \ ((x) & VM_DEFINECLASS_FLAG_HAS_SUPERCLASS) +#define VM_DEFINECLASS_DYNAMIC_CREF_P(x) \ + ((x) & VM_DEFINECLASS_FLAG_DYNAMIC_CREF) /* iseq.c */ RUBY_SYMBOL_EXPORT_BEGIN @@ -1274,12 +1297,13 @@ RUBY_EXTERN VALUE rb_mRubyVMFrozenCore; RUBY_EXTERN VALUE rb_block_param_proxy; RUBY_SYMBOL_EXPORT_END +extern const rb_data_type_t ruby_proc_data_type; + #define GetProcPtr(obj, ptr) \ - GetCoreDataFromValue((obj), rb_proc_t, (ptr)) + GetCoreDataFromValue((obj), rb_proc_t, &ruby_proc_data_type, (ptr)) typedef struct { const struct rb_block block; - const rb_namespace_t *ns; unsigned int is_from_method: 1; /* bool */ unsigned int is_lambda: 1; /* bool */ unsigned int is_isolated: 1; /* bool */ @@ -1287,8 +1311,8 @@ typedef struct { RUBY_SYMBOL_EXPORT_BEGIN VALUE rb_proc_isolate(VALUE self); -VALUE rb_proc_isolate_bang(VALUE self); -VALUE rb_proc_ractor_make_shareable(VALUE self); +VALUE rb_proc_isolate_bang(VALUE self, VALUE replace_self); +VALUE rb_proc_ractor_make_shareable(VALUE proc, VALUE replace_self); RUBY_SYMBOL_EXPORT_END typedef struct { @@ -1302,7 +1326,7 @@ typedef struct { extern const rb_data_type_t ruby_binding_data_type; #define GetBindingPtr(obj, ptr) \ - GetCoreDataFromValue((obj), rb_binding_t, (ptr)) + GetCoreDataFromValue((obj), rb_binding_t, &ruby_binding_data_type, (ptr)) typedef struct { const struct rb_block block; @@ -1371,11 +1395,11 @@ typedef rb_control_frame_t * enum vm_frame_env_flags { /* Frame/Environment flag bits: - * MMMM MMMM MMMM MMMM __FF FFFF FFFE EEEX (LSB) + * MMMM MMMM MMMM MMMM ___F FFFF FFFE EEEX (LSB) * * X : tag for GC marking (It seems as Fixnum) * EEE : 4 bits Env flags - * FF..: 9 bits Frame flags + * FF..: 8 bits Frame flags * MM..: 15 bits frame magic (to check frame corruption) */ @@ -1398,10 +1422,9 @@ enum vm_frame_env_flags { VM_FRAME_FLAG_CFRAME = 0x0080, VM_FRAME_FLAG_LAMBDA = 0x0100, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = 0x0200, - VM_FRAME_FLAG_CFRAME_KW = 0x0400, - VM_FRAME_FLAG_PASSED = 0x0800, - VM_FRAME_FLAG_NS_SWITCH = 0x1000, - VM_FRAME_FLAG_LOAD_ISEQ = 0x2000, + VM_FRAME_FLAG_CFRAME_KW = 0x0400, + VM_FRAME_FLAG_PASSED = 0x0800, + VM_FRAME_FLAG_BOX_REQUIRE = 0x1000, /* env flag */ VM_ENV_FLAG_LOCAL = 0x0002, @@ -1446,11 +1469,30 @@ VM_ENV_FLAGS(const VALUE *ep, long flag) } static inline unsigned long +VM_ENV_FLAGS_UNCHECKED(const VALUE *ep, long flag) +{ + VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS]; + return flags & flag; +} + +static inline unsigned long +VM_ENV_FRAME_TYPE_P(const VALUE *ep, unsigned long frame_type) +{ + return VM_ENV_FLAGS(ep, VM_FRAME_MAGIC_MASK) == frame_type; +} + +static inline unsigned long VM_FRAME_TYPE(const rb_control_frame_t *cfp) { return VM_ENV_FLAGS(cfp->ep, VM_FRAME_MAGIC_MASK); } +static inline unsigned long +VM_FRAME_TYPE_UNCHECKED(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_MAGIC_MASK); +} + static inline int VM_FRAME_LAMBDA_P(const rb_control_frame_t *cfp) { @@ -1470,6 +1512,12 @@ VM_FRAME_FINISHED_P(const rb_control_frame_t *cfp) } static inline int +VM_FRAME_FINISHED_P_UNCHECKED(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_FLAG_FINISH) != 0; +} + +static inline int VM_FRAME_BMETHOD_P(const rb_control_frame_t *cfp) { return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_BMETHOD) != 0; @@ -1489,21 +1537,36 @@ static inline int VM_FRAME_CFRAME_P(const rb_control_frame_t *cfp) { int cframe_p = VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_CFRAME) != 0; - VM_ASSERT(RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) != cframe_p || + // With ZJIT lightweight frames, cfp->_iseq may be stale (not yet materialized), + // so skip this assertion when jit_return is set (zjit.h is not available here). + VM_ASSERT(cfp->jit_return || + RUBY_VM_NORMAL_ISEQ_P(cfp->_iseq) != cframe_p || (VM_FRAME_TYPE(cfp) & VM_FRAME_MAGIC_MASK) == VM_FRAME_MAGIC_DUMMY); return cframe_p; } static inline int +VM_FRAME_CFRAME_P_UNCHECKED(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS_UNCHECKED(cfp->ep, VM_FRAME_FLAG_CFRAME) != 0; +} + +static inline int VM_FRAME_RUBYFRAME_P(const rb_control_frame_t *cfp) { return !VM_FRAME_CFRAME_P(cfp); } static inline int -VM_FRAME_NS_SWITCH_P(const rb_control_frame_t *cfp) +VM_FRAME_RUBYFRAME_P_UNCHECKED(const rb_control_frame_t *cfp) { - return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_NS_SWITCH) != 0; + return !VM_FRAME_CFRAME_P_UNCHECKED(cfp); +} + +static inline int +VM_FRAME_NS_REQUIRE_P(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS(cfp->ep, VM_FRAME_FLAG_BOX_REQUIRE) != 0; } #define RUBYVM_CFUNC_FRAME_P(cfp) \ @@ -1518,20 +1581,57 @@ VM_ENV_LOCAL_P(const VALUE *ep) return VM_ENV_FLAGS(ep, VM_ENV_FLAG_LOCAL) ? 1 : 0; } +static inline int +VM_ENV_LOCAL_P_UNCHECKED(const VALUE *ep) +{ + return VM_ENV_FLAGS_UNCHECKED(ep, VM_ENV_FLAG_LOCAL) ? 1 : 0; +} + +static inline const VALUE * +VM_ENV_PREV_EP_UNCHECKED(const VALUE *ep) +{ + return GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]); +} + static inline const VALUE * VM_ENV_PREV_EP(const VALUE *ep) { VM_ASSERT(VM_ENV_LOCAL_P(ep) == 0); - return GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]); + return VM_ENV_PREV_EP_UNCHECKED(ep); +} + +static inline bool +VM_ENV_BOXED_P(const VALUE *ep) +{ + return VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_CLASS) || VM_ENV_FRAME_TYPE_P(ep, VM_FRAME_MAGIC_TOP); } static inline VALUE VM_ENV_BLOCK_HANDLER(const VALUE *ep) { + if (VM_ENV_BOXED_P(ep)) { + VM_ASSERT(VM_ENV_LOCAL_P(ep)); + return VM_BLOCK_HANDLER_NONE; + } + VM_ASSERT(VM_ENV_LOCAL_P(ep)); return ep[VM_ENV_DATA_INDEX_SPECVAL]; } +static inline const rb_box_t * +VM_ENV_BOX(const VALUE *ep) +{ + VM_ASSERT(VM_ENV_BOXED_P(ep)); + VM_ASSERT(VM_ENV_LOCAL_P(ep)); + return (const rb_box_t *)GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]); +} + +static inline const rb_box_t * +VM_ENV_BOX_UNCHECKED(const VALUE *ep) +{ + return (const rb_box_t *)GC_GUARDED_PTR_REF(ep[VM_ENV_DATA_INDEX_SPECVAL]); +} + #if VM_CHECK_MODE > 0 int rb_vm_ep_in_heap_p(const VALUE *ep); #endif @@ -1852,8 +1952,7 @@ NORETURN(void rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int /* functions about thread/vm execution */ RUBY_SYMBOL_EXPORT_BEGIN -VALUE rb_iseq_eval(const rb_iseq_t *iseq); -VALUE rb_iseq_eval_with_refinement(const rb_iseq_t *iseq, VALUE mod); +VALUE rb_iseq_eval(const rb_iseq_t *iseq, const rb_box_t *box); VALUE rb_iseq_eval_main(const rb_iseq_t *iseq); VALUE rb_iseq_path(const rb_iseq_t *iseq); VALUE rb_iseq_realpath(const rb_iseq_t *iseq); @@ -1913,6 +2012,7 @@ VALUE *rb_vm_svar_lep(const rb_execution_context_t *ec, const rb_control_frame_t int rb_vm_get_sourceline(const rb_control_frame_t *); void rb_vm_stack_to_heap(rb_execution_context_t *ec); void ruby_thread_init_stack(rb_thread_t *th, void *local_in_parent_frame); +void rb_thread_malloc_stack_set(rb_thread_t *th, void *stack, size_t stack_size); rb_thread_t * ruby_thread_from_native(void); int ruby_thread_set_native(rb_thread_t *th); int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp); @@ -1927,9 +2027,8 @@ void rb_vm_register_special_exception_str(enum ruby_special_exceptions sp, VALUE void rb_gc_mark_machine_context(const rb_execution_context_t *ec); -rb_cref_t *rb_vm_rewrite_cref(rb_cref_t *node, VALUE old_klass, VALUE new_klass); - const rb_callable_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp); +const rb_callable_method_entry_t *rb_vm_frame_method_entry_unchecked(const rb_control_frame_t *cfp); #define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack] @@ -1956,14 +2055,22 @@ rb_execution_context_t *rb_vm_main_ractor_ec(rb_vm_t *vm); // ractor.c RUBY_EXTERN struct rb_ractor_struct *ruby_single_main_ractor; // ractor.c RUBY_EXTERN rb_vm_t *ruby_current_vm_ptr; RUBY_EXTERN rb_event_flag_t ruby_vm_event_flags; -RUBY_EXTERN rb_event_flag_t ruby_vm_event_enabled_global_flags; -RUBY_EXTERN unsigned int ruby_vm_event_local_num; +RUBY_EXTERN rb_event_flag_t ruby_vm_event_enabled_global_flags; // only ever added to +RUBY_EXTERN unsigned int ruby_vm_iseq_events_enabled; +RUBY_EXTERN unsigned int ruby_vm_c_events_enabled; #define GET_VM() rb_current_vm() #define GET_RACTOR() rb_current_ractor() #define GET_THREAD() rb_current_thread() #define GET_EC() rb_current_execution_context(true) +static inline rb_serial_t +rb_ec_serial(struct rb_execution_context_struct *ec) +{ + VM_ASSERT(ec->serial >= 1); + return ec->serial; +} + static inline rb_thread_t * rb_ec_thread_ptr(const rb_execution_context_t *ec) { @@ -1983,6 +2090,14 @@ rb_ec_ractor_ptr(const rb_execution_context_t *ec) } } +static inline rb_serial_t +rb_ec_ractor_id(const rb_execution_context_t *ec) +{ + rb_serial_t ractor_id = ec->ractor_id; + RUBY_ASSERT(ractor_id); + return ractor_id; +} + static inline rb_vm_t * rb_ec_vm_ptr(const rb_execution_context_t *ec) { @@ -2001,7 +2116,7 @@ static inline rb_execution_context_t * rb_current_execution_context(bool expect_ec) { #ifdef RB_THREAD_LOCAL_SPECIFIER - #if defined(__arm64__) || defined(__aarch64__) + #ifdef RB_THREAD_CURRENT_EC_NOINLINE rb_execution_context_t * volatile ec = rb_current_ec(); #else rb_execution_context_t * volatile ec = ruby_current_ec; @@ -2011,9 +2126,9 @@ rb_current_execution_context(bool expect_ec) * and the address of the `ruby_current_ec` can be stored on a function * frame. However, this address can be mis-used after native thread * migration of a coroutine. - * 1) Get `ptr =&ruby_current_ec` op NT1 and store it on the frame. + * 1) Get `ptr = &ruby_current_ec` on NT1 and store it on the frame. * 2) Context switch and resume it on the NT2. - * 3) `ptr` is used on NT2 but it accesses to the TLS on NT1. + * 3) `ptr` is used on NT2 but it accesses the TLS of NT1. * This assertion checks such misusage. * * To avoid accidents, `GET_EC()` should be called once on the frame. @@ -2190,10 +2305,11 @@ struct rb_trace_arg_struct { }; void rb_hook_list_mark(rb_hook_list_t *hooks); -void rb_hook_list_mark_and_update(rb_hook_list_t *hooks); +void rb_hook_list_mark_and_move(rb_hook_list_t *hooks); void rb_hook_list_free(rb_hook_list_t *hooks); -void rb_hook_list_connect_tracepoint(VALUE target, rb_hook_list_t *list, VALUE tpval, unsigned int target_line); -void rb_hook_list_remove_tracepoint(rb_hook_list_t *list, VALUE tpval); +void rb_hook_list_connect_local_tracepoint(rb_hook_list_t *list, VALUE tpval, unsigned int target_line); +bool rb_hook_list_remove_local_tracepoint(rb_hook_list_t *list, VALUE tpval); +unsigned int rb_hook_list_count(rb_hook_list_t *list); void rb_exec_event_hooks(struct rb_trace_arg_struct *trace_arg, rb_hook_list_t *hooks, int pop_p); @@ -2232,6 +2348,8 @@ struct rb_ractor_pub { VALUE self; uint32_t id; rb_hook_list_t hooks; + st_table targeted_hooks; // also called "local hooks". {ISEQ => hook_list, def => hook_list...} + unsigned int targeted_hooks_cnt; // ex: tp.enabled(target: method(:puts)) }; static inline rb_hook_list_t * @@ -2241,11 +2359,31 @@ rb_ec_ractor_hooks(const rb_execution_context_t *ec) return &cr_pub->hooks; } +static inline rb_hook_list_t * +rb_vm_global_hooks(const rb_execution_context_t *ec) +{ + return &rb_ec_vm_ptr(ec)->global_hooks; +} + +static inline rb_hook_list_t * +rb_ec_hooks(const rb_execution_context_t *ec, rb_event_flag_t event) +{ + // Should be a single bit set + VM_ASSERT(event != 0 && ((event - 1) & event) == 0); + + if (event & RUBY_INTERNAL_EVENT_OBJSPACE_MASK) { + return rb_vm_global_hooks(ec); + } + else { + return rb_ec_ractor_hooks(ec); + } +} + #define EXEC_EVENT_HOOK(ec_, flag_, self_, id_, called_id_, klass_, data_) \ - EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_ractor_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 0) + EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_hooks(ec_, flag_), flag_, self_, id_, called_id_, klass_, data_, 0) #define EXEC_EVENT_HOOK_AND_POP_FRAME(ec_, flag_, self_, id_, called_id_, klass_, data_) \ - EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_ractor_hooks(ec_), flag_, self_, id_, called_id_, klass_, data_, 1) + EXEC_EVENT_HOOK_ORIG(ec_, rb_ec_hooks(ec_, flag_), flag_, self_, id_, called_id_, klass_, data_, 1) static inline void rb_exec_event_hook_script_compiled(rb_execution_context_t *ec, const rb_iseq_t *iseq, VALUE eval_script) @@ -2257,9 +2395,7 @@ rb_exec_event_hook_script_compiled(rb_execution_context_t *ec, const rb_iseq_t * void rb_vm_trap_exit(rb_vm_t *vm); void rb_vm_postponed_job_atfork(void); /* vm_trace.c */ -void rb_vm_postponed_job_free(void); /* vm_trace.c */ size_t rb_vm_memsize_postponed_job_queue(void); /* vm_trace.c */ -void rb_vm_postponed_job_queue_init(rb_vm_t *vm); /* vm_trace.c */ RUBY_SYMBOL_EXPORT_BEGIN |
