From 530461f9998dc358932de0b2feca44da4123feef Mon Sep 17 00:00:00 2001
Date: Thu, 27 Aug 2026 19:50:31 +0800
Subject: [PATCH] Improve primitive hashset

---
 .../share/classfile/bytecodeEnhancement.cpp   |   20 +-
 src/java.base/share/legal/fastutil.md         |  214 +++
 .../PrimitiveHashSetTest.java                 |   27 +-
 .../HashSet/PrimitiveHashSetBehaviorTest.java |   61 +-
 .../classdata/java/util/HashSet.java          | 1323 +----------------
 .../classdata/java/util/IntHashSet.java       |  531 +++++++
 .../classdata/java/util/LongHashSet.java      |  532 +++++++
 .../classdata/java/util/PrimitiveHashSet.java |  225 +++
 8 files changed, 1658 insertions(+), 1275 deletions(-)
 create mode 100644 src/java.base/share/legal/fastutil.md
 create mode 100644 test/jdk/jdk/internal/enhancement/classdata/java/util/IntHashSet.java
 create mode 100644 test/jdk/jdk/internal/enhancement/classdata/java/util/LongHashSet.java
 create mode 100644 test/jdk/jdk/internal/enhancement/classdata/java/util/PrimitiveHashSet.java

diff --git a/src/hotspot/share/classfile/bytecodeEnhancement.cpp b/src/hotspot/share/classfile/bytecodeEnhancement.cpp
index c93440223..a1ceb739b 100644
--- a/src/hotspot/share/classfile/bytecodeEnhancement.cpp
+++ b/src/hotspot/share/classfile/bytecodeEnhancement.cpp
@@ -723,16 +723,16 @@ void BytecodeEnhancement::initialize() {
   _owner_class_loaders = new (mtClass) BytecodeEnhancementOwnerTable();
   if (UsePrimitiveHashSet) {
     add_internal_class_replacement("java/util/HashSet", 0x7a6d746bU);
-    add_internal_class_addition("java/util/HashSet$PrimitiveHashSet", BuiltinLoader::BootLoader);
-    add_internal_class_addition("java/util/HashSet$PrimitiveHashSet$1", BuiltinLoader::BootLoader);
-    add_internal_class_addition("java/util/HashSet$LongHashSet", BuiltinLoader::BootLoader);
-    add_internal_class_addition("java/util/HashSet$LongHashSet$LongIterator", BuiltinLoader::BootLoader);
-    add_internal_class_addition("java/util/HashSet$LongHashSet$LongSpliterator", BuiltinLoader::BootLoader);
-    add_internal_class_addition("java/util/HashSet$LongHashSet$LongArrayList", BuiltinLoader::BootLoader);
-    add_internal_class_addition("java/util/HashSet$IntHashSet", BuiltinLoader::BootLoader);
-    add_internal_class_addition("java/util/HashSet$IntHashSet$IntIterator", BuiltinLoader::BootLoader);
-    add_internal_class_addition("java/util/HashSet$IntHashSet$IntSpliterator", BuiltinLoader::BootLoader);
-    add_internal_class_addition("java/util/HashSet$IntHashSet$IntArrayList", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/PrimitiveHashSet", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/PrimitiveHashSet$1", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/LongHashSet", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/LongHashSet$LongIterator", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/LongHashSet$LongSpliterator", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/LongHashSet$LongArrayList", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/IntHashSet", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/IntHashSet$IntIterator", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/IntHashSet$IntSpliterator", BuiltinLoader::BootLoader);
+    add_internal_class_addition("java/util/IntHashSet$IntArrayList", BuiltinLoader::BootLoader);
   }
   if (BytecodeEnhancementPaths != nullptr) {
     GrowableArray<ClassPathEntry*> path_entries;
diff --git a/src/java.base/share/legal/fastutil.md b/src/java.base/share/legal/fastutil.md
new file mode 100644
index 000000000..50b4c0a2e
--- /dev/null
+++ b/src/java.base/share/legal/fastutil.md
@@ -0,0 +1,214 @@
+## fastutil
+
+### Notice
+This product includes code derived from fastutil OpenHashSet.
+
+Copyright (C) 2002-2026 Sebastiano Vigna
+
+Source: https://github.com/vigna/fastutil
+
+### License
+```
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+```
diff --git a/test/hotspot/jtreg/runtime/BytecodeEnhancement/PrimitiveHashSetTest.java b/test/hotspot/jtreg/runtime/BytecodeEnhancement/PrimitiveHashSetTest.java
index 6264706ec..db28ab061 100644
--- a/test/hotspot/jtreg/runtime/BytecodeEnhancement/PrimitiveHashSetTest.java
+++ b/test/hotspot/jtreg/runtime/BytecodeEnhancement/PrimitiveHashSetTest.java
@@ -36,16 +36,16 @@ import jdk.test.lib.process.ProcessTools;
 public class PrimitiveHashSetTest {
     private static final String PRIMITIVE_HASH_SET_FIELD = "primitiveHashSet";
     private static final String[] PRIMITIVE_HASH_SET_CLASSES = {
-            "java.util.HashSet$PrimitiveHashSet",
-            "java.util.HashSet$PrimitiveHashSet$1",
-            "java.util.HashSet$LongHashSet",
-            "java.util.HashSet$LongHashSet$LongIterator",
-            "java.util.HashSet$LongHashSet$LongSpliterator",
-            "java.util.HashSet$LongHashSet$LongArrayList",
-            "java.util.HashSet$IntHashSet",
-            "java.util.HashSet$IntHashSet$IntIterator",
-            "java.util.HashSet$IntHashSet$IntSpliterator",
-            "java.util.HashSet$IntHashSet$IntArrayList"
+            "java.util.PrimitiveHashSet",
+            "java.util.PrimitiveHashSet$1",
+            "java.util.LongHashSet",
+            "java.util.LongHashSet$LongIterator",
+            "java.util.LongHashSet$LongSpliterator",
+            "java.util.LongHashSet$LongArrayList",
+            "java.util.IntHashSet",
+            "java.util.IntHashSet$IntIterator",
+            "java.util.IntHashSet$IntSpliterator",
+            "java.util.IntHashSet$IntArrayList"
     };
 
     public static void main(String[] args) throws Exception {
@@ -87,9 +87,10 @@ public class PrimitiveHashSetTest {
             }
             if (expected) {
                 int modifiers = primitiveHashSetClass.getModifiers();
-                if (!Modifier.isPrivate(modifiers) || !Modifier.isStatic(modifiers)
-                        || !Modifier.isAbstract(modifiers)) {
-                    throw new RuntimeException("HashSet.PrimitiveHashSet must be private static abstract");
+                if (!Modifier.isAbstract(modifiers) || Modifier.isPublic(modifiers)
+                        || Modifier.isProtected(modifiers) || Modifier.isPrivate(modifiers)
+                        || Modifier.isStatic(modifiers)) {
+                    throw new RuntimeException("PrimitiveHashSet must be package-private abstract");
                 }
                 if (field.getType() != primitiveHashSetClass || !Modifier.isTransient(field.getModifiers())
                         || Modifier.isPublic(field.getModifiers())) {
diff --git a/test/jdk/java/util/HashSet/PrimitiveHashSetBehaviorTest.java b/test/jdk/java/util/HashSet/PrimitiveHashSetBehaviorTest.java
index d9328d4cb..dd7730317 100644
--- a/test/jdk/java/util/HashSet/PrimitiveHashSetBehaviorTest.java
+++ b/test/jdk/java/util/HashSet/PrimitiveHashSetBehaviorTest.java
@@ -37,6 +37,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
@@ -71,6 +72,7 @@ public class PrimitiveHashSetBehaviorTest {
         specializedIteratorRemoval();
         randomizedDifferential();
         streamOperations();
+        failedSpecializationFallsBack();
     }
 
     private static void constructors() {
@@ -158,6 +160,8 @@ public class PrimitiveHashSetBehaviorTest {
 
         Iterator<Long> failFast = set.iterator();
         set.add(10_000L);
+        assertTrue(failFast.hasNext());
+        assertThrows(IllegalStateException.class, failFast::remove);
         assertThrows(ConcurrentModificationException.class, failFast::next);
 
         HashSet<Long> empty = new HashSet<>();
@@ -532,7 +536,8 @@ public class PrimitiveHashSetBehaviorTest {
 
         Iterator<Number> beforeRollback = set.iterator();
         set.add(3.14d);
-        assertThrows(ConcurrentModificationException.class, beforeRollback::hasNext);
+        assertTrue(beforeRollback.hasNext());
+        assertThrows(ConcurrentModificationException.class, beforeRollback::next);
 
         HashSet<Number> values = new HashSet<>();
         values.add(null);
@@ -583,6 +588,60 @@ public class PrimitiveHashSetBehaviorTest {
         assertEquals(set, set.parallelStream().collect(Collectors.toSet()));
     }
 
+    private static void failedSpecializationFallsBack() throws Exception {
+        failedSpecializationFallsBack(true);
+        failedSpecializationFallsBack(false);
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static void failedSpecializationFallsBack(boolean useLongs) throws Exception {
+        Field mapField = HashSet.class.getDeclaredField("map");
+        Field primitiveSetField = HashSet.class.getDeclaredField("primitiveHashSet");
+        Field candidateStateField = HashSet.class.getDeclaredField("primitiveCandidateState");
+        mapField.setAccessible(true);
+        primitiveSetField.setAccessible(true);
+        candidateStateField.setAccessible(true);
+
+        HashSet<Number> set = new HashSet<>();
+        FailingIterationHashMap<Number, Object> map = new FailingIterationHashMap<>();
+        for (int i = 0; i < 100; i++) {
+            map.put(useLongs ? Long.valueOf(i) : Integer.valueOf(i), new Object());
+        }
+        mapField.set(set, map);
+        candidateStateField.setInt(set, useLongs ? 1 : 2);
+
+        Number added = useLongs ? Long.valueOf(100) : Integer.valueOf(100);
+        assertTrue(set.add(added));
+        assertSame(map, mapField.get(set));
+        assertNull(primitiveSetField.get(set));
+        assertEquals(-1, candidateStateField.getInt(set));
+        assertTrue(set.contains(added));
+
+        Number next = useLongs ? Long.valueOf(101) : Integer.valueOf(101);
+        assertTrue(set.add(next));
+        assertSame(map, mapField.get(set));
+        assertNull(primitiveSetField.get(set));
+        assertTrue(set.contains(next));
+    }
+
+    private static final class FailingIterationHashMap<K, V> extends HashMap<K, V> {
+        @Override
+        public Set<K> keySet() {
+            Set<K> keys = super.keySet();
+            return new java.util.AbstractSet<>() {
+                @Override
+                public Iterator<K> iterator() {
+                    throw new ConcurrentModificationException();
+                }
+
+                @Override
+                public int size() {
+                    return keys.size();
+                }
+            };
+        }
+    }
+
     private static void randomizedDifferential() {
         runRandomizedDifferential(true);
         runRandomizedDifferential(false);
diff --git a/test/jdk/jdk/internal/enhancement/classdata/java/util/HashSet.java b/test/jdk/jdk/internal/enhancement/classdata/java/util/HashSet.java
index 8d6495079..247a2251d 100644
--- a/test/jdk/jdk/internal/enhancement/classdata/java/util/HashSet.java
+++ b/test/jdk/jdk/internal/enhancement/classdata/java/util/HashSet.java
@@ -256,6 +256,7 @@ public class HashSet<E>
      */
     public boolean add(E e) {
         PrimitiveHashSet specializedSet = primitiveHashSet;
+        HashMap<E, Object> currentMap = map;
         if (specializedSet != null) {
             if (e == null) {
                 return specializedSet.addNull();
@@ -267,15 +268,16 @@ public class HashSet<E>
             } else if (e instanceof Integer key) {
                 return ((IntHashSet) specializedSet).addInt(key.intValue());
             }
-            rollbackToHashMap();
-            return this.map.put(e, PRESENT) == null;
+            HashMap<E, Object> rollbackMap = rollbackToHashMap(specializedSet);
+            return rollbackMap.put(e, PRESENT) == null;
+        } else if (currentMap != null) {
+            return addToMap(e, currentMap);
         }
-
-        return addToMap(e);
+        return false;
     }
 
-    private boolean addToMap(E e) {
-        boolean result = map.put(e, PRESENT) == null;
+    private boolean addToMap(E e, HashMap<E, Object> currentMap) {
+        boolean result = currentMap.put(e, PRESENT) == null;
         if (!result) {
             return false;
         }
@@ -284,7 +286,7 @@ public class HashSet<E>
         }
         // LinkedHashSet must retain LinkedHashMap ordering and cannot switch
         // to the unordered primitive HashSet representation.
-        if (map instanceof LinkedHashMap || getClass() != HashSet.class) {
+        if (currentMap instanceof LinkedHashMap || getClass() != HashSet.class) {
             primitiveCandidateState = PRIMITIVE_SPECIALIZATION_DISABLED;
             return true;
         }
@@ -297,15 +299,15 @@ public class HashSet<E>
                 && (primitiveCandidateState == NO_PRIMITIVE_CANDIDATE
                     || primitiveCandidateState == LONG_PRIMITIVE_CANDIDATE)) {
             primitiveCandidateState = LONG_PRIMITIVE_CANDIDATE;
-            if (map.size() >= PRIMITIVE_SPECIALIZATION_THRESHOLD) {
-                switchToLongHashSet();
+            if (currentMap.size() >= PRIMITIVE_SPECIALIZATION_THRESHOLD) {
+                switchToLongHashSet(currentMap);
             }
         } else if (e instanceof Integer
                 && (primitiveCandidateState == NO_PRIMITIVE_CANDIDATE
                     || primitiveCandidateState == INT_PRIMITIVE_CANDIDATE)) {
             primitiveCandidateState = INT_PRIMITIVE_CANDIDATE;
-            if (map.size() >= PRIMITIVE_SPECIALIZATION_THRESHOLD) {
-                switchToIntHashSet();
+            if (currentMap.size() >= PRIMITIVE_SPECIALIZATION_THRESHOLD) {
+                switchToIntHashSet(currentMap);
             }
         } else {
             primitiveCandidateState = PRIMITIVE_SPECIALIZATION_DISABLED;
@@ -577,1273 +579,92 @@ public class HashSet<E>
         return super.hashCode();
     }
 
-    private void switchToLongHashSet() {
+    private void switchToLongHashSet(HashMap<E, Object> sourceMap) {
         if (primitiveHashSet != null) {
             return;
         }
-        LongHashSet newLongHashSet = new LongHashSet();
-        newLongHashSet.hashMapLoadFactor = this.map.loadFactor();
-        for (E key : this.map.keySet()) {
-            if (key == null) {
-                newLongHashSet.addNull();
-            } else if (key.getClass() == Long.class) {
-                newLongHashSet.addLong(((Long) key).longValue());
-            } else {
-                this.primitiveCandidateState = PRIMITIVE_SPECIALIZATION_DISABLED;
+        try {
+            int expectedModCount = sourceMap.modCount;
+            LongHashSet newLongHashSet = new LongHashSet();
+            newLongHashSet.hashMapLoadFactor = sourceMap.loadFactor();
+            for (E key : sourceMap.keySet()) {
+                if (key == null) {
+                    newLongHashSet.addNull();
+                } else if (key.getClass() == Long.class) {
+                    newLongHashSet.addLong(((Long) key).longValue());
+                } else {
+                    primitiveCandidateState = PRIMITIVE_SPECIALIZATION_DISABLED;
+                    return;
+                }
+            }
+            if (sourceMap.modCount != expectedModCount || map != sourceMap
+                    || primitiveHashSet != null) {
+                disablePrimitiveSpecialization(sourceMap);
                 return;
             }
+            // Publish only after the temporary set has been fully populated.
+            primitiveHashSet = newLongHashSet;
+            primitiveCandidateState = NO_PRIMITIVE_CANDIDATE;
+            map = null;
+        } catch (RuntimeException e) {
+            disablePrimitiveSpecialization(sourceMap);
         }
-        this.primitiveHashSet = newLongHashSet;
-        this.primitiveCandidateState = 0;
-        this.map = null;
     }
 
-    private void switchToIntHashSet() {
+    private void switchToIntHashSet(HashMap<E, Object> sourceMap) {
         if (primitiveHashSet != null) {
             return;
         }
-        IntHashSet newIntHashSet = new IntHashSet();
-        newIntHashSet.hashMapLoadFactor = this.map.loadFactor();
-        for (E key : this.map.keySet()) {
-            if (key == null) {
-                newIntHashSet.addNull();
-            } else if (key.getClass() == Integer.class) {
-                newIntHashSet.addInt(((Integer) key).intValue());
-            } else {
-                this.primitiveCandidateState = PRIMITIVE_SPECIALIZATION_DISABLED;
+        try {
+            int expectedModCount = sourceMap.modCount;
+            IntHashSet newIntHashSet = new IntHashSet();
+            newIntHashSet.hashMapLoadFactor = sourceMap.loadFactor();
+            for (E key : sourceMap.keySet()) {
+                if (key == null) {
+                    newIntHashSet.addNull();
+                } else if (key.getClass() == Integer.class) {
+                    newIntHashSet.addInt(((Integer) key).intValue());
+                } else {
+                    primitiveCandidateState = PRIMITIVE_SPECIALIZATION_DISABLED;
+                    return;
+                }
+            }
+            if (sourceMap.modCount != expectedModCount || map != sourceMap
+                    || primitiveHashSet != null) {
+                disablePrimitiveSpecialization(sourceMap);
                 return;
             }
+            // Publish only after the temporary set has been fully populated.
+            primitiveHashSet = newIntHashSet;
+            primitiveCandidateState = NO_PRIMITIVE_CANDIDATE;
+            map = null;
+        } catch (RuntimeException e) {
+            disablePrimitiveSpecialization(sourceMap);
         }
-        this.primitiveHashSet = newIntHashSet;
-        this.primitiveCandidateState = 0;
-        this.map = null;
     }
 
-    private void rollbackToHashMap() {
-        if (this.primitiveHashSet == null) {
-            return;
+    private void disablePrimitiveSpecialization(HashMap<E, Object> sourceMap) {
+        if (map == sourceMap && primitiveHashSet == null) {
+            primitiveCandidateState = PRIMITIVE_SPECIALIZATION_DISABLED;
         }
-        float loadFactor = this.primitiveHashSet.hashMapLoadFactor;
+    }
+
+    private HashMap<E, Object> rollbackToHashMap(PrimitiveHashSet specializedSet) {
+        float loadFactor = specializedSet.hashMapLoadFactor;
         int capacity = (int) Math.min(
-                Math.ceil(size() / (double) loadFactor),
+                Math.ceil(specializedSet.size() / (double) loadFactor),
                 HashMap.MAXIMUM_CAPACITY);
         HashMap<E, Object> newMap = new HashMap<>(capacity, loadFactor);
-        for (Number key : this.primitiveHashSet) {
+        for (Number key : specializedSet) {
             @SuppressWarnings("unchecked")
             E element = (E) key;
             newMap.put(element, PRESENT);
         }
-        this.primitiveHashSet.invalidateIterators();
+        specializedSet.invalidateIterators();
         this.map = newMap;
         this.primitiveHashSet = null;
         this.primitiveCandidateState = PRIMITIVE_SPECIALIZATION_DISABLED;
+        return newMap;
     }
 
-    private static abstract class PrimitiveHashSet extends AbstractSet<Number> implements Cloneable {
-        int mask;
-
-        boolean containsNull;
-
-        boolean containsZero;
-
-        int capacity;
-
-        int threshold;
-
-        int minCapacity;
-
-        int size;
-
-        int modCount;
-
-        float loadFactor;
-
-        // Retained only to emit the standard HashSet serialization metadata.
-        // It is intentionally independent of this table's occupancy factor.
-        float hashMapLoadFactor = HashMap.DEFAULT_LOAD_FACTOR;
-
-        static final long LONG_PHI = 0x9E3779B97F4A7C15L;
-
-        static final int DEFAULT_INITIAL_CAPACITY = 16;
-
-        static final float DEFAULT_LOAD_FACTOR = .75f;
-
-        public PrimitiveHashSet(final int initialCapacity, final float loadFactor) {
-            if (loadFactor <= 0 || Float.isNaN(loadFactor) || loadFactor >= 1) {
-                throw new IllegalArgumentException("Load factor must be between 0 and 1");
-            }
-            if (initialCapacity < 0) {
-                throw new IllegalArgumentException("Initial capacity must be non-negative");
-            }
-            this.loadFactor = loadFactor;
-            this.minCapacity = this.capacity = PrimitiveHashSet.leastArraySize(initialCapacity, loadFactor);
-            this.mask = this.capacity - 1;
-            this.threshold = PrimitiveHashSet.maxEntriesFill(this.capacity, loadFactor);
-        }
-
-        protected int realSize() {
-            return this.size - (this.containsZero ? 1 : 0) - (this.containsNull ? 1 : 0);
-        }
-
-        protected static long mixBits(final long n) {
-            long res = n * LONG_PHI;
-            res ^= res >>> 32;
-            return res ^ (res >>> 16);
-        }
-
-        protected static int maxEntriesFill(int capacity, float loadFactor) {
-            return Math.min((int) Math.ceil(capacity * loadFactor), capacity - 1);
-        }
-
-        protected static int leastArraySize(int expectedElements, float loadFactor) {
-            final long size = Math.max(2, nextPowerOfTwo((long) Math.ceil(expectedElements / loadFactor)));
-            if (size > (1 << 30)) {
-                throw new IllegalArgumentException("Expected number of elements is too large: " + expectedElements
-                        + " with load factor " + loadFactor);
-            }
-            return (int) size;
-        }
-
-        protected static long nextPowerOfTwo(long n) {
-            if (n == 0) {
-                return 1;
-            }
-            n--;
-            n |= n >> 1;
-            n |= n >> 2;
-            n |= n >> 4;
-            n |= n >> 8;
-            n |= n >> 16;
-            return (n | n >> 32) + 1;
-        }
-
-        @Override
-        public int size() {
-            return this.size;
-        }
-
-        public boolean isEmpty() {
-            return this.size == 0;
-        }
-
-
-        abstract Iterator<? extends Number> valueIterator();
-
-        abstract void forEachElement(Consumer<? super Number> action);
-
-        final boolean addNull() {
-            if (containsNull) {
-                return false;
-            }
-            containsNull = true;
-            size++;
-            modCount++;
-            return true;
-        }
-
-        final boolean removeNull() {
-            if (!containsNull) {
-                return false;
-            }
-            containsNull = false;
-            size--;
-            modCount++;
-            return true;
-        }
-
-        final void invalidateIterators() {
-            modCount++;
-        }
-
-        @Override
-        public final Iterator<Number> iterator() {
-            return new Iterator<>() {
-                private final Iterator<? extends Number> values = valueIterator();
-                private int expectedModCount = modCount;
-                private boolean nullPending = containsNull;
-                private boolean canRemove;
-                private boolean lastWasNull;
-
-                private void checkForComodification() {
-                    if (expectedModCount != modCount) {
-                        throw new ConcurrentModificationException();
-                    }
-                }
-
-                @Override
-                public boolean hasNext() {
-                    checkForComodification();
-                    return nullPending || values.hasNext();
-                }
-
-                @Override
-                public Number next() {
-                    checkForComodification();
-                    if (nullPending) {
-                        nullPending = false;
-                        canRemove = true;
-                        lastWasNull = true;
-                        return null;
-                    }
-                    Number value = values.next();
-                    canRemove = true;
-                    lastWasNull = false;
-                    return value;
-                }
-
-                @Override
-                public void remove() {
-                    checkForComodification();
-                    if (!canRemove) {
-                        throw new IllegalStateException();
-                    }
-                    if (lastWasNull) {
-                        removeNull();
-                    } else {
-                        values.remove();
-                    }
-                    expectedModCount = modCount;
-                    canRemove = false;
-                }
-            };
-        }
-
-        @Override
-        public final void forEach(Consumer<? super Number> action) {
-            Objects.requireNonNull(action);
-            int expectedModCount = modCount;
-            if (containsNull) {
-                action.accept(null);
-            }
-            forEachElement(action);
-            if (expectedModCount != modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-
-        @Override
-        public abstract boolean contains(Object e);
-
-        @Override
-        public abstract boolean remove(Object e);
-
-        public PrimitiveHashSet clone() {
-            try {
-                PrimitiveHashSet cloned = (PrimitiveHashSet) super.clone();
-                return cloned;
-            } catch (CloneNotSupportedException e) {
-                throw new InternalError(e);
-            }
-        }
-    }
-
-    private static class LongHashSet extends PrimitiveHashSet {
-        long[] keys;
-        public LongHashSet() {
-            this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
-        }
-
-        public LongHashSet(final int initialCapacity, final float loadFactor) {
-            super(initialCapacity, loadFactor);
-            this.keys = new long[this.capacity + 1];
-        }
-
-        boolean addLong(long key) {
-            int pos;
-            if (key == 0L) {
-                if (this.containsZero) {
-                    return false;
-                }
-                this.containsZero = true;
-            } else {
-                long current;
-                final long[] curKeys = this.keys;
-                if (!((current = curKeys[pos = (int) LongHashSet.mixBits(key) & this.mask]) == 0)) {
-                    if (current == key) {
-                        return false;
-                    }
-                    while (!((current = curKeys[pos = (pos + 1) & this.mask]) == 0)) {
-                        if (current == key) {
-                            return false;
-                        }
-                    }
-                }
-                curKeys[pos] = key;
-            }
-            if (this.size++ >= this.threshold) {
-                rehash(LongHashSet.leastArraySize(this.size + 1, this.loadFactor));
-            }
-            this.modCount++;
-            return true;
-        }
-
-        @Override
-        public boolean remove(Object key) {
-            if (key == null) {
-                return removeNull();
-            }
-            return key instanceof Long && removeLong((Long) key);
-        }
-
-        boolean removeLong(long key) {
-            if (key == 0L) {
-                if (this.containsZero) {
-                    return removeNullEntry();
-                }
-                return false;
-            }
-            long current;
-            final long[] curKeys = this.keys;
-            int pos;
-            if (((current = curKeys[pos = (int) LongHashSet.mixBits(key) & this.mask]) == 0)) {
-                return false;
-            }
-            if (current == key) {
-                return removeEntry(pos);
-            }
-            while (true) {
-                if (((current = curKeys[pos = (pos + 1) & this.mask]) == 0)) {
-                    return false;
-                }
-                if (current == key) {
-                    return removeEntry(pos);
-                }
-            }
-        }
-
-        @Override
-        public boolean contains(Object key) {
-            if (key == null) {
-                return this.containsNull;
-            }
-            return key instanceof Long && containsLong((Long) key);
-        }
-
-        boolean containsLong(long key) {
-            if (key == 0L) return this.containsZero;
-            long current;
-            final long[] curKeys = this.keys;
-            int pos = (int) LongHashSet.mixBits(key) & this.mask;
-            if ((current = curKeys[pos]) == 0) return false;
-            if (current == key) return true;
-            while ((current = curKeys[pos = (pos + 1) & this.mask]) != 0) {
-                if (current == key) return true;
-            }
-            return false;
-        }
-
-
-        Iterator<Long> valueIterator() {
-            return new LongIterator();
-        }
-
-        @Override
-        public Spliterator<Number> spliterator() {
-            return new LongSpliterator(0, -1, 0, 0, false, false, false);
-        }
-
-        @Override
-        void forEachElement(Consumer<? super Number> action) {
-            if (containsZero) {
-                action.accept(Long.valueOf(0));
-            }
-            final long[] curKeys = keys;
-            for (int i = capacity; i-- != 0;) {
-                long key = curKeys[i];
-                if (key != 0) {
-                    action.accept(Long.valueOf(key));
-                }
-            }
-        }
-
-        public void clear() {
-            if (this.size == 0) {
-                return;
-            }
-            this.size = 0;
-            this.containsZero = false;
-            this.containsNull = false;
-            Arrays.fill(this.keys, 0);
-            this.modCount++;
-        }
-
-        @Override
-        public LongHashSet clone() {
-            LongHashSet newSet = (LongHashSet) super.clone();
-            newSet.keys = this.keys.clone();
-            return newSet;
-        }
-
-        @Override
-        public int hashCode() {
-            int h = 0;
-            for (int j = realSize(), i = 0; j-- != 0;) {
-                while (this.keys[i] == 0) {
-                    i++;
-                }
-                h += (int) (this.keys[i] ^ (this.keys[i] >>> 32));
-                i++;
-            }
-            return h;
-        }
-
-        private boolean removeEntry(int pos) {
-            this.size--;
-            shiftKeys(pos);
-            if (this.capacity > this.minCapacity && this.size < this.threshold >> 2
-                    && this.capacity > DEFAULT_INITIAL_CAPACITY) {
-                rehash(this.capacity >> 1);
-            }
-            this.modCount++;
-            return true;
-        }
-
-        private void shiftKeys(int pos) {
-            int last, slot;
-            long current;
-            final long[] curKeys = this.keys;
-            for (;;) {
-                pos = ((last = pos) + 1) & this.mask;
-                for (;;) {
-                    if (((current = curKeys[pos]) == 0)) {
-                        curKeys[last] = 0;
-                        return;
-                    }
-                    slot = (int) LongHashSet.mixBits(current) & this.mask;
-                    if (last <= pos ? (last >= slot || slot > pos) : (last >= slot && slot > pos)) {
-                        break;
-                    }
-                    pos = (pos + 1) & this.mask;
-                }
-                curKeys[last] = current;
-            }
-        }
-
-        private boolean removeNullEntry() {
-            this.containsZero = false;
-            this.keys[this.capacity] = 0;
-            this.size--;
-            if (this.capacity > this.minCapacity && this.size < this.threshold >> 2
-                    && this.capacity > DEFAULT_INITIAL_CAPACITY) {
-                rehash(this.capacity >> 1);
-            }
-            this.modCount++;
-            return true;
-        }
-
-        private void rehash(final int newCapacity) {
-            final long[] oldKeys = this.keys;
-            final int newMask = newCapacity - 1;
-            final long[] newKeys = new long[newCapacity + 1];
-            int i = this.capacity, pos;
-            for (int j = realSize(); j-- != 0;) {
-                while ((oldKeys[--i] == 0))
-                    ;
-                if (!((newKeys[pos = (int) LongHashSet.mixBits(oldKeys[i]) & newMask]) == 0)) {
-                    while (!((newKeys[pos = (pos + 1) & newMask]) == 0))
-                        ;
-                }
-                newKeys[pos] = oldKeys[i];
-            }
-            this.capacity = newCapacity;
-            this.mask = newMask;
-            this.threshold = LongHashSet.maxEntriesFill(this.capacity, this.loadFactor);
-            this.keys = newKeys;
-        }
-
-        private final class LongIterator implements PrimitiveIterator.OfLong {
-            private int position = LongHashSet.this.capacity;
-            private int last = -1;
-            private int counter = LongHashSet.this.size - (LongHashSet.this.containsNull ? 1 : 0);
-            private boolean mustReturnZero = LongHashSet.this.containsZero;
-            private LongArrayList wrapped;
-
-            @Override
-            public long nextLong() {
-                if (!hasNext()) {
-                    throw new java.util.NoSuchElementException();
-                }
-                this.counter--;
-                if (this.mustReturnZero) {
-                    this.mustReturnZero = false;
-                    last = LongHashSet.this.capacity;
-                    return LongHashSet.this.keys[LongHashSet.this.capacity];
-                }
-                final long[] curKeys = LongHashSet.this.keys;
-                for (;;) {
-                    if (--this.position < 0) {
-                        this.last = Integer.MIN_VALUE;
-                        return this.wrapped.getLong(-this.position - 1);
-                    }
-                    if (!(curKeys[this.position] == 0)) {
-                        return curKeys[this.last = this.position];
-                    }
-                }
-            }
-
-            @Override
-            public boolean hasNext() {
-                return this.counter != 0;
-            }
-
-            private final void shiftKeys(int pos) {
-                int lastPos, slot;
-                long current;
-                final long[] curKeys = LongHashSet.this.keys;
-                for (;;) {
-                    pos = ((lastPos = pos) + 1) & LongHashSet.this.mask;
-                    for (;;) {
-                        if (((current = curKeys[pos]) == 0)) {
-                            curKeys[lastPos] = 0;
-                            return;
-                        }
-                        slot = (int) LongHashSet.mixBits(current) & LongHashSet.this.mask;
-                        if (lastPos <= pos ? (lastPos >= slot || slot > pos) : (lastPos >= slot && slot > pos)) {
-                            break;
-                        }
-                        pos = (pos + 1) & LongHashSet.this.mask;
-                    }
-                    if (pos < lastPos) {
-                        if (wrapped == null) {
-                            wrapped = new LongArrayList(2);
-                        }
-                        wrapped.add(curKeys[pos]);
-                    }
-                    curKeys[lastPos] = current;
-                }
-            }
-
-            @Override
-            public void remove() {
-                if (this.last == -1) {
-                    throw new IllegalStateException();
-                }
-                if (this.last == LongHashSet.this.capacity) {
-                    LongHashSet.this.containsZero = false;
-                    LongHashSet.this.keys[LongHashSet.this.capacity] = 0;
-                } else if (this.position >= 0) {
-                    shiftKeys(this.last);
-                } else {
-                    LongHashSet.this.remove(this.wrapped.getLong(-this.position - 1));
-                    this.last = -1;
-                    return;
-                }
-                LongHashSet.this.size--;
-                LongHashSet.this.modCount++;
-                this.last = -1;
-            }
-
-        }
-
-        private final class LongSpliterator implements Spliterator<Number> {
-            private int position;
-            private int fence;
-            private int expectedModCount;
-            private long estimatedSize;
-            private boolean nullPending;
-            private boolean zeroPending;
-            private boolean hasSplit;
-
-            LongSpliterator(int position, int fence, int expectedModCount,
-                    long estimatedSize, boolean nullPending,
-                    boolean zeroPending, boolean hasSplit) {
-                this.position = position;
-                this.fence = fence;
-                this.expectedModCount = expectedModCount;
-                this.estimatedSize = estimatedSize;
-                this.nullPending = nullPending;
-                this.zeroPending = zeroPending;
-                this.hasSplit = hasSplit;
-            }
-
-            private int getFence() {
-                if (fence < 0) {
-                    expectedModCount = modCount;
-                    estimatedSize = size;
-                    nullPending = containsNull;
-                    zeroPending = containsZero;
-                    fence = capacity;
-                }
-                return fence;
-            }
-
-            private void checkForComodification() {
-                if (expectedModCount != modCount) {
-                    throw new ConcurrentModificationException();
-                }
-            }
-
-            @Override
-            public Spliterator<Number> trySplit() {
-                int high = getFence();
-                int low = position;
-                int middle = (low + high) >>> 1;
-                if (low >= middle) {
-                    return null;
-                }
-                long splitEstimate = estimatedSize >>> 1;
-                LongSpliterator split = new LongSpliterator(low, middle,
-                        expectedModCount, splitEstimate, nullPending,
-                        zeroPending, true);
-                position = middle;
-                estimatedSize -= splitEstimate;
-                nullPending = false;
-                zeroPending = false;
-                hasSplit = true;
-                return split;
-            }
-
-            @Override
-            public boolean tryAdvance(Consumer<? super Number> action) {
-                Objects.requireNonNull(action);
-                int high = getFence();
-                if (nullPending) {
-                    nullPending = false;
-                    if (estimatedSize > 0) {
-                        estimatedSize--;
-                    }
-                    action.accept(null);
-                    checkForComodification();
-                    return true;
-                }
-                if (zeroPending) {
-                    zeroPending = false;
-                    if (estimatedSize > 0) {
-                        estimatedSize--;
-                    }
-                    action.accept(Long.valueOf(0L));
-                    checkForComodification();
-                    return true;
-                }
-                final long[] curKeys = keys;
-                while (position < high) {
-                    long key = curKeys[position++];
-                    if (key != 0L) {
-                        if (estimatedSize > 0) {
-                            estimatedSize--;
-                        }
-                        action.accept(Long.valueOf(key));
-                        checkForComodification();
-                        return true;
-                    }
-                }
-                checkForComodification();
-                return false;
-            }
-
-            @Override
-            public void forEachRemaining(Consumer<? super Number> action) {
-                Objects.requireNonNull(action);
-                int high = getFence();
-                if (nullPending) {
-                    nullPending = false;
-                    action.accept(null);
-                }
-                if (zeroPending) {
-                    zeroPending = false;
-                    action.accept(Long.valueOf(0L));
-                }
-                final long[] curKeys = keys;
-                while (position < high) {
-                    long key = curKeys[position++];
-                    if (key != 0L) {
-                        action.accept(Long.valueOf(key));
-                    }
-                }
-                estimatedSize = 0;
-                checkForComodification();
-            }
-
-            @Override
-            public long estimateSize() {
-                getFence();
-                return estimatedSize;
-            }
-
-            @Override
-            public int characteristics() {
-                return Spliterator.DISTINCT | (hasSplit ? 0 : Spliterator.SIZED);
-            }
-        }
-
-        private static class LongArrayList {
-            /** The initial default capacity of an array list. */
-            public static final int DEFAULT_INITIAL_CAPACITY = 10;
-            /** The backing array. */
-            protected long a[];
-            /**
-             * The current actual size of the list (never greater than the backing-array
-             * length).
-             */
-            protected int size;
-
-            private static final long[] DEFAULT_EMPTY_ARRAY = {};
-
-            private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
-            /**
-             * Creates a new array list with given capacity.
-             *
-             * @param capacity the initial capacity of the array list (may be 0).
-             */
-            public LongArrayList(final int capacity) {
-                initArrayFromCapacity(capacity);
-            }
-
-            private void initArrayFromCapacity(final int capacity) {
-                if (capacity < 0)
-                    throw new IllegalArgumentException("Initial capacity (" + capacity + ") is negative");
-                if (capacity == 0)
-                    a = LongArrayList.DEFAULT_EMPTY_ARRAY;
-                else
-                    a = new long[capacity];
-            }
-
-            public static long[] forceCapacity(final long[] array, final int length, final int preserve) {
-                final long t[] = new long[length];
-                System.arraycopy(array, 0, t, 0, preserve);
-                return t;
-            }
-
-            /**
-             * Grows this array list, ensuring that it can contain the given number of
-             * entries without resizing,
-             * and in case increasing the current capacity at least by a factor of 50%.
-             *
-             * @param capacity the new minimum capacity for this array list.
-             */
-
-            private void grow(int capacity) {
-                if (capacity <= a.length)
-                    return;
-                if (a != LongArrayList.DEFAULT_EMPTY_ARRAY)
-                    capacity = (int) Math.max(Math.min((long) a.length + (a.length >> 1), LongArrayList.MAX_ARRAY_SIZE),
-                            capacity);
-                else if (capacity < DEFAULT_INITIAL_CAPACITY)
-                    capacity = DEFAULT_INITIAL_CAPACITY;
-                a = LongArrayList.forceCapacity(a, capacity, size);
-                assert size <= a.length;
-            }
-
-            public boolean add(final long k) {
-                grow(size + 1);
-                a[size++] = k;
-                assert size <= a.length;
-                return true;
-            }
-
-            public long getLong(final int index) {
-                if (index >= size)
-                    throw new IndexOutOfBoundsException(
-                            "Index (" + index + ") is greater than or equal to list size (" + size + ")");
-                return a[index];
-            }
-
-        }
-    }
-
-    private static class IntHashSet extends PrimitiveHashSet {
-        int[] keys;
-
-        public IntHashSet() {
-            this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
-        }
-
-        public IntHashSet(final int initialCapacity, final float loadFactor) {
-            super(initialCapacity, loadFactor);
-            this.keys = new int[this.capacity + 1];
-        }
-
-        boolean addInt(int key) {
-            int pos;
-            if (key == 0) {
-                if (this.containsZero) {
-                    return false;
-                }
-                this.containsZero = true;
-            } else {
-                int current;
-                final int[] curKeys = this.keys;
-                if (!((current = curKeys[pos = (int) IntHashSet.mixBits(key) & this.mask]) == 0)) {
-                    if (current == key) {
-                        return false;
-                    }
-                    while (!((current = curKeys[pos = (pos + 1) & this.mask]) == 0)) {
-                        if (current == key) {
-                            return false;
-                        }
-                    }
-                }
-                curKeys[pos] = key;
-            }
-            if (this.size++ >= this.threshold) {
-                rehash(IntHashSet.leastArraySize(this.size + 1, this.loadFactor));
-            }
-            this.modCount++;
-            return true;
-        }
-
-        @Override
-        public boolean remove(Object key) {
-            if (key == null) {
-                return removeNull();
-            }
-            return key instanceof Integer && removeInt((Integer) key);
-        }
-
-        boolean removeInt(int key) {
-            if (key == 0) {
-                if (this.containsZero) {
-                    return removeNullEntry();
-                }
-                return false;
-            }
-            int current;
-            final int[] curKeys = this.keys;
-            int pos;
-            if (((current = curKeys[pos = (int) IntHashSet.mixBits(key) & this.mask]) == 0)) {
-                return false;
-            }
-            if (current == key) {
-                return removeEntry(pos);
-            }
-            while (true) {
-                if (((current = curKeys[pos = (pos + 1) & this.mask]) == 0)) {
-                    return false;
-                }
-                if (current == key) {
-                    return removeEntry(pos);
-                }
-            }
-        }
-
-        @Override
-        public boolean contains(Object key) {
-            if (key == null) {
-                return this.containsNull;
-            }
-            return key instanceof Integer && containsInt((Integer) key);
-        }
-
-        boolean containsInt(int key) {
-            if (key == 0) return this.containsZero;
-            int current;
-            final int[] curKeys = this.keys;
-            int pos = (int) IntHashSet.mixBits(key) & this.mask;
-            if ((current = curKeys[pos]) == 0) return false;
-            if (current == key) return true;
-            while ((current = curKeys[pos = (pos + 1) & this.mask]) != 0) {
-                if (current == key) return true;
-            }
-            return false;
-        }
-
-        Iterator<Integer> valueIterator() {
-            return new IntIterator();
-        }
-
-        @Override
-        public Spliterator<Number> spliterator() {
-            return new IntSpliterator(0, -1, 0, 0, false, false, false);
-        }
-
-        @Override
-        void forEachElement(Consumer<? super Number> action) {
-            if (containsZero) {
-                action.accept(Integer.valueOf(0));
-            }
-            final int[] curKeys = keys;
-            for (int i = capacity; i-- != 0;) {
-                int key = curKeys[i];
-                if (key != 0) {
-                    action.accept(Integer.valueOf(key));
-                }
-            }
-        }
-
-        public void clear() {
-            if (this.size == 0) {
-                return;
-            }
-            this.size = 0;
-            this.containsZero = false;
-            this.containsNull = false;
-            Arrays.fill(this.keys, 0);
-            this.modCount++;
-        }
-
-        @Override
-        public IntHashSet clone() {
-            IntHashSet newSet = (IntHashSet) super.clone();
-            newSet.keys = this.keys.clone();
-            return newSet;
-        }
-
-        @Override
-        public int hashCode() {
-            int h = 0;
-            for (int j = realSize(), i = 0; j-- != 0;) {
-                while (this.keys[i] == 0) {
-                    i++;
-                }
-                h += this.keys[i];
-                i++;
-            }
-            return h;
-        }
-
-        private boolean removeEntry(int pos) {
-            this.size--;
-            shiftKeys(pos);
-            if (this.capacity > this.minCapacity && this.size < this.threshold >> 2
-                    && this.capacity > DEFAULT_INITIAL_CAPACITY) {
-                rehash(this.capacity >> 1);
-            }
-            this.modCount++;
-            return true;
-        }
-
-        private void shiftKeys(int pos) {
-            int last, slot;
-            int current;
-            final int[] curKeys = this.keys;
-            for (;;) {
-                pos = ((last = pos) + 1) & this.mask;
-                for (;;) {
-                    if (((current = curKeys[pos]) == 0)) {
-                        curKeys[last] = 0;
-                        return;
-                    }
-                    slot = (int) IntHashSet.mixBits(current) & this.mask;
-                    if (last <= pos ? (last >= slot || slot > pos) : (last >= slot && slot > pos)) {
-                        break;
-                    }
-                    pos = (pos + 1) & this.mask;
-                }
-                curKeys[last] = current;
-            }
-        }
-
-        private boolean removeNullEntry() {
-            this.containsZero = false;
-            this.keys[this.capacity] = 0;
-            this.size--;
-            if (this.capacity > this.minCapacity && this.size < this.threshold >> 2
-                    && this.capacity > DEFAULT_INITIAL_CAPACITY) {
-                rehash(this.capacity >> 1);
-            }
-            this.modCount++;
-            return true;
-        }
-
-        private void rehash(final int newCapacity) {
-            final int[] oldKeys = this.keys;
-            final int newMask = newCapacity - 1;
-            final int[] newKeys = new int[newCapacity + 1];
-            int i = this.capacity, pos;
-            for (int j = realSize(); j-- != 0;) {
-                while ((oldKeys[--i] == 0))
-                    ;
-                if (!((newKeys[pos = (int) IntHashSet.mixBits(oldKeys[i]) & newMask]) == 0)) {
-                    while (!((newKeys[pos = (pos + 1) & newMask]) == 0))
-                        ;
-                }
-                newKeys[pos] = oldKeys[i];
-            }
-            this.capacity = newCapacity;
-            this.mask = newMask;
-            this.threshold = IntHashSet.maxEntriesFill(this.capacity, this.loadFactor);
-            this.keys = newKeys;
-        }
-
-        private final class IntIterator implements PrimitiveIterator.OfInt {
-            private int position = IntHashSet.this.capacity;
-            private int last = -1;
-            private int counter = IntHashSet.this.size - (IntHashSet.this.containsNull ? 1 : 0);
-            private boolean mustReturnZero = IntHashSet.this.containsZero;
-            private IntArrayList wrapped;
-
-            @Override
-            public int nextInt() {
-                if (!hasNext()) {
-                    throw new java.util.NoSuchElementException();
-                }
-                this.counter--;
-                if (this.mustReturnZero) {
-                    this.mustReturnZero = false;
-                    last = IntHashSet.this.capacity;
-                    return IntHashSet.this.keys[IntHashSet.this.capacity];
-                }
-                final int[] curKeys = IntHashSet.this.keys;
-                for (;;) {
-                    if (--this.position < 0) {
-                        this.last = Integer.MIN_VALUE;
-                        return this.wrapped.getInt(-this.position - 1);
-                    }
-                    if (!(curKeys[this.position] == 0)) {
-                        return curKeys[this.last = this.position];
-                    }
-                }
-            }
-
-            @Override
-            public boolean hasNext() {
-                return this.counter != 0;
-            }
-
-            private final void shiftKeys(int pos) {
-                int lastPos, slot;
-                int current;
-                final int[] curKeys = IntHashSet.this.keys;
-                for (;;) {
-                    pos = ((lastPos = pos) + 1) & IntHashSet.this.mask;
-                    for (;;) {
-                        if (((current = curKeys[pos]) == 0)) {
-                            curKeys[lastPos] = 0;
-                            return;
-                        }
-                        slot = (int) IntHashSet.mixBits(current) & IntHashSet.this.mask;
-                        if (lastPos <= pos ? (lastPos >= slot || slot > pos) : (lastPos >= slot && slot > pos)) {
-                            break;
-                        }
-                        pos = (pos + 1) & IntHashSet.this.mask;
-                    }
-                    if (pos < lastPos) {
-                        if (wrapped == null) {
-                            wrapped = new IntArrayList(2);
-                        }
-                        wrapped.add(curKeys[pos]);
-                    }
-                    curKeys[lastPos] = current;
-                }
-            }
-
-            @Override
-            public void remove() {
-                if (this.last == -1) {
-                    throw new IllegalStateException();
-                }
-                if (this.last == IntHashSet.this.capacity) {
-                    IntHashSet.this.containsZero = false;
-                    IntHashSet.this.keys[IntHashSet.this.capacity] = 0;
-                } else if (this.position >= 0) {
-                    shiftKeys(this.last);
-                } else {
-                    IntHashSet.this.remove(this.wrapped.getInt(-this.position - 1));
-                    this.last = -1;
-                    return;
-                }
-                IntHashSet.this.size--;
-                IntHashSet.this.modCount++;
-                this.last = -1;
-            }
-
-        }
-
-        private final class IntSpliterator implements Spliterator<Number> {
-            private int position;
-            private int fence;
-            private int expectedModCount;
-            private long estimatedSize;
-            private boolean nullPending;
-            private boolean zeroPending;
-            private boolean hasSplit;
-
-            IntSpliterator(int position, int fence, int expectedModCount,
-                    long estimatedSize, boolean nullPending,
-                    boolean zeroPending, boolean hasSplit) {
-                this.position = position;
-                this.fence = fence;
-                this.expectedModCount = expectedModCount;
-                this.estimatedSize = estimatedSize;
-                this.nullPending = nullPending;
-                this.zeroPending = zeroPending;
-                this.hasSplit = hasSplit;
-            }
-
-            private int getFence() {
-                if (fence < 0) {
-                    expectedModCount = modCount;
-                    estimatedSize = size;
-                    nullPending = containsNull;
-                    zeroPending = containsZero;
-                    fence = capacity;
-                }
-                return fence;
-            }
-
-            private void checkForComodification() {
-                if (expectedModCount != modCount) {
-                    throw new ConcurrentModificationException();
-                }
-            }
-
-            @Override
-            public Spliterator<Number> trySplit() {
-                int high = getFence();
-                int low = position;
-                int middle = (low + high) >>> 1;
-                if (low >= middle) {
-                    return null;
-                }
-                long splitEstimate = estimatedSize >>> 1;
-                IntSpliterator split = new IntSpliterator(low, middle,
-                        expectedModCount, splitEstimate, nullPending,
-                        zeroPending, true);
-                position = middle;
-                estimatedSize -= splitEstimate;
-                nullPending = false;
-                zeroPending = false;
-                hasSplit = true;
-                return split;
-            }
-
-            @Override
-            public boolean tryAdvance(Consumer<? super Number> action) {
-                Objects.requireNonNull(action);
-                int high = getFence();
-                if (nullPending) {
-                    nullPending = false;
-                    if (estimatedSize > 0) {
-                        estimatedSize--;
-                    }
-                    action.accept(null);
-                    checkForComodification();
-                    return true;
-                }
-                if (zeroPending) {
-                    zeroPending = false;
-                    if (estimatedSize > 0) {
-                        estimatedSize--;
-                    }
-                    action.accept(Integer.valueOf(0));
-                    checkForComodification();
-                    return true;
-                }
-                final int[] curKeys = keys;
-                while (position < high) {
-                    int key = curKeys[position++];
-                    if (key != 0) {
-                        if (estimatedSize > 0) {
-                            estimatedSize--;
-                        }
-                        action.accept(Integer.valueOf(key));
-                        checkForComodification();
-                        return true;
-                    }
-                }
-                checkForComodification();
-                return false;
-            }
-
-            @Override
-            public void forEachRemaining(Consumer<? super Number> action) {
-                Objects.requireNonNull(action);
-                int high = getFence();
-                if (nullPending) {
-                    nullPending = false;
-                    action.accept(null);
-                }
-                if (zeroPending) {
-                    zeroPending = false;
-                    action.accept(Integer.valueOf(0));
-                }
-                final int[] curKeys = keys;
-                while (position < high) {
-                    int key = curKeys[position++];
-                    if (key != 0) {
-                        action.accept(Integer.valueOf(key));
-                    }
-                }
-                estimatedSize = 0;
-                checkForComodification();
-            }
-
-            @Override
-            public long estimateSize() {
-                getFence();
-                return estimatedSize;
-            }
-
-            @Override
-            public int characteristics() {
-                return Spliterator.DISTINCT | (hasSplit ? 0 : Spliterator.SIZED);
-            }
-        }
-
-        private static class IntArrayList {
-            /** The initial default capacity of an array list. */
-            public static final int DEFAULT_INITIAL_CAPACITY = 10;
-            /** The backing array. */
-            protected int a[];
-            /**
-             * The current actual size of the list (never greater than the backing-array
-             * length).
-             */
-            protected int size;
-
-            private static final int[] DEFAULT_EMPTY_ARRAY = {};
-
-            private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
-
-            /**
-             * Creates a new array list with given capacity.
-             *
-             * @param capacity the initial capacity of the array list (may be 0).
-             */
-            public IntArrayList(final int capacity) {
-                initArrayFromCapacity(capacity);
-            }
-
-            private void initArrayFromCapacity(final int capacity) {
-                if (capacity < 0)
-                    throw new IllegalArgumentException("Initial capacity (" + capacity + ") is negative");
-                if (capacity == 0)
-                    a = IntArrayList.DEFAULT_EMPTY_ARRAY;
-                else
-                    a = new int[capacity];
-            }
-
-            public static int[] forceCapacity(final int[] array, final int length, final int preserve) {
-                final int t[] = new int[length];
-                System.arraycopy(array, 0, t, 0, preserve);
-                return t;
-            }
-
-            /**
-             * Grows this array list, ensuring that it can contain the given number of
-             * entries without resizing,
-             * and in case increasing the current capacity at least by a factor of 50%.
-             *
-             * @param capacity the new minimum capacity for this array list.
-             */
-
-            private void grow(int capacity) {
-                if (capacity <= a.length)
-                    return;
-                if (a != IntArrayList.DEFAULT_EMPTY_ARRAY)
-                    capacity = (int) Math.max(Math.min((long) a.length + (a.length >> 1), IntArrayList.MAX_ARRAY_SIZE),
-                            capacity);
-                else if (capacity < DEFAULT_INITIAL_CAPACITY)
-                    capacity = DEFAULT_INITIAL_CAPACITY;
-                a = IntArrayList.forceCapacity(a, capacity, size);
-                assert size <= a.length;
-            }
-
-            public boolean add(final int k) {
-                grow(size + 1);
-                a[size++] = k;
-                assert size <= a.length;
-                return true;
-            }
-
-            public int getInt(final int index) {
-                if (index >= size)
-                    throw new IndexOutOfBoundsException(
-                            "Index (" + index + ") is greater than or equal to list size (" + size + ")");
-                return a[index];
-            }
-
-        }
-    }
 }
diff --git a/test/jdk/jdk/internal/enhancement/classdata/java/util/IntHashSet.java b/test/jdk/jdk/internal/enhancement/classdata/java/util/IntHashSet.java
new file mode 100644
index 000000000..803c96025
--- /dev/null
+++ b/test/jdk/jdk/internal/enhancement/classdata/java/util/IntHashSet.java
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2002-2026 Sebastiano Vigna
+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * Primitive int representation used by the bytecode-enhanced HashSet.
+ *
+ * <p>This implementation incorporates and adapts ideas and portions from
+ * fastutil OpenHashSet, with separate null and zero-key handling required by
+ * java.util.HashSet semantics.
+ */
+class IntHashSet extends PrimitiveHashSet {
+    int[] keys;
+
+    public IntHashSet() {
+        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+    }
+
+    public IntHashSet(final int initialCapacity, final float loadFactor) {
+        super(initialCapacity, loadFactor);
+        this.keys = new int[this.capacity + 1];
+    }
+
+    boolean addInt(int key) {
+        int pos;
+        if (key == 0) {
+            if (this.containsZero) {
+                return false;
+            }
+            this.containsZero = true;
+        } else {
+            int current;
+            final int[] curKeys = this.keys;
+            if (!((current = curKeys[pos = (int) IntHashSet.mixBits(key) & this.mask]) == 0)) {
+                if (current == key) {
+                    return false;
+                }
+                while (!((current = curKeys[pos = (pos + 1) & this.mask]) == 0)) {
+                    if (current == key) {
+                        return false;
+                    }
+                }
+            }
+            curKeys[pos] = key;
+        }
+        if (this.size++ >= this.threshold) {
+            rehash(IntHashSet.leastArraySize(this.size + 1, this.loadFactor));
+        }
+        this.modCount++;
+        return true;
+    }
+
+    @Override
+    public boolean remove(Object key) {
+        if (key == null) {
+            return removeNull();
+        }
+        return key instanceof Integer && removeInt((Integer) key);
+    }
+
+    boolean removeInt(int key) {
+        if (key == 0) {
+            if (this.containsZero) {
+                return removeNullEntry();
+            }
+            return false;
+        }
+        int current;
+        final int[] curKeys = this.keys;
+        int pos;
+        if (((current = curKeys[pos = (int) IntHashSet.mixBits(key) & this.mask]) == 0)) {
+            return false;
+        }
+        if (current == key) {
+            return removeEntry(pos);
+        }
+        while (true) {
+            if (((current = curKeys[pos = (pos + 1) & this.mask]) == 0)) {
+                return false;
+            }
+            if (current == key) {
+                return removeEntry(pos);
+            }
+        }
+    }
+
+    @Override
+    public boolean contains(Object key) {
+        if (key == null) {
+            return this.containsNull;
+        }
+        return key instanceof Integer && containsInt((Integer) key);
+    }
+
+    boolean containsInt(int key) {
+        if (key == 0) return this.containsZero;
+        int current;
+        final int[] curKeys = this.keys;
+        int pos = (int) IntHashSet.mixBits(key) & this.mask;
+        if ((current = curKeys[pos]) == 0) return false;
+        if (current == key) return true;
+        while ((current = curKeys[pos = (pos + 1) & this.mask]) != 0) {
+            if (current == key) return true;
+        }
+        return false;
+    }
+
+    Iterator<Integer> valueIterator() {
+        return new IntIterator();
+    }
+
+    @Override
+    public Spliterator<Number> spliterator() {
+        return new IntSpliterator(0, -1, 0, 0, false, false, false);
+    }
+
+    @Override
+    void forEachElement(Consumer<? super Number> action) {
+        if (containsZero) {
+            action.accept(Integer.valueOf(0));
+        }
+        final int[] curKeys = keys;
+        for (int i = capacity; i-- != 0;) {
+            int key = curKeys[i];
+            if (key != 0) {
+                action.accept(Integer.valueOf(key));
+            }
+        }
+    }
+
+    public void clear() {
+        if (this.size == 0) {
+            return;
+        }
+        this.size = 0;
+        this.containsZero = false;
+        this.containsNull = false;
+        Arrays.fill(this.keys, 0);
+        this.modCount++;
+    }
+
+    @Override
+    public IntHashSet clone() {
+        IntHashSet newSet = (IntHashSet) super.clone();
+        newSet.keys = this.keys.clone();
+        return newSet;
+    }
+
+    @Override
+    public int hashCode() {
+        int h = 0;
+        for (int j = realSize(), i = 0; j-- != 0;) {
+            while (this.keys[i] == 0) {
+                i++;
+            }
+            h += this.keys[i];
+            i++;
+        }
+        return h;
+    }
+
+    private boolean removeEntry(int pos) {
+        this.size--;
+        shiftKeys(pos);
+        if (this.capacity > this.minCapacity && this.size < this.threshold >> 2
+                && this.capacity > DEFAULT_INITIAL_CAPACITY) {
+            rehash(this.capacity >> 1);
+        }
+        this.modCount++;
+        return true;
+    }
+
+    private void shiftKeys(int pos) {
+        int last, slot;
+        int current;
+        final int[] curKeys = this.keys;
+        for (;;) {
+            pos = ((last = pos) + 1) & this.mask;
+            for (;;) {
+                if (((current = curKeys[pos]) == 0)) {
+                    curKeys[last] = 0;
+                    return;
+                }
+                slot = (int) IntHashSet.mixBits(current) & this.mask;
+                if (last <= pos ? (last >= slot || slot > pos) : (last >= slot && slot > pos)) {
+                    break;
+                }
+                pos = (pos + 1) & this.mask;
+            }
+            curKeys[last] = current;
+        }
+    }
+
+    private boolean removeNullEntry() {
+        this.containsZero = false;
+        this.keys[this.capacity] = 0;
+        this.size--;
+        if (this.capacity > this.minCapacity && this.size < this.threshold >> 2
+                && this.capacity > DEFAULT_INITIAL_CAPACITY) {
+            rehash(this.capacity >> 1);
+        }
+        this.modCount++;
+        return true;
+    }
+
+    private void rehash(final int newCapacity) {
+        final int[] oldKeys = this.keys;
+        final int newMask = newCapacity - 1;
+        final int[] newKeys = new int[newCapacity + 1];
+        int i = this.capacity, pos;
+        for (int j = realSize(); j-- != 0;) {
+            while ((oldKeys[--i] == 0))
+                ;
+            if (!((newKeys[pos = (int) IntHashSet.mixBits(oldKeys[i]) & newMask]) == 0)) {
+                while (!((newKeys[pos = (pos + 1) & newMask]) == 0))
+                    ;
+            }
+            newKeys[pos] = oldKeys[i];
+        }
+        this.capacity = newCapacity;
+        this.mask = newMask;
+        this.threshold = IntHashSet.maxEntriesFill(this.capacity, this.loadFactor);
+        this.keys = newKeys;
+    }
+
+    private final class IntIterator implements PrimitiveIterator.OfInt {
+        private int position = IntHashSet.this.capacity;
+        private int last = -1;
+        private int counter = IntHashSet.this.size - (IntHashSet.this.containsNull ? 1 : 0);
+        private boolean mustReturnZero = IntHashSet.this.containsZero;
+        private IntArrayList wrapped;
+
+        @Override
+        public int nextInt() {
+            if (!hasNext()) {
+                throw new java.util.NoSuchElementException();
+            }
+            this.counter--;
+            if (this.mustReturnZero) {
+                this.mustReturnZero = false;
+                last = IntHashSet.this.capacity;
+                return IntHashSet.this.keys[IntHashSet.this.capacity];
+            }
+            final int[] curKeys = IntHashSet.this.keys;
+            for (;;) {
+                if (--this.position < 0) {
+                    this.last = Integer.MIN_VALUE;
+                    return this.wrapped.getInt(-this.position - 1);
+                }
+                if (!(curKeys[this.position] == 0)) {
+                    return curKeys[this.last = this.position];
+                }
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            return this.counter != 0;
+        }
+
+        private final void shiftKeys(int pos) {
+            int lastPos, slot;
+            int current;
+            final int[] curKeys = IntHashSet.this.keys;
+            for (;;) {
+                pos = ((lastPos = pos) + 1) & IntHashSet.this.mask;
+                for (;;) {
+                    if (((current = curKeys[pos]) == 0)) {
+                        curKeys[lastPos] = 0;
+                        return;
+                    }
+                    slot = (int) IntHashSet.mixBits(current) & IntHashSet.this.mask;
+                    if (lastPos <= pos ? (lastPos >= slot || slot > pos) : (lastPos >= slot && slot > pos)) {
+                        break;
+                    }
+                    pos = (pos + 1) & IntHashSet.this.mask;
+                }
+                if (pos < lastPos) {
+                    if (wrapped == null) {
+                        wrapped = new IntArrayList(2);
+                    }
+                    wrapped.add(curKeys[pos]);
+                }
+                curKeys[lastPos] = current;
+            }
+        }
+
+        @Override
+        public void remove() {
+            if (this.last == -1) {
+                throw new IllegalStateException();
+            }
+            if (this.last == IntHashSet.this.capacity) {
+                IntHashSet.this.containsZero = false;
+                IntHashSet.this.keys[IntHashSet.this.capacity] = 0;
+            } else if (this.position >= 0) {
+                shiftKeys(this.last);
+            } else {
+                IntHashSet.this.remove(this.wrapped.getInt(-this.position - 1));
+                this.last = -1;
+                return;
+            }
+            IntHashSet.this.size--;
+            IntHashSet.this.modCount++;
+            this.last = -1;
+        }
+
+    }
+
+    private final class IntSpliterator implements Spliterator<Number> {
+        private int position;
+        private int fence;
+        private int expectedModCount;
+        private long estimatedSize;
+        private boolean nullPending;
+        private boolean zeroPending;
+        private boolean hasSplit;
+
+        IntSpliterator(int position, int fence, int expectedModCount,
+                long estimatedSize, boolean nullPending,
+                boolean zeroPending, boolean hasSplit) {
+            this.position = position;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+            this.estimatedSize = estimatedSize;
+            this.nullPending = nullPending;
+            this.zeroPending = zeroPending;
+            this.hasSplit = hasSplit;
+        }
+
+        private int getFence() {
+            if (fence < 0) {
+                expectedModCount = modCount;
+                estimatedSize = size;
+                nullPending = containsNull;
+                zeroPending = containsZero;
+                fence = capacity;
+            }
+            return fence;
+        }
+
+        private void checkForComodification() {
+            if (expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        @Override
+        public Spliterator<Number> trySplit() {
+            int high = getFence();
+            int low = position;
+            int middle = (low + high) >>> 1;
+            if (low >= middle) {
+                return null;
+            }
+            long splitEstimate = estimatedSize >>> 1;
+            IntSpliterator split = new IntSpliterator(low, middle,
+                    expectedModCount, splitEstimate, nullPending,
+                    zeroPending, true);
+            position = middle;
+            estimatedSize -= splitEstimate;
+            nullPending = false;
+            zeroPending = false;
+            hasSplit = true;
+            return split;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super Number> action) {
+            Objects.requireNonNull(action);
+            int high = getFence();
+            if (nullPending) {
+                nullPending = false;
+                if (estimatedSize > 0) {
+                    estimatedSize--;
+                }
+                action.accept(null);
+                checkForComodification();
+                return true;
+            }
+            if (zeroPending) {
+                zeroPending = false;
+                if (estimatedSize > 0) {
+                    estimatedSize--;
+                }
+                action.accept(Integer.valueOf(0));
+                checkForComodification();
+                return true;
+            }
+            final int[] curKeys = keys;
+            while (position < high) {
+                int key = curKeys[position++];
+                if (key != 0) {
+                    if (estimatedSize > 0) {
+                        estimatedSize--;
+                    }
+                    action.accept(Integer.valueOf(key));
+                    checkForComodification();
+                    return true;
+                }
+            }
+            checkForComodification();
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super Number> action) {
+            Objects.requireNonNull(action);
+            int high = getFence();
+            if (nullPending) {
+                nullPending = false;
+                action.accept(null);
+            }
+            if (zeroPending) {
+                zeroPending = false;
+                action.accept(Integer.valueOf(0));
+            }
+            final int[] curKeys = keys;
+            while (position < high) {
+                int key = curKeys[position++];
+                if (key != 0) {
+                    action.accept(Integer.valueOf(key));
+                }
+            }
+            estimatedSize = 0;
+            checkForComodification();
+        }
+
+        @Override
+        public long estimateSize() {
+            getFence();
+            return estimatedSize;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.DISTINCT | (hasSplit ? 0 : Spliterator.SIZED);
+        }
+    }
+
+    private static class IntArrayList {
+        /** The initial default capacity of an array list. */
+        public static final int DEFAULT_INITIAL_CAPACITY = 10;
+        private static final int[] DEFAULT_EMPTY_ARRAY = {};
+        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+        /** The backing array. */
+        protected int a[];
+        /**
+         * The current actual size of the list (never greater than the backing-array
+         * length).
+         */
+        protected int size;
+
+        /**
+         * Creates a new array list with given capacity.
+         *
+         * @param capacity the initial capacity of the array list (may be 0).
+         */
+        public IntArrayList(final int capacity) {
+            initArrayFromCapacity(capacity);
+        }
+
+        private void initArrayFromCapacity(final int capacity) {
+            if (capacity < 0)
+                throw new IllegalArgumentException("Initial capacity (" + capacity + ") is negative");
+            if (capacity == 0)
+                a = IntArrayList.DEFAULT_EMPTY_ARRAY;
+            else
+                a = new int[capacity];
+        }
+
+        public static int[] forceCapacity(final int[] array, final int length, final int preserve) {
+            final int t[] = new int[length];
+            System.arraycopy(array, 0, t, 0, preserve);
+            return t;
+        }
+
+        /**
+         * Grows this array list, ensuring that it can contain the given number of
+         * entries without resizing,
+         * and in case increasing the current capacity at least by a factor of 50%.
+         *
+         * @param capacity the new minimum capacity for this array list.
+         */
+
+        private void grow(int capacity) {
+            if (capacity <= a.length)
+                return;
+            if (a != IntArrayList.DEFAULT_EMPTY_ARRAY)
+                capacity = (int) Math.max(Math.min((long) a.length + (a.length >> 1), IntArrayList.MAX_ARRAY_SIZE),
+                        capacity);
+            else if (capacity < DEFAULT_INITIAL_CAPACITY)
+                capacity = DEFAULT_INITIAL_CAPACITY;
+            a = IntArrayList.forceCapacity(a, capacity, size);
+            assert size <= a.length;
+        }
+
+        public boolean add(final int k) {
+            grow(size + 1);
+            a[size++] = k;
+            assert size <= a.length;
+            return true;
+        }
+
+        public int getInt(final int index) {
+            if (index >= size)
+                throw new IndexOutOfBoundsException(
+                        "Index (" + index + ") is greater than or equal to list size (" + size + ")");
+            return a[index];
+        }
+
+    }
+}
diff --git a/test/jdk/jdk/internal/enhancement/classdata/java/util/LongHashSet.java b/test/jdk/jdk/internal/enhancement/classdata/java/util/LongHashSet.java
new file mode 100644
index 000000000..8f9f9d040
--- /dev/null
+++ b/test/jdk/jdk/internal/enhancement/classdata/java/util/LongHashSet.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2002-2026 Sebastiano Vigna
+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * Primitive long representation used by the bytecode-enhanced HashSet.
+ *
+ * <p>This implementation incorporates and adapts ideas and portions from
+ * fastutil OpenHashSet, with separate null and zero-key handling required by
+ * java.util.HashSet semantics.
+ */
+class LongHashSet extends PrimitiveHashSet {
+    long[] keys;
+
+    public LongHashSet() {
+        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+    }
+
+    public LongHashSet(final int initialCapacity, final float loadFactor) {
+        super(initialCapacity, loadFactor);
+        this.keys = new long[this.capacity + 1];
+    }
+
+    boolean addLong(long key) {
+        int pos;
+        if (key == 0L) {
+            if (this.containsZero) {
+                return false;
+            }
+            this.containsZero = true;
+        } else {
+            long current;
+            final long[] curKeys = this.keys;
+            if (!((current = curKeys[pos = (int) LongHashSet.mixBits(key) & this.mask]) == 0)) {
+                if (current == key) {
+                    return false;
+                }
+                while (!((current = curKeys[pos = (pos + 1) & this.mask]) == 0)) {
+                    if (current == key) {
+                        return false;
+                    }
+                }
+            }
+            curKeys[pos] = key;
+        }
+        if (this.size++ >= this.threshold) {
+            rehash(LongHashSet.leastArraySize(this.size + 1, this.loadFactor));
+        }
+        this.modCount++;
+        return true;
+    }
+
+    @Override
+    public boolean remove(Object key) {
+        if (key == null) {
+            return removeNull();
+        }
+        return key instanceof Long && removeLong((Long) key);
+    }
+
+    boolean removeLong(long key) {
+        if (key == 0L) {
+            if (this.containsZero) {
+                return removeNullEntry();
+            }
+            return false;
+        }
+        long current;
+        final long[] curKeys = this.keys;
+        int pos;
+        if (((current = curKeys[pos = (int) LongHashSet.mixBits(key) & this.mask]) == 0)) {
+            return false;
+        }
+        if (current == key) {
+            return removeEntry(pos);
+        }
+        while (true) {
+            if (((current = curKeys[pos = (pos + 1) & this.mask]) == 0)) {
+                return false;
+            }
+            if (current == key) {
+                return removeEntry(pos);
+            }
+        }
+    }
+
+    @Override
+    public boolean contains(Object key) {
+        if (key == null) {
+            return this.containsNull;
+        }
+        return key instanceof Long && containsLong((Long) key);
+    }
+
+    boolean containsLong(long key) {
+        if (key == 0L) return this.containsZero;
+        long current;
+        final long[] curKeys = this.keys;
+        int pos = (int) LongHashSet.mixBits(key) & this.mask;
+        if ((current = curKeys[pos]) == 0) return false;
+        if (current == key) return true;
+        while ((current = curKeys[pos = (pos + 1) & this.mask]) != 0) {
+            if (current == key) return true;
+        }
+        return false;
+    }
+
+
+    Iterator<Long> valueIterator() {
+        return new LongIterator();
+    }
+
+    @Override
+    public Spliterator<Number> spliterator() {
+        return new LongSpliterator(0, -1, 0, 0, false, false, false);
+    }
+
+    @Override
+    void forEachElement(Consumer<? super Number> action) {
+        if (containsZero) {
+            action.accept(Long.valueOf(0));
+        }
+        final long[] curKeys = keys;
+        for (int i = capacity; i-- != 0;) {
+            long key = curKeys[i];
+            if (key != 0) {
+                action.accept(Long.valueOf(key));
+            }
+        }
+    }
+
+    public void clear() {
+        if (this.size == 0) {
+            return;
+        }
+        this.size = 0;
+        this.containsZero = false;
+        this.containsNull = false;
+        Arrays.fill(this.keys, 0);
+        this.modCount++;
+    }
+
+    @Override
+    public LongHashSet clone() {
+        LongHashSet newSet = (LongHashSet) super.clone();
+        newSet.keys = this.keys.clone();
+        return newSet;
+    }
+
+    @Override
+    public int hashCode() {
+        int h = 0;
+        for (int j = realSize(), i = 0; j-- != 0;) {
+            while (this.keys[i] == 0) {
+                i++;
+            }
+            h += (int) (this.keys[i] ^ (this.keys[i] >>> 32));
+            i++;
+        }
+        return h;
+    }
+
+    private boolean removeEntry(int pos) {
+        this.size--;
+        shiftKeys(pos);
+        if (this.capacity > this.minCapacity && this.size < this.threshold >> 2
+                && this.capacity > DEFAULT_INITIAL_CAPACITY) {
+            rehash(this.capacity >> 1);
+        }
+        this.modCount++;
+        return true;
+    }
+
+    private void shiftKeys(int pos) {
+        int last, slot;
+        long current;
+        final long[] curKeys = this.keys;
+        for (;;) {
+            pos = ((last = pos) + 1) & this.mask;
+            for (;;) {
+                if (((current = curKeys[pos]) == 0)) {
+                    curKeys[last] = 0;
+                    return;
+                }
+                slot = (int) LongHashSet.mixBits(current) & this.mask;
+                if (last <= pos ? (last >= slot || slot > pos) : (last >= slot && slot > pos)) {
+                    break;
+                }
+                pos = (pos + 1) & this.mask;
+            }
+            curKeys[last] = current;
+        }
+    }
+
+    private boolean removeNullEntry() {
+        this.containsZero = false;
+        this.keys[this.capacity] = 0;
+        this.size--;
+        if (this.capacity > this.minCapacity && this.size < this.threshold >> 2
+                && this.capacity > DEFAULT_INITIAL_CAPACITY) {
+            rehash(this.capacity >> 1);
+        }
+        this.modCount++;
+        return true;
+    }
+
+    private void rehash(final int newCapacity) {
+        final long[] oldKeys = this.keys;
+        final int newMask = newCapacity - 1;
+        final long[] newKeys = new long[newCapacity + 1];
+        int i = this.capacity, pos;
+        for (int j = realSize(); j-- != 0;) {
+            while ((oldKeys[--i] == 0))
+                ;
+            if (!((newKeys[pos = (int) LongHashSet.mixBits(oldKeys[i]) & newMask]) == 0)) {
+                while (!((newKeys[pos = (pos + 1) & newMask]) == 0))
+                    ;
+            }
+            newKeys[pos] = oldKeys[i];
+        }
+        this.capacity = newCapacity;
+        this.mask = newMask;
+        this.threshold = LongHashSet.maxEntriesFill(this.capacity, this.loadFactor);
+        this.keys = newKeys;
+    }
+
+    private final class LongIterator implements PrimitiveIterator.OfLong {
+        private int position = LongHashSet.this.capacity;
+        private int last = -1;
+        private int counter = LongHashSet.this.size - (LongHashSet.this.containsNull ? 1 : 0);
+        private boolean mustReturnZero = LongHashSet.this.containsZero;
+        private LongArrayList wrapped;
+
+        @Override
+        public long nextLong() {
+            if (!hasNext()) {
+                throw new java.util.NoSuchElementException();
+            }
+            this.counter--;
+            if (this.mustReturnZero) {
+                this.mustReturnZero = false;
+                last = LongHashSet.this.capacity;
+                return LongHashSet.this.keys[LongHashSet.this.capacity];
+            }
+            final long[] curKeys = LongHashSet.this.keys;
+            for (;;) {
+                if (--this.position < 0) {
+                    this.last = Integer.MIN_VALUE;
+                    return this.wrapped.getLong(-this.position - 1);
+                }
+                if (!(curKeys[this.position] == 0)) {
+                    return curKeys[this.last = this.position];
+                }
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            return this.counter != 0;
+        }
+
+        private final void shiftKeys(int pos) {
+            int lastPos, slot;
+            long current;
+            final long[] curKeys = LongHashSet.this.keys;
+            for (;;) {
+                pos = ((lastPos = pos) + 1) & LongHashSet.this.mask;
+                for (;;) {
+                    if (((current = curKeys[pos]) == 0)) {
+                        curKeys[lastPos] = 0;
+                        return;
+                    }
+                    slot = (int) LongHashSet.mixBits(current) & LongHashSet.this.mask;
+                    if (lastPos <= pos ? (lastPos >= slot || slot > pos) : (lastPos >= slot && slot > pos)) {
+                        break;
+                    }
+                    pos = (pos + 1) & LongHashSet.this.mask;
+                }
+                if (pos < lastPos) {
+                    if (wrapped == null) {
+                        wrapped = new LongArrayList(2);
+                    }
+                    wrapped.add(curKeys[pos]);
+                }
+                curKeys[lastPos] = current;
+            }
+        }
+
+        @Override
+        public void remove() {
+            if (this.last == -1) {
+                throw new IllegalStateException();
+            }
+            if (this.last == LongHashSet.this.capacity) {
+                LongHashSet.this.containsZero = false;
+                LongHashSet.this.keys[LongHashSet.this.capacity] = 0;
+            } else if (this.position >= 0) {
+                shiftKeys(this.last);
+            } else {
+                LongHashSet.this.remove(this.wrapped.getLong(-this.position - 1));
+                this.last = -1;
+                return;
+            }
+            LongHashSet.this.size--;
+            LongHashSet.this.modCount++;
+            this.last = -1;
+        }
+
+    }
+
+    private final class LongSpliterator implements Spliterator<Number> {
+        private int position;
+        private int fence;
+        private int expectedModCount;
+        private long estimatedSize;
+        private boolean nullPending;
+        private boolean zeroPending;
+        private boolean hasSplit;
+
+        LongSpliterator(int position, int fence, int expectedModCount,
+                long estimatedSize, boolean nullPending,
+                boolean zeroPending, boolean hasSplit) {
+            this.position = position;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+            this.estimatedSize = estimatedSize;
+            this.nullPending = nullPending;
+            this.zeroPending = zeroPending;
+            this.hasSplit = hasSplit;
+        }
+
+        private int getFence() {
+            if (fence < 0) {
+                expectedModCount = modCount;
+                estimatedSize = size;
+                nullPending = containsNull;
+                zeroPending = containsZero;
+                fence = capacity;
+            }
+            return fence;
+        }
+
+        private void checkForComodification() {
+            if (expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        @Override
+        public Spliterator<Number> trySplit() {
+            int high = getFence();
+            int low = position;
+            int middle = (low + high) >>> 1;
+            if (low >= middle) {
+                return null;
+            }
+            long splitEstimate = estimatedSize >>> 1;
+            LongSpliterator split = new LongSpliterator(low, middle,
+                    expectedModCount, splitEstimate, nullPending,
+                    zeroPending, true);
+            position = middle;
+            estimatedSize -= splitEstimate;
+            nullPending = false;
+            zeroPending = false;
+            hasSplit = true;
+            return split;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super Number> action) {
+            Objects.requireNonNull(action);
+            int high = getFence();
+            if (nullPending) {
+                nullPending = false;
+                if (estimatedSize > 0) {
+                    estimatedSize--;
+                }
+                action.accept(null);
+                checkForComodification();
+                return true;
+            }
+            if (zeroPending) {
+                zeroPending = false;
+                if (estimatedSize > 0) {
+                    estimatedSize--;
+                }
+                action.accept(Long.valueOf(0L));
+                checkForComodification();
+                return true;
+            }
+            final long[] curKeys = keys;
+            while (position < high) {
+                long key = curKeys[position++];
+                if (key != 0L) {
+                    if (estimatedSize > 0) {
+                        estimatedSize--;
+                    }
+                    action.accept(Long.valueOf(key));
+                    checkForComodification();
+                    return true;
+                }
+            }
+            checkForComodification();
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super Number> action) {
+            Objects.requireNonNull(action);
+            int high = getFence();
+            if (nullPending) {
+                nullPending = false;
+                action.accept(null);
+            }
+            if (zeroPending) {
+                zeroPending = false;
+                action.accept(Long.valueOf(0L));
+            }
+            final long[] curKeys = keys;
+            while (position < high) {
+                long key = curKeys[position++];
+                if (key != 0L) {
+                    action.accept(Long.valueOf(key));
+                }
+            }
+            estimatedSize = 0;
+            checkForComodification();
+        }
+
+        @Override
+        public long estimateSize() {
+            getFence();
+            return estimatedSize;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.DISTINCT | (hasSplit ? 0 : Spliterator.SIZED);
+        }
+    }
+
+    private static class LongArrayList {
+        /** The initial default capacity of an array list. */
+        public static final int DEFAULT_INITIAL_CAPACITY = 10;
+        private static final long[] DEFAULT_EMPTY_ARRAY = {};
+        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+        /** The backing array. */
+        protected long a[];
+        /**
+         * The current actual size of the list (never greater than the backing-array
+         * length).
+         */
+        protected int size;
+
+        /**
+         * Creates a new array list with given capacity.
+         *
+         * @param capacity the initial capacity of the array list (may be 0).
+         */
+        public LongArrayList(final int capacity) {
+            initArrayFromCapacity(capacity);
+        }
+
+        private void initArrayFromCapacity(final int capacity) {
+            if (capacity < 0)
+                throw new IllegalArgumentException("Initial capacity (" + capacity + ") is negative");
+            if (capacity == 0)
+                a = LongArrayList.DEFAULT_EMPTY_ARRAY;
+            else
+                a = new long[capacity];
+        }
+
+        public static long[] forceCapacity(final long[] array, final int length, final int preserve) {
+            final long t[] = new long[length];
+            System.arraycopy(array, 0, t, 0, preserve);
+            return t;
+        }
+
+        /**
+         * Grows this array list, ensuring that it can contain the given number of
+         * entries without resizing,
+         * and in case increasing the current capacity at least by a factor of 50%.
+         *
+         * @param capacity the new minimum capacity for this array list.
+         */
+
+        private void grow(int capacity) {
+            if (capacity <= a.length)
+                return;
+            if (a != LongArrayList.DEFAULT_EMPTY_ARRAY)
+                capacity = (int) Math.max(Math.min((long) a.length + (a.length >> 1), LongArrayList.MAX_ARRAY_SIZE),
+                        capacity);
+            else if (capacity < DEFAULT_INITIAL_CAPACITY)
+                capacity = DEFAULT_INITIAL_CAPACITY;
+            a = LongArrayList.forceCapacity(a, capacity, size);
+            assert size <= a.length;
+        }
+
+        public boolean add(final long k) {
+            grow(size + 1);
+            a[size++] = k;
+            assert size <= a.length;
+            return true;
+        }
+
+        public long getLong(final int index) {
+            if (index >= size)
+                throw new IndexOutOfBoundsException(
+                        "Index (" + index + ") is greater than or equal to list size (" + size + ")");
+            return a[index];
+        }
+
+    }
+}
diff --git a/test/jdk/jdk/internal/enhancement/classdata/java/util/PrimitiveHashSet.java b/test/jdk/jdk/internal/enhancement/classdata/java/util/PrimitiveHashSet.java
new file mode 100644
index 000000000..30481f4c6
--- /dev/null
+++ b/test/jdk/jdk/internal/enhancement/classdata/java/util/PrimitiveHashSet.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2002-2026 Sebastiano Vigna
+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * Common contract for the primitive-specialized HashSet representations.
+ *
+ * <p>This implementation incorporates and adapts ideas and portions from
+ * fastutil OpenHashSet. It is specialized for the bytecode-enhanced
+ * java.util.HashSet implementation in BiSheng JDK.
+ */
+abstract class PrimitiveHashSet extends AbstractSet<Number> implements Cloneable {
+    static final long LONG_PHI = 0x9E3779B97F4A7C15L;
+
+    static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    static final float DEFAULT_LOAD_FACTOR = .75f;
+
+    int mask;
+
+    boolean containsNull;
+
+    boolean containsZero;
+
+    int capacity;
+
+    int threshold;
+
+    int minCapacity;
+
+    int size;
+
+    int modCount;
+
+    float loadFactor;
+
+    // Retained only to emit the standard HashSet serialization metadata.
+    // It is intentionally independent of this table's occupancy factor.
+    float hashMapLoadFactor = HashMap.DEFAULT_LOAD_FACTOR;
+
+    public PrimitiveHashSet(final int initialCapacity, final float loadFactor) {
+        if (loadFactor <= 0 || Float.isNaN(loadFactor) || loadFactor >= 1) {
+            throw new IllegalArgumentException("Load factor must be between 0 and 1");
+        }
+        if (initialCapacity < 0) {
+            throw new IllegalArgumentException("Initial capacity must be non-negative");
+        }
+        this.loadFactor = loadFactor;
+        this.minCapacity = this.capacity = PrimitiveHashSet.leastArraySize(initialCapacity, loadFactor);
+        this.mask = this.capacity - 1;
+        this.threshold = PrimitiveHashSet.maxEntriesFill(this.capacity, loadFactor);
+    }
+
+    protected int realSize() {
+        return this.size - (this.containsZero ? 1 : 0) - (this.containsNull ? 1 : 0);
+    }
+
+    protected static long mixBits(final long n) {
+        long res = n * LONG_PHI;
+        res ^= res >>> 32;
+        return res ^ (res >>> 16);
+    }
+
+    protected static int maxEntriesFill(int capacity, float loadFactor) {
+        return Math.min((int) Math.ceil(capacity * loadFactor), capacity - 1);
+    }
+
+    protected static int leastArraySize(int expectedElements, float loadFactor) {
+        final long size = Math.max(2, nextPowerOfTwo((long) Math.ceil(expectedElements / loadFactor)));
+        if (size > (1 << 30)) {
+            throw new IllegalArgumentException("Expected number of elements is too large: " + expectedElements
+                    + " with load factor " + loadFactor);
+        }
+        return (int) size;
+    }
+
+    protected static long nextPowerOfTwo(long n) {
+        if (n == 0) {
+            return 1;
+        }
+        n--;
+        n |= n >> 1;
+        n |= n >> 2;
+        n |= n >> 4;
+        n |= n >> 8;
+        n |= n >> 16;
+        return (n | n >> 32) + 1;
+    }
+
+    @Override
+    public int size() {
+        return this.size;
+    }
+
+    public boolean isEmpty() {
+        return this.size == 0;
+    }
+
+
+    abstract Iterator<? extends Number> valueIterator();
+
+    abstract void forEachElement(Consumer<? super Number> action);
+
+    final boolean addNull() {
+        if (containsNull) {
+            return false;
+        }
+        containsNull = true;
+        size++;
+        modCount++;
+        return true;
+    }
+
+    final boolean removeNull() {
+        if (!containsNull) {
+            return false;
+        }
+        containsNull = false;
+        size--;
+        modCount++;
+        return true;
+    }
+
+    final void invalidateIterators() {
+        modCount++;
+    }
+
+    @Override
+    public final Iterator<Number> iterator() {
+        return new Iterator<>() {
+            private final Iterator<? extends Number> values = valueIterator();
+            private int expectedModCount = modCount;
+            private boolean nullPending = containsNull;
+            private boolean canRemove;
+            private boolean lastWasNull;
+
+            private void checkForComodification() {
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+
+            @Override
+            public boolean hasNext() {
+                return nullPending || values.hasNext();
+            }
+
+            @Override
+            public Number next() {
+                checkForComodification();
+                if (nullPending) {
+                    nullPending = false;
+                    canRemove = true;
+                    lastWasNull = true;
+                    return null;
+                }
+                Number value = values.next();
+                canRemove = true;
+                lastWasNull = false;
+                return value;
+            }
+
+            @Override
+            public void remove() {
+                if (!canRemove) {
+                    throw new IllegalStateException();
+                }
+                checkForComodification();
+                if (lastWasNull) {
+                    removeNull();
+                } else {
+                    values.remove();
+                }
+                expectedModCount = modCount;
+                canRemove = false;
+            }
+        };
+    }
+
+    @Override
+    public final void forEach(Consumer<? super Number> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+        if (containsNull) {
+            action.accept(null);
+        }
+        forEachElement(action);
+        if (expectedModCount != modCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    @Override
+    public abstract boolean contains(Object e);
+
+    @Override
+    public abstract boolean remove(Object e);
+
+    public PrimitiveHashSet clone() {
+        try {
+            PrimitiveHashSet cloned = (PrimitiveHashSet) super.clone();
+            return cloned;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+}
+