8266097: Better hashing support

Reviewed-by: chegar, dfuchs, ahgross, smarks, rhalade
This commit is contained in:
Julia Boes 2021-05-25 10:19:55 +00:00 committed by Henry Jen
parent 3a7b663b6f
commit dd199ee063
2 changed files with 38 additions and 19 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2019, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ package java.util;
import java.io.IOException; import java.io.IOException;
import java.io.InvalidObjectException; import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -1504,23 +1505,28 @@ public class HashMap<K,V> extends AbstractMap<K,V>
* @throws IOException if an I/O error occurs * @throws IOException if an I/O error occurs
*/ */
@java.io.Serial @java.io.Serial
private void readObject(java.io.ObjectInputStream s) private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException { 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(); reinitialize();
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new InvalidObjectException("Illegal load factor: " +
loadFactor);
s.readInt(); // Read and ignore number of buckets s.readInt(); // Read and ignore number of buckets
int mappings = s.readInt(); // Read number of mappings (size) int mappings = s.readInt(); // Read number of mappings (size)
if (mappings < 0) if (mappings < 0) {
throw new InvalidObjectException("Illegal mappings count: " + throw new InvalidObjectException("Illegal mappings count: " + mappings);
mappings); } else if (mappings == 0) {
else if (mappings > 0) { // (if zero, use defaults) // use defaults
// Size the table using given load factor only if within } else if (mappings > 0) {
// range of 0.25...4.0
float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
float fc = (float)mappings / lf + 1.0f; float fc = (float)mappings / lf + 1.0f;
int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ? int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
DEFAULT_INITIAL_CAPACITY : DEFAULT_INITIAL_CAPACITY :
@ -1549,6 +1555,18 @@ public class HashMap<K,V> extends AbstractMap<K,V>
} }
} }
// Support for resetting final field during deserializing
private static final class UnsafeHolder {
private UnsafeHolder() { throw new InternalError(); }
private static final jdk.internal.misc.Unsafe unsafe
= jdk.internal.misc.Unsafe.getUnsafe();
private static final long LF_OFFSET
= unsafe.objectFieldOffset(HashMap.class, "loadFactor");
static void putLoadFactor(HashMap<?, ?> map, float lf) {
unsafe.putFloat(map, LF_OFFSET, lf);
}
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
// iterators // iterators

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2019, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -297,8 +297,8 @@ public class HashSet<E>
@java.io.Serial @java.io.Serial
private void readObject(java.io.ObjectInputStream s) private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException { throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic // Consume and ignore stream fields (currently zero).
s.defaultReadObject(); s.readFields();
// Read capacity and verify non-negative. // Read capacity and verify non-negative.
int capacity = s.readInt(); int capacity = s.readInt();
@ -313,12 +313,13 @@ public class HashSet<E>
throw new InvalidObjectException("Illegal load factor: " + throw new InvalidObjectException("Illegal load factor: " +
loadFactor); 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. // Read size and verify non-negative.
int size = s.readInt(); int size = s.readInt();
if (size < 0) { if (size < 0) {
throw new InvalidObjectException("Illegal size: " + throw new InvalidObjectException("Illegal size: " + size);
size);
} }
// Set the capacity according to the size and load factor ensuring that // Set the capacity according to the size and load factor ensuring that