8371656: HashMap.putAll() optimizations #28243
Open
+235
−5
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.HashMapandj.u.Collections$UnmodifiableMap. The optimizations targetHashMap(Map)constructor andputAll()operations based on the real-world megamorphic behavior identified in JDK-8368292, delivering significant performance improvements when multipleMapsubtypes 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:m.entrySet()becomes megamorphic across different map implementationsentrySet().iterator()creates different iterator typesentry.getKey()andentry.getValue()calls vary by map typeputVal()calls for each entryWhen 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 copyingputMapEntries(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
Directly iterates over
src.tableto eliminate entrySet() allocation and polymorphic iterator calls, using the internal Node structure for maximum efficiency.UnmodifiableMap Unwrapping
Detects UnmodifiableMap instances and accesses the underlying map directly via the
mfield, eliminating wrapper-induced megamorphic call sites. UnmodifiableMap visibility changed fromprivateto package-private to enable this direct access.Performance Impact
This shows substantial improvements (32-81%) for optimized paths while maintaining no significant regression for non-optimized paths.
Call Site Poisoning Impact
FAQ
Q: Why use exact class check instead of instanceof for HashMap?
A: This prevents the fast path from becoming megamorphic if HashMap subclasses are common, ensuring the optimization remains effective. Also, subclasses might override behavior in ways that make direct table access incorrect.
Q: Is it safe to make UnmodifiableMap package-private?
A: Yes. The class remains non-public and is only accessible within java.util. The change enables internal optimizations without exposing implementation details to external code.
Q: Are these optimizations safe?
A: Yes. HashMap-to-HashMap copying maintains identical behavior, and UnmodifiableMap unwrapping accesses the exact same data through a more direct path.
Q: What about other Map types?
A: Profiling data shows these are the biggest opportunities. Others exist but are lower-priority.
Q: How do these optimizations interact with existing code?
A: These are internal implementation optimizations that maintain full API compatibility. No external code changes are required.
Testing
Comprehensive unit tests added to MOAT.java covering:
Tier-1 tests passed.
Progress
Issue
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/28243/head:pull/28243$ git checkout pull/28243Update a local copy of the PR:
$ git checkout pull/28243$ git pull https://git.openjdk.org/jdk.git pull/28243/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 28243View PR using the GUI difftool:
$ git pr show -t 28243Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/28243.diff
Using Webrev
Link to Webrev Comment