Skip to content

Commit de51e67

Browse files
committed
WIP
1 parent 229c07c commit de51e67

7 files changed

Lines changed: 104 additions & 42 deletions

File tree

class.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ class_duplicate_iclass_classext(VALUE iclass, rb_classext_t *mod_ext, const rb_n
278278
else {
279279
RCLASSEXT_M_TBL(ext) = RCLASSEXT_M_TBL(mod_ext);
280280
}
281-
RCLASSEXT_SET_FIELDS(ext, rb_imemo_obj_fields_new_complex(st_init_numtable()));
281+
282282
RCLASSEXT_CONST_TBL(ext) = RCLASSEXT_CONST_TBL(mod_ext);
283283
RCLASSEXT_CVC_TBL(ext) = RCLASSEXT_CVC_TBL(mod_ext);
284284

@@ -318,11 +318,11 @@ rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_namespace
318318
// TODO: consider shapes for performance
319319
if (RCLASSEXT_FIELDS(orig)) {
320320
st_table *tbl = st_copy((st_table *)RCLASSEXT_FIELDS(orig));
321-
RCLASSEXT_SET_FIELDS(ext, rb_imemo_obj_fields_new_complex(tbl));
321+
RCLASSEXT_SET_FIELDS(ext, rb_imemo_obj_fields_new_complex(klass, tbl));
322322
rb_autoload_copy_table_for_namespace((st_table *)RCLASSEXT_FIELDS(ext), ns);
323323
}
324324
else {
325-
RCLASSEXT_SET_FIELDS(ext, rb_imemo_obj_fields_new_complex(st_init_numtable()));
325+
RCLASSEXT_SET_FIELDS(ext, rb_imemo_obj_fields_new_complex(klass, st_init_numtable()));
326326
}
327327

328328
if (RCLASSEXT_SHARED_CONST_TBL(orig)) {

imemo.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,17 @@ rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
112112
static const size_t IMEMO_BUF_OVERHEAD = sizeof(VALUE); // flags
113113

114114
VALUE
115-
rb_imemo_obj_fields_new(size_t capa)
115+
rb_imemo_obj_fields_new(VALUE klass, size_t capa)
116116
{
117+
klass = rb_singleton_class(klass);
118+
117119
if (rb_gc_size_allocatable_p(capa + IMEMO_BUF_OVERHEAD)) {
118-
VALUE fields = rb_imemo_new(imemo_obj_fields, 0, capa + IMEMO_BUF_OVERHEAD);
120+
VALUE fields = rb_imemo_new(imemo_obj_fields, klass, capa + IMEMO_BUF_OVERHEAD);
119121
RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_obj_fields));
120122
return fields;
121123
}
122124
else {
123-
VALUE fields = rb_imemo_new(imemo_obj_fields, 0, sizeof(VALUE *));
125+
VALUE fields = rb_imemo_new(imemo_obj_fields, klass, sizeof(VALUE *));
124126
FL_SET_RAW(fields, OBJ_FIELD_EXTERNAL);
125127
// TODO: malloc + tag.
126128
rb_bug("TODO: malloc + tag.");
@@ -129,9 +131,9 @@ rb_imemo_obj_fields_new(size_t capa)
129131
}
130132

131133
VALUE
132-
rb_imemo_obj_fields_new_complex(st_table *tbl)
134+
rb_imemo_obj_fields_new_complex(VALUE klass, st_table *tbl)
133135
{
134-
VALUE fields = rb_imemo_obj_fields_new(sizeof(tbl));
136+
VALUE fields = rb_imemo_obj_fields_new(klass, sizeof(tbl));
135137
IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
136138
return fields;
137139
}

internal/class.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ RCLASS_SET_FIELDS_HASH(VALUE obj, st_table *tbl)
569569
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
570570
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
571571

572-
VALUE fields = rb_imemo_obj_fields_new(sizeof(tbl));
572+
VALUE fields = rb_imemo_obj_fields_new(obj, sizeof(tbl));
573573
IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
574574
RCLASSEXT_SET_FIELDS(RCLASS_EXT_PRIME(obj), fields);
575575
}
@@ -580,7 +580,7 @@ RCLASS_WRITE_FIELDS_HASH(VALUE obj, st_table *tbl)
580580
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
581581
RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
582582

583-
VALUE fields = rb_imemo_obj_fields_new(sizeof(tbl));
583+
VALUE fields = rb_imemo_obj_fields_new(obj, sizeof(tbl));
584584
IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
585585
RCLASSEXT_SET_FIELDS(RCLASS_EXT_WRITABLE(obj), fields);
586586
}

internal/imemo.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,7 @@ MEMO_V2_SET(struct MEMO *m, VALUE v)
260260

261261
struct rb_obj_fields {
262262
VALUE flags;
263-
// We're padding the struct so that capacity match T_OBJECT.
264-
// Ideally we'd have a different root to make use of that extra slot.
265-
VALUE _unused;
263+
VALUE klass;
266264
union {
267265
struct {
268266
VALUE fields[1];
@@ -280,8 +278,8 @@ struct rb_obj_fields {
280278
#define OBJ_FIELD_COMPLEX IMEMO_FL_USER1
281279
#define IMEMO_OBJ_FIELDS(fields) ((struct rb_obj_fields *)fields)
282280

283-
VALUE rb_imemo_obj_fields_new(size_t capa);
284-
VALUE rb_imemo_obj_fields_new_complex(st_table *tbl);
281+
VALUE rb_imemo_obj_fields_new(VALUE klass, size_t capa);
282+
VALUE rb_imemo_obj_fields_new_complex(VALUE klass, st_table *tbl);
285283

286284
static inline VALUE *
287285
rb_imemo_obj_fields_ptr(VALUE obj_fields)

shape.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -810,12 +810,17 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
810810
klass = rb_singleton_class(obj);
811811
allow_new_root = true;
812812
break;
813+
case T_IMEMO:
814+
RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_obj_fields));
815+
allow_new_root = true;
816+
klass = Qfalse;
817+
break;
813818
default:
814819
klass = rb_obj_class(obj);
815820
break;
816821
}
817822

818-
bool allow_new_shape = RCLASS_VARIATION_COUNT(klass) < SHAPE_MAX_VARIATIONS;
823+
bool allow_new_shape = !klass || RCLASS_VARIATION_COUNT(klass) < SHAPE_MAX_VARIATIONS;
819824
bool variation_created = false;
820825
allow_new_root &= allow_new_shape;
821826

@@ -833,7 +838,7 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
833838
rb_shape_t *new_shape = get_next_shape_internal(shape, id, SHAPE_IVAR, &variation_created, allow_new_shape);
834839

835840
// Check if we should update max_iv_count on the object's class
836-
if (obj != klass && new_shape->next_field_index > RCLASS_MAX_IV_COUNT(klass)) {
841+
if (klass && new_shape->next_field_index > RCLASS_MAX_IV_COUNT(klass)) {
837842
RCLASS_SET_MAX_IV_COUNT(klass, new_shape->next_field_index);
838843
}
839844

shape.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,15 @@ static inline shape_id_t
9494
get_shape_id_from_flags(VALUE obj)
9595
{
9696
RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
97-
RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO));
97+
RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_obj_fields));
9898
return (shape_id_t)((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT);
9999
}
100100

101101
static inline void
102102
set_shape_id_in_flags(VALUE obj, shape_id_t shape_id)
103103
{
104104
RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
105-
RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO));
105+
RUBY_ASSERT(!RB_TYPE_P(obj, T_IMEMO) || IMEMO_TYPE_P(obj, imemo_obj_fields));
106106
// Ractors are occupying the upper 32 bits of flags, but only in debug mode
107107
// Object shapes are occupying top bits
108108
RBASIC(obj)->flags &= SHAPE_FLAG_MASK;

variable.c

Lines changed: 80 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,17 +1415,17 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
14151415
case T_MODULE:
14161416
{
14171417
bool found = false;
1418-
VALUE val;
1418+
VALUE val = undef;
14191419

1420-
RB_VM_LOCK_ENTER();
1421-
{
1420+
VALUE fields_obj = RCLASS_PRIME_FIELDS_VALUE(obj); // TODO: figure namespaces
1421+
if (fields_obj) {
14221422
#if !SHAPE_IN_BASIC_FLAGS
1423-
shape_id = RCLASS_SHAPE_ID(obj);
1423+
shape_id = get_shape_id_from_flags(fields_obj);
14241424
#endif
14251425

1426-
if (rb_shape_obj_too_complex_p(obj)) {
1427-
st_table * iv_table = RCLASS_FIELDS_HASH(obj);
1428-
if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) {
1426+
if (rb_shape_obj_too_complex_p(fields_obj)) {
1427+
st_table *fields_tbl = IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table;
1428+
if (rb_st_lookup(fields_tbl, (st_data_t)id, (st_data_t *)&val)) {
14291429
found = true;
14301430
}
14311431
else {
@@ -1438,7 +1438,7 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
14381438
found = rb_shape_get_iv_index(shape, id, &index);
14391439

14401440
if (found) {
1441-
ivar_list = RCLASS_PRIME_FIELDS(obj);
1441+
ivar_list = rb_imemo_obj_fields_ptr(fields_obj);
14421442
RUBY_ASSERT(ivar_list);
14431443

14441444
val = ivar_list[index];
@@ -1448,7 +1448,6 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef)
14481448
}
14491449
}
14501450
}
1451-
RB_VM_LOCK_LEAVE();
14521451

14531452
if (found &&
14541453
rb_is_instance_id(id) &&
@@ -4738,7 +4737,7 @@ class_ivar_set_shape_fields(VALUE obj, void *_data)
47384737
static void
47394738
class_ivar_set_shape_resize_fields(VALUE obj, attr_index_t old_capa, attr_index_t new_capa, void *_data)
47404739
{
4741-
VALUE new_fields = rb_imemo_obj_fields_new(new_capa);
4740+
VALUE new_fields = rb_imemo_obj_fields_new(obj, new_capa);
47424741
if (old_capa) {
47434742
MEMCPY(rb_imemo_obj_fields_ptr(new_fields), RCLASS_PRIME_FIELDS(obj), VALUE, old_capa);
47444743
}
@@ -4765,27 +4764,85 @@ class_ivar_set_too_complex_table(VALUE obj, void *_data)
47654764
return RCLASS_WRITABLE_FIELDS_HASH(obj);
47664765
}
47674766

4767+
int
4768+
class_atomic_ivar_set(VALUE obj, ID id, VALUE val)
4769+
{
4770+
bool existing = true;
4771+
4772+
VALUE original_fields_obj = RCLASS_PRIME_FIELDS_VALUE(obj); // TODO: figure out namespaces
4773+
VALUE fields_obj = original_fields_obj;
4774+
4775+
if (!fields_obj) {
4776+
fields_obj = rb_imemo_obj_fields_new(obj, 0);
4777+
}
4778+
4779+
rb_shape_t *current_shape = rb_obj_shape(fields_obj);
4780+
if (UNLIKELY(rb_shape_too_complex_p(current_shape))) {
4781+
goto too_complex;
4782+
}
4783+
4784+
attr_index_t index;
4785+
shape_id_t next_shape_id = 0;
4786+
if (!rb_shape_get_iv_index(current_shape, id, &index)) {
4787+
existing = false;
4788+
4789+
index = current_shape->next_field_index;
4790+
if (index >= SHAPE_MAX_FIELDS) {
4791+
rb_raise(rb_eArgError, "too many instance variables");
4792+
}
4793+
4794+
next_shape_id = rb_shape_transition_add_ivar(obj, id);
4795+
rb_shape_t *next_shape = RSHAPE(next_shape_id);
4796+
if (UNLIKELY(rb_shape_too_complex_p(next_shape))) {
4797+
rb_bug("TODO: transition_too_complex");
4798+
goto too_complex;
4799+
}
4800+
else if (UNLIKELY(next_shape->capacity != current_shape->capacity)) {
4801+
RUBY_ASSERT(next_shape->capacity > current_shape->capacity);
4802+
fields_obj = rb_imemo_obj_fields_new(obj, next_shape->capacity);
4803+
}
4804+
4805+
RUBY_ASSERT(next_shape->type == SHAPE_IVAR);
4806+
RUBY_ASSERT(index == (next_shape->next_field_index - 1));
4807+
}
4808+
4809+
VALUE *fields = rb_imemo_obj_fields_ptr(fields_obj);
4810+
RB_OBJ_WRITE(obj, &fields[index], val);
4811+
if (!existing) {
4812+
rb_shape_set_shape_id(fields_obj, next_shape_id);
4813+
}
4814+
4815+
if (fields_obj != original_fields_obj) {
4816+
RUBY_ATOMIC_VALUE_SET(RCLASS_PRIME_FIELDS_VALUE(obj), fields_obj);
4817+
}
4818+
4819+
return existing;
4820+
4821+
too_complex:
4822+
{
4823+
rb_bug("TODO: handle too_complex");
4824+
}
4825+
return existing;
4826+
}
4827+
47684828
int
47694829
rb_class_ivar_set(VALUE obj, ID id, VALUE val)
47704830
{
47714831
RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
4772-
bool existing = false;
47734832
rb_check_frozen(obj);
4774-
47754833
rb_class_ensure_writable(obj);
47764834

4777-
RB_VM_LOCK_ENTER();
4778-
{
4779-
existing = general_ivar_set(obj, id, val, NULL,
4780-
class_ivar_set_shape_fields,
4781-
class_ivar_set_shape_resize_fields,
4782-
class_ivar_set_set_shape_id,
4783-
class_ivar_set_transition_too_complex,
4784-
class_ivar_set_too_complex_table).existing;
4835+
if (rb_multi_ractor_p()) {
4836+
return class_atomic_ivar_set(obj, id, val);
4837+
}
4838+
else {
4839+
return general_ivar_set(obj, id, val, NULL,
4840+
class_ivar_set_shape_fields,
4841+
class_ivar_set_shape_resize_fields,
4842+
class_ivar_set_set_shape_id,
4843+
class_ivar_set_transition_too_complex,
4844+
class_ivar_set_too_complex_table).existing;
47854845
}
4786-
RB_VM_LOCK_LEAVE();
4787-
4788-
return existing;
47894846
}
47904847

47914848
static void

0 commit comments

Comments
 (0)