On Wed, 11 Feb 2026 15:28:56 GMT, jengebr <[email protected]> wrote:

>> # HashMap.putAll() optimizations: Eliminating Megamorphic Call Site 
>> Bottlenecks
>> 
>> ## Summary
>> 
>> This PR addresses performance bottlenecks in `HashMap.putMapEntries()` by 
>> implementing direct optimizations for specific input types: `j.u.HashMap` 
>> and `j.u.Collections$UnmodifiableMap`. The optimizations target 
>> `HashMap(Map)` constructor and `putAll()` operations based on the real-world 
>> megamorphic behavior identified in 
>> [JDK-8368292](https://bugs.openjdk.org/browse/JDK-8368292), delivering 
>> significant performance improvements when multiple `Map` subtypes are used.
>> 
>> ## Problem Context
>> 
>> ### Megamorphic Call Site Overhead in Map Iteration
>> `HashMap.putMapEntries()` currently uses a generic approach that suffers 
>> from megamorphic call site overhead when applications perform bulk creation 
>> or population of HashMaps from various source map types:
>> 
>> 1. `m.entrySet()` becomes megamorphic across different map implementations
>> 2. `entrySet().iterator()` creates different iterator types
>> 3. `entry.getKey()` and `entry.getValue()` calls vary by map type
>> 4. Individual `putVal()` calls for each entry
>> 
>> When the source is `Collections$UnmodifiableMap`, the problem is compounded 
>> by megamorphic wrappers around the already-megamorphic iteration methods. In 
>> cases where the unwrapped map is also a HashMap, both the wrapper overhead 
>> and the iteration overhead can be eliminated with a single optimization.
>> 
>> ## Optimized Methods
>> 
>> ### HashMap
>> - **`putMapEntries(Map<? extends K, ? extends V> m, boolean evict)`**: Added 
>> fast paths for UnmodifiableMap unwrapping and HashMap-to-HashMap copying
>> - **`putMapEntries(HashMap<? extends K, ? extends V> src, boolean evict)`**: 
>> copies HashMap-to-HashMap via direct Node processing.  Avoids polymorphic 
>> issues and eliminates redundant calls to HashMap.hash().
>> 
>> ## Implementation Details
>> 
>> ### HashMap-to-HashMap Fast Path
>> Eliminates megamorphic iteration by targeting internal Node structure - and 
>> also reuses the pre-calculated hash code, thus avoiding megamorphic calls to 
>> Object.hashCode() and the sometimes-expensive recalculation (depending on 
>> key type).  This also eliminates direct reads from the key, thus reducing 
>> the set of objects accessed.
>> 
>> ### UnmodifiableMap Unwrapping
>> Detects UnmodifiableMap instances and accesses the underlying map directly 
>> via the `m` field, eliminating wrapper-induced megamorphic call sites. 
>> UnmodifiableMap visibility changed from `private` to package-private to 
>> enable this...
>
> jengebr has updated the pull request incrementally with one additional commit 
> since the last revision:
> 
>   Addressing CR feedback (formatting + safe casts)

src/java.base/share/classes/java/util/HashMap.java line 498:

> 496:     private void putMapEntries(HashMap<? extends K, ? extends V> src, 
> boolean evict) {
> 497:         if (src.table != null) {
> 498:             for (Node<? extends K, ? extends V> node : src.table) {

This copy of iteration code imo causes future maintenance cost if iteration 
logic needs an update. I would prefer we just do an entry set iteration, and 
comment clearly that this copy of bytecode is for specialize exact type 
profiling (like the comments in #27533)

src/java.base/share/classes/java/util/HashMap.java line 540:

> 538:                 putMapEntries(hashMap, evict);
> 539:                 return;
> 540:             }

Same comment, add comments to indicate the two branches have same 
code/bytecode, they differ in the method profiling data which makes a huge 
difference.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/28243#discussion_r3011728580
PR Review Comment: https://git.openjdk.org/jdk/pull/28243#discussion_r3011737374

Reply via email to