summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-metaprog/src
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2020-08-27 21:43:20 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2020-10-12 18:20:06 +0900
commit397b005715b443ff8175ffe3549f13ebfc6a9e7f (patch)
tree51f9799d21389daee0b090915039ac613002f58f /mrbgems/mruby-metaprog/src
parentbf118b90064ad41412f918458f8082c7e0e14bce (diff)
downloadmruby-397b005715b443ff8175ffe3549f13ebfc6a9e7f.tar.gz
mruby-397b005715b443ff8175ffe3549f13ebfc6a9e7f.zip
Replace the implementation of method tables in classes/modules.
They are basically the copy of instance variable tables. On my Linux box, memory consumption of `mrbtest` measured by `valgrind` is: - old: 17,683,830 bytes - new: 14,283,749 bytes
Diffstat (limited to 'mrbgems/mruby-metaprog/src')
-rw-r--r--mrbgems/mruby-metaprog/src/metaprog.c83
1 files changed, 42 insertions, 41 deletions
diff --git a/mrbgems/mruby-metaprog/src/metaprog.c b/mrbgems/mruby-metaprog/src/metaprog.c
index 20fcc29cb..b421226f9 100644
--- a/mrbgems/mruby-metaprog/src/metaprog.c
+++ b/mrbgems/mruby-metaprog/src/metaprog.c
@@ -168,29 +168,50 @@ mrb_local_variables(mrb_state *mrb, mrb_value self)
return mrb_hash_keys(mrb, vars);
}
-KHASH_DECLARE(st, mrb_sym, char, FALSE)
+KHASH_DECLARE(st, mrb_sym, char, FALSE);
+KHASH_DEFINE(st, mrb_sym, char, FALSE, kh_int_hash_func, kh_int_hash_equal);
+
+union mt_ptr {
+ struct RProc *proc;
+ mrb_func_t func;
+};
+
+struct mt_elem {
+ union mt_ptr ptr;
+ size_t func_p:1;
+ mrb_sym key:sizeof(mrb_sym)*8-1;
+};
+
+struct mt_set {
+ khash_t(st) *set;
+ khash_t(st) *undef;
+};
+
+static int
+method_entry_i(mrb_state *mrb, mrb_sym mid, struct mt_elem *e, void *p)
+{
+ struct mt_set *s = (struct mt_set*)p;
+
+ if (e->ptr.proc == 0) {
+ if (s->undef) {
+ kh_put(st, mrb, s->undef, mid);
+ }
+ }
+ else if (s->undef == NULL ||
+ kh_get(st, mrb, s->undef, mid) == kh_end(s->undef)) {
+ kh_put(st, mrb, s->set, mid);
+ }
+ return 0;
+}
static void
method_entry_loop(mrb_state *mrb, struct RClass *klass, khash_t(st) *set, khash_t(st) *undef)
{
- khint_t i;
+ struct mt_set s;
- khash_t(mt) *h = klass->mt;
- if (!h || kh_size(h) == 0) return;
- for (i=0;i<kh_end(h);i++) {
- if (kh_exist(h, i)) {
- mrb_method_t m = kh_value(h, i);
- if (MRB_METHOD_UNDEF_P(m)) {
- if (undef) {
- kh_put(st, mrb, undef, kh_key(h, i));
- }
- }
- else if (undef == NULL ||
- kh_get(st, mrb, undef, kh_key(h, i)) == kh_end(undef)) {
- kh_put(st, mrb, set, kh_key(h, i));
- }
- }
- }
+ s.set = set;
+ s.undef = undef;
+ mrb_mt_foreach(mrb, klass, method_entry_i, (void*)&s);
}
static mrb_value
@@ -608,28 +629,6 @@ mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod)
return mrb_class_instance_method_list(mrb, recur, c, 0);
}
-static void
-remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid)
-{
- struct RClass *c = mrb_class_ptr(mod);
- khash_t(mt) *h;
- khiter_t k;
-
- MRB_CLASS_ORIGIN(c);
- h = c->mt;
-
- if (h) {
- k = kh_get(mt, mrb, h, mid);
- if (k != kh_end(h)) {
- kh_del(mt, mrb, h, k);
- mrb_funcall_id(mrb, mod, MRB_SYM(method_removed), 1, mrb_symbol_value(mid));
- return;
- }
- }
-
- mrb_name_error(mrb, mid, "method '%n' not defined in %v", mid, mod);
-}
-
/* 15.2.2.4.41 */
/*
* call-seq:
@@ -644,11 +643,13 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod)
{
mrb_int argc;
mrb_value *argv;
+ struct RClass *c = mrb_class_ptr(mod);
mrb_get_args(mrb, "*", &argv, &argc);
mrb_check_frozen(mrb, mrb_obj_ptr(mod));
while (argc--) {
- remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv));
+ mrb_remove_method(mrb, c, mrb_obj_to_sym(mrb, *argv));
+ mrb_funcall_id(mrb, mod, MRB_SYM(method_removed), 1, *argv);
argv++;
}
return mod;