/* * Copyright 2009 Goldman Sachs International. All Rights Reserved. * Copyright (C) 2022 THL A29 Limited, a Tencent company. 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
/* * @test * @bug 6865031 * @summary Application gives bad result (throws bad exception) with compressed oops * * @requires vm.bits == 64 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops * -XX:HeapBaseMinAddress=32g -XX:-LoopUnswitching * -XX:CompileCommand=inline,compiler.c2.cr6865031.AbstractMemoryEfficientList::equals * compiler.c2.cr6865031.Test hello goodbye
*/
public WeakPool()
{ this.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = DEFAULT_INITIAL_CAPACITY;
table = new Entry[DEFAULT_INITIAL_CAPACITY];
}
/** * Check for equality of non-null reference x and possibly-null y. By * default uses Object.equals.
*/ privateboolean eq(Object x, Object y)
{ return x == y || x.equals(y);
}
/** * Return index for hash code h.
*/ privateint indexFor(int h, int length)
{ return h & length - 1;
}
/** * Expunge stale entries from the table.
*/ privatevoid expungeStaleEntries()
{
Object r; while ((r = queue.poll()) != null)
{
Entry e = (Entry) r; int h = e.hash; int i = indexFor(h, table.length);
// System.out.println("EXPUNGING " + h);
Entry<V> prev = table[i];
Entry<V> p = prev; while (p != null)
{
Entry<V> next = p.next; if (p == e)
{ if (prev == e)
{
table[i] = next;
} else
{
prev.next = next;
}
e.next = null; // Help GC
size--; break;
}
prev = p;
p = next;
}
}
}
/** * Return the table after first expunging stale entries
*/ private Entry<V>[] getTable()
{
expungeStaleEntries(); return table;
}
/** * Returns the number of key-value mappings in this map. * This result is a snapshot, and may not reflect unprocessed * entries that will be removed before next attempted access * because they are no longer referenced.
*/ publicint size()
{ if (size == 0)
{ return 0;
}
expungeStaleEntries(); return size;
}
/** * Returns <tt>true</tt> if this map contains no key-value mappings. * This result is a snapshot, and may not reflect unprocessed * entries that will be removed before next attempted access * because they are no longer referenced.
*/ publicboolean isEmpty()
{ return size() == 0;
}
/** * Returns the value stored in the pool that equals the requested key * or <tt>null</tt> if the map contains no mapping for * this key (or the key is null) * * @param key the key whose equals value is to be returned. * @return the object that is equal the specified key, or * <tt>null</tt> if key is null or no object in the pool equals the key.
*/ public V get(V key)
{ if (key == null)
{ returnnull;
} int h = key.hashCode();
Entry<V>[] tab = getTable(); int index = indexFor(h, tab.length);
Entry<V> e = tab[index]; while (e != null)
{
V candidate = e.get(); if (e.hash == h && eq(key, candidate))
{ return candidate;
}
e = e.next;
} returnnull;
}
/** * Returns the entry associated with the specified key in the HashMap. * Returns null if the HashMap contains no mapping for this key.
*/
Entry getEntry(Object key)
{ int h = key.hashCode();
Entry[] tab = getTable(); int index = indexFor(h, tab.length);
Entry e = tab[index]; while (e != null && !(e.hash == h && eq(key, e.get())))
{
e = e.next;
} return e;
}
/** * Places the object into the pool. If the object is null, nothing happens. * If an equal object already exists, it is not replaced. * * @param key the object to put into the pool. key may be null. * @return the object in the pool that is equal to the key, or the newly placed key if no such object existed when put was called
*/ public V put(V key)
{ if (key == null)
{ returnnull;
} int h = key.hashCode();
Entry<V>[] tab = getTable(); int i = indexFor(h, tab.length);
for (Entry<V> e = tab[i]; e != null; e = e.next)
{
V candidate = e.get(); if (h == e.hash && eq(key, candidate))
{ return candidate;
}
}
tab[i] = new Entry<V>(key, queue, h, tab[i]);
if (++size >= threshold)
{
resize(tab.length * 2);
}
/** * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * <p/> * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant).
*/ void resize(int newCapacity)
{
Entry<V>[] oldTable = getTable(); int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY)
{
threshold = Integer.MAX_VALUE; return;
}
Entry<V>[] newTable = new Entry[newCapacity];
transfer(oldTable, newTable);
table = newTable;
/* * If ignoring null elements and processing ref queue caused massive * shrinkage, then restore old table. This should be rare, but avoids * unbounded expansion of garbage-filled tables.
*/ if (size >= threshold / 2)
{
threshold = (int) (newCapacity * loadFactor);
} else
{
expungeStaleEntries();
transfer(newTable, oldTable);
table = oldTable;
}
}
/** * Transfer all entries from src to dest tables
*/ privatevoid transfer(Entry[] src, Entry[] dest)
{ for (int j = 0; j < src.length; ++j)
{
Entry e = src[j];
src[j] = null; while (e != null)
{
Entry next = e.next;
Object key = e.get(); if (key == null)
{
e.next = null; // Help GC
size--;
} else
{ int i = indexFor(e.hash, dest.length);
e.next = dest[i];
dest[i] = e;
}
e = next;
}
}
}
/** * Removes the object in the pool that equals the key. * * @param key * @return previous value associated with specified key, or <tt>null</tt> * if there was no mapping for key or the key is null.
*/ public V removeFromPool(V key)
{ if (key == null)
{ returnnull;
} int h = key.hashCode();
Entry<V>[] tab = getTable(); int i = indexFor(h, tab.length);
Entry<V> prev = tab[i];
Entry<V> e = prev;
while (e != null)
{
Entry<V> next = e.next;
V candidate = e.get(); if (h == e.hash && eq(key, candidate))
{
size--; if (prev == e)
{
tab[i] = next;
} else
{
prev.next = next;
} return candidate;
}
prev = e;
e = next;
}
returnnull;
}
/** * Removes all mappings from this map.
*/ publicvoid clear()
{ // clear out ref queue. We don't need to expunge entries // since table is getting cleared. while (queue.poll() != null)
{ // nop
}
table = new Entry[DEFAULT_INITIAL_CAPACITY];
threshold = DEFAULT_INITIAL_CAPACITY;
size = 0;
// Allocation of array may have caused GC, which may have caused // additional entries to go stale. Removing these entries from the // reference queue will make them eligible for reclamation. while (queue.poll() != null)
{ // nop
}
}
/** * The entries in this hash table extend WeakReference, using its main ref * field as the key.
*/ protectedstaticclass Entry<V> extends WeakReference<V>
{ privatefinalint hash; private Entry<V> next;
/** * Create new entry.
*/
Entry(final V key, final ReferenceQueue<V> queue, finalint hash, final Entry<V> next)
{ super(key, queue); this.hash = hash; this.next = next;
}
public V getKey()
{ returnsuper.get();
}
publicboolean equals(Object o)
{ if (!(o instanceof WeakPool.Entry))
{ returnfalse;
}
WeakPool.Entry<V> that = (WeakPool.Entry<V>) o;
V k1 = this.getKey();
V k2 = that.getKey(); return (k1==k2 || k1.equals(k2));
}
publicint hashCode()
{ returnthis.hash;
}
public String toString()
{ return String.valueOf(this.getKey());
}
}
}
test.ml1 = new MultiSynonymKey(new SingletonList(new String(test.arg1)));
test.ml2 = new MultiSynonymKey(new DoubletonList(new String(test.arg1), new String(test.arg2)));
test.ml3 = new MultiSynonymKey(new DoubletonList(new String(test.arg1), new String(test.arg2)));
wp.put(test.ml1);
wp.put(test.ml2);
test.setDaemon(true);
test.start();
int counter = 0; while (true) { synchronized (wp) {
MultiSynonymKey foo = test.ml3;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.