class.c: use linear search for method tables; make ROM entries const

Replace binary search with linear scan in mt_get(), mt_put(),
mt_del(), mt_chain_has(), and mrb_mt_foreach(). The method cache
makes repeated lookups O(1), so linear scan on cache misses is
acceptable.

This removes the sorting requirement, allowing ROM entry arrays
to be declared const. On embedded systems, const static data
resides in flash/ROM instead of RAM, saving ~8.4KB for ~700
method entries on 32-bit MCUs.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-02-20 08:26:05 +09:00
parent ce8ce3f96d
commit 0fab703028
34 changed files with 119 additions and 176 deletions
+15 -14
View File
@@ -57,9 +57,9 @@ Values are `union mrb_mt_ptr` (function pointer or proc pointer). Keys
are pure `mrb_sym` (no flag encoding). Flags are a separate `uint32_t`
field that stores visibility, func/proc type, and argument spec.
Entries must be sorted by symbol ID for binary search. The
`mrb_mt_init_rom()` function handles sorting at startup, so the
source code order does not matter.
Entries are searched linearly, so source code order does not matter.
The method cache makes repeated lookups O(1), so the linear scan
only occurs on cache misses.
## How to Define a ROM Method Table
@@ -73,7 +73,7 @@ constants) and define the ROM entries:
#include <mruby/internal.h>
#include <mruby/presym.h>
static mrb_mt_entry my_rom_entries[] = {
static const mrb_mt_entry my_rom_entries[] = {
MRB_MT_ENTRY(my_method_a, MRB_SYM(method_a), MRB_MT_FUNC),
MRB_MT_ENTRY(my_method_b, MRB_SYM(method_b), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(my_method_eq, MRB_OPSYM(eq), MRB_MT_FUNC),
@@ -95,8 +95,8 @@ mrb_mruby_mygem_gem_init(mrb_state *mrb)
}
```
`mrb_mt_init_rom()` sorts the entries by symbol ID, sets the readonly
flag, and pushes the ROM layer onto the class's method table chain.
`mrb_mt_init_rom()` pushes the ROM layer onto the class's method
table chain.
### Step 3: Verify
@@ -187,22 +187,23 @@ MRB_IVSYM(name) /* @name */
void mrb_mt_init_rom(struct RClass *c, mrb_mt_tbl *rom);
```
Sorts the ROM table, sets the readonly flag, and pushes it onto the
class's method table chain. Multiple calls push additional layers,
which is how extension gems add methods to core classes.
Pushes the ROM layer onto the class's method table chain. The
readonly flag is already set by `MRB_MT_ROM_TAB()`. Multiple calls
push additional layers, which is how extension gems add methods to
core classes.
## Entry Correspondence
Each `MRB_MT_ENTRY()` bundles a function pointer with its method name
and flags in a single line. Their order in the source code does not
matter (they are sorted at init time), but keeping related methods
matter, but keeping related methods
together improves readability.
**Method aliases** (two names for the same function) are expressed as
separate entries sharing the same function pointer:
```c
static mrb_mt_entry str_rom_entries[] = {
static const mrb_mt_entry str_rom_entries[] = {
MRB_MT_ENTRY(mrb_str_size, MRB_SYM(size), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_str_size, MRB_SYM(length), MRB_MT_FUNC|MRB_MT_NOARG),
};
@@ -218,7 +219,7 @@ blocks):
```c
#ifndef MRB_NO_FLOAT
static mrb_mt_entry float_rom_entries[] = { ... };
static const mrb_mt_entry float_rom_entries[] = { ... };
static mrb_mt_tbl float_rom_mt = MRB_MT_ROM_TAB(float_rom_entries);
#endif
@@ -255,7 +256,7 @@ ROM layer in front of the core ROM layer:
```c
/* mrbgems/mruby-string-ext/src/string.c */
static mrb_mt_entry string_ext_rom_entries[] = { ... };
static const mrb_mt_entry string_ext_rom_entries[] = { ... };
static mrb_mt_tbl string_ext_rom_mt = MRB_MT_ROM_TAB(string_ext_rom_entries);
void mrb_mruby_string_ext_gem_init(mrb_state *mrb)
@@ -389,7 +390,7 @@ void mrb_mruby_foo_gem_init(mrb_state *mrb) {
### After
```c
static mrb_mt_entry foo_rom_entries[] = {
static const mrb_mt_entry foo_rom_entries[] = {
MRB_MT_ENTRY(foo_bar, MRB_SYM(bar), MRB_MT_FUNC),
MRB_MT_ENTRY(foo_baz, MRB_SYM(baz), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(foo_eq, MRB_OPSYM(eq), MRB_MT_FUNC),
+5 -3
View File
@@ -59,11 +59,13 @@ typedef struct mrb_mt_tbl {
#define MRB_MT_ENTRY(fn, sym, flags) \
{ { .func = (fn) }, (sym), (flags) }
/* ROM table initializer from entries array (auto-computes size) */
/* ROM table initializer from const entries array (auto-computes size).
Casts away const because mrb_mt_tbl.ptr is shared with mutable layers;
the MRB_MT_READONLY_BIT prevents writes. */
#define MRB_MT_ROM_TAB(entries) { \
(int)(sizeof(entries)/sizeof(entries[0])), \
(int)(sizeof(entries)/sizeof(entries[0])), \
(entries), NULL }
(int)(sizeof(entries)/sizeof(entries[0])) | MRB_MT_READONLY_BIT, \
(mrb_mt_entry*)(entries), NULL }
/* "removed" tombstone: MRB_MT_FUNC flag set with NULL function pointer.
This combination never occurs naturally (C functions are never NULL).
+1 -1
View File
@@ -1537,7 +1537,7 @@ ary_combination_next(mrb_state *mrb, mrb_value self)
}
/* ---------------------------*/
static mrb_mt_entry array_ext_rom_entries[] = {
static const mrb_mt_entry array_ext_rom_entries[] = {
MRB_MT_ENTRY(ary_assoc, MRB_SYM(assoc), MRB_MT_FUNC),
MRB_MT_ENTRY(ary_at, MRB_SYM(at), MRB_MT_FUNC),
MRB_MT_ENTRY(ary_rassoc, MRB_SYM(rassoc), MRB_MT_FUNC),
+2 -2
View File
@@ -335,7 +335,7 @@ mrb_mod_cmp(mrb_state *mrb, mrb_value self)
}
/* ---------------------------*/
static mrb_mt_entry mod_ext_rom_entries[] = {
static const mrb_mt_entry mod_ext_rom_entries[] = {
MRB_MT_ENTRY(mrb_mod_lt, MRB_OPSYM(lt), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_mod_le, MRB_OPSYM(le), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_mod_cmp, MRB_OPSYM(cmp), MRB_MT_FUNC),
@@ -348,7 +348,7 @@ static mrb_mt_entry mod_ext_rom_entries[] = {
};
static mrb_mt_tbl mod_ext_rom_mt = MRB_MT_ROM_TAB(mod_ext_rom_entries);
static mrb_mt_entry cls_ext_rom_entries[] = {
static const mrb_mt_entry cls_ext_rom_entries[] = {
MRB_MT_ENTRY(class_attached_object, MRB_SYM(attached_object), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(class_subclasses, MRB_SYM(subclasses), MRB_MT_FUNC|MRB_MT_NOARG),
};
+3 -3
View File
@@ -558,7 +558,7 @@ complex_pow(mrb_state *mrb, mrb_value self)
}
/* ---------------------------*/
static mrb_mt_entry complex_rom_entries[] = {
static const mrb_mt_entry complex_rom_entries[] = {
MRB_MT_ENTRY(complex_real, MRB_SYM(real), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(complex_imaginary, MRB_SYM(imaginary), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_complex_to_f, MRB_SYM(to_f), MRB_MT_FUNC|MRB_MT_NOARG),
@@ -575,12 +575,12 @@ static mrb_mt_entry complex_rom_entries[] = {
};
static mrb_mt_tbl complex_rom_mt = MRB_MT_ROM_TAB(complex_rom_entries);
static mrb_mt_entry nil_to_c_rom_entries[] = {
static const mrb_mt_entry nil_to_c_rom_entries[] = {
MRB_MT_ENTRY(nil_to_c, MRB_SYM(to_c), MRB_MT_FUNC|MRB_MT_NOARG),
};
static mrb_mt_tbl nil_to_c_rom_mt = MRB_MT_ROM_TAB(nil_to_c_rom_entries);
static mrb_mt_entry kernel_complex_rom_entries[] = {
static const mrb_mt_entry kernel_complex_rom_entries[] = {
MRB_MT_ENTRY(complex_s_rect, MRB_SYM(Complex), MRB_MT_FUNC|MRB_MT_PRIVATE),
};
static mrb_mt_tbl kernel_complex_rom_mt = MRB_MT_ROM_TAB(kernel_complex_rom_entries);
+1 -1
View File
@@ -367,7 +367,7 @@ hash_merge(mrb_state *mrb, mrb_value hash)
return hash;
}
static mrb_mt_entry hash_ext_rom_entries[] = {
static const mrb_mt_entry hash_ext_rom_entries[] = {
MRB_MT_ENTRY(hash_values_at, MRB_SYM(values_at), MRB_MT_FUNC),
MRB_MT_ENTRY(hash_slice, MRB_SYM(slice), MRB_MT_FUNC),
MRB_MT_ENTRY(hash_slice_bang, MRB_SYM_B(slice), MRB_MT_FUNC),
+1 -1
View File
@@ -1122,7 +1122,7 @@ mrb_file_join(mrb_state *mrb, mrb_value klass)
}
/* ---------------------------*/
static mrb_mt_entry file_rom_entries[] = {
static const mrb_mt_entry file_rom_entries[] = {
MRB_MT_ENTRY(mrb_file_flock, MRB_SYM(flock), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_file_atime, MRB_SYM(_atime), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_file_ctime, MRB_SYM(_ctime), MRB_MT_FUNC|MRB_MT_NOARG),
+1 -1
View File
@@ -2197,7 +2197,7 @@ io_flush(mrb_state *mrb, mrb_value io)
}
/* ---------------------------*/
static mrb_mt_entry io_rom_entries[] = {
static const mrb_mt_entry io_rom_entries[] = {
MRB_MT_ENTRY(io_init, MRB_SYM(initialize), MRB_MT_FUNC),
MRB_MT_ENTRY(io_init_copy, MRB_SYM(initialize_copy), MRB_MT_FUNC|MRB_MT_PRIVATE),
MRB_MT_ENTRY(io_isatty, MRB_SYM(isatty), MRB_MT_FUNC|MRB_MT_NOARG),
+1 -1
View File
@@ -288,7 +288,7 @@ mrb_f_hash(mrb_state *mrb, mrb_value self)
return arg;
}
static mrb_mt_entry kernel_ext_rom_entries[] = {
static const mrb_mt_entry kernel_ext_rom_entries[] = {
MRB_MT_ENTRY(mrb_f_raise, MRB_SYM(fail), MRB_MT_FUNC|MRB_MT_PRIVATE),
MRB_MT_ENTRY(mrb_f_caller, MRB_SYM(caller), MRB_MT_FUNC|MRB_MT_PRIVATE),
MRB_MT_ENTRY(mrb_f_method, MRB_SYM(__method__), MRB_MT_FUNC|MRB_MT_NOARG|MRB_MT_PRIVATE),
+2 -2
View File
@@ -690,7 +690,7 @@ mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod)
}
/* ---------------------------*/
static mrb_mt_entry metaprog_krn_rom_entries[] = {
static const mrb_mt_entry metaprog_krn_rom_entries[] = {
MRB_MT_ENTRY(mrb_f_global_variables, MRB_SYM(global_variables), MRB_MT_FUNC|MRB_MT_NOARG|MRB_MT_PRIVATE),
MRB_MT_ENTRY(mrb_local_variables, MRB_SYM(local_variables), MRB_MT_FUNC|MRB_MT_NOARG|MRB_MT_PRIVATE),
MRB_MT_ENTRY(mrb_singleton_class, MRB_SYM(singleton_class), MRB_MT_FUNC|MRB_MT_NOARG),
@@ -709,7 +709,7 @@ static mrb_mt_entry metaprog_krn_rom_entries[] = {
};
static mrb_mt_tbl metaprog_krn_rom_mt = MRB_MT_ROM_TAB(metaprog_krn_rom_entries);
static mrb_mt_entry metaprog_mod_rom_entries[] = {
static const mrb_mt_entry metaprog_mod_rom_entries[] = {
MRB_MT_ENTRY(mrb_mod_class_variables, MRB_SYM(class_variables), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_mod_remove_cvar, MRB_SYM(remove_class_variable), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_mod_cvar_defined, MRB_SYM_Q(class_variable_defined), MRB_MT_FUNC),
+4 -4
View File
@@ -832,7 +832,7 @@ method_name(mrb_state *mrb, mrb_value self)
}
/* ---------------------------*/
static mrb_mt_entry method_ubm_rom_entries[] = {
static const mrb_mt_entry method_ubm_rom_entries[] = {
MRB_MT_ENTRY(unbound_method_bind, MRB_SYM(bind), MRB_MT_FUNC),
MRB_MT_ENTRY(method_super_method, MRB_SYM(super_method), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(method_eql, MRB_OPSYM(eq), MRB_MT_FUNC),
@@ -848,7 +848,7 @@ static mrb_mt_entry method_ubm_rom_entries[] = {
};
static mrb_mt_tbl method_ubm_rom_mt = MRB_MT_ROM_TAB(method_ubm_rom_entries);
static mrb_mt_entry method_mtd_rom_entries[] = {
static const mrb_mt_entry method_mtd_rom_entries[] = {
MRB_MT_ENTRY(method_eql, MRB_OPSYM(eq), MRB_MT_FUNC),
MRB_MT_ENTRY(method_eql, MRB_SYM_Q(eql), MRB_MT_FUNC),
MRB_MT_ENTRY(method_to_s, MRB_SYM(to_s), MRB_MT_FUNC|MRB_MT_NOARG),
@@ -866,13 +866,13 @@ static mrb_mt_entry method_mtd_rom_entries[] = {
};
static mrb_mt_tbl method_mtd_rom_mt = MRB_MT_ROM_TAB(method_mtd_rom_entries);
static mrb_mt_entry method_krn_rom_entries[] = {
static const mrb_mt_entry method_krn_rom_entries[] = {
MRB_MT_ENTRY(mrb_kernel_method, MRB_SYM(method), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_kernel_singleton_method, MRB_SYM(singleton_method), MRB_MT_FUNC),
};
static mrb_mt_tbl method_krn_rom_mt = MRB_MT_ROM_TAB(method_krn_rom_entries);
static mrb_mt_entry method_mod_rom_entries[] = {
static const mrb_mt_entry method_mod_rom_entries[] = {
MRB_MT_ENTRY(mrb_module_instance_method, MRB_SYM(instance_method), MRB_MT_FUNC),
};
static mrb_mt_tbl method_mod_rom_mt = MRB_MT_ROM_TAB(method_mod_rom_entries);
+1 -1
View File
@@ -480,7 +480,7 @@ int_sqrt(mrb_state *mrb, mrb_value self)
}
}
static mrb_mt_entry integer_ext_rom_entries[] = {
static const mrb_mt_entry integer_ext_rom_entries[] = {
MRB_MT_ENTRY(int_remainder, MRB_SYM(remainder), MRB_MT_FUNC),
MRB_MT_ENTRY(int_powm, MRB_SYM(pow), MRB_MT_FUNC),
MRB_MT_ENTRY(int_digits, MRB_SYM(digits), MRB_MT_FUNC),
+3 -3
View File
@@ -97,19 +97,19 @@ obj_instance_exec(mrb_state *mrb, mrb_value self)
return mrb_object_exec(mrb, self, mrb_singleton_class_ptr(mrb, self));
}
static mrb_mt_entry nil_ext_rom_entries[] = {
static const mrb_mt_entry nil_ext_rom_entries[] = {
MRB_MT_ENTRY(nil_to_a, MRB_SYM(to_a), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(nil_to_h, MRB_SYM(to_h), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(nil_to_i, MRB_SYM(to_i), MRB_MT_FUNC|MRB_MT_NOARG),
};
static mrb_mt_tbl nil_ext_rom_mt = MRB_MT_ROM_TAB(nil_ext_rom_entries);
static mrb_mt_entry kernel_ext_rom_entries[] = {
static const mrb_mt_entry kernel_ext_rom_entries[] = {
MRB_MT_ENTRY(mrb_obj_itself, MRB_SYM(itself), MRB_MT_FUNC|MRB_MT_NOARG),
};
static mrb_mt_tbl kernel_ext_rom_mt = MRB_MT_ROM_TAB(kernel_ext_rom_entries);
static mrb_mt_entry bob_ext_rom_entries[] = {
static const mrb_mt_entry bob_ext_rom_entries[] = {
MRB_MT_ENTRY(obj_instance_exec, MRB_SYM(instance_exec), MRB_MT_FUNC),
};
static mrb_mt_tbl bob_ext_rom_mt = MRB_MT_ROM_TAB(bob_ext_rom_entries);
+2 -2
View File
@@ -244,7 +244,7 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self)
}
/* ---------------------------*/
static mrb_mt_entry proc_ext_rom_entries[] = {
static const mrb_mt_entry proc_ext_rom_entries[] = {
MRB_MT_ENTRY(proc_inspect, MRB_SYM(inspect), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(proc_lambda_p, MRB_SYM_Q(lambda), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_proc_parameters, MRB_SYM(parameters), MRB_MT_FUNC|MRB_MT_NOARG),
@@ -253,7 +253,7 @@ static mrb_mt_entry proc_ext_rom_entries[] = {
};
static mrb_mt_tbl proc_ext_rom_mt = MRB_MT_ROM_TAB(proc_ext_rom_entries);
static mrb_mt_entry kernel_ext_rom_entries[] = {
static const mrb_mt_entry kernel_ext_rom_entries[] = {
MRB_MT_ENTRY(kernel_proc, MRB_SYM(proc), MRB_MT_FUNC|MRB_MT_PRIVATE),
};
static mrb_mt_tbl kernel_ext_rom_mt = MRB_MT_ROM_TAB(kernel_ext_rom_entries);
+3 -3
View File
@@ -568,13 +568,13 @@ random_f_bytes(mrb_state *mrb, mrb_value self)
}
static mrb_mt_entry kernel_rand_rom_entries[] = {
static const mrb_mt_entry kernel_rand_rom_entries[] = {
MRB_MT_ENTRY(random_f_rand, MRB_SYM(rand), MRB_MT_FUNC|MRB_MT_PRIVATE),
MRB_MT_ENTRY(random_f_srand, MRB_SYM(srand), MRB_MT_FUNC|MRB_MT_PRIVATE),
};
static mrb_mt_tbl kernel_rand_rom_mt = MRB_MT_ROM_TAB(kernel_rand_rom_entries);
static mrb_mt_entry random_rom_entries[] = {
static const mrb_mt_entry random_rom_entries[] = {
MRB_MT_ENTRY(random_m_init, MRB_SYM(initialize), MRB_MT_FUNC),
MRB_MT_ENTRY(random_m_rand, MRB_SYM(rand), MRB_MT_FUNC),
MRB_MT_ENTRY(random_m_srand, MRB_SYM(srand), MRB_MT_FUNC),
@@ -582,7 +582,7 @@ static mrb_mt_entry random_rom_entries[] = {
};
static mrb_mt_tbl random_rom_mt = MRB_MT_ROM_TAB(random_rom_entries);
static mrb_mt_entry array_rand_rom_entries[] = {
static const mrb_mt_entry array_rand_rom_entries[] = {
MRB_MT_ENTRY(mrb_ary_shuffle, MRB_SYM(shuffle), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_ary_shuffle_bang, MRB_SYM_B(shuffle), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_ary_sample, MRB_SYM(sample), MRB_MT_FUNC),
+1 -1
View File
@@ -216,7 +216,7 @@ range_empty_p(mrb_state *mrb, mrb_value range)
return mrb_bool_value(comp == -2 || comp > 0 || (comp == 0 && excl));
}
static mrb_mt_entry range_ext_rom_entries[] = {
static const mrb_mt_entry range_ext_rom_entries[] = {
MRB_MT_ENTRY(range_cover, MRB_SYM_Q(cover), MRB_MT_FUNC),
MRB_MT_ENTRY(range_size, MRB_SYM(size), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(range_empty_p, MRB_SYM_Q(__empty_range), MRB_MT_FUNC),
+4 -4
View File
@@ -1228,7 +1228,7 @@ rational_hash(mrb_state *mrb, mrb_value rat)
}
/* ---------------------------*/
static mrb_mt_entry rational_rom_entries[] = {
static const mrb_mt_entry rational_rom_entries[] = {
MRB_MT_ENTRY(rational_numerator, MRB_SYM(numerator), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(rational_denominator, MRB_SYM(denominator), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_rational_to_i, MRB_SYM(to_i), MRB_MT_FUNC|MRB_MT_NOARG),
@@ -1246,17 +1246,17 @@ static mrb_mt_entry rational_rom_entries[] = {
};
static mrb_mt_tbl rational_rom_mt = MRB_MT_ROM_TAB(rational_rom_entries);
static mrb_mt_entry integer_to_r_rom_entries[] = {
static const mrb_mt_entry integer_to_r_rom_entries[] = {
MRB_MT_ENTRY(int_to_r, MRB_SYM(to_r), MRB_MT_FUNC|MRB_MT_NOARG),
};
static mrb_mt_tbl integer_to_r_rom_mt = MRB_MT_ROM_TAB(integer_to_r_rom_entries);
static mrb_mt_entry nil_to_r_rom_entries[] = {
static const mrb_mt_entry nil_to_r_rom_entries[] = {
MRB_MT_ENTRY(nil_to_r, MRB_SYM(to_r), MRB_MT_FUNC|MRB_MT_NOARG),
};
static mrb_mt_tbl nil_to_r_rom_mt = MRB_MT_ROM_TAB(nil_to_r_rom_entries);
static mrb_mt_entry kernel_rational_rom_entries[] = {
static const mrb_mt_entry kernel_rational_rom_entries[] = {
MRB_MT_ENTRY(rational_m, MRB_SYM(Rational), MRB_MT_FUNC|MRB_MT_PRIVATE),
};
static mrb_mt_tbl kernel_rational_rom_mt = MRB_MT_ROM_TAB(kernel_rational_rom_entries);
+1 -1
View File
@@ -1464,7 +1464,7 @@ set_s_create(mrb_state *mrb, mrb_value klass)
return set;
}
static mrb_mt_entry set_rom_entries[] = {
static const mrb_mt_entry set_rom_entries[] = {
MRB_MT_ENTRY(set_size, MRB_SYM(size), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(set_size, MRB_SYM(length), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(set_empty_p, MRB_SYM_Q(empty), MRB_MT_FUNC|MRB_MT_NOARG),
+4 -4
View File
@@ -1271,13 +1271,13 @@ mrb_win32_basicsocket_syswrite(mrb_state *mrb, mrb_value self)
#endif
/* ---------------------------*/
static mrb_mt_entry addrinfo_rom_entries[] = {
static const mrb_mt_entry addrinfo_rom_entries[] = {
MRB_MT_ENTRY(mrb_addrinfo_getnameinfo, MRB_SYM(getnameinfo), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_addrinfo_unix_path, MRB_SYM(unix_path), MRB_MT_FUNC|MRB_MT_NOARG),
};
static mrb_mt_tbl addrinfo_rom_mt = MRB_MT_ROM_TAB(addrinfo_rom_entries);
static mrb_mt_entry basicsocket_rom_entries[] = {
static const mrb_mt_entry basicsocket_rom_entries[] = {
MRB_MT_ENTRY(mrb_basicsocket_recvfrom, MRB_SYM(_recvfrom), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_basicsocket_setnonblock, MRB_SYM(_setnonblock), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_basicsocket_getpeereid, MRB_SYM(getpeereid), MRB_MT_FUNC|MRB_MT_NOARG),
@@ -1292,12 +1292,12 @@ static mrb_mt_entry basicsocket_rom_entries[] = {
};
static mrb_mt_tbl basicsocket_rom_mt = MRB_MT_ROM_TAB(basicsocket_rom_entries);
static mrb_mt_entry ipsocket_rom_entries[] = {
static const mrb_mt_entry ipsocket_rom_entries[] = {
MRB_MT_ENTRY(mrb_ipsocket_recvfrom, MRB_SYM(recvfrom), MRB_MT_FUNC),
};
static mrb_mt_tbl ipsocket_rom_mt = MRB_MT_ROM_TAB(ipsocket_rom_entries);
static mrb_mt_entry socket_option_rom_entries[] = {
static const mrb_mt_entry socket_option_rom_entries[] = {
MRB_MT_ENTRY(socket_option_init, MRB_SYM(initialize), MRB_MT_FUNC),
MRB_MT_ENTRY(socket_option_inspect, MRB_SYM(inspect), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(socket_option_family, MRB_SYM(family), MRB_MT_FUNC|MRB_MT_NOARG),
+2 -2
View File
@@ -2219,7 +2219,7 @@ str_prepend(mrb_state *mrb, mrb_value self)
}
/* ---------------------------*/
static mrb_mt_entry string_ext_rom_entries[] = {
static const mrb_mt_entry string_ext_rom_entries[] = {
MRB_MT_ENTRY(mrb_str_dump, MRB_SYM(dump), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(str_swapcase_bang, MRB_SYM_B(swapcase), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_str_slice_bang, MRB_SYM_B(slice), MRB_MT_FUNC),
@@ -2276,7 +2276,7 @@ static mrb_mt_entry string_ext_rom_entries[] = {
};
static mrb_mt_tbl string_ext_rom_mt = MRB_MT_ROM_TAB(string_ext_rom_entries);
static mrb_mt_entry integer_chr_rom_entries[] = {
static const mrb_mt_entry integer_chr_rom_entries[] = {
MRB_MT_ENTRY(int_chr, MRB_SYM(chr), MRB_MT_FUNC),
};
static mrb_mt_tbl integer_chr_rom_mt = MRB_MT_ROM_TAB(integer_chr_rom_entries);
+1 -1
View File
@@ -776,7 +776,7 @@ mrb_struct_to_s(mrb_state *mrb, mrb_value self)
* `Symbol` (such as `:name`).
*/
/* ---------------------------*/
static mrb_mt_entry struct_rom_entries[] = {
static const mrb_mt_entry struct_rom_entries[] = {
MRB_MT_ENTRY(mrb_struct_equal, MRB_OPSYM(eq), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_struct_aref, MRB_OPSYM(aref), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_struct_aset, MRB_OPSYM(aset), MRB_MT_FUNC),
+1 -1
View File
@@ -58,7 +58,7 @@ mrb_sym_length(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(len);
}
static mrb_mt_entry symbol_ext_rom_entries[] = {
static const mrb_mt_entry symbol_ext_rom_entries[] = {
MRB_MT_ENTRY(mrb_sym_length, MRB_SYM(length), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_sym_length, MRB_SYM(size), MRB_MT_FUNC|MRB_MT_NOARG),
};
+1 -1
View File
@@ -1664,7 +1664,7 @@ time_utc_offset(mrb_state *mrb, mrb_value self)
}
/* ---------------------------*/
static mrb_mt_entry time_rom_entries[] = {
static const mrb_mt_entry time_rom_entries[] = {
MRB_MT_ENTRY(time_hash, MRB_SYM(hash), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(time_eq, MRB_SYM_Q(eql), MRB_MT_FUNC),
MRB_MT_ENTRY(time_eq, MRB_OPSYM(eq), MRB_MT_FUNC),
+1 -1
View File
@@ -2249,7 +2249,7 @@ mrb_ary_to_a(mrb_state *mrb, mrb_value self)
}
/* ---------------------------*/
static mrb_mt_entry array_rom_entries[] = {
static const mrb_mt_entry array_rom_entries[] = {
MRB_MT_ENTRY(mrb_ary_plus, MRB_OPSYM(add), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_ary_times, MRB_OPSYM(mul), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_ary_push_m, MRB_OPSYM(lshift), MRB_MT_FUNC),
+45 -105
View File
@@ -53,85 +53,48 @@ mt_new(mrb_state *mrb)
return t;
}
/* Branch-free binary search helper for method table entries */
static inline int
mt_bsearch_idx(mrb_mt_entry *entries, int size, mrb_sym target)
{
if (size == 0) return 0;
int n = size;
mrb_mt_entry *p = entries;
/* While more than one element remains, halve the range each iteration */
while (n > 1) {
int half = n >> 1;
MRB_MEM_PREFETCH(p + (half >> 1));
MRB_MEM_PREFETCH(p + half + (half >> 1));
/*
* Update pointer p without a branch:
* If key < target, move p forward by half; otherwise keep p unchanged.
* Compiler will emit a CMOV or equivalent.
*/
p = (p[half].key < target) ? p + half : p;
n -= half;
}
/* Final adjustment: if the remaining element is still less than target, advance by one */
int offset = (p->key < target);
return (int)(p - entries) + offset;
}
/* Inserts or updates an entry in the method table */
/* Inserts or updates an entry in the method table (linear scan) */
static void
mt_put(mrb_state *mrb, mrb_mt_tbl *t, mrb_sym sym, uint32_t flags, union mrb_mt_ptr ptrval)
{
/* Ensure there is capacity */
mrb_mt_entry *entries = t->ptr;
/* Linear scan for existing key */
for (int i = 0; i < t->size; i++) {
if (entries[i].key == sym) {
entries[i].flags = flags;
entries[i].val = ptrval;
return;
}
}
/* Not found — append to end */
if (MT_ALLOC(t) == 0) {
mt_grow(mrb, t, 8);
}
else if (t->size == MT_ALLOC(t)) {
mt_grow(mrb, t, MT_ALLOC(t) * 2);
}
mrb_mt_entry *entries = t->ptr;
/*
* If table is empty, insertion index is 0.
* Otherwise, find the insertion/update position branch-free.
*/
int lo = mt_bsearch_idx(entries, t->size, sym);
/* If the key already exists, update its value and return */
if (lo < t->size && entries[lo].key == sym) {
entries[lo].flags = flags;
entries[lo].val = ptrval;
return;
}
/* Shift existing entries to make room at index lo */
if (t->size > lo) {
memmove(&entries[lo+1], &entries[lo],
(t->size - lo) * sizeof(mrb_mt_entry));
}
/* Insert the new entry */
entries[lo].key = sym;
entries[lo].flags = flags;
entries[lo].val = ptrval;
entries = t->ptr;
entries[t->size].key = sym;
entries[t->size].flags = flags;
entries[t->size].val = ptrval;
t->size++;
}
/* Retrieves a value from the method table (walks chain).
/* Retrieves a value from the method table (walks chain, linear scan).
Returns TRUE if found, FALSE if not found.
On success, *pp and *fp are set. */
static mrb_bool
mt_get(mrb_state *mrb, mrb_mt_tbl *t, mrb_sym sym, union mrb_mt_ptr *pp, uint32_t *fp)
{
while (t) {
if (t->size > 0) {
mrb_mt_entry *entries = t->ptr;
int lo = mt_bsearch_idx(entries, t->size, sym);
if (lo < t->size && entries[lo].key == sym) {
if (MRB_MT_REMOVED_P(entries[lo])) return FALSE; /* removed tombstone */
*pp = entries[lo].val;
*fp = entries[lo].flags;
mrb_mt_entry *entries = t->ptr;
for (int i = 0; i < t->size; i++) {
if (entries[i].key == sym) {
if (MRB_MT_REMOVED_P(entries[i])) return FALSE;
*pp = entries[i].val;
*fp = entries[i].flags;
return TRUE;
}
}
@@ -140,27 +103,22 @@ mt_get(mrb_state *mrb, mrb_mt_tbl *t, mrb_sym sym, union mrb_mt_ptr *pp, uint32_
return FALSE;
}
/* Deletes an entry from the method table */
/* Deletes an entry from the method table (swap with last) */
static mrb_bool
mt_del(mrb_state *mrb, mrb_mt_tbl *t, mrb_sym sym)
{
/* Return FALSE if table is null or empty */
if (!t || t->size == 0) return FALSE;
mrb_mt_entry *entries = t->ptr;
/* Find the index of `sym` in a branch-free manner */
int lo = mt_bsearch_idx(entries, t->size, sym);
/* If the key exists at index lo, remove it by shifting left */
if (lo < t->size && entries[lo].key == sym) {
memmove(&entries[lo], &entries[lo + 1],
(t->size - lo - 1) * sizeof(mrb_mt_entry));
t->size--;
return TRUE;
for (int i = 0; i < t->size; i++) {
if (entries[i].key == sym) {
t->size--;
if (i < t->size) {
entries[i] = entries[t->size];
}
return TRUE;
}
}
/* Key not found */
return FALSE;
}
@@ -169,10 +127,9 @@ static mrb_bool
mt_chain_has(mrb_mt_tbl *t, mrb_sym sym)
{
while (t) {
if (t->size > 0) {
mrb_mt_entry *entries = t->ptr;
int lo = mt_bsearch_idx(entries, t->size, sym);
if (lo < t->size && entries[lo].key == sym) return TRUE;
mrb_mt_entry *entries = t->ptr;
for (int i = 0; i < t->size; i++) {
if (entries[i].key == sym) return TRUE;
}
t = t->next;
}
@@ -214,29 +171,11 @@ mt_free(mrb_state *mrb, mrb_mt_tbl *t)
}
}
/* Sorts entries array by key symbol (insertion sort) */
static void
mt_sort(mrb_mt_entry *entries, int n)
{
for (int i = 1; i < n; i++) {
mrb_mt_entry e = entries[i];
mrb_sym sym = e.key;
int j = i;
while (j > 0 && entries[j-1].key > sym) {
entries[j] = entries[j-1];
j--;
}
entries[j] = e;
}
}
/* Sorts a static ROM table, sets readonly flag, and pushes it to the class */
/* Pushes a ROM table layer onto the class's method table chain.
The readonly flag is already set by MRB_MT_ROM_TAB(). */
void
mrb_mt_init_rom(struct RClass *c, mrb_mt_tbl *rom)
{
mt_sort(rom->ptr, rom->size);
rom->alloc = rom->size | MRB_MT_READONLY_BIT;
/* push ROM layer */
mrb_mt_tbl *t = c->mt;
if (!t || mt_readonly_p(t)) {
@@ -290,13 +229,14 @@ mrb_mt_foreach(mrb_state *mrb, struct RClass *c, mrb_mt_foreach_func *fn, void *
if (layer != t) {
mrb_bool shadowed = FALSE;
for (mrb_mt_tbl *upper = t; upper != layer; upper = upper->next) {
if (upper->size > 0) {
int lo = mt_bsearch_idx(upper->ptr, upper->size, sym);
if (lo < upper->size && upper->ptr[lo].key == sym) {
mrb_mt_entry *up = upper->ptr;
for (int j = 0; j < upper->size; j++) {
if (up[j].key == sym) {
shadowed = TRUE;
break;
}
}
if (shadowed) break;
}
if (shadowed) continue;
}
@@ -4319,7 +4259,7 @@ static const struct RProc neq_proc = {
};
/* ---------------------------*/
static mrb_mt_entry bob_rom_entries[] = {
static const mrb_mt_entry bob_rom_entries[] = {
MRB_MT_ENTRY(mrb_obj_equal_m, MRB_OPSYM(eq), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_bob_not, MRB_OPSYM(not), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_obj_id_m, MRB_SYM(__id__), MRB_MT_FUNC|MRB_MT_NOARG),
@@ -4334,7 +4274,7 @@ static mrb_mt_entry bob_rom_entries[] = {
};
static mrb_mt_tbl bob_rom_mt = MRB_MT_ROM_TAB(bob_rom_entries);
static mrb_mt_entry cls_rom_entries[] = {
static const mrb_mt_entry cls_rom_entries[] = {
MRB_MT_ENTRY(mrb_instance_alloc, MRB_SYM(allocate), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_do_nothing, MRB_SYM(inherited), MRB_MT_FUNC|MRB_MT_PRIVATE),
MRB_MT_ENTRY(mrb_class_initialize, MRB_SYM(initialize), MRB_MT_FUNC|MRB_MT_PRIVATE),
@@ -4342,7 +4282,7 @@ static mrb_mt_entry cls_rom_entries[] = {
};
static mrb_mt_tbl cls_rom_mt = MRB_MT_ROM_TAB(cls_rom_entries);
static mrb_mt_entry mod_rom_entries[] = {
static const mrb_mt_entry mod_rom_entries[] = {
MRB_MT_ENTRY(mrb_mod_eqq, MRB_OPSYM(eqq), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_mod_alias, MRB_SYM(alias_method), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_mod_ancestors, MRB_SYM(ancestors), MRB_MT_FUNC|MRB_MT_NOARG),
+1 -1
View File
@@ -892,7 +892,7 @@ mrb_check_error(mrb_state *mrb)
}
/* ---------------------------*/
static mrb_mt_entry exception_rom_entries[] = {
static const mrb_mt_entry exception_rom_entries[] = {
MRB_MT_ENTRY(exc_exception, MRB_SYM(exception), MRB_MT_FUNC),
MRB_MT_ENTRY(exc_initialize, MRB_SYM(initialize), MRB_MT_FUNC|MRB_MT_PRIVATE),
MRB_MT_ENTRY(exc_to_s, MRB_SYM(to_s), MRB_MT_FUNC|MRB_MT_NOARG),
+1 -1
View File
@@ -2303,7 +2303,7 @@ mrb_hash_eql(mrb_state *mrb, mrb_value hash)
}
/* ---------------------------*/
static mrb_mt_entry hash_rom_entries[] = {
static const mrb_mt_entry hash_rom_entries[] = {
MRB_MT_ENTRY(mrb_hash_equal, MRB_OPSYM(eq), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_hash_aget, MRB_OPSYM(aref), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_hash_aset, MRB_OPSYM(aset), MRB_MT_FUNC),
+1 -1
View File
@@ -666,7 +666,7 @@ mrb_p_m(mrb_state *mrb, mrb_value self)
#endif
/* ---------------------------*/
static mrb_mt_entry kernel_rom_entries[] = {
static const mrb_mt_entry kernel_rom_entries[] = {
MRB_MT_ENTRY(mrb_eqq_m, MRB_OPSYM(eqq), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_cmp_m, MRB_OPSYM(cmp), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_f_block_given_p_m, MRB_SYM_Q(block_given), MRB_MT_FUNC|MRB_MT_NOARG|MRB_MT_PRIVATE),
+3 -3
View File
@@ -2299,14 +2299,14 @@ flo_hash(mrb_state *mrb, mrb_value flo)
#endif
/* ------------------------------------------------------------------------*/
static mrb_mt_entry numeric_rom_entries[] = {
static const mrb_mt_entry numeric_rom_entries[] = {
MRB_MT_ENTRY(num_finite_p, MRB_SYM_Q(finite), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(num_infinite_p, MRB_SYM_Q(infinite), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(num_eql, MRB_SYM_Q(eql), MRB_MT_FUNC),
};
static mrb_mt_tbl numeric_rom_mt = MRB_MT_ROM_TAB(numeric_rom_entries);
static mrb_mt_entry integer_rom_entries[] = {
static const mrb_mt_entry integer_rom_entries[] = {
MRB_MT_ENTRY(int_pow, MRB_OPSYM(pow), MRB_MT_FUNC),
MRB_MT_ENTRY(num_cmp, MRB_OPSYM(cmp), MRB_MT_FUNC),
MRB_MT_ENTRY(num_lt, MRB_OPSYM(lt), MRB_MT_FUNC),
@@ -2342,7 +2342,7 @@ static mrb_mt_entry integer_rom_entries[] = {
static mrb_mt_tbl integer_rom_mt = MRB_MT_ROM_TAB(integer_rom_entries);
#ifndef MRB_NO_FLOAT
static mrb_mt_entry float_rom_entries[] = {
static const mrb_mt_entry float_rom_entries[] = {
MRB_MT_ENTRY(flo_pow, MRB_OPSYM(pow), MRB_MT_FUNC),
MRB_MT_ENTRY(flo_div, MRB_OPSYM(div), MRB_MT_FUNC),
MRB_MT_ENTRY(flo_div, MRB_SYM(quo), MRB_MT_FUNC),
+3 -3
View File
@@ -322,7 +322,7 @@ false_to_s(mrb_state *mrb, mrb_value obj)
}
/* ---------------------------*/
static mrb_mt_entry nil_rom_entries[] = {
static const mrb_mt_entry nil_rom_entries[] = {
MRB_MT_ENTRY(false_and, MRB_OPSYM(and), MRB_MT_FUNC),
MRB_MT_ENTRY(false_or, MRB_OPSYM(or), MRB_MT_FUNC),
MRB_MT_ENTRY(false_xor, MRB_OPSYM(xor), MRB_MT_FUNC),
@@ -332,7 +332,7 @@ static mrb_mt_entry nil_rom_entries[] = {
};
static mrb_mt_tbl nil_rom_mt = MRB_MT_ROM_TAB(nil_rom_entries);
static mrb_mt_entry true_rom_entries[] = {
static const mrb_mt_entry true_rom_entries[] = {
MRB_MT_ENTRY(true_and, MRB_OPSYM(and), MRB_MT_FUNC),
MRB_MT_ENTRY(true_or, MRB_OPSYM(or), MRB_MT_FUNC),
MRB_MT_ENTRY(true_xor, MRB_OPSYM(xor), MRB_MT_FUNC),
@@ -341,7 +341,7 @@ static mrb_mt_entry true_rom_entries[] = {
};
static mrb_mt_tbl true_rom_mt = MRB_MT_ROM_TAB(true_rom_entries);
static mrb_mt_entry false_rom_entries[] = {
static const mrb_mt_entry false_rom_entries[] = {
MRB_MT_ENTRY(false_and, MRB_OPSYM(and), MRB_MT_FUNC),
MRB_MT_ENTRY(false_or, MRB_OPSYM(or), MRB_MT_FUNC),
MRB_MT_ENTRY(false_xor, MRB_OPSYM(xor), MRB_MT_FUNC),
+1 -1
View File
@@ -545,7 +545,7 @@ mrb_proc_merge_lvar(mrb_state *mrb, mrb_irep *irep, struct REnv *env, int num, c
}
/* ---------------------------*/
static mrb_mt_entry proc_rom_entries[] = {
static const mrb_mt_entry proc_rom_entries[] = {
MRB_MT_ENTRY(mrb_proc_init_copy, MRB_SYM(initialize_copy), MRB_MT_FUNC|MRB_MT_PRIVATE),
MRB_MT_ENTRY(proc_arity, MRB_SYM(arity), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(proc_eql, MRB_OPSYM(eq), MRB_MT_FUNC),
+1 -1
View File
@@ -566,7 +566,7 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp,
}
/* ---------------------------*/
static mrb_mt_entry range_rom_entries[] = {
static const mrb_mt_entry range_rom_entries[] = {
MRB_MT_ENTRY(range_beg, MRB_SYM(begin), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(range_end, MRB_SYM(end), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(range_eq, MRB_OPSYM(eq), MRB_MT_FUNC),
+1 -1
View File
@@ -3508,7 +3508,7 @@ mrb_encoding(mrb_state *mrb, mrb_value self)
}
/* ---------------------------*/
static mrb_mt_entry string_rom_entries[] = {
static const mrb_mt_entry string_rom_entries[] = {
MRB_MT_ENTRY(mrb_str_bytesize, MRB_SYM(bytesize), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_str_cmp_m, MRB_OPSYM(cmp), MRB_MT_FUNC),
MRB_MT_ENTRY(mrb_str_equal_m, MRB_OPSYM(eq), MRB_MT_FUNC),
+1 -1
View File
@@ -1001,7 +1001,7 @@ sym_cmp(mrb_state *mrb, mrb_value s1)
#undef lesser
/* ---------------------------*/
static mrb_mt_entry symbol_rom_entries[] = {
static const mrb_mt_entry symbol_rom_entries[] = {
MRB_MT_ENTRY(sym_to_s, MRB_SYM(to_s), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(sym_name, MRB_SYM(name), MRB_MT_FUNC|MRB_MT_NOARG),
MRB_MT_ENTRY(mrb_obj_itself, MRB_SYM(to_sym), MRB_MT_FUNC|MRB_MT_NOARG),