|
10 | 10 | */ |
11 | 11 | #include "id.h" |
12 | 12 | #include "id_table.h" /* for struct rb_id_table */ |
| 13 | +#include "internal/object.h" /* for rb_class_allocate_instance */ |
13 | 14 | #include "internal/namespace.h" /* for rb_current_namespace */ |
14 | 15 | #include "internal/serial.h" /* for rb_serial_t */ |
15 | 16 | #include "internal/static_assert.h" |
@@ -79,7 +80,7 @@ struct rb_cvar_class_tbl_entry { |
79 | 80 | struct rb_classext_struct { |
80 | 81 | const rb_namespace_t *ns; |
81 | 82 | 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 |
83 | 84 | struct rb_id_table *m_tbl; |
84 | 85 | struct rb_id_table *const_tbl; |
85 | 86 | struct rb_id_table *callable_m_tbl; |
@@ -176,7 +177,8 @@ static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj); |
176 | 177 |
|
177 | 178 | #define RCLASSEXT_NS(ext) (ext->ns) |
178 | 179 | #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) |
180 | 182 | #define RCLASSEXT_M_TBL(ext) (ext->m_tbl) |
181 | 183 | #define RCLASSEXT_CONST_TBL(ext) (ext->const_tbl) |
182 | 184 | #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 |
209 | 211 | #define RCLASS_PRIME_NS(c) (RCLASS_EXT_PRIME(c)->ns) |
210 | 212 | // To invalidate CC by inserting&invalidating method entry into tables containing the target cme |
211 | 213 | // 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) |
213 | 215 | #define RCLASS_PRIME_M_TBL(c) (RCLASS_EXT_PRIME(c)->m_tbl) |
214 | 216 | #define RCLASS_PRIME_CONST_TBL(c) (RCLASS_EXT_PRIME(c)->const_tbl) |
215 | 217 | #define RCLASS_PRIME_CALLABLE_M_TBL(c) (RCLASS_EXT_PRIME(c)->callable_m_tbl) |
@@ -255,9 +257,7 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE |
255 | 257 |
|
256 | 258 | static inline void RCLASS_SET_SUPER(VALUE klass, VALUE super); |
257 | 259 | static inline void RCLASS_WRITE_SUPER(VALUE klass, VALUE super); |
258 | | -static inline st_table * RCLASS_FIELDS_HASH(VALUE obj); |
259 | 260 | static inline st_table * RCLASS_WRITABLE_FIELDS_HASH(VALUE obj); |
260 | | -static inline uint32_t RCLASS_FIELDS_COUNT(VALUE obj); |
261 | 261 | static inline void RCLASS_SET_FIELDS_HASH(VALUE obj, const st_table *table); |
262 | 262 | static inline void RCLASS_WRITE_FIELDS_HASH(VALUE obj, const st_table *table); |
263 | 263 | // TODO: rename RCLASS_SET_M_TBL_WORKAROUND (and _WRITE_) to RCLASS_SET_M_TBL with write barrier |
@@ -531,58 +531,67 @@ RCLASS_WRITE_SUPER(VALUE klass, VALUE super) |
531 | 531 | RB_OBJ_WRITE(klass, &RCLASSEXT_SUPER(RCLASS_EXT_WRITABLE(klass)), super); |
532 | 532 | } |
533 | 533 |
|
534 | | -static inline st_table * |
535 | | -RCLASS_FIELDS_HASH(VALUE obj) |
| 534 | +static inline VALUE |
| 535 | +RCLASS_FIELDS_OBJ(VALUE obj) |
536 | 536 | { |
537 | 537 | RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); |
538 | | - RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); |
539 | | - return (st_table *)RCLASSEXT_FIELDS(RCLASS_EXT_READABLE(obj)); |
| 538 | + return RCLASSEXT_FIELDS_OBJ(RCLASS_EXT_READABLE(obj)); |
| 539 | +} |
| 540 | + |
| 541 | +static inline VALUE |
| 542 | +rb_allocate_fields_obj(VALUE klass) |
| 543 | +{ |
| 544 | + VALUE fields_obj = rb_class_allocate_instance(rb_singleton_class(klass)); |
| 545 | + FL_SET_RAW(fields_obj, ROBJECT_HIDDEN); // HACK |
| 546 | + return fields_obj; |
| 547 | +} |
| 548 | + |
| 549 | +static inline VALUE |
| 550 | +RCLASS_ENSURE_FIELDS_OBJ(VALUE obj) |
| 551 | +{ |
| 552 | + RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); |
| 553 | + rb_classext_t *ext = RCLASS_EXT_READABLE(obj); |
| 554 | + if (!ext->fields_obj) { |
| 555 | + RB_OBJ_WRITE(obj, &ext->fields_obj, rb_allocate_fields_obj(obj)); |
| 556 | + } |
| 557 | + return ext->fields_obj; |
540 | 558 | } |
541 | 559 |
|
542 | | -static inline st_table * |
543 | | -RCLASS_WRITABLE_FIELDS_HASH(VALUE obj) |
| 560 | +static inline VALUE |
| 561 | +RCLASS_WRITABLE_FIELDS_OBJ(VALUE obj) |
544 | 562 | { |
545 | 563 | RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); |
546 | | - RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); |
547 | | - return (st_table *)RCLASSEXT_FIELDS(RCLASS_EXT_WRITABLE(obj)); |
| 564 | + return RCLASSEXT_FIELDS_OBJ(RCLASS_EXT_WRITABLE(obj)); |
548 | 565 | } |
549 | 566 |
|
550 | 567 | static inline void |
551 | | -RCLASS_SET_FIELDS_HASH(VALUE obj, const st_table *tbl) |
| 568 | +RCLASSEXT_SET_FIELDS_HASH(VALUE obj, rb_classext_t *ext, const st_table *tbl) |
552 | 569 | { |
553 | 570 | RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); |
554 | 571 | RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); |
555 | | - RCLASSEXT_FIELDS(RCLASS_EXT_PRIME(obj)) = (VALUE *)tbl; |
| 572 | + |
| 573 | + if (!ext->fields_obj) { |
| 574 | + // FIXME: We can trigger GC here and `*tbl` may not be marked |
| 575 | + RB_OBJ_WRITE(obj, &ext->fields_obj, rb_allocate_fields_obj(obj)); |
| 576 | + } |
| 577 | + ROBJECT_SET_FIELDS_HASH(ext->fields_obj, tbl); |
556 | 578 | } |
557 | 579 |
|
558 | 580 | static inline void |
559 | | -RCLASS_WRITE_FIELDS_HASH(VALUE obj, const st_table *tbl) |
| 581 | +RCLASS_SET_FIELDS_HASH(VALUE obj, const st_table *tbl) |
560 | 582 | { |
561 | 583 | RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); |
562 | 584 | RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); |
563 | | - RCLASSEXT_FIELDS(RCLASS_EXT_WRITABLE(obj)) = (VALUE *)tbl; |
| 585 | + |
| 586 | + RCLASSEXT_SET_FIELDS_HASH(obj, RCLASS_EXT_PRIME(obj), tbl); |
564 | 587 | } |
565 | 588 |
|
566 | | -static inline uint32_t |
567 | | -RCLASS_FIELDS_COUNT(VALUE obj) |
| 589 | +static inline void |
| 590 | +RCLASS_WRITE_FIELDS_HASH(VALUE obj, const st_table *tbl) |
568 | 591 | { |
569 | 592 | RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE)); |
570 | | - if (rb_shape_obj_too_complex_p(obj)) { |
571 | | - uint32_t count; |
572 | | - |
573 | | - // "Too complex" classes could have their IV hash mutated in |
574 | | - // parallel, so lets lock around getting the hash size. |
575 | | - RB_VM_LOCK_ENTER(); |
576 | | - { |
577 | | - count = (uint32_t)rb_st_table_size(RCLASS_FIELDS_HASH(obj)); |
578 | | - } |
579 | | - RB_VM_LOCK_LEAVE(); |
580 | | - |
581 | | - return count; |
582 | | - } |
583 | | - else { |
584 | | - return RSHAPE(RCLASS_SHAPE_ID(obj))->next_field_index; |
585 | | - } |
| 593 | + RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); |
| 594 | + RCLASSEXT_SET_FIELDS_HASH(obj, RCLASS_EXT_WRITABLE(obj), tbl); |
586 | 595 | } |
587 | 596 |
|
588 | 597 | #define RCLASS_SET_M_TBL_EVEN_WHEN_PROMOTED(klass, table) RCLASS_SET_M_TBL_WORKAROUND(klass, table, false) |
|
0 commit comments