Skip to content

Commit 8e96d6f

Browse files
committed
rb_gc_obj_optimal_size: don't enlarge small AR table hashes
Ref: ruby#16653 Frozen hashes backed by AR tables can be smaller than 160B.
1 parent d0ef5d1 commit 8e96d6f

3 files changed

Lines changed: 22 additions & 17 deletions

File tree

gc.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3601,7 +3601,12 @@ rb_gc_obj_optimal_size(VALUE obj)
36013601
}
36023602

36033603
case T_HASH:
3604-
return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table));
3604+
{
3605+
if (RB_OBJ_FROZEN(obj) && RHASH_AR_TABLE_P(obj)) {
3606+
return sizeof(struct RHash) + offsetof(ar_table, pairs) + RHASH_AR_TABLE_BOUND(obj) * sizeof(ar_table_pair);
3607+
}
3608+
return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table));
3609+
}
36053610

36063611
default:
36073612
return 0;

hash.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -471,24 +471,8 @@ ar_set_entry(VALUE hash, unsigned int index, st_data_t key, st_data_t val, st_ha
471471
#define RHASH_AR_TABLE_SIZE(h) (HASH_ASSERT(RHASH_AR_TABLE_P(h)), \
472472
RHASH_AR_TABLE_SIZE_RAW(h))
473473

474-
#define RHASH_AR_TABLE_BOUND_RAW(h) \
475-
((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
476-
(RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))
477-
478-
#define RHASH_ST_TABLE_SET(h, s) rb_hash_st_table_set(h, s)
479-
#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type)
480-
481474
#define HASH_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(HASH_DEBUG, expr, #expr)
482475

483-
static inline unsigned int
484-
RHASH_AR_TABLE_BOUND(VALUE h)
485-
{
486-
HASH_ASSERT(RHASH_AR_TABLE_P(h));
487-
const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h);
488-
HASH_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE);
489-
return bound;
490-
}
491-
492476
#if HASH_DEBUG
493477
#define hash_verify(hash) hash_verify_(hash, __FILE__, __LINE__)
494478

internal/hash.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,20 @@ RHASH_AR_TABLE_SIZE_RAW(VALUE h)
193193
return (unsigned)ret;
194194
}
195195

196+
#define RHASH_AR_TABLE_BOUND_RAW(h) \
197+
((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
198+
(RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))
199+
200+
#define RHASH_ST_TABLE_SET(h, s) rb_hash_st_table_set(h, s)
201+
#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type)
202+
203+
static inline unsigned int
204+
RHASH_AR_TABLE_BOUND(VALUE h)
205+
{
206+
RUBY_ASSERT(RHASH_AR_TABLE_P(h));
207+
const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h);
208+
RUBY_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE);
209+
return bound;
210+
}
211+
196212
#endif /* INTERNAL_HASH_H */

0 commit comments

Comments
 (0)