vm.c: add constant lookup cache with generation counter

Cache OP_GETCONST results in a global direct-mapped cache (64 entries)
keyed by (irep, sym). Invalidate all entries via a generation counter
bumped on mrb_const_set(), mrb_const_remove(), and
mrb_define_const_id(). ~10% faster on constant-heavy code; disabled
with MRB_NO_CONST_CACHE.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-03-03 16:03:35 +09:00
parent b2d935b6d3
commit 7675601b92
3 changed files with 52 additions and 3 deletions
+23
View File
@@ -243,6 +243,24 @@ struct mrb_cache_entry {
};
#endif
#ifdef MRB_CONST_CACHE_SIZE
# undef MRB_NO_CONST_CACHE
mrb_static_assert_powerof2(MRB_CONST_CACHE_SIZE);
#else
/* default constant cache size: 64 */
/* cache size needs to be power of 2 */
# define MRB_CONST_CACHE_SIZE (1<<6)
#endif
#ifndef MRB_NO_CONST_CACHE
struct mrb_const_cache_entry {
const struct mrb_irep *irep;
mrb_sym sym;
uint32_t generation;
mrb_value value;
};
#endif
struct mrb_jmpbuf;
typedef void (*mrb_atexit_func)(mrb_state*);
@@ -297,6 +315,11 @@ struct mrb_state {
struct mrb_cache_entry cache[MRB_METHOD_CACHE_SIZE];
#endif
#ifndef MRB_NO_CONST_CACHE
uint32_t const_generation;
struct mrb_const_cache_entry const_cache[MRB_CONST_CACHE_SIZE];
#endif
mrb_sym symidx;
const char **symtbl;
size_t symcapa;
+9
View File
@@ -1431,6 +1431,9 @@ mrb_const_set(mrb_state *mrb, mrb_value mod, mrb_sym sym, mrb_value v)
mrb_class_name_class(mrb, mrb_class_ptr(mod), mrb_class_ptr(v), sym);
}
mrb_obj_iv_set(mrb, mrb_obj_ptr(mod), sym, v);
#ifndef MRB_NO_CONST_CACHE
mrb->const_generation++;
#endif
if (!mrb->bootstrapping) {
mrb_value name = mrb_symbol_value(sym);
@@ -1457,6 +1460,9 @@ mrb_const_remove(mrb_state *mrb, mrb_value mod, mrb_sym sym)
{
mod_const_check(mrb, mod);
mrb_iv_remove(mrb, mod, sym);
#ifndef MRB_NO_CONST_CACHE
mrb->const_generation++;
#endif
}
/*
@@ -1474,6 +1480,9 @@ MRB_API void
mrb_define_const_id(mrb_state *mrb, struct RClass *mod, mrb_sym name, mrb_value v)
{
mrb_obj_iv_set(mrb, (struct RObject*)mod, name, v);
#ifndef MRB_NO_CONST_CACHE
mrb->const_generation++;
#endif
}
/*
+20 -3
View File
@@ -2028,9 +2028,26 @@ RETRY_TRY_BLOCK:
}
CASE(OP_GETCONST, BB) {
mrb_value v = mrb_vm_const_get(mrb, irep->syms[b]);
ci = mrb->c->ci;
regs[a] = v;
#ifndef MRB_NO_CONST_CACHE
mrb_sym sym = irep->syms[b];
uint32_t h = mrb_int_hash_func(mrb, ((intptr_t)irep) ^ sym) & (MRB_CONST_CACHE_SIZE-1);
struct mrb_const_cache_entry *cc = &mrb->const_cache[h];
if (cc->irep == irep && cc->sym == sym && cc->generation == mrb->const_generation) {
regs[a] = cc->value;
NEXT;
}
#endif
{
mrb_value v = mrb_vm_const_get(mrb, irep->syms[b]);
ci = mrb->c->ci;
regs[a] = v;
#ifndef MRB_NO_CONST_CACHE
cc->irep = irep;
cc->sym = sym;
cc->generation = mrb->const_generation;
cc->value = v;
#endif
}
NEXT;
}