Skip to content

[GR-65670] Prohibit collections with unstable iteration order. #11589

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

graalvmbot
Copy link
Collaborator

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 of HashMap, 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 a Map backed by an EconomicMap, 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 the EconomicMap uses identity and the system hash code.
  • new HashSet<>() -> new EconomicHashSet<>() creates a Set backed by an EconomicMap, 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 and EconomicHashSet are designed to be compatible with HashMap and HashSet whenever possible. As a consequence:

  • They allow null keys/elements (adding some runtime cost). As an alternative, we could not support it, which is allowed by the Map contract. ObjectCopier requires null keys, but that was the only known usage that needed it so far.
  • They detect invalid iterator usages and throw ConcurrentModificationException (adding some runtime cost).

Other Changes

  • Changed EconomicMapImpl iterators to throw NoSuchElementException as dictatated by the Iterator API.

Checkstyle Supressions

When a valid usage is prohibited by checkstyle, there are two options to suppress the checks.

Suppress for an adjacent line:

// STABLE ITERATION ORDER: describe reason here...
new HashMap<>();

Suppress for a range:

// Checkstyle: stop stable iteration order check
new HashMap<>();
new HashMap<>();
new HashMap<>();
// Checkstyle: resume stable iteration order check

These suppressions are needed for testing and benchmarking.

@oracle-contributor-agreement oracle-contributor-agreement bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Jul 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OCA Verified All contributors have signed the Oracle Contributor Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants