class.c: remove `mt_elem` structure to avoid alignment gaps.

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