diff --git a/cont.c b/cont.c index 4582466faca335..a23b551d83aebd 100644 --- a/cont.c +++ b/cont.c @@ -215,7 +215,6 @@ typedef struct rb_context_struct { enum context_type type; int argc; int kw_splat; - bool root; VALUE self; VALUE value; @@ -282,7 +281,7 @@ rb_free_shared_fiber_pool(void) struct fiber_pool_allocation *allocations = shared_fiber_pool.allocations; while (allocations) { struct fiber_pool_allocation *next = allocations->next; - xfree(allocations); + SIZED_FREE(allocations); allocations = next; } } @@ -658,7 +657,7 @@ fiber_pool_allocation_free(struct fiber_pool_allocation * allocation) allocation->pool->count -= allocation->count; - ruby_xfree(allocation); + SIZED_FREE(allocation); } #endif @@ -1089,7 +1088,7 @@ cont_free(void *ptr) RUBY_FREE_ENTER("cont"); if (cont->type == CONTINUATION_CONTEXT) { - ruby_xfree(cont->saved_ec.vm_stack); + SIZED_FREE_N(cont->saved_ec.vm_stack, cont->saved_ec.vm_stack_size); RUBY_FREE_UNLESS_NULL(cont->machine.stack); } else { @@ -1103,11 +1102,11 @@ cont_free(void *ptr) VM_ASSERT(cont->jit_cont != NULL); jit_cont_free(cont->jit_cont); /* free rb_cont_t or rb_fiber_t */ - if (cont->root) { - ruby_mimfree(ptr); + if (cont->type == CONTINUATION_CONTEXT) { + SIZED_FREE(cont); } else { - ruby_xfree(ptr); + SIZED_FREE((rb_fiber_t *)cont); } RUBY_FREE_LEAVE("cont"); } @@ -1221,6 +1220,7 @@ rb_obj_is_fiber(VALUE obj) static void cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont) { + const size_t old_stack_size = cont->machine.stack_size; size_t size; SET_MACHINE_STACK_END(&th->ec->machine.stack_end); @@ -1235,10 +1235,10 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont) } if (cont->machine.stack) { - REALLOC_N(cont->machine.stack, VALUE, size); + SIZED_REALLOC_N(cont->machine.stack, VALUE, cont->machine.stack_size, old_stack_size); } else { - cont->machine.stack = ALLOC_N(VALUE, size); + cont->machine.stack = ALLOC_N(VALUE, cont->machine.stack_size); } FLUSH_REGISTER_WINDOWS; @@ -2574,13 +2574,12 @@ rb_fiber_start(rb_fiber_t *fiber) void rb_threadptr_root_fiber_setup(rb_thread_t *th) { - rb_fiber_t *fiber = ruby_mimcalloc(1, sizeof(rb_fiber_t)); + rb_fiber_t *fiber = ZALLOC(rb_fiber_t); if (!fiber) { rb_bug("%s", strerror(errno)); /* ... is it possible to call rb_bug here? */ } fiber->cont.type = FIBER_CONTEXT; - fiber->cont.root = true; fiber->cont.saved_ec.fiber_ptr = fiber; fiber->cont.saved_ec.serial = next_ec_serial(th->ractor); fiber->cont.saved_ec.thread_ptr = th; @@ -3407,7 +3406,7 @@ fiber_pool_free(void *ptr) RUBY_FREE_ENTER("fiber_pool"); fiber_pool_allocation_free(fiber_pool->allocations); - ruby_xfree(fiber_pool); + SIZED_FREE(fiber_pool); RUBY_FREE_LEAVE("fiber_pool"); } diff --git a/doc/_timezones.rdoc b/doc/_timezones.rdoc index a2ac46584fd75a..945654c1630570 100644 --- a/doc/_timezones.rdoc +++ b/doc/_timezones.rdoc @@ -11,7 +11,7 @@ Certain +Time+ methods accept arguments that specify timezones: The value given with any of these must be one of the following (each detailed below): -- {Hours/minutes offset}[rdoc-ref:Time@Hours-2FMinutes+Offsets]. +- {Hours/minutes offset}[rdoc-ref:Time@HoursMinutes+Offsets]. - {Single-letter offset}[rdoc-ref:Time@Single-Letter+Offsets]. - {Integer offset}[rdoc-ref:Time@Integer+Offsets]. - {Timezone object}[rdoc-ref:Time@Timezone+Objects]. diff --git a/doc/contributing/documentation_guide.md b/doc/contributing/documentation_guide.md index 4b1e2ac9adaf2e..4378e028737a37 100644 --- a/doc/contributing/documentation_guide.md +++ b/doc/contributing/documentation_guide.md @@ -318,7 +318,7 @@ Alternatives: will not be honored: - Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/file.c#L6570-L6596]. - - Corresponding {output}[rdoc-ref:File@Read-2FWrite+Mode]. + - Corresponding {output}[rdoc-ref:File@ReadWrite+Mode]. - (Markdown format only): A {Github Flavored Markdown (GFM) table}[https://github.github.com/gfm/#tables-extension-], using special formatting for the text: diff --git a/doc/jit/zjit.md b/doc/jit/zjit.md index a284fce8115869..ab215a0172fb65 100644 --- a/doc/jit/zjit.md +++ b/doc/jit/zjit.md @@ -306,6 +306,21 @@ A file called `zjit_exits_{pid}.dump` will be created in the same directory as ` stackprof path/to/zjit_exits_{pid}.dump ``` +### Viewing HIR as text + +The compiled ZJIT HIR can be viewed as text using the `--zjit-dump-hir` option. However, HIR will only be generated if the call threshold is reached (default 30). By setting the threshold to 1 you can easily view the HIR for code snippets such as `1 + 1`: + +```bash +./miniruby --zjit --zjit-dump-hir --zjit-call-threshold=1 -e "1 + 1" +``` + +Note that this disables profiling. To inject interpreter profiles into ZJIT, consider running your sample code 30 times: + +```bash +./miniruby --zjit --zjit-dump-hir -e "30.times { 1 + 1 }" +``` +``` + ### Viewing HIR in Iongraph Using `--zjit-dump-hir-iongraph` will dump all compiled functions into a directory named `/tmp/zjit-iongraph-{PROCESS_PID}`. Each file will be named `func_{ZJIT_FUNC_NAME}.json`. In order to use them in the Iongraph viewer, you'll need to use `jq` to collate them to a single file. An example invocation of `jq` is shown below for reference. diff --git a/doc/string.rb b/doc/string.rb index e2dfb37c9fa5eb..4dac94e93a04aa 100644 --- a/doc/string.rb +++ b/doc/string.rb @@ -169,7 +169,7 @@ # Here, class +String+ provides methods that are useful for: # # - {Creating a \String}[rdoc-ref:String@Creating+a+String]. -# - {Freezing/Unfreezing a \String}[rdoc-ref:String@Freezing-2FUnfreezing]. +# - {Freezing/Unfreezing a \String}[rdoc-ref:String@FreezingUnfreezing]. # - {Querying a \String}[rdoc-ref:String@Querying]. # - {Comparing Strings}[rdoc-ref:String@Comparing]. # - {Modifying a \String}[rdoc-ref:String@Modifying]. diff --git a/file.c b/file.c index 706b60c9997919..0af968cefb805a 100644 --- a/file.c +++ b/file.c @@ -6866,7 +6866,7 @@ const char ruby_null_device[] = * Methods File.new and File.open each may take string argument +mode+, which: * * - Begins with a 1- or 2-character - * {read/write mode}[rdoc-ref:File@Read-2FWrite+Mode]. + * {read/write mode}[rdoc-ref:File@ReadWrite+Mode]. * - May also contain a 1-character {data mode}[rdoc-ref:File@Data+Mode]. * - May also contain a 1-character * {file-create mode}[rdoc-ref:File@File-Create+Mode]. diff --git a/hash.rb b/hash.rb index 99b34a9bda6a8b..40f823783e7387 100644 --- a/hash.rb +++ b/hash.rb @@ -7,7 +7,7 @@ class Hash # # Initializes the values of Hash#default and Hash#default_proc, # which determine the behavior when a given key is not found; - # see {Key Not Found?}[rdoc-ref:Hash@Key+Not+Found-3F]. + # see {Key Not Found?}[rdoc-ref:Hash@Key+Not+Found]. # # By default, a hash has +nil+ values for both +default+ and +default_proc+: # diff --git a/imemo.c b/imemo.c index 0f7c260eb92cdd..b8132aca69ff5f 100644 --- a/imemo.c +++ b/imemo.c @@ -550,7 +550,7 @@ static enum rb_id_table_iterator_result free_const_entry_i(VALUE value, void *data) { rb_const_entry_t *ce = (rb_const_entry_t *)value; - xfree(ce); + SIZED_FREE(ce); return ID_TABLE_CONTINUE; } @@ -565,11 +565,12 @@ static inline void imemo_fields_free(struct rb_fields *fields) { if (FL_TEST_RAW((VALUE)fields, OBJ_FIELD_HEAP)) { - if (rb_shape_obj_too_complex_p((VALUE)fields)) { + shape_id_t shape_id = RBASIC_SHAPE_ID((VALUE)fields); + if (rb_shape_too_complex_p(shape_id)) { st_free_table(fields->as.complex.table); } else { - xfree(fields->as.external.ptr); + SIZED_FREE_N(fields->as.external.ptr, RSHAPE_CAPACITY(shape_id)); } } } @@ -587,7 +588,9 @@ rb_imemo_free(VALUE obj) if (ci->kwarg) { ((struct rb_callinfo_kwarg *)ci->kwarg)->references--; - if (ci->kwarg->references == 0) xfree((void *)ci->kwarg); + if (ci->kwarg->references == 0) { + ruby_sized_xfree((void *)ci->kwarg, rb_callinfo_kwarg_bytes(ci->kwarg->keyword_len)); + } } RB_DEBUG_COUNTER_INC(obj_imemo_callinfo); @@ -605,7 +608,7 @@ rb_imemo_free(VALUE obj) rb_env_t *env = (rb_env_t *)obj; RUBY_ASSERT(VM_ENV_ESCAPED_P(env->ep)); - xfree((VALUE *)env->env); + SIZED_FREE_N(env->env, env->env_size); RB_DEBUG_COUNTER_INC(obj_imemo_env); break; @@ -636,7 +639,7 @@ rb_imemo_free(VALUE obj) break; case imemo_tmpbuf: - xfree(((rb_imemo_tmpbuf_t *)obj)->ptr); + ruby_sized_xfree(((rb_imemo_tmpbuf_t *)obj)->ptr, ((rb_imemo_tmpbuf_t *)obj)->size); RB_DEBUG_COUNTER_INC(obj_imemo_tmpbuf); break; diff --git a/internal/gc.h b/internal/gc.h index b28fd25bced6b2..e719a3ddc35ba1 100644 --- a/internal/gc.h +++ b/internal/gc.h @@ -314,7 +314,7 @@ ruby_sized_xfree_inlined(void *ptr, size_t size) ((v) = (T *)ruby_sized_xrealloc2((void *)(v), (m), sizeof(T), (n))) # define SIZED_FREE(v) ruby_sized_xfree((void *)(v), sizeof(*(v))) -# define SIZED_FREE_N(v, n) ruby_sized_xfree((void *)(v), sizeof(*(v)) * n) +# define SIZED_FREE_N(v, n) ruby_sized_xfree((void *)(v), sizeof(*(v)) * (n)) static inline void * ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t old_count) diff --git a/io.c b/io.c index ca97e321f7179a..cf95db70df961e 100644 --- a/io.c +++ b/io.c @@ -14954,9 +14954,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y) * ["ARGV", ["-"]] * ["ARGF.read", "Open the pod bay doors, Hal.\n"] * - * When no character '-' is given, stream $stdin is ignored - * (exception: - * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+stdin+in+ARGV]): + * When no character '-' is given, stream $stdin is ignored. * * - Command and output: * @@ -15071,7 +15069,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y) * Like a File stream, an \IO stream has: * * - A read/write mode, which may be read-only, write-only, or read/write; - * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode]. + * see {Read/Write Mode}[rdoc-ref:File@ReadWrite+Mode]. * - A data mode, which may be text-only or binary; * see {Data Mode}[rdoc-ref:File@Data+Mode]. * - Internal and external encodings; diff --git a/iseq.c b/iseq.c index 88aa29dce32ecc..c418e1786988b9 100644 --- a/iseq.c +++ b/iseq.c @@ -88,7 +88,7 @@ free_arena(struct iseq_compile_data_storage *cur) while (cur) { next = cur->next; - ruby_xfree(cur); + ruby_sized_xfree(cur, offsetof(struct iseq_compile_data_storage, buff) + cur->size * sizeof(char)); cur = next; } } @@ -102,7 +102,7 @@ compile_data_free(struct iseq_compile_data *compile_data) if (compile_data->ivar_cache_table) { rb_id_table_free(compile_data->ivar_cache_table); } - ruby_xfree(compile_data); + SIZED_FREE(compile_data); } } @@ -152,13 +152,14 @@ iseq_clear_ic_references(const rb_iseq_t *iseq) if (segments == NULL) continue; - for (int i = 0; segments[i]; i++) { + int i; + for (i = 0; segments[i]; i++) { ID id = segments[i]; if (id == idNULL) continue; remove_from_constant_cache(id, ic); } - ruby_xfree((void *)segments); + SIZED_FREE_N(segments, i + 1); } } @@ -198,38 +199,41 @@ rb_iseq_free(const rb_iseq_t *iseq) #if USE_ZJIT rb_zjit_iseq_free(iseq); #endif - ruby_xfree((void *)body->iseq_encoded); - ruby_xfree((void *)body->insns_info.body); - ruby_xfree((void *)body->insns_info.positions); + SIZED_FREE_N(body->iseq_encoded, body->iseq_size); + SIZED_FREE_N(body->insns_info.body, body->insns_info.size); + SIZED_FREE_N(body->insns_info.positions, body->insns_info.size); #if VM_INSN_INFO_TABLE_IMPL == 2 ruby_xfree(body->insns_info.succ_index_table); #endif - ruby_xfree((void *)body->is_entries); - ruby_xfree(body->call_data); - ruby_xfree((void *)body->catch_table); - ruby_xfree((void *)body->param.opt_table); + SIZED_FREE_N(body->is_entries, ISEQ_IS_SIZE(body)); + SIZED_FREE_N(body->call_data, body->ci_size); + if (body->catch_table) { + ruby_sized_xfree(body->catch_table, iseq_catch_table_bytes(body->catch_table->size)); + } + SIZED_FREE_N(body->param.opt_table, body->param.opt_num + 1); if (ISEQ_MBITS_BUFLEN(body->iseq_size) > 1 && body->mark_bits.list) { - ruby_xfree((void *)body->mark_bits.list); + SIZED_FREE_N(body->mark_bits.list, ISEQ_MBITS_BUFLEN(body->iseq_size)); } - ruby_xfree(body->variable.original_iseq); + ISEQ_ORIGINAL_ISEQ_CLEAR(iseq); - if (body->param.keyword != NULL) { - if (body->param.keyword->table != &body->local_table[body->param.keyword->bits_start - body->param.keyword->num]) - ruby_xfree((void *)body->param.keyword->table); - if (body->param.keyword->default_values) { - ruby_xfree((void *)body->param.keyword->default_values); + struct rb_iseq_param_keyword *pkw = (struct rb_iseq_param_keyword *)body->param.keyword; + if (pkw != NULL) { + if (pkw->table != &body->local_table[pkw->bits_start - pkw->num]) + SIZED_FREE_N(pkw->table, pkw->required_num); + if (pkw->default_values) { + SIZED_FREE_N(pkw->default_values, pkw->num - pkw->required_num); } - ruby_xfree((void *)body->param.keyword); + SIZED_FREE(pkw); } if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl)) { - ruby_xfree((void *)body->local_table); + SIZED_FREE_N(body->local_table, body->local_table_size); } - ruby_xfree((void *)body->lvar_states); + SIZED_FREE_N(body->lvar_states, body->local_table_size); compile_data_free(ISEQ_COMPILE_DATA(iseq)); if (body->outer_variables) rb_id_table_free(body->outer_variables); - ruby_xfree(body); + SIZED_FREE(body); } RUBY_FREE_LEAVE("iseq"); @@ -758,7 +762,7 @@ rb_iseq_insns_info_encode_positions(const rb_iseq_t *iseq) if (body->insns_info.succ_index_table) ruby_xfree(body->insns_info.succ_index_table); body->insns_info.succ_index_table = succ_index_table_create(max_pos, data, size); #if VM_CHECK_MODE == 0 - ruby_xfree(body->insns_info.positions); + SIZED_FREE_N(body->insns_info.positions, body->insns_info.size); body->insns_info.positions = NULL; #endif #endif diff --git a/iseq.h b/iseq.h index 5221c8aeb4fdfc..b9bc03c23c80fd 100644 --- a/iseq.h +++ b/iseq.h @@ -68,9 +68,11 @@ ISEQ_ORIGINAL_ISEQ(const rb_iseq_t *iseq) static inline void ISEQ_ORIGINAL_ISEQ_CLEAR(const rb_iseq_t *iseq) { - void *ptr = ISEQ_BODY(iseq)->variable.original_iseq; - ISEQ_BODY(iseq)->variable.original_iseq = NULL; - ruby_xfree(ptr); + VALUE *ptr = (VALUE *)ISEQ_BODY(iseq)->variable.original_iseq; + if (ptr) { + ISEQ_BODY(iseq)->variable.original_iseq = NULL; + SIZED_FREE_N(ptr, ISEQ_BODY(iseq)->iseq_size); + } } static inline VALUE * diff --git a/ractor.c b/ractor.c index da1db8d803ce06..df8d46b9fe578d 100644 --- a/ractor.c +++ b/ractor.c @@ -298,11 +298,8 @@ ractor_free(void *ptr) } ractor_sync_free(r); - if (r->main_ractor) { - ruby_mimfree(r); - } - else { - ruby_xfree(r); + if (!r->main_ractor) { + SIZED_FREE(r); } } @@ -469,10 +466,12 @@ ractor_alloc(VALUE klass) return rv; } +static rb_ractor_t _main_ractor; + rb_ractor_t * rb_ractor_main_alloc(void) { - rb_ractor_t *r = ruby_mimcalloc(1, sizeof(rb_ractor_t)); + rb_ractor_t *r = &_main_ractor; if (r == NULL) { fprintf(stderr, "[FATAL] failed to allocate memory for main ractor\n"); exit(EXIT_FAILURE); @@ -2213,7 +2212,7 @@ rb_ractor_local_storage_delkey(rb_ractor_local_key_t key) RB_VM_LOCKING() { if (freed_ractor_local_keys.cnt == freed_ractor_local_keys.capa) { freed_ractor_local_keys.capa = freed_ractor_local_keys.capa ? freed_ractor_local_keys.capa * 2 : 4; - REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, freed_ractor_local_keys.capa); + SIZED_REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, freed_ractor_local_keys.capa, freed_ractor_local_keys.cnt); } freed_ractor_local_keys.keys[freed_ractor_local_keys.cnt++] = key; } @@ -2312,12 +2311,12 @@ void rb_ractor_finish_marking(void) { for (int i=0; i DEFAULT_KEYS_CAPA) { freed_ractor_local_keys.capa = DEFAULT_KEYS_CAPA; - REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, DEFAULT_KEYS_CAPA); + SIZED_REALLOC_N(freed_ractor_local_keys.keys, rb_ractor_local_key_t, DEFAULT_KEYS_CAPA, freed_ractor_local_keys.capa); } } diff --git a/string.c b/string.c index 3cfc77600b6f1b..448594278d9e05 100644 --- a/string.c +++ b/string.c @@ -293,7 +293,9 @@ rb_str_make_embedded(VALUE str) RUBY_ASSERT(rb_str_reembeddable_p(str)); RUBY_ASSERT(!STR_EMBED_P(str)); + int termlen = TERM_LEN(str); char *buf = RSTRING(str)->as.heap.ptr; + long old_capa = RSTRING(str)->as.heap.aux.capa + termlen; long len = RSTRING(str)->len; STR_SET_EMBED(str); @@ -301,10 +303,10 @@ rb_str_make_embedded(VALUE str) if (len > 0) { memcpy(RSTRING_PTR(str), buf, len); - ruby_xfree(buf); + ruby_sized_xfree(buf, old_capa); } - TERM_FILL(RSTRING(str)->as.embed.ary + len, TERM_LEN(str)); + TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen); } void @@ -3309,7 +3311,7 @@ rb_str_freeze(VALUE str) * * Otherwise returns self.dup, which is not frozen. * - * Related: see {Freezing/Unfreezing}[rdoc-ref:String@Freezing-2FUnfreezing]. + * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing]. */ static VALUE str_uplus(VALUE str) @@ -3354,7 +3356,7 @@ str_uplus(VALUE str) * * 'foo'.dedup.gsub!('o') * - * Related: see {Freezing/Unfreezing}[rdoc-ref:String@Freezing-2FUnfreezing]. + * Related: see {Freezing/Unfreezing}[rdoc-ref:String@FreezingUnfreezing]. */ static VALUE str_uminus(VALUE str) @@ -3474,13 +3476,16 @@ rb_str_resize(VALUE str, long len) str_make_independent_expand(str, slen, len - slen, termlen); } else if (str_embed_capa(str) >= len + termlen) { + capa = RSTRING(str)->as.heap.aux.capa; char *ptr = STR_HEAP_PTR(str); STR_SET_EMBED(str); if (slen > len) slen = len; if (slen > 0) MEMCPY(RSTRING(str)->as.embed.ary, ptr, char, slen); TERM_FILL(RSTRING(str)->as.embed.ary + len, termlen); STR_SET_LEN(str, len); - if (independent) ruby_xfree(ptr); + if (independent) { + ruby_sized_xfree(ptr, capa + termlen); + } return str; } else if (!independent) { diff --git a/thread_sync.c b/thread_sync.c index e3916c97cbd0a6..fa6a60ab62db36 100644 --- a/thread_sync.c +++ b/thread_sync.c @@ -696,13 +696,20 @@ queue_mark_and_move(void *ptr) } } +static inline void +queue_free_buffer(struct rb_queue *q) +{ + if (q->buffer) { + SIZED_FREE_N(q->buffer, q->capa); + } +} + static void queue_free(void *ptr) { struct rb_queue *q = ptr; - if (q->buffer) { - ruby_sized_xfree(q->buffer, q->capa * sizeof(VALUE)); - } + queue_free_buffer(q); + SIZED_FREE(q); } static size_t @@ -806,7 +813,8 @@ static void szqueue_free(void *ptr) { struct rb_szqueue *sq = ptr; - queue_free(&sq->q); + queue_free_buffer(&sq->q); + SIZED_FREE(sq); } static size_t diff --git a/vm.c b/vm.c index 05d2025a12a178..264bdfa1f23b2a 100644 --- a/vm.c +++ b/vm.c @@ -3392,8 +3392,6 @@ ruby_vm_destruct(rb_vm_t *vm) st_free_table(vm->static_ext_inits); - rb_vm_postponed_job_free(); - rb_id_table_free(vm->constant_cache); set_free_table(vm->unused_block_warning_table); @@ -3433,14 +3431,11 @@ ruby_vm_destruct(rb_vm_t *vm) rb_objspace_free_objects(objspace); rb_free_generic_fields_tbl_(); rb_free_default_rand_key(); - - ruby_mimfree(th); } rb_objspace_free(objspace); } rb_native_mutex_destroy(&vm->workqueue_lock); /* after freeing objspace, you *can't* use ruby_xfree() */ - ruby_mimfree(vm); ruby_current_vm_ptr = NULL; if (rb_free_at_exit) { @@ -3785,7 +3780,7 @@ thread_mark(void *ptr) rb_gc_mark(th->top_wrapper); if (th->root_fiber) rb_fiber_mark_self(th->root_fiber); - RUBY_ASSERT(th->ec == rb_fiberptr_get_ec(th->ec->fiber_ptr)); + RUBY_ASSERT(th->ec == NULL || th->ec == rb_fiberptr_get_ec(th->ec->fiber_ptr)); rb_gc_mark(th->last_status); rb_gc_mark(th->locking_mutex); rb_gc_mark(th->name); @@ -3822,10 +3817,7 @@ thread_free(void *ptr) else { // ruby_xfree(th->nt); // TODO: MN system collect nt, but without MN system it should be freed here. - if (th->main_thread) { - ruby_mimfree(th); - } - else { + if (!th->main_thread) { ruby_xfree(th); } } @@ -4576,12 +4568,15 @@ rb_vm_set_progname(VALUE filename) extern const struct st_hash_type rb_fstring_hash_type; +static rb_vm_t _vm; +static rb_thread_t _main_thread = { .main_thread = 1 }; + void Init_BareVM(void) { /* VM bootstrap: phase 1 */ - rb_vm_t *vm = ruby_mimcalloc(1, sizeof(*vm)); - rb_thread_t *th = ruby_mimcalloc(1, sizeof(*th)); + rb_vm_t *vm = &_vm; + rb_thread_t *th = &_main_thread; if (!vm || !th) { fputs("[FATAL] failed to allocate memory\n", stderr); exit(EXIT_FAILURE); @@ -4590,7 +4585,6 @@ Init_BareVM(void) // setup the VM vm_init2(vm); - rb_vm_postponed_job_queue_init(vm); ruby_current_vm_ptr = vm; rb_objspace_alloc(); vm->negative_cme_table = rb_id_table_create(16); @@ -4600,7 +4594,6 @@ Init_BareVM(void) vm->global_hooks.type = hook_list_type_global; // setup main thread - th->main_thread = 1; th->nt = ZALLOC(struct rb_native_thread); th->vm = vm; th->ractor = vm->ractor.main_ractor = rb_ractor_main_alloc(); diff --git a/vm_core.h b/vm_core.h index 8240a3b4f54c42..55ec08a6e238b7 100644 --- a/vm_core.h +++ b/vm_core.h @@ -787,9 +787,6 @@ typedef struct rb_vm_struct { /* hook (for internal events: NEWOBJ, FREEOBJ, GC events, etc.) */ rb_hook_list_t global_hooks; - /* postponed_job (async-signal-safe, and thread-safe) */ - struct rb_postponed_job_queue *postponed_job_queue; - int src_encoding_index; /* workqueue (thread-safe, NOT async-signal-safe) */ @@ -2387,9 +2384,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 diff --git a/vm_trace.c b/vm_trace.c index 11cf7f55b5e18e..273faa5f888a4c 100644 --- a/vm_trace.c +++ b/vm_trace.c @@ -1864,16 +1864,7 @@ typedef struct rb_postponed_job_queue { rb_atomic_t triggered_bitset; } rb_postponed_job_queues_t; -void -rb_vm_postponed_job_queue_init(rb_vm_t *vm) -{ - /* use mimmalloc; postponed job registration is a dependency of objspace, so this gets - * called _VERY_ early inside Init_BareVM */ - rb_postponed_job_queues_t *pjq = ruby_mimmalloc(sizeof(rb_postponed_job_queues_t)); - pjq->triggered_bitset = 0; - memset(pjq->table, 0, sizeof(pjq->table)); - vm->postponed_job_queue = pjq; -} +static rb_postponed_job_queues_t postponed_job_queue; static rb_execution_context_t * get_valid_ec(rb_vm_t *vm) @@ -1886,25 +1877,15 @@ get_valid_ec(rb_vm_t *vm) void rb_vm_postponed_job_atfork(void) { - rb_vm_t *vm = GET_VM(); - rb_postponed_job_queues_t *pjq = vm->postponed_job_queue; + rb_postponed_job_queues_t *pjq = &postponed_job_queue; /* make sure we set the interrupt flag on _this_ thread if we carried any pjobs over * from the other side of the fork */ if (pjq->triggered_bitset) { - RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(get_valid_ec(vm)); + RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(get_valid_ec(GET_VM())); } } -/* Frees the memory managed by the postponed job infrastructure at shutdown */ -void -rb_vm_postponed_job_free(void) -{ - rb_vm_t *vm = GET_VM(); - ruby_mimfree(vm->postponed_job_queue); - vm->postponed_job_queue = NULL; -} - // Used for VM memsize reporting. Returns the total size of the postponed job // queue infrastructure. size_t @@ -1926,7 +1907,7 @@ rb_postponed_job_preregister(unsigned int flags, rb_postponed_job_func_t func, v * of concurrent calls to both _preregister and _register functions on the same * func, however, the data may get mixed up between them. */ - rb_postponed_job_queues_t *pjq = GET_VM()->postponed_job_queue; + rb_postponed_job_queues_t *pjq = &postponed_job_queue; for (unsigned int i = 0; i < PJOB_TABLE_SIZE; i++) { /* Try and set this slot to equal `func` */ rb_postponed_job_func_t existing_func = (rb_postponed_job_func_t)(uintptr_t)RUBY_ATOMIC_PTR_CAS(pjq->table[i].func, NULL, (void *)(uintptr_t)func); @@ -1951,11 +1932,10 @@ rb_postponed_job_preregister(unsigned int flags, rb_postponed_job_func_t func, v void rb_postponed_job_trigger(rb_postponed_job_handle_t h) { - rb_vm_t *vm = GET_VM(); - rb_postponed_job_queues_t *pjq = vm->postponed_job_queue; + rb_postponed_job_queues_t *pjq = &postponed_job_queue; RUBY_ATOMIC_OR(pjq->triggered_bitset, (((rb_atomic_t)1UL) << h)); - RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(get_valid_ec(vm)); + RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(get_valid_ec(GET_VM())); } @@ -1988,7 +1968,7 @@ rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void rb_postponed_job_flush(rb_vm_t *vm) { - rb_postponed_job_queues_t *pjq = GET_VM()->postponed_job_queue; + rb_postponed_job_queues_t *pjq = &postponed_job_queue; rb_execution_context_t *ec = GET_EC(); const rb_atomic_t block_mask = POSTPONED_JOB_INTERRUPT_MASK | TRAP_INTERRUPT_MASK; volatile rb_atomic_t saved_mask = ec->interrupt_mask & block_mask;