Skip to content
  • Dylan Thacker-Smith's avatar
    b9702590
    Stop making a redundant hash copy in Hash#dup (#2489) · b9702590
    Dylan Thacker-Smith authored
    * Stop making a redundant hash copy in Hash#dup
    
    It was making a copy of the hash without rehashing, then created an
    extra copy of the hash to do the rehashing.  Since rehashing creates
    a new copy already, this change just uses that rehashing to make
    the copy.
    
    [Bug #16121]
    
    * Remove redundant Check_Type after to_hash
    
    * Fix freeing and clearing destination hash in Hash#initialize_copy
    
    The code was assuming the state of the destination hash based on the
    source hash for clearing any existing table on it. If these don't match,
    then that can cause the old table to be leaked. This can be seen by
    compiling hash.c with `#define HASH_DEBUG 1` and running the following
    script, which will crash from a debug assertion.
    
    ```ruby
    h = 9.times.map { |i| [i, i] }.to_h
    h.send(:initialize_copy, {})
    ```
    
    * Remove dead code paths in rb_hash_initialize_copy
    
    Given that `RHASH_ST_TABLE_P(h)` is defined as `(!RHASH_AR_TABLE_P(h))`
    it shouldn't be possible for a hash to be neither of these, so there
    is no need for the removed `else if` blocks.
    
    * Share implementation between Hash#replace and Hash#initialize_copy
    
    This also fixes key rehashing for small hashes backed by an array
    table for Hash#replace.  This used to be done consistently in ruby
    2.5.x, but stopped being done for small arrays in ruby 2.6.x.
    
    This also bring optimization improvements that were done for
    Hash#initialize_copy to Hash#replace.
    
    * Add the Hash#dup benchmark
    b9702590
    Stop making a redundant hash copy in Hash#dup (#2489)
    Dylan Thacker-Smith authored
    * Stop making a redundant hash copy in Hash#dup
    
    It was making a copy of the hash without rehashing, then created an
    extra copy of the hash to do the rehashing.  Since rehashing creates
    a new copy already, this change just uses that rehashing to make
    the copy.
    
    [Bug #16121]
    
    * Remove redundant Check_Type after to_hash
    
    * Fix freeing and clearing destination hash in Hash#initialize_copy
    
    The code was assuming the state of the destination hash based on the
    source hash for clearing any existing table on it. If these don't match,
    then that can cause the old table to be leaked. This can be seen by
    compiling hash.c with `#define HASH_DEBUG 1` and running the following
    script, which will crash from a debug assertion.
    
    ```ruby
    h = 9.times.map { |i| [i, i] }.to_h
    h.send(:initialize_copy, {})
    ```
    
    * Remove dead code paths in rb_hash_initialize_copy
    
    Given that `RHASH_ST_TABLE_P(h)` is defined as `(!RHASH_AR_TABLE_P(h))`
    it shouldn't be possible for a hash to be neither of these, so there
    is no need for the removed `else if` blocks.
    
    * Share implementation between Hash#replace and Hash#initialize_copy
    
    This also fixes key rehashing for small hashes backed by an array
    table for Hash#replace.  This used to be done consistently in ruby
    2.5.x, but stopped being done for small arrays in ruby 2.6.x.
    
    This also bring optimization improvements that were done for
    Hash#initialize_copy to Hash#replace.
    
    * Add the Hash#dup benchmark
Loading