summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/class.h67
-rw-r--r--internal/imemo.h54
-rw-r--r--internal/thread.h1
3 files changed, 85 insertions, 37 deletions
diff --git a/internal/class.h b/internal/class.h
index 5601978292..2250d3f343 100644
--- a/internal/class.h
+++ b/internal/class.h
@@ -79,7 +79,7 @@ struct rb_cvar_class_tbl_entry {
struct rb_classext_struct {
const rb_namespace_t *ns;
VALUE super;
- VALUE *fields; // Fields are either ivar or other internal properties stored inline
+ VALUE fields_obj; // Fields are either ivar or other internal properties stored inline
struct rb_id_table *m_tbl;
struct rb_id_table *const_tbl;
struct rb_id_table *callable_m_tbl;
@@ -175,7 +175,8 @@ static inline rb_classext_t * RCLASS_EXT_WRITABLE(VALUE obj);
#define RCLASSEXT_NS(ext) (ext->ns)
#define RCLASSEXT_SUPER(ext) (ext->super)
-#define RCLASSEXT_FIELDS(ext) (ext->fields)
+#define RCLASSEXT_FIELDS(ext) (ext->fields_obj ? ROBJECT_FIELDS(ext->fields_obj) : NULL)
+#define RCLASSEXT_FIELDS_OBJ(ext) (ext->fields_obj)
#define RCLASSEXT_M_TBL(ext) (ext->m_tbl)
#define RCLASSEXT_CONST_TBL(ext) (ext->const_tbl)
#define RCLASSEXT_CALLABLE_M_TBL(ext) (ext->callable_m_tbl)
@@ -205,7 +206,7 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE
#define RCLASS_PRIME_NS(c) (RCLASS_EXT_PRIME(c)->ns)
// To invalidate CC by inserting&invalidating method entry into tables containing the target cme
// See clear_method_cache_by_id_in_class()
-#define RCLASS_PRIME_FIELDS(c) (RCLASS_EXT_PRIME(c)->fields)
+#define RCLASS_PRIME_FIELDS_OBJ(c) (RCLASS_EXT_PRIME(c)->fields_obj)
#define RCLASS_PRIME_M_TBL(c) (RCLASS_EXT_PRIME(c)->m_tbl)
#define RCLASS_PRIME_CONST_TBL(c) (RCLASS_EXT_PRIME(c)->const_tbl)
#define RCLASS_PRIME_CALLABLE_M_TBL(c) (RCLASS_EXT_PRIME(c)->callable_m_tbl)
@@ -255,11 +256,6 @@ static inline void RCLASSEXT_SET_INCLUDER(rb_classext_t *ext, VALUE klass, VALUE
static inline void RCLASS_SET_SUPER(VALUE klass, VALUE super);
static inline void RCLASS_WRITE_SUPER(VALUE klass, VALUE super);
-static inline st_table * RCLASS_FIELDS_HASH(VALUE obj);
-static inline st_table * RCLASS_WRITABLE_FIELDS_HASH(VALUE obj);
-static inline uint32_t RCLASS_FIELDS_COUNT(VALUE obj);
-static inline void RCLASS_SET_FIELDS_HASH(VALUE obj, const st_table *table);
-static inline void RCLASS_WRITE_FIELDS_HASH(VALUE obj, const st_table *table);
// TODO: rename RCLASS_SET_M_TBL_WORKAROUND (and _WRITE_) to RCLASS_SET_M_TBL with write barrier
static inline void RCLASS_SET_M_TBL_WORKAROUND(VALUE klass, struct rb_id_table *table, bool check_promoted);
static inline void RCLASS_WRITE_M_TBL_WORKAROUND(VALUE klass, struct rb_id_table *table, bool check_promoted);
@@ -407,10 +403,6 @@ RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
if (ext)
return ext;
- if (!rb_shape_obj_too_complex_p(obj)) {
- rb_evict_ivars_to_hash(obj); // fallback to ivptr for ivars from shapes
- }
-
RB_VM_LOCKING() {
// re-check the classext is not created to avoid the multi-thread race
ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(obj, ns);
@@ -528,56 +520,57 @@ RCLASS_WRITE_SUPER(VALUE klass, VALUE super)
RB_OBJ_WRITE(klass, &RCLASSEXT_SUPER(RCLASS_EXT_WRITABLE(klass)), super);
}
-static inline st_table *
-RCLASS_FIELDS_HASH(VALUE obj)
+static inline VALUE
+RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(VALUE obj)
{
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
- return (st_table *)RCLASSEXT_FIELDS(RCLASS_EXT_READABLE(obj));
+ rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj);
+ if (!ext->fields_obj) {
+ RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_class_fields_new(obj, 1));
+ }
+ return ext->fields_obj;
}
-static inline st_table *
-RCLASS_WRITABLE_FIELDS_HASH(VALUE obj)
+static inline VALUE
+RCLASS_WRITABLE_FIELDS_OBJ(VALUE obj)
{
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
- return (st_table *)RCLASSEXT_FIELDS(RCLASS_EXT_WRITABLE(obj));
+ return RCLASSEXT_FIELDS_OBJ(RCLASS_EXT_WRITABLE(obj));
}
static inline void
-RCLASS_SET_FIELDS_HASH(VALUE obj, const st_table *tbl)
+RCLASSEXT_SET_FIELDS_OBJ(VALUE obj, rb_classext_t *ext, VALUE fields_obj)
{
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
- RCLASSEXT_FIELDS(RCLASS_EXT_PRIME(obj)) = (VALUE *)tbl;
+
+ VALUE old_fields_obj = ext->fields_obj;
+ RUBY_ATOMIC_VALUE_SET(ext->fields_obj, fields_obj);
+ RB_OBJ_WRITTEN(obj, old_fields_obj, fields_obj);
}
static inline void
-RCLASS_WRITE_FIELDS_HASH(VALUE obj, const st_table *tbl)
+RCLASS_WRITABLE_SET_FIELDS_OBJ(VALUE obj, VALUE fields_obj)
{
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- RUBY_ASSERT(rb_shape_obj_too_complex_p(obj));
- RCLASSEXT_FIELDS(RCLASS_EXT_WRITABLE(obj)) = (VALUE *)tbl;
+
+ RCLASSEXT_SET_FIELDS_OBJ(obj, RCLASS_EXT_WRITABLE(obj), fields_obj);
}
static inline uint32_t
RCLASS_FIELDS_COUNT(VALUE obj)
{
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- if (rb_shape_obj_too_complex_p(obj)) {
- uint32_t count;
- // "Too complex" classes could have their IV hash mutated in
- // parallel, so lets lock around getting the hash size.
- RB_VM_LOCKING() {
- count = (uint32_t)rb_st_table_size(RCLASS_FIELDS_HASH(obj));
+ VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj);
+ if (fields_obj) {
+ if (rb_shape_obj_too_complex_p(fields_obj)) {
+ return (uint32_t)rb_st_table_size(rb_imemo_class_fields_complex_tbl(fields_obj));
+ }
+ else {
+ return RSHAPE_LEN(RBASIC_SHAPE_ID(fields_obj));
}
-
- return count;
- }
- else {
- return RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
}
+ return 0;
}
#define RCLASS_SET_M_TBL_EVEN_WHEN_PROMOTED(klass, table) RCLASS_SET_M_TBL_WORKAROUND(klass, table, false)
diff --git a/internal/imemo.h b/internal/imemo.h
index 305d12d240..0806baa9a6 100644
--- a/internal/imemo.h
+++ b/internal/imemo.h
@@ -42,6 +42,7 @@ enum imemo_type {
imemo_callinfo = 11,
imemo_callcache = 12,
imemo_constcache = 13,
+ imemo_class_fields = 14,
};
/* CREF (Class REFerence) is defined in method.h */
@@ -257,4 +258,57 @@ MEMO_V2_SET(struct MEMO *m, VALUE v)
RB_OBJ_WRITE(m, &m->v2, v);
}
+struct rb_class_fields {
+ struct RBasic basic;
+ union {
+ struct {
+ VALUE fields[1];
+ } embed;
+ struct {
+ VALUE *ptr;
+ } external;
+ struct {
+ // Note: the st_table could be embedded, but complex T_CLASS should be rare to
+ // non-existent, so not really worth the trouble.
+ st_table *table;
+ } complex;
+ } as;
+};
+
+#define OBJ_FIELD_EXTERNAL IMEMO_FL_USER0
+#define IMEMO_OBJ_FIELDS(fields) ((struct rb_class_fields *)fields)
+
+VALUE rb_imemo_class_fields_new(VALUE klass, size_t capa);
+VALUE rb_imemo_class_fields_new_complex(VALUE klass, size_t capa);
+VALUE rb_imemo_class_fields_clone(VALUE fields_obj);
+
+static inline VALUE *
+rb_imemo_class_fields_ptr(VALUE obj_fields)
+{
+ if (!obj_fields) {
+ return NULL;
+ }
+
+ RUBY_ASSERT(IMEMO_TYPE_P(obj_fields, imemo_class_fields));
+
+ if (RB_UNLIKELY(FL_TEST_RAW(obj_fields, OBJ_FIELD_EXTERNAL))) {
+ return IMEMO_OBJ_FIELDS(obj_fields)->as.external.ptr;
+ }
+ else {
+ return IMEMO_OBJ_FIELDS(obj_fields)->as.embed.fields;
+ }
+}
+
+static inline st_table *
+rb_imemo_class_fields_complex_tbl(VALUE obj_fields)
+{
+ if (!obj_fields) {
+ return NULL;
+ }
+
+ RUBY_ASSERT(IMEMO_TYPE_P(obj_fields, imemo_class_fields));
+
+ return IMEMO_OBJ_FIELDS(obj_fields)->as.complex.table;
+}
+
#endif /* INTERNAL_IMEMO_H */
diff --git a/internal/thread.h b/internal/thread.h
index 8403ac2663..00fcbfc560 100644
--- a/internal/thread.h
+++ b/internal/thread.h
@@ -90,6 +90,7 @@ typedef VALUE (rb_interrupt_exec_func_t)(void *data);
enum rb_interrupt_exec_flag {
rb_interrupt_exec_flag_none = 0x00,
rb_interrupt_exec_flag_value_data = 0x01,
+ rb_interrupt_exec_flag_new_thread = 0x02,
};
// interrupt the target_th and run func.