OpenJDK / jdk8u / jdk8u / jdk
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.