Skip to content

Commit

Permalink
Implement object shapes for T_CLASS and T_MODULE (ruby#6637)
Browse files Browse the repository at this point in the history
* Avoid RCLASS_IV_TBL in marshal.c
* Avoid RCLASS_IV_TBL for class names
* Avoid RCLASS_IV_TBL for autoload
* Avoid RCLASS_IV_TBL for class variables
* Avoid copying RCLASS_IV_TBL onto ICLASSes
* Use object shapes for Class and Module IVs
  • Loading branch information
jhawthorn committed Oct 31, 2022
1 parent 2b39640 commit 02f1554
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 202 deletions.
21 changes: 5 additions & 16 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ class_alloc(VALUE flags, VALUE klass)
#endif

/* ZALLOC
RCLASS_IV_TBL(obj) = 0;
RCLASS_CONST_TBL(obj) = 0;
RCLASS_M_TBL(obj) = 0;
RCLASS_IV_INDEX_TBL(obj) = 0;
Expand Down Expand Up @@ -402,23 +401,19 @@ class_init_copy_check(VALUE clone, VALUE orig)
static void
copy_tables(VALUE clone, VALUE orig)
{
if (RCLASS_IV_TBL(clone)) {
st_free_table(RCLASS_IV_TBL(clone));
RCLASS_IV_TBL(clone) = 0;
}
if (RCLASS_CONST_TBL(clone)) {
rb_free_const_table(RCLASS_CONST_TBL(clone));
RCLASS_CONST_TBL(clone) = 0;
}
RCLASS_M_TBL(clone) = 0;
if (RCLASS_IV_TBL(orig)) {
if (!RB_TYPE_P(clone, T_ICLASS)) {
st_data_t id;

rb_iv_tbl_copy(clone, orig);
CONST_ID(id, "__tmp_classpath__");
st_delete(RCLASS_IV_TBL(clone), &id, 0);
rb_attr_delete(clone, id);
CONST_ID(id, "__classpath__");
st_delete(RCLASS_IV_TBL(clone), &id, 0);
rb_attr_delete(clone, id);
}
if (RCLASS_CONST_TBL(orig)) {
struct clone_const_arg arg;
Expand Down Expand Up @@ -520,7 +515,6 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
prev_clone_p = clone_p;
RCLASS_M_TBL(clone_p) = RCLASS_M_TBL(p);
RCLASS_CONST_TBL(clone_p) = RCLASS_CONST_TBL(p);
RCLASS_IV_TBL(clone_p) = RCLASS_IV_TBL(p);
RCLASS_ALLOCATOR(clone_p) = RCLASS_ALLOCATOR(p);
if (RB_TYPE_P(clone, T_CLASS)) {
RCLASS_SET_INCLUDER(clone_p, clone);
Expand Down Expand Up @@ -607,9 +601,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)

RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(klass);
if (RCLASS_IV_TBL(klass)) {
rb_iv_tbl_copy(clone, klass);
}
rb_iv_tbl_copy(clone, klass);
if (RCLASS_CONST_TBL(klass)) {
struct clone_const_arg arg;
arg.tbl = RCLASS_CONST_TBL(clone) = rb_id_table_create(0);
Expand Down Expand Up @@ -1062,13 +1054,10 @@ rb_include_class_new(VALUE module, VALUE super)
module = METACLASS_OF(module);
}
RUBY_ASSERT(!RB_TYPE_P(module, T_ICLASS));
if (!RCLASS_IV_TBL(module)) {
RCLASS_IV_TBL(module) = st_init_numtable();
}
if (!RCLASS_CONST_TBL(module)) {
RCLASS_CONST_TBL(module) = rb_id_table_create(0);
}
RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);

RCLASS_CVC_TBL(klass) = RCLASS_CVC_TBL(module);
RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);

Expand Down
23 changes: 10 additions & 13 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3447,8 +3447,8 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
case T_CLASS:
rb_id_table_free(RCLASS_M_TBL(obj));
cc_table_free(objspace, obj, FALSE);
if (RCLASS_IV_TBL(obj)) {
st_free_table(RCLASS_IV_TBL(obj));
if (RCLASS_IVPTR(obj)) {
xfree(RCLASS_IVPTR(obj));
}
if (RCLASS_CONST_TBL(obj)) {
rb_free_const_table(RCLASS_CONST_TBL(obj));
Expand Down Expand Up @@ -4865,15 +4865,11 @@ obj_memsize_of(VALUE obj, int use_all_types)
if (RCLASS_M_TBL(obj)) {
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
}
if (RCLASS_IV_TBL(obj)) {
size += st_memsize(RCLASS_IV_TBL(obj));
}
// class IV sizes are allocated as powers of two
size += SIZEOF_VALUE << bit_length(RCLASS_IV_COUNT(obj));
if (RCLASS_CVC_TBL(obj)) {
size += rb_id_table_memsize(RCLASS_CVC_TBL(obj));
}
if (RCLASS_EXT(obj)->iv_tbl) {
size += st_memsize(RCLASS_EXT(obj)->iv_tbl);
}
if (RCLASS_EXT(obj)->const_tbl) {
size += rb_id_table_memsize(RCLASS_EXT(obj)->const_tbl);
}
Expand Down Expand Up @@ -7212,7 +7208,9 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)

mark_m_tbl(objspace, RCLASS_M_TBL(obj));
cc_table_mark(objspace, obj);
mark_tbl_no_pin(objspace, RCLASS_IV_TBL(obj));
for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
gc_mark(objspace, RCLASS_IVPTR(obj)[i]);
}
mark_const_tbl(objspace, RCLASS_CONST_TBL(obj));
break;

Expand Down Expand Up @@ -10439,7 +10437,9 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
update_cvc_tbl(objspace, obj);
update_superclasses(objspace, obj);

gc_update_tbl_refs(objspace, RCLASS_IV_TBL(obj));
for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
UPDATE_IF_MOVED(objspace, RCLASS_IVPTR(obj)[i]);
}

update_class_ext(objspace, RCLASS_EXT(obj));
update_const_tbl(objspace, RCLASS_CONST_TBL(obj));
Expand All @@ -10454,9 +10454,6 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
}
if (!RCLASS_EXT(obj)) break;
if (RCLASS_IV_TBL(obj)) {
gc_update_tbl_refs(objspace, RCLASS_IV_TBL(obj));
}
update_class_ext(objspace, RCLASS_EXT(obj));
update_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
update_cc_tbl(objspace, obj);
Expand Down
4 changes: 2 additions & 2 deletions internal/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct rb_cvar_class_tbl_entry {
};

struct rb_classext_struct {
struct st_table *iv_tbl;
VALUE *iv_ptr;
struct rb_id_table *const_tbl;
struct rb_id_table *callable_m_tbl;
struct rb_id_table *cc_tbl; /* ID -> [[ci, cc1], cc2, ...] */
Expand Down Expand Up @@ -75,9 +75,9 @@ typedef struct rb_classext_struct rb_classext_t;
#else
# define RCLASS_EXT(c) (RCLASS(c)->ptr)
#endif
#define RCLASS_IV_TBL(c) (RCLASS_EXT(c)->iv_tbl)
#define RCLASS_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl)
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
#define RCLASS_IVPTR(c) (RCLASS_EXT(c)->iv_ptr)
#define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl)
#define RCLASS_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl)
#define RCLASS_CVC_TBL(c) (RCLASS_EXT(c)->cvc_tbl)
Expand Down
2 changes: 1 addition & 1 deletion internal/variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ void rb_gc_update_global_tbl(void);
size_t rb_generic_ivar_memsize(VALUE);
VALUE rb_search_class_path(VALUE);
VALUE rb_attr_delete(VALUE, ID);
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef);
void rb_autoload_str(VALUE mod, ID id, VALUE file);
VALUE rb_autoload_at_p(VALUE, ID, int);
NORETURN(VALUE rb_mod_const_missing(VALUE,VALUE));
Expand All @@ -49,6 +48,7 @@ void rb_iv_tbl_copy(VALUE dst, VALUE src);
RUBY_SYMBOL_EXPORT_END

MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef);
VALUE rb_gvar_get(ID);
VALUE rb_gvar_set(ID, VALUE);
VALUE rb_gvar_defined(ID);
Expand Down
2 changes: 1 addition & 1 deletion marshal.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ hash_each(VALUE key, VALUE value, VALUE v)

#define SINGLETON_DUMP_UNABLE_P(klass) \
(rb_id_table_size(RCLASS_M_TBL(klass)) > 0 || \
(RCLASS_IV_TBL(klass) && RCLASS_IV_TBL(klass)->num_entries > 1))
rb_ivar_count(klass) > 1)

static void
w_extended(VALUE klass, struct dump_arg *arg, int check)
Expand Down
18 changes: 10 additions & 8 deletions object.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,20 +298,22 @@ init_copy(VALUE dest, VALUE obj)
rb_copy_generic_ivar(dest, obj);
rb_gc_copy_finalizer(dest, obj);

rb_shape_t *shape_to_set = rb_shape_get_shape(obj);
if (!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE)) {
rb_shape_t *shape_to_set = rb_shape_get_shape(obj);

// If the object is frozen, the "dup"'d object will *not* be frozen,
// so we need to copy the frozen shape's parent to the new object.
if (rb_shape_frozen_shape_p(shape_to_set)) {
shape_to_set = rb_shape_get_shape_by_id(shape_to_set->parent_id);
// If the object is frozen, the "dup"'d object will *not* be frozen,
// so we need to copy the frozen shape's parent to the new object.
if (rb_shape_frozen_shape_p(shape_to_set)) {
shape_to_set = rb_shape_get_shape_by_id(shape_to_set->parent_id);
}

// shape ids are different
rb_shape_set_shape(dest, shape_to_set);
}

if (RB_TYPE_P(obj, T_OBJECT)) {
rb_obj_copy_ivar(dest, obj);
}

// shape ids are different
rb_shape_set_shape(dest, shape_to_set);
}

static VALUE immutable_obj_clone(VALUE obj, VALUE kwfreeze);
Expand Down
9 changes: 6 additions & 3 deletions shape.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id)
}

#if !SHAPE_IN_BASIC_FLAGS
static inline shape_id_t
RCLASS_SHAPE_ID(VALUE obj)
shape_id_t
rb_rclass_shape_id(VALUE obj)
{
RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
return RCLASS_EXT(obj)->shape_id;
}

Expand Down Expand Up @@ -115,7 +116,9 @@ static rb_shape_t*
get_next_shape_internal(rb_shape_t* shape, ID id, VALUE obj, enum shape_type shape_type)
{
rb_shape_t *res = NULL;
RUBY_ASSERT(SHAPE_FROZEN != (enum shape_type)shape->type);

RUBY_ASSERT(SHAPE_FROZEN != (enum shape_type)shape->type || RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS));

RB_VM_LOCK_ENTER();
{
if (rb_shape_lookup_id(shape, id, shape_type)) {
Expand Down
24 changes: 24 additions & 0 deletions shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
RBASIC_SET_SHAPE_ID(obj, shape_id);
}

static inline shape_id_t
RCLASS_SHAPE_ID(VALUE obj)
{
RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
return RBASIC_SHAPE_ID(obj);
}

#else

static inline shape_id_t
Expand All @@ -105,6 +112,15 @@ ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
}

MJIT_SYMBOL_EXPORT_BEGIN
shape_id_t rb_rclass_shape_id(VALUE obj);
MJIT_SYMBOL_EXPORT_END

static inline shape_id_t RCLASS_SHAPE_ID(VALUE obj) {
return rb_rclass_shape_id(obj);
}

#endif

bool rb_shape_root_shape_p(rb_shape_t* shape);
Expand Down Expand Up @@ -134,6 +150,14 @@ ROBJECT_IV_COUNT(VALUE obj)
return ivc;
}

static inline uint32_t
RCLASS_IV_COUNT(VALUE obj)
{
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
uint32_t ivc = rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_iv_index;
return ivc;
}

rb_shape_t * rb_shape_alloc(ID edge_name, rb_shape_t * parent);
rb_shape_t * rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id);

Expand Down
Loading

0 comments on commit 02f1554

Please sign in to comment.