[GR-65670] Prohibit collections with unstable iteration order. #11589
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.
This PR prohibits using map and set implementations where the order of iteration may be unstable, i.e., different between VM runs even if the contents of the maps/sets do not change. Such an unstable order can lead to non-determinism and transient failures. We prohibit these usages with a checkstyle rule.
Prohibited Usages
(new|extends) (HashMap|HashSet|IdentityHashMap|Hashtable)
. Prohibits instantiation and subclassing ofHashMap
,HashSet
, etc. Reason: if the hash code of the key type is the system identity hash code, the iteration order is unstable.Hash(Map|Set)\.newHash(Map|Set)
. Prohibits factory methods for maps and sets. Reason: same as above.(Map|Set)\.(of|copyOf|ofEntries)
. Reason: the iteration order of immutable maps is intentionally randomized.Replacements for Prohibited Usages
new HashMap<>()
->new EconomicHashMap<>()
creates aMap
backed by anEconomicMap
, preserving the insertion order. The returned map has a minor restriction on how entries can be modified using iterators (details in code).new IdentityHashMap<>()
->EconomicHashMap.newIdentityMap()
- same as above, except theEconomicMap
uses identity and the system hash code.new HashSet<>()
->new EconomicHashSet<>()
creates aSet
backed by anEconomicMap
, preserving the insertion order.Map.of(...)
->CollectionsUtil.mapOf(...)
creates an immutable map with insertion order.Map.ofEntries(...)
->CollectionsUtil.mapOfEntries(...)
creates an immutable map with entries, preserving insertion order.Set.of(...)
->CollectionsUtil.setOf(...)
creates an immutable set with insertion order.Set.copyOf(...)
->CollectionsUtil.setCopyOf
creates an immutable copy of a set.Replacements in Annotation Processors etc
There is code that cannot use
CollectionsUtil
and the new collections since it does not have those libraries on the classpath - annotation processors,JVMCIVersionCheck
, graphio. In these cases, we must resort to alternatives from the standard library or suppress the checks using a comment.new HashMap<>()
->new LinkedHashMap<>()
.new HashSet<>()
->new LinkedHashSet<>()
.Set.of(...)
->Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(...)
.Map.of(...)
->var map = new LinkedHashMap<>(); map.put(...); Collections.unmodifiableMap(map);
.New Collections - EconomicHashSet and EconomicHashMap
EconomicHashMap
andEconomicHashSet
are designed to be compatible withHashMap
andHashSet
whenever possible. As a consequence:null
keys/elements (adding some runtime cost). As an alternative, we could not support it, which is allowed by theMap
contract.ObjectCopier
requires null keys, but that was the only known usage that needed it so far.ConcurrentModificationException
(adding some runtime cost).Other Changes
EconomicMapImpl
iterators to throwNoSuchElementException
as dictatated by theIterator
API.Checkstyle Supressions
When a valid usage is prohibited by checkstyle, there are two options to suppress the checks.
Suppress for an adjacent line:
Suppress for a range:
These suppressions are needed for testing and benchmarking.