From 95656c40fffd61f4b6ba0cb0580e859348d6e22a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 8 Jul 2025 10:26:53 +0900 Subject: [PATCH] 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 --- include/mruby.h | 3 +++ src/class.c | 9 ++++----- src/state.c | 4 ++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/mruby.h b/include/mruby.h index 1fd525a41..9d90869cb 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -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. diff --git a/src/class.c b/src/class.c index a23b87447..1d7b42e9f 100644 --- a/src/class.c +++ b/src/class.c @@ -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}; diff --git a/src/state.c b/src/state.c index 1aeb42552..1b3d687b9 100644 --- a/src/state.c +++ b/src/state.c @@ -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; }