10#include "gc/gc_impl.h"
11#include "gc/mmtk/mmtk.h"
14# include "gc/mmtk/zjit_fastpath.h"
17#include "ccan/list/list.h"
21#include <sys/sysctl.h>
25 bool user_gc_disabled;
30 size_t moving_gc_count;
32 size_t total_allocated_objects;
38 struct ccan_list_head ractor_caches;
39 unsigned long live_ractor_cache_count;
41 pthread_mutex_t mutex;
44 pthread_cond_t cond_world_stopped;
45 pthread_cond_t cond_world_started;
46 size_t start_the_world_count;
48 pthread_mutex_t event_hook_mutex;
51 bool gc_thread_crashed;
57 unsigned int fork_hook_vm_lock_lev;
59 uintptr_t vo_bit_log_region_size;
60 uintptr_t vo_bit_base_addr;
61 size_t max_non_los_default_alloc_bytes;
64#define OBJ_FREE_BUF_CAPACITY 128
67 struct ccan_list_node list_node;
69 MMTk_Mutator *mutator;
74 MMTk_ObjectReference obj_free_parallel_buf[OBJ_FREE_BUF_CAPACITY];
75 size_t obj_free_parallel_count;
76 MMTk_ObjectReference obj_free_non_parallel_buf[OBJ_FREE_BUF_CAPACITY];
77 size_t obj_free_non_parallel_count;
84 MMTK_FINAL_JOB_FINALIZE,
93 VALUE finalizer_array;
98#ifdef RB_THREAD_LOCAL_SPECIFIER
101RB_THREAD_LOCAL_SPECIFIER
VALUE marking_parent_object;
103# error We currently need language-supported TLS
107# define MMTK_ASSERT(expr, ...) RUBY_ASSERT_ALWAYS(expr, #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
109# define MMTK_ASSERT(expr, ...) ((void)0)
114#define MMTK_ALLOCATION_SEMANTICS_DEFAULT 0
115#define MMTK_ALLOCATION_SEMANTICS_LOS 2
117static inline VALUE rb_mmtk_call_object_closure(
VALUE obj,
bool pin);
122 rb_mmtk_gc_thread_tls = gc_thread_tls;
126rb_mmtk_is_mutator(
void)
132rb_mmtk_stop_the_world(
void)
137 if ((err = pthread_mutex_lock(&
objspace->mutex)) != 0) {
138 rb_bug(
"ERROR: cannot lock objspace->mutex: %s", strerror(err));
145 if ((err = pthread_mutex_unlock(&
objspace->mutex)) != 0) {
146 rb_bug(
"ERROR: cannot release objspace->mutex: %s", strerror(err));
151rb_mmtk_resume_mutators(
bool current_gc_may_move)
156 if ((err = pthread_mutex_lock(&
objspace->mutex)) != 0) {
157 rb_bug(
"ERROR: cannot lock objspace->mutex: %s", strerror(err));
162 if (current_gc_may_move)
objspace->moving_gc_count++;
163 pthread_cond_broadcast(&
objspace->cond_world_started);
165 if ((err = pthread_mutex_unlock(&
objspace->mutex)) != 0) {
166 rb_bug(
"ERROR: cannot release objspace->mutex: %s", strerror(err));
177 size_t starting_gc_count =
objspace->gc_count;
179 int lock_lev = RB_GC_VM_LOCK();
182 if ((err = pthread_mutex_lock(&
objspace->mutex)) != 0) {
183 rb_bug(
"ERROR: cannot lock objspace->mutex: %s", strerror(err));
186 if (
objspace->gc_count == starting_gc_count) {
189 rb_gc_initialize_vm_context(&
objspace->vm_context);
191 mutator->gc_mutator_p =
true;
195 clock_gettime(CLOCK_MONOTONIC, &gc_start_time);
198 rb_gc_save_machine_context();
203 ccan_list_for_each(&
objspace->ractor_caches, rc, list_node) {
204 mmtk_flush_obj_free_buffer(rc);
209 pthread_cond_broadcast(&
objspace->cond_world_stopped);
216 if (RB_UNLIKELY(
objspace->crash_context.gc_thread_crashed)) {
217 rb_bug(
"%s",
objspace->crash_context.crash_msg);
222 clock_gettime(CLOCK_MONOTONIC, &gc_end_time);
225 (gc_end_time.tv_sec - gc_start_time.tv_sec) * (1000 * 1000 * 1000) +
226 (gc_end_time.tv_nsec - gc_start_time.tv_nsec);
230 if ((err = pthread_mutex_unlock(&
objspace->mutex)) != 0) {
231 rb_bug(
"ERROR: cannot release objspace->mutex: %s", strerror(err));
233 RB_GC_VM_UNLOCK(lock_lev);
237rb_mmtk_before_updating_jit_code(
void)
239 rb_gc_before_updating_jit_code();
243rb_mmtk_after_updating_jit_code(
void)
245 rb_gc_after_updating_jit_code();
249rb_mmtk_number_of_mutators(
void)
252 return objspace->live_ractor_cache_count;
256rb_mmtk_get_mutators(
void (*visit_mutator)(MMTk_Mutator *mutator,
void *data),
void *data)
261 ccan_list_for_each(&
objspace->ractor_caches, ractor_cache, list_node) {
262 visit_mutator(ractor_cache->mutator, data);
267rb_mmtk_scan_gc_roots(
void)
275pin_value(st_data_t key, st_data_t value, st_data_t data)
277 rb_gc_impl_mark_and_pin((
void *)data, (
VALUE)value);
283rb_mmtk_scan_objspace(
void)
287 if (
objspace->finalizer_table != NULL) {
292 while (job != NULL) {
294 case MMTK_FINAL_JOB_DFREE:
296 case MMTK_FINAL_JOB_FINALIZE:
297 rb_gc_impl_mark(
objspace, job->as.finalize.finalizer_array);
300 rb_bug(
"rb_mmtk_scan_objspace: unknown final job type %d", job->kind);
308rb_mmtk_move_obj_during_marking(MMTk_ObjectReference from, MMTk_ObjectReference to)
310 rb_gc_move_obj_during_marking((
VALUE)from, (
VALUE)to);
314rb_mmtk_update_object_references(MMTk_ObjectReference mmtk_object)
319 marking_parent_object = object;
320 rb_gc_update_object_references(rb_gc_get_objspace(),
object);
321 marking_parent_object = 0;
326rb_mmtk_call_gc_mark_children(MMTk_ObjectReference
object)
328 marking_parent_object = (
VALUE)
object;
329 rb_gc_mark_children(rb_gc_get_objspace(), (
VALUE)
object);
330 marking_parent_object = 0;
334rb_mmtk_handle_weak_references(MMTk_ObjectReference mmtk_object,
bool moving)
338 marking_parent_object = object;
340 rb_gc_handle_weak_references(
object);
343 rb_gc_update_object_references(rb_gc_get_objspace(),
object);
346 marking_parent_object = 0;
350rb_mmtk_call_obj_free(MMTk_ObjectReference
object)
356 pthread_mutex_lock(&
objspace->event_hook_mutex);
358 pthread_mutex_unlock(&
objspace->event_hook_mutex);
361 if (RB_UNLIKELY(rb_gc_obj_needs_cleanup_p(obj))) {
366 memset((
void *)obj, 0, rb_gc_impl_obj_slot_size(obj));
371rb_mmtk_vm_live_bytes(
void)
382 job->next =
objspace->finalizer_jobs;
383 job->kind = MMTK_FINAL_JOB_FINALIZE;
384 job->as.finalize.finalizer_array = table;
390rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data,
int error)
392 MMTK_ASSERT(mmtk_is_reachable((MMTk_ObjectReference)value));
397 if (mmtk_is_reachable((MMTk_ObjectReference)key)) {
398 VALUE new_key_location = rb_mmtk_call_object_closure((
VALUE)key,
false);
402 if (new_key_location != key) {
418rb_mmtk_update_finalizer_table_replace_i(st_data_t *key, st_data_t *value, st_data_t data,
int existing)
420 *key = rb_mmtk_call_object_closure((
VALUE)*key,
false);
426rb_mmtk_update_finalizer_table(
void)
430 st_foreach_with_replace(
432 rb_mmtk_update_finalizer_table_i,
433 rb_mmtk_update_finalizer_table_replace_i,
439rb_mmtk_global_tables_count(
void)
441 return RB_GC_VM_WEAK_TABLE_COUNT;
444static inline VALUE rb_mmtk_call_object_closure(
VALUE obj,
bool pin);
447rb_mmtk_update_global_tables_i(
VALUE val,
void *data)
449 if (!mmtk_is_reachable((MMTk_ObjectReference)val)) {
454 if (rb_mmtk_call_object_closure(val,
false) != val) {
462rb_mmtk_update_global_tables_replace_i(
VALUE *ptr,
void *data)
465 *ptr = rb_mmtk_call_object_closure(*ptr,
false);
471rb_mmtk_update_global_tables(
int table,
bool moving)
473 MMTK_ASSERT(table < RB_GC_VM_WEAK_TABLE_COUNT);
475 rb_gc_vm_weak_table_foreach(
476 rb_mmtk_update_global_tables_i,
477 rb_mmtk_update_global_tables_replace_i,
480 (
enum rb_gc_vm_weak_tables)table
485rb_mmtk_special_const_p(MMTk_ObjectReference
object)
495rb_mmtk_gc_thread_bug(const
char *msg, ...)
499 objspace->crash_context.gc_thread_crashed =
true;
503 vsnprintf(
objspace->crash_context.crash_msg,
sizeof(
objspace->crash_context.crash_msg), msg, args);
506 fprintf(stderr,
"-- GC thread backtrace "
507 "-------------------------------------------\n");
508 rb_gc_print_backtrace();
509 fprintf(stderr,
"\n");
511 rb_mmtk_resume_mutators(
false);
515 rb_bug(
"rb_mmtk_gc_thread_bug");
520rb_mmtk_gc_thread_panic_handler(
void)
522 rb_mmtk_gc_thread_bug(
"MMTk GC thread panicked");
527rb_mmtk_mutator_thread_panic_handler(
void)
529 rb_bug(
"Ruby mutator thread panicked");
534 rb_mmtk_init_gc_worker_thread,
536 rb_mmtk_stop_the_world,
537 rb_mmtk_resume_mutators,
538 rb_mmtk_block_for_gc,
539 rb_mmtk_before_updating_jit_code,
540 rb_mmtk_after_updating_jit_code,
541 rb_mmtk_number_of_mutators,
542 rb_mmtk_get_mutators,
543 rb_mmtk_scan_gc_roots,
544 rb_mmtk_scan_objspace,
545 rb_mmtk_move_obj_during_marking,
546 rb_mmtk_update_object_references,
547 rb_mmtk_call_gc_mark_children,
548 rb_mmtk_handle_weak_references,
549 rb_mmtk_call_obj_free,
550 rb_mmtk_vm_live_bytes,
551 rb_mmtk_update_global_tables,
552 rb_mmtk_global_tables_count,
553 rb_mmtk_update_finalizer_table,
554 rb_mmtk_special_const_p,
555 rb_mmtk_mutator_thread_panic_handler,
556 rb_mmtk_gc_thread_panic_handler,
560#define RB_MMTK_HEAP_LIMIT_PERC 80
561#define RB_MMTK_DEFAULT_HEAP_MIN (1024 * 1024)
562#define RB_MMTK_DEFAULT_HEAP_MAX (rb_mmtk_system_physical_memory() / 100 * RB_MMTK_HEAP_LIMIT_PERC)
565 RB_MMTK_DYNAMIC_HEAP,
570rb_mmtk_builder_init(
void)
572 MMTk_Builder *builder = mmtk_builder_default();
578rb_gc_impl_objspace_alloc(
void)
583 static struct objspace *the_objspace = NULL;
584 if (the_objspace == NULL) {
585 MMTk_Builder *builder = rb_mmtk_builder_init();
589 mmtk_init_binding(builder, &binding_options, &ruby_upcalls);
590 the_objspace = calloc(1,
sizeof(
struct objspace));
597rb_gc_impl_multi_objspace_p(
void)
602static void gc_run_finalizers(
void *data);
605rb_gc_impl_objspace_init(
void *objspace_ptr)
611 if (
objspace->finalizer_table != NULL)
return;
615 objspace->finalizer_table = st_init_numtable();
618 ccan_list_head_init(&
objspace->ractor_caches);
620 objspace->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
621 objspace->cond_world_stopped = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
622 objspace->cond_world_started = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
624 objspace->event_hook_mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
626 objspace->vo_bit_log_region_size = mmtk_get_vo_bit_log_region_size();
627 objspace->vo_bit_base_addr = mmtk_get_vo_bit_base_addr();
628 objspace->max_non_los_default_alloc_bytes = mmtk_max_non_los_default_alloc_bytes();
632rb_gc_impl_objspace_free(
void *objspace_ptr)
638rb_gc_impl_ractor_cache_alloc(
void *objspace_ptr,
void *ractor)
641 if (
objspace->live_ractor_cache_count == 0) {
642 mmtk_initialize_collection(ractor);
644 objspace->live_ractor_cache_count++;
647 ccan_list_add(&
objspace->ractor_caches, &cache->list_node);
649 cache->mutator = mmtk_bind_mutator(cache);
650 cache->bump_pointer = mmtk_get_bump_pointer_allocator(cache->mutator);
656rb_gc_impl_objspace_retire_gc(
void *objspace_ptr)
662rb_gc_impl_ractor_cache_free(
void *objspace_ptr,
void *cache_ptr)
667 ccan_list_del(&cache->list_node);
669 mmtk_flush_obj_free_buffer(cache);
671 if (ruby_free_at_exit_p()) {
672 MMTK_ASSERT(
objspace->live_ractor_cache_count > 0);
675 MMTK_ASSERT(
objspace->live_ractor_cache_count > 1);
678 objspace->live_ractor_cache_count--;
680 mmtk_destroy_mutator(cache->mutator);
686zjit_mmtk_gc_stress_p(
void *objspace_ptr)
688 return ((
struct objspace *)objspace_ptr)->gc_stress;
692zjit_mmtk_newobj_tracing_p(
void)
697void rb_gc_impl_set_params(
void *objspace_ptr) { }
699static VALUE gc_verify_internal_consistency(
VALUE self) {
return Qnil; }
702rb_mmtk_align_obj_size(
size_t object_size)
704 return (object_size + MMTk_MIN_OBJ_ALIGN - 1) & ~((size_t)MMTk_MIN_OBJ_ALIGN - 1);
708rb_gc_impl_zjit_new_obj_fastpath(
void *objspace_ptr,
size_t alloc_size,
VALUE flags,
VALUE klass,
714 size_t total_size = rb_mmtk_align_obj_size(alloc_size +
sizeof(
VALUE));
715 size_t object_size = total_size -
sizeof(
VALUE);
716 size_t value_size_shift =
sizeof(
VALUE) == 8 ? 3 : 2;
718 if (total_size >
objspace->max_non_los_default_alloc_bytes)
return false;
722 offsetof(
struct objspace, total_allocated_objects),
732 MMTK_ALLOCATION_SEMANTICS_DEFAULT,
733 (uintptr_t)zjit_mmtk_gc_stress_p,
734 (uintptr_t)zjit_mmtk_newobj_tracing_p,
735 (uintptr_t)mmtk_post_alloc,
736 OBJ_FREE_BUF_CAPACITY - 1,
742 memset(fastpath, 0,
sizeof(*fastpath));
743 fastpath->kind = RB_GC_ZJIT_FASTPATH_MMTK;
744 memcpy(fastpath->data.words, &mmtk_fastpath,
sizeof(mmtk_fastpath));
755 VALUE gc_constants = rb_hash_new();
756 rb_hash_aset(gc_constants,
ID2SYM(rb_intern(
"RVALUE_SIZE")),
SIZET2NUM(
sizeof(
struct RBasic) +
sizeof(
VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX])));
758 rb_hash_aset(gc_constants,
ID2SYM(rb_intern(
"RVALUE_OVERHEAD")),
INT2NUM(0));
760 rb_hash_aset(gc_constants,
ID2SYM(rb_intern(
"RVALUE_OLD_AGE")),
INT2FIX(0));
762 rb_define_const(
rb_mGC,
"INTERNAL_CONSTANTS", gc_constants);
775rb_mmtk_obj_free_iter_wrapper(
VALUE obj,
void *data)
780 rb_gc_obj_free_vm_weak_references(obj);
791rb_gc_impl_shutdown_free_objects(
void *objspace_ptr)
793 mmtk_set_gc_enabled(
false);
794 each_object(objspace_ptr, rb_mmtk_obj_free_iter_wrapper, objspace_ptr);
795 mmtk_set_gc_enabled(
true);
800rb_gc_impl_start(
void *objspace_ptr,
bool full_mark,
bool immediate_mark,
bool immediate_sweep,
bool compact)
802 mmtk_handle_user_collection_request(rb_gc_get_ractor_newobj_cache(),
true, full_mark);
806rb_gc_impl_during_gc_p(
void *objspace_ptr)
813rb_gc_impl_prepare_heap_i(MMTk_ObjectReference obj,
void *d)
815 rb_gc_prepare_heap_process_object((
VALUE)obj);
819rb_gc_impl_prepare_heap(
void *objspace_ptr)
821 mmtk_enumerate_objects(rb_gc_impl_prepare_heap_i, NULL);
825rb_gc_impl_gc_enable(
void *objspace_ptr)
827 mmtk_set_gc_enabled(
true);
831rb_gc_impl_gc_disable(
void *objspace_ptr,
bool finish_current_gc)
833 mmtk_set_gc_enabled(
false);
837rb_gc_impl_user_gc_disabled_set(
void *objspace_ptr,
bool disable)
840 const bool was =
objspace->user_gc_disabled;
841 objspace->user_gc_disabled = disable;
843 if (was != disable) {
844 mmtk_set_gc_enabled(!disable);
845 objspace->user_gc_disabled = disable;
852rb_gc_impl_user_gc_disabled_p(
void *objspace_ptr)
859rb_gc_impl_gc_enabled_p(
void *objspace_ptr)
861 return mmtk_gc_enabled_p();
865rb_gc_impl_stress_set(
void *objspace_ptr,
VALUE flag)
873rb_gc_impl_stress_get(
void *objspace_ptr)
881rb_gc_impl_config_get(
void *objspace_ptr)
883 VALUE hash = rb_hash_new();
888 size_t heap_min = mmtk_heap_min();
896rb_gc_impl_config_set(
void *objspace_ptr,
VALUE hash)
902rb_gc_impl_get_vm_context(
void *objspace_ptr)
915 if (bump_pointer == NULL)
return 0;
917 uintptr_t cursor = bump_pointer->cursor;
920 size_t mask = align - 1;
921 cursor = (cursor + mask) & ~mask;
925 if (cursor > bump_pointer->limit) {
929 VALUE obj = cursor - size;
930 bump_pointer->cursor = cursor;
936obj_can_parallel_free_p(
VALUE obj)
957obj_need_obj_free_p(
VALUE obj)
973 if (cache->obj_free_parallel_count > 0) {
974 mmtk_add_obj_free_candidates(cache->obj_free_parallel_buf,
975 cache->obj_free_parallel_count,
true);
976 cache->obj_free_parallel_count = 0;
978 if (cache->obj_free_non_parallel_count > 0) {
979 mmtk_add_obj_free_candidates(cache->obj_free_non_parallel_buf,
980 cache->obj_free_non_parallel_count,
false);
981 cache->obj_free_non_parallel_count = 0;
988 if (obj_can_parallel_free_p(obj)) {
989 cache->obj_free_parallel_buf[cache->obj_free_parallel_count++] = (MMTk_ObjectReference)obj;
990 if (cache->obj_free_parallel_count >= OBJ_FREE_BUF_CAPACITY) {
991 mmtk_add_obj_free_candidates(cache->obj_free_parallel_buf,
992 cache->obj_free_parallel_count,
true);
993 cache->obj_free_parallel_count = 0;
997 cache->obj_free_non_parallel_buf[cache->obj_free_non_parallel_count++] = (MMTk_ObjectReference)obj;
998 if (cache->obj_free_non_parallel_count >= OBJ_FREE_BUF_CAPACITY) {
999 mmtk_add_obj_free_candidates(cache->obj_free_non_parallel_buf,
1000 cache->obj_free_non_parallel_count,
false);
1001 cache->obj_free_non_parallel_count = 0;
1009 uintptr_t region_offset = obj >>
objspace->vo_bit_log_region_size;
1010 uintptr_t byte_offset = region_offset / 8;
1011 uintptr_t bit_offset = region_offset % 8;
1012 uintptr_t meta_byte_address =
objspace->vo_bit_base_addr + byte_offset;
1013 uint8_t
byte = 1 << bit_offset;
1014 uint8_t *meta_byte_ptr = (uint8_t*)meta_byte_address;
1015 *meta_byte_ptr |= byte;
1019rb_gc_impl_new_obj(
void *objspace_ptr,
void *cache_ptr,
VALUE klass,
VALUE flags,
bool wb_protected,
size_t alloc_size,
size_t *actual_alloc_size)
1024 if (alloc_size == 0) {
1025 rb_bug(
"rb_gc_impl_new_obj: allocation size out of range (size=%"PRIuSIZE
")", alloc_size);
1029 size_t total_size = rb_mmtk_align_obj_size(alloc_size +
sizeof(
VALUE));
1030 size_t object_size = total_size -
sizeof(
VALUE);
1031 MMTk_AllocationSemantics semantics = total_size >
objspace->max_non_los_default_alloc_bytes
1032 ? MMTK_ALLOCATION_SEMANTICS_LOS
1033 : MMTK_ALLOCATION_SEMANTICS_DEFAULT;
1034 *actual_alloc_size = object_size;
1037 mmtk_handle_user_collection_request(ractor_cache,
false,
false);
1040 VALUE *alloc_obj = semantics == MMTK_ALLOCATION_SEMANTICS_DEFAULT
1041 ? (
VALUE *)rb_mmtk_alloc_fast_path(
objspace, ractor_cache, total_size, MMTk_MIN_OBJ_ALIGN)
1044 alloc_obj = mmtk_alloc(ractor_cache->mutator, total_size, MMTk_MIN_OBJ_ALIGN, 0, semantics);
1047 if (RB_UNLIKELY(alloc_obj == NULL)) {
1053 alloc_obj[-1] = object_size;
1054 alloc_obj[0] = flags;
1055 alloc_obj[1] = klass;
1057 if (RB_UNLIKELY(!wb_protected)) {
1058 mmtk_register_wb_unprotected_object((MMTk_ObjectReference)alloc_obj);
1061 if (semantics == MMTK_ALLOCATION_SEMANTICS_LOS || ractor_cache->bump_pointer == NULL) {
1062 mmtk_post_alloc(ractor_cache->mutator, (
void*)alloc_obj, total_size, semantics);
1066 mmtk_post_alloc_fast_immix(
objspace, ractor_cache, (uintptr_t)alloc_obj);
1069 if (obj_need_obj_free_p((
VALUE)alloc_obj)) {
1070 mmtk_buffer_obj_free_candidate(ractor_cache, (
VALUE)alloc_obj);
1073 objspace->total_allocated_objects++;
1075 return (
VALUE)alloc_obj;
1079rb_gc_impl_obj_slot_size(
VALUE obj)
1081 return ((
VALUE *)obj)[-1];
1085rb_gc_impl_size_slot_size(
void *objspace_ptr,
size_t size)
1088 rb_bug(
"rb_gc_impl_size_slot_size: size too large (size=%"PRIuSIZE
")", size);
1091 return rb_mmtk_align_obj_size(size +
sizeof(
VALUE)) -
sizeof(
VALUE);
1095rb_gc_impl_size_allocatable_p(
size_t size)
1101rb_gc_impl_max_allocation_size(
void)
1108rb_gc_impl_malloc(
void *objspace_ptr,
size_t size,
bool gc_allowed)
1111 return malloc(size);
1115rb_gc_impl_calloc(
void *objspace_ptr,
size_t size,
bool gc_allowed)
1118 return calloc(1, size);
1122rb_gc_impl_realloc(
void *objspace_ptr,
void *ptr,
size_t new_size,
size_t old_size,
bool gc_allowed)
1125 return realloc(ptr, new_size);
1129rb_gc_impl_free(
void *objspace_ptr,
void *ptr,
size_t old_size)
1135void rb_gc_impl_adjust_memory_usage(
void *objspace_ptr, ssize_t diff) { }
1139rb_mmtk_call_object_closure(
VALUE obj,
bool pin)
1142 enum { info_size = 256 };
1143 char obj_info_buf[info_size];
1144 rb_raw_obj_info(obj_info_buf, info_size, obj);
1146 char parent_obj_info_buf[info_size];
1147 rb_raw_obj_info(parent_obj_info_buf, info_size, marking_parent_object);
1149 rb_mmtk_gc_thread_bug(
"try to mark T_NONE object (obj: %s, parent: %s)", obj_info_buf, parent_obj_info_buf);
1154 rb_mmtk_gc_thread_tls->gc_context,
1155 (MMTk_ObjectReference)obj,
1161rb_gc_impl_mark(
void *objspace_ptr,
VALUE obj)
1165 rb_mmtk_call_object_closure(obj,
false);
1169rb_gc_impl_mark_and_move(
void *objspace_ptr,
VALUE *ptr)
1173 VALUE new_obj = rb_mmtk_call_object_closure(*ptr,
false);
1174 if (new_obj != *ptr) {
1180rb_gc_impl_mark_and_pin(
void *objspace_ptr,
VALUE obj)
1184 rb_mmtk_call_object_closure(obj,
true);
1188rb_gc_impl_mark_maybe(
void *objspace_ptr,
VALUE obj)
1190 if (rb_gc_impl_live_object_p(objspace_ptr, (
const void *)obj)) {
1191 rb_gc_impl_mark_and_pin(objspace_ptr, obj);
1196rb_gc_impl_declare_weak_references(
void *objspace_ptr,
VALUE obj)
1199 mmtk_declare_weak_references((MMTk_ObjectReference)obj);
1203rb_gc_impl_handle_weak_references_alive_p(
void *objspace_ptr,
VALUE obj)
1205 return mmtk_weak_references_alive_p((MMTk_ObjectReference)obj);
1210rb_gc_impl_register_pinning_obj(
void *objspace_ptr,
VALUE obj)
1212 mmtk_register_pinning_obj((MMTk_ObjectReference)obj);
1216rb_gc_impl_object_moved_p(
void *objspace_ptr,
VALUE obj)
1218 return rb_mmtk_call_object_closure(obj,
false) != obj;
1222rb_gc_impl_pinned_p(
void *objspace_ptr,
VALUE obj)
1229rb_gc_impl_location(
void *objspace_ptr,
VALUE obj)
1231 return rb_mmtk_call_object_closure(obj,
false);
1236rb_gc_impl_writebarrier(
void *objspace_ptr,
VALUE a,
VALUE b)
1243 if (!rb_gc_impl_live_object_p(objspace_ptr, (
void *)a)) {
1245 rb_bug(
"a: %s is not an object", rb_raw_obj_info(buff, 256, a));
1248 if (!rb_gc_impl_live_object_p(objspace_ptr, (
void *)b)) {
1250 rb_bug(
"b: %s is not an object", rb_raw_obj_info(buff, 256, b));
1257 mmtk_object_reference_write_post(cache->mutator, (MMTk_ObjectReference)a);
1261rb_gc_impl_writebarrier_unprotect(
void *objspace_ptr,
VALUE obj)
1263 mmtk_register_wb_unprotected_object((MMTk_ObjectReference)obj);
1267rb_gc_impl_obj_became_shareable(
void *objspace_ptr,
VALUE obj)
1273rb_gc_impl_writebarrier_remember(
void *objspace_ptr,
VALUE obj)
1277 mmtk_object_reference_write_post(cache->mutator, (MMTk_ObjectReference)obj);
1282each_objects_i(MMTk_ObjectReference obj,
void *d)
1284 rb_darray(
VALUE) *objs = d;
1286 rb_darray_append(objs, (
VALUE)obj);
1292 rb_darray(
VALUE) objs;
1293 rb_darray_make(&objs, 0);
1295 mmtk_enumerate_objects(each_objects_i, &objs);
1298 rb_darray_foreach(objs, i, obj_ptr) {
1299 if (!mmtk_is_mmtk_object((MMTk_ObjectReference)*obj_ptr))
continue;
1301 if (func(*obj_ptr, data) != 0) {
1306 rb_darray_free(objs);
1310 int (*func)(
void *,
void *, size_t,
void *);
1315rb_gc_impl_each_objects_i(
VALUE obj,
void *d)
1319 size_t slot_size = rb_gc_impl_obj_slot_size(obj);
1321 return data->func((
void *)obj, (
void *)(obj + slot_size), slot_size, data->data);
1325rb_gc_impl_each_objects(
void *objspace_ptr,
int (*func)(
void *,
void *,
size_t,
void *),
void *data)
1332 each_object(objspace_ptr, rb_gc_impl_each_objects_i, &each_objects_data);
1336 void (*func)(
VALUE,
void *);
1341rb_gc_impl_each_object_i(
VALUE obj,
void *d)
1345 data->func(obj, data->data);
1351rb_gc_impl_each_object(
void *objspace_ptr,
void (*func)(
VALUE,
void *),
void *data)
1358 each_object(objspace_ptr, rb_gc_impl_each_object_i, &each_object_data);
1363gc_run_finalizers_get_final(
long i,
void *data)
1371gc_run_finalizers(
void *data)
1375 rb_gc_set_pending_interrupt();
1377 while (
objspace->finalizer_jobs != NULL) {
1379 objspace->finalizer_jobs = job->next;
1381 switch (job->kind) {
1382 case MMTK_FINAL_JOB_DFREE:
1383 job->as.dfree.func(job->as.dfree.data);
1385 case MMTK_FINAL_JOB_FINALIZE: {
1386 VALUE finalizer_array = job->as.finalize.finalizer_array;
1388 rb_gc_run_obj_finalizer(
1391 gc_run_finalizers_get_final,
1392 (
void *)finalizer_array
1403 rb_gc_unset_pending_interrupt();
1407rb_gc_impl_make_zombie(
void *objspace_ptr,
VALUE obj,
void (*dfree)(
void *),
void *data)
1409 if (dfree == NULL)
return;
1414 job->kind = MMTK_FINAL_JOB_DFREE;
1415 job->as.dfree.func = dfree;
1416 job->as.dfree.data = data;
1420 job->next =
objspace->finalizer_jobs;
1422 }
while (prev != job->next);
1424 if (!ruby_free_at_exit_p()) {
1430rb_gc_impl_define_finalizer(
void *objspace_ptr,
VALUE obj,
VALUE block)
1438 int lev = RB_GC_VM_LOCK();
1440 if (st_lookup(
objspace->finalizer_table, obj, &data)) {
1441 table = (
VALUE)data;
1448 for (i = 0; i <
len; i++) {
1451 RB_GC_VM_UNLOCK(lev);
1462 st_add_direct(
objspace->finalizer_table, obj, table);
1465 RB_GC_VM_UNLOCK(lev);
1471rb_gc_impl_undefine_finalizer(
void *objspace_ptr,
VALUE obj)
1475 st_data_t data = obj;
1477 int lev = RB_GC_VM_LOCK();
1478 st_delete(
objspace->finalizer_table, &data, 0);
1479 RB_GC_VM_UNLOCK(lev);
1485rb_gc_impl_copy_finalizer(
void *objspace_ptr,
VALUE dest,
VALUE obj)
1493 int lev = RB_GC_VM_LOCK();
1494 if (RB_LIKELY(st_lookup(
objspace->finalizer_table, obj, &data))) {
1497 st_insert(
objspace->finalizer_table, dest, table);
1501 rb_bug(
"rb_gc_copy_finalizer: FL_FINALIZE set but not found in finalizer_table: %s", rb_obj_info(obj));
1503 RB_GC_VM_UNLOCK(lev);
1507move_finalizer_from_table_i(st_data_t key, st_data_t val, st_data_t arg)
1517rb_gc_impl_shutdown_call_finalizer(
void *objspace_ptr)
1521 while (
objspace->finalizer_table->num_entries) {
1522 st_foreach(
objspace->finalizer_table, move_finalizer_from_table_i, (st_data_t)
objspace);
1527 unsigned int lev = RB_GC_VM_LOCK();
1530 ccan_list_for_each(&
objspace->ractor_caches, rc, list_node) {
1531 mmtk_flush_obj_free_buffer(rc);
1535 for (
size_t i = 0; i < registered_candidates.len; i++) {
1536 VALUE obj = (
VALUE)registered_candidates.ptr[i];
1538 if (rb_gc_shutdown_call_finalizer_p(obj)) {
1539 rb_gc_obj_free(objspace_ptr, obj);
1543 mmtk_free_raw_vec_of_obj_ref(registered_candidates);
1545 RB_GC_VM_UNLOCK(lev);
1553rb_gc_impl_before_fork(
void *objspace_ptr)
1558 objspace->fork_hook_vm_lock_lev = RB_GC_VM_LOCK();
1572 if (mutator_blocking_count != 0) {
1573 RB_GC_VM_UNLOCK(
objspace->fork_hook_vm_lock_lev);
1581rb_gc_impl_after_fork(
void *objspace_ptr, rb_pid_t pid)
1585 mmtk_after_fork(rb_gc_get_ractor_newobj_cache());
1587 RB_GC_VM_UNLOCK(
objspace->fork_hook_vm_lock_lev);
1593rb_gc_impl_set_measure_total_time(
void *objspace_ptr,
VALUE flag)
1601rb_gc_impl_get_measure_total_time(
void *objspace_ptr)
1609rb_gc_impl_get_total_time(
void *objspace_ptr)
1617rb_gc_impl_gc_count(
void *objspace_ptr)
1625rb_gc_impl_latest_gc_info(
void *objspace_ptr,
VALUE hash_or_key)
1636 rb_bug(
"gc_info_decode: non-hash or symbol given");
1639#define SET(name, attr) \
1640 if (key == ID2SYM(rb_intern_const(#name))) \
1642 else if (hash != Qnil) \
1643 rb_hash_aset(hash, ID2SYM(rb_intern_const(#name)), (attr));
1660 gc_stat_sym_moving_gc_count,
1662 gc_stat_sym_total_allocated_objects,
1663 gc_stat_sym_total_bytes,
1664 gc_stat_sym_used_bytes,
1665 gc_stat_sym_free_bytes,
1666 gc_stat_sym_starting_heap_address,
1667 gc_stat_sym_last_heap_address,
1668 gc_stat_sym_weak_references_count,
1672static VALUE gc_stat_symbols[gc_stat_sym_last];
1675setup_gc_stat_symbols(
void)
1677 if (gc_stat_symbols[0] == 0) {
1678#define S(s) gc_stat_symbols[gc_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
1682 S(total_allocated_objects);
1686 S(starting_heap_address);
1687 S(last_heap_address);
1688 S(weak_references_count);
1693rb_gc_impl_stat(
void *objspace_ptr,
VALUE hash_or_sym)
1698 setup_gc_stat_symbols();
1707 rb_bug(
"non-hash or symbol given");
1710#define SET(name, attr) \
1711 if (key == gc_stat_symbols[gc_stat_sym_##name]) \
1712 return SIZET2NUM(attr); \
1713 else if (hash != Qnil) \
1714 rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], SIZET2NUM(attr));
1717 SET(moving_gc_count,
objspace->moving_gc_count);
1718 SET(time,
objspace->total_gc_time / (1000 * 1000));
1719 SET(total_allocated_objects,
objspace->total_allocated_objects);
1720 SET(total_bytes, mmtk_total_bytes());
1721 SET(used_bytes, mmtk_used_bytes());
1722 SET(free_bytes, mmtk_free_bytes());
1723 SET(starting_heap_address, (
size_t)mmtk_starting_heap_address());
1724 SET(last_heap_address, (
size_t)mmtk_last_heap_address());
1725 SET(weak_references_count, mmtk_weak_references_count());
1737rb_gc_impl_stat_heap(
void *objspace_ptr,
VALUE heap_name,
VALUE hash_or_sym)
1748#define RB_GC_OBJECT_METADATA_ENTRY_COUNT 2
1752rb_gc_impl_object_metadata(
void *objspace_ptr,
VALUE obj)
1754 static ID ID_wb_protected;
1755 static ID ID_object_id;
1757 if (!ID_object_id) {
1758#define I(s) ID_##s = rb_intern(#s);
1766#define SET_ENTRY(na, v) do { \
1767 MMTK_ASSERT(n <= RB_GC_OBJECT_METADATA_ENTRY_COUNT); \
1768 object_metadata_entries[n].name = ID_##na; \
1769 object_metadata_entries[n].val = v; \
1773 if (!mmtk_object_wb_unprotected_p((MMTk_ObjectReference)obj)) SET_ENTRY(wb_protected,
Qtrue);
1774 if (rb_obj_id_p(obj)) SET_ENTRY(object_id, rb_obj_id(obj));
1776 object_metadata_entries[n].name = 0;
1777 object_metadata_entries[n].val = 0;
1779 return object_metadata_entries;
1783rb_gc_impl_live_object_p(
void *objspace_ptr,
const void *ptr)
1785 if (ptr == NULL)
return false;
1786 if ((uintptr_t)ptr %
sizeof(
void*) != 0)
return false;
1787 return mmtk_is_mmtk_object((MMTk_Address)ptr);
1791rb_gc_impl_garbage_object_p(
void *objspace_ptr,
VALUE obj)
1796void rb_gc_impl_set_event_hook(
void *objspace_ptr,
const rb_event_flag_t event) { }
1799rb_gc_impl_copy_attributes(
void *objspace_ptr,
VALUE dest,
VALUE obj)
1801 if (mmtk_object_wb_unprotected_p((MMTk_ObjectReference)obj)) {
1802 rb_gc_impl_writebarrier_unprotect(objspace_ptr, dest);
1805 rb_gc_impl_copy_finalizer(objspace_ptr, dest, obj);
1811rb_gc_impl_active_gc_name(
void)
1817rb_gc_impl_during_global_gc_p(
void *objspace_ptr)
1827rb_gc_impl_during_postmortem_p(
void *objspace_ptr)
1834rb_gc_impl_obj_foreign_p(
void *objspace_ptr,
VALUE obj)
1841rb_gc_impl_shref_marked_p(
void *objspace_ptr,
VALUE obj)
1848rb_gc_impl_heap_page_count(
void *objspace_ptr)
1855rb_gc_impl_objspace_absorb(
void *dst_ptr,
void *src_ptr)
1861rb_gc_impl_gc_rest(
void *objspace_ptr)
1868 int (*func)(
void *,
void *, size_t,
void *);
1873each_objects_shareable_i(
void *start,
void *end,
size_t stride,
void *d)
1878 int ret = data->func((
void *)obj, (
void *)(obj + stride), stride, data->data);
1879 if (ret)
return ret;
1886rb_gc_impl_each_objects_shareable(
void *objspace_ptr,
int (*func)(
void *,
void *,
size_t,
void *),
void *data)
1889 rb_gc_impl_each_objects(objspace_ptr, each_objects_shareable_i, &d);
1893rb_gc_impl_each_objects_foreign(
void *objspace_ptr,
int (*func)(
void *,
void *,
size_t,
void *),
void *data)
#define RUBY_ATOMIC_INC(var)
Atomically increments the value pointed by var.
#define RUBY_ATOMIC_PTR_CAS(var, oldval, newval)
Identical to RUBY_ATOMIC_CAS, except it expects its arguments are void*.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
#define RUBY_ATOMIC_DEC(var)
Atomically decrements the value pointed by var.
#define RUBY_ATOMIC_LOAD(var)
Atomic load.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
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 ...
#define RUBY_INTERNAL_EVENT_FREEOBJ
Object swept.
#define RUBY_INTERNAL_EVENT_GC_START
GC started.
uint32_t rb_event_flag_t
Represents event(s).
#define RUBY_INTERNAL_EVENT_NEWOBJ
Object allocated.
static VALUE RB_FL_TEST(VALUE obj, VALUE flags)
Tests if the given flag(s) are set or not.
static VALUE RB_FL_TEST_RAW(VALUE obj, VALUE flags)
This is an implementation detail of RB_FL_TEST().
static void RB_FL_SET(VALUE obj, VALUE flags)
Sets the given flag(s).
@ RUBY_FL_SHAREABLE
This flag has something to do with Ractor.
@ RUBY_FL_FINALIZE
This flag has something to do with finalisers.
@ RUBY_FL_WEAK_REFERENCE
This object weakly refers to other objects.
#define T_COMPLEX
Old name of RUBY_T_COMPLEX.
#define T_STRING
Old name of RUBY_T_STRING.
#define xfree
Old name of ruby_xfree.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define T_FLOAT
Old name of RUBY_T_FLOAT.
#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_NONE
Old name of RUBY_T_NONE.
#define SIZET2NUM
Old name of RB_SIZE2NUM.
#define xmalloc
Old name of ruby_xmalloc.
#define FL_FINALIZE
Old name of RUBY_FL_FINALIZE.
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
#define T_HASH
Old name of RUBY_T_HASH.
#define FL_SET
Old name of RB_FL_SET.
#define rb_ary_new3
Old name of rb_ary_new_from_args.
#define Qtrue
Old name of RUBY_Qtrue.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#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 T_SYMBOL
Old name of RUBY_T_SYMBOL.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
#define FL_TEST
Old name of RB_FL_TEST.
#define FL_UNSET
Old name of RB_FL_UNSET.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define T_REGEXP
Old name of RUBY_T_REGEXP.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_f_notimplement(int argc, const VALUE *argv, VALUE obj, VALUE marker)
Raises rb_eNotImpError.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
int len
Length of the buffer.
#define RB_ULONG2NUM
Just another name of rb_ulong2num_inline.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define RBIMPL_ATTR_NORETURN()
Wraps (or simulates) [[noreturn]]
#define RARRAY_LEN
Just another name of rb_array_len.
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
#define RARRAY_AREF(a, i)
#define RBASIC(obj)
Convenient casting macro.
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.
void * rust_closure
The pointer to the Rust-level closure object.
MMTk_ObjectClosureFunction c_function
The function to be called from C.
Ruby object's base components.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static enum ruby_value_type RB_BUILTIN_TYPE(VALUE obj)
Queries the type of the object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.