diff --git a/compile.c b/compile.c index 17f870e3e5..f95b3bb143 100644 --- a/compile.c +++ b/compile.c @@ -2074,6 +2074,25 @@ get_ivar_ic_value(rb_iseq_t *iseq,ID id) return val; } +static inline VALUE +get_cvar_ic_value(rb_iseq_t *iseq,ID id) +{ + VALUE val; + struct rb_id_table *tbl = ISEQ_COMPILE_DATA(iseq)->ivar_cache_table; + if (tbl) { + if (rb_id_table_lookup(tbl,id,&val)) { + return val; + } + } + else { + tbl = rb_id_table_create(1); + ISEQ_COMPILE_DATA(iseq)->ivar_cache_table = tbl; + } + val = INT2FIX(ISEQ_BODY(iseq)->icvarc_size++); + rb_id_table_insert(tbl,id,val); + return val; +} + #define BADINSN_DUMP(anchor, list, dest) \ dump_disasm_list_with_cursor(FIRST_ELEMENT(anchor), list, dest) @@ -2412,7 +2431,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor) } break; } - /* [ TS_(ICVARC|IVC) ... | TS_ISE | TS_IC ] */ + /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */ case TS_IC: /* inline cache: constants */ case TS_ISE: /* inline storage entry: `once` insn */ case TS_ICVARC: /* inline cvar cache */ @@ -9336,7 +9355,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no } ADD_INSN2(ret, node, setclassvariable, ID2SYM(node->nd_vid), - get_ivar_ic_value(iseq,node->nd_vid)); + get_cvar_ic_value(iseq,node->nd_vid)); break; } case NODE_OP_ASGN1: @@ -9463,7 +9482,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no if (!popped) { ADD_INSN2(ret, node, getclassvariable, ID2SYM(node->nd_vid), - get_ivar_ic_value(iseq,node->nd_vid)); + get_cvar_ic_value(iseq,node->nd_vid)); } break; } @@ -10339,12 +10358,17 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, } break; case TS_IVC: /* inline ivar cache */ - case TS_ICVARC: /* inline cvar cache */ argv[j] = op; if (NUM2UINT(op) >= ISEQ_BODY(iseq)->ivc_size) { ISEQ_BODY(iseq)->ivc_size = NUM2INT(op) + 1; } break; + case TS_ICVARC: /* inline cvar cache */ + argv[j] = op; + if (NUM2UINT(op) >= ISEQ_BODY(iseq)->icvarc_size) { + ISEQ_BODY(iseq)->icvarc_size = NUM2INT(op) + 1; + } + break; case TS_CALLDATA: argv[j] = iseq_build_callinfo_from_hash(iseq, op); break; @@ -11807,6 +11831,7 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq) ibf_dump_write_small_value(dump, body->variable.flip_count); ibf_dump_write_small_value(dump, body->local_table_size); ibf_dump_write_small_value(dump, body->ivc_size); + ibf_dump_write_small_value(dump, body->icvarc_size); ibf_dump_write_small_value(dump, body->ise_size); ibf_dump_write_small_value(dump, body->ic_size); ibf_dump_write_small_value(dump, body->ci_size); @@ -11918,6 +11943,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset) const unsigned int local_table_size = (unsigned int)ibf_load_small_value(load, &reading_pos); const unsigned int ivc_size = (unsigned int)ibf_load_small_value(load, &reading_pos); + const unsigned int icvarc_size = (unsigned int)ibf_load_small_value(load, &reading_pos); const unsigned int ise_size = (unsigned int)ibf_load_small_value(load, &reading_pos); const unsigned int ic_size = (unsigned int)ibf_load_small_value(load, &reading_pos); @@ -11966,6 +11992,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset) load_body->builtin_inline_p = builtin_inline_p; load_body->ivc_size = ivc_size; + load_body->icvarc_size = icvarc_size; load_body->ise_size = ise_size; load_body->ic_size = ic_size; load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body)); diff --git a/iseq.c b/iseq.c index 20ca93b596..0369830bdd 100644 --- a/iseq.c +++ b/iseq.c @@ -274,13 +274,11 @@ rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data) union iseq_inline_storage_entry *is_entries = body->is_entries; if (body->is_entries) { - // IVC and ICVARC entries + // IVC entries for (unsigned int i = 0; i < body->ivc_size; i++, is_entries++) { IVC ivc = (IVC)is_entries; if (ivc->entry) { - if (RB_TYPE_P(ivc->entry->class_value, T_NONE)) { - rb_bug("!! %u", ivc->entry->index); - } + RUBY_ASSERT(!RB_TYPE_P(ivc->entry->class_value, T_NONE)); VALUE nv = func(data, ivc->entry->class_value); if (ivc->entry->class_value != nv) { @@ -289,6 +287,19 @@ rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data) } } + // ICVARC entries + for (unsigned int i = 0; i < body->icvarc_size; i++, is_entries++) { + ICVARC icvarc = (ICVARC)is_entries; + if (icvarc->entry) { + RUBY_ASSERT(!RB_TYPE_P(icvarc->entry->class_value, T_NONE)); + + VALUE nv = func(data, icvarc->entry->class_value); + if (icvarc->entry->class_value != nv) { + icvarc->entry->class_value = nv; + } + } + } + // ISE entries for (unsigned int i = 0; i < body->ise_size; i++, is_entries++) { union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)is_entries; diff --git a/tool/ruby_vm/views/_insn_type_chars.erb b/tool/ruby_vm/views/_insn_type_chars.erb index e2ef222548..27daec6c6d 100644 --- a/tool/ruby_vm/views/_insn_type_chars.erb +++ b/tool/ruby_vm/views/_insn_type_chars.erb @@ -20,9 +20,10 @@ ISEQ_IS_ENTRY_START(const struct rb_iseq_constant_body *body, char op_type) case TS_IC: relative_ic_offset += body->ise_size; case TS_ISE: + relative_ic_offset += body->icvarc_size; + case TS_ICVARC: relative_ic_offset += body->ivc_size; case TS_IVC: - case TS_ICVARC: break; default: rb_bug("Wrong op type"); diff --git a/vm_core.h b/vm_core.h index f8eea13750..2a6d15bfbc 100644 --- a/vm_core.h +++ b/vm_core.h @@ -337,7 +337,7 @@ struct rb_mjit_unit; typedef uintptr_t iseq_bits_t; -#define ISEQ_IS_SIZE(body) (body->ic_size + body->ivc_size + body->ise_size) +#define ISEQ_IS_SIZE(body) (body->ic_size + body->ivc_size + body->ise_size + body->icvarc_size) struct rb_iseq_constant_body { enum iseq_type { @@ -448,7 +448,7 @@ struct rb_iseq_constant_body { const struct rb_iseq_struct *parent_iseq; struct rb_iseq_struct *local_iseq; /* local_iseq->flip_cnt can be modified */ - union iseq_inline_storage_entry *is_entries; /* [ TS_(ICVARC|IVC) ... | TS_ISE | TS_IC ] */ + union iseq_inline_storage_entry *is_entries; /* [ TS_IVC | TS_ICVARC | TS_ISE | TS_IC ] */ struct rb_call_data *call_data; //struct rb_call_data calls[ci_size]; struct { @@ -460,9 +460,10 @@ struct rb_iseq_constant_body { } variable; unsigned int local_table_size; - unsigned int ic_size; // Number of IC caches - unsigned int ise_size; // Number of ISE caches - unsigned int ivc_size; // Number of IVC and ICVARC caches + unsigned int ic_size; // Number of IC caches + unsigned int ise_size; // Number of ISE caches + unsigned int ivc_size; // Number of IVC caches + unsigned int icvarc_size; // Number of ICVARC caches unsigned int ci_size; unsigned int stack_max; /* for stack overflow check */ union {