Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 42 additions & 9 deletions cont.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ static const int DEBUG = 0;
#define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1))
static long pagesize;

static const rb_data_type_t cont_data_type, fiber_data_type;
const rb_data_type_t rb_cont_data_type;
const rb_data_type_t rb_fiber_data_type;
static VALUE rb_cContinuation;
static VALUE rb_cFiber;
static VALUE rb_eFiberError;
Expand Down Expand Up @@ -982,7 +983,7 @@ cont_ptr(VALUE obj)
{
rb_context_t *cont;

TypedData_Get_Struct(obj, rb_context_t, &cont_data_type, cont);
TypedData_Get_Struct(obj, rb_context_t, &rb_cont_data_type, cont);

return cont;
}
Expand All @@ -992,7 +993,7 @@ fiber_ptr(VALUE obj)
{
rb_fiber_t *fiber;

TypedData_Get_Struct(obj, rb_fiber_t, &fiber_data_type, fiber);
TypedData_Get_Struct(obj, rb_fiber_t, &rb_fiber_data_type, fiber);
if (!fiber) rb_raise(rb_eFiberError, "uninitialized fiber");

return fiber;
Expand Down Expand Up @@ -1211,7 +1212,7 @@ fiber_memsize(const void *ptr)
VALUE
rb_obj_is_fiber(VALUE obj)
{
return RBOOL(rb_typeddata_is_kind_of(obj, &fiber_data_type));
return RBOOL(rb_typeddata_is_kind_of(obj, &rb_fiber_data_type));
}

static void
Expand Down Expand Up @@ -1241,13 +1242,27 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
asan_unpoison_memory_region(cont->machine.stack_src, size, false);
MEMCPY(cont->machine.stack, cont->machine.stack_src, VALUE, size);
}

static const rb_data_type_t cont_data_type = {
const rb_data_type_t rb_cont_data_type = {
"continuation",
{cont_mark, cont_free, cont_memsize, cont_compact},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};

void
rb_cont_handle_weak_references(VALUE obj)
{
rb_context_t *cont;
TypedData_Get_Struct(obj, rb_context_t, &rb_cont_data_type, cont);

if (!cont) return;

if (!rb_gc_handle_weak_references_alive_p(cont->saved_ec.gen_fields_cache.obj) ||
!rb_gc_handle_weak_references_alive_p(cont->saved_ec.gen_fields_cache.fields_obj)) {
cont->saved_ec.gen_fields_cache.obj = Qundef;
cont->saved_ec.gen_fields_cache.fields_obj = Qundef;
}
}

static inline void
cont_save_thread(rb_context_t *cont, rb_thread_t *th)
{
Expand Down Expand Up @@ -1404,7 +1419,8 @@ cont_new(VALUE klass)
rb_thread_t *th = GET_THREAD();

THREAD_MUST_BE_RUNNING(th);
contval = TypedData_Make_Struct(klass, rb_context_t, &cont_data_type, cont);
contval = TypedData_Make_Struct(klass, rb_context_t, &rb_cont_data_type, cont);
rb_gc_declare_weak_references(contval);
cont->self = contval;
cont_init(cont, th);
return cont;
Expand Down Expand Up @@ -1983,16 +1999,33 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
*
*/

static const rb_data_type_t fiber_data_type = {
const rb_data_type_t rb_fiber_data_type = {
"fiber",
{fiber_mark, fiber_free, fiber_memsize, fiber_compact,},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};

void
rb_fiber_handle_weak_references(VALUE obj)
{
rb_fiber_t *fiber;
TypedData_Get_Struct(obj, rb_fiber_t, &rb_fiber_data_type, fiber);

if (!fiber) return;

if (!rb_gc_handle_weak_references_alive_p(fiber->cont.saved_ec.gen_fields_cache.obj) ||
!rb_gc_handle_weak_references_alive_p(fiber->cont.saved_ec.gen_fields_cache.fields_obj)) {
fiber->cont.saved_ec.gen_fields_cache.obj = Qundef;
fiber->cont.saved_ec.gen_fields_cache.fields_obj = Qundef;
}
}

static VALUE
fiber_alloc(VALUE klass)
{
return TypedData_Wrap_Struct(klass, &fiber_data_type, 0);
VALUE obj = TypedData_Wrap_Struct(klass, &rb_fiber_data_type, 0);
rb_gc_declare_weak_references(obj);
return obj;
}

static rb_serial_t
Expand Down
14 changes: 14 additions & 0 deletions darray.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@
(*(ptr_to_ary))->meta.size++; \
} while (0)

/* Removes the element at idx and replaces it with the last element.
* ptr_to_ary and idx is evaluated multiple times.
* Warning: not bounds checked.
*
* void rb_darray_swap_remove(rb_darray(T) *ptr_to_ary, size_t idx);
*/
#define rb_darray_swap_remove(ptr_to_ary, idx) do { \
size_t _darray_size = rb_darray_size(*(ptr_to_ary)); \
if ((idx) != _darray_size - 1) { \
(*(ptr_to_ary))->data[idx] = (*(ptr_to_ary))->data[_darray_size - 1]; \
} \
(*(ptr_to_ary))->meta.size--; \
} while (0)

// Iterate over items of the array in a for loop
//
#define rb_darray_foreach(ary, idx_name, elem_ptr_var) \
Expand Down
107 changes: 78 additions & 29 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,8 +637,9 @@ typedef struct gc_function_map {
void (*mark_and_move)(void *objspace_ptr, VALUE *ptr);
void (*mark_and_pin)(void *objspace_ptr, VALUE obj);
void (*mark_maybe)(void *objspace_ptr, VALUE obj);
void (*mark_weak)(void *objspace_ptr, VALUE *ptr);
void (*remove_weak)(void *objspace_ptr, VALUE parent_obj, VALUE *ptr);
// Weak references
void (*declare_weak_references)(void *objspace_ptr, VALUE obj);
bool (*handle_weak_references_alive_p)(void *objspace_ptr, VALUE obj);
// Compaction
bool (*object_moved_p)(void *objspace_ptr, VALUE obj);
VALUE (*location)(void *objspace_ptr, VALUE value);
Expand Down Expand Up @@ -811,8 +812,9 @@ ruby_modular_gc_init(void)
load_modular_gc_func(mark_and_move);
load_modular_gc_func(mark_and_pin);
load_modular_gc_func(mark_maybe);
load_modular_gc_func(mark_weak);
load_modular_gc_func(remove_weak);
// Weak references
load_modular_gc_func(declare_weak_references);
load_modular_gc_func(handle_weak_references_alive_p);
// Compaction
load_modular_gc_func(object_moved_p);
load_modular_gc_func(location);
Expand Down Expand Up @@ -891,8 +893,9 @@ ruby_modular_gc_init(void)
# define rb_gc_impl_mark_and_move rb_gc_functions.mark_and_move
# define rb_gc_impl_mark_and_pin rb_gc_functions.mark_and_pin
# define rb_gc_impl_mark_maybe rb_gc_functions.mark_maybe
# define rb_gc_impl_mark_weak rb_gc_functions.mark_weak
# define rb_gc_impl_remove_weak rb_gc_functions.remove_weak
// Weak references
# define rb_gc_impl_declare_weak_references rb_gc_functions.declare_weak_references
# define rb_gc_impl_handle_weak_references_alive_p rb_gc_functions.handle_weak_references_alive_p
// Compaction
# define rb_gc_impl_object_moved_p rb_gc_functions.object_moved_p
# define rb_gc_impl_location rb_gc_functions.location
Expand Down Expand Up @@ -1165,6 +1168,75 @@ rb_objspace_data_type_name(VALUE obj)
}
}

void
rb_gc_declare_weak_references(VALUE obj)
{
rb_gc_impl_declare_weak_references(rb_gc_get_objspace(), obj);
}

bool
rb_gc_handle_weak_references_alive_p(VALUE obj)
{
if (SPECIAL_CONST_P(obj)) return true;

return rb_gc_impl_handle_weak_references_alive_p(rb_gc_get_objspace(), obj);
}

extern const rb_data_type_t rb_weakmap_type;
void rb_wmap_handle_weak_references(VALUE obj);
extern const rb_data_type_t rb_weakkeymap_type;
void rb_wkmap_handle_weak_references(VALUE obj);

extern const rb_data_type_t rb_fiber_data_type;
void rb_fiber_handle_weak_references(VALUE obj);

extern const rb_data_type_t rb_cont_data_type;
void rb_cont_handle_weak_references(VALUE obj);

void
rb_gc_handle_weak_references(VALUE obj)
{
switch (BUILTIN_TYPE(obj)) {
case T_DATA:
if (RTYPEDDATA_P(obj)) {
const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);

if (type == &rb_fiber_data_type) {
rb_fiber_handle_weak_references(obj);
}
else if (type == &rb_cont_data_type) {
rb_cont_handle_weak_references(obj);
}
else if (type == &rb_weakmap_type) {
rb_wmap_handle_weak_references(obj);
}
else if (type == &rb_weakkeymap_type) {
rb_wkmap_handle_weak_references(obj);
}
else {
rb_bug("rb_gc_handle_weak_references: unknown TypedData %s", RTYPEDDATA_TYPE(obj)->wrap_struct_name);
}
}
else {
rb_bug("rb_gc_handle_weak_references: unknown T_DATA");
}
break;

case T_IMEMO: {
GC_ASSERT(imemo_type(obj) == imemo_callcache);

struct rb_callcache *cc = (struct rb_callcache *)obj;
if (!rb_gc_handle_weak_references_alive_p(cc->klass)) {
vm_cc_invalidate(cc);
}

break;
}
default:
rb_bug("rb_gc_handle_weak_references: type not supported\n");
}
}

static void
io_fptr_finalize(void *fptr)
{
Expand Down Expand Up @@ -2649,29 +2721,6 @@ rb_gc_mark_maybe(VALUE obj)
gc_mark_maybe_internal(obj);
}

void
rb_gc_mark_weak(VALUE *ptr)
{
if (RB_SPECIAL_CONST_P(*ptr)) return;

rb_vm_t *vm = GET_VM();
void *objspace = vm->gc.objspace;
if (LIKELY(vm->gc.mark_func_data == NULL)) {
GC_ASSERT(rb_gc_impl_during_gc_p(objspace));

rb_gc_impl_mark_weak(objspace, ptr);
}
else {
GC_ASSERT(!rb_gc_impl_during_gc_p(objspace));
}
}

void
rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr)
{
rb_gc_impl_remove_weak(rb_gc_get_objspace(), parent_obj, ptr);
}

ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static void each_location(register const VALUE *x, register long n, void (*cb)(VALUE, void *), void *data));
static void
each_location(register const VALUE *x, register long n, void (*cb)(VALUE, void *), void *data)
Expand Down
Loading