mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
class.c: remove mt_elem structure to avoid alignment gaps.
This commit is contained in:
+91
-88
@@ -23,18 +23,22 @@ union mt_ptr {
|
||||
mrb_func_t func;
|
||||
};
|
||||
|
||||
struct mt_elem {
|
||||
union mt_ptr ptr;
|
||||
size_t func_p:1;
|
||||
size_t noarg_p:1;
|
||||
mrb_sym key:sizeof(mrb_sym)*8-2;
|
||||
};
|
||||
#define MT_KEY_P(k) (((k)>>2) != 0)
|
||||
#define MT_FUNC_P 1
|
||||
#define MT_NOARG_P 2
|
||||
#define MT_EMPTY 0
|
||||
#define MT_DELETED 1
|
||||
|
||||
#define MT_KEY(sym, flags) ((sym)<<2|(flags))
|
||||
#define MT_FLAGS(func_p, noarg_p) ((func_p)?MT_FUNC_P:0)|((noarg_p)?MT_NOARG_P:0)
|
||||
#define MT_KEY_SYM(k) ((k)>>2)
|
||||
#define MT_KEY_FLG(k) ((k)&3)
|
||||
|
||||
/* method table structure */
|
||||
typedef struct mt_tbl {
|
||||
size_t size;
|
||||
size_t alloc;
|
||||
struct mt_elem *table;
|
||||
union mt_ptr *ptr;
|
||||
} mt_tbl;
|
||||
|
||||
#ifdef MRB_USE_INLINE_METHOD_CACHE
|
||||
@@ -51,101 +55,99 @@ mt_new(mrb_state *mrb)
|
||||
t = (mt_tbl*)mrb_malloc(mrb, sizeof(mt_tbl));
|
||||
t->size = 0;
|
||||
t->alloc = 0;
|
||||
t->table = NULL;
|
||||
t->ptr = NULL;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static struct mt_elem *mt_put(mrb_state *mrb, mt_tbl *t, mrb_sym sym, size_t func_p, size_t noarg_p, union mt_ptr ptr);
|
||||
static void mt_put(mrb_state *mrb, mt_tbl *t, mrb_sym sym, mrb_sym flags, union mt_ptr ptr);
|
||||
|
||||
static void
|
||||
mt_rehash(mrb_state *mrb, mt_tbl *t)
|
||||
{
|
||||
size_t old_alloc = t->alloc;
|
||||
size_t new_alloc = old_alloc+8;
|
||||
struct mt_elem *old_table = t->table;
|
||||
union mt_ptr *old_ptr = t->ptr;
|
||||
|
||||
khash_power2(new_alloc);
|
||||
if (old_alloc == new_alloc) return;
|
||||
|
||||
t->alloc = new_alloc;
|
||||
t->size = 0;
|
||||
t->table = (struct mt_elem*)mrb_calloc(mrb, sizeof(struct mt_elem), new_alloc);
|
||||
t->ptr = (union mt_ptr*)mrb_calloc(mrb, sizeof(union mt_ptr)+sizeof(mrb_sym), new_alloc);
|
||||
if (old_alloc == 0) return;
|
||||
|
||||
mrb_sym *keys = (mrb_sym*)&old_ptr[old_alloc];
|
||||
union mt_ptr *vals = old_ptr;
|
||||
for (size_t i = 0; i < old_alloc; i++) {
|
||||
struct mt_elem *slot = &old_table[i];
|
||||
|
||||
/* key = 0 means empty or deleted */
|
||||
if (slot->key != 0) {
|
||||
mt_put(mrb, t, slot->key, slot->func_p, slot->noarg_p, slot->ptr);
|
||||
mrb_sym key = keys[i];
|
||||
if (MT_KEY_P(key)) {
|
||||
mt_put(mrb, t, MT_KEY_SYM(key), MT_KEY_FLG(key), vals[i]);
|
||||
}
|
||||
}
|
||||
mrb_free(mrb, old_table);
|
||||
mrb_free(mrb, old_ptr);
|
||||
}
|
||||
|
||||
#define slot_empty_p(slot) ((slot)->key == 0 && (slot)->func_p == 0)
|
||||
|
||||
/* Set the value for the symbol in the method table. */
|
||||
static struct mt_elem*
|
||||
mt_put(mrb_state *mrb, mt_tbl *t, mrb_sym sym, size_t func_p, size_t noarg_p, union mt_ptr ptr)
|
||||
static void
|
||||
mt_put(mrb_state *mrb, mt_tbl *t, mrb_sym sym, mrb_sym flags, union mt_ptr ptr)
|
||||
{
|
||||
size_t hash, pos, start;
|
||||
struct mt_elem *dslot = NULL;
|
||||
ssize_t dpos = -1;
|
||||
|
||||
if (t->alloc == 0) {
|
||||
mt_rehash(mrb, t);
|
||||
}
|
||||
|
||||
mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
|
||||
union mt_ptr *vals = t->ptr;
|
||||
hash = kh_int_hash_func(mrb, sym);
|
||||
start = pos = hash & (t->alloc-1);
|
||||
for (;;) {
|
||||
struct mt_elem *slot = &t->table[pos];
|
||||
|
||||
if (slot->key == sym) {
|
||||
slot->func_p = func_p;
|
||||
slot->noarg_p = noarg_p;
|
||||
slot->ptr = ptr;
|
||||
return slot;
|
||||
mrb_sym key = keys[pos];
|
||||
if (MT_KEY_SYM(key) == sym) {
|
||||
value_set:
|
||||
keys[pos] = MT_KEY(sym, flags);
|
||||
vals[pos] = ptr;
|
||||
return;
|
||||
}
|
||||
else if (slot->key == 0) { /* empty or deleted */
|
||||
if (slot->func_p == 0) { /* empty */
|
||||
t->size++;
|
||||
slot->key = sym;
|
||||
slot->func_p = func_p;
|
||||
slot->noarg_p = noarg_p;
|
||||
slot->ptr = ptr;
|
||||
return slot;
|
||||
}
|
||||
else if (!dslot) { /* deleted */
|
||||
dslot = slot;
|
||||
}
|
||||
else if (key == MT_EMPTY) {
|
||||
t->size++;
|
||||
goto value_set;
|
||||
}
|
||||
else if (key == MT_DELETED && dpos < 0) {
|
||||
dpos = pos;
|
||||
}
|
||||
pos = (pos+1) & (t->alloc-1);
|
||||
if (pos == start) { /* not found */
|
||||
if (dslot) {
|
||||
if (dpos > 0) {
|
||||
t->size++;
|
||||
dslot->key = sym;
|
||||
dslot->func_p = func_p;
|
||||
dslot->noarg_p = noarg_p;
|
||||
dslot->ptr = ptr;
|
||||
return dslot;
|
||||
pos = dpos;
|
||||
goto value_set;
|
||||
}
|
||||
/* no room */
|
||||
mt_rehash(mrb, t);
|
||||
start = pos = hash & (t->alloc-1);
|
||||
keys = (mrb_sym*)&t->ptr[t->alloc];
|
||||
vals = t->ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a value for a symbol from the method table. */
|
||||
static struct mt_elem*
|
||||
mt_get(mrb_state *mrb, mt_tbl *t, mrb_sym sym)
|
||||
static mrb_sym
|
||||
mt_get(mrb_state *mrb, mt_tbl *t, mrb_sym sym, union mt_ptr *pp)
|
||||
{
|
||||
size_t hash, pos, start;
|
||||
|
||||
if (t == NULL) return NULL;
|
||||
if (t->alloc == 0) return NULL;
|
||||
if (t->size == 0) return NULL;
|
||||
if (t == NULL) return 0;
|
||||
if (t->alloc == 0) return 0;
|
||||
if (t->size == 0) return 0;
|
||||
|
||||
mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
|
||||
union mt_ptr *vals = t->ptr;
|
||||
hash = kh_int_hash_func(mrb, sym);
|
||||
#ifdef MRB_USE_INLINE_METHOD_CACHE
|
||||
size_t cpos = (hash^(uintptr_t)t) % MT_CACHE_SIZE;
|
||||
@@ -156,22 +158,22 @@ mt_get(mrb_state *mrb, mt_tbl *t, mrb_sym sym)
|
||||
#endif
|
||||
start = pos = hash & (t->alloc-1);
|
||||
for (;;) {
|
||||
struct mt_elem *slot = &t->table[pos];
|
||||
|
||||
if (slot->key == sym) {
|
||||
mrb_sym key = keys[pos];
|
||||
if (MT_KEY_SYM(key) == sym) {
|
||||
*pp = vals[pos];
|
||||
#ifdef MRB_USE_INLINE_METHOD_CACHE
|
||||
if (pos < 0xff) {
|
||||
mt_cache[cpos] = pos;
|
||||
}
|
||||
#endif
|
||||
return slot;
|
||||
return key;
|
||||
}
|
||||
else if (slot_empty_p(slot)) {
|
||||
return NULL;
|
||||
else if (key == MT_EMPTY) {
|
||||
return 0;
|
||||
}
|
||||
pos = (pos+1) & (t->alloc-1);
|
||||
if (pos == start) { /* not found */
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,18 +188,17 @@ mt_del(mrb_state *mrb, mt_tbl *t, mrb_sym sym)
|
||||
if (t->alloc == 0) return FALSE;
|
||||
if (t->size == 0) return FALSE;
|
||||
|
||||
mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
|
||||
hash = kh_int_hash_func(mrb, sym);
|
||||
start = pos = hash & (t->alloc-1);
|
||||
for (;;) {
|
||||
struct mt_elem *slot = &t->table[pos];
|
||||
|
||||
if (slot->key == sym) {
|
||||
mrb_sym key = keys[pos];
|
||||
if (MT_KEY_SYM(key) == sym) {
|
||||
t->size--;
|
||||
slot->key = 0;
|
||||
slot->func_p = 1;
|
||||
keys[pos] = MT_DELETED;
|
||||
return TRUE;
|
||||
}
|
||||
else if (slot_empty_p(slot)) {
|
||||
else if (key == MT_EMPTY) {
|
||||
return FALSE;
|
||||
}
|
||||
pos = (pos+1) & (t->alloc-1);
|
||||
@@ -219,11 +220,11 @@ mt_copy(mrb_state *mrb, mt_tbl *t)
|
||||
if (t->size == 0) return NULL;
|
||||
|
||||
t2 = mt_new(mrb);
|
||||
mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
|
||||
union mt_ptr *vals = t->ptr;
|
||||
for (i=0; i<t->alloc; i++) {
|
||||
struct mt_elem *slot = &t->table[i];
|
||||
|
||||
if (slot->key) {
|
||||
mt_put(mrb, t2, slot->key, slot->func_p, slot->noarg_p, slot->ptr);
|
||||
if (MT_KEY_P(keys[i])) {
|
||||
mt_put(mrb, t2, MT_KEY_SYM(keys[i]), MT_KEY_FLG(keys[i]), vals[i]);
|
||||
}
|
||||
}
|
||||
return t2;
|
||||
@@ -233,7 +234,7 @@ mt_copy(mrb_state *mrb, mt_tbl *t)
|
||||
static void
|
||||
mt_free(mrb_state *mrb, mt_tbl *t)
|
||||
{
|
||||
mrb_free(mrb, t->table);
|
||||
mrb_free(mrb, t->ptr);
|
||||
mrb_free(mrb, t);
|
||||
}
|
||||
|
||||
@@ -247,23 +248,24 @@ mrb_mt_foreach(mrb_state *mrb, struct RClass *c, mrb_mt_foreach_func *fn, void *
|
||||
if (t->alloc == 0) return;
|
||||
if (t->size == 0) return;
|
||||
|
||||
mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
|
||||
union mt_ptr *vals = t->ptr;
|
||||
for (i=0; i<t->alloc; i++) {
|
||||
struct mt_elem *slot = &t->table[i];
|
||||
|
||||
if (slot->key) {
|
||||
mrb_sym key = keys[i];
|
||||
if (MT_KEY_SYM(key)) {
|
||||
mrb_method_t m;
|
||||
|
||||
if (slot->func_p) {
|
||||
MRB_METHOD_FROM_FUNC(m, slot->ptr.func);
|
||||
if (key & MT_FUNC_P) {
|
||||
MRB_METHOD_FROM_FUNC(m, vals[i].func);
|
||||
}
|
||||
else {
|
||||
MRB_METHOD_FROM_PROC(m, slot->ptr.proc);
|
||||
MRB_METHOD_FROM_PROC(m, vals[i].proc);
|
||||
}
|
||||
if (slot->noarg_p) {
|
||||
if (key & MT_NOARG_P) {
|
||||
MRB_METHOD_NOARG_SET(m);
|
||||
}
|
||||
|
||||
if (fn(mrb, slot->key, m, p) != 0)
|
||||
if (fn(mrb, MT_KEY_SYM(key), m, p) != 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -280,11 +282,11 @@ mrb_gc_mark_mt(mrb_state *mrb, struct RClass *c)
|
||||
if (t->alloc == 0) return;
|
||||
if (t->size == 0) return;
|
||||
|
||||
mrb_sym *keys = (mrb_sym*)&t->ptr[t->alloc];
|
||||
union mt_ptr *vals = t->ptr;
|
||||
for (i=0; i<t->alloc; i++) {
|
||||
struct mt_elem *slot = &t->table[i];
|
||||
|
||||
if (slot->key && !slot->func_p) { /* Proc pointer */
|
||||
struct RProc *p = slot->ptr.proc;
|
||||
if (MT_KEY_P(keys[i]) && (keys[i] & MT_FUNC_P) == 0) { /* Proc pointer */
|
||||
struct RProc *p = vals[i].proc;
|
||||
mrb_gc_mark(mrb, (struct RBasic*)p);
|
||||
}
|
||||
}
|
||||
@@ -769,7 +771,7 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, mrb_method_
|
||||
else {
|
||||
ptr.func = MRB_METHOD_FUNC(m);
|
||||
}
|
||||
mt_put(mrb, h, mid, MRB_METHOD_FUNC_P(m), MRB_METHOD_NOARG_P(m), ptr);
|
||||
mt_put(mrb, h, mid, MT_FLAGS(MRB_METHOD_FUNC_P(m), MRB_METHOD_NOARG_P(m)), ptr);
|
||||
mc_clear(mrb);
|
||||
}
|
||||
|
||||
@@ -1782,17 +1784,18 @@ mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid)
|
||||
mt_tbl *h = c->mt;
|
||||
|
||||
if (h) {
|
||||
struct mt_elem *e = mt_get(mrb, h, mid);
|
||||
if (e) {
|
||||
if (e->ptr.proc == 0) break;
|
||||
union mt_ptr ptr;
|
||||
mrb_sym ret = mt_get(mrb, h, mid, &ptr);
|
||||
if (ret) {
|
||||
if (ptr.proc == 0) break;
|
||||
*cp = c;
|
||||
if (e->func_p) {
|
||||
MRB_METHOD_FROM_FUNC(m, e->ptr.func);
|
||||
if (ret & MT_FUNC_P) {
|
||||
MRB_METHOD_FROM_FUNC(m, ptr.func);
|
||||
}
|
||||
else {
|
||||
MRB_METHOD_FROM_PROC(m, e->ptr.proc);
|
||||
MRB_METHOD_FROM_PROC(m, ptr.proc);
|
||||
}
|
||||
if (e->noarg_p) {
|
||||
if (ret & MT_NOARG_P) {
|
||||
MRB_METHOD_NOARG_SET(m);
|
||||
}
|
||||
#ifndef MRB_NO_METHOD_CACHE
|
||||
|
||||
Reference in New Issue
Block a user