Skip to content

Commit f70c081

Browse files
committed
Always allocate CDHASH in 80B slots
Up to size 8, `rb_hash_new_with_size()` will allocate a 160B slot to fit a full `ar_table`. But in the case of CDHASH, we immediately assign a custom hash type, which trigger the conversion into an `st_table`, potentially wasting 80B.
1 parent c0d86a0 commit f70c081

File tree

3 files changed

+30
-12
lines changed

3 files changed

+30
-12
lines changed

compile.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7067,7 +7067,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
70677067
DECL_ANCHOR(body_seq);
70687068
DECL_ANCHOR(cond_seq);
70697069
int only_special_literals = 1;
7070-
VALUE literals = rb_hash_new();
7070+
VALUE literals = rb_hash_new_with_size_and_type(0, 0, &cdhash_type);
70717071
int line;
70727072
enum node_type type;
70737073
const NODE *line_node;
@@ -7078,8 +7078,6 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
70787078
INIT_ANCHOR(body_seq);
70797079
INIT_ANCHOR(cond_seq);
70807080

7081-
RHASH_TBL_RAW(literals)->type = &cdhash_type;
7082-
70837081
CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
70847082

70857083
branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
@@ -7165,7 +7163,6 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
71657163

71667164
if (only_special_literals && ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
71677165
ADD_INSN(ret, orig_node, dup);
7168-
rb_obj_hide(literals);
71697166
ADD_INSN2(ret, orig_node, opt_case_dispatch, literals, elselabel);
71707167
RB_OBJ_WRITTEN(iseq, Qundef, literals);
71717168
LABEL_REF(elselabel);
@@ -12167,9 +12164,8 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
1216712164
case TS_CDHASH:
1216812165
{
1216912166
int i;
12170-
VALUE map = rb_hash_new_with_size(RARRAY_LEN(op)/2);
12167+
VALUE map = rb_hash_new_with_size_and_type(0, RARRAY_LEN(op)/2, &cdhash_type);
1217112168

12172-
RHASH_TBL_RAW(map)->type = &cdhash_type;
1217312169
op = rb_to_array_type(op);
1217412170
for (i=0; i<RARRAY_LEN(op); i+=2) {
1217512171
VALUE key = RARRAY_AREF(op, i);
@@ -12179,7 +12175,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
1217912175
rb_hash_aset(map, key, (VALUE)label | 1);
1218012176
}
1218112177
RB_GC_GUARD(op);
12182-
RB_OBJ_SET_SHAREABLE(rb_obj_hide(map)); // allow mutation while compiling
12178+
RB_OBJ_SET_SHAREABLE(map); // allow mutation while compiling
1218312179
argv[j] = map;
1218412180
RB_OBJ_WRITTEN(iseq, Qundef, map);
1218512181
}
@@ -13004,6 +13000,20 @@ ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
1300413000
return offset;
1300513001
}
1300613002

13003+
static int
13004+
cdhash_copy_i(st_data_t key, st_data_t val, st_data_t arg)
13005+
{
13006+
rb_hash_aset((VALUE)arg, (VALUE)key, (VALUE)val);
13007+
return ST_CONTINUE;
13008+
}
13009+
13010+
static VALUE
13011+
cdhash_copy(VALUE dest, VALUE src)
13012+
{
13013+
rb_hash_stlike_foreach(src, cdhash_copy_i, dest);
13014+
return dest;
13015+
}
13016+
1300713017
static VALUE *
1300813018
ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecode_offset, ibf_offset_t bytecode_size, unsigned int iseq_size)
1300913019
{
@@ -13058,11 +13068,10 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
1305813068
case TS_CDHASH:
1305913069
{
1306013070
VALUE op = ibf_load_small_value(load, &reading_pos);
13061-
VALUE v = ibf_load_object(load, op);
13062-
v = rb_hash_dup(v); // hash dumped as frozen
13063-
RHASH_TBL_RAW(v)->type = &cdhash_type;
13064-
rb_hash_rehash(v); // hash function changed
13065-
RB_OBJ_SET_SHAREABLE(freeze_hide_obj(v));
13071+
VALUE src = ibf_load_object(load, op);
13072+
VALUE v = rb_hash_new_with_size_and_type(0, RHASH_SIZE(src), &cdhash_type);
13073+
rb_hash_rehash(cdhash_copy(v, src));
13074+
RB_OBJ_SET_SHAREABLE(v);
1306613075

1306713076
// Overwrite the existing hash in the object list. This
1306813077
// is to keep the object alive during load time.

hash.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,6 +1490,14 @@ rb_hash_new_with_size(st_index_t size)
14901490
return ret;
14911491
}
14921492

1493+
VALUE
1494+
rb_hash_new_with_size_and_type(VALUE klass, st_index_t size, const struct st_hash_type *type)
1495+
{
1496+
VALUE ret = hash_alloc_flags(klass, 0, Qnil, true);
1497+
hash_st_table_init(ret, type, size);
1498+
return ret;
1499+
}
1500+
14931501
VALUE
14941502
rb_hash_new_capa(long capa)
14951503
{

internal/hash.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t
112112
RUBY_SYMBOL_EXPORT_END
113113

114114
VALUE rb_hash_new_with_size(st_index_t size);
115+
VALUE rb_hash_new_with_size_and_type(VALUE klass, st_index_t size, const struct st_hash_type *type);
115116
VALUE rb_hash_resurrect(VALUE hash);
116117
int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
117118
VALUE rb_hash_keys(VALUE hash);

0 commit comments

Comments
 (0)