8000 Filling cache values on cvar write · github/ruby@08de37f · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit 08de37f

Browse files
eileencodestenderlove
authored andcommitted
Filling cache values on cvar write
Instead of on read. Once it's in the inline cache we never have to make one again. We want to eventually put the value into the cache, and the best opportunity to do that is when you write the value.
1 parent e8ae922 commit 08de37f

File tree

6 files changed

+65
-12
lines changed

6 files changed

+65
-12
lines changed

class.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,7 @@ rb_include_class_new(VALUE module, VALUE super)
960960
RCLASS_CONST_TBL(module) = rb_id_table_create(0);
961961
}
962962
RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
963+
RCLASS_CVC_TBL(klass) = RCLASS_CVC_TBL(module);
963964
RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);
964965

965966
RCLASS_SET_SUPER(klass, super);

compile.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8044,8 +8044,9 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
80448044
if (!popped) {
80458045
ADD_INSN(ret, line_node, dup);
80468046
}
8047-
ADD_INSN1(ret, line_node, setclassvariable,
8048-
ID2SYM(node->nd_vid));
8047+
ADD_INSN2(ret, line_node, setclassvariable,
8048+
ID2SYM(node->nd_vid),
8049+
get_ivar_ic_value(iseq,node->nd_vid));
80498050
break;
80508051
}
80518052
case NODE_OP_ASGN1: {

debug_counter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ R 10000 B_DEBUG_COUNTER(mc_inline_miss_same_cme) // IMC miss, but same CME
2424
RB_DEBUG_COUNTER(mc_inline_miss_same_def) // IMC miss, but same definition
2525
RB_DEBUG_COUNTER(mc_inline_miss_diff) // IMC miss, different methods
2626

27-
RB_DEBUG_COUNTER(cvar_inline_hit) // cvar cache hit
27+
RB_DEBUG_COUNTER(cvar_write_inline_hit) // cvar cache hit on write
28+
RB_DEBUG_COUNTER(cvar_read_inline_hit) // cvar cache hit on read
2829
RB_DEBUG_COUNTER(cvar_inline_miss) // miss inline cache
2930
RB_DEBUG_COUNTER(cvar_class_invalidate) // invalidate cvar cache when define a cvar that's defined on a subclass
3031
RB_DEBUG_COUNTER(cvar_include_invalidate) // invalidate cvar cache on module include or prepend

insns.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,14 +244,14 @@ getclassvariable
244244
/* Set value of class variable id of klass as val. */
245245
DEFINE_INSN
246246
setclassvariable
247-
(ID id)
247+
(ID id, IVC ic)
248248
(VALUE val)
249249
()
250250
/* "class variable access from toplevel" warning can be hooked. */
251251
// attr bool leaf = false; /* has rb_warning() */
252252
{
253253
vm_ensure_not_refinement_module(GET_SELF());
254-
vm_setclassvariable(vm_get_cref(GET_EP()), GET_CFP(), id, val);
254+
vm_setclassvariable(GET_ISEQ(), vm_get_cref(GET_EP()), GET_CFP(), id, val, (ICVARC)ic);
255255
}
256256

257257
/* Get constant variable id. If klass is Qnil and allow_nil is Qtrue, constants

variable.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "vm_sync.h"
4141

4242
RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
43+
#define GET_GLOBAL_CVAR_STATE() (ruby_vm_global_cvar_state)
4344

4445
typedef void rb_gvar_compact_t(void *var);
4546

@@ -3399,6 +3400,24 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
33993400

34003401
int result = rb_class_ivar_set(target, id, val);
34013402

3403+
struct rb_id_table *rb_cvc_tbl = RCLASS_CVC_TBL(target);
3404+
3405+
if (!rb_cvc_tbl) {
3406+
rb_cvc_tbl = RCLASS_CVC_TBL(target) = rb_id_table_create(2);
3407+
}
3408+
3409+
struct rb_cvar_class_tbl_entry *ent;
3410+
3411+
if (!rb_id_table_lookup(rb_cvc_tbl, id, (VALUE*)&ent)) {
3412+
ent = ALLOC(struct rb_cvar_class_tbl_entry);
3413+
ent->class_value = target;
3414+
ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
3415+
rb_id_table_insert(rb_cvc_tbl, id, (VALUE)ent);
3416+
RB_DEBUG_COUNTER_INC(cvar_inline_miss);
3417+
} else {
3418+
ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
3419+
}
3420+
34023421
// Break the cvar cache if this is a new class variable
34033422
// and target is a module or a subclass with the same
34043423
// cvar in this lookup.

vm_insnhelper.c

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ vm_getclassvariable(const rb_iseq_t *iseq, const rb_cref_t *cref, const rb_contr
12861286
{
12871287
if (ic->entry && ic->entry->global_cvar_state == GET_GLOBAL_CVAR_STATE()) {
12881288
VALUE v = Qundef;
1289-
RB_DEBUG_COUNTER_INC(cvar_inline_hit);
1289+
RB_DEBUG_COUNTER_INC(cvar_read_inline_hit);
12901290

12911291
if (st_lookup(RCLASS_IV_TBL(ic->entry->class_value), (st_data_t)id, &v)) {
12921292
return v;
@@ -1298,6 +1298,10 @@ vm_getclassvariable(const rb_iseq_t *iseq, const rb_cref_t *cref, const rb_contr
12981298

12991299
VALUE cvar_value = rb_cvar_find(klass, id, &defined_class);
13001300

1301+
if (RB_TYPE_P(defined_class, T_ICLASS)) {
1302+
defined_class = RBASIC(defined_class)->klass;
1303+
}
1304+
13011305
struct rb_id_table *rb_cvc_tbl = RCLASS_CVC_TBL(defined_class);
13021306

13031307
if (!rb_cvc_tbl) {
@@ -1307,11 +1311,7 @@ vm_getclassvariable(const rb_iseq_t *iseq, const rb_cref_t *cref, const rb_contr
13071311
struct rb_cvar_class_tbl_entry *ent;
13081312

13091313
if (!rb_id_table_lookup(rb_cvc_tbl, id, (VALUE*)&ent)) {
1310-
ent = ALLOC(struct rb_cvar_class_tbl_entry);
1311-
ent->class_value = defined_class;
1312-
ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
1313-
rb_id_table_insert(rb_cvc_tbl, id, (VALUE)ent);
1314-
RB_DEBUG_COUNTER_INC(cvar_inline_miss);
1314+
rb_bug("should have cvar cache entry");
13151315
} else {
13161316
ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
13171317
}
@@ -1323,11 +1323,42 @@ vm_getclassvariable(const rb_iseq_t *iseq, const rb_cref_t *cref, const rb_contr
13231323
}
13241324

13251325
static inline void
1326-
vm_setclassvariable(const rb_cref_t *cref, const rb_control_frame_t *cfp, ID id, VALUE val)
1326+
vm_setclassvariable(const rb_iseq_t *iseq, const rb_cref_t *cref, const rb_control_frame_t *cfp, ID id, VALUE val, ICVARC ic)
13271327
{
1328+
if (ic->entry && ic->entry->global_cvar_state == GET_GLOBAL_CVAR_STATE()) {
1329+
RB_DEBUG_COUNTER_INC(cvar_write_inline_hit);
1330+
1331+
rb_class_ivar_set(ic->entry->class_value, id, val);
1332+
return;
1333+
}
1334+
13281335
VALUE klass = vm_get_cvar_base(cref, cfp, 1);
13291336

13301337
rb_cvar_set(klass, id, val);
1338+
1339+
VALUE defined_class = 0;
1340+
rb_cvar_find(klass, id, &defined_class);
1341+
1342+
if (RB_TYPE_P(defined_class, T_ICLASS)) {
1343+
defined_class = RBASIC(defined_class)->klass;
1344+
}
1345+
1346+
struct rb_id_table *rb_cvc_tbl = RCLASS_CVC_TBL(defined_class);
1347+
1348+
if (!rb_cvc_tb 9211 l) {
1349+
rb_bug("the cvc table should be set");
1350+
}
1351+
1352+
struct rb_cvar_class_tbl_entry *ent;
1353+
1354+
if (!rb_id_table_lookup(rb_cvc_tbl, id, (VALUE*)&ent)) {
1355+
rb_bug("should have cvar cache entry");
1356+
} else {
1357+
ent->global_cvar_state = GET_GLOBAL_CVAR_STATE();
1358+
}
1359+
1360+
ic->entry = ent;
1361+
RB_OBJ_WRITTEN(iseq, Qundef, ent->class_value);
13311362
}
13321363

13331364
static inline VALUE

0 commit comments

Comments
 (0)
0