Skip to content

Commit 02f1554

Browse files
authored
Implement object shapes for T_CLASS and T_MODULE (ruby#6637)
* 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
1 parent 2b39640 commit 02f1554

File tree

10 files changed

+265
-202
lines changed

10 files changed

+265
-202
lines changed

class.c

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,6 @@ class_alloc(VALUE flags, VALUE klass)
213213
#endif
214214

215215
/* ZALLOC
216-
RCLASS_IV_TBL(obj) = 0;
217216
RCLASS_CONST_TBL(obj) = 0;
218217
RCLASS_M_TBL(obj) = 0;
219218
RCLASS_IV_INDEX_TBL(obj) = 0;
@@ -402,23 +401,19 @@ class_init_copy_check(VALUE clone, VALUE orig)
402401
static void
403402
copy_tables(VALUE clone, VALUE orig)
404403
{
405-
if (RCLASS_IV_TBL(clone)) {
406-
st_free_table(RCLASS_IV_TBL(clone));
407-
RCLASS_IV_TBL(clone) = 0;
408-
}
409404
if (RCLASS_CONST_TBL(clone)) {
410405
rb_free_const_table(RCLASS_CONST_TBL(clone));
411406
RCLASS_CONST_TBL(clone) = 0;
412407
}
413408
RCLASS_M_TBL(clone) = 0;
414-
if (RCLASS_IV_TBL(orig)) {
409+
if (!RB_TYPE_P(clone, T_ICLASS)) {
415410
st_data_t id;
416411

417412
rb_iv_tbl_copy(clone, orig);
418413
CONST_ID(id, "__tmp_classpath__");
419-
st_delete(RCLASS_IV_TBL(clone), &id, 0);
414+
rb_attr_delete(clone, id);
420415
CONST_ID(id, "__classpath__");
421-
st_delete(RCLASS_IV_TBL(clone), &id, 0);
416+
rb_attr_delete(clone, id);
422417
}
423418
if (RCLASS_CONST_TBL(orig)) {
424419
struct clone_const_arg arg;
@@ -520,7 +515,6 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
520515
prev_clone_p = clone_p;
521516
RCLASS_M_TBL(clone_p) = RCLASS_M_TBL(p);
522517
RCLASS_CONST_TBL(clone_p) = RCLASS_CONST_TBL(p);
523-
RCLASS_IV_TBL(clone_p) = RCLASS_IV_TBL(p);
524518
RCLASS_ALLOCATOR(clone_p) = RCLASS_ALLOCATOR(p);
525519
if (RB_TYPE_P(clone, T_CLASS)) {
526520
RCLASS_SET_INCLUDER(clone_p, clone);
@@ -607,9 +601,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
607601

608602
RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
609603
RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(klass);
610-
if (RCLASS_IV_TBL(klass)) {
611-
rb_iv_tbl_copy(clone, klass);
612-
}
604+
rb_iv_tbl_copy(clone, klass);
613605
if (RCLASS_CONST_TBL(klass)) {
614606
struct clone_const_arg arg;
615607
arg.tbl = RCLASS_CONST_TBL(clone) = rb_id_table_create(0);
@@ -1062,13 +1054,10 @@ rb_include_class_new(VALUE module, VALUE super)
10621054
module = METACLASS_OF(module);
10631055
}
10641056
RUBY_ASSERT(!RB_TYPE_P(module, T_ICLASS));
1065-
if (!RCLASS_IV_TBL(module)) {
1066-
RCLASS_IV_TBL(module) = st_init_numtable();
1067-
}
10681057
if (!RCLASS_CONST_TBL(module)) {
10691058
RCLASS_CONST_TBL(module) = rb_id_table_create(0);
10701059
}
1071-
RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
1060+
10721061
RCLASS_CVC_TBL(klass) = RCLASS_CVC_TBL(module);
10731062
RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);
10741063

gc.c

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,8 +3447,8 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
34473447
case T_CLASS:
34483448
rb_id_table_free(RCLASS_M_TBL(obj));
34493449
cc_table_free(objspace, obj, FALSE);
3450-
if (RCLASS_IV_TBL(obj)) {
3451-
st_free_table(RCLASS_IV_TBL(obj));
3450+
if (RCLASS_IVPTR(obj)) {
3451+
xfree(RCLASS_IVPTR(obj));
34523452
}
34533453
if (RCLASS_CONST_TBL(obj)) {
34543454
rb_free_const_table(RCLASS_CONST_TBL(obj));
@@ -4865,15 +4865,11 @@ obj_memsize_of(VALUE obj, int use_all_types)
48654865
if (RCLASS_M_TBL(obj)) {
48664866
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
48674867
}
4868-
if (RCLASS_IV_TBL(obj)) {
4869-
size += st_memsize(RCLASS_IV_TBL(obj));
4870-
}
4868+
// class IV sizes are allocated as powers of two
4869+
size += SIZEOF_VALUE << bit_length(RCLASS_IV_COUNT(obj));
48714870
if (RCLASS_CVC_TBL(obj)) {
48724871
size += rb_id_table_memsize(RCLASS_CVC_TBL(obj));
48734872
}
4874-
if (RCLASS_EXT(obj)->iv_tbl) {
4875-
size += st_memsize(RCLASS_EXT(obj)->iv_tbl);
4876-
}
48774873
if (RCLASS_EXT(obj)->const_tbl) {
48784874
size += rb_id_table_memsize(RCLASS_EXT(obj)->const_tbl);
48794875
}
@@ -7212,7 +7208,9 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
72127208

72137209
mark_m_tbl(objspace, RCLASS_M_TBL(obj));
72147210
cc_table_mark(objspace, obj);
7215-
mark_tbl_no_pin(objspace, RCLASS_IV_TBL(obj));
7211+
for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
7212+
gc_mark(objspace, RCLASS_IVPTR(obj)[i]);
7213+
}
72167214
mark_const_tbl(objspace, RCLASS_CONST_TBL(obj));
72177215
break;
72187216

@@ -10439,7 +10437,9 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
1043910437
update_cvc_tbl(objspace, obj);
1044010438
update_superclasses(objspace, obj);
1044110439

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

1044410444
update_class_ext(objspace, RCLASS_EXT(obj));
1044510445
update_const_tbl(objspace, RCLASS_CONST_TBL(obj));
@@ -10454,9 +10454,6 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
1045410454
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
1045510455
}
1045610456
if (!RCLASS_EXT(obj)) break;
10457-
if (RCLASS_IV_TBL(obj)) {
10458-
gc_update_tbl_refs(objspace, RCLASS_IV_TBL(obj));
10459-
}
1046010457
update_class_ext(objspace, RCLASS_EXT(obj));
1046110458
update_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
1046210459
update_cc_tbl(objspace, obj);

internal/class.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ struct rb_cvar_class_tbl_entry {
3333
};
3434

3535
struct rb_classext_struct {
36-
struct st_table *iv_tbl;
36+
VALUE *iv_ptr;
3737
struct rb_id_table *const_tbl;
3838
struct rb_id_table *callable_m_tbl;
3939
struct rb_id_table *cc_tbl; /* ID -> [[ci, cc1], cc2, ...] */
@@ -75,9 +75,9 @@ typedef struct rb_classext_struct rb_classext_t;
7575
#else
7676
# define RCLASS_EXT(c) (RCLASS(c)->ptr)
7777
#endif
78-
#define RCLASS_IV_TBL(c) (RCLASS_EXT(c)->iv_tbl)
7978
#define RCLASS_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl)
8079
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
80+
#define RCLASS_IVPTR(c) (RCLASS_EXT(c)->iv_ptr)
8181
#define RCLASS_CALLABLE_M_TBL(c) (RCLASS_EXT(c)->callable_m_tbl)
8282
#define RCLASS_CC_TBL(c) (RCLASS_EXT(c)->cc_tbl)
8383
#define RCLASS_CVC_TBL(c) (RCLASS_EXT(c)->cvc_tbl)

internal/variable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ void rb_gc_update_global_tbl(void);
2424
size_t rb_generic_ivar_memsize(VALUE);
2525
VALUE rb_search_class_path(VALUE);
2626
VALUE rb_attr_delete(VALUE, ID);
27-
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef);
2827
void rb_autoload_str(VALUE mod, ID id, VALUE file);
2928
VALUE rb_autoload_at_p(VALUE, ID, int);
3029
NORETURN(VALUE rb_mod_const_missing(VALUE,VALUE));
@@ -49,6 +48,7 @@ void rb_iv_tbl_copy(VALUE dst, VALUE src);
4948
RUBY_SYMBOL_EXPORT_END
5049

5150
MJIT_SYMBOL_EXPORT_BEGIN
51+
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef);
5252
VALUE rb_gvar_get(ID);
5353
VALUE rb_gvar_set(ID, VALUE);
5454
VALUE rb_gvar_defined(ID);

marshal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ hash_each(VALUE key, VALUE value, VALUE v)
523523

524524
#define SINGLETON_DUMP_UNABLE_P(klass) \
525525
(rb_id_table_size(RCLASS_M_TBL(klass)) > 0 || \
526-
(RCLASS_IV_TBL(klass) && RCLASS_IV_TBL(klass)->num_entries > 1))
526+
rb_ivar_count(klass) > 1)
527527

528528
static void
529529
w_extended(VALUE klass, struct dump_arg *arg, int check)

object.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -298,20 +298,22 @@ init_copy(VALUE dest, VALUE obj)
298298
rb_copy_generic_ivar(dest, obj);
299299
rb_gc_copy_finalizer(dest, obj);
300300

301-
rb_shape_t *shape_to_set = rb_shape_get_shape(obj);
301+
if (!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE)) {
302+
rb_shape_t *shape_to_set = rb_shape_get_shape(obj);
302303

303-
// If the object is frozen, the "dup"'d object will *not* be frozen,
304-
// so we need to copy the frozen shape's parent to the new object.
305-
if (rb_shape_frozen_shape_p(shape_to_set)) {
306-
shape_to_set = rb_shape_get_shape_by_id(shape_to_set->parent_id);
304+
// If the object is frozen, the "dup"'d object will *not* be frozen,
305+
// so we need to copy the frozen shape's parent to the new object.
306+
if (rb_shape_frozen_shape_p(shape_to_set)) {
307+
shape_to_set = rb_shape_get_shape_by_id(shape_to_set->parent_id);
308+
}
309+
310+
// shape ids are different
311+
rb_shape_set_shape(dest, shape_to_set);
307312
}
308313

309314
if (RB_TYPE_P(obj, T_OBJECT)) {
310315
rb_obj_copy_ivar(dest, obj);
311316
}
312-
313-
// shape ids are different
314-
rb_shape_set_shape(dest, shape_to_set);
315317
}
316318

317319
static VALUE immutable_obj_clone(VALUE obj, VALUE kwfreeze);

shape.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id)
5454
}
5555

5656
#if !SHAPE_IN_BASIC_FLAGS
57-
static inline shape_id_t
58-
RCLASS_SHAPE_ID(VALUE obj)
57+
shape_id_t
58+
rb_rclass_shape_id(VALUE obj)
5959
{
60+
RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
6061
return RCLASS_EXT(obj)->shape_id;
6162
}
6263

@@ -115,7 +116,9 @@ static rb_shape_t*
115116
get_next_shape_internal(rb_shape_t* shape, ID id, VALUE obj, enum shape_type shape_type)
116117
{
117118
rb_shape_t *res = NULL;
118-
RUBY_ASSERT(SHAPE_FROZEN != (enum shape_type)shape->type);
119+
120+
RUBY_ASSERT(SHAPE_FROZEN != (enum shape_type)shape->type || RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS));
121+
119122
RB_VM_LOCK_ENTER();
120123
{
121124
if (rb_shape_lookup_id(shape, id, shape_type)) {

shape.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@ ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
9090
RBASIC_SET_SHAPE_ID(obj, shape_id);
9191
}
9292

93+
static inline shape_id_t
94+
RCLASS_SHAPE_ID(VALUE obj)
95+
{
96+
RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
97+
return RBASIC_SHAPE_ID(obj);
98+
}
99+
93100
#else
94101

95102
static inline shape_id_t
@@ -105,6 +112,15 @@ ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
105112
RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
106113
RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
107114
}
115+
116+
MJIT_SYMBOL_EXPORT_BEGIN
117+
shape_id_t rb_rclass_shape_id(VALUE obj);
118+
MJIT_SYMBOL_EXPORT_END
119+
120+
static inline shape_id_t RCLASS_SHAPE_ID(VALUE obj) {
121+
return rb_rclass_shape_id(obj);
122+
}
123+
108124
#endif
109125

110126
bool rb_shape_root_shape_p(rb_shape_t* shape);
@@ -134,6 +150,14 @@ ROBJECT_IV_COUNT(VALUE obj)
134150
return ivc;
135151
}
136152

153+
static inline uint32_t
154+
RCLASS_IV_COUNT(VALUE obj)
155+
{
156+
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
157+
uint32_t ivc = rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_iv_index;
158+
return ivc;
159+
}
160+
137161
rb_shape_t * rb_shape_alloc(ID edge_name, rb_shape_t * parent);
138162
rb_shape_t * rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id);
139163

0 commit comments

Comments
 (0)