state.c: optimize mrb_state initialization by deferring method cache clear

During mrb_state initialization, especially when defining core classes and methods,
the method cache is repeatedly cleared. This causes significant overhead in
scenarios like mrbtest where mrb_state is initialized multiple times.

This commit introduces a `bootstrapping` flag in `struct mrb_state`.
When this flag is TRUE (during mrb_open_core), method cache clears
triggered by `mrb_define_method_raw` and `include_module_at` are suppressed.
The cache is cleared only once at the very end of `mrb_open_core` after
all core methods are defined, and the flag is then set to FALSE.

This optimization significantly reduces the number of method cache clears
during initialization, improving performance for repeated mrb_state creations.

Co-authored-by: Gemini <gemini@google.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-07-08 10:26:53 +09:00
parent 2735340702
commit 95656c40ff
3 changed files with 11 additions and 5 deletions
+3
View File
@@ -273,6 +273,8 @@ typedef struct mrb_state {
mrb_gc gc;
mrb_bool bootstrapping;
#ifndef MRB_NO_METHOD_CACHE
struct mrb_cache_entry cache[MRB_METHOD_CACHE_SIZE];
#endif
@@ -1247,6 +1249,7 @@ MRB_API mrb_state* mrb_open_core(void);
* Pointer to the mrb_state to be closed.
*/
MRB_API void mrb_close(mrb_state *mrb);
MRB_API void mrb_method_cache_clear(mrb_state *mrb);
/**
* The memory allocation function. You can redefine this function for your own allocator.
+4 -5
View File
@@ -600,7 +600,6 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super)
static mrb_value mrb_do_nothing(mrb_state *mrb, mrb_value);
#ifndef MRB_NO_METHOD_CACHE
static void mc_clear(mrb_state *mrb);
static void mc_clear_by_id(mrb_state *mrb, mrb_sym mid);
#else
#define mc_clear(mrb)
@@ -1033,7 +1032,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_
MRB_SET_VISIBILITY_FLAGS(flags, (e ? MRB_ENV_VISIBILITY(e) : MRB_CI_VISIBILITY(ci)));
}
mt_put(mrb, h, mid, flags, ptr);
mc_clear_by_id(mrb, mid);
if (!mrb->bootstrapping) mc_clear_by_id(mrb, mid);
}
static void
@@ -1900,7 +1899,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru
skip:
m = m->super;
}
mc_clear(mrb);
if (!mrb->bootstrapping) mrb_method_cache_clear(mrb);
return 0;
}
@@ -2503,8 +2502,8 @@ mrb_define_module_function(mrb_state *mrb, struct RClass *c, const char *name, m
#ifndef MRB_NO_METHOD_CACHE
/* clear whole method cache table */
static void
mc_clear(mrb_state *mrb)
MRB_API void
mrb_method_cache_clear(mrb_state *mrb)
{
static const struct mrb_cache_entry ce_zero ={0};
+4
View File
@@ -47,12 +47,16 @@ mrb_open_core(void)
*mrb = mrb_state_zero;
mrb->atexit_stack_len = 0;
mrb->bootstrapping = TRUE;
if (mrb_core_init_protect(mrb, init_gc_and_core, NULL)) {
mrb_close(mrb);
return NULL;
}
mrb_method_cache_clear(mrb);
mrb->bootstrapping = FALSE;
return mrb;
}