mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
support theap for T_HASH. [Feature #14989]
* hash.c, internal.h: support theap for small Hash. Introduce RHASH_ARRAY (li_table) besides st_table and small Hash (<=8 entries) are managed by an array data structure. This array data can be managed by theap. If st_table is needed, then converting array data to st_table data. For st_table using code, we prepare "stlike" APIs which accepts hash value and are very similar to st_ APIs. This work is based on the GSoC achievement by tacinight <tacingiht@gmail.com> and refined by ko1. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65454 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
ca83ed8db6
commit
8f675cdd00
22 changed files with 1400 additions and 252 deletions
8
.gdbinit
8
.gdbinit
|
@ -156,8 +156,12 @@ define rp
|
|||
else
|
||||
if ($flags & RUBY_T_MASK) == RUBY_T_HASH
|
||||
printf "%sT_HASH%s: ", $color_type, $color_end,
|
||||
if ((struct RHash *)($arg0))->ntbl
|
||||
printf "len=%ld ", ((struct RHash *)($arg0))->ntbl->num_entries
|
||||
if (((struct RHash *)($arg0))->basic->flags & RHASH_ST_TABLE_FLAG)
|
||||
printf "st len=%ld ", ((struct RHash *)($arg0))->as.st->num_entries
|
||||
else
|
||||
printf "li len=%ld bound=%ld ", \
|
||||
((((struct RHash *)($arg0))->basic->flags & RHASH_ARRAY_LEN_MASK) >> RHASH_ARRAY_LEN_SHIFT), \
|
||||
((((struct RHash *)($arg0))->basic->flags & RHASH_ARRAY_BOUND_MASK) >> RHASH_ARRAY_BOUND_SHIFT)
|
||||
end
|
||||
print (struct RHash *)($arg0)
|
||||
else
|
||||
|
|
18
array.c
18
array.c
|
@ -4420,11 +4420,11 @@ static inline void
|
|||
ary_recycle_hash(VALUE hash)
|
||||
{
|
||||
assert(RBASIC_CLASS(hash) == 0);
|
||||
if (RHASH(hash)->ntbl) {
|
||||
st_table *tbl = RHASH(hash)->ntbl;
|
||||
if (RHASH_TABLE_P(hash)) {
|
||||
st_table *tbl = RHASH_ST_TABLE(hash);
|
||||
st_free_table(tbl);
|
||||
RHASH_CLEAR(hash);
|
||||
}
|
||||
rb_gc_force_recycle(hash);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4467,7 +4467,7 @@ rb_ary_diff(VALUE ary1, VALUE ary2)
|
|||
|
||||
hash = ary_make_hash(ary2);
|
||||
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
||||
if (st_lookup(rb_hash_tbl_raw(hash), RARRAY_AREF(ary1, i), 0)) continue;
|
||||
if (rb_hash_stlike_lookup(hash, RARRAY_AREF(ary1, i), NULL)) continue;
|
||||
rb_ary_push(ary3, rb_ary_elt(ary1, i));
|
||||
}
|
||||
ary_recycle_hash(hash);
|
||||
|
@ -4515,7 +4515,7 @@ rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary)
|
|||
VALUE elt = rb_ary_elt(ary, i);
|
||||
for (j = 0; j < argc; j++){
|
||||
if (is_hash[j]) {
|
||||
if (st_lookup(rb_hash_tbl_raw(argv[j]), RARRAY_AREF(ary, i), 0))
|
||||
if (rb_hash_stlike_lookup(argv[j], RARRAY_AREF(ary, i), NULL))
|
||||
break;
|
||||
}
|
||||
else {
|
||||
|
@ -4551,7 +4551,6 @@ static VALUE
|
|||
rb_ary_and(VALUE ary1, VALUE ary2)
|
||||
{
|
||||
VALUE hash, ary3, v;
|
||||
st_table *table;
|
||||
st_data_t vv;
|
||||
long i;
|
||||
|
||||
|
@ -4570,12 +4569,11 @@ rb_ary_and(VALUE ary1, VALUE ary2)
|
|||
}
|
||||
|
||||
hash = ary_make_hash(ary2);
|
||||
table = rb_hash_tbl_raw(hash);
|
||||
|
||||
for (i=0; i<RARRAY_LEN(ary1); i++) {
|
||||
v = RARRAY_AREF(ary1, i);
|
||||
vv = (st_data_t)v;
|
||||
if (st_delete(table, &vv, 0)) {
|
||||
if (rb_hash_stlike_delete(hash, &vv, 0)) {
|
||||
rb_ary_push(ary3, v);
|
||||
}
|
||||
}
|
||||
|
@ -4609,7 +4607,7 @@ rb_ary_union_hash(VALUE hash, VALUE ary2)
|
|||
long i;
|
||||
for (i = 0; i < RARRAY_LEN(ary2); i++) {
|
||||
VALUE elt = RARRAY_AREF(ary2, i);
|
||||
if (!st_update(RHASH_TBL_RAW(hash), (st_data_t)elt, ary_hash_orset, (st_data_t)elt)) {
|
||||
if (!rb_hash_stlike_update(hash, (st_data_t)elt, ary_hash_orset, (st_data_t)elt)) {
|
||||
RB_OBJ_WRITTEN(hash, Qundef, elt);
|
||||
}
|
||||
}
|
||||
|
@ -4866,7 +4864,7 @@ rb_ary_uniq_bang(VALUE ary)
|
|||
FL_SET_EMBED(ary);
|
||||
}
|
||||
ary_resize_capa(ary, hash_size);
|
||||
st_foreach(rb_hash_tbl_raw(hash), push_value, ary);
|
||||
rb_hash_foreach(hash, push_value, ary);
|
||||
ary_recycle_hash(hash);
|
||||
|
||||
return ary;
|
||||
|
|
9
class.c
9
class.c
|
@ -1804,11 +1804,10 @@ NORETURN(static void unknown_keyword_error(VALUE hash, const ID *table, int keyw
|
|||
static void
|
||||
unknown_keyword_error(VALUE hash, const ID *table, int keywords)
|
||||
{
|
||||
st_table *tbl = rb_hash_tbl_raw(hash);
|
||||
int i;
|
||||
for (i = 0; i < keywords; i++) {
|
||||
st_data_t key = ID2SYM(table[i]);
|
||||
st_delete(tbl, &key, NULL);
|
||||
rb_hash_stlike_delete(hash, &key, NULL);
|
||||
}
|
||||
rb_keyword_error("unknown", rb_hash_keys(hash));
|
||||
}
|
||||
|
@ -1855,7 +1854,7 @@ rb_extract_keywords(VALUE *orighash)
|
|||
*orighash = 0;
|
||||
return hash;
|
||||
}
|
||||
st_foreach(rb_hash_tbl_raw(hash), separate_symbol, (st_data_t)&arg);
|
||||
rb_hash_foreach(hash, separate_symbol, (st_data_t)&arg);
|
||||
if (arg.kwdhash) {
|
||||
if (arg.nonsymkey != Qundef) {
|
||||
rb_raise(rb_eArgError, "non-symbol key in keyword arguments: %+"PRIsVALUE,
|
||||
|
@ -1876,8 +1875,8 @@ rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, V
|
|||
|
||||
#define extract_kwarg(keyword, val) \
|
||||
(key = (st_data_t)(keyword), values ? \
|
||||
st_delete(rb_hash_tbl_raw(keyword_hash), &key, (val)) : \
|
||||
st_lookup(rb_hash_tbl_raw(keyword_hash), key, (val)))
|
||||
rb_hash_stlike_delete(keyword_hash, &key, (val)) : \
|
||||
rb_hash_stlike_lookup(keyword_hash, key, (val)))
|
||||
|
||||
if (NIL_P(keyword_hash)) keyword_hash = 0;
|
||||
|
||||
|
|
|
@ -5017,7 +5017,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
|
|||
INIT_ANCHOR(body_seq);
|
||||
INIT_ANCHOR(cond_seq);
|
||||
|
||||
rb_hash_tbl_raw(literals)->type = &cdhash_type;
|
||||
RHASH_TBL_RAW(literals)->type = &cdhash_type;
|
||||
|
||||
CHECK(COMPILE(head, "case base", node->nd_head));
|
||||
|
||||
|
@ -7990,7 +7990,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
|
|||
int i;
|
||||
VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
|
||||
|
||||
rb_hash_tbl_raw(map)->type = &cdhash_type;
|
||||
RHASH_TBL_RAW(map)->type = &cdhash_type;
|
||||
op = rb_to_array_type(op);
|
||||
for (i=0; i<RARRAY_LEN(op); i+=2) {
|
||||
VALUE key = RARRAY_AREF(op, i);
|
||||
|
|
|
@ -181,6 +181,11 @@ RB_DEBUG_COUNTER(obj_hash_empty)
|
|||
RB_DEBUG_COUNTER(obj_hash_under4)
|
||||
RB_DEBUG_COUNTER(obj_hash_ge4)
|
||||
RB_DEBUG_COUNTER(obj_hash_ge8)
|
||||
RB_DEBUG_COUNTER(obj_hash_array)
|
||||
RB_DEBUG_COUNTER(obj_hash_st)
|
||||
RB_DEBUG_COUNTER(obj_hash_transient)
|
||||
|
||||
RB_DEBUG_COUNTER(obj_hash_force_convert)
|
||||
|
||||
RB_DEBUG_COUNTER(obj_struct_embed)
|
||||
RB_DEBUG_COUNTER(obj_struct_transient)
|
||||
|
|
|
@ -824,7 +824,7 @@ static int
|
|||
collect_values_of_values(VALUE category, VALUE category_objects, VALUE categories)
|
||||
{
|
||||
VALUE ary = rb_ary_new();
|
||||
st_foreach(rb_hash_tbl(category_objects), collect_values, ary);
|
||||
rb_hash_foreach(category_objects, collect_values, ary);
|
||||
rb_hash_aset(categories, category, ary);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
|
93
gc.c
93
gc.c
|
@ -2265,23 +2265,43 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
|
|||
rb_ary_free(obj);
|
||||
break;
|
||||
case T_HASH:
|
||||
if (RANY(obj)->as.hash.ntbl) {
|
||||
#if USE_DEBUG_COUNTER
|
||||
if (RHASH_SIZE(obj) >= 8) {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_ge8);
|
||||
}
|
||||
if (RHASH_SIZE(obj) >= 4) {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_ge4);
|
||||
}
|
||||
else {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_under4);
|
||||
}
|
||||
#endif
|
||||
st_free_table(RANY(obj)->as.hash.ntbl);
|
||||
}
|
||||
if (RHASH_SIZE(obj) >= 8) {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_ge8);
|
||||
}
|
||||
else if (RHASH_SIZE(obj) >= 4) {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_ge4);
|
||||
}
|
||||
else if (RHASH_SIZE(obj) >= 1) {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_under4);
|
||||
}
|
||||
else {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_empty);
|
||||
}
|
||||
|
||||
if (RHASH_ARRAY_P(obj)) {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_array);
|
||||
}
|
||||
else {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_st);
|
||||
}
|
||||
#endif
|
||||
if (/* RHASH_ARRAY_P(obj) */ !FL_TEST_RAW(obj, RHASH_ST_TABLE_FLAG)) {
|
||||
li_table *tab = RHASH(obj)->as.li;
|
||||
|
||||
if (tab) {
|
||||
if (RHASH_TRANSIENT_P(obj)) {
|
||||
RB_DEBUG_COUNTER_INC(obj_hash_transient);
|
||||
}
|
||||
else {
|
||||
ruby_xfree(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
GC_ASSERT(RHASH_TABLE_P(obj));
|
||||
st_free_table(RHASH(obj)->as.st);
|
||||
}
|
||||
break;
|
||||
case T_REGEXP:
|
||||
if (RANY(obj)->as.regexp.ptr) {
|
||||
|
@ -3337,8 +3357,12 @@ obj_memsize_of(VALUE obj, int use_all_types)
|
|||
size += rb_ary_memsize(obj);
|
||||
break;
|
||||
case T_HASH:
|
||||
if (RHASH(obj)->ntbl) {
|
||||
size += st_memsize(RHASH(obj)->ntbl);
|
||||
if (RHASH_ARRAY_P(obj)) {
|
||||
size += sizeof(li_table);
|
||||
}
|
||||
else {
|
||||
VM_ASSERT(RHASH_ST_TABLE(obj) != NULL);
|
||||
size += st_memsize(RHASH_ST_TABLE(obj));
|
||||
}
|
||||
break;
|
||||
case T_REGEXP:
|
||||
|
@ -3491,7 +3515,7 @@ count_objects(int argc, VALUE *argv, VALUE os)
|
|||
hash = rb_hash_new();
|
||||
}
|
||||
else if (!RHASH_EMPTY_P(hash)) {
|
||||
st_foreach(RHASH_TBL_RAW(hash), set_zero, hash);
|
||||
rb_hash_stlike_foreach(hash, set_zero, hash);
|
||||
}
|
||||
rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
|
||||
rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed));
|
||||
|
@ -4225,7 +4249,23 @@ mark_keyvalue(st_data_t key, st_data_t value, st_data_t data)
|
|||
}
|
||||
|
||||
static void
|
||||
mark_hash(rb_objspace_t *objspace, st_table *tbl)
|
||||
mark_hash(rb_objspace_t *objspace, VALUE hash)
|
||||
{
|
||||
rb_hash_stlike_foreach(hash, mark_keyvalue, (st_data_t)objspace);
|
||||
|
||||
if (RHASH_ARRAY_P(hash)) {
|
||||
if (objspace->mark_func_data == NULL && RHASH_TRANSIENT_P(hash)) {
|
||||
rb_transient_heap_mark(hash, RHASH_ARRAY(hash));
|
||||
}
|
||||
}
|
||||
else {
|
||||
VM_ASSERT(!RHASH_TRANSIENT_P(hash));
|
||||
}
|
||||
gc_mark(objspace, RHASH(hash)->ifnone);
|
||||
}
|
||||
|
||||
static void
|
||||
mark_st(rb_objspace_t *objspace, st_table *tbl)
|
||||
{
|
||||
if (!tbl) return;
|
||||
st_foreach(tbl, mark_keyvalue, (st_data_t)objspace);
|
||||
|
@ -4234,7 +4274,7 @@ mark_hash(rb_objspace_t *objspace, st_table *tbl)
|
|||
void
|
||||
rb_mark_hash(st_table *tbl)
|
||||
{
|
||||
mark_hash(&rb_objspace, tbl);
|
||||
mark_st(&rb_objspace, tbl);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -4699,8 +4739,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj)
|
|||
break;
|
||||
|
||||
case T_HASH:
|
||||
mark_hash(objspace, any->as.hash.ntbl);
|
||||
gc_mark(objspace, any->as.hash.ifnone);
|
||||
mark_hash(objspace, obj);
|
||||
break;
|
||||
|
||||
case T_STRING:
|
||||
|
@ -9582,6 +9621,13 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
|
|||
{
|
||||
if (SPECIAL_CONST_P(obj)) {
|
||||
snprintf(buff, buff_size, "%s", obj_type_name(obj));
|
||||
|
||||
if (FIXNUM_P(obj)) {
|
||||
snprintf(buff, buff_size, "%s %ld", buff, FIX2LONG(obj));
|
||||
}
|
||||
else if (SYMBOL_P(obj)) {
|
||||
snprintf(buff, buff_size, "%s %s", buff, rb_id2name(SYM2ID(obj)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
#define TF(c) ((c) != 0 ? "true" : "false")
|
||||
|
@ -9658,6 +9704,13 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
|
|||
snprintf(buff, buff_size, "%s %s", buff, RSTRING_PTR(obj));
|
||||
break;
|
||||
}
|
||||
case T_HASH: {
|
||||
snprintf(buff, buff_size, "%s [%c%c] %d", buff,
|
||||
RHASH_ARRAY_P(obj) ? 'A' : 'S',
|
||||
RHASH_TRANSIENT_P(obj) ? 'T' : ' ',
|
||||
(int)RHASH_SIZE(obj));
|
||||
break;
|
||||
}
|
||||
case T_CLASS: {
|
||||
VALUE class_path = rb_class_path_cached(obj);
|
||||
if (!NIL_P(class_path)) {
|
||||
|
|
|
@ -520,11 +520,12 @@ VALUE rb_hash_delete(VALUE,VALUE);
|
|||
VALUE rb_hash_set_ifnone(VALUE hash, VALUE ifnone);
|
||||
typedef VALUE rb_hash_update_func(VALUE newkey, VALUE oldkey, VALUE value);
|
||||
VALUE rb_hash_update_by(VALUE hash1, VALUE hash2, rb_hash_update_func *func);
|
||||
struct st_table *rb_hash_tbl(VALUE);
|
||||
struct st_table *rb_hash_tbl(VALUE, const char *file, int line);
|
||||
int rb_path_check(const char*);
|
||||
int rb_env_path_tainted(void);
|
||||
VALUE rb_env_clear(void);
|
||||
VALUE rb_hash_size(VALUE);
|
||||
void rb_hash_free(VALUE);
|
||||
/* io.c */
|
||||
#define rb_defout rb_stdout
|
||||
RUBY_EXTERN VALUE rb_fs;
|
||||
|
|
|
@ -1088,11 +1088,13 @@ struct RRegexp {
|
|||
#define RREGEXP_SRC_LEN(r) RSTRING_LEN(RREGEXP(r)->src)
|
||||
#define RREGEXP_SRC_END(r) RSTRING_END(RREGEXP(r)->src)
|
||||
|
||||
/* RHASH_TBL allocates st_table if not available. */
|
||||
#define RHASH_TBL(h) rb_hash_tbl(h)
|
||||
/* RHash is defined at internal.h */
|
||||
size_t rb_hash_size_num(VALUE hash);
|
||||
|
||||
#define RHASH_TBL(h) rb_hash_tbl(h, __FILE__, __LINE__)
|
||||
#define RHASH_ITER_LEV(h) rb_hash_iter_lev(h)
|
||||
#define RHASH_IFNONE(h) rb_hash_ifnone(h)
|
||||
#define RHASH_SIZE(h) NUM2SIZET(rb_hash_size(h))
|
||||
#define RHASH_SIZE(h) rb_hash_size_num(h)
|
||||
#define RHASH_EMPTY_P(h) (RHASH_SIZE(h) == 0)
|
||||
#define RHASH_SET_IFNONE(h, ifnone) rb_hash_set_ifnone((VALUE)h, ifnone)
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ CONSTFUNC(st_index_t st_hash_end(st_index_t h));
|
|||
CONSTFUNC(st_index_t st_hash_start(st_index_t h));
|
||||
#define st_hash_start(h) ((st_index_t)(h))
|
||||
|
||||
void rb_hash_bulk_insert(long, const VALUE *, VALUE);
|
||||
void rb_hash_bulk_insert_into_st_table(long, const VALUE *, VALUE);
|
||||
|
||||
RUBY_SYMBOL_EXPORT_END
|
||||
|
||||
|
|
103
internal.h
103
internal.h
|
@ -672,23 +672,90 @@ struct RComplex {
|
|||
#define RCOMPLEX_SET_REAL(cmp, r) RB_OBJ_WRITE((cmp), &((struct RComplex *)(cmp))->real,(r))
|
||||
#define RCOMPLEX_SET_IMAG(cmp, i) RB_OBJ_WRITE((cmp), &((struct RComplex *)(cmp))->imag,(i))
|
||||
|
||||
enum ruby_rhash_flags {
|
||||
RHASH_ST_TABLE_FLAG = FL_USER3,
|
||||
RHASH_ARRAY_MAX_SIZE = 8,
|
||||
RHASH_ARRAY_SIZE_MASK = (FL_USER4|FL_USER5|FL_USER6|FL_USER7),
|
||||
RHASH_ARRAY_SIZE_SHIFT = (FL_USHIFT+4),
|
||||
RHASH_ARRAY_BOUND_MASK = (FL_USER8|FL_USER9|FL_USER10|FL_USER11),
|
||||
RHASH_ARRAY_BOUND_SHIFT = (FL_USHIFT+8),
|
||||
|
||||
RHASH_ENUM_END
|
||||
};
|
||||
|
||||
#define HASH_PROC_DEFAULT FL_USER2
|
||||
|
||||
#define RHASH_ARRAY_SIZE_RAW(h) \
|
||||
((long)((RBASIC(h)->flags & RHASH_ARRAY_SIZE_MASK) >> RHASH_ARRAY_SIZE_SHIFT))
|
||||
|
||||
int rb_hash_array_p(VALUE hash);
|
||||
struct li_table *rb_hash_array(VALUE hash);
|
||||
st_table *rb_hash_st_table(VALUE hash);
|
||||
void rb_hash_st_table_set(VALUE hash, st_table *st);
|
||||
|
||||
#if 0 /* for debug */
|
||||
#define RHASH_ARRAY_P(hash) rb_hash_array_p(hash)
|
||||
#define RHASH_ARRAY(h) rb_hash_array(h)
|
||||
#define RHASH_ST_TABLE(h) rb_hash_st_table(h)
|
||||
#else
|
||||
#define RHASH_ARRAY_P(hash) (!FL_TEST_RAW((hash), RHASH_ST_TABLE_FLAG))
|
||||
#define RHASH_ARRAY(hash) (RHASH(hash)->as.li)
|
||||
#define RHASH_ST_TABLE(hash) (RHASH(hash)->as.st)
|
||||
#endif
|
||||
|
||||
#define RHASH(obj) (R_CAST(RHash)(obj))
|
||||
#define RHASH_ST_SIZE(h) (RHASH_ST_TABLE(h)->num_entries)
|
||||
#define RHASH_TABLE_P(h) (!RHASH_ARRAY_P(h))
|
||||
#define RHASH_CLEAR(h) (FL_UNSET_RAW(h, RHASH_ST_TABLE_FLAG), RHASH(h)->as.li = NULL)
|
||||
|
||||
#define RHASH_ARRAY_SIZE_MASK (VALUE)RHASH_ARRAY_SIZE_MASK
|
||||
#define RHASH_ARRAY_SIZE_SHIFT RHASH_ARRAY_SIZE_SHIFT
|
||||
#define RHASH_ARRAY_BOUND_MASK (VALUE)RHASH_ARRAY_BOUND_MASK
|
||||
#define RHASH_ARRAY_BOUND_SHIFT RHASH_ARRAY_BOUND_SHIFT
|
||||
#define RHASH_TRANSIENT_FLAG FL_USER14
|
||||
#define RHASH_TRANSIENT_P(hash) FL_TEST_RAW((hash), RHASH_TRANSIENT_FLAG)
|
||||
|
||||
#define RHASH_ARRAY_MAX_SIZE 8
|
||||
#define RHASH_ARRAY_MAX_BOUND RHASH_ARRAY_MAX_SIZE
|
||||
|
||||
typedef struct li_table_entry {
|
||||
VALUE hash;
|
||||
VALUE key;
|
||||
VALUE record;
|
||||
} li_table_entry;
|
||||
|
||||
typedef struct li_table {
|
||||
li_table_entry entries[RHASH_ARRAY_MAX_SIZE];
|
||||
} li_table;
|
||||
|
||||
/*
|
||||
* RHASH_ARRAY_P(h):
|
||||
* * as.li == NULL or
|
||||
* as.li points li_table.
|
||||
* * as.li is allocated by transient heap or xmalloc.
|
||||
*
|
||||
* !RHASH_ARRAY_P(h):
|
||||
* * as.st points st_table.
|
||||
*/
|
||||
struct RHash {
|
||||
struct RBasic basic;
|
||||
struct st_table *ntbl; /* possibly 0 */
|
||||
union {
|
||||
struct st_table *st;
|
||||
struct li_table *li; /* possibly 0 */
|
||||
} as;
|
||||
int iter_lev;
|
||||
const VALUE ifnone;
|
||||
};
|
||||
|
||||
#define RHASH(obj) (R_CAST(RHash)(obj))
|
||||
|
||||
#ifdef RHASH_ITER_LEV
|
||||
#undef RHASH_ITER_LEV
|
||||
#undef RHASH_IFNONE
|
||||
#undef RHASH_SIZE
|
||||
#define RHASH_ITER_LEV(h) (RHASH(h)->iter_lev)
|
||||
#define RHASH_IFNONE(h) (RHASH(h)->ifnone)
|
||||
#define RHASH_SIZE(h) (RHASH(h)->ntbl ? RHASH(h)->ntbl->num_entries : (st_index_t)0)
|
||||
#endif
|
||||
# undef RHASH_ITER_LEV
|
||||
# undef RHASH_IFNONE
|
||||
# undef RHASH_SIZE
|
||||
|
||||
# define RHASH_ITER_LEV(h) (RHASH(h)->iter_lev)
|
||||
# define RHASH_IFNONE(h) (RHASH(h)->ifnone)
|
||||
# define RHASH_SIZE(h) (RHASH_ARRAY_P(h) ? RHASH_ARRAY_SIZE_RAW(h) : RHASH_ST_SIZE(h))
|
||||
#endif /* #ifdef RHASH_ITER_LEV */
|
||||
|
||||
/* missing/setproctitle.c */
|
||||
#ifndef HAVE_SETPROCTITLE
|
||||
|
@ -1372,7 +1439,14 @@ void *rb_aligned_malloc(size_t, size_t);
|
|||
void rb_aligned_free(void *);
|
||||
|
||||
/* hash.c */
|
||||
#if RHASH_CONVERT_TABLE_DEBUG
|
||||
struct st_table *rb_hash_tbl_raw(VALUE hash, const char *file, int line);
|
||||
#define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h, __FILE__, __LINE__)
|
||||
#else
|
||||
struct st_table *rb_hash_tbl_raw(VALUE hash);
|
||||
#define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h)
|
||||
#endif
|
||||
|
||||
VALUE rb_hash_new_with_size(st_index_t size);
|
||||
RUBY_SYMBOL_EXPORT_BEGIN
|
||||
VALUE rb_hash_new_compare_by_id(void);
|
||||
|
@ -1387,14 +1461,17 @@ st_table *rb_init_identtable_with_size(st_index_t size);
|
|||
VALUE rb_hash_compare_by_id_p(VALUE hash);
|
||||
VALUE rb_to_hash_type(VALUE obj);
|
||||
VALUE rb_hash_key_str(VALUE);
|
||||
|
||||
#define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h)
|
||||
VALUE rb_hash_keys(VALUE hash);
|
||||
VALUE rb_hash_values(VALUE hash);
|
||||
VALUE rb_hash_rehash(VALUE hash);
|
||||
int rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val);
|
||||
#define HASH_PROC_DEFAULT FL_USER2
|
||||
VALUE rb_hash_set_pair(VALUE hash, VALUE pair);
|
||||
void rb_hash_bulk_insert(long, const VALUE *, VALUE);
|
||||
|
||||
int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
|
||||
int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval);
|
||||
int rb_hash_stlike_foreach(VALUE hash, int (*func)(ANYARGS), st_data_t arg);
|
||||
int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func func, st_data_t arg);
|
||||
|
||||
/* inits.c */
|
||||
void rb_call_inits(void);
|
||||
|
|
|
@ -887,7 +887,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
|
|||
else {
|
||||
w_byte(TYPE_HASH_DEF, arg);
|
||||
}
|
||||
w_long(RHASH_SIZE(obj), arg);
|
||||
w_long(rb_hash_size_num(obj), arg);
|
||||
rb_hash_foreach(obj, hash_each, (st_data_t)&c_arg);
|
||||
if (!NIL_P(RHASH_IFNONE(obj))) {
|
||||
w_object(RHASH_IFNONE(obj), arg, limit);
|
||||
|
|
|
@ -489,7 +489,7 @@ mjit_valid_class_serial_p(rb_serial_t class_serial)
|
|||
int found_p;
|
||||
|
||||
CRITICAL_SECTION_START(3, "in valid_class_serial_p");
|
||||
found_p = st_lookup(RHASH_TBL_RAW(valid_class_serials), LONG2FIX(class_serial), NULL);
|
||||
found_p = rb_hash_stlike_lookup(valid_class_serials, LONG2FIX(class_serial), NULL);
|
||||
CRITICAL_SECTION_FINISH(3, "in valid_class_serial_p");
|
||||
return found_p;
|
||||
}
|
||||
|
|
|
@ -2214,7 +2214,7 @@ rb_check_exec_options(VALUE opthash, VALUE execarg_obj)
|
|||
{
|
||||
if (RHASH_EMPTY_P(opthash))
|
||||
return;
|
||||
st_foreach(rb_hash_tbl_raw(opthash), check_exec_options_i, (st_data_t)execarg_obj);
|
||||
rb_hash_stlike_foreach(opthash, check_exec_options_i, (st_data_t)execarg_obj);
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -2225,7 +2225,7 @@ rb_execarg_extract_options(VALUE execarg_obj, VALUE opthash)
|
|||
return Qnil;
|
||||
args[0] = execarg_obj;
|
||||
args[1] = Qnil;
|
||||
st_foreach(rb_hash_tbl_raw(opthash), check_exec_options_i_extract, (st_data_t)args);
|
||||
rb_hash_stlike_foreach(opthash, check_exec_options_i_extract, (st_data_t)args);
|
||||
return args[1];
|
||||
}
|
||||
|
||||
|
@ -2269,7 +2269,7 @@ rb_check_exec_env(VALUE hash, VALUE *path)
|
|||
|
||||
env[0] = hide_obj(rb_ary_new());
|
||||
env[1] = Qfalse;
|
||||
st_foreach(rb_hash_tbl_raw(hash), check_exec_env_i, (st_data_t)env);
|
||||
rb_hash_stlike_foreach(hash, check_exec_env_i, (st_data_t)env);
|
||||
*path = env[1];
|
||||
|
||||
return env[0];
|
||||
|
@ -2733,7 +2733,7 @@ rb_execarg_parent_start1(VALUE execarg_obj)
|
|||
}
|
||||
envp_buf = rb_str_buf_new(0);
|
||||
hide_obj(envp_buf);
|
||||
st_foreach(RHASH_TBL_RAW(envtbl), fill_envp_buf_i, (st_data_t)envp_buf);
|
||||
rb_hash_stlike_foreach(envtbl, fill_envp_buf_i, (st_data_t)envp_buf);
|
||||
envp_str = rb_str_buf_new(sizeof(char*) * (RHASH_SIZE(envtbl) + 1));
|
||||
hide_obj(envp_str);
|
||||
p = RSTRING_PTR(envp_buf);
|
||||
|
|
24
st.c
24
st.c
|
@ -1196,7 +1196,7 @@ st_insert(st_table *tab, st_data_t key, st_data_t value)
|
|||
|
||||
/* Insert (KEY, VALUE, HASH) into table TAB. The table should not have
|
||||
entry with KEY before the insertion. */
|
||||
static inline void
|
||||
void
|
||||
st_add_direct_with_hash(st_table *tab,
|
||||
st_data_t key, st_data_t value, st_hash_t hash)
|
||||
{
|
||||
|
@ -2281,24 +2281,16 @@ st_insert_generic(st_table *tab, long argc, const VALUE *argv, VALUE hash)
|
|||
st_rehash(tab);
|
||||
}
|
||||
|
||||
/* Mimics ruby's { foo => bar } syntax. This function is placed here
|
||||
because it touches table internals and write barriers at once. */
|
||||
/* Mimics ruby's { foo => bar } syntax. This function is subpart
|
||||
of rb_hash_bulk_insert. */
|
||||
void
|
||||
rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
|
||||
rb_hash_bulk_insert_into_st_table(long argc, const VALUE *argv, VALUE hash)
|
||||
{
|
||||
st_index_t n;
|
||||
st_table *tab = RHASH(hash)->ntbl;
|
||||
st_index_t n, size = argc / 2;
|
||||
st_table *tab = RHASH_ST_TABLE(hash);
|
||||
|
||||
st_assert(argc % 2 == 0);
|
||||
if (! argc)
|
||||
return;
|
||||
if (! tab) {
|
||||
VALUE tmp = rb_hash_new_with_size(argc / 2);
|
||||
RBASIC_CLEAR_CLASS(tmp);
|
||||
RHASH(hash)->ntbl = tab = RHASH(tmp)->ntbl;
|
||||
RHASH(tmp)->ntbl = NULL;
|
||||
}
|
||||
n = tab->num_entries + argc / 2;
|
||||
tab = RHASH_TBL_RAW(hash);
|
||||
n = tab->num_entries + size;
|
||||
st_expand_table(tab, n);
|
||||
if (UNLIKELY(tab->num_entries))
|
||||
st_insert_generic(tab, argc, argv, hash);
|
||||
|
|
|
@ -1138,6 +1138,7 @@ class TestTime < Test::Unit::TestCase
|
|||
case size
|
||||
when 20 then expect = 50
|
||||
when 40 then expect = 86
|
||||
when 48 then expect = 94
|
||||
else
|
||||
flunk "Unsupported RVALUE_SIZE=#{size}, update test_memsize"
|
||||
end
|
||||
|
|
10
thread.c
10
thread.c
|
@ -3492,11 +3492,11 @@ rb_thread_variable_p(VALUE thread, VALUE key)
|
|||
|
||||
locals = rb_ivar_get(thread, id_locals);
|
||||
|
||||
if (!RHASH(locals)->ntbl)
|
||||
if (rb_hash_lookup(locals, ID2SYM(id)) != Qnil) {
|
||||
return Qtrue;
|
||||
}
|
||||
else {
|
||||
return Qfalse;
|
||||
|
||||
if (st_lookup(RHASH(locals)->ntbl, ID2SYM(id), 0)) {
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
return Qfalse;
|
||||
|
@ -4349,7 +4349,7 @@ rb_clear_coverages(void)
|
|||
{
|
||||
VALUE coverages = rb_get_coverages();
|
||||
if (RTEST(coverages)) {
|
||||
st_foreach(rb_hash_tbl_raw(coverages), clear_coverage_i, 0);
|
||||
rb_hash_foreach(coverages, clear_coverage_i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -353,9 +353,10 @@ rb_transient_heap_alloc(VALUE obj, size_t req_size)
|
|||
struct transient_heap* theap = transient_heap_get();
|
||||
size_t size = ROUND_UP(req_size + sizeof(struct transient_alloc_header), TRANSIENT_HEAP_ALLOC_ALIGN);
|
||||
|
||||
TH_ASSERT(RB_TYPE_P(obj, T_ARRAY) ||
|
||||
TH_ASSERT(RB_TYPE_P(obj, T_ARRAY) ||
|
||||
RB_TYPE_P(obj, T_OBJECT) ||
|
||||
RB_TYPE_P(obj, T_STRUCT)); /* supported types */
|
||||
RB_TYPE_P(obj, T_STRUCT) ||
|
||||
RB_TYPE_P(obj, T_HASH)); /* supported types */
|
||||
|
||||
if (size > TRANSIENT_HEAP_ALLOC_MAX) {
|
||||
if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [too big: %ld] %s\n", (long)size, rb_obj_info(obj));
|
||||
|
@ -458,7 +459,6 @@ alloc_header_to_block_verbose(struct transient_heap *theap, struct transient_all
|
|||
else {
|
||||
return NULL;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
static struct transient_alloc_header *
|
||||
|
@ -508,7 +508,7 @@ void
|
|||
rb_transient_heap_mark(VALUE obj, const void *ptr)
|
||||
{
|
||||
struct transient_alloc_header *header = ptr_to_alloc_header(ptr);
|
||||
|
||||
if (header->magic != TRANSIENT_HEAP_ALLOC_MAGIC) rb_bug("rb_transient_heap_mark: wrong header, %s (%p)", rb_obj_info(obj), ptr);
|
||||
if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_mark: %s (%p)\n", rb_obj_info(obj), ptr);
|
||||
|
||||
#if TRANSIENT_HEAP_CHECK_MODE > 0
|
||||
|
@ -522,7 +522,7 @@ rb_transient_heap_mark(VALUE obj, const void *ptr)
|
|||
rb_bug("rb_transient_heap_mark: magic is broken");
|
||||
}
|
||||
else if (header->obj != obj) {
|
||||
transient_heap_dump(theap);
|
||||
// transient_heap_dump(theap);
|
||||
rb_bug("rb_transient_heap_mark: unmatch (%s is stored, but %s is given)\n",
|
||||
rb_obj_info(header->obj), rb_obj_info(obj));
|
||||
}
|
||||
|
@ -566,6 +566,15 @@ transient_heap_ptr(VALUE obj, int error)
|
|||
ptr = rb_struct_const_heap_ptr(obj);
|
||||
}
|
||||
break;
|
||||
case T_HASH:
|
||||
if (RHASH_TRANSIENT_P(obj)) {
|
||||
TH_ASSERT(RHASH_ARRAY_P(obj));
|
||||
ptr = (VALUE *)(RHASH(obj)->as.li);
|
||||
}
|
||||
else {
|
||||
ptr = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (error) {
|
||||
rb_bug("transient_heap_ptr: unknown obj %s\n", rb_obj_info(obj));
|
||||
|
@ -657,6 +666,8 @@ transient_heap_block_evacuate(struct transient_heap* theap, struct transient_hea
|
|||
while (marked_index >= 0) {
|
||||
struct transient_alloc_header *header = alloc_header(block, marked_index);
|
||||
VALUE obj = header->obj;
|
||||
TH_ASSERT(header->magic == TRANSIENT_HEAP_ALLOC_MAGIC);
|
||||
if (header->magic != TRANSIENT_HEAP_ALLOC_MAGIC) rb_bug("rb_transient_heap_mark: wrong header %s\n", rb_obj_info(obj));
|
||||
|
||||
if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, " * transient_heap_block_evacuate %p %s\n", header, rb_obj_info(obj));
|
||||
|
||||
|
@ -673,8 +684,11 @@ transient_heap_block_evacuate(struct transient_heap* theap, struct transient_hea
|
|||
case T_STRUCT:
|
||||
rb_struct_transient_heap_evacuate(obj, !TRANSIENT_HEAP_DEBUG_DONT_PROMOTE);
|
||||
break;
|
||||
case T_HASH:
|
||||
rb_hash_transient_heap_evacuate(obj, !TRANSIENT_HEAP_DEBUG_DONT_PROMOTE);
|
||||
break;
|
||||
default:
|
||||
rb_bug("unsupporeted");
|
||||
rb_bug("unsupporeted: %s\n", rb_obj_info(obj));
|
||||
}
|
||||
header->obj = Qundef; /* for debug */
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@ void rb_transient_heap_dump(void);
|
|||
void rb_transient_heap_verify(void);
|
||||
int rb_transient_heap_managed_ptr_p(const void *ptr);
|
||||
|
||||
/* evacuate functions */
|
||||
/* evacuate functions for each type */
|
||||
void rb_ary_transient_heap_evacuate(VALUE ary, int promote);
|
||||
void rb_obj_transient_heap_evacuate(VALUE obj, int promote);
|
||||
void rb_hash_transient_heap_evacuate(VALUE hash, int promote);
|
||||
void rb_struct_transient_heap_evacuate(VALUE st, int promote);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2035,10 +2035,9 @@ static void
|
|||
local_var_list_add(const struct local_var_list *vars, ID lid)
|
||||
{
|
||||
if (lid && rb_is_local_id(lid)) {
|
||||
/* should skip temporary variable */
|
||||
st_table *tbl = RHASH_TBL_RAW(vars->tbl);
|
||||
st_data_t idx = 0; /* tbl->num_entries */
|
||||
st_update(tbl, ID2SYM(lid), local_var_list_update, idx);
|
||||
/* should skip temporary variable */
|
||||
st_data_t idx = 0; /* tbl->num_entries */
|
||||
rb_hash_stlike_update(vars->tbl, ID2SYM(lid), local_var_list_update, idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3327,7 +3327,7 @@ vm_case_dispatch(CDHASH hash, OFFSET else_offset, VALUE key)
|
|||
key = FIXABLE(kval) ? LONG2FIX((long)kval) : rb_dbl2big(kval);
|
||||
}
|
||||
}
|
||||
if (st_lookup(RHASH_TBL_RAW(hash), key, &val)) {
|
||||
if (rb_hash_stlike_lookup(hash, key, &val)) {
|
||||
return FIX2LONG((VALUE)val);
|
||||
}
|
||||
else {
|
||||
|
|
Loading…
Reference in a new issue