1
0
Fork 0
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:
ko1 2018-10-30 22:11:51 +00:00
parent ca83ed8db6
commit 8f675cdd00
22 changed files with 1400 additions and 252 deletions

View file

@ -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
View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

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

View file

@ -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
View file

@ -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)) {

1311
hash.c

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

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

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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
View file

@ -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);

View file

@ -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

View file

@ -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);
}
}

View file

@ -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 */
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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 {