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;