summaryrefslogtreecommitdiff
path: root/imemo.c
diff options
context:
space:
mode:
Diffstat (limited to 'imemo.c')
-rw-r--r--imemo.c557
1 files changed, 352 insertions, 205 deletions
diff --git a/imemo.c b/imemo.c
index ac094eb931..796e078c89 100644
--- a/imemo.c
+++ b/imemo.c
@@ -3,6 +3,8 @@
#include "id_table.h"
#include "internal.h"
#include "internal/imemo.h"
+#include "internal/object.h"
+#include "internal/st.h"
#include "vm_callinfo.h"
size_t rb_iseq_memsize(const rb_iseq_t *iseq);
@@ -15,7 +17,6 @@ rb_imemo_name(enum imemo_type type)
// put no default case to get a warning if an imemo type is missing
switch (type) {
#define IMEMO_NAME(x) case imemo_##x: return #x;
- IMEMO_NAME(ast);
IMEMO_NAME(callcache);
IMEMO_NAME(callinfo);
IMEMO_NAME(constcache);
@@ -25,14 +26,16 @@ rb_imemo_name(enum imemo_type type)
IMEMO_NAME(iseq);
IMEMO_NAME(memo);
IMEMO_NAME(ment);
- IMEMO_NAME(parser_strterm);
IMEMO_NAME(svar);
IMEMO_NAME(throw_data);
IMEMO_NAME(tmpbuf);
+ IMEMO_NAME(cvar_entry);
+ IMEMO_NAME(fields);
+ IMEMO_NAME(subclasses);
+ IMEMO_NAME(cdhash);
#undef IMEMO_NAME
- default:
- rb_bug("unreachable");
}
+ rb_bug("unreachable");
}
/* =========================================================================
@@ -40,85 +43,226 @@ rb_imemo_name(enum imemo_type type)
* ========================================================================= */
VALUE
-rb_imemo_new(enum imemo_type type, VALUE v0)
+rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable)
{
- size_t size = RVALUE_SIZE;
- VALUE flags = T_IMEMO | FL_WB_PROTECTED | (type << FL_USHIFT);
- NEWOBJ_OF(obj, void, v0, flags, size, 0);
-
- return (VALUE)obj;
+ VALUE flags = T_IMEMO | (type << FL_USHIFT) | (is_shareable ? FL_SHAREABLE : 0);
+ return rb_newobj_of(v0, flags, size);
}
-static rb_imemo_tmpbuf_t *
+VALUE
rb_imemo_tmpbuf_new(void)
{
- size_t size = sizeof(struct rb_imemo_tmpbuf_struct);
VALUE flags = T_IMEMO | (imemo_tmpbuf << FL_USHIFT);
- NEWOBJ_OF(obj, struct rb_imemo_tmpbuf_struct, 0, flags, size, 0);
+ UNPROTECTED_NEWOBJ_OF(obj, rb_imemo_tmpbuf_t, 0, flags, sizeof(rb_imemo_tmpbuf_t));
+
+ rb_gc_register_pinning_obj((VALUE)obj);
- return obj;
+ obj->ptr = NULL;
+ obj->size = 0;
+
+ return (VALUE)obj;
}
void *
-rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
+rb_alloc_tmp_buffer(volatile VALUE *store, long len)
{
- void *ptr;
- rb_imemo_tmpbuf_t *tmpbuf;
+ if (len < 0) {
+ rb_raise(rb_eArgError, "negative buffer size (or size too big)");
+ }
/* Keep the order; allocate an empty imemo first then xmalloc, to
* get rid of potential memory leak */
- tmpbuf = rb_imemo_tmpbuf_new();
+ rb_imemo_tmpbuf_t *tmpbuf = (rb_imemo_tmpbuf_t *)rb_imemo_tmpbuf_new();
*store = (VALUE)tmpbuf;
- ptr = ruby_xmalloc(size);
+ void *ptr = ruby_xmalloc(len);
tmpbuf->ptr = ptr;
- tmpbuf->cnt = cnt;
+ tmpbuf->size = len;
return ptr;
}
void *
-rb_alloc_tmp_buffer(volatile VALUE *store, long len)
+rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
{
- long cnt;
-
- if (len < 0 || (cnt = (long)roomof(len, sizeof(VALUE))) < 0) {
- rb_raise(rb_eArgError, "negative buffer size (or size too big)");
- }
-
- return rb_alloc_tmp_buffer_with_count(store, len, cnt);
+ return rb_alloc_tmp_buffer(store, (long)size);
}
void
rb_free_tmp_buffer(volatile VALUE *store)
{
+ if (!*store) return;
rb_imemo_tmpbuf_t *s = (rb_imemo_tmpbuf_t*)ATOMIC_VALUE_EXCHANGE(*store, 0);
if (s) {
void *ptr = ATOMIC_PTR_EXCHANGE(s->ptr, 0);
- s->cnt = 0;
- ruby_xfree(ptr);
+ long size = s->size;
+ s->size = 0;
+ ruby_xfree_sized(ptr, size);
}
}
-rb_imemo_tmpbuf_t *
-rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
+struct MEMO *
+rb_imemo_memo_new(VALUE a, VALUE b, long c)
{
- rb_imemo_tmpbuf_t *tmpbuf = rb_imemo_tmpbuf_new();
- tmpbuf->ptr = buf;
- tmpbuf->next = old_heap;
- tmpbuf->cnt = cnt;
+ struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0);
- return tmpbuf;
+ *((VALUE *)&memo->v1) = a;
+ *((VALUE *)&memo->v2) = b;
+ memo->u3.cnt = c;
+
+ return memo;
}
-#if IMEMO_DEBUG
-VALUE
-rb_imemo_new_debug(enum imemo_type type, VALUE v0, const char *file, int line)
+struct MEMO *
+rb_imemo_memo_new_value(VALUE a, VALUE b, VALUE c)
{
- VALUE memo = rb_imemo_new(type, v0);
- fprintf(stderr, "memo %p (type: %d) @ %s:%d\n", (void *)memo, imemo_type(memo), file, line);
+ struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0);
+
+ *((VALUE *)&memo->v1) = a;
+ *((VALUE *)&memo->v2) = b;
+ *((VALUE *)&memo->u3.value) = c;
+ memo->flags |= MEMO_U3_IS_VALUE;
+
return memo;
}
-#endif
+
+VALUE
+rb_imemo_cdhash_new(size_t size, const struct st_hash_type *type)
+{
+ struct rb_imemo_cdhash *memo = IMEMO_NEW(struct rb_imemo_cdhash, imemo_cdhash, 0);
+ memo->tbl.num_entries = 0;
+ st_init_existing_table_with_size(&memo->tbl, type, size);
+ return (VALUE)memo;
+}
+
+VALUE
+rb_imemo_fields_new(VALUE owner, shape_id_t shape_id, bool shareable)
+{
+ size_t capa = RSHAPE_CAPACITY(shape_id);
+ size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE);
+ RUBY_ASSERT(rb_gc_size_allocatable_p(embedded_size));
+ VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size, shareable);
+ // imemo fields objects should always have "RObject" layout. The
+ // layout in the shape describes the layout of the thing on which it is set.
+ // Imemo fields have the same layout as robject, therefore the layout
+ // should reflect that fact.
+ RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id));
+ RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields));
+ return fields;
+}
+
+VALUE
+rb_imemo_fields_new_complex(VALUE owner, shape_id_t shape_id, size_t capa, bool shareable)
+{
+ VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable);
+ IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa);
+ FL_SET_RAW(fields, OBJ_FIELD_HEAP);
+ // imemo fields objects should always have "RObject" layout. The
+ // layout in the shape describes the layout of the thing on which it is set.
+ // Imemo fields have the same layout as robject, therefore the layout
+ // should reflect that fact.
+ RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id));
+ return fields;
+}
+
+static int
+imemo_fields_trigger_wb_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ VALUE field_obj = (VALUE)arg;
+ RB_OBJ_WRITTEN(field_obj, Qundef, (VALUE)value);
+ return ST_CONTINUE;
+}
+
+static int
+imemo_fields_complex_wb_i(st_data_t key, st_data_t value, st_data_t arg)
+{
+ RB_OBJ_WRITTEN((VALUE)arg, Qundef, (VALUE)value);
+ return ST_CONTINUE;
+}
+
+VALUE
+rb_imemo_fields_new_complex_tbl(VALUE owner, shape_id_t shape_id, st_table *tbl, bool shareable)
+{
+ VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields), shareable);
+ IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
+ FL_SET_RAW(fields, OBJ_FIELD_HEAP);
+ // imemo fields objects should always have "RObject" layout. The
+ // layout in the shape describes the layout of the thing on which it is set.
+ // Imemo fields have the same layout as robject, therefore the layout
+ // should reflect that fact.
+ RBASIC_SET_SHAPE_ID(fields, rb_shape_id_with_robject_layout(shape_id));
+ st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields);
+ return fields;
+}
+
+VALUE
+rb_imemo_fields_clone(VALUE fields_obj)
+{
+ shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj);
+ VALUE clone;
+
+ if (rb_shape_complex_p(shape_id)) {
+ st_table *src_table = rb_imemo_fields_complex_tbl(fields_obj);
+
+ st_table *dest_table = xcalloc(1, sizeof(st_table));
+ clone = rb_imemo_fields_new_complex_tbl(rb_imemo_fields_owner(fields_obj), shape_id, dest_table, false /* TODO: check */);
+
+ st_replace(dest_table, src_table);
+
+ st_foreach(dest_table, imemo_fields_complex_wb_i, (st_data_t)clone);
+ }
+ else {
+ clone = rb_imemo_fields_new(rb_imemo_fields_owner(fields_obj), shape_id, false /* TODO: check */);
+ VALUE *fields = rb_imemo_fields_ptr(clone);
+ attr_index_t fields_count = RSHAPE_LEN(shape_id);
+ MEMCPY(fields, rb_imemo_fields_ptr(fields_obj), VALUE, fields_count);
+ for (attr_index_t i = 0; i < fields_count; i++) {
+ RB_OBJ_WRITTEN(clone, Qundef, fields[i]);
+ }
+ }
+
+ return clone;
+}
+
+void
+rb_imemo_fields_clear(VALUE fields_obj)
+{
+ // When replacing an imemo/fields by another one, we must clear
+ // its shape so that gc.c:obj_free_object_id won't be called.
+ if (rb_obj_shape_complex_p(fields_obj)) {
+ RBASIC_SET_SHAPE_ID(fields_obj, ROOT_COMPLEX_SHAPE_ID);
+ }
+ else {
+ RBASIC_SET_SHAPE_ID(fields_obj, ROOT_SHAPE_ID);
+ }
+ // Invalidate the ec->gen_fields_cache.
+ RBASIC_CLEAR_CLASS(fields_obj);
+}
+
+VALUE
+rb_imemo_subclasses_new(uint32_t capacity)
+{
+ size_t embed_size = offsetof(struct rb_subclasses, as) + capacity * sizeof(VALUE);
+ struct rb_subclasses *subs;
+
+ if (rb_gc_size_allocatable_p(embed_size)) {
+ subs = (struct rb_subclasses *)rb_imemo_new(imemo_subclasses, 0, embed_size, true);
+ subs->count = 0;
+ subs->capacity = capacity;
+ memset(subs->as.embed, 0, capacity * sizeof(VALUE));
+ rb_gc_declare_weak_references((VALUE)subs);
+ }
+ else {
+ subs = (struct rb_subclasses *)rb_imemo_new(imemo_subclasses, 0, sizeof(struct rb_subclasses), true);
+ subs->as.external = NULL;
+ subs->count = 0;
+ subs->capacity = 0;
+ FL_SET_RAW((VALUE)subs, IMEMO_SUBCLASSES_HEAP);
+ rb_gc_declare_weak_references((VALUE)subs);
+ subs->as.external = ZALLOC_N(VALUE, capacity);
+ subs->capacity = capacity;
+ }
+ return (VALUE)subs;
+}
/* =========================================================================
* memsize
@@ -129,10 +273,6 @@ rb_imemo_memsize(VALUE obj)
{
size_t size = 0;
switch (imemo_type(obj)) {
- case imemo_ast:
- rb_bug("imemo_ast is obsolete");
-
- break;
case imemo_callcache:
break;
case imemo_callinfo:
@@ -157,14 +297,32 @@ rb_imemo_memsize(VALUE obj)
size += sizeof(((rb_method_entry_t *)obj)->def);
break;
- case imemo_parser_strterm:
- break;
case imemo_svar:
break;
case imemo_throw_data:
break;
case imemo_tmpbuf:
- size += ((rb_imemo_tmpbuf_t *)obj)->cnt * sizeof(VALUE);
+ size += ((rb_imemo_tmpbuf_t *)obj)->size;
+
+ break;
+ case imemo_cvar_entry:
+ break;
+ case imemo_fields:
+ if (rb_obj_shape_complex_p(obj)) {
+ size += st_memsize(IMEMO_OBJ_FIELDS(obj)->as.complex.table);
+ }
+
+ break;
+ case imemo_subclasses: {
+ if (FL_TEST_RAW(obj, IMEMO_SUBCLASSES_HEAP)) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ size += subs->capacity * sizeof(VALUE);
+ }
+
+ break;
+ }
+ case imemo_cdhash:
+ size += st_memsize(rb_imemo_cdhash_tbl(obj)) - sizeof(st_table);
break;
default:
@@ -178,49 +336,10 @@ rb_imemo_memsize(VALUE obj)
* mark
* ========================================================================= */
-static enum rb_id_table_iterator_result
-cc_table_mark_i(VALUE ccs_ptr, void *data)
-{
- struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
- VM_ASSERT(vm_ccs_p(ccs));
-#if VM_CHECK_MODE > 0
- VALUE klass = (VALUE)data;
-
- VALUE lookup_val;
- VM_ASSERT(rb_id_table_lookup(RCLASS_CC_TBL(klass), ccs->cme->called_id, &lookup_val));
- VM_ASSERT(lookup_val == ccs_ptr);
-#endif
-
- if (METHOD_ENTRY_INVALIDATED(ccs->cme)) {
- rb_vm_ccs_free(ccs);
- return ID_TABLE_DELETE;
- }
- else {
- rb_gc_mark_movable((VALUE)ccs->cme);
-
- for (int i=0; i<ccs->len; i++) {
- VM_ASSERT(klass == ccs->entries[i].cc->klass);
- VM_ASSERT(vm_cc_check_cme(ccs->entries[i].cc, ccs->cme));
-
- rb_gc_mark_movable((VALUE)ccs->entries[i].cc);
- }
- return ID_TABLE_CONTINUE;
- }
-}
-
-void
-rb_cc_table_mark(VALUE klass)
-{
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
- if (cc_tbl) {
- rb_id_table_foreach_values(cc_tbl, cc_table_mark_i, (void *)klass);
- }
-}
-
static bool
moved_or_living_object_strictly_p(VALUE obj)
{
- return obj && (!rb_objspace_garbage_object_p(obj) || BUILTIN_TYPE(obj) == T_MOVED);
+ return !SPECIAL_CONST_P(obj) && (!rb_objspace_garbage_object_p(obj) || BUILTIN_TYPE(obj) == T_MOVED);
}
static void
@@ -252,9 +371,8 @@ mark_and_move_method_entry(rb_method_entry_t *ment, bool reference_updating)
rb_gc_mark_and_move(&def->body.attr.location);
break;
case VM_METHOD_TYPE_BMETHOD:
- rb_gc_mark_and_move(&def->body.bmethod.proc);
- if (!reference_updating) {
- if (def->body.bmethod.hooks) rb_hook_list_mark(def->body.bmethod.hooks);
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&def->body.bmethod.proc);
}
break;
case VM_METHOD_TYPE_ALIAS:
@@ -278,51 +396,52 @@ void
rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
{
switch (imemo_type(obj)) {
- case imemo_ast:
- rb_bug("imemo_ast is obsolete");
-
- break;
case imemo_callcache: {
/* cc is callcache.
*
* cc->klass (klass) should not be marked because if the klass is
* free'ed, the cc->klass will be cleared by `vm_cc_invalidate()`.
*
- * cc->cme (cme) should not be marked because if cc is invalidated
- * when cme is free'ed.
+ * For "normal" CCs cc->cme (cme) should not be marked because the cc is
+ * invalidated through the klass when the cme is free'd.
* - klass marks cme if klass uses cme.
- * - caller classe's ccs->cme marks cc->cme.
- * - if cc is invalidated (klass doesn't refer the cc),
- * cc is invalidated by `vm_cc_invalidate()` and cc->cme is
- * not be accessed.
- * - On the multi-Ractors, cme will be collected with global GC
+ * - caller class's ccs->cme marks cc->cme.
+ * - if cc is invalidated (klass doesn't refer the cc), cc is
+ * invalidated by `vm_cc_invalidate()` after which cc->cme must not
+ * be accessed.
+ * - With multi-Ractors, cme will be collected with global GC
* so that it is safe if GC is not interleaving while accessing
* cc and cme.
- * - However, cc_type_super and cc_type_refinement are not chained
- * from ccs so cc->cme should be marked; the cme might be
- * reachable only through cc in these cases.
+ *
+ * However cc_type_super and cc_type_refinement are not chained
+ * from ccs so cc->cme should be marked as long as the cc is valid;
+ * the cme might be reachable only through cc in these cases.
*/
struct rb_callcache *cc = (struct rb_callcache *)obj;
- if (reference_updating) {
- if (!cc->klass) {
- // already invalidated
+ if (UNDEF_P(cc->klass)) {
+ /* If it's invalidated, we must not mark anything.
+ * All fields should are considered invalid
+ */
+ }
+ else if (reference_updating) {
+ if (moved_or_living_object_strictly_p((VALUE)cc->cme_)) {
+ *((VALUE *)&cc->klass) = rb_gc_location(cc->klass);
+ *((struct rb_callable_method_entry_struct **)&cc->cme_) =
+ (struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cc->cme_);
+
+ RUBY_ASSERT(RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
+ RUBY_ASSERT(IMEMO_TYPE_P((VALUE)cc->cme_, imemo_ment));
}
else {
- if (moved_or_living_object_strictly_p(cc->klass) &&
- moved_or_living_object_strictly_p((VALUE)cc->cme_)) {
- *((VALUE *)&cc->klass) = rb_gc_location(cc->klass);
- *((struct rb_callable_method_entry_struct **)&cc->cme_) =
- (struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cc->cme_);
- }
- else {
- vm_cc_invalidate(cc);
- }
+ vm_cc_invalidate(cc);
}
}
else {
- if (vm_cc_super_p(cc) || vm_cc_refinement_p(cc)) {
+ RUBY_ASSERT(RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
+ RUBY_ASSERT(IMEMO_TYPE_P((VALUE)cc->cme_, imemo_ment));
+
+ if ((vm_cc_super_p(cc) || vm_cc_refinement_p(cc))) {
rb_gc_mark_movable((VALUE)cc->cme_);
- rb_gc_mark_movable((VALUE)cc->klass);
}
}
@@ -333,16 +452,27 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
case imemo_constcache: {
struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
- rb_gc_mark_and_move(&ice->value);
+ if ((ice->flags & IMEMO_CONST_CACHE_SHAREABLE) ||
+ !rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&ice->value);
+ }
break;
}
case imemo_cref: {
rb_cref_t *cref = (rb_cref_t *)obj;
- rb_gc_mark_and_move(&cref->klass_or_self);
+ if (!rb_gc_checking_shareable()) {
+ // cref->klass_or_self can be unshareable, but no way to access it from other ractors
+ rb_gc_mark_and_move(&cref->klass_or_self);
+ }
+
rb_gc_mark_and_move_ptr(&cref->next);
- rb_gc_mark_and_move(&cref->refinements);
+
+ // TODO: Ractor and refeinements are not resolved yet
+ if (!rb_gc_checking_shareable()) {
+ rb_gc_mark_and_move(&cref->refinements);
+ }
break;
}
@@ -360,6 +490,13 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
rb_gc_mark_and_move_ptr(&env->iseq);
+ if (VM_ENV_LOCAL_P(env->ep) && VM_ENV_BOXED_P(env->ep)) {
+ const rb_box_t *box = VM_ENV_BOX(env->ep);
+ if (BOX_USER_P(box)) {
+ rb_gc_mark_and_move((VALUE *)&box->box_object);
+ }
+ }
+
if (reference_updating) {
((VALUE *)env->ep)[VM_ENV_DATA_INDEX_ENV] = rb_gc_location(env->ep[VM_ENV_DATA_INDEX_ENV]);
}
@@ -390,8 +527,8 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
rb_gc_mark_and_move((VALUE *)&memo->v1);
rb_gc_mark_and_move((VALUE *)&memo->v2);
- if (!reference_updating) {
- rb_gc_mark_maybe(memo->u3.value);
+ if (FL_TEST_RAW(obj, MEMO_U3_IS_VALUE)) {
+ rb_gc_mark_and_move((VALUE *)&memo->u3.value);
}
break;
@@ -399,8 +536,6 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
case imemo_ment:
mark_and_move_method_entry((rb_method_entry_t *)obj, reference_updating);
break;
- case imemo_parser_strterm:
- break;
case imemo_svar: {
struct vm_svar *svar = (struct vm_svar *)obj;
@@ -422,13 +557,65 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
const rb_imemo_tmpbuf_t *m = (const rb_imemo_tmpbuf_t *)obj;
if (!reference_updating) {
- do {
- rb_gc_mark_locations(m->ptr, m->ptr + m->cnt);
- } while ((m = m->next) != NULL);
+ rb_gc_mark_locations(m->ptr, m->ptr + (m->size / sizeof(VALUE)));
}
break;
}
+ case imemo_cvar_entry: {
+ struct rb_cvar_class_tbl_entry *ent = (struct rb_cvar_class_tbl_entry *)obj;
+ rb_gc_mark_and_move(&ent->class_value);
+ rb_gc_mark_and_move((VALUE *)&ent->cref);
+ break;
+ }
+ case imemo_subclasses: {
+ if (reference_updating) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ VALUE *entries = rb_imemo_subclasses_entries(obj);
+ for (uint32_t i = 0; i < subs->count; i++) {
+ if (entries[i]) {
+ entries[i] = rb_gc_location(entries[i]);
+ }
+ }
+ }
+ break;
+ }
+ case imemo_fields: {
+ rb_gc_mark_and_move((VALUE *)&RBASIC(obj)->klass);
+
+ if (!rb_gc_checking_shareable()) {
+ // imemo_fields can refer unshareable objects
+ // even if the imemo_fields is shareable.
+
+ if (rb_obj_shape_complex_p(obj)) {
+ st_table *tbl = rb_imemo_fields_complex_tbl(obj);
+ if (reference_updating) {
+ rb_gc_ref_update_table_values_only(tbl);
+ }
+ else {
+ rb_mark_tbl_no_pin(tbl);
+ }
+ }
+ else {
+ VALUE *fields = rb_imemo_fields_ptr(obj);
+ attr_index_t len = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
+ for (attr_index_t i = 0; i < len; i++) {
+ rb_gc_mark_and_move(&fields[i]);
+ }
+ }
+ }
+ break;
+ }
+ case imemo_cdhash: {
+ st_table *tbl = rb_imemo_cdhash_tbl(obj);
+ if (reference_updating) {
+ rb_gc_update_set_refs(tbl);
+ }
+ else {
+ rb_gc_mark_set_no_pin(tbl);
+ }
+ break;
+ }
default:
rb_bug("unreachable");
}
@@ -442,7 +629,7 @@ static enum rb_id_table_iterator_result
free_const_entry_i(VALUE value, void *data)
{
rb_const_entry_t *ce = (rb_const_entry_t *)value;
- xfree(ce);
+ SIZED_FREE(ce);
return ID_TABLE_CONTINUE;
}
@@ -453,67 +640,12 @@ rb_free_const_table(struct rb_id_table *tbl)
rb_id_table_free(tbl);
}
-// alive: if false, target pointers can be freed already.
-static void
-vm_ccs_free(struct rb_class_cc_entries *ccs, int alive, VALUE klass)
-{
- if (ccs->entries) {
- for (int i=0; i<ccs->len; i++) {
- const struct rb_callcache *cc = ccs->entries[i].cc;
- if (!alive) {
- void *ptr = asan_unpoison_object_temporary((VALUE)cc);
- // ccs can be free'ed.
- if (!rb_objspace_garbage_object_p((VALUE)cc) &&
- IMEMO_TYPE_P(cc, imemo_callcache) &&
- cc->klass == klass) {
- // OK. maybe target cc.
- }
- else {
- if (ptr) {
- asan_poison_object((VALUE)cc);
- }
- continue;
- }
- if (ptr) {
- asan_poison_object((VALUE)cc);
- }
- }
-
- VM_ASSERT(!vm_cc_super_p(cc) && !vm_cc_refinement_p(cc));
- vm_cc_invalidate(cc);
- }
- ruby_xfree(ccs->entries);
- }
- ruby_xfree(ccs);
-}
-
-void
-rb_vm_ccs_free(struct rb_class_cc_entries *ccs)
-{
- RB_DEBUG_COUNTER_INC(ccs_free);
- vm_ccs_free(ccs, true, Qundef);
-}
-
-static enum rb_id_table_iterator_result
-cc_table_free_i(VALUE ccs_ptr, void *data)
-{
- struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
- VALUE klass = (VALUE)data;
- VM_ASSERT(vm_ccs_p(ccs));
-
- vm_ccs_free(ccs, false, klass);
-
- return ID_TABLE_CONTINUE;
-}
-
-void
-rb_cc_table_free(VALUE klass)
+static inline void
+imemo_fields_free(struct rb_fields *fields)
{
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
-
- if (cc_tbl) {
- rb_id_table_foreach_values(cc_tbl, cc_table_free_i, (void *)klass);
- rb_id_table_free(cc_tbl);
+ if (FL_TEST_RAW((VALUE)fields, OBJ_FIELD_HEAP)) {
+ RUBY_ASSERT(rb_shape_complex_p(RBASIC_SHAPE_ID((VALUE)fields)));
+ st_free_table(fields->as.complex.table);
}
}
@@ -521,10 +653,6 @@ void
rb_imemo_free(VALUE obj)
{
switch (imemo_type(obj)) {
- case imemo_ast:
- rb_bug("imemo_ast is obsolete");
-
- break;
case imemo_callcache:
RB_DEBUG_COUNTER_INC(obj_imemo_callcache);
@@ -532,10 +660,10 @@ rb_imemo_free(VALUE obj)
case imemo_callinfo:{
const struct rb_callinfo *ci = ((const struct rb_callinfo *)obj);
- rb_vm_ci_free(ci);
if (ci->kwarg) {
- ((struct rb_callinfo_kwarg *)ci->kwarg)->references--;
- if (ci->kwarg->references == 0) xfree((void *)ci->kwarg);
+ if (RUBY_ATOMIC_FETCH_SUB(((struct rb_callinfo_kwarg *)ci->kwarg)->references, 1) == 1) {
+ ruby_xfree_sized((void *)ci->kwarg, rb_callinfo_kwarg_bytes(ci->kwarg->keyword_len));
+ }
}
RB_DEBUG_COUNTER_INC(obj_imemo_callinfo);
@@ -553,7 +681,7 @@ rb_imemo_free(VALUE obj)
rb_env_t *env = (rb_env_t *)obj;
RUBY_ASSERT(VM_ENV_ESCAPED_P(env->ep));
- xfree((VALUE *)env->env);
+ SIZED_FREE_N(env->env, env->env_size);
RB_DEBUG_COUNTER_INC(obj_imemo_env);
break;
@@ -575,22 +703,41 @@ rb_imemo_free(VALUE obj)
RB_DEBUG_COUNTER_INC(obj_imemo_ment);
break;
- case imemo_parser_strterm:
- RB_DEBUG_COUNTER_INC(obj_imemo_parser_strterm);
-
- break;
case imemo_svar:
RB_DEBUG_COUNTER_INC(obj_imemo_svar);
+
break;
case imemo_throw_data:
RB_DEBUG_COUNTER_INC(obj_imemo_throw_data);
break;
case imemo_tmpbuf:
- xfree(((rb_imemo_tmpbuf_t *)obj)->ptr);
+ ruby_xfree_sized(((rb_imemo_tmpbuf_t *)obj)->ptr, ((rb_imemo_tmpbuf_t *)obj)->size);
RB_DEBUG_COUNTER_INC(obj_imemo_tmpbuf);
break;
+ case imemo_cvar_entry:
+ RB_DEBUG_COUNTER_INC(obj_imemo_cvar_entry);
+
+ break;
+ case imemo_fields:
+ imemo_fields_free(IMEMO_OBJ_FIELDS(obj));
+ RB_DEBUG_COUNTER_INC(obj_imemo_fields);
+
+ break;
+ case imemo_subclasses: {
+ if (FL_TEST_RAW(obj, IMEMO_SUBCLASSES_HEAP)) {
+ struct rb_subclasses *subs = (struct rb_subclasses *)obj;
+ SIZED_FREE_N(subs->as.external, subs->capacity);
+ }
+ RB_DEBUG_COUNTER_INC(obj_imemo_subclasses);
+ break;
+ }
+ case imemo_cdhash:
+ st_free_embedded_table(rb_imemo_cdhash_tbl(obj));
+ RB_DEBUG_COUNTER_INC(obj_imemo_cdhash);
+
+ break;
default:
rb_bug("unreachable");
}