14#include "ruby/internal/config.h"
19#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
20# include "wasm/setjmp.h"
21# include "wasm/machine.h"
29#ifndef HAVE_MALLOC_USABLE_SIZE
31# define HAVE_MALLOC_USABLE_SIZE
32# define malloc_usable_size(a) _msize(a)
33# elif defined HAVE_MALLOC_SIZE
34# define HAVE_MALLOC_USABLE_SIZE
35# define malloc_usable_size(a) malloc_size(a)
39#ifdef HAVE_MALLOC_USABLE_SIZE
40# ifdef RUBY_ALTERNATIVE_MALLOC_HEADER
42# elif defined(HAVE_MALLOC_H)
44# elif defined(HAVE_MALLOC_NP_H)
45# include <malloc_np.h>
46# elif defined(HAVE_MALLOC_MALLOC_H)
47# include <malloc/malloc.h>
57#ifdef HAVE_SYS_RESOURCE_H
58# include <sys/resource.h>
61#if defined _WIN32 || defined __CYGWIN__
63#elif defined(HAVE_POSIX_MEMALIGN)
64#elif defined(HAVE_MEMALIGN)
71#include <emscripten.h>
75#ifdef HAVE_SYS_PRCTL_H
82#include "debug_counter.h"
83#include "eval_intern.h"
87#include "internal/class.h"
88#include "internal/compile.h"
89#include "internal/complex.h"
90#include "internal/concurrent_set.h"
91#include "internal/cont.h"
92#include "internal/error.h"
93#include "internal/eval.h"
94#include "internal/gc.h"
95#include "internal/hash.h"
96#include "internal/imemo.h"
97#include "internal/io.h"
98#include "internal/numeric.h"
99#include "internal/object.h"
100#include "internal/proc.h"
101#include "internal/rational.h"
102#include "internal/re.h"
103#include "internal/sanitizers.h"
104#include "internal/struct.h"
105#include "internal/symbol.h"
106#include "internal/thread.h"
107#include "internal/variable.h"
108#include "internal/warnings.h"
118#include "ruby_assert.h"
119#include "ruby_atomic.h"
124#include "vm_callinfo.h"
125#include "ractor_core.h"
135rb_gc_print_backtrace(
void)
137 rb_print_backtrace(stderr);
141rb_gc_vm_lock(
const char *file,
int line)
143 unsigned int lev = 0;
144 rb_vm_lock_enter(&lev, file, line);
149rb_gc_vm_unlock(
unsigned int lev,
const char *file,
int line)
151 rb_vm_lock_leave(&lev, file, line);
155rb_gc_vm_lock_no_barrier(
const char *file,
int line)
157 unsigned int lev = 0;
158 rb_vm_lock_enter_nb(&lev, file, line);
163rb_gc_vm_unlock_no_barrier(
unsigned int lev,
const char *file,
int line)
165 rb_vm_lock_leave_nb(&lev, file, line);
169rb_gc_vm_barrier(
void)
175rb_gc_get_ractor_newobj_cache(
void)
177 return GET_RACTOR()->newobj_cache;
183 context->ec = GET_EC();
189 return ruby_vm_event_flags & event;
195 if (LIKELY(!rb_gc_event_hook_required_p(event)))
return;
206 bool gc_thread_p =
false;
214# ifdef RB_THREAD_LOCAL_SPECIFIER
215 rb_current_ec_set(ec);
217 native_tls_set(ruby_current_ec_key, ec);
222 if (RB_LIKELY(ec->cfp != NULL)) {
223 EXEC_EVENT_HOOK(ec, event, ec->cfp->self, 0, 0, 0, obj);
228# ifdef RB_THREAD_LOCAL_SPECIFIER
229 rb_current_ec_set(NULL);
231 native_tls_set(ruby_current_ec_key, NULL);
242rb_gc_stash_cleanup_objspace(
void)
244 GET_VM()->gc.cleanup_objspace = rb_gc_get_objspace();
250 if (RB_UNLIKELY(ruby_vm_during_cleanup) && GET_VM()->gc.cleanup_objspace) {
251 return GET_VM()->gc.cleanup_objspace;
256 return GET_VM()->ractor.main_ractor->objspace;
264rb_gc_get_objspace(
void)
266 return gc_current_objspace_of(rb_current_ractor_raw(
false));
270rb_gc_run_obj_finalizer(
VALUE objid,
long count,
VALUE (*callback)(
long i,
void *data),
void *data)
281#define RESTORE_FINALIZER() (\
282 ec->cfp = saved.cfp, \
283 ec->cfp->sp = saved.sp, \
284 ec->errinfo = saved.errinfo)
286 saved.errinfo = ec->errinfo;
288 saved.sp = ec->cfp->sp;
292 ASSERT_vm_unlocking();
293 rb_ractor_ignore_belonging(
true);
295 enum ruby_tag_type state = EC_EXEC_TAG();
296 if (state != TAG_NONE) {
299 VALUE failed_final = saved.final;
302 rb_warn(
"Exception in finalizer %+"PRIsVALUE, failed_final);
303 rb_ec_error_print(ec, ec->errinfo);
307 for (
long i = saved.finished; RESTORE_FINALIZER(), i < count; saved.finished = ++i) {
308 saved.final = callback(i, data);
312 rb_ractor_ignore_belonging(
false);
313#undef RESTORE_FINALIZER
317rb_gc_set_pending_interrupt(
void)
320 ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
330 rb_ractor_t *
const cr = rb_current_ractor_raw(
false);
331 if (cr == NULL || cr->objspace !=
objspace) {
337 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
339 rb_postponed_job_trigger_for_ractor(pjob, r->pub.self);
348rb_gc_unset_pending_interrupt(
void)
351 ec->interrupt_mask &= ~PENDING_INTERRUPT_MASK;
355rb_gc_multi_ractor_p(
void)
357 return rb_multi_ractor_p();
361rb_gc_shutdown_call_finalizer_p(
VALUE obj)
365 if (!ruby_free_at_exit_p()) {
367 if (!rbimpl_typeddata_embedded_p(obj) && !
RTYPEDDATA(obj)->data)
return false;
369 if (rb_obj_is_thread(obj))
return false;
370 if (rb_obj_is_mutex(obj))
return false;
371 if (rb_obj_is_fiber(obj))
return false;
372 if (rb_ractor_p(obj))
return false;
373 if (rb_obj_is_fstring_table(obj))
return false;
374 if (rb_obj_is_symbol_table(obj))
return false;
388 return ruby_free_at_exit_p();
393rb_gc_obj_changed_slot_size(
VALUE obj,
size_t slot_size)
395 shape_id_t shape_id = rb_obj_shape_transition_capacity(obj, rb_shape_capacity_for_slot_size(slot_size));
396 RBASIC_SET_FULL_SHAPE_ID(obj, shape_id);
399void rb_vm_update_references(
void *ptr);
401#define rb_setjmp(env) RUBY_SETJMP(env)
402#define rb_jmp_buf rb_jmpbuf_t
404#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
405#define MAP_ANONYMOUS MAP_ANON
408#define unless_objspace(objspace) \
410 rb_vm_t *unless_objspace_vm = GET_VM(); \
411 if (unless_objspace_vm) objspace = rb_gc_get_objspace(); \
414#define RMOVED(obj) ((struct RMoved *)(obj))
416#define TYPED_UPDATE_IF_MOVED(_objspace, _type, _thing) do { \
417 if (gc_object_moved_p_internal((_objspace), (VALUE)(_thing))) { \
418 *(_type *)&(_thing) = (_type)gc_location_internal(_objspace, (VALUE)_thing); \
422#define UPDATE_IF_MOVED(_objspace, _thing) TYPED_UPDATE_IF_MOVED(_objspace, VALUE, _thing)
424#if RUBY_MARK_FREE_DEBUG
425int ruby_gc_debug_indent = 0;
428#ifndef RGENGC_OBJ_INFO
429# define RGENGC_OBJ_INFO RGENGC_CHECK_MODE
432#ifndef CALC_EXACT_MALLOC_SIZE
433# define CALC_EXACT_MALLOC_SIZE 0
438static size_t malloc_offset = 0;
439#if defined(HAVE_MALLOC_USABLE_SIZE)
441gc_compute_malloc_offset(
void)
452 for (offset = 0; offset <= 16; offset += 8) {
453 size_t allocated = (64 - offset);
454 void *test_ptr = malloc(allocated);
455 size_t wasted = malloc_usable_size(test_ptr) - allocated;
466gc_compute_malloc_offset(
void)
474rb_malloc_grow_capa(
size_t current,
size_t type_size)
476 size_t current_capacity = current;
477 if (current_capacity < 4) {
478 current_capacity = 4;
480 current_capacity *= type_size;
483 size_t new_capacity = (current_capacity * 2);
486 if (rb_popcount64(new_capacity) != 1) {
487 new_capacity = (size_t)(1 << (64 - nlz_int64(new_capacity)));
490 new_capacity -= malloc_offset;
491 new_capacity /= type_size;
492 if (current > new_capacity) {
493 rb_bug(
"rb_malloc_grow_capa: current_capacity=%zu, new_capacity=%zu, malloc_offset=%zu", current, new_capacity, malloc_offset);
499static inline struct rbimpl_size_overflow_tag
500size_mul_add_overflow(size_t x, size_t y, size_t z)
502 struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(x, y);
503 struct rbimpl_size_overflow_tag u = rbimpl_size_add_overflow(t.result, z);
504 return (
struct rbimpl_size_overflow_tag) { t.overflowed || u.overflowed, u.result };
507static inline struct rbimpl_size_overflow_tag
508size_mul_add_mul_overflow(size_t x, size_t y, size_t z, size_t w)
510 struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(x, y);
511 struct rbimpl_size_overflow_tag u = rbimpl_size_mul_overflow(z, w);
512 struct rbimpl_size_overflow_tag v = rbimpl_size_add_overflow(t.result, u.result);
513 return (
struct rbimpl_size_overflow_tag) { t.overflowed || u.overflowed || v.overflowed, v.result };
516PRINTF_ARGS(NORETURN(
static void gc_raise(
VALUE,
const char*, ...)), 2, 3);
519size_mul_or_raise(
size_t x,
size_t y,
VALUE exc)
521 struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(x, y);
522 if (LIKELY(!t.overflowed)) {
525 else if (rb_during_gc()) {
531 "integer overflow: %"PRIuSIZE
534 x, y, (
size_t)SIZE_MAX);
539rb_size_mul_or_raise(
size_t x,
size_t y,
VALUE exc)
541 return size_mul_or_raise(x, y, exc);
545size_mul_add_or_raise(
size_t x,
size_t y,
size_t z,
VALUE exc)
547 struct rbimpl_size_overflow_tag t = size_mul_add_overflow(x, y, z);
548 if (LIKELY(!t.overflowed)) {
551 else if (rb_during_gc()) {
557 "integer overflow: %"PRIuSIZE
561 x, y, z, (
size_t)SIZE_MAX);
566rb_size_mul_add_or_raise(
size_t x,
size_t y,
size_t z,
VALUE exc)
568 return size_mul_add_or_raise(x, y, z, exc);
572size_mul_add_mul_or_raise(
size_t x,
size_t y,
size_t z,
size_t w,
VALUE exc)
574 struct rbimpl_size_overflow_tag t = size_mul_add_mul_overflow(x, y, z, w);
575 if (LIKELY(!t.overflowed)) {
578 else if (rb_during_gc()) {
584 "integer overflow: %"PRIdSIZE
589 x, y, z, w, (
size_t)SIZE_MAX);
593#if defined(HAVE_RB_GC_GUARDED_PTR_VAL) && HAVE_RB_GC_GUARDED_PTR_VAL
595volatile VALUE rb_gc_guarded_val;
597rb_gc_guarded_ptr_val(
volatile VALUE *ptr,
VALUE val)
599 rb_gc_guarded_val = val;
605static const char *obj_type_name(
VALUE obj);
611rb_gc_atfork_global_locks(
void)
617#include "gc/default/default.c"
619#if USE_MODULAR_GC && !defined(HAVE_DLOPEN)
620# error "Modular GC requires dlopen"
624typedef struct gc_function_map {
626 void *(*objspace_alloc)(void);
627 void (*objspace_init)(
void *objspace_ptr);
628 void *(*ractor_cache_alloc)(
void *objspace_ptr,
void *ractor);
629 void (*objspace_retire_gc)(
void *objspace_ptr);
630 void (*set_params)(
void *objspace_ptr);
633 void (*shutdown_free_objects)(
void *objspace_ptr);
634 void (*objspace_free)(
void *objspace_ptr);
635 void (*ractor_cache_free)(
void *objspace_ptr,
void *cache);
637 void (*start)(
void *objspace_ptr,
bool full_mark,
bool immediate_mark,
bool immediate_sweep,
bool compact);
638 bool (*during_gc_p)(
void *objspace_ptr);
639 void (*prepare_heap)(
void *objspace_ptr);
640 void (*gc_enable)(
void *objspace_ptr);
641 void (*gc_disable)(
void *objspace_ptr,
bool finish_current_gc);
642 bool (*gc_enabled_p)(
void *objspace_ptr);
643 bool (*user_gc_disabled_set)(
void *objspace_ptr,
bool disable);
644 bool (*user_gc_disabled_p)(
void *objspace_ptr);
645 bool (*multi_objspace_p)(void);
646 bool (*during_global_gc_p)(
void *objspace_ptr);
647 bool (*during_postmortem_p)(
void *objspace_ptr);
648 bool (*obj_foreign_p)(
void *objspace_ptr,
VALUE obj);
649 bool (*shref_marked_p)(
void *objspace_ptr,
VALUE obj);
650 size_t (*heap_page_count)(
void *objspace_ptr);
651 void (*objspace_absorb)(
void *dst_ptr,
void *src_ptr);
652 void (*gc_rest)(
void *objspace_ptr);
653 VALUE (*config_get)(
void *objpace_ptr);
654 void (*config_set)(
void *objspace_ptr,
VALUE hash);
655 void (*stress_set)(
void *objspace_ptr,
VALUE flag);
656 VALUE (*stress_get)(
void *objspace_ptr);
659 VALUE (*new_obj)(
void *objspace_ptr,
void *cache_ptr,
VALUE klass,
VALUE flags,
bool wb_protected,
size_t alloc_size,
size_t *actual_alloc_size);
661 size_t (*obj_slot_size)(
VALUE obj);
662 size_t (*size_slot_size)(
void *objspace_ptr,
size_t size);
663 bool (*size_allocatable_p)(
size_t size);
664 size_t (*max_allocation_size)(void);
666 void *(*malloc)(
void *objspace_ptr,
size_t size,
bool gc_allowed);
667 void *(*calloc)(
void *objspace_ptr,
size_t size,
bool gc_allowed);
668 void *(*realloc)(
void *objspace_ptr,
void *ptr,
size_t new_size,
size_t old_size,
bool gc_allowed);
669 void (*free)(
void *objspace_ptr,
void *ptr,
size_t old_size);
670 void (*adjust_memory_usage)(
void *objspace_ptr, ssize_t diff);
672 void (*mark)(
void *objspace_ptr,
VALUE obj);
673 void (*mark_and_move)(
void *objspace_ptr,
VALUE *ptr);
674 void (*mark_and_pin)(
void *objspace_ptr,
VALUE obj);
675 void (*mark_maybe)(
void *objspace_ptr,
VALUE obj);
677 void (*declare_weak_references)(
void *objspace_ptr,
VALUE obj);
678 bool (*handle_weak_references_alive_p)(
void *objspace_ptr,
VALUE obj);
680 void (*register_pinning_obj)(
void *objspace_ptr,
VALUE obj);
681 bool (*object_moved_p)(
void *objspace_ptr,
VALUE obj);
682 bool (*pinned_p)(
void *objspace_ptr,
VALUE obj);
683 VALUE (*location)(
void *objspace_ptr,
VALUE value);
685 void (*writebarrier)(
void *objspace_ptr,
VALUE a,
VALUE b);
686 void (*writebarrier_unprotect)(
void *objspace_ptr,
VALUE obj);
687 void (*writebarrier_remember)(
void *objspace_ptr,
VALUE obj);
688 void (*obj_became_shareable)(
void *objspace_ptr,
VALUE obj);
690 void (*each_objects)(
void *objspace_ptr, int (*callback)(
void *,
void *, size_t,
void *),
void *data);
691 void (*each_objects_shareable)(
void *objspace_ptr, int (*callback)(
void *,
void *, size_t,
void *),
void *data);
692 void (*each_objects_foreign)(
void *objspace_ptr, int (*callback)(
void *,
void *, size_t,
void *),
void *data);
693 void (*each_object)(
void *objspace_ptr, void (*func)(
VALUE obj,
void *data),
void *data);
695 void (*make_zombie)(
void *objspace_ptr,
VALUE obj, void (*dfree)(
void *),
void *data);
697 void (*undefine_finalizer)(
void *objspace_ptr,
VALUE obj);
698 void (*copy_finalizer)(
void *objspace_ptr,
VALUE dest,
VALUE obj);
699 void (*shutdown_call_finalizer)(
void *objspace_ptr);
701 void (*before_fork)(
void *objspace_ptr);
702 void (*after_fork)(
void *objspace_ptr, rb_pid_t pid);
704 void (*set_measure_total_time)(
void *objspace_ptr,
VALUE flag);
705 bool (*get_measure_total_time)(
void *objspace_ptr);
706 unsigned long long (*get_total_time)(
void *objspace_ptr);
707 size_t (*gc_count)(
void *objspace_ptr);
708 VALUE (*latest_gc_info)(
void *objspace_ptr,
VALUE key);
709 VALUE (*stat)(
void *objspace_ptr,
VALUE hash_or_sym);
710 VALUE (*stat_heap)(
void *objspace_ptr,
VALUE heap_name,
VALUE hash_or_sym);
711 const char *(*active_gc_name)(void);
714 bool (*live_object_p)(
void *objspace_ptr,
const void *ptr);
715 bool (*garbage_object_p)(
void *objspace_ptr,
VALUE obj);
716 void (*set_event_hook)(
void *objspace_ptr,
const rb_event_flag_t event);
717 void (*copy_attributes)(
void *objspace_ptr,
VALUE dest,
VALUE obj);
719 bool modular_gc_loaded_p;
720} rb_gc_function_map_t;
722static rb_gc_function_map_t rb_gc_functions;
724# define RUBY_GC_LIBRARY "RUBY_GC_LIBRARY"
725# define MODULAR_GC_DIR STRINGIZE(modular_gc_dir)
728ruby_modular_gc_init(
void)
733 const char *gc_so_file = getenv(RUBY_GC_LIBRARY);
735 rb_gc_function_map_t gc_functions = { 0 };
737 char *gc_so_path = NULL;
742 for (
size_t i = 0; i < strlen(gc_so_file); i++) {
743 char c = gc_so_file[i];
744 if (isalnum(c))
continue;
750 fprintf(stderr,
"Only alphanumeric, dash, and underscore is allowed in "RUBY_GC_LIBRARY
"\n");
755 size_t gc_so_path_size = strlen(MODULAR_GC_DIR
"librubygc." DLEXT) + strlen(gc_so_file) + 1;
758 size_t prefix_len = 0;
759 if (dladdr((
void *)(uintptr_t)ruby_modular_gc_init, &dli)) {
760 const char *base = strrchr(dli.dli_fname,
'/');
763# define end_with_p(lit) \
764 (prefix_len >= (tail = rb_strlen_lit(lit)) && \
765 memcmp(base - tail, lit, tail) == 0)
767 prefix_len = base - dli.dli_fname;
768 if (end_with_p(
"/bin") || end_with_p(
"/lib")) {
771 prefix_len += MODULAR_GC_DIR[0] !=
'/';
772 gc_so_path_size += prefix_len;
776 gc_so_path = alloca(gc_so_path_size);
778 size_t gc_so_path_idx = 0;
779#define GC_SO_PATH_APPEND(str) do { \
780 gc_so_path_idx += strlcpy(gc_so_path + gc_so_path_idx, str, gc_so_path_size - gc_so_path_idx); \
783 if (prefix_len > 0) {
784 memcpy(gc_so_path, dli.dli_fname, prefix_len);
785 gc_so_path_idx = prefix_len;
788 GC_SO_PATH_APPEND(MODULAR_GC_DIR
"librubygc.");
789 GC_SO_PATH_APPEND(gc_so_file);
790 GC_SO_PATH_APPEND(DLEXT);
791 GC_ASSERT(gc_so_path_idx == gc_so_path_size - 1);
792#undef GC_SO_PATH_APPEND
795 handle = dlopen(gc_so_path, RTLD_LAZY | RTLD_GLOBAL);
797 fprintf(stderr,
"ruby_modular_gc_init: Shared library %s cannot be opened: %s\n", gc_so_path, dlerror());
801 gc_functions.modular_gc_loaded_p =
true;
804 unsigned int err_count = 0;
806# define load_modular_gc_func(name) do { \
808 const char *func_name = "rb_gc_impl_" #name; \
809 gc_functions.name = dlsym(handle, func_name); \
810 if (!gc_functions.name) { \
811 fprintf(stderr, "ruby_modular_gc_init: %s function not exported by library %s\n", func_name, gc_so_path); \
816 gc_functions.name = rb_gc_impl_##name; \
821 load_modular_gc_func(objspace_alloc);
822 load_modular_gc_func(objspace_init);
823 load_modular_gc_func(ractor_cache_alloc);
824 load_modular_gc_func(objspace_retire_gc);
825 load_modular_gc_func(set_params);
826 load_modular_gc_func(init);
828 load_modular_gc_func(shutdown_free_objects);
829 load_modular_gc_func(objspace_free);
830 load_modular_gc_func(ractor_cache_free);
832 load_modular_gc_func(start);
833 load_modular_gc_func(during_gc_p);
834 load_modular_gc_func(prepare_heap);
835 load_modular_gc_func(gc_enable);
836 load_modular_gc_func(gc_disable);
837 load_modular_gc_func(gc_enabled_p);
838 load_modular_gc_func(user_gc_disabled_set);
839 load_modular_gc_func(user_gc_disabled_p);
840 load_modular_gc_func(multi_objspace_p);
841 load_modular_gc_func(during_global_gc_p);
842 load_modular_gc_func(during_postmortem_p);
843 load_modular_gc_func(obj_foreign_p);
844 load_modular_gc_func(shref_marked_p);
845 load_modular_gc_func(heap_page_count);
846 load_modular_gc_func(objspace_absorb);
847 load_modular_gc_func(gc_rest);
848 load_modular_gc_func(config_set);
849 load_modular_gc_func(config_get);
850 load_modular_gc_func(stress_set);
851 load_modular_gc_func(stress_get);
852 load_modular_gc_func(get_vm_context);
854 load_modular_gc_func(new_obj);
855 load_modular_gc_func(zjit_new_obj_fastpath);
856 load_modular_gc_func(obj_slot_size);
857 load_modular_gc_func(size_slot_size);
858 load_modular_gc_func(size_allocatable_p);
859 load_modular_gc_func(max_allocation_size);
861 load_modular_gc_func(malloc);
862 load_modular_gc_func(calloc);
863 load_modular_gc_func(realloc);
864 load_modular_gc_func(free);
865 load_modular_gc_func(adjust_memory_usage);
867 load_modular_gc_func(mark);
868 load_modular_gc_func(mark_and_move);
869 load_modular_gc_func(mark_and_pin);
870 load_modular_gc_func(mark_maybe);
872 load_modular_gc_func(declare_weak_references);
873 load_modular_gc_func(handle_weak_references_alive_p);
875 load_modular_gc_func(register_pinning_obj);
876 load_modular_gc_func(object_moved_p);
877 load_modular_gc_func(pinned_p);
878 load_modular_gc_func(location);
880 load_modular_gc_func(writebarrier);
881 load_modular_gc_func(writebarrier_unprotect);
882 load_modular_gc_func(writebarrier_remember);
883 load_modular_gc_func(obj_became_shareable);
885 load_modular_gc_func(each_objects);
886 load_modular_gc_func(each_objects_shareable);
887 load_modular_gc_func(each_objects_foreign);
888 load_modular_gc_func(each_object);
890 load_modular_gc_func(make_zombie);
891 load_modular_gc_func(define_finalizer);
892 load_modular_gc_func(undefine_finalizer);
893 load_modular_gc_func(copy_finalizer);
894 load_modular_gc_func(shutdown_call_finalizer);
896 load_modular_gc_func(before_fork);
897 load_modular_gc_func(after_fork);
899 load_modular_gc_func(set_measure_total_time);
900 load_modular_gc_func(get_measure_total_time);
901 load_modular_gc_func(get_total_time);
902 load_modular_gc_func(gc_count);
903 load_modular_gc_func(latest_gc_info);
904 load_modular_gc_func(stat);
905 load_modular_gc_func(stat_heap);
906 load_modular_gc_func(active_gc_name);
908 load_modular_gc_func(object_metadata);
909 load_modular_gc_func(live_object_p);
910 load_modular_gc_func(garbage_object_p);
911 load_modular_gc_func(set_event_hook);
912 load_modular_gc_func(copy_attributes);
915 fprintf(stderr,
"ruby_modular_gc_init: found %u missing exports in library %s\n", err_count, gc_so_path);
919# undef load_modular_gc_func
921 rb_gc_functions = gc_functions;
925# define rb_gc_impl_objspace_alloc rb_gc_functions.objspace_alloc
926# define rb_gc_impl_objspace_init rb_gc_functions.objspace_init
927# define rb_gc_impl_ractor_cache_alloc rb_gc_functions.ractor_cache_alloc
928# define rb_gc_impl_objspace_retire_gc rb_gc_functions.objspace_retire_gc
929# define rb_gc_impl_set_params rb_gc_functions.set_params
930# define rb_gc_impl_init rb_gc_functions.init
932# define rb_gc_impl_shutdown_free_objects rb_gc_functions.shutdown_free_objects
933# define rb_gc_impl_objspace_free rb_gc_functions.objspace_free
934# define rb_gc_impl_ractor_cache_free rb_gc_functions.ractor_cache_free
936# define rb_gc_impl_start rb_gc_functions.start
937# define rb_gc_impl_during_gc_p rb_gc_functions.during_gc_p
938# define rb_gc_impl_prepare_heap rb_gc_functions.prepare_heap
939# define rb_gc_impl_gc_enable rb_gc_functions.gc_enable
940# define rb_gc_impl_gc_disable rb_gc_functions.gc_disable
941# define rb_gc_impl_gc_enabled_p rb_gc_functions.gc_enabled_p
942# define rb_gc_impl_user_gc_disabled_set rb_gc_functions.user_gc_disabled_set
943# define rb_gc_impl_user_gc_disabled_p rb_gc_functions.user_gc_disabled_p
944# define rb_gc_impl_multi_objspace_p rb_gc_functions.multi_objspace_p
945# define rb_gc_impl_during_global_gc_p rb_gc_functions.during_global_gc_p
946# define rb_gc_impl_during_postmortem_p rb_gc_functions.during_postmortem_p
947# define rb_gc_impl_obj_foreign_p rb_gc_functions.obj_foreign_p
948# define rb_gc_impl_shref_marked_p rb_gc_functions.shref_marked_p
949# define rb_gc_impl_heap_page_count rb_gc_functions.heap_page_count
950# define rb_gc_impl_objspace_absorb rb_gc_functions.objspace_absorb
951# define rb_gc_impl_gc_rest rb_gc_functions.gc_rest
952# define rb_gc_impl_config_get rb_gc_functions.config_get
953# define rb_gc_impl_config_set rb_gc_functions.config_set
954# define rb_gc_impl_stress_set rb_gc_functions.stress_set
955# define rb_gc_impl_stress_get rb_gc_functions.stress_get
956# define rb_gc_impl_get_vm_context rb_gc_functions.get_vm_context
958# define rb_gc_impl_new_obj rb_gc_functions.new_obj
959# define rb_gc_impl_zjit_new_obj_fastpath rb_gc_functions.zjit_new_obj_fastpath
960# define rb_gc_impl_obj_slot_size rb_gc_functions.obj_slot_size
961# define rb_gc_impl_size_slot_size rb_gc_functions.size_slot_size
962# define rb_gc_impl_size_allocatable_p rb_gc_functions.size_allocatable_p
963# define rb_gc_impl_max_allocation_size rb_gc_functions.max_allocation_size
965# define rb_gc_impl_malloc rb_gc_functions.malloc
966# define rb_gc_impl_calloc rb_gc_functions.calloc
967# define rb_gc_impl_realloc rb_gc_functions.realloc
968# define rb_gc_impl_free rb_gc_functions.free
969# define rb_gc_impl_adjust_memory_usage rb_gc_functions.adjust_memory_usage
971# define rb_gc_impl_mark rb_gc_functions.mark
972# define rb_gc_impl_mark_and_move rb_gc_functions.mark_and_move
973# define rb_gc_impl_mark_and_pin rb_gc_functions.mark_and_pin
974# define rb_gc_impl_mark_maybe rb_gc_functions.mark_maybe
976# define rb_gc_impl_declare_weak_references rb_gc_functions.declare_weak_references
977# define rb_gc_impl_handle_weak_references_alive_p rb_gc_functions.handle_weak_references_alive_p
979# define rb_gc_impl_register_pinning_obj rb_gc_functions.register_pinning_obj
980# define rb_gc_impl_object_moved_p rb_gc_functions.object_moved_p
981# define rb_gc_impl_pinned_p rb_gc_functions.pinned_p
982# define rb_gc_impl_location rb_gc_functions.location
984# define rb_gc_impl_writebarrier rb_gc_functions.writebarrier
985# define rb_gc_impl_writebarrier_unprotect rb_gc_functions.writebarrier_unprotect
986# define rb_gc_impl_writebarrier_remember rb_gc_functions.writebarrier_remember
987# define rb_gc_impl_obj_became_shareable rb_gc_functions.obj_became_shareable
989# define rb_gc_impl_each_objects rb_gc_functions.each_objects
990# define rb_gc_impl_each_objects_shareable rb_gc_functions.each_objects_shareable
991# define rb_gc_impl_each_objects_foreign rb_gc_functions.each_objects_foreign
992# define rb_gc_impl_each_object rb_gc_functions.each_object
994# define rb_gc_impl_make_zombie rb_gc_functions.make_zombie
995# define rb_gc_impl_define_finalizer rb_gc_functions.define_finalizer
996# define rb_gc_impl_undefine_finalizer rb_gc_functions.undefine_finalizer
997# define rb_gc_impl_copy_finalizer rb_gc_functions.copy_finalizer
998# define rb_gc_impl_shutdown_call_finalizer rb_gc_functions.shutdown_call_finalizer
1000# define rb_gc_impl_before_fork rb_gc_functions.before_fork
1001# define rb_gc_impl_after_fork rb_gc_functions.after_fork
1003# define rb_gc_impl_set_measure_total_time rb_gc_functions.set_measure_total_time
1004# define rb_gc_impl_get_measure_total_time rb_gc_functions.get_measure_total_time
1005# define rb_gc_impl_get_total_time rb_gc_functions.get_total_time
1006# define rb_gc_impl_gc_count rb_gc_functions.gc_count
1007# define rb_gc_impl_latest_gc_info rb_gc_functions.latest_gc_info
1008# define rb_gc_impl_stat rb_gc_functions.stat
1009# define rb_gc_impl_stat_heap rb_gc_functions.stat_heap
1010# define rb_gc_impl_active_gc_name rb_gc_functions.active_gc_name
1012# define rb_gc_impl_object_metadata rb_gc_functions.object_metadata
1013# define rb_gc_impl_live_object_p rb_gc_functions.live_object_p
1014# define rb_gc_impl_garbage_object_p rb_gc_functions.garbage_object_p
1015# define rb_gc_impl_set_event_hook rb_gc_functions.set_event_hook
1016# define rb_gc_impl_copy_attributes rb_gc_functions.copy_attributes
1019#ifdef RUBY_ASAN_ENABLED
1021asan_death_callback(
void)
1024 rb_bug_without_die(
"ASAN error");
1032rb_gc_init_objspaces(
void)
1035 ruby_modular_gc_init();
1038 rb_vm_t *vm = ruby_current_vm_ptr;
1040 void *
objspace = rb_gc_impl_objspace_alloc();
1042 vm->ractor.main_ractor->objspace =
objspace;
1043 rb_gc_impl_objspace_init(
objspace);
1044 rb_gc_impl_stress_set(
objspace, initial_stress);
1046#ifdef RUBY_ASAN_ENABLED
1047 __sanitizer_set_death_callback(asan_death_callback);
1054static bool gc_ever_multi_ractor =
false;
1057rb_gc_ever_multi_ractor_p(
void)
1059 if (!gc_ever_multi_ractor && rb_multi_ractor_p()) gc_ever_multi_ractor =
true;
1060 return gc_ever_multi_ractor;
1066rb_gc_objspace_alloc(
void)
1068 gc_ever_multi_ractor =
true;
1069 if (!rb_gc_impl_multi_objspace_p()) {
1071 return rb_gc_get_objspace();
1073 void *
objspace = rb_gc_impl_objspace_alloc();
1074 rb_gc_impl_objspace_init(
objspace);
1082 rb_gc_impl_objspace_free(
objspace);
1086rb_gc_obj_slot_size(
VALUE obj)
1088 return rb_gc_impl_obj_slot_size(obj);
1092gc_validate_pc(
VALUE obj)
1100 if (cfp && VM_FRAME_RUBYFRAME_P(cfp) && CFP_PC(cfp)) {
1101 const VALUE *iseq_encoded = ISEQ_BODY(CFP_ISEQ(cfp))->iseq_encoded;
1102 const VALUE *iseq_encoded_end = iseq_encoded + ISEQ_BODY(CFP_ISEQ(cfp))->iseq_size;
1103 RUBY_ASSERT(CFP_PC(cfp) >= iseq_encoded,
"PC not set when allocating, breaking tracing");
1104 RUBY_ASSERT(CFP_PC(cfp) <= iseq_encoded_end,
"PC not set when allocating, breaking tracing");
1109NOINLINE(
static void gc_newobj_hook(
VALUE obj));
1111gc_newobj_hook(
VALUE obj)
1113 int lev = RB_GC_VM_LOCK_NO_BARRIER();
1115 size_t slot_size = rb_gc_obj_slot_size(obj);
1116 memset((
char *)obj +
sizeof(
struct RBasic), 0, slot_size -
sizeof(
struct RBasic));
1123 bool gc_disabled =
RTEST(rb_gc_local_disable_no_rest());
1127 if (!gc_disabled) rb_gc_local_enable();
1129 RB_GC_VM_UNLOCK_NO_BARRIER(lev);
1144 size_t actual_alloc_size;
1145 VALUE obj = rb_gc_impl_new_obj(cr->objspace, cr->newobj_cache, klass, flags, wb_protected, size, &actual_alloc_size);
1147 GC_ASSERT(actual_alloc_size >= size);
1148 shape_id = rb_shape_transition_slot_size(shape_id, actual_alloc_size);
1150 RBASIC_SET_FULL_SHAPE_ID_NO_CHECKS(obj, shape_id);
1152 gc_validate_pc(obj);
1155 gc_newobj_hook(obj);
1158 if (RUBY_DTRACE_GC_OBJ_NEW_ENABLED()) {
1159 RUBY_DTRACE_GC_OBJ_NEW((
void*)obj, flags);
1162#if RGENGC_CHECK_MODE
1163# ifndef GC_DEBUG_SLOT_FILL_SPECIAL_VALUE
1164# define GC_DEBUG_SLOT_FILL_SPECIAL_VALUE 255
1168 (
void *)(obj +
sizeof(
struct RBasic)),
1169 GC_DEBUG_SLOT_FILL_SPECIAL_VALUE,
1170 rb_gc_obj_slot_size(obj) -
sizeof(
struct RBasic)
1180 return newobj_body(ec, klass, flags, shape_id, wb_protected, size);
1194 return newobj_body(ec, klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER,
true, size);
1198rb_newobj_of_with_shape(
VALUE klass,
VALUE flags, shape_id_t shape_id,
size_t size)
1200 return rb_newobj(GET_EC(), klass, flags, shape_id,
true, size);
1204rb_newobj_of(
VALUE klass,
VALUE flags,
size_t size)
1206 return rb_newobj(GET_EC(), klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_OTHER,
true, size);
1210VALUE class_allocate_complex_instance(
VALUE klass, uint32_t capacity)
1212 VALUE obj = rb_newobj_of_with_shape(klass,
T_OBJECT, rb_shape_transition_extended(ROOT_COMPLEX_SHAPE_ID),
sizeof(
struct RObject));
1213 VALUE fields_obj = rb_imemo_fields_new_complex(obj, ROOT_COMPLEX_SHAPE_ID, capacity,
false);
1214 ROBJECT_SET_EXTENDED(obj, fields_obj);
1219robject_embedded_size(uint32_t fields_count)
1221 size_t size = rb_obj_embedded_size(fields_count);
1222 if (!rb_gc_size_allocatable_p(size)) {
1223 size =
sizeof(
struct RObject);
1229rb_class_allocate_instance_capa(
VALUE klass, attr_index_t max_iv_count)
1235 if (RB_UNLIKELY(max_iv_count > rb_shape_max_capacity())) {
1236 obj = class_allocate_complex_instance(klass, max_iv_count);
1239 size_t size = robject_embedded_size(max_iv_count);
1243 obj = rb_newobj_of_with_shape(klass,
T_OBJECT, rb_shape_transition_robject(0), size);
1246 VALUE *ptr = ROBJECT_FIELDS(obj);
1247 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1248 attr_index_t fields_count = RSHAPE_LEN(shape_id);
1249 attr_index_t capacity = RSHAPE_CAPACITY(shape_id);
1251 for (attr_index_t i = fields_count; i < capacity; i++) {
1259 rb_bug(
"Expected rb_class_allocate_instance to set the class correctly");
1267rb_class_allocate_instance(
VALUE klass)
1269 return rb_class_allocate_instance_capa(klass, RCLASS_MAX_IV_COUNT(klass));
1274rb_zjit_class_allocate_instance_fastpath(
VALUE klass,
size_t *size_out,
VALUE *flags_out)
1276 uint32_t index_tbl_num_entries = RCLASS_MAX_IV_COUNT(klass);
1279 if (RB_UNLIKELY(index_tbl_num_entries > rb_shape_max_capacity())) {
1283 *size_out = robject_embedded_size(index_tbl_num_entries);
1284 *flags_out =
T_OBJECT | rb_shape_transition_robject(0);
1290rb_zjit_newobj_hook_enabled_p(
void)
1297rb_gc_register_pinning_obj(
VALUE obj)
1299 rb_gc_impl_register_pinning_obj(rb_gc_get_objspace(), obj);
1302#define UNEXPECTED_NODE(func) \
1303 rb_bug(#func"(): GC does not handle T_NODE 0x%x(%p) 0x%"PRIxVALUE, \
1304 BUILTIN_TYPE(obj), (void*)(obj), RBASIC(obj)->flags)
1307rb_data_object_check(
VALUE klass)
1312 rb_warn(
"undefining the allocator of T_DATA class %"PRIsVALUE, klass);
1316#define RTYPEDDATA_EMBEDDED_P rbimpl_typeddata_embedded_p
1317#define RB_DATA_TYPE_EMBEDDABLE_P(type) ((type)->flags & RUBY_TYPED_EMBEDDABLE)
1318#define RTYPEDDATA_EMBEDDABLE_P(obj) RB_DATA_TYPE_EMBEDDABLE_P(RTYPEDDATA_TYPE(obj))
1323 RBIMPL_NONNULL_ARG(
type);
1324 if (klass) rb_data_object_check(klass);
1326 VALUE obj = rb_newobj(GET_EC(), klass,
T_DATA, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_RDATA, wb_protected, size);
1328 rb_gc_register_pinning_obj(obj);
1341 if (UNLIKELY(RB_DATA_TYPE_EMBEDDABLE_P(
type))) {
1342 rb_raise(
rb_eTypeError,
"Cannot wrap an embeddable TypedData");
1345 return typed_data_alloc(klass, 0, datap,
type,
sizeof(
struct RTypedData));
1351 if (RB_DATA_TYPE_EMBEDDABLE_P(
type)) {
1353 rb_raise(
rb_eTypeError,
"Embeddable TypedData must be freed immediately");
1357 if (rb_gc_size_allocatable_p(embed_size)) {
1358 VALUE obj = typed_data_alloc(klass, TYPED_DATA_EMBEDDED, 0,
type, embed_size);
1359 memset((
char *)obj + offsetof(
struct RTypedData,
data), 0, size);
1370ruby_xmalloc_usable_size(
void *ptr)
1372#ifdef HAVE_MALLOC_USABLE_SIZE
1373#if CALC_EXACT_MALLOC_SIZE
1377 return malloc_usable_size(ptr);
1385rb_objspace_data_type_memsize(
VALUE obj)
1388 const void *ptr = RTYPEDDATA_GET_DATA(obj);
1391 if (RTYPEDDATA_EMBEDDABLE_P(obj) && !RTYPEDDATA_EMBEDDED_P(obj)) {
1392 size += ruby_xmalloc_usable_size((
void *)ptr);
1396 if (
type->function.dsize) {
1397 size +=
type->function.dsize(ptr);
1405rb_objspace_data_type_name(
VALUE obj)
1411rb_gc_declare_weak_references(
VALUE obj)
1413 rb_gc_impl_declare_weak_references(rb_gc_get_objspace(), obj);
1417rb_gc_handle_weak_references_alive_p(
VALUE obj)
1421 return rb_gc_impl_handle_weak_references_alive_p(rb_gc_get_objspace(), obj);
1425rb_gc_handle_weak_references(
VALUE obj)
1432 if (
type->function.handle_weak_references) {
1433 (
type->function.handle_weak_references)(RTYPEDDATA_GET_DATA(obj));
1437 "rb_gc_handle_weak_references: TypedData %s does not implement handle_weak_references",
1445 switch (imemo_type(obj)) {
1446 case imemo_callcache: {
1448 if (cc->klass !=
Qundef &&
1449 (!rb_gc_handle_weak_references_alive_p(cc->klass) ||
1450 !rb_gc_handle_weak_references_alive_p((
VALUE)cc->cme_))) {
1451 vm_cc_invalidate(cc);
1455 case imemo_subclasses: {
1457 VALUE *entries = rb_imemo_subclasses_entries(obj);
1458 for (uint32_t i = 0; i < subs->count; i++) {
1459 if (entries[i] && !rb_gc_handle_weak_references_alive_p(entries[i])) {
1466 rb_bug(
"rb_gc_handle_weak_references: unexpected imemo type");
1472 rb_bug(
"rb_gc_handle_weak_references: type not supported\n");
1477rb_gc_imemo_needs_cleanup_p(
VALUE obj)
1479 switch (imemo_type(obj)) {
1480 case imemo_constcache:
1485 case imemo_callcache:
1486 case imemo_throw_data:
1487 case imemo_cvar_entry:
1493 case imemo_callinfo:
1497 case imemo_subclasses:
1504 return rb_obj_shape_complex_p(obj);
1522rb_gc_obj_needs_cleanup_p(
VALUE obj)
1529 return rb_gc_imemo_needs_cleanup_p(obj);
1535 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
1536 if (rb_shape_has_fields(shape_id) && rb_shape_layout(shape_id) == SHAPE_ID_LAYOUT_OTHER) {
1561 if (
type & TYPED_DATA_EMBEDDED) {
1571 return (flags & (RSTRING_NOEMBED | RSTRING_FSTR));
1574 return !(flags & RARRAY_EMBED_FLAG);
1577 return (flags & RHASH_ST_TABLE_FLAG);
1580 return (flags & (RMATCH_ONIG | RMATCH_OFFSETS_EXTERNAL)) || USE_DEBUG_COUNTER;
1583 return !(flags & BIGNUM_EMBED_FLAG);
1586 return !(flags & RSTRUCT_EMBED_LEN_MASK);
1593io_fptr_finalize(
void *fptr)
1602 rb_gc_impl_make_zombie(
objspace, obj, io_fptr_finalize, fptr);
1608 void *data = RTYPEDDATA_GET_DATA(obj);
1611 void (*dfree)(
void *) =
type->function.dfree;
1614 bool embedded = RTYPEDDATA_EMBEDDED_P(obj);
1616 bool free_embeddable_data = RB_DATA_TYPE_EMBEDDABLE_P(
type) && !embedded;
1621 RB_DEBUG_COUNTER_INC(obj_data_xfree);
1624 else if (free_immediately) {
1626 if (free_embeddable_data) {
1630 RB_DEBUG_COUNTER_INC(obj_data_imm_free);
1633 rb_gc_impl_make_zombie(
objspace, obj, dfree, data);
1634 RB_DEBUG_COUNTER_INC(obj_data_zombie);
1639 RB_DEBUG_COUNTER_INC(obj_data_empty);
1656 rb_class_classext_free(args->klass, ext, is_prime);
1664 rb_iclass_classext_free(args->klass, ext, is_prime);
1672 RB_DEBUG_COUNTER_INC(obj_free);
1676 if (RUBY_DTRACE_GC_OBJ_FREE_ENABLED()) {
1677 RUBY_DTRACE_GC_OBJ_FREE((
void*)obj,
RBASIC(obj)->flags);
1680 switch (builtin_type) {
1685 rb_bug(
"obj_free() called for broken object");
1691 switch (builtin_type) {
1697 rb_zjit_klass_free(obj);
1700 rb_class_classext_foreach(obj, classext_free, (
void *)&args);
1701 if (RCLASS_CLASSEXT_TBL(obj)) {
1702 st_free_table(RCLASS_CLASSEXT_TBL(obj));
1714#if USE_DEBUG_COUNTER
1717 RB_DEBUG_COUNTER_INC(obj_hash_empty);
1720 RB_DEBUG_COUNTER_INC(obj_hash_1);
1723 RB_DEBUG_COUNTER_INC(obj_hash_2);
1726 RB_DEBUG_COUNTER_INC(obj_hash_3);
1729 RB_DEBUG_COUNTER_INC(obj_hash_4);
1735 RB_DEBUG_COUNTER_INC(obj_hash_5_8);
1739 RB_DEBUG_COUNTER_INC(obj_hash_g8);
1742 if (RHASH_AR_TABLE_P(obj)) {
1743 if (RHASH_AR_TABLE(obj) == NULL) {
1744 RB_DEBUG_COUNTER_INC(obj_hash_null);
1747 RB_DEBUG_COUNTER_INC(obj_hash_ar);
1751 RB_DEBUG_COUNTER_INC(obj_hash_st);
1760 RB_DEBUG_COUNTER_INC(obj_regexp_ptr);
1764 if (!rb_data_free(
objspace, obj))
return false;
1769#if USE_DEBUG_COUNTER
1771 RB_DEBUG_COUNTER_INC(obj_match_ge8);
1774 RB_DEBUG_COUNTER_INC(obj_match_ge4);
1777 RB_DEBUG_COUNTER_INC(obj_match_under4);
1781 onig_region_free(&rm->
as.onig, 0);
1785 RB_DEBUG_COUNTER_INC(obj_match_ptr);
1789 if (
RFILE(obj)->fptr) {
1790 bool closed = rb_io_fptr_finalize_closed(
RFILE(obj)->fptr);
1791 if (!closed) make_io_zombie(
objspace, obj);
1792 RB_DEBUG_COUNTER_INC(obj_file_ptr);
1797 RB_DEBUG_COUNTER_INC(obj_rational);
1800 RB_DEBUG_COUNTER_INC(obj_complex);
1807 rb_class_classext_foreach(obj, classext_iclass_free, (
void *)&args);
1808 if (RCLASS_CLASSEXT_TBL(obj)) {
1809 st_free_table(RCLASS_CLASSEXT_TBL(obj));
1812 RB_DEBUG_COUNTER_INC(obj_iclass_ptr);
1816 RB_DEBUG_COUNTER_INC(obj_float);
1820 if (!BIGNUM_EMBED_P(obj) && BIGNUM_DIGITS(obj)) {
1821 SIZED_FREE_N(BIGNUM_DIGITS(obj), BIGNUM_LEN(obj));
1822 RB_DEBUG_COUNTER_INC(obj_bignum_ptr);
1825 RB_DEBUG_COUNTER_INC(obj_bignum_embed);
1830 UNEXPECTED_NODE(obj_free);
1834 if ((
RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) ||
1835 RSTRUCT(obj)->
as.heap.ptr == NULL) {
1836 RB_DEBUG_COUNTER_INC(obj_struct_embed);
1839 SIZED_FREE_N(RSTRUCT(obj)->
as.heap.ptr, RSTRUCT(obj)->
as.heap.len);
1840 RB_DEBUG_COUNTER_INC(obj_struct_ptr);
1845 RB_DEBUG_COUNTER_INC(obj_symbol);
1849 rb_imemo_free((
VALUE)obj);
1853 rb_bug(
"gc_sweep(): unknown data type 0x%x(%p) 0x%"PRIxVALUE,
1858 rb_gc_impl_make_zombie(
objspace, obj, 0, 0);
1873 const rb_ractor_t *
const cr = rb_current_ractor_raw(
false);
1874 if (cr != NULL && cr != GET_VM()->ractor.main_ractor) {
1875 e &= ~RUBY_INTERNAL_EVENT_FREEOBJ;
1877 rb_gc_impl_set_event_hook(rb_gc_get_objspace(), e);
1881internal_object_p(
VALUE obj)
1883 void *ptr = asan_unpoison_object_temporary(obj);
1885 if (
RBASIC(obj)->flags) {
1888 UNEXPECTED_NODE(internal_object_p);
1897 if (obj == rb_mRubyVMFrozenCore)
1901 if (RCLASS_SINGLETON_P(obj)) {
1902 return rb_singleton_class_internal_p(obj);
1906 if (!
RBASIC(obj)->klass)
break;
1910 if (ptr || !
RBASIC(obj)->flags) {
1911 rb_asan_poison_object(obj);
1917rb_objspace_internal_object_p(
VALUE obj)
1919 return internal_object_p(obj);
1928os_obj_of_i(
void *vstart,
void *vend,
size_t stride,
void *data)
1933 for (; v != (
VALUE)vend; v += stride) {
1934 if (!internal_object_p(v)) {
1954os_shareable_collect_i(
void *vstart,
void *vend,
size_t stride,
void *data)
1959 for (; v != (
VALUE)vend; v += stride) {
1973static void rb_gc_critical_disable(
void);
1974static void rb_gc_critical_enable(
void);
1987 rb_gc_impl_each_objects(rb_gc_get_objspace(), os_obj_of_i, &oes);
1992 if (rb_multi_ractor_p()) {
1997 rb_gc_critical_disable();
2001 void *self = rb_gc_get_objspace();
2004 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
2005 if (r->objspace && r->objspace != self) {
2006 rb_gc_impl_each_objects_shareable(r->objspace, os_shareable_collect_i, &ocs);
2010 rb_gc_critical_enable();
2013 for (
long i = 0; i <
len; i++) {
2076 return os_obj_of(of);
2092 return rb_undefine_finalizer(obj);
2098 rb_check_frozen(obj);
2100 rb_gc_impl_undefine_finalizer(rb_gc_get_objspace(), obj);
2106should_be_callable(
VALUE block)
2109 rb_raise(rb_eArgError,
"wrong type argument %"PRIsVALUE
" (should be callable)",
2115should_be_finalizable(
VALUE obj)
2118 rb_raise(rb_eArgError,
"cannot define finalizer for %s",
2121 rb_check_frozen(obj);
2127 rb_gc_impl_copy_finalizer(rb_gc_get_objspace(), dest, obj);
2207 if (rb_callable_receiver(block) == obj) {
2208 rb_warn(
"finalizer references object to be finalized");
2211 return rb_define_finalizer(obj, block);
2217 should_be_finalizable(obj);
2218 should_be_callable(block);
2220 block = rb_gc_impl_define_finalizer(rb_gc_get_objspace(), obj, block);
2228rb_objspace_call_finalizer(
void)
2230 rb_gc_impl_shutdown_call_finalizer(rb_gc_get_objspace());
2234rb_objspace_free_objects(
void *
objspace)
2236 rb_gc_impl_shutdown_free_objects(
objspace);
2240rb_objspace_garbage_object_p(
VALUE obj)
2242 return !
SPECIAL_CONST_P(obj) && rb_gc_impl_garbage_object_p(rb_gc_get_objspace(), obj);
2246rb_objspace_foreign_object_p(
VALUE obj)
2251#define OBJ_ID_INCREMENT (RUBY_IMMEDIATE_MASK + 1)
2252#define LAST_OBJECT_ID() (object_id_counter * OBJ_ID_INCREMENT)
2254#if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
2255static size_t object_id_counter = 1;
2257static unsigned long long object_id_counter = 1;
2261generate_next_object_id(
void)
2263#if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
2267 unsigned int lock_lev = RB_GC_VM_LOCK();
2268 VALUE id =
ULL2NUM(++object_id_counter * OBJ_ID_INCREMENT);
2269 RB_GC_VM_UNLOCK(lock_lev);
2274static void gc_mark_tbl_no_pin(
st_table *table);
2277class_object_id(
VALUE klass)
2279 VALUE id = RUBY_ATOMIC_VALUE_LOAD(
RCLASS(klass)->object_id);
2281 unsigned int lock_lev = RB_GC_VM_LOCK();
2282 id = generate_next_object_id();
2287 RB_GC_VM_UNLOCK(lock_lev);
2293object_id_get(
VALUE obj, shape_id_t shape_id)
2296 if (rb_shape_complex_p(shape_id)) {
2297 id = rb_obj_field_get(obj, ROOT_COMPLEX_WITH_OBJ_ID);
2300 id = rb_obj_field_get(obj, rb_shape_object_id(shape_id));
2306 rb_bug(
"Object's shape includes object_id, but it's missing %s", rb_obj_info(obj));
2314object_id0(
VALUE obj)
2317 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
2319 if (rb_shape_has_object_id(shape_id)) {
2320 return object_id_get(obj, shape_id);
2323 shape_id_t object_id_shape_id = rb_obj_shape_transition_object_id(obj);
2325 id = generate_next_object_id();
2326 rb_obj_field_set(obj, object_id_shape_id, 0,
id);
2342 return class_object_id(obj);
2351 unsigned int lock_lev = RB_GC_VM_LOCK();
2352 VALUE id = object_id0(obj);
2353 RB_GC_VM_UNLOCK(lock_lev);
2357 return object_id0(obj);
2361rb_gc_obj_free_vm_weak_references(
VALUE obj)
2368 if (rb_obj_gen_fields_p(obj)) {
2375 rb_gc_free_fstring(obj);
2379 rb_gc_free_dsymbol(obj);
2382 switch (imemo_type(obj)) {
2383 case imemo_callinfo:
2402#if SIZEOF_LONG == SIZEOF_VOIDP
2409 return get_heap_object_id(obj);
2413nonspecial_obj_id(
VALUE obj)
2415#if SIZEOF_LONG == SIZEOF_VOIDP
2417#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
2420# error not supported
2427 return rb_find_object_id(NULL, obj, nonspecial_obj_id);
2464 return rb_find_object_id(rb_gc_get_objspace(), obj, object_id);
2468rb_obj_id_p(
VALUE obj)
2480rb_gc_before_updating_jit_code(
void)
2483 rb_yjit_mark_all_writeable();
2486 rb_zjit_mark_all_writable();
2496rb_gc_after_updating_jit_code(
void)
2499 rb_yjit_mark_all_executable();
2502 rb_zjit_mark_all_executable();
2509 size_t *size = (
size_t *)arg;
2512 if (RCLASSEXT_M_TBL(ext)) {
2513 s += rb_id_table_memsize(RCLASSEXT_M_TBL(ext));
2515 if (RCLASSEXT_CONST_TBL(ext)) {
2516 s += rb_id_table_memsize(RCLASSEXT_CONST_TBL(ext));
2518 if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
2519 s += (RCLASSEXT_SUPERCLASS_DEPTH(ext) + 1) *
sizeof(
VALUE);
2528classext_superclasses_memsize(
rb_classext_t *ext,
bool prime,
VALUE box_value,
void *arg)
2530 size_t *size = (
size_t *)arg;
2532 if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
2534 array_size = RCLASSEXT_SUPERCLASS_DEPTH(ext) + 1;
2535 *size += array_size *
sizeof(
VALUE);
2540rb_obj_memsize_of(
VALUE obj)
2553 rb_class_classext_foreach(obj, classext_memsize, (
void *)&size);
2554 rb_class_classext_foreach(obj, classext_superclasses_memsize, (
void *)&size);
2557 if (RICLASS_OWNS_M_TBL_P(obj)) {
2558 if (RCLASS_M_TBL(obj)) {
2559 size += rb_id_table_memsize(RCLASS_M_TBL(obj));
2564 size += rb_str_memsize(obj);
2567 size += rb_ary_memsize(obj);
2570 if (RHASH_ST_TABLE_P(obj)) {
2571 VM_ASSERT(RHASH_ST_TABLE(obj) != NULL);
2573 size += st_memsize(RHASH_ST_TABLE(obj)) -
sizeof(
st_table);
2582 size += rb_objspace_data_type_memsize(obj);
2588 size += onig_region_memsize(&rm->
as.onig);
2594 if (
RFILE(obj)->fptr) {
2595 size += rb_io_memsize(
RFILE(obj)->fptr);
2602 size += rb_imemo_memsize(obj);
2610 if (!(
RBASIC(obj)->flags & BIGNUM_EMBED_FLAG) && BIGNUM_DIGITS(obj)) {
2611 size += BIGNUM_LEN(obj) *
sizeof(BDIGIT);
2616 UNEXPECTED_NODE(obj_memsize_of);
2620 if (RSTRUCT_EMBED_LEN(obj) == 0) {
2621 size +=
sizeof(
VALUE) * RSTRUCT_LEN_RAW(obj);
2630 rb_bug(
"objspace/memsize_of(): unknown data type 0x%x(%p)",
2634 return size + rb_gc_obj_slot_size(obj);
2638set_zero(st_data_t key, st_data_t val, st_data_t arg)
2642 rb_hash_aset(hash, k,
INT2FIX(0));
2653count_objects_i(
VALUE obj,
void *d)
2657 if (
RBASIC(obj)->flags) {
2708count_objects(
int argc,
VALUE *argv,
VALUE os)
2720 for (
size_t i = 0; i <=
T_MASK; i++) {
2724 types[i] = type_sym(i);
2731 rb_gc_impl_each_object(rb_gc_get_objspace(), count_objects_i, &data);
2734 hash = rb_hash_new_capa(2 +
T_MASK);
2737 rb_hash_stlike_foreach(hash, set_zero, hash);
2739 rb_hash_aset(hash, total,
SIZET2NUM(data.total));
2740 rb_hash_aset(hash, free,
SIZET2NUM(data.freed));
2742 for (
size_t i = 0; i <=
T_MASK; i++) {
2743 if (data.counts[i]) {
2744 rb_hash_aset(hash, types[i],
SIZET2NUM(data.counts[i]));
2751#define SET_STACK_END SET_MACHINE_STACK_END(&ec->machine.stack_end)
2753#define STACK_START (ec->machine.stack_start)
2754#define STACK_END (ec->machine.stack_end)
2755#define STACK_LEVEL_MAX (ec->machine.stack_maxsize/sizeof(VALUE))
2757#if STACK_GROW_DIRECTION < 0
2758# define STACK_LENGTH (size_t)(STACK_START - STACK_END)
2759#elif STACK_GROW_DIRECTION > 0
2760# define STACK_LENGTH (size_t)(STACK_END - STACK_START + 1)
2762# define STACK_LENGTH ((STACK_END < STACK_START) ? (size_t)(STACK_START - STACK_END) \
2763 : (size_t)(STACK_END - STACK_START + 1))
2765#if !STACK_GROW_DIRECTION
2766int ruby_stack_grow_direction;
2768ruby_get_stack_grow_direction(
volatile VALUE *addr)
2771 SET_MACHINE_STACK_END(&end);
2773 if (end > addr)
return ruby_stack_grow_direction = 1;
2774 return ruby_stack_grow_direction = -1;
2783 if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
2784 return STACK_LENGTH;
2787#define PREVENT_STACK_OVERFLOW 1
2788#ifndef PREVENT_STACK_OVERFLOW
2789#if !(defined(POSIX_SIGNAL) && defined(SIGSEGV) && defined(HAVE_SIGALTSTACK))
2790# define PREVENT_STACK_OVERFLOW 1
2792# define PREVENT_STACK_OVERFLOW 0
2795#if PREVENT_STACK_OVERFLOW && !defined(__EMSCRIPTEN__)
2801 size_t length = STACK_LENGTH;
2802 size_t maximum_length = STACK_LEVEL_MAX - water_mark;
2804 return length > maximum_length;
2807#define stack_check(ec, water_mark) FALSE
2810#define STACKFRAME_FOR_CALL_CFUNC 2048
2815 return stack_check(ec, STACKFRAME_FOR_CALL_CFUNC);
2821 return stack_check(GET_EC(), STACKFRAME_FOR_CALL_CFUNC);
2835 return cr != NULL ? &cr->mark_func_data : &GET_VM()->gc.mark_func_data;
2838 return &cr->mark_func_data;
2841#define GC_MARK_FUNC_DATA_SLOTP() gc_mark_func_data_slotp_of(rb_current_ractor_raw(false))
2845#define RB_GC_MARK_OR_TRAVERSE(func, obj_or_ptr, obj, check_obj) do { \
2846 if (!RB_SPECIAL_CONST_P(obj)) { \
2847 rb_ractor_t *const mark_cr = rb_current_ractor_raw(false); \
2848 struct gc_mark_func_data_struct **mfdp = gc_mark_func_data_slotp_of(mark_cr); \
2849 struct gc_mark_func_data_struct *mark_func_data = *mfdp; \
2850 void *objspace = gc_current_objspace_of(mark_cr); \
2851 if (LIKELY(mark_func_data == NULL)) { \
2852 GC_ASSERT(rb_gc_impl_during_gc_p(objspace)); \
2853 (func)(objspace, (obj_or_ptr)); \
2855 else if (check_obj ? \
2856 rb_gc_impl_live_object_p(objspace, (const void *)obj) && \
2857 !rb_gc_impl_garbage_object_p(objspace, obj) : \
2859 GC_ASSERT(!rb_gc_impl_during_gc_p(objspace)); \
2861 mark_func_data->mark_func((obj), mark_func_data->data); \
2862 *mfdp = mark_func_data; \
2868gc_mark_internal(
VALUE obj)
2870 RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark, obj, obj,
false);
2876 gc_mark_internal(obj);
2880rb_gc_mark_and_move(
VALUE *ptr)
2882 RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark_and_move, ptr, *ptr,
false);
2886gc_mark_and_pin_internal(
VALUE obj)
2888 RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark_and_pin, obj, obj,
false);
2894 gc_mark_and_pin_internal(obj);
2898gc_mark_maybe_internal(
VALUE obj)
2900 RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark_maybe, obj, obj,
true);
2906 gc_mark_maybe_internal(obj);
2909ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(
static void each_location(
register const VALUE *x,
register long n,
void (*cb)(
VALUE,
void *),
void *data));
2911each_location(
register const VALUE *x,
register long n,
void (*cb)(
VALUE,
void *),
void *data)
2922each_location_ptr(
const VALUE *start,
const VALUE *end,
void (*cb)(
VALUE,
void *),
void *data)
2924 if (end <= start)
return;
2925 each_location(start, end - start, cb, data);
2929gc_mark_maybe_each_location(
VALUE obj,
void *data)
2931 gc_mark_maybe_internal(obj);
2937 each_location_ptr(start, end, gc_mark_maybe_each_location, NULL);
2941rb_gc_mark_values(
long n,
const VALUE *values)
2943 for (
long i = 0; i < n; i++) {
2944 gc_mark_internal(values[i]);
2949rb_gc_mark_vm_stack_values(
long n,
const VALUE *values)
2951 for (
long i = 0; i < n; i++) {
2952 gc_mark_and_pin_internal(values[i]);
2957mark_key(st_data_t key, st_data_t value, st_data_t data)
2959 gc_mark_and_pin_internal((
VALUE)key);
2969 st_foreach(tbl, mark_key, (st_data_t)rb_gc_get_objspace());
2973mark_keyvalue(st_data_t key, st_data_t value, st_data_t data)
2975 gc_mark_internal((
VALUE)key);
2976 gc_mark_internal((
VALUE)value);
2982pin_key_pin_value(st_data_t key, st_data_t value, st_data_t data)
2984 gc_mark_and_pin_internal((
VALUE)key);
2985 gc_mark_and_pin_internal((
VALUE)value);
2991pin_key_mark_value(st_data_t key, st_data_t value, st_data_t data)
2993 gc_mark_and_pin_internal((
VALUE)key);
2994 gc_mark_internal((
VALUE)value);
3000mark_hash(
VALUE hash)
3002 if (rb_hash_compare_by_id_p(hash)) {
3003 rb_hash_stlike_foreach(hash, pin_key_mark_value, 0);
3006 rb_hash_stlike_foreach(hash, mark_keyvalue, 0);
3009 gc_mark_internal(RHASH(hash)->ifnone);
3017 st_foreach(tbl, pin_key_pin_value, 0);
3020static enum rb_id_table_iterator_result
3023 gc_mark_internal(me);
3025 return ID_TABLE_CONTINUE;
3032 rb_id_table_foreach_values(tbl, mark_method_entry_i,
objspace);
3036static enum rb_id_table_iterator_result
3041 gc_mark_internal(ce->value);
3042 gc_mark_internal(ce->file);
3044 return ID_TABLE_CONTINUE;
3051 rb_id_table_foreach_values(tbl, mark_const_entry_i,
objspace);
3054#if STACK_GROW_DIRECTION < 0
3055#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START)
3056#elif STACK_GROW_DIRECTION > 0
3057#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_START, (end) = STACK_END+(appendix))
3059#define GET_STACK_BOUNDS(start, end, appendix) \
3060 ((STACK_END < STACK_START) ? \
3061 ((start) = STACK_END, (end) = STACK_START) : ((start) = STACK_START, (end) = STACK_END+(appendix)))
3065gc_mark_machine_stack_location_maybe(
VALUE obj,
void *data)
3067 gc_mark_maybe_internal(obj);
3069#ifdef RUBY_ASAN_ENABLED
3071 void *fake_frame_start;
3072 void *fake_frame_end;
3073 bool is_fake_frame = asan_get_fake_stack_extents(
3074 ec->machine.asan_fake_stack_handle, obj,
3075 ec->machine.stack_start, ec->machine.stack_end,
3076 &fake_frame_start, &fake_frame_end
3078 if (is_fake_frame) {
3079 each_location_ptr(fake_frame_start, fake_frame_end, gc_mark_maybe_each_location, NULL);
3091 return rb_gc_impl_object_moved_p(
objspace, obj);
3101 return rb_gc_impl_location(
objspace, value);
3107 return gc_location_internal(rb_gc_get_objspace(), value);
3110#if defined(__wasm__)
3113static VALUE *rb_stack_range_tmp[2];
3116rb_mark_locations(
void *begin,
void *end)
3118 rb_stack_range_tmp[0] = begin;
3119 rb_stack_range_tmp[1] = end;
3123rb_gc_save_machine_context(
void)
3128# if defined(__EMSCRIPTEN__)
3133 emscripten_scan_stack(rb_mark_locations);
3134 each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe_each_location, NULL);
3136 emscripten_scan_registers(rb_mark_locations);
3137 each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe_each_location, NULL);
3144 VALUE *stack_start, *stack_end;
3146 GET_STACK_BOUNDS(stack_start, stack_end, 1);
3147 each_location_ptr(stack_start, stack_end, gc_mark_maybe_each_location, NULL);
3149 rb_wasm_scan_locals(rb_mark_locations);
3150 each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe_each_location, NULL);
3158rb_gc_save_machine_context(
void)
3162 RB_VM_SAVE_MACHINE_CONTEXT(thread);
3169 rb_gc_mark_machine_context(ec);
3176 VALUE *stack_start, *stack_end;
3178 GET_STACK_BOUNDS(stack_start, stack_end, 0);
3179 RUBY_DEBUG_LOG(
"ec->th:%u stack_start:%p stack_end:%p", rb_ec_thread_ptr(ec)->serial, stack_start, stack_end);
3182#ifdef RUBY_ASAN_ENABLED
3189 each_location_ptr(stack_start, stack_end, gc_mark_machine_stack_location_maybe, data);
3190 int num_regs =
sizeof(ec->machine.regs)/(
sizeof(
VALUE));
3191 each_location((
VALUE*)&ec->machine.regs, num_regs, gc_mark_machine_stack_location_maybe, data);
3195rb_mark_tbl_i(st_data_t key, st_data_t value, st_data_t data)
3197 gc_mark_and_pin_internal((
VALUE)value);
3205 if (!tbl || tbl->num_entries == 0)
return;
3207 st_foreach(tbl, rb_mark_tbl_i, 0);
3213 if (!tbl || tbl->num_entries == 0)
return;
3215 st_foreach(tbl, gc_mark_tbl_no_pin_i, 0);
3221 gc_mark_tbl_no_pin(tbl);
3225rb_gc_mark_set_no_pin(
st_table *tbl)
3227 if (!tbl || tbl->num_entries == 0)
return;
3229 st_foreach(tbl, gc_mark_set_no_pin_i, 0);
3235 return (
type->flags & RUBY_TYPED_DECL_MARKING) != 0;
3241 void *
objspace = rb_gc_get_objspace();
3243 if (RB_LIKELY(rb_gc_impl_during_gc_p(
objspace))) {
3244 return rb_gc_impl_get_vm_context(
objspace)->ec;
3252rb_gc_mark_roots(
void *
objspace,
const char **categoryp)
3255 rb_vm_t *vm = rb_ec_vm_ptr(ec);
3257#define MARK_CHECKPOINT(category) do { \
3258 if (categoryp) *categoryp = category; \
3263 const bool global_gc = rb_gc_impl_during_global_gc_p(
objspace) ||
3264 !rb_gc_impl_multi_objspace_p();
3268 MARK_CHECKPOINT(
"ractor");
3271 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
3272 rb_ractor_mark_local_roots(r);
3277 if (vm->ractor.cnt == 0 && vm->ractor.main_ractor) {
3278 rb_ractor_mark_local_roots(vm->ractor.main_ractor);
3284 for (
size_t i = 0; i < vm->gc.zombie_objspaces_count; i++) {
3285 rb_ractor_t *owner = vm->gc.zombie_objspaces[i].owner;
3287 rb_gc_mark_vm_stack_values((
long)owner->registered_marks_cnt,
3288 owner->registered_marks);
3295 if (!rb_gc_impl_multi_objspace_p()) {
3298 ccan_list_for_each(&vm->ractor.terminated_set,
tr, vmlr_node) {
3299 rb_gc_mark_vm_stack_values((
long)
tr->registered_marks_cnt,
3300 tr->registered_marks);
3306 rb_ractor_mark_local_roots(rb_ec_ractor_ptr(ec));
3312 MARK_CHECKPOINT(
"registered_globals");
3314 for (
size_t i = 0; i < vm->gc.registered_globals.addrs_cnt; i++) {
3315 rb_gc_mark_maybe(*vm->gc.registered_globals.addrs[i]);
3322 MARK_CHECKPOINT(
"trap_list");
3323 rb_gc_mark_values(RUBY_NSIG, vm->trap_list.cmd);
3327 if (global_gc ||
objspace == vm->ractor.main_ractor->objspace) {
3330 MARK_CHECKPOINT(
"end_proc");
3333 MARK_CHECKPOINT(
"vm");
3337 const bool vm_mark_needs_lock = rb_multi_ractor_p() && !global_gc;
3338 unsigned int vm_mark_lock_lev = 0;
3339 if (vm_mark_needs_lock) vm_mark_lock_lev = RB_GC_VM_LOCK_NO_BARRIER();
3342 MARK_CHECKPOINT(
"global_tbl");
3343 rb_gc_mark_global_tbl();
3346 void rb_yjit_root_mark(
void);
3348 if (rb_yjit_enabled_p) {
3349 MARK_CHECKPOINT(
"YJIT");
3350 rb_yjit_root_mark();
3355 void rb_zjit_root_mark(
void);
3356 if (rb_zjit_enabled_p) {
3357 MARK_CHECKPOINT(
"ZJIT");
3358 rb_zjit_root_mark();
3361 if (vm_mark_needs_lock) RB_GC_VM_UNLOCK_NO_BARRIER(vm_mark_lock_lev);
3363 if (global_gc || rb_gc_single_objspace_p()) {
3364 MARK_CHECKPOINT(
"global_symbols");
3365 rb_sym_global_symbols_mark_and_move();
3373 if (!rb_gc_impl_during_postmortem_p(
objspace)) {
3374 MARK_CHECKPOINT(
"machine_context");
3375 mark_current_machine_context(ec);
3378 MARK_CHECKPOINT(
"finish");
3380#undef MARK_CHECKPOINT
3394 if (RCLASSEXT_SUPER(ext)) {
3395 gc_mark_internal(RCLASSEXT_SUPER(ext));
3397 mark_m_tbl(
objspace, RCLASSEXT_M_TBL(ext));
3399 gc_mark_internal(RCLASSEXT_FIELDS_OBJ(ext));
3400 gc_mark_internal(RCLASSEXT_CVC_TBL(ext));
3402 if (!RCLASSEXT_SHARED_CONST_TBL(ext) && RCLASSEXT_CONST_TBL(ext)) {
3403 mark_const_tbl(
objspace, RCLASSEXT_CONST_TBL(ext));
3405 mark_m_tbl(
objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
3406 gc_mark_internal(RCLASSEXT_CC_TBL(ext));
3407 if (RCLASSEXT_SUBCLASSES(ext)) {
3408 gc_mark_internal(RCLASSEXT_SUBCLASSES(ext));
3410 gc_mark_internal(RCLASSEXT_CLASSPATH(ext));
3419 if (RCLASSEXT_SUPER(ext)) {
3420 gc_mark_internal(RCLASSEXT_SUPER(ext));
3422 if (RCLASSEXT_ICLASS_IS_ORIGIN(ext) && !RCLASSEXT_ICLASS_ORIGIN_SHARED_MTBL(ext)) {
3423 mark_m_tbl(
objspace, RCLASSEXT_M_TBL(ext));
3425 if (RCLASSEXT_INCLUDER(ext)) {
3426 gc_mark_internal(RCLASSEXT_INCLUDER(ext));
3428 mark_m_tbl(
objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
3429 gc_mark_internal(RCLASSEXT_CC_TBL(ext));
3430 if (RCLASSEXT_SUBCLASSES(ext)) {
3431 gc_mark_internal(RCLASSEXT_SUBCLASSES(ext));
3435#define TYPED_DATA_REFS_OFFSET_LIST(d) (size_t *)(uintptr_t)RTYPEDDATA_TYPE(d)->function.dmark
3438rb_obj_using_gen_fields_table_p(
VALUE obj)
3449 return rb_obj_gen_fields_p(obj);
3453rb_gc_move_obj_during_marking(
VALUE from,
VALUE to)
3455 if (rb_obj_using_gen_fields_table_p(to)) {
3456 rb_mark_generic_ivar(from);
3465 if (rb_obj_using_gen_fields_table_p(obj)) {
3466 rb_mark_generic_ivar(obj);
3476 rb_bug(
"rb_gc_mark() called for broken object");
3480 UNEXPECTED_NODE(rb_gc_mark);
3484 rb_imemo_mark_and_move(obj,
false);
3491 gc_mark_internal(
RBASIC(obj)->klass);
3496 gc_mark_internal(RCLASS_ATTACHED_OBJECT(obj));
3501 foreach_args.obj = obj;
3502 rb_class_classext_foreach(obj, gc_mark_classext_module, (
void *)&foreach_args);
3503 if (BOX_USER_P(RCLASS_PRIME_BOX(obj))) {
3504 gc_mark_internal(RCLASS_PRIME_BOX(obj)->box_object);
3510 foreach_args.obj = obj;
3511 rb_class_classext_foreach(obj, gc_mark_classext_iclass, (
void *)&foreach_args);
3512 if (BOX_USER_P(RCLASS_PRIME_BOX(obj))) {
3513 gc_mark_internal(RCLASS_PRIME_BOX(obj)->box_object);
3518 if (ARY_SHARED_P(obj)) {
3519 VALUE root = ARY_SHARED_ROOT(obj);
3521 gc_mark_internal(root);
3527 gc_mark_and_pin_internal(root);
3533 for (
long i = 0; i <
len; i++) {
3534 gc_mark_internal(ptr[i]);
3544 gc_mark_internal(RSYMBOL(obj)->fstr);
3548 if (STR_SHARED_P(obj)) {
3549 if (STR_EMBED_P(
RSTRING(obj)->as.heap.aux.shared)) {
3554 gc_mark_and_pin_internal(
RSTRING(obj)->as.heap.aux.shared);
3557 gc_mark_internal(
RSTRING(obj)->as.heap.aux.shared);
3563 void *
const ptr = RTYPEDDATA_GET_DATA(obj);
3565 gc_mark_internal(
RTYPEDDATA(obj)->fields_obj);
3569 size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj);
3571 for (
size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
3572 gc_mark_internal(*(
VALUE *)((
char *)ptr + offset));
3577 if (mark_func) (*mark_func)(ptr);
3585 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
3586 if (rb_shape_embedded_p(shape_id)) {
3587 uint32_t
len = RSHAPE_LEN(shape_id);
3590 for (uint32_t i = 0; i <
len; i++) {
3591 gc_mark_internal(ptr[i]);
3595 if (!rb_gc_checking_shareable()) {
3596 gc_mark_internal(
ROBJECT(obj)->as.extended);
3603 if (
RFILE(obj)->fptr) {
3604 gc_mark_internal(
RFILE(obj)->fptr->self);
3605 gc_mark_internal(
RFILE(obj)->fptr->pathv);
3606 gc_mark_internal(
RFILE(obj)->fptr->tied_io_for_writing);
3607 gc_mark_internal(
RFILE(obj)->fptr->writeconv_asciicompat);
3608 gc_mark_internal(
RFILE(obj)->fptr->writeconv_pre_ecopts);
3609 gc_mark_internal(
RFILE(obj)->fptr->encs.ecopts);
3610 gc_mark_internal(
RFILE(obj)->fptr->write_lock);
3611 gc_mark_internal(
RFILE(obj)->fptr->timeout);
3612 gc_mark_internal(
RFILE(obj)->fptr->wakeup_mutex);
3617 gc_mark_internal(
RREGEXP(obj)->src);
3621 gc_mark_internal(
RMATCH(obj)->regexp);
3623 gc_mark_internal(
RMATCH(obj)->str);
3628 gc_mark_internal(RRATIONAL(obj)->num);
3629 gc_mark_internal(RRATIONAL(obj)->den);
3633 gc_mark_internal(RCOMPLEX(obj)->real);
3634 gc_mark_internal(RCOMPLEX(obj)->imag);
3639 const VALUE *
const ptr = RSTRUCT_CONST_PTR(obj);
3641 for (
long i = 0; i <
len; i++) {
3642 gc_mark_internal(ptr[i]);
3645 gc_mark_internal(RSTRUCT_FIELDS_OBJ(obj));
3654 rb_bug(
"rb_gc_mark(): unknown data type 0x%x(%p) %s",
3656 rb_gc_impl_live_object_p(
objspace, (
void *)obj) ?
"corrupted object" :
"non object");
3661rb_gc_obj_optimal_size(
VALUE obj)
3666 size_t size = rb_ary_size_as_embedded(obj);
3667 if (rb_gc_size_allocatable_p(size)) {
3671 return sizeof(
struct RArray);
3676 if (rb_obj_shape_complex_p(obj)) {
3677 return sizeof(
struct RObject);
3680 size_t size = rb_obj_embedded_size(RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj)));
3681 if (rb_gc_size_allocatable_p(size)) {
3685 return sizeof(
struct RObject);
3691 size_t size = rb_str_size_as_embedded(obj);
3692 if (rb_gc_size_allocatable_p(size)) {
3696 return sizeof(
struct RString);
3702 if (RHASH_AR_TABLE_P(obj)) {
3703 const unsigned bound = RHASH_AR_TABLE_BOUND(obj);
3704 const size_t ar_size = RHASH_AR_SLOT_SIZE(bound);
3705 if (ar_size > RHASH_ST_SLOT_SIZE ||
OBJ_FROZEN(obj)) {
3710 return RHASH_ST_SLOT_SIZE;
3721 rb_gc_impl_writebarrier(rb_gc_get_objspace(), a, b);
3727 rb_gc_impl_writebarrier_unprotect(rb_gc_get_objspace(), obj);
3734rb_gc_writebarrier_remember(
VALUE obj)
3736 rb_gc_impl_writebarrier_remember(rb_gc_get_objspace(), obj);
3742rb_gc_obj_became_shareable(
VALUE obj)
3744 rb_gc_impl_obj_became_shareable(rb_gc_get_objspace(), obj);
3752 rb_gc_impl_copy_attributes(rb_gc_get_objspace(), dest, obj);
3757rb_gc_modular_gc_loaded_p(
void)
3759 return rb_gc_functions.modular_gc_loaded_p;
3763rb_gc_active_gc_name(
void)
3765 const char *gc_name = rb_gc_impl_active_gc_name();
3767 const size_t len = strlen(gc_name);
3768 if (
len > RB_GC_MAX_NAME_LEN) {
3769 rb_bug(
"GC should have a name no more than %d chars long. Currently: %zu (%s)",
3770 RB_GC_MAX_NAME_LEN,
len, gc_name);
3778rb_gc_object_metadata(
VALUE obj)
3780 return rb_gc_impl_object_metadata(rb_gc_get_objspace(), obj);
3788 return rb_gc_impl_ractor_cache_alloc(rb_gc_get_objspace(), ractor);
3792rb_gc_ractor_cache_free(
void *cache)
3794 rb_gc_impl_ractor_cache_free(rb_gc_get_objspace(), cache);
3800#if defined(RUBY_ASAN_ENABLED)
3801 (void)rb_gc_impl_zjit_new_obj_fastpath;
3804 return rb_gc_impl_zjit_new_obj_fastpath(rb_gc_get_objspace(), alloc_size, flags, klass, fastpath);
3815 if (rb_gc_impl_live_object_p(rb_gc_get_objspace(), (
void *)obj)) {
3816 rb_vm_register_global_object(obj);
3827 if (vm->gc.registered_globals.addrs_cnt == vm->gc.registered_globals.addrs_capa) {
3828 size_t nc = vm->gc.registered_globals.addrs_capa ? vm->gc.registered_globals.addrs_capa * 2 : 64;
3829 VALUE **p = realloc(vm->gc.registered_globals.addrs, nc *
sizeof(
VALUE *));
3830 if (!p) rb_bug(
"rb_gc_register_address: out of memory");
3831 vm->gc.registered_globals.addrs = p;
3832 vm->gc.registered_globals.addrs_capa = nc;
3834 vm->gc.registered_globals.addrs[vm->gc.registered_globals.addrs_cnt++] = addr;
3850 for (
size_t i = 0; i < vm->gc.registered_globals.addrs_cnt; i++) {
3851 if (vm->gc.registered_globals.addrs[i] == addr) {
3852 MEMMOVE(&vm->gc.registered_globals.addrs[i], &vm->gc.registered_globals.addrs[i + 1],
3853 VALUE *, vm->gc.registered_globals.addrs_cnt - i - 1);
3854 vm->gc.registered_globals.addrs_cnt--;
3864 rb_gc_register_address(var);
3870 rb_gc_impl_start(rb_gc_get_objspace(),
RTEST(full_mark),
RTEST(immediate_mark),
RTEST(immediate_sweep),
RTEST(compact));
3877 int (*callback)(
void *,
void *, size_t,
void *);
3882each_objects_foreign_i(
void *
objspace,
void *arg)
3886 rb_gc_impl_each_objects_foreign(
objspace, a->callback, a->data);
3934rb_objspace_each_objects(
int (*callback)(
void *,
void *,
size_t,
void *),
void *data)
3939 void *self = rb_gc_get_objspace();
3940 rb_gc_impl_each_objects(self, callback, data);
3947 rb_gc_vm_each_objspace(each_objects_foreign_i, &arg);
3955rb_gc_vm_each_objspace(
void (*func)(
void *
objspace,
void *data),
void *data)
3957 ASSERT_vm_locking();
3961 ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
3963 func(r->objspace, data);
3968 if (r->creating_child_objspace) {
3969 func(r->creating_child_objspace, data);
3972 for (
size_t i = 0; i < vm->gc.zombie_objspaces_count; i++) {
3973 func(vm->gc.zombie_objspaces[i].objspace, data);
3981static void gc_orphan_merge_job(
void *unused);
3989 if (vm->gc.zombie_objspaces_count == vm->gc.zombie_objspaces_capa) {
3990 size_t new_capa = vm->gc.zombie_objspaces_capa ? vm->gc.zombie_objspaces_capa * 2 : 16;
3991 struct rb_objspace_zombie *grown =
3992 realloc(vm->gc.zombie_objspaces, new_capa *
sizeof(
struct rb_objspace_zombie));
3993 if (grown == NULL) rb_bug(
"zombie_objspaces_push: out of memory");
3994 vm->gc.zombie_objspaces = grown;
3995 vm->gc.zombie_objspaces_capa = new_capa;
3997 size_t pages = rb_gc_impl_heap_page_count(
objspace);
3998 vm->gc.zombie_objspaces[vm->gc.zombie_objspaces_count++] = (
struct rb_objspace_zombie){
4000 .owner_slot = owner_slot,
4004 vm->gc.zombie_total_pages += pages;
4015gc_orphan_merge_pjob_ensure(
void)
4017 if (GET_VM()->gc.orphan_merge_pjob == POSTPONED_JOB_HANDLE_INVALID) {
4019 if (GET_VM()->gc.orphan_merge_pjob == POSTPONED_JOB_HANDLE_INVALID) {
4020 rb_bug(
"Could not preregister postponed job for GC");
4027rb_gc_objspace_retire_gc(
void)
4029 rb_gc_impl_objspace_retire_gc(rb_gc_get_objspace());
4033rb_gc_objspace_retire(
void **objspace_slot)
4037 if (!rb_gc_impl_multi_objspace_p()) {
4039 *objspace_slot = NULL;
4045 if (rb_gc_impl_user_gc_disabled_set(*objspace_slot,
false)) {
4050 gc_orphan_merge_pjob_ensure();
4056 zombie_objspaces_push(vm, *objspace_slot, objspace_slot, owner);
4064rb_gc_objspace_disown(
void *
objspace)
4066 if (!rb_gc_impl_multi_objspace_p())
return;
4070 for (
size_t i = 0; i < vm->gc.zombie_objspaces_count; i++) {
4071 if (vm->gc.zombie_objspaces[i].objspace ==
objspace) {
4072 vm->gc.zombie_objspaces[i].owner_slot = NULL;
4075 vm->gc.zombie_objspaces[i].owner = NULL;
4081 zombie_objspaces_push(vm,
objspace, NULL, NULL);
4086 gc_orphan_merge_pjob_ensure();
4087 rb_postponed_job_trigger_for_ractor(GET_VM()->gc.orphan_merge_pjob, vm->ractor.main_ractor->pub.self);
4093rb_gc_during_global_gc_p(
void)
4095 return rb_gc_impl_during_global_gc_p(rb_gc_get_objspace());
4099rb_gc_vm_forget_zombie(
void *
objspace)
4102 size_t n = vm->gc.zombie_objspaces_count;
4103 for (
size_t i = 0; i < n; i++) {
4104 if (vm->gc.zombie_objspaces[i].objspace ==
objspace) {
4105 vm->gc.zombie_total_pages -= vm->gc.zombie_objspaces[i].pages;
4106 vm->gc.zombie_objspaces[i] = vm->gc.zombie_objspaces[n - 1];
4107 vm->gc.zombie_objspaces_count = n - 1;
4117rb_gc_vm_zombie_total_pages(
void)
4119 return GET_VM()->gc.zombie_total_pages;
4124rb_gc_vm_ractor_count(
void)
4126 return GET_VM()->ractor.cnt;
4131rb_gc_vm_refresh_zombie_pages(
void)
4135 for (
size_t i = 0; i < vm->gc.zombie_objspaces_count; i++) {
4136 size_t pages = rb_gc_impl_heap_page_count(vm->gc.zombie_objspaces[i].objspace);
4137 vm->gc.zombie_objspaces[i].pages = pages;
4140 vm->gc.zombie_total_pages = total;
4146 rb_gc_impl_gc_rest(rb_gc_get_objspace());
4152static int gc_absorbing_zombie = 0;
4157static bool gc_absorbed_since_global_gc =
false;
4160rb_gc_reset_absorbed_since_global_gc(
void)
4162 gc_absorbed_since_global_gc =
false;
4175rb_gc_multi_objspace_p(
void)
4177 return rb_gc_impl_multi_objspace_p();
4183rb_gc_obj_foreign_p(
VALUE obj)
4185 return rb_gc_impl_obj_foreign_p(rb_gc_get_objspace(), obj);
4189rb_gc_single_objspace_p(
void)
4191 if (!rb_gc_impl_multi_objspace_p())
return true;
4195 return (ruby_single_main_ractor != NULL || vm->ractor.cnt == 1) &&
4196 vm->gc.zombie_objspaces_count == 0 && gc_absorbing_zombie == 0 &&
4197 !gc_absorbed_since_global_gc &&
4198 (vm->ractor.main_ractor == NULL ||
4199 vm->ractor.main_ractor->creating_child_objspace == NULL);
4206objspace_absorb_merge(
void *dst,
void *src)
4208 ASSERT_vm_locking();
4209 rb_gc_impl_objspace_absorb(dst, src);
4210 gc_absorbed_since_global_gc =
true;
4217rb_gc_objspace_postmortem_self(
void)
4219 if (!rb_gc_impl_multi_objspace_p())
return;
4221 rb_gc_impl_objspace_retire_gc(rb_gc_get_objspace());
4225rb_gc_objspace_absorb_into_current(
void **objspace_slot)
4227 if (!rb_gc_impl_multi_objspace_p()) {
4228 *objspace_slot = NULL;
4234 *objspace_slot = NULL;
4235 gc_absorbing_zombie++;
4237 objspace_absorb_merge(rb_gc_get_objspace(),
objspace);
4238 gc_absorbing_zombie--;
4247objspace_absorb_disowned_zombies(
void)
4253 while (i < vm->gc.zombie_objspaces_count) {
4254 if (vm->gc.zombie_objspaces[i].owner_slot == NULL) {
4255 void *zombie = vm->gc.zombie_objspaces[i].objspace;
4259 gc_absorbing_zombie++;
4260 rb_gc_vm_forget_zombie(zombie);
4261 objspace_absorb_merge(rb_gc_get_objspace(), zombie);
4262 gc_absorbing_zombie--;
4272gc_orphan_merge_job(
void *unused)
4275 objspace_absorb_disowned_zombies();
4283rb_gc_disable_holders_atfork(
void)
4286 rb_gc_impl_user_gc_disabled_p(rb_gc_get_objspace()) ? 1 : 0);
4290rb_gc_zombie_objspaces_atfork(
void)
4294 for (
size_t i = 0; i < vm->gc.zombie_objspaces_count; i++) {
4295 if (vm->gc.zombie_objspaces[i].owner_slot == NULL) {
4296 rb_postponed_job_trigger_for_ractor(GET_VM()->gc.orphan_merge_pjob, vm->ractor.main_ractor->pub.self);
4306rb_gc_objspace_absorb_all_zombies(
void)
4312 objspace_absorb_disowned_zombies();
4314 while (vm->gc.zombie_objspaces_count > 0) {
4315 size_t before = vm->gc.zombie_objspaces_count;
4316 GC_ASSERT(vm->gc.zombie_objspaces[0].owner_slot != NULL);
4319 rb_ractor_t *owner = vm->gc.zombie_objspaces[0].owner;
4321 rb_ractor_absorb_registered_marks(GET_RACTOR(), owner);
4323 rb_gc_objspace_absorb_into_current(vm->gc.zombie_objspaces[0].owner_slot);
4324 if (vm->gc.zombie_objspaces_count >= before) {
4325 rb_bug(
"rb_gc_objspace_absorb_all_zombies: zombie list did not shrink");
4333 if (ARY_SHARED_P(v)) {
4334 VALUE old_root =
RARRAY(v)->as.heap.aux.shared_root;
4338 VALUE new_root =
RARRAY(v)->as.heap.aux.shared_root;
4342 if (
RB_TYPE_P(new_root,
T_ARRAY) && ARY_EMBED_P(new_root) && new_root != old_root) {
4343 size_t offset = (size_t)(
RARRAY(v)->as.heap.ptr -
RARRAY(old_root)->as.ary);
4344 GC_ASSERT(
RARRAY(v)->as.heap.ptr >=
RARRAY(old_root)->as.ary);
4345 RARRAY(v)->as.heap.ptr =
RARRAY(new_root)->as.ary + offset;
4353 for (
long i = 0; i <
len; i++) {
4358 if (rb_gc_obj_slot_size(v) >= rb_ary_size_as_embedded(v)) {
4362 if (rb_ary_embeddable_p(v) && !rb_gc_impl_pinned_p(
objspace, v)) {
4363 rb_ary_make_embedded(v);
4372 RUBY_ASSERT(rb_gc_obj_slot_size(v) == rb_obj_shape_slot_size(v));
4373 shape_id_t shape_id = RBASIC_SHAPE_ID(v);
4375 if (!rb_shape_embedded_p(shape_id)) {
4378 if (!rb_shape_complex_p(shape_id) && rb_shape_embedded_capacity(shape_id) >= RSHAPE_LEN(shape_id)) {
4379 VALUE *embedded_fields = ROBJECT_EMBEDDED_FIELDS(v);
4380 VALUE *extended_fields = ROBJECT_FIELDS(v);
4381 MEMCPY(embedded_fields, extended_fields,
VALUE, RSHAPE_LEN(shape_id));
4382 shape_id = rb_shape_transition_robject(shape_id);
4383 RBASIC_SET_FULL_SHAPE_ID(v, shape_id);
4384 rb_gc_writebarrier_remember(v);
4391 VALUE *ptr = ROBJECT_FIELDS(v);
4392 attr_index_t
len = RSHAPE_LEN(shape_id);
4393 for (attr_index_t i = 0; i <
len; i++) {
4399rb_gc_ref_update_table_values_only(
st_table *tbl)
4401 gc_ref_update_table_values_only(tbl);
4408 gc_update_table_refs(ptr);
4412rb_gc_update_set_refs_i(st_data_t key, st_data_t value, st_data_t argp,
int error)
4414 if (rb_gc_location((
VALUE)key) != (
VALUE)key) {
4422rb_gc_update_set_refs_replace_i(st_data_t *key, st_data_t *value, st_data_t argp,
int existing)
4424 if (rb_gc_location((
VALUE)*key) != (
VALUE)*key) {
4425 *key = rb_gc_location((
VALUE)*key);
4432rb_gc_update_set_refs(
st_table *tbl)
4434 if (!tbl || tbl->num_entries == 0)
return;
4436 if (st_foreach_with_replace(tbl, rb_gc_update_set_refs_i, rb_gc_update_set_refs_replace_i, 0)) {
4444 rb_hash_stlike_foreach_with_replace(v, hash_foreach_replace, hash_replace_ref, (st_data_t)
objspace);
4450 for (
long i = 0; i < n; i++) {
4451 UPDATE_IF_MOVED(
objspace, values[i]);
4456rb_gc_update_values(
long n,
VALUE *values)
4458 gc_update_values(rb_gc_get_objspace(), n, values);
4461static enum rb_id_table_iterator_result
4462check_id_table_move(
VALUE value,
void *data)
4467 return ID_TABLE_REPLACE;
4470 return ID_TABLE_CONTINUE;
4474rb_gc_prepare_heap_process_object(
VALUE obj)
4480 rb_enc_str_coderange(obj);
4488rb_gc_prepare_heap(
void)
4490 rb_gc_impl_prepare_heap(rb_gc_get_objspace());
4494rb_gc_size_slot_size(
size_t size)
4496 return rb_gc_impl_size_slot_size(rb_gc_get_objspace(), size);
4500rb_gc_size_allocatable_p(
size_t size)
4502 return rb_gc_impl_size_allocatable_p(size);
4506rb_gc_max_allocation_size(
void)
4508 return rb_gc_impl_max_allocation_size();
4511static enum rb_id_table_iterator_result
4512update_id_table(
VALUE *value,
void *data,
int existing)
4520 return ID_TABLE_CONTINUE;
4527 rb_id_table_foreach_values_with_replace(tbl, check_id_table_move, update_id_table,
objspace);
4531static enum rb_id_table_iterator_result
4536 if (gc_object_moved_p_internal(
objspace, ce->value)) {
4537 ce->value = gc_location_internal(
objspace, ce->value);
4540 if (gc_object_moved_p_internal(
objspace, ce->file)) {
4541 ce->file = gc_location_internal(
objspace, ce->file);
4544 return ID_TABLE_CONTINUE;
4551 rb_id_table_foreach_values(tbl, update_const_tbl_i,
objspace);
4557 if (RCLASSEXT_SUPERCLASSES_WITH_SELF(ext)) {
4558 size_t array_size = RCLASSEXT_SUPERCLASS_DEPTH(ext) + 1;
4559 for (
size_t i = 0; i < array_size; i++) {
4560 UPDATE_IF_MOVED(
objspace, RCLASSEXT_SUPERCLASSES(ext)[i]);
4568 UPDATE_IF_MOVED(
objspace, RCLASSEXT_ORIGIN(ext));
4569 UPDATE_IF_MOVED(
objspace, RCLASSEXT_REFINED_CLASS(ext));
4570 UPDATE_IF_MOVED(
objspace, RCLASSEXT_CLASSPATH(ext));
4572 UPDATE_IF_MOVED(
objspace, RCLASSEXT_INCLUDER(ext));
4582 if (RCLASSEXT_SUPER(ext)) {
4583 UPDATE_IF_MOVED(
objspace, RCLASSEXT_SUPER(ext));
4586 update_m_tbl(
objspace, RCLASSEXT_M_TBL(ext));
4588 UPDATE_IF_MOVED(
objspace, ext->fields_obj);
4589 if (!RCLASSEXT_SHARED_CONST_TBL(ext)) {
4590 update_const_tbl(
objspace, RCLASSEXT_CONST_TBL(ext));
4592 UPDATE_IF_MOVED(
objspace, RCLASSEXT_CC_TBL(ext));
4593 UPDATE_IF_MOVED(
objspace, RCLASSEXT_CVC_TBL(ext));
4594 update_superclasses(
objspace, ext);
4595 if (RCLASSEXT_SUBCLASSES(ext)) {
4596 UPDATE_IF_MOVED(
objspace, RCLASSEXT_SUBCLASSES(ext));
4599 update_classext_values(
objspace, ext,
false);
4608 if (RCLASSEXT_SUPER(ext)) {
4609 UPDATE_IF_MOVED(
objspace, RCLASSEXT_SUPER(ext));
4611 update_m_tbl(
objspace, RCLASSEXT_M_TBL(ext));
4612 update_m_tbl(
objspace, RCLASSEXT_CALLABLE_M_TBL(ext));
4613 UPDATE_IF_MOVED(
objspace, RCLASSEXT_CC_TBL(ext));
4614 UPDATE_IF_MOVED(
objspace, RCLASSEXT_CVC_TBL(ext));
4615 if (RCLASSEXT_SUBCLASSES(ext)) {
4616 UPDATE_IF_MOVED(
objspace, RCLASSEXT_SUBCLASSES(ext));
4619 update_classext_values(
objspace, ext,
true);
4623 vm_table_foreach_callback_func callback;
4624 vm_table_update_callback_func update_callback;
4629 struct st_table *gen_fields_current_tbl;
4633 size_t gf_deferred_cnt, gf_deferred_capa;
4637vm_weak_table_foreach_weak_key(st_data_t key, st_data_t value, st_data_t data,
int error)
4641 int ret = iter_data->callback((
VALUE)key, iter_data->data);
4643 if (!iter_data->weak_only) {
4644 if (ret != ST_CONTINUE)
return ret;
4646 ret = iter_data->callback((
VALUE)value, iter_data->data);
4653vm_weak_table_foreach_update_weak_key(st_data_t *key, st_data_t *value, st_data_t data,
int existing)
4657 int ret = iter_data->update_callback((
VALUE *)key, iter_data->data);
4659 if (!iter_data->weak_only) {
4660 if (ret != ST_CONTINUE)
return ret;
4662 ret = iter_data->update_callback((
VALUE *)value, iter_data->data);
4669vm_weak_table_sym_set_foreach(
VALUE *sym_ptr,
void *data)
4671 VALUE sym = *sym_ptr;
4676 int ret = iter_data->callback(sym, iter_data->data);
4678 if (ret == ST_REPLACE) {
4679 ret = iter_data->update_callback(sym_ptr, iter_data->data);
4685struct st_table *rb_generic_fields_tbl_get(
void);
4688vm_weak_table_gen_fields_foreach(st_data_t key, st_data_t value, st_data_t data)
4692 int ret = iter_data->callback((
VALUE)key, iter_data->data);
4707 RBASIC_SET_SHAPE_ID((
VALUE)key, ROOT_SHAPE_ID);
4712 ret = iter_data->update_callback(&new_key, iter_data->data);
4713 if (key != new_key) {
4720 rb_bug(
"vm_weak_table_gen_fields_foreach: return value %d not supported", ret);
4723 if (!iter_data->weak_only) {
4724 int ivar_ret = iter_data->callback(new_value, iter_data->data);
4730 iter_data->update_callback(&new_value, iter_data->data);
4737 RBASIC_SET_SHAPE_ID((
VALUE)key, ROOT_SHAPE_ID);
4741 rb_bug(
"vm_weak_table_gen_fields_foreach: return value %d not supported", ivar_ret);
4745 if (key != new_key) {
4747 if (iter_data->gf_deferred_cnt == iter_data->gf_deferred_capa) {
4748 size_t nc = iter_data->gf_deferred_capa ? iter_data->gf_deferred_capa * 2 : 64;
4749 struct gen_fields_deferred_insert *p =
4750 realloc(iter_data->gf_deferred, nc *
sizeof(*p));
4751 if (!p) rb_bug(
"vm_weak_table_gen_fields_foreach: out of memory");
4752 iter_data->gf_deferred = p;
4753 iter_data->gf_deferred_capa = nc;
4755 iter_data->gf_deferred[iter_data->gf_deferred_cnt++] =
4756 (
struct gen_fields_deferred_insert){ .k = (st_data_t)new_key, .v = (st_data_t)new_value };
4758 else if (value != new_value) {
4759 DURING_GC_COULD_MALLOC_REGION_START();
4762 st_insert(iter_data->gen_fields_current_tbl, (st_data_t)new_key, new_value);
4764 DURING_GC_COULD_MALLOC_REGION_END();
4771vm_weak_table_frozen_strings_foreach(
VALUE *str,
void *data)
4775 int retval = iter_data->callback(*str, iter_data->data);
4777 if (retval == ST_REPLACE) {
4778 retval = iter_data->update_callback(str, iter_data->data);
4781 if (retval == ST_DELETE) {
4788void rb_fstring_foreach_with_replace(
int (*callback)(
VALUE *str,
void *data),
void *data);
4794vm_weak_table_gen_fields_tbl_cb(
struct st_table *tbl,
void *arg)
4797 foreach_data->gen_fields_current_tbl = tbl;
4798 st_foreach(tbl, vm_weak_table_gen_fields_foreach, (st_data_t)foreach_data);
4802rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
4803 vm_table_update_callback_func update_callback,
4806 enum rb_gc_vm_weak_tables table)
4811 .callback = callback,
4812 .update_callback = update_callback,
4814 .weak_only = weak_only,
4818 case RB_GC_VM_CI_TABLE: {
4819 st_foreach_with_replace(
4821 vm_weak_table_foreach_weak_key,
4822 vm_weak_table_foreach_update_weak_key,
4823 (st_data_t)&foreach_data
4827 case RB_GC_VM_OVERLOADED_CME_TABLE: {
4828 st_foreach_with_replace(
4829 &vm->overloaded_cme_table,
4830 vm_weak_table_foreach_weak_key,
4831 vm_weak_table_foreach_update_weak_key,
4832 (st_data_t)&foreach_data
4836 case RB_GC_VM_GLOBAL_SYMBOLS_TABLE: {
4837 rb_sym_global_symbol_table_foreach_weak_reference(
4838 vm_weak_table_sym_set_foreach,
4843 case RB_GC_VM_GENERIC_FIELDS_TABLE: {
4848 if (rb_gc_during_global_gc_p()) {
4849 rb_generic_fields_tables_foreach(vm_weak_table_gen_fields_tbl_cb, (
void *)&foreach_data);
4851 else if (!weak_only) {
4852 rb_generic_fields_shared_table_foreach(vm_weak_table_gen_fields_tbl_cb, (
void *)&foreach_data);
4854 if (foreach_data.gf_deferred != NULL) {
4855 DURING_GC_COULD_MALLOC_REGION_START();
4857 for (
size_t i = 0; i < foreach_data.gf_deferred_cnt; i++) {
4858 struct gen_fields_deferred_insert *
const d = &foreach_data.gf_deferred[i];
4859 st_insert(foreach_data.gen_fields_current_tbl, d->k, d->v);
4862 DURING_GC_COULD_MALLOC_REGION_END();
4863 free(foreach_data.gf_deferred);
4867 case RB_GC_VM_FROZEN_STRINGS_TABLE: {
4868 rb_fstring_foreach_with_replace(
4869 vm_weak_table_frozen_strings_foreach,
4874 case RB_GC_VM_WEAK_TABLE_COUNT:
4875 rb_bug(
"Unreachable");
4877 rb_bug(
"rb_gc_vm_weak_table_foreach: unknown table %d", table);
4889gf_mark_foreach_i(st_data_t key, st_data_t val, st_data_t data)
4892 return ctx->cb((
VALUE)key, (
VALUE)val, ctx->arg);
4896gf_mark_foreach_table_cb(
struct st_table *tbl,
void *arg)
4898 st_foreach(tbl, gf_mark_foreach_i, (st_data_t)arg);
4902rb_gc_vm_generic_fields_mark_foreach(
int (*cb)(
VALUE key,
VALUE val,
void *arg),
void *arg)
4905 rb_generic_fields_tables_foreach(gf_mark_foreach_table_cb, &ctx);
4909 bool (*is_dead)(
VALUE key);
4913gf_drain_i(st_data_t key, st_data_t val, st_data_t data)
4916 if (ctx->is_dead((
VALUE)key)) {
4926gf_drain_table_cb(
struct st_table *tbl,
void *arg)
4928 st_foreach(tbl, gf_drain_i, (st_data_t)arg);
4932rb_gc_vm_generic_fields_drain_dead(
bool (*is_dead)(
VALUE key))
4935 rb_generic_fields_tables_foreach(gf_drain_table_cb, &ctx);
4939rb_gc_vm_top_self(
void)
4941 return rb_vm_top_self();
4945rb_gc_update_vm_references(
void *
objspace)
4948 rb_vm_t *vm = rb_ec_vm_ptr(ec);
4950 rb_vm_update_references(vm);
4951 rb_gc_update_global_tbl();
4952 rb_sym_global_symbols_mark_and_move();
4955 void rb_yjit_root_update_references(
void);
4957 if (rb_yjit_enabled_p) {
4958 rb_yjit_root_update_references();
4963 void rb_zjit_root_update_references(
void);
4965 if (rb_zjit_enabled_p) {
4966 rb_zjit_root_update_references();
4979 UPDATE_IF_MOVED(
objspace, RCLASS_ATTACHED_OBJECT(obj));
4985 rb_class_classext_foreach(obj, update_classext, (
void *)&args);
4990 rb_class_classext_foreach(obj, update_iclass_classext, (
void *)&args);
4994 rb_imemo_mark_and_move(obj,
true);
5006 gc_ref_update_array(
objspace, obj);
5011 UPDATE_IF_MOVED(
objspace, RHASH(obj)->ifnone);
5016 if (STR_SHARED_P(obj)) {
5024 if (rb_gc_obj_slot_size(obj) >= rb_str_size_as_embedded(obj)) {
5025 if (!STR_EMBED_P(obj) && rb_str_reembeddable_p(obj)
5026 && !rb_gc_impl_pinned_p(
objspace, obj)) {
5027 rb_str_make_embedded(obj);
5036 void *
const ptr = RTYPEDDATA_GET_DATA(obj);
5042 size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj);
5044 for (
size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
5045 VALUE *ref = (
VALUE *)((
char *)ptr + offset);
5046 *ref = gc_location_internal(
objspace, *ref);
5051 if (compact_func) (*compact_func)(ptr);
5058 gc_ref_update_object(
objspace, obj);
5062 if (
RFILE(obj)->fptr) {
5065 UPDATE_IF_MOVED(
objspace,
RFILE(obj)->fptr->tied_io_for_writing);
5066 UPDATE_IF_MOVED(
objspace,
RFILE(obj)->fptr->writeconv_asciicompat);
5067 UPDATE_IF_MOVED(
objspace,
RFILE(obj)->fptr->writeconv_pre_ecopts);
5079 UPDATE_IF_MOVED(
objspace, RSYMBOL(obj)->fstr);
5095 UPDATE_IF_MOVED(
objspace, RRATIONAL(obj)->num);
5096 UPDATE_IF_MOVED(
objspace, RRATIONAL(obj)->den);
5100 UPDATE_IF_MOVED(
objspace, RCOMPLEX(obj)->real);
5101 UPDATE_IF_MOVED(
objspace, RCOMPLEX(obj)->imag);
5108 VALUE *ptr = (
VALUE *)RSTRUCT_CONST_PTR(obj);
5110 for (i = 0; i <
len; i++) {
5114 UPDATE_IF_MOVED(
objspace, RSTRUCT(obj)->fields_obj);
5118 rb_bug(
"unreachable");
5135 unless_objspace(
objspace) {
return; }
5137 rb_gc_impl_start(
objspace,
true,
true,
true,
false);
5143 unless_objspace(
objspace) {
return FALSE; }
5145 return rb_gc_impl_during_gc_p(
objspace);
5151 return rb_gc_impl_gc_count(rb_gc_get_objspace());
5167 VALUE val = rb_gc_impl_latest_gc_info(rb_gc_get_objspace(), key);
5170 rb_raise(rb_eArgError,
"unknown key: %"PRIsVALUE,
rb_sym2str(key));
5180 arg = rb_hash_new();
5186 VALUE ret = rb_gc_impl_stat(rb_gc_get_objspace(), arg);
5191 rb_raise(rb_eArgError,
"unknown key: %"PRIsVALUE,
rb_sym2str(arg));
5204 VALUE ret = rb_gc_impl_stat(rb_gc_get_objspace(), arg);
5209 rb_raise(rb_eArgError,
"unknown key: %"PRIsVALUE,
rb_sym2str(arg));
5224 arg = rb_hash_new();
5227 if (
NIL_P(heap_name)) {
5238 rb_raise(
rb_eTypeError,
"heap_name must be nil or an Integer");
5241 VALUE ret = rb_gc_impl_stat_heap(rb_gc_get_objspace(), heap_name, arg);
5246 rb_raise(rb_eArgError,
"unknown key: %"PRIsVALUE,
rb_sym2str(arg));
5255 VALUE cfg_hash = rb_gc_impl_config_get(rb_gc_get_objspace());
5256 rb_hash_aset(cfg_hash, sym(
"implementation"), rb_fstring_cstr(rb_gc_impl_active_gc_name()));
5264 void *
objspace = rb_gc_get_objspace();
5266 rb_gc_impl_config_set(
objspace, hash);
5274 return rb_gc_impl_stress_get(rb_gc_get_objspace());
5280 rb_gc_impl_stress_set(rb_gc_get_objspace(), flag);
5286rb_gc_initial_stress_set(
VALUE flag)
5288 initial_stress = flag;
5296rb_gc_critical_disable(
void)
5298 rb_gc_impl_gc_rest(rb_gc_get_objspace());
5303rb_gc_critical_enable(
void)
5309rb_gc_gc_disabled_global_p(
void)
5317gc_ractor_disable_set(
bool disable)
5319 const bool was = rb_gc_impl_user_gc_disabled_set(rb_gc_get_objspace(), disable);
5320 if (was != disable) {
5334 return RBOOL(gc_ractor_disable_set(
false));
5338rb_gc_disable_no_rest(
void)
5340 return RBOOL(gc_ractor_disable_set(
true));
5346 const bool was_disabled = gc_ractor_disable_set(
true);
5347 if (!was_disabled) {
5348 rb_gc_impl_gc_rest(rb_gc_get_objspace());
5350 return RBOOL(was_disabled);
5354rb_objspace_gc_enable(
void *
objspace)
5356 bool disabled = !rb_gc_impl_gc_enabled_p(
objspace);
5358 return RBOOL(disabled);
5362rb_objspace_gc_disable(
void *
objspace)
5364 bool disabled = !rb_gc_impl_gc_enabled_p(
objspace);
5365 rb_gc_impl_gc_disable(
objspace,
true);
5366 return RBOOL(disabled);
5370rb_gc_local_enable(
void)
5372 return rb_objspace_gc_enable(rb_gc_get_objspace());
5377rb_gc_local_disable_no_rest(
void)
5379 void *
objspace = rb_gc_get_objspace();
5380 bool disabled = !rb_gc_impl_gc_enabled_p(
objspace);
5381 rb_gc_impl_gc_disable(
objspace,
false);
5382 return RBOOL(disabled);
5388 return rb_gc_enable();
5394 return rb_gc_disable();
5399ruby_gc_set_params(
void)
5401 rb_gc_impl_set_params(rb_gc_get_objspace());
5405rb_objspace_reachable_objects_from(
VALUE obj,
void (func)(
VALUE,
void *),
void *data)
5408 if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug(
"rb_objspace_reachable_objects_from() is not supported while during GC");
5419 rb_gc_mark_children(rb_gc_get_objspace(), obj);
5426 const char *category;
5427 void (*func)(
const char *category,
VALUE,
void *);
5432root_objects_from(
VALUE obj,
void *ptr)
5435 (*data->func)(data->category, obj, data->data);
5439rb_objspace_reachable_objects_from_root(
void (func)(
const char *category,
VALUE,
void *),
void *passing_data)
5441 if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug(
"rb_gc_impl_objspace_reachable_objects_from_root() is not supported while during GC");
5445 .data = passing_data,
5451 .mark_func = root_objects_from,
5456 rb_gc_save_machine_context();
5457 rb_gc_mark_roots(rb_gc_get_objspace(), &data.category);
5469#define TYPE_NAME(t) case (t): return #t;
5496 if (obj && rb_objspace_data_type_name(obj)) {
5497 return rb_objspace_data_type_name(obj);
5506obj_type_name(
VALUE obj)
5508 return type_name(
TYPE(obj), obj);
5512rb_method_type_name(rb_method_type_t
type)
5515 case VM_METHOD_TYPE_ISEQ:
return "iseq";
5516 case VM_METHOD_TYPE_ATTRSET:
return "attrset";
5517 case VM_METHOD_TYPE_IVAR:
return "ivar";
5518 case VM_METHOD_TYPE_BMETHOD:
return "bmethod";
5519 case VM_METHOD_TYPE_ALIAS:
return "alias";
5520 case VM_METHOD_TYPE_REFINED:
return "refined";
5521 case VM_METHOD_TYPE_CFUNC:
return "cfunc";
5522 case VM_METHOD_TYPE_ZSUPER:
return "zsuper";
5523 case VM_METHOD_TYPE_MISSING:
return "missing";
5524 case VM_METHOD_TYPE_OPTIMIZED:
return "optimized";
5525 case VM_METHOD_TYPE_UNDEF:
return "undef";
5526 case VM_METHOD_TYPE_NOTIMPLEMENTED:
return "notimplemented";
5528 rb_bug(
"rb_method_type_name: unreachable (type: %d)",
type);
5532rb_raw_iseq_info(
char *
const buff,
const size_t buff_size,
const rb_iseq_t *iseq)
5534 if (buff_size > 0 && ISEQ_BODY(iseq) && ISEQ_BODY(iseq)->location.label && !
RB_TYPE_P(ISEQ_BODY(iseq)->location.pathobj,
T_MOVED)) {
5535 VALUE path = rb_iseq_path(iseq);
5536 int n = ISEQ_BODY(iseq)->location.first_lineno;
5537 VALUE label = ISEQ_BODY(iseq)->location.label;
5538 snprintf(buff, buff_size,
" %.*s@%.*s:%d",
5545str_len_no_raise(
VALUE str)
5547 long len = RSTRING_LEN(str);
5548 if (
len < 0)
return 0;
5549 if (
len > INT_MAX)
return INT_MAX;
5553#define BUFF_ARGS buff + pos, buff_size - pos
5554#define APPEND_F(...) if ((pos += snprintf(BUFF_ARGS, "" __VA_ARGS__)) >= buff_size) goto end
5555#define APPEND_S(s) do { \
5556 if ((pos + (int)rb_strlen_lit(s)) >= buff_size) { \
5560 memcpy(buff + pos, (s), rb_strlen_lit(s) + 1); \
5563#define C(c, s) ((c) != 0 ? (s) : " ")
5566rb_raw_obj_info_common(
char *
const buff,
const size_t buff_size,
const VALUE obj)
5571 APPEND_F(
"%s", obj_type_name(obj));
5577 APPEND_F(
" %s", rb_id2name(
SYM2ID(obj)));
5583 if (rb_gc_impl_live_object_p(rb_gc_get_objspace(), (
void *)obj)) {
5584 APPEND_F(
"%p %s/", (
void *)obj, obj_type_name(obj));
5603 if (internal_object_p(obj)) {
5606 else if (
RBASIC(obj)->klass == 0) {
5607 APPEND_S(
"(temporary internal)");
5611 if (!
NIL_P(class_path)) {
5612 APPEND_F(
"%.*s ", str_len_no_raise(class_path), RSTRING_PTR(class_path));
5621const char *rb_raw_obj_info(
char *
const buff,
const size_t buff_size,
VALUE obj);
5624rb_raw_obj_info_buitin_type(
char *
const buff,
const size_t buff_size,
const VALUE obj,
size_t pos)
5631 UNEXPECTED_NODE(rb_raw_obj_info);
5634 if (ARY_SHARED_P(obj)) {
5635 APPEND_S(
"shared -> ");
5636 rb_raw_obj_info(BUFF_ARGS, ARY_SHARED_ROOT(obj));
5639 APPEND_F(
"[%s%s%s] ",
5640 C(ARY_EMBED_P(obj),
"E"),
5641 C(ARY_SHARED_P(obj),
"S"),
5642 C(ARY_SHARED_ROOT_P(obj),
"R"));
5644 if (ARY_EMBED_P(obj)) {
5645 APPEND_F(
"len: %ld (embed)",
5649 APPEND_F(
"len: %ld, capa:%ld ptr:%p",
5651 RARRAY(obj)->as.heap.aux.capa,
5658 C(
FL_TEST(obj, RSTRING_FSTR),
"F"),
5661 if (STR_SHARED_P(obj)) {
5662 APPEND_F(
" [shared] len: %ld", RSTRING_LEN(obj));
5665 if (STR_EMBED_P(obj)) APPEND_S(
" [embed]");
5667 APPEND_F(
" len: %ld, capa: %" PRIdSIZE, RSTRING_LEN(obj),
rb_str_capacity(obj));
5669 APPEND_F(
" \"%.*s\"", str_len_no_raise(obj), RSTRING_PTR(obj));
5673 VALUE fstr = RSYMBOL(obj)->fstr;
5674 ID id = RSYMBOL(obj)->id;
5676 APPEND_F(
":%.*s id:%d", str_len_no_raise(fstr), RSTRING_PTR(fstr), (
unsigned int)
id);
5679 APPEND_F(
"(%p) id:%d", (
void *)fstr, (
unsigned int)
id);
5684 APPEND_F(
"-> %p", (
void*)gc_location_internal(rb_gc_get_objspace(), obj));
5688 APPEND_F(
"[%c] %"PRIdSIZE,
5689 RHASH_AR_TABLE_P(obj) ?
'A' :
'S',
5697 if (!
NIL_P(class_path)) {
5698 APPEND_F(
"%.*s", str_len_no_raise(class_path), RSTRING_PTR(class_path));
5708 if (!
NIL_P(class_path)) {
5709 APPEND_F(
"src:%.*s", str_len_no_raise(class_path), RSTRING_PTR(class_path));
5715 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
5716 if (rb_shape_embedded_p(shape_id)) {
5717 APPEND_F(
"(embed) len:%d capa:%d", RSHAPE_LEN(shape_id), RSHAPE_CAPACITY(shape_id));
5720 VALUE fields_obj = ROBJECT_FIELDS_OBJ(obj);
5721 if (rb_shape_complex_p(shape_id)) {
5722 size_t hash_len = rb_st_table_size(rb_imemo_fields_complex_tbl(fields_obj));
5723 APPEND_F(
"(complex) len:%zu extended:%p", hash_len, (
void *)fields_obj);
5726 APPEND_F(
"(extended) len:%d capa:%d extended:%p", RSHAPE_LEN(shape_id), RSHAPE_CAPACITY(shape_id), (
void *)fields_obj);
5735 (block = vm_proc_block(obj)) != NULL &&
5736 (vm_block_type(block) == block_type_iseq) &&
5737 (iseq = vm_block_iseq(block)) != NULL) {
5738 rb_raw_iseq_info(BUFF_ARGS, iseq);
5740 else if (rb_ractor_p(obj)) {
5743 APPEND_F(
"r:%d", r->pub.id);
5749 APPEND_F(
"<%s> ", rb_imemo_name(imemo_type(obj)));
5751 switch (imemo_type(obj)) {
5754 shape_id_t shape_id = RBASIC_SHAPE_ID(obj);
5755 if (rb_shape_complex_p(shape_id)) {
5756 size_t hash_len = rb_st_table_size(rb_imemo_fields_complex_tbl(obj));
5757 APPEND_F(
"(complex) len:%zu", hash_len);
5760 APPEND_F(
"(embed) len:%d capa:%d", RSHAPE_LEN(shape_id), RSHAPE_CAPACITY(shape_id));
5763 APPEND_S(
"owner -> ");
5764 rb_raw_obj_info(BUFF_ARGS,
CLASS_OF(obj));
5772 APPEND_F(
":%s (%s%s%s%s) type:%s aliased:%d owner:%p defined_class:%p",
5773 rb_id2name(me->called_id),
5774 METHOD_ENTRY_VISI(me) == METHOD_VISI_PUBLIC ?
"pub" :
5775 METHOD_ENTRY_VISI(me) == METHOD_VISI_PRIVATE ?
"pri" :
"pro",
5776 METHOD_ENTRY_COMPLEMENTED(me) ?
",cmp" :
"",
5777 METHOD_ENTRY_CACHED(me) ?
",cc" :
"",
5778 METHOD_ENTRY_INVALIDATED(me) ?
",inv" :
"",
5779 me->def ? rb_method_type_name(me->def->
type) :
"NULL",
5780 me->def ? me->def->aliased : -1,
5782 (void *)me->defined_class);
5785 switch (me->def->type) {
5786 case VM_METHOD_TYPE_ISEQ:
5787 APPEND_S(
" (iseq:");
5788 rb_raw_obj_info(BUFF_ARGS, (
VALUE)me->def->body.iseq.
iseqptr);
5800 rb_raw_iseq_info(BUFF_ARGS, iseq);
5803 case imemo_callinfo:
5806 APPEND_F(
"(mid:%s, flag:%x argc:%d, kwarg:%s)",
5807 rb_id2name(vm_ci_mid(ci)),
5810 vm_ci_kwarg(ci) ?
"available" :
"NULL");
5813 case imemo_callcache:
5818 const char *class_name;
5821 if (
NIL_P(class_path)) {
5822 class_name = vm_cc_valid(cc) ?
"??" :
"<NULL>";
5823 class_name_len = vm_cc_valid(cc) ? 2 : 6;
5826 class_name = RSTRING_PTR(class_path);
5827 class_name_len = str_len_no_raise(class_path);
5830 APPEND_F(
"(klass:%.*s cme:%s%s (%p) call:%p",
5831 class_name_len, class_name,
5832 cme ? rb_id2name(cme->called_id) :
"<NULL>",
5833 cme ? (METHOD_ENTRY_INVALIDATED(cme) ?
" [inv]" :
"") :
"",
5835 (void *)(uintptr_t)vm_cc_call(cc));
5853#ifdef RUBY_ASAN_ENABLED
5855rb_asan_poison_object(
VALUE obj)
5857 MAYBE_UNUSED(
struct RVALUE *) ptr = (
void *)obj;
5858 asan_poison_memory_region(ptr, rb_gc_obj_slot_size(obj));
5862rb_asan_unpoison_object(
VALUE obj,
bool newobj_p)
5864 MAYBE_UNUSED(
struct RVALUE *) ptr = (
void *)obj;
5865 asan_unpoison_memory_region(ptr, rb_gc_obj_slot_size(obj), newobj_p);
5869rb_asan_poisoned_object_p(
VALUE obj)
5871 MAYBE_UNUSED(
struct RVALUE *) ptr = (
void *)obj;
5872 return __asan_region_is_poisoned(ptr, rb_gc_obj_slot_size(obj));
5877raw_obj_info(
char *
const buff,
const size_t buff_size,
VALUE obj)
5879 size_t pos = rb_raw_obj_info_common(buff, buff_size, obj);
5880 pos = rb_raw_obj_info_buitin_type(buff, buff_size, obj, pos);
5881 if (pos >= buff_size) {}
5885rb_raw_obj_info(
char *
const buff,
const size_t buff_size,
VALUE obj)
5887 void *
objspace = rb_gc_get_objspace();
5890 raw_obj_info(buff, buff_size, obj);
5892 else if (!rb_gc_impl_live_object_p(
objspace, (
const void *)obj)) {
5893 snprintf(buff, buff_size,
"out-of-heap:%p", (
void *)obj);
5896 else if (0 && rb_gc_impl_garbage_object_p(
objspace, obj)) {
5897 snprintf(buff, buff_size,
"garbage:%p", (
void *)obj);
5901 asan_unpoisoning_object(obj) {
5902 raw_obj_info(buff, buff_size, obj);
5918 if (RB_UNLIKELY(oldval >= maxval - 1)) {
5929 if (RGENGC_OBJ_INFO) {
5932 char buffers[10][0x100];
5935 rb_atomic_t index = atomic_inc_wraparound(&info.index, numberof(info.buffers));
5936 char *
const buff = info.buffers[index];
5937 return rb_raw_obj_info(buff,
sizeof(info.buffers[0]), obj);
5939 return obj_type_name(obj);
5956 rb_vraise(argv->exc, argv->fmt, *argv->ap);
5961gc_raise(
VALUE exc,
const char *fmt, ...)
5975 fprintf(stderr,
"%s",
"[FATAL] ");
5976 vfprintf(stderr, fmt, ap);
5983NORETURN(
static void negative_size_allocation_error(
const char *));
5985negative_size_allocation_error(
const char *msg)
5991ruby_memerror_body(
void *dummy)
5997NORETURN(
static void ruby_memerror(
void));
6002 if (ruby_thread_has_gvl_p()) {
6011 fprintf(stderr,
"[FATAL] failed to allocate memory\n");
6029 VALUE exc = GET_VM()->special_exceptions[ruby_error_nomemory];
6032 rb_ec_raised_p(ec, RAISED_NOMEMORY) ||
6033 rb_ec_vm_lock_rec(ec) != ec->tag->lock_rec) {
6034 fprintf(stderr,
"[FATAL] failed to allocate memory\n");
6037 if (rb_ec_raised_p(ec, RAISED_NOMEMORY)) {
6038 rb_ec_raised_clear(ec);
6041 rb_ec_raised_set(ec, RAISED_NOMEMORY);
6042 exc = ruby_vm_special_exception_copy(exc);
6045 EC_JUMP_TAG(ec, TAG_RAISE);
6049rb_memerror_reentered(
void)
6052 return (ec && rb_ec_raised_p(ec, RAISED_NOMEMORY));
6056handle_malloc_failure(
void *ptr)
6067static void *ruby_xmalloc_body(
size_t size);
6070ruby_xmalloc(
size_t size)
6072 if (RUBY_DTRACE_GC_XMALLOC_ENABLED()) {
6073 RUBY_DTRACE_GC_XMALLOC(1, size);
6076 return handle_malloc_failure(ruby_xmalloc_body(size));
6080malloc_gc_allowed(
void)
6084 return r == NULL || !r->malloc_gc_disabled;
6088ruby_xmalloc_body(
size_t size)
6090 if ((ssize_t)size < 0) {
6091 negative_size_allocation_error(
"too large allocation size");
6094 return rb_gc_impl_malloc(rb_gc_get_objspace(), size, malloc_gc_allowed());
6098ruby_malloc_size_overflow(
size_t count,
size_t elsize)
6100 rb_raise(rb_eArgError,
6101 "malloc: possible integer overflow (%"PRIuSIZE
"*%"PRIuSIZE
")",
6106ruby_malloc_add_size_overflow(
size_t x,
size_t y)
6108 rb_raise(rb_eArgError,
6109 "malloc: possible integer overflow (%"PRIuSIZE
"+%"PRIuSIZE
")",
6113static void *ruby_xmalloc2_body(
size_t n,
size_t size);
6116ruby_xmalloc2(
size_t n,
size_t size)
6118 if (RUBY_DTRACE_GC_XMALLOC_ENABLED()) {
6119 RUBY_DTRACE_GC_XMALLOC(n, size);
6122 return handle_malloc_failure(ruby_xmalloc2_body(n, size));
6126ruby_xmalloc2_body(
size_t n,
size_t size)
6128 return rb_gc_impl_malloc(rb_gc_get_objspace(), xmalloc2_size(n, size), malloc_gc_allowed());
6131static void *ruby_xcalloc_body(
size_t n,
size_t size);
6134ruby_xcalloc(
size_t n,
size_t size)
6136 if (RUBY_DTRACE_GC_XCALLOC_ENABLED()) {
6137 RUBY_DTRACE_GC_XCALLOC(n, size);
6140 return handle_malloc_failure(ruby_xcalloc_body(n, size));
6144ruby_xcalloc_body(
size_t n,
size_t size)
6146 return rb_gc_impl_calloc(rb_gc_get_objspace(), xmalloc2_size(n, size), malloc_gc_allowed());
6149static void *ruby_xrealloc_sized_body(
void *ptr,
size_t new_size,
size_t old_size);
6151#ifdef ruby_xrealloc_sized
6152#undef ruby_xrealloc_sized
6155ruby_xrealloc_sized(
void *ptr,
size_t new_size,
size_t old_size)
6157 return handle_malloc_failure(ruby_xrealloc_sized_body(ptr, new_size, old_size));
6161ruby_xrealloc_sized_body(
void *ptr,
size_t new_size,
size_t old_size)
6163 if ((ssize_t)new_size < 0) {
6164 negative_size_allocation_error(
"too large allocation size");
6167 return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, new_size, old_size, malloc_gc_allowed());
6171ruby_xrealloc(
void *ptr,
size_t new_size)
6173 return ruby_xrealloc_sized(ptr, new_size, 0);
6176static void *ruby_xrealloc2_sized_body(
void *ptr,
size_t n,
size_t size,
size_t old_n);
6178#ifdef ruby_xrealloc2_sized
6179#undef ruby_xrealloc2_sized
6182ruby_xrealloc2_sized(
void *ptr,
size_t n,
size_t size,
size_t old_n)
6184 return handle_malloc_failure(ruby_xrealloc2_sized_body(ptr, n, size, old_n));
6188ruby_xrealloc2_sized_body(
void *ptr,
size_t n,
size_t size,
size_t old_n)
6190 size_t len = xmalloc2_size(n, size);
6191 return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr,
len, old_n * size, malloc_gc_allowed());
6195ruby_xrealloc2(
void *ptr,
size_t n,
size_t size)
6197 return ruby_xrealloc2_sized(ptr, n, size, 0);
6200#ifdef ruby_xfree_sized
6201#undef ruby_xfree_sized
6211static bool g_nofree =
false;
6215ruby_xfree_sized(
void *x,
size_t size)
6223 if (RUBY_DTRACE_GC_XFREE_ENABLED()) {
6224 RUBY_DTRACE_GC_XFREE(x, size);
6231 if (LIKELY(GET_VM())) {
6232 rb_gc_impl_free(rb_gc_get_objspace(), x, size);
6243 ruby_xfree_sized(x, 0);
6247rb_xmalloc_mul_add(
size_t x,
size_t y,
size_t z)
6249 size_t w = size_mul_add_or_raise(x, y, z, rb_eArgError);
6250 return ruby_xmalloc(w);
6254rb_xcalloc_mul_add(
size_t x,
size_t y,
size_t z)
6256 size_t w = size_mul_add_or_raise(x, y, z, rb_eArgError);
6257 return ruby_xcalloc(w, 1);
6261rb_xrealloc_mul_add(
const void *p,
size_t x,
size_t y,
size_t z)
6263 size_t w = size_mul_add_or_raise(x, y, z, rb_eArgError);
6264 return ruby_xrealloc((
void *)p, w);
6268rb_xmalloc_mul_add_mul(
size_t x,
size_t y,
size_t z,
size_t w)
6270 size_t u = size_mul_add_mul_or_raise(x, y, z, w, rb_eArgError);
6271 return ruby_xmalloc(u);
6275rb_xcalloc_mul_add_mul(
size_t x,
size_t y,
size_t z,
size_t w)
6277 size_t u = size_mul_add_mul_or_raise(x, y, z, w, rb_eArgError);
6278 return ruby_xcalloc(u, 1);
6285ruby_mimmalloc(
size_t size)
6288#if CALC_EXACT_MALLOC_SIZE
6292#if CALC_EXACT_MALLOC_SIZE
6308ruby_mimcalloc(
size_t num,
size_t size)
6311#if CALC_EXACT_MALLOC_SIZE
6312 struct rbimpl_size_overflow_tag t = rbimpl_size_mul_overflow(num, size);
6313 if (UNLIKELY(t.overflowed)) {
6317 mem = calloc1(size);
6329 mem = calloc(num, size);
6335ruby_mimfree(
void *ptr)
6337#if CALC_EXACT_MALLOC_SIZE
6345rb_gc_adjust_memory_usage(ssize_t diff)
6347 unless_objspace(
objspace) {
return; }
6349 rb_gc_impl_adjust_memory_usage(
objspace, diff);
6353rb_obj_info(
VALUE obj)
6355 return obj_info(obj);
6359rb_obj_info_dump(
VALUE obj)
6362 fprintf(stderr,
"rb_obj_info_dump: %s\n", rb_raw_obj_info(buff, 0x100, obj));
6366rb_obj_info_dump_loc(
VALUE obj,
const char *file,
int line,
const char *func)
6369 fprintf(stderr,
"<OBJ_INFO:%s@%s:%d> %s\n", func, file, line, rb_raw_obj_info(buff, 0x100, obj));
6373rb_gc_before_fork(
void)
6375 rb_gc_impl_before_fork(rb_gc_get_objspace());
6379rb_gc_after_fork(rb_pid_t pid)
6381 rb_gc_impl_after_fork(rb_gc_get_objspace(), pid);
6385rb_gc_obj_shareable_p(
VALUE obj)
6402check_shareable_i(
const VALUE child,
void *ptr)
6406 if (!rb_gc_obj_shareable_p(child)) {
6411 if (rb_gc_impl_shref_marked_p(rb_gc_get_objspace(), child)) {
6415 fprintf(stderr,
"(a) ");
6416 rb_gc_rp(data->parent);
6417 fprintf(stderr,
"(b) ");
6419 fprintf(stderr,
"check_shareable_i: shareable (a) -> unshareable (b) without a shref record\n");
6422 rb_bug(
"!! violate shareable constraint !!");
6435rb_gc_verify_shareable(
VALUE obj)
6446 .mark_func = check_shareable_i,
6448 .checking_shareable =
true,
6452 rb_gc_mark_children(rb_gc_get_objspace(), obj);
6456 if (data.err_count > 0) {
6457 rb_bug(
"rb_gc_verify_shareable");
6462rb_gc_checking_shareable(
void)
6465 return mfd && mfd->checking_shareable;
6501 const char* nofree_str = getenv(
"RUBY_NO_FREE");
6502 if (nofree_str && strcmp(nofree_str,
"1") == 0) {
6503 fprintf(stderr,
"WARNING: Enabling no-free mode! xfree() will never free anything!\n");
6509 malloc_offset = gc_compute_malloc_offset();
6511 rb_mGC = rb_define_module(
"GC");
6513 VALUE rb_mObjSpace = rb_define_module(
"ObjectSpace");
6520 rb_vm_register_special_exception(ruby_error_nomemory,
rb_eNoMemError,
"failed to allocate memory");
6543ruby_annotate_mmap(
const void *addr,
unsigned long size,
const char *name)
6545#if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_VMA) && defined(PR_SET_VMA_ANON_NAME)
6548 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (
unsigned long)addr, size, name);
#define RUBY_ASSERT_ALWAYS(expr,...)
A variant of RUBY_ASSERT that does not interface with RUBY_DEBUG.
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
#define RUBY_ATOMIC_VALUE_CAS(var, oldval, newval)
Identical to RUBY_ATOMIC_CAS, except it expects its arguments are VALUE.
#define RUBY_ATOMIC_SIZE_FETCH_ADD(var, val)
Identical to RUBY_ATOMIC_FETCH_ADD, except it expects its arguments to be size_t.
#define RUBY_ATOMIC_INC(var)
Atomically increments the value pointed by var.
#define RUBY_ATOMIC_CAS(var, oldval, newval)
Atomic compare-and-swap.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
#define RUBY_ATOMIC_FETCH_ADD(var, val)
Atomically replaces the value pointed by var with the result of addition of val to the old value of v...
#define RUBY_ATOMIC_DEC(var)
Atomically decrements the value pointed by var.
#define RUBY_ATOMIC_LOAD(var)
Atomic load.
#define RUBY_ATOMIC_SET(var, val)
Identical to RUBY_ATOMIC_EXCHANGE, except for the return type.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_module_function(klass, mid, func, arity)
Defines klass#mid and makes it a module function.
unsigned int rb_postponed_job_handle_t
The type of a handle returned from rb_postponed_job_preregister and passed to rb_postponed_job_trigge...
void rb_postponed_job_trigger(rb_postponed_job_handle_t h)
Triggers a pre-registered job registered with rb_postponed_job_preregister, scheduling it for executi...
rb_postponed_job_handle_t rb_postponed_job_preregister(unsigned int flags, rb_postponed_job_func_t func, void *data)
Pre-registers a func in Ruby's postponed job preregistration table, returning an opaque handle which ...
uint32_t rb_event_flag_t
Represents event(s).
#define RUBY_INTERNAL_EVENT_NEWOBJ
Object allocated.
static bool RB_OBJ_FROZEN(VALUE obj)
Checks if an object is frozen.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
#define TYPE(_)
Old name of rb_type.
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
#define T_FILE
Old name of RUBY_T_FILE.
#define T_STRING
Old name of RUBY_T_STRING.
#define xfree
Old name of ruby_xfree.
#define T_MASK
Old name of RUBY_T_MASK.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define T_FLOAT
Old name of RUBY_T_FLOAT.
#define T_IMEMO
Old name of RUBY_T_IMEMO.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define T_STRUCT
Old name of RUBY_T_STRUCT.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define SYM2ID
Old name of RB_SYM2ID.
#define T_DATA
Old name of RUBY_T_DATA.
#define FIXNUM_FLAG
Old name of RUBY_FIXNUM_FLAG.
#define LL2NUM
Old name of RB_LL2NUM.
#define CLASS_OF
Old name of rb_class_of.
#define T_NONE
Old name of RUBY_T_NONE.
#define T_NODE
Old name of RUBY_T_NODE.
#define SIZET2NUM
Old name of RB_SIZE2NUM.
#define FL_FINALIZE
Old name of RUBY_FL_FINALIZE.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define ASSUME
Old name of RBIMPL_ASSUME.
#define T_TRUE
Old name of RUBY_T_TRUE.
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
#define T_ICLASS
Old name of RUBY_T_ICLASS.
#define T_HASH
Old name of RUBY_T_HASH.
#define FL_ABLE
Old name of RB_FL_ABLE.
#define FL_TEST_RAW
Old name of RB_FL_TEST_RAW.
#define rb_ary_new3
Old name of rb_ary_new_from_args.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define T_FALSE
Old name of RUBY_T_FALSE.
#define ULL2NUM
Old name of RB_ULL2NUM.
#define T_UNDEF
Old name of RUBY_T_UNDEF.
#define T_ZOMBIE
Old name of RUBY_T_ZOMBIE.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define T_OBJECT
Old name of RUBY_T_OBJECT.
#define NIL_P
Old name of RB_NIL_P.
#define FL_WB_PROTECTED
Old name of RUBY_FL_WB_PROTECTED.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
#define T_MATCH
Old name of RUBY_T_MATCH.
#define T_CLASS
Old name of RUBY_T_CLASS.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
#define T_MOVED
Old name of RUBY_T_MOVED.
#define FL_TEST
Old name of RB_FL_TEST.
#define xcalloc
Old name of ruby_xcalloc.
#define FL_UNSET
Old name of RB_FL_UNSET.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define T_REGEXP
Old name of RUBY_T_REGEXP.
size_t ruby_stack_length(VALUE **p)
Queries what Ruby thinks is the machine stack.
int ruby_stack_check(void)
Checks for stack overflow.
VALUE rb_eNoMemError
NoMemoryError exception.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_mKernel
Kernel module.
VALUE rb_cObject
Object class.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_cBasicObject
BasicObject class.
VALUE rb_class_real(VALUE klass)
Finds a "real" class.
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Defines RBIMPL_HAS_BUILTIN.
void rb_ary_free(VALUE ary)
Destroys the given array for no reason.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_block_proc(void)
Constructs a Proc object from implicitly passed components.
VALUE rb_obj_is_proc(VALUE recv)
Queries if the given object is a proc.
void rb_str_free(VALUE str)
Destroys the given string for no reason.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_mod_name(VALUE mod)
Queries the name of a module.
void rb_free_generic_ivar(VALUE obj)
Frees the list of instance variables.
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
rb_alloc_func_t rb_get_alloc_func(VALUE klass)
Queries the allocator function of a class.
int rb_obj_respond_to(VALUE obj, ID mid, int private_p)
Identical to rb_respond_to(), except it additionally takes the visibility parameter.
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
int len
Length of the buffer.
static bool rb_ractor_shareable_p(VALUE obj)
Queries if multiple Ractors can share the passed object or not.
#define RB_OBJ_SHAREABLE_P(obj)
Queries if the passed object has previously classified as shareable or not.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
VALUE rb_yield(VALUE val)
Yields the block.
#define RBIMPL_ATTR_MAYBE_UNUSED()
Wraps (or simulates) [[maybe_unused]]
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY(obj)
Convenient casting macro.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
static VALUE RBASIC_CLASS(VALUE obj)
Queries the class of an object.
#define RBASIC(obj)
Convenient casting macro.
#define RCLASS(obj)
Convenient casting macro.
#define RUBY_DEFAULT_FREE
This is a value you can set to RData::dfree.
void(* RUBY_DATA_FUNC)(void *)
This is the type of callbacks registered to RData.
#define RUBY_NEVER_FREE
This is a value you can set to RData::dfree.
#define RFILE(obj)
Convenient casting macro.
#define RHASH_SIZE(h)
Queries the size of the hash.
#define RHASH_EMPTY_P(h)
Checks if the hash is empty.
#define RMATCH(obj)
Convenient casting macro.
#define ROBJECT(obj)
Convenient casting macro.
#define RREGEXP(obj)
Convenient casting macro.
static struct re_pattern_buffer * RREGEXP_PTR(VALUE rexp)
Convenient getter function.
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
#define RSTRING(obj)
Convenient casting macro.
static long RSTRUCT_LEN(VALUE st)
Returns the number of struct members.
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type)
This is the primitive way to wrap an existing C struct into RTypedData.
VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type)
Identical to rb_data_typed_object_wrap(), except it allocates a new data region internally instead of...
#define RUBY_TYPED_FREE_IMMEDIATELY
Macros to see if each corresponding flag is defined.
#define DATA_PTR(obj)
Convenient casting macro for backward compatibility.
static const rb_data_type_t * RTYPEDDATA_TYPE(VALUE obj)
Queries for the type of given object.
#define RDATA(obj)
Convenient casting macro for backward compatibility.
#define RTYPEDDATA(obj)
Convenient casting macro.
const char * rb_obj_classname(VALUE obj)
Queries the name of the class of the passed object.
void rb_p(VALUE obj)
Inspects an object.
#define errno
Ractor-aware version of errno.
int ruby_native_thread_p(void)
Queries if the thread which calls this function is a ruby's thread.
static bool RB_SPECIAL_CONST_P(VALUE obj)
Checks if the given object is of enum ruby_special_consts.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Ruby object's base components.
Regular expression execution context.
union RMatch::@58 as
"Registers" of a match.
struct rmatch_offset * char_offset
Capture group offsets, in C array.
int char_offset_num_allocated
Number of rmatch_offset that ::rmatch::char_offset holds.
int num_regs
Number of capture-group registers.
void * data
Pointer to the actual C level struct that you want to wrap.
VALUE fields_obj
Direct reference to the slots that holds instance variables, if any.
This is the struct that holds necessary info for a struct.
struct rb_data_type_struct::@64 function
Function pointers.
RUBY_DATA_FUNC dcompact
This function is called when the object is relocated.
const char * wrap_struct_name
Name of structs of this kind.
RUBY_DATA_FUNC dmark
This function is called when the object is experiencing GC marks.
Ruby's IO, metadata and buffers.
const rb_iseq_t * iseqptr
iseq pointer, should be separated from iseqval
Represents the region of a capture group.
void rb_native_mutex_lock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_lock.
void rb_native_mutex_initialize(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_initialize.
void rb_native_mutex_unlock(rb_nativethread_lock_t *lock)
Just another name of rb_nativethread_lock_unlock.
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
ruby_value_type
C-level type of an object.
@ RUBY_T_MASK
Bitmask of ruby_value_type.