remove `origin` member to implement prepend from struct RClass; ref #2885

instead origin is saved in ICLASS with MRB_FLAG_IS_ORIGIN set.
parent 8bb7962e
...@@ -16,7 +16,6 @@ struct RClass { ...@@ -16,7 +16,6 @@ struct RClass {
struct iv_tbl *iv; struct iv_tbl *iv;
struct kh_mt *mt; struct kh_mt *mt;
struct RClass *super; struct RClass *super;
struct RClass *origin;
}; };
#define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v))) #define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v)))
...@@ -50,7 +49,16 @@ mrb_class(mrb_state *mrb, mrb_value v) ...@@ -50,7 +49,16 @@ mrb_class(mrb_state *mrb, mrb_value v)
} }
// TODO: figure out where to put user flags // TODO: figure out where to put user flags
#define MRB_FLAG_IS_PREPENDED (1 << 19)
#define MRB_FLAG_IS_ORIGIN (1 << 20) #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_INSTANCE_TT_MASK (0xFF)
#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt) #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) #define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK)
......
...@@ -76,7 +76,6 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o) ...@@ -76,7 +76,6 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
if (o->c->tt == MRB_TT_SCLASS) return; if (o->c->tt == MRB_TT_SCLASS) return;
sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class); sc = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_SCLASS, mrb->class_class);
sc->origin = sc;
sc->mt = kh_init(mt, mrb); sc->mt = kh_init(mt, mrb);
sc->iv = 0; sc->iv = 0;
if (o->tt == MRB_TT_CLASS) { if (o->tt == MRB_TT_CLASS) {
...@@ -188,6 +187,13 @@ mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name) ...@@ -188,6 +187,13 @@ mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name)
return c; return c;
} }
static struct RClass*
find_origin(struct RClass *c)
{
MRB_CLASS_ORIGIN(c);
return c;
}
static struct RClass* static struct RClass*
define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *outer) 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 * ...@@ -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)) { if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) {
c = class_from_sym(mrb, outer, name); c = class_from_sym(mrb, outer, name);
c = c->origin; MRB_CLASS_ORIGIN(c);
if (super && mrb_class_real(c->super) != super) { if (super && mrb_class_real(c->super) != super) {
mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)", mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)",
mrb_sym2str(mrb, name), mrb_sym2str(mrb, name),
...@@ -327,7 +333,8 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro ...@@ -327,7 +333,8 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro
{ {
khash_t(mt) *h; khash_t(mt) *h;
khiter_t k; khiter_t k;
h = c->origin->mt; MRB_CLASS_ORIGIN(c);
h = c->mt;
if (!h) h = c->mt = kh_init(mt, mrb); if (!h) h = c->mt = kh_init(mt, mrb);
k = kh_put(mt, mrb, h, mid); k = kh_put(mt, mrb, h, mid);
...@@ -809,7 +816,6 @@ boot_defclass(mrb_state *mrb, struct RClass *super) ...@@ -809,7 +816,6 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
struct RClass *c; struct RClass *c;
c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class); c = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_CLASS, mrb->class_class);
c->origin = c;
if (super) { if (super) {
c->super = super; c->super = super;
mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super); mrb_field_write_barrier(mrb, (struct RBasic*)c, (struct RBasic*)super);
...@@ -824,7 +830,6 @@ boot_defclass(mrb_state *mrb, struct RClass *super) ...@@ -824,7 +830,6 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
static void static void
boot_initmod(mrb_state *mrb, struct RClass *mod) boot_initmod(mrb_state *mrb, struct RClass *mod)
{ {
mod->origin = mod;
mod->mt = kh_init(mt, mrb); mod->mt = kh_init(mt, mrb);
} }
...@@ -835,9 +840,9 @@ include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super) ...@@ -835,9 +840,9 @@ include_class_new(mrb_state *mrb, struct RClass *m, struct RClass *super)
if (m->tt == MRB_TT_ICLASS) { if (m->tt == MRB_TT_ICLASS) {
m = m->c; m = m->c;
} }
ic->origin = ic; MRB_CLASS_ORIGIN(m);
ic->iv = m->iv; ic->iv = m->iv;
ic->mt = m->origin->mt; ic->mt = m->mt;
ic->super = super; ic->super = super;
if (m->tt == MRB_TT_ICLASS) { if (m->tt == MRB_TT_ICLASS) {
ic->c = m->c; ic->c = m->c;
...@@ -851,12 +856,12 @@ static int ...@@ -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) include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, struct RClass *m, int search_super)
{ {
struct RClass *p, *ic; struct RClass *p, *ic;
void *klass_mt = c->origin->mt; void *klass_mt = find_origin(c)->mt;
while (m) { while (m) {
int superclass_seen = 0; int superclass_seen = 0;
if (m->origin != m) if (m->flags & MRB_FLAG_IS_PREPENDED)
goto skip; goto skip;
if (klass_mt && klass_mt == m->mt) 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 ...@@ -891,7 +896,7 @@ include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *ins_pos, stru
MRB_API void MRB_API void
mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m) 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) { if (changed < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "cyclic include detected"); 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) ...@@ -903,17 +908,15 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
struct RClass *origin; struct RClass *origin;
int changed = 0; int changed = 0;
origin = c->origin; if (!(c->flags & MRB_FLAG_IS_PREPENDED)) {
if (origin == c) {
origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c); origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
origin->flags |= MRB_FLAG_IS_ORIGIN; origin->flags |= MRB_FLAG_IS_ORIGIN;
origin->origin = origin;
origin->super = c->super; origin->super = c->super;
c->super = origin; c->super = origin;
c->origin = origin;
origin->mt = c->mt; origin->mt = c->mt;
c->mt = kh_init(mt, mrb); 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); changed = include_module_at(mrb, c, c, m, 0);
if (changed < 0) { if (changed < 0) {
...@@ -1026,7 +1029,7 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self) ...@@ -1026,7 +1029,7 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self)
if (c->tt == MRB_TT_ICLASS) { if (c->tt == MRB_TT_ICLASS) {
mrb_ary_push(mrb, result, mrb_obj_value(c->c)); 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)); mrb_ary_push(mrb, result, mrb_obj_value(c));
} }
c = c->super; c = c->super;
...@@ -1051,8 +1054,9 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self) ...@@ -1051,8 +1054,9 @@ mrb_mod_included_modules(mrb_state *mrb, mrb_value self)
{ {
mrb_value result; mrb_value result;
struct RClass *c = mrb_class_ptr(self); 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); result = mrb_ary_new(mrb);
while (c) { while (c) {
if (c != origin && c->tt == MRB_TT_ICLASS) { if (c != origin && c->tt == MRB_TT_ICLASS) {
...@@ -1391,9 +1395,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass) ...@@ -1391,9 +1395,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass)
struct RClass *c; struct RClass *c;
c = mrb_class_ptr(klass); c = mrb_class_ptr(klass);
c = c->origin->super; c = find_origin(c)->super;
while (c && c->tt == MRB_TT_ICLASS) { while (c && c->tt == MRB_TT_ICLASS) {
c = c->origin->super; c = find_origin(c)->super;
} }
if (!c) return mrb_nil_value(); if (!c) return mrb_nil_value();
return mrb_obj_value(c); return mrb_obj_value(c);
...@@ -1990,7 +1994,7 @@ static void ...@@ -1990,7 +1994,7 @@ static void
remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid)
{ {
struct RClass *c = mrb_class_ptr(mod); 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; khiter_t k;
if (h) { if (h) {
......
...@@ -240,19 +240,12 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj) ...@@ -240,19 +240,12 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
/* copy singleton(unnamed) class */ /* copy singleton(unnamed) class */
struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class); struct RClass *clone = (struct RClass*)mrb_obj_alloc(mrb, klass->tt, mrb->class_class);
if ((mrb_type(obj) == MRB_TT_CLASS) || if ((mrb_type(obj) == MRB_TT_CLASS) || (mrb_type(obj) == MRB_TT_SCLASS)) {
(mrb_type(obj) == MRB_TT_SCLASS)) { /* BUILTIN_TYPE(obj) == T_CLASS */
clone->c = clone; clone->c = clone;
} }
else { else {
clone->c = mrb_singleton_class_clone(mrb, mrb_obj_value(klass)); 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; clone->super = klass->super;
if (klass->iv) { if (klass->iv) {
mrb_iv_copy(mrb, mrb_obj_value(clone), mrb_obj_value(klass)); 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) ...@@ -276,10 +269,18 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src)
struct RClass *sc = mrb_class_ptr(src); struct RClass *sc = mrb_class_ptr(src);
/* if the origin is not the same as the class, then the origin and /* if the origin is not the same as the class, then the origin and
the current class need to be copied */ the current class need to be copied */
if (sc->origin != sc) { if (sc->flags & MRB_FLAG_IS_PREPENDED) {
dc->origin = mrb_class_ptr(mrb_obj_dup(mrb, mrb_obj_value(sc->origin))); struct RClass *c0 = sc->super;
} else { struct RClass *c1 = dc;
dc->origin = 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->mt = kh_copy(mt, mrb, sc->mt);
dc->super = sc->super; dc->super = sc->super;
...@@ -657,8 +658,8 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl ...@@ -657,8 +658,8 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl
struct RClass* oldklass; struct RClass* oldklass;
khash_t(st)* set = kh_init(st, mrb); khash_t(st)* set = kh_init(st, mrb);
if (!recur && klass->origin != klass) { if (!recur && (klass->flags & MRB_FLAG_IS_PREPENDED)) {
klass = klass->origin; MRB_CLASS_ORIGIN(klass);
prepended = 1; prepended = 1;
} }
......
...@@ -487,7 +487,7 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *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"); mrb_raise(mrb, E_TYPE_ERROR, "class or module required");
} }
c = c->origin; MRB_CLASS_ORIGIN(c);
while (cl) { while (cl) {
if (cl == c || cl->mt == c->mt) if (cl == c || cl->mt == c->mt)
return TRUE; return TRUE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment