changeset 14560:f143814b41fb

8266097: Better hashing support Reviewed-by: mbalao, andrew
author yan
date Thu, 26 Aug 2021 14:33:15 +0300
parents 1b77223b4674
children 4074e9c839a3
files src/share/classes/java/util/HashMap.java src/share/classes/java/util/HashSet.java
diffstat 2 files changed, 44 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/HashMap.java	Thu Aug 19 18:38:42 2021 +0300
+++ b/src/share/classes/java/util/HashMap.java	Thu Aug 26 14:33:15 2021 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 
 import java.io.IOException;
 import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
 import java.io.Serializable;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
@@ -1370,23 +1371,28 @@
      *         could not be found
      * @throws IOException if an I/O error occurs
      */
-    private void readObject(java.io.ObjectInputStream s)
+    private void readObject(ObjectInputStream s)
         throws IOException, ClassNotFoundException {
-        // Read in the threshold (ignored), loadfactor, and any hidden stuff
-        s.defaultReadObject();
+
+        ObjectInputStream.GetField fields = s.readFields();
+
+        // Read loadFactor (ignore threshold)
+        float lf = fields.get("loadFactor", 0.75f);
+        if (lf <= 0 || Float.isNaN(lf))
+            throw new InvalidObjectException("Illegal load factor: " + lf);
+
+        lf = Math.min(Math.max(0.25f, lf), 4.0f);
+        HashMap.UnsafeHolder.putLoadFactor(this, lf);
+
         reinitialize();
-        if (loadFactor <= 0 || Float.isNaN(loadFactor))
-            throw new InvalidObjectException("Illegal load factor: " +
-                                             loadFactor);
+
         s.readInt();                // Read and ignore number of buckets
         int mappings = s.readInt(); // Read number of mappings (size)
-        if (mappings < 0)
-            throw new InvalidObjectException("Illegal mappings count: " +
-                                             mappings);
-        else if (mappings > 0) { // (if zero, use defaults)
-            // Size the table using given load factor only if within
-            // range of 0.25...4.0
-            float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
+        if (mappings < 0) {
+            throw new InvalidObjectException("Illegal mappings count: " + mappings);
+        } else if (mappings == 0) {
+            // use defaults
+        } else if (mappings > 0) {
             float fc = (float)mappings / lf + 1.0f;
             int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
                        DEFAULT_INITIAL_CAPACITY :
@@ -1415,6 +1421,24 @@
         }
     }
 
+    // Support for resetting final field during deserializing
+    private static final class UnsafeHolder {
+        private UnsafeHolder() { throw new InternalError(); }
+        private static final sun.misc.Unsafe unsafe
+                = sun.misc.Unsafe.getUnsafe();
+        private static final long LF_OFFSET;
+        static {
+            try {
+                LF_OFFSET = unsafe.objectFieldOffset(HashMap.class.getDeclaredField("loadFactor"));
+            } catch (NoSuchFieldException nfe) {
+                throw new InternalError();
+            }
+        }
+        static void putLoadFactor(HashMap<?, ?> map, float lf) {
+            unsafe.putFloat(map, LF_OFFSET, lf);
+        }
+    }
+
     /* ------------------------------------------------------------ */
     // iterators
 
--- a/src/share/classes/java/util/HashSet.java	Thu Aug 19 18:38:42 2021 +0300
+++ b/src/share/classes/java/util/HashSet.java	Thu Aug 26 14:33:15 2021 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -294,8 +294,8 @@
      */
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
-        // Read in any hidden serialization magic
-        s.defaultReadObject();
+        // Consume and ignore stream fields (currently zero).
+        s.readFields();
 
         // Read capacity and verify non-negative.
         int capacity = s.readInt();
@@ -310,12 +310,13 @@
             throw new InvalidObjectException("Illegal load factor: " +
                                              loadFactor);
         }
+        // Clamp load factor to range of 0.25...4.0.
+        loadFactor = Math.min(Math.max(0.25f, loadFactor), 4.0f);
 
         // Read size and verify non-negative.
         int size = s.readInt();
         if (size < 0) {
-            throw new InvalidObjectException("Illegal size: " +
-                                             size);
+            throw new InvalidObjectException("Illegal size: " + size);
         }
         // Set the capacity according to the size and load factor ensuring that
         // the HashMap is at least 25% full but clamping to maximum capacity.