From bd2686d82d233774003fe683e9396f366b152b6d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 1 Jun 2015 00:13:12 +0900 Subject: singleton_class should not be cloned; close #2815 --- src/kernel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/kernel.c') diff --git a/src/kernel.c b/src/kernel.c index d1e10a7f8..9d056178e 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -330,6 +330,9 @@ mrb_obj_clone(mrb_state *mrb, mrb_value self) if (mrb_immediate_p(self)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't clone %S", self); } + if (mrb_type(self) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't clone singleton class"); + } p = (struct RObject*)mrb_obj_alloc(mrb, mrb_type(self), mrb_obj_class(mrb, self)); p->c = mrb_singleton_class_clone(mrb, self); clone = mrb_obj_value(p); -- cgit v1.2.3 From b6121adc7dbedcf0e6fd262de536c2f8c9217120 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 1 Jun 2015 21:30:07 +0900 Subject: singleton_class should not be duped; fix #2815 --- src/kernel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/kernel.c') diff --git a/src/kernel.c b/src/kernel.c index 9d056178e..b5b13f874 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -369,6 +369,9 @@ mrb_obj_dup(mrb_state *mrb, mrb_value obj) if (mrb_immediate_p(obj)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't dup %S", obj); } + if (mrb_type(obj) == MRB_TT_SCLASS) { + mrb_raise(mrb, E_TYPE_ERROR, "can't dup singleton class"); + } p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj)); dup = mrb_obj_value(p); init_copy(mrb, dup, obj); -- cgit v1.2.3 From 005cacf18b8ce2cf854872aa8cb803819478a47d Mon Sep 17 00:00:00 2001 From: Corey Powell Date: Sat, 11 Jul 2015 11:15:18 +0200 Subject: Additional patches to make this work --- src/class.c | 129 ++++++++++++++++++++++++++++++++--------------------------- src/kernel.c | 12 ++++++ 2 files changed, 83 insertions(+), 58 deletions(-) (limited to 'src/kernel.c') diff --git a/src/class.c b/src/class.c index ca4582041..73e6687c0 100644 --- a/src/class.c +++ b/src/class.c @@ -325,9 +325,16 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s MRB_API void mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RProc *p) { - khash_t(mt) *h = c->mt; + khash_t(mt) *h; khiter_t k; + if (!c->origin) { + printf("Warning, class %s does not have valid origin\n", mrb_class_name(mrb, c)); + mrb_raisef(mrb, E_RUNTIME_ERROR, "Invalid origin"); + c->origin = c; + } + h = c->origin->mt; + if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = p; @@ -758,6 +765,7 @@ boot_defclass(mrb_state *mrb, struct RClass *super) struct RClass *c; c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class); + c->origin = c; if (super) { c->super = super; mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); @@ -765,71 +773,74 @@ boot_defclass(mrb_state *mrb, struct RClass *super) else { c->super = mrb->object_class; } - c->origin = c; c->mt = kh_init(mt, mrb); return c; } -MRB_API inline void -include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super) +static struct RClass* +include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) +{ + struct RClass *ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); + if (m->tt == MRB_TT_ICLASS) { + m = m->c; + } + ic->origin = ic; + ic->iv = m->iv; + ic->mt = m->origin->mt; + ic->super = super; + if (m->tt == MRB_TT_ICLASS) { + ic->c = m->c; + } else { + ic->c = m; + } + return ic; +} + +MRB_API int +include_module_at(mrb_state *mrb, struct RClass *klass, struct RClass *c, struct RClass *module, int search_super) { - while (m) { - struct RClass *p = c, *ic; + struct RClass *p, *iclass; + void *klass_mt = klass->origin->mt; + + while (module) { int superclass_seen = 0; - - //if (m->origin != m) - // goto skip; - if (c->mt && c->mt == m->mt) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); - } - while (p) { - /*if (p->tt == MRB_TT_ICLASS) { - if (!superclass_seen) { - ins_pos = p; // move insert point + + if (module->origin != module) + goto skip; + + if (klass_mt && klass_mt == module->mt) + return -1; + + p = klass->super; + while(p) { + if (p->tt == MRB_TT_ICLASS) { + if (p->mt == module->mt) { + if (!superclass_seen) { + c = p; // move insert point + } + goto skip; } - goto skip; } else if (p->tt == MRB_TT_CLASS) { - if (p->mt == m->mt) { - if (!search_super) break; - superclass_seen = 1; - } - }*/ - // - if (c != p && p->tt == MRB_TT_CLASS) { if (!search_super) break; superclass_seen = 1; } - else if (p->mt == m->mt) { - if (p->tt == MRB_TT_ICLASS && !superclass_seen) { - ins_pos = p; - } - goto skip; - } p = p->super; } - ic = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, mrb->class_class); - if (m->tt == MRB_TT_ICLASS) { - ic->c = m->c; - } - else { - ic->c = m; - } - ic->origin = ic; - ic->mt = m->mt; - ic->iv = m->iv; - ic->super = ins_pos->super; - ins_pos->super = ic; - mrb_field_write_barrier(mrb, (struct RBasic*)ins_pos, (struct RBasic*)ic); - ins_pos = ic; + + iclass = include_class_new(mrb, module, c->super); + c->super = iclass; + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)c->super); + c = iclass; skip: - m = m->super; + module = module->super; } + return 0; } MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - include_module_at(mrb, c, c->origin, m, FALSE); + include_module_at(mrb, c, c->origin, m, 1); } MRB_API void @@ -842,16 +853,16 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) if (origin == c) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->origin = origin; - //OBJ_WB_UNPROTECT(origin); /* TODO: conservative shading. Need more survey. */ origin->super = c->super; c->super = origin; c->origin = origin; origin->mt = c->mt; c->mt = kh_init(mt, mrb); + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)c->origin); } - include_module_at(mrb, c, c, m, FALSE); // changed = - if (changed) { - //rb_vm_check_redefinition_by_prepend(klass); + changed = include_module_at(mrb, c, c, m, 0); + if (changed < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic prepend detected"); } } @@ -955,15 +966,12 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) { mrb_value result; struct RClass *c = mrb_class_ptr(self); - result = mrb_ary_new(mrb); - mrb_ary_push(mrb, result, mrb_obj_value(c)); - c = c->super; while (c) { if (c->tt == MRB_TT_ICLASS) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } - else if (c->tt != MRB_TT_SCLASS) { + else if (c->origin == c) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -1005,9 +1013,14 @@ mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { mrb_value b; + /* hack, fix missing module->origin */ + struct RClass *m = mrb_class_ptr(mod); + if (!m->origin) + m->origin = m; + mrb_get_args(mrb, "&", &b); if (!mrb_nil_p(b)) { - mrb_yield_with_class(mrb, b, 1, &mod, mod, mrb_class_ptr(mod)); + mrb_yield_with_class(mrb, b, 1, &mod, mod, m); } return mod; } @@ -1324,9 +1337,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass) struct RClass *c; c = mrb_class_ptr(klass); - c = c->super; + c = c->origin->super; while (c && c->tt == MRB_TT_ICLASS) { - c = c->super; + c = c->origin->super; } if (!c) return mrb_nil_value(); return mrb_obj_value(c); @@ -1925,7 +1938,7 @@ static void remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) { struct RClass *c = mrb_class_ptr(mod); - khash_t(mt) *h = c->mt; + khash_t(mt) *h = c->origin->mt; khiter_t k; if (h) { diff --git a/src/kernel.c b/src/kernel.c index b5b13f874..bafab6e76 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -248,6 +248,11 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj) clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass)); } + if (klass->origin != klass) + clone->origin = klass->origin; + else + clone->origin = clone; + clone->super = klass->super; if (klass->iv) { mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass)); @@ -269,6 +274,13 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) { struct RClass *dc = mrb_class_ptr(dst); struct RClass *sc = mrb_class_ptr(src); + /* if the origin is not the same as the class, then the origin and + the current class need to be copied */ + if (sc->origin != sc) { + dc->origin = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(sc->origin))); + } else { + dc->origin = dc; + } dc->mt = kh_copy(mt, mrb, sc->mt); dc->super = sc->super; } -- cgit v1.2.3 From a725cb909333335ad178997795e84c332e555c65 Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Sun, 12 Jul 2015 22:07:16 +0200 Subject: Include prepended methods in the instance_methods list. --- src/kernel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/kernel.c') diff --git a/src/kernel.c b/src/kernel.c index bafab6e76..36ad683ee 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -653,13 +653,19 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl { khint_t i; mrb_value ary; + mrb_bool prepended; struct RClass* oldklass; khash_t(st)* set = kh_init(st, mrb); + if (!recur && klass->origin != klass) { + klass = klass->origin; + prepended = 1; + } + oldklass = 0; while (klass && (klass != oldklass)) { method_entry_loop(mrb, klass, set); - if ((klass->tt == MRB_TT_ICLASS) || + if ((klass->tt == MRB_TT_ICLASS && !prepended) || (klass->tt == MRB_TT_SCLASS)) { } else { -- cgit v1.2.3 From 2550edd570f1d7485e862ce11ceb50ea59dee3c5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 5 Sep 2015 02:01:02 +0900 Subject: remove `origin` member to implement prepend from struct RClass; ref #2885 instead origin is saved in ICLASS with MRB_FLAG_IS_ORIGIN set. --- include/mruby/class.h | 10 +++++++++- src/class.c | 44 ++++++++++++++++++++++++-------------------- src/kernel.c | 29 +++++++++++++++-------------- src/object.c | 2 +- 4 files changed, 49 insertions(+), 36 deletions(-) (limited to 'src/kernel.c') diff --git a/include/mruby/class.h b/include/mruby/class.h index 80a0cbe35..85f3e12c6 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -16,7 +16,6 @@ struct RClass { struct iv_tbl *iv; struct kh_mt *mt; struct RClass *super; - struct RClass *origin; }; #define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v))) @@ -50,7 +49,16 @@ mrb_class(mrb_state *mrb, mrb_value v) } // TODO: figure out where to put user flags +#define MRB_FLAG_IS_PREPENDED (1 << 19) #define MRB_FLAG_IS_ORIGIN (1 << 20) +#define MRB_CLASS_ORIGIN(c) do {\ + if (c->flags & MRB_FLAG_IS_PREPENDED) {\ + c = c->super;\ + while (!(c->flags & MRB_FLAG_IS_ORIGIN)) {\ + c = c->super;\ + }\ + }\ +} while (0) #define MRB_INSTANCE_TT_MASK (0xFF) #define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt) #define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK) diff --git a/src/class.c b/src/class.c index 462ab40b5..c3c3e0b8f 100644 --- a/src/class.c +++ b/src/class.c @@ -76,7 +76,6 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) if (o->c->tt == MRB_TT_SCLASS) return; sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); - sc->origin = sc; sc->mt = kh_init(mt, mrb); sc->iv = 0; if (o->tt == MRB_TT_CLASS) { @@ -188,6 +187,13 @@ mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name) return c; } +static struct RClass* +find_origin(struct RClass *c) +{ + MRB_CLASS_ORIGIN(c); + return c; +} + static struct RClass* define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *outer) { @@ -195,7 +201,7 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass * if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) { c = class_from_sym(mrb, outer, name); - c = c->origin; + MRB_CLASS_ORIGIN(c); if (super && mrb_class_real(c->super) != super) { mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", mrb_sym2str(mrb, name), @@ -327,7 +333,8 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro { khash_t(mt) *h; khiter_t k; - h = c->origin->mt; + MRB_CLASS_ORIGIN(c); + h = c->mt; if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); @@ -809,7 +816,6 @@ boot_defclass(mrb_state *mrb, struct RClass *super) struct RClass *c; c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class); - c->origin = c; if (super) { c->super = super; mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); @@ -824,7 +830,6 @@ boot_defclass(mrb_state *mrb, struct RClass *super) static void boot_initmod(mrb_state *mrb, struct RClass *mod) { - mod->origin = mod; mod->mt = kh_init(mt, mrb); } @@ -835,9 +840,9 @@ include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) if (m->tt == MRB_TT_ICLASS) { m = m->c; } - ic->origin = ic; + MRB_CLASS_ORIGIN(m); ic->iv = m->iv; - ic->mt = m->origin->mt; + ic->mt = m->mt; ic->super = super; if (m->tt == MRB_TT_ICLASS) { ic->c = m->c; @@ -851,12 +856,12 @@ static int include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super) { struct RClass *p, *ic; - void *klass_mt = c->origin->mt; + void *klass_mt = find_origin(c)->mt; while (m) { int superclass_seen = 0; - if (m->origin != m) + if (m->flags & MRB_FLAG_IS_PREPENDED) goto skip; if (klass_mt && klass_mt == m->mt) @@ -891,7 +896,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru MRB_API void mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) { - int changed = include_module_at(mrb, c, c->origin, m, 1); + int changed = include_module_at(mrb, c, find_origin(c), m, 1); if (changed < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); } @@ -903,17 +908,15 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) struct RClass *origin; int changed = 0; - origin = c->origin; - if (origin == c) { + if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin->flags |= MRB_FLAG_IS_ORIGIN; - origin->origin = origin; origin->super = c->super; c->super = origin; - c->origin = origin; origin->mt = c->mt; c->mt = kh_init(mt, mrb); - mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)c->origin); + mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)origin); + c->flags |= MRB_FLAG_IS_PREPENDED; } changed = include_module_at(mrb, c, c, m, 0); if (changed < 0) { @@ -1026,7 +1029,7 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) if (c->tt == MRB_TT_ICLASS) { mrb_ary_push(mrb, result, mrb_obj_value(c->c)); } - else if (c->origin == c) { + else if (!(c->flags & MRB_FLAG_IS_PREPENDED)) { mrb_ary_push(mrb, result, mrb_obj_value(c)); } c = c->super; @@ -1051,8 +1054,9 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) { mrb_value result; struct RClass *c = mrb_class_ptr(self); - struct RClass *origin = c->origin; + struct RClass *origin = c; + MRB_CLASS_ORIGIN(origin); result = mrb_ary_new(mrb); while (c) { if (c != origin && c->tt == MRB_TT_ICLASS) { @@ -1391,9 +1395,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass) struct RClass *c; c = mrb_class_ptr(klass); - c = c->origin->super; + c = find_origin(c)->super; while (c && c->tt == MRB_TT_ICLASS) { - c = c->origin->super; + c = find_origin(c)->super; } if (!c) return mrb_nil_value(); return mrb_obj_value(c); @@ -1990,7 +1994,7 @@ static void remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) { struct RClass *c = mrb_class_ptr(mod); - khash_t(mt) *h = c->origin->mt; + khash_t(mt) *h = find_origin(c)->mt; khiter_t k; if (h) { diff --git a/src/kernel.c b/src/kernel.c index 36ad683ee..225f7fa54 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -240,19 +240,12 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj) /* copy singleton(unnamed) class */ struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class); - if ((mrb_type(obj) == MRB_TT_CLASS) || - (mrb_type(obj) == MRB_TT_SCLASS)) { /* BUILTIN_TYPE(obj) == T_CLASS */ + if ((mrb_type(obj) == MRB_TT_CLASS) || (mrb_type(obj) == MRB_TT_SCLASS)) { clone->c = clone; } else { clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass)); } - - if (klass->origin != klass) - clone->origin = klass->origin; - else - clone->origin = clone; - clone->super = klass->super; if (klass->iv) { mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass)); @@ -276,10 +269,18 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) struct RClass *sc = mrb_class_ptr(src); /* if the origin is not the same as the class, then the origin and the current class need to be copied */ - if (sc->origin != sc) { - dc->origin = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(sc->origin))); - } else { - dc->origin = dc; + if (sc->flags & MRB_FLAG_IS_PREPENDED) { + struct RClass *c0 = sc->super; + struct RClass *c1 = dc; + + /* copy prepended iclasses */ + while (!(c0->flags & MRB_FLAG_IS_ORIGIN)) { + c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); + c1 = c1->super; + c0 = c0->super; + } + c1->super = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(c0))); + c1->super->flags |= MRB_FLAG_IS_ORIGIN; } dc->mt = kh_copy(mt, mrb, sc->mt); dc->super = sc->super; @@ -657,8 +658,8 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl struct RClass* oldklass; khash_t(st)* set = kh_init(st, mrb); - if (!recur && klass->origin != klass) { - klass = klass->origin; + if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) { + MRB_CLASS_ORIGIN(klass); prepended = 1; } diff --git a/src/object.c b/src/object.c index c834ee04f..2e0bd245f 100644 --- a/src/object.c +++ b/src/object.c @@ -487,7 +487,7 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) mrb_raise(mrb, E_TYPE_ERROR, "class or module required"); } - c = c->origin; + MRB_CLASS_ORIGIN(c); while (cl) { if (cl == c || cl->mt == c->mt) return TRUE; -- cgit v1.2.3