Skip to content

Commit 1295058

Browse files
committed
WIP
1 parent e7ba6bd commit 1295058

7 files changed

Lines changed: 151 additions & 177 deletions

File tree

class.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -317,13 +317,8 @@ rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_namespace
317317

318318
RCLASSEXT_M_TBL(ext) = duplicate_classext_m_tbl(RCLASSEXT_M_TBL(orig), klass, dup_iclass);
319319

320-
// TODO: consider shapes for performance
321-
if (RCLASSEXT_FIELDS(orig)) {
322-
RCLASSEXT_FIELDS(ext) = (VALUE *)st_copy((st_table *)RCLASSEXT_FIELDS(orig));
323-
rb_autoload_copy_table_for_namespace((st_table *)RCLASSEXT_FIELDS(ext), ns);
324-
}
325-
else {
326-
RCLASSEXT_FIELDS(ext) = (VALUE *)st_init_numtable();
320+
if (orig->fields_obj) {
321+
ext->fields_obj = rb_obj_clone(orig->fields_obj);
327322
}
328323

329324
if (RCLASSEXT_SHARED_CONST_TBL(orig)) {

gc.c

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,6 @@ rb_data_free(void *objspace, VALUE obj)
12121212

12131213
struct classext_foreach_args {
12141214
VALUE klass;
1215-
bool obj_too_complex;
12161215
rb_objspace_t *objspace; // used for update_*
12171216
};
12181217

@@ -1224,12 +1223,6 @@ classext_free(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
12241223

12251224
rb_id_table_free(RCLASSEXT_M_TBL(ext));
12261225
rb_cc_tbl_free(RCLASSEXT_CC_TBL(ext), args->klass);
1227-
if (args->obj_too_complex) {
1228-
st_free_table((st_table *)RCLASSEXT_FIELDS(ext));
1229-
}
1230-
else {
1231-
xfree(RCLASSEXT_FIELDS(ext));
1232-
}
12331226
if (!RCLASSEXT_SHARED_CONST_TBL(ext) && (tbl = RCLASSEXT_CONST_TBL(ext)) != NULL) {
12341227
rb_free_const_table(tbl);
12351228
}
@@ -1302,8 +1295,6 @@ rb_gc_obj_free(void *objspace, VALUE obj)
13021295
case T_MODULE:
13031296
case T_CLASS:
13041297
args.klass = obj;
1305-
args.obj_too_complex = rb_shape_obj_too_complex_p(obj) ? true : false;
1306-
13071298
rb_class_classext_foreach(obj, classext_free, (void *)&args);
13081299
if (RCLASS(obj)->ns_classext_tbl) {
13091300
st_free_table(RCLASS(obj)->ns_classext_tbl);
@@ -3107,10 +3098,7 @@ gc_mark_classext_module(rb_classext_t *ext, bool prime, VALUE namespace, void *a
31073098
gc_mark_internal(RCLASSEXT_SUPER(ext));
31083099
}
31093100
mark_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
3110-
if (rb_shape_obj_too_complex_p(obj)) {
3111-
gc_mark_tbl_no_pin((st_table *)RCLASSEXT_FIELDS(ext));
3112-
// for the case ELSE is written in rb_gc_mark_children() because it's per RClass, not classext
3113-
}
3101+
gc_mark_internal(RCLASSEXT_FIELDS_OBJ(ext));
31143102
if (!RCLASSEXT_SHARED_CONST_TBL(ext) && RCLASSEXT_CONST_TBL(ext)) {
31153103
mark_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
31163104
}
@@ -3191,11 +3179,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
31913179
foreach_args.obj = obj;
31923180
rb_class_classext_foreach(obj, gc_mark_classext_module, (void *)&foreach_args);
31933181

3194-
if (!rb_shape_obj_too_complex_p(obj)) {
3195-
for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(obj); i++) {
3196-
gc_mark_internal(RCLASS_PRIME_FIELDS(obj)[i]);
3197-
}
3198-
}
3182+
gc_mark_internal(RCLASS_PRIME_FIELDS_OBJ(obj));
31993183
break;
32003184

32013185
case T_ICLASS:
@@ -3827,7 +3811,6 @@ static void
38273811
update_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
38283812
{
38293813
struct classext_foreach_args *args = (struct classext_foreach_args *)arg;
3830-
VALUE klass = args->klass;
38313814
rb_objspace_t *objspace = args->objspace;
38323815

38333816
if (RCLASSEXT_SUPER(ext)) {
@@ -3836,16 +3819,7 @@ update_classext(rb_classext_t *ext, bool is_prime, VALUE namespace, void *arg)
38363819

38373820
update_m_tbl(objspace, RCLASSEXT_M_TBL(ext));
38383821

3839-
if (args->obj_too_complex) {
3840-
gc_ref_update_table_values_only((st_table *)RCLASSEXT_FIELDS(ext));
3841-
}
3842-
else {
3843-
// Classext is not copied in this case
3844-
for (attr_index_t i = 0; i < RCLASS_FIELDS_COUNT(klass); i++) {
3845-
UPDATE_IF_MOVED(objspace, RCLASSEXT_FIELDS(RCLASS_EXT_PRIME(klass))[i]);
3846-
}
3847-
}
3848-
3822+
UPDATE_IF_MOVED(objspace, ext->fields_obj);
38493823
if (!RCLASSEXT_SHARED_CONST_TBL(ext)) {
38503824
update_const_tbl(objspace, RCLASSEXT_CONST_TBL(ext));
38513825
}
@@ -4202,7 +4176,6 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
42024176
// Continue to the shared T_CLASS/T_MODULE
42034177
case T_MODULE:
42044178
args.klass = obj;
4205-
args.obj_too_complex = rb_shape_obj_too_complex_p(obj);
42064179
args.objspace = objspace;
42074180
rb_class_classext_foreach(obj, update_classext, (void *)&args);
42084181
break;

internal/class.h

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*/
1111
#include "id.h"
1212
#include "id_table.h" /* for struct rb_id_table */
13+
#include "internal/object.h" /* for rb_class_allocate_instance */
1314
#include "internal/namespace.h" /* for rb_current_namespace */
1415
#include "internal/serial.h" /* for rb_serial_t */
1516
#include "internal/static_assert.h"
@@ -79,7 +80,7 @@ struct rb_cvar_class_tbl_entry {
7980
struct rb_classext_struct {
8081
const rb_namespace_t *ns;
8182
VALUE super;
82-
VALUE *fields; // Fields are either ivar or other internal properties stored inline
83+
VALUE fields_obj; // Fields are either ivar or other internal properties stored inline
8384
struct rb_id_table *m_tbl;
8485
struct rb_id_table *const_tbl;
8586
struct rb_id_table *callable_m_tbl;
@@ -176,7 +177,8 @@ static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj);
176177

177178
#define RCLASSEXT_NS(ext) (ext->ns)
178179
#define RCLASSEXT_SUPER(ext) (ext->super)
179-
#define RCLASSEXT_FIELDS(ext) (ext->fields)
180+
#define RCLASSEXT_FIELDS(ext) (ext->fields_obj ? ROBJECT_FIELDS(ext->fields_obj) : NULL)
181+
#define RCLASSEXT_FIELDS_OBJ(ext) (ext->fields_obj)
180182
#define RCLASSEXT_M_TBL(ext) (ext->m_tbl)
181183
#define RCLASSEXT_CONST_TBL(ext) (ext->const_tbl)
182184
#define RCLASSEXT_CALLABLE_M_TBL(ext) (ext->callable_m_tbl)
@@ -209,7 +211,7 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE
209211
#define RCLASS_PRIME_NS(c) (RCLASS_EXT_PRIME(c)->ns)
210212
// To invalidate CC by inserting&invalidating method entry into tables containing the target cme
211213
// See clear_method_cache_by_id_in_class()
212-
#define RCLASS_PRIME_FIELDS(c) (RCLASS_EXT_PRIME(c)->fields)
214+
#define RCLASS_PRIME_FIELDS_OBJ(c) (RCLASS_EXT_PRIME(c)->fields_obj)
213215
#define RCLASS_PRIME_M_TBL(c) (RCLASS_EXT_PRIME(c)->m_tbl)
214216
#define RCLASS_PRIME_CONST_TBL(c) (RCLASS_EXT_PRIME(c)->const_tbl)
215217
#define RCLASS_PRIME_CALLABLE_M_TBL(c) (RCLASS_EXT_PRIME(c)->callable_m_tbl)
@@ -531,6 +533,24 @@ RCLASS_WRITE_SUPER(VALUE klass, VALUE super)
531533
RB_OBJ_WRITE(klass, &RCLASSEXT_SUPER(RCLASS_EXT_WRITABLE(klass)), super);
532534
}
533535

536+
static inline VALUE
537+
RCLASS_FIELDS_OBJ(VALUE obj)
538+
{
539+
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
540+
return RCLASSEXT_FIELDS_OBJ(RCLASS_EXT_READABLE(obj));
541+
}
542+
543+
static inline VALUE
544+
RCLASS_ENSURE_FIELDS_OBJ(VALUE obj)
545+
{
546+
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
547+
rb_classext_t *ext = RCLASS_EXT_READABLE(obj);
548+
if (!ext->fields_obj) {
549+
RB_OBJ_WRITE(obj, &ext->fields_obj, rb_class_allocate_instance(rb_singleton_class(obj)));
550+
}
551+
return ext->fields_obj;
552+
}
553+
534554
static inline st_table *
535555
RCLASS_FIELDS_HASH(VALUE obj)
536556
{
@@ -547,20 +567,41 @@ RCLASS_WRITABLE_FIELDS_HASH(VALUE obj)
547567
return (st_table *)RCLASSEXT_FIELDS(RCLASS_EXT_WRITABLE(obj));
548568
}
549569

570+
static inline VALUE
571+
RCLASS_WRITABLE_FIELDS_OBJ(VALUE obj)
572+
{
573+
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
574+
return RCLASSEXT_FIELDS_OBJ(RCLASS_EXT_WRITABLE(obj));
575+
}
576+
577+
static inline void
578+
RCLASSEXT_SET_FIELDS_HASH(VALUE obj, rb_classext_t *ext, const st_table *tbl)
579+
{
580+
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
581+
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
582+
583+
if (!ext->fields_obj) {
584+
// FIXME: We can trigger GC here and `*tbl` may not be marked
585+
RB_OBJ_WRITE(obj, &ext->fields_obj, rb_class_allocate_instance(rb_singleton_class(obj)));
586+
}
587+
ROBJECT_SET_FIELDS_HASH(ext->fields_obj, tbl);
588+
}
589+
550590
static inline void
551591
RCLASS_SET_FIELDS_HASH(VALUE obj, const st_table *tbl)
552592
{
553593
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
554594
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
555-
RCLASSEXT_FIELDS(RCLASS_EXT_PRIME(obj)) = (VALUE *)tbl;
595+
596+
RCLASSEXT_SET_FIELDS_HASH(obj, RCLASS_EXT_PRIME(obj), tbl);
556597
}
557598

558599
static inline void
559600
RCLASS_WRITE_FIELDS_HASH(VALUE obj, const st_table *tbl)
560601
{
561602
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
562603
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
563-
RCLASSEXT_FIELDS(RCLASS_EXT_WRITABLE(obj)) = (VALUE *)tbl;
604+
RCLASSEXT_SET_FIELDS_HASH(obj, RCLASS_EXT_WRITABLE(obj), tbl);
564605
}
565606

566607
static inline uint32_t

shape.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -359,15 +359,27 @@ rb_obj_shape_id(VALUE obj)
359359
}
360360

361361
#if SHAPE_IN_BASIC_FLAGS
362+
if (BUILTIN_TYPE(obj) == T_CLASS || BUILTIN_TYPE(obj) == T_MODULE) {
363+
VALUE fields_obj = RCLASS_FIELDS_OBJ(obj);
364+
if (fields_obj) {
365+
return ROBJECT_SHAPE_ID(fields_obj);
366+
}
367+
return ROOT_SHAPE_ID;
368+
}
362369
return RBASIC_SHAPE_ID(obj);
363370
#else
364371
switch (BUILTIN_TYPE(obj)) {
365372
case T_OBJECT:
366373
return ROBJECT_SHAPE_ID(obj);
367374
break;
368375
case T_CLASS:
369-
case T_MODULE:
370-
return RCLASS_SHAPE_ID(obj);
376+
case T_MODULE: {
377+
VALUE fields_obj = RCLASS_FIELDS_OBJ(obj);
378+
if (fields_obj) {
379+
ROBJECT_SHAPE_ID(fields_obj);
380+
}
381+
return ROOT_SHAPE_ID;
382+
}
371383
default:
372384
return rb_generic_shape_id(obj);
373385
}
@@ -635,6 +647,19 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
635647
bool
636648
rb_shape_transition_remove_ivar(VALUE obj, ID id, VALUE *removed)
637649
{
650+
switch(BUILTIN_TYPE(obj)) {
651+
case T_CLASS:
652+
case T_MODULE: {
653+
VALUE fields_obj = RCLASS_PRIME_FIELDS_OBJ(obj);
654+
if (fields_obj) {
655+
return rb_shape_transition_remove_ivar(fields_obj, id, removed);
656+
}
657+
return false;
658+
}
659+
default:
660+
break;
661+
}
662+
638663
rb_shape_t *shape = rb_obj_shape(obj);
639664

640665
if (UNLIKELY(rb_shape_too_complex_p(shape))) {
@@ -656,7 +681,7 @@ rb_shape_transition_remove_ivar(VALUE obj, ID id, VALUE *removed)
656681
switch(BUILTIN_TYPE(obj)) {
657682
case T_CLASS:
658683
case T_MODULE:
659-
fields = RCLASS_PRIME_FIELDS(obj);
684+
rb_bug("Unreacheable");
660685
break;
661686
case T_OBJECT:
662687
fields = ROBJECT_FIELDS(obj);

shape.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ get_shape_id_from_flags(VALUE obj)
9595
{
9696
RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
9797
RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO));
98+
RUBY_ASSERT(!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE));
99+
98100
return (shape_id_t)((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT);
99101
}
100102

0 commit comments

Comments
 (0)