diff options
| author | Jean Boussier <jean.boussier@gmail.com> | 2026-04-11 15:42:19 +0200 |
|---|---|---|
| committer | Jean Boussier <jean.boussier@gmail.com> | 2026-04-12 14:59:53 +0200 |
| commit | 8e96d6f792ccc840b804a4fd443d0b0064b54752 (patch) | |
| tree | 3735cbc6491777f39a1a41c3e1f70c6c58f9e38d | |
| parent | d0ef5d137fa1d128a0fcb8564c6966177313ab92 (diff) | |
rb_gc_obj_optimal_size: don't enlarge small AR table hashes
Ref: https://github.com/ruby/ruby/pull/16653
Frozen hashes backed by AR tables can be smaller than 160B.
| -rw-r--r-- | gc.c | 7 | ||||
| -rw-r--r-- | hash.c | 16 | ||||
| -rw-r--r-- | internal/hash.h | 16 |
3 files changed, 22 insertions, 17 deletions
@@ -3601,7 +3601,12 @@ rb_gc_obj_optimal_size(VALUE obj) } case T_HASH: - return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table)); + { + if (RB_OBJ_FROZEN(obj) && RHASH_AR_TABLE_P(obj)) { + return sizeof(struct RHash) + offsetof(ar_table, pairs) + RHASH_AR_TABLE_BOUND(obj) * sizeof(ar_table_pair); + } + return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table)); + } default: return 0; @@ -471,24 +471,8 @@ ar_set_entry(VALUE hash, unsigned int index, st_data_t key, st_data_t val, st_ha #define RHASH_AR_TABLE_SIZE(h) (HASH_ASSERT(RHASH_AR_TABLE_P(h)), \ RHASH_AR_TABLE_SIZE_RAW(h)) -#define RHASH_AR_TABLE_BOUND_RAW(h) \ - ((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \ - (RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT))) - -#define RHASH_ST_TABLE_SET(h, s) rb_hash_st_table_set(h, s) -#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type) - #define HASH_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(HASH_DEBUG, expr, #expr) -static inline unsigned int -RHASH_AR_TABLE_BOUND(VALUE h) -{ - HASH_ASSERT(RHASH_AR_TABLE_P(h)); - const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h); - HASH_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE); - return bound; -} - #if HASH_DEBUG #define hash_verify(hash) hash_verify_(hash, __FILE__, __LINE__) diff --git a/internal/hash.h b/internal/hash.h index 3a5be14ad7..8c5511e82b 100644 --- a/internal/hash.h +++ b/internal/hash.h @@ -193,4 +193,20 @@ RHASH_AR_TABLE_SIZE_RAW(VALUE h) return (unsigned)ret; } +#define RHASH_AR_TABLE_BOUND_RAW(h) \ + ((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \ + (RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT))) + +#define RHASH_ST_TABLE_SET(h, s) rb_hash_st_table_set(h, s) +#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type) + +static inline unsigned int +RHASH_AR_TABLE_BOUND(VALUE h) +{ + RUBY_ASSERT(RHASH_AR_TABLE_P(h)); + const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h); + RUBY_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE); + return bound; +} + #endif /* INTERNAL_HASH_H */ |
