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(-) 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